Recently, I began to study Julia, coding a simple implementation of Self Organizing Maps. I want the size and dimensions of the map to be specified by the user, which means that I cannot use loops to work with map arrays, because I do not know in advance how many layers of loops I will need. Therefore, I absolutely need the broadcast and slicing functions that work on arrays of arbitrary sizes.
Now I need to build an array of map indices. Let's say my map is defined by an array of size mapsize = (5, 10, 15) , I need to build an array of indices size (3, 5, 10, 15) , where indices[:, a, b, c] should return [a, b, c] .
I come from the Python / NumPy background, in which the solution is already defined by a specific "function", mgrid:
indices = numpy.mgrid[:5, :10, :15] print indices.shape
I did not expect that Julia would have such a function on the go, so I turned to broadcasting. In NumPy, translation is based on a set of rules that I find quite clear and logical. You can use arrays of different sizes in one expression if the sizes in each dimension are the same or one of them is 1:
(5, 10, 15) broadcasts to (5, 10, 15) (10, 1) (5, 1, 15) also broadcasts to (5, 10, 15) (1, 10, 1)
To help with this, you can also use numpy.newaxis or None to easily add new dimensions to your array:
array = numpy.zeros((5, 15)) array[:,None,:] has shape (5, 1, 15)
This makes it easy to cast arrays:
A = numpy.arange(5) B = numpy.arange(10) C = numpy.arange(15) bA, bB, bC = numpy.broadcast_arrays(A[:,None,None], B[None,:,None], C[None,None,:]) bA.shape == bB.shape == bC.shape = (5, 10, 15)
Using this, creating an indices array is quite simple:
indices = numpy.array(numpy.broadcast_arrays(A[:,None,None], B[None,:,None], C[None,None,:])) (indices == numpy.mgrid[:5,:10,:15]).all() returns True
The general case, of course, is a little more complicated, but it can be used using an understanding of lists and fragments:
arrays = [ numpy.arange(i)[tuple([None if m!=n else slice(None) for m in range(len(mapsize))])] for n, i in enumerate(mapsize) ] indices = numpy.array(numpy.broadcast_arrays(*arrays))
So back to Julia. I tried to apply the same rationale and ended up with the equivalent arrays list of the above code. This turned out to be simpler than the NumPy counterpart due to the syntax of the compound expression:
arrays = [ (idx = ones(Int, length(mapsize)); idx[n] = i;reshape([1:i], tuple(idx...))) for (n,i)=enumerate(mapsize) ]
Now I'm stuck here, since I really don’t know how to apply translation in my list of generator arrays here ... The broadcast[!] Functions require the use of the f function, and I don’t have any. I tried using the for loop to try to force broadcasting:
indices = Array(Int, tuple(unshift!([i for i=mapsize], length(mapsize))...)) for i=1:length(mapsize) A[i] = arrays[i] end
But this gives me an error: ERROR: convert has no method matching convert(::Type{Int64}, ::Array{Int64,3})
Am I doing it right? Am I missing something important? Any help is appreciated.