Using a diagonal values in a square matrix? to avoid loop - matlab

I have 2 (1 x n) matrices that I want to multiply each element together, n number of times, shifting the second matrix 1 step each time.
This code works fine, but I'm wondering if a better way with (n by n) matrix, values on the diagonals and no 'for loop' would be faster (more elegant) ?
y = [];
for i=[1:length(x1)]
x2 = circshift(x2,[0,1]);
y(i) = sum(x1 .* x2);
end;

You can use convolution to obtain the same result as your code:
y = conv(x1, fliplr([x2 x2]), 'same');

Related

How can I multiply a matrix with vector and reshape it using one matrix multiplication using matlab

I have a matrix X with size N x N, and a vector Y with size NM x 1. I want to multiply the matrix X with every N elements in Y and then reshape the resultant matrix Z row-wise. In other words, I first reshape the vector Y into a matrix Y_2 with size N x M . Then, get the matrix Z = X * Y_2, and finally reshape the matrix Z row-wise.
That process, I want to do it in matlab using matrices multiplications, as follows:
clear all; clc; clear;
N = 4; M = 8;
X = randn(N,N);
Y = randn(N*M,1);
Z = kron(eye(M,M),X) * Y;
The problem, is that I don't get $Z$ similar to that process explained above. I mean the result of the way I used in Matlab code is not similar to the results of the process explained before. how can I do it, where is it error in my other method?

Multiplying non-zeros values of two matrices

I have two matrices multiplied with each other H.Z where both matrices H and Z have the same size of (256,256). Matrix Z is permutation matrix has the following pattern: In the first 32 rows, only columns 1,9,17,...(256-8) are non-zeros, other columns are zeros, next 32 rows, only columns 2,10,18,...(256-7) are non-zeros, other columns are zeros and so on till the last 32 rows, where columns 8,16,24,....,256 are non-zeros and other columns are zeros.
Therefore, multiplying matrix H with Z includes only multiplying the first 32 elements of first row in H with the first 32 element of column 1 of matrix Z, then next 32 element of first rows of matrix H with next 32 element (33-64 elements) of column 2 in matrix Z and so on. because all other multiplications will result of zero. So in that way, the number of multiplication will be less.
My question, I couldn't write that in Matlab !! I don't know how create the loop to go through only the non-zeros elements. Could you please help in that?
Thank you in advance.
For loops are generally much slower than inbuilt MATLAB operations. A better options is to multiply only the nonzero elements of Z using the following approach.
result = zeros(256,256);
result(Z ~= 0) = H(Z ~= 0) .* Z(Z ~= 0);
You can see the complete code below, running a test to make sure it gets the right answer, and timing the code to see if it's faster.
% setup variables
H = rand(256,256);
Z = zeros(256,256);
for i = 1:8
Z((i-1)*32+1:i*32, i:8:256) = 1;
end
% run calcuations and check that they are equal
HZ1 = f1(H, Z);
HZ2 = f2(H, Z);
are_equal = all(all(HZ1 == HZ2));
% time both functions
timeit(#() f1(H,Z))
timeit(#() f2(H,Z))
function result = f1(H, Z)
result = H .* Z;
end
function result = f2(H, Z)
result = zeros(256,256);
result(Z ~= 0) = H(Z ~= 0) .* Z(Z ~= 0);
end
Timeit results:
f1 - 6.875835e-05 s
f2 - 0.0008205853 s
Unfortunately, the new approach is about 12 times slower than just multiplying the matrices elementwise. This is because MATLAB is heavily optimised for matrix multiplication, and multiplying the complete matrices H and Z ensures the memory to be operated on is contiguous.

MATLAB: summing out one variable in equation

I have the variables
X = 1x20 vector of doubles
i = 0:M
j = 0:M
And the equation
sum n=1 to length(X) : (X(n)^(i+j))
Is there a way to obtain an MxM matrix (through the indices i,j) while summing out n in each cell? I tried this with symsum but it doesn't allow indexing with n.
Any help is appreciated!
By reshaping X to a vector of size [1 x 1 x 20] and using implicit expansion a 3D [M+1 x M+1 x 20] array is created then by summing along the third dimension the result can be obtained.
X = rand(1,20);
M = 30;
ii = 0:M;
jj = (0:M).';
Y = reshape(X,1,1,[]);
result = sum(Y.^(ii+jj), 3);
However as the expression Y.^(ii+jj) creates a 3D [M+1 x M+1 x 20] array it may need a large amount of memory that leads to decreased performance.
We know that x^(i+j) can be written as x^i * x^j So the expression can be written as:
result = sum(Y.^ii .* Y.^jj,3);
It has the same memory consumption as the previous method. But when we reach an expression that contains sum of products we should think about converting it to very fast matrix multiplication :
Z = X .^ jj; % A [M+1 x 20] matrix is created(implicit expansion)
result = Z * Z.' % multiply Z by its transpose
So the same result is obtained without the complexity of the other solutions.

Best way to perform a convolution with a new vector for each image?

I try to figure out the best way to perform a kind of convolution.
I have a 3D matrix I = [N x M x P] and a 2D matrix S = [1 x 1 x K x P]. For each pth frame (third dimension) of my 3D matrix I want to return the valid convolution between I(:, :, p-K/2:p+K/2) and S(1, 1, :, p). Do you see a way to do this ?
In fact, in terms of computation the numbers of operation in very close to a standard convolution, the difference is that I need to change the second matrix for each frame...
This is the method I currently use:
% I = 3D matrix [N x M x P]
% S = Filter [1 x 1 x K x P] (K is an odd number)
% OUT = Result
[N, M, P] = size(I); % Data size
K = size(S, 3); % Filter length
win = (K-1)/2 ; % Window
OUT = zeros(size(I)); % Pre-allocation
for p = win+1:P-win
OUT(:, :, p) = convn(I(:, :, p-win:p+win), S(1, 1, :, p), 'valid'); % Perform convolution
end
At the end we have the same number of operations than the standard convolution, the only difference is that the filter is different for each frame...
Any idea ?
Thanks ;)
So you want to convolve a NxMxK sub-image with a 1x1xKx1 kernel, and then only take the valid part, which is an NxM image.
Let's look at this operation for a single (x,y) location. This 1D convolution, of which you only keep 1 value, is equivalent to the dot product of the sub-image and your kernel:
OUT(x,y,p) = squeeze(I(x,y,p-win:p+win))' * squeeze(S(1,1,:,p))
This you can vectorize across all (x,y) by reshaping the sub-image of I to a (N*M)xK matrix (the K is horizontal, S is a column vector).
Repeating this across all p is easiest to implement with a loop, as you do now. The alternative is to create a larger S where each column is shifted by one, so you can do a single dot product between tge two matrices. But that S is also espensive to create, presumably requires a loop too. I don't think that avoiding loops is that pressing any more in MATLAB (it's gotten a lot faster over the years) and the product itself is probably the most expensive part of the algorithm anyway.

