dast
dast

Reputation: 53

Linear index of the maximum of a multi-dimensional matrix - MATLAB

Let's say I have a 3-dimensional matrix and have computed the max along the second dimension, and want to get the linear indices of the max values. However, the max-function only returns the subscripts along one dimension.

A = randn([5,5,5]);        % Generate random matrix
[M, Ind] = max(A,[],2);    % Take the max along dimension 2

How do I transfer the index to linear indexing, such that

M == A(Ind)

becomes true?

My intention for this problem is that I have two multi-dimensional matrices and need to compute the max in the first one. Then, I want to access the values in the second matrix at exactly those positions where I found a max in the first one.

Upvotes: 5

Views: 655

Answers (4)

Luis Mendo
Luis Mendo

Reputation: 112769

3-dimensional case:

[m, n, p] = size(A);
[M, Ind] = max(A,[],2);
LinInd = bsxfun(@plus, (1:m).', (0:p-1)*m*n); %'//
LinInd = LinInd(:) + (Ind(:)-1)*m;

The desired linear index is LinInd. This produces

A(LinInd) == M(:)

with all true entries (note you need (:) on the right-hand side so that the comparison makes sense).

General multi-dimensonal case:

d = 3; %// dimension along which max will be computed
s = size(A);
sLow = prod(s(1:d-1));
sHigh = prod(s(d+1:end));
[M, Ind] = max(A,[],d);
LinInd = bsxfun(@plus, (1:sLow).', (0:sHigh-1)*sLow*s(d)); %'//
LinInd = LinInd(:) + (Ind(:)-1)*sLow;

Upvotes: 1

Steffen
Steffen

Reputation: 2441

Create the indices for the other dimensions.

In dim 1 the index needs to change fastest: [1,2,...,size(A,1)] and this size(A,3) times:

idx1 = repmat((1:size(A,1))',size(A,3),1);

In dim 2 the index is given by Ind.

In dim 3 the index need to change slowest: [1,1,...,1] for size(A,1) times and then [2,2,...,2] and so on until size(A,3).

idx3 = ones(size(A,1),1)*(1:size(A,3));

Access single values:

 M_ = A(sub2ind(size(A),idx1(:),Ind(:),idx3(:)));

Compare:

M(:) == M_

Upvotes: 1

Divakar
Divakar

Reputation: 221744

Let's suppose A and B are the two matrices you have and you need to get max indices from A and use those indices to index into B for the desired output. One approach to achieve the same could be like this -

%// Your code to get Ind
A = randn([5,5,5]);        % Generate random matrix
[M, Ind] = max(A,[],2);    % Take the max along dimension 2

%// ------- Solution code -------------

%// Get the size of A
[n1,n2,n3] = size(A)

%// Linear indices corresponding to column and third dimension indices
col_dim3_lin_idx = bsxfun(@plus,(Ind-1)*n1,permute([0:n3-1]*n1*n2,[1 3 2]))

%// Finally get the overall linear indices
linear_index = bsxfun(@plus,col_dim3_lin_idx,[1:n1]') %//'

%// Get the corresponding elements from B
out = B(linear_index)

Slightly different way to have the desired linear indices as a 2D array would be like this -

[n1,n2,n3] = size(A) %// Get the size of A
idx = bsxfun(@plus,bsxfun(@plus,squeeze((Ind-1)*n1),[0:n3-1]*n1*n2),[1:n1]')

idx(:) would be the column vector of linear indices with this new approach, which you can index into B i.e. B(idx(:)) to have the desired output as a column vector.

Upvotes: 0

Dan
Dan

Reputation: 45762

One way is to use sub2ind:

A = randn([5,5,5]);       
[M, col] = max(A,[],2);   

[m,n,o] = size(A);

dim1 = mod((0:m*o-1)', m)+1;
dim2 = col(:);
dim3 = ceil((1:m*o)/m)';

ind = sub2ind(size(A), dim1, dim2, dim3)

verify it works with

isequal(M(:), A(ind))

to get them to have the same shape as M:

reshape(ind, m, 1, o)

Upvotes: 2

Related Questions