simple-squiggle

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

collection.js (4962B)


      1 import { isCollection, isMatrix } from './is.js';
      2 import { IndexError } from '../error/IndexError.js';
      3 import { arraySize } from './array.js';
      4 import { _switch } from './switch.js';
      5 /**
      6  * Test whether an array contains collections
      7  * @param {Array} array
      8  * @returns {boolean} Returns true when the array contains one or multiple
      9  *                    collections (Arrays or Matrices). Returns false otherwise.
     10  */
     11 
     12 export function containsCollections(array) {
     13   for (var i = 0; i < array.length; i++) {
     14     if (isCollection(array[i])) {
     15       return true;
     16     }
     17   }
     18 
     19   return false;
     20 }
     21 /**
     22  * Recursively loop over all elements in a given multi dimensional array
     23  * and invoke the callback on each of the elements.
     24  * @param {Array | Matrix} array
     25  * @param {Function} callback     The callback method is invoked with one
     26  *                                parameter: the current element in the array
     27  */
     28 
     29 export function deepForEach(array, callback) {
     30   if (isMatrix(array)) {
     31     array = array.valueOf();
     32   }
     33 
     34   for (var i = 0, ii = array.length; i < ii; i++) {
     35     var value = array[i];
     36 
     37     if (Array.isArray(value)) {
     38       deepForEach(value, callback);
     39     } else {
     40       callback(value);
     41     }
     42   }
     43 }
     44 /**
     45  * Execute the callback function element wise for each element in array and any
     46  * nested array
     47  * Returns an array with the results
     48  * @param {Array | Matrix} array
     49  * @param {Function} callback   The callback is called with two parameters:
     50  *                              value1 and value2, which contain the current
     51  *                              element of both arrays.
     52  * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
     53  *
     54  * @return {Array | Matrix} res
     55  */
     56 
     57 export function deepMap(array, callback, skipZeros) {
     58   if (array && typeof array.map === 'function') {
     59     // TODO: replace array.map with a for loop to improve performance
     60     return array.map(function (x) {
     61       return deepMap(x, callback, skipZeros);
     62     });
     63   } else {
     64     return callback(array);
     65   }
     66 }
     67 /**
     68  * Reduce a given matrix or array to a new matrix or
     69  * array with one less dimension, applying the given
     70  * callback in the selected dimension.
     71  * @param {Array | Matrix} mat
     72  * @param {number} dim
     73  * @param {Function} callback
     74  * @return {Array | Matrix} res
     75  */
     76 
     77 export function reduce(mat, dim, callback) {
     78   var size = Array.isArray(mat) ? arraySize(mat) : mat.size();
     79 
     80   if (dim < 0 || dim >= size.length) {
     81     // TODO: would be more clear when throwing a DimensionError here
     82     throw new IndexError(dim, size.length);
     83   }
     84 
     85   if (isMatrix(mat)) {
     86     return mat.create(_reduce(mat.valueOf(), dim, callback));
     87   } else {
     88     return _reduce(mat, dim, callback);
     89   }
     90 }
     91 /**
     92  * Recursively reduce a matrix
     93  * @param {Array} mat
     94  * @param {number} dim
     95  * @param {Function} callback
     96  * @returns {Array} ret
     97  * @private
     98  */
     99 
    100 function _reduce(mat, dim, callback) {
    101   var i, ret, val, tran;
    102 
    103   if (dim <= 0) {
    104     if (!Array.isArray(mat[0])) {
    105       val = mat[0];
    106 
    107       for (i = 1; i < mat.length; i++) {
    108         val = callback(val, mat[i]);
    109       }
    110 
    111       return val;
    112     } else {
    113       tran = _switch(mat);
    114       ret = [];
    115 
    116       for (i = 0; i < tran.length; i++) {
    117         ret[i] = _reduce(tran[i], dim - 1, callback);
    118       }
    119 
    120       return ret;
    121     }
    122   } else {
    123     ret = [];
    124 
    125     for (i = 0; i < mat.length; i++) {
    126       ret[i] = _reduce(mat[i], dim - 1, callback);
    127     }
    128 
    129     return ret;
    130   }
    131 } // TODO: document function scatter
    132 
    133 
    134 export function scatter(a, j, w, x, u, mark, cindex, f, inverse, update, value) {
    135   // a arrays
    136   var avalues = a._values;
    137   var aindex = a._index;
    138   var aptr = a._ptr; // vars
    139 
    140   var k, k0, k1, i; // check we need to process values (pattern matrix)
    141 
    142   if (x) {
    143     // values in j
    144     for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
    145       // row
    146       i = aindex[k]; // check value exists in current j
    147 
    148       if (w[i] !== mark) {
    149         // i is new entry in j
    150         w[i] = mark; // add i to pattern of C
    151 
    152         cindex.push(i); // x(i) = A, check we need to call function this time
    153 
    154         if (update) {
    155           // copy value to workspace calling callback function
    156           x[i] = inverse ? f(avalues[k], value) : f(value, avalues[k]); // function was called on current row
    157 
    158           u[i] = mark;
    159         } else {
    160           // copy value to workspace
    161           x[i] = avalues[k];
    162         }
    163       } else {
    164         // i exists in C already
    165         x[i] = inverse ? f(avalues[k], x[i]) : f(x[i], avalues[k]); // function was called on current row
    166 
    167         u[i] = mark;
    168       }
    169     }
    170   } else {
    171     // values in j
    172     for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
    173       // row
    174       i = aindex[k]; // check value exists in current j
    175 
    176       if (w[i] !== mark) {
    177         // i is new entry in j
    178         w[i] = mark; // add i to pattern of C
    179 
    180         cindex.push(i);
    181       } else {
    182         // indicate function was called on current row
    183         u[i] = mark;
    184       }
    185     }
    186   }
    187 }