UNPKG

mathjs

Version:

Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with dif

184 lines (172 loc) 5.14 kB
'use strict' function factory (type, config, load, typed) { const matrix = load(require('../../../type/matrix/function/matrix')) const divideScalar = load(require('../../arithmetic/divideScalar')) const multiplyScalar = load(require('../../arithmetic/multiplyScalar')) const subtract = load(require('../../arithmetic/subtract')) const equalScalar = load(require('../../relational/equalScalar')) const solveValidation = load(require('./utils/solveValidation')) const DenseMatrix = type.DenseMatrix /** * Solves the linear equation system by forwards substitution. Matrix must be a lower triangular matrix. * * `L * x = b` * * Syntax: * * math.lsolve(L, b) * * Examples: * * const a = [[-2, 3], [2, 1]] * const b = [11, 9] * const x = lsolve(a, b) // [[-5.5], [20]] * * See also: * * lup, slu, usolve, lusolve * * @param {Matrix, Array} L A N x N matrix or array (L) * @param {Matrix, Array} b A column vector with the b values * * @return {DenseMatrix | Array} A column vector with the linear system solution (x) */ const lsolve = typed('lsolve', { 'SparseMatrix, Array | Matrix': function (m, b) { // process matrix return _sparseForwardSubstitution(m, b) }, 'DenseMatrix, Array | Matrix': function (m, b) { // process matrix return _denseForwardSubstitution(m, b) }, 'Array, Array | Matrix': function (a, b) { // create dense matrix from array const m = matrix(a) // use matrix implementation const r = _denseForwardSubstitution(m, b) // result return r.valueOf() } }) function _denseForwardSubstitution (m, b) { // validate matrix and vector, return copy of column vector b b = solveValidation(m, b, true) // column vector data const bdata = b._data // rows & columns const rows = m._size[0] const columns = m._size[1] // result const x = [] // data const data = m._data // forward solve m * x = b, loop columns for (let j = 0; j < columns; j++) { // b[j] const bj = bdata[j][0] || 0 // x[j] let xj // forward substitution (outer product) avoids inner looping when bj === 0 if (!equalScalar(bj, 0)) { // value @ [j, j] const vjj = data[j][j] // check vjj if (equalScalar(vjj, 0)) { // system cannot be solved throw new Error('Linear system cannot be solved since matrix is singular') } // calculate xj xj = divideScalar(bj, vjj) // loop rows for (let i = j + 1; i < rows; i++) { // update copy of b bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar(xj, data[i][j]))] } } else { // zero @ j xj = 0 } // update x x[j] = [xj] } // return vector return new DenseMatrix({ data: x, size: [rows, 1] }) } function _sparseForwardSubstitution (m, b) { // validate matrix and vector, return copy of column vector b b = solveValidation(m, b, true) // column vector data const bdata = b._data // rows & columns const rows = m._size[0] const columns = m._size[1] // matrix arrays const values = m._values const index = m._index const ptr = m._ptr // vars let i, k // result const x = [] // forward solve m * x = b, loop columns for (let j = 0; j < columns; j++) { // b[j] const bj = bdata[j][0] || 0 // forward substitution (outer product) avoids inner looping when bj === 0 if (!equalScalar(bj, 0)) { // value @ [j, j] let vjj = 0 // lower triangular matrix values & index (column j) const jvalues = [] const jindex = [] // last index in column let l = ptr[j + 1] // values in column, find value @ [j, j] for (k = ptr[j]; k < l; k++) { // row i = index[k] // check row (rows are not sorted!) if (i === j) { // update vjj vjj = values[k] } else if (i > j) { // store lower triangular jvalues.push(values[k]) jindex.push(i) } } // at this point we must have a value @ [j, j] if (equalScalar(vjj, 0)) { // system cannot be solved, there is no value @ [j, j] throw new Error('Linear system cannot be solved since matrix is singular') } // calculate xj const xj = divideScalar(bj, vjj) // loop lower triangular for (k = 0, l = jindex.length; k < l; k++) { // row i = jindex[k] // update copy of b bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar(xj, jvalues[k]))] } // update x x[j] = [xj] } else { // update x x[j] = [0] } } // return vector return new DenseMatrix({ data: x, size: [rows, 1] }) } return lsolve } exports.name = 'lsolve' exports.factory = factory