simple-squiggle

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

inv.js (6132B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createInv = void 0;
      7 
      8 var _is = require("../../utils/is.js");
      9 
     10 var _array = require("../../utils/array.js");
     11 
     12 var _factory = require("../../utils/factory.js");
     13 
     14 var _string = require("../../utils/string.js");
     15 
     16 var name = 'inv';
     17 var dependencies = ['typed', 'matrix', 'divideScalar', 'addScalar', 'multiply', 'unaryMinus', 'det', 'identity', 'abs'];
     18 var createInv = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     19   var typed = _ref.typed,
     20       matrix = _ref.matrix,
     21       divideScalar = _ref.divideScalar,
     22       addScalar = _ref.addScalar,
     23       multiply = _ref.multiply,
     24       unaryMinus = _ref.unaryMinus,
     25       det = _ref.det,
     26       identity = _ref.identity,
     27       abs = _ref.abs;
     28 
     29   /**
     30    * Calculate the inverse of a square matrix.
     31    *
     32    * Syntax:
     33    *
     34    *     math.inv(x)
     35    *
     36    * Examples:
     37    *
     38    *     math.inv([[1, 2], [3, 4]])  // returns [[-2, 1], [1.5, -0.5]]
     39    *     math.inv(4)                 // returns 0.25
     40    *     1 / 4                       // returns 0.25
     41    *
     42    * See also:
     43    *
     44    *     det, transpose
     45    *
     46    * @param {number | Complex | Array | Matrix} x     Matrix to be inversed
     47    * @return {number | Complex | Array | Matrix} The inverse of `x`.
     48    */
     49   return typed(name, {
     50     'Array | Matrix': function ArrayMatrix(x) {
     51       var size = (0, _is.isMatrix)(x) ? x.size() : (0, _array.arraySize)(x);
     52 
     53       switch (size.length) {
     54         case 1:
     55           // vector
     56           if (size[0] === 1) {
     57             if ((0, _is.isMatrix)(x)) {
     58               return matrix([divideScalar(1, x.valueOf()[0])]);
     59             } else {
     60               return [divideScalar(1, x[0])];
     61             }
     62           } else {
     63             throw new RangeError('Matrix must be square ' + '(size: ' + (0, _string.format)(size) + ')');
     64           }
     65 
     66         case 2:
     67           // two dimensional array
     68           {
     69             var rows = size[0];
     70             var cols = size[1];
     71 
     72             if (rows === cols) {
     73               if ((0, _is.isMatrix)(x)) {
     74                 return matrix(_inv(x.valueOf(), rows, cols), x.storage());
     75               } else {
     76                 // return an Array
     77                 return _inv(x, rows, cols);
     78               }
     79             } else {
     80               throw new RangeError('Matrix must be square ' + '(size: ' + (0, _string.format)(size) + ')');
     81             }
     82           }
     83 
     84         default:
     85           // multi dimensional array
     86           throw new RangeError('Matrix must be two dimensional ' + '(size: ' + (0, _string.format)(size) + ')');
     87       }
     88     },
     89     any: function any(x) {
     90       // scalar
     91       return divideScalar(1, x); // FIXME: create a BigNumber one when configured for bignumbers
     92     }
     93   });
     94   /**
     95    * Calculate the inverse of a square matrix
     96    * @param {Array[]} mat     A square matrix
     97    * @param {number} rows     Number of rows
     98    * @param {number} cols     Number of columns, must equal rows
     99    * @return {Array[]} inv    Inverse matrix
    100    * @private
    101    */
    102 
    103   function _inv(mat, rows, cols) {
    104     var r, s, f, value, temp;
    105 
    106     if (rows === 1) {
    107       // this is a 1 x 1 matrix
    108       value = mat[0][0];
    109 
    110       if (value === 0) {
    111         throw Error('Cannot calculate inverse, determinant is zero');
    112       }
    113 
    114       return [[divideScalar(1, value)]];
    115     } else if (rows === 2) {
    116       // this is a 2 x 2 matrix
    117       var d = det(mat);
    118 
    119       if (d === 0) {
    120         throw Error('Cannot calculate inverse, determinant is zero');
    121       }
    122 
    123       return [[divideScalar(mat[1][1], d), divideScalar(unaryMinus(mat[0][1]), d)], [divideScalar(unaryMinus(mat[1][0]), d), divideScalar(mat[0][0], d)]];
    124     } else {
    125       // this is a matrix of 3 x 3 or larger
    126       // calculate inverse using gauss-jordan elimination
    127       //      https://en.wikipedia.org/wiki/Gaussian_elimination
    128       //      http://mathworld.wolfram.com/MatrixInverse.html
    129       //      http://math.uww.edu/~mcfarlat/inverse.htm
    130       // make a copy of the matrix (only the arrays, not of the elements)
    131       var A = mat.concat();
    132 
    133       for (r = 0; r < rows; r++) {
    134         A[r] = A[r].concat();
    135       } // create an identity matrix which in the end will contain the
    136       // matrix inverse
    137 
    138 
    139       var B = identity(rows).valueOf(); // loop over all columns, and perform row reductions
    140 
    141       for (var c = 0; c < cols; c++) {
    142         // Pivoting: Swap row c with row r, where row r contains the largest element A[r][c]
    143         var ABig = abs(A[c][c]);
    144         var rBig = c;
    145         r = c + 1;
    146 
    147         while (r < rows) {
    148           if (abs(A[r][c]) > ABig) {
    149             ABig = abs(A[r][c]);
    150             rBig = r;
    151           }
    152 
    153           r++;
    154         }
    155 
    156         if (ABig === 0) {
    157           throw Error('Cannot calculate inverse, determinant is zero');
    158         }
    159 
    160         r = rBig;
    161 
    162         if (r !== c) {
    163           temp = A[c];
    164           A[c] = A[r];
    165           A[r] = temp;
    166           temp = B[c];
    167           B[c] = B[r];
    168           B[r] = temp;
    169         } // eliminate non-zero values on the other rows at column c
    170 
    171 
    172         var Ac = A[c];
    173         var Bc = B[c];
    174 
    175         for (r = 0; r < rows; r++) {
    176           var Ar = A[r];
    177           var Br = B[r];
    178 
    179           if (r !== c) {
    180             // eliminate value at column c and row r
    181             if (Ar[c] !== 0) {
    182               f = divideScalar(unaryMinus(Ar[c]), Ac[c]); // add (f * row c) to row r to eliminate the value
    183               // at column c
    184 
    185               for (s = c; s < cols; s++) {
    186                 Ar[s] = addScalar(Ar[s], multiply(f, Ac[s]));
    187               }
    188 
    189               for (s = 0; s < cols; s++) {
    190                 Br[s] = addScalar(Br[s], multiply(f, Bc[s]));
    191               }
    192             }
    193           } else {
    194             // normalize value at Acc to 1,
    195             // divide each value on row r with the value at Acc
    196             f = Ac[c];
    197 
    198             for (s = c; s < cols; s++) {
    199               Ar[s] = divideScalar(Ar[s], f);
    200             }
    201 
    202             for (s = 0; s < cols; s++) {
    203               Br[s] = divideScalar(Br[s], f);
    204             }
    205           }
    206         }
    207       }
    208 
    209       return B;
    210     }
    211   }
    212 });
    213 exports.createInv = createInv;