Build a 3D least squares distance matrix without loops? - matlab

I am trying to build a three dimensional matrix out of three vectors where I take the least squares distance between each element of each vector as the entries of the matrix.
For example for the 3d matrix d,
d(m,n,o)=(vec1(m)-vec2(n))^2+(vec1(m)-vec3(o))^2+(vec2(n)-vec1(o))^2
I am currently doing this with a triple for loop:
d=zeros(N,M,O);
for o=1:O
for n=1:N
for m=1:M
d(n,m,o)=(((t(n)-r(m))^2)+((t(n)-z(o))^2)+((r(m)-z(o))^2));
end
end
end
My question is whether there is a quicker, cleverer way to do this for instance for a 2d version of this I could use:
%for n=1:N
% for m=1:M
% d(n,m)=(t(n)-r(m))^2;
% end
%end
d=(repmat(t(:),1,M)-repmat(r(:)',N,1)).^2; %this replaces the nested for loops from above Thanks Georg Schmitz
Whoever Georg Schmitz is came up with a way to use repmat to replace the double for loops in the 2d version. I could of course adapt this method and replace my triple for loops with one for loop that repeats the repmat method (o) number of times, But I feel like there should be a way to do this without loops.
Any ideas? Thanks

You can indeed vectorize the calculation:
%# properly reshape the vectors
vec1 = vec1(:); %# n-by-1
vec2 = reshape(vec2,1,[]); %# 1-by-m
vec3 = reshape(vec3,1,1,[]); %# 1-by-1-by-o
%# use bsxfun to efficiently replicate the arrays
d = bsxfun(#plus,bsxfun(#plus,...
bsxfun(#minus,vec1,vec2).^2,...
bsxfun(#minus,vec2,vec3).^2)),...
bsxfun(#minus,vec3,vec1).^2));

You should try pdist or pdist2 depending on your needs. pdist computes inner distances, while pdist2 computes a pairwise distance matrix.

Related

Store 3x3 matrix in a variable in a for loop

I have a 9x3 matrix that I subdivided into three (3) 3x3 matrix. Now I want to make a for loop function that will store each 3x3 matrix into a variable.
X=reshape(1:27,3,9)'; % sample 9x3 matrix
xx = mat2cell(X,[3,3,3],3); % subdivide X matrix into 3x3 cell matrix
for i:1:3
x(i) = xx{i,1}; %store the three cells into x1 x2 and x3 matrix
end
I know that this does not how it works in matlab but just to show the function I would like to attain.
You can use eval function.
X=reshape(1:27,3,9)'; % sample 9x3 matrix
xx = mat2cell(X,[3,3,3],3); % subdivide X matrix into 3x3 cell matrix
for i=1:3
eval(['x' num2str(i) ' = xx{' num2str(i) ',1};']);
end
But What you are asking for is not recommended at all. In fact i always avoid using eval because the code doesn't get checked by MATLAB editor.
It is also not a good idea to have multiple variables, instead use cells, structures, and so on for a better usage in the rest of your code.
Is this what you're looking for?
X=reshape(1:27,3,9)';
for i=1:3
block = X(3*i-2:3*i,:);
disp(block);
end
The preferred way to do this is to actually just store it in a 3D array and you can access each element along the third dimension. The reason for that is that MATLAB is optimized for computing using matrices, so if you keep all of your data in a matrix, operations can be performed in a vectorized fashion on all components.
Better yet you can remove the for loop needed to create it by using reshape and permute.
X = permute(reshape(X', [3 3 3]), [2 1 3]);
% And access each element
X(:,:,1)
X(:,:,2)
X(:,:,3)
This is going to be more performance than using cell arrays or eval.

How can I make dot product of vector and matrix faster in MATLAB?

My code works however it's fairly slow and i need to run it multiple times so it's very inefficient. i am positive there is a more efficient way of calculating it.
The code is an implementation of this equation:
where k(x,y) is the dot product of the two vectors
xi and yj are the rows i,j of the two matrices A and B, respectively.
I'd like to also note that the number of rows in each matrix is in the thousands.
here is my code
m=size(A,1);
Kxx=0;
for i=1:m
x=A(i,:);
X=A(i+1:end,:);
Kxx=Kxx+2*sum(dot(ones(m-i,1)*x,X,2));
end
Kxx=Kxx/(m*(m-1));
n=size(B,1);
Kyy=0;
for j=1:n
y=B(j,:);
YY=B(j+1:end,:);
Kyy=Kyy+2*sum(dot(ones(n-j,1)*y,YY,2));
end
Kyy=Kyy/(n*(n-1));
Kxy=0;
for i=1:m
x=A(i,:);
for j=1:n
y=B(j,:);
Kxy=Kxy+dot(x,y);
end
end
Kxy=Kxy*2/(m*n);
Dxy=Kxx+Kyy-Kxy;
Your edit makes our jub much easier. Here's what you just have to do for a fully vectorized solution:
C=A*A'; %'
Kxx=sum(sum(C-diag(diag(C))))/m/(m-1);
C=B*B'; %'
Kyy=sum(sum(C-diag(diag(C))))/n/(n-1);
Kxy=2*mean(reshape(A*B.',[],1)); %'
Dxy=Kxx+Kyy-Kxy;
Thanks to #hiandbaii for pointing out that the equivalent of dot for complex vectors involves the conjugate transpose rather than the transpose.
Original, looping version for historical sentimental reasons:
I'm not sure whether the first two loops can be vectorized without huge memory overhead. So while I figure this out, here's a version in which the first two loops are a bit simplified, and the third loop is replaced by a vectorized operation:
%dummy input data
A=rand(5);
B=rand(5);
m=size(A,1);
Kxx=0;
for l=1:m
x=A(l,:);
X=A(l+1:end,:);
Kxx=Kxx+2*sum(X*x.'); %'
end
Kxx=Kxx/(m*(m-1));
n=size(B,1);
Kyy=0;
for l=1:n
y=B(l,:);
YY=B(l+1:end,:);
Kyy=Kyy+2*sum(YY*y.'); %'
end
Kyy=Kyy/(n*(n-1));
Kxy=2*mean(reshape(A*B.',[],1)); %'
Dxy=Kxx+Kyy-Kxy;

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.

Large Vector Outer Product Matlab

I want to compute an outer product of the same vector in Matlab. A representative example would be:
x=rand(1e5,1);
sigma=x*x'-spdiags(x,0,length(x),length(x));
Is there any obvious way to speed this up? x*x' is a symmetric matrix, but have not figured out a way to help Matlab use that information to speed things up.
EDIT: There is a way to do this with loops but I cannot see the benefit yet:
for k=1:length(x)
sigma(k:length(x),k)=x(k).*x(k:length(x));
end
The above might work with a sparse array.
Have you considered using pdist with custom distance function
sigmaCompact = pdist( x(:), #(x, Y) x.*Y );
sigma = squareform(sigmaCompact);
up to the special treatment of sigma( k, k );

How to vectorise this simple assignment loop in matlab

I have a vector v of values and a vector r of indices. I want to store the values in a matrix m as follows:
for i = 1:length(v)
m(i, r(i)) = v(i);
end
What is the fastest way to do this in a vectorized way?
I do not know if it is faster, I suppose so but the difference might be very small, but here is one way:
m(sub2ind(size(m),1:length(v),r(1:length(v))))=v;
If r is a column vector then sub2ind will complain about vectors size, you can just take its transpose and it will solve this.