1 | import { factory } from '../../utils/factory'
|
2 | import { arraySize } from '../../utils/array'
|
3 | import { isMatrix } from '../../utils/is'
|
4 | import { IndexError } from '../../error/IndexError'
|
5 |
|
6 | const name = 'apply'
|
7 | const dependencies = ['typed', 'isInteger']
|
8 |
|
9 | export const createApply = /* #__PURE__ */ factory(name, dependencies, ({ typed, isInteger }) => {
|
10 | /**
|
11 | * Apply a function that maps an array to a scalar
|
12 | * along a given axis of a matrix or array.
|
13 | * Returns a new matrix or array with one less dimension than the input.
|
14 | *
|
15 | * Syntax:
|
16 | *
|
17 | * math.apply(A, dim, callback)
|
18 | *
|
19 | * Where:
|
20 | *
|
21 | * - `dim: number` is a zero-based dimension over which to concatenate the matrices.
|
22 | *
|
23 | * Examples:
|
24 | *
|
25 | * const A = [[1, 2], [3, 4]]
|
26 | * const sum = math.sum
|
27 | *
|
28 | * math.apply(A, 0, sum) // returns [4, 6]
|
29 | * math.apply(A, 1, sum) // returns [3, 7]
|
30 | *
|
31 | * See also:
|
32 | *
|
33 | * map, filter, forEach
|
34 | *
|
35 | * @param {Array | Matrix} array The input Matrix
|
36 | * @param {number} dim The dimension along which the callback is applied
|
37 | * @param {Function} callback The callback function that is applied. This Function
|
38 | * should take an array or 1-d matrix as an input and
|
39 | * return a number.
|
40 | * @return {Array | Matrix} res The residual matrix with the function applied over some dimension.
|
41 | */
|
42 | return typed(name, {
|
43 | 'Array | Matrix, number | BigNumber, function': function (mat, dim, callback) {
|
44 | if (!isInteger(dim)) {
|
45 | throw new TypeError('Integer number expected for dimension')
|
46 | }
|
47 |
|
48 | const size = Array.isArray(mat) ? arraySize(mat) : mat.size()
|
49 | if (dim < 0 || (dim >= size.length)) {
|
50 | throw new IndexError(dim, size.length)
|
51 | }
|
52 |
|
53 | if (isMatrix(mat)) {
|
54 | return mat.create(_apply(mat.valueOf(), dim, callback))
|
55 | } else {
|
56 | return _apply(mat, dim, callback)
|
57 | }
|
58 | }
|
59 | })
|
60 | })
|
61 |
|
62 | /**
|
63 | * Recursively reduce a matrix
|
64 | * @param {Array} mat
|
65 | * @param {number} dim
|
66 | * @param {Function} callback
|
67 | * @returns {Array} ret
|
68 | * @private
|
69 | */
|
70 | function _apply (mat, dim, callback) {
|
71 | let i, ret, tran
|
72 |
|
73 | if (dim <= 0) {
|
74 | if (!Array.isArray(mat[0])) {
|
75 | return callback(mat)
|
76 | } else {
|
77 | tran = _switch(mat)
|
78 | ret = []
|
79 | for (i = 0; i < tran.length; i++) {
|
80 | ret[i] = _apply(tran[i], dim - 1, callback)
|
81 | }
|
82 | return ret
|
83 | }
|
84 | } else {
|
85 | ret = []
|
86 | for (i = 0; i < mat.length; i++) {
|
87 | ret[i] = _apply(mat[i], dim - 1, callback)
|
88 | }
|
89 | return ret
|
90 | }
|
91 | }
|
92 |
|
93 | /**
|
94 | * Transpose a matrix
|
95 | * @param {Array} mat
|
96 | * @returns {Array} ret
|
97 | * @private
|
98 | */
|
99 | function _switch (mat) {
|
100 | const I = mat.length
|
101 | const J = mat[0].length
|
102 | let i, j
|
103 | const ret = []
|
104 | for (j = 0; j < J; j++) {
|
105 | const tmp = []
|
106 | for (i = 0; i < I; i++) {
|
107 | tmp.push(mat[i][j])
|
108 | }
|
109 | ret.push(tmp)
|
110 | }
|
111 | return ret
|
112 | }
|