1 /*!
  2 *
  3 *       JSMatrix : JavaScript matrix and vector implementation
  4 *                      version 0.6 (2012-04-20)
  5 *
  6 *             Copyright (C)  2011 - 2012  Jan Stransky
  7 *
  8 *      Czech Technical University, Faculty of Civil Engineering,
  9 *  Department of Structural Mechanics, 166 29 Prague, Czech Republic
 10 *
 11 *
 12 *  JSMatrix is free software: you can redistribute it and/or modify
 13 *  it under the terms of the GNU General Public License as published by
 14 *  the Free Software Foundation, either version 3 of the License, or
 15 *  (at your option) any later version.
 16 *
 17 *  JSMatrix is distributed in the hope that it will be useful,
 18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20 *  GNU General Public License for more details.
 21 *
 22 *  You should have received a copy of the GNU General Public License
 23 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 24 */
 25 
 26 /**
 27 * @fileOverview JavaScript vector and matrix implementation.
 28 * This file contains JavaScript implementation of vectors and matrices, i.e 1d and 2d arrays of real (floating point) numbers and corresponding mathematical operations. The objects creation is inspired by Numerical Python (numpy) package ( v = vec([1,2,3]), m = mat([[1,2,3],[4,5,6],[7,8,9]]) ). The implementation is such that coefficient access can be done directly by a=v[1], v[1]=3., a=m[1][0], m[1][0] = 4. (it is simple and easy, but no dimension is checked), or (in safer but longer way) by get/set method, where dimensions are checked ( a=v.get(1), v.set(1,3.), a=m.get(1,0), m.set(1,0,4.) ). Access function numbering is 0-based(!) (first element has index 0).
 29 * <br /><br />
 30 * When a method returns a new object (e.g. ret = m1.add(m2); ), if operation is successfull (e.g. dimensions agree), the object is returned, if operation fails (e.g. dimensions are mismatched), null value is returned (inspired by <a href="http://sylvester.jcoglan.com/">Sylvester project</a>).
 31 * <br /><br />
 32 * In vector-matrix context, vectors are considered in their natural representation (row x column vectors). For example in matrix*vector multiplication the vector is considered as 1d column matrix, while in vector*matrix the vector is considered as 1d row matrix (similar approach is used in Mathematica program). In documantetion, vectors are considered as 1d column matrix (e.g. vec^T indiceates transposition of vec, i.e. 1d row matrix).
 33 * <br /><br />
 34 * Method naming is usualy following (example is on matrix transposition): verb infinitive (e.g. transpose) is used for function changing receiver - receiver is changed (to its transposition for example) and nothing is returned. Verb past simple (e.g. transposed) is used for function returning new object (transposed copy of receiver for example), receiver is not changed. Names beSomethingOf (e.g. beTranspositionOf) indicates that receiver is modified to become something (transposition of given matrix for example), receiver is changed and given parameter is not. Names isSomething or canSomething (e.g. isTranspositionOf) returns usually bools (true if receiver is transposition of given matrix for example).
 35 * <br /><br />
 36 * Current implementation contains: basic operations (coefficient access, +, -, *, /, +=, -=, *=, vector norms), testing operations, subvector/submatrix operations, solving linear system of equations, eigenvalues and eigenvector solving, matrix decmpositions (LU, LDU, Cholesky, QR, SVD, Schur, spectral, polar) and meny others, see 
 37 * <br /><br />
 38 * For more information see <a href="http://mech.fsv.cvut.cz/~stransky/software/jsmatrix/">project homepage</a> or further documentation.
 39 * <br /><br />
 40 * JSMatrix is a free software distributed under <a href='http://www.gnu.org/licenses/gpl.html'>GNU GPL license</a>.
 41 * <br /><br />
 42 * Example:<br />
 43 * v = Vector(); // creates empty vector object<br />
 44 * v = Vector(4); // creates (zeroed) vector with 4 elements<br />
 45 * v = Vector.create([2,4,3]); // creates vector corresponding to given array (length 3, elements=2,4,3)<br />
 46 * a = v[1]; // a = 4.<br />
 47 * a[1] = 5.; // sets 5. to a[1]<br />
 48 * a[9] = 3.; // sets 3. to a[9] (out of bounds, no error!!)<br />
 49 * a.set(9,3.); // sets 3. to a[9], checks bounds, finds that index 9 is out of bounds and does nothing<br />
 50 * <br />
 51 * References:<br />
 52 * [1] Quarteroni, A., Sacco, R. and Saleri, F. 2010. Numerical Mathematics, 2nd edition. Springer-Verlag New York<br />
 53 
 54 * [2] http://en.wikipedia.org/wiki/Matrix_decomposition<br />
 55 * [3] Press, W. H., Teukolsky, S. A., Vetterling, W. T. and Flannery, B. P. 2007. The Numerical Recipes: The Art of Scientific Computing, Third Edition<br />
 56 * [4] inspiration from <a href="http://www.oofem.org>OOFEM project</a><br />
 57 * [5] inspiration from <a href="http://sylvester.jcoglan.com/">Sylvester project</a><br />
 58 * @author <a href="http://mech.fsv.cvut.cz/~stransky/">Jan Stránský</a>
 59 * @version 0.6 (2012-04-20)
 60 */
 61 
 62 
 63 // constants for easier manipulation
 64 /**constant ( = 0 )*/ var JSM_X = 0;
 65 /**constant ( = 1 )*/ var JSM_Y = 1;
 66 /**constant ( = 2 )*/ var JSM_Z = 2;
 67 /**constant ( = 1e-8)*/ var JSM_TOL = 1e-8;
 68 /**constant ( = 1e-32)*/ var JSM_TOL2 = 1e-32;
 69 /**constant ( = 10000.)*/ var JSM_ROUNDFACTOR = 10000.;
 70 
 71 
 72 // console messages
 73 /**#@+ * @ignore*/
 74 /*
 75 JSMLogger = function() {
 76 	this.warn = function(msg) { if (window.console) { if (window.console.warn) { window.console.warn(msg); } } }
 77 	this.debug = function(msg) { if (window.console) { if (window.console.debug) { window.console.debug(msg); } } }
 78 	this.log = function(msg) { if (window.console) { if (window.console.log) { window.console.debug(msg); } } }
 79 }
 80 var jsmLogger = new JSMLogger();
 81 var JSM_DEBUG = false;
 82 */
 83 /**#@-*/
 84 	
 85 
 86 
 87 
 88 
 89 
 90 /** Vector implementation
 91 * @class Represents a vector (1D matrix) of real (floating point) numbers
 92 * @param {int} [nElements=0] number of elements of newly created Vector object
 93 * @property {int} [nElements=0] Number of vector elements
 94 */
 95 Vector = function(nElements) {
 96 	this.nElements = nElements || 0;
 97 	for (var e=0; e<this.nElements; e++) { this[e] = 0.; }
 98 }
 99 
