UNPKG

ml-matrix

Version:

Matrix manipulation and computation library

170 lines (149 loc) 4.46 kB
'use strict'; var Matrix = require('../matrix'); // https://github.com/lutzroeder/Mapack/blob/master/Source/LuDecomposition.cs function LuDecomposition(matrix) { if (!(this instanceof LuDecomposition)) { return new LuDecomposition(matrix); } matrix = Matrix.checkMatrix(matrix); var lu = matrix.clone(), rows = lu.rows, columns = lu.columns, pivotVector = new Array(rows), pivotSign = 1, i, j, k, p, s, t, v, LUrowi, LUcolj, kmax; for (i = 0; i < rows; i++) { pivotVector[i] = i; } LUcolj = new Array(rows); for (j = 0; j < columns; j++) { for (i = 0; i < rows; i++) { LUcolj[i] = lu[i][j]; } for (i = 0; i < rows; i++) { LUrowi = lu[i]; kmax = Math.min(i, j); s = 0; for (k = 0; k < kmax; k++) { s += LUrowi[k] * LUcolj[k]; } LUrowi[j] = LUcolj[i] -= s; } 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[p][k]; lu[p][k] = lu[j][k]; lu[j][k] = t; } v = pivotVector[p]; pivotVector[p] = pivotVector[j]; pivotVector[j] = v; pivotSign = -pivotSign; } if (j < rows && lu[j][j] !== 0) { for (i = j + 1; i < rows; i++) { lu[i][j] /= lu[j][j]; } } } this.LU = lu; this.pivotVector = pivotVector; this.pivotSign = pivotSign; } LuDecomposition.prototype = { isSingular: function () { var data = this.LU, col = data.columns; for (var j = 0; j < col; j++) { if (data[j][j] === 0) { return true; } } return false; }, get determinant() { var data = this.LU; if (!data.isSquare()) throw new Error('Matrix must be square'); var determinant = this.pivotSign, col = data.columns; for (var j = 0; j < col; j++) determinant *= data[j][j]; return determinant; }, get lowerTriangularMatrix() { var data = this.LU, rows = data.rows, columns = data.columns, X = new Matrix(rows, columns); for (var i = 0; i < rows; i++) { for (var j = 0; j < columns; j++) { if (i > j) { X[i][j] = data[i][j]; } else if (i === j) { X[i][j] = 1; } else { X[i][j] = 0; } } } return X; }, get upperTriangularMatrix() { var data = this.LU, rows = data.rows, columns = data.columns, X = new Matrix(rows, columns); for (var i = 0; i < rows; i++) { for (var j = 0; j < columns; j++) { if (i <= j) { X[i][j] = data[i][j]; } else { X[i][j] = 0; } } } return X; }, get pivotPermutationVector() { return this.pivotVector.slice(); }, solve: function (value) { value = Matrix.checkMatrix(value); var lu = this.LU, rows = lu.rows; if (rows !== value.rows) throw new Error('Invalid matrix dimensions'); if (this.isSingular()) throw new Error('LU matrix is singular'); var count = value.columns, X = value.subMatrixRow(this.pivotVector, 0, count - 1), columns = lu.columns, i, j, k; for (k = 0; k < columns; k++) { for (i = k + 1; i < columns; i++) { for (j = 0; j < count; j++) { X[i][j] -= X[k][j] * lu[i][k]; } } } for (k = columns - 1; k >= 0; k--) { for (j = 0; j < count; j++) { X[k][j] /= lu[k][k]; } for (i = 0; i < k; i++) { for (j = 0; j < count; j++) { X[i][j] -= X[k][j] * lu[i][k]; } } } return X; } }; module.exports = LuDecomposition;