Multiplication of vectors in two loops

I want to multiply two vectors to produce a matrix.
I have a vector 1*m and another 1*n which are in my case V (1*71) and I (1*315). The other vectors have same length as I.
I want to multiply every value of I with all values of V and have the answer in a matrix where every row or column of new matrix is I(t).*V
Ir and Temp are vectors with the size of 1*315 and all the variables have the same length and T is 315.
The other parameters that you see in the code are constant values.
This is the code :
function [I] = solar2diodedyn( Ir,time,Temp )
V = 0:0.01:0.7; %open circuit voltage of one cell in V.
for t=1:time;
T(t)= Temp(t)+273;
Vt(t)=(k*T(t))/q;
Iph(t) = Isc_cell*(Ir(t)/1000)*(1+(T_co*(Temp(t)-25)));
I0(t)=Is1*((T(t)/Tmeas)^(3/n1))*exp(Eg*((T(t)/Tmeas)-1)/(n1*Vt(t)));
I02(t)=Is2*((T(t)/Tmeas)^(3/n2))*exp(Eg*((T(t)/Tmeas)-1)/(n2*Vt(t)));
I(t) = zeros(size(t));
i=length(V);
for x=1:i
I(t) = Iph(t) - I0(t)*(exp((V(x)+I(t)*Rs)/(n1*Vt(t)))-1)-I02(t)*(exp((V(x)+I(t)*Rs)/(n2*Vt(t)))-1)-((V(x)+I(t)*Rs)/Rsh);
end
end
Thanks in advance
If you have two vectors x (of size 1-by-n) and y (of size 1-by-m) and you want a matrix M of size n-by-m such that M(i,j) = x(i) * y(j) then you are trying to compute the outer product of x and y.
This can be done easily with matlab
>> M = x.' * y;