Rework me on GitHub

Lücken stopfen

root (Edward Gerhold)

Heute frisch aus dem Drucker:

Lineare Integralgleichungen

Variationsrechung

Ich habe hier noch Nachholbedarf.

Muss erstmal gucken, ob die PSB auf hat, damit ich lochen und einen Heftstreifen reinstecken kann.

Werde natürlich primär mit der Numerik weitermachen. Ich hatte das geschrieben, weil es Zeit ist, damit fertig zu werden.

 

Numerik

root (Edward Gerhold)

Ich habe es endlich geschafft.

Über die Wiederholung der Differentialgleichungen und durch persönliches sich Verbessern über die Numerik partieller Differentialgleichungen zur Numerik an sich. Natürlich habe ich das oberflächlich schon eine Weile mitverfolgt, was die Numerik bietet und kann die Namen der Verfahren und Bereiche und wozu die Sachen gut sind (nicht alle) bereits einigermassen aufzählen. Das ist aber nicht Sinn der Sache. Was ich lernen muß ist zum einen die Maschinengenauigkeit und den Rundungsfehler, zum anderen die zahlreichen Abschätzungen und Differenzen, die es zu vergleichen und zu bewerten gilt. Zum anderen aber, gibt es Dinge, wie die Quadratur (Integration), die ich lernen muss, um zum Beispiel meinen Ausflug in die Funktionentheorie zu vervollständigen. Während ich theoretisch und handschriftlich mit Grenzwerten, Cauchy-Integralen und Residuensatz umgehen kann, und könnte, fehlt mir praktisch die komplette Einrichtung auf dem Computer. Ich kann keine Integrale ausrechnen, ausser ich kenne die Stammfunktion. Oder ich näher mich mit Riemann Summme oder neu mit Lebesgue Integral, indem ich die Ergebnisse zerlege und nach Intervallmass zusammenrechne. Die Trapez, Simpson, die aus der Schule, und andere Regeln kriegt man aber wohlimplementiert und perfekt abgeschätzt in der Numerik geboten.

Also bevor es Residuen und Cauchyformeln in meinem komplexen Datentyp (das Posting zwei tiefer) gibt, bringe ich mir die Tage jetzt erstmal ein paar Dinge bei. Wenn eine |d(f(x1),f(x2))<=|d(x1,x2)| dann sagt man, die Funktion kontrahiert und besitzt einen Fixpunkt x* mit f(x*)=x*, oder anders, ich fange mit Fixpunktiteration an. Newtonsmethode, Nullstellen zu finden, die man auch mit x* bezeichnen kann, kennt man ja. Oder Eulers Polygonzugmethode. Das sind iterative Methoden, also, wo x_n+1 von x_n + irgendwas abhängt. Diese Methoden gibt es auch mit Matrizen und davon habe ich mir in letzter Zeit einige durchgelesen und versucht zu verstehen. Um demnächst meine komplexen Zahlen  vernünftig auf der Gauss-Ebene zu sehen, in einer offenen Umgebung, wo meine Folgen punktgenau konvergieren, und meine Funktion beliebig oft differenzierbar ist, muss ich mehr machen als Residuensatz oder Cauchys Formeln implementieren. Erstmal muss ich mir Rundung und Fehlerabschätzung beibringen, und das Integral neu schreiben, denn meine einfache Riemann-Summe (die weder linke noch rechte Summe ist, wenn ich jetzt ganz grob auf das Ding unten zeige, wo ich mir auch keine Gedanken machte) ist nichts gegen die numerischen Grundlagen, die man sich aneignen kann. Dann klappts auch mit der Riemannschen Zahlenkugel in 3-D (scherzhaft), oder auf der Mannigfaltigkeit. Achja, dass ich mich bereits an der Lie-Klammer versucht habe, ist ein anderes Thema.

Also demnächst werde ich es schaffen, norm(u-f) <= norm(v-f) auszurechnen, um zu gucken, ob u oder v die Funktion f besser approximiert. Apropos f. Die Funktionalanalysis, die mit unendlichdimensionalen Vektorräumen zugange ist, und eine komplexe Definition der linearen Algebra beinhaltet, macht mir thematisch Riesenspass. Nun hat man differenzierbare Funktionen die auf differenzierbare Funktionen abbilden und auch neue Differentiations- und Konvergenzbegriffe, und noch ein paar tolle Stunden vor sich.

Vor einigen Monaten war ich noch stolz auf mich, selbst für "Lineare Algebra" für "Webgl" gesorgt zu haben und meine eigene "Matrix" library zu schreiben, die "affine Transformationen" und "Projektionsmatrizen" beinhaltet, damit ich Koordinaten transformieren kann. Ich hatte vergessen, mir lineare Algebra richtig anzusehen, als ich jünger war und mal linux-swt werden wollte. Ok, in den Kernel kam ich mit C auch so. Gauss hatte ich in Minuten verstanden, weil ich das Schulrechnen ja bereits wiederholt hatte und schon mit Calculus (amerik. Infinitesimalrechnung) angefangen hatte. Die Matrixfaktorisierungen und die Rechenregeln hatte ich schnell begriffen, weil der Strang ein guter Lehrer ist. Mittlerweile habe ich das alles auf Deutsch nochmal gemacht.

