-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMatrix.jsx
250 lines (221 loc) · 6.73 KB
/
Matrix.jsx
1
/** * Matrix Constructor. Accepts 2D array of Transform Values. * @param {[[array]]} trans [2D Array of Number/Integer] * @return void */ Matrix = function Matrix(){ if(typeof arguments[0] === "boolean" && arguments[0]) return; //Can't make empty matrix. if(arguments.length == 0) throw new Error("Please pass one or more Number Arrays to construct a Matrix"); var elements = (arguments.length == 1)?arguments[0]:Array.prototype.slice.call(arguments); //Forward calls without constructor. if ((this.constructor.name != "Matrix") ) { return new Matrix(elements); } //Ensure we have been passed at least 1 array if(!elements || !(elements instanceof Array) || !elements.length) throw new Error("Error: Cannot construct empty matrix. Please pass a 2D Matrix"); this.setValues(elements);}/** * Calculate Cofactor of matrix element at i, j * @param {int} i The Row Index * @param {int} j The Column Index * @return {float} The Cofactor */ Matrix.prototype.cofactor = function(i, j){ var minor = this.minor(i, j); var sign = 1; if((i * this.columns + j) % 2){ sign = -1; } return sign * minor.determinant(); }/** * Calculates the matrix of Cofactors for this matrix. * @return {Matrix} The matrix of Cofactors. */ Matrix.prototype.cofactorMatrix = function(){ var result = []; for(var i = 0; i < this.rows; i++){ result.push([]); for(var j = 0; j < this.columns; j++){ result[i].push(this.cofactor(i, j)); } } return new Matrix(result);}/** * Calculate the determinant of the matrix. * @return {[type]} [description] */ Matrix.prototype.determinant = function(){ if(this.columns != this.rows){ throw new Error("Cannot calculate determinant of non-square matrix"); } //Base Case. if(this.columns == 2){ return this[0][0] * this[1][1]- this[0][1] * this[1][0]; } //Else recurse through matrix minors. var sign = 1; var det = 0; for(var i = 0; i < this.columns; i++){ det += sign * this[0][i] * this.minor(0, i).determinant(); sign *= -1; } return det; }//Return the adjoint of this matrix.Matrix.prototype.adjoint = function(){ var m = this.cofactorMatrix(); return m.transpose();}/** * minor * @param {int} y The Row Number to discard * @param {int} x The Column Number to discard * @return {Matrix} The Minor matrix. */ Matrix.prototype.minor = function(y, x){ var minor = []; for(var i = 0; i < this.rows; i++){ if(i == y) continue; var row = []; minor.push(row) for(var j = 0; j < this.columns; j++){ if(j == x) continue; row.push(this[i][j]); } } return new Matrix(minor);}/** * Return the inverse of this matrix * @return {Matrix} The Inverse Matrix. */ Matrix.prototype.inverse = function(){ return this.adjoint() / this.determinant();}/** * String representation of this matrix * @return {String} String Representation */ Matrix.prototype.toString = function() { var asString = ""; for(var i= 0; i < this.rows; i++){ asString += "\n\t"; var row = []; for(var j = 0; j < this.columns; j++){ row.push(this[i][j]); } asString += "["+row+"]"; } return asString;};/** * Transpose this matrix * @return {Matrix} The Transpose of this matrix */ Matrix.prototype.transpose = function(){ var result = []; for(var j = 0; j < this.columns; j++){ var row = []; result.push(row); for(var i = 0; i < this.rows; i++){ row.push(this[i][j]); } } return new Matrix(result);}Matrix.prototype.clear = function(){ for(var i = 0; i < this.rows; i++){ delete this[i]; } this.rows = this.columns = 0;}Matrix.prototype.setValues = function(){ var elements = (arguments.length == 1)?arguments[0]:Array.prototype.slice.call(arguments); this.rows = elements.length; delete this.columns; //Populate rows. for(var i = 0; i < this.rows; i++){ var row = elements[i]; var rowLength = row.length; if(!('columns' in this)){ this.columns = rowLength; if(!rowLength){ throw new Error("Error: Row #"+i+" in matrix is empty"); } } //Ensure all rows must be of the same length. if(rowLength != this.columns){ throw new Error("Error: Not all rows of equal length in "+"["+elements.join("][")+"]"); } //Populate columns for(var j = 0; j < rowLength; j++){ if(isNaN(row[j])){ throw new Error("Error: Item at "+i+":"+j+" is not a number") } if(!this[i]) this[i] = new Array(j); this[i][j] = row[j]; } }}Matrix.prototype.toArray = function(){ var result = []; for(var i = 0; i < this.rows; i++){ result.push([]); for(var j = 0; j < this.columns; j++){ result[i].push(this[i][j]); } } return result;}/** * / * @param {Float} other Divide elements of this matrix by "other" * @param {Boolean} reverse Whether this was called in reverse order (e.g 5 / Matrix) (Not supported.) * @return {Matrix} The divided Matrix. */ Matrix.prototype["/"] = function(other, reverse){ if(isNaN(other) || reverse){ throw new Error("Matrix must be divided by a single number in correct order"); } var result = []; for(var i = 0; i < this.rows; i++){ var row = []; result.push(row); for(var j = 0; j < this.columns; j++){ row.push(this[i][j]/other); } } return new Matrix(result);}/** * Multiply this Matrix with another matrix * @param {Matrix} other The other matrix. Must have same number of rows as the first matrix has columns * @return {Matrix} The resultant matrix. */ Matrix.prototype["*"] = function(other) { if(this.columns != other.rows) throw new Error("Cannot multiply matrices. Columns for A "+this.columns+" do not match Rows for B "+other.rows); var result = new Array(this.rows); for(var i = 0; i < this.rows; i++){ result[i] = new Array(other.columns); }; for(var i = 0; i < this.rows; i++){ var row = this[i]; for(var j = 0; j < other.columns; j++){ var cell = 0; for(var a = 0; a < this.columns; a++){ cell += row[a] * other[a][j]; } result[i][j] = cell; } } return new Matrix(result);}; new Matrix([1,0,0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0,0,0,1]).inverse().transpose();