123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- import _extends from "@babel/runtime/helpers/extends";
- import { factory } from '../../../utils/factory.js';
- var name = 'qr';
- var dependencies = ['typed', 'matrix', 'zeros', 'identity', 'isZero', 'equal', 'sign', 'sqrt', 'conj', 'unaryMinus', 'addScalar', 'divideScalar', 'multiplyScalar', 'subtract', 'complex'];
- export var createQr = /* #__PURE__ */factory(name, dependencies, _ref => {
- var {
- typed,
- matrix,
- zeros,
- identity,
- isZero,
- equal,
- sign,
- sqrt,
- conj,
- unaryMinus,
- addScalar,
- divideScalar,
- multiplyScalar,
- subtract,
- complex
- } = _ref;
- /**
- * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in
- * two matrices (`Q`, `R`) where `Q` is an
- * orthogonal matrix and `R` is an upper triangular matrix.
- *
- * Syntax:
- *
- * math.qr(A)
- *
- * Example:
- *
- * const m = [
- * [1, -1, 4],
- * [1, 4, -2],
- * [1, 4, 2],
- * [1, -1, 0]
- * ]
- * const result = math.qr(m)
- * // r = {
- * // Q: [
- * // [0.5, -0.5, 0.5],
- * // [0.5, 0.5, -0.5],
- * // [0.5, 0.5, 0.5],
- * // [0.5, -0.5, -0.5],
- * // ],
- * // R: [
- * // [2, 3, 2],
- * // [0, 5, -2],
- * // [0, 0, 4],
- * // [0, 0, 0]
- * // ]
- * // }
- *
- * See also:
- *
- * lup, lusolve
- *
- * @param {Matrix | Array} A A two dimensional matrix or array
- * for which to get the QR decomposition.
- *
- * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthogonal
- * matrix and R: the upper triangular matrix
- */
- return _extends(typed(name, {
- DenseMatrix: function DenseMatrix(m) {
- return _denseQR(m);
- },
- SparseMatrix: function SparseMatrix(m) {
- return _sparseQR(m);
- },
- Array: function Array(a) {
- // create dense matrix from array
- var m = matrix(a);
- // lup, use matrix implementation
- var r = _denseQR(m);
- // result
- return {
- Q: r.Q.valueOf(),
- R: r.R.valueOf()
- };
- }
- }), {
- _denseQRimpl
- });
- function _denseQRimpl(m) {
- // rows & columns (m x n)
- var rows = m._size[0]; // m
- var cols = m._size[1]; // n
- var Q = identity([rows], 'dense');
- var Qdata = Q._data;
- var R = m.clone();
- var Rdata = R._data;
- // vars
- var i, j, k;
- var w = zeros([rows], '');
- for (k = 0; k < Math.min(cols, rows); ++k) {
- /*
- * **k-th Household matrix**
- *
- * The matrix I - 2*v*transpose(v)
- * x = first column of A
- * x1 = first element of x
- * alpha = x1 / |x1| * |x|
- * e1 = tranpose([1, 0, 0, ...])
- * u = x - alpha * e1
- * v = u / |u|
- *
- * Household matrix = I - 2 * v * tranpose(v)
- *
- * * Initially Q = I and R = A.
- * * Household matrix is a reflection in a plane normal to v which
- * will zero out all but the top right element in R.
- * * Appplying reflection to both Q and R will not change product.
- * * Repeat this process on the (1,1) minor to get R as an upper
- * triangular matrix.
- * * Reflections leave the magnitude of the columns of Q unchanged
- * so Q remains othoganal.
- *
- */
- var pivot = Rdata[k][k];
- var sgn = unaryMinus(equal(pivot, 0) ? 1 : sign(pivot));
- var conjSgn = conj(sgn);
- var alphaSquared = 0;
- for (i = k; i < rows; i++) {
- alphaSquared = addScalar(alphaSquared, multiplyScalar(Rdata[i][k], conj(Rdata[i][k])));
- }
- var alpha = multiplyScalar(sgn, sqrt(alphaSquared));
- if (!isZero(alpha)) {
- // first element in vector u
- var u1 = subtract(pivot, alpha);
- // w = v * u1 / |u| (only elements k to (rows-1) are used)
- w[k] = 1;
- for (i = k + 1; i < rows; i++) {
- w[i] = divideScalar(Rdata[i][k], u1);
- }
- // tau = - conj(u1 / alpha)
- var tau = unaryMinus(conj(divideScalar(u1, alpha)));
- var s = void 0;
- /*
- * tau and w have been choosen so that
- *
- * 2 * v * tranpose(v) = tau * w * tranpose(w)
- */
- /*
- * -- calculate R = R - tau * w * tranpose(w) * R --
- * Only do calculation with rows k to (rows-1)
- * Additionally columns 0 to (k-1) will not be changed by this
- * multiplication so do not bother recalculating them
- */
- for (j = k; j < cols; j++) {
- s = 0.0;
- // calculate jth element of [tranpose(w) * R]
- for (i = k; i < rows; i++) {
- s = addScalar(s, multiplyScalar(conj(w[i]), Rdata[i][j]));
- }
- // calculate the jth element of [tau * transpose(w) * R]
- s = multiplyScalar(s, tau);
- for (i = k; i < rows; i++) {
- Rdata[i][j] = multiplyScalar(subtract(Rdata[i][j], multiplyScalar(w[i], s)), conjSgn);
- }
- }
- /*
- * -- calculate Q = Q - tau * Q * w * transpose(w) --
- * Q is a square matrix (rows x rows)
- * Only do calculation with columns k to (rows-1)
- * Additionally rows 0 to (k-1) will not be changed by this
- * multiplication so do not bother recalculating them
- */
- for (i = 0; i < rows; i++) {
- s = 0.0;
- // calculate ith element of [Q * w]
- for (j = k; j < rows; j++) {
- s = addScalar(s, multiplyScalar(Qdata[i][j], w[j]));
- }
- // calculate the ith element of [tau * Q * w]
- s = multiplyScalar(s, tau);
- for (j = k; j < rows; ++j) {
- Qdata[i][j] = divideScalar(subtract(Qdata[i][j], multiplyScalar(s, conj(w[j]))), conjSgn);
- }
- }
- }
- }
- // return matrices
- return {
- Q,
- R,
- toString: function toString() {
- return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString();
- }
- };
- }
- function _denseQR(m) {
- var ret = _denseQRimpl(m);
- var Rdata = ret.R._data;
- if (m._data.length > 0) {
- var zero = Rdata[0][0].type === 'Complex' ? complex(0) : 0;
- for (var i = 0; i < Rdata.length; ++i) {
- for (var j = 0; j < i && j < (Rdata[0] || []).length; ++j) {
- Rdata[i][j] = zero;
- }
- }
- }
- return ret;
- }
- function _sparseQR(m) {
- throw new Error('qr not implemented for sparse matrices yet');
- }
- });
|