Concatenate matrices out of a cell in Matlab - matlab

I wrote a simple matlab test code where I store 3 matrices (a,b,c) inside of a cell (D). I then create a vector of indexes (idx) so I am able to selected only the first and third matrix out of the cell. The code is presented below:
% Begin code %
a = [0 1; 2 3]; % matrix a
b = [4 5]; % matrix b
c = [5 6; 7 8; 9 10]; % matrix c
D = cell(3,1); % Initialize cell D
D{1,1} = a; D{2,1} = b; D{3,1} = c; % Copy matrices inside cell
idx = [1 3]'; % Indexes vector
D = D(idx); % select matrix a and c from D
% End code (Solution should start from here...) %
if I display D{:,1} what I get is
ans =
0 1
2 3
ans =
5 6
7 8
9 10
My goal is to concatenate the 2 matrices (a,b) out of the cell D in a smart way (using some specific built in matlab function) and possibly avoiding for loop;
This is what I want:
E = [0 1
2 3
5 6
7 8
9 10];
the solution should be the most elegant possible but I am open to any suggestion. The only constrain should be not to change the code I presented, since the solution should be a continuation of what I have written.
NOTICE: Since what I am trying to do should work with an undefined number of matrices (in this example I have only 3 but the could be also 1000), solutions like E = [D{1,:};D{2,1}] are not accepted.

Answer to my question found here:
cat(1,D{:})

Related

Matlab - how to create matrix from two or more vectors, which represents every combination of a single element from each vector [duplicate]