Ich hab noch gar nicht alles erzählt, es gibt dreitausend Definitionen, Sätze und Beweise und noch mehr Beispiele und Bemerkungen zu entdecken. Und noch mehr. Wie zum Beispiel jetzt. Sich ein paar Stützstellen auf einem äquidistanten Gitter rauspicken und dann abzuschätzen, ob das nah genug ist, das ist wohl nicht so schwer. Oder ob I(f) der einen oder anderen Bedingung genügt, die ich abrupt in der Sekunde alle vergessen habe, wo ich sie vor drei Stunden noch interessiert gelesen hatte.

Ok, genug geredet. Ich mache die Tage dann Numerik. Wir brauchen die Matrizen, mit einfacher Matrix und/oder Vektor Multiplikation, aber nxn und keine hardcoded Matrizen, ausser man will viel zu warten haben. Das Gram-Schmidt Verfahren für Orthonormalbasen, weil wir die unbedingt brauchen, und und und. Die Funktionen für die Normen müssen sein, 1-norm, sup-Norm, p-Norm, eukl. 2-Norm, alle werden gebraucht und dann natürlich die Polynomfolgen. Und weil es so toll ist, die Numerik aus dem Unterricht. Die aus dem Unterricht. Wenn ich jetzt weiter erzählen würde, würde ich rausrutschen, dabei sind mir die Kurven der Differentialgleichungen und die Matrixmethoden bereits klar. Eigenwerte kann auch ich zu Fuss ausrechnen mit det(A-lamdbaE)=0 und Eigenvektoren mit (A-lambdaE)v=0. Was Spur auf Deutsch ist, ist Trace auf Amerikanisch. Was der Null Space auf Englisch ist, ist der Kern auf Deutsch. Aber Achtung. Das Fundamentale Theorem, was ich beim Strang gelesen habe, ist besser als das Deutsche. Wobei mir die Homomorphismen und Abbildungen aller Art auf Deutsch natürlich mehr Spass machen als das Weggelassene im Englischen. Dennoch habe ich mit Mathe erst auf Englisch begonnen, ganz evolutionär.

Jetzt wollen wir mal weiter machen. Wenn ich mal soweit bin, poste ich Code und Verfahren. Und korrigiere die komplexe Zahl.

Jetzt weiss man wieder zuviel, was ich heimlich mache, oder? Ist bloss für die Allmende. Bloss für die Allmende. Und weil das Arbeitsamt sich eh nicht um mich schert. Und weils mehr Spass macht, als erwartet. Ist halt Mathe.

Mathematik

root (Edward Gerhold)

Vor einem halben Jahr konnte ich nichtmal mehr die Mathematik der zehnten Klasse.

Heute stelle ich die Abiturklasse in den Schatten.

Und weil das Arbeitsamt mir nichtmal sechs Monate LPI 1+2 zahlen möchte, beziehungsweise gar nichts, nehme ich es um so ernster.

Algebra 1-2, Analysis 1-5, Lineare Algebra 1-2, Differentialgleichungen 1-3, Stochastik 1-2, Differntialgeometrie, Numerik 1-3, Mathe für Informatiker

Ich hab alles da. Und nicht alles genannt. Und ich bin schon zweimal erwachsen.

Wer würd´ da nicht mal sein JavaScript-Schnipsel geposte auf seiner Homepage vernachlässigen?

Vor einem halben Jahr hätte ich nicht gewusst, daß ich in einem halben Jahr zum Beispiel gut in Topologien geworden bin.

Mathe macht Riesenspass und ich lerne jeden Tag.

 

 

Bugs as usual

root (Edward Gerhold)

// few days old, but...
// 2 pi continued in a few days
//
// convention:
// this.method() alters the object, if the method returns a complex number
// Complex.method(this) return a new complex object by constructor calls

function Complex(real, imag, freeze)  // freeze is to create constants on the fly
{
    // changed
    // this.re to this[0]
    // and this.im to this[1]

    "use strict";
    // could check real and imag ( the spec impl would )
    // and throw, but there is no need today
    // other methods should and will throw typeerrors and range errors
    this[0] = real ||0;
    this[1] = imag ||0;	

    this.length = 2; // let´s be array like for common js programming
    
    if (freeze) Object.freeze(this);
}

function OpenEnvironment(r, z) {
    this[0] = r;
    this[1] = z;
}

