UNPKG

ml-matrix

Version:

Matrix manipulation and computation library

172 lines (149 loc) 3.89 kB
import Matrix from '../matrix'; import WrapperMatrix2D from '../wrap/WrapperMatrix2D'; export default class LuDecomposition { constructor(matrix) { matrix = WrapperMatrix2D.checkMatrix(matrix); let lu = matrix.clone(); let rows = lu.rows; let columns = lu.columns; let pivotVector = new Float64Array(rows); let pivotSign = 1; let i, j, k, p, s, t, v; let LUcolj, kmax; for (i = 0; i < rows; i++) { pivotVector[i] = i; } LUcolj = new Float64Array(rows); for (j = 0; j < columns; j++) { for (i = 0; i < rows; i++) { LUcolj[i] = lu.get(i, j); } for (i = 0; i < rows; i++) { kmax = Math.min(i, j); s = 0; for (k = 0; k < kmax; k++) { s += lu.get(i, k) * LUcolj[k]; } LUcolj[i] -= s; lu.set(i, j, LUcolj[i]); } p = j; for (i = j + 1; i < rows; i++) { if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) { p = i; } } if (p !== j) { for (k = 0; k < columns; k++) { t = lu.get(p, k); lu.set(p, k, lu.get(j, k)); lu.set(j, k, t); } v = pivotVector[p]; pivotVector[p] = pivotVector[j]; pivotVector[j] = v; pivotSign = -pivotSign; } if (j < rows && lu.get(j, j) !== 0) { for (i = j + 1; i < rows; i++) { lu.set(i, j, lu.get(i, j) / lu.get(j, j)); } } } this.LU = lu; this.pivotVector = pivotVector; this.pivotSign = pivotSign; } isSingular() { let data = this.LU; let col = data.columns; for (let j = 0; j < col; j++) { if (data.get(j, j) === 0) { return true; } } return false; } solve(value) { value = Matrix.checkMatrix(value); let lu = this.LU; let rows = lu.rows; if (rows !== value.rows) { throw new Error('Invalid matrix dimensions'); } if (this.isSingular()) { throw new Error('LU matrix is singular'); } let count = value.columns; let X = value.subMatrixRow(this.pivotVector, 0, count - 1); let columns = lu.columns; let i, j, k; for (k = 0; k < columns; k++) { for (i = k + 1; i < columns; i++) { for (j = 0; j < count; j++) { X.set(i, j, X.get(i, j) - X.get(k, j) * lu.get(i, k)); } } } for (k = columns - 1; k >= 0; k--) { for (j = 0; j < count; j++) { X.set(k, j, X.get(k, j) / lu.get(k, k)); } for (i = 0; i < k; i++) { for (j = 0; j < count; j++) { X.set(i, j, X.get(i, j) - X.get(k, j) * lu.get(i, k)); } } } return X; } get determinant() { let data = this.LU; if (!data.isSquare()) { throw new Error('Matrix must be square'); } let determinant = this.pivotSign; let col = data.columns; for (let j = 0; j < col; j++) { determinant *= data.get(j, j); } return determinant; } get lowerTriangularMatrix() { let data = this.LU; let rows = data.rows; let columns = data.columns; let X = new Matrix(rows, columns); for (let i = 0; i < rows; i++) { for (let j = 0; j < columns; j++) { if (i > j) { X.set(i, j, data.get(i, j)); } else if (i === j) { X.set(i, j, 1); } else { X.set(i, j, 0); } } } return X; } get upperTriangularMatrix() { let data = this.LU; let rows = data.rows; let columns = data.columns; let X = new Matrix(rows, columns); for (let i = 0; i < rows; i++) { for (let j = 0; j < columns; j++) { if (i <= j) { X.set(i, j, data.get(i, j)); } else { X.set(i, j, 0); } } } return X; } get pivotPermutationVector() { return Array.from(this.pivotVector); } }