@@ -203,15 +203,25 @@ end
203
203
return SparseArrayDOK {T} (size... )
204
204
end
205
205
206
+ # map over a specified subset of indices of the inputs.
207
+ function map_indices! end
208
+
209
+ @interface interface:: AbstractArrayInterface function map_indices! (
210
+ f, a_dest:: AbstractArray , indices, as:: AbstractArray...
211
+ )
212
+ for I in indices
213
+ a_dest[I] = f (map (a -> a[I], as)... )
214
+ end
215
+ return a_dest
216
+ end
217
+
206
218
# Only map the stored values of the inputs.
207
219
function map_stored! end
208
220
209
221
@interface interface:: AbstractArrayInterface function map_stored! (
210
222
f, a_dest:: AbstractArray , as:: AbstractArray...
211
223
)
212
- for I in eachstoredindex (as... )
213
- a_dest[I] = f (map (a -> a[I], as)... )
214
- end
224
+ @interface interface map_indices! (f, a_dest, eachstoredindex (as... ), as... )
215
225
return a_dest
216
226
end
217
227
@@ -221,9 +231,7 @@ function map_all! end
221
231
@interface interface:: AbstractArrayInterface function map_all! (
222
232
f, a_dest:: AbstractArray , as:: AbstractArray...
223
233
)
224
- for I in eachindex (as... )
225
- a_dest[I] = map (f, map (a -> a[I], as)... )
226
- end
234
+ @interface interface map_indices! (f, a_dest, eachindex (as... ), as... )
227
235
return a_dest
228
236
end
229
237
@@ -261,19 +269,18 @@ end
261
269
@interface interface map_all! (f, a_dest, as... )
262
270
return a_dest
263
271
end
264
- # First zero out the destination.
265
- # TODO : Make this more nuanced, skip when possible, for
266
- # example if the sparsity of the destination is a subset of
267
- # the sparsity of the sources, i.e.:
268
- # ```julia
269
- # if eachstoredindex(as...) ∉ eachstoredindex(a_dest)
270
- # zero!(a_dest)
271
- # end
272
- # ```
273
- # This is the safest thing to do in general, for example
274
- # if the destination is dense but the sources are sparse.
275
- @interface interface zero! (a_dest)
276
- @interface interface map_stored! (f, a_dest, as... )
272
+ # Unalias the inputs from the destination
273
+ # to make sure the inputs aren't overwritten incorrectly.
274
+ # See: https://github.com/JuliaLang/julia/blob/v1.11.2/base/broadcast.jl#L935-L948
275
+ as = map (a -> a_dest === a ? a : Base. unalias (a_dest, a), as)
276
+ indices_stored = eachstoredindex (as... )
277
+ if eachstoredindex (a_dest) ⊈ indices_stored
278
+ # If not all indices being mapped over are stored in the destination,
279
+ # zero out the destination. An extreme example of this is when
280
+ # the sources are sparse but the destination is dense.
281
+ @interface interface zero! (a_dest)
282
+ end
283
+ @interface interface map_indices! (f, a_dest, indices_stored, as... )
277
284
return a_dest
278
285
end
279
286
0 commit comments