OpenEnvironment.prototype = {
    distance: function (z) {
	// return a distance for re and one for i 
	// in a new complex number with distre=Re and distim=Im
	var r = this[0];
	var z = this[1];
	var dre = z[0]-w[0];	
	var dim = z[1]-w[1];
	return new Complex(dre, dim);
    },
    inside: function (w) {
	var r = this[0];
	var d = this.distance(this[1], w);
	return ((d[0] < r)&&(d[1] < r));
    }
};


Complex.prototype = {

	relError: function (x) {
	    var xx = Math.round(x);
	    return Math.abs(x-Math.round(x))/Math.abs(x);
	},
	absError: function (x) {
	    return Math.abs(x - Math.round(x));
	},

	precision: function () {
	    
	},
	env: function (r) {
	    var env = new OpenEnvironment(r, this);
	    this.environment = env;
	},
	
	length: 2,
	
	get re () {
	    return this[0];
	},
	
	set re (v) {
	    this[0] = v;
	},
	get im () {
	    return this[1];
	},
	set im (v) {
	    this[1] = v;
	},
		
	assign: function (z) {
	    this[0]=z[0];
	    this[1]=z[1];
	},
	
	clear: function () {
	    this[0] = 0;
	    this[1] = 0;
	},
	
	add: function (z) 
	{
		if (typeof z === "number") {
			this[0] += z;
		} else {
			this[0] += z[0];
			this[1] += z[1];
		}
		return this;
	},
	sub: function (z) 
	{
		if (typeof z === "number") {
			this[0] -= z;
		} else {
			this[0] -= z[0];
			this[1] -= z[1];
		}
		return this;
	},
	multiply: function (z) {
		// multiplication for the complex body C
		if (typeof z === "number") {
		    this[0] *= z;
		    this[1] *= z;
		} else {
		    this[0] = this[0] * z[0] - this[1] * z[1];
		    this[1] = this[1] * z[0] + this[0] * z[1];
		}
		return this;
	},
	divide: function (z) 
	{
		if (typeof z === "number") {
			this[0] /= z;
			this[1] /= z;
		} else {
			var im = (this[0] * -z[1])+ (this[1] * z[0]); 
			var re = (this[0] * z[0]) - (this[1] * -z[1])
			var nom= (z[0] * z[0]) - ( z[1] * -z[1]);
			this[0] = re / nom;
			this[1] = im / nom;
		}
		return this;
	},
	conjugate: function () 
	{
		this[1] = -this[1];
		return this;
	},
	abs: function () 
	{
		return Math.sqrt(this[1]*this[1] + this[0]*this[0]);
	},
	exp: function () 
	{   
		var ex = Math.pow(Math.E, this[0]);
		this[0] = ex * Math.cos(this[1]);
		this[1] = ex * Math.sin(this[1]);
		return this;
	},
	log: function () 
	{
		var abs = Math.sqrt(this[1]*this[1] + this[0]*this[0]);
		var log = Math.log(abs);
		
		if (this[1] <= 0) {
			this[0] = log;
			this[1] = Math.PI; 
		} 
		
		var sign = this[1] < 0 ? -1 : 1;
		this[1]=sign * Math.acos(this[0] / abs);
		this[0]=log;
		return this;
	},
	cosh: function () { return this.cos(); },
	cos: function () 
	{
		var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, this));
		var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, this));
		return eiz.add(emiz).divide(Complex.Constants.TWO_RE);
	},
	sinh: function () { return this.sin(); },
	sin: function () 
	{
		var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, this));
		var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, this));
		return eiz.sub(emiz).divide(Complex.Constants.TWO_I);
		
		// change thisvalue into cos, throw this numbers cos in a new object from the static methods on Complex
	},
	isZero: function () 
	{
		return (this[1] === 0) && (this[0] === 0);
	},
	isReal: function () 
	{
		return (this[1] === 0) && (this[0] === +this[0]);
	},
	isValid: function () 
	{
		// tests for nan
		return (this[1] === this[1]) && (this[0] === this[0]);
	},
	isNaN: function () 
	{
		// tests for nan
		return (this[1] !== this[1]) || (this[0] !== this[0]);
	},
	isFinite: function () 
	{
		return (Math.abs(this[0]) != Infinity) && (Math.abs(this[1]) != Infinity);
	},
	freeze: function () 
	{
		Object.freeze(this);
	},
	equals2: function (z) 
	{
		if (typeof z == "number") {
			return (this[0] === z) && this[1] == 0;
		}
		return (this[0] === z[0]) && (this[1] === z[1]);
	},	
	equals3: function (z) 
	{
		if (typeof z == "number") {
			return (Math.abs(this[0] - z) < Complex.equalsExactness) && (this[1] === 0);
		}
		return (Math.abs(this[0] - z[0]) < Complex.equalsExactness) && (Math.abs(this[1] - z[1]) < Complex.equalsExactness);
	},
	equals: function (z) {
		if (typeof z == "number") {
			return ((Math.abs(this[0] - z)/Math.abs(this[0])) <= Complex.doubleEps) && (Math.abs(this[1]) < Complex.doubleEps);
		}
		return ((Math.abs(this[0] - z[0])/Math.abs(this[0])) < Complex.doubleEps) && ((Math.abs(this[1] - z[1])/Math.abs(this[1]) < Complex.doubleEps));
	},
	clone: function () 
	{
		return new Complex(this[0], this[1]);
	},	
	toVector: function () {
		return [this[0], this[1]];
	},
	fromVector: function (v) {
		this[0] = v[0];
		this[1] = v[1];
	},
	
	toString: function () {
		return "[object Complex]";
	},
	
        converges: function (againstZ) {
    	    return (Math.abs(this[0] - againstZ[0]) < Complex.defaultConvergence) && (Math.abs(this[1] - againstZ[1]) < Complex.defaultConvergence);	
	}
};