100 /** Empties receiver (resizes it to size 0)
101 * @example
102 * v = vec([1,2,3,4]);
103 * v.empty(); // v = Vector([])
104 */
105 Vector.prototype.empty = function() {
106 	this.resize(0);
107 }
108 
109 /** Tests if receiver is empty (has size 0)
110 * @returns true if receiver is empty, false otherwise
111 * @example
112 * v = new Vector(3);
113 * b1 = v.isEmpty(); // b1 = false
114 * v.empty();
115 * b2 = v.isEmpty(); // b2 = true
116 */
117 Vector.prototype.isEmpty = function() {
118 	return this.nElements==0;
119 }
120 
121 /** Zeroes all elements of receiver
122 * @example
123 * v = vec([1,2,3,4]);
124 * v.zero(); // v = Vector([0,0,0,0])
125 */
126 Vector.prototype.zero = function() {
127 	for (var e=0; e<this.nElements; e++) { this[e] = 0.; }
128 }
129 
130 /** Sets all elements of receiver to 1.0
131 * @example
132 * v = vec([1,2,3,4]);
133 * v.beFullOfOnes(); // v = Vector([1,1,1,1])
134 */
135 Vector.prototype.beFullOfOnes = function() {
136 	for (var e=0; e<this.nElements; e++) { this[e] = 1.; }
137 }
138 
139 /** Alias for beFullOfOnes(), see {@link Vector#beFullOfOnes}
140 * @function
141 */
142 Vector.prototype.one = Vector.prototype.beFullOfOnes;
143 
144 /** Returns size (numer of elements) of receiver
145 * @returns {int} length (number of elements) of receiver
146 * @example
147 * v = vec([1,5,8,2]);
148 * s = v.size(); // s = 4
149 */
150 Vector.prototype.size = function() {
151 	return this.nElements;
152 }
153 
154 /** Returns sum of all elements of receiver
155 * @returns {float} sum of all elements of receiver
156 * @example
157 * v = vec([1,2,3]);
158 * s = v.sum(); // s = 6
159 */
160 Vector.prototype.sum = function() {
161 	var ret = 0.;
162 	for (var e=0; e<this.nElements; e++) { ret += this[e]; }
163 	return ret;
164 }
165 
166 /** Returns maximal value of receiver elements
167 * @returns {float} maximal value of receiver elements
168 * @example
169 * v = vec([1,-4,3,2]);
170 * m = v.max(); // m = 3
171 */
172 Vector.prototype.max = function() {
173 	ret = -1e64;
174 	for (var e=0; e<this.nElements; e++) {
175 		if (this[e] > ret) { ret = this[e]; }
176 	}
177 	return ret;
178 }
179 
180 /** Returns minimal value of receiver elements
181 * @returns {float} minimal value of receiver elements
182 * @example
183 * v = vec([3,3,1,2]);
184 * m = v.min(); // m = 1
185 */
186 Vector.prototype.min = function() {
187 	ret = 1e64;
188 	for (var e=0; e<this.nElements; e++) {
189 		if (this[e] < ret) { ret = this[e]; }
190 	}
191 	return ret;
192 }
193 
194 /** Returns index of first occurrence of given value
195 * @param {float} val value whose index will be returned
196 * @returns {int} index of first occurrence of val
197 * @example
198 * v = vec([5,6,1,2,6,8,6,2]);
199 * i1 = v.indexOf(2); // i1 = 3
200 * i2 = v.indexOf(6); // i2 = 1
201 * i3 = v.indexOf(8); // i3 = 5
202 */
203 Vector.prototype.indexOf = function(val) {
204 	for (var e=0; e<this.nElements; e++) {
205 		if (Math.abs(this[e]-val) < JSM_TOL) { return e; }
206 	}
207 	return null;
208 }
209 
210 /** Testing vectors equality
211 * @param {Vector} vec vector to be compared with receiver
212 * @returns {bool} true if this==vec, false otherwise
213 * @example
214 * v1 = vec([1,2,3]);
215 * v2 = vec([1,2,2.999999999]);
216 * v3 = vec([1,2,1]);
217 * t1 = v1.isEqualTo(v2); // t1 = true
218 * t2 = v1.isEqualTo(v3); // t2 = false
219 */
220 Vector.prototype.isEqualTo = function(vec) {
221 	if (!this.isSameSizeAs(vec)) { return false; }
222 	for (var e=0; e<this.nElements; e++) {
223 		if (Math.abs(this[e]-vec[e]) > JSM_TOL) { return false; }
224 	}
225 	return true;
226 }
227 
228 /** Coefficient access function, returns one element of receiver ( ret = this[r] ). Vector.get(e) is almost equivalent to direct Vector[e] access method
229 * @param {int} e index of element to be returned
230 * @returns {float} value of the e-th element
231 * @example
232 * v = vec([4,7,2,4]);
233 * a = v.get(1); // a = 7
234 * a = v[1]; // a = 7
235 * a = v.get(9); // a = null
236 * a = v[9]; // a = undefined
237 */
238 Vector.prototype.get = function(e) {
239 	if (e<0 || e>=this.nElements) { /*jsmLogger.warn('Vector.get: out fo bounds');*/ return null; }
240 	return this[e];
241 }
242 
243 /** Coefficient access function, sets one element of receiver ( this[r] = val ). Vector.set(e) is almost equivalent to direct Vector[e] access method
244 * @param {int} e index of element to be set
245 * @param {float} val value to be set
246 * @example
247 * v = vec([4,7,2,4]);
248 * v.set(1,68.); // v = Vector([4,68,2,4])
249 * v[1] = 43.; // v = Vector([4,43,2,4])
250 * v.set(9,68.); // nothing is done - out of bounds
251 * // v = Vector([4,43,2,4])
252 * v[9] = 43.;
253 * /// new object this[9] is created, but no reflection to actual Vector is made
254 * // v = Vector([4,43,2,4])
255 */
256 Vector.prototype.set = function(e,val) {
257 	if (e<0 || e>=this.nElements) { /*jsmLogger.warn('Vector.set: out of bounds');*/ return; }
258 	this[e] = val;
259 }
260 
261 /** Coefficient access function, increment one element of receiver ( this[r] += val ). Vector.incr(e,val) is much safer than direct Vector[e] += val (see example)
262 * @param {int} e index of element to be incremented
263 * @param {float} val value to be added
264 * @example
265 * v = vec([4,7,2,4]);
266 * v.incr(1,4.); // v = Vector([4,11,2,4])
267 * v[1] += 4.; // v = Vector([4,15,2,4])
268 * v.incr(9,4.); // nothing is done, out of bounds
269 * // v = Vector([4,15,2,4])
270 * /// v[9] += 4. would result into error (v[9] is not defined)
271 */
272 Vector.prototype.incr = function(e,val) {
273 	if (e<0 || e>=this.nElements) { /*jsmLogger.warn('Vector.incr: out of bounds');*/ return; }
274 	if (val) { this[e] += val; }
275 }
276 
277 /** Testing vectors size equality
278 * @param {Vector} vec vector to be tested
279 * @returns {bool} true if vec and receiver has same size, false otherwise
280 * @example
281 * a = vec([1,2,3,4]);
282 * b = vec([5,6,7,8,9,10,11,12]);
283 * c = vec([13,14,15,16]);
284 * t1 = a.isSameSizeAs(b); // t1 = false
285 * t2 = a.isSameSizeAs(c); // t2 = true
286 */
287 Vector.prototype.isSameSizeAs = function(vec) {
288 	return this.nElements==vec.nElements;
289 }
290 
291 /** Testing if receiver can multiply given matrix from left ( this^T * mat )
292 * @param {Matrix} mat matrix to be tested
293 * @returns {bool} true if the multiplication is possible, false otherwise
294 * @example
295 * v = vec([1,2,3]);
296 * m1 = mat([[11,12,13],[21,22,23]]);
297 * m2 = mat([[11,12],[21,22],[31,32]]);
298 * t1 = v.canMultiplyMat(m1); // t1 = true
299 * t2 = v.canMultiplyMat(m2); // t2 = false
300 */
301 Vector.prototype.canMultiplyMat = function(mat) {
302 return this.nElements ==  mat.nCols;
303 }
304 
305 /** Alias for canMultiplyMat(), see {@link Vector#canMultiplyMat}
306 * @function
307 */
308 canMultiplyMatFromLeft = Vector.prototype.canMultiplyMat;
309 
310 /** Sets elements of receiver form given Array object
311 * @param {[floats]} arry Array object containing new receiver elements
312 * @example
313 * v.fromArray([3,6,5,2]); // v = Vector([3,6,5,2])
314 */
315 Vector.prototype.fromArray = function(arry) {
316 	var n = arry.length;
317 	var e;
318 	for (e=0; e<n; e++) { this[e] = arry[e]; }
319 	for (e=n; e<this.nElements; e++) { delete this[e]; }
320 	this.nElements = n;
321 }
322 
323 /** Returns elements of receiver as an Array object
324 * @returns {[floats]} Array object containing receiver's elements
325 * @example
326 * v =vec([3,4,5,6]);
327 * s = v.toArray(); // s = [3,4,5,6]
328 */
329 Vector.prototype.toArray = function() {
330 	var ret = [];
331 	for (var i=0; i<this.nElements; i++) { ret[i] = this[i]; }
332 	return ret;
333 }
334 
335 /** Returns sum of receiver and vector ( ret = this + vec )
336 * @param {Vector} vec 2nd vector of the sum
337 * @returns {Vector} sum of receiver and vec
338 * @example
339 * v1 = vec([1,2,3]);
340 * v2 = vec([6,1,5]);
341 * v4 = v1.add(v2); // v4 = Vector([7,3,8])
342 */
343 Vector.prototype.add = function(vec) {
344 	if (!this.isSameSizeAs(vec)) { /*jsmLogger.warn('Vector.add: dimensions mismatched');*/ return null; }
345 	var ret = new Vector();
346 	for (var e=0; e<this.nElements; e++) { ret[e] = this[e] + vec[e]; }
347 	ret.nElements = this.nElements;
348 	return ret;
349 }
350 
351 /** Add given vector to receiver ( this += vec )
352 * @param {Vector} vec vector to be added
353 * @example
354 * v1 = vec([1,2,3]);
355 * v2 = vec([6,1,5]);
356 * v1.iadd(v2); // v1 = Vector([7,3,8])
357 */
358 Vector.prototype.iadd = function(vec) {
359 	if (!this.isSameSizeAs(vec)) { /*jsmLogger.warn('Vector.iadd: dimensions mismatched');*/ return; }
360 	for (var e=0; e<this.nElements; e++) { this[e] += vec[e]; }
361 }
362 
363 /** Modifies receiver to become sum of two vectors ( this = vec1 + vec2 ). Receiver's size is adjusted
364 * @param {Vector} vec1 1st vector of the sum
365 * @param {Vector} vec2 2nd vector of the sum
366 * @example
367 * v = vec([3,4]);
368 * v1 = vec([1,2,3]);
369 * v2 = vec([6,1,5]);
370 * v.beSumOf(v1,v2); // v = Vector([7,3,8])
371 */
372 Vector.prototype.beSumOf = function(vec1,vec2) {
373 	if (!vec1.isSameSizeAs(vec2)) { /*jsmLogger.warn('Vector.beSumOf: dimensions mismatched');*/ return; }
374 	var e, n = vec1.nElements;
375 	for (e=0; e<n; e++) { this[e] = vec1[e] + vec2[e]; }
376 	for (e=n; e<this.nElements; e++) { delete this[e]; }
377 	this.nElements = n;
378 }
379 
380 /** Returns difference of receiver and vector ( ret = this - vec )
381 * @param {Vector} vec 2nd vector of subtraction
382 * @returns {Vector} difference of receiver and vec
383 * @example
384 * v1 = vec([1,2,3]);
385 * v2 = vec([6,1,5]);
386 * v4 = v1.sub(v2); // v4 = Vector([-5,1,-2])
387 */
388 Vector.prototype.sub = function(vec) {
389 	if (!this.isSameSizeAs(vec)) { /*jsmLogger.warn('Vector.sub: dimensions mismatched');*/ return null; }
390 	var ret = new Vector();
391 	for (var e=0; e<this.nElements; e++) { ret[e] = this[e] - vec[e]; }
392 	ret.nElements = this.nElements;
393 	return ret;
394 }
395 
396 /** Subtract given vector to receiver ( this -= vec )
397 * @param {Vector} vec vector to be subtracted
398 * @example
399 * v1 = vec([1,2,3]);
400 * v1.isub(v2); // v1 = Vector([-5,1,-2])
401 */
402 Vector.prototype.isub = function(vec) {
403 	if (!this.isSameSizeAs(vec)) { /*jsmLogger.warn('Vector.isub: dimensions mismatched');*/ return; }
404 	for (var e=0; e<this.nElements; e++) { this[e] -= vec[e]; }
405 }
406 
407 /** Modifies receiver to become difference of two vectors ( this = vec1 - vec2 ). Receiver's size is adjusted
408 * @param {Vector} vec1 1st vector of the difference
409 * @param {Vector} vec2 2nd vector of the difference
410 * @example
411 * v = vec([4,5]);
412 * v1 = vec([1,2,3]);
413 * v2 = vec([6,1,5]);
414 * v.beDifferenceOf(v1,v2); // v = Vector([-5,1,-2])
415 */
416 Vector.prototype.beDifferenceOf = function(vec1,vec2) {
417 	if (!vec1.isSameSizeAs(vec2)) { /*jsmLogger.warn('Vector.beDifferenceOf: dimensions mismatched');*/ return; }
418 	var e, n = vec1.nElements;
419 	for (e=0; e<n; e++) { this[e] = vec1[e] - vec2[e]; }
420 	for (e=n; e<this.nElements; e++) { delete this[e]; }
421 	this.nElements = n;
422 }
423 
424 /** Returns dot (inner) product of receiver and given vector
425 * @param {Vector} vec vector for dot product
426 * @param {int} [n=0] dot product will be made from first n elements. If not specified, zero or negative, all elements are used
427 * @returns {float} dot product of receiver and vec from first n elements
428 * @example
429 * v1 = vec([1,2,3]);
430 * v2 = vec([6,1,5]);
431 * d2 = v1.dot(v2,2); // d2 = 8
432 */
433 Vector.prototype.dot = function(vec,n) {
434 	var n = n || -1;
435 	if (n<=0 || n>this.nElements) { n = this.nElements; }
436 	if (n > vec.nElements) { /*jsmLogger.warn('Vector.dot: wrong number of elements');*/ return null; }
437 	var ret = 0.;
438 	for (var e=0; e<n; e++) { ret += this[e]*vec[e]; }
439 	return ret;
440 }
441 
442 /** Returns squared (Euclidean) norm of receiver (ret = this.^T * this )
443 * @returns {float} squared Euclidean norm of receiver
444 * @example
445 * v = vec([4,2,4]);
446 * n = v.squaredNorm(); // n = 36
447 */
448 Vector.prototype.squaredNorm = function() {
449 	return this.dot(this);
450 }
451 
452 /** Returns (Euclidean) norm of receiver (ret = sqrt(this^T * this) )
453 * @returns {float} Euclidean norm of receiver
454 * @example
455 * v = vec([4,2,4]);
456 * n = v.norm(); // n = 6
457 */
458 Vector.prototype.norm = function() {
459 	return Math.sqrt(this.dot(this));
460 }
461 
462 /** Normlize receiver ( this.norm()=1. )
463 * @example
464 * v = vec([4,2,4]);
465 * v.normalize(); // v = Vector([0.6666,0.3333,0.6666])
466 */
467 Vector.prototype.normalize = function() {
468 	var n = this.norm();
469 	if (n==0.) { /*jsmLogger.warn('Vector.normalize: norm == 0.');*/ return; }
470 	this.imulf(1/n);
471 }
472 
473 /** Returns normalized copy of receiver ( ret.norm()=1. )
474 * @returns {Vector} normalized copy of receiver
475 * @example
476 * v1 = vec([4,2,4]);
477 * v2 = v1.normalized(); // v2 = Vector([0.6666,0.3333,0.6666])
478 */
479 Vector.prototype.normalized = function() {
480 	var n = this.norm();
481 	if (n==0.) { /*jsmLogger.warn('Vector.normalized: norm == 0.');*/ return null; }
482 	var e, ret = new Vector(), nn=1/n;
483 	for (e=0; e<this.nElements; e++) { ret[e] = this[e]*nn; }
484 	ret.nElements = this.nElements;
485 	return ret;
486 }
487 
488 /** Returns squared energy norm of receiver (ret = this^T*mat*this)
489 * @param {Matrix} mat marix of norm
490 * @returns {float} squared energy norm of receiver
491 * @example
492 * v = vec([1,2,3]);
493 * m = mat([[8,0,0],[0,2,1],[0,1,3]]);
494 * n = v.squaredEnergyNorm(m); // n = 55
495 */
496 Vector.prototype.squaredEnergyNorm = function(mat) {
497 	var mat = mat;
498 	return this.mulm(mat).dot(this);
499 }
500 
501 /** Returns energy norm of receiver (ret = sqrt(this*mat*this))
502 * @param {Matrix} mat marix of norm
503 * @returns {float} energy norm of receiver
504 * @example
505 * v = vec([1,2,3]);
506 * m = mat([[8,0,0],[0,2,1],[0,1,3]]);
507 * n = v.energyNorm(m); // n = 7.4162
508 */
509 Vector.prototype.energyNorm = function(mat) {
510 	var mat = mat;
511 	return Math.sqrt(this.squaredEnergyNorm(mat));
512 }
513 
514 /** Returns dyadic (tensor, outer, direct,..) product of receiver and given vector
515 * @param {Vector} vec vector for multiplication
516 * @returns {Matrix} dyadic product of receiver and vec
517 * @example
518 * v1 = vec([1,2,3]);
519 * v2 = vec([4,5,6]);
520 * m = v1.dyadic(v2); // m = Matrix([[4,5,6],[8,10,12],[12,15,18]])
521 */
522 Vector.prototype.dyadic = function(vec) {
523 	var vec = vec;
524 	var ret = new Matrix();
525 	for (var r=0; r<this.nElements; r++) {
526 		ret[r] = {};
527 		for (var c=0; c<vec.nElements; c++) { ret[r][c] = this[r] * vec[c]; }
528 	}
529 	ret.nRows = this.nElements;
530 	ret.nCols = vec.nElements;
531 	return ret;
532 }
533 
534 /** Alias for dyadic() (inspired by LaTeX symbol for dyadic product operation), see {@link Vector#dyadic}
535 * @function
536 */
537 Vector.prototype.otimes = Vector.prototype.dyadic;
538 
539 /** Alias for dyadic(), see {@link Vector#dyadic}
540 * @function
541 */
542 Vector.prototype.outer = Vector.prototype.dyadic;
543 
544 /** Alias for dyadic(), see {@link Vector#dyadic}
545 * @function
546 */
547 Vector.prototype.tensor = Vector.prototype.dyadic;
548 
549 /** Returns vector (cross) product of receiver and given vector. Both receiver and given vector have to be of length 3.
550 * @param {Vector} vec 2nd vector of multiplication
551 * @returns {Vector} cross product of receiver and vec
552 * @example
553 * v1 = vec([1,2,3]);
554 * v2 = vec([4,5,6]);
555 * v3 = v1.cross(v2); // v3 = Vector([-3,6,-3])
556 */
557 Vector.prototype.cross = function(vec) {
558 	if (this.nElements!=3 || vec.nElements!=3) { /*jsmLogger.warn('Vector.cross: wrong dimensions');*/ return null; }
559 	return Vector.create([
560 		this[1]*vec[2]-this[2]*vec[1],
561 		this[2]*vec[0]-this[0]*vec[2],
562 		this[0]*vec[1]-this[1]*vec[0]]);
563 }
564 
565 /** Modifies receiver to become cross product of two vectors. Both given vectors have to be of length 3. Receiver's size is adjusted
566 * @param {Vector} vec1 1st vector for multiplication
567 * @param {Vector} vec1 2nd vector for multiplication
568 * @example
569 * v = vec([5,6]);
570 * v1 = vec([1,2,3]);
571 * v2 = vec([4,5,6]);
572 * v.beCrossProductOf(v1,v2); // v = Vector([-3,6,-3])
573 */
574 Vector.prototype.beCrossProductOf = function(vec1,vec2) {
575 	if (vec1.nElements!=3 || vec2.nElements!=3) { /*jsmLogger.warn('Vector.beCrossProductOf: wrong dimensions');*/ return; }
576 	this[0] = vec1[1]*vec2[2]-vec1[2]*vec2[1];
577 	this[1] = vec1[2]*vec2[0]-vec1[0]*vec2[2];
578 	this[2] = vec1[0]*vec2[1]-vec1[1]*vec2[0];
579 	for (var e=3; e<this.nElements; e++) { delete this[e]; }
580 	this.nElements = 3;
581 }
582 
583 /** Returns negative of receiver ( ret = -this )
584 * @returns {Vector} negative of receiver
585 * @example
586 * v1 = vec([1,2,3]);
587 * v2 = v1.negated(); // v2 = Vector([-1,-2,-3])
588 */
589 Vector.prototype.negated = function() {
590 	return this.mulf(-1.);
591 }
592 
593 /** Alias for negated(), see {@link Vector#negated}
594 * @function
595 */
596 Vector.prototype.neg = Vector.prototype.negated;
597 
598 /** Negate receiver ( ret *= -1., ret = -ret )
599 * @example
600 * v1 = vec([1,2,3]);
601 * v1.negate(); // v1 = Vector([-1,-2,-3])
602 */
603 Vector.prototype.negate = function() {
604 	for (var e=0; e<this.nElements; e++) { this[e] *= -1.; }
605 }
606 
607 /** Alias for neagete(), see {@link Vector#negate}
608 * @function
609 */
610 Vector.prototype.ineg = Vector.prototype.negate;
611 
612 /** Modifies receiver to become negative of given vector (this = -vec). Receiver's size is adjusted
613 * @param {Vector} vec given vector
614 * @example
615 * v1 = vec([4,5])
616 * v2 = vec([1,2,3]);
617 * v1.beNegativeOf(v2); // v1 = Vector([-1,-2,-3])
618 */
619 Vector.prototype.beNegativeOf = function(vec) {
620 	var e, n = vec.nElements;
621 	for (e=0; e<n; e++) { this[e] = -vec[e]; }
622 	for (e=n; e<this.nElements; e++) { delete this[e]; }
623 	this.nElements = n;
624 }
625 
626 /** Returns receiver multiplied by float f ( ret = this * f )
627 * @param {float} f float multiplier
628 * @returns {Vector} copy of receiver multiplied by f
629 * @example
630 * v1 = vec([1,2,3]);
631 * v2 = v1.mulf(3); // v2 = Vector([3,6,9])
632 */
633 Vector.prototype.mulf = function(f) {
634 	var ret = new Vector();
635 	for (var e=0; e<this.nElements; e++) { ret[e] = f*this[e]; }
636 	ret.nElements = this.nElements;
637 	return ret;
638 }
639 
640 /** Multiply receiver by float f ( this *= f )
641 * @param {float} f float multiplier
642 * @example
643 * v = vec([1,2,3]);
644 * v.imulf(3); // v = Vector([3,6,9])
645 */
646 Vector.prototype.imulf = function(f) {
647 	for (var e=0; e<this.nElements; e++) { this[e] *= f; }
648 }
649 
650 /** Returns product of receiver and given matrix ( ret = this^T * mat )
651 * @param {Matrix} mat matrix to multiply
652 * @returns {Vector} copy of receiver multiplied by mat
653 * @example
654 * v1 = vec([1,2,3]);
655 * m = mat([[11,12,13],[21,22,23],[31,32,33]])
656 * v2 = v1.mulm(m); // v2 = Vector([146,152,158])
657 */
658 Vector.prototype.mulm = function(mat) {
659 	if (!this.canMultiplyMat(mat)) { /*jsmLogger.warn('Vector.mulm: dimensions mismatched');*/ return null; }
660 	var ret = new Vector(), temp, nc = mat.nCols, nr = this.nElements;
661 	for (var c=0; c<nc; c++) {
662 		temp = 0.;
663 		for (var r=0; r<nr; r++) {
664 			temp += this[r]*mat[r][c];
665 		}
666 		ret[c] = temp;
667 	}
668 	ret.nElements = nc;
669 	return ret;
670 }
671 
672 /** Returns product of receiver and given multiplier (float or Matrix)
673 * @param {Matrix|float} what matrix or float to multiply
674 * @returns {Vector} copy of receiver multiplied by what
675 * @example
676 * v1 = vec([1,2,3]);
677 * v2 = v1.mul(mat([[11,12,13],[21,22,23],[31,32,33]])); // v2 = Vector([146,152,158])
678 * v3 = v1.mul(3); // v3 = Vector([3,6,9])
679 */
680 Vector.prototype.mul = function(what) {
681 	if (what instanceof Matrix) { return this.mulm(what); }
682 	if ((typeof what).toLowerCase() == 'number') { return this.mulf(what); }
683 	/*jsmLogger.warn('Vector.mul: wrong argument');*/
684 	return null;
685 }
686 
687 /** Alias for mul(), see {@link Vector#mul}
688 * @function
689 */
690 Vector.prototype.x = Vector.prototype.mul;
691 
692 /** Modifies receiver to become product of given matrix and vector ( this =  mat * vec ). Receiver's size is adjusted
693 * @param {Matrix} mat matrix of multiplication
694 * @param {Vector} vec vector of multiplication
695 * @example
696 * v = vec([4,5]);
697 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
698 * v1 = vec([1,2,3]);
699 * v.beProductOf(m,v1); // v = Vector([74,134,194])
700 */
701 Vector.prototype.beProductOf = function(mat,vec) {
702 	if (!mat.canMultiplyVec(vec)) { /*jsmLogger.warn('Vector.beProductOf: dimensions mismatched');*/ return; }
703 	var nr = mat.nRows;
704 	var nc = mat.nCols;
705 	var temp, r, c;
706 	for (r=0; r<nr; r++) {
707 		temp = 0.;
708 		for (c=0; c<nc; c++) {
709 			temp += mat[r][c]*vec[c];
710 		}
711 		this[r] = temp;
712 	}
713 	for (r=nr; r<this.nElements; r++) { delete this[r]; }
714 	this.nElements = nr;
715 }
716 
717 /** Modifies receiver to become product of given vector and matrix ( this =  vec^T * mat )
718 * @param {Vector} vec vector of multiplication
719 * @param {Matrix} mat matrix of multiplication
720 * @example
721 * v= vec([5,6]);
722 * v1 = vec([1,2,3]);
723 * m = mat([[11,12,13],[21,22,23],[31,32,33]])
724 * v.beTProductOf(v1,m); // v = Vector([146,152,158])
725 */
726 Vector.prototype.beTProductOf = function(vec,mat) {
727 if (!vec.canMultiplyMat(mat)) { /*jsmLogger.warn('Vector.beTProductOf: dimensions mismatched');*/ return; }
728 var nr = mat.nRows;
729 var nc = mat.nCols;
730 var temp, r, c;
731 for (c=0; c<nc; c++) {
732 	temp = 0.;
733 	for (r=0; r<nr; r++) {
734 		temp += vec[r]*mat[r][c];
735 	}
736 	this[c] = temp;
737 }
738 for (c=nc; c<this.nElements; c++) { delete this[c]; }
739 this.nElements = nc;
740 }
741 
742 /** Returns subvector of receiver. ret = this[coeffs]
743 * @param {[floats]|Vector} coeffs array containing coefficients of desired subvector
744 * @returns {Vector} desired subvector
745 * @example
746 * v1 = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]);
747 * v2 = v1.getSubVector([2,3,6,8,9]); // v2 = Vector([9,1,2,6,7])
748 */
749 Vector.prototype.getSubVector = function(coeffs) {
750 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
751 	if (n>this.nElements) { /*jsmLogger.warn('Vector.getSubVector: wrong argument dimensions');*/ return null; }
752 	var e, ce;
753 	var ret = new Vector();
754 	for (e=0; e<n; e++) {
755 		ce = coeffs[e];
756 		if (ce<0 || ce>=this.nElements) { /*jsmLogger.warn('Vector.getSubVector: wrong argument values');*/ return null; }
757 		ret[e] = this[coeffs[e]];
758 	}
759 	ret.nElements = n;
760 	return ret;
761 }
762 
763 /** Alias for getSubVector, see {@link Vector#getSubVector}
764 * @function
765 */
766 Vector.prototype.getsv = Vector.prototype.getSubVector;
767 
768 /** Modifies receiver to become subvector of given vector (this = vec[coeffs]). Receiver's size is adjusted
769 * @param {Vector} vec vector to get subvector from
770 * @param {[floats]|Vector} coeffs array containing coefficients of desired subvector
771 * @example
772 * v1 = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]);
773 * v2 = vec([3,4]);
774 * v2.beSubVectorOf(v1,[2,3,6,8,9]); // v2 = Vector([9,1,2,6,7])
775 */
776 Vector.prototype.beSubVectorOf = function(vec,coeffs) {
777 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
778 	if (n>vec.nElements) { /*jsmLogger.warn('Vector.beSubVectorOf: wrong argument dimensions');*/ return; }
779 	var e;
780 	for (e=0; e<n; e++) { if (coeffs[e]<0 || coeffs[e]>=vec.nElements) { /*jsmLogger.warn('Vector.beSubVectorOf: wrong argument values');*/ return; } }
781 	for (e=0; e<n; e++) { this[e] = vec[coeffs[e]]; }
782 	for (e=n; e<this.nElements; e++) { delete this[e]; }
783 	this.nElements = n;
784 }
785 
786 /** Sets subvector at defined positions of receiver ( this[coeffs]=vec )
787 * @param {[floats]|Vector} coeffs array containing coefficients to be set
788 * @param {Vector} vec vector to be set
789 * @example
790 * v = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]);
791 * v.setSubVector([2,3,6,8,9],vec([1.1,2.2,3.3,4.4,5.5])); // v = Vector([4,7,1.1,2.2,8,3,3.3,4,4.4,5.5,5,1,6,9])
792 */
793 Vector.prototype.setSubVector = function(coeffs,vec) {
794 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
795 	var vi = vec.nElements;
796 	if (vi != n) { /*jsmLogger.warn('Vector.setSubVector: wrong argument dimensions');*/ return; }
797 	if (n>this.nElements) { /*jsmLogger.warn('Vector.setSubVector: wrong argument dimensions');*/ return; }
798 	var e;
799 	for (e=0; e<n; e++) { if (coeffs[e]<0 || coeffs[e]>=this.nElements) { /*jsmLogger.warn('Vector.setSubVector: wrong argument values');*/ return; } }
800 	for (e=0; e<n; e++) { this[coeffs[e]] = vec[e]; }
801 }
802 
803 /** Alias for setSubVector, see {@link Vector#setSubVector}
804 * @function
805 */
806 Vector.prototype.setsv = Vector.prototype.setSubVector;
807 
808 /** Increment subvector at defined positions of receiver (this[coeffs] += vec)
809 * @param {[floats]|Vector} coeffs array containing coefficients to be incremented
810 * @param {Vector} vec vector to be added
811 * @example
812 * v = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]);
813 * v.incrSubVector([2,3,6,8,9],vec([1.1,2.2,3.3,4.4,5.5])); // v = Vector([4,7,10.1,3.2,8,3,5.3,4,10.4,12.5,5,1,6,9])
814 */
815 Vector.prototype.incrSubVector = function(coeffs,vec) {
816 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
817 	var vi = vec.nElements;
818 	if (vi != n) { /*jsmLogger.warn('Vector.incrSubVector: wrong argument dimensions');*/ return; }
819 	if (n>this.nElements) { /*jsmLogger.warn('Vector.incrSubVector: wrong argument dimensions');*/ return; }
820 	var e;
821 	for (e=0; e<n; e++) { if (coeffs[e]<0 || coeffs[e]>=this.nElements) { /*jsmLogger.warn('Vector.incrSubVector: wrong argument values');*/ return; } }
822 	for (e=0; e<n; e++) { this[coeffs[e]] += vec[e]; }
823 }
824 
825 /** Alias for incrSubVector, see {@link Vector#incrSubVector}
826 * @function
827 */
828 Vector.prototype.incrsv = Vector.prototype.incrSubVector;
829 
830 /** Decrement subvector at defined positions of receiver (this[coeffs] -= vec)
831 * @param {[floats]|Vector} coeffs array containing coefficients to be decremented
832 * @param {Vector} vec vector to be subtracted
833 * @example
834 * v = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]);
835 * v.decrSubVector([2,3,6,8,9],vec([1.1,2.2,3.3,4.4,5.5])); // v = Vector([4,7,7.9,-1.2,8,3,-1.3,4,1.6,1.5,5,1,6,9])
836 */
837 Vector.prototype.decrSubVector = function(coeffs,vec) {
838 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
839 	var vi = vec.nElements;
840 	if (vi != n) { /*jsmLogger.warn('Vector.decrSubVector: wrong argument dimensions');*/ return; }
841 	if (n>this.nElements) { /*jsmLogger.warn('Vector.decrSubVector: wrong argument dimensions');*/ return; }
842 	var e;
843 	for (e=0; e<n; e++) { if (coeffs[e]<0 || coeffs[e]>=this.nElements) { /*jsmLogger.warn('Vector.decrSubVector: wrong argument values');*/ return; } }
844 	for (e=0; e<n; e++) { this[coeffs[e]] -= vec[e]; }
845 }
846 
847 /** Alias for decrSubVector, see {@link Vector#decrSubVector}
848 * @function
849 */
850 Vector.prototype.decrsv = Vector.prototype.decrSubVector;
851 
852 /** assemble receiver to given vector ( vec[coeffs] += this )
853 * @param {Vector} vec vector where receiver is assembled
854 * @param {[floats]|Vector} coeffs array containing coefficients of vec to be incremented
855 * @example
856 * v1 = vec([5,8,2,4,3,5]);
857 * v2 = vec([1,2,3]);
858 * v2.assemble(v1,[5,1,2]); // v1 = Vector([5,10,5,4,3,6])
859 */
860 Vector.prototype.assemble = function(vec,coeffs) {
861 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
862 	var vi = this.nElements;
863 	if (vi != n) { /*jsmLogger.warn('Vector.assemble: wrong argument dimensions');*/ return; }
864 	if (n>vec.nElements) { /*jsmLogger.warn('Vector.assemble: wrong argument dimensions');*/ return; }
865 	var e;
866 	for (e=0; e<n; e++) { if (coeffs[e]<0 || coeffs[e]>=vec.nElements) { /*jsmLogger.warn('Vector.assemble: wrong argument values');*/ return; } }
867 	for (e=0; e<n; e++) { vec[coeffs[e]] += this[e]; }
868 }
869 
870 /** Modifies receiver to become row of given matrix - indexing from 0. Receiver's size is adjusted
871 * @param {Matix} mat given matrix
872 * @param {float} r desired row (indexing from 0)
873 * @example
874 * v = vec([1,2]);
875 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
876 * v.beRowOf(m,1) // v = Vector([21,22,23])
877 */
878 Vector.prototype.beRowOf = function(mat,r) {
879 	var c, nc = mat.nCols;
880 	for (c=0; c<nc; c++) { this[c] = mat[r][c]; }
881 	for (c=nc; n<this.nElements; c++) { delete this[c]; }
882 	this.nElements = nc;
883 }
884 
885 /** Modifies receiver to become column of given matrix - indexing from 0. Receiver's size is adjusted
886 * @param {Matix} mat given matrix
887 * @param {float} c desired column (indexing from 0)
888 * @example
889 * v = vec([1,2]);
890 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
891 * v.beColOf(m,1) // v = Vector([12,22,32])
892 */
893 Vector.prototype.beColOf = function(mat,c) {
894 	var r, nr = mat.nRows;
895 	for (r=0; r<nr; r++) { this[r] = mat[r][c]; }
896 	for (r=nr; n<this.nElements; r++) { delete this[r]; }
897 	this.nElements = nr;
898 }
899 
900 /** Alias for beColOf(), see {@link Vector#beColOf}
901 * @function
902 */
903 Vector.prototype.beColumnOf = Vector.prototype.beColOf;
904 
905 /** Returns copy of receiver
906 * @returns {Vector} copy of receiver
907 * @example
908 * v1 = vec([1,2,3]);
909 * v2 = v1;
910 * v3 = v1.copied();
911 * v1.set(1,6);
912 * // v1; = Vector([1,6,3])
913 * // v2; = Vector([1,6,3])
914 * // v3; = Vector([1,2,3])
915 */
916 Vector.prototype.copied = function() {
917 	var ret = new Vector(), e, n = this.nElements;
918 	for (e=0; e<n; e++) { ret[e] = this[e]; }
919 	ret.nElements = n;
920 	return ret;
921 }
922 
923 /** Alias for copied(), see {@link Vector#copied}
924 * @function
925 */
926 Vector.prototype.copy = Vector.prototype.copied;
927 
928 /** Modifies receiver to become copy of given vector (this = vec). Receiver's size is adjusted
929 * @param {Vector} vec vector to be copied to receiver
930 * @example
931 * v1 = vec([4,5]);
932 * v2 = vec([1,2,3]);
933 * v1.beCopyOf(v2) // v2 = Vector([1,2,3])
934 */
935 Vector.prototype.beCopyOf = function(vec) {
936 	var s = vec.nElements, e;
937 	for (e=0; e<s; e++) { this[e] = vec[e]; }
938 	for (e=s; e<this.nElements; e++) { delete this[e]; }
939 	this.nElements = s;
940 }
941 
942 /** Returns string representation of receiver
943 * @returns {string} string representation of receiver
944 * @example
945 * v1 = vec([0.5999999999999999,2,3]);
946 * s = v1.toString(); // s = 'Vector([ 1, 2, 3 ])'
947 */
948 Vector.prototype.toString = function() {
949 	var nn = this.nElements, e, val;
950 	if (nn == 0) { return "Vector([])\n"; }
951 	var ret = "Vector([ ";
952 	for (e=0; e<nn-1; e++) {
953 		val = this[e];
954 		//val = (Math.abs(val) < JSM_TOL)? 0. : Math.round(val*JSM_ROUNDFACTOR)/JSM_ROUNDFACTOR;
955 		ret += val.toExponential(3)+", ";
956 	}
957 	val = this[nn-1];
958 	//val = (Math.abs(val) < JSM_TOL)? 0. : Math.round(val*JSM_ROUNDFACTOR)/JSM_ROUNDFACTOR;
959 	ret += val.toExponential(3)+" ])\n";
960 	return ret;
961 }
962 
963 /** Swaps two elements of receiver
964 * @param {int} e1 index of first element to swap
965 * @param {int} e2 index of second element to swap
966 * @example
967 * v = vec([1,2,3,4,5,6,7]);
968 * v.swapElements(1,4); // v = Vector([1,5,3,4,2,6,7])
969 */
970 Vector.prototype.swapElements = function(e1,e2) {
971 	if (e1==e2) { return; }
972 	if (e1<0 || e2<0 || e1>=this.nElements || e2>=this.nElements) { /*jsmLogger.warn('Vector.swapElements: wrong coefficients');*/ return; }
973 	var temp = this[e1];
974 	this[e1] = this[e2];
975 	this[e2] = temp;
976 }
977 
978 /** Appends given float/vector to the end of receiver
979 * @param {float|Vector|[Vectors]} newElems new element(s) to be appended
980 * @example
981 * v = vec([1,2]);
982 * v.appendElements(4); // v = Vector([1,2,4]);
983 * v.appendElements(vec([7,6])); // v = Vector([1,2,4,7,6]);
984 * v.appendElements([vec([1,2]),vec([3,4])]); // v = Vector([1,2,4,6,7,1,2,3,4])
985 */
986 Vector.prototype.appendElements = function(newElems) {
987 	if (newElems instanceof Vector) {
988 		var n = newElems.nElements, e;
989 		for (e=0; e<n; e++) {
990 			this[this.nElements] = newElems[e];
991 			this.nElements++;
992 		}
993 		return;
994 	}
995 	if (newElems instanceof Array) {
996 		var n = newElems.length, e;
997 		for (e=0; e<n; e++) {
998 			this.appendElements(newElems[e]);
999 		}
1000 		return;
1001 	}
1002 	if ((typeof newElems).toLowerCase() == 'number') {
1003 		this[this.nElements] = newElems;
1004 		this.nElements++;
1005 		return;
1006 	}
1007 }
1008 
1009 /** Permute elements of receiver according to given coefficients
1010 * @param {[ints]|Vector} coeffs coefficients of permutation
1011 * @param {bool} [backward=false] if false, receiver is permutated to given coefficients (forward). If true, from given coefficients (backward)
1012 * @example
1013 * v = vec([7,9,6]);
1014 * v.permuteElements([1,2,0]); // v = Vector([9,6,7])
1015 * v.permuteElements([1,2,0],true); // v = Vector([7,9,6])
1016 */
1017 Vector.prototype.permuteElements = function(coeffs,backward) {
1018 	var n;
1019 	if (coeffs.nElements==undefined) { // coeffs == Array
1020 		n = coeffs.length;
1021 		var coeffs = coeffs.slice();
1022 	} else { // coeffs == Vector
1023 		n = coeffs.nElements;
1024 		var coeffs = coeffs.toArray();
1025 	}
1026 	if (n != this.nElements) { /*jsmLogger.warn('Vector.permuteElements: wrong argument size');*/ return; }
1027 	for (var e=0; e<n; e++) { if (e<0 || e>=this.nElements) { /*jsmLogger.warn('Vector.permuteElements: wrong argument values');*/ return; } }
1028 	var backward = backward || false;
1029 	var ee;
1030 	if (backward) {
1031 		for (var e=0; e<n; e++) {
1032 			ee = coeffs[e];
1033 			while (ee!=e) {
1034 				this.swapElements(e,ee);
1035 				coeffs[e] = coeffs[ee];
1036 				coeffs[ee] = ee;
1037 				ee = coeffs[e];
1038 			}
1039 		}
1040 	} else {
1041 		for (var e=n-1; e>0; e--) {
1042 			ee = coeffs[e];
1043 			this.swapElements(e,ee);
1044 			coeffs[coeffs.indexOf(e)] = ee;
1045 		}
1046 	}
1047 	return;
1048 }
1049 
1050 /** Returns permutated copy of receiver according to given coefficients
1051 * @param {[ints]|Vector} coeffs coefficients of permutation. The content will be changed(!), use a copy if you need to preserve the content
1052 * @param {bool} [backward=false] if false, receiver is permutated to given coefficients (forward). If true, from given coefficients (backward)
1053 * @returns {Vector} permutated copy of receiver
1054 * @example
1055 * v1 = vec([7,9,6]);
1056 * v2 = v1.elementsPermutation([1,2,0]); // v2 = Vector([9,6,7])
1057 * v3 = v1.elementsPermutation([1,2,0],true); // v3 = Vector([6,7,9])
1058 */
1059 Vector.prototype.elementsPermutation = function(coeffs,backward) {
1060 	var n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
1061 	if (n != this.nElements) { /*jsmLogger.warn('Vector.elementsPermutation: wrong argument size');*/ return; }
1062 	for (var e=0; e<n; e++) { if (e<0 || e>=this.nElements) { /*jsmLogger.warn('Vector.elementsPermutation: wrong argument values');*/ return; } }
1063 	var ret = new Vector();
1064 	if (backward) {
1065 		for (e=0; e<this.nElements; e++) {
1066 			ret[coeffs[e]] = this[e];
1067 		}
1068 	} else {
1069 		for (e=0; e<this.nElements; e++) {
1070 			ret[e] = this[coeffs[e]];
1071 		}
1072 	}
1073 	ret.nElements = this.nElements;
1074 	return ret;
1075 }
1076 
1077 /** Resize receiver according to given size (delete extra elements or add zero elements)
1078 * @param {int} nElements new number of elements
1079 * @example
1080 * v1 = vec([4,7,9,1,7,3])
1081 * v2 = vec([4,6]);
1082 * v1.resize(4); // v1 = Vector([4,7,9,1])
1083 * v2.resize(4); // v2 = Vector([4,6,0,0])
1084 */
1085 Vector.prototype.resize = function(nElements) {
1086 	if (nElements==this.nElements) { return; }
1087 	if (nElements > this.nElements) {
1088 		for (var e=this.nElements; e<nElements; e++) { this[e] = 0.; }
1089 		this.nElements = nElements;
1090 		return;
1091 	}
1092 	if (nElements < this.nElements) {
1093 		for (var e=nElements; e<this.nElements; e++) { delete this[e]; }
1094 		this.nElements = nElements;
1095 		return;
1096 	}
1097 }
1098 
1099 /** Returns resized copy of receiver according to given size (delete extra elements or add zero elements)
1100 * @param {int} nElements new number of elements
1101 * @returns {Vector} resized copy of receiver
1102 * @example
1103 * v1 = vec([4,7,9,1]);
1104 * v2 = v1.resized(2); // v2 = Vector([4,7])
1105 * v3 = v1.resized(6); // v3 = Vector([4,7,9,1,0,0])
1106 */
1107 Vector.prototype.resized = function(nElements) {
1108 	var e, ret = new Vector();
1109 	if (nElements<=this.nElements) {
1110 		for (e=0; e<nElements; e++) { ret[e] = this[e]; }
1111 	} else {
1112 		for (e=0; e<this.nElements; e++) { ret[e] = this[e]; }
1113 		for (e=this.nElements; e<nElements; e++) { ret[e] = 0.; }
1114 	}
1115 	ret.nElements = nElements;
1116 	return ret;
1117 }
1118 
1119 /** Returns matrix with receiver's elements on its diagonal
1120 * @returns {Matrix} diagonal matrix with receiver's elements on its diagonal
1121 * @example
1122 * v = vec([1,2,3]);
1123 * m = v.toDiagonalMatrix(); // m = Matrix([[1,0,0],[0,2,0],[0,0,3]])
1124 */
1125 Vector.prototype.toDiagonalMatrix = function() {
1126 	var ret = Matrix.Zeros(this.nElements,this.nElements);
1127 	for (var e=0; e<this.nElements; e++) { ret[e][e] = this[e]; }
1128 	return ret;
1129 }
1130 
1131 /** Modifies receiver to contain diagonal elements of mat ( this = diag(mat) )
1132 * @param {Matrix} mat matrix whose diagonal is copied to receiver
1133 * @example
1134 * v = vec([6,7]);
1135 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1136 * v.beDiagonalFrom(m); // v = Vector([1,5,9])
1137 */
1138 Vector.prototype.beDiagonalFrom = function(mat) {
1139 	if (!mat.isSquare()) { /*jsmLogger.warn('Vector.beDiagonalFrom: non-square matrix');*/ return; }
1140 	var e, s = mat.nRows;
1141 	for (e=0; e<s; e++) { this[e] = mat[e][e]; }
1142 	for (e=s; s<this.nElements; e++) { delete this[e]; }
1143 	this.nElements = s;
1144 }
1145 
1146 /** Returns matrix with receiver's elements on diagonal (if no argument is specified, see{@link Vector#toDiagonalMatrix}) or modifies receiver to contain diagonal elements of given matrix (if given matrix is specified, see{@link Vector#beDiagonalFrom})
1147 * @param {Matrix} [mat=undefined] matrix whose diagonal is copied to receiver. If not specified, diagnal matrix is returned
1148 * @returns {Matrix|undefined} if no input parameter, returns diagonal matrix, otherwise nothing
1149 * @example
1150 * v = vec([6,7]);
1151 * m1 = mat([[1,2,3],[4,5,6],[7,8,9]]);
1152 * v.diag(m1); // v = Vector([1,5,9])
1153 * m2 = v.diag(); // m2 = Matrix([[1,0,0],[0,5,0],[0,0,9]])
1154 */
1155 Vector.prototype.diag = function(mat) {
1156 	if (mat==undefined) { return this.toDiagonalMatrix(); }
1157 	this.beDiagonalFrom(mat);
1158 }
1159 
1160 /** Modifies receiver to be a solution of linear system of equations mat*this = rhs. Receiver's size is adjusted
1161 * @param {Matrix} mat matrix of the system
1162 * @param {Vector} rhs vector of right hand side
1163 * @param {string} [method="default"] see {@link Matrix#linSolve}
1164 * @param {bool} [saveOrig=true] see {@link Matrix#linSolve}
1165 * @param {[Matrices]} [precompDecomps=undefined] see {@link Matrix#linSolve}
1166 * @example
1167 * v = vec([2,3]);
1168 * a = mat([[1,2,9],[8,3,2],[3,7,3]]);
1169 * b = vec([32,20,26]);
1170 * v.beSolutionOf(a,b); // v = Vector([1,2,3])
1171 */
1172 Vector.prototype.beSolutionOf = function(mat,rhs,method,saveOrig,precompDecomps) {
1173 	var saveOrig = saveOrig==undefined? true : saveOrig;
1174 	var mat = saveOrig? mat.copy() : mat;
1175 	var rhs = rhs;
1176 	this.beCopyOf(rhs);
1177 	mat.linSolve(this,method,false,precompDecomps);
1178 	//mat.gaussianElimination(this,'default',false);
1179 }
1180 
1181 /** Constructs new Vector from given array
1182 * @param {[floats]} [arry=[]] array containing elements of new vector
1183 * @returns {Vector} new Vector object 
1184 * @example
1185 * v = Vector.create([1,2,3,4]); // v = Vector([1,2,3,4])
1186 */
1187 Vector.create = function(arry) {
1188 var a = arry || [];
1189 var n = a.length;
1190 var ret = new Vector();
1191 for (var i=0; i<n; i++) { ret[i] = a[i]; }
1192 ret.nElements = n;
1193 return ret;
1194 }
1195 
1196 /** Creates unit vector in x direction
1197 * @returns {Vector} unit x vector
1198 * @example
1199 * v = Vector.UnitX(); // v = Vector([1,0,0])
1200 */
1201 Vector.UnitX = function() { return Vector.create([1,0,0]); }
1202 
1203 /** Creates unit vector in y direction
1204 * @returns {Vector} unit y vector
1205 * @example
1206 * v = Vector.UnitY(); // v = Vector([0,1,0])
1207 */
1208 Vector.UnitY = function() { return Vector.create([0,1,0]); }
1209 
1210 /** Creates unit vector in z direction
1211 * @returns {Vector} unit z vector
1212 * @example
1213 * v = Vector.UnitZ(); // v = Vector([0,0,1])
1214 */
1215 Vector.UnitZ = function() { return Vector.create([0,0,1]); }
1216 
1217 /** Creates a vector full of zeros
1218 * @param {int} [nElements=0] number of elements
1219 * @returns {Vector} new vector full of zeros
1220 * @example
1221 * v = Vector.Zeros(4); // v = Vector([0,0,0,0])
1222 */
1223 Vector.Zeros = function(nElements) {
1224 	var nElements = nElements || 0;
1225 	return new Vector(nElements)
1226 }
1227 
1228 /** Creates a vector full of ones
1229 * @param {int} [nElements=0] number of elements
1230 * @returns {Vector} new vector full of zeros
1231 * @example
1232 * v = Vector.Ones(6); // v = Vector([1,1,1,1,1,1])
1233 */
1234 Vector.Ones = function(nElements) {
1235 	var nElements = nElements || 0;
1236 	var r, ret = new Vector();
1237 	for (r=0; r<nElements; r++) { ret[r] = 1.; }
1238 	ret.nElements = nElements;
1239 	return ret;
1240 }
1241 
1242 
1243 
1244 
1245 
1246 
1247 
1248 /** Matrix implementation
1249 * @class Represents 2D matrix of real (floating point) numbers
1250 * @param {int} [nRows=0] number or rows of newly created Matrix
1251 * @param {int} [nCols=0] number or columns of newly created Matrix
1252 * @property {int} [nRows=0] number of rows of receiver
1253 * @property {int} [nCols=0] number of columns of receiver
1254 */
1255 Matrix = function(nRows,nCols) {
1256 	this.nRows = nRows || 0;
1257 	this.nCols = nCols || 0;
1258 	var r,c;
1259 	for (r=0; r<this.nRows; r++) {
1260 		this[r] = {};
1261 		for (c=0; c<this.nCols; c++) { this[r][c] = 0.; }
1262 	}
1263 }
1264 
1265 /** Empties receiver (resizes it to size 0)
1266 * @example
1267 * m = mat([[1,2],[3,4]]);
1268 * m.empty(); // m = Matrix([])
1269 */
1270 Matrix.prototype.empty = function() {
1271 	this.resize(0,0);
1272 }
1273 
1274 /** Tests if receiver is empty (has size 0,0)
1275 * @returns true if receiver is empty, false otherwise
1276 * @example
1277 * v1 = new Matrix(2,3);
1278 * v2 = new Matrix();
1279 * b1 = v1.isEmpty(); // b1 = false
1280 * b2 = v2.isEmpty(); // b2 = true
1281 */
1282 Matrix.prototype.isEmpty = function() {
1283 	return this.nRows==0 && this.nCols==0;
1284 }
1285 
1286 /** Zeroes all elements of receiver
1287 * @example
1288 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1289 * m.zero(); // m = Matrix([[0,0,0],[0,0,0],[0,0,0]])
1290 */
1291 Matrix.prototype.zero = function() {
1292 	for (var r=0; r<this.nRows; r++) {
1293 		for (var c=0; c<this.nCols; c++) { this[r][c] = 0.; }
1294 	}
1295 }
1296 
1297 /** Sets all elements of receiver to 1.0
1298 * @example
1299 * m = mat([[2,3,4],[5,6,7]]);
1300 * m.beFullOfOnes(); // m = Matrix([[1,1,1],[1,1,1]])
1301 */
1302 Matrix.prototype.beFullOfOnes = function() {
1303 	for (var r=0; r<this.nRows; r++) {
1304 		for (var c=0; c<this.nCols; c++) { this[r][c] = 1.; }
1305 	}
1306 }
1307 
1308 /** Alias for beFullOfOnes(), see {@link Matrix#beFullOfOnes}
1309 * @function
1310 */
1311 Matrix.prototype.one = Matrix.prototype.beFullOfOnes;
1312 
1313 /** Modifies receiver to be unit matrix
1314 * @param {int} [newSize=0] new size or receiver. If omitted or 0, current size is considered (then required square matrix), else resized to newSize
1315 * @example
1316 * m = mat([[1],[2]]);
1317 * m.beUnitMatrix(); // m = Matrix([[1],[2]])
1318 * /// nothing happened, m is not square
1319 * m.beUnitMatrix(2); // m = Matrix([[1,0],[0,1]])
1320 * m = mat([[2,3],[4,5]]);
1321 * m.beUnitMatrix(); // m = Matrix([[1,0],[0,1]])
1322 */
1323 Matrix.prototype.beUnitMatrix = function(newSize) {
1324 	var newSize = newSize || 0;
1325 	if (newSize<=0) {
1326 		if (!this.isSquare) { /*jsmLogger.warn('Matrix.beUnitMatrix: matrix is not square');*/ return; }
1327 		this.zero();
1328 		for (var i=0; i<this.nRows; i++) { this[i][i] = 1.; }
1329 		return;
1330 	}
1331 	var r,c;
1332 	this.resize(newSize,newSize);
1333 	for (r=0; r<newSize; r++) { this[r][r] = 1.; }
1334 }
1335 
1336 /** Returns size of receiver as [nRows,nCols]
1337 * @returns {[int,int]} size of receiver
1338 * @example
1339 * m = mat([[1,2,3],[4,5,6]]);
1340 * s = m.size(); // s = [2,3]
1341 */
1342 Matrix.prototype.size = function() {
1343 	return [this.nRows,this.nCols];
1344 }
1345 
1346 /** Returns trace (sum of diagonal elements) of the receiver
1347 * @returns {float} trace of the receiver
1348 * @example
1349 * m = mat([[1,2,3],[4,5,6],[7,8,9]])
1350 * tr = m.trace() // tr = 15
1351 */
1352 Matrix.prototype.trace = function() {
1353 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.trace: matrix is not square');*/ return null; }
1354 	var ret = 0.;
1355 	for (var e=0; e<this.nRows; e++) {
1356 		ret += this[e][e];
1357 	}
1358 	return ret;
1359 }
1360 
1361 /** Alias for trace, see {@link Matrix#trace}
1362 * @function
1363 */
1364 Matrix.prototype.diagSum = Matrix.prototype.trace;
1365 
1366 /** Returns product of diagonal elements of the receiver
1367 * @returns {float} product of diagonal elements of the receiver
1368 * @example
1369 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1370 * p = m.diagProduct(); // p = 45
1371 */
1372 Matrix.prototype.diagProduct = function() {
1373 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.trace: matrix is not square');*/ return null; }
1374 	var ret = 1.;
1375 	for (var e=0; e<this.nRows; e++) {
1376 		ret *= this[e][e];
1377 		if (ret==0.) { return 0.; }
1378 	}
1379 	return ret;
1380 }
1381 
1382 /** Alias for diagProduct, see {@link Matrix#diagProduct}
1383 * @function
1384 */
1385 Matrix.prototype.dprod = Matrix.prototype.diagProduct;
1386 
1387 /** Coefficient access function, returns one element of receiver ( ret = this[r][c] ). Matrix.get(r,c) is much safer than direct Matrix[r][c] access method
1388 * @param {int} r index of row of element to be returned
1389 * @param {int} c index of column of element to be returned
1390 * @returns {float} value of the element at r-th row and c-th column
1391 * @example
1392 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1393 * g = m.get(1,2); // g = 23
1394 * g = m[1][2]; // g = 23
1395 * /// c out of bounds
1396 * g = m.get(1,5); // g = null
1397 * g = m[1][5]; // g = undefined
1398 * /// r out of bounds
1399 * g = m.get(6,5) // g = null
1400 * /// g = m[6][5]; would be error (m[6] is not defined)
1401 */
1402 Matrix.prototype.get = function(r,c) {
1403 	if (r<0 || c<0) { /*jsmLogger.warn('Matrix.get: coefficients out of bounds');*/ return null; }
1404 	if (r>=this.nRows || c>=this.nCols) { return null; }
1405 	return this[r][c];
1406 }
1407 
1408 /** Coefficient access function, sets one element of receiver ( this[r][c] = val ). Matrix.set(r,c,val) is much safer than direct Matrix[r][c]=val access method
1409 * @param {int} r index of row of element to be set
1410 * @param {int} c index of column of element to be set
1411 * @param {float} val value to be set
1412 * @example
1413 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1414 * m.set(1,2,3.45); // m = Matrix([[11,12,13],[21,22,3.45],[31,32,33]])
1415 * m[1][2] = 3.45; // m = Matrix([[11,12,13],[21,22,3.45],[31,32,33]])
1416 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1417 * /// c out of bounds (nothing is done by both appraches)
1418 * m.set(1,5,8.45); // m = Matrix([[11,12,13],[21,22,3.45],[31,32,33]])
1419 * m[1][5] = 8.45; // m = Matrix([[11,12,13],[21,22,3.45],[31,32,33]])
1420 * /// r out of bounds
1421 * m.set(6,5,8.45); // m = Matrix([[11,12,13],[21,22,3.45],[31,32,33]])
1422 * /// m[6][5] = 8.45; would be error (m[6] is not defined)
1423 */
1424 Matrix.prototype.set = function(r,c,val) {
1425 	if (r<0 || c<0) { /*jsmLogger.warn('Matrix.set: coefficients out of bounds');*/ return; }
1426 	if (r>=this.nRows || c>=this.nCols) { return; }
1427 	this[r][c] = val;
1428 }
1429 
1430 /** Coefficient access function, increment one element of receiver ( this[r][c] += val ). Matrix.incr(r,c,val) is much safer than direct Matrix[r][c]+=val access method
1431 * @param {int} r index of row of element to be incremented
1432 * @param {int} c index of column of element to be incremented
1433 * @param {float} val value to be add
1434 * @example
1435 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1436 * m.incr(1,2,3.45); // m = Matrix([[11,12,13],[21,22,26.45],[31,32,33]])
1437 * m[1][2] += 3.45; // m = Matrix([[11,12,13],[21,22,29.9],[31,32,33]])
1438 * /// c out of bounds
1439 * m.incr(1,5,3.45); // m = Matrix([[11,12,13],[21,22,29.9],[31,32,33]])
1440 * /// m[1][5] += 3.45); would be error (m[1][5] is not defined)
1441 * /// r out of bounds
1442 * m.incr(6,5,3.45); // m = Matrix([[11,12,13],[21,22,29.9],[31,32,33]])
1443 * /// m[6][5] += 3.45; would be error (m[6] is not defined)
1444 */
1445 Matrix.prototype.incr = function(r,c,val) {
1446 	if (r<0 || c<0) { /*jsmLogger.warn('Matrix.incr: coefficients out of bounds');*/ return; }
1447 	if (r>=this.nRows || c>=this.nCols) { return; }
1448 	if (val) { this[r][c] += val; }
1449 }
1450 
1451 /** Sets elements of receiver form given Array object
1452 * @param {[floats](2D)} arry array containing new receiver elements
1453 * @example
1454 * m = mat([[3,2],[1,1]])
1455 m.fromArray([[1,2,3],[4,5,6],[7,8,9]]); // m = Matrix([[1,2,3],[4,5,6],[7,8,9]])
1456 */
1457 Matrix.prototype.fromArray = function(arry) {
1458 	var r, c, nr = arry.length, nc = arry[0].length;
1459 	for (r=0; r<nr; r++) {
1460 		if (r >= this.nRows) { this[r] = {}; }
1461 		for (c=0; c<nc; c++) {
1462 			this[r][c] = arry[r][c];
1463 		}
1464 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
1465 	}
1466 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
1467 	this.nRows = nr;
1468 	this.nCols = nc;
1469 }
1470 
1471 /** Returns elements of receiver as an Array object
1472 * @returns {[floats](2D)} array containing receiver's elements
1473 * @example
1474 * m =mat([[11,12],[21,22]]);
1475 * a = m.toArray(); // a = [[11,12],[21,22]]
1476 */
1477 Matrix.prototype.toArray = function() {
1478 	var r, c, ret = []
1479 	for (r=0; r<this.nRows; r++) {
1480 		ret[r] = [];
1481 		for (c=0; c<this.nCols; c++) {
1482 			ret[r][c] = this[r][c];
1483 		}
1484 	}
1485 	return ret;
1486 }
1487 
1488 /** Returns sum of receiver and matrix ( ret = this + mat )
1489 * @param {Matrix} mat matrix to be added
1490 * @returns {Matrix} sum of receiver and matrix
1491 * @example
1492 * m1 = mat([[1,2],[3,4]]);
1493 * m2 = mat([[2,5],[3,2]]);
1494 * m3 = m1.add(m2); // m3 = Matrix([[3,7],[6,6]])
1495 */
1496 Matrix.prototype.add = function(mat) {
1497 	if (!this.isSameSizeAs(mat)) { /*jsmLogger.warn('Matrix.add: dimensions mismatched');*/ return null; }
1498 	var r, c, nr = this.nRows, nc = this.nCols, ret = new Matrix();
1499 	for (r=0; r<nr; r++) {
1500 		ret[r] = {};
1501 		for (c=0; c<nc; c++) { ret[r][c] = this[r][c] + mat[r][c]; }
1502 	}
1503 	ret.nRows = nr;
1504 	ret.nCols = nc;
1505 	return ret;
1506 }
1507 
1508 /** Add given matrix to receiver ( this += mat )
1509 * @param {Matrix} mat matrix to be added
1510 * @example
1511 * m1 = mat([[1,2],[3,4]]);
1512 * m2 = mat([[2,5],[3,2]]);
1513 * m1.iadd(m2); // m1 = Matrix([[3,7],[6,6]])
1514 */
1515 Matrix.prototype.iadd = function(mat) {
1516 	if (!this.isSameSizeAs(mat)) { /*jsmLogger.warn('Matrix.iadd: dimensions mismatched');*/ return; }
1517 	for (var r=0; r<this.nRows; r++) {
1518 		for (var c=0; c<this.nCols; c++) { this[r][c] += mat[r][c]; }
1519 	}
1520 }
1521 
1522 /** Modifies receiver to become sum of two matrices ( this = mat1 + mat2 ). Receiver's size is adjusted
1523 * @param {Matrix} mat1 1st matrix of the sum
1524 * @param {Matrix} mat2 2nd matrix of the sum
1525 * @example
1526 * m = mat([[5],[9]]);
1527 * m1 = mat([[1,2],[3,4]]);
1528 * m2 = mat([[2,5],[3,2]]);
1529 * m.beSumOf(m1,m2); // m = Matrix([[3,7],[6,6]])
1530 */
1531 Matrix.prototype.beSumOf = function(mat1,mat2) {
1532 	if (!mat1.isSameSizeAs(mat2)) { /*jsmLogger.warn('Matrix.beSumOf: dimensions mismatched');*/ return; }
1533 	var r, c , nr = mat1.nRows, nc = mat1.nCols;
1534 	for (r=0; r<nr; r++) {
1535 		if (r >= this.nRows) { this[r] = {}; }
1536 		for (c=0; c<nc; c++) { this[r][c] = mat1[r][c] + mat2[r][c]; }
1537 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
1538 	}
1539 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
1540 	this.nRows = nr;
1541 	this.nCols = nc;
1542 }
1543 
1544 /** Returns difference of receiver and matrix ( ret = this - mat )
1545 * @param {Matrix} mat matrix to be added
1546 * @returns {Matrix} sum of receiver and matrix
1547 * @example
1548 * m1 = mat([[1,2],[3,4]]);
1549 * m2 = mat([[2,5],[3,2]]);
1550 * m3 = m1.sub(m2); // m3 = Matrix([[-1,-3],[0,2]])
1551 */
1552 Matrix.prototype.sub = function(mat) {
1553 	if (!this.isSameSizeAs(mat)) { /*jsmLogger.warn('Matrix.sub: dimensions mismatched');*/ return null; }
1554 	var r, c, nr = this.nRows, nc = this.nCols, ret = new Matrix();
1555 	for (r=0; r<nr; r++) {
1556 		ret[r] = {};
1557 		for (c=0; c<nc; c++) { ret[r][c] = this[r][c] - mat[r][c]; }
1558 	}
1559 	ret.nRows = nr;
1560 	ret.nCols = nc;
1561 	return ret;
1562 }
1563 
1564 /** Subtract given matrix to receiver ( this -= mat )
1565 * @param {Matrix} mat matrix to be added
1566 * @example
1567 * m1 = mat([[1,2],[3,4]]);
1568 * m2 = mat([[2,5],[3,2]]);
1569 * m1.isub(m2); // m1 = Matrix([[-1,-3],[0,2]])
1570 */
1571 Matrix.prototype.isub = function(mat) {
1572 	if (!this.isSameSizeAs(mat)) { /*jsmLogger.warn('Matrix.isub: dimensions mismatched');*/ return; }
1573 	for (var r=0; r<this.nRows; r++) {
1574 		for (var c=0; c<this.nCols; c++) { this[r][c] -= mat[r][c]; }
1575 	}
1576 }
1577 
1578 /** Modifies receiver to become difference of two matrices ( this = mat1 - mat2 ). Receiver's size is adjusted
1579 * @param {Matrix} mat1 1st matrix of the difference
1580 * @param {Matrix} mat2 2nd matrix of the difference
1581 * @example
1582 * m = mat([[5],[9]]);
1583 * m1 = mat([[1,2],[3,4]]);
1584 * m2 = mat([[2,5],[3,2]]);
1585 * m.beDifferenceOf(m1,m2); // m = Matrix([[-1,-3],[0,2]])
1586 */
1587 Matrix.prototype.beDifferenceOf = function(mat1,mat2) {
1588 	if (!mat1.isSameSizeAs(mat2)) { /*jsmLogger.warn('Matrix.beDifferenceOf: dimensions mismatched');*/ return; }
1589 	var r, c , nr = mat1.nRows, nc = mat1.nCols;
1590 	for (r=0; r<nr; r++) {
1591 		if (r >= this.nRows) { this[r] = {}; }
1592 		for (c=0; c<nc; c++) { this[r][c] = mat1[r][c] - mat2[r][c]; }
1593 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
1594 	}
1595 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
1596 	this.nRows = nr;
1597 	this.nCols = nc;
1598 }
1599 
1600 /** Returns negative of receiver ( ret = -this )
1601 * @returns {Matrix} negative of receiver
1602 * @example
1603 * m1 = mat([[1,2,3],[4,5,6]]);
1604 * m2 = m1.negated(); // m2 = Matrix([[-1,-2,-3],[-4,-5,-6]])
1605 */
1606 Matrix.prototype.negated = function() {
1607 	return this.mulf(-1.);
1608 }
1609 
1610 /** Alias for neageted(), see {@link Matrix#negated}
1611 * @function
1612 */
1613 Matrix.prototype.neg = Matrix.prototype.negated;
1614 
1615 /** Negate receiver ( ret *= -1., ret = -ret )
1616 * @example
1617 * m1 = mat([[1,2,3],[4,5,6]]);
1618 * m1.negate(); // m1 = Matrix([[-1,-2,-3],[-4,-5,-6]])
1619 */
1620 Matrix.prototype.negate = function() {
1621 	for (var r=0; r<this.nRows; r++) {
1622 		for (var c=0; c<this.nCols; c++) { this[r][c] *= -1.; }
1623 	}
1624 }
1625 
1626 /** Alias for neagete(), see {@link Matrix#negate}
1627 * @function
1628 */
1629 Matrix.prototype.ineg = Matrix.prototype.negate;
1630 
1631 /** Modifies receiver to become negative of given matrix (this = -vec). Receiver's size is adjusted
1632 * @param {Matrix} mat given matrix
1633 * @example
1634 * m1 = mat([[2],[3]]);
1635 * m2 = mat([[1,2,3],[4,5,6]]);
1636 * m1.beNegativeOf(m2); // m1 = Matrix([[-1,-2,-3],[-4,-5,-6]])
1637 */
1638 Matrix.prototype.beNegativeOf = function(mat) {
1639 	var r, c , nr = mat.nRows, nc = mat.nCols;
1640 	for (r=0; r<nr; r++) {
1641 		if (r >= this.nRows) { this[r] = {}; }
1642 		for (c=0; c<nc; c++) { this[r][c] = -mat[r][c]; }
1643 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
1644 	}
1645 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
1646 	this.nRows = nr;
1647 	this.nCols = nc;
1648 }
1649 
1650 /** Returns one row of receiver
1651 * @param {int} r index of row to return
1652 * @returns {Vector} r-th row of receiver as vector
1653 * @example
1654 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1655 * v = m.getRow(1); // v = Vector([4,5,6])
1656 */
1657 Matrix.prototype.getRow = function(r) {
1658 	var ret = new Vector();
1659 	for (var c=0; c<this.nCols; c++) { ret[c] = this[r][c]; }
1660 	ret.nElements = this.nCols;
1661 	return ret;
1662 }
1663 
1664 /** Returns one column of receiver
1665 * @param {int} c index of column to return
1666 * @returns {Vector} c-th column of receiver as vector
1667 * @example
1668 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1669 * v = m.getCol(1); // v = Vector([2,5,8])
1670 */
1671 Matrix.prototype.getCol = function(c) {
1672 	var ret = new Vector()
1673 	for (var r=0; r<this.nRows; r++) { ret[r] = this[r][c]; }
1674 	ret.nElements = this.nRows;
1675 	return ret;
1676 }
1677 
1678 /** Sets one row of receiver
1679 * @param {int} r index of row to set
1680 * @param {Vector} vec vector to be set as new r-th row
1681 * @example
1682 * mat([[1,2,3],[4,5,6],[7,8,9]]);
1683 * m.setRow(1,vec([11,12,13])); // m = Matrix([[1,2,3],[11,12,13],[7,8,9]])
1684 */
1685 Matrix.prototype.setRow = function(r,vec) {
1686 	if (r<0 || r>=this.nRows) { /*jsmLogger.warn('Matrix.setRow: wrong row');*/ return; }
1687 	var n = vec.nElements;
1688 	if (this.nCols != n) { /*jsmLogger.warn('Matrix.setRow: wrong argument');*/ return; }
1689 	for (var c=0; c<this.nCols; c++) { this[r][c] = vec[c]; }
1690 }
1691 
1692 /** Sets one column of receiver
1693 * @param {int} c index of column to set
1694 * @param {Vector} vec vector to be set as new c-th column
1695 * @example
1696 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1697 * m.setCol(1,vec([11,12,13])); // m = Matrix([[1,11,3],[4,12,6],[7,13,9]])
1698 */
1699 Matrix.prototype.setCol = function(c,vec) {
1700 	if (c<0 || c>=this.nCols) { /*jsmLogger.warn('Matrix.setCol: wrong column');*/ return; }
1701 	var n = vec.nElements;
1702 	if (this.nRows != n) { /*jsmLogger.warn('Matrix.setCol: wrong argument');*/ return; }
1703 	for (var r=0; r<this.nRows; r++) { this[r][c] = vec[r]; }
1704 }
1705 
1706 /** Incerements one row of receiver
1707 * @param {int} r index of row to set
1708 * @param {Vector} vec vector to be incremented to r-th row
1709 * @example
1710 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1711 * m.incrRow(1,vec([11,12,13])); // m = Matrix([[1,2,3],[15,17,19],[7,8,9]])
1712 */
1713 Matrix.prototype.incrRow = function(r,vec) {
1714 	if (r<0 || r>=this.nRows) { /*jsmLogger.warn('Matrix.incrRow: wrong column');*/ return; }
1715 	var n = vec.nElements;
1716 	if (this.nCols != n) { /*jsmLogger.warn('Matrix.incrRow: wrong argument');*/ return; }
1717 	for (var c=0; c<this.nCols; c++) { this[r][c] += vec[c]; }
1718 }
1719 
1720 /** Incerements one column of receiver
1721 * @param {int} c index of column to set
1722 * @param {Vector} vec vector to be incremented to c-th column
1723 * @example
1724 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1725 * m.incrCol(1,vec([11,12,13])); // m = Matrix([[1,13,3],[4,17,6],[7,21,9]])
1726 */
1727 Matrix.prototype.incrCol = function(c,vec) {
1728 	if (c<0 || c>=this.nCols) { /*jsmLogger.warn('Matrix.incrCol: wrong column');*/ return; }
1729 	var n = vec.nElements;
1730 	if (this.nRows != n) { /*jsmLogger.warn('Matrix.incrCol: wrong argument');*/ return; }
1731 	for (var r=0; r<this.nRows; r++) { this[r][c] += vec[r]; }
1732 }
1733 
1734 /** Decerements one row of receiver
1735 * @param {int} r index of row to set
1736 * @param {Vector} vec vector to be decremented from r-th row
1737 * @example
1738 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1739 * m.decrRow(1,vec([11,12,13])); // m = Matrix([[1,2,3],[-7,-7,-7],[7,8,9]])
1740 */
1741 Matrix.prototype.decrRow = function(r,vec) {
1742 	if (r<0 || r>=this.nRows) { /*jsmLogger.warn('Matrix.decrRow: wrong column');*/ return; }
1743 	var n = vec.nElements;
1744 	if (this.nCols != n) { /*jsmLogger.warn('Matrix.decrRow: wrong argument');*/ return; }
1745 	for (var c=0; c<this.nCols; c++) { this[r][c] -= vec[c]; }
1746 }
1747 
1748 /** Decerements one column of receiver
1749 * @param {int} c index of column to set
1750 * @param {Vector} vec vector to be decremented from c-th column
1751 * @example
1752 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
1753 * m.decrCol(1,vec([11,12,13])); // m = Matrix([[1,-9,3],[4,-7,6],[7,-5,9]])
1754 */
1755 Matrix.prototype.decrCol = function(c,vec) {
1756 	if (c<0 || c>=this.nCols) { /*jsmLogger.warn('Matrix.decrCol: wrong column');*/ return; }
1757 	var n = vec.nElements;
1758 	if (this.nRows != n) { /*jsmLogger.warn('Matrix.decrCol: wrong argument');*/ return; }
1759 	for (var r=0; r<this.nRows; r++) { this[r][c] -= vec[r]; }
1760 }
1761 
1762 /** Swaps two rows of receiver
1763 * @param {int} r1 index of first row to swap
1764 * @param {int} r2 index of second row to swap
1765 * @example
1766 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1767 * m.swapRows(0,2); // m = Matrix([[31,32,33],[21,22,23],[11,12,13]])
1768 */
1769 Matrix.prototype.swapRows = function(r1,r2) {
1770 	if (r1==r2) { return; }
1771 	if (r1<0 || r1>=this.nRows || r2<0 || r2>=this.nRows) { /*jsmLogger.warn('Matrix.swapRows: wrong coefficients');*/ return; }
1772 	var temp = this[r1];
1773 	this[r1] = this[r2];
1774 	this[r2] = temp;
1775 }
1776 
1777 /** Swaps two columns of receiver
1778 * @param {int} c1 index of first row to swap
1779 * @param {int} c2 index of second row to swap
1780 * @example
1781 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1782 * m.swapCols(0,2); // m = Matrix([[13,12,11],[23,22,21],[33,32,31]])
1783 */
1784 Matrix.prototype.swapCols = function(c1,c2) {
1785 	if (c1==c2) { return; }
1786 	if (c1<0 || c1>=this.nCols || c2<0 || c2>=this.nCols) { /*jsmLogger.warn('Matrix.swapCols: wrong coefficients');*/ return; }
1787 	var temp;
1788 	for (var r=0; r<this.nRows; r++) {
1789 		temp = this[r][c1];
1790 		this[r][c1] = this[r][c2];
1791 		this[r][c2] = temp;
1792 	}
1793 }
1794 
1795 /** Permute rows of receiver according to given coefficients
1796 * @param {[ints]|Vector} coeffs coefficients of row permutation
1797 * @param {bool} [backward=false] if false, receiver's rows is permutated to given coefficients (forward). If true, from given coefficients (backward)
1798 * @example
1799 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1800 * m.permuteRows([1,2,0]); // m = Matrix([[21,22,23],[31,32,33],[11,12,13]])
1801 * m.permuteRows([1,2,0],true); // m = mat([[11,12,13],[21,22,23],[31,32,33]])
1802 */
1803 Matrix.prototype.permuteRows = function(coeffs,backward) {
1804 	var n, r, coeffs;
1805 	if (coeffs.nElements==undefined) { // coeffs == Array
1806 		n = coeffs.length;
1807 		coeffs = coeffs.slice();
1808 	} else { // coeffs == Vector
1809 		n = coeffs.nElements;
1810 		coeffs = coeffs.toArray();
1811 	}
1812 	if (n != this.nRows) { /*jsmLogger.warn('Matrix.permuteRows: wrong argument size');*/ return; }
1813 	for (var r=0; r<n; r++) { if (r<0 || r>=this.nRows) { /*jsmLogger.warn('Matrix.permuteRows: wrong argument values');*/ return; } }
1814 	var backward = backward || false;
1815 	var rr;
1816 	if (backward) {
1817 		for (r=0; r<n; r++) {
1818 			rr = coeffs[r];
1819 			while (rr!=r) {
1820 				this.swapRows(r,rr);
1821 				coeffs[r] = coeffs[rr];
1822 				coeffs[rr] = rr;
1823 				rr = coeffs[r];
1824 			}
1825 		}
1826 	} else {
1827 		for (r=n-1; r>0; r--) {
1828 			rr = coeffs[r];
1829 			this.swapRows(r,rr);
1830 			coeffs[coeffs.indexOf(r)] = rr;
1831 		}
1832 	}
1833 	return;
1834 }
1835 
1836 
1837 /** Returns copy of receiver with rows permutated according to given coefficients
1838 * @param {[ints]|Vector} coeffs coefficients of permutation.
1839 * @param {bool} [backward=false] if false, receiver is permutated to given coefficients (forward). If true, from given coefficients (backward)
1840 * @returns {Matrix} copy of receiver with permutated rows
1841 * @example
1842 * m1 = mat([[11,12,13],[21,22,23],[31,32,33]]);
1843 * m2 = m1.rowPermutation([1,2,0]); // m2 = Matrix([[21,22,23],[31,32,33],[11,12,13]])
1844 * m3 = m1.rowPermutation([1,2,0],true); // m3 = mat([[31,32,33],[11,12,13],[21,22,23]])
1845 */
1846 Matrix.prototype.rowPermutation = function(coeffs,backward) {
1847 	var r, c, n = coeffs.nElements==undefined? coeffs.length : coeffs.nElements;
1848 	if (n != this.nRows) { /*jsmLogger.warn('Matrix.rowPermutation: wrong argument size');*/ return null; }
1849 	for (var r=0; r<n; r++) { if (r<0 || r>=this.nRows) { /*jsmLogger.warn('Matrix.rowPermutation: wrong argument values');*/ return; } }
1850 	var ret = new Matrix();
1851 	if (backward) {
1852 		for (r=0; r<this.nRows; r++) { ret[r] = {}; }
1853 		for (r=0; r<this.nRows; r++) {
1854 			for (c=0; c<this.nCols; c++) {
1855 				ret[coeffs[r]][c] = this[r][c];
1856 			}
1857 		}
1858 	} else {
1859 		for (r=0; r<this.nRows; r++) {
1860 			ret[r] = {};
1861 			for (c=0; c<this.nCols; c++) {
1862 				ret[r][c] = this[coeffs[r]][c];
1863 			}
1864 		}
1865 	}
1866 	ret.nRows = this.nRows;
1867 	ret.nCols = this.nCols;
1868 	return ret;
1869 }
1870 
1871 /** Returns receiver multiplied by float f ( ret = this * f )
1872 * @param {float} f float multiplier
1873 * @returns {Matrix} copy of receiver multiplied by f
1874 * @example
1875 * m1 = mat([[1,2,3],[4,5,6]]);
1876 * m2 = m1.mulf(3); // m2 = Matrix([[3,6,9],[12,15,18]])
1877 */
1878 Matrix.prototype.mulf = function(f) {
1879 	var ret = new Matrix(), r, c, nr = this.nRows, nc = this.nCols;
1880 	for (r=0; r<nr; r++) {
1881 		ret[r] = {};
1882 		for (c=0; c<nc; c++) {
1883 			ret[r][c] = f*this[r][c];
1884 		}
1885 	}
1886 	ret.nRows = nr;
1887 	ret.nCols = nc;
1888 	return ret;
1889 }
1890 
1891 /** Multiply receiver by float f ( this *= f )
1892 * @param {float} f float multiplier
1893 * @example
1894 * m = mat([[1,2,3],[4,5,6]]);
1895 * m.imulf(3); // m = Matrix([[3,6,9],[12,15,18]])
1896 */
1897 Matrix.prototype.imulf = function(f) {
1898 	for (var r=0; r<this.nRows; r++) {
1899 		for (var c=0; c<this.nCols; c++) { this[r][c] *= f; }
1900 	}
1901 }
1902 
1903 /** Returns product of receiver and given vector ( ret = this * vec )
1904 * @param {Vector} vec vector to multiply
1905 * @returns {Vector} copy of receiver multiplied by vec
1906 * @example
1907 * m = mat([[11,12,13],[21,22,23],[31,32,33]]);
1908 * v1 = vec([1,2,3]);
1909 * v2 = m.mulv(v1); // v2 = Vector([74,134,194])
1910 */
1911 Matrix.prototype.mulv = function(vec) {
1912 	if (!this.canMultiplyVec(vec)) { /*jsmLogger.warn('Matrix.mulv: dimensions mismatched');*/ return null; }
1913 	var ret = new Vector();
1914 	var temp;
1915 	for (var r=0; r<this.nRows; r++) {
1916 		temp = 0.;
1917 		for (var c=0; c<this.nCols; c++) {
1918 			temp += this[r][c]*vec[c]
1919 		}
1920 		ret[r] = temp;
1921 	}
1922 	ret.nElements = this.nRows
1923 	return ret;
1924 }
1925 
1926 /** Returns product of receiver and given matrix ( ret = this * mat )
1927 * @param {Matrix} mat matrix to multiply
1928 * @returns {Matrix} copy of receiver multiplied by mat
1929 * @example
1930 * m1 = mat([[11,12],[21,22]]);
1931 * m2 = mat([[1,2],[3,4]]);
1932 * m3 = m1.mulm(m2); // m3 = Matrix([[47,70],[87,130]])
1933 */
1934 Matrix.prototype.mulm = function(mat) {
1935 	if (!this.canMultiplyMat(mat)) { /*jsmLogger.warn('Matrix.mulm: dimensions mismatched');*/ return null; }
1936 	var ret = new Matrix(), r, c, k;
1937 	var temp;
1938 	for (r=0; r<this.nRows; r++) {
1939 		ret[r] = {};
1940 		for (c=0; c<mat.nCols; c++) {
1941 			temp = 0.;
1942 			for (k=0; k<this.nCols; k++) {
1943 				temp += this[r][k]*mat[k][c];
1944 			}
1945 			ret[r][c] = temp;
1946 		}
1947 	}
1948 	ret.nRows = this.nRows;
1949 	ret.nCols = mat.nCols;
1950 	return ret;
1951 }
1952 
1953 /** Returns product of receiver and given multiplier (Matrix, Vector or float)
1954 * @param {Matrix|Vector|float} what matrix, vector or float to multiply
1955 * @returns {Matrix|Vector} copy of receiver multiplied by what
1956 * @example
1957 * m1 = mat([[1,2,3],[4,5,6]]);
1958 * m2 = m1.mul(3); // m2 = Matrix([[3,6,9],[12,15,18]])
1959 * //
1960 * m3 = mat([[11,12,13],[21,22,23],[31,32,33]]);
1961 * v1 = vec([1,2,3]);
1962 * v2 = m3.mul(v1) // v2 = Vector([74,134,194]);
1963 * //
1964 * m4 = mat([[11,12],[21,22]]);
1965 * m5 = mat([[1,2],[3,4]]);
1966 * m6 = m4.mul(m5); // m6 = Matrix([[47,70],[87,130]])
1967 */
1968 Matrix.prototype.mul = function(what) {
1969 	if (what instanceof Vector) { return this.mulv(what); }
1970 	if (what instanceof Matrix) { return this.mulm(what); }
1971 	if ((typeof what).toLowerCase() == 'number') { return this.mulf(what); }
1972 	/*jsmLogger.warn('Matrix.mul: wrong argument');*/
1973 	return null;
1974 }
1975 
1976 /** Alias for mul(), see {@link Matrix#mul}
1977 * @function
1978 */
1979 Matrix.prototype.x = Matrix.prototype.mul;
1980 
1981 /** Modifies receiver to become dyadic product of two vectors (this = vec1*vec2^T ). Receiver's size is adjusted
1982 * @param {Vector} vec1 1st vector of product
1983 * @param {Vector} vec2 2nd vector of product
1984 * @example
1985 * m = mat([[4],[5]]);
1986 * v1 = vec([1,2,3]);
1987 * v2 = vec([4,5,6]);
1988 * m.beDyadicProductOf(v1,v2); // m = Matrix([[4,5,6],[8,10,12],[12,15,18]])
1989 */
1990 Matrix.prototype.beDyadicProductOf = function(vec1,vec2) {
1991 	var r, c, nr = vec1.nElements, nc = vec2.nElements;
1992 	for (r=0; r<nr; r++) {
1993 		if (r >= this.nRows) { this[r] = {}; }
1994 		for (c=0; c<nc; c++) { this[r][c] = vec1[r]*vec2[c]; }
1995 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
1996 	}
1997 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
1998 	this.nRows = nr;
1999 	this.nCols = nc;
2000 }
2001 
2002 /** Modifies receiver to become product of two matrices (this = mat1*mat2 ). Receiver's size is adjusted
2003 * @param {Matrix} mat1 1st matrix of product
2004 * @param {Matrix} mat2 2nd matrix of product
2005 * @example
2006 * m1 = mat([[1],[2]]);
2007 * m2 = mat([[11,12],[21,22]]);
2008 * m3 = mat([[1,2],[3,4]]);
2009 * m1.beProductOf(m2,m3); // m1 = Matrix([[47,70],[87,130]])
2010 */
2011 Matrix.prototype.beProductOf = function(mat1,mat2) {
2012 	if (!mat1.canMultiplyMat(mat2)) { /*jsmLogger.warn('Matrix.beProductOf: dimensions mismatched');*/ return; }
2013 	var r, c, k, temp, nr = mat1.nRows; nc = mat2.nCols;
2014 	for (r=0; r<nr; r++) {
2015 		if (r >= this.nRows) { this[r] = {}; }
2016 		for (c=0; c<nc; c++) {
2017 			temp = 0.;
2018 			for (k=0; k<mat1.nCols; k++) { temp += mat1[r][k]*mat2[k][c]; }
2019 			this[r][c] = temp;
2020 		}
2021 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2022 	}
2023 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2024 	this.nRows = nr;
2025 	this.nCols = nc;
2026 }
2027 
2028 /** Modifies receiver to become product of two matrices (this = mat1^T*mat2 )
2029 * @param {Vector} mat1 1st matrix of product
2030 * @param {Vector} mat2 2nd matrix of product
2031 * @example
2032 * m1 = mat([[1],[2]]);
2033 * m2 = mat([[11,21],[12,22]]);
2034 * m3 = mat([[1,2],[3,4]]);
2035 * m1.beTProductOf(m2,m3); // m1 = Matrix([[47,70],[87,130]])
2036 */
2037 Matrix.prototype.beTProductOf = function(mat1,mat2) {
2038 	var r, c, k, temp, nr = mat1.nCols; nc = mat2.nCols;
2039 	if (mat1.nRows != mat2.nRows) { /*jsmLogger.warn('Matrix.beTProductOf: dimensions mismatched');*/ return; }
2040 	for (r=0; r<nr; r++) {
2041 		if (r >= this.nRows) { this[r] = {}; }
2042 		for (c=0; c<nc; c++) {
2043 			temp = 0.;
2044 			for (k=0; k<mat1.nRows; k++) { temp += mat1[k][r]*mat2[k][c]; }
2045 			this[r][c] = temp;
2046 		}
2047 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2048 	}
2049 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2050 	this.nRows = nr;
2051 	this.nCols = nc;
2052 }
2053 
2054 /** Modifies receiver to become product of two matrices (this = mat1*mat2^T )
2055 * @param {Vector} mat1 1st matrix of product
2056 * @param {Vector} mat2 2nd matrix of product
2057 * @example
2058 * m1 = mat([[1],[2]]);
2059 * m2 = mat([[11,12],[21,22]]);
2060 * m3 = mat([[1,3],[2,4]]);
2061 * m1.beProductTOf(m2,m3); // m1 = Matrix([[47,70],[87,130]])
2062 */
2063 Matrix.prototype.beProductTOf = function(mat1,mat2) {
2064 	var r, c, k, temp, nr = mat1.nRows; nc = mat2.nRows;
2065 	if (mat1.nCols != mat2.nCols) { /*jsmLogger.warn('Matrix.beProductTOf: dimensions mismatched');*/ return; }
2066 	for (r=0; r<nr; r++) {
2067 		if (r >= this.nRows) { this[r] = {}; }
2068 		for (c=0; c<nc; c++) {
2069 			temp = 0.;
2070 			for (k=0; k<mat1.nCols; k++) { temp += mat1[r][k]*mat2[c][k]; }
2071 			this[r][c] = temp;
2072 		}
2073 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2074 	}
2075 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2076 	this.nRows = nr;
2077 	this.nCols = nc;
2078 }
2079 
2080 /** Modifies receiver to become product of two matrices (this = mat1^T*mat2^T )
2081 * @param {Vector} mat1 1st matrix of product
2082 * @param {Vector} mat2 2nd matrix of product
2083 * @example
2084 * m1 = mat([[1],[2]]);
2085 * m2 = mat([[11,21],[12,22]]);
2086 * m3 = mat([[1,3],[2,4]]);
2087 * m1.beTProductTOf(m2,m3); // m1 = Matrix([[47,70],[87,130]])
2088 */
2089 Matrix.prototype.beTProductTOf = function(mat1,mat2) {
2090 	var r, c, k, temp, nr = mat1.nRows; nc = mat2.nCols;
2091 	if (mat1.nCols != mat2.nCols) { /*jsmLogger.warn('Matrix.beTProductTOf: dimensions mismatched');*/ return; }
2092 	for (r=0; r<nr; r++) {
2093 		if (r >= this.nRows) { this[r] = {}; }
2094 		for (c=0; c<nc; c++) {
2095 			temp = 0.;
2096 			for (k=0; k<mat1.nRows; k++) { temp += mat1[k][r]*mat2[c][k]; }
2097 			this[r][c] = temp;
2098 		}
2099 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2100 	}
2101 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2102 	this.nRows = nr;
2103 	this.nCols = nc;
2104 }
2105 
2106 /** Returns transposition of receiver ( ret = this^T )
2107 * @returns {Matrix} transposed copy of receiver
2108 * @example
2109 * m1 = mat([[1,2,3],[4,5,6]]);
2110 * m2 = m1.transposed(); // m2 = Matrix([[1,4],[2,5],[3,6]])
2111 */
2112 Matrix.prototype.transposed = function() {
2113 	var ret = new Matrix(this.nCols,this.nRows);
2114 	for (var r=0; r<this.nCols; r++) {
2115 		ret[r] = {};
2116 		for (var c=0; c<this.nRows; c++) {
2117 			ret[r][c] = this[c][r];
2118 		}
2119 	}
2120 	return ret;
2121 }
2122 
2123 /** Alias for transposed(), see {@link Matrix#transposed}
2124 * @function
2125 */
2126 Matrix.prototype.T = Matrix.prototype.transposed;
2127 
2128 /** Modifies receiver to become transposition of itself ( this = this^T )
2129 * @example
2130 * m = mat([[1,2,3],[4,5,6]]);
2131 * m.transpose(); // m = Matrix([[1,4],[2,5],[3,6]])
2132 * m.transpose(); // m = Matrix([[1,2,3],[4,5,6]])
2133 */
2134 Matrix.prototype.transpose = function() {
2135 	var temp, r, c, nr = this.nRows, nc = this.nCols, n=Math.min(nr,nc);
2136 	for (r=0; r<n; r++) {
2137 		for (c=r+1; c<n; c++) {
2138 			temp = this[r][c];
2139 			this[r][c] = this[c][r];
2140 			this[c][r] = temp;
2141 		}
2142 	}
2143 	if (nr>nc) {
2144 		for (r=nc; r<nr; r++) {
2145 			for (c=0; c<nc; c++) {
2146 				this[c][r] = this[r][c];
2147 			}
2148 			delete this[r];
2149 		}
2150 	} else if (nr<nc) {
2151 		for (c=nr; c<nc; c++) {
2152 			this[c] = {};
2153 			for (r=0; r<nr; r++) {
2154 				this[c][r] = this[r][c];
2155 				delete this[r][c];
2156 			}
2157 		}
2158 	}
2159 	this.nRows = nc;
2160 	this.nCols = nr;
2161 }
2162 
2163 /** Modifies receiver to become transposition of given matrix (this = mat^T ). Receiver's size is adjusted
2164 * @param {Matrix} mat matrix of transposition
2165 * @example
2166 * m1 = mat([[4],[5]]);
2167 * m2 = mat([[1,2,3],[4,5,6]]);
2168 * m1.beTranspositionOf(m2) // m1 = mat([[1,4],[2,5],[3,6]])
2169 */
2170 Matrix.prototype.beTranspositionOf = function(mat) {
2171 	var r, c, nr = mat.nCols, nc = mat.nRows;
2172 	for (r=0; r<nr; r++) {
2173 		if (r >= this.nRows) { this[r] = {}; }
2174 		for (c=0; c<nc; c++) { this[r][c] = mat[c][r]; }
2175 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2176 	}
2177 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2178 	this.nRows = nr;
2179 	this.nCols = nc;
2180 }
2181 
2182 /** Symmetrize receiver ( this = .5*(this+this^T) ). Receiver must be square
2183 * @example
2184 * m = mat([[1,2,3],[0,-1,5],[-1,1,7]])
2185 * m.symmetrize(); // m = Matrix([[1,1,1],[1,-1,3],[1,3,7]])
2186 */
2187 Matrix.prototype.symmetrize = function() {
2188 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.symmetrize: matrix is not square');*/ return; }
2189 	var r, c, temp, n = this.nRows;
2190 	for (r=0; r<n-1; r++) {
2191 		for (c=r+1; c<n; c++) {
2192 			temp = .5*(this[r][c]+this[c][r]);
2193 			this[r][c] = temp;
2194 			this[c][r] = temp;
2195 		}
2196 	}
2197 }
2198 
2199 /** Returns symmetric part of receiver ( ret = .5*(this+this^T) ). Receiver must be square
2200 * @example
2201 * m1 = mat([[1,2,3],[0,-1,5],[-1,1,7]])
2202 * m2 = m1.symmetrized(); // m2 = Matrix([[1,1,1],[1,-1,3],[1,3,7]])
2203 */
2204 Matrix.prototype.symmetrized = function() {
2205 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.symmetrized: matrix is not square');*/ return null; }
2206 	ret = new Matrix();
2207 	var r, c, temp, n = this.nRows;
2208 	for (r=0; r<n; r++) { ret[r] = {}; }
2209 	for (r=0; r<n; r++) { ret[r][r] = this[r][r]; }
2210 	for (r=0; r<n-1; r++) {
2211 		for (c=r+1; c<n; c++) {
2212 			temp = .5*(this[r][c]+this[c][r]);
2213 			ret[r][c] = temp;
2214 			ret[c][r] = temp;
2215 		}
2216 	}
2217 	ret.nRows = n;
2218 	ret.nCols = n;
2219 	return ret;
2220 }
2221 
2222 /** Alias for symmetrized(), see {@link Matrix#symmetrized}
2223 * @function
2224 */
2225 Matrix.prototype.giveSymmetricPart = Matrix.prototype.symmetrized;
2226 
2227 /** Modifies receiver to become symmetric part of given matrix (this = .5*(mat+mat^T) ). mat has to be square
2228 * @param {Matrix} mat given matrix. Receiver's size is adjusted
2229 * @example
2230 * m1 = mat([[1],[3]]);
2231 * m2 = mat([[1,2,3],[0,-1,5],[-1,1,7]])
2232 * m1.beSymmetricPartOf(m2); // m1 = Matrix([[1,1,1],[1,-1,3],[1,3,7]])
2233 */
2234 Matrix.prototype.beSymmetricPartOf = function(mat) {
2235 	if (!mat.isSquare()) { /*jsmLogger.warn('Matrix.beSymmetricPartOf: argument matrix is not square');*/ return; }
2236 	var r, c, temp, n = mat.nRows;
2237 	for (r=0; r<n; r++) {
2238 		if (r>=this.nRows) { this[r] = {}; }
2239 		this[r][r] = mat[r][r];
2240 	}
2241 	for (r=0; r<n-1; r++) {
2242 		for (c=r+1; c<n; c++) {
2243 			temp = .5*(mat[r][c]+mat[c][r]);
2244 			this[r][c] = temp;
2245 			this[c][r] = temp;
2246 		}
2247 		for (c=n; c<this.nCols; c++) { delete this[r][c]; }
2248 	}
2249 	for (r=n; r<this.nRows; r++) { delete this[r]; }
2250 	this.nRows = n;
2251 	this.nCols = n;
2252 }
2253 
2254 /** Anti-symmetrize receiver ( this = this - .5*(this+this^T) ). Receiver must be square
2255 * @example
2256 * m = mat([[1,2,3],[0,-1,5],[-1,1,7]])
2257 * m.antiSymmetrize(); // m = Matrix([[0,1,2],[-1,0,2],[-2,-2,0]])
2258 */
2259 Matrix.prototype.antiSymmetrize = function() {
2260 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.antiSymmetrize: matrix is not square');*/ return; }
2261 	var r, c, temp, n = this.nRows;
2262 	for (r=0; r<n; r++) { this[r][r] = 0.; }
2263 	for (r=0; r<n; r++) {
2264 		for (c=r+1; c<n; c++) {
2265 			temp = .5*(this[r][c]+this[c][r]);
2266 			this[r][c] -= temp;
2267 			this[c][r] -= temp;
2268 		}
2269 	}
2270 }
2271 
2272 /** Returns anti-symetric part of receiver ( ret = this - .5*(this+this^T) ). Receiver must be square
2273 * @example
2274 * m1 = mat([[1,2,3],[0,-1,5],[-1,1,7]])
2275 * m2 = m1.antiSymmetrized(); // m2 = Matrix([[0,1,2],[-1,0,3],[-2,0,0]])
2276 */
2277 Matrix.prototype.antiSymmetrized = function() {
2278 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.antiSymmetrized: matrix is not square');*/ return null; }
2279 	ret = new Matrix();
2280 	var r, c, temp, n = this.nRows;
2281 	for (r=0; r<n; r++) { ret[r] = {}; }
2282 	for (r=0; r<n; r++) { ret[r][r] = 0.; }
2283 	for (r=0; r<n-1; r++) {
2284 		for (c=r+1; c<n; c++) {
2285 			temp = .5*(this[r][c]+this[c][r]);
2286 			ret[r][c] = this[r][c] - temp;
2287 			ret[c][r] = this[c][r] - temp;
2288 		}
2289 	}
2290 	ret.nRows = n;
2291 	ret.nCols = n;
2292 	return ret;
2293 }
2294 
2295 /** Alias for symetrized(), see {@link Matrix#antiSymmetrized}
2296 * @function
2297 */
2298 Matrix.prototype.giveAntiSymmetricPart = Matrix.prototype.antiSymmetrized;
2299 
2300 /** Modifies receiver to become anti-symmetric part of given matrix (this = mat - .5*(mat+mat^T) ). mat has to be square
2301 * @param {Matrix} mat given matrix
2302 * @example
2303 * m1 = mat([[1],[3]]);
2304 * m2 = mat([[1,2,3],[0,-1,5],[-1,1,7]])
2305 * m1.beAntiSymmetricPartOf(m2); // m1 = Matrix([[0,1,2],[-1,0,3],[-2,0,0]])
2306 */
2307 Matrix.prototype.beAntiSymmetricPartOf = function(mat) {
2308 	if (!mat.isSquare()) { /*jsmLogger.warn('Matrix.beAntiSymmetricPartOf: argument matrix is not square');*/ return; }
2309 	var r, c, temp, n = mat.nRows;
2310 	for (r=0; r<n; r++) {
2311 		if (r>=this.nRows) { this[r] = {}; }
2312 		this[r][r] = 0.;
2313 	}
2314 	for (r=0; r<n; r++) {
2315 		for (c=r+1; c<n; c++) {
2316 			temp = .5*(mat[r][c]+mat[c][r]);
2317 			this[r][c] = mat[r][c] - temp;
2318 			this[c][r] = mat[c][r] - temp;
2319 		}
2320 		for (c=n; c<this.nCols; c++) { delete this[r][c]; }
2321 	}
2322 	for (r=n; r<this.nRows; r++) { delete this[r]; }
2323 	this.nRows = n;
2324 	this.nCols = n;
2325 }
2326 
2327 /** Returns submatrix of receiver ( ret = this[rows][cols] )
2328 * @param {[floats]|Vector} rows array containing rows coefficients of desired submatrix
2329 * @param {[floats]|Vector} cols array containing columns coefficients of desired submatrix
2330 * @returns {Matrix} desired submatrix
2331 * @example
2332 * m1 = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2333 * m2 = m1.getSubMatrix([1,2],[0,2]); // m2 = Matrix([[21,23],[31,33]])
2334 */
2335 Matrix.prototype.getSubMatrix = function(rows,cols) {
2336 	var nr = rows.nElements==undefined? rows.length : rows.nElements;
2337 	var nc = cols.nElements==undefined? cols.length : cols.nElements;
2338 	if (nr>this.nRows || nc>this.nCols) { /*jsmLogger.warn('Matrix.getSubMatrix: wrong argument dimensions');*/ return null; }
2339 	var r,c,rr,cc;
2340 	var ret = new Matrix();
2341 	for (r=0; r<nr; r++) {
2342 		ret[r] = {};
2343 		for (c=0; c<nc; c++) {
2344 			rr = rows[r]; cc = cols[c];
2345 			if (rr<0 || rr>=this.nRows) { /*jsmLogger.warn('Matrix.getSubMatrix: wrong argument values');*/ return null; }
2346 			if (cc<0 || cc>=this.nCols) { /*jsmLogger.warn('Matrix.getSubMatrix: wrong argument values');*/ return null; }
2347 			ret[r][c] = this[rr][cc];
2348 		}
2349 	}
2350 	ret.nRows = nr;
2351 	ret.nCols = nc;
2352 	return ret;
2353 }
2354 
2355 /** Alias for getSubMatrix, see {@link Matrix#getSubMatrix}
2356 * @function
2357 */
2358 Matrix.prototype.getsm = Matrix.prototype.getSubMatrix;
2359 
2360 /** Sets receiver to be submatrix of given matrix ( this = mat[rows][cols] )
2361 * @param {Matrix} mat matrix to get submatrix from
2362 * @param {[floats]|Vector} rows array containing rows coefficients of desired submatrix
2363 * @param {[floats]|Vector} cols array containing columns coefficients of desired submatrix
2364 * @returns {Matrix} desired submatrix
2365 * @example
2366 * m1 = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2367 * m2 = mat([[1],[2]]);
2368 * m2.beSubMatrixOf(m1,[1,2],[0,2]); // m2 = Matrix([[21,23],[31,33]])
2369 */
2370 Matrix.prototype.beSubMatrixOf = function(mat,rows,cols) {
2371 	var nr = rows.nElements==undefined? rows.length : rows.nElements;
2372 	var nc = cols.nElements==undefined? cols.length : cols.nElements;
2373 	if (nr>mat.nRows || nc>mat.nCols) { /*jsmLogger.warn('Matrix.beSubMatrixOf: wrong argument dimensions');*/ return null; }
2374 	var r,c;
2375 	for (r=0; r<n; r++) { if (rows[r]<0 || rows[r]>=mat.nRows) { /*jsmLogger.warn('Matrix.beSubMatrixOf: wrong argument values');*/ return; } }
2376 	for (c=0; c<n; c++) { if (cols[c]<0 || cols[c]>=mat.nCols) { /*jsmLogger.warn('Matrix.beSubMatrixOf: wrong argument values');*/ return; } }
2377 	for (r=0; r<nr; r++) {
2378 		this[r] = {};
2379 		for (c=0; c<nc; c++) { this[r][c] = mat[rows[r]][cols[c]]; }
2380 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2381 	}
2382 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2383 	this.nRows = nr;
2384 	this.nCols = nc;
2385 }
2386 
2387 /** Sets submatrix at defined positions of receiver ( this[rows][cols] = mat )
2388 * @param {[floats]|Vector} rows array containing rows coefficients to be set
2389 * @param {[floats]|Vector} cols array containing columns coefficients to be set
2390 * @param {Matrix} mat matrix to be set on desired positions
2391 * @example
2392 * m = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2393 * m.setSubMatrix([1,2],[0,2],mat([[66,77],[88,99]]));
2394 * // m = Matrix([[11,12,13,14],[66,22,77,24],[88,32,99,34],[41,42,43,44]])
2395 */
2396 Matrix.prototype.setSubMatrix = function(rows,cols,mat) {
2397 	var nr = rows.nElements==undefined? rows.length : rows.nElements;
2398 	var nc = cols.nElements==undefined? cols.length : cols.nElements;
2399 	var mnr = mat.nRows, mnc=mat.nCols;
2400 	if (mnr != nr || mnc != nc) { /*jsmLogger.warn('Matrix.setSubMatrix: wrong argument dimensions');*/ return; }
2401 	if (nr>this.nRows || nc>this.nCols) { /*jsmLogger.warn('Matrix.setSubMatrix: wrong argument dimensions');*/ return; }
2402 	var r,c;
2403 	for (r=0; r<n; r++) { if (rows[r]<0 || rows[r]>=this.nRows) { /*jsmLogger.warn('Matrix.setSubMatrix: wrong argument values');*/ return; } }
2404 	for (c=0; c<n; c++) { if (cols[c]<0 || cols[c]>=this.nCols) { /*jsmLogger.warn('Matrix.setSubMatrix: wrong argument values');*/ return; } }
2405 	for (r=0; r<nr; r++) {
2406 		for (c=0; c<nc; c++) { this[rows[r]][cols[c]] = mat[r][c]; }
2407 	}
2408 }
2409 
2410 /** Alias for setSubMatrix, see {@link Matrix#setSubMatrix}
2411 * @function
2412 */
2413 Matrix.prototype.setsm = Matrix.prototype.setSubMatrix;
2414 
2415 /** Increment submatrix at defined positions of receiver ( this[rows][cols] += mat )
2416 * @param {[floats]|Vector} rows array containing rows coefficients to be incrementes
2417 * @param {[floats]|Vector} cols array containing columns coefficients to be incremented
2418 * @param {Matrix} mat matrix to be incremented on desired positions
2419 * @example
2420 * m = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2421 * m.incrSubMatrix([1,2],[0,2],mat([[66,77],[88,99]]));
2422 * // m = Matrix([11,12,13,14],[87,22,100,24],[119,32,132,34],[41,42,43,44]])
2423 */
2424 Matrix.prototype.incrSubMatrix = function(rows,cols,mat) {
2425 	var nr = rows.nElements==undefined? rows.length : rows.nElements;
2426 	var nc = cols.nElements==undefined? cols.length : cols.nElements;
2427 	var mnr = mat.nRows, mnc=mat.nCols;
2428 	if (mnr != nr || mnc != nc) { /*jsmLogger.warn('Matrix.incrSubMatrix: wrong argument dimensions');*/ return; }
2429 	if (nr>this.nRows || nc>this.nCols) { /*jsmLogger.warn('Matrix.incrSubMatrix: wrong argument dimensions');*/ return; }
2430 	var r,c;
2431 	for (r=0; r<n; r++) { if (rows[r]<0 || rows[r]>=this.nRows) { /*jsmLogger.warn('Matrix.incrSubMatrix: wrong argument values');*/ return; } }
2432 	for (c=0; c<n; c++) { if (cols[c]<0 || cols[c]>=this.nCols) { /*jsmLogger.warn('Matrix.incrSubMatrix: wrong argument values');*/ return; } }
2433 	for (r=0; r<nr; r++) {
2434 		for (c=0; c<nc; c++) { this[rows[r]][cols[c]] += mat[r][c]; }
2435 	}
2436 }
2437 
2438 /** Alias for incrSubMatrix, see {@link Matrix#incrSubMatrix}
2439 * @function
2440 */
2441 Matrix.prototype.incrsm = Matrix.prototype.incrSubMatrix;
2442 
2443 /** Decrement submatrix at defined positions of receiver ( this[rows][cols] -= mat )
2444 * @param {[floats]|Vector} rows array containing rows coefficients to be decrementes
2445 * @param {[floats]|Vector} cols array containing columns coefficients to be decremented
2446 * @param {Matrix} mat matrix to be decremented on desired positions
2447 * @example
2448 * m = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2449 * m.decrSubMatrix([1,2],[0,2],mat([[66,77],[88,99]]));
2450 * // m = Matrix([11,12,13,14],[-45,22,-54,24],[-57,32,-66,34],[41,42,43,44]])
2451 */
2452 Matrix.prototype.decrSubMatrix = function(rows,cols,mat) {
2453 	var nr = rows.nElements==undefined? rows.length : rows.nElements;
2454 	var nc = cols.nElements==undefined? cols.length : cols.nElements;
2455 	var mnr = mat.nRows, mnc=mat.nCols;
2456 	if (mnr != nr || mnc != nc) { /*jsmLogger.warn('Matrix.decrSubMatrix: wrong argument dimensions');*/ return; }
2457 	if (nr>this.nRows || nc>this.nCols) { /*jsmLogger.warn('Matrix.decrSubMatrix: wrong argument dimensions');*/ return; }
2458 	var r,c;
2459 	for (r=0; r<n; r++) { if (rows[r]<0 || rows[r]>=this.nRows) { /*jsmLogger.warn('Matrix.decrSubMatrix: wrong argument values');*/ return; } }
2460 	for (c=0; c<n; c++) { if (cols[c]<0 || cols[c]>=this.nCols) { /*jsmLogger.warn('Matrix.decrSubMatrix: wrong argument values');*/ return; } }
2461 	for (r=0; r<nr; r++) {
2462 		for (c=0; c<nc; c++) { this[rows[r]][cols[c]] -= mat[r][c]; }
2463 	}
2464 }
2465 
2466 /** Alias for decrSubMatrix, see {@link Matrix#decrSubMatrix}
2467 * @function
2468 */
2469 Matrix.prototype.decrsm = Matrix.prototype.decrSubMatrix;
2470 
2471 /** assemble receiver to given matrix ( mat[rows][cols] += this )
2472 * @param {Matrix} mat matrix where receiver is assembled
2473 * @param {[floats]|Vector} rows array containing row coefficients of mat to be incremented
2474 * @param {[floats]|Vector} cols array containing column coefficients of mat to be incremented
2475 * @example
2476 * m1 = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2477 * m2 = mat([[66,77],[88,99]]);
2478 * m2.assemble(m1,[1,2],[0,2]);
2479 * // m1 = Matrix([11,12,13,14],[87,22,100,24],[119,32,132,34],[41,42,43,44]])
2480 */
2481 Matrix.prototype.assemble = function(mat,rows,cols) {
2482 	var nr = rows.nElements==undefined? rows.length : rows.nElements;
2483 	var nc = cols.nElements==undefined? cols.length : cols.nElements;
2484 	var mnr = this.nRows, mnc = this.nCols;
2485 	if (mnr != nr || mnc != nc) { /*jsmLogger.warn('Matrix.assemble: wrong argument dimensions');*/ return; }
2486 	if (nr>mat.nRows || nc>mat.nCols) { /*jsmLogger.warn('Matrix.assemble: wrong argument dimensions');*/ return; }
2487 	var r,c;
2488 	for (r=0; r<nr; r++) { if (rows[r]<0 || rows[r]>=mat.nRows) { /*jsmLogger.warn('Matrix.assemble: wrong argument values');*/ return; } }
2489 	for (c=0; c<nc; c++) { if (cols[c]<0 || cols[c]>=mat.nCols) { /*jsmLogger.warn('Matrix.assemble: wrong argument values');*/ return; } }
2490 	for (r=0; r<nr; r++) {
2491 		for (c=0; c<nc; c++) { mat[rows[r]][cols[c]] += this[r][c]; }
2492 	}
2493 }
2494 
2495 /** Returns copy of receiver
2496 * @returns {Matrix} copy of receiver
2497 * @example
2498 * m1 = mat([[11,12],[21,22]]);
2499 * m2 = m1;
2500 * m3 = m1.copied();
2501 * m1.set(1,0,6);
2502 * // m1 = Matrix([[11,12],[6,22]])
2503 * // m2 = Matrix([[11,12],[6,22]])
2504 * // m3 = Matrix([[11,12],[21,22]])
2505 */
2506 Matrix.prototype.copied = function() {
2507 	var ret = new Matrix();
2508 	for (var r=0; r<this.nRows; r++) {
2509 		ret[r] = {};
2510 		for (var c=0; c<this.nCols; c++) {
2511 			ret[r][c] = this[r][c];
2512 		}
2513 	}
2514 	ret.nRows = this.nRows;
2515 	ret.nCols = this.nCols;
2516 	return ret;
2517 }
2518 
2519 /** Alias for copied(), see {@link Matrix#copied}
2520 * @function
2521 */
2522 Matrix.prototype.copy = Matrix.prototype.copied;
2523 
2524 /** Modifies receiver to become copy of given matrix (this = mat). Receiver's size is adjusted
2525 * @param {Matrix} mat matrix to be copied to receiver
2526 * @example
2527 * m1 = mat([[4],[5]]);
2528 * m2 = mat([[1,2,3],[4,5,6]]);
2529 * m1.beCopyOf(m2); // m1 = Matrix([[1,2,3],[4,5,6]])
2530 */
2531 Matrix.prototype.beCopyOf = function(mat) {
2532 	var r, c, nr = mat.nRows, nc = mat.nCols;
2533 	for (r=0; r<nr; r++) {
2534 		if (r >= this.nRows) { this[r] = {}; }
2535 		for (c=0; c<nc; c++) { this[r][c] = mat[r][c]; }
2536 		for (c=nc; c<this.nCols; c++) { delete this[r][c]; }
2537 	}
2538 	for (r=nr; r<this.nRows; r++) { delete this[r]; }
2539 	this.nRows = nr;
2540 	this.nCols = nc;
2541 }
2542 
2543 /** Returns vector containing receiver's diagonal elements
2544 * @returns {Vector} vector containing receiver's diagonal elements
2545 * @example
2546 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
2547 * v = m.diag(); // v = Vector([1,5,9])
2548 */
2549 Matrix.prototype.diagonalToVector = function() {
2550 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.diagonalToVector: matrix is not square');*/ return null; }
2551 	var ret = new Vector()
2552 	for (var r=0; r<this.nRows; r++) { ret[r] = this[r][r]; }
2553 	ret.nElements = this.nRows;
2554 	return ret;
2555 }
2556 
2557 /** Alias for diagonalToVector(), see {@link Matrix#diagonalToVector}
2558 * @function
2559 */
2560 Matrix.prototype.diag = Matrix.prototype.diagonalToVector;
2561 
2562 /** Returns string representation of receiver
2563 * @returns {string} string representation of receiver
2564 * @example
2565 * m = mat([[1,2,3],[4,5,6],[7,8,9]]);
2566 * s = m.toString(); // s = 'Matrix([[1,2,3],[4,5,6],[7,8,9]])'
2567 */
2568 Matrix.prototype.toString = function() {
2569 	var nr = this.nRows;
2570 	var nc = this.nCols;
2571 	var r,c,val;
2572 	var ret = "Matrix([[ ";
2573 	if (nr == 0) { return ret+"]])"; }
2574 	if (nc == 0) {
2575 		for (r=0; r<nr-1; r++) {
2576 			ret += " [], ";
2577 		}
2578 		return ret + "])";
2579 	}
2580 	for (r=0; r<nr-1; r++) {
2581 		for (c=0; c<nc-1; c++) {
2582 			val = this[r][c];
2583 			//val = (Math.abs(val) < JSM_TOL)? 0. : Math.round(val*JSM_ROUNDFACTOR)/JSM_ROUNDFACTOR;
2584 			ret += val.toExponential(3)+", ";
2585 		}
2586 		val = this[r][nc-1];
2587 		//val = (Math.abs(val) < JSM_TOL)? 0. : Math.round(val*JSM_ROUNDFACTOR)/JSM_ROUNDFACTOR;
2588 		ret += val.toExponential(3)+" ], [ ";
2589 	}
2590 	for (c=0; c<nc-1; c++) {
2591 		val = this[nr-1][c];
2592 		//val = (Math.abs(val) < JSM_TOL)? 0. : Math.round(val*JSM_ROUNDFACTOR)/JSM_ROUNDFACTOR;
2593 		ret += val.toExponential(3)+", ";
2594 	}
2595 	val = this[nr-1][nc-1];
2596 	//val = (Math.abs(val) < JSM_TOL)? 0. : Math.round(val*JSM_ROUNDFACTOR)/JSM_ROUNDFACTOR;
2597 	ret += val.toExponential(3)+" ]])"
2598 	return ret;
2599 }
2600 
2601 /** Resize receiver according to given size (delete extra elements or add zero elements)
2602 * @param {int} nRows new number of rows
2603 * @param {int} nCols new number of columns
2604 * @example
2605 * m1 = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]);
2606 * m2 = mat([[11,12],[21,22]]);
2607 * m1.resize(3,3); // m1 = Matrix([[11,12,13],[21,22,23],[31,32,33]])
2608 * m2.resize(3,3); // m2 = Matrix([[11,12,0],[21,22,0],[0,0,0]])
2609 */
2610 Matrix.prototype.resize = function(nRows,nCols) {
2611 	if (this.nRows < nRows) {
2612 		for (var r=this.nRows; r<nRows; r++) {
2613 			this[r] = {};
2614 			for (var c=0; c<this.nCols; c++) {
2615 				this[r][c] = 0.;
2616 			}
2617 		}
2618 		this.nRows = nRows;
2619 	}
2620 	if (this.nRows > nRows) {
2621 		for (var r=nRows; r<this.nRows; r++) { delete this[r]; }
2622 		this.nRows = nRows;
2623 	}
2624 	if (this.nCols < nCols) {
2625 		for (var r=0; r<this.nRows; r++) {
2626 			for (var c=this.nCols; c<nCols; c++) {
2627 				this[r][c] = 0.;
2628 			}
2629 		}
2630 		this.nCols = nCols;
2631 	}
2632 	if (this.nCols > nCols) {
2633 		for (var r=0; r<this.nRows; r++) {
2634 			for (var c=nCols; c<this.nCols; c++) {
2635 				delete this[r][c];
2636 			}
2637 		}
2638 		this.nCols = nCols;
2639 	}
2640 }
2641 
2642 /** Returns resized copy of receiver according to given size (delete extra elements or add zero elements)
2643 * @param {int} nRows new number of rows
2644 * @param {int} nCols new number of columns
2645 * @returns {Matrix} resized copy of receiver
2646 * @example
2647 * m1 = mat([[11,12,13],[21,22,23],[31,32,33]]);
2648 * m2 = m1.resized(2,4); // m2 = Matrix([[11,12,13,0],[21,22,23,0]])
2649 * m3 = m1.resized(4,2); // m3 = Matrix([[11,12],[21,22],[31,32],[0,0]])
2650 */
2651 Matrix.prototype.resized = function(nRows,nCols) {
2652 	var r, c, ret = new Matrix();
2653 	for (var r=0; r<nRows; r++) { ret[r] = {}; }
2654 	if (nRows<=this.nRows) {
2655 		if (nCols<=this.nCols) {
2656 			for (r=0; r<nRows; r++) {
2657 				for (c=0; c<nCols; c++) { ret[r][c] = this[r][c]; }
2658 			}
2659 		} else {
2660 			for (r=0; r<nRows; r++) {
2661 				for (c=0; c<this.nCols; c++) { ret[r][c] = this[r][c]; }
2662 				for (c=this.nCols; c<nCols; c++) { ret[r][c] = 0.; }
2663 			}
2664 		}
2665 	} else {
2666 		if (nCols<=this.nCols) {
2667 			for (r=0; r<this.nRows; r++) {
2668 				for (c=0; c<nCols; c++) { ret[r][c] = this[r][c]; }
2669 			}
2670 			for (r=this.nRows; r<nRows; r++) {
2671 				for (c=0; c<nCols; c++) { ret[r][c] = 0.; }
2672 			}
2673 		} else {
2674 			for (r=0; r<this.nRows; r++) {
2675 				for (c=0; c<this.nRows; c++) { ret[r][c] = this[r][c]; }
2676 				for (c=this.nCols; c<nCols; c++) { ret[r][c] = 0.; }
2677 			}
2678 			for (r=this.nRows; r<nRows; r++) {
2679 				for (c=0; c<nCols; c++) { ret[r][c] = 0.; }
2680 			}
2681 		}
2682 	}
2683 	ret.nRows = nRows;
2684 	ret.nCols = nCols;
2685 	return ret;
2686 }
2687 
2688 /** Appends vector(s)/matrix(s) as row(s) to receiver
2689 * @param {Vector|Matrix|[Vectors]|[Matrices]} rows new row(s) to be appended
2690 * @example
2691 * m = mat([[1,2],[3,4]]);
2692 * m.appendRows(vec([7,6]));
2693 * // m = Matrix([[1,2],[3,4],[7,6]])
2694 * m.appendRows(mat([[1,3],[2,4]]));
2695 * // m = Matrix([[1,2],[3,4],[7,6],[1,3],[2,4]])
2696 * m = mat([[1,2],[3,4]]);
2697 * m.appendRows([vec([2,1]),vec([33,44])]);
2698 * // m = Matrix([[1,2],[3,4],[2,1],[33,44]])
2699 * m = mat([[1,2],[3,4]]);
2700 * m.appendRows([mat([[11,12],[21,22]]),mat([[5,6],[7,8]])]);
2701 * // m = Matrix([[1,2],[3,4],[11,12],[21,22],[5,6],[7,8]])
2702 */
2703 Matrix.prototype.appendRows = function(rows) {
2704 	if (rows instanceof Vector) {
2705 		if (rows.nElements != this.nCols) { /*jsmLogger.warn('Matrix.appendRows: wrong argument dimensions');*/ return; }
2706 		this[this.nRows] = {};
2707 		for (var c=0; c<this.nCols; c++) { this[this.nRows][c] = rows[c]; }
2708 		this.nRows++;
2709 		return;
2710 	}
2711 	if (rows instanceof Matrix) {
2712 		if (rows.nCols != this.nCols) { /*jsmLogger.warn('Matrix.appendRows: wrong argument dimensions');*/ return; }
2713 		for (var r=0; r<rows.nRows; r++) {
2714 			this[this.nRows] = {};
2715 			for (var c=0; c<this.nCols; c++) { this[this.nRows][c] = rows[r][c]; }
2716 			this.nRows++;
2717 		}
2718 		return;
2719 	}
2720 	if (rows instanceof Array) {
2721 		for (var i=0; i<rows.length; i++) {
2722 			this.appendRows(rows[i]);
2723 		}
2724 	}
2725 }
2726 
2727 /** Appends vector(s)/matrix(s) as column(s) to receiver
2728 * @param {Vector|Matrix|[Vectors]|[Matrices]} cols new row(s) to be appended
2729 * @example
2730 * m = mat([[1,2],[3,4]]);
2731 * m.appendCols(vec([7,6]));
2732 * // m = Matrix([[1,2,7],[3,4,6]])
2733 * m.appendCols(mat([[1,3],[2,4]]));
2734 * // m = Matrix([[1,2,7,1,3],[3,4,6,2,4]])
2735 * m = mat([[1,2],[3,4]]);
2736 * m.appendCols([vec([2,1]),vec([33,44])]);
2737 * // m = Matrix([[1,2,2,33],[3,4,1,44]])
2738 * m = mat([[1,2],[3,4]]);
2739 * m.appendCols([mat([[11,12],[21,22]]),mat([[9,8],[7,6]])]);
2740 * // m = Matrix([[1,2,11,12,9,8],[3,4,21,22,7,6]])
2741 */
2742 Matrix.prototype.appendCols = function(cols) {
2743 	if (cols instanceof Vector) {
2744 		if (cols.nElements != this.nRows) { /*jsmLogger.warn('Matrix.appendCols: wrong argument dimensions');*/ return; }
2745 		for (var r=0; r<this.nRows; r++) { this[r][this.nCols] = cols[r]; }
2746 		this.nCols++;
2747 		return;
2748 	}
2749 	if (cols instanceof Matrix) {
2750 		if (cols.nRows != this.nRows) { /*jsmLogger.warn('Matrix.appendCols: wrong argument dimensions');*/ return; }
2751 		for (var r=0; r<this.nRows; r++) {
2752 			for (var c=0; c<cols.nCols; c++) { this[r][this.nCols+c] = cols[r][c]; }
2753 		}
2754 		this.nCols += cols.nCols;
2755 		return;
2756 	}
2757 	if (cols instanceof Array) {
2758 		for (var i=0; i<cols.length; i++) {
2759 			this.appendCols(cols[i]);
2760 		}
2761 	}
2762 }
2763 
2764 /** Testing matrix equality
2765 * @param {Matrix} mat matrix to be compared with receiver
2766 * @returns {bool} true if this==mat, false otherwise
2767 * @example
2768 * a = mat([[1,2,3],[4,5,6],[7,8,9]]);
2769 * b = mat([[1,2,2.999999999],[4.0000000000002,5,6],[7,8,8.9999999999]]);
2770 * c = mat([[1,2,3],[4,5,6],[7,8,9],[10,11,12]]);
2771 * t1 = a.isEqualTo(b); // t1 = true
2772 * t2 = a.isEqualTo(c); // t2 = false
2773 */
2774 Matrix.prototype.isEqualTo = function(mat) {
2775 	if (!this.isSameSizeAs(mat)) { return false; }
2776 	for (var r=0; r<this.nRows; r++) {
2777 		for (var c=0; c<this.nCols; c++) {
2778 			if (Math.abs(this[r][c] - mat[r][c]) > JSM_TOL) { return false; }
2779 		}
2780 	}
2781 	return true;
2782 }
2783 
2784 /** Testing matrix size equality
2785 * @param {Matrix} mat matrix to be tested
2786 * @returns {bool} true if mat and receiver has same size, false otherwise
2787 * @example
2788 * a = mat([[1,2,3],[4,5,6]]);
2789 * b = mat([[5,6,7],[8,9,10],[11,12,13]]);
2790 * c = mat([[14,15,16],[17,18,19]]);
2791 * t1 = a.isSameSizeAs(b); // t1 = false
2792 * t2 = a.isSameSizeAs(c); // t2 = true
2793 */
2794 Matrix.prototype.isSameSizeAs = function(mat) {
2795 	return (this.nRows==mat.nRows && this.nCols==mat.nCols);
2796 }
2797 
2798 /** Testing if receiver can multiply given matrix ( this * mat )
2799 * @param {Matrix} mat matrix to be tested
2800 * @returns {bool} true if the multiplication is possible, false otherwise
2801 * @example
2802 * m1 = mat([[1,2,3],[4,5,6]]);
2803 * m2 = mat([[7,8,9],[10,11,12]]);
2804 * m3 = mat([[11,12],[21,22],[31,32]]);
2805 * t1 = m1.canMultiplyMat(m2); // t1 = false
2806 * t2 = m1.canMultiplyMat(m3); // t2 = true
2807 */
2808 Matrix.prototype.canMultiplyMat = function(mat) {
2809 	return (this.nCols==mat.nRows);
2810 }
2811 
2812 /** Testing if receiver can multiply given vector ( this * vec )
2813 * @param {Vector} vec vector to be tested
2814 * @returns {bool} true if the multiplication is possible, false otherwise
2815 * @example
2816 * m = mat([[1,2,3],[4,5,6]]);
2817 * v1 = vec([1,2,3]);
2818 * v2 = vec([4,5]);
2819 * t1 = m.canMultiplyVec(v1); // t1 = true
2820 * t2 = m.canMultiplyVec(v2); // t2 = false
2821 */
2822 Matrix.prototype.canMultiplyVec = function(vec) {
2823 	return (this.nCols==vec.nElements);
2824 }
2825 
2826 /** Testing if receiver is square
2827 * @returns {bool} true if receiver is square matrix, false otherwise
2828 * @example
2829 * m1 = mat([[1,2,3],[4,5,6]]);
2830 * m2 = mat([[1,2,3],[4,5,6],[7,8,9]]);
2831 * t1 = m1.isSquare(); // t1 = false
2832 * t2 = m2.isSquare(); // t2 = true
2833 */
2834 Matrix.prototype.isSquare = function() {
2835 	return (this.nRows==this.nCols);
2836 }
2837 
2838 /** Testing if receiver is symmetric
2839 * @returns {bool} true if receiver is symmetric, false otherwise
2840 * @example
2841 * m1 = mat([[11,12,13],[21,22,23],[31,32,33]]);
2842 * m2 = mat([[11,12,13],[12,22,23],[13,23,33]]);
2843 * t1 = m1.isSymmetric(); // t1 = false
2844 * t2 = m2.isSymmetric(); // t2 = true
2845 */
2846 Matrix.prototype.isSymmetric = function() {
2847 	if (!this.isSquare()) { return false; }
2848 	for (var r=0; r<this.nRows; r++) {
2849 		for (var c=r+1; c<this.nCols; c++) {
2850 			if (Math.abs(this[r][c] - this[c][r]) > JSM_TOL) { return false; }
2851 		}
2852 	}
2853 	return true;
2854 }
2855 
2856 /** Testing if receiver is transposition of given matrix
2857 * @param {Matrix} mat given matrix
2858 * @returns {bool} true if this==mat^T, false otherwise
2859 * @example
2860 * m1 = mat([[1,2,3],[4,5,6]]);
2861 * m2 = mat([[1,4],[2,5],[3,6]]);
2862 * m3 = mat([[1,2],[4,5]]);
2863 * b1 = m1.isTranspositionOf(m2); // b1 = true
2864 * b2 = m1.isTranspositionOf(m3); // b2 = false
2865 */
2866 Matrix.prototype.isTranspositionOf = function(mat) {
2867 	if (this.nRows!=mat.nCols || this.nCols!=mat.nRows) { return false; }
2868 	var r,c;
2869 	for (r=0; r<this.nRows; r++) {
2870 		for (c=0; c<this.nCols; c++) {
2871 			if (Math.abs(this[r][c]-mat[c][r]) > JSM_TOL) { return false; }
2872 		}
2873 	}
2874 	return true;
2875 }
2876 
2877 /** Testing if receiver is lower triangular matrix
2878 * @returns {bool} true if receiver is lower triangular, false otherwise
2879 * @example
2880 * m1 = mat([[1,2,3],[4,5,6],[7,8,9]]);
2881 * m2 = mat([[1,0,0],[4,5,0],[7,8,9]]);
2882 * t1 = m1.isLowerTriangular(); // t1 = false
2883 * t2 = m2.isLowerTriangular(); // t2 = true
2884 */
2885 Matrix.prototype.isLowerTriangular = function() {
2886 	for (var r=0; r<this.nRows; r++) {
2887 		for (var c=r+1; c<this.nCols; c++) {
2888 			if (Math.abs(this[r][c]) > JSM_TOL) { return false; }
2889 		}
2890 	}
2891 	return true;
2892 }
2893 
2894 /** Testing if receiver is upper triangular matrix
2895 * @returns {bool} true if receiver is upper triangular, false otherwise
2896 * @example
2897 * m1 = mat([[1,2,3],[4,5,6],[7,8,9]]);
2898 * m2 = mat([[1,2,3],[0,5,6],[0,0,9]]);
2899 * t1 = m1.isUpperTriangular(); // t1 = false
2900 * t2 = m2.isUpperTriangular(); // t2 = true
2901 */
2902 Matrix.prototype.isUpperTriangular = function() {
2903 	for (var r=0; r<this.nRows; r++) {
2904 		for (var c=0; c<r; c++) {
2905 			if (Math.abs(this[r][c]) > JSM_TOL) { return false; }
2906 		}
2907 	}
2908 	return true;
2909 }
2910 
2911 /** Test receiver's singularity
2912 * @returns {bool} true if receiver is singular (if abs(this.det()) < JSM_TOL), false otherwise
2913 * @example
2914 * a = mat([[1,2,3],[2,4,6],[4,5,6]]);
2915 * b = mat([[4,2,1],[2,5,3],[1,3,6]]);
2916 * s1 = a.isSingular(); // s1 = true
2917 * s2 = b.isSingular(); // s2 = false
2918 */
2919 Matrix.prototype.isSingular = function() {
2920 	var d = this.determinant();
2921 	// matrix is singular <=> det(matrix)==0
2922 	return isNaN(d)? true : (Math.abs(d) < JSM_TOL);
2923 }
2924 
2925 /** Test if receiver is identity matrix
2926 * @returns {bool} true if receiver is identity, false otherwise
2927 * @example
2928 * m1 = mat([[1,0,0],[0,1,0],[0,0,-1]]);
2929 * m2 = mat([[1,0,0],[0,1,0],[0,0,1]]);
2930 * i1 = m1.isIdentity() // i1 = false
2931 * i2 = m2.isIdentity() // i2 = true
2932 */
2933 Matrix.prototype.isIdentity = function() {
2934 	if (!this.isSquare()) { return false; }
2935 	var r, c;
2936 	for (var r=0; r<this.nRows; r++) {
2937 		if (Math.abs(this[r][r]-1.) > JSM_TOL) { return false; }
2938 	}
2939 	for (var r=1; r<this.nRows; r++) {
2940 		for (var c=r+1; c<this.nCols; c++) {
2941 			if (Math.abs(this[r][c]) > JSM_TOL) { return false; }
2942 			if (Math.abs(this[c][r]) > JSM_TOL) { return false; }
2943 		}
2944 	}
2945 	return true;
2946 }
2947 
2948 /** Alias for isIdentity, see {@link Matrix#isIdentity}
2949 * @function
2950 */
2951 Matrix.prototype.isUnitMatrix = Matrix.prototype.isIdentity;
2952 
2953 /** Test if receiver is zero matrix (full of zeroes)
2954 * @returns {bool} true if receiver is zero, false otherwise
2955 * @example
2956 * m1 = mat([[0,0,0],[0,1e-16,0],[0,0,0]]);
2957 * m2 = mat([[1,0,0],[0,1,0],[0,0,1]]);
2958 * i1 = m1.isZero() // i1 = true
2959 * i2 = m2.isZero() // i2 = false
2960 */
2961 Matrix.prototype.isZero = function() {
2962 	for (var i=0; i<this.nRows; i++) {
2963 		for (var j=0; j<this.nCols; j++) {
2964 			if (Math.abs(this[i][j]) > JSM_TOL) { return false; }
2965 		}
2966 	}
2967 	return true;
2968 }
2969 
2970 /** Alias for isZero(), see {@link Matrix#isZero}
2971 * @function
2972 */
2973 Matrix.prototype.containsOnlyZeros = Matrix.prototype.isZero;
2974 
2975 /** Test if receiver is matrix full of ones
2976 * @returns {bool} true if receiver is full of ones, false otherwise
2977 * @example
2978 * m1 = mat([[1,1,1],[1,.999999999999,1],[1,1,1]]);
2979 * m2 = mat([[1,0,0],[0,1,0],[0,0,1]]);
2980 * i1 = m1.isOne() // i1 = true
2981 * i2 = m2.isOne() // i2 = false
2982 */
2983 Matrix.prototype.isOne = function() {
2984 	for (var r=0; r<this.nRows; r++) {
2985 		for (var c=0; c<this.nCols; c++) {
2986 			if (Math.abs(this[r][c]-1.) > 2*JSM_TOL) { return false; }
2987 		}
2988 	}
2989 	return true;
2990 }
2991 
2992 /** Alias for isOne(), see {@link Matrix#isOne}
2993 * @function
2994 */
2995 Matrix.prototype.containsOnlyOnes = Matrix.prototype.isOne;
2996 
2997 /** Tests receiver's orthogonality (i.e. this*this^T = I => this^-1 = this^T)
2998 * @returns {bool} true if receiver is orthogonal, false otherwise
2999 * @example
3000 * m1 = Matrix.Householder(vec([0,1,0]))
3001 * // m1 = Matrix([[1,0,0],[0,-1,0],[0,0,1]]);
3002 * m2 = mat([[0,0,1],[1,0,0],[0,1,0]])
3003 * m3 = mat([[1,2,3],[4,5,6],[7,8,9]])
3004 * m4 = mat([[0.8,0,0.6],[0,1,0],[-0.8,0,0.6]]);
3005 * b1 = m1.isOrthogonal() // b1 = true
3006 * b2 = m2.isOrthogonal() // b2 = true
3007 * b3 = m3.isOrthogonal() // b3 = false
3008 * b4 = m4.isOrthogonal() // b4 = true
3009 */
3010 Matrix.prototype.isOrthogonal = function() {
3011 	var temp = new Matrix();
3012 	temp.beProductTOf(this,this);
3013 	return temp.isIdentity();
3014 }
3015 
3016 /** Tests receiver's positive definitness
3017 * @returns {bool} true if receiver is positive definite (if Cholesky decomposition can be performed), false otherwise
3018 * @example
3019 * m1 = mat([[9,2,1],[2,8,3],[1,3,7]])
3020 * m2 = mat([[-9,2,1],[2,8,3],[1,3,7]])
3021 * b1 = m1.isPositiveDefinite() // b1 = true
3022 * b2 = m2.isPositiveDefinite() // b2 = false
3023 */
3024 Matrix.prototype.isPositiveDefinite = function() {
3025 	// matrix is positive definite <=> cholesky decomposition can be performed
3026 	return this.choleskyDecomposition() != null;
3027 }
3028 
3029 /** Tests receiver's involutariness (if this*this=I -> this^-1=this)
3030 * @returns {bool} true if receiver is involutary, false otherwise
3031 * @example
3032 * m = mat([[1,0,0],[0,-1,0],[0,0,-1]])
3033 * t = m.isInvolutary() // t = true
3034 */
3035 Matrix.prototype.isInvolutary = function() {
3036 	var temp = new Matrix();
3037 	temp.beProductOf(this,this);
3038 	return temp.isIdentity();
3039 }
3040 
3041 /** Returns row permutation matrix using implicit partial pivoting (for each column find row with relatively highest element at that column and place that line to the position such that the highest element is on diagonal. Lines that are placed in this way are not considered for further steps)
3042 * @param {bool} [saveOrig=true] if true, returns permutated copy of receiver. If false, permutate receiver and return this
3043 * @Returns {[Matrix,[ints]]} permutated matrix and array containing coefficients of original matrix according to position in the permutated one ( such that this.rowPermutation(coeffs) = ret )
3044 * @example
3045 * m1 = mat([[1,2,4,9],[1,8,1,1],[9,4,5,3],[1,2,6,2]]);
3046 * m2 = m1.implicitPartialPivotPermutation();
3047 * // m2[0] = Matrix([[9,4,5,3],[1,8,1,1],[1,2,6,2],[1,2,4,9]])
3048 * // m2[1] = [2,1,3,0]
3049 * // m1 = Matrix([[1,2,4,9],[1,8,1,1],[9,4,5,3],[1,2,6,2]])
3050 * m3 = m1.rowPermutation(m2[1]); // m3 = Matrix([[9,4,5,3],[1,8,1,1],[1,2,6,2],[1,2,4,9]])
3051 * m4 = m2[0].rowPermutation(m2[1],true); // m4 = Matrix([[1,2,4,9],[1,8,1,1],[9,4,5,3],[1,2,6,2]])
3052 * m1 = m1.implicitPartialPivotPermutation(false)[0];
3053 * // m1 = Matrix([[9,4,5,3],[1,8,1,1],[1,2,6,2],[1,2,4,9]])
3054 */
3055 Matrix.prototype.implicitPartialPivotPermutation = function(saveOrig) {
3056 	var saveOrig = saveOrig==undefined? true : saveOrig;
3057 	var n = this.nRows;
3058 	var ret = saveOrig? this.copy() : this;
3059 	var vv = [];
3060 	var coeffs = range(n);
3061 	var big, i, j, k;
3062 	for (i=0; i<n; i++) {
3063 		big = 0.;
3064 		for (j=0; j<n; j++) {
3065 			if ((temp=Math.abs(ret[i][j])) > big) { big=temp; }
3066 		}
3067 		if (big == 0.0) { /*jsmLogger.warn('Matrix.implicitPartialPivotPermutation: singular matrix');*/ return null; }
3068 		vv[i]=1.0/big;
3069 	}
3070 	for (k=0; k<n; k++) {
3071 		big=0.0;
3072 		for (i=k; i<n; i++) {
3073 			temp = vv[i]*Math.abs(ret[i][k]);
3074 			if (temp > big) {
3075 				big = temp;
3076 				imax = i;
3077 			}
3078 		}
3079 		if (k != imax) {
3080 			ret.swapRows(k,imax);
3081 			vv[imax]=vv[k];
3082 			temp = coeffs[k]
3083 			coeffs[k] = imax;
3084 			coeffs[imax] = temp;
3085 		}
3086 	}
3087 	return [ret,coeffs];
3088 }
3089 
3090 /** Returns vector x as a solution of this*ret = vec, receiver is assumed to be lower triangular matrix
3091 * @param {Vector} vec right hand side
3092 * @param {bool} [saveOrig=true] if true, returns vec will be unchanged and new vector will be returned. If false, solution will be saved to vec and vec will be returned
3093 * @Returns {Vector} solution of this*ret = vec
3094 * @example
3095 * a = mat([[1,0,0,0],[2,3,0,0],[4,5,6,0],[7,8,9,10]]);
3096 * y = vec([4,17,43,80]);
3097 * x = a.forwardSubstitution(y);
3098 * // x = Vector([4,3,2,1])
3099 * // y = Vector([4,17,43,80])
3100 * check = a.mul(x); // check = Vector([4,17,43,80])
3101 * // x = Vector([4,3,2,1])
3102 * // y = Vector([4,17,43,80])
3103 * yy = y.copy();
3104 * // yy = Vector([4,17,43,80])
3105 * a.forwardSubstitution(yy,false);
3106 * // yy = Vector([4,3,2,1])
3107 */
3108 Matrix.prototype.forwardSubstitution = function(vec,saveOrig) {
3109 if (!this.isSquare() || !this.canMultiplyVec(vec)) { /*jsmLogger.warn('Matrix.forwardSubstitution: dimensions mismatched');*/ return null; }
3110 var saveOrig = saveOrig==undefined? true : saveOrig;
3111 var temp;
3112 var n = this.nRows;
3113 var ret = saveOrig? vec.copy() : vec;
3114 var i, j;
3115 /* this is lower triangular
3116 * this*ret = vec
3117 *
3118 * |t00  0   0  0 ... 0 |   |ret0|   |vec0|
3119 * |t10 t11  0  0 ... 0 | * |ret1| = |vec1|
3120 * |t20 t21 t22 0 ... 0 |   |ret2|   |vec2|
3121 *
3122 * ret0 = vec0/t00
3123 * ret1 = (vec1-t10*ret0)/t11
3124 * ret2 = (vec2-t20*ret0-t21*ret1)/t22
3125 * ...
3126 * retI = (vecI - sum_{j=0,I-1}(tIj*retj))/tII
3127 */
3128 for (i=0; i<n; i++) {
3129 	temp = ret[i];
3130 	for (j=0; j<i; j++) {
3131 		temp -= this[i][j]*ret[j];
3132 	}
3133 	ret[i] = temp/this[i][i];
3134 }
3135 return ret;
3136 }
3137 
3138 /** Returns vector x as a solution of this*ret = vec, receiver is assumed to be upper triangular matrix
3139 * @param {Vector} vec right hand side
3140 * @param {bool} [saveOrig=true] if true, returns vec will be unchanged and new vector will be returned. If false, solution will be saved to vec and vec will be returned
3141 * @Returns {Vector} solution of this*ret = vec
3142 * @example
3143 * a = mat([[1,2,3,4],[0,5,6,7],[0,0,8,9],[0,0,0,10]]);
3144 * y = vec([20,34,25,10]);
3145 * x = a.backwardSubstitution(y);
3146 * // x = Vector([4,3,2,1])
3147 * // y = Vector([20,34,25,10])
3148 * check = a.mul(x); // check = Vector([20,34,25,10])
3149 * // x = Vector([4,3,2,1])
3150 * // y = Vector([20,34,25,10])
3151 * yy = y.copy();
3152 * // yy = Vector([20,34,25,10])
3153 * a.backwardSubstitution(yy,false);
3154 * // yy = Vector([4,3,2,1])
3155 */
3156 Matrix.prototype.backwardSubstitution = function(vec,saveOrig) {
3157 	if (!this.isSquare() || !this.canMultiplyVec(vec)) { /*jsmLogger.warn('Matrix.backwardSubstitution: dimensions mismatched');*/ return null; }
3158 	var saveOrig = saveOrig==undefined? true : saveOrig;
3159 	var temp;
3160 	var n = this.nRows;
3161 	var ret = saveOrig? vec.copy() : vec;
3162 	var i, j;
3163 	/* this is upper triangular
3164 	* this*ret = vec
3165 	*
3166 	* | ...   (N, M=N-1, L=N-2)
3167 	* |0 ... tLL tLM tLN|   |retL|   |vecL|
3168 	* |0 ...  0  tMM tMN| * |retM| = |vecM|
3169 	* |0 ...  0   0  tNN|   |retN|   |vecN|
3170 	*
3171 	* retN = vecN/tNN
3172 	* retM = (vecM-tMN*retN)/tMM
3173 	* retL = (vecL-tLN*retN-tLM*retM)/tMM
3174 	* ...
3175 	* retI = (vecI-sum_{j=I+1,N}(tIj*retj))/tII
3176 	*/
3177 	for (i=n-1; i>=0; i--) {
3178 		temp = ret[i];
3179 		for (j=i+1; j<n; j++) {
3180 			temp -= this[i][j]*ret[j];
3181 		}
3182 		ret[i] = temp/this[i][i];
3183 	}
3184 	return ret;
3185 }
3186 
3187 /** Returns vector as a solution of system of linear equations using gaussian elimination method (this * ret = rhs --> ret )
3188 * @param {Vector} rhs vector of right hand sides
3189 * @param {string} [pivoting="default"] what type of pivoting to use. "default" and "nopivot" stands for no pivoting, "partpivot" for implicit partial pivoting (only row interchanges)
3190 * @returns {Vector} vector of solution
3191 * @example
3192 * a = mat([[1,2,9],[8,3,2],[3,7,3]]);
3193 * b = vec([32,20,26]);
3194 * x = a.gaussianElimination(b); // x = Vector([1,2,3])
3195 * x = a.gaussianElimination(b,'partpivot'); // x = Vector([1,2,3])
3196 * a.gaussianElimination(b,'nopivot',false);
3197 * // a = Matrix([[1,2,9],[8,-13,-70],[3,1,-29.384615384615387]])
3198 * // b = Vector([1,2,3])
3199 */
3200 Matrix.prototype.gaussianElimination = function(rhs,pivoting,saveOrig) {
3201 	if (!this.canMultiplyVec(rhs) || !this.isSquare()) { /*jsmLogger.warn('Matrix.gaussianElimination: dimensions mismatched');*/ return null; }
3202 	var pivoting = pivoting || "default";
3203 	var saveOrig = saveOrig==undefined? true : saveOrig;
3204 	var n = this.nRows;
3205 	var i, j, k;
3206 	if (pivoting == "nopivot" || pivoting=="default") {
3207 		var a = saveOrig? this.copy() : this;
3208 		var b = saveOrig? rhs.copy() : rhs;
3209 		for (k=0; k<n-1; k++) {
3210 			akk = a[k][k]; // "pivot"
3211 			for (i=k+1; i<n; i++) {
3212 				for (j=k+1; j<n; j++) {
3213 					a[i][j] -= a[k][j]*a[i][k]/akk;
3214 				}
3215 				b[i] -= b[k]*a[i][k]/akk;
3216 			}
3217 		}
3218 		return a.backwardSubstitution(b,false);
3219 	}
3220 	if (pivoting == "partpivot") {
3221 		var a = this.implicitPartialPivotPermutation(saveOrig);
3222 		var b = saveOrig? rhs.copy() : rhs;
3223 		b.permuteElements(a[1]);
3224 		return a[0].gaussianElimination(b,"nopivot",false);
3225 	}
3226 	return this.gaussianElimination(rhs,"default",saveOrig);
3227 }
3228 
3229 /** Returns matrix, whose columns are solutions of system of equations this*ret = rhs
3230 * @param {Matrix,[Vectors],Vector} rhs matrix/vector/array of vectors representing right hand sides
3231 * @param {string} [pivoting="default"] what type of pivoting to use. "default" and "nopivot" stands for no pivoting, "partpivot" for implicit partial pivoting (only row interchanges)
3232 * @param {bool} [saveOrig=true] if true, receiver is not changed. If false, solution will be saved to rhs and rhs will be returned
3233 * @returns {Matrix} matrix, whose columns are solution for particular right hand sides
3234 * @example
3235 * a = mat([[1,2,9],[8,3,2],[3,7,3]]);
3236 * b1 = vec([32,20,26]);
3237 * b2 = vec([16,32,26]);
3238 * b3 = [b1.copy(),b2.copy()];
3239 * b4 = mat([b1.toArray(),b2.toArray()]).T();
3240 * x1 = a.gaussJordanElimination(b1);
3241 * // x1 = Vector([ 1, 2, 3 ])
3242 * x2 = a.gaussJordanElimination(b2);
3243 * // x2 = Vector([ 3, 2, 1 ])
3244 * x3 = a.gaussJordanElimination(b3);
3245 * // x3 = [Vector([ 1, 2, 3 ]) ,Vector([ 3, 2, 1 ])]
3246 * x4 = a.gaussJordanElimination(b4);
3247 * // x4 = Matrix([[ 1, 3 ], [ 2, 2 ], [ 3, 1 ]])
3248 * x5 = a.gaussJordanElimination(b1,'nopivot');;
3249 * // x5 = Vector([ 1, 2, 3 ])
3250 * x6 = a.gaussJordanElimination(b2,'nopivot');
3251 * // x6 = Vector([ 3, 2, 1 ])
3252 * x7 = a.gaussJordanElimination(b3,'nopivot');
3253 * // x7 = Vector([ 1, 2, 3 ]) ,Vector([ 3, 2, 1 ])
3254 * x8 = a.gaussJordanElimination(b4,'nopivot');
3255 * // x8 = Matrix([[ 1, 3 ], [ 2, 2 ], [ 3, 1 ]])
3256 * a.gaussJordanElimination(b4,'nopivot',false);
3257 * // b4 = Matrix([[ 1, 3 ], [ 2, 2 ], [ 3, 1 ]])
3258 */
3259 Matrix.prototype.gaussJordanElimination = function(rhs,pivoting,saveOrig) {
3260 	if (!this.isSquare) { /*jsmLogger.warn('Matrix.gaussJordanElimination: dimensions mismatched');*/ return null; }
3261 	var rhsInstance = (rhs instanceof Vector)? 1 : ((rhs instanceof Array)? 2 : ((rhs instanceof Matrix)? 3 : 4));
3262 	if (!(rhsInstance==1 || rhsInstance==2 || rhsInstance==3)) { /*jsmLogger.warn('Matrix.gaussJordanElimination: wrong argument');*/ return null; }
3263 	var pivoting = pivoting || "default";
3264 	var saveOrig = saveOrig==undefined? true : saveOrig;
3265 	var i, j, k, akk;
3266 	var n = this.nRows;
3267 	var nrhs = rhsInstance==2? rhs.length : (rhsInstance==3? rhs.nCols : 1);
3268 	if (pivoting=="default" || pivoting=="nopivot") {
3269 		var a = saveOrig? this.copy() : this;
3270 		var b;
3271 		if (rhsInstance==1 || rhsInstance==3) { b = saveOrig? rhs.copy() : rhs; }
3272 		else {
3273 			b = [];
3274 			for (i=0; i<nrhs; i++) { b[i] = saveOrig? rhs[i].copy() : rhs[i]; }
3275 		}
3276 		for (k=0; k<n; k++) {
3277 			akk = a[k][k];
3278 			for (i=k+1; i<n; i++) {
3279 				for (j=k+1; j<n; j++) {
3280 					a[i][j] -= a[k][j]*a[i][k]/akk;
3281 				}
3282 				switch (rhsInstance) {
3283 					case 1: b[i] -= b[k]*a[i][k]/akk; break;
3284 					case 2: for (j=0; j<nrhs; j++) { b[j][i] -= b[j][k]*a[i][k]/akk; } break;
3285 					case 3: for (j=0; j<nrhs; j++) { b[i][j] -= b[k][j]*a[i][k]/akk; } break;
3286 				}
3287 			}
3288 		}
3289 		for (k=n-1; k>=0; k--) {
3290 			akk = a[k][k];
3291 			for (i=k-1; i>=0; i--) {
3292 				for (j=n-1; j>k; j--) {
3293 					a[i][j] -= a[k][j]*a[i][k]/akk;
3294 				}
3295 				switch (rhsInstance) {
3296 					case 1: b[i] -= b[k]*a[i][k]/akk; break;
3297 					case 2: for (j=0; j<nrhs; j++) { b[j][i] -= b[j][k]*a[i][k]/akk; } break;
3298 					case 3: for (j=0; j<nrhs; j++) { b[i][j] -= b[k][j]*a[i][k]/akk; } break;
3299 				}
3300 			}
3301 		}
3302 		for (k=0; k<n; k++) {
3303 			akk = a[k][k];
3304 			switch (rhsInstance) {
3305 				case 1: b[k] /= akk; break;
3306 				case 2: for (j=0; j<nrhs; j++) { b[j][k] /= akk; } break;
3307 				case 3: for (j=0; j<nrhs; j++) { b[k][j] /= akk; } break;
3308 			}
3309 		}
3310 		return b;
3311 	}
3312 	if (pivoting == "partpivot") {
3313 		var a = this.implicitPartialPivotPermutation(saveOrig);
3314 		var temp;
3315 		switch (rhsInstance) {
3316 			case 1: temp = saveOrig? rhs.copy() : rhs; temp.permuteElements(a[1]); break;
3317 			case 2:
3318 				temp = [];
3319 				for (i=0; i<nrhs; i++) {
3320 					temp[i] = saveOrig? rhs[i].copy() : rhs[i];
3321 					temp[i].permuteElements(a[1]);
3322 				}
3323 				break;
3324 			case 3:
3325 				temp = saveOrig? rhs.copy() : rhs;
3326 				temp.permuteRows(a[1]);
3327 				break;
3328 		}
3329 		return a[0].gaussJordanElimination(temp,"nopivot",false);
3330 	}
3331 	return this.gaussJordanElimination(rhs,"default",saveOrig);
3332 }
3333 
3334 /** Returns lower triangular matrix of Cholesky decomposition of receiver. Receiver must be square, symmetric and positive definite. ( ret * ret^T = this )
3335 * @param {bool} [saveOrig=true] if true, receiver is not changed. If false, solution will be saved to receiver
3336 * @param {bool} [checkSymm=false] if true, test of receiver symmetricity is performed, otherwise not
3337 * @returns {Matrix} lower triangular Cholesky matrix
3338 * @example
3339 * a = mat([[1,2,4],[2,13,23],[4,23,77]]);
3340 * l = a.choleskyDecomposition(); // l = Matrix([[1,0,0],[2,3,0],[4,5,6]])
3341 * check = l.x(l.T()); // check = Matrix([[1,2,4],[2,13,23],[4,23,77]]);
3342 */
3343 Matrix.prototype.choleskyDecomposition = function(saveOrig,checkSymm) {
3344 	var checkSymm = checkSymm==undefined? true : check;
3345 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.choleskyDecomposition: matrix is not square');*/ return null; }
3346 	if (checkSymm) {
3347 		if (!this.isSymmetric()) { /*jsmLogger.warn('Matrix.choleskyDecomposition: matrix is not symmetric');*/ return null; }
3348 	}
3349 	var saveOrig = saveOrig==undefined? true : saveOrig;
3350 	var n = this.nRows;
3351 	var a = saveOrig? this.copy() : this;
3352 	var aii, temp, i, j, k;
3353 	/*
3354 	* |t00 t01 t02 ..| |l00  0   0  ..| |l00 l10 l20 ..|
3355 	* |t01 t11 t12 ..|=|l10 l11  0  ..|*| 0  l11 l21 ..|
3356 	* |t02 t12 t22 ..| |l20 l21 l22 ..| | 0   0  l22 ..|
3357 	* |  ..........  | |  ..........  | |  ..........  |
3358 	*
3359 	* t00 = l00*l00  ->  l00 = sqrt(t00)
3360 	* t01 = l00*l10  ->  l10 = t01/l00
3361 	* t02 = l00*l20  ->  l20 = t02/l00
3362 	* t11 = l10*l10+l11*l11 -> l11 = sqrt(t11-l00*l00)
3363 	* t12 = l10*l20+l11*l21 -> l21 = (t12-l10*l20)/l11
3364 	* t22 = l20*l20+l21*l21+l22*l22 -> l22=sqrt(t22-l20*l20-l21*l21)
3365 	* t32 = l30*l20+l31*l21+l32*l22 -> l32 = (t32-l30*l20-l31*l21)/l22
3366 	* ...
3367 	* lii = sqrt(tii - sum_{k=0,i-1}(lik*lik))
3368 	* lij = (tij-sum_{k=0,j-1}(lik*ljk))/lii
3369 	*/
3370 	for (i=0; i<n; i++) {
3371 		aii = a[i][i];
3372 		for (k=0; k<i; k++) { aii -= a[i][k]*a[i][k]; }
3373 		if (aii<=0.) { /*jsmLogger.warn('Matrix.choleskyDecomposition: matrix is not positive definite');*/ return null; }
3374 		aii = Math.sqrt(aii);
3375 		a[i][i] = aii;
3376 		for (j=i+1; j<n; j++) {
3377 			temp = a[j][i];
3378 			for (k=0; k<i; k++) { temp -= a[i][k]*a[j][k]; }
3379 			a[j][i] = temp/aii;
3380 		}
3381 		for (k=i+1; k<n; k++) { a[i][k] = 0.; }
3382 	}
3383 	return a;
3384 }
3385 
3386 /** Alias for Cholesky decomposition, see {@link Matrix#choleskyDecomposition}
3387 * @function
3388 */
3389 Matrix.prototype.chol = Matrix.prototype.choleskyDecomposition;
3390 
3391 /** Alias for Cholesky decomposition, see {@link Matrix#choleskyDecomposition}
3392 * @function
3393 */
3394 Matrix.prototype.lltDecomposition = Matrix.prototype.choleskyDecomposition;
3395 
3396 /** Returns lower (L) and upper (U) triangular matrix of the receiver such that L*U=this. Diagonal elements of L are all 1. Receiver must be square.
3397 * @param {string} [pivoting="default"] what type of pivoting to use. "default" and "nopivot" stands for no pivoting, "partpivot" for implicit partial pivoting (only row interchanges)
3398 * @returns {[Matrix,Matrix]} [L,U], lower and upper triangular matrices
3399 * @example
3400 * a = mat([[6,5,4],[12,13,10],[18,27,21]]);
3401 * lu = a.luDecomposition();
3402 * l = lu[0]; // l = Matrix([[1,0,0],[2,1,0],[3,4,1]])
3403 * u = lu[1]; // u = Matrix([[6,5,4],[0,3,2],[0,0,1]])
3404 * check = l.x(u); // check = Matrix([[6,5,4],[12,13,10],[18,27,21]])
3405 */
3406 Matrix.prototype.luDecomposition = function(pivoting) {
3407 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.luDecomposition: matrix is not square');*/ return null; }
3408 	var pivoting = pivoting || "default";
3409 	var n = this.nRows;
3410 	var l = Matrix.Zeros(n,n);
3411 	var u = Matrix.Zeros(n,n);
3412 	var i, j, k, imax;
3413 	var temp;
3414 	/*
3415 	* |t00 t01 t02 ..| |l00  0   0  ..| |u00 u01 u02 ..|
3416 	* |t10 t11 t12 ..|=|l10 l11  0  ..|*| 0  u11 u12 ..|
3417 	* |t20 t21 t22 ..| |l20 l21 l22 ..| | 0   0  u22 ..|
3418 	*
3419 	* assumtion: lkk = 1.
3420 	* t00 = l00*u00 -> l00=1, u00=t00
3421 	* t01 = l00*u01 -> u01=t01/l00
3422 	* t02 = l00*u02 -> u02=t02/l00
3423 	* ...
3424 	* t10 = l10*u00 -> l10=t10/u00
3425 	* t11 = l10*u01+l11*u11 -> l11=1, u11=(t11-l10*u01)
3426 	* t12 = l10*u02+l11*u12 -> u12=t12-l10*u02
3427 	* t13 = l10*u03+l11*u13 -> u13=t13-l10*u03
3428 	* ...
3429 	* t20 = l20*u00 -> l20=t10/u00
3430 	* t21 = l20*u01+l21*u11 -> l21=(t21-l20*u01)/u11
3431 	* t22 = l20*u02+l21*u12+l22*u22 -> l22=1, u22=(t22-l20*u02-l21*u12)
3432 	* ...
3433 	* lkk = 1.
3434 	* ukj = tkj - sum_{i=0,k-1}(lki*uij)
3435 	* ljk = tjk - sum_{i=0,k-1}(lji*uik)
3436 	*/
3437 	if (pivoting=="default" || pivoting=="nopivot") {
3438 		for (k=0; k<n; k++) {
3439 			l[k][k] = 1.;
3440 			for (j=k; j<n; j++) {
3441 				temp = this[k][j];
3442 				for (i=0; i<k; i++) {
3443 					temp -= l[k][i]*u[i][j];
3444 				}
3445 				u[k][j] = temp;
3446 			}
3447 			for (j=k+1; j<n; j++) {
3448 				temp = this[j][k]
3449 				for (i=0; i<k; i++) {
3450 					temp -= l[j][i]*u[i][k]
3451 				}
3452 				l[j][k] = temp/u[k][k]
3453 			}
3454 		}
3455 		return [l,u]
3456 	}
3457 	if (pivoting == "partpivot") {
3458 		var a = this.implicitPartialPivotPermutation()
3459 		var ret = a[0].luDecomposition("nopivot");
3460 		ret[2] = a[1];
3461 		return ret;
3462 	}
3463 	return this.luDecomposition("default");
3464 }
3465 
3466 /** Returns lower triangular (L), diagonal (D) and upper triangular (U) matrix of the receiver such that L*D*U=this. Diagonal elements of both L and U are all 1. Receiver must be square.
3467 * @param {string} [pivoting="default"] what type of pivoting to use. "default" and "nopivot" stands for no pivoting, "partpivot" for implicit partial pivoting (only row interchanges)
3468 * @returns {[Matrix,Vector,Matrix]} [L,D,U], lower, diagonal and upper triangular matrices
3469 * @example
3470 * a = mat([[2,10,8],[4,23,22],[6,42,52]]);
3471 * ldu = a.lduDecomposition();
3472 * l = ldu[0]; // l = Matrix([[1,0,0],[2,1,0],[3,4,1]])
3473 * d = ldu[1]; // d = Vector([2,3,4])
3474 * u = ldu[2]; // u = Matrix([[1,5,4],[0,1,2],[0,0,1]])
3475 * check = l.x(d.diag()).x(u) // check = Matrix([[2,10,8],[4,23,22],[6,42,52]]);
3476 */
3477 Matrix.prototype.lduDecomposition = function(pivoting) {
3478 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.lduDecomposition: matrix is not square');*/ return null; }
3479 	var pivoting = pivoting || "default";
3480 	if (pivoting=="default" || pivoting=="nopivot") {
3481 		var n = this.nRows;
3482 		var l = Matrix.Zeros(n,n);
3483 		var d = Vector.Zeros(n);
3484 		var u = Matrix.Zeros(n,n);
3485 		var temp;
3486 		for (var i=0; i<n; i++) {
3487 			l[i][i] = 1.;
3488 			u[i][i] = 1.;
3489 			for (var j=0; j<i; j++) {
3490 				temp = this[i][j];
3491 				for (var k=0; k<j; k++) {
3492 					temp -= l[i][k]*d[k]*u[k][j];
3493 				}
3494 				l[i][j] = temp/d[j];
3495 			}
3496 			temp = this[i][i];
3497 			for (var k=0; k<i; k++) {
3498 				temp -= l[i][k]*d[k]*u[k][i];
3499 			}
3500 			d[i] = temp;
3501 			for (var j=i+1; j<n; j++) {
3502 				temp = this[i][j];
3503 				for (var k=0; k<i; k++) {
3504 					temp -= l[i][k]*d[k]*u[k][j];
3505 				}
3506 				u[i][j] = temp/d[i];
3507 			}
3508 		}
3509 		return [l,d,u];
3510 	}
3511 	if (pivoting = "partpivot") {
3512 		var a = this.implicitPartialPivotPermutation();
3513 		var ret = a.lduDecomposition("nopivot");
3514 		ret[3] = a[1];
3515 		return ret;
3516 	}
3517 	return this.lduDecomposition("default");
3518 }
3519 
3520 /* Returns orthogonal matrix Q and upper triangular matrix R of QR decomposition of receiver such that Q*R=this. Implemented for square matrices only
3521 * @param {string} [method="default"] method for solution. "default" and "grammschmidt" stand for Gramm-Schmidt process, "householder" for using Householder transformations
3522 * @param {bool} [saveOrig=true] if true, receiver is not changed. If false, solution (R matrix) will be saved to this and this will be returned
3523 * @returns {[Matrix,Matrix]} Q and R of QR decomposition of receiver
3524 * @example
3525 * a = mat([[0.8,1.6,6],[0,4,5],[-0.6,-1.2,3]])
3526 * qr = a.qrDecomposition();
3527 * q = qr[0]; // q = Matrix([[0.8,0,0.6],[0,1,0],[-0.6,0,0.8]])
3528 * r = qr[1]; // r = Matrix([[1,2,3],[0,4,5],[0,0,6]])
3529 * check = q.x(r); // check = Matrix([[0.8,1.6,6],[0,4,5],[-0.6,-1.2,3]])
3530 * o1 = q.isOrthogonal(); // o1 = true
3531 * o2 = r.isUpperTriangular(); // o2 = true
3532 * //
3533 * qr = a.qrDecomposition('householder');
3534 * q = qr[0]; // q = Matrix([[ 0.11624763874381927, 0.24071784839360483, 0.9636085325230572 ], [ 0.9299811099505543, -0.3670351351744072, -0.02050230920261827 ], [ 0.34874291623145787, 0.8985210776672174, -0.26653001963403705 ]])
3535 * r = qr[1]; // r = Matrix([[ 8.602325267042627, 5.463639020959507, 5.1148961047280475 ], [ 2.5252117732828282e-17, 5.669977834934511, 1.5968411725120326 ], [ -2.206040279013976e-16, 4.440892098500626e-16, 8.323937536263006 ]])
3536 * check = q.x(r); // check = Matrix([[1,2,9],[8,3,4],[3,7,1]])
3537 * o1 = q.isOrthogonal(); // o1 = true
3538 * o2 = r.isUpperTriangular(); // o2 = true
3539 */
3540 Matrix.prototype.qrDecomposition = function(method,saveOrig) {
3541 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.qrDecomposition: matrix is not square');*/ return null; }
3542 	var saveOrig = saveOrig==undefined? true : saveOrig;
3543 	var method = method || "default";
3544 	var n = this.nRows;
3545 	if (method=="default" || method=="grammschmidt" || method=="gramm-schmidt" || method=="gs") {
3546 		//TODO
3547 		proj = function(ee,aa) { return ee.mulf(ee.dot(aa)/(ee.dot(ee))); }
3548 		var r = saveOrig? this.copy() : this;
3549 		var q = new Matrix(n,n);
3550 		var a, e=[];
3551 		var j,k;
3552 		for (k=0; k<n; k++) {
3553 			a = r.getCol(k);
3554 			e[k] = a.copy();
3555 			for (j=0; j<k; j++) { e[k].isub(proj(e[j],a)); }
3556 			e[k].normalize();
3557 			for (j=0; j<=k; j++) { r[j][k] = e[j].dot(a); }
3558 			for (j=k+1; j<n; j++) { r[j][k] = 0.; }
3559 			q.setCol(k,e[k]);
3560 		}
3561 		return [q,r];
3562 	}
3563 	if (method=="householder") {
3564 		//TODO
3565 		var r = saveOrig? this.copy() : this;
3566 		var e = Vector.Zeros(n);
3567 		e[0] = 1.;
3568 		var a, x, rkn, qtemp, q=Matrix.Identity(n), piv;
3569 		// TODO operation reduction
3570 		for (var k=0; k<n-1; k++) {
3571 			e.resize(n-k);
3572 			rkn = range(k,n);
3573 			a = r.getSubMatrix(rkn,rkn);
3574 			x = a.getCol(0);
3575 			qtemp = Matrix.Identity(n);
3576 			piv = x[k]>0.? -1. : 1.;
3577 			qtemp.setSubMatrix(rkn,rkn,Matrix.Householder(x.add(e.mulf(piv*x.norm()))));
3578 			r = qtemp.mulm(r);
3579 			q = q.mulm(qtemp.transposed());
3580 		}
3581 		return [q,r];
3582 	}
3583 	return this.qrDecomposition("default",saveOrig);
3584 }
3585 
3586 /** Returns vector/array of vectors/matrix as a solution of system of linear equations (this*ret=rhs --> ret). Receiver must be square. TODO: solution with LU decomposition with permutation
3587 * @param {Vector|[Vectors]|Matrix} rhs vector of right hand sides. Array of vectors or Matrix as rhs is supported only with "gaussjordan" method
3588 * @param {string} [method="default"] method of the solution. Implemented methods are "default" and "gauss" for gaussian elimination, "gaussjordan" for Gauss-Jordan elimination (supporting more than one right hand sides in form of array of vectors or matrix with columns as rhs), "lu" for using LU decomposition, "ldu" for using LDU decomposition, "cholesky" for using Cholesky decomposition, "qr" for using QR decomposition
3589 * @param {bool} [saveOrig=true] if true, receiver and rhs is not changed. If false, solution will be saved to rhs and rhs will be returned and receiver will be changed
3590 * @param {[Matrices]} [precompDecomps=undefined] array of Matrices objects, used for solution using matrix decomposition as precomputed values (the decomposition is performed within linSolve function if args parameter is not specified)
3591 * @returns {Vector|[Vectors]|Matrix} vector/array of vectors/matrix of solution
3592 * @example
3593 * a = mat([[1,2,9],[8,3,2],[3,7,3]]);
3594 * b = vec([32,20,26]);
3595 * x1 = a.linSolve(b); // x1 = Vector([1,2,3])
3596 * x2 = a.linSolve(b,'gauss'); // x2 = Vector([1,2,3])
3597 * x3 = a.linSolve(b,'gaussjordan'); // x3 = Vector([1,2,3])
3598 * x4 = a.linSolve(b,'lu'); // x4 = Vector([1,2,3])
3599 * x5 = a.linSolve(b,'ldu'); // x5 = Vector([1,2,3])
3600 * x7 = a.linSolve(b,'qr'); // x7 = Vector([1,2,3])
3601 * a2 = mat([[1,2,4],[2,13,23],[4,23,77]]);
3602 * b2 = vec([17,97,281]);
3603 * x6 = a2.linSolve(b2,'cholesky'); // x6 = Vector([1,2,3])
3604 */
3605 Matrix.prototype.linSolve = function(rhs,method,saveOrig,precompDecomps) {
3606 	var saveOrig = saveOrig==undefined? true : saveOrig;
3607 	var method = method || "default";
3608 	method = method.toLowerCase();
3609 	if (method=="default" || method=="gauss" || method=="gaussian") { // gaussian elimination
3610 		return this.gaussianElimination(rhs,"partpivot",saveOrig);
3611 	}
3612 	if (method=="gaussjordan" || method=="gauss-jordan" || method=="gj") { // gauss-jordan elimination
3613 		return this.gaussJordanElimination(rhs,"partpivot",saveOrig);
3614 	}
3615 	if (method=="lu") { // use LU factorization
3616 		var lu = precompDecomps || this.luDecomposition();
3617 		var l = lu[0];
3618 		var u = lu[1];
3619 		var y;
3620 		if (rhs instanceof Vector) {
3621 			y = l.forwardSubstitution(rhs,saveOrig);
3622 			return u.backwardSubstitution(y,false);
3623 		}
3624 		if (rhs instanceof Matrix) {
3625 			var ret = saveOrig? Matrix.Zeros(this.nRows,rhs.nCols) : rhs;
3626 			for (var i=0; i<ret.nCols; i++) {
3627 				y = l.forwardSubstitution(rhs.getCol(i),false);
3628 				ret.setCol(i,u.backwardSubstitution(y,false));
3629 			}
3630 			return ret;
3631 		}
3632 		if (rhs instanceof Array) {
3633 			return null;
3634 			// TODO
3635 		}
3636 	}
3637 	if (method=="ldu") { // use LDU decomposition
3638 		var ldu = precompDecomps || this.lduDecomposition("nopivot",true);
3639 		var l = ldu[0];
3640 		var d = (ldu[1] instanceof Matrix)? ldu[1].diag() : ldu[1];
3641 		var u = ldu[2];
3642 		var y = l.forwardSubstitution(rhs,saveOrig);
3643 		for (var r=0; r<this.nRows; r++) { y[r] /= d[r]; }
3644 		return u.backwardSubstitution(y,false);
3645 	}
3646 	if (method=="cholesky" || method=="chol") { // use Cholesky's decomposition
3647 		var l = precompDecomps || this.choleskyDecomposition();
3648 		if (l==null) { /*jsmLogger.warn('Matrix.linSolve: matrix is not positive definite');*/ return null; }
3649 		var y = l.forwardSubstitution(rhs,saveOrig);
3650 		return l.transposed().backwardSubstitution(y,false);
3651 	}
3652 	if (method=="qr") { // use QR decomposition
3653 		var qr = precompDecomps || this.qrDecomposition("grammschmidt",saveOrig);
3654 		return qr[1].backwardSubstitution(qr[0].transposed().mulv(rhs),false);
3655 	}
3656 	return this.linSolve(rhs,"default",saveOrig,precompDecomps);
3657 }
3658 
3659 /** returns Schur form of receiver (upper triangular matrix with eigenvalues of the receiver on the diagonal). QR algorithm is used for calculation
3660 * @param {bool} [saveOrig=true] if true, returns new matrix, if false the Schur form is formed on original matrix
3661 * @param {int} [maxiter=1000] maximum number of iterations
3662 * @returns {Matrix} Schur form of receiver (upper triangular matrix with eigenvalues on diagonal)
3663 * @example
3664 * m1 = mat([[4,2,3,1],[3,6,5,7],[5,3,8,1],[2,3,4,5]]);
3665 * m2 = m1.schurForm(); // m2 = Matrix([[ 15.6072, -3.6605, -0.7006, 2.3149 ], [ 0, 4.1916, 3.3807, 2.0775 ], [ 0, 0, 2.2012, 0.0769 ], [ 0, 0, 0, 1 ]])
3666 * b = m2.isUpperTriangular(); // b = true
3667 */
3668 Matrix.prototype.schurForm = function(saveOrig,maxiter) {
3669 	//return this.schurDecomposition(saveOrig,maxiter)[1];
3670 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.schurForm: matrix is not square');*/ return null; }
3671 	var n = this.nRows;
3672 	var saveOrig = saveOrig==undefined? true : saveOrig;
3673 	var maxiter = maxiter || 1000;
3674 	var qr, s = saveOrig? this.copy() : this;
3675 	var rhos, rhosNew=Vector.Zeros(n), rhosRatio=Vector.Zeros(n), maxRhosRatio, i, q, r, iter=0, qq=Matrix.Identity(n);
3676 	for (i=0; i<n; i++) { rhosNew[i] = 0.; }
3677 	do {
3678 		qr = s.qrDecomposition()
3679 		q = qr[0];
3680 		r = qr[1];
3681 		s = r.mulm(q);
3682 		rhos = rhosNew.copy();
3683 		rhosNew = s.diagonalToVector();
3684 		for (i=0; i<n; i++) { rhosRatio[i] = Math.abs((rhosNew[i] - rhos[i])/rhosNew[i]); }
3685 		maxRhosRatio = 0.;
3686 		for (var i=0; i<n; i++) {
3687 			if (rhosRatio[i] > maxRhosRatio) { maxRhosRatio = rhosRatio[i]; }
3688 		}
3689 		iter++;
3690 		if (iter > maxiter) {
3691 			if (maxRhosRatio > JSM_TOL) { /*jsmLogger.warn('Matrix.schurForm: maximum number of iterations reached');*/ return null; }
3692 			break;
3693 		}
3694 	} while (maxRhosRatio > JSM_TOL2)
3695 	return s;
3696 }
3697 
3698 /** returns orthogonal matrix Q and upper triangular matrix S as Schur decomposition of receiver such that this=Q*S*Q^-1. Columns of Q are eigenvectors of receiver and diagonal elements of S are eigenvalues of receiver 
3699 * @param {bool} [saveOrig=true] if true, returns new matrices, if false, S is formed into original matrix
3700 * @param {int} [maxiter=1000] maximum number of iterations
3701 * @returns {[Matrix,Matrix]} Q,S - Scur decomposition of receiver
3702 * @example
3703 * m1 = mat([[4,2,3,1],[3,6,5,7],[5,3,8,1],[2,3,4,5]]);
3704 * qs = m1.schurDecomposition();
3705 * q = qs[0]; s = qs[1];
3706 * // s = Matrix([[ 15.6072, -3.6605, -0.7006, 2.3149 ], [ 0, 4.1916, 3.3807, 2.0775 ], [ 0, 0, 2.2012, 0.0769 ], [ 0, 0, 0, 1 ]])
3707 * qr = s.qrDecomposition();
3708 * q1 = qr[0]; r = qr[1];
3709 * // q1 = Matrix([[ 1, 0, 0, 0 ], [ 0, 1, 0, 0 ], [ 0, 0, 1, 0 ], [ 0, 0, 0, 1 ]])
3710 * // r = Matrix([[ 15.6072, -3.6605, -0.7006, 2.3149 ], [ 0, 4.1916, 3.3807, 2.0775 ], [ 0, 0, 2.2012, 0.0769 ], [ 0, 0, 0, 1 ]])
3711 * b1 = q.isOrthogonal() // b1 = true
3712 * b2 = s.isUpperTriangular() // b2 = true
3713 * c = q.mulm(s).mulm(q.inv()); // c = Matrix([[4,2,3,1],[3,6,5,7],[5,3,8,1],[2,3,4,5]])
3714 */
3715 Matrix.prototype.schurDecomposition = function(saveOrig,maxiter) {
3716 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.schurDecomposition: matrix is not square');*/ return null; }
3717 	var n = this.nRows;
3718 	var saveOrig = saveOrig==undefined? true : saveOrig;
3719 	var maxiter = maxiter || 1000;
3720 	var qr, s = saveOrig? this.copy() : this;
3721 	var rhos, rhosNew=Vector.Zeros(n), rhosRatio=Vector.Zeros(n), maxRhosRatio, i, q, r, iter=0, qq=Matrix.Identity(n);
3722 	for (i=0; i<n; i++) { rhosNew[i] = 0.; }
3723 	do {
3724 		// A(k)=Q(k)*R(k), A(k+1)=R(k)*Q(k)=Q(k)^T*A(k)*Q(k)
3725 		// A(k+1) converges to Schur form
3726 		// Furthermore Q=sum_k(Q(k)), S=A(N)=Q^T*this*Q -> this=Q*S*Q^T
3727 		// (Q is othogonal)
3728 		qr = s.qrDecomposition()
3729 		q = qr[0];
3730 		qq = qq.mulm(q);
3731 		r = qr[1];
3732 		s = r.mulm(q);
3733 		rhos = rhosNew.copy();
3734 		rhosNew = s.diagonalToVector();
3735 		for (i=0; i<n; i++) { rhosRatio[i] = Math.abs((rhosNew[i] - rhos[i])/rhosNew[i]); }
3736 		maxRhosRatio = 0.;
3737 		for (var i=0; i<n; i++) {
3738 			if (rhosRatio[i] > maxRhosRatio) { maxRhosRatio = rhosRatio[i]; }
3739 		}
3740 		iter++;
3741 		if (iter > maxiter) {
3742 			if (maxRhosRatio > JSM_TOL) { /*jsmLogger.warn('Matrix.schurDecomposition: maximum number of iterations reached');*/ return null; }
3743 			break;
3744 		}
3745 	} while (maxRhosRatio > JSM_TOL2)
3746 	return [qq,s];
3747 }
3748 
3749 /** Returns orthogonal matrix U, diagonal matrix S and orthogonal matrix V of singular value decomposition (SVD) of receiver such that this = U*S*V^T. U is computed as orthonormalized iegenvectors of this^T*this, V as orhonormalized eigenvectors of this*this^T and diagonal components of S as square roots of eigenvalues of this^T*this (TODO faster algorithm). this*V = U*S, A^T*U = V*S. Current implementation allows only square matrices (TODO gegeral-shape dmatrices)
3750 * @returns {[Matrix,Vector,Matrix]} [U,S,V] orthogonal matrix U, diagonal of matrix S and orthogonal matrix V of svd decomposition of receiver
3751 * @example
3752 * m1 = mat([[3,2,1],[2,5,2],[1,2,6]]);
3753 * m1 = mat([[1.6,0.6,0.],[-1.2,0.8,0.],[0.,0.,3.]])
3754 * svd = m1.singularValueDecomposition();
3755 * u = svd[0]; // u = Matrix([[0.6,0.8,0],[0.8,-0.6,0],[0,0,1]])
3756 * s = svd[1]; // s = Vector([1,2,3])
3757 * v = svd[2]; // v = Matrix([[0,1,0],[1,0,0],[0,0,1]])
3758 * b1 = u.isOrthogonal() // b1 = true
3759 * b2 = v.isOrthogonal() // b2 = true
3760 * c = u.mulm(s.diag()).mulm(v.transposed());
3761 * // c = mat([[1.6,0.6,0.],[-1.2,0.8,0.],[0.,0.,3.]])
3762 */
3763 Matrix.prototype.singularValueDecomposition = function() {
3764 	if (!this.isSquare()) { return null; }
3765 	var aat = this.mulm(this.transposed());
3766 	var naat = aat.nRows;
3767 	var ata = this.transposed().mulm(this);
3768 	var nata = ata.nRows;
3769 	var aatEig = aat.eigSymmetric({nEigModes:'all'});
3770 	var ataEig = ata.eigSymmetric({nEigModes:'all'});
3771 	var U = Matrix.Zeros(aat.nRows,aat.nCols);
3772 	var V = Matrix.Zeros(ata.nRows,ata.nCols);
3773 	for (var n=0; n<naat; n++) { U.setCol(n,aatEig[1][n]); }
3774 	for (var n=0; n<nata; n++) { V.setCol(n,ataEig[1][n]); }
3775 	s = [];
3776 	for (var n=0; n<nata; n++) { s[n] = Math.sqrt(ataEig[0][n]); }
3777 	return [U,Vector.create(s),V];
3778 }
3779 
3780 /** Alias for singular value decomposition, see {@link Matrix.singularValueDecomposition}
3781 * @function
3782 */
3783 Matrix.prototype.svd = Matrix.prototype.singularValueDecomposition;
3784 
3785 /* * Returns pseudoinverse of receiver 
3786 * @param {string} [method="defualt"] method of evaluation. Options are 'defualt' for ( ret = (this^T*this)^-1 * this^T ), 'svd' for SVD decomposition ( this=U*S*V^T -> this^+ = V*S^+*U^T, A^+ means pseudoinverse)
3787 * @param {[Matrix,Matrix,Matrix]} [precompSvd=undefined] precomputed SVD decomposition of receiver
3788 * @returns {Matrix} pseudoinverse of receiver
3789 * @ example
3790 * m1 = mat([[2,-4,5],[6,0,3],[2,-4,5],[6,0,3]]);
3791 * b = vec([1,3,-1,3]);
3792 * m2 = m1.pseudoinverse();
3793 * // m2 =
3794 * x2 = m2.mulv(b);
3795 * // x2 = 
3796 * c2 = m1.mulv(x2)
3797 * // c2 =
3798 * /
3799 pseudoinverse: function(method,precompSvd) {
3800 	var method = method || 'defualt'
3801 	method = method.toLowerCase();
3802 	//if (method=='default') {
3803 		//var t = this.inversed();
3804 		//return (t.mulm(this)).inversed().mulm(t);
3805 	//}
3806 	if (method=='svd' || method=='default') {
3807 		var svd = precompSvd? precompSvd : this.singularValueDecomposition();
3808 		var u = svd[0];
3809 		var s = svd[1];
3810 		var v = svd[2];
3811 		var n = s.nElements;
3812 		var ss = new Matrix(n,n);
3813 		for (var i=0; i<n; i++) {
3814 			if (Math.abs(s[i]) > JSM_TOL) { ss[i][i] = 1./s[i]; }
3815 		}
3816 		return v.mulm(ss).mulm(u.transposed());
3817 	}
3818 	return this.pseudoinverse('default',precompSvd);
3819 }
3820 */
3821 
3822 /** Returns orthogonal matrix R and symmetric matrix U of polar decomposition of the receiver such that this=R*U. The decomposition is computed from SVD decomposition (this = U*S*V^T -> R = U*V^T, U = V*S*V^T
3823 * @param {[Matrix,Matrix,Matrix]} [precompSvd=undefined] precomputed SVD decomposition
3824 * @returns {[Matrix,Matrix]} [R,U] orthogonal matrix R and symmetric matrix U of polar decomposition of receiver
3825 * @example
3826 * m = mat([[1.6,.6,0],[-1.2,0.8,0],[0,0,3]])
3827 * ru = m.polarDecomposition();
3828 * r = ru[0]; // r = Matrix([[0.8,0.6,0],[-0.6,0.8,0],[0,0,1]])
3829 * u = ru[1]; // u = Matrix([[2,0,0],[0,1,0],[0,0,3]])
3830 * b1 = r.isOrthogonal(); // b1 = true
3831 * b2 = u.isSymmetric(); // b2 = true
3832 * c = r.mulm(u); // c = Matrix([[1.6,.6,0],[-1.2,0.8,0],[0,0,3]])
3833 */
3834 Matrix.prototype.polarDecomposition = function(precompSvd) {
3835 	if (!this.isSquare) { /*jsmLogger.warn('Matrix.polarDecomposition: matrix is not square');*/ return null; }
3836 	var svd = precompSvd? precompSvd : this.singularValueDecomposition();
3837 	var u = svd[0];
3838 	var s = svd[1];
3839 	var v = svd[2];
3840 	return [u.mulm(v.transposed()), v.mulm(s.diag()).mulm(v.transposed())];
3841 }
3842 
3843 /** Returns eigenvalues (L) and eigenvectors (P) of symmetric receiver ( (this-lambda*mat)*phi = 0 ). Eigenvectors are normalized with respect to mat
3844 * @param {Object} params object of parameters
3845 * @param {Matrix} [params.mat=Matrix.Identity] mat in (this-lambda*mat)*phi = 0 ). If mat==Matix.Identity, then the "classical" eigenvalue problem is solved ( (this-lambda*I)*phi = 0 -> this*phi=lambda*phi)
3846 * @param {int|string("all")} [params.nEigModes='all'] number of first eigenvalues and eigenvectors to be returned. if "all" is, then all eigenvalues are returned
3847 * @param {string} [params.method="default"] method of the solution. "default" and "invit" stands for Stodola's inverse iterations methods with Gramm-Schmidt orthogonalization, "subspace" for subspace iterations
3848 @param {bool} [params.highest=true] find params.nEigModes highest eigenvalues if true, params.nEigModes lowest eigenvalues otherwise
3849 * @param {int} [params.maxiter=1000] maximum number of iterations
3850 * @returns {[[floats],[Vectors]]} [[lambda1,lambda2,...,lambdaN],[phi1,phi2,...,phiN]], oi is i-th eigenvalue, vi is i-th eigenvector. N = nEigModes
3851 * //
3852 * @example
3853 * k = mat([[9,3,0,0],[3,8,2,0],[0,2,7,2],[0,0,2,8]]);
3854 * m = Matrix.Diagonal([3,2,4,3]);
3855 * e = k.eigSymmetric({mat:m,nEigModes:2,highest:false});
3856 * ls = e[0];
3857 * ps = e[1];
3858 * l1 = ls[0]; // l1 = 1.2504038497315775
3859 * l2 = ls[1]; // l2 = 2.279120228657416
3860 * p1 = ps[0]; // p1 = Vector([ 0.1288306767139194, -0.22540165581364102, 0.4265175098731745, -0.20077135620035116 ])
3861 * p2 = ps[1]; // p2 = Vector([ 0.4514687335612619, -0.32545467450354726, -0.11713473474653795, 0.2014979513549984 ])
3862 * //
3863 * e = k.eigSymmetric({mat:m,nEigModes:2,highest:true,method:'subspace'});
3864 * ls = e[0];
3865 * ps = e[1];
3866 * l3 = ls[1]; // l3 = 2.948867853467429
3867 * l4 = ls[0]; // l4 = 4.938274734810245
3868 * p3 = ps[1]; // p3 = Vector([ 0.14681878659487543, -0.007507144503266177, -0.21233717286242818, -0.5016212772448967 ])
3869 * p4 = ps[0]; // p4 = Vector([ 0.3022519091588433, 0.585847242190032, 0.09630780190740544, 0.028264211960396433 ])
3870 * //
3871 * c1 = k.x(p1).sub(m.x(p1).x(l1)); // c1 = Vector([0,0,0,0])
3872 * c2 = k.x(p2).sub(m.x(p2).x(l2)); // c2 = Vector([0,0,0,0])
3873 * c3 = k.x(p3).sub(m.x(p3) .x(l3)); // c3 = Vector([0,0,0,0])
3874 * c4 = k.x(p4).sub(m.x(p4).x(l4)); // c4 = Vector([0,0,0,0])
3875 */
3876 Matrix.prototype.eigSymmetric = function(params) {
3877 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.eigSymmetric: matrix is not square');*/ return null; }
3878 	var params = params || {};
3879 	var mat = params.mat || Matrix.Identity(this.nRows,this.nCols);
3880 	if (!mat.isSquare() || !this.isSameSizeAs(mat)) { /*jsmLogger.warn('Matrix.eigSymmetric: dimensions mismatched');*/ return null; }
3881 	var nEigModes = params.nEigModes || this.nRows; // nEigModes first eigenvalues and eigenvectors will be returned
3882 	if (nEigModes=="all") { nEigModes = this.nRows; }
3883 	else if (nEigModes > this.nRows) { nEigModes = this.nRows; }
3884 	var method = params.method || "default";
3885 	var highest = params.highest || false;
3886 	var maxiter = params.maxiter || 1000;
3887 	if (method=="default" || method=="invit") { // Stodola's inverse iteration with Gramm-Schmidt orthogonalization
3888 		var DM = highest? mat.inv().mulm(this) : this.inv().mulm(mat)
3889 		var eigVals = [];
3890 		var eigVecs = [];
3891 		var eigVecsMulmM = [];
3892 		var rho, rhoRatio, rhoNew, iter;
3893 		var xk = Vector.Zeros(this.nRows);
3894 		for (var k=0; k<nEigModes; k++) {
3895 			xk.one();
3896 			iter = 0;
3897 			rhoNew = 0.;
3898 			do {
3899 				xk = DM.mulv(xk);
3900 				for (var j=0; j<k; j++) { xk.isub(eigVecs[j].mulf(eigVecsMulmM[j].dot(xk))); } // Gramm-Schmidt orthogonalization
3901 				xk.imulf(1./xk.energyNorm(mat));
3902 				rho = rhoNew;
3903 				rhoNew = xk.squaredEnergyNorm(this) / xk.squaredEnergyNorm(mat)
3904 				rhoRatio = Math.abs((rhoNew-rho)/rhoNew);
3905 				iter++;
3906 				if (iter > maxiter) {
3907 					if (rhoRatio > JSM_TOL) {
3908 						/*jsmLogger.warn('Matrix.eigSymmetric: maximum number of iterations reached');*/
3909 						return null;
3910 					}
3911 					break;
3912 				}
3913 			} while (rhoRatio > JSM_TOL2)
3914 			eigVals[k] = rhoNew;
3915 			eigVecs[k] = xk.copy();
3916 			eigVecsMulmM[k] = xk.mulm(mat);
3917 		}
3918 		return [eigVals,eigVecs];
3919 	}
3920 	if (method == "subspace") { // subspace iteration
3921 		var eigVals = [];
3922 		var eigVecs = [];
3923 		var n = this.nRows;
3924 		var kk, mm, r, q;
3925 		var rhos, rhosRatio, rhoNews, maxRhosRatio, iter;
3926 		var xk = Vector.Zeros(this.nRows);
3927 		x = Matrix.Ones(n,nEigModes);
3928 		for (var i=0; i<n; i++) { x.set(i,i,0.); }
3929 		lu = highest? mat.luDecomposition() : this.luDecomposition()
3930 		rhosNew = [];
3931 		for (var n=0; n<nEigModes; n++) { rhosNew[n] = 0.; }
3932 		rhosRatio = rhosNew.slice();
3933 		iter = 0;
3934 		do {
3935 			x = highest? mat.linSolve(this.mulm(x),"lu",false,lu) : this.linSolve(mat.mulm(x),"lu",false,lu)
3936 			kk = x.transposed().mulm(this).mulm(x);
3937 			mm = x.transposed().mulm(mat).mulm(x);
3938 			r = kk.eigSymmetric({mat:mm,nEigModes:nEigModes,highest:highest});
3939 			q = Matrix.Zeros(nEigModes,nEigModes);
3940 			for (var j=0; j<nEigModes; j++) {
3941 				q.setCol(j,r[1][j]);
3942 			}
3943 			x = x.mulm(q);
3944 			rhos = rhosNew.slice();
3945 			rhosNew = r[0].slice();
3946 			for (var n=0; n<nEigModes; n++) { rhosRatio[n] = Math.abs((rhosNew[n] - rhos[n])/rhosNew[n]); }
3947 			maxRhosRatio = 0.;
3948 			for (var n=0; n<nEigModes; n++) {
3949 				if (rhosRatio[n] > maxRhosRatio) { maxRhosRatio = rhosRatio[n]; }
3950 			}
3951 			iter++;
3952 			if (iter > maxiter) {
3953 				if (maxRhosRatio > JSM_TOL) {
3954 					return null;
3955 					/*jsmLogger.warn('Matrix.eigSymmetric: maximum number of iterations reached');*/
3956 				}
3957 				break;
3958 			}
3959 		} while (maxRhosRatio > JSM_TOL2)
3960 		for (var i=0; i<nEigModes; i++) {
3961 			eigVals.push(r[0][i]);
3962 			eigVecs.push(x.getCol(i));
3963 		}
3964 		return [eigVals,eigVecs];
3965 	}
3966 	params.method = "default";
3967 	return this.eig(params);
3968 }
3969 
3970 /** Returns eigenvalues of receiver (this*x = ret*x)
3971 * @param {string} [method="default"] method of solution. "default and "schur" stand for similar transformation of receiver into schur form
3972 * @returns {[floats]} eigenvalues of receiver
3973 * @example
3974 * m1 = mat([[4,2,3,1],[3,6,5,7],[5,3,8,1],[2,3,4,5]]);
3975 * v1 = m1.schurForm().diag().toArray();
3976 * // v1 = [15.6072, 4.1916, 2.2012, 1 ]
3977 * v2 = m1.eigVals();
3978 * // v2 = [15.6072, 4.1916, 2.2012, 1 ]
3979 */
3980 Matrix.prototype.eigVals = function(method) {
3981 	var method = method || "default";
3982 	method = method.toLowerCase();
3983 	if (method=="default" || method=="schur") {
3984 		return this.schurForm().diagonalToVector().toArray();
3985 	}
3986 	return this.eigVals("default");
3987 }
3988 
3989 /** Returns orthogonal matrix Q and diagonal matrix L of eigendecomposition of the receiver such that this=P*L*P^-1 (obtained from eigenvalue equation this*P = P*L). If receiver is symmetric, P is orthogonal. Columns of P are eigenvectors of this and diagonal elements of L are corresponding eigenvalues
3990 * @param {string} [method="default"] method of eigenvalues solution. See {@link Matrix#eig}
3991 * @returns {[Matrix,Matrix]} [P,L] matrix P and diagonal matrix L of eigendecomposition of receiver
3992 * @example
3993 * m1 = mat([[4,2,3,1],[3,6,5,7],[5,3,8,1],[2,3,4,5]]);
3994 * pl = m1.eigenDecomposition()
3995 * p = pl[0]
3996 * l = pl[1]
3997 * // p =
3998 * // l =
3999 * c = p.mulm(l).mulm(p.inv())
4000 * // c = 
4001 */
4002 Matrix.prototype.eigenDecomposition = function(method,precompSchurDecomp) {
4003 	if (!this.isSquare) { /*jsmLogger.warn('Matrix.eigenDecomposition: matrix is not square');*/ return null; }
4004 	var method = method || "default"
4005 	if (method=="default") {
4006 		var i, j, n=this.nRows;
4007 		var sd = precompSchurDecomp? precompSchurDecomp : this.schurDecomposition()
4008 		var q = sd[0];
4009 		var s = sd[1];
4010 		var l = new Matrix(n,n);
4011 		for (i=0; i<n; i++) { l[i][i] = s[i][i]; }
4012 		var p = Matrix.Zeros(n,n);
4013 		var t11 = new Matrix(), nn, lambda, v = new Vector(), y = new Vector(n);
4014 		p.setCol(0,q.getCol(0));
4015 		for (i=1; i<n; i++) {
4016 			ii = range(i);
4017 			t11.beSubMatrixOf(s,ii,ii);
4018 			lambda = s[i][i];
4019 			v.resize(i);
4020 			for (j=0; j<i; j++) {
4021 				t11[j][j] -= lambda;
4022 				v[j] = s[j][i];
4023 			}
4024 			y.beSolutionOf(t11,v);
4025 			y.negate();
4026 			y.appendElements(1.);
4027 			y.resize(n);
4028 			p.setCol(i,q.mulv(y));				
4029 		}
4030 		return [p,l];
4031 	}
4032 	if (method=="symm" || method=="symmeig" || method=="eigsymm" || method=="eigsymmetric") {
4033 		var n = this.nRows;
4034 		var e = this.eigSymmetric();
4035 		var p = Matrix.Zeros(n,n);
4036 		var l = Matrix.Zeros(n,n);
4037 		for (var i=0; i<n; i++) {
4038 			p.setCol(i,e[1][i]);
4039 			l[i][i] = e[0][i];
4040 		}
4041 		return [p,l]
4042 	}
4043 	return this.eigenDecomposition("default")
4044 }
4045 
4046 
4047 /** Returns spectral decomposition of receiver, identical to {@link Matrix#eigenDecomposition}
4048 * @function
4049 */
4050 Matrix.prototype.spectralDecomposition = Matrix.prototype.eigenDecomposition;
4051 
4052 /* * Returns generalized eigenvalues of receiver (this*x = ret*mat*x)
4053 * @param {Matrix} mat matrix in generalized eigenvalue equation this*x = ret*mat*x
4054 * @param {string} [method="default"] method of solution. "default and "inv" stand for solution mat-1*this*x = ret*x (standard eigenvalue problem), "qz" for qz decomposition
4055 * @returns {[floats]} eigenvalues of receiver
4056 * @ example
4057 * /
4058 generalizedEigVals: function(mat,method) {
4059 	var method = method || "default";
4060 	method = method.toLowerCase();
4061 	if (method=="default" || method=="inv") {
4062 		return mat.inv().mulm(this).eigVals();
4063 	}
4064 	if (method=="qz" || method=="qzdecomposition") {
4065 		var qz = this.qzDecomposition(mat);
4066 		//TODO
4067 		return null;
4068 	}
4069 	return this.generalizedEigVals(mat);
4070 }
4071 */
4072 
4073 /** Returns inversion of receiver
4074 * @param {string} [method="default"] method used for solution. Options are "default" and "gaussjordan" for Gauss-Jordan method, "lu" for solution with LU decomposition, "eigen" with eigen decomposition, "symmeigen" with eigen decomposition when receiver is symmetric, "svd" for SVD decomposition
4075 * @param {[Matrices]} [precompDecomps=undefined] precomputed matrix decompositions if we want to use some
4076 * @returns {Matrix} inversion of receiver
4077 * @example
4078 * a = mat([[1,2,2],[1,0,1],[1,2,1]]);
4079 * i1 = a.inversed(); // i1 =
4080 * c = a.mulm(i1) // c = Matrix([[1,0,0],[0,1,0],[0,0,1]])
4081 * i2 = a.inversed('lu') // i2 = Matrix([[-1,1,1],[0,-0.5,0.5],[1,0,-1]])
4082 * i3 = a.inversed('eigen') // i3 = Matrix([[-1,1,1],[0,-0.5,0.5],[1,0,-1]])
4083 * i4 = a.inversed('svd') // i4 = Matrix([[-1,1,1],[0,-0.5,0.5],[1,0,-1]])
4084 * check = a.x(i1); // check = Matrix([[1,0,0],[0,1,0],[0,0,1]])
4085 */
4086 Matrix.prototype.inversed = function(method,precompDecomps) {
4087 	if (!this.isSquare) { /*jsmLogger.warn('Matrix.inversed: matrix is not square');*/ return null; }
4088 	var method = method || "default";
4089 	method = method.toLowerCase();
4090 	if (method=="default" || method=="gaussjordan") {
4091 		/* solves this*ret = I with Gauss-Jordan ellimination*/
4092 		return this.gaussJordanElimination(Matrix.Identity(this.nRows,this.nRows));
4093 	}
4094 	if (method=="lu") {
4095 		/* solves this*ret[:,i] = I[:,i] for i=0,1,..,this.nRows with the help of LU decomposition*/
4096 		var lu = precompDecomps? precompDecomps : this.luDecomposition();
4097 		var n = this.nRows;
4098 		var ret = new Matrix(n,n);
4099 		var vec = Vector.Zeros(n);
4100 		for (var i=0; i<n; i++) {
4101 			vec.zero();
4102 			vec[i] = 1.;
4103 			this.linSolve(vec,"lu",false,lu);
4104 			ret.setCol(i,vec)
4105 		}
4106 		return ret;
4107 	}
4108 	if (method=="chol" || method=='cholesky') {
4109 		/* solves this*ret[:,i] = I[:,i] for i=0,1,..,this.nRows with the help of Cholesky decomposition*/
4110 		var l = precompDecomps? precompDecomps : this.choleskyDecomposition();
4111 		if (l==null) { return null; }
4112 		var n = this.nRows;
4113 		var ret = new Matrix(n,n);
4114 		var vec = Vector.Zeros(n);
4115 		for (var i=0; i<n; i++) {
4116 			vec.zero();
4117 			vec[i] = 1.;
4118 			this.linSolve(vec,"cholesky",false,l);
4119 			ret.setCol(i,vec)
4120 		}
4121 		return ret;
4122 	}
4123 	if (method=="eigen" || method=="eig") {
4124 		/* this = V*L*V^-1 -> this^-1=V*L^-1*V^-1. As L is diagonal, the inversion is easy to compute*/
4125 		var e = precompDecomps? precompDecomps : this.eigenDecomposition();
4126 		var p = e[0];
4127 		var l = e[1];
4128 		for (var i=0; i<this.nRows; i++) { l[i][i] = 1./l[i][i]; }
4129 		return p.mulm(l).mulm(p.inversed());
4130 	}
4131 	if (method=="symmeig" || method=="eigsymm" || method=="eigsymmetric") {
4132 		var e = precompDecomps? precompDecomps : this.eigenDecomposition("symm");
4133 		var p = e[0];
4134 		var l = e[1];
4135 		for (var i=0; i<this.nRows; i++) { l[i][i] = 1./l[i][i]; }
4136 		return p.mulm(l).mulm(p.transposed());
4137 	}
4138 	if (method=="svd") {
4139 		svd = precompDecomps? precompDecomps : this.singularValueDecomposition();
4140 		var u=svd[0], s=svd[1], v=svd[2];
4141 		var n = s.nElements;
4142 		var ss = new Matrix(n,n);
4143 		for (var i=0; i<n; i++) { if (s[i] > JSM_TOL) { ss[i][i] = 1./s[i]; } }
4144 		return v.mulm(ss).mulm(u.transposed());
4145 	}
4146 	return this.inversed("default");
4147 }
4148 
4149 /** Alias for inversion, see {@link Matrix#inversed}
4150 * @function
4151 */
4152 Matrix.prototype.inv = Matrix.prototype.inversed;
4153 
4154 /** Sets receiver as an inversion of given matrix
4155 * @param {Matrices} mat given matrix
4156 * @param {string} [method="default"] see {@link Matrix#inversed} for details}
4157 * @param {[Matrices]} [precompDecomps=undefined] precomputed matrix decompositions if we want to use some
4158 * @example
4159 * m1 = mat([[1],[2]]);
4160 * m2 = mat([[1,2,2],[1,0,1],[1,2,1]]);
4161 * m1.beInverseOf(m2); // m1 = Matrix([[2.3,-1.4,-0.8],[-1.4,1.2,0.4],[-0.8,0.4,0.8]])
4162 */
4163 Matrix.prototype.beInverseOf = function(mat,method,precompDecomps) {
4164 	if (!mat.isSquare()) { /*jsmLogger.warn('Matrix.beInverseOf: matrix is not square');*/ return; }
4165 	var method = method || "default";
4166 	method = method.toLowerCase();
4167 	if (method=="default" || method=="gaussjordan") {
4168 		var temp = mat.copy();
4169 		this.beUnitMatrix(mat.nRows);
4170 		temp.gaussJordanElimination(this,"nopivot",false)
4171 		return
4172 	} else { // TODO
4173 		this.beCopyOf(mat.inversed(method,precompDecomps));
4174 	}
4175 	this.beInverseOf(mat,"default",precompDecomps);
4176 }
4177 
4178 /** Returns determinant of receiver.
4179 * @param {string} [method="default"] used method. Options are "default" and "lu" for using LU decomposition, "schurForm" or "schur" for using schur form, "schurDecomposition" for using schur decomposition, "eigen" or "eigenDecomposition" for using eigendecomposition
4180 * @param {[Matrices]} precompDecomps precomputed matrix decompositions if we want to use some
4181 * @returns {float} determinant of receiver
4182 * @example
4183 * a = mat([[4,2,1],[2,5,3],[1,3,6]]);
4184 * d = a.determinant(); // d = 67
4185 * d = a.determinant('schur'); // d = 67
4186 * d = a.determinant('schurdecomposition'); // d = 67
4187 * d = a.determinant('eigen'); // d = 67
4188 */
4189 Matrix.prototype.determinant = function(method,precompDecomps) {
4190 	if (!this.isSquare()) { /*jsmLogger.warn('Matrix.determinant: matrix is not square');*/ return null; }
4191 	var method = method || "default"
4192 	method = method.toLowerCase();
4193 	var mats = precompDecomps || undefined
4194 	if (method=="default" || method=="lu") {
4195 		// transform matrix to lower and upper triangular. Determinant is then product of diagonal elements. As L has 1. on diagonal, det is product of diagnal elements of U only
4196 		u = precompDecomps? precompDecomps[1] : this.luDecomposition()[1];
4197 		return u.diagProduct();
4198 	}
4199 	if (method=="schurform" || method=="schur") {
4200 		// create schur form (upper triangular matrix with eigenvalues on diagonal). It is triangular, so det is product of diagonal elements (as well as product of eigenvalues)
4201 		var s = precompDecomps? precompDecomps : this.schurForm();
4202 		return s.diagProduct();
4203 	}
4204 	if (method=="schurdecomposition") {
4205 		// see case:"schurform"
4206 		var s = precompDecomps? precompDecomps : this.schurDecomposition()[1];
4207 		return s.diagProduct();
4208 	}
4209 	if (method=="eigen" || method=="eigendecomposition") {
4210 		var l = precompDecomps? precompDecomps[1] : this.eigenDecomposition()[1]
4211 		return l.diagProduct();
4212 	}
4213 	return this.determinant("default",precompDecomps);
4214 }
4215 
4216 /** Alias for determinant, see {@link Matrix#determinant}
4217 * @function
4218 */
4219 Matrix.prototype.det = Matrix.prototype.determinant;
4220 
4221 /** Alias for determinant, see {@link Matrix#determinant}
4222 * @function
4223 */
4224 Matrix.prototype.giveDeterminant = Matrix.prototype.determinant;
4225 
4226 /** Constructs new Matrix from given 2D array
4227 * @param {[floats](2D)} [arry=[]] array containing elements of new matrix
4228 * @returns {Matrix} new Matrix object
4229 * @example
4230 * m = Matrix.create([[1,2,3],[4,5,6],[7,8,9]]) // m = Matrix([[1,2,3],[4,5,6],[7,8,9]])
4231 */
4232 Matrix.create = function(arry) {
4233 	if (arry==undefined) { return new Matrix(); }
4234 	if (arry.length==0) { return new Matrix(); }
4235 	var a = arry;
4236 	var nRows = a.length, nCols = a[0].length, r, c;
4237 	ret = new Matrix();
4238 	for (var r=0; r<nRows; r++) {
4239 		ret[r] = {};
4240 		for (var c=0; c<nCols; c++) {
4241 			ret[r][c] = arry[r][c];
4242 		}
4243 	}
4244 	ret.nRows = nRows;
4245 	ret.nCols = nCols;
4246 	return ret;
4247 }
4248 
4249 /** Constructs new diagonal matrix from given 1D array
4250 * @param {[floats]|Vector} arry array or vector containing elements of new matrix
4251 * @returns {Matrix} new Matrix object 
4252 * @example
4253 * m1 = Matrix.Diagonal([1,2,3]); // m1 = Matrix([[1,0,0],[0,2,0],[0,0,3]])
4254 * m2 = Matrix.Diagonal(vec([1,2,3])); // m2 = Matrix([[1,0,0],[0,2,0],[0,0,3]])
4255 */
4256 Matrix.Diagonal = function(arry) {
4257 	var s = arry.nElements==undefined? arry.length : arry.nElements;
4258 	var ret = new Matrix(s,s);
4259 	for (var i=0; i<s; i++) {
4260 		ret[i][i] = arry[i];
4261 	}
4262 	return ret;
4263 }
4264 
4265 /** Constructs new identity matrix of given size
4266 * @param {int} size size of returned matrix
4267 * @returns {Matrix} identity matri
4268 * @example
4269 * m = Matrix.Identity(4) // m = Matrix([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])
4270 */
4271 Matrix.Identity = function(size) {
4272 	var ret = new Matrix(size,size);
4273 	for (var i=0; i<size; i++) {
4274 		ret[i][i] = 1.;
4275 	}
4276 	return ret;
4277 }
4278 
4279 /** Alias for Matrix.Identity(), see {@link Matrix#Identity}
4280 * @function
4281 */
4282 Matrix.I =  Matrix.Identity;
4283 
4284 /** Alias for Matrix.Identity(), see {@link Matrix#Identity}
4285 * @function
4286 */
4287 Matrix.UnitMatrix = Matrix.Identity;
4288 
4289 /** Creates a matrix of given size full of zeros
4290 * @param {int} [nRows=0] number of rows
4291 * @param {int} [nCols=0] number of columns
4292 * @returns {Matrix} new matrix full of zero
4293 * @example
4294 * m = Matrix.Zeros(2,3); // m = Matrix([[0,0,0],[0,0,0]])
4295 */
4296 Matrix.Zeros = function(nRows,nCols) {
4297 	return new Matrix(nRows,nCols);
4298 }
4299 
4300 /** Creates a matrix of given size full of ones
4301 * @param {int} [nRows=0] number of rows
4302 * @param {int} [nCols=0] number of columns
4303 * @returns {Matrix} new vector full of zero
4304 * @example
4305 * m = Matrix.Ones(2,3); // m = Matrix([[1,1,1],[1,1,1]])
4306 */
4307 Matrix.Ones = function(nRows,nCols) {
4308 	var nRows = nRows || 0;
4309 	var nCols = nCols || 0;
4310 	var ret = new Matrix();
4311 	for (var r=0; r<nRows; r++) {
4312 		ret[r] = {};
4313 		for (var c=0; c<nCols; c++) {
4314 			ret[r][c] = 1.;
4315 		}
4316 	}
4317 	ret.nRows = nRows;
4318 	ret.nCols = nCols;
4319 	return ret;
4320 }
4321 
4322 /** Creates a Householder matrix from given vector (ret = I - 2*v*v^T/(v^T*v). Householder matrix is symmetric, orthogonal and involutary
4323 * @param {Vector} vec=0 Householder vector to form Householder matrix
4324 * @param {Matrix} [precompI=undefined] precomputed identity matrix to save some time of creation
4325 * @returns {Matrix} Householder matrix
4326 * @example
4327 * m1 = Matrix.Householder(vec([0,1,0]))
4328 * // m1 = Matrix([[1,0,0],[0,-1,0],[0,0,1]])
4329 * b1 = m1.isSymmetric() // b1 = true
4330 * b2 = m1.isOrthogonal() // b2 = true
4331 * b3 = m1.isInvolutary() // b3 = true
4332 * m2 = mat([[1,2,3],[4,5,6],[7,8,9]]);
4333 * v = m2.getCol(0);
4334 * q = Matrix.Householder(v.sub(vec([1,0,0]).mulf(v.norm())));
4335 * m3 = q.mulm(m2);
4336 * // m3 = 
4337 */
4338 Matrix.Householder = function(vec,precompI) {
4339 	var nElements = vec.nElements==undefined? vec.length : vec.nElements;
4340 	return (precompI? precompI : Matrix.Identity(nElements)).sub(vec.dyadic(vec).mulf(2./vec.dot(vec)));
4341 }
4342 
4343 
4344 
4345 
4346 
4347 
4348 
4349 /* **************************************************
4350 *
4351 * Initializing functions (shotcuts constructors)
4352 *
4353 ***************************************************/
4354 
4355 /** Returns new Matrix object from given array
4356 * @param {[floats](2D)} [arry=[]] array containing matrix elements
4357 * @returns {Matrix} new Matrix object
4358 * @example
4359 * m = mat([[1,2,3],[4,5,6],[7,8,9]]) // m = Matrix([[1,2,3],[4,5,6],[7,8,9]])
4360 */
4361 mat = Matrix.create;
4362 
4363 /** Returns new Vector object from given array
4364 * @param {[floats]} [arry=[]] array containing vector elements
4365 * @returns {Vector} new Vector object
4366 * @example
4367 * v = vec([1,2,3,4]) // v = Vector([1,2,3,4])
4368 */
4369 vec = Vector.create;
4370 
4371 /** Returns new Vector or Matrix full of given size full of zeros
4372 * @param {int} nRows number of rows of returned object
4373 * @param {int} [nCols] if specified, new Matrix of size (nRows,nCols) is returned, new vector of size nRows otherwise
4374 * @returns {Matrix|Vector} new Matrix or Vector object
4375 * @example
4376 * m = zeros(2,3); // m = Matrix([[0,0,0],[0,0,0]])
4377 * v = zeros(4) // v = Vector([0,0,0,0])
4378 */
4379 zeros = function(nRows,nCols) {
4380 	if (nCols) { return Matrix.Zeros(nRows,nCols); }
4381 	if (nRows) { return Vector.Zeros(nRows); }
4382 	return null;
4383 }
4384 
4385 /** Returns new Vector or Matrix full of given size full of ones
4386 * @param {int} nRows number of rows of returned object
4387 * @param {int} [nCols] if specified, new Matrix of size (nRows,nCols) is returned, new vector of size nRows otherwise
4388 * @returns {Matrix|Vector} new Matrix or Vector object
4389 * @example
4390 * m = zeros(2,3); // m = Matrix([[1,1,1],[1,1,1]])
4391 * v = zeros(4) // v = Vector([1,1,1,1])
4392 */
4393 ones = function(nRows,nCols) {
4394 	if (nCols) { return Matrix.Ones(nRows,nCols); }
4395 	if (nRows) { return Vector.Ones(nRows); }
4396 	return null;
4397 }
4398 
4399 /** Returned identity matrix of given size, see {@link Matrix#Identity}
4400 * @param {int} size number of rows and columns of returned matrix
4401 * @returns {Matrix} nRows x nRows identity matrix
4402 * @example
4403 * m = identity(3); // m = Matrix([[1,0,0],[0,1,0],[0,0,1]])
4404 */
4405 identity = Matrix.Identity;
4406 
4407 /** Alias for dentity(), see {@link identity}
4408 */
4409 eye = Matrix.Identity;
4410 
4411 /** Alias for dentity(), see {@link identity}
4412 */
4413 unitMatrix = Matrix.Identity;
4414 
4415 
4416 /* ***********************************************************
4417 *
4418 * Other functions
4419 *
4420 ************************************************************/
4421 
4422 /** Linear system equation solver. Returns vector x as a solution of a*ret=rhs, see {@link Matrix#linSolve} for input desription
4423 * @param {Matrix} a
4424 * @param {Vector|[Vectors]|Matrix} rhs
4425 * @param {bool} [saveOrig=true]
4426 * @param {int} [method="default"]
4427 * @param {[Matrices]} [precompDecomps]
4428 * @returns {Vector|[Vectors]|Matrix} solution x of a*x=rhs
4429 */
4430 linSolve = function(a,rhs,saveOrig,method,precompDecomps) { return a.linSolve(rhs,saveOrig,method,precompDecomps); }
4431 
4432 
4433 /** Eigenvalues and eigenvectors solver. Returns first nEigModes eigenvales (lambda) and eigenvectors (phi) of problem mat1*phi=lambda*mat2*phi. See {@link Matrix#eig} for input description. Eigenvectors are normalized with respect to mat2
4434 * @param {Object} params object of parameters
4435 * @param {Matrix} params.mat1
4436 * @param {Matrix} [params.mat2=Matrix.Identity]
4437 * @param {int} [params.nEigModes=1]
4438 * @param {int} [method="default"]
4439 @param {bool} [params.highest=false]
4440 * @param {int} [params.maxiter=1000]
4441 * @returns {[[floats],[Vectors]]} [[lambda1,lambda2,...,lambdaN],[phi1,phi2,...,phiN]], lambdai is i-th eigenvale, phii is i-th eigenvector. N = nEigModes
4442 */
4443 eigSolve = function(params) { return params.mat1.eig({mat:params.mat2,nEigModes:params.nEigModes,method:params.method,highest:params.highest,maxiter:params.maxiter}); }
4444 
4445 
4446 
4447 /** Returns sequence (array) with start, stop, step. Inspired by <a href="www.python.org">Python</a> syntax
4448 * @param {float|int} a start/stop (according to b, see example)
4449 * @param {float|int} [b] stop
4450 * @param {float|int} [c=1] step
4451 * @returns {[floats]} array containing given sequence
4452 * @example
4453 * r = range(8);     // r = [0,1,2,3,4,5,6,7]
4454 * r = range(2,8);   // r = [2,3,4,5,7]
4455 * r = range(2,8,2); // r = [2,4,6]
4456 */
4457 range = function(a,b,c) {
4458 	var start;
4459 	var step;
4460 	var stop;
4461 	if (b==null && c==null) {
4462 		start = 0;
4463 		stop  = a;
4464 		step  = 1;
4465 	} else if (c==null) {
4466 		start = a;
4467 		stop  = b;
4468 		step  = 1;
4469 	} else {
4470 		start = a;
4471 		stop  = b;
4472 		step  = c;
4473 	}
4474 	var ret = []
4475 	var val = start;
4476 	while (val < stop) {
4477 		ret.push(val);
4478 		val += step;
4479 	}
4480 	return ret;
4481 }
4482 
4483 /**@ignore*/
4484 Array.prototype.indexOf = function(val) {
4485 	for (var i=0; i<this.length; i++) {
4486 		if (this[i] === val) { return i; }
4487 	}
4488 }
4489