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;