Complex.equalsExactness = Number.MIN_VALUE*2;
Complex.eps = function (q, l)
{
    // eps(q,l):=(q/2)q^-l
    return (q/2)*Math.pow(q,-l);
};

Complex.doubleEps = Complex.eps(10, 11); // 10 or 2


Complex.TWO_PI = Math.PI*2;

Complex.fact = function (n) 
{
	// for series. calculation each n only once
	var product;
	if (product = Complex._factmem[n]) return product;
	product = n;
	var m = n;
	if (n < 1) return 1;
	while (n > 1) {
	    n--;
	    product *= n;
	}
	return Complex._factmem[m] = product;
};
Complex._factmem = Object.create(null);


Complex.add = function (z1, z2) {
	if (typeof z2 === "number") {
	return new Complex(z1[0]+z2, z1[1]);
	}
	return new Complex(z1[0]+z2[0], z1[1]+z2[1]);
};

Complex.sub = function (z1, z2) 
{
	if (typeof z2 === "number") {
	return new Complex(z1[0]-z2, z1[1]);
	}
	return new Complex(z1[0]-z2[0], z1[1]-z2[1]);
};


Complex.multiply = function (z1, z2) {
	if (typeof z2 === "number") {
	    return new Complex(z1[0]*z2, z1[1]*z2);
	}
	return new Complex(z1[0]*z2[0] - z1[1]*z2[1], 
			   z1[1]*z2[0] + z1[0]*z2[1]);
};

Complex.divide = function (z1, z2) {
	if (typeof z2 === "number") {
	return new Complex(z1[0]/z2, z1[1]/z2);
	}
	var re =  z1[0] * z2[0];     
	var im1 = z1[0] * -z2[1];  
	var im2 = z1[1] * z2[0]; 
	var isq = z1[1] * -z2[1]; 
	var den_re = re-isq;
	var den_im = im1+im2;
	re =  z2[0] * z2[0];
	isq = z2[1] * -z2[1];
	var nom = re-isq;  
	return new Complex(den_re/nom, den_im/nom); 
};



Complex.conjugate = function (c) 
{
	return new Complex(c[0], -c[1]);
};

Complex.arg = function (z) 
{
	if (z[1] === 0 || z[1] === -Infinity) { 
	// this range is not correct, but the main sense of arg is
		return Math.PI;
	} 
	
	return (z[1] < 0? -1:1) * Math.acos(z[0] / abs);
};

Complex.log = function (z) 
{
	var abs = Math.sqrt(z[1]*z[1] + z[0]*z[0]);
	var log = Math.log(abs);
	if (z[1] <= 0) {
		return new Complex(log, Math.PI);
	} 
	return new Complex(log, ((z[1] < 0) ? -1:1) * Math.acos(z[0] / abs));
};

Complex.abs = function (z) {    
	// euclidean norm is equal
	return Math.sqrt(z[1]*z[1] + z[0]*z[0]);
};

Complex.exp = function (z) {
	if (typeof z === "number") z = new Complex(z, 0);
	var ex = Math.exp(z[0]);
	// var ex = Math.pow(Math.E, z[0]);
	return new Complex(ex * Math.cos(z[1]), ex * Math.sin(z[1]));
};

Complex.exp2 = function (phi) {
	phi = phi % (Math.PI *2); 
	// prolly neccessary otherwhere, too. Here it is.
	return new Complex(Math.cos(phi), Math.sin(phi));
};



// z go to zzero, maybe by 2^-53 differenc
// i already have a algorithmic limit theory, but no impl of (yet)
Complex.limit = function (z, z0, f) {
	// returns f´(z0) or gives a limit
	var nominator = Complex.sub(z, z0);
	var denominator = Complex.sub(f(z), f(z0));
	if (Complex.isZero(nominator)) return;
	return Complex.divide(denominator, nominator);
};


