"Desort" a matrix. Undo a sorting in Matlab - matlab

This question is basically an extension of that question.
I have a matrix A in Matlab and want to sort that matrix along one dimension:
A = rand(3,3,5);
[B idx] = sort(A,3);
Now idx is a matrix containing the "sorted" indices. How can i get back the matrix A using only B and idx?
The answer of the original question doesn't work for matrices, unfortunately.

You need to sort the indices idxto get back the original indices. Rest of the work would involve getting the formatted row and column indices corresponding to all those dim-3 indices. The implementation would look something like this -
[~,dim3idx] = sort(idx,3);
[m,n,r] = size(B);
[rowidx,colidx,~] = ndgrid(1:m,1:n,1:r);
Aout = B(sub2ind(size(B),rowidx,colidx,dim3idx))
Please note that for performance, one can get the linear indices generated by sub2ind alternatively with bsxfun directly from the size parameters and thus also avoid ndgrid, like so -
Aout = B(bsxfun(#plus,bsxfun(#plus,(1:m)',m*(0:n-1)),m*n*(dim3idx-1)))

Related

How to vectorize nested for loop for operations on different indices of the same matrix/array?

I've been trying to vectorize a for loop in Matlab because it bottlenecks the whole program but I have no clue about how to do it when iterating on different rows or columns of a single matrix inside of the loop. Here's the code :
// X is an n*k matrix, W is n*n
// W(i,j) stores the norm of the vector resulting from subtracting
// the j-th line of X from its i-th line.
for i = 1:n
for j = 1:n
W(i,j) = norm(X(i,:) - X(j,:))
end
end
Edit :
I chose Luis Mendo's answer as it was the most convenient for me and the one that's closer to the mathematical concept behind my algorithm, yet all three answers were correct and I'd advise to use the one that's the most convenient depending on which Matlab Toolboxes you have or the way you want to code.
I also noticed that the common point of all answers was to use a different format, for example : using an array that would store the indices, reshaping current arrays, using one more dimension...
So I think that's the right thing to explore if you have a similar problem.
Using combinatory:
% sample data
X = randi(9,5,4);
n = size(X,1);
% row index combinations
combIdx = combvec(1:n,1:n);
% difference between row combinations
D = X(combIdx(1,:),:)-X(combIdx(2,:),:);
% norm of each row
W = diag(sqrt(D*D'));
% reshape
W = reshape(W,n,[]);
Here is another solution that may be more efficient for big matrices.
For Matlab >=R2016 you can simple use
W = sqrt(sum(abs(reshape(X,n,1,k) - reshape(X,1,n,k)).^2,3))
(if your array is real-valued you can also skip the abs). For earlier versions of Matlab you need to add some repmat magic, namely:
W = sqrt(sum(abs(repmat(reshape(X,n,1,k),[1,n,1]) - repmat(reshape(X,1,n,k),[n,1,1])).^2,3));
P.S.: R2017b might make it even more convenient, at least the release notes mention a function called vecnorm that could replace the somewhat ugly sqrt(sum(abs(.).^2))) thing. But the documentation is not up yet so I don't know what exactly it will do. "
If you have the Statistics Toolbox, use pdist:
W = squareform(pdist(X));
No toolbox: good old bsxfun:
W = sqrt(sum(bsxfun(#minus, permute(X, [1 3 2]), permute(X, [3 1 2])).^2, 3));

Create diagonal matrix without using MATLAB built-in functions

I know the answer to this question as shown below.
function a = reverse_diag(n)
b = zeros(n);
b(1:n+1:end) = 1;
a(1:n, n:-1:1) = b(1:n, 1:n);
end
But why does it look like that? What does this mean?
b(1:n+1:end) = 1;
I seem to recall seeing something similar to this in MATLAB answers very recently, hence I will be brief.
MATLAB arrays can be indexed in 2 relevant ways:
Like A(x,y) using the actual coordinates in the matrix.
Like A(index), no matter how many dimensions the matrix A actually has. This is called linear indexing and will go through the matrix column by column. So for a 10x10 matrix, A(11) is actually A(2,1).
Read up on ind2sub and sub2ind to get a sense of how these work. You should now be able to figure out why that line works.

nonzero elements of sparse Matrix

let's say I have a big Matrix X with a lot of zeros, so of course I make it sparse in order to save on memory and CPU. After that I do some stuff and at some point I want to have the nonzero elements. My code looks something like this:
ind = M ~= 0; % Whereby M is the sparse Matrix
This looks however rather silly to me since the structure of the sparse Matrix should allow the direct extraction of the information.
To clarify: I do not look for a solution that works, but rather would like to avoid doing the same thing twice. A sparse Matrix should perdefinition already know it's nonzero values, so there should be no need to search for it.
yours magu_
The direct way to retrieve nonzero elements from a sparse matrix, is to call nonzeros().
The direct way is obviously the fastest method, however I performed some tests against logical indexing on the sparse and its full() counterparty, and the indexing on the former is faster (results depend on the sparsity pattern and dimension of the matrix).
The sum of times over 100 iterations is:
nonzeros: 0.02657 seconds
sparse idx: 0.52946 seconds
full idx: 2.27051 seconds
The testing suite:
N = 100;
t = zeros(N,3);
for ii = 1:N
s = sprand(10000,1000,0.01);
r = full(s);
% Direct call nonzeros
tic
nonzeros(s);
t(ii,1) = toc;
% Indexing sparse
tic
full(s(s ~= 0));
t(ii,2) = toc;
% Indexing full
tic
r(r~=0);
t(ii,3) = toc;
end
sum(t)
I'm not 100% sure what you're after but maybe [r c] = find(M) suits you better?
You can get to the values of M by going M(r,c) but the best method will surely be dictated by what you intend to do with the data next.
find function is recommended by MATLAB:
[row,col] = find(X, ...) returns the row and column indices of the nonzero entries in the matrix X. This syntax is especially useful when working with sparse matrices.
While find has been proposed before, I think this is an important addition:
[r,c,v] = find(M);
Gives you not only the indices r,c, but also the non-zero values v. Using the nonzeros command seems to be a bit faster, but find is in general very useful when dealing with sparse matrices because the [r,c,v] vectors describe the complete matrix (except matrix dimension).

Matlab 3d-matrix

I have to create a very big 3D matrix (such as: 500000x60x60). Is there any way to do this in matlab?
When I try
omega = zeros(500000,60,60,'single');
I get an out-of-memory error.
The sparse function is no option since it is only meant for 2D matrices. So is there any alternative to that for higher dimensional matrices?
Matlab only has support for sparse matrices (2D). For 3D tensors/arrays, you'll have to use a workaround. I can think of two:
linear indexing
cell arrays
Linear indexing
You can create a sparse vector like so:
A = spalloc(500000*60*60, 1, 100);
where the last entry (100) refers to the amount of non-zeros eventually to be assigned to A. If you know this amount beforehand it makes memory usage for A more efficient. If you don't know it beforehand just use some number close to it, it'll still work, but A can consume more memory in the end than it strictly needs to.
Then you can refer to elements as if it is a 3D array like so:
A(sub2ind(size(A), i,j,k))
where i, j and k are the indices to the 1st, 2nd and 3rd dimension, respectively.
Cell arrays
Create each 2D page in the 3D tensor/array as a cell array:
a = cellfun(#(x) spalloc(500000, 60, 100), cell(60,1), 'UniformOutput', false);
The same story goes for this last entry into spalloc. Then concatenate in 3D like so:
A = cat(3, a{:});
then you can refer to individual elements like so:
A{i,j,k}
where i, j and k are the indices to the 1st, 2nd and 3rd dimension, respectively.
Since your matrix is sparse, try to use ndsparse (N-dimensional sparse arrays FEX)

Matlab: a smart way to create a sparse matrix

I have to create a matlab matrix that is much bigger that my phisical memory, and i want to take advantage of the sparsity.
This matrix is really really sparse [say N elements in an NxN matrix], and my ram is enought for this. I create the matrix in this way:
A=sparse(zeros(N));
but it goes out of memory.
Do you know the right way to create this matrix?
zeros(N) is creating an NxN matrix, which is not sparse, hence you are running out of memory. Your code is equivalent to
temp = zeros(N)
A = sparse(temp)
Just do sparse(N,N).
Creating an all zeros sparse matrix, and then modifying it is extremely inefficient in matlab.
Instead of doing something like:
A = sparse(N,N) % or even A = sparse([],[],[],N,N,N)
A(1:N,7) = 1:N
It is much more efficient to construct the matrix in triplet form. That is,
construct the column and row indices and the nonzero entries first, then
form the matrix. For example,
i = 1:N;
j = 7*ones(1,N);
x = 1:N;
A = sparse(i,j,x,N,N);
I'd actually recommend the full syntax of sparse([],[],[],N,N,N).
It's useful to preallocate if you know the maximum number of nonzero elements as otherwise you'll get reallocs when you insert new elements.