ml-matrix
Version:
Matrix manipulation and computation library
172 lines (149 loc) • 3.89 kB
JavaScript
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);
}
}