Reputation: 53
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
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
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
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
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