simple-squiggle

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

norm.js (7832B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createNorm = void 0;
      7 
      8 var _factory = require("../../utils/factory.js");
      9 
     10 var name = 'norm';
     11 var dependencies = ['typed', 'abs', 'add', 'pow', 'conj', 'sqrt', 'multiply', 'equalScalar', 'larger', 'smaller', 'matrix', 'ctranspose', 'eigs'];
     12 var createNorm = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     13   var typed = _ref.typed,
     14       abs = _ref.abs,
     15       add = _ref.add,
     16       pow = _ref.pow,
     17       conj = _ref.conj,
     18       sqrt = _ref.sqrt,
     19       multiply = _ref.multiply,
     20       equalScalar = _ref.equalScalar,
     21       larger = _ref.larger,
     22       smaller = _ref.smaller,
     23       matrix = _ref.matrix,
     24       ctranspose = _ref.ctranspose,
     25       eigs = _ref.eigs;
     26 
     27   /**
     28    * Calculate the norm of a number, vector or matrix.
     29    *
     30    * The second parameter p is optional. If not provided, it defaults to 2.
     31    *
     32    * Syntax:
     33    *
     34    *    math.norm(x)
     35    *    math.norm(x, p)
     36    *
     37    * Examples:
     38    *
     39    *    math.abs(-3.5)                         // returns 3.5
     40    *    math.norm(-3.5)                        // returns 3.5
     41    *
     42    *    math.norm(math.complex(3, -4))         // returns 5
     43    *
     44    *    math.norm([1, 2, -3], Infinity)        // returns 3
     45    *    math.norm([1, 2, -3], -Infinity)       // returns 1
     46    *
     47    *    math.norm([3, 4], 2)                   // returns 5
     48    *
     49    *    math.norm([[1, 2], [3, 4]], 1)          // returns 6
     50    *    math.norm([[1, 2], [3, 4]], 'inf')     // returns 7
     51    *    math.norm([[1, 2], [3, 4]], 'fro')     // returns 5.477225575051661
     52    *
     53    * See also:
     54    *
     55    *    abs, hypot
     56    *
     57    * @param  {number | BigNumber | Complex | Array | Matrix} x
     58    *            Value for which to calculate the norm
     59    * @param  {number | BigNumber | string} [p=2]
     60    *            Vector space.
     61    *            Supported numbers include Infinity and -Infinity.
     62    *            Supported strings are: 'inf', '-inf', and 'fro' (The Frobenius norm)
     63    * @return {number | BigNumber} the p-norm
     64    */
     65   return typed(name, {
     66     number: Math.abs,
     67     Complex: function Complex(x) {
     68       return x.abs();
     69     },
     70     BigNumber: function BigNumber(x) {
     71       // norm(x) = abs(x)
     72       return x.abs();
     73     },
     74     boolean: function boolean(x) {
     75       // norm(x) = abs(x)
     76       return Math.abs(x);
     77     },
     78     Array: function Array(x) {
     79       return _norm(matrix(x), 2);
     80     },
     81     Matrix: function Matrix(x) {
     82       return _norm(x, 2);
     83     },
     84     'number | Complex | BigNumber | boolean, number | BigNumber | string': function numberComplexBigNumberBooleanNumberBigNumberString(x) {
     85       // ignore second parameter, TODO: remove the option of second parameter for these types
     86       return this(x);
     87     },
     88     'Array, number | BigNumber | string': function ArrayNumberBigNumberString(x, p) {
     89       return _norm(matrix(x), p);
     90     },
     91     'Matrix, number | BigNumber | string': function MatrixNumberBigNumberString(x, p) {
     92       return _norm(x, p);
     93     }
     94   });
     95   /**
     96    * Calculate the plus infinity norm for a vector
     97    * @param {Matrix} x
     98    * @returns {number} Returns the norm
     99    * @private
    100    */
    101 
    102   function _vectorNormPlusInfinity(x) {
    103     // norm(x, Infinity) = max(abs(x))
    104     var pinf = 0; // skip zeros since abs(0) === 0
    105 
    106     x.forEach(function (value) {
    107       var v = abs(value);
    108 
    109       if (larger(v, pinf)) {
    110         pinf = v;
    111       }
    112     }, true);
    113     return pinf;
    114   }
    115   /**
    116    * Calculate the minus infinity norm for a vector
    117    * @param {Matrix} x
    118    * @returns {number} Returns the norm
    119    * @private
    120    */
    121 
    122 
    123   function _vectorNormMinusInfinity(x) {
    124     // norm(x, -Infinity) = min(abs(x))
    125     var ninf; // skip zeros since abs(0) === 0
    126 
    127     x.forEach(function (value) {
    128       var v = abs(value);
    129 
    130       if (!ninf || smaller(v, ninf)) {
    131         ninf = v;
    132       }
    133     }, true);
    134     return ninf || 0;
    135   }
    136   /**
    137    * Calculate the norm for a vector
    138    * @param {Matrix} x
    139    * @param {number | string} p
    140    * @returns {number} Returns the norm
    141    * @private
    142    */
    143 
    144 
    145   function _vectorNorm(x, p) {
    146     // check p
    147     if (p === Number.POSITIVE_INFINITY || p === 'inf') {
    148       return _vectorNormPlusInfinity(x);
    149     }
    150 
    151     if (p === Number.NEGATIVE_INFINITY || p === '-inf') {
    152       return _vectorNormMinusInfinity(x);
    153     }
    154 
    155     if (p === 'fro') {
    156       return _norm(x, 2);
    157     }
    158 
    159     if (typeof p === 'number' && !isNaN(p)) {
    160       // check p != 0
    161       if (!equalScalar(p, 0)) {
    162         // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p
    163         var n = 0; // skip zeros since abs(0) === 0
    164 
    165         x.forEach(function (value) {
    166           n = add(pow(abs(value), p), n);
    167         }, true);
    168         return pow(n, 1 / p);
    169       }
    170 
    171       return Number.POSITIVE_INFINITY;
    172     } // invalid parameter value
    173 
    174 
    175     throw new Error('Unsupported parameter value');
    176   }
    177   /**
    178    * Calculate the Frobenius norm for a matrix
    179    * @param {Matrix} x
    180    * @returns {number} Returns the norm
    181    * @private
    182    */
    183 
    184 
    185   function _matrixNormFrobenius(x) {
    186     // norm(x) = sqrt(sum(diag(x'x)))
    187     var fro = 0;
    188     x.forEach(function (value, index) {
    189       fro = add(fro, multiply(value, conj(value)));
    190     });
    191     return abs(sqrt(fro));
    192   }
    193   /**
    194    * Calculate the norm L1 for a matrix
    195    * @param {Matrix} x
    196    * @returns {number} Returns the norm
    197    * @private
    198    */
    199 
    200 
    201   function _matrixNormOne(x) {
    202     // norm(x) = the largest column sum
    203     var c = []; // result
    204 
    205     var maxc = 0; // skip zeros since abs(0) == 0
    206 
    207     x.forEach(function (value, index) {
    208       var j = index[1];
    209       var cj = add(c[j] || 0, abs(value));
    210 
    211       if (larger(cj, maxc)) {
    212         maxc = cj;
    213       }
    214 
    215       c[j] = cj;
    216     }, true);
    217     return maxc;
    218   }
    219   /**
    220    * Calculate the norm L2 for a matrix
    221    * @param {Matrix} x
    222    * @returns {number} Returns the norm
    223    * @private
    224    */
    225 
    226 
    227   function _matrixNormTwo(x) {
    228     // norm(x) = sqrt( max eigenvalue of A*.A)
    229     var sizeX = x.size();
    230 
    231     if (sizeX[0] !== sizeX[1]) {
    232       throw new RangeError('Invalid matrix dimensions');
    233     }
    234 
    235     var tx = ctranspose(x);
    236     var squaredX = multiply(tx, x);
    237     var eigenVals = eigs(squaredX).values.toArray();
    238     var rho = eigenVals[eigenVals.length - 1];
    239     return abs(sqrt(rho));
    240   }
    241   /**
    242    * Calculate the infinity norm for a matrix
    243    * @param {Matrix} x
    244    * @returns {number} Returns the norm
    245    * @private
    246    */
    247 
    248 
    249   function _matrixNormInfinity(x) {
    250     // norm(x) = the largest row sum
    251     var r = []; // result
    252 
    253     var maxr = 0; // skip zeros since abs(0) == 0
    254 
    255     x.forEach(function (value, index) {
    256       var i = index[0];
    257       var ri = add(r[i] || 0, abs(value));
    258 
    259       if (larger(ri, maxr)) {
    260         maxr = ri;
    261       }
    262 
    263       r[i] = ri;
    264     }, true);
    265     return maxr;
    266   }
    267   /**
    268    * Calculate the norm for a 2D Matrix (M*N)
    269    * @param {Matrix} x
    270    * @param {number | string} p
    271    * @returns {number} Returns the norm
    272    * @private
    273    */
    274 
    275 
    276   function _matrixNorm(x, p) {
    277     // check p
    278     if (p === 1) {
    279       return _matrixNormOne(x);
    280     }
    281 
    282     if (p === Number.POSITIVE_INFINITY || p === 'inf') {
    283       return _matrixNormInfinity(x);
    284     }
    285 
    286     if (p === 'fro') {
    287       return _matrixNormFrobenius(x);
    288     }
    289 
    290     if (p === 2) {
    291       return _matrixNormTwo(x);
    292     } // invalid parameter value
    293 
    294 
    295     throw new Error('Unsupported parameter value ' + p);
    296   }
    297   /**
    298    * Calculate the norm for an array
    299    * @param {Matrix} x
    300    * @param {number | string} p
    301    * @returns {number} Returns the norm
    302    * @private
    303    */
    304 
    305 
    306   function _norm(x, p) {
    307     // size
    308     var sizeX = x.size(); // check if it is a vector
    309 
    310     if (sizeX.length === 1) {
    311       return _vectorNorm(x, p);
    312     } // MxN matrix
    313 
    314 
    315     if (sizeX.length === 2) {
    316       if (sizeX[0] && sizeX[1]) {
    317         return _matrixNorm(x, p);
    318       } else {
    319         throw new RangeError('Invalid matrix dimensions');
    320       }
    321     }
    322   }
    323 });
    324 exports.createNorm = createNorm;