simple-squiggle

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

lsolveAll.js (5312B)


      1 import { factory } from '../../../utils/factory.js';
      2 import { createSolveValidation } from './utils/solveValidation.js';
      3 var name = 'lsolveAll';
      4 var dependencies = ['typed', 'matrix', 'divideScalar', 'multiplyScalar', 'subtract', 'equalScalar', 'DenseMatrix'];
      5 export var createLsolveAll = /* #__PURE__ */factory(name, dependencies, _ref => {
      6   var {
      7     typed,
      8     matrix,
      9     divideScalar,
     10     multiplyScalar,
     11     subtract,
     12     equalScalar,
     13     DenseMatrix
     14   } = _ref;
     15   var solveValidation = createSolveValidation({
     16     DenseMatrix
     17   });
     18   /**
     19    * Finds all solutions of a linear equation system by forwards substitution. Matrix must be a lower triangular matrix.
     20    *
     21    * `L * x = b`
     22    *
     23    * Syntax:
     24    *
     25    *    math.lsolveAll(L, b)
     26    *
     27    * Examples:
     28    *
     29    *    const a = [[-2, 3], [2, 1]]
     30    *    const b = [11, 9]
     31    *    const x = lsolveAll(a, b)  // [ [[-5.5], [20]] ]
     32    *
     33    * See also:
     34    *
     35    *    lsolve, lup, slu, usolve, lusolve
     36    *
     37    * @param {Matrix, Array} L       A N x N matrix or array (L)
     38    * @param {Matrix, Array} b       A column vector with the b values
     39    *
     40    * @return {DenseMatrix[] | Array[]}  An array of affine-independent column vectors (x) that solve the linear system
     41    */
     42 
     43   return typed(name, {
     44     'SparseMatrix, Array | Matrix': function SparseMatrixArrayMatrix(m, b) {
     45       return _sparseForwardSubstitution(m, b);
     46     },
     47     'DenseMatrix, Array | Matrix': function DenseMatrixArrayMatrix(m, b) {
     48       return _denseForwardSubstitution(m, b);
     49     },
     50     'Array, Array | Matrix': function ArrayArrayMatrix(a, b) {
     51       var m = matrix(a);
     52 
     53       var R = _denseForwardSubstitution(m, b);
     54 
     55       return R.map(r => r.valueOf());
     56     }
     57   });
     58 
     59   function _denseForwardSubstitution(m, b_) {
     60     // the algorithm is derived from
     61     // https://www.overleaf.com/read/csvgqdxggyjv
     62     // array of right-hand sides
     63     var B = [solveValidation(m, b_, true)._data.map(e => e[0])];
     64     var M = m._data;
     65     var rows = m._size[0];
     66     var columns = m._size[1]; // loop columns
     67 
     68     for (var i = 0; i < columns; i++) {
     69       var L = B.length; // loop right-hand sides
     70 
     71       for (var k = 0; k < L; k++) {
     72         var b = B[k];
     73 
     74         if (!equalScalar(M[i][i], 0)) {
     75           // non-singular row
     76           b[i] = divideScalar(b[i], M[i][i]);
     77 
     78           for (var j = i + 1; j < columns; j++) {
     79             // b[j] -= b[i] * M[j,i]
     80             b[j] = subtract(b[j], multiplyScalar(b[i], M[j][i]));
     81           }
     82         } else if (!equalScalar(b[i], 0)) {
     83           // singular row, nonzero RHS
     84           if (k === 0) {
     85             // There is no valid solution
     86             return [];
     87           } else {
     88             // This RHS is invalid but other solutions may still exist
     89             B.splice(k, 1);
     90             k -= 1;
     91             L -= 1;
     92           }
     93         } else if (k === 0) {
     94           // singular row, RHS is zero
     95           var bNew = [...b];
     96           bNew[i] = 1;
     97 
     98           for (var _j = i + 1; _j < columns; _j++) {
     99             bNew[_j] = subtract(bNew[_j], M[_j][i]);
    100           }
    101 
    102           B.push(bNew);
    103         }
    104       }
    105     }
    106 
    107     return B.map(x => new DenseMatrix({
    108       data: x.map(e => [e]),
    109       size: [rows, 1]
    110     }));
    111   }
    112 
    113   function _sparseForwardSubstitution(m, b_) {
    114     // array of right-hand sides
    115     var B = [solveValidation(m, b_, true)._data.map(e => e[0])];
    116     var rows = m._size[0];
    117     var columns = m._size[1];
    118     var values = m._values;
    119     var index = m._index;
    120     var ptr = m._ptr; // loop columns
    121 
    122     for (var i = 0; i < columns; i++) {
    123       var L = B.length; // loop right-hand sides
    124 
    125       for (var k = 0; k < L; k++) {
    126         var b = B[k]; // values & indices (column i)
    127 
    128         var iValues = [];
    129         var iIndices = []; // first & last indeces in column
    130 
    131         var firstIndex = ptr[i];
    132         var lastIndex = ptr[i + 1]; // find the value at [i, i]
    133 
    134         var Mii = 0;
    135 
    136         for (var j = firstIndex; j < lastIndex; j++) {
    137           var J = index[j]; // check row
    138 
    139           if (J === i) {
    140             Mii = values[j];
    141           } else if (J > i) {
    142             // store lower triangular
    143             iValues.push(values[j]);
    144             iIndices.push(J);
    145           }
    146         }
    147 
    148         if (!equalScalar(Mii, 0)) {
    149           // non-singular row
    150           b[i] = divideScalar(b[i], Mii);
    151 
    152           for (var _j2 = 0, _lastIndex = iIndices.length; _j2 < _lastIndex; _j2++) {
    153             var _J = iIndices[_j2];
    154             b[_J] = subtract(b[_J], multiplyScalar(b[i], iValues[_j2]));
    155           }
    156         } else if (!equalScalar(b[i], 0)) {
    157           // singular row, nonzero RHS
    158           if (k === 0) {
    159             // There is no valid solution
    160             return [];
    161           } else {
    162             // This RHS is invalid but other solutions may still exist
    163             B.splice(k, 1);
    164             k -= 1;
    165             L -= 1;
    166           }
    167         } else if (k === 0) {
    168           // singular row, RHS is zero
    169           var bNew = [...b];
    170           bNew[i] = 1;
    171 
    172           for (var _j3 = 0, _lastIndex2 = iIndices.length; _j3 < _lastIndex2; _j3++) {
    173             var _J2 = iIndices[_j3];
    174             bNew[_J2] = subtract(bNew[_J2], iValues[_j3]);
    175           }
    176 
    177           B.push(bNew);
    178         }
    179       }
    180     }
    181 
    182     return B.map(x => new DenseMatrix({
    183       data: x.map(e => [e]),
    184       size: [rows, 1]
    185     }));
    186   }
    187 });