Comparing version
@@ -1,5 +0,6 @@ | ||
0.0.5 / head | ||
============ | ||
0.1.0 / 2015-06-11 | ||
================== | ||
* use standard errors, remove MatrixError | ||
* implement getColumnVector and getRowVector | ||
@@ -6,0 +7,0 @@ 0.0.4 / 2015-06-11 |
{ | ||
"name": "ml-matrix", | ||
"version": "0.1.0", | ||
"version": "1.0.0-0", | ||
"description": "Matrix manipulation and computation library", | ||
@@ -41,7 +41,12 @@ "main": "src/index.js", | ||
"devDependencies": { | ||
"mocha-better-spec-reporter": "latest", | ||
"mocha": "latest", | ||
"should": "latest", | ||
"should-approximately-deep": "latest" | ||
"benchmark": "^1.0.0", | ||
"csv-parse": "^1.0.0", | ||
"mathjs": "^2.1.1", | ||
"mocha": "^2.2.5", | ||
"mocha-better-spec-reporter": "^2.1.1", | ||
"numeric": "^1.2.6", | ||
"pretty-hrtime": "^1.0.0", | ||
"should": "^7.0.4", | ||
"should-approximately-deep": "^1.1.0" | ||
} | ||
} |
'use strict'; | ||
var Matrix = require('../matrix'); | ||
const Matrix = require('../matrix'); | ||
@@ -5,0 +5,0 @@ // https://github.com/lutzroeder/Mapack/blob/master/Source/CholeskyDecomposition.cs |
'use strict'; | ||
var Matrix = require('../matrix'); | ||
var hypotenuse = require('./util').hypotenuse; | ||
const Matrix = require('../matrix'); | ||
const util = require('./util'); | ||
const hypotenuse = util.hypotenuse; | ||
const getFilled2DArray = util.getFilled2DArray; | ||
@@ -17,3 +19,3 @@ // https://github.com/lutzroeder/Mapack/blob/master/Source/EigenvalueDecomposition.cs | ||
var n = matrix.columns, | ||
V = Matrix.zeros(n, n), | ||
V = getFilled2DArray(n, n, 0), | ||
d = new Array(n), | ||
@@ -34,3 +36,3 @@ e = new Array(n), | ||
else { | ||
var H = Matrix.zeros(n, n), | ||
var H = getFilled2DArray(n, n, 0), | ||
ort = new Array(n); | ||
@@ -60,2 +62,5 @@ for (j = 0; j < n; j++) { | ||
get eigenvectorMatrix() { | ||
if (!Matrix.isMatrix(this.V)) { | ||
this.V = new Matrix(this.V); | ||
} | ||
return this.V; | ||
@@ -62,0 +67,0 @@ }, |
'use strict'; | ||
var Matrix = require('../matrix'); | ||
const Matrix = require('../matrix'); | ||
@@ -5,0 +5,0 @@ // https://github.com/lutzroeder/Mapack/blob/master/Source/LuDecomposition.cs |
'use strict'; | ||
var Matrix = require('../matrix'); | ||
var hypotenuse = require('./util').hypotenuse; | ||
const Matrix = require('../matrix'); | ||
const hypotenuse = require('./util').hypotenuse; | ||
@@ -6,0 +6,0 @@ //https://github.com/lutzroeder/Mapack/blob/master/Source/QrDecomposition.cs |
'use strict'; | ||
var Matrix = require('../matrix'); | ||
var hypotenuse = require('./util').hypotenuse; | ||
const Matrix = require('../matrix'); | ||
const util = require('./util'); | ||
const hypotenuse = util.hypotenuse; | ||
const getFilled2DArray = util.getFilled2DArray; | ||
@@ -15,4 +17,3 @@ // https://github.com/lutzroeder/Mapack/blob/master/Source/SingularValueDecomposition.cs | ||
var a = value.clone(), | ||
m = value.rows, | ||
var m = value.rows, | ||
n = value.columns, | ||
@@ -29,7 +30,9 @@ nu = Math.min(m, n); | ||
var swapped = false; | ||
var a; | ||
if (m < n) { | ||
if (!autoTranspose) { | ||
a = value.clone(); | ||
console.warn('Computing SVD on a matrix with more columns than rows. Consider enabling autoTranspose'); | ||
} else { | ||
a = a.transpose(); | ||
a = value.transpose(); | ||
m = a.rows; | ||
@@ -42,7 +45,9 @@ n = a.columns; | ||
} | ||
} else { | ||
a = value.clone(); | ||
} | ||
var s = new Array(Math.min(m + 1, n)), | ||
U = Matrix.zeros(m, nu), | ||
V = Matrix.zeros(n, n), | ||
U = getFilled2DArray(m, nu, 0), | ||
V = getFilled2DArray(n, n, 0), | ||
e = new Array(n), | ||
@@ -418,5 +423,11 @@ work = new Array(m); | ||
get leftSingularVectors() { | ||
if (!Matrix.isMatrix(this.U)) { | ||
this.U = new Matrix(this.U); | ||
} | ||
return this.U; | ||
}, | ||
get rightSingularVectors() { | ||
if (!Matrix.isMatrix(this.V)) { | ||
this.V = new Matrix(this.V); | ||
} | ||
return this.V; | ||
@@ -443,6 +454,8 @@ }, | ||
var U = this.U; | ||
var V = this.rightSingularVectors; | ||
var VL = this.V.mmul(Ls), | ||
vrows = this.V.rows, | ||
urows = this.U.rows, | ||
var VL = V.mmul(Ls), | ||
vrows = V.rows, | ||
urows = U.length, | ||
VLU = Matrix.zeros(vrows, urows), | ||
@@ -455,3 +468,3 @@ j, k, sum; | ||
for (k = 0; k < scols; k++) { | ||
sum += VL[i][k] * this.U[j][k]; | ||
sum += VL[i][k] * U[j][k]; | ||
} | ||
@@ -468,5 +481,6 @@ VLU[i][j] = sum; | ||
inverse: function () { | ||
var V = this.V; | ||
var e = this.threshold, | ||
vrows = this.V.rows, | ||
vcols = this.V.columns, | ||
vrows = V.length, | ||
vcols = V[0].length, | ||
X = new Matrix(vrows, this.s.length), | ||
@@ -478,3 +492,3 @@ i, j; | ||
if (Math.abs(this.s[j]) > e) { | ||
X[i][j] = this.V[i][j] / this.s[j]; | ||
X[i][j] = V[i][j] / this.s[j]; | ||
} else { | ||
@@ -486,4 +500,6 @@ X[i][j] = 0; | ||
var urows = this.U.rows, | ||
ucols = this.U.columns, | ||
var U = this.U; | ||
var urows = U.length, | ||
ucols = U[0].length, | ||
Y = new Matrix(vrows, urows), | ||
@@ -496,3 +512,3 @@ k, sum; | ||
for (k = 0; k < ucols; k++) { | ||
sum += X[i][k] * this.U[j][k]; | ||
sum += X[i][k] * U[j][k]; | ||
} | ||
@@ -499,0 +515,0 @@ Y[i][j] = sum; |
'use strict'; | ||
exports.hypotenuse = function hypotenuse(a, b) { | ||
var r; | ||
if (Math.abs(a) > Math.abs(b)) { | ||
r = b / a; | ||
let r = b / a; | ||
return Math.abs(a) * Math.sqrt(1 + r * r); | ||
} | ||
if (b !== 0) { | ||
r = a / b; | ||
let r = a / b; | ||
return Math.abs(b) * Math.sqrt(1 + r * r); | ||
@@ -15,1 +14,24 @@ } | ||
}; | ||
// For use in the decomposition algorithms. With big matrices, access time is | ||
// too long on elements from array subclass | ||
// todo check when it is fixed in v8 | ||
// http://jsperf.com/access-and-write-array-subclass | ||
exports.getEmpty2DArray = function (rows, columns) { | ||
var array = new Array(rows); | ||
for (var i = 0; i < rows; i++) { | ||
array[i] = new Array(columns); | ||
} | ||
return array; | ||
}; | ||
exports.getFilled2DArray = function (rows, columns, value) { | ||
var array = new Array(rows); | ||
for (var i = 0; i < rows; i++) { | ||
array[i] = new Array(columns); | ||
for (var j = 0; j < columns; j++) { | ||
array[i][j] = value; | ||
} | ||
} | ||
return array; | ||
}; |
'use strict'; | ||
var Matrix = require('./matrix'); | ||
const Matrix = require('./matrix'); | ||
var SingularValueDecomposition = require('./dc/svd'); | ||
var EigenvalueDecomposition = require('./dc/evd'); | ||
var LuDecomposition = require('./dc/lu'); | ||
var QrDecomposition = require('./dc/qr'); | ||
var CholeskyDecomposition = require('./dc/cholesky'); | ||
const SingularValueDecomposition = require('./dc/svd'); | ||
const EigenvalueDecomposition = require('./dc/evd'); | ||
const LuDecomposition = require('./dc/lu'); | ||
const QrDecomposition = require('./dc/qr'); | ||
const CholeskyDecomposition = require('./dc/cholesky'); | ||
function inverse(matrix) { | ||
matrix = Matrix.checkMatrix(matrix); | ||
return solve(matrix, Matrix.eye(matrix.rows)); | ||
} | ||
Matrix.prototype.inverse = function () { | ||
Matrix.inverse = Matrix.inv = inverse; | ||
Matrix.prototype.inverse = Matrix.prototype.inv = function () { | ||
return inverse(this); | ||
@@ -20,5 +22,8 @@ }; | ||
function solve(leftHandSide, rightHandSide) { | ||
leftHandSide = Matrix.checkMatrix(leftHandSide); | ||
rightHandSide = Matrix.checkMatrix(rightHandSide); | ||
return leftHandSide.isSquare() ? new LuDecomposition(leftHandSide).solve(rightHandSide) : new QrDecomposition(leftHandSide).solve(rightHandSide); | ||
} | ||
Matrix.solve = solve; | ||
Matrix.prototype.solve = function (other) { | ||
@@ -25,0 +30,0 @@ return solve(this, other); |
2397
src/matrix.js
'use strict'; | ||
var Asplice = Array.prototype.splice, | ||
Aconcat = Array.prototype.concat; | ||
// For performance : http://jsperf.com/clone-array-slice-vs-while-vs-for | ||
function slice(arr) { | ||
var i = 0, | ||
ii = arr.length, | ||
result = new Array(ii); | ||
for (; i < ii; i++) { | ||
result[i] = arr[i]; | ||
} | ||
return result; | ||
} | ||
/** | ||
* Real matrix. | ||
* @constructor | ||
* @param {number|Array} nRows - Number of rows of the new matrix or a 2D array containing the data. | ||
* @param {number|boolean} [nColumns] - Number of columns of the new matrix or a boolean specifying if the input array should be cloned | ||
* Real matrix | ||
*/ | ||
function Matrix(nRows, nColumns) { | ||
var i = 0, rows, columns, matrix, newInstance; | ||
if (Array.isArray(nRows)) { | ||
newInstance = nColumns; | ||
matrix = newInstance ? slice(nRows) : nRows; | ||
nRows = matrix.length; | ||
nColumns = matrix[0].length; | ||
if (typeof nColumns === 'undefined') { | ||
throw new TypeError('Data must be a 2D array'); | ||
} | ||
if (nRows > 0 && nColumns > 0) { | ||
for (; i < nRows; i++) { | ||
class Matrix extends Array { | ||
/** | ||
* @constructor | ||
* @param {number|Array|Matrix} nRows - Number of rows of the new matrix, | ||
* 2D array containing the data or Matrix instance to clone | ||
* @param {number} [nColumns] - Number of columns of the new matrix | ||
*/ | ||
constructor(nRows, nColumns) { | ||
if (Matrix.isMatrix(nRows)) { | ||
return nRows.clone(); | ||
} else if (typeof nRows === 'number' && nRows > 0) { // Create an empty matrix | ||
super(nRows); | ||
if (typeof nColumns === 'number' && nColumns > 0) { | ||
for (var i = 0; i < nRows; i++) { | ||
this[i] = new Array(nColumns); | ||
} | ||
} else { | ||
throw new TypeError('nColumns must be a positive number'); | ||
} | ||
} else if (Array.isArray(nRows)) { // Copy the values from the 2D array | ||
var matrix = nRows; | ||
nRows = matrix.length; | ||
nColumns = matrix[0].length; | ||
if (typeof nColumns !== 'number' || nColumns === 0) { | ||
throw new TypeError('Data must be a 2D array with at least one element'); | ||
} | ||
super(nRows); | ||
for (var i = 0; i < nRows; i++) { | ||
if (matrix[i].length !== nColumns) { | ||
throw new RangeError('Inconsistent array dimensions'); | ||
} else if (newInstance) { | ||
matrix[i] = slice(matrix[i]); | ||
} | ||
this[i] = [].concat(matrix[i]); | ||
} | ||
} else { | ||
throw new RangeError('Invalid dimensions: ' + nRows + 'x' + nColumns); | ||
throw new TypeError('First argument must be a positive number or an array'); | ||
} | ||
} else if (typeof nRows === 'number') { // Create empty matrix | ||
if (nRows > 0 && nColumns > 0) { | ||
matrix = new Array(nRows); | ||
for (; i < nRows; i++) { | ||
matrix[i] = new Array(nColumns); | ||
this.rows = nRows; | ||
this.columns = nColumns; | ||
} | ||
/** | ||
* Constructs a Matrix with the chosen dimensions from a 1D array | ||
* @param {number} newRows - Number of rows | ||
* @param {number} newColumns - Number of columns | ||
* @param {Array} newData - A 1D array containing data for the matrix | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
static from1DArray(newRows, newColumns, newData) { | ||
let length = newRows * newColumns; | ||
if (length !== newData.length) { | ||
throw new RangeError('Data length does not match given dimensions'); | ||
} | ||
let newMatrix = new Matrix(newRows, newColumns); | ||
for (var row = 0; row < newRows; row++) { | ||
for (var column = 0; column < newColumns; column++) { | ||
newMatrix[row][column] = newData[row * newColumns + column]; | ||
} | ||
} else { | ||
throw new RangeError('Invalid dimensions: ' + nRows + 'x' + nColumns); | ||
} | ||
} else { | ||
throw new TypeError('Invalid arguments'); | ||
return newMatrix; | ||
} | ||
Object.defineProperty(matrix, 'rows', {writable: true, value: nRows}); | ||
Object.defineProperty(matrix, 'columns', {writable: true, value: nColumns}); | ||
/** | ||
* Creates a row vector, a matrix with only one row. | ||
* @param {Array} newData - A 1D array containing data for the vector | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
static rowVector(newData) { | ||
let vector = new Matrix(1, newData.length); | ||
for (var i = 0; i < newData.length; i++) { | ||
vector[0][i] = newData[i]; | ||
} | ||
return vector; | ||
} | ||
matrix.__proto__ = Matrix.prototype; | ||
/** | ||
* Creates a column vector, a matrix with only one column. | ||
* @param {Array} newData - A 1D array containing data for the vector | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
static columnVector(newData) { | ||
let vector = new Matrix(newData.length, 1); | ||
for (var i = 0; i < newData.length; i++) { | ||
vector[i][0] = newData[i]; | ||
} | ||
return vector; | ||
} | ||
return matrix; | ||
} | ||
/** | ||
* Creates an empty matrix with the given dimensions. Values will be undefined. Same as using new Matrix(rows, columns). | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
static empty(rows, columns) { | ||
return new Matrix(rows, columns); | ||
} | ||
/** | ||
* Constructs a Matrix with the chosen dimensions from a 1D array. | ||
* @param {number} newRows - Number of rows | ||
* @param {number} newColumns - Number of columns | ||
* @param {Array} newData - A 1D array containing data for the matrix | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.from1DArray = function from1DArray(newRows, newColumns, newData) { | ||
var length, data, i = 0; | ||
/** | ||
* Creates a matrix with the given dimensions. Values will be set to zero. | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
static zeros(rows, columns) { | ||
return Matrix.empty(rows, columns).fill(0); | ||
} | ||
length = newRows * newColumns; | ||
if (length !== newData.length) | ||
throw new RangeError('Data length does not match given dimensions'); | ||
/** | ||
* Creates a matrix with the given dimensions. Values will be set to one. | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
static ones(rows, columns) { | ||
return Matrix.empty(rows, columns).fill(1); | ||
} | ||
data = new Array(newRows); | ||
for (; i < newRows; i++) { | ||
data[i] = newData.slice(i * newColumns, (i + 1) * newColumns); | ||
/** | ||
* Creates a matrix with the given dimensions. Values will be randomly set. | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @param {function} [rng] - Random number generator (default: Math.random) | ||
* @returns {Matrix} The new matrix | ||
*/ | ||
static rand(rows, columns, rng) { | ||
if (rng === undefined) rng = Math.random; | ||
let matrix = Matrix.empty(rows, columns); | ||
for (var i = 0; i < rows; i++) { | ||
for (var j = 0; j < rows; j++) { | ||
matrix[i][j] = rng(); | ||
} | ||
} | ||
return matrix; | ||
} | ||
return new Matrix(data); | ||
}; | ||
/** | ||
* Creates a row vector, a matrix with only one row. | ||
* @param {Array} newData - A 1D array containing data for the vector | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.rowVector = function rowVector(newData) { | ||
return new Matrix([newData]); | ||
}; | ||
/** | ||
* Creates an identity matrix with the given dimension. Values of the diagonal will be 1 and others will be 0. | ||
* @param {number} rows - Number of rows | ||
* @param {number} [columns] - Number of columns (Default: rows) | ||
* @returns {Matrix} - The new identity matrix | ||
*/ | ||
static eye(rows, columns) { | ||
if (columns === undefined) columns = rows; | ||
const min = Math.min(rows, columns); | ||
let matrix = Matrix.zeros(rows, columns); | ||
for (var i = 0; i < min; i++) { | ||
matrix[i][i] = 1; | ||
} | ||
return matrix; | ||
} | ||
/** | ||
* Creates a column vector, a matrix with only one column. | ||
* @param {Array} newData - A 1D array containing data for the vector | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.columnVector = function columnVector(newData) { | ||
var l = newData.length, vector = new Array(l); | ||
for (var i = 0; i < l; i++) | ||
vector[i] = [newData[i]]; | ||
return new Matrix(vector); | ||
}; | ||
/** | ||
* Creates a diagonal matrix based on the given array. | ||
* @param {Array} data - Array containing the data for the diagonal | ||
* @param {number} [rows] - Number of rows (Default: data.length) | ||
* @param {number} [columns] - Number of columns (Default: rows) | ||
* @returns {Matrix} - The new diagonal matrix | ||
*/ | ||
static diag(data, rows, columns) { | ||
const l = data.length; | ||
if (rows === undefined) rows = l; | ||
if (columns === undefined) columns = rows; | ||
const min = Math.min(l, rows, columns); | ||
let matrix = Matrix.zeros(rows, columns); | ||
for (var i = 0; i < min; i++) { | ||
matrix[i][i] = data[i]; | ||
} | ||
return matrix; | ||
} | ||
/** | ||
* Creates an empty matrix with the given dimensions. Values will be undefined. Same as using new Matrix(rows, columns). | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.empty = function empty(rows, columns) { | ||
return new Matrix(rows, columns); | ||
}; | ||
/** | ||
* Returns a matrix whose elements are the minimum between matrix1 and matrix2 | ||
* @param matrix1 | ||
* @param matrix2 | ||
* @returns {Matrix} | ||
*/ | ||
static min(matrix1, matrix2) { | ||
const rows = matrix1.length; | ||
const columns = matrix1[0].length; | ||
let result = new Matrix(rows, columns); | ||
for (var i = 0; i < rows; i++) { | ||
for(var j = 0; j < columns; j++) { | ||
result[i][j] = Math.min(matrix1[i][j], matrix2[i][j]); | ||
} | ||
} | ||
return result; | ||
} | ||
/** | ||
* Creates a matrix with the given dimensions. Values will be set to zero. | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.zeros = function zeros(rows, columns) { | ||
return Matrix.empty(rows, columns).fill(0); | ||
}; | ||
/** | ||
* Creates a matrix with the given dimensions. Values will be set to one. | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.ones = function ones(rows, columns) { | ||
return Matrix.empty(rows, columns).fill(1); | ||
}; | ||
/** | ||
* Creates a matrix with the given dimensions. Values will be randomly set using Math.random(). | ||
* @param {number} rows - Number of rows | ||
* @param {number} columns - Number of columns | ||
* @returns {Matrix} The new matrix | ||
*/ | ||
Matrix.rand = function rand(rows, columns) { | ||
var matrix = Matrix.empty(rows, columns); | ||
for (var i = 0, ii = matrix.rows; i < ii; i++) { | ||
for (var j = 0, jj = matrix.columns; j < jj; j++) { | ||
matrix[i][j] = Math.random(); | ||
/** | ||
* Returns a matrix whose elements are the maximum between matrix1 and matrix2 | ||
* @param matrix1 | ||
* @param matrix2 | ||
* @returns {Matrix} | ||
*/ | ||
static max(matrix1, matrix2) { | ||
const rows = matrix1.length; | ||
const columns = matrix1[0].length; | ||
let result = new Matrix(rows, columns); | ||
for (var i = 0; i < rows; i++) { | ||
for(var j = 0; j < columns; j++) { | ||
result[i][j] = Math.max(matrix1[i][j], matrix2[i][j]); | ||
} | ||
} | ||
return result; | ||
} | ||
return matrix; | ||
}; | ||
/** | ||
* Creates an identity matrix with the given dimension. Values of the diagonal will be 1 and other will be 0. | ||
* @param {number} n - Number of rows and columns | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.eye = function eye(n) { | ||
var matrix = Matrix.zeros(n, n), l = matrix.rows; | ||
for (var i = 0; i < l; i++) { | ||
matrix[i][i] = 1; | ||
/** | ||
* Check that the provided value is a Matrix and tries to instantiate one if not | ||
* @param value - The value to check | ||
* @returns {Matrix} | ||
*/ | ||
static checkMatrix(value) { | ||
return Matrix.isMatrix(value) ? value : new Matrix(value); | ||
} | ||
return matrix; | ||
}; | ||
/** | ||
* Creates a diagonal matrix based on the given array. | ||
* @param {Array} data - Array containing the data for the diagonal | ||
* @returns {Matrix} - The new matrix | ||
*/ | ||
Matrix.diag = function diag(data) { | ||
var l = data.length, matrix = Matrix.zeros(l, l); | ||
for (var i = 0; i < l; i++) { | ||
matrix[i][i] = data[i]; | ||
/** | ||
* Returns true if the argument is a Matrix, false otherwise | ||
* @param value - The value to check | ||
* @return {boolean} | ||
*/ | ||
static isMatrix(value) { | ||
return (value != null) && (value.klass === 'Matrix'); | ||
} | ||
return matrix; | ||
}; | ||
/** | ||
* Creates an array of indices between two values | ||
* @param {number} from | ||
* @param {number} to | ||
* @returns {Array} | ||
*/ | ||
Matrix.indices = function indices(from, to) { | ||
var vector = new Array(to - from); | ||
for (var i = 0; i < vector.length; i++) | ||
vector[i] = from++; | ||
return vector; | ||
}; | ||
/** | ||
* @property {number} - The number of elements in the matrix. | ||
*/ | ||
get size() { | ||
return this.rows * this.columns; | ||
} | ||
// TODO DOC | ||
Matrix.stack = function stack(arg1) { | ||
var i, j, k; | ||
if (Matrix.isMatrix(arg1)) { | ||
var rows = 0, | ||
cols = 0; | ||
for (i = 0; i < arguments.length; i++) { | ||
rows += arguments[i].rows; | ||
if (arguments[i].columns > cols) | ||
cols = arguments[i].columns; | ||
/** | ||
* Applies a callback for each element of the matrix. The function is called in the matrix (this) context. | ||
* @param {function} callback - Function that will be called with two parameters : i (row) and j (column) | ||
* @returns {Matrix} this | ||
*/ | ||
apply(callback) { | ||
let ii = this.rows; | ||
let jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
callback.call(this, i, j); | ||
} | ||
} | ||
return this; | ||
} | ||
var r = Matrix.zeros(rows, cols); | ||
var c = 0; | ||
for (i = 0; i < arguments.length; i++) { | ||
var current = arguments[i]; | ||
for (j = 0; j < current.rows; j++) { | ||
for (k = 0; k < current.columns; k++) | ||
r[c][k] = current[j][k]; | ||
c++; | ||
/** | ||
* Creates an exact and independent copy of the matrix | ||
* @returns {Matrix} | ||
*/ | ||
clone() { | ||
let newMatrix = new Matrix(this.rows, this.columns); | ||
for (var row = 0; row < this.rows; row++) { | ||
for (var column = 0; column < this.columns; column++) { | ||
newMatrix[row][column] = this[row][column]; | ||
} | ||
} | ||
return r; | ||
return newMatrix; | ||
} | ||
else if (Array.isArray(arg1)) { | ||
var matrix = Matrix.empty(arguments.length, arg1.length); | ||
for (i = 0; i < arguments.length; i++) | ||
matrix.setRow(i, arguments[i]); | ||
return matrix; | ||
/** | ||
* Returns a new 1D array filled row by row with the matrix values | ||
* @returns {Array} | ||
*/ | ||
to1DArray() { | ||
let array = new Array(this.size); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
array[i * this.columns + j] = this[i][j]; | ||
} | ||
} | ||
return array; | ||
} | ||
}; | ||
// TODO DOC | ||
Matrix.expand = function expand(base, count) { | ||
var expansion = []; | ||
for (var i = 0; i < count.length; i++) | ||
for (var j = 0; j < count[i]; j++) | ||
expansion.push(base[i]); | ||
return new Matrix(expansion); | ||
}; | ||
/** | ||
* Returns a 2D array containing a copy of the data | ||
* @returns {Array} | ||
*/ | ||
to2DArray() { | ||
let copy = new Array(this.rows); | ||
for (var i = 0; i < this.rows; i++) { | ||
copy[i] = [].concat(this[i]); | ||
} | ||
return copy; | ||
} | ||
/** | ||
* Check that the provided value is a Matrix and tries to instantiate one if not | ||
* @param value - The value to check | ||
* @returns {Matrix} | ||
* @throws {TypeError} | ||
*/ | ||
Matrix.checkMatrix = function checkMatrix(value) { | ||
if (!value) { | ||
throw new TypeError('Argument has to be a matrix'); | ||
/** | ||
* @returns {boolean} true if the matrix has one row | ||
*/ | ||
isRowVector() { | ||
return this.rows === 1; | ||
} | ||
if (value.klass !== 'Matrix') { | ||
value = new Matrix(value); | ||
/** | ||
* @returns {boolean} true if the matrix has one column | ||
*/ | ||
isColumnVector() { | ||
return this.columns === 1; | ||
} | ||
return value; | ||
}; | ||
/** | ||
* Returns true if the argument is a Matrix, false otherwise | ||
* @param value - The value to check | ||
* @returns {boolean} | ||
*/ | ||
Matrix.isMatrix = function isMatrix(value) { | ||
return value ? value.klass === 'Matrix' : false; | ||
}; | ||
/** | ||
* @returns {boolean} true if the matrix has one row or one column | ||
*/ | ||
isVector() { | ||
return (this.rows === 1) || (this.columns === 1); | ||
} | ||
/** | ||
* @property {string} - The name of this class. | ||
*/ | ||
Object.defineProperty(Matrix.prototype, 'klass', { | ||
get: function klass() { | ||
return 'Matrix'; | ||
/** | ||
* @returns {boolean} true if the matrix has the same number of rows and columns | ||
*/ | ||
isSquare() { | ||
return this.rows === this.columns; | ||
} | ||
}); | ||
/** | ||
* @property {number} - The number of elements in the matrix. | ||
*/ | ||
Object.defineProperty(Matrix.prototype, 'size', { | ||
get: function size() { | ||
return this.rows * this.columns; | ||
/** | ||
* @returns {boolean} true if the matrix is square and has the same values on both sides of the diagonal | ||
*/ | ||
isSymmetric() { | ||
if (this.isSquare()) { | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j <= i; j++) { | ||
if (this[i][j] !== this[j][i]) { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
}); | ||
/** | ||
* @private | ||
* Internal check that a row index is not out of bounds | ||
* @param {number} index | ||
*/ | ||
Matrix.prototype.checkRowIndex = function checkRowIndex(index) { | ||
if (index < 0 || index > this.rows - 1) | ||
throw new RangeError('Row index out of range.'); | ||
}; | ||
/** | ||
* Sets a given element of the matrix. mat.set(3,4,1) is equivalent to mat[3][4]=1 | ||
* @param {number} rowIndex - Index of the row | ||
* @param {number} columnIndex - Index of the column | ||
* @param {number} value - The new value for the element | ||
* @returns {Matrix} this | ||
*/ | ||
set(rowIndex, columnIndex, value) { | ||
this[rowIndex][columnIndex] = value; | ||
return this; | ||
} | ||
/** | ||
* @private | ||
* Internal check that a column index is not out of bounds | ||
* @param {number} index | ||
*/ | ||
Matrix.prototype.checkColumnIndex = function checkColumnIndex(index) { | ||
if (index < 0 || index > this.columns - 1) | ||
throw new RangeError('Column index out of range.'); | ||
}; | ||
/** | ||
* Returns the given element of the matrix. mat.get(3,4) is equivalent to matrix[3][4] | ||
* @param {number} rowIndex - Index of the row | ||
* @param {number} columnIndex - Index of the column | ||
* @returns {number} | ||
*/ | ||
get(rowIndex, columnIndex) { | ||
return this[rowIndex][columnIndex]; | ||
} | ||
/** | ||
* @private | ||
* Internal check that two matrices have the same dimensions | ||
* @param {Matrix} otherMatrix | ||
*/ | ||
Matrix.prototype.checkDimensions = function checkDimensions(otherMatrix) { | ||
if ((this.rows !== otherMatrix.rows) || (this.columns !== otherMatrix.columns)) | ||
throw new RangeError('Matrices dimensions must be equal.'); | ||
}; | ||
/** | ||
* Applies a callback for each element of the matrix. The function is called in the matrix (this) context. | ||
* @param {function} callback - Function that will be called with two parameters : i (row) and j (column) | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.apply = function apply(callback) { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
callback.call(this, i, j); | ||
/** | ||
* Fills the matrix with a given value. All elements will be set to this value. | ||
* @param {number} value - New value | ||
* @returns {Matrix} this | ||
*/ | ||
fill(value) { | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] = value; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Creates an exact and independent copy of the matrix | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.clone = function clone() { | ||
return new Matrix(this.to2DArray()); | ||
}; | ||
/** | ||
* Negates the matrix. All elements will be multiplied by (-1) | ||
* @returns {Matrix} this | ||
*/ | ||
neg() { | ||
return this.mulS(-1); | ||
} | ||
/** | ||
* Returns a new 1D array filled row by row with the matrix values | ||
* @returns {Array} | ||
*/ | ||
Matrix.prototype.to1DArray = function to1DArray() { | ||
return Aconcat.apply([], this); | ||
}; | ||
/** | ||
* Returns a new array from the given row index | ||
* @param {number} index - Row index | ||
* @returns {Array} | ||
*/ | ||
getRow(index) { | ||
checkRowIndex(this, index); | ||
return [].concat(this[index]); | ||
} | ||
/** | ||
* Returns a 2D array containing a copy of the data | ||
* @returns {Array} | ||
*/ | ||
Matrix.prototype.to2DArray = function to2DArray() { | ||
var l = this.rows, copy = new Array(l); | ||
for (var i = 0; i < l; i++) { | ||
copy[i] = slice(this[i]); | ||
/** | ||
* Returns a new row vector from the given row index | ||
* @param {number} index - Row index | ||
* @returns {Matrix} | ||
*/ | ||
getRowVector(index) { | ||
return Matrix.rowVector(this.getRow(index)); | ||
} | ||
return copy; | ||
}; | ||
/** | ||
* @returns {boolean} true if the matrix has one row | ||
*/ | ||
Matrix.prototype.isRowVector = function isRowVector() { | ||
return this.rows === 1; | ||
}; | ||
/** | ||
* Sets a row at the given index | ||
* @param {number} index - Row index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
setRow(index, array) { | ||
checkRowIndex(this, index); | ||
array = checkRowVector(this, array, true); | ||
this[index] = array; | ||
return this; | ||
} | ||
/** | ||
* @returns {boolean} true if the matrix has one column | ||
*/ | ||
Matrix.prototype.isColumnVector = function isColumnVector() { | ||
return this.columns === 1; | ||
}; | ||
/** | ||
* Removes a row from the given index | ||
* @param {number} index - Row index | ||
* @returns {Matrix} this | ||
*/ | ||
removeRow(index) { | ||
checkRowIndex(this, index); | ||
if (this.rows === 1) | ||
throw new RangeError('A matrix cannot have less than one row'); | ||
this.splice(index, 1); | ||
this.rows -= 1; | ||
return this; | ||
} | ||
/** | ||
* @returns {boolean} true if the matrix has one row or one column | ||
*/ | ||
Matrix.prototype.isVector = function isVector() { | ||
return (this.rows === 1) || (this.columns === 1); | ||
}; | ||
/** | ||
* Adds a row at the given index | ||
* @param {number} [index = this.rows] - Row index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
addRow(index, array) { | ||
if (array === undefined) { | ||
array = index; | ||
index = this.rows; | ||
} | ||
checkRowIndex(this, index, true); | ||
array = checkRowVector(this, array, true); | ||
this.splice(index, 0, array); | ||
this.rows += 1; | ||
return this; | ||
} | ||
/** | ||
* @returns {boolean} true if the matrix has the same number of rows and columns | ||
*/ | ||
Matrix.prototype.isSquare = function isSquare() { | ||
return this.rows === this.columns; | ||
}; | ||
/** | ||
* Swaps two rows | ||
* @param {number} row1 - First row index | ||
* @param {number} row2 - Second row index | ||
* @returns {Matrix} this | ||
*/ | ||
swapRows(row1, row2) { | ||
checkRowIndex(this, row1); | ||
checkRowIndex(this, row2); | ||
var temp = this[row1]; | ||
this[row1] = this[row2]; | ||
this[row2] = temp; | ||
return this; | ||
} | ||
/** | ||
* @returns {boolean} true if the matrix is square and has the same values on both sides of the diagonal | ||
*/ | ||
Matrix.prototype.isSymmetric = function isSymmetric() { | ||
if (this.isSquare()) { | ||
var l = this.rows; | ||
for (var i = 0; i < l; i++) { | ||
for (var j = 0; j <= i; j++) { | ||
if (this[i][j] !== this[j][i]) { | ||
return false; | ||
} | ||
} | ||
/** | ||
* Returns a new array from the given column index | ||
* @param {number} index - Column index | ||
* @returns {Array} | ||
*/ | ||
getColumn(index) { | ||
checkColumnIndex(this, index); | ||
let column = new Array(this.rows); | ||
for (var i = 0; i < this.rows; i++) { | ||
column[i] = this[i][index]; | ||
} | ||
return true; | ||
return column; | ||
} | ||
return false; | ||
}; | ||
/** | ||
* Sets a given element of the matrix. mat.set(3,4,1) is equivalent to mat[3][4]=1 | ||
* @param {number} rowIndex - Index of the row | ||
* @param {number} columnIndex - Index of the column | ||
* @param {number} value - The new value for the element | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.set = function set(rowIndex, columnIndex, value) { | ||
this[rowIndex][columnIndex] = value; | ||
return this; | ||
}; | ||
/** | ||
* Returns a new column vector from the given column index | ||
* @param {number} index - Column index | ||
* @returns {Matrix} | ||
*/ | ||
getColumnVector(index) { | ||
return Matrix.columnVector(this.getColumn(index)); | ||
} | ||
/** | ||
* Returns the given element of the matrix. mat.get(3,4) is equivalent to matrix[3][4] | ||
* @param {number} rowIndex - Index of the row | ||
* @param {number} columnIndex - Index of the column | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.get = function get(rowIndex, columnIndex) { | ||
return this[rowIndex][columnIndex]; | ||
}; | ||
/** | ||
* Sets a column at the given index | ||
* @param {number} index - Column index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
setColumn(index, array) { | ||
checkColumnIndex(this, index); | ||
array = checkColumnVector(this, array); | ||
for (var i = 0; i < this.rows; i++) { | ||
this[i][index] = array[i]; | ||
} | ||
return this; | ||
} | ||
/** | ||
* Fills the matrix with a given value. All elements will be set to this value. | ||
* @param {number} value - New value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.fill = function fill(value) { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] = value; | ||
/** | ||
* Removes a column from the given index | ||
* @param {number} index - Column index | ||
* @returns {Matrix} this | ||
*/ | ||
removeColumn(index) { | ||
checkColumnIndex(this, index); | ||
if (this.columns === 1) | ||
throw new RangeError('A matrix cannot have less than one column'); | ||
for (var i = 0; i < this.rows; i++) { | ||
this[i].splice(index, 1); | ||
} | ||
this.columns -= 1; | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Negates the matrix. All elements will be multiplied by (-1) | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.neg = function neg() { | ||
return this.mulS(-1); | ||
}; | ||
/** | ||
* Adds a column at the given index | ||
* @param {number} [index = this.columns] - Column index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
addColumn(index, array) { | ||
if (typeof array === 'undefined') { | ||
array = index; | ||
index = this.columns; | ||
} | ||
checkColumnIndex(this, index, true); | ||
array = checkColumnVector(this, array); | ||
for (var i = 0; i < this.rows; i++) { | ||
this[i].splice(index, 0, array[i]); | ||
} | ||
this.columns += 1; | ||
return this; | ||
} | ||
/** | ||
* Adds a scalar or values from another matrix (in place) | ||
* @param {number|Matrix} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.add = function add(value) { | ||
if (typeof value === 'number') | ||
return this.addS(value); | ||
value = Matrix.checkMatrix(value); | ||
return this.addM(value); | ||
}; | ||
/** | ||
* Swaps two columns | ||
* @param {number} column1 - First column index | ||
* @param {number} column2 - Second column index | ||
* @returns {Matrix} this | ||
*/ | ||
swapColumns(column1, column2) { | ||
checkColumnIndex(this, column1); | ||
checkColumnIndex(this, column2); | ||
let temp, row; | ||
for (var i = 0; i < this.rows; i++) { | ||
row = this[i]; | ||
temp = row[column1]; | ||
row[column1] = row[column2]; | ||
row[column2] = temp; | ||
} | ||
return this; | ||
} | ||
/** | ||
* Adds a scalar to each element of the matrix | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.addS = function addS(value) { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] += value; | ||
/** | ||
* Adds the values of a vector to each row | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
addRowVector(vector) { | ||
vector = checkRowVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] += vector[j]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Adds the value of each element of matrix to the corresponding element of this | ||
* @param {Matrix} matrix | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.addM = function addM(matrix) { | ||
this.checkDimensions(matrix); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] += matrix[i][j]; | ||
/** | ||
* Subtracts the values of a vector from each row | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
subRowVector(vector) { | ||
vector = checkRowVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] -= vector[j]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Subtracts a scalar or values from another matrix (in place) | ||
* @param {number|Matrix} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.sub = function sub(value) { | ||
if (typeof value === 'number') | ||
return this.subS(value); | ||
value = Matrix.checkMatrix(value); | ||
return this.subM(value); | ||
}; | ||
/** | ||
* Multiplies the values of a vector with each row | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
mulRowVector(vector) { | ||
vector = checkRowVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] *= vector[j]; | ||
} | ||
} | ||
return this; | ||
} | ||
/** | ||
* Subtracts a scalar from each element of the matrix | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.subS = function subS(value) { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] -= value; | ||
/** | ||
* Divides the values of each row by those of a vector | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
divRowVector(vector) { | ||
vector = checkRowVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] /= vector[j]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Subtracts the value of each element of matrix from the corresponding element of this | ||
* @param {Matrix} matrix | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.subM = function subM(matrix) { | ||
this.checkDimensions(matrix); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] -= matrix[i][j]; | ||
/** | ||
* Adds the values of a vector to each column | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
addColumnVector(vector) { | ||
vector = checkColumnVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] += vector[i]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Multiplies a scalar or values from another matrix (in place) | ||
* @param {number|Matrix} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mul = function mul(value) { | ||
if (typeof value === 'number') | ||
return this.mulS(value); | ||
value = Matrix.checkMatrix(value); | ||
return this.mulM(value); | ||
}; | ||
/** | ||
* Multiplies a scalar with each element of the matrix | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mulS = function mulS(value) { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] *= value; | ||
/** | ||
* Subtracts the values of a vector from each column | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
subColumnVector(vector) { | ||
vector = checkColumnVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] -= vector[i]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Multiplies the value of each element of matrix with the corresponding element of this | ||
* @param {Matrix} matrix | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mulM = function mulM(matrix) { | ||
this.checkDimensions(matrix); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] *= matrix[i][j]; | ||
/** | ||
* Multiplies the values of a vector with each column | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
mulColumnVector(vector) { | ||
vector = checkColumnVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] *= vector[i]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Divides by a scalar or values from another matrix (in place) | ||
* @param {number|Matrix} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.div = function div(value) { | ||
if (typeof value === 'number') | ||
return this.divS(value); | ||
value = Matrix.checkMatrix(value); | ||
return this.divM(value); | ||
}; | ||
/** | ||
* Divides each element of the matrix by a scalar | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.divS = function divS(value) { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] /= value; | ||
/** | ||
* Divides the values of each column by those of a vector | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
divColumnVector(vector) { | ||
vector = checkColumnVector(this, vector); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] /= vector[i]; | ||
} | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Divides each element of this by the corresponding element of matrix | ||
* @param {Matrix} matrix | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.divM = function divM(matrix) { | ||
this.checkDimensions(matrix); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] /= matrix[i][j]; | ||
/** | ||
* Multiplies the values of a row with a scalar | ||
* @param {number} index - Row index | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
mulRow(index, value) { | ||
checkRowIndex(this, index); | ||
for (var i = 0; i < this.columns; i++) { | ||
this[index][i] *= value; | ||
} | ||
return this; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Returns a new array from the given row index | ||
* @param {number} index - Row index | ||
* @returns {Array} | ||
*/ | ||
Matrix.prototype.getRow = function getRow(index) { | ||
this.checkRowIndex(index); | ||
return slice(this[index]); | ||
}; | ||
/** | ||
* Returns a new row vector from the given row index | ||
* @param {number} index - Row index | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.getRowVector = function getRowVector(index) { | ||
return Matrix.rowVector(this.getRow(index)); | ||
}; | ||
/** | ||
* Sets a row at the given index | ||
* @param {number} index - Row index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.setRow = function setRow(index, array) { | ||
this.checkRowIndex(index); | ||
if (Matrix.isMatrix(array)) array = array.to1DArray(); | ||
if (array.length !== this.columns) | ||
throw new RangeError('Invalid row size'); | ||
this[index] = slice(array); | ||
return this; | ||
}; | ||
/** | ||
* Removes a row from the given index | ||
* @param {number} index - Row index | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.removeRow = function removeRow(index) { | ||
this.checkRowIndex(index); | ||
if (this.rows === 1) | ||
throw new RangeError('A matrix cannot have less than one row'); | ||
Asplice.call(this, index, 1); | ||
this.rows -= 1; | ||
return this; | ||
}; | ||
/** | ||
* Adds a row at the given index | ||
* @param {number} [index = this.rows] - Row index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.addRow = function addRow(index, array) { | ||
if (typeof array === 'undefined') { | ||
array = index; | ||
index = this.rows; | ||
/** | ||
* Multiplies the values of a column with a scalar | ||
* @param {number} index - Column index | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
mulColumn(index, value) { | ||
checkColumnIndex(this, index); | ||
for (var i = 0; i < this.rows; i++) { | ||
this[i][index] *= value; | ||
} | ||
} | ||
if (index < 0 || index > this.rows) | ||
throw new RangeError('Row index out of range.'); | ||
if (Matrix.isMatrix(array)) array = array.to1DArray(); | ||
if (array.length !== this.columns) | ||
throw new RangeError('Invalid row size'); | ||
Asplice.call(this, index, 0, slice(array)); | ||
this.rows += 1; | ||
return this; | ||
}; | ||
/** | ||
* Swaps two rows | ||
* @param {number} row1 - First row index | ||
* @param {number} row2 - Second row index | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.swapRows = function swapRows(row1, row2) { | ||
this.checkRowIndex(row1); | ||
this.checkRowIndex(row2); | ||
var temp = this[row1]; | ||
this[row1] = this[row2]; | ||
this[row2] = temp; | ||
return this; | ||
}; | ||
/** | ||
* Returns a new array from the given column index | ||
* @param {number} index - Column index | ||
* @returns {Array} | ||
*/ | ||
Matrix.prototype.getColumn = function getColumn(index) { | ||
this.checkColumnIndex(index); | ||
var l = this.rows, column = new Array(l); | ||
for (var i = 0; i < l; i++) { | ||
column[i] = this[i][index]; | ||
/** | ||
* Returns the maximum value of the matrix | ||
* @returns {number} | ||
*/ | ||
max() { | ||
let v = this[0][0]; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
if (this[i][j] > v) { | ||
v = this[i][j]; | ||
} | ||
} | ||
} | ||
return v; | ||
} | ||
return column; | ||
}; | ||
/** | ||
* Returns a new column vector from the given column index | ||
* @param {number} index - Column index | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.getColumnVector = function getColumnVector(index) { | ||
return Matrix.columnVector(this.getColumn(index)); | ||
}; | ||
/** | ||
* Sets a column at the given index | ||
* @param {number} index - Column index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.setColumn = function setColumn(index, array) { | ||
this.checkColumnIndex(index); | ||
if (Matrix.isMatrix(array)) array = array.to1DArray(); | ||
var l = this.rows; | ||
if (array.length !== l) | ||
throw new RangeError('Invalid column size'); | ||
for (var i = 0; i < l; i++) { | ||
this[i][index] = array[i]; | ||
/** | ||
* Returns the index of the maximum value | ||
* @returns {Array} | ||
*/ | ||
maxIndex() { | ||
let v = this[0][0]; | ||
let idx = [0, 0]; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
if (this[i][j] > v) { | ||
v = this[i][j]; | ||
idx[0] = i; | ||
idx[1] = j; | ||
} | ||
} | ||
} | ||
return idx; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Removes a column from the given index | ||
* @param {number} index - Column index | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.removeColumn = function removeColumn(index) { | ||
this.checkColumnIndex(index); | ||
if (this.columns === 1) | ||
throw new RangeError('A matrix cannot have less than one column'); | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
this[i].splice(index, 1); | ||
/** | ||
* Returns the minimum value of the matrix | ||
* @returns {number} | ||
*/ | ||
min() { | ||
let v = this[0][0]; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
if (this[i][j] < v) { | ||
v = this[i][j]; | ||
} | ||
} | ||
} | ||
return v; | ||
} | ||
this.columns -= 1; | ||
return this; | ||
}; | ||
/** | ||
* Adds a column at the given index | ||
* @param {number} [index = this.columns] - Column index | ||
* @param {Array|Matrix} array - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.addColumn = function addColumn(index, array) { | ||
if (typeof array === 'undefined') { | ||
array = index; | ||
index = this.columns; | ||
/** | ||
* Returns the index of the minimum value | ||
* @returns {Array} | ||
*/ | ||
minIndex() { | ||
let v = this[0][0]; | ||
let idx = [0, 0]; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
if (this[i][j] < v) { | ||
v = this[i][j]; | ||
idx[0] = i; | ||
idx[1] = j; | ||
} | ||
} | ||
} | ||
return idx; | ||
} | ||
if (index < 0 || index > this.columns) | ||
throw new RangeError('Column index out of range.'); | ||
if (Matrix.isMatrix(array)) array = array.to1DArray(); | ||
var l = this.rows; | ||
if (array.length !== l) | ||
throw new RangeError('Invalid column size'); | ||
for (var i = 0; i < l; i++) { | ||
this[i].splice(index, 0, array[i]); | ||
} | ||
this.columns += 1; | ||
return this; | ||
}; | ||
/** | ||
* Swaps two columns | ||
* @param {number} column1 - First column index | ||
* @param {number} column2 - Second column index | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.swapColumns = function swapColumns(column1, column2) { | ||
this.checkRowIndex(column1); | ||
this.checkRowIndex(column2); | ||
var l = this.rows, temp, row; | ||
for (var i = 0; i < l; i++) { | ||
row = this[i]; | ||
temp = row[column1]; | ||
row[column1] = row[column2]; | ||
row[column2] = temp; | ||
/** | ||
* Returns the maximum value of one row | ||
* @param {number} row - Row index | ||
* @returns {number} | ||
*/ | ||
maxRow(row) { | ||
checkRowIndex(this, row); | ||
let v = this[row][0]; | ||
for (var i = 1; i < this.columns; i++) { | ||
if (this[row][i] > v) { | ||
v = this[row][i]; | ||
} | ||
} | ||
return v; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* @private | ||
* Internal check that the provided vector is an array with the right length | ||
* @param {Array|Matrix} vector | ||
* @returns {Array} | ||
* @throws {RangeError} | ||
*/ | ||
Matrix.prototype.checkRowVector = function checkRowVector(vector) { | ||
if (Matrix.isMatrix(vector)) | ||
vector = vector.to1DArray(); | ||
if (vector.length !== this.columns) | ||
throw new RangeError('vector size must be the same as the number of columns'); | ||
return vector; | ||
}; | ||
/** | ||
* @private | ||
* Internal check that the provided vector is an array with the right length | ||
* @param {Array|Matrix} vector | ||
* @returns {Array} | ||
* @throws {RangeError} | ||
*/ | ||
Matrix.prototype.checkColumnVector = function checkColumnVector(vector) { | ||
if (Matrix.isMatrix(vector)) | ||
vector = vector.to1DArray(); | ||
if (vector.length !== this.rows) | ||
throw new RangeError('vector size must be the same as the number of rows'); | ||
return vector; | ||
}; | ||
/** | ||
* Adds the values of a vector to each row | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.addRowVector = function addRowVector(vector) { | ||
vector = this.checkRowVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] += vector[j]; | ||
/** | ||
* Returns the index of the maximum value of one row | ||
* @param {number} row - Row index | ||
* @returns {Array} | ||
*/ | ||
maxRowIndex(row) { | ||
checkRowIndex(this, row); | ||
let v = this[row][0]; | ||
let idx = [row, 0]; | ||
for (var i = 1; i < this.columns; i++) { | ||
if (this[row][i] > v) { | ||
v = this[row][i]; | ||
idx[1] = i; | ||
} | ||
} | ||
return idx; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Subtracts the values of a vector from each row | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.subRowVector = function subRowVector(vector) { | ||
vector = this.checkRowVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] -= vector[j]; | ||
/** | ||
* Returns the minimum value of one row | ||
* @param {number} row - Row index | ||
* @returns {number} | ||
*/ | ||
minRow(row) { | ||
checkRowIndex(this, row); | ||
let v = this[row][0]; | ||
for (var i = 1; i < this.columns; i++) { | ||
if (this[row][i] < v) { | ||
v = this[row][i]; | ||
} | ||
} | ||
return v; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Multiplies the values of a vector with each row | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mulRowVector = function mulRowVector(vector) { | ||
vector = this.checkRowVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] *= vector[j]; | ||
/** | ||
* Returns the index of the maximum value of one row | ||
* @param {number} row - Row index | ||
* @returns {Array} | ||
*/ | ||
minRowIndex(row) { | ||
checkRowIndex(this, row); | ||
let v = this[row][0]; | ||
let idx = [row, 0]; | ||
for (var i = 1; i < this.columns; i++) { | ||
if (this[row][i] < v) { | ||
v = this[row][i]; | ||
idx[1] = i; | ||
} | ||
} | ||
return idx; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Divides the values of each row by those of a vector | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.divRowVector = function divRowVector(vector) { | ||
vector = this.checkRowVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] /= vector[j]; | ||
/** | ||
* Returns the maximum value of one column | ||
* @param {number} column - Column index | ||
* @returns {number} | ||
*/ | ||
maxColumn(column) { | ||
checkColumnIndex(this, column); | ||
let v = this[0][column]; | ||
for (var i = 1; i < this.rows; i++) { | ||
if (this[i][column] > v) { | ||
v = this[i][column]; | ||
} | ||
} | ||
return v; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Adds the values of a vector to each column | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.addColumnVector = function addColumnVector(vector) { | ||
vector = this.checkColumnVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] += vector[i]; | ||
/** | ||
* Returns the index of the maximum value of one column | ||
* @param {number} column - Column index | ||
* @returns {Array} | ||
*/ | ||
maxColumnIndex(column) { | ||
checkColumnIndex(this, column); | ||
let v = this[0][column]; | ||
let idx = [0, column]; | ||
for (var i = 1; i < this.rows; i++) { | ||
if (this[i][column] > v) { | ||
v = this[i][column]; | ||
idx[0] = i; | ||
} | ||
} | ||
return idx; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Subtracts the values of a vector from each column | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.subColumnVector = function subColumnVector(vector) { | ||
vector = this.checkColumnVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] -= vector[i]; | ||
/** | ||
* Returns the minimum value of one column | ||
* @param {number} column - Column index | ||
* @returns {number} | ||
*/ | ||
minColumn(column) { | ||
checkColumnIndex(this, column); | ||
let v = this[0][column]; | ||
for (var i = 1; i < this.rows; i++) { | ||
if (this[i][column] < v) { | ||
v = this[i][column]; | ||
} | ||
} | ||
return v; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Multiplies the values of a vector with each column | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mulColumnVector = function mulColumnVector(vector) { | ||
vector = this.checkColumnVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] *= vector[i]; | ||
/** | ||
* Returns the index of the minimum value of one column | ||
* @param {number} column - Column index | ||
* @returns {Array} | ||
*/ | ||
minColumnIndex(column) { | ||
checkColumnIndex(this, column); | ||
let v = this[0][column]; | ||
let idx = [0, column]; | ||
for (var i = 1; i < this.rows; i++) { | ||
if (this[i][column] < v) { | ||
v = this[i][column]; | ||
idx[0] = i; | ||
} | ||
} | ||
return idx; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Divides the values of each column by those of a vector | ||
* @param {Array|Matrix} vector - Array or vector | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.divColumnVector = function divColumnVector(vector) { | ||
vector = this.checkColumnVector(vector); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] /= vector[i]; | ||
/** | ||
* Returns an array containing the diagonal values of the matrix | ||
* @returns {Array} | ||
*/ | ||
diag() { | ||
const min = Math.min(this.rows, this.columns); | ||
let diag = new Array(min); | ||
for (var i = 0; i < min; i++) { | ||
diag[i] = this[i][i]; | ||
} | ||
return diag; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Multiplies the values of a row with a scalar | ||
* @param {number} index - Row index | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mulRow = function mulRow(index, value) { | ||
this.checkRowIndex(index); | ||
var i = 0, l = this.columns; | ||
for (; i < l; i++) { | ||
this[index][i] *= value; | ||
/** | ||
* Returns the sum of all elements of the matrix | ||
* @returns {number} | ||
*/ | ||
sum() { | ||
let v = 0; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
v += this[i][j]; | ||
} | ||
} | ||
return v; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Multiplies the values of a column with a scalar | ||
* @param {number} index - Column index | ||
* @param {number} value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.mulColumn = function mulColumn(index, value) { | ||
this.checkColumnIndex(index); | ||
var i = 0, l = this.rows; | ||
for (; i < l; i++) { | ||
this[i][index] *= value; | ||
/** | ||
* Returns the mean of all elements of the matrix | ||
* @returns {number} | ||
*/ | ||
mean() { | ||
return this.sum() / this.size; | ||
} | ||
}; | ||
/** | ||
* A matrix index | ||
* @typedef {Object} MatrixIndex | ||
* @property {number} row | ||
* @property {number} column | ||
*/ | ||
/** | ||
* Returns the maximum value of the matrix | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.max = function max() { | ||
var v = -Infinity; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
if (this[i][j] > v) { | ||
v = this[i][j]; | ||
/** | ||
* Returns the product of all elements of the matrix | ||
* @returns {number} | ||
*/ | ||
prod() { | ||
let prod = 1; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
prod *= this[i][j]; | ||
} | ||
} | ||
return prod; | ||
} | ||
return v; | ||
}; | ||
/** | ||
* Returns the index of the maximum value | ||
* @returns {MatrixIndex} | ||
*/ | ||
Matrix.prototype.maxIndex = function maxIndex() { | ||
var v = -Infinity; | ||
var idx = {}; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
if (this[i][j] > v) { | ||
v = this[i][j]; | ||
idx.row = i; | ||
idx.column = j; | ||
/** | ||
* Computes the cumulative sum of the matrix elements (in place, row by row) | ||
* @returns {Matrix} this | ||
*/ | ||
cumulativeSum() { | ||
let sum = 0; | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
sum += this[i][j]; | ||
this[i][j] = sum; | ||
} | ||
} | ||
return this; | ||
} | ||
return idx; | ||
}; | ||
/** | ||
* Returns the minimum value of the matrix | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.min = function min() { | ||
var v = Infinity; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
if (this[i][j] < v) { | ||
v = this[i][j]; | ||
} | ||
/** | ||
* Computes the dot (scalar) product between the matrix and another | ||
* @param {Matrix} vector2 vector | ||
* @returns {number} | ||
*/ | ||
dot(vector2) { | ||
if (Matrix.isMatrix(vector2)) vector2 = vector2.to1DArray(); | ||
let vector1 = this.to1DArray(); | ||
if (vector1.length !== vector2.length) { | ||
throw new RangeError('vectors do not have the same size'); | ||
} | ||
var dot = 0; | ||
for (var i = 0; i < vector1.length; i++) { | ||
dot += vector1[i] * vector2[i]; | ||
} | ||
return dot; | ||
} | ||
return v; | ||
}; | ||
/** | ||
* Returns the index of the minimum value | ||
* @returns {MatrixIndex} | ||
*/ | ||
Matrix.prototype.minIndex = function minIndex() { | ||
var v = Infinity; | ||
var idx = {}; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
if (this[i][j] < v) { | ||
v = this[i][j]; | ||
idx.row = i; | ||
idx.column = j; | ||
/** | ||
* Returns the matrix product between this and other | ||
* @returns {Matrix} | ||
*/ | ||
mmul(other) { | ||
other = Matrix.checkMatrix(other); | ||
if (this.columns !== other.rows) | ||
console.warn('Number of columns of left matrix are not equal to number of rows of right matrix.'); | ||
const m = this.rows; | ||
const n = this.columns; | ||
const p = other.columns; | ||
let result = new Matrix(m, p); | ||
let Bcolj = new Array(n); | ||
for (var j = 0; j < p; j++) { | ||
for (var k = 0; k < n; k++) | ||
Bcolj[k] = other[k][j]; | ||
for (var i = 0; i < m; i++) { | ||
var Arowi = this[i]; | ||
var s = 0; | ||
for (k = 0; k < n; k++) | ||
s += Arowi[k] * Bcolj[k]; | ||
result[i][j] = s; | ||
} | ||
} | ||
return result; | ||
} | ||
return idx; | ||
}; | ||
/** | ||
* Returns the maximum value of one row | ||
* @param {number} index - Row index | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.maxRow = function maxRow(index) { | ||
this.checkRowIndex(index); | ||
var v = -Infinity; | ||
for (var i = 0, ii = this.columns; i < ii; i++) { | ||
if (this[index][i] > v) { | ||
v = this[index][i]; | ||
/** | ||
* Transposes the matrix and returns a new one containing the result | ||
* @returns {Matrix} | ||
*/ | ||
transpose() { | ||
let result = new Matrix(this.columns, this.rows); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
result[j][i] = this[i][j]; | ||
} | ||
} | ||
return result; | ||
} | ||
return v; | ||
}; | ||
/** | ||
* Returns the index of the maximum value of one row | ||
* @param {number} index - Row index | ||
* @returns {MatrixIndex} | ||
*/ | ||
Matrix.prototype.maxRowIndex = function maxRowIndex(index) { | ||
this.checkRowIndex(index); | ||
var v = -Infinity; | ||
var idx = { | ||
row: index | ||
}; | ||
for (var i = 0, ii = this.columns; i < ii; i++) { | ||
if (this[index][i] > v) { | ||
v = this[index][i]; | ||
idx.column = i; | ||
/** | ||
* Sorts the rows (in place) | ||
* @param {function} compareFunction - usual Array.prototype.sort comparison function | ||
* @returns {Matrix} this | ||
*/ | ||
sortRows(compareFunction) { | ||
if (compareFunction === undefined) compareFunction = compareNumbers; | ||
for (var i = 0; i < this.rows; i++) { | ||
this[i].sort(compareFunction); | ||
} | ||
return this; | ||
} | ||
return idx; | ||
}; | ||
/** | ||
* Returns the minimum value of one row | ||
* @param {number} index - Row index | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.minRow = function minRow(index) { | ||
this.checkRowIndex(index); | ||
var v = Infinity; | ||
for (var i = 0, ii = this.columns; i < ii; i++) { | ||
if (this[index][i] < v) { | ||
v = this[index][i]; | ||
/** | ||
* Sorts the columns (in place) | ||
* @param {function} compareFunction - usual Array.prototype.sort comparison function | ||
* @returns {Matrix} this | ||
*/ | ||
sortColumns(compareFunction) { | ||
if (compareFunction === undefined) compareFunction = compareNumbers; | ||
for (var i = 0; i < this.columns; i++) { | ||
this.setColumn(i, this.getColumn(i).sort(compareFunction)); | ||
} | ||
return this; | ||
} | ||
return v; | ||
}; | ||
/** | ||
* Returns the index of the maximum value of one row | ||
* @param {number} index - Row index | ||
* @returns {MatrixIndex} | ||
*/ | ||
Matrix.prototype.minRowIndex = function minRowIndex(index) { | ||
this.checkRowIndex(index); | ||
var v = Infinity; | ||
var idx = { | ||
row: index, | ||
column: 0 | ||
}; | ||
for (var i = 0, ii = this.columns; i < ii; i++) { | ||
if (this[index][i] < v) { | ||
v = this[index][i]; | ||
idx.column = i; | ||
/** | ||
* Returns a subset of the matrix | ||
* @param {number} startRow - First row index | ||
* @param {number} endRow - Last row index | ||
* @param {number} startColumn - First column index | ||
* @param {number} endColumn - Last column index | ||
* @returns {Matrix} | ||
*/ | ||
subMatrix(startRow, endRow, startColumn, endColumn) { | ||
if ((startRow > endRow) || (startColumn > endColumn) || (startRow < 0) || (startRow >= this.rows) || (endRow < 0) || (endRow >= this.rows) || (startColumn < 0) || (startColumn >= this.columns) || (endColumn < 0) || (endColumn >= this.columns)) { | ||
throw new RangeError('Argument out of range'); | ||
} | ||
let newMatrix = new Matrix(endRow - startRow + 1, endColumn - startColumn + 1); | ||
for (var i = startRow; i <= endRow; i++) { | ||
for (var j = startColumn; j <= endColumn; j++) { | ||
newMatrix[i - startRow][j - startColumn] = this[i][j]; | ||
} | ||
} | ||
return newMatrix; | ||
} | ||
return idx; | ||
}; | ||
/** | ||
* Returns the maximum value of one column | ||
* @param {number} index - Column index | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.maxColumn = function maxColumn(index) { | ||
this.checkColumnIndex(index); | ||
var v = -Infinity; | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
if (this[i][index] > v) { | ||
v = this[i][index]; | ||
/** | ||
* Returns a subset of the matrix based on an array of row indices | ||
* @param {Array} indices - Array containing the row indices | ||
* @param {number} [startColumn = 0] - First column index | ||
* @param {number} [endColumn = this.columns-1] - Last column index | ||
* @returns {Matrix} | ||
*/ | ||
subMatrixRow(indices, startColumn, endColumn) { | ||
if (startColumn === undefined) startColumn = 0; | ||
if (endColumn === undefined) endColumn = this.columns - 1; | ||
if ((startColumn > endColumn) || (startColumn < 0) || (startColumn >= this.columns) || (endColumn < 0) || (endColumn >= this.columns)) { | ||
throw new RangeError('Argument out of range'); | ||
} | ||
let newMatrix = new Matrix(indices.length, endColumn - startColumn + 1); | ||
for (var i = 0; i < indices.length; i++) { | ||
for (var j = startColumn; j <= endColumn; j++) { | ||
if (indices[i] < 0 || indices[i] >= this.rows) { | ||
throw new RangeError('Row index out of range: ' + indices[i]); | ||
} | ||
newMatrix[i][j - startColumn] = this[indices[i]][j]; | ||
} | ||
} | ||
return newMatrix; | ||
} | ||
return v; | ||
}; | ||
/** | ||
* Returns the index of the maximum value of one column | ||
* @param {number} index - Column index | ||
* @returns {MatrixIndex} | ||
*/ | ||
Matrix.prototype.maxColumnIndex = function maxColumnIndex(index) { | ||
this.checkColumnIndex(index); | ||
var v = -Infinity; | ||
var idx = { | ||
row: 0, | ||
column: index | ||
}; | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
if (this[i][index] > v) { | ||
v = this[i][index]; | ||
idx.row = i; | ||
/** | ||
* Returns a subset of the matrix based on an array of column indices | ||
* @param {Array} indices - Array containing the column indices | ||
* @param {number} [startRow = 0] - First row index | ||
* @param {number} [endRow = this.rows-1] - Last row index | ||
* @returns {Matrix} | ||
*/ | ||
subMatrixColumn(indices, startRow, endRow) { | ||
if (startRow === undefined) startRow = 0; | ||
if (endRow === undefined) endRow = this.rows - 1; | ||
if ((startRow > endRow) || (startRow < 0) || (startRow >= this.rows) || (endRow < 0) || (endRow >= this.rows)) { | ||
throw new RangeError('Argument out of range'); | ||
} | ||
let newMatrix = new Matrix(endRow - startRow + 1, indices.length); | ||
for (var i = 0; i < indices.length; i++) { | ||
for (var j = startRow; j <= endRow; j++) { | ||
if (indices[i] < 0 || indices[i] >= this.columns) { | ||
throw new RangeError('Column index out of range: ' + indices[i]); | ||
} | ||
newMatrix[j - startRow][i] = this[j][indices[i]]; | ||
} | ||
} | ||
return newMatrix; | ||
} | ||
return idx; | ||
}; | ||
/** | ||
* Returns the minimum value of one column | ||
* @param {number} index - Column index | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.minColumn = function minColumn(index) { | ||
this.checkColumnIndex(index); | ||
var v = Infinity; | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
if (this[i][index] < v) { | ||
v = this[i][index]; | ||
/** | ||
* Returns the trace of the matrix (sum of the diagonal elements) | ||
* @returns {number} | ||
*/ | ||
trace() { | ||
const min = Math.min(this.rows, this.columns); | ||
let trace = 0; | ||
for (var i = 0; i < min; i++) { | ||
trace += this[i][i]; | ||
} | ||
return trace; | ||
} | ||
return v; | ||
}; | ||
} | ||
Matrix.prototype.klass = 'Matrix'; | ||
module.exports = Matrix; | ||
/** | ||
* Returns the index of the minimum value of one column | ||
* @param {number} index - Column index | ||
* @returns {MatrixIndex} | ||
* @private | ||
* Check that a row index is not out of bounds | ||
* @param {Matrix} matrix | ||
* @param {number} index | ||
* @param {boolean} [outer] | ||
*/ | ||
Matrix.prototype.minColumnIndex = function minColumnIndex(index) { | ||
this.checkColumnIndex(index); | ||
var v = Infinity; | ||
var idx = { | ||
row: 0, | ||
column: index | ||
}; | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
if (this[i][index] < v) { | ||
v = this[i][index]; | ||
idx.row = i; | ||
} | ||
} | ||
return idx; | ||
}; | ||
function checkRowIndex(matrix, index, outer) { | ||
const max = outer ? matrix.rows : matrix.rows - 1; | ||
if (index < 0 || index > max) | ||
throw new RangeError('Row index out of range'); | ||
} | ||
/** | ||
* Returns an array containing the diagonal values of the matrix | ||
* @private | ||
* Check that the provided vector is an array with the right length | ||
* @param {Matrix} matrix | ||
* @param {Array|Matrix} vector | ||
* @param {boolean} copy | ||
* @returns {Array} | ||
* @throws {RangeError} | ||
*/ | ||
Matrix.prototype.diag = function diag() { | ||
if (!this.isSquare()) | ||
throw new TypeError('Only square matrices have a diagonal.'); | ||
var diag = new Array(this.rows); | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
diag[i] = this[i][i]; | ||
function checkRowVector(matrix, vector, copy) { | ||
if (Matrix.isMatrix(vector)) { | ||
vector = vector.to1DArray(); | ||
} else if (copy) { | ||
vector = [].concat(vector); | ||
} | ||
return diag; | ||
}; | ||
if (vector.length !== matrix.columns) | ||
throw new RangeError('vector size must be the same as the number of columns'); | ||
return vector; | ||
} | ||
/** | ||
* Returns the sum of all elements of the matrix | ||
* @returns {number} | ||
* @private | ||
* Check that the provided vector is an array with the right length | ||
* @param {Matrix} matrix | ||
* @param {Array|Matrix} vector | ||
* @param {boolean} copy | ||
* @returns {Array} | ||
* @throws {RangeError} | ||
*/ | ||
Matrix.prototype.sum = function sum() { | ||
var v = 0; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
v += this[i][j]; | ||
} | ||
function checkColumnVector(matrix, vector, copy) { | ||
if (Matrix.isMatrix(vector)) { | ||
vector = vector.to1DArray(); | ||
} else if (copy) { | ||
vector = [].concat(vector); | ||
} | ||
return v; | ||
}; | ||
if (vector.length !== matrix.rows) | ||
throw new RangeError('vector size must be the same as the number of rows'); | ||
return vector; | ||
} | ||
/** | ||
* Returns the mean of all elements of the matrix | ||
* @returns {number} | ||
* @private | ||
* Check that a column index is not out of bounds | ||
* @param {Matrix} matrix | ||
* @param {number} index | ||
* @param {boolean} [outer] | ||
*/ | ||
Matrix.prototype.mean = function mean() { | ||
return this.sum() / this.size; | ||
}; | ||
function checkColumnIndex(matrix, index, outer) { | ||
const max = outer ? matrix.columns : matrix.columns - 1; | ||
if (index < 0 || index > max) | ||
throw new RangeError('Column index out of range'); | ||
} | ||
/** | ||
* Returns the product of all elements of the matrix | ||
* @returns {number} | ||
* @private | ||
* Check that two matrices have the same dimensions | ||
* @param {Matrix} matrix | ||
* @param {Matrix} otherMatrix | ||
*/ | ||
Matrix.prototype.prod = function prod() { | ||
var prod = 1; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
prod *= this[i][j]; | ||
} | ||
function checkDimensions(matrix, otherMatrix) { | ||
if (matrix.rows !== otherMatrix.length || | ||
matrix.columns !== otherMatrix[0].length) { | ||
throw new RangeError('Matrices dimensions must be equal'); | ||
} | ||
return prod; | ||
}; | ||
} | ||
/** | ||
* Computes the cumulative sum of the matrix elements (in place, row by row) | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.cumulativeSum = function cumulativeSum() { | ||
var sum = 0; | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
sum += this[i][j]; | ||
this[i][j] = sum; | ||
} | ||
} | ||
return this; | ||
}; | ||
function compareNumbers(a, b) { | ||
return a - b; | ||
} | ||
/** | ||
* Computes the dot (scalar) product between the matrix and another | ||
* @param {Matrix} other vector | ||
* @returns {number} | ||
/* | ||
Synonyms | ||
*/ | ||
Matrix.prototype.dot = function dot(other) { | ||
if (this.size !== other.size) | ||
throw new RangeError('vectors do not have the same size'); | ||
var vector1 = this.to1DArray(); | ||
var vector2 = other.to1DArray(); | ||
var dot = 0, l = vector1.length; | ||
for (var i = 0; i < l; i++) { | ||
dot += vector1[i] * vector2[i]; | ||
} | ||
return dot; | ||
}; | ||
/** | ||
* Returns the matrix product between this and other | ||
* @returns {Matrix} | ||
Matrix.random = Matrix.rand; | ||
Matrix.diagonal = Matrix.diag; | ||
Matrix.prototype.diagonal = Matrix.prototype.diag; | ||
Matrix.identity = Matrix.eye; | ||
Matrix.prototype.negate = Matrix.prototype.neg; | ||
/* | ||
Add dynamically instance and static methods for mathematical operations | ||
*/ | ||
Matrix.prototype.mmul = function mmul(other) { | ||
if (!Matrix.isMatrix(other)) | ||
throw new TypeError('parameter "other" must be a matrix'); | ||
if (this.columns !== other.rows) | ||
console.warn('Number of columns of left matrix are not equal to number of rows of right matrix.'); | ||
var m = this.rows, n = this.columns, p = other.columns; | ||
var result = new Matrix(m, p); | ||
const inplaceOperator = ` | ||
(function %name%(value) { | ||
if (typeof value === 'number') return this.%name%S(value); | ||
return this.%name%M(value); | ||
}) | ||
`; | ||
var Bcolj = new Array(n); | ||
var i, j, k; | ||
for (j = 0; j < p; j++) { | ||
for (k = 0; k < n; k++) | ||
Bcolj[k] = other[k][j]; | ||
for (i = 0; i < m; i++) { | ||
var Arowi = this[i]; | ||
var s = 0; | ||
for (k = 0; k < n; k++) | ||
s += Arowi[k] * Bcolj[k]; | ||
result[i][j] = s; | ||
const inplaceOperatorScalar = ` | ||
(function %name%S(value) { | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] = this[i][j] %op% value; | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Sorts the rows (in place) | ||
* @param {function} compareFunction - usual Array.prototype.sort comparison function | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.sortRows = function sortRows(compareFunction) { | ||
for (var i = 0, ii = this.rows; i < ii; i++) { | ||
this[i].sort(compareFunction); | ||
} | ||
return this; | ||
}; | ||
}) | ||
`; | ||
/** | ||
* Sorts the columns (in place) | ||
* @param {function} compareFunction - usual Array.prototype.sort comparison function | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.sortColumns = function sortColumns(compareFunction) { | ||
for (var i = 0, ii = this.columns; i < ii; i++) { | ||
this.setColumn(i, this.getColumn(i).sort(compareFunction)); | ||
const inplaceOperatorMatrix = ` | ||
(function %name%M(matrix) { | ||
checkDimensions(this, matrix); | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] = this[i][j] %op% matrix[i][j]; | ||
} | ||
} | ||
return this; | ||
}; | ||
}) | ||
`; | ||
/** | ||
* Transposes the matrix and returns a new one containing the result | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.transpose = function transpose() { | ||
var result = new Matrix(this.columns, this.rows); | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
result[j][i] = this[i][j]; | ||
} | ||
} | ||
return result; | ||
}; | ||
const staticOperator = ` | ||
(function %name%(matrix, value) { | ||
const newMatrix = new Matrix(matrix); | ||
return newMatrix.%name%(value); | ||
}) | ||
`; | ||
/** | ||
* Returns a subset of the matrix | ||
* @param {number} startRow - First row index | ||
* @param {number} endRow - Last row index | ||
* @param {number} startColumn - First column index | ||
* @param {number} endColumn - Last column index | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.subMatrix = function subMatrix(startRow, endRow, startColumn, endColumn) { | ||
if ((startRow > endRow) || (startColumn > endColumn) || (startRow < 0) || (startRow >= this.rows) || (endRow < 0) || (endRow >= this.rows) || (startColumn < 0) || (startColumn >= this.columns) || (endColumn < 0) || (endColumn >= this.columns)) | ||
throw new RangeError('Argument out of range'); | ||
var newMatrix = new Matrix(endRow - startRow + 1, endColumn - startColumn + 1); | ||
for (var i = startRow; i <= endRow; i++) { | ||
for (var j = startColumn; j <= endColumn; j++) { | ||
newMatrix[i - startRow][j - startColumn] = this[i][j]; | ||
const inplaceMethod = ` | ||
(function %name%() { | ||
for (var i = 0; i < this.rows; i++) { | ||
for (var j = 0; j < this.columns; j++) { | ||
this[i][j] = %method%(this[i][j]); | ||
} | ||
} | ||
return newMatrix; | ||
}; | ||
return this; | ||
}) | ||
`; | ||
/** | ||
* Returns a subset of the matrix based on an array of row indices | ||
* @param {Array} indices - Array containing the row indices | ||
* @param {number} [startColumn = 0] - First column index | ||
* @param {number} [endColumn = this.columns-1] - Last column index | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.subMatrixRow = function subMatrixRow(indices, startColumn, endColumn) { | ||
if (typeof startColumn === 'undefined') { | ||
startColumn = 0; | ||
endColumn = this.columns - 1; | ||
} else if (typeof endColumn === 'undefined') { | ||
endColumn = this.columns - 1; | ||
} | ||
if ((startColumn > endColumn) || (startColumn < 0) || (startColumn >= this.columns) || (endColumn < 0) || (endColumn >= this.columns)) | ||
throw new RangeError('Argument out of range.'); | ||
var l = indices.length, rows = this.rows, | ||
X = new Matrix(l, endColumn - startColumn + 1); | ||
for (var i = 0; i < l; i++) { | ||
for (var j = startColumn; j <= endColumn; j++) { | ||
if ((indices[i] < 0) || (indices[i] >= rows)) | ||
throw new RangeError('Argument out of range.'); | ||
X[i][j - startColumn] = this[indices[i]][j]; | ||
} | ||
} | ||
return X; | ||
}; | ||
const staticMethod = ` | ||
(function %name%(matrix) { | ||
const newMatrix = new Matrix(matrix); | ||
return newMatrix.%name%(); | ||
}) | ||
`; | ||
/** | ||
* Returns a subset of the matrix based on an array of column indices | ||
* @param {Array} indices - Array containing the column indices | ||
* @param {number} [startRow = 0] - First row index | ||
* @param {number} [endRow = this.rows-1] - Last row index | ||
* @returns {Matrix} | ||
*/ | ||
Matrix.prototype.subMatrixColumn = function subMatrixColumn(indices, startRow, endRow) { | ||
if (typeof startRow === 'undefined') { | ||
startRow = 0; | ||
endRow = this.rows - 1; | ||
} else if (typeof endRow === 'undefined') { | ||
endRow = this.rows - 1; | ||
const operators = [ | ||
// Arithmetic operators | ||
['+', 'add'], | ||
['-', 'sub', 'subtract'], | ||
['*', 'mul', 'multiply'], | ||
['/', 'div', 'divide'], | ||
['%', 'mod', 'modulus'], | ||
// Bitwise operators | ||
['&', 'and'], | ||
['|', 'or'], | ||
['^', 'xor'], | ||
['<<', 'leftShift'], | ||
['>>', 'signPropagatingRightShift'], | ||
['>>>', 'rightShift', 'zeroFillRightShift'] | ||
]; | ||
for (let operator of operators) { | ||
for (let i = 1; i < operator.length; i++) { | ||
Matrix.prototype[operator[i]] = eval(fillTemplateFunction(inplaceOperator, {name: operator[i], op: operator[0]})); | ||
Matrix.prototype[operator[i] + 'S'] = eval(fillTemplateFunction(inplaceOperatorScalar, {name: operator[i] + 'S', op: operator[0]})); | ||
Matrix.prototype[operator[i] + 'M'] = eval(fillTemplateFunction(inplaceOperatorMatrix, {name: operator[i] + 'M', op: operator[0]})); | ||
Matrix[operator[i]] = eval(fillTemplateFunction(staticOperator, {name: operator[i]})); | ||
} | ||
if ((startRow > endRow) || (startRow < 0) || (startRow >= this.rows) || (endRow < 0) || (endRow >= this.rows)) | ||
throw new RangeError('Argument out of range.'); | ||
var l = indices.length, columns = this.columns, | ||
X = new Matrix(endRow - startRow + 1, l); | ||
for (var i = 0; i < l; i++) { | ||
for (var j = startRow; j <= endRow; j++) { | ||
if ((indices[i] < 0) || (indices[i] >= columns)) | ||
throw new RangeError('Argument out of range.'); | ||
X[j - startRow][i] = this[j][indices[i]]; | ||
} | ||
} | ||
return X; | ||
}; | ||
} | ||
/** | ||
* Returns the trace of the matrix (sum of the diagonal elements) | ||
* @returns {number} | ||
*/ | ||
Matrix.prototype.trace = function trace() { | ||
if (!this.isSquare()) | ||
throw new TypeError('The matrix is not square'); | ||
var trace = 0, i = 0, l = this.rows; | ||
for (; i < l; i++) { | ||
trace += this[i][i]; | ||
const methods = [ | ||
['~', 'not'] | ||
]; | ||
[ | ||
'abs', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cbrt', 'ceil', | ||
'clz32', 'cos', 'cosh', 'exp', 'expm1', 'floor', 'fround', 'log', 'log1p', | ||
'log10', 'log2', 'round', 'sign', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc' | ||
].forEach(function (mathMethod) { | ||
methods.push(['Math.' + mathMethod, mathMethod]); | ||
}); | ||
for (let method of methods) { | ||
for (let i = 1; i < method.length; i++) { | ||
Matrix.prototype[method[i]] = eval(fillTemplateFunction(inplaceMethod, {name: method[i], method: method[0]})); | ||
Matrix[method[i]] = eval(fillTemplateFunction(staticMethod, {name: method[i]})); | ||
} | ||
return trace; | ||
}; | ||
} | ||
/** | ||
* Sets each element of the matrix to its absolute value | ||
* @returns {Matrix} this | ||
*/ | ||
Matrix.prototype.abs = function abs() { | ||
var ii = this.rows, jj = this.columns; | ||
for (var i = 0; i < ii; i++) { | ||
for (var j = 0; j < jj; j++) { | ||
this[i][j] = Math.abs(this[i][j]); | ||
} | ||
function fillTemplateFunction(template, values) { | ||
for (var i in values) { | ||
template = template.replace(new RegExp('%' + i + '%', 'g'), values[i]); | ||
} | ||
}; | ||
module.exports = Matrix; | ||
return template; | ||
} |
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
3001991
3180.94%25
66.67%3065
5.62%9
125%1
Infinity%