Multiplying non-zeros values of two matrices - matlab

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.

Related

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.

Generating random diagonally dominant dense/sparse matrices in matlab

Is there a matlab command for generating a random n by n matrix, with elements taken in the interval [0,1], with x% of the entries on the off-diagonal to be 0. Then, additionally setting the element in the diagonal to be the sum of every element in its respective column? In order to create a diagonally dominant dense/sparse matrix? This may be easy enough to write a code for but I was wondering if there was already a built in function with this capability.
EDIT:
I am new to Matlab/programming so this was an easier said than done. I'm having trouble making the matrix with the percentage ignoring the diagonal. It's a n x n matrix, so there are $n^2$ entries, with n of them on the diagonal, I want the percentage of zeros to be taken from $n^2 - n$ elements, i.e. all the off-diagonal elements. I cannot implement this correctly. I do not know how to initialize my M (see below) to correspond correctly.
% Enter percentage as a decimal
function [M] = DiagDomSparse(n,x)
M = rand(n);
disp("Original matrix");
disp(M);
x = sum(M);
for i=1:n
for j=1:n
if(i == j)
M(i,j) = x(i);
end
end
end
disp(M);
Here is one approach that you could use. I'm sure you will get some other answers now with a more clever approach, but I like to keep things simple and understandable.
What I'm doing below is creating the data to be put in the off-diagonal elements first. I create an empty matrix and copy this data into the off-diagonal elements using linear indexing. Now I can compute the sum of columns and write those into the diagonal elements using linear indexing again. Because the matrix was initialized to zero, the diagonal elements are still zero when I compute the sum of columns, so they don't interfere.
n = 5;
x = 0.3; % fraction of zeros in off-diagonal
k = round(n*(n-1)*x); % number of zeros in off-diagonal
data = randn(n*(n-1)-k,1); % random numbers, pick your distribution here!
data = [data;zeros(k,1)]; % the k zeros
data = data(randperm(length(data))); % shuffle
diag_index = 1:n+1:n*n; % linear index to all diagonal elements
offd_index = setdiff(1:n*n,diag_index); % linear index to all other elements
M = zeros(n,n);
M(offd_index) = data; % set off-diagonal elements to data
M(diag_index) = sum(M,1); % set diagonal elements to sum of columns
To refer to the diagonal you want eye(n,'logical'). Here is a solution:
n=5;
M = rand(n);
disp("Original matrix");
disp(M);
x = sum(M);
for i=1:n
for j=1:n
if(i == j)
M(i,j) = x(i);
end
end
end
disp('loop solution:')
disp(M);
M(eye(n,'logical'))=x;
disp('eye solution:')
disp(M);

Perform element wise multiplication of vectors efficiently?

I have to perform matrix updating by M = M + c*a*a' large number of times, where c is a constant and a is a column vector. If the size of matrix is larger than 1000, this simple updating will cost most of the time of my function, typically more than 1 min counted by profile.
Main codes are:
for i = 1:N
_do something..._
for k = 1:n
a(1:k) = M(1:k,1:k)*p(1:k);
M(1:k,1:k) = M(1:k,1:k)+c*a(1:k)*a(1:k)';
M(1:k, k+1) = b(1:k);
M(k+1, 1:k) = b(1:k)';
M(k+1, k+1) = x;
......
end
end
I have preallocated all variables, column vectors p and b are known, and x is another constant.
As I have large number of data to process by this function, does there exist more efficient alternative to this matrix updating?
You can concatenate a vectors to create a matrix A then apply multiplication just one time.
A =[a1 a2 a3];
M = c * A * A.';
consider the example
A = rand(5,5);
M = 0;
c=4;
for n = 1:5
M = M + c * A(:,n) * A(:,n).';
end
and this one
M1 = c * A * A.'
both M and M1 are equal
Have you tried using bsxfun?
In any case, bsxfun is much faster than regular multiplication, but the vectors/matrices have to be of equal length (which they are for you, aren't they?), and it's operating elementwise (i.e. a Nx1 vector bsx-multiplied with itself yields a Nx1 vector, multiplied with the transpose however yields a NxN matrix).
see https://mathworks.com/help/matlab/ref/bsxfun.html
use as
bsxfun(#times, a, a')

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

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

Two for loops (nested), computing matrices Matlab

my current code is below.
What I have is two sets of data phi and theta both 18x30 and I have a for loop running from 1 to 30 which are the 30 columns of my data. Each of these individual columns will produce a matrix 'B' for me. The matrix 'B' is produced after going through the 18 rows of each column.
The problem I have is that I need to multiply all the resulting 'B' matrices for each of the 18 rows with each other in order to get a final matrix for each of the 30 columns, that is why I have set A(:,:,i) = eye(2) so that my first matrix will multiply by A. But I don't want to store A or B for each loop, instead what I want is that on the first loop of i my matrix B will multiply the identity matrix A. Then that matrix A will multiply the next matrix B...with the result of each multiplication being carried forward to the next matrix B that will be calculated, so the multiplications will get done as the program loops. That's why I have the line:
A(:,:,i) = A.*B;
but it doesn't seem to work. I get an error message saying the dimensions must match.
At the end of the program I want to be able to access each of the 30 matrices using a command like:
A(:,:,3), for example, to get my 2x2 matrix for the 3rd column.
Hope that was clear enough!
theta = dlmread('theta.dat');
phi = dlmread('phi.dat');
ne = 1.7;
no = 1.5;
d = 0.000001;
w = 0.000000555;
for i = 1:30
A(:,:,i) = eye(2);
for j = 1:18
nx =((cos(theta(j,i)).^2)/(no^2) + ((sin(theta(j,i)).^2)/(ne^2))).^(-1/2);
D = (2*pi*(nx-no)*d)/w;
x = ((cos(phi(j,i))).^2).*exp((-1i.*D)/2) + ((sin(phi(j,i))).^2).*exp((1i.*D)/2);
y = 1i*(sin(D/2)).*sin(2*phi(j,i));
z = ((cos(phi(j,i))).^2).*exp((1i.*D/2) + ((sin(phi(j,i))).^2).*exp((-1i.*D)/2));
B = [x y;y z];
A(:,:,i) = A.*B;
end
end
B is a 2x2 matrix. For A.*B to work, A must also be 2x2. But A in your program is three-dimensional.
From your problem description, I think you want
A(:,:,i) = A(:,:,i)*B; % Edited now that I see this happens 18 times on the same i
(Please note, I also replaced element-wise multiply .* with matrix multiply *, because that's what it sounds like you want.)
But I suggest
A = eye(2);
and
A = A*B;
and store it at the end like
results(:,:,i) = A;