simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

csLu.js (5259B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createCsLu = void 0;
      7 
      8 var _factory = require("../../../utils/factory.js");
      9 
     10 var _csSpsolve = require("./csSpsolve.js");
     11 
     12 var name = 'csLu';
     13 var dependencies = ['abs', 'divideScalar', 'multiply', 'subtract', 'larger', 'largerEq', 'SparseMatrix'];
     14 var createCsLu = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     15   var abs = _ref.abs,
     16       divideScalar = _ref.divideScalar,
     17       multiply = _ref.multiply,
     18       subtract = _ref.subtract,
     19       larger = _ref.larger,
     20       largerEq = _ref.largerEq,
     21       SparseMatrix = _ref.SparseMatrix;
     22   var csSpsolve = (0, _csSpsolve.createCsSpsolve)({
     23     divideScalar: divideScalar,
     24     multiply: multiply,
     25     subtract: subtract
     26   });
     27   /**
     28    * Computes the numeric LU factorization of the sparse matrix A. Implements a Left-looking LU factorization
     29    * algorithm that computes L and U one column at a tume. At the kth step, it access columns 1 to k-1 of L
     30    * and column k of A. Given the fill-reducing column ordering q (see parameter s) computes L, U and pinv so
     31    * L * U = A(p, q), where p is the inverse of pinv.
     32    *
     33    * @param {Matrix}  m               The A Matrix to factorize
     34    * @param {Object}  s               The symbolic analysis from csSqr(). Provides the fill-reducing
     35    *                                  column ordering q
     36    * @param {Number}  tol             Partial pivoting threshold (1 for partial pivoting)
     37    *
     38    * @return {Number}                 The numeric LU factorization of A or null
     39    *
     40    * Reference: http://faculty.cse.tamu.edu/davis/publications.html
     41    */
     42 
     43   return function csLu(m, s, tol) {
     44     // validate input
     45     if (!m) {
     46       return null;
     47     } // m arrays
     48 
     49 
     50     var size = m._size; // columns
     51 
     52     var n = size[1]; // symbolic analysis result
     53 
     54     var q;
     55     var lnz = 100;
     56     var unz = 100; // update symbolic analysis parameters
     57 
     58     if (s) {
     59       q = s.q;
     60       lnz = s.lnz || lnz;
     61       unz = s.unz || unz;
     62     } // L arrays
     63 
     64 
     65     var lvalues = []; // (lnz)
     66 
     67     var lindex = []; // (lnz)
     68 
     69     var lptr = []; // (n + 1)
     70     // L
     71 
     72     var L = new SparseMatrix({
     73       values: lvalues,
     74       index: lindex,
     75       ptr: lptr,
     76       size: [n, n]
     77     }); // U arrays
     78 
     79     var uvalues = []; // (unz)
     80 
     81     var uindex = []; // (unz)
     82 
     83     var uptr = []; // (n + 1)
     84     // U
     85 
     86     var U = new SparseMatrix({
     87       values: uvalues,
     88       index: uindex,
     89       ptr: uptr,
     90       size: [n, n]
     91     }); // inverse of permutation vector
     92 
     93     var pinv = []; // (n)
     94     // vars
     95 
     96     var i, p; // allocate arrays
     97 
     98     var x = []; // (n)
     99 
    100     var xi = []; // (2 * n)
    101     // initialize variables
    102 
    103     for (i = 0; i < n; i++) {
    104       // clear workspace
    105       x[i] = 0; // no rows pivotal yet
    106 
    107       pinv[i] = -1; // no cols of L yet
    108 
    109       lptr[i + 1] = 0;
    110     } // reset number of nonzero elements in L and U
    111 
    112 
    113     lnz = 0;
    114     unz = 0; // compute L(:,k) and U(:,k)
    115 
    116     for (var k = 0; k < n; k++) {
    117       // update ptr
    118       lptr[k] = lnz;
    119       uptr[k] = unz; // apply column permutations if needed
    120 
    121       var col = q ? q[k] : k; // solve triangular system, x = L\A(:,col)
    122 
    123       var top = csSpsolve(L, m, col, xi, x, pinv, 1); // find pivot
    124 
    125       var ipiv = -1;
    126       var a = -1; // loop xi[] from top -> n
    127 
    128       for (p = top; p < n; p++) {
    129         // x[i] is nonzero
    130         i = xi[p]; // check row i is not yet pivotal
    131 
    132         if (pinv[i] < 0) {
    133           // absolute value of x[i]
    134           var xabs = abs(x[i]); // check absoulte value is greater than pivot value
    135 
    136           if (larger(xabs, a)) {
    137             // largest pivot candidate so far
    138             a = xabs;
    139             ipiv = i;
    140           }
    141         } else {
    142           // x(i) is the entry U(pinv[i],k)
    143           uindex[unz] = pinv[i];
    144           uvalues[unz++] = x[i];
    145         }
    146       } // validate we found a valid pivot
    147 
    148 
    149       if (ipiv === -1 || a <= 0) {
    150         return null;
    151       } // update actual pivot column, give preference to diagonal value
    152 
    153 
    154       if (pinv[col] < 0 && largerEq(abs(x[col]), multiply(a, tol))) {
    155         ipiv = col;
    156       } // the chosen pivot
    157 
    158 
    159       var pivot = x[ipiv]; // last entry in U(:,k) is U(k,k)
    160 
    161       uindex[unz] = k;
    162       uvalues[unz++] = pivot; // ipiv is the kth pivot row
    163 
    164       pinv[ipiv] = k; // first entry in L(:,k) is L(k,k) = 1
    165 
    166       lindex[lnz] = ipiv;
    167       lvalues[lnz++] = 1; // L(k+1:n,k) = x / pivot
    168 
    169       for (p = top; p < n; p++) {
    170         // row
    171         i = xi[p]; // check x(i) is an entry in L(:,k)
    172 
    173         if (pinv[i] < 0) {
    174           // save unpermuted row in L
    175           lindex[lnz] = i; // scale pivot column
    176 
    177           lvalues[lnz++] = divideScalar(x[i], pivot);
    178         } // x[0..n-1] = 0 for next k
    179 
    180 
    181         x[i] = 0;
    182       }
    183     } // update ptr
    184 
    185 
    186     lptr[n] = lnz;
    187     uptr[n] = unz; // fix row indices of L for final pinv
    188 
    189     for (p = 0; p < lnz; p++) {
    190       lindex[p] = pinv[lindex[p]];
    191     } // trim arrays
    192 
    193 
    194     lvalues.splice(lnz, lvalues.length - lnz);
    195     lindex.splice(lnz, lindex.length - lnz);
    196     uvalues.splice(unz, uvalues.length - unz);
    197     uindex.splice(unz, uindex.length - unz); // return LU factor
    198 
    199     return {
    200       L: L,
    201       U: U,
    202       pinv: pinv
    203     };
    204   };
    205 });
    206 exports.createCsLu = createCsLu;