Matrix.js
Summary
This file defines the Matrix class, instance methods, and static objects/methods. It depends on the Vector class, but as long as easyload.js is loaded first, Vector.js will automatically be included with this file.
dependencies = ['Vector'];
require(dependencies);
function Matrix(elements) {
this.components = new Array();
if(elements instanceof Vector) {
this.components[0] = new Vector(elements);
}
if(elements instanceof Array) {
if(typeof elements[0][0] != 'undefined') {
for(i = 0; i < elements.length; i++) {
this.components[i] = new Vector(elements[i]);
}
} else {
this.components[0] = new Vector(elements);
}
}
if(elements instanceof Matrix) {
for(i = 0; i < elements.numRows(); i++) {
this.components[i] = new Vector(elements.components[i]);
}
}
}
Matrix.prototype = {
get: function(i,j) {
return (i < 1 || i > this.components.length || j < 1 || j > this.components[0].dimension()) ? null : this.components[i-1].components[j-1];
},
equalTo: function(matrix) {
var M = matrix;
if(matrix instanceof Vector) {
M = new Matrix(matrix);
}
if(!this.sameSizeAs(M)) {
return false;
}
for(i = 1; i <= this.numRows(); i++) {
if(!this.row(i).equalTo(M.row(i))) {
return false;
}
}
return true;
},
map: function(func) {
var rows = new Array();
for(k = 0; k < this.numRows(); k++) {
rows[k] = this.components[k].map(func);
rows[k] = rows[k].components;
}
return new Matrix(rows);
},
row: function(i) {
return new Vector(this.components[i-1]);
},
col: function(j) {
var column = new Array();
for(i = 1; i <= this.components.length; i++) {
column[i-1] = this.get(i,j);
}
return new Vector(column);
},
numRows: function() {
return this.components.length;
},
numCols: function() {
return this.components[0].dimension();
},
add: function(matrix) {
if(!this.sameSizeAs(matrix)) {
return null;
}
return this.map(function(x,i,k) { return x + matrix.get(k+1,i+1); });
},
subtract: function(matrix) {
if(!this.sameSizeAs(matrix)) {
return null;
}
return this.map(function(x,i,k) { return x - matrix.get(k+1,i+1); });
},
multiplyBy: function(k) {
return this.map(function(x) { return x*k; });
},
canMultiplyFromLeft: function(matrix) {
if(matrix instanceof Matrix) {
return (this.numCols() == matrix.numRows());
}
if(matrix instanceof Vector) {
return (this.numCols() == matrix.dimension());
}
if(typeof matrix == 'number') {
return true;
}
if(matrix instanceof point2D || matrix instanceof point3D) {
return (this.numCols() == matrix.components.length);
}
},
multiply: function(matrix) {
if(!this.canMultiplyFromLeft(matrix)) {
return null;
}
if(typeof matrix == 'number') {
return this.multiplyBy(matrix);
}
var elements = new Array(this.numRows());
var M = matrix;
if(M.n) {
for(i = 1; i <= this.numRows(); i++) {
elements[i-1] = this.row(i).dot(M);
}
return new Vector(elements);
}
var i = 1;
while(i <= this.numRows()) {
elements[i-1] = new Array();
for(j = 1; j <= matrix.numCols(); j++) {
elements[i-1][j-1] = this.row(i).dot(M.col(j));
}
i++;
}
return new Matrix(elements);
},
transpose: function() {
var elements = new Array(this.numCols());
for(i = 0; i < this.numCols(); i++) {
elements[i] = new Array();
for(j = 0; j < this.numRows(); j++) {
elements[i][j] = this.components[j].components[i];
}
}
return new Matrix(elements);
},
isSquare: function() {
var dims = this.dimensions();
return (dims.rows == dims.columns);
},
trace: function() {
if(!this.isSquare()) {
return null;
}
var tr = 0;
for(i = 1; i <= this.numRows(); i++) {
tr += this.get(i,i);
}
return tr;
},
tr: function() {
return this.trace();
},
toUpperTriangular: function() {
var M = new Matrix(this);
var i = 1, j = 1;
var rows = this.numRows(), cols = this.numCols();
while (i <= rows && j <= cols) {
if(M.get(i,i) == 0) {
for(k = i+1; k <= rows; k++) {
if(M.get(k,i) != 0) {
M.components[i-1] = M.row(1).add(M.row(k));
break;
}
}
}
if(M.get(i,i) != 0) {
for(k = i+1; k<=rows; k++) {
var multiplier = M.get(k,i) / M.get(i,i);
M.components[k-1] = M.row(k).subtract(M.row(i).multiplyBy(multiplier));
}
}
i++;
j++;
}
return M;
},
determinant: function() {
if(!this.isSquare()) {
return null;
}
var M = this.toUpperTriangular();
var det = M.get(1,1);
for(i = 1; i <= M.numRows(); i++) {
det = det*M.get(i,i);
}
return det;
},
det: function() {
return this.determinant();
},
isSingular: function() {
return (this.isSquare() && this.determinant() == 0);
},
invertible: function() {
return (this.isSingular() ? false : true);
},
invert: function() {
if(!this.invertible()) {
return null;
}
var M = this.augment(Matrix.I(this.numRows())).toUpperTriangular();
var thisRow = M.numRows();
while(thisRow > 0) {
M.components[thisRow-1] = M.row(thisRow).multiplyBy(1/M.get(thisRow,thisRow));
for(j = thisRow - 1; j > 0; j--) {
var multBy = M.get(j,thisRow);
var temp = M.row(thisRow).multiplyBy(multBy);
M.components[j-1] = M.row(j).subtract(temp);
}
thisRow--;
}
var rows = M.numRows();
return M.minor(1,rows+1,rows,rows);
},
minor: function(row, col, numrows, numcols) {
var row1 = row, col1 = col, nrows = numrows, ncols = numcols;
var elements = new Array();
var i = 0, rows = this.numRows(), cols=this.numCols();
while(i < nrows) {
elements[i] = new Array();
var j = 0;
while(j < ncols) {
elements[i][j] = this.components[(row1+i-1)%rows].components[(col1+j-1)%cols];
j++;
}
i++;
}
return new Matrix(elements);
},
augment: function(matrix) {
var thisMatrix = new Matrix(this);
var M = matrix;
if(!(M instanceof Matrix)) {
if(M instanceof Vector || M instanceof Array) {
M = new Matrix(matrix);
}
}
if(thisMatrix.numRows() == M.numRows()) {
var i = 1, cols = thisMatrix.numCols();
while(i <= thisMatrix.numRows()) {
var j = 1;
while(j <= M.numCols()) {
thisMatrix.components[i-1].components[(cols + j) - 1] = M.get(i,j);
j++;
}
i++;
}
}
return new Matrix(thisMatrix);
},
rank: function() {
var M = this.toUpperTriangular();
rank = 0;
for(i = 1; i <= this.numRows(); i++) {
for(j = 1; j <= this.numCols(); j++) {
if(Math.abs(M.get(i,j)) > Zero) {
rank++;
break;
}
}
}
return rank;
},
dimensions: function() {
return {rows: this.numRows(), columns: this.numCols()};
},
round: function() {
return this.map(function(x) { Math.round(x); });
},
max: function() {
var max = 0, i = 1;
while(i <= this.numRows()) {
var temp = this.row(i).max();
if(Math.abs(temp) > Math.abs(max)) {
max = temp;
}
i++;
}
return max;
},
snapTo: function(val) {
return this.map(function(x) {
return (Math.abs(x - val) <= Zero) ? val : x;
});
},
getDiagonal: function() {
if(!this.isSquare()) {
return null;
}
var elements = new Array(), i = 1;
while(i <= this.numRows()) {
elements[i-1] = this.get(i,i);
i++;
}
return new Vector(elements);
},
negative: function() {
return this.map(function(x) { return -x; });
},
toVector: function() {
if(this.numCols() == 1) {
var els = new Array();
for(i = 1; i <= this.numRows(); i++) {
els[i-1] = this.get(i,1);
}
return new Vector(els);
}
if(this.numRows() == 1) {
return new Vector(this.components[0]);
}
return null;
},
indexOf: function(val) {
var i = 1;
while(i <= this.numRows()) {
var temp = this.row(i).indexOf(val);
if(temp) {
return {i: i, j: temp};
}
i++;
}
return null;
},
sameSizeAs: function(matrix) {
var thisDim = this.dimensions();
var mDim = matrix.dimensions();
return (thisDim.rows == mDim.rows && thisDim.columns == mDim.columns);
},
setElement: function(i, j, val) {
this.components[i-1].components[j-1] = val;
},
toString: function() {
return this.components.join("\n");
}
}
Matrix.I = function(n) {
var matrix = new Array(n);
for(i = 0; i < n; i++) {
var row = new Array(n);
row[i] = 1;
for(j = 0; j < n; j++) {
if(j != i) {
row[j] = 0;
}
}
matrix[i] = row;
}
return new Matrix(matrix);
}
Matrix.zero = function(rows, cols) {
var elements = new Array();
for(i = 0; i < rows; i++) {
elements[i] = new Array();
for(j = 0; j < cols; j++) {
elements[i][j] = 0;
}
}
return new Matrix(elements);
}
Matrix.random = function(rows, cols, max) {
return Matrix.zero(rows, cols).map(function() {
if(max) {
return Math.floor(Math.random()*(max+1));
}
return Math.random();
});
}
Matrix.diagonal = function(elements) {
var els;
if(elements instanceof Vector) {
els = elements.components;
} else if(elements instanceof Array) {
els = elements;
} else {
return null;
}
var M = Matrix.I(els.length);
for(i = 0; i < els.length; i++) {
M.setElement(i+1,i+1,els[i]);
}
return M;
}
Documentation generated by
JSDoc on Mon Aug 11 13:58:31 2008