This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 3 years ago.
I'm new to matlab and have a question on how to efficiently create a matrix from two or more vectors, where every combination of a single element from each vector is represented in a resulting matrix.
For example, say we have vectors:
x = [1 2 3 4]; y = [5 6 7 8];
I'd like to get the following result in matrix ans:
ans = [1 5; 1 6; 1 7; 1 8; 2 5; 2 6; 2 7; ... 4 7; 4 8]
The above example is for two-dimensions (two input vectors), however it would be ideal if the solution is for d-dimensions (d-number of input vectors). Thanks!
[X,Y] = ndgrid(x,y);
desiredOutput = [X(:),Y(:)];
Here is the solution for d dimensions.
%% Input.
x = [1 2 3 4];
y = [5 6 7 8];
%% Fixed 2d solution as provided by Alex.
[X, Y] = ndgrid(x, y);
desiredOutput = [X(:), Y(:)]
%% Arbitrary dimension solution.
% Store all input vectors in cell array.
vectors{1} = x;
vectors{2} = y;
% Initialize output for ndgrid.
VECTORS = cell(numel(vectors), 1);
% Call ndgrid with arbitrary number of vectors.
[VECTORS{:}] = ndgrid(vectors{:});
% Convert VECTORS.
VECTORS = cellfun(#(x) x(:), VECTORS, 'UniformOutput', false);
% Output.
desiredOutput = [VECTORS{:}]
%% Expanded input.
z = [9 10 11 12];
vectors{3} = z;
VECTORS = cell(numel(vectors), 1);[VECTORS{:}] = ndgrid(vectors{:});
VECTORS = cellfun(#(x) x(:), VECTORS, 'UniformOutput', false);
desiredOutput = [VECTORS{:}]

extract 3D matrix's columns based on "surface" values - vectorization

I have an NxMxK matrix A
A = [1 2 1; 1 1 2];
A = cat(3, A, [3 3 3; 3 3 3])
A(:,:,1) =
1 2 1
1 1 2
A(:,:,2) =
3 3 3
3 3 3
and I want to create a YxK 2D matrix B where K is the number of elements of A(:,:,1)==2:
k=0;
for ii=1:size(A,1)
for jj=1:size(A,2)
if A(ii,jj)==2
k=k+1;
B(k,:) = A(ii,jj,:);
end
end
end
Is there a way of vectorizing this code?
My attempt was to find the indices of A(:,:,1)==2 and then try to select the whole column but I do not know how to do it:
inds = find(A(:,:,1)==2)
B = A(inds,:) %this line does not make sense
EDIT
Preallocating B helps:
inds=find(A(:,:,1)==2);
B=NaN(numel(inds),size(A,3));
k=0;
for ii=1:size(A,1)
for jj=1:size(A,2)
if A(ii,jj)==2
k=k+1;
B(k,:) = squeeze(A(ii,jj,:));
end
end
end
But still not vectorized.
You can reshape matrix A to a (N*M)xK 2D matrix.
A = [1 2 1; 1 1 2];
A = cat(3, A, [3 3 3; 3 3 3]);
A_ = reshape(A,numel(A(:,:,1)),size(A,3));
B = A_(A_(:,1)==2,:);
Your first attempt at vectorization is almost right. Just don't use find, but use the logical matrix for indexing.
inds = A(:,:,1)==2;
The inds matrix is 2D, not 3D, so we use repmat to repeat its values along the 3rd dimension:
K = size(A,3);
inds = repmat(inds,1,1,K); % or simply cat(3,inds,inds) if K==2
B = A(inds);
The result is a column vector of size Y*K, not a matrix of size YxK, we can use reshape to fix that:
B = reshape(B,[],K);
I guess this answer is similar to Anthony's, except the indexing and the reshaping are reversed. I didn't really notice the similarity until after I wrote it down. I guess also Anthony's is a little shorter. :/

Convert a cell containing matrices to a 2d matrix

I want to find easy way to convert a 1x324 cell array which contains matrices to a 2-dimensional matrix.
Each of the cell array's elements is a matrix of size 27x94, so they contain 2538 different values. I want to convert this cell array of matrices to a 324x2538 matrix - where the rows of the output contain each matrix (as a row vector) from the cell array.
To clarify what my data looks like and what I'm trying to create, see this example:
matrix1 = [1,2,3,4,...,94 ; 95,96,97,... ; 2445,2446,2447,...,2538]; % (27x94 matrix)
% ... other matrices are similar
A = {matrix1, matrix2, matrix3, ..., matrix324}; % Matrices are in 1st row of cell array
What I am trying to get:
% 324x2538 output matrix
B = [1 , 2 , ..., 2538 ; % matrix1
2539 , 2540, ..., 5076 ; % matrix2
...
819775, 819776, ..., 822312];
The cell2mat function does exactly that. The doc example:
C = {[1], [2 3 4];
[5; 9], [6 7 8; 10 11 12]};
A = cell2mat(C)
A =
1 2 3 4
5 6 7 8
9 10 11 12
You have your matrix now, so just rework it to contain rows:
B = rand(27,302456); % your B
D = reshape(B,27,94,324); % stack your matrices to 3D
E = reshape(D,1, 2538,324); % reshape each slice to a row vector
E = permute(E,[3 2 1]); % permute the dimensions to the correct order
% Based on sizes instead of fixed numbers
% D = reshape(B, [size(A{1}) numel(A)]);
% E = reshape(D,[1 prod(size(A{1})) numel(A)]);
% E = permute(E,[3 2 1]); % permute the dimensions to the correct order
Or, to one line it from your B:
B = reshape(B,prod(size(A{1})),numel(A)).'
One way to write this would be using cellfun to operate on each element of the cell, then concatenating the result.
% Using your input cell array A, turn all matrices into column vectors
% You need shiftdim so that the result is e.g. [1 2 3 4] not [1 3 2 4] for [1 2; 3 4]
B = cellfun(#(r) reshape(shiftdim(r,1),[],1), A, 'uniformoutput', false);
% Stack all columns vectors together then transpose
B = [B{:}].';
Now I found the solution and I will add it here if anyone have similar problems in future:
for ii = 1:length(A)
B{ii} = A{ii}(:);
end
B = cell2mat(B).';

Multiply each column in a matrix by corresponding row in another and sum results in Matlab

Lets say I have matrices A = [1 2; 3 4], B = [4 3; 2 1]. I want to multiply each column from matrix A ([1; 3], [2; 4]) by the corresponding row in matrix B ([4 3], [2 1]) and sum resulting matrices. I have came up with the following code:
C = zeros(size(A));
for i = 1 : size(A, 1)
C = C + A(:, i) * B(i, :);
end
Could it be rewritten using some math trick or matlab function to get rid of the for loop?
I see there is unclarity in my question regarding the result I want. The result should exactly mimic provided Matlab code, therefore I seek one matrix which is given by the matrix summation of the intermediate matrices that are created by multiplying each column vector with corresponding row vector from both matrices. For this specific example, it would be given by
C = A(:, 1) * B(1, :) + A(:, 2) * B(2, :);
I am just looking for some generic, for-loop less version for any matrices of compatible dimensions.
I just tried out my suggestion in the comments, and it seems to work with this octave tester:
Short form (only works in Octave):
A = [1 2; 3 4], B = [4 3; 2 1]
X = sum((A * B)(:))
Long form (Matlab):
A = [1 2; 3 4]
B = [4 3; 2 1]
C = A * B % Stop here if you want the exact result from your Matlab code
x = sum(C(:)) % To get the sum of the resulting matrix
Sources:
https://www.tutorialspoint.com/matlab/matlab_matrix_multiplication.htm
https://www.mathworks.com/matlabcentral/newsreader/view_thread/51252
Update, based on your update:
Output of A * B:
8 5
20 13
Output of your code:
8 5
20 13
It appears that
C = zeros(size(A));
for i = 1 : size(A, 1)
C = C + A(:, i) * B(i, :);
end
is equivalent to the matrix multiplication
C = A*B
for square matrices A and B.
You can also do this in MATLAB, to get the sum.
C=ones(1,2)*A*B*ones(2,1)
The general form would be
C=ones(1,size(A,1))*(A*B)*ones(size(B,2),1);
EDIT
I see you updated your question for clarity. The matrix product can be calculated directly
C = A*B;
as pointed out by jodag.
This works provided you follow rules of linear algebra where inner dimensions of your matrices are the same (i.e. when number of columns in A match the number of rows in B; size(A,2)==size(B,1)).

MATLAB/OCTAVE Extracting elements from different sized vectors in a cell array

I have a simple question but I can't figure it out or find it anywhere.
I have a cell array where c{1} is a vector and c{2} is a vector but of different lengths, up to c{i}. What I want is one vector that is [c{1};c{2};c{3}...c{i}]. What is the most efficient way to do this?
The following one-liner even works for completely inconsistent inputs:
result = [cell2mat(cellfun(#(x) x(:), A, 'uni', 0)')]'
Example:
for:
A{1} = [1, 2, 3, 4, 5];
A{2} = [6; 7; 8; 9];
A{3} = [10, 12; 11, 13];
it returns:
result =
1 2 3 4 5 6 7 8 9 10 11 12 13
Matlab/Octave allows this king of really-not-efficient but very-convenient notation, assuming a is a structure only containing column-vectors:
x = []; #% A fresh new vector/matrix/tensor, who knows?
for i=1:numel(a) #% parse container item by item
x = [x;a{i}]; #% append container item a{i} to x in a column-fashion way
end
This will works but it is bloody inefficient since it will reallocate x each for step and it is not bulletproof (no error handling, no type checking): therefore it will fail if it encounters anything (matrix, string, row vector) but column vector which are likely to be found in such containers.
Anyway, it will ease a not-so-stringent-and-heuristic design, but please consider reimplementing when robust design is needed.
You can padding each cell with zeros, and align the lengths to the longest cell vector. It is done in a loop by iterating each cell vector.
This depends on whether the vectors in c are row or column vectors. But usually the fastest and most compact ways are:
c={[1 2 3], [4 5 6 7 8], [9 10]}
cell2mat(c)
cat(2, c{:})
or
c={[1 2 3]', [4 5 6 7 8]', [9 10]'}
% cell2mat(c) % Doesn't work.
cat(1, c{:})
so personally, I prefer cat.
In Matlab; without loops:
If the cell array contains column vectors and you want to arrange them into one big column vector:
result = vertcat(c{:}); %// vertically concat all vectors
Example:
>> c = {[1;2], [1;2;3]};
>> result = vertcat(c{:})
result =
1
2
1
2
3
If the cell array contains row vectors, you can arrange them as rows of a matrix, filling non-existent values with NaN (or any other value):
M = max(cellfun(#numel, c)); %// max length of vectors
c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0); %// fill with NaN
result = vertcat(c2{:}); %// concat all equal-size row vectors into a matrix
Example:
>> c = {[1 2], [1 2 3]};
>> M = max(cellfun(#numel, c));
>> c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0);
>> result = vertcat(c2{:})
result =
1 2 NaN
1 2 3