Julia (here 1.6RC1 on Windows 10) has a number of mechanism to calculate with positions inside an array such as ranges like (1:10) or generators or via CartesianIndices(x). Yet they all seem to not automatically propagate in larger pointwise array operations involving the array x and such index positions:
x = zeros(1000,1000);
xx(x) = (i[1] for i in CartesianIndices(x))
y = collect(xx(x))
@time y .= xx(x) .+ 0.0
Note that about 7.8 MB are allocated, which means that the “.+” operation forces an evaluation of xx(x) into an array instead of propagating the pointwise operation through the generator.
A similar effect is observed when encapsulating ranges in functions:
g(x) = (1:size(x,1)) .+ reshape((1:size(x,2)),(1,size(x,2)))
yy = g(x)
@time yy .= g(x)
Also here 7,8 Mb are allocated.
For longer expressions on arrays that involve mathematics using the index positions, I think it would be quite nice, if they could be written down in high-level notation without causing any intermediate array evaluations with associated memory and data transport overhead.
The only way, I was able to achieve this was via using a macro:
macro xx(x)
return :((1:size($x,1)) .+ reshape((1:size($x,2)),(1,size($x,2))))
end
yy = @xx(x)
@time yy .= @xx(x)
Note that there is no memory overhead this time, but writing macros sounds like not the ideal solution to me here.
So my question: Is there a way that one can prevent ranges or CartesianIndices from prematurely generating arrays when they are encapsulated in functions and used in point-wise expressions?
Alternatively: Is there a way to obtain access to index positions (such as a CartesianIndex) from inside scalar functions, if they are called with the dor (“.”) notation to be applied to an array. This would be extremely useful, as then one could easily write nice functions that not only involve values of arrays put also the local position inside the array.
Thanks for any help on this matter!