Complex.cube = function (z) {
	return new Complex(z[0]*z[0]*z[0] - 3*z[0]*z[1]*z[1], 3*z[0]*z[0]*z[1] - z[1]*z[1]*z[1]);
};

Complex.square = function (z) {
	return new Complex(z[0]*z[0] - z[1]*z[1], z[0]*z[1] + z[0]*z[1]);
};

Complex.sin = function (z) 
{
	var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, z));		
	var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, z));
	return eiz.sub(emiz).divide(Complex.Constants.TWO_I);
};

Complex.cos = function (z) 
{
	var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, z));
	var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, z));
	return eiz.add(emiz).divide(Complex.Constants.TWO_RE);
};
	
Complex.pow = function(z, k)    
{
	// raise z to kth power
	
	// oh, i forgot first
	// this only takes integers, no 0.5 = sqrt or such.
	if (k == 0) {
		return new Complex(1, 0);
	} 
		var result;
	if (k > 0) {
		result = Complex.clone(z);
		while (k > 1) {
			result.multiply(z);
			k--;
		}
		return result;
	} 
	if (k < 0) {
		result = new Complex(1,0);
		while (k < 0) {
			result.divide(z);
			k++;
		}
		return result;
	}
};

Complex.complexDet2x2 = function (A) {
    // return ad-bc
    return Complex.multiply(A[0], A[3]).subtract(Complex.multiply(A[1],A[2]));
};

Complex.mat2 = function (a,b,c,d) {
    // for a complex typed array version the code must
    // go through replacing all [1] and [0] with [1] and [0]
    // done one afternoon. now we try vanilla js.
    
    // complex matrices have 2 fields each entry. maybe i can develop
    // for and find a place to put some idea by me. 
    return [a,b,c,d];
}

Complex.Mat2x2 = function Mat2x2(a,b,c,d) {
    "use strict";
    this[0] = a;
    this[1] = b;
    this[2] = c;
    this[3] = d;
    this.length = 4;
    
};
Complex.Mat2x2.prototype = {
    multiply: function (B) {
	// currently skipping double impl.
	var m = Complex.mat2mul(this, B);
	// temp
	for (var i = 0, j = m.length; i < j; i++) {
	    this[i] = m[i];
	}
	this.length = m.length;
	return this;
    }    
};

Complex.mat2mul = function (A,B) {

    var C = [];
    if (A.length == 4 && B.length == 2) {
	// 2x2 with 2x1
	C[0] = Complex.multiply(A[0], B[0]).add(Complex.multiply(A[2], B[1]));
	C[1] = Complex.multiply(A[1], B[0]).add(Complex.multiply(A[3], B[1]));
	C.length = 2;
	return C;
    }

    if (A.length == 4 && B.length == 4) {
	// Matrix 2x2 with 2x2
	C[0] = Complex.multiply(A[0], B[0]).add(Complex.multiply(A[2], B[2]));
	C[1] = Complex.multiply(A[0], B[1]).add(Complex.multiply(A[2], B[3]));
	C[2] = Complex.multiply(A[1], B[0]).add(Complex.multiply(A[3], B[2]));
	C[3] = Complex.multiply(A[1], B[1]).add(Complex.multiply(A[3], B[3]));
	C.length = 4;
	return C;
    }

    if (A.length == 2 && B.length == 4) {
	// 2x1 with 2x2
	// is 2x2
	C[0] = Complex.multiply(A[0], B[0]);
	C[1] = Complex.multiply(A[0], B[1]);
	C[2] = Complex.multiply(A[1], B[2]);
	C[3] = Complex.multiply(A[1], B[3]);
	C.length = 4;
	return C;
    }
    
    if (A.length == 2 && B.length == 2) {
	//this returns NO ARRAY!! just a scalar
	return Complex.multiply(A[0], B[0]).add(Complex.multiply(A[1]+B[1]));
	
	
	// return [1]?
	//C[0] = Complex.multiply(A[0], B[0]).add(Complex.multiply(A[1]+B[1]));
	//C.length = 1;
	//return C;
    }
    
};

Complex.mTransform = function (A, z) {
	// A = [a, b; c, d]
	
	if (Complex.isZero(Complex.complexDet2x2(A))) return undefined;
	
	var den = Complex.multiply(z, A[0]).add(A[1]);
	var nom = Complex.multiply(z, A[2]).add(A[3]);
	nom.multiply(Complex.conjugate(nom));
	if (nom[0] !== 0)
	return new Complex(den[0]/nom[0], den[1]/nom[0]);
};

Complex.cayleyTransform = function (z) {    
	return Complex.mTransform(
	    [ Complex.Constants.ONE_RE, Complex.Constants.MINUS_ONE_I, Complex.Constants.ONE_RE, Complex.Constants.ONE_I ], 
	    z
	);	
};

