/* MatrixMath.js C Odenthal 2008-04 This file contains JavaScript functions to do some matrix computations. Nothing fancy, matrix multiplication and addition; maybe a bit more. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (at http://www.gnu.org/licences/lgpl.html) for more details. */ // Vectors are implemented as javascript Arrays of numbers. Vectors can // be displayed as either row or column vectors. A matrix consists of an // Array of row vectors. When a row or column is removed from a matrix // it becomes nondenominational - either a row or a column vector, and // a vector can be inserted into a matrix as either a row or column. // // All functions return explicit values and have no side effects. Since // javascript passes Arrays by reference, explicit copies have to be // made of all matrix and vector inputs to functions. This is inefficient, // but we're not doing anything computationally intensive enough for this // to matter. Much. // Functions to create matrices and vectors. // Many of these use the 'ran' function from ASCIIMathML.js function rr () { return ran(-9,9,3) } // The attempt is to use inheritance (rather than aggregation) from the // builtin Array class to make Vector and Matrix classes. See page 116 // of "Javascript Objects" by Nakhimovsky and Myers. // // First some prototyped functions to add Array methods. // They change the original Array and return the modified Array. // // Performs a random shuffle of the entries of the Array. Array.prototype.shuffle = function () { if (this.copy) { that = this.copy() } else { that = this.slice() } for (var rnd, tmp, i=that.length-1; i>0; i--) { rnd = ran(0,i) tmp = that[rnd] that[rnd] = that[i] that[i] = tmp } return that } // Applies the provided function 'fun' to every entry of the Array. // This prototype is provided by the Mozilla foundation and // is distributed under the MIT license. // http://www.ibiblio.org/pub/Linux/LICENSES/mit.license // But I fiddled with the code's formatting. I couldn't help myself. if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) res[i] = fun.call(thisp, this[i], i, this); } return res; }; } // // Some numerical constants in my version of javascript: // 1e-324 == 0 // 1e309 == Infinity // 1+1e-15 == 1.000000000000001 // 1+1e-16 == 1 // // // Vector constructor and methods // function Vector () { if (arguments.length==1) { for (var i=0; i max_v) { max_i = k max_v = Math.abs(C[k][i]) } } if (max_v > 0) { col = C.transpose()[i] row = C[max_i] ddd = row[i] col = col.div(ddd) Lt.push( col ) U.push( row ) C = C.sub(col.mul(row)) if (i != max_i) { permuted.push(i) if (permuted.indexOf(max_i) == -1) { parity = -parity permuted.push(max_i) } } } } if (Lt.length == 0) { Lt = zeros(1,m) Lt[0][0] = 1 U = zeros(1,n) } return [Lt.transpose(), U, parity] } Matrix.prototype.qdr = function () { // Returns [Q,D,R] where A=QDR and Q has orthogonal columns, // the diagonal D stores the inverses of the squares of the // column lengths of Q, and R is upper triangular. var C = this.copy() var m = C[0].length var Qt = new Matrix() var R = new Matrix() var row = new Vector() var col = new Vector() var d = new Vector() var sca = 0 for (var i=0; i 0.00000000000000000000000001) { row = col.mul(C) // Cleanup row. for (var j=0; j 0.00000000000000000000000001) { row = col.mul(C) // Cleanup row. for (var j=0; j 0.00000000000000000000000001) { row = col.mul(C) // Cleanup row. for (var j=0; j 0.0000000000001) { row = col.mul(C) // scale row and column row = row.div(sca) col = col.div(sca) // Cleanup row. for (var j=0; j-1; k--) { x[k] = x[k]/this[k][k] for (var i=0; i-1; k--) { x[k] = x[k].div(this[k][k]) for (var i=0; i 1e-25) { var tau = (a-b)/(2*d) var t = sign(tau)/( Math.abs(tau) + Math.sqrt(1+tau*tau) ) var c = 1/Math.sqrt(1+t*t) var s = c*t mat[i][i] = c mat[i][j] = -s mat[j][i] = s mat[j][j] = c } } return mat } Matrix.prototype.householder = function (j,k) { // Returns a Householder reflector H such that // H*'this' has zeros in column j past position // k. if (!k) { k = j } var mat = eye(this.length) var vec = this.transpose()[j] for (var i=0; i1) { As = "(" + As + ")" } return As } Matrix.prototype.natascii = function () { var m = this.length var n = this[0].length var As = [] for (var i=0; i1) { As = "(" + As + ")" } return As } // The next method produces a string representation that // is a javascript Array of Arrays. ASCIIMathML.js will // format this as a matrix with square brackets and // floating point numbers. Matrix.prototype.jscript = function () { var m = this.length var n = this[0].length var As = [] var t = 0 for (var i=0; i1) { As = "[" + As + "]" } return As } // // Global functions using Matrix and Vector classes // function random_vector (m,lo,hi) { var vec = new Vector() for (var i=0; i1 if (j == n-1) { return A.stack(zeros(m-1,n)) } // We reach here if m>1 and j