MATLAB: Forming an array of matrices and do operations with respect to each matrix "element" - matlab

I have an array of matrix m such that
m1 = [1 2;3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
m = [m1 m2 m3]
m =
1 2 2 7 9 7
3 4 8 9 8 91
I also have a vector
v = [1 2 3];
such that i want the operations between v and m result in h such that
h = [1*m1 2*m2 3*m3] = [h1 h2 h3];
I imagine I have to do this in 3-dimensional array for h, which is a 3d array. Or maybe there are better ways.
Let A be a simple 2 by 2 matrix, rand(2,2).
From h i want to extract h1 h2 and h3 out(or better not doing any extraction) and perform operations to A such that
1.
h1*A*h1'
h2*A*h2'
h3*A*h3'
and
2.
h1*h1', h2*h2', h3*h3'.
Why i want to do this in array is because i have a lot of matrix mi so I want to avoid for loop by vectorization.

From what i could understand from the question, i suppose element-wise multiplication would be better choice. You would just have to use proper concatenation and repeatation of matrices.
m1 = [1 2; 3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
% Concatenate to create 3D matrix
m = cat(3,m1,m2,m3);
v = [1 2 3];
% Create similar 3D matrix
v1 = cat(3,ones(size(m1))*v(1),ones(size(m2))*v(2),ones(size(m3))*v(3));
% Simple element wise multiplication
h = m.*v1;
% Creating a repeated 3D matrix A, repetation is along third dimension
A = repmat(rand(2,2),[1 1 3]);
% Outputs
op_1 = h.*A.*permute(h,[2 1 3]);
op_2 = h.*permute(h,[2 1 3]);

Related

Algorithmically construct block matrices (matlab)

Let Matrices = [A B C D] be a set of square matrices. I want to construct
H = [A B C D;
B A B C;
C B A B;
D C B A]
If all I was interested in was the 4 by 4 case, then this would be enough. However, I want to construct the analogous matrix when Matrices = [A B C D E F] etc. What code could I write to do this?
This can be done as follows:
Concatenate the matrices into a 3D array;
Build the basic with numbers instead of matrices using toeplitz;
Extend this structure so that using linear indexing into the 3D array produces the desired result.
N = 2; % matrix size
M = 3; % number of matrices
matrices = arrayfun(#(x) {randi(9,N)}, 1:M); % input matrices
matrices_3D = cat(3, matrices{:}); % concatenate the matrices along the third dim
ind1 = repmat(reshape(1:N^2, N, N), M, M); % linear indices within each matrix
ind2 = (repelem(toeplitz(1:M), N, N)-1)*N^2; % linear indices to select the matrices
result = matrices_3D(ind1 + ind2); % build result
Example run:
>> celldisp(matrices)
matrices{1} =
1 4
2 6
matrices{2} =
6 4
5 9
matrices{3} =
5 4
6 5
>> result
result =
1 4 6 4 5 4
2 6 5 9 6 5
6 4 1 4 6 4
5 9 2 6 5 9
5 4 6 4 1 4
6 5 5 9 2 6

Element-wise mutiplication .* of vectors gives matrix in Matlab

Given two vectors
a = 1:3;
b = 2:4;
it's well known that the element-wise mutiplication a.*b produces
[ 2 6 12 ]
Calling that result c, we have c(i) = a(i)*b(i)
But I don't understand how a.*b', b'.*a and b'*a all produce
[ 2 4 6
3 6 9
4 8 12 ]
For the matrix multiplication b'*a, we know c(i,j) = b(i)*a(j).
But why do the other two also produce the same result?
Due to implicit expansion (introduced in 2016b) it's essentially the same as using bsxfun.
But what does that mean?
Setup:
a = 1:3;
b = 2:4;
All MATLAB versions:
c = a.*b;
% c = [2 6 12], element-wise multiplication c(j) = a(j)*b(j)
c = b'*a;
% c = [2 4 5; 3 6 9; 4 8 12]
% standard matrix multiplication of vectors
% c(i,j) = a(i) + b(j)
c = bsxfun(#times, b', a)
% c = [2 4 5; 3 6 9; 4 8 12]
% bsxfun applies the function (in this case #times) to b' and a
By definition, bsxfun "applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled". This means that singleton dimensions (dimensions whose size is 1) are expanded row-wise/column-wise to match the size of the other argument supplied to bsxfun.
So, bsxfun(#times, b', a) is equivalent to
% b' in singleton in the 2nd dimension, a is singleton in the 1st dimension
% Use repmat to perform the expansion to the correct size
repmat(b', 1, size(a,2)) .* repmat(a, size(b',1), 1)
% Equivalent to...
repmat(b', 1, 3) .* repmat(a, 3, 1)
% Equivalent to...
[2 2 2; 3 3 3; 4 4 4] .* [1 2 3; 1 2 3; 1 2 3]
% = [2 4 5; 3 6 9; 4 8 12] the same as b'*a
Before R2016b
c = a.*b'; % Error: Matrix dimensions must agree.
c = b'.*a; % Error: Matrix dimensions must agree.
Since R2016b
Newer MATLAB versions use implicit expansion, which basically means that a bsxfun equivalent is called 'under the hood' if necessary for a valid operation.
c = a.*b'; % [2 4 5; 3 6 9; 4 8 12] the same as bsxfun(#times, a, b')
c = b'.*a; % [2 4 5; 3 6 9; 4 8 12] the same as bsxfun(#times, b', a)
% These two are equivalent also because order of operations is irrelevant
% We can see this by thinking about the expansion discussed above
As you've noticed, this can be confusing if you don't keep track of your vector orientations! If you ever want to get a 1D output (without expansion), then you can ensure your inputs are 1D column vectors by using the colon operator like so
c = a(:).*b(:); % c = [2; 6; 12] always a column vector
The examples you listed are all element-wise multiplication.
a.*b' will give error in earlier matlab, while it performs
bsxfun(#times, a, b')
in Matlab since R2016b. This should explain the identical result for a.*b', b'.*a and b'*a.
a * b' will be matrix multiplication (inner dimension match).

Turning matrix diagonals to columns

I am looking for a matrix operation of the form: B = M*A*N where A is some general square matrix and M and N are the matrices I want to find.
Such that the columns of B are the diagonals of A. The first column the main diagonal, the second the diagonal shifted by 1 from the main and so on.
e.g. In MATLAB syntax:
A = [1, 2, 3
4, 5, 6
7, 8, 9]
and
B = [1, 2, 3
5, 6, 4
9, 7, 8]
Edit:
It seems a pure linear algebra solution doesn't exist. So I'll be more precise about what I was trying to do:
For some vector v of size 1 x m. Then define C = repmat(v,m,1). My matrix is A = C-C.';.
Therefore, A is essentially all differences of values in v but I'm only interested in the difference up to some distance between values.
Those are the diagonals of A; but m is so large that the construction of such m x m matrices causes out-of-memory issues.
I'm looking for a way to extract those diagonals in a way that is as efficient as possible (in MATLAB).
Thanks!
If you're not actually looking for a linear algebra solution, then I would argue that constructing three additional matrices the same size as A using two matrix multiplications is very inefficient in both time and space complexity. I'm not sure it's even possible to find a matrix solution, given my limited knowledge of linear algebra, but even if it is it's sure to be messy.
Since you say you only need the values along some diagonals, I'd construct only those diagonals using diag:
A = [1 2 3;
4 5 6;
7 8 9];
m = size(A, 1); % assume A is square
k = 1; % let's get the k'th diagonal
kdiag = [diag(A, k); diag(A, k-m)];
kdiag =
2
6
7
Diagonal 0 is the main diagonal, diagonal m-1 (for an mxm matrix) is the last. So if you wanted all of B you could easily loop:
B = zeros(size(A));
for k = 0:m-1
B(:,k+1) = [diag(A, k); diag(A, k-m)];
end
B =
1 2 3
5 6 4
9 7 8
From the comments:
For v some vector of size 1xm. Then B=repmat(v,m,1). My matrix is A=B-B.'; A is essentially all differences of values in v but I'm only interested in the difference up to some distance between values.
Let's say
m = 4;
v = [1 3 7 11];
If you construct the entire matrix,
B = repmat(v, m, 1);
A = B - B.';
A =
0 2 6 10
-2 0 4 8
-6 -4 0 4
-10 -8 -4 0
The main diagonal is zeros, so that's not very interesting. The next diagonal, which I'll call k = 1 is
[2 4 4 -10].'
You can construct this diagonal without constructing A or even B by shifting the elements of v:
k = 1;
diag1 = circshift(v, m-k, 2) - v;
diag1 =
2 4 4 -10
The main diagonal is given by k = 0, the last diagonal by k = m-1.
You can do this using the function toeplitz to create column indices for the reshuffling, then convert those to a linear index to use for reordering A, like so:
>> A = [1 2 3; 4 5 6; 7 8 9]
A =
1 2 3
4 5 6
7 8 9
>> n = size(A, 1);
>> index = repmat((1:n).', 1, n)+n*(toeplitz([1 n:-1:2], 1:n)-1);
>> B = zeros(n);
>> B(index) = A
B =
1 2 3
5 6 4
9 7 8
This will generalize to any size square matrix A.

How can i insert 2d random numbers into a given 2d matrix in matlab

I want to insert random numbers into a given 2D matrix in MATLAB. For example
if
A = [1 2 3;
4 5 6;
7 8 9];
and if B is a matrix which is uniformly distributed matrix, then I want a new matrix merging this two matrices (A & B), like
new matrix
C = [1 0.653 2 2.55 3;
4 4.3 5 5.4 6;
7 7.6 8 8.09 9]
How could I write MATLAB code for that?
If you've already got B and assuming that A is an n-by-m matrix and B is an n-by-m-1 matrix:
[n,m] = size(A);
C = zeros(n,2*m-1);
C(:,1:2:end) = A;
C(:,2:2:end) = B; % end-1 is not necessary since 2*m-1 is an odd number but if you prefer for readability then you can do C(:,2:2:end-1) = B
You could create B like this (depends on the limits of B which are not clear from your question)
B = A(:,1:end-1) + rand(n,m-1)*2 - 1

Design a simple matrix to group values from matrices

This problem is a succession of my previous problem:
1) Extract submatrices, 2) vectorize and then 3) put back
Now, I have two patients, named Ann and Ben.
Indeed the matrices A and B are data for Ann and the matrix C is data for Ben:
Now, I need to design a matrix M such that y = M*x where
y = [a11, a21, a12, a22, b11, b21, b12, b22]' which is a vector, resulting from concatenation of the top-left sub-matrices, Ann and Ben;
x = [2, 5, 4, 6, 7, 9, 6, 2, 9, 3, 4, 2]' which is a vector, resulting from concatenation of sub-matrices A, B and C.
Here, the M is a 8 by 12 matrix that
a11 = 2 + 7, a21 = 5 + 9, .., a22 = 6 + 2 and b11 = 9, ..b22 = 2.
I design the M manually by:
M=zeros(8,12)
M(1,1)=1; M(1,5)=1; % compute a11
M(2,2)=1; M(2,6)=1; % compute a21
M(3,3)=1; M(3,7)=1; % compute a12
M(4,4)=1; M(4,8)=1; % compute a22
M(5,9)=1; % for setting b11 = 9, C(1,1)
M(6,10)=1; % for setting b21 = 3, C(2,1)
M(7,11)=1; % for setting b12 = 4, C(1,2)
M(8,12)=1 % for setting b22 = 2, C(2,2)
Obviously, in general for M(i,j), i means the 8 linear-index position of vector y and j means linear-index position of vector x.
However, I largely simplified my original problem that I want to construct this M automatically.
Thanks in advance for giving me a hand.
Here you have my solution. I have essentially build the matrix M automatically (from the proper indexes) as you suggested.
A = [2 4 8;
5 6 3;
10 3 6];
B = [7 6 3;
9 2 9;
10 2 3];
C = [9 4 7;
3 2 5;
10 3 4];
% All matrices in the same array
concat = cat(3, A, B, C);
concat_sub = concat(1:2,1:2,:);
x = concat_sub(:);
n = numel(x)/3; %Number of elements in each subset
M2 = zeros(12,8); %Transpose of the M matrix (it could be implemented directly over M but that was my first approach)
% The indexes you need
idx1 = 1:13:12*n; % Indeces for A
idx2 = 5:13:12*2*n; % Indices for B and C
M2([idx1 idx2]) = 1;
M = M2';
y = M*x
I have taken advantage of the shape that the matrix M shold take:
You can index into things and extract what you want without multiplication. For your example:
A = [2 4 8; 5 6 3; 10 3 6];
B = [7 6 3; 9 2 9; 10 2 3];
C = [9 4 7;3 2 5; 10 3 4];
idx = logical([1 1 0;1 1 0; 0 0 0]);
Ai = A(idx);
Bi = B(idx);
Ci = C(idx);
output = [Ai; Bi; Ci];
y = [Ai + Bi; Ci]; % desired y vector
This shows each step individually but they can be done in 2 lines. Define the index and then apply it.
idx = logical([1 1 0;1 1 0;0 0 0]);
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Also you can use linear indexing with idx = [1 2 4 5]' This will produce the same subvector for each of A B C. Either way works.
idx = [1 2 4 5]';
or alternatively
idx = [1;2;4;5];
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Either way works. Check out doc sub2ind for some examples of indexing from MathWorks.