I am trying to create a tensor (can be conceived as a multidimensional array) package in scala. So far I was storing the data in a 1D Vector and doing index arithmetic.
But slicing and subarrays are not so easy to get. One needs to do a lot of arithmetic to convert multidimensional indices to 1D indices.
Is there any optimal way of storing a multidimensional array? If not, i.e. 1D array is the best solution, how one can optimally slice arrays (some concrete code would really help me)?
The key to answering this question is: when is pointer indirection faster than arithmetic? The answer is pretty much never. In-order traversals can be about equally fast for 2D, and things get worse from there:
So you’re better off just doing the math.
Now the question is how to do slicing. Initially, if you have dimensions of n1, n2, n3, … and indices of i1, i2, i3, …, you compute the offset into the array by
where typically
i1is chosen to be the last (innermost) dimension (but in general it should be the dimension most often in the innermost loop). That is, if it were an array of arrays of (…), you would index into it asa(...)(i3)(i2)(i1).Now suppose you want to slice this. First, you might give an offset o1, o2, o3 to every index:
and then you will have a shorter range on each (let’s call these m1, m2, m3, …).
Finally, if you eliminate a dimension entirely–let’s say, for example, that
m2 == 1, meaning thati2 == 0, you just simplify the formula:I will leave it as an exercise to the reader to figure out how to do this in general, but note that we can store new constants
o1 + n1*o21andn1+n2so we don’t need to keep doing that math on the slice.Finally, if you are allowing arbitrary dimensions, you just put that math into a while loop. This does, admittedly, slow it down a little bit, but you’re still at least as well off as if you’d used a pointer dereference (in almost every case).