UNPKG

ml-matrix

Version:

Matrix manipulation and computation library

151 lines (135 loc) 4 kB
'use strict'; var Matrix = require('../matrix'); var hypotenuse = require('./util').hypotenuse; //https://github.com/lutzroeder/Mapack/blob/master/Source/QrDecomposition.cs function QrDecomposition(value) { if (!(this instanceof QrDecomposition)) { return new QrDecomposition(value); } value = Matrix.checkMatrix(value); var qr = value.clone(), m = value.rows, n = value.columns, rdiag = new Array(n), i, j, k, s; for (k = 0; k < n; k++) { var nrm = 0; for (i = k; i < m; i++) { nrm = hypotenuse(nrm, qr[i][k]); } if (nrm !== 0) { if (qr[k][k] < 0) { nrm = -nrm; } for (i = k; i < m; i++) { qr[i][k] /= nrm; } qr[k][k] += 1; for (j = k + 1; j < n; j++) { s = 0; for (i = k; i < m; i++) { s += qr[i][k] * qr[i][j]; } s = -s / qr[k][k]; for (i = k; i < m; i++) { qr[i][j] += s * qr[i][k]; } } } rdiag[k] = -nrm; } this.QR = qr; this.Rdiag = rdiag; } QrDecomposition.prototype = { solve: function (value) { value = Matrix.checkMatrix(value); var qr = this.QR, m = qr.rows; if (value.rows !== m) throw new Error('Matrix row dimensions must agree'); if (!this.isFullRank()) throw new Error('Matrix is rank deficient'); var count = value.columns, X = value.clone(), n = qr.columns, i, j, k, s; for (k = 0; k < n; k++) { for (j = 0; j < count; j++) { s = 0; for (i = k; i < m; i++) { s += qr[i][k] * X[i][j]; } s = -s / qr[k][k]; for (i = k; i < m; i++) { X[i][j] += s * qr[i][k]; } } } for (k = n - 1; k >= 0; k--) { for (j = 0; j < count; j++) { X[k][j] /= this.Rdiag[k]; } for (i = 0; i < k; i++) { for (j = 0; j < count; j++) { X[i][j] -= X[k][j] * qr[i][k]; } } } return X.subMatrix(0, n - 1, 0, count - 1); }, isFullRank: function () { var columns = this.QR.columns; for (var i = 0; i < columns; i++) { if (this.Rdiag[i] === 0) { return false; } } return true; }, get upperTriangularMatrix() { var qr = this.QR, n = qr.columns, X = new Matrix(n, n), i, j; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { if (i < j) { X[i][j] = qr[i][j]; } else if (i === j) { X[i][j] = this.Rdiag[i]; } else { X[i][j] = 0; } } } return X; }, get orthogonalMatrix() { var qr = this.QR, rows = qr.rows, columns = qr.columns, X = new Matrix(rows, columns), i, j, k, s; for (k = columns - 1; k >= 0; k--) { for (i = 0; i < rows; i++) { X[i][k] = 0; } X[k][k] = 1; for (j = k; j < columns; j++) { if (qr[k][k] !== 0) { s = 0; for (i = k; i < rows; i++) { s += qr[i][k] * X[i][j]; } s = -s / qr[k][k]; for (i = k; i < rows; i++) { X[i][j] += s * qr[i][k]; } } } } return X; } }; module.exports = QrDecomposition;