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 });