Complex.translate = function (b, z) 
{
	return Complex.add(z, b);
};

Complex.scale = function (a, z) {
	return Complex.multiply(a,z);    
};

Complex.invert = function (z) 
{
	return (new Complex(1, 0)).divide(z);
};

Complex.doubleRatio = function (z1, z2, z3, z4) {
	// "Doppelverhaeltnis" 
	// it is
	// (z1-z2) * (z3-z4) divided by
	// (z2-z3) * (z4-z1)
	return Complex.sub(z1,z2).multiply(Complex.sub(z3,z4)).divide( 
		Complex.sub(z2,z3).multiply(Complex.sub(z4,z1)) 
	);
}


/*
	Next is getting the line integrals along the border working, eh

	
*/

Complex.integrate = function (a, b, n, f) {
P	// [a,b] is the interval, n the number of rectangles
	// this summarises two integrals for the real and the imaginary part.
	
	// anyways, it´s wrong and i was about remembering $ pdx + qdy
	// but that´s not today
	
		var deltaz = (b-a)/n;
		var riemann_sum_re = 0;
		var riemann_sum_im = 0;
	for (var i = a; i <= b; i+= deltaz) {
		var z = f(new Complex(i))
		riemann_sum_re += z[0] * deltaz;
		riemann_sum_im += z[1] * deltaz;
	}
	return new Complex(riemann_sum_re, riemann_sum_im);
};

// No check if I^(S) and I_(S) are equal? 

Complex.integrate_double_check_the_rules = function (a, b, n, f) {
	// [a,b] is the interval, n the number of rectangles
	var deltaz = (b-a)/n;
	var riemann_sum = new Complex;
	for (var i = a; i <= b; i+= deltaz) {
		riemann_sum.add(Complex.multiply(f(new Complex(i)), deltaz));
	}
	return riemann_sum;
};




Complex.lineIntegral = function (a, b, f, delta)
{
    
    // absolutly wrong implementation (yet)

    
    delta = delta || 0.01; // how far i go on the arc
    
    var deltax;
    var deltay;

    var x = 0,
        y = 0, 
        lastx = 0, 
	lasty = 0;

    var sum = new Complex(0,0);
    var arc, work;
    
    for (var i = a; i <= b; i+=delta) {
	
	z = f(i);
	var x = z[0];
	var y = z[1];
	deltax = x - lastx;
	deltay = y - lasty;
	
	// not right, but it´s going into the right direction, guys
	// this from the physics work integral
	// after becoming valid it has to become a complex cauchy integral
	// currently it´s not even giving a valid result
		
	arc = Math.sqrt(deltax*deltax + deltay*deltay);
	work = Complex.multiply(z, arc);
	sum.add(work);
	
	lastx = x;
	lasty = y;
    }
    
    return sum;
};


Complex.defaultConvergence = 1e-33;
Complex.converges = function (z1, z2) {
	return (Math.abs(Math.abs(z1[0]) - Math.abs(z2[0])) < Complex.defaultConvergence) && (Math.abs(Math.abs(z1[1]) - Math.abs(z2[1])) < Complex.defaultConvergence);	
};

Complex.sequence = function (z0, k, fz) 
{
	if (!Complex.isComplexType(z0)) {
	    z0 = Complex(z0, 0);
	}
	var last;
	var zk = z0;
	var seq = [z0];
	for (var i = 1; i <= k; i++) {    
	    last = zk;
	    zk = fz(i, zk);
	    if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
	    seq.push(zk);
	    //if Complex.converges(last, zk)) break;
	}
	return seq;
};

Complex.series = function (z0, k, fz) 
{
	var sum = new Complex(0,0);
	    if (!Complex.isComplexType(z0)) {
	    z0 = Complex(z0, 0);
	}
	var zk = z0;
	var seq = [z0];
	var last;
	for (var i = 1; i <= k; i++) {    
	    last = zk;
	    zk = fz(i, zk); // i is k passed into, with the last zk
	    
	    // i am missing the coefficients array or callback (fourier) here
	    if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
	    sum.add(zk);
	    //if Complex.converges(zk, last)) break;
	}
	return sum;
};


Complex.sequence2 = function (z, z0, k, coeffs, callback) {
	var ak = 1;
	var zk = z0;
	var sequence = [];
	var last;
	for (var i = 0; i < k; i++) {
		if (coeffs) ak = (coeffs[i] || 0);
		else ak = 1;
		last = zk;
		zk = callback(ak, z, z0, i, zk); // next = callback(..., prev);

		if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
		sequence.push(zk);
		//if Complex.converges(zk, last)) break;
	}
	return sequence;
	
};

