Matlab 3D matrix multiplication - matlab

In Matlab, I have two m-by-n matrices X and Y, with n>m.
I need to define a 3D m-by-m-by-n matrix Z whose components can be computed as
for i=2:m
for j=i+1:m
for k=1:n
Z(i,j,k) = (Y(j-1,k)-Y(i-1,k))*X(j-1,k);
end
end
end
As these nested loops require a long computational time, I have been looking for a way to define the matrix Z using matrices multiplication, but I have not managed so far. Any suggestion?

You can simply remove the inner loop (over k) by writing
Z(i,j,:) = (Y(j-1,:)-Y(i-1,:)).*X(j-1,:);
Note the .* element-wise multiplication. You can then proceed to remove additional loops in a similar manner.
But note that, most likely, your loop is slow because you don't preallocate the output array. Do this before the loop:
Z = zeros(m,m,n);
You can also gain a bit of speed by reversing the loop order, such that the first index is iterated over in the innermost loop, and the last index is iterated over in the outermost loop. This accesses the matrix data in memory order, making your cache more efficient.

Related

How would you do this matrix operation in MATLAB?

Given two random variables X and Y, where X=(x1,..,xn) and Y=(y1,...,yn) in a nx2 matrix A, so A=[X Y], i need to perform the next operation:
median((x-median(x))(y-median(y)))
I'm trying to obtain an estimator of the covariance matrix using the median instead the mean, for a nxt matrix where t represents the number of random variables and n the length of the data set.
So far, I made the next code:
for i=1:n
for j=1:n
a1=median(A(:,i));
a2=median(A(:,j));
SMM(i,j)=median(((A(:,i)-a1(ones(t,1),:)).*(A(:,j)-a2(ones(t,1),:))));
end
end
However, theoretically I must obtain a semidefinite (positive or negative) symmetric matrix, however that's not the case with this code.
Am I making any mistake in the code formulation?
Various points:
For each of your columns of A (x, y), the median (a1, a2) doesn't change. You should compute these outside the loops.
The loops go over n, rather than t, which are the variables and the indices to the output matrix.
I would first subtract the median from each column, to avoid repeatedly doing the same computations:
A = A - median(A,1); % be explicit about which dimension to take the median over!
Next, we'd loop over the txt output elements of the covariance matrix, and compute each of the elements:
t = size(A,2);
SMM = zeros(t,t); % always preallocate output arrays before a loop
for j=1:t
for i=1:t
SMM(i,j) = median(A(:,i).*A(:,j));
end
end
The loop can likely be vectorized, but that leads to a large intermediate matrix, which slow down code also. So it might not be worth the effort to vectorize. Only try it if this code is too slow!
It should also be possible to run the inner loop from i=j:t, to skip computing the redundant half of the symmetric matrix, instead copying over the previously computed values.

Matlab: stack all values under each other in double for loop

I'm running a double for loop for the calculation of solar radiation, something like:
for b=1:365 %amount of days
for n=1:24 %amount of hours
solar(b,n)=sin(ht(b,n))+...
end
end
However, instead of the creation of a 365x24 martrix, I'd like a 8760x1 array where all the values are plotted under each other in 1 colomn. It is important that this happens within the for loop, as some other calculation need to be done on the array in this loop.
Thanks!
MATLAB matrices are inherently accessible as if they are 1-dimensional vectors via linear indexing. The linear order of matrix elements goes in ascending order of dimension, so to make your matrix order by hour and then by day, simply swap the dimensions you index into solar:
solar(n,b)=sin(ht(b,n))+...
If you explicitly need a 8760x1 array, you can then obtain this as solar(:). However if you simply needed to iterate over all elements in a single loop you can rely on linear indexing without reshaping the matrix:
for n = 1:numel(solar)
% doSomething(solar(n));
end

"Filling up" an empty vector in Matlab by a for loop

