UNPKG

25 kBJavaScriptView Raw
1import { isArray, isBigNumber, isIndex, isMatrix, isNumber, isString, typeOf } from '../../utils/is'
2import { arraySize, getArrayDataType, reshape, resize, unsqueeze, validate, validateIndex } from '../../utils/array'
3import { format } from '../../utils/string'
4import { isInteger } from '../../utils/number'
5import { clone, deepStrictEqual } from '../../utils/object'
6import { DimensionError } from '../../error/DimensionError'
7import { factory } from '../../utils/factory'
8
9const name = 'DenseMatrix'
10const dependencies = [
11 'Matrix'
12]
13
14export const createDenseMatrixClass = /* #__PURE__ */ factory(name, dependencies, ({ Matrix }) => {
15 /**
16 * Dense Matrix implementation. A regular, dense matrix, supporting multi-dimensional matrices. This is the default matrix type.
17 * @class DenseMatrix
18 */
19 function DenseMatrix (data, datatype) {
20 if (!(this instanceof DenseMatrix)) { throw new SyntaxError('Constructor must be called with the new operator') }
21 if (datatype && !isString(datatype)) { throw new Error('Invalid datatype: ' + datatype) }
22
23 if (isMatrix(data)) {
24 // check data is a DenseMatrix
25 if (data.type === 'DenseMatrix') {
26 // clone data & size
27 this._data = clone(data._data)
28 this._size = clone(data._size)
29 this._datatype = datatype || data._datatype
30 } else {
31 // build data from existing matrix
32 this._data = data.toArray()
33 this._size = data.size()
34 this._datatype = datatype || data._datatype
35 }
36 } else if (data && isArray(data.data) && isArray(data.size)) {
37 // initialize fields from JSON representation
38 this._data = data.data
39 this._size = data.size
40 this._datatype = datatype || data.datatype
41 } else if (isArray(data)) {
42 // replace nested Matrices with Arrays
43 this._data = preprocess(data)
44 // get the dimensions of the array
45 this._size = arraySize(this._data)
46 // verify the dimensions of the array, TODO: compute size while processing array
47 validate(this._data, this._size)
48 // data type unknown
49 this._datatype = datatype
50 } else if (data) {
51 // unsupported type
52 throw new TypeError('Unsupported type of data (' + typeOf(data) + ')')
53 } else {
54 // nothing provided
55 this._data = []
56 this._size = [0]
57 this._datatype = datatype
58 }
59 }
60
61 DenseMatrix.prototype = new Matrix()
62
63 /**
64 * Create a new DenseMatrix
65 */
66 DenseMatrix.prototype.createDenseMatrix = function (data, datatype) {
67 return new DenseMatrix(data, datatype)
68 }
69
70 /**
71 * Attach type information
72 */
73 DenseMatrix.prototype.type = 'DenseMatrix'
74 DenseMatrix.prototype.isDenseMatrix = true
75
76 /**
77 * Get the matrix type
78 *
79 * Usage:
80 * const matrixType = matrix.getDataType() // retrieves the matrix type
81 *
82 * @memberOf DenseMatrix
83 * @return {string} type information; if multiple types are found from the Matrix, it will return "mixed"
84 */
85 DenseMatrix.prototype.getDataType = function () {
86 return getArrayDataType(this._data, typeOf)
87 }
88
89 /**
90 * Get the storage format used by the matrix.
91 *
92 * Usage:
93 * const format = matrix.storage() // retrieve storage format
94 *
95 * @memberof DenseMatrix
96 * @return {string} The storage format.
97 */
98 DenseMatrix.prototype.storage = function () {
99 return 'dense'
100 }
101
102 /**
103 * Get the datatype of the data stored in the matrix.
104 *
105 * Usage:
106 * const format = matrix.datatype() // retrieve matrix datatype
107 *
108 * @memberof DenseMatrix
109 * @return {string} The datatype.
110 */
111 DenseMatrix.prototype.datatype = function () {
112 return this._datatype
113 }
114
115 /**
116 * Create a new DenseMatrix
117 * @memberof DenseMatrix
118 * @param {Array} data
119 * @param {string} [datatype]
120 */
121 DenseMatrix.prototype.create = function (data, datatype) {
122 return new DenseMatrix(data, datatype)
123 }
124
125 /**
126 * Get a subset of the matrix, or replace a subset of the matrix.
127 *
128 * Usage:
129 * const subset = matrix.subset(index) // retrieve subset
130 * const value = matrix.subset(index, replacement) // replace subset
131 *
132 * @memberof DenseMatrix
133 * @param {Index} index
134 * @param {Array | Matrix | *} [replacement]
135 * @param {*} [defaultValue=0] Default value, filled in on new entries when
136 * the matrix is resized. If not provided,
137 * new matrix elements will be filled with zeros.
138 */
139 DenseMatrix.prototype.subset = function (index, replacement, defaultValue) {
140 switch (arguments.length) {
141 case 1:
142 return _get(this, index)
143
144 // intentional fall through
145 case 2:
146 case 3:
147 return _set(this, index, replacement, defaultValue)
148
149 default:
150 throw new SyntaxError('Wrong number of arguments')
151 }
152 }
153
154 /**
155 * Get a single element from the matrix.
156 * @memberof DenseMatrix
157 * @param {number[]} index Zero-based index
158 * @return {*} value
159 */
160 DenseMatrix.prototype.get = function (index) {
161 if (!isArray(index)) { throw new TypeError('Array expected') }
162 if (index.length !== this._size.length) { throw new DimensionError(index.length, this._size.length) }
163
164 // check index
165 for (let x = 0; x < index.length; x++) { validateIndex(index[x], this._size[x]) }
166
167 let data = this._data
168 for (let i = 0, ii = index.length; i < ii; i++) {
169 const indexI = index[i]
170 validateIndex(indexI, data.length)
171 data = data[indexI]
172 }
173
174 return data
175 }
176
177 /**
178 * Replace a single element in the matrix.
179 * @memberof DenseMatrix
180 * @param {number[]} index Zero-based index
181 * @param {*} value
182 * @param {*} [defaultValue] Default value, filled in on new entries when
183 * the matrix is resized. If not provided,
184 * new matrix elements will be left undefined.
185 * @return {DenseMatrix} self
186 */
187 DenseMatrix.prototype.set = function (index, value, defaultValue) {
188 if (!isArray(index)) { throw new TypeError('Array expected') }
189 if (index.length < this._size.length) { throw new DimensionError(index.length, this._size.length, '<') }
190
191 let i, ii, indexI
192
193 // enlarge matrix when needed
194 const size = index.map(function (i) {
195 return i + 1
196 })
197 _fit(this, size, defaultValue)
198
199 // traverse over the dimensions
200 let data = this._data
201 for (i = 0, ii = index.length - 1; i < ii; i++) {
202 indexI = index[i]
203 validateIndex(indexI, data.length)
204 data = data[indexI]
205 }
206
207 // set new value
208 indexI = index[index.length - 1]
209 validateIndex(indexI, data.length)
210 data[indexI] = value
211
212 return this
213 }
214
215 /**
216 * Get a submatrix of this matrix
217 * @memberof DenseMatrix
218 * @param {DenseMatrix} matrix
219 * @param {Index} index Zero-based index
220 * @private
221 */
222 function _get (matrix, index) {
223 if (!isIndex(index)) {
224 throw new TypeError('Invalid index')
225 }
226
227 const isScalar = index.isScalar()
228 if (isScalar) {
229 // return a scalar
230 return matrix.get(index.min())
231 } else {
232 // validate dimensions
233 const size = index.size()
234 if (size.length !== matrix._size.length) {
235 throw new DimensionError(size.length, matrix._size.length)
236 }
237
238 // validate if any of the ranges in the index is out of range
239 const min = index.min()
240 const max = index.max()
241 for (let i = 0, ii = matrix._size.length; i < ii; i++) {
242 validateIndex(min[i], matrix._size[i])
243 validateIndex(max[i], matrix._size[i])
244 }
245
246 // retrieve submatrix
247 // TODO: more efficient when creating an empty matrix and setting _data and _size manually
248 return new DenseMatrix(_getSubmatrix(matrix._data, index, size.length, 0), matrix._datatype)
249 }
250 }
251
252 /**
253 * Recursively get a submatrix of a multi dimensional matrix.
254 * Index is not checked for correct number or length of dimensions.
255 * @memberof DenseMatrix
256 * @param {Array} data
257 * @param {Index} index
258 * @param {number} dims Total number of dimensions
259 * @param {number} dim Current dimension
260 * @return {Array} submatrix
261 * @private
262 */
263 function _getSubmatrix (data, index, dims, dim) {
264 const last = (dim === dims - 1)
265 const range = index.dimension(dim)
266
267 if (last) {
268 return range.map(function (i) {
269 validateIndex(i, data.length)
270 return data[i]
271 }).valueOf()
272 } else {
273 return range.map(function (i) {
274 validateIndex(i, data.length)
275 const child = data[i]
276 return _getSubmatrix(child, index, dims, dim + 1)
277 }).valueOf()
278 }
279 }
280
281 /**
282 * Replace a submatrix in this matrix
283 * Indexes are zero-based.
284 * @memberof DenseMatrix
285 * @param {DenseMatrix} matrix
286 * @param {Index} index
287 * @param {DenseMatrix | Array | *} submatrix
288 * @param {*} defaultValue Default value, filled in on new entries when
289 * the matrix is resized.
290 * @return {DenseMatrix} matrix
291 * @private
292 */
293 function _set (matrix, index, submatrix, defaultValue) {
294 if (!index || index.isIndex !== true) {
295 throw new TypeError('Invalid index')
296 }
297
298 // get index size and check whether the index contains a single value
299 const iSize = index.size()
300 const isScalar = index.isScalar()
301
302 // calculate the size of the submatrix, and convert it into an Array if needed
303 let sSize
304 if (isMatrix(submatrix)) {
305 sSize = submatrix.size()
306 submatrix = submatrix.valueOf()
307 } else {
308 sSize = arraySize(submatrix)
309 }
310
311 if (isScalar) {
312 // set a scalar
313
314 // check whether submatrix is a scalar
315 if (sSize.length !== 0) {
316 throw new TypeError('Scalar expected')
317 }
318
319 matrix.set(index.min(), submatrix, defaultValue)
320 } else {
321 // set a submatrix
322
323 // validate dimensions
324 if (iSize.length < matrix._size.length) {
325 throw new DimensionError(iSize.length, matrix._size.length, '<')
326 }
327
328 if (sSize.length < iSize.length) {
329 // calculate number of missing outer dimensions
330 let i = 0
331 let outer = 0
332 while (iSize[i] === 1 && sSize[i] === 1) {
333 i++
334 }
335 while (iSize[i] === 1) {
336 outer++
337 i++
338 }
339
340 // unsqueeze both outer and inner dimensions
341 submatrix = unsqueeze(submatrix, iSize.length, outer, sSize)
342 }
343
344 // check whether the size of the submatrix matches the index size
345 if (!deepStrictEqual(iSize, sSize)) {
346 throw new DimensionError(iSize, sSize, '>')
347 }
348
349 // enlarge matrix when needed
350 const size = index.max().map(function (i) {
351 return i + 1
352 })
353 _fit(matrix, size, defaultValue)
354
355 // insert the sub matrix
356 const dims = iSize.length
357 const dim = 0
358 _setSubmatrix(matrix._data, index, submatrix, dims, dim)
359 }
360
361 return matrix
362 }
363
364 /**
365 * Replace a submatrix of a multi dimensional matrix.
366 * @memberof DenseMatrix
367 * @param {Array} data
368 * @param {Index} index
369 * @param {Array} submatrix
370 * @param {number} dims Total number of dimensions
371 * @param {number} dim
372 * @private
373 */
374 function _setSubmatrix (data, index, submatrix, dims, dim) {
375 const last = (dim === dims - 1)
376 const range = index.dimension(dim)
377
378 if (last) {
379 range.forEach(function (dataIndex, subIndex) {
380 validateIndex(dataIndex)
381 data[dataIndex] = submatrix[subIndex[0]]
382 })
383 } else {
384 range.forEach(function (dataIndex, subIndex) {
385 validateIndex(dataIndex)
386 _setSubmatrix(data[dataIndex], index, submatrix[subIndex[0]], dims, dim + 1)
387 })
388 }
389 }
390
391 /**
392 * Resize the matrix to the given size. Returns a copy of the matrix when
393 * `copy=true`, otherwise return the matrix itself (resize in place).
394 *
395 * @memberof DenseMatrix
396 * @param {number[]} size The new size the matrix should have.
397 * @param {*} [defaultValue=0] Default value, filled in on new entries.
398 * If not provided, the matrix elements will
399 * be filled with zeros.
400 * @param {boolean} [copy] Return a resized copy of the matrix
401 *
402 * @return {Matrix} The resized matrix
403 */
404 DenseMatrix.prototype.resize = function (size, defaultValue, copy) {
405 // validate arguments
406 if (!isArray(size)) { throw new TypeError('Array expected') }
407
408 // matrix to resize
409 const m = copy ? this.clone() : this
410 // resize matrix
411 return _resize(m, size, defaultValue)
412 }
413
414 function _resize (matrix, size, defaultValue) {
415 // check size
416 if (size.length === 0) {
417 // first value in matrix
418 let v = matrix._data
419 // go deep
420 while (isArray(v)) {
421 v = v[0]
422 }
423 return v
424 }
425 // resize matrix
426 matrix._size = size.slice(0) // copy the array
427 matrix._data = resize(matrix._data, matrix._size, defaultValue)
428 // return matrix
429 return matrix
430 }
431
432 /**
433 * Reshape the matrix to the given size. Returns a copy of the matrix when
434 * `copy=true`, otherwise return the matrix itself (reshape in place).
435 *
436 * NOTE: This might be better suited to copy by default, instead of modifying
437 * in place. For now, it operates in place to remain consistent with
438 * resize().
439 *
440 * @memberof DenseMatrix
441 * @param {number[]} size The new size the matrix should have.
442 * @param {boolean} [copy] Return a reshaped copy of the matrix
443 *
444 * @return {Matrix} The reshaped matrix
445 */
446 DenseMatrix.prototype.reshape = function (size, copy) {
447 const m = copy ? this.clone() : this
448
449 m._data = reshape(m._data, size)
450 m._size = size.slice(0)
451 return m
452 }
453
454 /**
455 * Enlarge the matrix when it is smaller than given size.
456 * If the matrix is larger or equal sized, nothing is done.
457 * @memberof DenseMatrix
458 * @param {DenseMatrix} matrix The matrix to be resized
459 * @param {number[]} size
460 * @param {*} defaultValue Default value, filled in on new entries.
461 * @private
462 */
463 function _fit (matrix, size, defaultValue) {
464 const // copy the array
465 newSize = matrix._size.slice(0)
466
467 let changed = false
468
469 // add dimensions when needed
470 while (newSize.length < size.length) {
471 newSize.push(0)
472 changed = true
473 }
474
475 // enlarge size when needed
476 for (let i = 0, ii = size.length; i < ii; i++) {
477 if (size[i] > newSize[i]) {
478 newSize[i] = size[i]
479 changed = true
480 }
481 }
482
483 if (changed) {
484 // resize only when size is changed
485 _resize(matrix, newSize, defaultValue)
486 }
487 }
488
489 /**
490 * Create a clone of the matrix
491 * @memberof DenseMatrix
492 * @return {DenseMatrix} clone
493 */
494 DenseMatrix.prototype.clone = function () {
495 const m = new DenseMatrix({
496 data: clone(this._data),
497 size: clone(this._size),
498 datatype: this._datatype
499 })
500 return m
501 }
502
503 /**
504 * Retrieve the size of the matrix.
505 * @memberof DenseMatrix
506 * @returns {number[]} size
507 */
508 DenseMatrix.prototype.size = function () {
509 return this._size.slice(0) // return a clone of _size
510 }
511
512 /**
513 * Create a new matrix with the results of the callback function executed on
514 * each entry of the matrix.
515 * @memberof DenseMatrix
516 * @param {Function} callback The callback function is invoked with three
517 * parameters: the value of the element, the index
518 * of the element, and the Matrix being traversed.
519 *
520 * @return {DenseMatrix} matrix
521 */
522 DenseMatrix.prototype.map = function (callback) {
523 // matrix instance
524 const me = this
525 const recurse = function (value, index) {
526 if (isArray(value)) {
527 return value.map(function (child, i) {
528 return recurse(child, index.concat(i))
529 })
530 } else {
531 return callback(value, index, me)
532 }
533 }
534 // return dense format
535 return new DenseMatrix({
536 data: recurse(this._data, []),
537 size: clone(this._size),
538 datatype: this._datatype
539 })
540 }
541
542 /**
543 * Execute a callback function on each entry of the matrix.
544 * @memberof DenseMatrix
545 * @param {Function} callback The callback function is invoked with three
546 * parameters: the value of the element, the index
547 * of the element, and the Matrix being traversed.
548 */
549 DenseMatrix.prototype.forEach = function (callback) {
550 // matrix instance
551 const me = this
552 const recurse = function (value, index) {
553 if (isArray(value)) {
554 value.forEach(function (child, i) {
555 recurse(child, index.concat(i))
556 })
557 } else {
558 callback(value, index, me)
559 }
560 }
561 recurse(this._data, [])
562 }
563
564 /**
565 * Create an Array with a copy of the data of the DenseMatrix
566 * @memberof DenseMatrix
567 * @returns {Array} array
568 */
569 DenseMatrix.prototype.toArray = function () {
570 return clone(this._data)
571 }
572
573 /**
574 * Get the primitive value of the DenseMatrix: a multidimensional array
575 * @memberof DenseMatrix
576 * @returns {Array} array
577 */
578 DenseMatrix.prototype.valueOf = function () {
579 return this._data
580 }
581
582 /**
583 * Get a string representation of the matrix, with optional formatting options.
584 * @memberof DenseMatrix
585 * @param {Object | number | Function} [options] Formatting options. See
586 * lib/utils/number:format for a
587 * description of the available
588 * options.
589 * @returns {string} str
590 */
591 DenseMatrix.prototype.format = function (options) {
592 return format(this._data, options)
593 }
594
595 /**
596 * Get a string representation of the matrix
597 * @memberof DenseMatrix
598 * @returns {string} str
599 */
600 DenseMatrix.prototype.toString = function () {
601 return format(this._data)
602 }
603
604 /**
605 * Get a JSON representation of the matrix
606 * @memberof DenseMatrix
607 * @returns {Object}
608 */
609 DenseMatrix.prototype.toJSON = function () {
610 return {
611 mathjs: 'DenseMatrix',
612 data: this._data,
613 size: this._size,
614 datatype: this._datatype
615 }
616 }
617
618 /**
619 * Get the kth Matrix diagonal.
620 *
621 * @memberof DenseMatrix
622 * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved.
623 *
624 * @returns {Matrix} The matrix with the diagonal values.
625 */
626 DenseMatrix.prototype.diagonal = function (k) {
627 // validate k if any
628 if (k) {
629 // convert BigNumber to a number
630 if (isBigNumber(k)) { k = k.toNumber() }
631 // is must be an integer
632 if (!isNumber(k) || !isInteger(k)) {
633 throw new TypeError('The parameter k must be an integer number')
634 }
635 } else {
636 // default value
637 k = 0
638 }
639
640 const kSuper = k > 0 ? k : 0
641 const kSub = k < 0 ? -k : 0
642
643 // rows & columns
644 const rows = this._size[0]
645 const columns = this._size[1]
646
647 // number diagonal values
648 const n = Math.min(rows - kSub, columns - kSuper)
649
650 // x is a matrix get diagonal from matrix
651 const data = []
652
653 // loop rows
654 for (let i = 0; i < n; i++) {
655 data[i] = this._data[i + kSub][i + kSuper]
656 }
657
658 // create DenseMatrix
659 return new DenseMatrix({
660 data: data,
661 size: [n],
662 datatype: this._datatype
663 })
664 }
665
666 /**
667 * Create a diagonal matrix.
668 *
669 * @memberof DenseMatrix
670 * @param {Array} size The matrix size.
671 * @param {number | Matrix | Array } value The values for the diagonal.
672 * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in.
673 * @param {number} [defaultValue] The default value for non-diagonal
674 * @param {string} [datatype] The datatype for the diagonal
675 *
676 * @returns {DenseMatrix}
677 */
678 DenseMatrix.diagonal = function (size, value, k, defaultValue) {
679 if (!isArray(size)) { throw new TypeError('Array expected, size parameter') }
680 if (size.length !== 2) { throw new Error('Only two dimensions matrix are supported') }
681
682 // map size & validate
683 size = size.map(function (s) {
684 // check it is a big number
685 if (isBigNumber(s)) {
686 // convert it
687 s = s.toNumber()
688 }
689 // validate arguments
690 if (!isNumber(s) || !isInteger(s) || s < 1) {
691 throw new Error('Size values must be positive integers')
692 }
693 return s
694 })
695
696 // validate k if any
697 if (k) {
698 // convert BigNumber to a number
699 if (isBigNumber(k)) { k = k.toNumber() }
700 // is must be an integer
701 if (!isNumber(k) || !isInteger(k)) {
702 throw new TypeError('The parameter k must be an integer number')
703 }
704 } else {
705 // default value
706 k = 0
707 }
708
709 const kSuper = k > 0 ? k : 0
710 const kSub = k < 0 ? -k : 0
711
712 // rows and columns
713 const rows = size[0]
714 const columns = size[1]
715
716 // number of non-zero items
717 const n = Math.min(rows - kSub, columns - kSuper)
718
719 // value extraction function
720 let _value
721
722 // check value
723 if (isArray(value)) {
724 // validate array
725 if (value.length !== n) {
726 // number of values in array must be n
727 throw new Error('Invalid value array length')
728 }
729 // define function
730 _value = function (i) {
731 // return value @ i
732 return value[i]
733 }
734 } else if (isMatrix(value)) {
735 // matrix size
736 const ms = value.size()
737 // validate matrix
738 if (ms.length !== 1 || ms[0] !== n) {
739 // number of values in array must be n
740 throw new Error('Invalid matrix length')
741 }
742 // define function
743 _value = function (i) {
744 // return value @ i
745 return value.get([i])
746 }
747 } else {
748 // define function
749 _value = function () {
750 // return value
751 return value
752 }
753 }
754
755 // discover default value if needed
756 if (!defaultValue) {
757 // check first value in array
758 defaultValue = isBigNumber(_value(0))
759 ? _value(0).mul(0) // trick to create a BigNumber with value zero
760 : 0
761 }
762
763 // empty array
764 let data = []
765
766 // check we need to resize array
767 if (size.length > 0) {
768 // resize array
769 data = resize(data, size, defaultValue)
770 // fill diagonal
771 for (let d = 0; d < n; d++) {
772 data[d + kSub][d + kSuper] = _value(d)
773 }
774 }
775
776 // create DenseMatrix
777 return new DenseMatrix({
778 data: data,
779 size: [rows, columns]
780 })
781 }
782
783 /**
784 * Generate a matrix from a JSON object
785 * @memberof DenseMatrix
786 * @param {Object} json An object structured like
787 * `{"mathjs": "DenseMatrix", data: [], size: []}`,
788 * where mathjs is optional
789 * @returns {DenseMatrix}
790 */
791 DenseMatrix.fromJSON = function (json) {
792 return new DenseMatrix(json)
793 }
794
795 /**
796 * Swap rows i and j in Matrix.
797 *
798 * @memberof DenseMatrix
799 * @param {number} i Matrix row index 1
800 * @param {number} j Matrix row index 2
801 *
802 * @return {Matrix} The matrix reference
803 */
804 DenseMatrix.prototype.swapRows = function (i, j) {
805 // check index
806 if (!isNumber(i) || !isInteger(i) || !isNumber(j) || !isInteger(j)) {
807 throw new Error('Row index must be positive integers')
808 }
809 // check dimensions
810 if (this._size.length !== 2) {
811 throw new Error('Only two dimensional matrix is supported')
812 }
813 // validate index
814 validateIndex(i, this._size[0])
815 validateIndex(j, this._size[0])
816
817 // swap rows
818 DenseMatrix._swapRows(i, j, this._data)
819 // return current instance
820 return this
821 }
822
823 /**
824 * Swap rows i and j in Dense Matrix data structure.
825 *
826 * @param {number} i Matrix row index 1
827 * @param {number} j Matrix row index 2
828 * @param {Array} data Matrix data
829 */
830 DenseMatrix._swapRows = function (i, j, data) {
831 // swap values i <-> j
832 const vi = data[i]
833 data[i] = data[j]
834 data[j] = vi
835 }
836
837 /**
838 * Preprocess data, which can be an Array or DenseMatrix with nested Arrays and
839 * Matrices. Replaces all nested Matrices with Arrays
840 * @memberof DenseMatrix
841 * @param {Array} data
842 * @return {Array} data
843 */
844 function preprocess (data) {
845 for (let i = 0, ii = data.length; i < ii; i++) {
846 const elem = data[i]
847 if (isArray(elem)) {
848 data[i] = preprocess(elem)
849 } else if (elem && elem.isMatrix === true) {
850 data[i] = preprocess(elem.valueOf())
851 }
852 }
853
854 return data
855 }
856
857 return DenseMatrix
858}, { isClass: true })