Find the maximum value of four dimensional matrix along with the indices - matlab

I am trying to find the entry of matrix Athat has the maximum value.
I have generated matrix A, how can I ask MATLAB to return the four indices in addition to the maximum value of the entry within matrix A
for i = 1:size(CB,2)
for j=1:size(CB,2)
for k=1:size(CB,2)
for l=1:size(CB,2)
A(i,j,k,l)= (abs( conj(transpose([CB(:,i); CB(:,j)]))*MATRIX* [CB(:,k); CB(:,l)])^2);
end
end
end
end

You can use a combination of max and ind2sub:
a = rand(5, 5, 5, 5);
[maxa, maxidx] = max(a(:));
[I, J, K, L] = ind2sub(size(a), maxidx);
Which we can test:
>> a(I, J, K, L) == maxa
ans =
1
The way this works is that we receive a linear index from the second output of the max command. I used the colon operator with max so our input is really one long column vector of a, and the output is the maximum value of the entire matrix, maxa, along with the location of that value in the column vector, maxidx. You can then use ind2sub with size to convert that linear index into subscripts for your matrix.

Use 1-D indexing:
[M,I] = max(A(:));
I is then the index in A where M resides (i.e., M = A(I))
Then you need to use the following to convert from 1D indexing to 4D indexing:
[a,b,c,d] = ind2sub(size(A),I);

Related

Matlab: How to extract specific cells from a 3D array using list of indices?

I have a source matrix A(m,n) for which I used "find" and now I have a list of desired indices [y,x].
I also have a 3D matrix with dimensions B(m,n,3).
I want to extract all the elements in B using the result from find.
So if find yields 4 pairs of results, I would like to have a 4x3 matrix with the contents of the Z dimension of B for the resulting indices.
I tried many things but keep failing:
A = rand(480,640);
[y,x] = find(A < 0.5);
o = B(y,x,:);
Requested 39024x39024x3 (34.0GB) array exceeds maximum array size preference.
I am clearly doing something wrong since B has dimensions (640,640,3).
With the way you are trying to index, matlab tries to index B with every combination of the elements in y and x resulting in a massive matrix. I've implemented a for loop to do what I think you are asking.
I would also note that in order to index across B the first two dimensions need to be the same size as A, Otherwise you will not be able to index B past the maximum row or column index in A.
A = rand(480,640);
B = rand(480,640,3);
[x,y] = find(A < 0.5);
o = zeros(size(x,1),1,3); % x and y are the same length so it doesn't matter
for i = 1:size(x,1)
o(i,1,:)= B(x(i),y(i),:);
end
o = reshape(o,size(x,1),3);
You can reshape B to a 2D matrix of size [m*n , 3] then use logical indexing to extract elements:
C = reshape(B, [], 3);
o = C(A<0.5, :);

how to check the values of each variables from a resultant matrix in matlab?