I am trying to create a loop code in MATLAB that "fills up" the elements in an empty column vector of size l x 1, called m. As I don't have very much experience in MATLAB, I am unsure if this is the correct way to go about it.
Note: Seeing as i pertains to the complex quantity in matlab, I denote the i-th element of an array as the ii-th element.
l=length(A); %The number of rows in the empty vector we seek as our output;
%so as to preallocate space for this vector.
q=eigencentrality(A);%An lx1 column vector whose ii-th elements are used in the loop.
l1=max(eig(A)); %A scalar used in the loop.
CS=sg_centrality(A); %%An lx1 column vector whose ii-th elements are used in the loop.
%Now for the actual loop that will "fill up" each ii-th entry
%of our empty vector, m.
m=NaN(l,1); %create the empty vector to be "filled up".
for ii=1:l
m(ii,:)=log(q(ii)^2)*sinh(l1)/CS(ii)^1/2;%this is the form that I want each entry
%of m to have. Note how the ii-th element
%of m depends on the corresponding ii-th
%element of CS and q!
end
Is this the right way to go about "filling up" such an empty column vector, m, whose entries depend on the corresponding elements of two other vectors as above?
Cheers!
You can do this completely vectorized. Vectorization is the act of processing data chunks at a time rather than individually as you're doing in your code. In fact, this is one of MATLAB's main advantages. You can replace that for loop with:
m = log(q.^2).*(sinh(l1)./CS).^1/2;
The .* and .^ operators are known as element-wise operators. This means that each value in each of q, li and CS will contribute to the corresponding position in the output. There's no need to use a loop.
Check out this MathWorks note on vectorization here: http://www.mathworks.com/help/matlab/matlab_prog/vectorization.html
You can vectorize all the operations, without using a for loop. This should work:
m=log(q.^2).*(sinh(l1)./CS).^1/2;
Note, that the dots denote elementwise operations. Usually this is much faster than using a loop. Also, just as a side note, you can then drop the preallocation.

Are single loops or dense loops more computationlly efficent in matlab?

Im am currently writing a code to implement a numerical approximation to the 3D steady state heat equation using finite difference matrix methods. This involves discritising the 2nd order PDE into the matrix A and solving Ax=b. where x is temperature at each of the specified grid points. Further information on this type of question can be found here:
http://people.nas.nasa.gov/~pulliam/Classes/New_notes/Matrix_ODE.pdf
To complete this problem, I have represented the 3D matrix A by a 2D array calling the values in the 1D array b using an indexing function of the form:
i+(j-1)*Nx+Nx*Ny*(k-1)
for the (i,j,k)th element of the 3D matrix where Nx, Ny, Nz are the number of points in the x,y,z coordinates. There ends up being a lot of loop computation in order to create the matrix A and b and I was wondering what is the most computationally efficient and less memory exhaustive way to run these loops, i.e. is it better to use something like
for j=1:Ny
for i=2:Nx-1
b(i+(j-1)*Nx)=D4;
end
end
for j=1:Ny
for i=2:Nx-1
b(i+(j-1)*Nx+Nx*Ny*(Nz-1))=D3;
end
end
or should I condense these into a single loop like:
for j=1:Ny
for i=2:Nx-1
b(i+(j-1)*Nx)=D4;
b(i+(j-1)*Nx+Nx*Ny*(Nz-1))=D3;
end
end
I have preallocated both the arrays A and b. Is there a vectorised way to do this also?
Assuming Nx, Ny, Nz, D3 and D4 to be scalars and that you are using pre-allocation for b with zeros, you may try this vectorized approach -
I = 2:Nx-1; %// Vectors to represent i
J = 1:Ny; %// Vectors to represent j
ind1 = bsxfun(#plus,I,[(J-1)*Nx]'); %//' Indices, 1st set of nested loops
ind2 = bsxfun(#plus,I,[(J-1)*Nx+Nx*Ny*(Nz-1)]'); %//' Indices, 2nd set of loops
b(ind1) = D4; %// Assign values for 1st set
b(ind2) = D3; %// Assign values for 2nd set
The second method should be slightly faster since it performs the same number of calculations with fewer increments of the loop variables. You can look into MATLAB's built-in stopwatch commands tic and toc to time your code. http://www.mathworks.com/help/matlab/ref/tic.html
Something more vectorized might be possible but I would need to know more about the format of the arrays that contain D3 and D4. The reshape() function might be able to help.

Matlab - Create N sparse matrices and sum them

I have N kx1 sparse vectors and I need to multiply each of them by their transpose, creating N square matrices, which I then have to sum over. The desired output is a k by k matrix. I have tried doing this in a loop and using arrayfun, but both solutions are too slow. Perhaps one of you can come up with something faster. Below are specific details about the best solution I've come up with.
mdev_big is k by N sparse matrix, containing each of the N vectors.
fun_sigma_i = #(i) mdev_big(:,i)*mdev_big(:,i)';
sigma_i = arrayfun(fun_sigma_i,1:N,'UniformOutput',false);
sigma = sum(reshape(full([sigma_i{:}]),k,k,N),3);
The slow part of this process is making sigma_i full, but I cannot reshape it into a 3d array otherwise. I've also tried cat instead of reshape (slower), ndSparse instead of full (way slower), and making fun_sigma_i return a full matrix rather than a sparse one (slower).
Thanks for the help! ,