multiply.js 24 KB

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