Skip to content

Commit 422a2e4

Browse files
committed
Initial implementation of faster mapping of multiple arrays.
1 parent e84ade6 commit 422a2e4

File tree

1 file changed

+86
-13
lines changed

1 file changed

+86
-13
lines changed

src/function/matrix/map.js

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,34 +79,44 @@ export const createMap = /* #__PURE__ */ factory(name, dependencies, ({ typed })
7979
}
8080

8181
const firstArrayIsMatrix = Arrays[0].isMatrix
82-
83-
const newSize = broadcastSizes(...Arrays.map(M => M.isMatrix ? M.size() : arraySize(M)))
82+
const sizes = Arrays.map(M => M.isMatrix ? M.size() : arraySize(M))
83+
const newSize = broadcastSizes(...sizes)
84+
const numberOfArrays = Arrays.length
8485

8586
const _get = firstArrayIsMatrix
8687
? (matrix, idx) => matrix.get(idx)
8788
: get
8889

89-
const broadcastedArrays = firstArrayIsMatrix
90-
? Arrays.map(M => M.isMatrix
91-
? M.create(broadcastTo(M.toArray(), newSize), M.datatype())
92-
: Arrays[0].create(broadcastTo(M.valueOf(), newSize)))
93-
: Arrays.map(M => M.isMatrix
94-
? broadcastTo(M.toArray(), newSize)
95-
: broadcastTo(M, newSize))
90+
const firstValues = Arrays.map((collection, i) => {
91+
const firstIndex = sizes[i].map(x => 0)
92+
return collection.isMatrix ? collection.get(firstIndex) : get(collection, firstIndex)
93+
}
94+
)
9695

9796
let callback
97+
let callbackCase
9898

9999
if (typed.isTypedFunction(multiCallback)) {
100100
const firstIndex = newSize.map(() => 0)
101-
const firstValues = broadcastedArrays.map(array => _get(array, firstIndex))
102-
const callbackCase = _getTypedCallbackCase(multiCallback, firstValues, firstIndex, broadcastedArrays)
101+
callbackCase = _getTypedCallbackCase(multiCallback, firstValues, firstIndex, Arrays)
103102
callback = _getLimitedCallback(callbackCase)
104103
} else {
105-
const numberOfArrays = Arrays.length
106-
const callbackCase = _getCallbackCase(multiCallback, numberOfArrays)
104+
callbackCase = _getCallbackCase(multiCallback, numberOfArrays)
107105
callback = _getLimitedCallback(callbackCase)
108106
}
109107

108+
if (callbackCase < 2) {
109+
return mapMultiple(Arrays, callback)
110+
}
111+
112+
const broadcastedArrays = firstArrayIsMatrix
113+
? Arrays.map(M => M.isMatrix
114+
? M.create(broadcastTo(M.toArray(), newSize), M.datatype())
115+
: Arrays[0].create(broadcastTo(M.valueOf(), newSize)))
116+
: Arrays.map(M => M.isMatrix
117+
? broadcastTo(M.toArray(), newSize)
118+
: broadcastTo(M, newSize))
119+
110120
const broadcastedArraysCallback = (x, idx) =>
111121
callback(
112122
[x, ...broadcastedArrays.slice(1).map(Array => _get(Array, idx))],
@@ -143,6 +153,69 @@ export const createMap = /* #__PURE__ */ factory(name, dependencies, ({ typed })
143153
return 0
144154
}
145155
}
156+
157+
function mapMultiple (Collections, callback) {
158+
// collections can be matrices or arrays
159+
// callback must be a function of the form (collcetions, [index])
160+
const firstCollection = Collections[0]
161+
const firstCollectionIsMatrix = Boolean(firstCollection.isMatrix)
162+
const Arrays = Collections.map((collection) =>
163+
collection.isMatrix ? collection.valueOf() : collection
164+
)
165+
const sizes = Collections.map((collection) =>
166+
collection.isMatrix ? collection.size() : arraySize(collection)
167+
)
168+
// this should be changed for the specific function when impelemented
169+
const finalSize = broadcastSizes(...sizes)
170+
// the offset means for each initial array, how much smaller is it than the final size
171+
const offsets = sizes.map((size) => finalSize.length - size.length)
172+
// make the iteration algorithm
173+
const maxDepth = finalSize.length - 1
174+
const index = []
175+
const resultsArray = iterate(Arrays, 0)
176+
if (firstCollectionIsMatrix) {
177+
const returnMatrix = firstCollection.create()
178+
returnMatrix._data = resultsArray
179+
returnMatrix._size = finalSize
180+
return returnMatrix
181+
} else {
182+
return resultsArray
183+
}
184+
// will create references to the arrays depth, depending on the offset.
185+
186+
function iterate (arrays, depth = 0) {
187+
// each array can have differt sizes
188+
const N = finalSize[depth]
189+
const result = Array(N)
190+
if (depth < maxDepth) {
191+
for (let i = 0; i < N; i++) {
192+
index[depth] = i
193+
// if there is an offset greather than the current dimension
194+
// pass the array, if the size of the array is 1 pass the first
195+
// element of the array
196+
result[i] = iterate(
197+
arrays.map((array, arrayIndex) =>
198+
offsets[arrayIndex] > depth
199+
? array
200+
: array.length === 1
201+
? array[0]
202+
: array[i]
203+
),
204+
depth + 1
205+
)
206+
}
207+
} else {
208+
for (let i = 0; i < N; i++) {
209+
index[depth] = i
210+
result[i] = callback(
211+
arrays.map((a) => (a.length === 1 ? a[0] : a[i])),
212+
index.slice()
213+
)
214+
}
215+
}
216+
return result
217+
}
218+
}
146219
/**
147220
* Map for a multi dimensional array
148221
* @param {Array} array

0 commit comments

Comments
 (0)