If I got the question right, the problem is given $a_{ijk}$ and $b_{ijkl}$ to form
$$ c_{ijkl} = a_{ijb_{ijlk}} $$
or in matlab notation
C(i,j,k,l) = A(i,j,B(i,j,l,k));
4 nested loops
Without colon notation this would require 4 nested loops over variables i,j,k,l:
C(n1,n2,N,n3) = 0.0; % equivalent to C = zeros(n1,n2,N,n3);
for i = 1:n1,
for j = 1:n2,
for k = 1:N,
for l = 1:n3,
C(i,j,k,l) = A(i,j,B(i,j,l,k));
end,
end,
end,
end,
Note the preallocation of array C: having variable sized arrays inside a for loop is normally the main reason for inefficiency. In fact matlab is pretty good (compared to python) in evaluating for loops, provided that the l.h.s. does not change size during the iterations.
2 nested loops
Now let's go for the easy vectorization, eliminating the loops over k and l. The main problem here is that k,l are swapped in C and B so we have to permute the array dimensions:
C(n1,n2,n3,N) = 0.0;
for i = 1:n1,
for j = 1:n2,
C(i,j,:) = A(i,j,B(i,j,:));
end,
end,
C = permute(C, [1 2 4 3]);
(Remember that a trailing colon in an array squeezes all remaining dimension into a single one: size(C(i,j,:)) == [1 1 n3*N] ; correct stride is preserved, so that C(i,j,:) is OK as a l.h.s.)
no loops
Edited: corrected error and inserted final solution.
Now for the hard part of the question: how to eliminate the loops over i and j. The idea is simple: find an integer array indx such that C == A(indx): in fact A(indx) is an array with the same shape of indx and elements taken from A regarded as a single column.
In order to construct this array, we have to remember that matlab follows fortran convention:
size(A) == [n1 n2 n3]
A(i,j,k) == A(i + (j-1)*n1 + (k-1)*n1*n2)
So here is how to construct this matrix with 2 nested loops:
indx(n1,n2,n3,N) = 0.0;
for j=1:n2,
for i=1:n1,
indx(i,j,:) = i+(j-1)*n1+(B(i,j,:)-1)*n1*n2;
end,
end,
or with two instructions
indx = (B-1)*n1*n2;
indx(:) = indx(:) + repmat(1:n1*n2, n3*N)'
The no loops code reads
indx = (B-1)*n1*n2;
indx(:) = indx(:) + repmat(1:n1*n2, 1, n3*N)';
indx = permute(indx, [1 2 4 3]);
C = A(indx);
conclusions
In my opinion the most efficient way of computing C should be the 2 nested loops version. In the no loops version we put a great effort in computing indx instead of letting matlab do his own pointer arithmetic, so I would discourage it, unless the same array B and therefore the same vector indx can be used multiple times with different A arrays.
If this is the case I would still recommend to compute indx by two nested loops, instead of the no loops version. (Here Godric Seer is right: it is almost impossible to understand the logic behind.)
Let me stress out an important point: if array C is pre-allocated, two nested loops will be very fast in matlab, and there will be no substantial advantage in going to a no loops version, unless we have a fast method of computing the indx vector. (E.g. by using integer arithmetic.)
Hope this lengthy reply will be useful.
Edited previous wrong no loops version:
C(n1,n2,n3,N) = 0.0;
indx = ... % to be defined later
C(:) = A(indx);
C = permute(C, [1 2 4 3]);
Here we have to exploit the fact that C(:) is the multi-dimensional array viewed as a single column, and A(indx) is a single column of elements picked from A. We have to know how pointer arithmetic works in matlab
size(C) == [n1 n2 n3 N]
C(i,j,k,l) == C(i + (j-1)*n1 + (k-1)*n1*n2 + (l-1)*n1*n2*n3 )
Now
C(i,j,k,l) = A(i,j,B(i,j,k,l))
can be written as
C(i,j,k,l) = A(i + (j-1)*n1 + (B(i,j,k,l)-1)*n1*n2 );
or even
C(i,j,:) = A(i + (j-1)*n1 + (B(i,j,:)-1)*n1*n2);
therefore we can compute indx as
indx = [];
for j=1:n2,
for i=1:n1,
indx = [ indx, reshape( i+(j-1)*n1+(B(i,j,:)-1)*n1*n2, 1, n3*N ) ];
end,
end,
With some effort it should be possible to compute indx without loops: however I have no time to derive it now. By the way I fear that it would be neither elegant nor efficient, but who knows for sure!