qr.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.createQr = void 0;
  7. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  8. var _factory = require("../../../utils/factory.js");
  9. var name = 'qr';
  10. var dependencies = ['typed', 'matrix', 'zeros', 'identity', 'isZero', 'equal', 'sign', 'sqrt', 'conj', 'unaryMinus', 'addScalar', 'divideScalar', 'multiplyScalar', 'subtract', 'complex'];
  11. var createQr = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
  12. var typed = _ref.typed,
  13. matrix = _ref.matrix,
  14. zeros = _ref.zeros,
  15. identity = _ref.identity,
  16. isZero = _ref.isZero,
  17. equal = _ref.equal,
  18. sign = _ref.sign,
  19. sqrt = _ref.sqrt,
  20. conj = _ref.conj,
  21. unaryMinus = _ref.unaryMinus,
  22. addScalar = _ref.addScalar,
  23. divideScalar = _ref.divideScalar,
  24. multiplyScalar = _ref.multiplyScalar,
  25. subtract = _ref.subtract,
  26. complex = _ref.complex;
  27. /**
  28. * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in
  29. * two matrices (`Q`, `R`) where `Q` is an
  30. * orthogonal matrix and `R` is an upper triangular matrix.
  31. *
  32. * Syntax:
  33. *
  34. * math.qr(A)
  35. *
  36. * Example:
  37. *
  38. * const m = [
  39. * [1, -1, 4],
  40. * [1, 4, -2],
  41. * [1, 4, 2],
  42. * [1, -1, 0]
  43. * ]
  44. * const result = math.qr(m)
  45. * // r = {
  46. * // Q: [
  47. * // [0.5, -0.5, 0.5],
  48. * // [0.5, 0.5, -0.5],
  49. * // [0.5, 0.5, 0.5],
  50. * // [0.5, -0.5, -0.5],
  51. * // ],
  52. * // R: [
  53. * // [2, 3, 2],
  54. * // [0, 5, -2],
  55. * // [0, 0, 4],
  56. * // [0, 0, 0]
  57. * // ]
  58. * // }
  59. *
  60. * See also:
  61. *
  62. * lup, lusolve
  63. *
  64. * @param {Matrix | Array} A A two dimensional matrix or array
  65. * for which to get the QR decomposition.
  66. *
  67. * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthogonal
  68. * matrix and R: the upper triangular matrix
  69. */
  70. return (0, _extends2["default"])(typed(name, {
  71. DenseMatrix: function DenseMatrix(m) {
  72. return _denseQR(m);
  73. },
  74. SparseMatrix: function SparseMatrix(m) {
  75. return _sparseQR(m);
  76. },
  77. Array: function Array(a) {
  78. // create dense matrix from array
  79. var m = matrix(a);
  80. // lup, use matrix implementation
  81. var r = _denseQR(m);
  82. // result
  83. return {
  84. Q: r.Q.valueOf(),
  85. R: r.R.valueOf()
  86. };
  87. }
  88. }), {
  89. _denseQRimpl: _denseQRimpl
  90. });
  91. function _denseQRimpl(m) {
  92. // rows & columns (m x n)
  93. var rows = m._size[0]; // m
  94. var cols = m._size[1]; // n
  95. var Q = identity([rows], 'dense');
  96. var Qdata = Q._data;
  97. var R = m.clone();
  98. var Rdata = R._data;
  99. // vars
  100. var i, j, k;
  101. var w = zeros([rows], '');
  102. for (k = 0; k < Math.min(cols, rows); ++k) {
  103. /*
  104. * **k-th Household matrix**
  105. *
  106. * The matrix I - 2*v*transpose(v)
  107. * x = first column of A
  108. * x1 = first element of x
  109. * alpha = x1 / |x1| * |x|
  110. * e1 = tranpose([1, 0, 0, ...])
  111. * u = x - alpha * e1
  112. * v = u / |u|
  113. *
  114. * Household matrix = I - 2 * v * tranpose(v)
  115. *
  116. * * Initially Q = I and R = A.
  117. * * Household matrix is a reflection in a plane normal to v which
  118. * will zero out all but the top right element in R.
  119. * * Appplying reflection to both Q and R will not change product.
  120. * * Repeat this process on the (1,1) minor to get R as an upper
  121. * triangular matrix.
  122. * * Reflections leave the magnitude of the columns of Q unchanged
  123. * so Q remains othoganal.
  124. *
  125. */
  126. var pivot = Rdata[k][k];
  127. var sgn = unaryMinus(equal(pivot, 0) ? 1 : sign(pivot));
  128. var conjSgn = conj(sgn);
  129. var alphaSquared = 0;
  130. for (i = k; i < rows; i++) {
  131. alphaSquared = addScalar(alphaSquared, multiplyScalar(Rdata[i][k], conj(Rdata[i][k])));
  132. }
  133. var alpha = multiplyScalar(sgn, sqrt(alphaSquared));
  134. if (!isZero(alpha)) {
  135. // first element in vector u
  136. var u1 = subtract(pivot, alpha);
  137. // w = v * u1 / |u| (only elements k to (rows-1) are used)
  138. w[k] = 1;
  139. for (i = k + 1; i < rows; i++) {
  140. w[i] = divideScalar(Rdata[i][k], u1);
  141. }
  142. // tau = - conj(u1 / alpha)
  143. var tau = unaryMinus(conj(divideScalar(u1, alpha)));
  144. var s = void 0;
  145. /*
  146. * tau and w have been choosen so that
  147. *
  148. * 2 * v * tranpose(v) = tau * w * tranpose(w)
  149. */
  150. /*
  151. * -- calculate R = R - tau * w * tranpose(w) * R --
  152. * Only do calculation with rows k to (rows-1)
  153. * Additionally columns 0 to (k-1) will not be changed by this
  154. * multiplication so do not bother recalculating them
  155. */
  156. for (j = k; j < cols; j++) {
  157. s = 0.0;
  158. // calculate jth element of [tranpose(w) * R]
  159. for (i = k; i < rows; i++) {
  160. s = addScalar(s, multiplyScalar(conj(w[i]), Rdata[i][j]));
  161. }
  162. // calculate the jth element of [tau * transpose(w) * R]
  163. s = multiplyScalar(s, tau);
  164. for (i = k; i < rows; i++) {
  165. Rdata[i][j] = multiplyScalar(subtract(Rdata[i][j], multiplyScalar(w[i], s)), conjSgn);
  166. }
  167. }
  168. /*
  169. * -- calculate Q = Q - tau * Q * w * transpose(w) --
  170. * Q is a square matrix (rows x rows)
  171. * Only do calculation with columns k to (rows-1)
  172. * Additionally rows 0 to (k-1) will not be changed by this
  173. * multiplication so do not bother recalculating them
  174. */
  175. for (i = 0; i < rows; i++) {
  176. s = 0.0;
  177. // calculate ith element of [Q * w]
  178. for (j = k; j < rows; j++) {
  179. s = addScalar(s, multiplyScalar(Qdata[i][j], w[j]));
  180. }
  181. // calculate the ith element of [tau * Q * w]
  182. s = multiplyScalar(s, tau);
  183. for (j = k; j < rows; ++j) {
  184. Qdata[i][j] = divideScalar(subtract(Qdata[i][j], multiplyScalar(s, conj(w[j]))), conjSgn);
  185. }
  186. }
  187. }
  188. }
  189. // return matrices
  190. return {
  191. Q: Q,
  192. R: R,
  193. toString: function toString() {
  194. return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString();
  195. }
  196. };
  197. }
  198. function _denseQR(m) {
  199. var ret = _denseQRimpl(m);
  200. var Rdata = ret.R._data;
  201. if (m._data.length > 0) {
  202. var zero = Rdata[0][0].type === 'Complex' ? complex(0) : 0;
  203. for (var i = 0; i < Rdata.length; ++i) {
  204. for (var j = 0; j < i && j < (Rdata[0] || []).length; ++j) {
  205. Rdata[i][j] = zero;
  206. }
  207. }
  208. }
  209. return ret;
  210. }
  211. function _sparseQR(m) {
  212. throw new Error('qr not implemented for sparse matrices yet');
  213. }
  214. });
  215. exports.createQr = createQr;