Multiply two matrices element wise with summation - matlab

I have two matrices 4x2. How can I achieve such multiplication: the output should be a matrix 4x1, where each element is a sum of products of elements in rows in the original matrices.
Like this:
[1 2;
A = 3 4;
5 6;
7 8]
[1 2;
B = 3 4;
5 6;
7 8]
result C matrix will be:
[1*1 + 2*2;
C = 3*3 + 4*4;
5*5 + 6*6;
7*7 + 8*8]

Here is an even neater answer:
C = dot(A, B, 2);
You essentially want the dot product of the rows. This is one vectorized operation in MATLAB, so more efficient than element-wise product then a sum operation.

My matlab is a little rusty, but try
D = A .* B;
C = D(:,1) + D(:,2);
The first operation would produce a 4x2 matrix that contains the products of the corresponding elements from A and B, while the second operation adds the products from the same row.
The results you are seeking are also the diagonal elements from the matrix product, so you could use
C = diag(A * transpose(B));
although that would be terribly inefficient for larger matrices.

Aasmund Eldhuset is mostly correct but I believe the last line should be
C = D(:,1) + D(:,2);
as you want to sum each row in the final column

Related

How to code this matrix multiplication?

I have two matrices:
A = [1 2;
3 4;
5 6]
B = A'
The multiplication should take in the way as if row and column vector is extracted from both.
C = B(:,i) * A(i,:) such that for first instance (1st row and 1st column) the result would be:
[1 2;
2 4]
This will be summed up vertically to obtain [3 6]. This sum will give final answer 9. Likewise, 2nd row & 2nd column, 3rd row & 3rd column and so on if matrix size is higher.
This final scalar value will be used for comparing which row and its corresponding column has high yield.
Your required result is actually mathematically equivalent of:
sum(A,2).^2 %or sum(A,2) .* sum(A,2)
If A and B are not transpose of each other then:
sum(A,2).* sum(B,1).'
You can use sum:
result = sum(bsxfun(#times,sum(A,2), B.'),2);
Or in the recent version of MATLAB you can write:
result = sum(sum(A,2).*B.',2)
Previous answer:
You can use permute:
result = sum(reshape(permute(A,[2 3 1]) .* permute(A,[3 2 1]),[],size(A,1)));
Or in the case of A and B:
result = sum(reshape(permute(B,[1 3 2]) .* permute(A,[3 2 1]),[],size(A,1)));
result = [9 49 121]
Thanks to #TommasoBelluzzo and #SardarUsama .
If your Matrix is of Size Nx2, then one possible answer is
A.*A * [1;1] + 2*A(:,1).*A(:,2)

modifying matrix multiplication in matlab

I would like to have MATLAB perform matrix multiplication, where all multiply operations are replace by plus operation.
Here is an example:
a = [3,4; 5,6];
b = [1;2];
c = modified_multiplication(a,b); % = [3+1+4+2 ; 5+1+6+2] = [10 , 14].
How can I do this as efficient as the original * operation?
Your best bet is going to be to combine bsxfun with sum.
c = sum(bsxfun(#plus, a, b.'), 1);
% 10 14
The bsxfun call adds the first entry of b to all elements in the first row of a and the second entry of b to all the elements in the second row of a, etc..
bsxfun(#plus, a, b.')
% 4 6
% 6 8
Then the application of sum, sums down the columns.
For a and b of arbitrary sizes, it can be done as follows:
c = bsxfun(#plus, sum(a,2), sum(b,1));
This exploits the associative property of addition: first compute the sum of each row of a and of each column of b, and then compute all pairwise additions.

Shifting repeating rows to a new column in a matrix

I am working with a n x 1 matrix, A, that has repeating values inside it:
A = [0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4]
which correspond to an n x 1 matrix of B values:
B = [2;4;6;8;10; 3;5;7;9;11; 4;6;8;10;12; 5;7;9;11;13]
I am attempting to produce a generalised code to place each repetition into a separate column and store it into Aa and Bb, e.g.:
Aa = [0 0 0 0 Bb = [2 3 4 5
1 1 1 1 4 5 6 7
2 2 2 2 6 7 8 9
3 3 3 3 8 9 10 11
4 4 4 4] 10 11 12 13]
Essentially, each repetition from A and B needs to be copied into the next column and then deleted from the first column
So far I have managed to identify how many repetitions there are and copy the entire column over to the next column and then the next for the amount of repetitions there are but my method doesn't shift the matrix rows to columns as such.
clc;clf;close all
A = [0;1;2;3;4;0;1;2;3;4;0;1;2;3;4;0;1;2;3;4];
B = [2;4;6;8;10;3;5;7;9;11;4;6;8;10;12;5;7;9;11;13];
desiredCol = 1; %next column to go to
destinationCol = 0; %column to start on
n = length(A);
for i = 2:1:n-1
if A == 0;
A = [ A(:, 1:destinationCol)...
A(:, desiredCol+1:destinationCol)...
A(:, desiredCol)...
A(:, destinationCol+1:end) ];
end
end
A = [...] retrieved from Move a set of N-rows to another column in MATLAB
Any hints would be much appreciated. If you need further explanation, let me know!
Thanks!
Given our discussion in the comments, all you need is to use reshape which converts a matrix of known dimensions into an output matrix with specified dimensions provided that the number of elements match. You wish to transform a vector which has a set amount of repeating patterns into a matrix where each column has one of these repeating instances. reshape creates a matrix in column-major order where values are sampled column-wise and the matrix is populated this way. This is perfect for your situation.
Assuming that you already know how many "repeats" you're expecting, we call this An, you simply need to reshape your vector so that it has T = n / An rows where n is the length of the vector. Something like this will work.
n = numel(A); T = n / An;
Aa = reshape(A, T, []);
Bb = reshape(B, T, []);
The third parameter has empty braces and this tells MATLAB to infer how many columns there will be given that there are T rows. Technically, this would simply be An columns but it's nice to show you how flexible MATLAB can be.
If you say you already know the repeated subvector, and the number of times it repeats then it is relatively straight forward:
First make your new A matrix with the repmat function.
Then remap your B vector to the same size as you new A matrix
% Given that you already have the repeated subvector Asub, and the number
% of times it repeats; An:
Asub = [0;1;2;3;4];
An = 4;
lengthAsub = length(Asub);
Anew = repmat(Asub, [1,An]);
% If you can assume that the number of elements in B is equal to the number
% of elements in A:
numberColumns = size(Anew, 2);
newB = zeros(size(Anew));
for i = 1:numberColumns
indexStart = (i-1) * lengthAsub + 1;
indexEnd = indexStart + An;
newB(:,i) = B(indexStart:indexEnd);
end
If you don't know what is in your original A vector, but you do know it is repetitive, if you assume that the pattern has no repeats you can use the find function to find when the first element is repeated:
lengthAsub = find(A(2:end) == A(1), 1);
Asub = A(1:lengthAsub);
An = length(A) / lengthAsub
Hopefully this fits in with your data: the only reason it would not is if your subvector within A is a pattern which does not have unique numbers, such as:
A = [0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0;]
It is worth noting that from the above intuitively you would have lengthAsub = find(A(2:end) == A(1), 1) - 1;, But this is not necessary because you are already effectively taking the one off by only looking in the matrix A(2:end).

Filter elements from a 3D matrix without loop

I have a 3d matrix H(i,j,k) with dimensions (i=1:m,j=1:n,k=1:o). I will use a simple case with m=n=o = 2:
H(:,:,1) =[1 2; 3 4];
H(:,:,2) =[5 6; 7 8];
I want to filter this matrix and project it to an (m,n) matrix by selecting for each j in 1:n a different k in 1:0.
For instance, I would like to retrieve (j,k) = {(1,2), (2,1)}, resulting in matrix G:
G = [5 2; 7 4];
This can be achieved with a for loop:
filter = [2 1]; % meaning filter (j,k) = {(1,2), (2,1)}
for i = 1:length(filter)
G(:,i) = squeeze(H(:,i,filter(i)));
end
But I'm wondering if it is possible to avoid the for loop via some smart indexing.
You can create all the linear indices to get such an output with the expansion needed for the first dimension with bsxfun. The implementation would look like this -
szH = size(H)
offset = (filter-1)*szH(1)*szH(2) + (0:numel(filter)-1)*szH(1)
out = H(bsxfun(#plus,[1:szH(1)].',offset))
How does it work
(filter-1)*szH(1)*szH(2) and (0:numel(filter)-1)*szH(1) gets the linear indices considering only the third and second dimension elements respectively. Adding these two gives us the offset linear indices.
Add the first dimenion linear indices 1:szH(1) to offset array in elementwise fashion with bsxfun to give us the actual linear indices, which when indexed into H would be the output.
Sample run -
H(:,:,1) =
1 2
3 4
H(:,:,2) =
5 6
7 8
filter =
2 1
out =
5 2
7 4

How to efficiently access/change one item in each row of a matrix

I have a matrix A with size (nr,nc), a vector of column indices B (so B has size (nr,1) and every element in B is an integer between 1 and nc), and I want to do something to every element in A that is of the form A(i,B(i)) for i between 1 and nr, efficiency being the key concern.
For concreteness, say C is a vector of size (nr,1), the goal is to do
for i=1:nr
A(i,B(i))=A(i,B(i))+C(i)
end
more efficiently. The context is usually that nr>>nc (because when nr is large vectorization is efficient for many operations). I have gotten a factor 3 speedup by using an indicator function approach:
for k=1:nc
A(:,k)=A(:,k)+(k==B).*C
end
Are there other ways (more efficient hopefully) to do this?
I guess this is similar to many questions on double-indexing, but it's concretely one I run into all the time.
Use linear indexing:
idx = sub2ind(size(A), 1:nr, B');
A(idx) = A(idx) + C';
or (edited version with one less transpose)
idx = sub2ind(size(A), (1:nr)', B);
A(idx) = A(idx) + C;
One way would be to use linear indexing of the matrix. You will need a vector v holding the offsets of the first element in each line, then index using A(v + B). For example:
>A=[1 2 3; 4 5 6; 7 8 9]
A =
1 2 3
4 5 6
7 8 9
>B = [1 2 3] % we want the 1st element of row 1, 2nd of row 2, 3rd of row 3
>ii = [0 3 6] + B
>a(ii)
1 5 9
Note: As groovingandi had shown, it is also possible (and more readable) to use sub2ind to generate the ii linear indices vector. The idea is essentially the same.