tags:

views:

322

answers:

2

Given an n-dimensional matrix of values: what is the most efficient way of retrieving values by arbitrary indices (i.e. coordinates)?

E.g. in a random 5x5 matrix, if I want the values at (1,1) (2,3) and (4,5) what is the most efficient way of returning just the values at these coordinates?

If I provide these coordinates in a separate matrix for example is there a one line of MATLAB which can do the job? Something like:

    x=rand(5,5);

    y=[[1,1];[2,3];[4,5]];

    z=x(y);

Except that doesn't work.

One caveat however, for various reasons I am unable to use linear indexing - the results must be returned using the original indices. And the size of these matrices is potentially very large so I don't want to use loops either.

+4  A: 

If you're against using linear indexing and loops, the only other alternative, AFAIK, is logical indexing. But if y always comes in the form you've suggested, you'll need to create a logical matrix from the indices specified in y.

Could you explain why linear indexing is not allowed?

Anyway, if you want a really stupid answer (which is all I can provide with this much information):

z = diag(x(y(:,1),y(:,2)))

Of course, this will needlessly create a huge matrix and extract the diagonal elements (the ones you need) from it - but it gets it done in one line, etc.

EDIT: If the restriction is using linear indexing on the original data, then you can use linear indexing to create a logical matrix and index x with that. E.g.

% Each element of L is only one byte
L = false(size(x)); 
% Create the logical mask
L(sub2ind(size(x),y(:,1),y(:,2))) = true;
% Extract the required elements
z = x(L);

Similarly, for a 3-dimensional matrix:

x = rand(3,3,3);
y = [1 1 1;2 2 2;3 3 3];
L = false(size(x));
L(sub2ind(size(x),y(:,1),y(:,2),y(:,3))) = true;
z = x(L);

Also, logical indexing is supposed to be faster than linear indexing, so apart from building the mask, you're in good shape.

Jacob
Linear indexing is not an option because the matrices are very large and are chunked by the underlying toolkit we are using - in fact this question came from the fact that the toolkit fails when you try and use linear indexing to access the data.The diag idea would work except that we are using 3 dimensional data so the size of the resulting matrix would be the cube of the original matrix which as you say is needlessly huge.Thanks anyway
Ok, created a logical mask using linear indexing and used it to query `x`.
Jacob
Thanks for the alternative option, its interesting. In the meantime we worked out the problem came from trying to access data from different chunks when the chunks weren't all in memory. By ordering the coordinate access first we have worked around the problem.
A: 

why isn't sub2ind alone suitable for this problem? I don't see the need for the logical mask; e.g.

z = x(sub2ind(size(x),y(:,1),y(:,2)))

should work as well.

shabbychef
I thought the same thing, until I noticed the comment the OP left on Jacob's answer. Linear indexing seems to be out of the question.
gnovice
I'm not sure what one means by 'linear indexing is out of the question'; it sounded like either the OP wasn't aware of sub2ind or wanted to attach shape to the LHS variable, z, based on y?
shabbychef
@shabychef: It doesn't make much sense to me either, which is why I asked for a little more info from the OP. It may be that the "linear indexing" they were trying to do was actually not linear indexing at all and was just flat out wrong. It's hard to say without more detail about this "toolkit" they are using.
gnovice
The "toolkit" is a specialised toolbox for processing fMRI data. The problem with linear indexing is simply that there are bugs in the toolbox which causes the linear index to return the wrong values because of the way the toolbox handles very large data files to get around memory constraints by not reading the whole file in at one time. If it worked properly I would use sub2ind (in fact that was my original solution).

related questions