simple-squiggle

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

csLu.js (4947B)


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