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