csSqr.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import { csPermute } from './csPermute.js';
  2. import { csPost } from './csPost.js';
  3. import { csEtree } from './csEtree.js';
  4. import { createCsAmd } from './csAmd.js';
  5. import { createCsCounts } from './csCounts.js';
  6. import { factory } from '../../../utils/factory.js';
  7. var name = 'csSqr';
  8. var dependencies = ['add', 'multiply', 'transpose'];
  9. export var createCsSqr = /* #__PURE__ */factory(name, dependencies, _ref => {
  10. var {
  11. add,
  12. multiply,
  13. transpose
  14. } = _ref;
  15. var csAmd = createCsAmd({
  16. add,
  17. multiply,
  18. transpose
  19. });
  20. var csCounts = createCsCounts({
  21. transpose
  22. });
  23. /**
  24. * Symbolic ordering and analysis for QR and LU decompositions.
  25. *
  26. * @param {Number} order The ordering strategy (see csAmd for more details)
  27. * @param {Matrix} a The A matrix
  28. * @param {boolean} qr Symbolic ordering and analysis for QR decomposition (true) or
  29. * symbolic ordering and analysis for LU decomposition (false)
  30. *
  31. * @return {Object} The Symbolic ordering and analysis for matrix A
  32. *
  33. * Reference: http://faculty.cse.tamu.edu/davis/publications.html
  34. */
  35. return function csSqr(order, a, qr) {
  36. // a arrays
  37. var aptr = a._ptr;
  38. var asize = a._size;
  39. // columns
  40. var n = asize[1];
  41. // vars
  42. var k;
  43. // symbolic analysis result
  44. var s = {};
  45. // fill-reducing ordering
  46. s.q = csAmd(order, a);
  47. // validate results
  48. if (order && !s.q) {
  49. return null;
  50. }
  51. // QR symbolic analysis
  52. if (qr) {
  53. // apply permutations if needed
  54. var c = order ? csPermute(a, null, s.q, 0) : a;
  55. // etree of C'*C, where C=A(:,q)
  56. s.parent = csEtree(c, 1);
  57. // post order elimination tree
  58. var post = csPost(s.parent, n);
  59. // col counts chol(C'*C)
  60. s.cp = csCounts(c, s.parent, post, 1);
  61. // check we have everything needed to calculate number of nonzero elements
  62. if (c && s.parent && s.cp && _vcount(c, s)) {
  63. // calculate number of nonzero elements
  64. for (s.unz = 0, k = 0; k < n; k++) {
  65. s.unz += s.cp[k];
  66. }
  67. }
  68. } else {
  69. // for LU factorization only, guess nnz(L) and nnz(U)
  70. s.unz = 4 * aptr[n] + n;
  71. s.lnz = s.unz;
  72. }
  73. // return result S
  74. return s;
  75. };
  76. /**
  77. * Compute nnz(V) = s.lnz, s.pinv, s.leftmost, s.m2 from A and s.parent
  78. */
  79. function _vcount(a, s) {
  80. // a arrays
  81. var aptr = a._ptr;
  82. var aindex = a._index;
  83. var asize = a._size;
  84. // rows & columns
  85. var m = asize[0];
  86. var n = asize[1];
  87. // initialize s arrays
  88. s.pinv = []; // (m + n)
  89. s.leftmost = []; // (m)
  90. // vars
  91. var parent = s.parent;
  92. var pinv = s.pinv;
  93. var leftmost = s.leftmost;
  94. // workspace, next: first m entries, head: next n entries, tail: next n entries, nque: next n entries
  95. var w = []; // (m + 3 * n)
  96. var next = 0;
  97. var head = m;
  98. var tail = m + n;
  99. var nque = m + 2 * n;
  100. // vars
  101. var i, k, p, p0, p1;
  102. // initialize w
  103. for (k = 0; k < n; k++) {
  104. // queue k is empty
  105. w[head + k] = -1;
  106. w[tail + k] = -1;
  107. w[nque + k] = 0;
  108. }
  109. // initialize row arrays
  110. for (i = 0; i < m; i++) {
  111. leftmost[i] = -1;
  112. }
  113. // loop columns backwards
  114. for (k = n - 1; k >= 0; k--) {
  115. // values & index for column k
  116. for (p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) {
  117. // leftmost[i] = min(find(A(i,:)))
  118. leftmost[aindex[p]] = k;
  119. }
  120. }
  121. // scan rows in reverse order
  122. for (i = m - 1; i >= 0; i--) {
  123. // row i is not yet ordered
  124. pinv[i] = -1;
  125. k = leftmost[i];
  126. // check row i is empty
  127. if (k === -1) {
  128. continue;
  129. }
  130. // first row in queue k
  131. if (w[nque + k]++ === 0) {
  132. w[tail + k] = i;
  133. }
  134. // put i at head of queue k
  135. w[next + i] = w[head + k];
  136. w[head + k] = i;
  137. }
  138. s.lnz = 0;
  139. s.m2 = m;
  140. // find row permutation and nnz(V)
  141. for (k = 0; k < n; k++) {
  142. // remove row i from queue k
  143. i = w[head + k];
  144. // count V(k,k) as nonzero
  145. s.lnz++;
  146. // add a fictitious row
  147. if (i < 0) {
  148. i = s.m2++;
  149. }
  150. // associate row i with V(:,k)
  151. pinv[i] = k;
  152. // skip if V(k+1:m,k) is empty
  153. if (--nque[k] <= 0) {
  154. continue;
  155. }
  156. // nque[k] is nnz (V(k+1:m,k))
  157. s.lnz += w[nque + k];
  158. // move all rows to parent of k
  159. var pa = parent[k];
  160. if (pa !== -1) {
  161. if (w[nque + pa] === 0) {
  162. w[tail + pa] = w[tail + k];
  163. }
  164. w[next + w[tail + k]] = w[head + pa];
  165. w[head + pa] = w[next + i];
  166. w[nque + pa] += w[nque + k];
  167. }
  168. }
  169. for (i = 0; i < m; i++) {
  170. if (pinv[i] < 0) {
  171. pinv[i] = k++;
  172. }
  173. }
  174. return true;
  175. }
  176. });