Complex.sequence3 = function (z, z0, start, k, coeffs, callback) {
	var ak = 1;
	var zk = z0;
	var sequence = [];
	var last;
	for (var i = start; i < k; i++) {
		if (coeffs) ak = (coeffs[i] || 0);
		else ak = 1;
		last = zk;
		zk = callback(ak, z, z0, i, zk); // next = callback(..., prev);
		if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
		sequence.push(zk);
		//if Complex.converges(zk, last)) break;
	}
	return sequence;
	
};


Complex.series3 = function (z, z0, start, k, coeffs, callback) {
	var ak = 1;
	var zk = z0;
	var sum = new Complex;
	var last;
	for (var i = start; i < k; i++) {
		if (coeffs) ak = (coeffs[i] || 0);
		else ak = 1;
		last = zk;
		zk = callback(ak, z, z0, i, zk); 
		if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
		sum.add(zk);
		//if Complex.converges(zk, last)) break;
	}
	return sum;
};



Complex.power_series = function (z, z0, k, coeffs) 
{
	// ordinary power series
	var sum = new Complex;
	var zminusz0 = Complex.sub(z,z0);
	Complex.sequence2(z, z0, k, coeffs, function (ak, z, z0, k, zk) {
		zk = Complex.multiply(Complex.pow(zminusz0, k), ak); // this is the (ak*(z-z0)^k)k elem N.
		sum.add(zk);
		return zk;
	});
	return sum;
}

Complex.power_sequence = function (z, z0, k, coeffs) 
{
	var zminusz0 = Complex.sub(z,z0);
	return Complex.sequence2(z, z0, k, coeffs, function (ak, z, z0, k, zk) {
		return Complex.multiply(Complex.pow(zminusz0, k), ak);
	});
}


Complex.laurent_series = function ()
{
	// got my book closed
	var sum = new Complex;
	var zminusz0 = Complex.sub(z,z0);
	Complex.sequence3(z, z0,  Number.MIN_VALUE, Number.MAX_VALUE, coeffs, function (ak, z, z0, k, zk) {
		zk = Complex.multiply(Complex.pow(zminusz0, k), ak); // this is the (ak*(z-z0)^k)k elem N.
		sum.add(zk);
		return zk;
	});
	return sum;
};


Complex.fourier_series = function (f, n, t) 
{
	return Complex.se
}


Complex.exp_series = function (z) 
{
	var k = 0;
	var sum = new Complex(0,0);
	while (k < Infinity) {
		var zk = Complex.pow(z, k);
		zk.divide(Complex.fact(k));
		// here is better convergence testing by error estimation necc. i am taking class for, just begun
		if (Complex.isZero(zk) || !Complex.isValid(zk)) return sum;
		sum.add(zk);
		k++;
	}
	return sum;
};
Complex.sin_series = function (z) 
{
	var k = 0;
	var sum = new Complex(0,0);
	while (k < Infinity) {
		var sign = Math.pow(-1, k);
		var zk = Complex.pow(z, 2*k+1);
		zk[0] *= sign;
		zk[1] *= sign;
		zk.divide(Complex.fact(2*k+1));
		if (Complex.isZero(zk) || !Complex.isValid(zk)) return sum;
		sum.add(zk);
		k++;
	}
	return sum;
};

Complex.cos_series = function (z) 
{
	var last = 0;
	var k = 0;
	var sum = new Complex(0,0);
	while (k < Infinity) {
		var sign = Math.pow(-1, k);
		var zk = Complex.pow(z, 2*k);
		zk[0] *= sign;
		zk[1] *= sign;
		zk.divide(Complex.fact(2*k));
		if (last && Complex.converges(zk, last)) return sum;
		//if (Complex.isZero(zk) || !Complex.isValid(zk)) return sum;
		sum.add(zk);
		last = zk;
		k++;
	}
	return sum;
};



Complex.isConjugate = function (a,b) 
{
	return (a[0] === b[0]) && (a[1] === -b[1]);
};

Complex.isReal = function (z) 
{
	return z[1]===0;
};

Complex.isZero = function (z) 
{
	return z[0]===0&&z[1]===0;
};

Complex.isValid = function (z) 
{
	return (z[0] === z[0]) && (z[1] === z[1]);
};

Complex.isComplexType = function (z) 
{
	return z instanceof Complex;
};

Complex.toComplex = function (z) 
{
	if (Array.isArray(z)) return new Complex(z[0],z[1]);
	if (typeof (+z) === "number") return new Complex(+z, 0);
	if (z instanceof Complex) return z;
	throw new TypeError("can not convert");
};

Complex.clone = function (z) 
{
	if (typeof z=="number") return new Complex(z, 0);
	return new Complex(z[0], z[1]);
};


Complex.fromVector = function (z) 
{
	return new Complex(z[0], z[1]);
};
Complex.toVector = function (z) 
{
	if (typeof z === "number") {
	return [z, 0];
	}
	return [z[0], z[1]];
};

