UNPKG

encog

Version:

Encog is a NodeJs ES6 framework based on the Encog Machine Learning Framework by Jeff Heaton, plus some the of basic data manipulation helpers.

281 lines (254 loc) 7.56 kB
const ArrayUtils = require(PATHS.PREPROCESSING + 'array'); const MatrixError = require(PATHS.ERROR_HANDLING + 'matrix'); /** * This class implements a mathematical matrix. Matrix math is very important to * neural network processing. Many of the neural network classes make use of the * matrix classes in this package. */ class Matrix { /** * Create a blank array with the specified number of rows and columns. * * @param rows {number} || {Matrix} * How many rows in the matrix. * @param cols {number} * How many columns in the matrix. * @param defaultValue {number} */ constructor(rows, cols, defaultValue = 0) { this.matrix = []; if (arguments[0].constructor.name == 'Array') { this.setMatrix(arguments[0]) } else if (( arguments.length === 3 && arguments[0].constructor.name == 'Number' && arguments[1].constructor.name == 'Number' && arguments[2].constructor.name == 'Number') || ( arguments.length === 2 && arguments[0].constructor.name == 'Number' && arguments[1].constructor.name == 'Number')) { for (var i = 0; i < rows; i++) { this.matrix[i] = []; for (var j = 0; j < cols; j++) { this.matrix[i][j] = defaultValue; } } } else { throw new MatrixError('Invalid Matrix arguments'); } } /** * @param M {Array} */ setMatrix(M) { for (let i = 0; i < M.length; i++) { this.matrix[i] = []; for (let j = 0; j < M[0].length; j++) { this.matrix[i][j] = M[i][j]; } } } /** * Set all rows and columns to zero. */ clear() { for (let r = 0; r < this.getRows(); r++) { for (let c = 0; c < this.getCols(); c++) { this.matrix[r][c] = 0; } } } /** * Create a copy of the matrix. * * @return {Matrix} A colne of the matrix. */ clone() { return new Matrix(this.matrix); } /** * Read the specified cell in the matrix. * * @param row {Number} * The row to read. * @param col {Number} * The column to read. * @return {Number} The value at the specified row and column. */ get(row, col) { this._validate(row, col); return this.matrix[row][col]; } /** * Set an individual cell in the matrix to the specified value. * * @param row {Number} * The row to set. * @param col {Number} * The column to set. * @param value {Number} * The value to be set. */ set(row, col, value) { this._validate(row, col); this.matrix[row][col] = value; } /** * Increment an individual cell in the matrix with the specified value. * * @param row {Number} * The row to set. * @param col {Number} * The column to set. * @param value {Number} * The value to be set. */ inc(row, col, value) { this._validate(row, col); this.matrix[row][col] += value; } /** * Get the columns in the matrix. * * @return {Number} The number of columns in the matrix. */ getCols() { return this.matrix[0].length; } /** * @return {Array} Get the 2D matrix array. */ getData() { return this.matrix; } /** * Get the number of rows in the matrix. * * @return {Number} The number of rows in the matrix. */ getRows() { return this.matrix.length; } /** * Get the size of the array. This is the number of elements it would take * to store the matrix as a packed array. * * @return {number} The size of the matrix. */ size() { return this.getCols() * this.getRows(); } /** * Is the matrix non singular? * * @return {boolean} */ isNonSingular() { for (let j = 0; j < this.getCols(); j++) { if (this.matrix[j][j] == 0) return false; } return true; } /** * @param M {Matrix} * */ add(M) { for (let row = 0; row < this.matrix.length; row++) { for (let col = 0; col < this.matrix[row].length; col++) { this.matrix[row][col] += M.get(row, col); } } } /** * Add a value to one cell in the matrix. * * @param row {Number} * The row to add to. * @param col {Number} * The column to add to. * @param value {Number} * The value to add to the matrix. */ addValue(row, col, value) { this._validate(row, col); this.matrix[row][col] += value; } /** * Read one entire column from the matrix as a sub-matrix. * * @param col {Number} * The column to read. * @return {Matrix} The column as a sub-matrix. */ getCol(col) { if (col > this.getCols()) { throw new MatrixError("Can't get column #" + col + " because it does not exist."); } let newMatrix = ArrayUtils.newIntArray(this.getRows(), new Array(1)); for (let row = 0; row < this.getRows(); row++) { newMatrix[row][0] = this.matrix[row][col]; } return new Matrix(newMatrix); } /** * Get the specified row as a sub-matrix. * * @param row {Number} * The row to get. * @return {Matrix} A matrix. */ getRow(row) { if (row > this.getRows()) { throw new MatrixError("Can't get row #" + row + " because it does not exist."); } let newMatrix = ArrayUtils.newIntArray(this.getCols()); for (let col = 0; col < this.getCols(); col++) { newMatrix[0][col] = this.matrix[row][col]; } return new Matrix(newMatrix); } /** * Determine if the matrix is a vector. A vector is has either a single * number of rows or columns. * * @return {Boolean} True if this matrix is a vector. */ isVector() { if (this.getRows() == 1) { return true; } return this.getCols() == 1; } each(cb) { let value; cb = cb || function () { }; for (let row = 0; row < this.matrix.length; row++) { for (let col = 0; col < this.matrix[row].length; col++) { value = cb(row, col, this.get(row, col)); if (!isNaN(value)) { this.set(row, col, value); } } } } /** * Validate that the specified row and column are within the required * ranges. Otherwise throw a MatrixError exception. * * @param row {Number} * The row to check. * @param col {Number} * The column to check. */ _validate(row, col) { if ((row >= this.getRows()) || (row < 0)) { throw new MatrixError("The row:" + row + " is out of range:" + this.getRows()); } if ((col >= this.getCols()) || (col < 0)) { throw new MatrixError("The col:" + col + " is out of range:" + this.getCols()); } } } module.exports = Matrix;