I have sum of 3 cell arrays
A=72x1
B=72x720
C=72x90
resultant=A+B+C
size of resultant=72x64800
now when I find the minimum value with row and column indices I can locate the row element easily but how can I locate the column element in variables?
for example
after dong calculations for A,B,C I added them all and got a resultant in from of <72x(720x90)> or can say a matrix of integers of size <72x64800> then I found the minimum value of resultant with row and column index using the code below.
[minimumValue,ind]=min(resultant(:));
[row,col]=find(result== minimumValue);
then row got 14 and column got 6840 value..
now I can trace row 14 of all A,B,C variables easily but how can I know that the resultant column 6480 belongs to which combination of A,B,C?
Instead of using find, use the ind output from the min function. This is the linear index for minimumValue. To do that you can use ind2sub:
[r,c] = ind2sub(size(resultant),ind);
It is not quite clear what do you mean by resultant = A+B+C since you clearly don't sum them if you get a bigger array (72x64800), on the other hand, this is not a simple concatenation ([A B C]) since this would result in a 72x811 array.
However, assuming this is a concatenation you can do the following:
% get the 2nd dimension size of all matrices:
cols = cellfun(#(x) size(x,2),{A,B,C})
% create a vector with reapiting matrices names for all their columns:
mats = repelem(['A' 'B' 'C'],cols);
% get the relevant matrix for the c column:
mats(c)
so mats(c) will be the matrix with the minimum value.
EDIT:
From your comment I understand that your code looks something like this:
% arbitrary data:
A = rand(72,1);
B = rand(72,720);
C = rand(72,90);
% initializing:
K = size(B,2);
N = size(C,2);
counter = 1;
resultant = zeros(72,K*N);
% summing:
for k = 1:K
for n = 1:N
resultant(:,counter) = A + B(:,k) + C(:,n);
counter = counter+1;
end
end
% finding the minimum value:
[minimumValue,ind] = min(resultant(:))
and from the start of the answer you know that you can do this:
[r,c] = ind2sub(size(resultant),ind)
to get the row and column of minimumValue in resultant. So, in the same way you can do:
[Ccol,Bcol] = ind2sub([N,K],c)
where Bcol and Ccol is the column in B and C, respectively, so that:
minimumValue == A(r) + B(r,Bcol) + C(r,Ccol)
To see how it's working imagine that the loop above fills a matrix M with the value of counter, and M has a size of N-by-K. Because we fill M with a linear index, it will be filled in a column-major way, so the row will correspond to the n iterator, and the column will correspond to the k iterator. Now c corresponds to the counter where we got the minimum value, and the row and column of counter in M tells us the columns in B and C, so we can use ind2sub again to get the subscripts of the position of counter. Off course, we don't really need to create M, because the values within it are just the linear indices themselves.

Access a list of entries in MATLAB

I have a huge matrix MxN matrix, say, A=rand([M,N]); and an index vector with N integer values between 1 and M, say, RandomIndex = randi(M,[1,N]);.
Now I would like to generate a row vector with entries
result = [A(RandomIndex(1),1), A(RandomIndex(2),2), ..., A(RandomIndex(N),N)]
What would be an efficient way to do this? It should be a very cheap operation but all my implementations are slow. I don't think there is a notation in Matlab to do this directly, is there?
The fastest option so far is
indexFunction = #(r,c) A(r,c);
result = cell2mat(arrayfun(indexFunction,RandomIndex,1:N,'UniformOutput',false));
Is there a more efficient way?
Use sub2ind
A(sub2ind(size(A), RandomIndex, 1:N))
sub2ind will convert the row and column indices given by RandomIndex and 1:N to linear indices based on size(A) which you can then use to index A directly.
Another way to do this is to use RandomIndex and 1:N to return an NxN matrix and then take the diagonal of this with diag
diag(A(RandomIndex, 1:N)).'
Note: .' is used to convert the row vector returned by diag to a column vector.
M=10;N=50;
A=rand([M,N]);
RandomIndex = randi(M,[1,N]);
out = zeros(1,numel(RandomIndex));
for ii = 1:numel(RandomIndex)
out(ii)=A(RandomIndex(ii),ii);
end
Another approach would be to use sparse and logical indexing:
M = sparse(RandomIndex, 1:N, 1) == 1;
out = A(M);
The first line of code generates a logical matrix where there is only 1 true value set in each column. This is defined by each value of RandomIndex. We convert this to a logical matrix, then index into your matrix to obtain the final random vector.
Use your index directly.
M = 100;N=100;
A = rand(M,N);
% get a random index that can be as large as your matrix
% 10 rows by 1 column
idx = randi(numel(A), 10,1);
t = A(idx);

Incrementing values in a sparse matrix takes very long

i'm running the following code, where M is a ~200,000 by ~200,000 sparse matrix and points is ~200,000 by 2 matrix
inds=sub2ind(size(M),points(:,1),points(:,2));
M(inds)=M(inds)+1;
the problem is that the second line takes very long to run (15-90 seconds).
the operation takes longer depending on how many of the indices in inds are 'new' (i.e. that don't already have a value in the sparse matrix)
is there a more efficient way to do this?
Here's an idea:
M = M + sparse(points(:,1),points(:,2),1,size(M,1),size(M,2),size(points,1));
Just so you know,
S = sparse(i,j,s,m,n,nzmax) uses vectors i, j, and s to generate an
m-by-n sparse matrix such that S(i(k),j(k)) = s(k), with space
allocated for nzmax nonzeros. Vectors i, j, and s are all the same
length. Any elements of s that are zero are ignored, along with the
corresponding values of i and j. Any elements of s that have duplicate
values of i and j are added together.
For the curious:
M = sprand(200000,200000,1e-6);
points = [randperm(200000) ; randperm(200000)]'; %'//Initialization over
Mo = M;
tic;
inds=sub2ind(size(Mo),points(:,1),points(:,2));
Mo(inds) = Mo(inds)+1;
toc
tic;
M = M + sparse(points(:,1),points(:,2),1,size(M,1),size(M,2),size(points,1));
toc

Building a map from a matrix in Matlab

I have a matrix A which holds integers in a bounded range (0..255) and I need to build a table mapping a value (0..255) to all the coordinates in the matrix which hold this value.
What is the best way to achieve this? - I thought about using containers.Map for the task but Map doesn't support multiple values per key. I could have used lists but that would seem inefficient as I would have to create a new list on each iteration.
A vectorized solution, which gives the same output as the solution from Mikhail, is to sort all the pixel values in your image using the SORT function, convert the linear indices returned from SORT into subscripted indices using the function IND2SUB, and collect them together into a single cell array using the functions ACCUMARRAY and MAT2CELL:
A = randi([0 255],[5 5],'uint8'); %# A sample matrix
[values,indices] = sort(double(A(:))); %# Sort all the pixel values
[y,x] = ind2sub(size(A),indices); %# Convert linear index to subscript
counts = accumarray(values+1,1,[256 1]); %# Count number of each value
map = mat2cell([y x],counts); %# Create a 256-by-1 cell array
Now, for a given integer value iValue you can get the N-by-2 matrix containing the y (first column) and x (second column) coordinates for the N pixels in the image with that value by doing the following:
key = double(iValue)+1; %# Need to use double to avoid integer saturation
points = map{key}; %# An N-by-2 coordinate matrix
In addition, just in case you're interested, you could also make map a structure array with fields x and y using the function STRUCT:
map = struct('x',mat2cell(x,counts),'y',mat2cell(y,counts));
And you can then access the x and y coordinates for pixels with a value iValue as follows:
key = double(iValue)+1;
x = map(key).x;
y = map(key).y
What about using a cell array? You can index it with integers. For example:
map = {[1,1;13,56], [], [4,5]};
In this example index 0 is in the matrix in 1,1 and 13,56, index 1 in none and index 2 in 4,5
Your cell would have 256 elements (mine has 3) and to acces you would simply add 1 to the index.
You could also store indices linearly so the code to fill the table would be:
for ii = 0:255
map{ii+1} = find( mat(:)==ii )
end
Well, I wrote the following and it seems to work in reasonable time. I think the thing that does the trick is preallocating the cell arrays based on the histogram for each value:
[H, W] = size(A);
histogram = hist(A, 256);
AGT = arrayfun(#(avg) {0 cell(1, histogram(avg))}, 1:256, 'UniformOutput', false);
for y = 1:H
for x = 1:W
idx = A(y, x) + 1;
count = AGT{idx}{1};
AGT{idx}{2}{count + 1} = [y x];
AGT{idx}{1} = count + 1;
end
end
Accessing the table is a bit annoyting though :
AGT{200}{2}{:}
to access all coordinates with value 200.