simple-squiggle

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

multiply.js (24415B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createMultiply = void 0;
      7 
      8 var _factory = require("../../utils/factory.js");
      9 
     10 var _is = require("../../utils/is.js");
     11 
     12 var _object = require("../../utils/object.js");
     13 
     14 var _array = require("../../utils/array.js");
     15 
     16 var _algorithm = require("../../type/matrix/utils/algorithm11.js");
     17 
     18 var _algorithm2 = require("../../type/matrix/utils/algorithm14.js");
     19 
     20 var name = 'multiply';
     21 var dependencies = ['typed', 'matrix', 'addScalar', 'multiplyScalar', 'equalScalar', 'dot'];
     22 var createMultiply = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     23   var typed = _ref.typed,
     24       matrix = _ref.matrix,
     25       addScalar = _ref.addScalar,
     26       multiplyScalar = _ref.multiplyScalar,
     27       equalScalar = _ref.equalScalar,
     28       dot = _ref.dot;
     29   var algorithm11 = (0, _algorithm.createAlgorithm11)({
     30     typed: typed,
     31     equalScalar: equalScalar
     32   });
     33   var algorithm14 = (0, _algorithm2.createAlgorithm14)({
     34     typed: typed
     35   });
     36 
     37   function _validateMatrixDimensions(size1, size2) {
     38     // check left operand dimensions
     39     switch (size1.length) {
     40       case 1:
     41         // check size2
     42         switch (size2.length) {
     43           case 1:
     44             // Vector x Vector
     45             if (size1[0] !== size2[0]) {
     46               // throw error
     47               throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length');
     48             }
     49 
     50             break;
     51 
     52           case 2:
     53             // Vector x Matrix
     54             if (size1[0] !== size2[0]) {
     55               // throw error
     56               throw new RangeError('Dimension mismatch in multiplication. Vector length (' + size1[0] + ') must match Matrix rows (' + size2[0] + ')');
     57             }
     58 
     59             break;
     60 
     61           default:
     62             throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)');
     63         }
     64 
     65         break;
     66 
     67       case 2:
     68         // check size2
     69         switch (size2.length) {
     70           case 1:
     71             // Matrix x Vector
     72             if (size1[1] !== size2[0]) {
     73               // throw error
     74               throw new RangeError('Dimension mismatch in multiplication. Matrix columns (' + size1[1] + ') must match Vector length (' + size2[0] + ')');
     75             }
     76 
     77             break;
     78 
     79           case 2:
     80             // Matrix x Matrix
     81             if (size1[1] !== size2[0]) {
     82               // throw error
     83               throw new RangeError('Dimension mismatch in multiplication. Matrix A columns (' + size1[1] + ') must match Matrix B rows (' + size2[0] + ')');
     84             }
     85 
     86             break;
     87 
     88           default:
     89             throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)');
     90         }
     91 
     92         break;
     93 
     94       default:
     95         throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix A has ' + size1.length + ' dimensions)');
     96     }
     97   }
     98   /**
     99    * C = A * B
    100    *
    101    * @param {Matrix} a            Dense Vector   (N)
    102    * @param {Matrix} b            Dense Vector   (N)
    103    *
    104    * @return {number}             Scalar value
    105    */
    106 
    107 
    108   function _multiplyVectorVector(a, b, n) {
    109     // check empty vector
    110     if (n === 0) {
    111       throw new Error('Cannot multiply two empty vectors');
    112     }
    113 
    114     return dot(a, b);
    115   }
    116   /**
    117    * C = A * B
    118    *
    119    * @param {Matrix} a            Dense Vector   (M)
    120    * @param {Matrix} b            Matrix         (MxN)
    121    *
    122    * @return {Matrix}             Dense Vector   (N)
    123    */
    124 
    125 
    126   function _multiplyVectorMatrix(a, b) {
    127     // process storage
    128     if (b.storage() !== 'dense') {
    129       throw new Error('Support for SparseMatrix not implemented');
    130     }
    131 
    132     return _multiplyVectorDenseMatrix(a, b);
    133   }
    134   /**
    135    * C = A * B
    136    *
    137    * @param {Matrix} a            Dense Vector   (M)
    138    * @param {Matrix} b            Dense Matrix   (MxN)
    139    *
    140    * @return {Matrix}             Dense Vector   (N)
    141    */
    142 
    143 
    144   function _multiplyVectorDenseMatrix(a, b) {
    145     // a dense
    146     var adata = a._data;
    147     var asize = a._size;
    148     var adt = a._datatype; // b dense
    149 
    150     var bdata = b._data;
    151     var bsize = b._size;
    152     var bdt = b._datatype; // rows & columns
    153 
    154     var alength = asize[0];
    155     var bcolumns = bsize[1]; // datatype
    156 
    157     var dt; // addScalar signature to use
    158 
    159     var af = addScalar; // multiplyScalar signature to use
    160 
    161     var mf = multiplyScalar; // process data types
    162 
    163     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    164       // datatype
    165       dt = adt; // find signatures that matches (dt, dt)
    166 
    167       af = typed.find(addScalar, [dt, dt]);
    168       mf = typed.find(multiplyScalar, [dt, dt]);
    169     } // result
    170 
    171 
    172     var c = []; // loop matrix columns
    173 
    174     for (var j = 0; j < bcolumns; j++) {
    175       // sum (do not initialize it with zero)
    176       var sum = mf(adata[0], bdata[0][j]); // loop vector
    177 
    178       for (var i = 1; i < alength; i++) {
    179         // multiply & accumulate
    180         sum = af(sum, mf(adata[i], bdata[i][j]));
    181       }
    182 
    183       c[j] = sum;
    184     } // return matrix
    185 
    186 
    187     return a.createDenseMatrix({
    188       data: c,
    189       size: [bcolumns],
    190       datatype: dt
    191     });
    192   }
    193   /**
    194    * C = A * B
    195    *
    196    * @param {Matrix} a            Matrix         (MxN)
    197    * @param {Matrix} b            Dense Vector   (N)
    198    *
    199    * @return {Matrix}             Dense Vector   (M)
    200    */
    201 
    202 
    203   var _multiplyMatrixVector = typed('_multiplyMatrixVector', {
    204     'DenseMatrix, any': _multiplyDenseMatrixVector,
    205     'SparseMatrix, any': _multiplySparseMatrixVector
    206   });
    207   /**
    208    * C = A * B
    209    *
    210    * @param {Matrix} a            Matrix         (MxN)
    211    * @param {Matrix} b            Matrix         (NxC)
    212    *
    213    * @return {Matrix}             Matrix         (MxC)
    214    */
    215 
    216 
    217   var _multiplyMatrixMatrix = typed('_multiplyMatrixMatrix', {
    218     'DenseMatrix, DenseMatrix': _multiplyDenseMatrixDenseMatrix,
    219     'DenseMatrix, SparseMatrix': _multiplyDenseMatrixSparseMatrix,
    220     'SparseMatrix, DenseMatrix': _multiplySparseMatrixDenseMatrix,
    221     'SparseMatrix, SparseMatrix': _multiplySparseMatrixSparseMatrix
    222   });
    223   /**
    224    * C = A * B
    225    *
    226    * @param {Matrix} a            DenseMatrix  (MxN)
    227    * @param {Matrix} b            Dense Vector (N)
    228    *
    229    * @return {Matrix}             Dense Vector (M)
    230    */
    231 
    232 
    233   function _multiplyDenseMatrixVector(a, b) {
    234     // a dense
    235     var adata = a._data;
    236     var asize = a._size;
    237     var adt = a._datatype; // b dense
    238 
    239     var bdata = b._data;
    240     var bdt = b._datatype; // rows & columns
    241 
    242     var arows = asize[0];
    243     var acolumns = asize[1]; // datatype
    244 
    245     var dt; // addScalar signature to use
    246 
    247     var af = addScalar; // multiplyScalar signature to use
    248 
    249     var mf = multiplyScalar; // process data types
    250 
    251     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    252       // datatype
    253       dt = adt; // find signatures that matches (dt, dt)
    254 
    255       af = typed.find(addScalar, [dt, dt]);
    256       mf = typed.find(multiplyScalar, [dt, dt]);
    257     } // result
    258 
    259 
    260     var c = []; // loop matrix a rows
    261 
    262     for (var i = 0; i < arows; i++) {
    263       // current row
    264       var row = adata[i]; // sum (do not initialize it with zero)
    265 
    266       var sum = mf(row[0], bdata[0]); // loop matrix a columns
    267 
    268       for (var j = 1; j < acolumns; j++) {
    269         // multiply & accumulate
    270         sum = af(sum, mf(row[j], bdata[j]));
    271       }
    272 
    273       c[i] = sum;
    274     } // return matrix
    275 
    276 
    277     return a.createDenseMatrix({
    278       data: c,
    279       size: [arows],
    280       datatype: dt
    281     });
    282   }
    283   /**
    284    * C = A * B
    285    *
    286    * @param {Matrix} a            DenseMatrix    (MxN)
    287    * @param {Matrix} b            DenseMatrix    (NxC)
    288    *
    289    * @return {Matrix}             DenseMatrix    (MxC)
    290    */
    291 
    292 
    293   function _multiplyDenseMatrixDenseMatrix(a, b) {
    294     // a dense
    295     var adata = a._data;
    296     var asize = a._size;
    297     var adt = a._datatype; // b dense
    298 
    299     var bdata = b._data;
    300     var bsize = b._size;
    301     var bdt = b._datatype; // rows & columns
    302 
    303     var arows = asize[0];
    304     var acolumns = asize[1];
    305     var bcolumns = bsize[1]; // datatype
    306 
    307     var dt; // addScalar signature to use
    308 
    309     var af = addScalar; // multiplyScalar signature to use
    310 
    311     var mf = multiplyScalar; // process data types
    312 
    313     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    314       // datatype
    315       dt = adt; // find signatures that matches (dt, dt)
    316 
    317       af = typed.find(addScalar, [dt, dt]);
    318       mf = typed.find(multiplyScalar, [dt, dt]);
    319     } // result
    320 
    321 
    322     var c = []; // loop matrix a rows
    323 
    324     for (var i = 0; i < arows; i++) {
    325       // current row
    326       var row = adata[i]; // initialize row array
    327 
    328       c[i] = []; // loop matrix b columns
    329 
    330       for (var j = 0; j < bcolumns; j++) {
    331         // sum (avoid initializing sum to zero)
    332         var sum = mf(row[0], bdata[0][j]); // loop matrix a columns
    333 
    334         for (var x = 1; x < acolumns; x++) {
    335           // multiply & accumulate
    336           sum = af(sum, mf(row[x], bdata[x][j]));
    337         }
    338 
    339         c[i][j] = sum;
    340       }
    341     } // return matrix
    342 
    343 
    344     return a.createDenseMatrix({
    345       data: c,
    346       size: [arows, bcolumns],
    347       datatype: dt
    348     });
    349   }
    350   /**
    351    * C = A * B
    352    *
    353    * @param {Matrix} a            DenseMatrix    (MxN)
    354    * @param {Matrix} b            SparseMatrix   (NxC)
    355    *
    356    * @return {Matrix}             SparseMatrix   (MxC)
    357    */
    358 
    359 
    360   function _multiplyDenseMatrixSparseMatrix(a, b) {
    361     // a dense
    362     var adata = a._data;
    363     var asize = a._size;
    364     var adt = a._datatype; // b sparse
    365 
    366     var bvalues = b._values;
    367     var bindex = b._index;
    368     var bptr = b._ptr;
    369     var bsize = b._size;
    370     var bdt = b._datatype; // validate b matrix
    371 
    372     if (!bvalues) {
    373       throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix');
    374     } // rows & columns
    375 
    376 
    377     var arows = asize[0];
    378     var bcolumns = bsize[1]; // datatype
    379 
    380     var dt; // addScalar signature to use
    381 
    382     var af = addScalar; // multiplyScalar signature to use
    383 
    384     var mf = multiplyScalar; // equalScalar signature to use
    385 
    386     var eq = equalScalar; // zero value
    387 
    388     var zero = 0; // process data types
    389 
    390     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    391       // datatype
    392       dt = adt; // find signatures that matches (dt, dt)
    393 
    394       af = typed.find(addScalar, [dt, dt]);
    395       mf = typed.find(multiplyScalar, [dt, dt]);
    396       eq = typed.find(equalScalar, [dt, dt]); // convert 0 to the same datatype
    397 
    398       zero = typed.convert(0, dt);
    399     } // result
    400 
    401 
    402     var cvalues = [];
    403     var cindex = [];
    404     var cptr = []; // c matrix
    405 
    406     var c = b.createSparseMatrix({
    407       values: cvalues,
    408       index: cindex,
    409       ptr: cptr,
    410       size: [arows, bcolumns],
    411       datatype: dt
    412     }); // loop b columns
    413 
    414     for (var jb = 0; jb < bcolumns; jb++) {
    415       // update ptr
    416       cptr[jb] = cindex.length; // indeces in column jb
    417 
    418       var kb0 = bptr[jb];
    419       var kb1 = bptr[jb + 1]; // do not process column jb if no data exists
    420 
    421       if (kb1 > kb0) {
    422         // last row mark processed
    423         var last = 0; // loop a rows
    424 
    425         for (var i = 0; i < arows; i++) {
    426           // column mark
    427           var mark = i + 1; // C[i, jb]
    428 
    429           var cij = void 0; // values in b column j
    430 
    431           for (var kb = kb0; kb < kb1; kb++) {
    432             // row
    433             var ib = bindex[kb]; // check value has been initialized
    434 
    435             if (last !== mark) {
    436               // first value in column jb
    437               cij = mf(adata[i][ib], bvalues[kb]); // update mark
    438 
    439               last = mark;
    440             } else {
    441               // accumulate value
    442               cij = af(cij, mf(adata[i][ib], bvalues[kb]));
    443             }
    444           } // check column has been processed and value != 0
    445 
    446 
    447           if (last === mark && !eq(cij, zero)) {
    448             // push row & value
    449             cindex.push(i);
    450             cvalues.push(cij);
    451           }
    452         }
    453       }
    454     } // update ptr
    455 
    456 
    457     cptr[bcolumns] = cindex.length; // return sparse matrix
    458 
    459     return c;
    460   }
    461   /**
    462    * C = A * B
    463    *
    464    * @param {Matrix} a            SparseMatrix    (MxN)
    465    * @param {Matrix} b            Dense Vector (N)
    466    *
    467    * @return {Matrix}             SparseMatrix    (M, 1)
    468    */
    469 
    470 
    471   function _multiplySparseMatrixVector(a, b) {
    472     // a sparse
    473     var avalues = a._values;
    474     var aindex = a._index;
    475     var aptr = a._ptr;
    476     var adt = a._datatype; // validate a matrix
    477 
    478     if (!avalues) {
    479       throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix');
    480     } // b dense
    481 
    482 
    483     var bdata = b._data;
    484     var bdt = b._datatype; // rows & columns
    485 
    486     var arows = a._size[0];
    487     var brows = b._size[0]; // result
    488 
    489     var cvalues = [];
    490     var cindex = [];
    491     var cptr = []; // datatype
    492 
    493     var dt; // addScalar signature to use
    494 
    495     var af = addScalar; // multiplyScalar signature to use
    496 
    497     var mf = multiplyScalar; // equalScalar signature to use
    498 
    499     var eq = equalScalar; // zero value
    500 
    501     var zero = 0; // process data types
    502 
    503     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    504       // datatype
    505       dt = adt; // find signatures that matches (dt, dt)
    506 
    507       af = typed.find(addScalar, [dt, dt]);
    508       mf = typed.find(multiplyScalar, [dt, dt]);
    509       eq = typed.find(equalScalar, [dt, dt]); // convert 0 to the same datatype
    510 
    511       zero = typed.convert(0, dt);
    512     } // workspace
    513 
    514 
    515     var x = []; // vector with marks indicating a value x[i] exists in a given column
    516 
    517     var w = []; // update ptr
    518 
    519     cptr[0] = 0; // rows in b
    520 
    521     for (var ib = 0; ib < brows; ib++) {
    522       // b[ib]
    523       var vbi = bdata[ib]; // check b[ib] != 0, avoid loops
    524 
    525       if (!eq(vbi, zero)) {
    526         // A values & index in ib column
    527         for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
    528           // a row
    529           var ia = aindex[ka]; // check value exists in current j
    530 
    531           if (!w[ia]) {
    532             // ia is new entry in j
    533             w[ia] = true; // add i to pattern of C
    534 
    535             cindex.push(ia); // x(ia) = A
    536 
    537             x[ia] = mf(vbi, avalues[ka]);
    538           } else {
    539             // i exists in C already
    540             x[ia] = af(x[ia], mf(vbi, avalues[ka]));
    541           }
    542         }
    543       }
    544     } // copy values from x to column jb of c
    545 
    546 
    547     for (var p1 = cindex.length, p = 0; p < p1; p++) {
    548       // row
    549       var ic = cindex[p]; // copy value
    550 
    551       cvalues[p] = x[ic];
    552     } // update ptr
    553 
    554 
    555     cptr[1] = cindex.length; // return sparse matrix
    556 
    557     return a.createSparseMatrix({
    558       values: cvalues,
    559       index: cindex,
    560       ptr: cptr,
    561       size: [arows, 1],
    562       datatype: dt
    563     });
    564   }
    565   /**
    566    * C = A * B
    567    *
    568    * @param {Matrix} a            SparseMatrix      (MxN)
    569    * @param {Matrix} b            DenseMatrix       (NxC)
    570    *
    571    * @return {Matrix}             SparseMatrix      (MxC)
    572    */
    573 
    574 
    575   function _multiplySparseMatrixDenseMatrix(a, b) {
    576     // a sparse
    577     var avalues = a._values;
    578     var aindex = a._index;
    579     var aptr = a._ptr;
    580     var adt = a._datatype; // validate a matrix
    581 
    582     if (!avalues) {
    583       throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix');
    584     } // b dense
    585 
    586 
    587     var bdata = b._data;
    588     var bdt = b._datatype; // rows & columns
    589 
    590     var arows = a._size[0];
    591     var brows = b._size[0];
    592     var bcolumns = b._size[1]; // datatype
    593 
    594     var dt; // addScalar signature to use
    595 
    596     var af = addScalar; // multiplyScalar signature to use
    597 
    598     var mf = multiplyScalar; // equalScalar signature to use
    599 
    600     var eq = equalScalar; // zero value
    601 
    602     var zero = 0; // process data types
    603 
    604     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    605       // datatype
    606       dt = adt; // find signatures that matches (dt, dt)
    607 
    608       af = typed.find(addScalar, [dt, dt]);
    609       mf = typed.find(multiplyScalar, [dt, dt]);
    610       eq = typed.find(equalScalar, [dt, dt]); // convert 0 to the same datatype
    611 
    612       zero = typed.convert(0, dt);
    613     } // result
    614 
    615 
    616     var cvalues = [];
    617     var cindex = [];
    618     var cptr = []; // c matrix
    619 
    620     var c = a.createSparseMatrix({
    621       values: cvalues,
    622       index: cindex,
    623       ptr: cptr,
    624       size: [arows, bcolumns],
    625       datatype: dt
    626     }); // workspace
    627 
    628     var x = []; // vector with marks indicating a value x[i] exists in a given column
    629 
    630     var w = []; // loop b columns
    631 
    632     for (var jb = 0; jb < bcolumns; jb++) {
    633       // update ptr
    634       cptr[jb] = cindex.length; // mark in workspace for current column
    635 
    636       var mark = jb + 1; // rows in jb
    637 
    638       for (var ib = 0; ib < brows; ib++) {
    639         // b[ib, jb]
    640         var vbij = bdata[ib][jb]; // check b[ib, jb] != 0, avoid loops
    641 
    642         if (!eq(vbij, zero)) {
    643           // A values & index in ib column
    644           for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
    645             // a row
    646             var ia = aindex[ka]; // check value exists in current j
    647 
    648             if (w[ia] !== mark) {
    649               // ia is new entry in j
    650               w[ia] = mark; // add i to pattern of C
    651 
    652               cindex.push(ia); // x(ia) = A
    653 
    654               x[ia] = mf(vbij, avalues[ka]);
    655             } else {
    656               // i exists in C already
    657               x[ia] = af(x[ia], mf(vbij, avalues[ka]));
    658             }
    659           }
    660         }
    661       } // copy values from x to column jb of c
    662 
    663 
    664       for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) {
    665         // row
    666         var ic = cindex[p]; // copy value
    667 
    668         cvalues[p] = x[ic];
    669       }
    670     } // update ptr
    671 
    672 
    673     cptr[bcolumns] = cindex.length; // return sparse matrix
    674 
    675     return c;
    676   }
    677   /**
    678    * C = A * B
    679    *
    680    * @param {Matrix} a            SparseMatrix      (MxN)
    681    * @param {Matrix} b            SparseMatrix      (NxC)
    682    *
    683    * @return {Matrix}             SparseMatrix      (MxC)
    684    */
    685 
    686 
    687   function _multiplySparseMatrixSparseMatrix(a, b) {
    688     // a sparse
    689     var avalues = a._values;
    690     var aindex = a._index;
    691     var aptr = a._ptr;
    692     var adt = a._datatype; // b sparse
    693 
    694     var bvalues = b._values;
    695     var bindex = b._index;
    696     var bptr = b._ptr;
    697     var bdt = b._datatype; // rows & columns
    698 
    699     var arows = a._size[0];
    700     var bcolumns = b._size[1]; // flag indicating both matrices (a & b) contain data
    701 
    702     var values = avalues && bvalues; // datatype
    703 
    704     var dt; // addScalar signature to use
    705 
    706     var af = addScalar; // multiplyScalar signature to use
    707 
    708     var mf = multiplyScalar; // process data types
    709 
    710     if (adt && bdt && adt === bdt && typeof adt === 'string') {
    711       // datatype
    712       dt = adt; // find signatures that matches (dt, dt)
    713 
    714       af = typed.find(addScalar, [dt, dt]);
    715       mf = typed.find(multiplyScalar, [dt, dt]);
    716     } // result
    717 
    718 
    719     var cvalues = values ? [] : undefined;
    720     var cindex = [];
    721     var cptr = []; // c matrix
    722 
    723     var c = a.createSparseMatrix({
    724       values: cvalues,
    725       index: cindex,
    726       ptr: cptr,
    727       size: [arows, bcolumns],
    728       datatype: dt
    729     }); // workspace
    730 
    731     var x = values ? [] : undefined; // vector with marks indicating a value x[i] exists in a given column
    732 
    733     var w = []; // variables
    734 
    735     var ka, ka0, ka1, kb, kb0, kb1, ia, ib; // loop b columns
    736 
    737     for (var jb = 0; jb < bcolumns; jb++) {
    738       // update ptr
    739       cptr[jb] = cindex.length; // mark in workspace for current column
    740 
    741       var mark = jb + 1; // B values & index in j
    742 
    743       for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) {
    744         // b row
    745         ib = bindex[kb]; // check we need to process values
    746 
    747         if (values) {
    748           // loop values in a[:,ib]
    749           for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
    750             // row
    751             ia = aindex[ka]; // check value exists in current j
    752 
    753             if (w[ia] !== mark) {
    754               // ia is new entry in j
    755               w[ia] = mark; // add i to pattern of C
    756 
    757               cindex.push(ia); // x(ia) = A
    758 
    759               x[ia] = mf(bvalues[kb], avalues[ka]);
    760             } else {
    761               // i exists in C already
    762               x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka]));
    763             }
    764           }
    765         } else {
    766           // loop values in a[:,ib]
    767           for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
    768             // row
    769             ia = aindex[ka]; // check value exists in current j
    770 
    771             if (w[ia] !== mark) {
    772               // ia is new entry in j
    773               w[ia] = mark; // add i to pattern of C
    774 
    775               cindex.push(ia);
    776             }
    777           }
    778         }
    779       } // check we need to process matrix values (pattern matrix)
    780 
    781 
    782       if (values) {
    783         // copy values from x to column jb of c
    784         for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) {
    785           // row
    786           var ic = cindex[p]; // copy value
    787 
    788           cvalues[p] = x[ic];
    789         }
    790       }
    791     } // update ptr
    792 
    793 
    794     cptr[bcolumns] = cindex.length; // return sparse matrix
    795 
    796     return c;
    797   }
    798   /**
    799    * Multiply two or more values, `x * y`.
    800    * For matrices, the matrix product is calculated.
    801    *
    802    * Syntax:
    803    *
    804    *    math.multiply(x, y)
    805    *    math.multiply(x, y, z, ...)
    806    *
    807    * Examples:
    808    *
    809    *    math.multiply(4, 5.2)        // returns number 20.8
    810    *    math.multiply(2, 3, 4)       // returns number 24
    811    *
    812    *    const a = math.complex(2, 3)
    813    *    const b = math.complex(4, 1)
    814    *    math.multiply(a, b)          // returns Complex 5 + 14i
    815    *
    816    *    const c = [[1, 2], [4, 3]]
    817    *    const d = [[1, 2, 3], [3, -4, 7]]
    818    *    math.multiply(c, d)          // returns Array [[7, -6, 17], [13, -4, 33]]
    819    *
    820    *    const e = math.unit('2.1 km')
    821    *    math.multiply(3, e)          // returns Unit 6.3 km
    822    *
    823    * See also:
    824    *
    825    *    divide, prod, cross, dot
    826    *
    827    * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply
    828    * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply
    829    * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y`
    830    */
    831 
    832 
    833   return typed(name, (0, _object.extend)({
    834     // we extend the signatures of multiplyScalar with signatures dealing with matrices
    835     'Array, Array': function ArrayArray(x, y) {
    836       // check dimensions
    837       _validateMatrixDimensions((0, _array.arraySize)(x), (0, _array.arraySize)(y)); // use dense matrix implementation
    838 
    839 
    840       var m = this(matrix(x), matrix(y)); // return array or scalar
    841 
    842       return (0, _is.isMatrix)(m) ? m.valueOf() : m;
    843     },
    844     'Matrix, Matrix': function MatrixMatrix(x, y) {
    845       // dimensions
    846       var xsize = x.size();
    847       var ysize = y.size(); // check dimensions
    848 
    849       _validateMatrixDimensions(xsize, ysize); // process dimensions
    850 
    851 
    852       if (xsize.length === 1) {
    853         // process y dimensions
    854         if (ysize.length === 1) {
    855           // Vector * Vector
    856           return _multiplyVectorVector(x, y, xsize[0]);
    857         } // Vector * Matrix
    858 
    859 
    860         return _multiplyVectorMatrix(x, y);
    861       } // process y dimensions
    862 
    863 
    864       if (ysize.length === 1) {
    865         // Matrix * Vector
    866         return _multiplyMatrixVector(x, y);
    867       } // Matrix * Matrix
    868 
    869 
    870       return _multiplyMatrixMatrix(x, y);
    871     },
    872     'Matrix, Array': function MatrixArray(x, y) {
    873       // use Matrix * Matrix implementation
    874       return this(x, matrix(y));
    875     },
    876     'Array, Matrix': function ArrayMatrix(x, y) {
    877       // use Matrix * Matrix implementation
    878       return this(matrix(x, y.storage()), y);
    879     },
    880     'SparseMatrix, any': function SparseMatrixAny(x, y) {
    881       return algorithm11(x, y, multiplyScalar, false);
    882     },
    883     'DenseMatrix, any': function DenseMatrixAny(x, y) {
    884       return algorithm14(x, y, multiplyScalar, false);
    885     },
    886     'any, SparseMatrix': function anySparseMatrix(x, y) {
    887       return algorithm11(y, x, multiplyScalar, true);
    888     },
    889     'any, DenseMatrix': function anyDenseMatrix(x, y) {
    890       return algorithm14(y, x, multiplyScalar, true);
    891     },
    892     'Array, any': function ArrayAny(x, y) {
    893       // use matrix implementation
    894       return algorithm14(matrix(x), y, multiplyScalar, false).valueOf();
    895     },
    896     'any, Array': function anyArray(x, y) {
    897       // use matrix implementation
    898       return algorithm14(matrix(y), x, multiplyScalar, true).valueOf();
    899     },
    900     'any, any': multiplyScalar,
    901     'any, any, ...any': function anyAnyAny(x, y, rest) {
    902       var result = this(x, y);
    903 
    904       for (var i = 0; i < rest.length; i++) {
    905         result = this(result, rest[i]);
    906       }
    907 
    908       return result;
    909     }
    910   }, multiplyScalar.signatures));
    911 });
    912 exports.createMultiply = createMultiply;