Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Indexing of unknown dimensional matrix

I have a non-fixed dimensional matrix M, from which I want to access a single element. The element's indices are contained in a vector J.

So for example:

M = rand(6,4,8,2);
J = [5 2 7 1];

output = M(5,2,7,1)

This time M has 4 dimensions, but this is not known in advance. This is dependent on the setup of the algorithm I'm writing. It could likewise be that

M = rand(6,4);
J = [3 1];

output = M(3,1)

so I can't simply use

output=M(J(1),J(2))

I was thinking of using sub2ind, but this also needs its variables comma separated..

@gnovice

this works, but I intend to use this kind of element extraction from the matrix M quite a lot. So if I have to create a temporary variable cellJ every time I access M, wouldn't this tremendously slow down the computation??

I could also write a separate function

function x= getM(M,J)
    x=M(J(1),J(2));
    % M doesn't change in this function, so no mem copy needed = passed by reference
end

and adapt this for different configurations of the algorithm. This is of course a speed vs flexibility consideration which I hadn't included in my question..

BUT: this is only available for getting the element, for setting there is no other way than actually using the indices (and preferably the linear index). I still think sub2ind is an option. The final result I had intended was something like:

function idx = getLinearIdx(J, size_M)
    idx = ...
end

RESULTS:

function lin_idx = Lidx_ml( J, M )%#eml
%LIDX_ML converts an array of indices J for a multidimensional array M to
%linear indices, directly useable on M
%
% INPUT
%   J       NxP matrix containing P sets of N indices
%   M       A example matrix, with same size as on which the indices in J
%           will be applicable.
%
% OUTPUT
%   lin_idx Px1 array of linear indices
%

% method 1
%lin_idx = zeros(size(J,2),1);
%for ii = 1:size(J,2)
%    cellJ = num2cell(J(:,ii)); 
%    lin_idx(ii) = sub2ind(size(M),cellJ{:}); 
%end

% method 2
sizeM = size(M);
J(2:end,:) = J(2:end,:)-1;
lin_idx = cumprod([1 sizeM(1:end-1)])*J;

end

method 2 is 20 (small number of index sets (=P) to convert) to 80 (large number of index sets (=P)) times faster than method 1. easy choice

like image 784
Gunther Struyf Avatar asked Apr 13 '12 18:04

Gunther Struyf


1 Answers

For the general case where J can be any length (which I assume always matches the number of dimensions in M), there are a couple options you have:

  1. You can place each entry of J in a cell of a cell array using the num2cell function, then create a comma-separated list from this cell array using the colon operator:

    cellJ = num2cell(J);
    output = M(cellJ{:});
    
  2. You can sidestep the sub2ind function and compute the linear index yourself with a little bit of math:

    sizeM = size(M);
    index = cumprod([1 sizeM(1:end-1)]) * (J(:) - [0; ones(numel(J)-1, 1)]);
    output = M(index);
    
like image 71
gnovice Avatar answered Nov 15 '22 03:11

gnovice