Complex.cartesianProduct = function (I, J) 
{
	// return from cP: IxJ -> P a set of arrays of two points
	var P = [];
	for (var i = 0; i < I.length; i++) {
	for (var j = 0; j < J.length; j++) {
		P.push([I[i], J[j]]);
	}   
	}
	return P;
};


Complex.plot = function (I,f) {
	// I contains any number of points (single value)
	// f a function taking a complex number and returning a complex number
	var points = [];
	I.forEach(function (i) {
		points.push(f(new Complex(i)).toVector());
	});
	return points;
};

Complex.plot2 = function (a,b,n,f) {
	// a interval start
	// b end value
	// n number of points
	// f a function taking a number and returning a complex number
	var points = [];
	var deltaz = (b-a)/n;
	for (var i = a; i <= b; i+=deltaz) {    
	    points.push(f(i).multiply(deltaz).toVector());
	}
	return points;
};

/*
	the plotting isnt it yet

	this is before inveting a disc with a slit and some
	transformations by mTransform and the other functions


*/

Complex.print = function (c) 
{
	console.log("("+c[0]+" "+(c[1]<0 ? "":"+")+c[1]+"i)");
};

Complex.printAll = function (a) {
	a.forEach(Complex.print);
};


Complex.Constants = {	
	// creating new instances is costly,
	// these constants help doing redundant work



	ONE_RE: new Complex(1, 0, true), 
	MINUS_ONE_RE: new Complex(-1, 0, true),
	TWO_RE: new Complex(2, 0, true),
	ONE_OVER_TWO_PI_RE: (new Complex(1, 0)).divide(new Complex(Complex.TWO_PI, 0)).freeze(), // for cauchy
	ONE_I: new Complex(0,1, true), // for exp, caley xform
	MINUS_ONE_I: new Complex(0,-1,true), // for exp, caley xform
	TWO_I: new Complex(0,2,true),
	TWO_PI_I: new Complex(0, Complex.TWO_PI, true), // ..
	ONE_OVER_TWO_PI_I: (new Complex(1, 0)).divide(new Complex(0, Complex.TWO_PI)).freeze() // for cauchy
};


/****
	Making it require ready
***/
if (typeof exports !== "undefined") exports.Complex = Complex;




if (typeof window != "undefined") {

Complex.Canvas = function Canvas (context) {
	"use strict;"
	this.context = context;
};

Complex.Canvas.prototype.centerContext = function () {
	var context = this.context;
	if (context.resetTransform) context.resetTransform();
	context.translate(context.canvas.width/2, context.canvas.height/2);
};

Complex.Canvas.prototype.drawDisc = function (radius, centerx, centery) {
	var context = this.context;
	radius = radius || 1;
	var t = 0;
	var lastx = Math.cos(t) * radius;
	var lasty = Math.sin(t) * radius;
	var x, y;
	this.centerx = centerx = centerx || 0;
	this.centery = centery = centery || 0;
	context.save();
	for (t = 0; t <= Complex.TWO_PI; t+=0.01) {
		x = centerx + Math.cos(t) * radius; 
		y = centery + Math.sin(t) * radius;
		context.moveTo(lastx,lasty);
		context.lineTo(x,y);		 
		lastx = x;
		lasty = y;
	}
	context.stroke();
	contextrestore();
}
Complex.Canvas.prototype.drawPoints = function (points, color) {
	var context = this.context;
	// draw it on a canvas2drenderingcontext
	if (!points.length) throw new TypeError("got no points");
	var lastpoint = points[0];
	context.strokeStyle = color||"black";
	context.lineWidth = "2.0";
	context.save();
	context.beginPath();
	context.moveTo(lastpoint[0],lastpoint[1]);
	var point;
	for (var i = 0; i < points.length; i++) {
		point = points[i];
		context.moveTo(lastpoint[0], -(lastpoint[1]));
		context.lineTo(point[0], -(point[1]));
		lastpoint = point;		
	}
	context.stroke();
	context.closePath();
	contextrestore();
};
Complex.Canvas.WebGL = "deferred by defect notebook (no 3d left)";

Complex.Canvas.prototype.drawAxis = function (centerx, centery) {

    var context = this.context;

    centerx = centerx || this.centerx || 0;
    centery = centery || this.centery || 0;
    var xhead = centerx+context.canvas.width/4;
    var yhead = centery+context.canvas.heigth/4;
    
    context.save();
    context.beginPath();
    context.moveTo(centerx,centery);
    context.lineTo(xhead, centery);

    context.stroke();
    context.fillText("Re", xhead, centery);
    context.fill();
    contextrestore();

    context.save();
    context.moveTo(centerx, centery);
    context.lineTo(centerx, -yhead);
    context.stroke();
    context.fillText("Im", centerx, -yhead);
    context.fill();
    contextrestore();
};

}