1 /*! 2 * 3 * JSMatrix : JavaScript matrix and vector implementation 4 * version 0.5 (2011-09-19) 5 * 6 * Copyright (C) 2011 Jan Stransky 7 * 8 * Czech Technical University, Faculty of Civil Engineering, 9 * Department of Structural Mechanics, 166 29 Prague, Czech Republic 10 * 11 * 12 * This program 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 * This program 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. For more information see <a href="http://mech.fsv.cvut.cz/~stransky/software/jsmatrix/">project homepage</a>. The inspiration of publication "Press, W. H., Teukolsky, S. A., Vetterling, W. T. and Flannery, B. P. 2007. The Numerical Recipes: The Art of Scientific Computing, Third Edition" is gratefully acknowledged. 28 <br /><br/>JSMatrix is a free software distributed under <a href='http://www.gnu.org/licenses/gpl.html'>GNU GPL license</a>. 29 * @author <a href="http://mech.fsv.cvut.cz/~stransky/">Jan Stránský</a> 30 * @version 0.5 (2011-09-19) 31 */ 32 33 // constants for easier manipulation 34 /**constant*/ var JSM_GAUSS = 1; 35 /**constant*/ var JSM_GAUSSJORDAN = 2; 36 /**constant*/ var JSM_LU = 3; 37 /**constant*/ var JSM_LDU = 4; 38 /**constant*/ var JSM_CHOLESKY = 5; 39 /**constant*/ var JSM_QR = 6; 40 /**constant*/ var JSM_INV_IT = 7; 41 /**constant*/ var JSM_SUBSPACE = 8; 42 43 /**constant*/ var JSM_NOPIVOT = 9; 44 /**constant*/ var JSM_PARTPIVOT = 10; 45 /**constant*/ var JSM_FULLPIVOT = 11; 46 47 /**constant ( = 0 )*/ var X = 0; 48 /**constant ( = 1 )*/ var Y = 1; 49 /**constant ( = 2 )*/ var Z = 2; 50 /**constant ( = 1e-8)*/ var JSM_TOL = 1e-8; 51 52 /**@ignore*/ var JSM_DEBUG = 0; 53 if (JSM_DEBUG) { 54 /**@ignore*/ 55 assert = function(what,msg) { 56 if (!what) { alert("JSM_DEBUG:\n"+(msg||"")); } 57 } 58 } else { 59 /**@ignore*/ 60 assert = function() {} 61 } 62 63 64 65 66 67 /** Vector implementation 68 * @class represents a vector (1D matrix) of real (floating point) numbers*/ 69 Vector = function() { 70 /** @property {int} [nItems=0] Number of items (elements) of receiver*/ 71 this.nItems = 0; 72 /** @property {[floats]} [theArray=[]] array containing receiver's elements*/ 73 this.theArray = []; 74 } 75 Vector.prototype = { 76 /**#@+ 77 * @function 78 * @memberOf Vector# 79 */ 80 81 /** Zeros all elements of receiver 82 * @example v = vec([1,2,3,4]); 83 * v.zero(); // v = Vector([0,0,0,0])*/ 84 zero: function() { 85 for (var r=0; r<this.nItems; r++) { this.theArray[r] = 0.; } 86 }, 87 88 /** Returns size (numer of elements) of receiver 89 * @returns {int} length (number of elements) of receiver 90 * @example v = vec([1,5,8,2]); var s = v.size(); // s = 4*/ 91 size: function() { 92 return this.nItems; 93 }, 94 95 /** Testing vector equality 96 * @param {Vector} vec vector to be compared with receiver 97 * @returns {bool} true if this==vec, false otherwise 98 * @example a = vec([1,2,3]); 99 * b = vec([1,2,2.999999999]); 100 * c = vec([1,2,1]); 101 * t1 = a.isEqualTo(b); // t1 = true 102 * t2 = a.isEqualTo(c); // t2 = false*/ 103 isEqualTo: function(vec) { 104 if (!this.isSameSizeAs(vec)) { return false; } 105 var v = vec.theArray; 106 for (var r=0; r<this.nItems; r++) { 107 if (Math.abs(this.theArray[r]-v[r]) > JSM_TOL) { return false; } 108 } 109 return true; 110 }, 111 112 /** Returns one element of receiver ( ret = this[r] ) - numbering from 0 113 * @param {int} r index of row (element) to be get (numbering from 0) 114 * @returns {float} value of the r-th element 115 * @example v = vec([4,7,2,4]); a = v.get(1); // a = 7*/ 116 get: function(r) { 117 //assert(r < this.nItems,"Vector.get: r > this.nItems"); 118 return this.theArray[r]; 119 }, 120 121 /** Set one element of receiver ( this[r] = val ) - numbering from 0 122 * @param {int} r index of row (element) to be set (numbering from 0) 123 * @param {float} val value to be set 124 * @example v = vec([4,7,2,4]); v.set(1,68); // v = Vector([4,68,2,4])*/ 125 set: function(r,val) { 126 this.theArray[r] = val; 127 }, 128 129 /** Increment one element of receiver ( this[r] += val ) - numbering from 0 130 * @param {int} r index of row (element) to be incremented (numbering from 0) 131 * @param {float} val value to be add 132 * @example v = vec([4,7,2,4]); v.incr(1,4); // v = vec([4,11,2,4])*/ 133 incr: function(r,val) { 134 if (val) { this.theArray[r] += val; } 135 }, 136 137 /* 138 /* * Returns one element of receiver ( ret = this[r] ) - numbering from 1 139 * @param {int} r index of row (element) to be get (numbering from 1) 140 * @returns {float} value of the r-th element 141 * @example v = vec([4,7,2,4]); a = v.get1(1); // a = 4* / 142 get1: function(r) { 143 return this.theArray[r-1]; 144 }, 145 146 /* * Set one element of receiver ( this[r] = val ) - numbering from 1 147 * @param {int} r index of row (element) to be set (numbering from 1) 148 * @param {float} val value to be set 149 * @example 150 * v = vec([4,7,2,4]); v.set1(1,68); // v = vec([68,7,2,4])* / 151 set1: function(r,val) { 152 this.theArray[r-1] = val; 153 }, 154 155 /* * Increment one element of receiver ( this[r] += val ) - numbering from 1 156 * @param {int} r index of row (element) to be incremented (numbering from 1) 157 * @param {float} val value to be add 158 * @example v = vec([4,7,2,4]); v.incr1(1,4); // v = vec([8,7,2,4])* / 159 incr1: function(r,val) { 160 if (val) { this.theArray[r-1] += val; } 161 }, 162 */ 163 164 /** Testing vector's size equality 165 * @param {Vector} vec vector to be tested 166 * @returns {bool} true if vec and receiver has same size, false otherwise 167 * @example a = vec([1,2,3,4]); 168 * b = vec([5,6,7,8,9,10,11,12]); 169 * c = vec([13,14,15,16]); 170 * t1 = a.isSameSizeAs(b); // t1 = false 171 * t2 = a.isSameSizeAs(c); // t1 = true*/ 172 isSameSizeAs: function(vec) { 173 return (this.nItems==vec.nItems); 174 }, 175 176 /** Testing if receiver can multiply given matrix ( this^T * mat ) 177 * @param {Matrix} mat matrix to be tested 178 * @returns {bool} true if the multiplication is possible, false otherwise 179 * @example v = vec([1,2,3]); 180 * m1 = mat([[11,12,13],[21,22,23]]); 181 * m2 = [[11,12],[21,22],[31,32]]; 182 * t1 = v.canMultiplyMat(m1); // t1 = true 183 * t2 = v.canMultiplyMat(m2); // t2 = false*/ 184 canMultiplyMat: function(mat) { 185 return this.nItems==mat.nCols; 186 }, 187 188 /** Sets elements of receiver form given array 189 * @param {[floats]} arry array containing new receiver elements 190 * @example v.fromArray([3,6,5,2]); // v = Vector([3,6,5,2])*/ 191 fromArray: function(arry) { 192 this.nItems = arry.length; 193 this.theArray = arry.slice(); 194 }, 195 196 /** Returns elements of receiver as an array 197 * @returns {[floats]} array containing receiver's elements 198 * @example v =vec([3,4,5,6]); s = v.toArray(); // s = [3,4,5,6]*/ 199 toArray: function() { 200 return this.theArray.slice(); 201 }, 202 203 /** Returns sum of receiver and vector ( ret = this + vec ) 204 * @param {Vector} vec vector to be added 205 * @returns {Vector} sum of receiver and vec 206 * @example v1 = vec([1,2,3]); 207 * v2 = vec([6,1,5]); 208 * v3 = v1.add(v2); // v3 = Vector([7,3,8])*/ 209 add: function(vec) { 210 if (!this.isSameSizeAs(vec)) { return null; } 211 var v = vec.theArray; 212 var ret = []; 213 for (var r=0; r<this.nItems; r++) { ret[r] = this.theArray[r] + v[r]; } 214 return Vector.create(ret); 215 }, 216 217 /** Add given vector to receiver ( this += vec ) 218 * @param {Vector} vec vector to be added 219 * @example v1 = vec([1,2,3]); 220 * v2 = vec([6,1,5]); 221 * v1.iadd(v2); // v1 = Vector([7,3,8])*/ 222 iadd: function(vec) { 223 if (!this.isSameSizeAs(vec)) { return null; } 224 var v = vec.theArray; 225 for (var r=0; r<this.nItems; r++) { this.theArray[r] += v[r]; } 226 }, 227 228 /** Returns difference of receiver and vector ( ret = this - vec ) 229 * @param {Vector} vec vector to be substracted 230 * @returns {Vector} difference of receiver and vec 231 * @example v1 = vec([1,2,3]); 232 * v2 = vec([6,1,5]); 233 * v3 = v1.sub(v2); // v3 = Vector([-5,1,-2])*/ 234 sub: function(vec) { 235 if (!this.isSameSizeAs(vec)) { return null; } 236 var v = vec.theArray; 237 var ret = []; 238 for (var r=0; r<this.nItems; r++) { ret[r] = this.theArray[r] - v[r]; } 239 return Vector.create(ret); 240 }, 241 242 /** Substract given vector to receiver ( this -= vec ) 243 * @param {Vector} vec vector to be substracted 244 * @example v1 = vec([1,2,3]); 245 * v2 = vec([6,1,5]); 246 * v1.isub(v2); // v1 = Vector([-5,1,-2])*/ 247 isub: function(vec) { 248 if (!this.isSameSizeAs(vec)) { return null; } 249 var v = vec.theArray; 250 for (var r=0; r<this.nItems; r++) { this.theArray[r] -= v[r]; } 251 }, 252 253 /** Dot product of receiver and given vector 254 * @param {Vector} vec vector for dot product 255 * @param {int} [n=0] dot prodact will be made from first n elements. If not specified, zero or negative, all elements are used 256 * @returns {float} dot product of receiver and vec from first n elements 257 * @example v1 = vec([1,2,3]); 258 * v2 = vec([6,1,5]); 259 * d = v1.dot(v2,2); // d = 8*/ 260 dot: function(vec,n) { 261 var n = n || 0; 262 if (n<=0 || n>this.nItems) { n = this.nItems; } 263 if (n > vec.nItems) { return null; } 264 var v = vec.theArray; 265 var ret = 0.; 266 for (var r=0; r<n; r++) { ret += this.theArray[r]*v[r]; } 267 return ret; 268 }, 269 270 /** Returns squared (Eucleidian) norm of receiver (ret = this.dot(this) ) 271 * @returns {float} squared Eucleidian norm of receiver 272 * @example v = vec([4,2,4]); 273 * n = v.squaredNorm(); // n = 36*/ 274 squaredNorm: function() { 275 return this.dot(this); 276 }, 277 278 /** Returns (Eucleidian) norm of receiver (ret = sqrt(this.dot(this)) ) 279 * @returns {float} Eucleidian norm of receiver 280 * @example v = vec([4,2,4]); 281 * n = v.norm(); // n = 6*/ 282 norm: function() { 283 return Math.sqrt(this.dot(this)); 284 }, 285 286 /** Normlize receiver 287 * @example v = vec([4,2,4]); 288 * v.normalize(); // v = Vector([0.6666,0.5,0.66666])*/ 289 normalize: function() { 290 var n = this.norm(); 291 this.imulf(1/n); 292 }, 293 294 /** Returns normalized copy of receiver 295 * @returns {Vector} normalized copy of receiver 296 * @example v1 = vec([4,2,4]); 297 * v2 = v1.normalized(); // v2 = Vector([0.6666,0.5,0.66666])*/ 298 normalized: function() { 299 var ret = this.copy(); 300 ret.normalize(); 301 return ret; 302 }, 303 304 /** Returns outer (dyadic, tensor, ...) product of receiver and given vector 305 * @param {Vector} vec vector for multiplication 306 * @returns {Matrix} outer product of receiver and vec 307 * @example v1 = vec([1,2,3]); 308 * v2 = vec([4,5,6]); 309 * m = v1.outer(v2); // m = Matrix([[4,5,6],[8,10,12],[12,15,18]])*/ 310 outer: function(vec) { 311 var ret = []; 312 var v = vec.theArray; 313 for (var r=0; r<this.nItems; r++) { 314 ret[r] = []; 315 for (var c=0; c<v.length; c++) { ret[r][c] = this.theArray[r] * v[c]; } 316 } 317 return Matrix.create(ret); 318 }, 319 320 /** Returns vector (cross) product of receiver and given vector. Both receiver and given vector have to be of length 3. 321 * @param {Vector} vec vector for multiplication 322 * @returns {Vector} cross product of receiver and vec 323 * @example v1 = vec([1,2,3]); 324 * v2 = vec([4,5,6]); 325 * v3 = v1.cross(v2); // v = Vector([-3,6,-3])*/ 326 cross: function(vec) { 327 if (this.nItems!=3 || vec.nItems!=3) { return null; } 328 var v = vec.theArray; 329 return Vector.create([ 330 this.theArray[Y]*v[Z]-this.theArray[Z]*v[Y], 331 this.theArray[Z]*v[X]-this.theArray[X]*v[Z], 332 this.theArray[X]*v[Y]-this.theArray[Y]*v[X]]); 333 }, 334 335 /** Returns negative of receiver ( ret = -this ) 336 * @returns {Vector} negative of receiver 337 * @example v1 = vec([1,2,3]); 338 * v2 = v1.negated(); // v2 = Vector([-1,-2,-3])*/ 339 negated: function() { 340 var ret = this.copy(); 341 return ret.mulf(-1.); 342 }, 343 344 /** Alias for negated(), see {@link Vector#negated}*/ 345 neg: function() { return this.negated(); }, 346 347 /** Negate receiver ( ret *= -1., ret = -ret ) 348 * @example v1 = vec([1,2,3]); 349 * v1.negate(); // v1 = Vector([-1,-2,-3])*/ 350 negate: function() { 351 for (var r=0; r<this.nItems; r++) { this.theArray[r] *= -1.; } 352 }, 353 354 /** Alias for neagete(), see {@link Vector#negate}*/ 355 ineg: function() { this.negate(); }, 356 357 /** Returns receiver multiplied by float f ( ret = this * f ) 358 * @param {float} f float multiplier 359 * @returns {Vector} copy of receiver multiplied by f 360 * @example v1 = vec([1,2,3]); 361 * v2 = v1.mulf(3); // v2 = Vector([3,6,9])*/ 362 mulf: function(f) { 363 var ret = []; 364 for (var r=0; r<this.nItems; r++) { ret[r] = f*this.theArray[r]; } 365 return Vector.create(ret); 366 }, 367 368 /** Multiply receiver by float f ( this *= f ) 369 * @param {float} f float multiplier 370 * @example v = vec([1,2,3]); 371 * v.imulf(3); // v = Vector([3,6,9])*/ 372 imulf: function(f) { 373 for (var r=0; r<this.nItems; r++) { this.theArray[r] *= f; } 374 }, 375 376 /** Returns product of receiver and given matrix ( ret = this^T * mat ) 377 * @param {Matrix} mat matrix to multiply 378 * @returns {Vector} copy of receiver multiplied by mat 379 * @example v1 = vec([1,2,3]); 380 * m = mat([[11,12,13],[21,22,23],[31,32,33]]) 381 * v2 = v1.mulm(m); // v2 = Vector([146,152,158])*/ 382 mulm: function(mat) { 383 if (!this.canMultiplyMat(mat)) { return null; } 384 var m = mat.theArray; 385 var ret = []; 386 var temp; 387 for (var c=0; c<mat.nCols; c++) { 388 temp = 0.; 389 for (var r=0; r<this.nItems; r++) { 390 temp += this.theArray[r]*m[r][c]; 391 } 392 ret[c] = temp; 393 } 394 return Vector.create(ret); 395 }, 396 397 /** Returns product of receiver and given mltiplier (float or Matrix) 398 * @param {Matrix|float} what matrix or float to multiply 399 * @returns {Vector} copy of receiver multiplied by what 400 * @example v1 = vec([1,2,3]); 401 * v2 = v1.mul(mat([[11,12,13],[21,22,23],[31,32,33]])); // v2 = Vector([146,152,158]) 402 * v3 = v1.mul(3); // v3 = Vector([3,6,9])*/ 403 mul: function(what) { 404 if (what instanceof Matrix) { return this.mulm(what); } 405 if (typeof what == 'number') { return this.mulf(what); } 406 return null; 407 }, 408 409 /** Alias for mul(), see {@link Vector#mul}*/ 410 x: function(what) { return this.mul(what); }, 411 412 /** Returns subvector of receiver - numbering from 0 413 * @param {[floats]|Vector} items array containing row indices of desired subvector - numbering from 0 414 * @returns {Vector} desired subvector 415 * @example v1 = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]); 416 * v2 = v1.getsv([2,3,6,8,9]); // v2 = Vector([9,1,2,6,7])*/ 417 getsv: function(items) { 418 var items = items.theArray || items; 419 var n = items.length; 420 var ret = []; 421 for (var r=0; r<n; r++) { ret[r] = this.theArray[items[r]]; } 422 return Vector.create(ret); 423 }, 424 425 /** Set subvector to defined positions of receiver 426 * @param {[floats]|Vector} items array containing row indices to be set - numbering from 0 427 * @param {Vector|[floats]} vec vector to be set 428 * @example v = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]); 429 * v.setsv([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])*/ 430 setsv: function(items,vec) { 431 var v = vec.theArray || vec; 432 var items = items.theArray || items; 433 var n = items.length; 434 if (v.length != n) { return; } 435 for (var r=0; r<n; r++) { this.theArray[items[r]] = v[r]; } 436 }, 437 438 /** Increment subvector to defined positions of receiver 439 * @param {[floats]|Vector} items array containing row indices to be incremented - numbering from 0 440 * @param {Vector|[floats]} vec vector to be added 441 * @example v = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]); 442 * v.incrsv([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])*/ 443 incrsv: function(items,vec) { 444 var v = vec.theArray || vec; 445 var items = items.theArray || items; 446 var n = items.length; 447 if (v.length != n) { return; } 448 for (var r=0; r<n; r++) { this.theArray[items[r]] += v[r]; } 449 }, 450 451 /** Decrement subvector to defined positions of receiver 452 * @param {[floats]|Vector} items array containing row indices to be decremented - numbering from 0 453 * @param {Vector|[floats]} vec vector to be substracted 454 * @example v = vec([4,7,9,1,8,3,2,4,6,7,5,1,6,9]); 455 * v.decrsv([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])*/ 456 decrsv: function(items,vec) { 457 var v = vec.theArray || vec; 458 var items = items.theArray || items; 459 var n = items.length; 460 if (v.length != n) { return; } 461 for (var r=0; r<n; r++) { this.theArray[items[r]] -= v[r]; } 462 }, 463 464 /** Returns copy of receiver 465 * @returns {Vector} copy of receiver 466 * @example v1 = vec([1,2,3]); 467 * v2 = v1; 468 * v3 = v1.copy(); 469 * v1.set(1,6); 470 * // v1; = Vector([1,6,3]) 471 * // v2; = Vector([1,6,3]) 472 * // v3; = Vector([1,2,3])*/ 473 copy: function() { 474 var ret = new Vector(); 475 ret.fromArray(this.theArray.slice()); 476 return ret; 477 }, 478 479 /** Returns string representation of receiver 480 * @returns {string} string representation of receiver 481 * @example v1 = vec([1,2,3]); 482 * alert(v1); // alerts "Vector([ 1, 2, 3 ])"*/ 483 toString: function() { 484 var nn = this.nItems; 485 if (nn == 0) { return "Vector([])\n"; } 486 var ret = "Vector([ " 487 for (var r=0; r<nn-1; r++) { ret += this.theArray[r]+", "; } 488 ret += this.theArray[nn-1]+" ])\n"; 489 return ret; 490 }, 491 492 /** Swaps two items (items, elements..) of receiver - numbering from 0 493 * @param {int} r1 index of first row to swap - numbering from 0 494 * @param {int} r2 index of second row to swap - numbering from 0 495 * @example v = vec([1,2,3,4,5,6,7]); 496 * v.swapItems(1,4); // v = Vector([1,5,3,4,2,6,7])*/ 497 swapItems: function(r1,r2) { 498 var row1 = this.theArray[r1]; 499 this.theArray[r1] = this.theArray[r2]; 500 this.theArray[r2] = row1; 501 }, 502 503 /** Appends given float/vector to the end of receiver 504 * @param {float|Vector|[Vectors]} items new row(s) to be appended 505 * @example v = vec([1,2]); 506 * v.appendItems(4); // v = Vector([1,2,4]); 507 * v.appendItems(vec([7,6])); // v = Vector([1,2,4,7,6]); 508 * v.appendItems([vec([2,1]),vec([33,44])]); // v = Vector([1,2,4,7,6,2,1,33,44])*/ 509 appendItems: function(items) { 510 if (items instanceof Vector) { 511 for (var i=0; i<items.nItems; i++) { 512 this.theArray[this.nItems] = items.theArray[i]; 513 this.nItems++; 514 } 515 return; 516 } 517 if (items instanceof Array) { 518 for (var row=0; row<items.length; row++) { 519 this.appendItems(items[row]); 520 } 521 return; 522 } 523 if (typeof items == 'number') { 524 this.theArray[this.nItems] = items; 525 this.nItems++; 526 return; 527 } 528 }, 529 530 /** Permute items of receiver according to given indices 531 * @ param {[ints]|Vector} indx indices of permutation 532 * @ param {bool} [backward=false] if false, receiver is permutated to given indices (forward). If true, from given indices (backward) 533 * @ example v = vec([7,9,6]); 534 * v.permuteItems([1,2,0]); // v = Vector([9,6,7]) 535 * v.permuteItems([1,2,0],true); // v = Vector([7,9,6])*/ 536 permuteItems: function(indx,backward) { 537 var indx = indx.theArray || indx; 538 if (indx.length != this.nItems) { return; } 539 var backward = backward || false; 540 var newArry = []; 541 if (backward) { 542 for (var i=0; i<this.nItems; i++) { 543 newArry[i] = this.theArray[indx.indexOf(i)]; 544 } 545 this.fromArray(newArry); 546 return; 547 } 548 for (var i=0; i<this.nItems; i++) { 549 newArry[i] = this.theArray[indx[i]]; 550 } 551 this.fromArray(newArry); 552 }, 553 554 /** Returns permutated copy of receiver according to given indices 555 * @ param {[ints]|Vector} indx indices of permutation 556 * @ param {bool} [backward=false] if false, receiver is permutated to given indices (forward). If true, from given indices (backward) 557 * @returns {Vector} permutated copy of receiver 558 * @ example v1 = vec([7,9,6]); 559 * v2 = v1.itemPermutation([1,2,0]); // v2 = Vector([9,6,7]) 560 * v3 = v1.itemPermutation([1,2,0],true); // v3 = Vector([6,7,9])*/ 561 itemPermutation: function(indx,backward) { 562 var indx = indx.theArray || indx; 563 if (indx.length != this.nItems) { return null; } 564 var ret = this.copy(); 565 ret.permuteItems(indx,backward); 566 return ret; 567 }, 568 569 /** Resize receiver according to given size (delete extra elements or add zero elements) 570 * @param {int} nItems new number of items 571 * @example v1 = vec([4,7,9,1,7,3]) 572 * v2 = vec([4,6]); 573 * v1.resize(4); // v1 = Vector([4,7,9,1]) 574 * v2.resize(4); // v2 = Vector([4,6,0,0])*/ 575 resize: function(nItems) { 576 if (nItems==this.nItems) { return; } 577 if (nItems > this.nItems) { 578 for (var r=this.nItems; r<nItems; r++) { this.theArray[r] = 0.; } 579 this.nItems = nItems; 580 return; 581 } 582 if (nItems < this.nItems) { 583 this.theArray = this.theArray.slice(0,nItems); 584 this.nItems = nItems; 585 } 586 }, 587 /** Returns resized copy of receiver according to given size (delete extra elements or add zero elements) 588 * @param {int} nItems new number of items 589 * @returns {Vector} resized copy of receiver 590 * @example v1 = vec([4,7,9,1]); 591 * v2 = v1.resized(2); // v2 = Vector([4,7]) 592 * v3 = v1.resized(6); // v3 = Vector([4,7,9,1,0,0])*/ 593 resized: function(nItems) { 594 var ret = this.copy(); 595 ret.resize(nItems); 596 return ret; 597 }, 598 599 /** Returns matrix with receiver's elements on its diagonal 600 * @returns {Matrix} diagonal matrix with receiver's elements on its diagonal 601 * @example v = vec([1,2,3]); 602 * m = v.toDiagonalMatrix(); // m = Matrix([[1,0,0],[0,2,0],[0,0,3]])*/ 603 toDiagonalMatrix: function() { 604 var ret = Matrix.Zeros(this.nItems,this.nItems); 605 for (var r=0; r<this.nItems; r++) { ret.theArray[r][r] = this.theArray[r]; } 606 return ret; 607 }, 608 609 /** Alias for toDiagonalMatrix(), see {@link Vector#toDiagonalMatrix}*/ 610 diag: function() { return this.toDiagonalMatrix(); }, 611 612 /**#@-*/ 613 } 614 615 /** Constructs new Vector from given array 616 * @param {[floats]} [arry=[]] array containing elements of new vector 617 * @returns {Vector} new Vector object 618 * @example v = Vector.create([1,2,3,4]) // v = Vector([1,2,3,4])*/ 619 Vector.create = function(arry) { 620 var a = (arry==null)? []:arry.slice(); 621 var ret = new Vector(); 622 ret.fromArray(a); 623 return ret; 624 } 625 626 /** Creates unit vector in x direction 627 * @returns {Vector} unit x vector 628 * @example v = UnitX // v = Vector([1,0,0])*/ 629 Vector.UnitX = Vector.create([1,0,0]); 630 631 /** Creates unit vector in y direction 632 * @returns {Vector} unit y vector 633 * @example v = UnitX // v = Vector([0,1,0])*/ 634 Vector.UnitY = Vector.create([0,1,0]); 635 636 /** Creates unit vector in z direction 637 * @returns {Vector} unit z vector 638 * @example v = UnitX // v = Vector([0,0,1])*/ 639 Vector.UnitZ = Vector.create([0,0,1]); 640 641 /** Creates a vector full of zeros 642 * @param {int} [nItems=0] number of elements 643 * @returns {Vector} new vector full of zeros 644 * @example v = Vector.Zeros(4) // v = Vector([0,0,0,0])*/ 645 Vector.Zeros = function(nItems) { 646 var nItems = nItems || 0; 647 var arry = []; 648 for (var i=0; i<nItems; i++) { arry.push(0.); } 649 return Vector.create(arry); 650 } 651 652 /** Creates a vector full of ones 653 * @param {int} [nItems=0] number of elements 654 * @returns {Vector} new vector full of zeros 655 * @example v = Vector.Ones(6) // v = Vector([1,1,1,1,1,1])*/ 656 Vector.Ones = function(nItems) { 657 var nItems = nItems || 0; 658 var arry = []; 659 for (var i=0; i<nItems; i++) { arry.push(1.); } 660 return Vector.create(arry); 661 } 662 663 664 665 666 667 /** Matrix implementation 668 * @class represents a 2D matrix of real (floating point) numbers 669 * @property {int} [nRows=0] Number of rows of receiver 670 * @property {int} [nCols=0] Number of columns of receiver 671 * @property {[floats]} [theArray=[]] Array (2D) containing receiver's elements*/ 672 Matrix = function(nRows,nCols) { 673 this.nRows = nRows || 1; 674 this.nCols = nCols || 0; 675 this.theArray = [[]]; 676 } 677 Matrix.prototype = { 678 /**#@+ 679 * @function 680 * @memberOf Matrix# 681 */ 682 683 /** Zeros all elements of receiver 684 * @example m = mat([[1,2,3],[4,5,6],[7,8,9]]); 685 * m.zero(); // m = Matrix([[0,0,0],[0,0,0],[0,0,0]])*/ 686 zero: function() { 687 for (var r=0; r<this.nRows; r++) { 688 this.theArray[r] = [] 689 for (var c=0; c<this.nCols; c++) { this.theArray[r][c] = 0.; } 690 } 691 }, 692 693 /** Returns size of receiver as [nRows,nCols] 694 * @returns {[int,int]} array as [number of rows,number of columns] 695 * @example m = mat([[1,2,3],[4,5,6]]); 696 * s = m.size(); // s = [2,3]*/ 697 size: function() { 698 return [this.nRows,this.nCols]; 699 }, 700 701 /** Testing matrix equality 702 * @param {Matrix} mat matrix to be compared with receiver 703 * @returns {bool} true if this==mat, false otherwise 704 * @example a = mat([[1,2,3],[4,5,6],[7,8,9]]); 705 * b = mat([[1,2,2.999999999],[4.0000000000002,5,6],[7,8,8.9999999999]]); 706 * c = mat([[1,2,3],[4,5,6],[7,8,9],[10,11,12]]); 707 * t1 = a.isEqualTo(b); // t1 = true 708 * t2 = a.isEqualTo(c); // t2 = false*/ 709 isEqualTo: function(mat) { 710 if (!this.isSameSizeAs(mat)) { return false; } 711 var m = mat.theArray; 712 for (var r=0; r<this.nRows; r++) { 713 for (var c=0; c<this.nCols; c++) { 714 if (Math.abs(this.theArray[r][c] - m[r][c]) > JSM_TOL) { return false; } 715 } 716 } 717 return true; 718 }, 719 720 /** Returns one element of receiver ( ret = this[r,c] ) - numbering from 0 721 * @param {int} r index of row to be get (numbering from 0) 722 * @param {int} c index of column to be get (numbering from 0) 723 * @returns {float} value of the element at r-th row and c-th column 724 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 725 * g = m.get(1,2); // g = 23*/ 726 get: function(r,c) { 727 return this.theArray[r][c]; 728 }, 729 730 /** Set one element of receiver ( this[r,c] = val ) - numbering from 0 731 * @param {int} r index of row to be set (numbering from 0) 732 * @param {int} c index of column to be set (numbering from 0) 733 * @param {float} val value to be set 734 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 735 * m.set(1,2,3.45); // m = Matrix([[11,12,13],[21,22,3.45],[31,32,33]]) 736 */ 737 set: function(r,c,val) { 738 this.theArray[r][c] = val; 739 }, 740 741 /** Increment one element of receiver ( this[r,c] += val ) - numbering from 0 742 * @param {int} r index of row to be incremented (numbering from 0) 743 * @param {int} c index of column to be incremented (numbering from 0) 744 * @param {float} val value to be add 745 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 746 * m.incr(1,2,3.45); // m = Matrix([[11,12,13],[21,22,26.45],[31,32,33]]) 747 */ 748 incr: function(r,c,val) { 749 if (val) { this.theArray[r][c] += val; } 750 }, 751 752 /** Testing matrix size equality 753 * @param {Matrix} mat matrix to be tested 754 * @returns {bool} true if mat and receiver has same size, false otherwise 755 * @example a = mat([[1,2,3],[4,5,6]]); 756 * b = mat([[5,6,7],[8,9,10],[11,12,13]]); 757 * c = mat([[14,15,16],[17,18,19]]); 758 * t1 = a.isSameSizeAs(b); // t1 = false 759 * t2 = a.isSameSizeAs(c); // t1 = true*/ 760 isSameSizeAs: function(mat) { 761 return (this.nRows==mat.nRows && this.nCols==mat.nCols); 762 }, 763 764 /** Testing if receiver can multiply given matrix ( this * mat ) 765 * @param {Matrix} mat matrix to be tested 766 * @returns {bool} true if the multiplication is possible, false otherwise 767 * @example m1 = mat([[1,2,3],[4,5,6]]); 768 * m2 = mat([[7,8,9],[10,11,12]]); 769 * m3 = mat([[11,12],[21,22],[31,32]]); 770 * t1 = m1.canMultiplyMat(m2); // t1 = false 771 * t2 = m1.canMultiplyMat(m3); // t2 = true*/ 772 canMultiplyMat: function(mat) { 773 return (this.nCols==mat.nRows); 774 }, 775 776 /** Testing if receiver can multiply given vector ( this * vec ) 777 * @param {Vector} vec vector to be tested 778 * @returns {bool} true if the multiplication is possible, false otherwise 779 * @example m = mat([[1,2,3],[4,5,6]]); 780 * v1 = vec([1,2,3]); 781 * v2 = vec([4,5]); 782 * t1 = m.canMultiplyVec(v1); // t1 = true 783 * t2 = m.canMultiplyVec(v2); // t2 = false*/ 784 canMultiplyVec: function(vec) { 785 return (this.nCols==vec.nItems); 786 }, 787 788 /** Testing if receiver is square 789 * @returns {bool} true if receiver is square matrix, false otherwise 790 * @example m1 = mat([[1,2,3],[4,5,6]]); 791 * m2 = mat([[1,2,3],[4,5,6],[7,8,9]]); 792 * t1 = m1.isSquare(); // t1 = false 793 * t2 = m2.isSquare(); // t2 = true*/ 794 isSquare: function() { 795 return (this.nRows==this.nCols); 796 }, 797 798 /** Testing if receiver is symmetric matrix 799 * @returns {bool} true if receiver is symmetric, false otherwise 800 * @example m1 = mat([[11,12,13],[21,22,23],[31,32,33]]); 801 * m2 = mat([[11,12,13],[12,22,23],[13,23,33]]); 802 * t1 = m1.isSymmetric(); // t1 = false 803 * t2 = m2.isSymmetric(); // t2 = true*/ 804 isSymmetric: function() { 805 if (!this.isSquare()) { return false; } 806 for (var r=0; r<this.nRows; r++) { 807 for (var c=r+1; c<this.nCols; c++) { 808 if (Math.abs(this.theArray[r][c] - this.theArray[c][r]) > JSM_TOL) { return false; } 809 } 810 } 811 return true; 812 }, 813 814 /** Testing if receiver is lower triangular matrix 815 * @returns {bool} true if receiver is lower triangular, false otherwise 816 * @example m1 = mat([[1,2,3],[4,5,6],[7,8,9]]); 817 * m2 = mat([[1,0,0],[4,5,0],[7,8,9]]); 818 * t1 = m1.isLowerTriangular(); // t1 = false 819 * t2 = m2.isLowerTriangular(); // t2 = true*/ 820 isLowerTriangular: function() { 821 for (var r=0; r<this.nRows; r++) { 822 for (var c=r+1; c<this.nCols; c++) { 823 if (Math.abs(this.theArray[r][c]) > JSM_TOL) { return false; } 824 } 825 } 826 return true; 827 }, 828 829 /** Testing if receiver is upper triangular matrix 830 * @returns {bool} true if receiver is upper triangular, false otherwise 831 * @example m1 = mat([[1,2,3],[4,5,6],[7,8,9]]); 832 * m2 = mat([[1,2,3],[0,5,6],[0,0,9]]); 833 * t1 = m1.isUpperTriangular(); // t1 = false 834 * t2 = m2.isUpperTriangular(); // t2 = true*/ 835 isUpperTriangular: function() { 836 for (var r=0; r<this.nRows; r++) { 837 for (var c=0; c<r; c++) { 838 if (Math.abs(this.theArray[r][c]) > JSM_TOL) { return false; } 839 } 840 } 841 return true; 842 }, 843 844 /** Sets elements of receiver form given array 845 * @param {[floats](2D)} arry array containing new receiver elements 846 * @example m.fromArray([[1,2,3],[4,5,6],[7,8,9]]); // m = Matrix([[1,2,3],[4,5,6],[7,8,9]])*/ 847 fromArray: function(arry) { 848 this.nRows = arry.length; 849 if (this.nRows) { this.nCols = arry[0].length; } 850 else { this.nCols = 0; } 851 this.theArray = [] 852 for (var r=0; r<this.nRows; r++) { 853 this.theArray[r] = arry[r].slice(); 854 } 855 }, 856 857 /** Returns elements of receiver as an array 858 * @returns {[floats](2D)} array containing receiver's elements 859 * @example m =mat([[11,12],[21,22]]); 860 * a = m.toArray(); // a = [[11,12],[21,22]]*/ 861 toArray: function() { 862 var ret = [] 863 for (var r=0; r<this.nRows; r++) { ret[r] = this.theArray[r].slice(); } 864 return ret; 865 }, 866 867 /** Returns sum of receiver and matrix ( ret = this + mat ) 868 * @param {Matrix} mat vector to be added 869 * @returns {Matrix} sum of receiver and matrix 870 * @example m1 = mat([[1,2],[3,4]]); 871 * m2 = mat([[2,5],[3,2]]); 872 * m3 = m1.add(m2); // m3 = Matrix([[3,7],[6,6]])*/ 873 add: function(mat) { 874 if (!this.isSameSizeAs(mat)) { return null; } 875 var m = mat.theArray; 876 var ret = []; 877 for (var r=0; r<this.nRows; r++) { 878 ret[r] = []; 879 for (var c=0; c<this.nCols; c++) { ret[r][c] = this.theArray[r][c] + m[r][c]; } 880 } 881 return Matrix.create(ret); 882 }, 883 884 /** Add given matrix to receiver ( this += mat ) 885 * @param {Matrix} mat vector to be added 886 * @example m1 = mat([[1,2],[3,4]]); 887 * m2 = mat([[2,5],[3,2]]); 888 * m1.iadd(m2); // m1 = Matrix([[3,7],[6,6]])*/ 889 iadd: function(mat) { 890 if (!this.isSameSizeAs(mat)) { return null; } 891 var m = mat.theArray; 892 for (var r=0; r<this.nRows; r++) { 893 for (var c=0; c<this.nCols; c++) { this.theArray[r][c] += m[r][c]; } 894 } 895 }, 896 897 /** Returns difference of receiver and matrix ( ret = this - mat ) 898 * @param {Matrix} mat vector to be added 899 * @returns {Matrix} sum of receiver and matrix 900 * @example m1 = mat([[1,2],[3,4]]); 901 * m2 = mat([[2,5],[3,2]]); 902 * m3 = m1.sub(m2); // m3 = Matrix([[-1,-3],[0,2]])*/ 903 sub: function(mat) { 904 if (!this.isSameSizeAs(mat)) { return null; } 905 var m = mat.theArray; 906 var ret = []; 907 for (var r=0; r<this.nRows; r++) { 908 ret[r] = []; 909 for (var c=0; c<this.nCols; c++) { ret[r][c] = this.theArray[r][c] - m[r][c]; } 910 } 911 return Matrix.create(ret); 912 }, 913 914 /** Substract given matrix to receiver ( this -= mat ) 915 * @param {Matrix} mat vector to be added 916 * @example m1 = mat([[1,2],[3,4]]); 917 * m2 = mat([[2,5],[3,2]]); 918 * m1.isub(m2); // m1 = Matrix([[-1,-3],[0,2]])*/ 919 isub: function(mat) { 920 if (!this.isSameSizeAs(mat)) { return null; } 921 var m = mat.theArray; 922 for (var r=0; r<this.nRows; r++) { 923 for (var c=0; c<this.nCols; c++) { this.theArray[r][c] -= m[r][c]; } 924 } 925 }, 926 927 /** Returns negative of receiver ( ret = -this ) 928 * @returns {Matrix} negative of receiver 929 * @example m1 = mat([[1,2,3],[4,5,6]]); 930 * m2 = m1.negated(); // m2 = Matrix([[-1,-2,-3],[-4,-5,-6]])*/ 931 negated: function() { 932 var ret = this.copy() 933 return ret.mulf(-1.); 934 }, 935 936 /** Alias for neageted(), see {@link Matrix#negated}*/ 937 neg: function() { return this.negated(); }, 938 939 /** Negate receiver ( ret *= -1., ret = -ret ) 940 * @example m1 = mat([[1,2,3],[4,5,6]]); 941 * m1.negate(); // m1 = Matrix([[-1,-2,-3],[-4,-5,-6]])*/ 942 negate: function() { 943 for (var r=0; r<this.nRows; r++) { 944 for (var c=0; c<this.nCols; c++) { this.theArray[r][c] *= -1.; } 945 } 946 }, 947 948 /** Alias for neagete(), see {@link Matrix#negate}*/ 949 ineg: function() { this.negate(); }, 950 951 /** Returns one row of receiver - numbering from 0 952 * @param {int} r index of row to return - numbering from 0 953 * @returns {Vector} r-th row of receiver as vector 954 * @example m = m([[1,2,3],[4,5,6],[7,8,9]]); 955 * v = mat.getRow(1); // v = Vector([4,5,6])*/ 956 getRow: function(r) { 957 return Vector.create(this.theArray[r].slice()) 958 }, 959 960 /** Returns one column of receiver - numbering from 0 961 * @param {int} c index of column to return - numbering from 0 962 * @returns {Vector} c-th column of receiver as vector 963 * @example m = m([[1,2,3],[4,5,6],[7,8,9]]); 964 * v = mat.getCol(1); // v = Vector([2,5,8])*/ 965 getCol: function(c) { 966 var ret = [] 967 for (var r=0; r<this.nRows; r++) { ret[r] = this.theArray[r][c]; } 968 return Vector.create(ret); 969 }, 970 971 /** Sets one row of receiver - numbering from 0 972 * @param {int} r index of row to set - numbering from 0 973 * @param {Vector} vec vector to be set as new r-th row 974 * @example mat([[1,2,3],[4,5,6],[7,8,9]]); 975 * m.setRow(1,vec([11,12,13])); // m = Matrix([[1,2,3],[11,12,13],[7,8,9]])*/ 976 setRow: function(r,vec) { 977 if (this.nCols != vec.nItems) { return; } 978 var v = vec.theArray; 979 this.theArray[r] = v.slice(); 980 }, 981 982 /** Sets one column of receiver - numbering from 0 983 * @param {int} c index of column to set - numbering from 0 984 * @param {Vector} vec vector to be set as new r-th row 985 * @example m = mat([[1,2,3],[4,5,6],[7,8,9]]); 986 * m.setCol(1,vec([11,12,13])); // m = Matrix([[1,11,3],[4,12,6],[7,13,9]])*/ 987 setCol: function(c,vec) { 988 if (this.nRows != vec.nItems) { return; } 989 var v = vec.theArray; 990 for (var r=0; r<this.nRows; r++) { 991 this.theArray[r][c] = v[r]; 992 } 993 }, 994 995 /** Swaps two rows of receiver - numbering from 0 996 * @param {int} r1 index of first row to swap - numbering from 0 997 * @param {int} r2 index of second row to swap - numbering from 0 998 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 999 * m.swapRows(0,2); // m = Matrix([[31,32,33],[21,22,23],[11,12,13]])*/ 1000 swapRows: function(r1,r2) { 1001 var row1 = this.theArray[r1]; 1002 this.theArray[r1] = this.theArray[r2]; 1003 this.theArray[r2] = row1; 1004 }, 1005 1006 /** Swaps two columns of receiver - numbering from 0 1007 * @param {int} c1 index of first row to swap - numbering from 0 1008 * @param {int} c2 index of second row to swap - numbering from 0 1009 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 1010 * m.swapCols(0,2); // m = Matrix([[13,12,11],[23,22,21],[33,32,31]])*/ 1011 swapCols: function(c1,c2) { 1012 var temp 1013 for (var r=0; r<this.nRows; r++) { 1014 temp = this.theArray[r][c1]; 1015 this.theArray[r][c1] = this.theArray[r][c2]; 1016 this.theArray[r][c2] = temp; 1017 } 1018 }, 1019 1020 /** Permute rows of receiver according to given indices 1021 * @ param {[ints]|Vector} indx indices of row permutation 1022 * @ param {bool} [backward=false] if false, receiver's rows is permutated to given indices (forward). If true, from given indices (backward) 1023 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 1024 * m.permuteRows([1,2,0]); // m = Matrix([[21,22,23],[31,32,33],[11,12,13]]) 1025 * m.permuteRows([1,2,0],true); // m = mat([[11,12,13],[21,22,23],[31,32,33]])*/ 1026 permuteRows: function(indx,backward) { 1027 var indx = indx.theArray || indx; 1028 if (indx.length != this.nRows) { return null; } 1029 var backward = backward || false; 1030 var newArry = []; 1031 if (backward) { 1032 for (var i=0; i<this.nRows; i++) { 1033 newArry[i] = this.theArray[indx.indexOf(i)].slice(); 1034 } 1035 this.fromArray(newArry); 1036 return; 1037 } 1038 for (var i=0; i<this.nRows; i++) { 1039 newArry[i] = this.theArray[indx[i]].slice(); 1040 } 1041 this.fromArray(newArry); 1042 }, 1043 1044 /** Returns copy of receiver with rows permutated according to given indices 1045 * @ param {[ints]|Vector} indx indices of permutation 1046 * @ param {bool} [backward=false] if false, receiver is permutated to given indices (forward). If true, from given indices (backward) 1047 * @returns {Matrix} copy of receiver with permutated rows 1048 * @example m1 = mat([[11,12,13],[21,22,23],[31,32,33]]); 1049 * m2 = m1.permuteRows([1,2,0]); // m2 = Matrix([[21,22,23],[31,32,33],[11,12,13]]) 1050 * m3 = m1.permuteRows([1,2,0],true); // m3 = mat([[31,32,33],[11,12,13],[21,22,23]])*/ 1051 rowPermutation: function(indx,backward) { 1052 var indx = indx.theArray || indx; 1053 var backward = backward || false; 1054 if (indx.length != this.nRows) { return null; } 1055 var ret = this.copy(); 1056 ret.permuteRows(indx,backward); 1057 return ret; 1058 }, 1059 1060 /** Returns receiver multiplied by float f ( ret = this * f ) 1061 * @param {float} f float multiplier 1062 * @returns {Matrix} copy of receiver multiplied by f 1063 * @example m1 = mat([[1,2,3],[4,5,6]]); 1064 * m2 = m1.mulf(3); // m2 = Matrix([[3,6,9],[12,15,18]])*/ 1065 mulf: function(f) { 1066 var ret = this.copy() 1067 ret.imulf(f) 1068 return ret; 1069 }, 1070 1071 /** Multiply receiver by float f ( this *= f ) 1072 * @param {float} f float multiplier 1073 * @example m = mat([[1,2,3],[4,5,6]]); 1074 * m.imulf(3); // m = Matrix([[3,6,9],[12,15,18]])*/ 1075 imulf: function(f) { 1076 for (var r=0; r<this.nRows; r++) { 1077 for (var c=0; c<this.nCols; c++) { this.theArray[r][c] *= f; } 1078 } 1079 }, 1080 1081 /** Returns product of receiver and given vector ( ret = this * vec ) 1082 * @param {Vector} vec vector to multiply 1083 * @returns {Vector} copy of receiver multiplied by vec 1084 * @example m = mat([[11,12,13],[21,22,23],[31,32,33]]); 1085 * v1 = vec([1,2,3]); 1086 * v2 = m.mulv(v1); // v2 = Vector([74,134,194])*/ 1087 mulv: function(vec) { 1088 if (!this.canMultiplyVec(vec)) { return null; } 1089 var v = vec.theArray; 1090 var ret = []; 1091 var temp; 1092 for (var r=0; r<this.nRows; r++) { 1093 temp = 0. 1094 for (var c=0; c<this.nCols; c++) { 1095 temp += this.theArray[r][c]*v[c] 1096 } 1097 ret[r] = temp; 1098 } 1099 return Vector.create(ret); 1100 }, 1101 1102 /** Returns product of receiver and given matrix ( ret = this * mat ) 1103 * @param {Matrix} mat matrix to multiply 1104 * @returns {Matrix} copy of receiver multiplied by mat 1105 * @example m1 = mat([[11,12],[21,22]]); 1106 * m2 = mat([[1,2],[3,4]]); 1107 * m3 = m1.mulm(m2); // m3 = Matrix([[47,70],[87,130]])*/ 1108 mulm: function(mat) { 1109 if (!this.canMultiplyMat(mat)) { return null; } 1110 var m = mat.theArray; 1111 var ret = []; 1112 var temp; 1113 for (var r=0; r<this.nRows; r++) { 1114 ret[r] = []; 1115 for (var c=0; c<mat.nCols; c++) { 1116 temp = 0.; 1117 for (var k=0; k<this.nCols; k++) { 1118 temp += this.theArray[r][k]*m[k][c] 1119 } 1120 ret[r][c] = temp; 1121 } 1122 } 1123 return Matrix.create(ret); 1124 }, 1125 1126 /** Returns product of receiver and given mltiplier (float or Matrix) 1127 * @param {Matrix|Vector|float} what matrix or vector or float to multiply 1128 * @returns {Matrix|Vector} copy of receiver multiplied by what 1129 * @example m1 = mat([[1,2,3],[4,5,6]]); 1130 * m2 = m1.mulf(3); // m2 = Matrix([[3,6,9],[12,15,18]]) 1131 * 1132 * m3 = mat([[11,12,13],[21,22,23],[31,32,33]]); 1133 * v1 = vec([1,2,3]); 1134 * v2 = m3.mulv(v1) // v2 = Vector([74,134,194]); 1135 * 1136 * m4 = mat([[11,12],[21,22]]); 1137 * m5 = mat([[1,2],[3,4]]); 1138 * m6 = m4.mulm(m5); // m6 = Matrix([[47,70],[87,130]])*/ 1139 mul: function(what) { 1140 if (what instanceof Vector) { return this.mulv(what); } 1141 if (what instanceof Matrix) { return this.mulm(what); } 1142 if (typeof what == 'number') { return this.mulf(what); } 1143 return null; 1144 }, 1145 1146 /** Alias for mul(), see {@link Matrix#mul}*/ 1147 x: function(what) { return this.mul(what); }, 1148 1149 /** Returns transposition of receiver ( ret = this^T ) 1150 * @returns {Matrix} transposed copy of receiver 1151 * @example m1 = mat([[1,2,3],[4,5,6]]); 1152 * m2 = m1.transposed(); // m2 = Matrix([[1,4],[2,5],[3,6]])*/ 1153 transposed: function() { 1154 var ret = []; 1155 for (var r=0; r<this.nCols; r++) { 1156 ret[r] = []; 1157 for (var c=0; c<this.nRows; c++) { 1158 ret[r][c] = this.theArray[c][r]; 1159 } 1160 } 1161 return Matrix.create(ret); 1162 }, 1163 1164 /** Alias for transposed(), see {@link Matrix#transposed}*/ 1165 T: function() { return this.transposed(); }, 1166 1167 /** Returns submatrix of receiver - numbering from 0 1168 * @param {[floats]|Vector} rows array containing rowa indices of desired submatrix - numbering from 0 1169 * @param {[floats]|Vector} cols array containing columns indices of desired submatrix - numbering from 0 1170 * @returns {Matrix} desired submatrix 1171 * @example m1 = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]); 1172 * m2 = m1.getsm([1,2],[0,2]); // m2 = Matrix([[21,23],[31,33]])*/ 1173 getsm: function(rows,cols) { 1174 var nr = rows.nItems || rows.length 1175 var nc = cols.nItems || cols.length 1176 var rows = rows.theArray || rows; 1177 var cols = cols.theArray || cols; 1178 var ret = []; 1179 for (var r=0; r<nr; r++) { 1180 ret[r] = []; 1181 for (var c=0; c<nc; c++) { ret[r][c] = this.theArray[rows[r]][cols[c]]; } 1182 } 1183 return Matrix.create(ret); 1184 }, 1185 1186 /** Set submatrix to defined positions of receiver 1187 * @param {[floats]|Vector} rows array containing rows indices to be set - numbering from 0 1188 * @param {[floats]|Vector} cols array containing columns indices to be set - numbering from 0 1189 * @param {Matrix} mat matrix to be set on desired positions 1190 * @example m = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]); 1191 * m.setsm([1,2],[0,2],mat([[66,77],[88,99]])); 1192 * // m = Matrix([[11,12,13,14],[66,22,77,24],[88,32,99,34],[41,42,43,44]])*/ 1193 setsm: function(rows,cols,mat) { 1194 var rows = rows.theArray || rows; 1195 var cols = cols.theArray || cols; 1196 var nr = rows.length; 1197 var nc = cols.length; 1198 if (mat.nRows != nr || mat.nCols != nc) { return; } 1199 var m = mat.theArray; 1200 for (var r=0; r<nr; r++) { 1201 for (var c=0; c<nc; c++) { this.theArray[rows[r]][cols[c]] = m[r][c]; } 1202 } 1203 }, 1204 1205 /** Increment submatrix at defined positions of receiver 1206 * @param {[floats]|Vector} rows array containing rows indices to be incrementes - numbering from 0 1207 * @param {[floats]|Vector} cols array containing columns indices to be incremented - numbering from 0 1208 * @param {Matrix} mat matrix to be incremented on desired positions 1209 * @example m = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]); 1210 * m.incrsm([1,2],[0,2],mat([[66,77],[88,99]])); 1211 * // m = Matrix([11,12,13,14],[87,22,110,24],[119,32,132,34],[41,42,43,44]])*/ 1212 incrsm: function(rows,cols,mat) { 1213 var rows = rows.theArray || rows; 1214 var cols = cols.theArray || cols; 1215 var nr = rows.length; 1216 var nc = cols.length; 1217 if (mat.nRows != nr || mat.nCols != nc) { return; } 1218 var m = mat.theArray; 1219 for (var r=0; r<nr; r++) { 1220 for (var c=0; c<nc; c++) { this.theArray[rows[r]][cols[c]] += m[r][c]; } 1221 } 1222 }, 1223 1224 /** Decrement submatrix at defined positions of receiver 1225 * @param {[floats]|Vector} rows array containing rows indices to be decrementes - numbering from 0 1226 * @param {[floats]|Vector} cols array containing columns indices to be decremented - numbering from 0 1227 * @param {Matrix} mat matrix to be decremented on desired positions 1228 * @example m = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]); 1229 * m.decrsm([1,2],[0,2],mat([[66,77],[88,99]])); 1230 * // m = Matrix([11,12,13,14],[-45,22,-54,24],[-57,32,-66,34],[41,42,43,44]])*/ 1231 decrsm: function(rows,cols,mat) { 1232 var rows = rows.theArray || rows; 1233 var cols = cols.theArray || cols; 1234 var nr = rows.length; 1235 var nc = cols.length; 1236 if (mat.nRows != nr || mat.nCols != nc) { return; } 1237 var m = mat.theArray; 1238 for (var r=0; r<nr; r++) { 1239 for (var c=0; c<nc; c++) { this.theArray[rows[r]][cols[c]] -= m[r][c]; } 1240 } 1241 }, 1242 1243 /** Returns copy of receiver 1244 * @returns {Matrix} copy of receiver 1245 * @example m1 = mat([[11,12],[21,22]]); 1246 * m2 = m1; 1247 * m3 = m1.copy(); 1248 * m1.set(1,0,6); 1249 * // m1 = Matrix([[11,12],[6,22]]) 1250 * // m2 = Matrix([[11,12],[6,22]]) 1251 * // m3 = Matrix([[11,12],[21,22]])*/ 1252 copy: function() { 1253 var ret = [] 1254 for (var r=0; r<this.nRows; r++) { ret[r] = this.theArray[r].slice(); } 1255 return Matrix.create(ret); 1256 }, 1257 1258 /** Returns vector containing receiver's diagonal elements 1259 * @returns {Vector} vector containing receiver's diagonal elements 1260 * @example m = mat([[1,2,3],[4,5,6],[7,8,9]]); 1261 * v = m.diag(); // v = Vector([1,5,9])*/ 1262 diagonalToVector: function() { 1263 if (!this.isSquare()) { return null; } 1264 var ret = []; 1265 for (var r=0; r<this.nRows; r++) { ret[r] = this.theArray[r][r]; } 1266 return Vector.create(ret); 1267 }, 1268 1269 /** Alias for diagonalToVector(), see {@link Matrix#diagonalToVector}*/ 1270 diag: function() { return this.diagonalToVector(); }, 1271 1272 /** Returns string representation of receiver 1273 * @returns {string} string representation of receiver 1274 * @example m = mat([[1,2,3],[4,5,6],[7,8,9]]); 1275 * alert(m); // alerts "Matrix([[1,2,3],[4,5,6],[7,8,9]])"*/ 1276 toString: function() { 1277 var nr = this.nRows; 1278 var nc = this.nCols; 1279 var ret = "Matrix([[ " 1280 if (nr == 0) { return ret+"])"; } 1281 if (nc == 0) { 1282 for (var r=0; r<nr-1; r++) { 1283 ret += " [],"; 1284 } 1285 return ret + " ])"; 1286 } 1287 for (var r=0; r<nr-1; r++) { 1288 for (var c=0; c<nc-1; c++) { ret += this.theArray[r][c]+", "; } 1289 ret += this.theArray[r][nc-1]+" ], [ "; 1290 } 1291 for (var c=0; c<nc-1; c++) { ret += this.theArray[nr-1][c]+", "; } 1292 ret += this.theArray[nr-1][nc-1]+" ]])" 1293 return ret; 1294 }, 1295 1296 /** Resize receiver according to given size (delete extra elements or add zero elements) 1297 * @param {int} nRows new number of rows 1298 * @param {int} nCols new number of columns 1299 * @example m1 = mat([[11,12,13,14],[21,22,23,24],[31,32,33,34],[41,42,43,44]]); 1300 * m2 = mat([[11,12],[21,22]]); 1301 * m1.resize(3,3); // m1 = Matrix([[11,12,13],[21,22,23],[31,32,33]]) 1302 * m2.resize(3,3); // m2 = Matrix([[11,12,0],[21,22,0],[0,0,0]])*/ 1303 resize: function(nRows,nCols) { 1304 if (this.nRows < nRows) { 1305 for (var r=this.nRows; r<nRows; r++) { 1306 this.setRow(r,Vector.Zeros(this.nCols)); 1307 } 1308 this.nRows = nRows; 1309 } 1310 if (this.nRows > nRows) { 1311 this.theArray = this.theArray.slice(0,nRows); 1312 this.nRows = nRows; 1313 } 1314 if (this.nCols < nCols) { 1315 for (var r=0; r<this.nRows; r++) { 1316 for (var c=this.nCols; c<nCols; c++) { 1317 this.theArray[r][c] = 0.; 1318 } 1319 } 1320 this.nCols = nCols; 1321 } 1322 if (this.nCols > nCols) { 1323 for (var r=0; r<this.nRows; r++) { 1324 this.theArray[r] = this.theArray[r].slice(0,nCols); 1325 } 1326 this.nCols = nCols; 1327 } 1328 }, 1329 1330 /** Returns resized copy of receiver according to given size (delete extra elements or add zero elements) 1331 * @param {int} nRows new number of rows 1332 * @param {int} nCols new number of columns 1333 * @returns {Matrix} resized copy of receiver 1334 * @example m1 = mat([[11,12,13],[21,22,23],[31,32,33]]); 1335 * m2 = m1.resized(2,4); // m2 = Matrix([[11,12,13,0],[21,22,23,0]]) 1336 * m3 = m1.resized(4,2); // m3 = Matrix([[11,12],[21,22],[31,32],[0,0]])*/ 1337 resized: function(nRows,nCols) { 1338 var ret = this.copy(); 1339 ret.resize(nRows,nCols); 1340 return ret; 1341 }, 1342 1343 /** Appends vector(s)/matrix as row(s) to receiver 1344 * @param {Vector|Matrix|[Vectors]|[Matrices]} rows new row(s) to be appended 1345 * @example m = mat([[1,2],[3,4]]); 1346 * m.appendRows(vec([7,6])); // m = Matrix([[1,2],[3,4],[7,6]]) 1347 * m.appendRows(mat([[1,3],[2,4]])); // m = Matrix([[1,2],[3,4],[7,6],[1,3],[2,4]]) 1348 * m.appendRows([vec([2,1]),vec([33,44])]); // m = Matrix([[1,2],[3,4],[7,6],[1,3],[2,4],[2,1],[33,44]]) 1349 * m.appendRows([mat([[2,1],[4,3]]),mat([[99,88],[77,66]])]); // m = Matrix([[1,2],[3,4],[7,6],[1,3],[2,4],[2,1],[33,44],[2,1],[4,3],[99,88],[77,66]])*/ 1350 appendRows: function(rows) { 1351 if (rows instanceof Vector) { 1352 if (rows.nItems != this.nCols) { return; } 1353 this.theArray[this.nRows] = rows.theArray.slice(); 1354 this.nRows++; 1355 return; 1356 } 1357 if (rows instanceof Matrix) { 1358 if (rows.nCols != this.nCols) { return; } 1359 for (var r=0; r<rows.nRows; r++) { 1360 this.theArray[this.nRows] = rows.theArray[r].slice(); 1361 this.nRows++; 1362 } 1363 return; 1364 } 1365 if (rows instanceof Array) { 1366 for (var i=0; i<rows.length; i++) { this.appendRows(rows[i]); } 1367 } 1368 }, 1369 1370 /** Appends vector(s)/matrix as column(s) to receiver 1371 * @param {Vector|Matrix|[Vectors]|[Matrices]} rows new row(s) to be appended 1372 * @example m = mat([[1,2],[3,4]]); 1373 * m.appendCols(vec([7,6])); // m = Matrix([[1,2,7],[3,4,6]]) 1374 * m.appendCols(mat([[1,3],[2,4]])); // m = Matrix([[1,2,7,1,3],[3,4,6,2,4]]) 1375 * m.appendCols([vec([2,1]),vec([33,44])]); // m = Matrix([[1,2,7,1,3,2,33],[3,4,6,2,4,1,44]]) 1376 * m.appendCols([mat([[2,1],[4,3]]),mat([[99,88],[77,66]])]); // m = Matrix([[1,2,7,1,3,2,33,2,1,99,88],[3,4,6,2,4,1,44,4,3,77,66]])*/ 1377 appendCols: function(cols) { 1378 if (cols instanceof Vector) { 1379 if (cols.nItems != this.nRows) { return; } 1380 for (var r=0; r<this.nRows; r++) { this.theArray[r][this.nCols] = cols.theArray[r]; } 1381 this.nCols++; 1382 return; 1383 } 1384 if (cols instanceof Matrix) { 1385 if (cols.nRows != this.nRows) { return; } 1386 for (var r=0; r<cols.nRows; r++) { 1387 for (var c=0; c<cols.nCols; c++) { this.theArray[r][this.nCols+c] = cols.theArray[r][c]; } 1388 } 1389 this.nCols += cols.nCols; 1390 return; 1391 } 1392 if (cols instanceof Array) { 1393 for (var i=0; i<cols.length; i++) { this.appendCols(cols[i]); } 1394 } 1395 }, 1396 1397 /** Returns row permutation matrix using implicit partial pivoting 1398 * @param {bool} [saveOrig=true] if true, returns permutated copy of receiver. If false, permutate receiver and return this 1399 * @Returns {[Matrix,[ints]]} permutated matrix and array containing indices of original matrix according to position in the permutated one ( such that this.rowPermutation(indx) = ret ) 1400 * @example m1 = mat([[1,2,4,9],[1,8,1,1],[9,4,5,3],[1,2,6,2]]); 1401 * m2 = m1.implicitPartialPivotPermutation(); 1402 * // m2[0] = Matrix([[9,4,5,3],[1,8,1,1],[1,2,6,2],[1,2,4,9]]) 1403 * // m2[1] = [2,1,3,0] 1404 * // m1 = Matrix([[1,2,4,9],[1,8,1,1],[9,4,5,3],[1,2,6,2]]) 1405 * m3 = m1.rowPermutation(m2[1]); // m3 = Matrix([[9,4,5,3],[1,8,1,1],[1,2,6,2],[1,2,4,9]]) 1406 * 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]]) 1407 * m1 = m1.implicitPartialPivotPermutation(false)[0]; 1408 * // m1 = Matrix([[9,4,5,3],[1,8,1,1],[1,2,6,2],[1,2,4,9]])*/ 1409 implicitPartialPivotPermutation: function(saveOrig) { 1410 var saveOrig = saveOrig==undefined? true : saveOrig; 1411 var n = this.nRows; 1412 var ret = saveOrig? this.copy() : this; 1413 var vv = []; 1414 var indx = range(n); 1415 var big, i, j, k; 1416 for (i=0; i<n; i++) { 1417 big = 0.; 1418 for (j=0; j<n; j++) { 1419 if ((temp=Math.abs(ret.theArray[i][j])) > big) { big=temp; } 1420 } 1421 if (big == 0.0) { return null; } 1422 vv[i]=1.0/big; 1423 } 1424 for (k=0; k<n; k++) { 1425 big=0.0; 1426 for (i=k; i<n; i++) { 1427 temp = vv[i]*Math.abs(ret.theArray[i][k]); 1428 if (temp > big) { 1429 big = temp; 1430 imax = i; 1431 } 1432 } 1433 if (k != imax) { 1434 ret.swapRows(k,imax); 1435 vv[imax]=vv[k]; 1436 temp = indx[k] 1437 indx[k] = imax; 1438 indx[imax] = temp; 1439 } 1440 } 1441 return [ret,indx]; 1442 }, 1443 1444 /** Returns vector x as a solution of this*ret = vec, receiver is assumed to be lower triangular matrix 1445 * @param {Vector} vec right hand side 1446 * @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 1447 * @Returns {Vector} solution of this*ret = vec 1448 * @example a = mat([[1,0,0,0],[2,3,0,0],[4,5,6,0],[7,8,9,10]]); 1449 * y = vec([4,17,43,80]); 1450 * x = a.forwardSubstitution(y); 1451 * // x = Vector([4,3,2,1]) 1452 * // y = Vector([4,17,43,61]) 1453 * check = a.mul(x); // check = Vector([4,17,43,61]) 1454 * // x = Vector([4,3,2,1]) 1455 * // y = Vector([4,17,43,61]) 1456 * yy - y.copy(); 1457 * x = a.forwardSubstitution(yy,false); 1458 * // x = Vector([4,3,2,1]) 1459 * // yy = Vector([4,3,2,1])*/ 1460 forwardSubstitution: function(vec,saveOrig) { 1461 if (!this.isSquare() || !this.canMultiplyVec(vec)) { return null; } 1462 var saveOrig = saveOrig==undefined? true : saveOrig; 1463 var temp; 1464 var n = this.nRows; 1465 var ret = saveOrig? vec.copy() : vec; 1466 var i, j; 1467 for (var i=0; i<n; i++) { 1468 temp = ret.theArray[i]; 1469 for (var j=0; j<i; j++) { 1470 temp -= this.theArray[i][j]*ret.theArray[j]; 1471 } 1472 ret.theArray[i] = temp/this.theArray[i][i]; 1473 } 1474 return ret; 1475 }, 1476 1477 /** Returns vector x as a solution of this*ret = vec, receiver is assumed to be upper triangular matrix 1478 * @param {Vector} vec right hand side 1479 * @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 1480 * @Returns {Vector} solution of this*ret = vec 1481 * @example a = mat([[1,2,3,4],[0,5,6,7],[0,0,8,9],[0,0,0,10]]); 1482 * y = vec([20,34,25,10]); 1483 * x = a.forwardSubstitution(y); 1484 * // x = Vector([4,3,2,1]) 1485 * // y = Vector([20,34,25,10]) 1486 * check = a.mul(x); // check = Vector([20,34,25,10]) 1487 * // x = Vector([4,3,2,1]) 1488 * // y = Vector([20,34,25,10]) 1489 * yy - y.copy(); 1490 * x = a.forwardSubstitution(yy,false); 1491 * // x = Vector([4,3,2,1]) 1492 * // yy = Vector([4,3,2,1])*/ 1493 backwardSubstitution: function(vec,saveOrig) { 1494 if (!this.isSquare() || !this.canMultiplyVec(vec)) { return null; } 1495 var saveOrig = saveOrig==undefined? true : saveOrig; 1496 var temp; 1497 var n = this.nRows; 1498 var ret = saveOrig? vec.copy() : vec; 1499 var i, j; 1500 for (i=n-1; i>=0; i--) { 1501 temp = ret.theArray[i]; 1502 for (j=i+1; j<n; j++) { 1503 temp -= this.theArray[i][j]*ret.theArray[j]; 1504 } 1505 ret.theArray[i] = temp/this.theArray[i][i]; 1506 } 1507 return ret; 1508 }, 1509 1510 /** Returns vector as a solution of system of linear equations using gaussian elimination method (this * ret = rhs --> ret ) 1511 * @param {Vector} rhs vector of right hand sides 1512 * @param {int} [pivoting=JSM_PARTPIVOT] what type of pivoting to use. JSM_NOPIVOT stands for no pivoting, JSM_PARTPIVOT for implicit partial pivoting (only row interchanges) 1513 * @returns {Vector} vector of solution 1514 * @example a = mat([[1,2,9],[8,3,2],[3,7,3]]) 1515 * b = vec([32,20,26]); 1516 * x = a.gaussianElimination(b) // x = Vector([1,2,3]) 1517 * x = a.gaussianElimination(b,JSM_PARTPIVOT); // x = Vector([1,2,3]) 1518 * a.gaussianElimination(b,JSM_NOPIVOT,false); 1519 * // a = Matrix([[1,2,9],[8,-13,-70],[3,1,-29.384615384615387]]) 1520 * // b = Vector([1,2,3])*/ 1521 gaussianElimination: function(rhs,pivoting,saveOrig) { 1522 if (!this.canMultiplyVec(rhs) || !this.isSquare()) { return null; } 1523 var pivoting = pivoting || JSM_PARTPIVOT; 1524 var saveOrig = saveOrig==undefined? true : saveOrig; 1525 var n = this.nRows; 1526 var i, j, k; 1527 if (pivoting == JSM_NOPIVOT) { 1528 var a = saveOrig? this.copy() : this; 1529 var b = saveOrig? rhs.copy() : rhs; 1530 for (k=0; k<n-1; k++) { 1531 akk = a.theArray[k][k]; 1532 for (i=k+1; i<n; i++) { 1533 for (j=k+1; j<n; j++) { 1534 a.theArray[i][j] -= a.theArray[k][j]*a.theArray[i][k]/akk; 1535 } 1536 b.theArray[i] -= b.theArray[k]*a.theArray[i][k]/akk; 1537 } 1538 } 1539 return a.backwardSubstitution(b,false); 1540 } 1541 if (pivoting == JSM_PARTPIVOT) { 1542 var a = this.implicitPartialPivotPermutation(saveOrig); 1543 return a[0].gaussianElimination((saveOrig? rhs.copy() : rhs).itemPermutation(a[1]),JSM_NOPIVOT,false); 1544 } 1545 }, 1546 1547 /** Returns matrix, whose columns are solutions of system of equations this*ret = rhs 1548 * @param {Matrix,[Vectors],Vector} rhs matrix/vector/array of vectors representing right hand sides 1549 * @param {int} [pivoting=JSM_PARTPIVOT] what type of pivoting to use. JSM_NOPIVOT stands for no pivoting, JSM_PARTPIVOT for implicit partial pivoting (only row interchanges) 1550 * @param {bool} [saveOrig=true] if true, receiver is not changed. If false, solution will be saved to rhs and rhs will be returned 1551 * @returns {Matrix} matrix, whose columns are solution for particular right hand sides 1552 * @example a = mat([[1,2,9],[8,3,2],[3,7,3]]); 1553 * b1 = vec([32,20,26]); 1554 * b2 = vec([16,32,26]); 1555 * b3 = [b1.copy(),b2.copy()]; 1556 * b4 = mat([b1.toArray(),b2.toArray()]); 1557 * x1 = a.gaussJordanElimination(b1); 1558 * // x1 = Vector([ 1, 2, 3 ]) 1559 * x2 = a.gaussJordanElimination(b2); 1560 * // x2 = Vector([ 3.0000000000000018, 2, 1 ]) 1561 * x3 = a.gaussJordanElimination(b3); 1562 * // x3 = Vector([ 1, 2, 3 ]) ,Vector([ 3.0000000000000018, 2, 1 ]) 1563 * x4 = a.gaussJordanElimination(b4); 1564 * // x4 = Matrix([[ 1, 3.0000000000000018 ], [ 2, 2 ], [ 3, 1 ]]) 1565 * x5 = a.gaussJordanElimination(b1,JSM_PARTPIVOT);; 1566 * // x5 = Vector([ 1, 2, 3 ]) 1567 * x6 = a.gaussJordanElimination(b2,JSM_PARTPIVOT); 1568 * // x6 = Vector([ 3, 2, 1 ]) 1569 * x7 = a.gaussJordanElimination(b3,JSM_PARTPIVOT); 1570 * // x7 = Vector([ 1, 2, 3 ]) ,Vector([ 3, 2, 1 ]) 1571 * x8 = a.gaussJordanElimination(b4,JSM_PARTPIVOT); 1572 * // x8 = Matrix([[ 1, 3 ], [ 2, 2 ], [ 3, 1 ]]) 1573 * a.gaussJordanElimination(b4,JSM_NOPIVOT,false); 1574 * // b4 = Matrix([[ 1, 3.0000000000000018 ], [ 2, 2 ], [ 3, 1 ]])*/ 1575 gaussJordanElimination: function(rhs,pivoting,saveOrig) { 1576 if (!this.isSquare) { return null; } 1577 var rhs = rhs || null; 1578 if (rhs == null) { return null; } 1579 var rhsInstance = (rhs instanceof Vector)? 1 : ((rhs instanceof Array)? 2 : ((rhs instanceof Matrix)? 3 : 4)); 1580 if (!(rhsInstance==1 || rhsInstance==2 || rhsInstance==3)) { return null; } 1581 var pivoting = pivoting || JSM_PARTPIVOT; 1582 var saveOrig = saveOrig==undefined? true : saveOrig; 1583 var i, j, k, akk; 1584 var n = this.nRows; 1585 var nrhs = rhsInstance==2? rhs.length : (rhsInstance==3? rhs.nCols : 0); 1586 if (pivoting == JSM_NOPIVOT) { 1587 var a = saveOrig? this.copy() : this; 1588 var b; 1589 if (rhsInstance==1 || rhsInstance==3) { b = saveOrig? rhs.copy() : rhs; } 1590 else { 1591 b = []; 1592 for (i=0; i<nrhs; i++) { b[i] = saveOrig? rhs[i].copy() : rhs[i]; } 1593 } 1594 for (k=0; k<n; k++) { 1595 akk = a.theArray[k][k]; 1596 for (i=k+1; i<n; i++) { 1597 for (j=k+1; j<n; j++) { 1598 a.theArray[i][j] -= a.theArray[k][j]*a.theArray[i][k]/akk; 1599 } 1600 switch (rhsInstance) { 1601 case 1: b.theArray[i] -= b.theArray[k]*a.theArray[i][k]/akk; break; 1602 case 2: for (j=0; j<nrhs; j++) { b[j].theArray[i] -= b[j].theArray[k]*a.theArray[i][k]/akk; } break; 1603 case 3: for (j=0; j<nrhs; j++) { b.theArray[i][j] -= b.theArray[k][j]*a.theArray[i][k]/akk; } break; 1604 } 1605 } 1606 } 1607 for (k=n-1; k>=0; k--) { 1608 akk = a.theArray[k][k]; 1609 for (i=k-1; i>=0; i--) { 1610 for (j=n-1; j>k; j--) { 1611 a.theArray[i][j] -= a.theArray[k][j]*a.theArray[i][k]/akk; 1612 } 1613 switch (rhsInstance) { 1614 case 1: b.theArray[i] -= b.theArray[k]*a.theArray[i][k]/akk; break; 1615 case 2: for (j=0; j<nrhs; j++) { b[j].theArray[i] -= b[j].theArray[k]*a.theArray[i][k]/akk; } break; 1616 case 3: for (j=0; j<nrhs; j++) { b.theArray[i][j] -= b.theArray[k][j]*a.theArray[i][k]/akk; } break; 1617 } 1618 } 1619 } 1620 for (k=0; k<n; k++) { 1621 akk = a.theArray[k][k]; 1622 switch (rhsInstance) { 1623 case 1: b.theArray[k] /= akk; break; 1624 case 2: for (j=0; j<nrhs; j++) { b[j].theArray[k] /= akk; } break; 1625 case 3: for (j=0; j<nrhs; j++) { b.theArray[k][j] /= akk; } break; 1626 } 1627 } 1628 return b; 1629 } 1630 if (pivoting == JSM_PARTPIVOT) { 1631 var a = this.implicitPartialPivotPermutation(saveOrig); 1632 var temp; 1633 switch (rhsInstance) { 1634 case 1: temp = saveOrig? rhs.copy() : rhs; temp.permuteItems(a[1]); break; 1635 case 2: 1636 temp = []; 1637 for (i=0; i<nrhs; i++) { 1638 temp[i] = saveOrig? rhs[i].copy() : rhs[i]; 1639 temp[i].permuteItems(a[1]); 1640 } 1641 break; 1642 case 3: 1643 temp = saveOrig? rhs.copy() : rhs; temp.permuteRows(a[1]); break; 1644 } 1645 return a[0].gaussJordanElimination(temp,JSM_NOPIVOT,false); 1646 } 1647 }, 1648 1649 /** Returns lower triangular matrix of Cholesky's (LLT) decomposition of receiver. Receiver must be square, symmetric and positive definite. ( ret * ret^T = this ) 1650 * @returns {Matrix} lower triangular matrix 1651 * @example a = mat([[1,2,4],[2,13,23],[4,23,77]]); 1652 * l = a.choleskyDecomposition(); // l = Matrix([[1,0,0],[2,3,0],[4,5,6]]) 1653 * check = l.x(l.T()); // check = Matrix([[1,2,4],[2,13,23],[4,23,77]]);*/ 1654 choleskyDecomposition: function() { 1655 if (!this.isSquare()) { return null; } 1656 if (!this.isSymmetric()) { return null; } 1657 var n = this.nRows; 1658 var ret = Matrix.Zeros(n,n); 1659 var retii, temp, i, j, k; 1660 for (i=0; i<n; i++) { 1661 retii = this.theArray[i][i] 1662 for (k=0; k<i; k++) { retii -= ret.theArray[i][k]*ret.theArray[i][k]; } 1663 if (retii<=0.) { return null; } 1664 retii = Math.sqrt(retii); 1665 ret.theArray[i][i] = retii; 1666 for (j=i; j<n; j++) { 1667 temp = this.theArray[i][j]; 1668 for (k=0; k<i; k++) { temp -= ret.theArray[i][k]*ret.theArray[j][k]; } 1669 ret.theArray[j][i] = temp/retii; 1670 } 1671 } 1672 return ret; 1673 }, 1674 1675 /** Alias for Cholesky decomposition, see {@link Matrix#choleskyDecomposition}*/ 1676 chol: function() { return this.choleskyDecomposition(); }, 1677 1678 /** Alias for Cholesky decomposition, see {@link Matrix#choleskyDecomposition}*/ 1679 lltDecomposition: function() { return this.choleskyDecomposition(); }, 1680 1681 /** 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. 1682 * @param {int} [pivoting=JSM_NOPIVOT] what type of pivoting to use. JSM_NOPIVOT stands for no pivoting, JSM_PARTPIVOT for implicit partial pivoting (only row interchanges) 1683 * @returns {[Matrix,Matrix]} [L,U], lower and upper triangular matrices 1684 * @example a = mat([[6,5,4],[12,13,10],[18,27,21]]); 1685 * lu = a.luDecomposition(); 1686 * l = lu[0]; // l = Matrix([[1,0,0],[2,1,0],[3,4,1]]) 1687 * u = lu[1]; // u = Matrix([[6,5,4],[0,3,2],[0,0,1]]) 1688 * check = l.x(u); // check = Matrix([[6,5,4],[12,13,10],[18,27,21]])*/ 1689 luDecomposition: function(pivoting) { 1690 if (!this.isSquare()) { return null; } 1691 var pivoting = pivoting || JSM_NOPIVOT; 1692 var n = this.nRows; 1693 var l = Matrix.Zeros(n,n); 1694 var u = Matrix.Zeros(n,n); 1695 var i, j, k, imax; 1696 var temp; 1697 if (pivoting == JSM_NOPIVOT) { 1698 for (k=0; k<n; k++) { 1699 l.theArray[k][k] = 1.; 1700 for (j=k; j<n; j++) { 1701 temp = this.theArray[k][j]; 1702 for (i=0; i<k; i++) { 1703 temp -= l.theArray[k][i]*u.theArray[i][j]; 1704 } 1705 u.theArray[k][j] = temp; 1706 } 1707 for (j=k+1; j<n; j++) { 1708 temp = this.theArray[j][k] 1709 for (i=0; i<k; i++) { 1710 temp -= l.theArray[j][i]*u.theArray[i][k] 1711 } 1712 l.theArray[j][k] = temp/u.theArray[k][k] 1713 } 1714 } 1715 return [l,u] 1716 } 1717 if (pivoting == JSM_PARTPIVOT) { 1718 var a = this.implicitPartialPivotPermutation() 1719 var ret = a[0].luDecomposition(JSM_NOPIVOT); 1720 ret[2] = a[1]; 1721 return ret; 1722 } 1723 }, 1724 1725 /** 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. 1726 * @param {int} [pivoting=JSM_NOPIVOT] what type of pivoting to use. JSM_NOPIVOT stands for no pivoting, JSM_PARTPIVOT for implicit partial pivoting (only row interchanges) 1727 * @param {bool} [retDiagAsVector = false] if true, d is returned as vector. If false, d is returned as diagonal matrix 1728 * @returns {[Matrix,Matrix|Vector,Matrix]} [L,D,U], lower, diagonal and upper triangular matrices 1729 * @example a = mat([[12,10,8],[24,29,22],[36,66,52]]); 1730 * ldu = a.lduDecomposition(); 1731 * l = ldu[0]; // l = Matrix([[1,0,0],[2,1,0],[3,4,1]]) 1732 * d = ldu[1]; // d = Matrix([[2,0,0],[0,3,0],[0,0,4]]) 1733 * u = ldu[2]; // u = Matrix([[6,5,4],[0,3,2],[0,0,1]]) 1734 * check = l.x(d).x(u) // check = Matrix([[12,10,8],[24,29,22],[36,66,52]])*/ 1735 lduDecomposition: function(pivoting,retDiagAsVector) { 1736 if (!this.isSquare()) { return null; } 1737 var pivoting = pivoting || JSM_NOPIVOT; 1738 var retDiagAsVector = retDiagAsVector || false; 1739 if (pivoting == JSM_NOPIVOT) { 1740 var n = this.nRows; 1741 var l = zeros(n,n); 1742 var d = zeros(n); 1743 var u = zeros(n,n); 1744 var temp; 1745 for (var i=0; i<n; i++) { 1746 l.theArray[i][i] = 1.; 1747 u.theArray[i][i] = 1.; 1748 for (var j=0; j<i; j++) { 1749 temp = this.theArray[i][j]; 1750 for (var k=0; k<j; k++) { 1751 temp -= l.theArray[i][k]*d.theArray[k]*u.theArray[k][j]; 1752 } 1753 l.theArray[i][j] = temp/d.theArray[j]; 1754 } 1755 temp = this.theArray[i][i]; 1756 for (var k=0; k<i; k++) { 1757 temp -= l.theArray[i][k]*d.theArray[k]*u.theArray[k][i]; 1758 } 1759 d.theArray[i] = temp; 1760 for (var j=i+1; j<n; j++) { 1761 temp = this.theArray[i][j]; 1762 for (var k=0; k<i; k++) { 1763 temp -= l.theArray[i][k]*d.theArray[k]*u.theArray[k][j]; 1764 } 1765 u.theArray[i][j] = temp/d.theArray[i]; 1766 } 1767 } 1768 if (retDiagAsVector) { return [l,d,u]; } 1769 return [l,d.toDiagonalMatrix(),u]; 1770 } 1771 if (pivoting = JSM_PARTPIVOT) { 1772 var a = this.implicitPartialPivotPermutation(); 1773 var ret = a.lduDecomposition(JSM_NOPIVOT,retDiagAsVector,false); 1774 ret[3] = a[1]; 1775 return ret; 1776 } 1777 }, 1778 1779 /** Returns orthogonal matrix Q^T and upper triangular matrix R of QR decomposition of receiver such that Q*R=this. 1780 * @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 1781 * @returns {[Matrix,Matrix]} Q^T and R of QR decomposition of receiver 1782 * @example a = mat([[1,2,9],[8,3,4],[3,7,1]]); 1783 * qr = a.qrDecomposition(); 1784 * qt = qr[0]; // qt = Matrix([[ -0.1162, -0.9299, -0.3487 ], [ 0.2407, -0.3670, 0.8985 ], [ -0.9636, 0.0205, 0.2665 ]]) 1785 * r = qr[1]; // r = Matrix([[ -8.6023, -5.4636, -5.1148 ], [ 0, 5.6699, 1.5968 ], [ 0, 0, -8.3239 ]]) 1786 * check = q.T().x(r); // check = Matrix([[1,2,9],[8,3,4],[3,7,1]]) 1787 * o = q.T().x(q); // o = Matrix([[1,0,0],[0,1,0],[0,0,1]])*/ 1788 qrDecomposition: function(saveOrig) { 1789 if (!this.isSquare()) { return null; } 1790 var saveOrig = saveOrig==undefined? true : saveOrig; 1791 var n = this.nRows; 1792 var qt = Matrix.Zeros(n,n); 1793 var r = saveOrig? this.copy() : this; 1794 var c = []; 1795 var d = []; 1796 var scale, sigma, sum, tau, sing; 1797 for (k=0; k<n-1; k++) { 1798 scale=0.0; 1799 for (i=k;i<n;i++) scale = Math.max(scale, Math.abs(r.theArray[i][k])); 1800 if (scale == 0.0) { // Singular case. 1801 sing = true; 1802 c[k] = 0.0; 1803 d[k] = 0.0; 1804 } 1805 else { // Form Qk and Qk A. 1806 for (i=k; i<n; i++) { r.theArray[i][k] /= scale; } 1807 sum = 0.; 1808 for (i=k; i<n; i++) { sum += (r.theArray[i][k]*r.theArray[i][k]); } 1809 sigma = Math.sqrt(sum)*(r.theArray[k][k]>=0.? 1. : -1.); 1810 r.theArray[k][k] += sigma; 1811 c[k] = sigma*r.theArray[k][k]; 1812 d[k] = -scale*sigma; 1813 for (j=k+1; j<n; j++) { 1814 sum = 0.; 1815 for (i=k; i<n; i++) { sum += r.theArray[i][k]*r.theArray[i][j]; } 1816 tau = sum/c[k]; 1817 for (i=k; i<n; i++) { r.theArray[i][j] -= tau*r.theArray[i][k]; } 1818 } 1819 } 1820 } 1821 d[n-1] = r.theArray[n-1][n-1]; 1822 if (d[n-1] == 0.0) { sing = true; } 1823 for (i=0; i<n; i++) { // Form QT explicitly. 1824 for (j=0; j<n; j++) { qt.theArray[i][j] = 0.; } 1825 qt.theArray[i][i] = 1.0; 1826 } 1827 for (k=0; k<n-1; k++) { 1828 if (c[k] != 0.0) { 1829 for (j=0; j<n; j++) { 1830 sum = 0.0; 1831 for (i=k ;i<n; i++) { 1832 sum += r.theArray[i][k]*qt.theArray[i][j]; 1833 } 1834 sum /= c[k]; 1835 for (i=k;i<n;i++) { 1836 qt.theArray[i][j] -= sum*r.theArray[i][k]; 1837 } 1838 } 1839 } 1840 } 1841 for (i=0; i<n; i++) { // Form R explicitly. 1842 r.theArray[i][i] = d[i]; 1843 for (j=0; j<i; j++) { r.theArray[i][j] = 0.0; } 1844 } 1845 return [qt,r]; 1846 }, 1847 1848 /** Returns inversion of receiver 1849 * @param {int} [method=JSM_GAUSSJORDAN] method used for solution. Options are JSM_GAUSSJORDAN for Gauss-Jordan method, JSM_LU for solution with LU decomposition 1850 * @param {[Matrices]} [precompDecomps=undefined] precomputed matrix decompositions if we want to se some 1851 * @returns {Matrix} inversion of receiver 1852 * @example a = mat([[2,2,1],[2,3,0.5],[1,0.5,2]]); 1853 * b = a.inversed(); // b = Matrix([[2.3,-1.4,-0.8],[-1.4,1.2,0.4],[-0.8,0.4,0.8]]) 1854 * check = a.x(b); // check = Matrix([[1,0,0],[0,1,0],[0,0,1]])*/ 1855 inversed: function(method,precompDecomps) { 1856 if (!this.isSquare) { return null; } 1857 var method = method || JSM_GAUSSJORDAN; 1858 switch (method) { 1859 case JSM_GAUSSJORDAN: return this.gaussJordanElimination(Matrix.Identity(this.nRows,this.nRows)); 1860 default: return null; 1861 } 1862 }, 1863 1864 /** Alias for inversion, see {@link Matrix#inversed}*/ 1865 inv: function(method,precompDecomps) { return this.inversed(method||undefined,precompDecomps||undefined); }, 1866 1867 /** Returns determinant of receiver. 1868 * @param {int} [method=JSM_LU] used method. Options are JSM_LU for using LU decomposition 1869 * @param {[Matrices]} precompDecomps precomputed matrix decompositions if we want to use some 1870 * @returns {float} determinant of receiver 1871 * @example a = mat([[4,2,1],[2,5,3],[1,3,6]]); 1872 * d = a.determinant(); // d = 67*/ 1873 determinant: function(method,precompDecomps) { 1874 if (!this.isSquare()) { return null; } 1875 var method = method || JSM_LU; 1876 var mats = precompDecomps || undefined 1877 switch (method) { 1878 case JSM_LU: 1879 mats = precompDecomps? precompDecomps : this.luDecomposition(); 1880 var diag = mats[1].diag(); 1881 var ret = diag.theArray[0]; 1882 for (var r=1; r<this.nRows; r++) { ret *= diag.theArray[r]; } 1883 return ret; 1884 default: return null; 1885 } 1886 }, 1887 1888 /** Alias for determinant, see {@link Matrix#determinant}*/ 1889 det: function(method,precompDecomps) { return this.determinant(method||undefined,precompDecomps||undefined); }, 1890 1891 /** Test receiver's singularity 1892 * @returns {bool} true if receiver is singular (if abs(this.det()) < JSM_TOL), false otherwise 1893 * @example a = mat([[1,2,3],[2,4,6],[4,5,6]]); 1894 * b = mat([[4,2,1],[2,5,3],[1,3,6]]); 1895 * s1 = a.isSingular(); // s1 = true 1896 * s2 = b.isSingular(); // s1 = false*/ 1897 isSingular: function() { 1898 var d = this.determinant(); 1899 return isNaN(d)? true : (Math.abs(d) < JSM_TOL); 1900 }, 1901 1902 /** 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 1903 * @param {Vector|[Vectors]|Matrix} rhs vector of right hand sides. Array of vectors or Matrix as rhs is supported only with JSM_GAUSSJORDAN method 1904 * @param {int} [method=JSM_GAUSS] method of the solution. Implemented methods are JSM_GAUSS for gaussian elimination, JSM_GAUSSJORDAN for Gauss-Jordan elimination (supporting more than one right hand sides in form of array of vectors or matrix with columns as rhs), JSM_LU for using LU decomposition, JSM_LDU for using LDU decomposition, JSM_CHOLESKY for using Cholesky decomposition 1905 * @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 1906 * @param {[Matrices]} [precompDecomps=undefined] array of Matrices objects, used for solution using matrix decomposition as precomputed values (the decomposition is performed within solveForRhs function if args parameter is not specified) 1907 * @returns {Vector|[Vectors]|Matrix} vector/array of vectors/matrix of solution 1908 * @example a = mat([[1,2,9],[8,3,2],[3,7,3]]); 1909 * b = vec([32,20,26]); 1910 * x1 = a.solveForRhs(b); // x1 = Vector([1,2,3]) 1911 * x2 = a.solveForRhs(b,JSM_GAUSS); // x2 = Vector([1,2,3]) 1912 * x3 = a.solveForRhs(b,JSM_GAUSSJORDAN); // x3 = Vector([1,2,3]) 1913 * x4 = a.solveForRhs(b,JSM_LU); // x4 = Vector([1,2,3]) 1914 * x5 = a.solveForRhs(b,JSM_LDU); // x5 = Vector([1,2,3]) 1915 * x6 = a.solveForRhs(b,JSM_CHOLESKY); // x6 = Vector([1,2,3]) 1916 * x7 = a.solveForRhs(b,JSM_QR); // x7 = Vector([1,2,3])*/ 1917 solveForRhs: function(rhs,method,saveOrig,precompDecomps) { 1918 var saveOrig = saveOrig==undefined? true : saveOrig; 1919 var method = method || JSM_GAUSS; 1920 if (method==JSM_GAUSS) { // gaussian elimination 1921 return this.gaussianElimination(rhs,JSM_PARTPIVOT,saveOrig); 1922 } 1923 if (method==JSM_GAUSSJORDAN) { // gaussian elimination 1924 return this.gaussJordanElimination(rhs,JSM_PARTPIVOT,saveOrig); 1925 } 1926 if (method==JSM_LU) { // use LU factorization 1927 var lu = precompDecomps || this.luDecomposition(); 1928 var l = lu[0]; 1929 var u = lu[1]; 1930 var y; 1931 if (rhs instanceof Vector) { 1932 y = l.forwardSubstitution(rhs,saveOrig); 1933 return u.backwardSubstitution(y,false); 1934 } 1935 if (rhs instanceof Matrix) { 1936 var ret = saveOrig? Matrix.Zeros(this.nRows,rhs.nCols) : rhs; 1937 for (var i=0; i<rhs.nCols; i++) { 1938 y = l.forwardSubstitution(rhs.getCol(i),false); 1939 ret.setCol(i,u.backwardSubstitution(y,false)); 1940 } 1941 return ret; 1942 } 1943 if (rhs instanceof Array) { 1944 return null; 1945 // TODO 1946 } 1947 } 1948 if (method==JSM_LDU) { // use LDU decomposition 1949 var ldu = precompDecomps || this.lduDecomposition(JSM_NOPIVOT,true); 1950 var l = ldu[0]; 1951 var d = (ldu[1] instanceof Matrix)? ldu[1].diag() : ldu[1]; 1952 var u = ldu[2]; 1953 var y = l.forwardSubstitution(rhs,saveOrig); 1954 for (var r=0; r<this.nRows; r++) { y.theArray[r] /= d.theArray[r]; } 1955 return u.backwardSubstitution(y,false); 1956 } 1957 if (method==JSM_CHOLESKY) { // use Cholesky's decomposition 1958 var l = precompDecomps || this.choleskyDecomposition(); 1959 if (l==null) { return null; } 1960 var y = l.forwardSubstitution(rhs,saveOrig); 1961 return l.T().backwardSubstitution(y,false); 1962 } 1963 if (method==JSM_QR) { // use QR decomposition 1964 var qr = precompDecomps || this.qrDecomposition(saveOrig); 1965 return qr[1].backwardSubstitution(qr[0].mulv(rhs),false); 1966 } 1967 return null; 1968 }, 1969 /**#@-*/ 1970 } 1971 1972 /** Constructs new Matrix from given 2D array 1973 * @param {[floats](2D)} [arry=[]] array containing elements of new matrix 1974 * @returns {Matrix} new Matrix object 1975 * @example m = Matrix.create([[1,2,3],[4,5,6],[7,8,9]]) // m = Matrix([[1,2,3],[4,5,6],[7,8,9]])*/ 1976 Matrix.create = function(arry) { 1977 var a = (arry==null)? [[]]:arry; 1978 ret = new Matrix(); 1979 ret.fromArray(a); 1980 return ret; 1981 } 1982 1983 /** Constructs new diagonal matrix from given 1D array 1984 * @param {[floats]|Vector} arry array or vector containing elements of new matrix 1985 * @returns {Matrix} new Matrix object 1986 * @example m1 = Matrix.Diagonal([1,2,3]); // m1 = Matrix([[1,0,0],[0,2,0],[0,0,3]]) 1987 * m2 = Matrix.Diagonal(vec([1,2,3])); // m2 = Matrix([[1,0,0],[0,2,0],[0,0,3]])*/ 1988 Matrix.Diagonal = function(arry) { 1989 return Vector.create(arry.theArray || arry).diag(); 1990 } 1991 1992 /** Constructs new identity matrix of given size 1993 * @param {int} size size of returned matrix 1994 * @returns {Matrix} identity matri 1995 * @example m = Matrix.Identity(4) // m = Matrix([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])*/ 1996 Matrix.Identity = function(size) { 1997 var a = [] 1998 for (var i=0; i<size; i++) { a[i] = 1.; } 1999 return Matrix.Diagonal(a); 2000 } 2001 2002 /** Alias for Matrix.Identity(), see {@link Matrix#Identity}*/ 2003 Matrix.I = function(nRows) { return Matrix.Identity(nRows); } 2004 2005 /** Creates a matrix of given size full of zeros 2006 * @param {int} [nRows=0] number of rows 2007 * @param {int} [nCols=0] number of columns 2008 * @returns {Matrix} new matrix full of zero 2009 * @example m = Matrix.Zeros(2,3); // m = Matrix([[0,0,0],[0,0,0]])*/ 2010 Matrix.Zeros = function(nRows,nCols) { 2011 var nRows = nRows || 0; 2012 var nCols = nCols || 0; 2013 var a = [] 2014 for (var r=0; r<nRows; r++) { 2015 a[r] = [] 2016 for (var c=0; c<nCols; c++) { 2017 a[r][c] = 0.; 2018 } 2019 } 2020 return Matrix.create(a); 2021 } 2022 2023 /** Creates a matrix of given size full of ones 2024 * @param {int} [nRows=0] number of rows 2025 * @param {int} [nCols=0] number of columns 2026 * @returns {Matrix} new vector full of zero 2027 * @example m = Matrix.Ones(2,3); // m = Matrix([[1,1,1],[1,1,1]])*/ 2028 Matrix.Ones = function(nRows,nCols) { 2029 var nRows = nRows || 0; 2030 var nCols = nCols || 0; 2031 var a = [] 2032 for (var r=0; r<nRows; r++) { 2033 a[r] = [] 2034 for (var c=0; c<nCols; c++) { 2035 a[r][c] = 1.; 2036 } 2037 } 2038 return Matrix.create(a); 2039 } 2040 2041 2042 2043 /* ************************************************** 2044 * 2045 * Initializing functions 2046 * 2047 ***************************************************/ 2048 2049 /** Returns new Matrix object from given array 2050 * @param {[floats](2D)} [arry=[]] array containing matrix elements 2051 * @returns {Matrix} new Matrix object 2052 * @example m = mat([[1,2,3],[4,5,6],[7,8,9]]) // m = Matrix([[1,2,3],[4,5,6],[7,8,9]])*/ 2053 mat = function(arry) { 2054 var arry = (arry==null)? [[]]:arry; 2055 return Matrix.create(arry); 2056 } 2057 2058 /** Returns new Vector object from given array 2059 * @param {[floats]} [arry=[]] array containing vector elements 2060 * @returns {Vector} new Vector object 2061 * @example v = vec([1,2,3,4]) // v = Vector([1,2,3,4])*/ 2062 vec = function(arry) { 2063 var arry = (arry==null)? []:arry; 2064 return Vector.create(arry); 2065 } 2066 2067 /** Returns new Vector or Matrix full of given size full of zeros 2068 * @param {int} nRows number of rows of returned object 2069 * @param {int} [nCols] if specified, new Matrix of size (nRows,nCols) is returned, new vector of size nRows otherwise 2070 * @returns {Matrix|Vector} new Matrix or Vector object 2071 * @example m = zeros(2,3); // m = Matrix([[0,0,0],[0,0,0]]) 2072 * v = zeros(4) // v = Vector([0,0,0,0])*/ 2073 zeros = function(nRows,nCols) { 2074 if (nCols) { return Matrix.Zeros(nRows,nCols); } 2075 if (nRows) { return Vector.Zeros(nRows); } 2076 return null; 2077 } 2078 2079 /** Returns new Vector or Matrix full of given size full of ones 2080 * @param {int} nRows number of rows of returned object 2081 * @param {int} [nCols] if specified, new Matrix of size (nRows,nCols) is returned, new vector of size nRows otherwise 2082 * @returns {Matrix|Vector} new Matrix or Vector object 2083 * @example m = zeros(2,3); // m = Matrix([[1,1,1],[1,1,1]]) 2084 * v = zeros(4) // v = Vector([1,1,1,1])*/ 2085 ones = function(nRows,nCols) { 2086 if (nCols) { return Matrix.Ones(nRows,nCols); } 2087 if (nRows) { return Vector.Ones(nRows); } 2088 return null; 2089 } 2090 2091 /** Returned identity matrix of given size, see {@link Matrix#Identity} 2092 * @param {int} nRows number of rows and columns of returned matrix 2093 * @returns {Matrix} nRows x nRows identity matrix 2094 * @example m = identity(3); // m = Matrix([[1,0,0],[0,1,0],[0,0,1]])*/ 2095 identity = function(nRows) { return Matrix.Identity(nRows); } 2096 2097 /** Alias for dentity(), see {@link identity}*/ 2098 eye = function(nRows) { return Matrix.Identity(nRows); } 2099 2100 2101 /* *********************************************************** 2102 * 2103 * Other functions 2104 * 2105 ************************************************************/ 2106 2107 /** Linear system equation solver. Returns vector x as a solution of a*ret=rhs, see {@link Matrix#solveForRhs} for input desription 2108 * @param {Matrix} a 2109 * @param {Vector|[Vectors]|Matrix} rhs 2110 * @param {bool} [saveOrig=true] 2111 * @param {int} [method=JSM_GAUSS] 2112 * @param {[Matrices]} [precompDecomps] 2113 * @returns {Vector|[Vectors]|Matrix} solution x of a*x=rhs*/ 2114 linSolve = function(a,rhs,saveOrig,method,precompDecomps) { return a.solveForRhs(rhs,saveOrig||undefined,method||undefined,precompDecomps||undefined); } 2115 2116 2117 /** Eigenvalues and eigenvectors solver. Returns first nEigModes eigenvales and eigenvectors of problem K*vi=oi^2*M*vi (oi is i-th eigenvale and vi is i-th eigenvector). Typycal example of usage is eigenvale dynamics. 2118 * @param {Matrix} K first matrix (stiffness matrix for dynamics) 2119 * @param {Matrix} M second matrix (mass matrix for dynamics) 2120 * @param {int} [nEigModes=1] number of first eigenvalues and eigenvectors to be returned 2121 * @param {int} [method=JSM_INV_IT] method of the solution. JSM_INV_IT stands for Stodola's inverse iterations methods with Gramm-Schmidt orthogonalization 2122 * @param {int} [maxiter=1000] maximum number of iterations 2123 * @returns {[[floats],[Vectors]]} [[o1,o2,...,oN],[v1,v2,...,vN]], oi is i-th eigenvale (squared eigenfrequency for dynamics), vi is i-th eigenvector. N = nEigModes 2124 * @example K = mat([[9,3,0,0],[3,8,2,0],[0,2,7,2],[0,0,2,8]]); 2125 * M = Matrix.Diagonal([3,2,4,3]); 2126 * e = eigSolve(K,M,4); 2127 * o = e[0]; 2128 * v = e[1]; 2129 * o1 = o[0]; // o1 = 1.2504038497315775 2130 * o2 = o[1]; // o2 = 2.279120228657416 2131 * o3 = o[2]; // o3 = 2.948867853467429 2132 * o4 = o[3]; // o4 = 4.938274734810245 2133 * v1 = v[0]; // v1 = Vector([ 0.1288306767139194, -0.22540165581364102, 0.4265175098731745, -0.20077135620035116 ]) 2134 * v2 = v[1]; // v2 = Vector([ 0.4514687335612619, -0.32545467450354726, -0.11713473474653795, 0.2014979513549984 ]) 2135 * v3 = v[2]; // v3 = Vector([ 0.14681878659487543, -0.007507144503266177, -0.21233717286242818, -0.5016212772448967 ]) 2136 * v4 = v[3]; // v4 = Vector([ 0.3022519091588433, 0.585847242190032, 0.09630780190740544, 0.028264211960396433 ]) 2137 * c1 = K.x(v1).sub(M.x(v1).x(o1)); // c1 = Vector([ 6.045241529584189e-10, -2.9052349415081835e-10, -2.091367079515294e-10, 2.697864154299623e-10 ]) 2138 * c2 = K.x(v2).sub(M.x(v2).x(o2)); // c2 = Vector([ 8.74326433475403e-9, -4.933693453779142e-10, -1.5765841965276195e-8, -2.9551703084607084e-8 ]) 2139 * c3 = K.x(v3).sub(M.x(v3).x(o3)); // c3 = Vector([ 4.5619911848149286e-8, 1.2227673172604536e-8, -9.32639299122684e-10, 1.3564216416739328e-8 ]) 2140 * c4 = K.x(v4).sub(M.x(v4).x(o4)); // c4 = Vector([ 9.357854047209457e-9, -3.189910557921394e-10, -1.804510585401431e-8, -3.197205944438508e-8 ])*/ 2141 eigSolve = function(K,M,nEigModes,method,maxiter) { 2142 var K = K; 2143 var M = M; 2144 if (!K.isSquare() || !M.isSquare() || !K.isSameSizeAs(M)) { return null; } 2145 var nEigModes = nEigModes || 1; // nEigModes first eigenvalues and eigenvectors will be returned 2146 if (nEigModes > K.nRows) { nEigModes = K.nRows; } 2147 var method = method || JSM_INV_IT; 2148 var maxiter = maxiter || 1000; 2149 if (method == JSM_INV_IT) { // Stodola's inverse iteration with Gramm-Schmidt orthogonalization 2150 var DM = K.inv().mulm(M); 2151 var tol = 1e-32; 2152 var eigVals = []; 2153 var eigVecs = []; 2154 var eigVecsMulmM = []; 2155 var rho, rhoRatio, rhoNew, iter; 2156 var xk = Vector.Zeros(K.nRows); 2157 for (var k=0; k<nEigModes; k++) { 2158 xk.zero(); xk.set(0,1.); 2159 iter = 0; 2160 rhoNew = 0.; 2161 do { 2162 xk = DM.mulv(xk); 2163 for (var j=0; j<k; j++) { xk.isub(eigVecs[j].mulf(eigVecsMulmM[j].dot(xk))); } // Gramm-Schmidt orthogonalization 2164 xk.imulf(1./Math.sqrt(xk.mulm(M).dot(xk))); 2165 rho = rhoNew; 2166 rhoNew = (xk.mulm(K).dot(xk)) / (xk.mulm(M).dot(xk)); 2167 rhoRatio = Math.abs(rhoNew-rho)/rhoNew; 2168 iter++; 2169 if (iter > maxiter) { 2170 if (rhoRatio > JSM_TOL) { 2171 //alert('Eigenvalue solution failed...'); 2172 } 2173 break; 2174 } 2175 } while (rhoRatio > tol) 2176 eigVals.push(rhoNew); 2177 eigVecs.push(xk.copy()); 2178 eigVecsMulmM.push(xk.mulm(M)); 2179 } 2180 return [eigVals,eigVecs]; 2181 } 2182 if (method == JSM_SUBSPACE) { // subspace iteration 2183 var n = K.nRows; 2184 var kk, mm, r, ret, q; 2185 x = Matrix.Ones(n,nEigModes); 2186 for (var i=0; i<n; i++) { x.set(i,i,0.); } 2187 lu = K.luDecomposition() 2188 for (var i=0; i<50; i++) { 2189 x = K.solveForRhs(M.x(x),JSM_LU,false,lu); 2190 kk = x.T().x(K).x(x); 2191 mm = x.T().x(M).x(x); 2192 r = eigSolve(kk,mm,nEigModes); 2193 q = Matrix.Zeros(nEigModes,nEigModes); 2194 for (var j=0; j<nEigModes; j++) { 2195 q.setCol(j,r[1][j]); 2196 } 2197 x = x.x(q); 2198 } 2199 ret = [[],[]]; 2200 for (var i=0; i<nEigModes; i++) { 2201 ret[0].push(r[0][i]); 2202 ret[1].push(x.getCol(i)); 2203 } 2204 return ret; 2205 } 2206 } 2207 2208 /** Returns sequence (array) with start, stop, step. Inspired by <a href="www.python.org">Python</a> syntax 2209 * @param {float|int} a start/stop (according to b, see example) 2210 * @param {float|int} [b] stop 2211 * @param {float|int} [c=1] step 2212 * @returns {[floats]} array containing given sequence 2213 * @example r = range(8); // r = [0,1,2,3,4,5,6,7] 2214 * r = range(2,8); // r = [2,3,4,5,7] 2215 * r = range(2,8,2); // r = [2,4,6]*/ 2216 range = function(a,b,c) { 2217 var start; 2218 var step; 2219 var stop; 2220 if (b==null && c==null) { 2221 start = 0; 2222 stop = a; 2223 step = 1; 2224 } else if (c==null) { 2225 start = a; 2226 stop = b; 2227 step = 1; 2228 } else { 2229 start = a; 2230 stop = b; 2231 step = c; 2232 } 2233 var ret = [] 2234 var item = start; 2235 while (item < stop) { 2236 ret.push(item); 2237 item += step; 2238 } 2239 return ret; 2240 } 2241 2242 /**@ignore*/ 2243 Array.prototype.indexOf = function(val) { 2244 for (var i=0; i<this.length; i++) { 2245 if (this[i] === val) { return i; } 2246 } 2247 } 2248