simple-squiggle

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

diff.js (5604B)


      1 import { factory } from '../../utils/factory.js';
      2 import { isInteger } from '../../utils/number.js';
      3 import { isMatrix } from '../../utils/is.js';
      4 var name = 'diff';
      5 var dependencies = ['typed', 'matrix', 'subtract', 'number'];
      6 export var createDiff = /* #__PURE__ */factory(name, dependencies, _ref => {
      7   var {
      8     typed,
      9     matrix,
     10     subtract,
     11     number
     12   } = _ref;
     13 
     14   /**
     15    * Create a new matrix or array of the difference between elements of the given array
     16    * The optional dim parameter lets you specify the dimension to evaluate the difference of
     17    * If no dimension parameter is passed it is assumed as dimension 0
     18    *
     19    * Dimension is zero-based in javascript and one-based in the parser and can be a number or bignumber
     20    * Arrays must be 'rectangular' meaning arrays like [1, 2]
     21    * If something is passed as a matrix it will be returned as a matrix but other than that all matrices are converted to arrays
     22    *
     23    * Syntax:
     24    *
     25    *     math.diff(arr)
     26    *     math.diff(arr, dim)
     27    *
     28    * Examples:
     29    *
     30    *     const arr = [1, 2, 4, 7, 0]
     31    *     math.diff(arr) // returns [1, 2, 3, -7] (no dimension passed so 0 is assumed)
     32    *     math.diff(math.matrix(arr)) // returns math.matrix([1, 2, 3, -7])
     33    *
     34    *     const arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [9, 8, 7, 6, 4]]
     35    *     math.diff(arr) // returns [[0, 0, 0, 0, 0], [8, 6, 4, 2, -1]]
     36    *     math.diff(arr, 0) // returns [[0, 0, 0, 0, 0], [8, 6, 4, 2, -1]]
     37    *     math.diff(arr, 1) // returns [[1, 1, 1, 1], [1, 1, 1, 1], [-1, -1, -1, -2]]
     38    *     math.diff(arr, math.bignumber(1)) // returns [[1, 1, 1, 1], [1, 1, 1, 1], [-1, -1, -1, -2]]
     39    *
     40    *     math.diff(arr, 2) // throws RangeError as arr is 2 dimensional not 3
     41    *     math.diff(arr, -1) // throws RangeError as negative dimensions are not allowed
     42    *
     43    *     // These will all produce the same result
     44    *     math.diff([[1, 2], [3, 4]])
     45    *     math.diff([math.matrix([1, 2]), math.matrix([3, 4])])
     46    *     math.diff([[1, 2], math.matrix([3, 4])])
     47    *     math.diff([math.matrix([1, 2]), [3, 4]])
     48    *     // They do not produce the same result as  math.diff(math.matrix([[1, 2], [3, 4]])) as this returns a matrix
     49    *
     50    * See Also:
     51    *
     52    *      sum
     53    *      subtract
     54    *      partitionSelect
     55    *
     56    * @param {Array | Matrix} arr    An array or matrix
     57    * @param {number} dim            Dimension
     58    * @return {Array | Matrix}       Difference between array elements in given dimension
     59    */
     60   return typed(name, {
     61     'Array | Matrix': function ArrayMatrix(arr) {
     62       // No dimension specified => assume dimension 0
     63       if (isMatrix(arr)) {
     64         return matrix(_diff(arr.toArray()));
     65       } else {
     66         return _diff(arr);
     67       }
     68     },
     69     'Array | Matrix, number': function ArrayMatrixNumber(arr, dim) {
     70       if (!isInteger(dim)) throw new RangeError('Dimension must be a whole number');
     71 
     72       if (isMatrix(arr)) {
     73         return matrix(_recursive(arr.toArray(), dim));
     74       } else {
     75         return _recursive(arr, dim);
     76       }
     77     },
     78     'Array | Matrix, BigNumber': function ArrayMatrixBigNumber(arr, dim) {
     79       return this(arr, number(dim));
     80     }
     81   });
     82   /**
     83    * Recursively find the correct dimension in the array/matrix
     84    * Then Apply _diff to that dimension
     85    *
     86    * @param {Array} arr      The array
     87    * @param {number} dim     Dimension
     88    * @return {Array}         resulting array
     89    */
     90 
     91   function _recursive(arr, dim) {
     92     if (isMatrix(arr)) {
     93       arr = arr.toArray(); // Makes sure arrays like [ matrix([0, 1]), matrix([1, 0]) ] are processed properly
     94     }
     95 
     96     if (!Array.isArray(arr)) {
     97       throw RangeError('Array/Matrix does not have that many dimensions');
     98     }
     99 
    100     if (dim > 0) {
    101       var result = [];
    102       arr.forEach(element => {
    103         result.push(_recursive(element, dim - 1));
    104       });
    105       return result;
    106     } else if (dim === 0) {
    107       return _diff(arr);
    108     } else {
    109       throw RangeError('Cannot have negative dimension');
    110     }
    111   }
    112   /**
    113    * Difference between elements in the array
    114    *
    115    * @param {Array} arr      An array
    116    * @return {Array}         resulting array
    117    */
    118 
    119 
    120   function _diff(arr) {
    121     var result = [];
    122     var size = arr.length;
    123 
    124     if (size < 2) {
    125       return arr;
    126     }
    127 
    128     for (var i = 1; i < size; i++) {
    129       result.push(_ElementDiff(arr[i - 1], arr[i]));
    130     }
    131 
    132     return result;
    133   }
    134   /**
    135    * Difference between 2 objects
    136    *
    137    * @param {Object} obj1    First object
    138    * @param {Object} obj2    Second object
    139    * @return {Array}         resulting array
    140    */
    141 
    142 
    143   function _ElementDiff(obj1, obj2) {
    144     // Convert matrices to arrays
    145     if (isMatrix(obj1)) obj1 = obj1.toArray();
    146     if (isMatrix(obj2)) obj2 = obj2.toArray();
    147     var obj1IsArray = Array.isArray(obj1);
    148     var obj2IsArray = Array.isArray(obj2);
    149 
    150     if (obj1IsArray && obj2IsArray) {
    151       return _ArrayDiff(obj1, obj2);
    152     }
    153 
    154     if (!obj1IsArray && !obj2IsArray) {
    155       return subtract(obj2, obj1); // Difference is (second - first) NOT (first - second)
    156     }
    157 
    158     throw TypeError('Cannot calculate difference between 1 array and 1 non-array');
    159   }
    160   /**
    161    * Difference of elements in 2 arrays
    162    *
    163    * @param {Array} arr1     Array 1
    164    * @param {Array} arr2     Array 2
    165    * @return {Array}         resulting array
    166    */
    167 
    168 
    169   function _ArrayDiff(arr1, arr2) {
    170     if (arr1.length !== arr2.length) {
    171       throw RangeError('Not all sub-arrays have the same length');
    172     }
    173 
    174     var result = [];
    175     var size = arr1.length;
    176 
    177     for (var i = 0; i < size; i++) {
    178       result.push(_ElementDiff(arr1[i], arr2[i]));
    179     }
    180 
    181     return result;
    182   }
    183 });