Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ml-matrix

Package Overview
Dependencies
Maintainers
7
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ml-matrix - npm Package Compare versions

Comparing version 1.4.0 to 2.0.0

src/abstractMatrix.js

23

History.md

@@ -0,1 +1,24 @@

<a name="2.0.0"></a>
# [2.0.0](https://github.com/mljs/matrix/compare/v1.4.0...v2.0.0) (2016-08-04)
### Features
* add column view ([5ff6680](https://github.com/mljs/matrix/commit/5ff6680))
* add concept of abstract matrix ([cbefc9b](https://github.com/mljs/matrix/commit/cbefc9b))
* add flipColumn and flipRow views ([55ee4a6](https://github.com/mljs/matrix/commit/55ee4a6))
* add method subMatrixView ([aa1df18](https://github.com/mljs/matrix/commit/aa1df18))
* add row view ([a9e99f2](https://github.com/mljs/matrix/commit/a9e99f2))
* add selection method and selection view ([59aa861](https://github.com/mljs/matrix/commit/59aa861))
* add transposeView ([fb0a0c9](https://github.com/mljs/matrix/commit/fb0a0c9))
* make use of Symbol.species to allow creating new matrices in any class ([eaee5de](https://github.com/mljs/matrix/commit/eaee5de))
### BREAKING CHANGES
* This is a non trivial change and could potentially break existing code.
There is no known backward incompatibility though.
<a name="1.4.0"></a>

@@ -2,0 +25,0 @@ # [1.4.0](https://github.com/mljs/matrix/compare/v1.3.0...v1.4.0) (2016-08-03)

2

package.json
{
"name": "ml-matrix",
"version": "1.4.0",
"version": "2.0.0",
"description": "Matrix manipulation and computation library",

@@ -5,0 +5,0 @@ "main": "src/index.js",

'use strict';
const arrayUtils = require('ml-array-utils');
require('./symbol-species');
var abstractMatrix = require('./abstractMatrix');
var util = require('./util');
/**
* Real matrix
* @class Matrix
* @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
*/
class Matrix extends Array {
class Matrix extends abstractMatrix(Array) {
constructor(nRows, nColumns) {
if (arguments.length === 1 && typeof nRows === 'number') {
return new Array(nRows);
}
if (Matrix.isMatrix(nRows)) {

@@ -46,218 +44,12 @@ return nRows.clone();

// Native array methods should return instances of Array, not Matrix
static get [Symbol.species]() {
return Array;
set(rowIndex, columnIndex, value) {
this[rowIndex][columnIndex] = value;
return this;
}
/**
* 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) {
var length = newRows * newColumns;
if (length !== newData.length) {
throw new RangeError('Data length does not match given dimensions');
}
var 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];
}
}
return newMatrix;
get(rowIndex, columnIndex) {
return this[rowIndex][columnIndex];
}
/**
* 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) {
var vector = new Matrix(1, newData.length);
for (var i = 0; i < newData.length; i++) {
vector[0][i] = newData[i];
}
return vector;
}
/**
* 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) {
var vector = new Matrix(newData.length, 1);
for (var i = 0; i < newData.length; i++) {
vector[i][0] = newData[i];
}
return vector;
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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;
var matrix = Matrix.empty(rows, columns);
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
matrix[i][j] = rng();
}
}
return matrix;
}
/**
* 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;
var min = Math.min(rows, columns);
var matrix = Matrix.zeros(rows, columns);
for (var i = 0; i < min; i++) {
matrix[i][i] = 1;
}
return matrix;
}
/**
* 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) {
var l = data.length;
if (rows === undefined) rows = l;
if (columns === undefined) columns = rows;
var min = Math.min(l, rows, columns);
var matrix = Matrix.zeros(rows, columns);
for (var i = 0; i < min; i++) {
matrix[i][i] = data[i];
}
return matrix;
}
/**
* Returns a matrix whose elements are the minimum between matrix1 and matrix2
* @param matrix1
* @param matrix2
* @returns {Matrix}
*/
static min(matrix1, matrix2) {
var rows = matrix1.length;
var columns = matrix1[0].length;
var 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;
}
/**
* Returns a matrix whose elements are the maximum between matrix1 and matrix2
* @param matrix1
* @param matrix2
* @returns {Matrix}
*/
static max(matrix1, matrix2) {
var rows = matrix1.length;
var columns = matrix1[0].length;
var 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;
}
/**
* 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);
}
/**
* 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');
}
/**
* @property {number} - The number of elements in the matrix.
*/
get size() {
return this.rows * this.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) {
if (typeof callback !== 'function') {
throw new TypeError('callback must be a function');
}
var ii = this.rows;
var jj = this.columns;
for (var i = 0; i < ii; i++) {
for (var j = 0; j < jj; j++) {
callback.call(this, i, j);
}
}
return this;
}
/**
* Creates an exact and independent copy of the matrix

@@ -267,6 +59,6 @@ * @returns {Matrix}

clone() {
var newMatrix = new Matrix(this.rows, this.columns);
var newMatrix = new this.constructor[Symbol.species](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];
newMatrix.set(row, column, this.get(row, column));
}

@@ -278,170 +70,2 @@ }

/**
* Returns a new 1D array filled row by row with the matrix values
* @returns {Array}
*/
to1DArray() {
var 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;
}
/**
* Returns a 2D array containing a copy of the data
* @returns {Array}
*/
to2DArray() {
var copy = new Array(this.rows);
for (var i = 0; i < this.rows; i++) {
copy[i] = [].concat(this[i]);
}
return copy;
}
/**
* @returns {boolean} true if the matrix has one row
*/
isRowVector() {
return this.rows === 1;
}
/**
* @returns {boolean} true if the matrix has one column
*/
isColumnVector() {
return this.columns === 1;
}
/**
* @returns {boolean} true if the matrix has one row or one column
*/
isVector() {
return (this.rows === 1) || (this.columns === 1);
}
/**
* @returns {boolean} true if the matrix has the same number of rows and columns
*/
isSquare() {
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;
}
/**
* 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;
}
/**
* 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];
}
/**
* Creates a new matrix that is a repetition of the current matrix. New matrix has rowRep times the number of
* rows of the matrix, and colRep times the number of columns of the matrix
* @param {number} rowRep - Number of times the rows should be repeated
* @param {number} colRep - Number of times the columns should be re
* @example
* var matrix = new Matrix([[1,2]]);
* matrix.repeat(2); // [[1,2],[1,2]]
*/
repeat(rowRep, colRep) {
rowRep = rowRep || 1;
colRep = colRep || 1;
var matrix = new Matrix(this.rows * rowRep, this.columns * colRep);
for (var i = 0; i < rowRep; i++) {
for (var j = 0; j < colRep; j++) {
matrix.setSubMatrix(this, this.rows * i, this.columns * j);
}
}
return matrix;
}
/**
* 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;
}
/**
* Negates the matrix. All elements will be multiplied by (-1)
* @returns {Matrix} this
*/
neg() {
return this.mulS(-1);
}
/**
* 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 new row vector from the given row index
* @param {number} index - Row index
* @returns {Matrix}
*/
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
*/
setRow(index, array) {
checkRowIndex(this, index);
array = checkRowVector(this, array, true);
this[index] = array;
return this;
}
/**
* Removes a row from the given index

@@ -452,3 +76,3 @@ * @param {number} index - Row index

removeRow(index) {
checkRowIndex(this, index);
util.checkRowIndex(this, index);
if (this.rows === 1)

@@ -472,4 +96,4 @@ throw new RangeError('A matrix cannot have less than one row');

}
checkRowIndex(this, index, true);
array = checkRowVector(this, array, true);
util.checkRowIndex(this, index, true);
array = util.checkRowVector(this, array, true);
this.splice(index, 0, array);

@@ -481,55 +105,2 @@ this.rows += 1;

/**
* 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 a new array from the given column index
* @param {number} index - Column index
* @returns {Array}
*/
getColumn(index) {
checkColumnIndex(this, index);
var column = new Array(this.rows);
for (var i = 0; i < this.rows; i++) {
column[i] = this[i][index];
}
return column;
}
/**
* 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));
}
/**
* 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;
}
/**
* Removes a column from the given index

@@ -540,3 +111,3 @@ * @param {number} index - Column index

removeColumn(index) {
checkColumnIndex(this, index);
util.checkColumnIndex(this, index);
if (this.columns === 1)

@@ -562,4 +133,4 @@ throw new RangeError('A matrix cannot have less than one column');

}
checkColumnIndex(this, index, true);
array = checkColumnVector(this, array);
util.checkColumnIndex(this, index, true);
array = util.checkColumnVector(this, array);
for (var i = 0; i < this.rows; i++) {

@@ -571,1016 +142,5 @@ this[i].splice(index, 0, array[i]);

}
/**
* 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);
var 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 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
}
/**
* Returns the maximum value of the matrix
* @returns {number}
*/
max() {
var 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;
}
/**
* Returns the index of the maximum value
* @returns {Array}
*/
maxIndex() {
var v = this[0][0];
var 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;
}
/**
* Returns the minimum value of the matrix
* @returns {number}
*/
min() {
var 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;
}
/**
* Returns the index of the minimum value
* @returns {Array}
*/
minIndex() {
var v = this[0][0];
var 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;
}
/**
* Returns the maximum value of one row
* @param {number} row - Row index
* @returns {number}
*/
maxRow(row) {
checkRowIndex(this, row);
var v = this[row][0];
for (var i = 1; i < this.columns; i++) {
if (this[row][i] > v) {
v = this[row][i];
}
}
return v;
}
/**
* Returns the index of the maximum value of one row
* @param {number} row - Row index
* @returns {Array}
*/
maxRowIndex(row) {
checkRowIndex(this, row);
var v = this[row][0];
var 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;
}
/**
* Returns the minimum value of one row
* @param {number} row - Row index
* @returns {number}
*/
minRow(row) {
checkRowIndex(this, row);
var v = this[row][0];
for (var i = 1; i < this.columns; i++) {
if (this[row][i] < v) {
v = this[row][i];
}
}
return v;
}
/**
* Returns the index of the maximum value of one row
* @param {number} row - Row index
* @returns {Array}
*/
minRowIndex(row) {
checkRowIndex(this, row);
var v = this[row][0];
var 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;
}
/**
* Returns the maximum value of one column
* @param {number} column - Column index
* @returns {number}
*/
maxColumn(column) {
checkColumnIndex(this, column);
var v = this[0][column];
for (var i = 1; i < this.rows; i++) {
if (this[i][column] > v) {
v = this[i][column];
}
}
return v;
}
/**
* Returns the index of the maximum value of one column
* @param {number} column - Column index
* @returns {Array}
*/
maxColumnIndex(column) {
checkColumnIndex(this, column);
var v = this[0][column];
var 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;
}
/**
* Returns the minimum value of one column
* @param {number} column - Column index
* @returns {number}
*/
minColumn(column) {
checkColumnIndex(this, column);
var v = this[0][column];
for (var i = 1; i < this.rows; i++) {
if (this[i][column] < v) {
v = this[i][column];
}
}
return v;
}
/**
* Returns the index of the minimum value of one column
* @param {number} column - Column index
* @returns {Array}
*/
minColumnIndex(column) {
checkColumnIndex(this, column);
var v = this[0][column];
var 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;
}
/**
* Returns an array containing the diagonal values of the matrix
* @returns {Array}
*/
diag() {
var min = Math.min(this.rows, this.columns);
var diag = new Array(min);
for (var i = 0; i < min; i++) {
diag[i] = this[i][i];
}
return diag;
}
/**
* Returns the sum of all elements of the matrix
* @returns {number}
*/
sum() {
var v = 0;
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.columns; j++) {
v += this[i][j];
}
}
return v;
}
/**
* Returns the mean of all elements of the matrix
* @returns {number}
*/
mean() {
return this.sum() / this.size;
}
/**
* Returns the product of all elements of the matrix
* @returns {number}
*/
prod() {
var prod = 1;
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.columns; j++) {
prod *= this[i][j];
}
}
return prod;
}
/**
* Computes the cumulative sum of the matrix elements (in place, row by row)
* @returns {Matrix} this
*/
cumulativeSum() {
var 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;
}
/**
* 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();
var 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;
}
/**
* Returns the matrix product between this and other
* @param {Matrix} 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.');
var m = this.rows;
var n = this.columns;
var p = other.columns;
var result = new Matrix(m, p);
var 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;
}
/**
* Returns a row-by-row scaled matrix
* @param {Number} [min=0] - Minimum scaled value
* @param {Number} [max=1] - Maximum scaled value
* @returns {Matrix} - The scaled matrix
*/
scaleRows(min, max) {
min = min === undefined ? 0 : min;
max = max === undefined ? 1 : max;
if (min >= max) {
throw new RangeError('min should be strictly smaller than max');
}
var newMatrix = Matrix.empty(this.rows, this.columns);
for (var i = 0; i < this.rows; i++) {
var scaled = arrayUtils.scale(this.getRow(i), {min, max});
newMatrix.setRow(i, scaled);
}
return newMatrix;
}
/**
* Returns a new column-by-column scaled matrix
* @param {Number} [min=0] - Minimum scaled value
* @param {Number} [max=1] - Maximum scaled value
* @returns {Matrix} - The new scaled matrix
* @example
* var matrix = new Matrix([[1,2],[-1,0]]);
* var scaledMatrix = matrix.scaleColumns(); // [[1,1],[0,0]]
*/
scaleColumns(min, max) {
min = min === undefined ? 0 : min;
max = max === undefined ? 1 : max;
if (min >= max) {
throw new RangeError('min should be strictly smaller than max');
}
var newMatrix = Matrix.empty(this.rows, this.columns);
for (var i = 0; i < this.columns; i++) {
var scaled = arrayUtils.scale(this.getColumn(i), {
min: min,
max: max
});
newMatrix.setColumn(i, scaled);
}
return newMatrix;
}
/**
* Returns the Kronecker product (also known as tensor product) between this and other
* See https://en.wikipedia.org/wiki/Kronecker_product
* @param {Matrix} other
* @return {Matrix}
*/
kroneckerProduct(other) {
other = Matrix.checkMatrix(other);
var m = this.rows;
var n = this.columns;
var p = other.rows;
var q = other.columns;
var result = new Matrix(m * p, n * q);
for (var i = 0; i < m; i++) {
for (var j = 0; j < n; j++) {
for (var k = 0; k < p; k++) {
for (var l = 0; l < q; l++) {
result[p * i + k][q * j + l] = this[i][j] * other[k][l];
}
}
}
}
return result;
}
/**
* Transposes the matrix and returns a new one containing the result
* @returns {Matrix}
*/
transpose() {
var 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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');
}
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];
}
}
return newMatrix;
}
/**
* 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');
}
var 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;
}
/**
* 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');
}
var 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;
}
/**
* Set a part of the matrix to the given sub-matrix
* @param {Matrix|Array< Array >} matrix - The source matrix from which to extract values.
* @param startRow - The index of the first row to set
* @param startColumn - The index of the first column to set
* @returns {Matrix}
*/
setSubMatrix(matrix, startRow, startColumn) {
matrix = Matrix.checkMatrix(matrix);
var endRow = startRow + matrix.rows - 1;
var endColumn = startColumn + matrix.columns - 1;
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');
}
for (var i = 0; i < matrix.rows; i++) {
for (var j = 0; j < matrix.columns; j++) {
this[startRow + i][startColumn + j] = matrix[i][j];
}
}
return this;
}
/**
* Returns the trace of the matrix (sum of the diagonal elements)
* @returns {number}
*/
trace() {
var min = Math.min(this.rows, this.columns);
var trace = 0;
for (var i = 0; i < min; i++) {
trace += this[i][i];
}
return trace;
}
}
Matrix.prototype.klass = 'Matrix';
module.exports = Matrix;
/**
* @private
* Check that a row index is not out of bounds
* @param {Matrix} matrix
* @param {number} index
* @param {boolean} [outer]
*/
function checkRowIndex(matrix, index, outer) {
var max = outer ? matrix.rows : matrix.rows - 1;
if (index < 0 || index > max)
throw new RangeError('Row index out of range');
}
/**
* @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}
*/
function checkRowVector(matrix, vector, copy) {
if (Matrix.isMatrix(vector)) {
vector = vector.to1DArray();
} else if (copy) {
vector = [].concat(vector);
}
if (vector.length !== matrix.columns)
throw new RangeError('vector size must be the same as the number of columns');
return vector;
}
/**
* @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}
*/
function checkColumnVector(matrix, vector, copy) {
if (Matrix.isMatrix(vector)) {
vector = vector.to1DArray();
} else if (copy) {
vector = [].concat(vector);
}
if (vector.length !== matrix.rows)
throw new RangeError('vector size must be the same as the number of rows');
return vector;
}
/**
* @private
* Check that a column index is not out of bounds
* @param {Matrix} matrix
* @param {number} index
* @param {boolean} [outer]
*/
function checkColumnIndex(matrix, index, outer) {
var max = outer ? matrix.columns : matrix.columns - 1;
if (index < 0 || index > max)
throw new RangeError('Column index out of range');
}
/**
* @private
* Check that two matrices have the same dimensions
* @param {Matrix} matrix
* @param {Matrix} otherMatrix
*/
function checkDimensions(matrix, otherMatrix) {
if (matrix.rows !== otherMatrix.length ||
matrix.columns !== otherMatrix[0].length) {
throw new RangeError('Matrices dimensions must be equal');
}
}
function compareNumbers(a, b) {
return a - b;
}
/*
Synonyms
*/
Matrix.random = Matrix.rand;
Matrix.diagonal = Matrix.diag;
Matrix.prototype.diagonal = Matrix.prototype.diag;
Matrix.identity = Matrix.eye;
Matrix.prototype.negate = Matrix.prototype.neg;
Matrix.prototype.tensorProduct = Matrix.prototype.kroneckerProduct;
/*
Add dynamically instance and static methods for mathematical operations
*/
var inplaceOperator = `
(function %name%(value) {
if (typeof value === 'number') return this.%name%S(value);
return this.%name%M(value);
})
`;
var 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 this;
})
`;
var 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;
})
`;
var staticOperator = `
(function %name%(matrix, value) {
var newMatrix = new Matrix(matrix);
return newMatrix.%name%(value);
})
`;
var 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 this;
})
`;
var staticMethod = `
(function %name%(matrix) {
var newMatrix = new Matrix(matrix);
return newMatrix.%name%();
})
`;
var inplaceMethodWithArgs = `
(function %name%(%args%) {
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.columns; j++) {
this[i][j] = %method%(this[i][j], %args%);
}
}
return this;
})
`;
var staticMethodWithArgs = `
(function %name%(matrix, %args%) {
var newMatrix = new Matrix(matrix);
return newMatrix.%name%(%args%);
})
`;
var inplaceMethodWithOneArgScalar = `
(function %name%S(%args%) {
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.columns; j++) {
this[i][j] = %method%(this[i][j], %args%);
}
}
return this;
})
`;
var inplaceMethodWithOneArgMatrix = `
(function %name%M(%args%) {
checkDimensions(this, %args%);
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.columns; j++) {
this[i][j] = %method%(this[i][j], %args%[i][j]);
}
}
return this;
})
`;
var inplaceMethodWithOneArg = `
(function %name%(value) {
if (typeof value === 'number') return this.%name%S(value);
return this.%name%M(value);
})
`;
var staticMethodWithOneArg = staticMethodWithArgs;
var operators = [
// Arithmetic operators
['+', 'add'],
['-', 'sub', 'subtract'],
['*', 'mul', 'multiply'],
['/', 'div', 'divide'],
['%', 'mod', 'modulus'],
// Bitwise operators
['&', 'and'],
['|', 'or'],
['^', 'xor'],
['<<', 'leftShift'],
['>>', 'signPropagatingRightShift'],
['>>>', 'rightShift', 'zeroFillRightShift']
];
for (var operator of operators) {
var inplaceOp = eval(fillTemplateFunction(inplaceOperator, {name: operator[1], op: operator[0]}));
var inplaceOpS = eval(fillTemplateFunction(inplaceOperatorScalar, {name: operator[1] + 'S', op: operator[0]}));
var inplaceOpM = eval(fillTemplateFunction(inplaceOperatorMatrix, {name: operator[1] + 'M', op: operator[0]}));
var staticOp = eval(fillTemplateFunction(staticOperator, {name: operator[1]}));
for (var i = 1; i < operator.length; i++) {
Matrix.prototype[operator[i]] = inplaceOp;
Matrix.prototype[operator[i] + 'S'] = inplaceOpS;
Matrix.prototype[operator[i] + 'M'] = inplaceOpM;
Matrix[operator[i]] = staticOp;
}
}
var 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 (var method of methods) {
var inplaceMeth = eval(fillTemplateFunction(inplaceMethod, {name: method[1], method: method[0]}));
var staticMeth = eval(fillTemplateFunction(staticMethod, {name: method[1]}));
for (var i = 1; i < method.length; i++) {
Matrix.prototype[method[i]] = inplaceMeth;
Matrix[method[i]] = staticMeth;
}
}
var methodsWithArgs = [
['Math.pow', 1, 'pow']
];
for (var methodWithArg of methodsWithArgs) {
var args = 'arg0';
for (var i = 1; i < methodWithArg[1]; i++) {
args += `, arg${i}`;
}
if (methodWithArg[1] !== 1) {
var inplaceMethWithArgs = eval(fillTemplateFunction(inplaceMethodWithArgs, {
name: methodWithArg[2],
method: methodWithArg[0],
args: args
}));
var staticMethWithArgs = eval(fillTemplateFunction(staticMethodWithArgs, {name: methodWithArg[2], args: args}));
for (var i = 2; i < methodWithArg.length; i++) {
Matrix.prototype[methodWithArg[i]] = inplaceMethWithArgs;
Matrix[methodWithArg[i]] = staticMethWithArgs;
}
} else {
var tmplVar = {
name: methodWithArg[2],
args: args,
method: methodWithArg[0]
};
console.log(tmplVar);
let inplaceMethod = eval(fillTemplateFunction(inplaceMethodWithOneArg, tmplVar));
let inplaceMethodS = eval(fillTemplateFunction(inplaceMethodWithOneArgScalar, tmplVar));
let inplaceMethodM = eval(fillTemplateFunction(inplaceMethodWithOneArgMatrix, tmplVar));
console.log(fillTemplateFunction(staticMethodWithOneArg, tmplVar));
let staticMethod = eval(fillTemplateFunction(staticMethodWithOneArg, tmplVar));
for (var i = 2; i < methodWithArg.length; i++) {
Matrix.prototype[methodWithArg[i]] = inplaceMethod;
Matrix.prototype[methodWithArg[i] + 'M'] = inplaceMethodM;
Matrix.prototype[methodWithArg[i] + 'S'] = inplaceMethodS;
Matrix[methodWithArg[i]] = staticMethod;
}
}
}
function fillTemplateFunction(template, values) {
for (var i in values) {
template = template.replace(new RegExp('%' + i + '%', 'g'), values[i]);
}
return template;
}
Matrix.abstractMatrix = abstractMatrix;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc