Element-wise mutiplication .* of vectors gives matrix in Matlab - 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).

Related

Extract values from 2d array with indices from another array (without loops)

I have an array [2; 3] and a matrix [ 1 3 4 5; 2 4 9 2].
Now I would like to extract the second element from the first row and the third element from the second row and thus obtain [3 ; 9]. I managed it to do it with a loop, but since I'm working with much larger arrays, I would like to avoid these.
You can use sub2ind to convert each of the column subscripts (along with their row subscripts) into a linear index and then use that to index into your matrix.
A = [1 3 4 5; 2 4 9 2];
cols = [2; 3];
% Compute the linear index using sub2ind
inds = sub2ind(size(A), (1:numel(cols)).', cols);
B = A(inds)
% 3
% 9
Alternately, you could compute the linear indices yourself which is going to be more performant than sub2ind
B = A((cols - 1) * size(A, 1) + (1:numel(cols)).');
% 3
% 9
By exploiting the diag function, you can obtain an elegant one-line solution:
A = [1 3 4 5; 2 4 9 2];
cols = [2; 3];
B = diag(A(:,cols))
% 3
% 9
Here is what diag(A(:,cols)) does:
A(:,cols) selects the columns cols of A, with column k of A(:,cols) corresponding to the column cols(k) of A, giving [3 4; 4 9];
diag returns the diagonal entries of this matrix, thus returning at position k the k-th diagonal element of A(:,cols), which is A(k,cols(k)).

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.

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

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]);

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

Construct a matrix from existing two other matrices, all with different sizes

I have two matrices
a = randi ([0 10], 5, 6)
b = randi ([0 10], 2, 45)
Now I want to construct a matrix c of size 8 x 15 with all the elements of a and b. Is it possible to do it in a single line code? Some suggestions please.
Here is an example of what I'm trying to do:
a = [1 4 6;
5 8 0;
3 7 9;
4 10 5];
b = [5 6;
5 0];
c = [1 4 6 5;
8 0 3 7;
9 4 10 5;
5 6 5 0]
The specifications for how to combine a and b aren't clear. Here is one way to do it.
Create a single column vector built from a and b. Then reshape that column vector into a matrix.
c = reshape( [ a(:); b(:) ], 8, 15);
This will only work if the numel(a) + numel(b) equals the total number of elements in c.
Attempts to execute c = reshape( [ a(:); b(:) ], 7,12); will fail as you aren't providing enough elements to create an 7x12 matrix.
Update
Noufal's comment on this answer changes the problem reqs a bit. Basically you stil create the column vector but you only populate C depending on how many elements you have at your disposal:
A = rand(5,6);
B = rand(2,45);
C = zeros(8,10);
tmp = [A(:); B(:)]; % create temporary column vector
maxIdx = min( [numel(tmp), numel(C)] ); % determine if tmp or C has fewer elements
C(1:maxIdx) = tmp(1:maxIdx); % fill C from tmp using indices 1:maxIdx