You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

149 lines
3.3 KiB

import Matrix from '../matrix';
import WrapperMatrix2D from '../wrap/WrapperMatrix2D';
import { hypotenuse } from './util';
export default class QrDecomposition {
constructor(value) {
value = WrapperMatrix2D.checkMatrix(value);
let qr = value.clone();
let m = value.rows;
let n = value.columns;
let rdiag = new Float64Array(n);
let i, j, k, s;
for (k = 0; k < n; k++) {
let nrm = 0;
for (i = k; i < m; i++) {
nrm = hypotenuse(nrm, qr.get(i, k));
}
if (nrm !== 0) {
if (qr.get(k, k) < 0) {
nrm = -nrm;
}
for (i = k; i < m; i++) {
qr.set(i, k, qr.get(i, k) / nrm);
}
qr.set(k, k, qr.get(k, k) + 1);
for (j = k + 1; j < n; j++) {
s = 0;
for (i = k; i < m; i++) {
s += qr.get(i, k) * qr.get(i, j);
}
s = -s / qr.get(k, k);
for (i = k; i < m; i++) {
qr.set(i, j, qr.get(i, j) + s * qr.get(i, k));
}
}
}
rdiag[k] = -nrm;
}
this.QR = qr;
this.Rdiag = rdiag;
}
solve(value) {
value = Matrix.checkMatrix(value);
let qr = this.QR;
let 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');
}
let count = value.columns;
let X = value.clone();
let n = qr.columns;
let 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.get(i, k) * X.get(i, j);
}
s = -s / qr.get(k, k);
for (i = k; i < m; i++) {
X.set(i, j, X.get(i, j) + s * qr.get(i, k));
}
}
}
for (k = n - 1; k >= 0; k--) {
for (j = 0; j < count; j++) {
X.set(k, j, X.get(k, j) / this.Rdiag[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) * qr.get(i, k));
}
}
}
return X.subMatrix(0, n - 1, 0, count - 1);
}
isFullRank() {
let columns = this.QR.columns;
for (let i = 0; i < columns; i++) {
if (this.Rdiag[i] === 0) {
return false;
}
}
return true;
}
get upperTriangularMatrix() {
let qr = this.QR;
let n = qr.columns;
let X = new Matrix(n, n);
let i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (i < j) {
X.set(i, j, qr.get(i, j));
} else if (i === j) {
X.set(i, j, this.Rdiag[i]);
} else {
X.set(i, j, 0);
}
}
}
return X;
}
get orthogonalMatrix() {
let qr = this.QR;
let rows = qr.rows;
let columns = qr.columns;
let X = new Matrix(rows, columns);
let i, j, k, s;
for (k = columns - 1; k >= 0; k--) {
for (i = 0; i < rows; i++) {
X.set(i, k, 0);
}
X.set(k, k, 1);
for (j = k; j < columns; j++) {
if (qr.get(k, k) !== 0) {
s = 0;
for (i = k; i < rows; i++) {
s += qr.get(i, k) * X.get(i, j);
}
s = -s / qr.get(k, k);
for (i = k; i < rows; i++) {
X.set(i, j, X.get(i, j) + s * qr.get(i, k));
}
}
}
}
return X;
}
}