I have an Nx3 array that contains N 3D points
a1 b1 c1
a2 b2 c2
....
aN bN cN
I want to calculate Euclidean distance in a NxN array that measures the Euclidean distance between each pair of 3D points. (i,j) in result array returns the distance between (ai,bi,ci) and (aj,bj,cj). Is it possible to write a code in matlab without loop ?
The challenge of your problem is to make a N*N matrix and the result should return in this matrix without using loops.
I overcome this challenge by giving suitable dimension to Bsxfun function. By default X and ReshapedX should have the same dimensions when we call bsxfun function. But if the size of the matrixes are not equal and one of them has a singleton (equal to 1) dimension, the matrix is virtually replicated along that dimension to match the other matrix. Therefore, it returns N*3*N matrix which provides subtraction of each 3D point from the others.
ReshapedX = permute(X,[3,2,1]);
DiffX = bsxfun(#minus,X,ReshapedX);
DistX =sqrt(sum(DiffX.^2,2));
D = squeeze(DistX);
Use pdist and squareform:
D = squareform( pdist(X, 'euclidean' ) );
For beginners, it can be a nice exercise to compute the distance matrix D using bsxfun (hover to see the solution).
elemDiff = bsxfun( #minus, permute(X,[ 1 3 2 ]), permute(X, [ 3 1 2 ]) );
D = sqrt( sum( elemDiff.^2, 3 ) );
To complete the comment of Divakar:
x = rand(10,3);
pdist2(x, x, 'euclidean')
Related
I have 5-dimensional array of numbers. The goal is to find maximum values along 5-th dimension and their coordinates. I use
[x,y] = max(A,[],5);
Ideally I expect that x == A(y), however this does not appear to happen. I need an idea of how to translate y to an array of coordinates z such that x == A(z). Using find + loops is costly in my case, since matrices are huge.
Suppose your matrix A has dimension of (m,n,o). Now you have the indices of maximum entries along the 3rd dimension in y and the corresponding maximum values in x. You can access the maximum values by the following code-
z = (1:m*n)' + (y(:)-1)*(m*n); % linear index of these locations in full array
final_matrix = reshape(A(z),m,n);
It can be easily extended to 5 dimensional matrices.
Try this code for 5-dimensional-
[x,y] = max(A,[], 5);
z = (1:m*n*o*p)' + (y(:)-1)*(m*n*o*p);
final_matrix = reshape(A(z),m,n,o,p);
s = size(A);
[v,ii] = max(reshape(A,[],s(3)));
[i1 j1 ] = ind2sub(s(1:2),ii);
out = [v;i1;j1;1:s(3)]';
QUESTION
I'm looking for an elegant way to multiply two arrays along one particular dimension.
SIMILAR QUESTION
There is already a similar question on the official matlab forum, but the thread is outdated (2004).
EXAMPLE
M1 a [6x4x4] matrix and M2 a [6x1] matrix, I would like to multiply (element by element) M1 with M2 along the 3rd dimension of M1 to obtain a matrix M [6x4x4]
An equivalent to:
M1 = rand(6,4,4);
M2 = rand(6,1);
for ii = 1:size(M1,2)
for jj = 1:size(M1,3)
M(:,ii,jj) = M1(:,ii,jj).*M2;
end
end
VISUAL EXAMPLE
Do you know a cool way to do that ? (no loop, 1 or 2 lines solution,...)
If I'm interpreting your question correctly, you want to take each temporal slice (i.e. 1 x 1 x n) at each spatial location in M1 and element-wise multiply it with a vector M2 of size n x 1. bsxfun and permute are perfect for that situation:
M = bsxfun(#times, M1, permute(M2, [2 3 1]));
Say i have a N-Dimensional matrix A that can be of any size. For example:
A = rand([2,5,3]);
I want to calculate all possible pairwise differences between elements of the matrix, along a given dimension. For example, if i wanted to calculate the differences along dimension 3, a shortcut would be to create a matrix like so:
B = cat(3, A(:,:,2) - A(:,:,1), A(:,:,3) - A(:,:,1), A(:,:,3) - A(:,:,2));
However, i want this to be able to operate along any dimension, with a matrix of any size. So, ideally, i'd like to either create a function that takes in a matrix A and calculates all pairwise differences along dimension DIM, or find a builtin MATLAB function that does the same thing.
The diff function seems like it could be useful, but it only calculates differences between adjacent elements, not all possible differences.
Doing my research on this issue, i have found a couple of posts about getting all possible differences, but most of these are for items in a vector (and ignore the dimensionality issue). Does anyone know of a quick fix?
Specific Dimension Cases
If you don't care about a general solution, for a dim=3 case, it would be as simple as couple lines of code -
dim = 3
idx = fliplr(nchoosek(1:size(A,dim),2))
B = A(:,:,idx(:,1)) - A(:,:,idx(:,2))
You can move around those idx(..) to specific dimension positions, if you happen to know the dimension before-hand. So, let's say dim = 4, then just do -
B = A(:,:,:,idx(:,1)) - A(:,:,:,idx(:,2))
Or let's say dim = 3, but A is a 4D array, then do -
B = A(:,:,idx(:,1),:) - A(:,:,idx(:,2),:)
Generic Case
For a Nth dim case, it seems you need to welcome a party of reshapes and permutes -
function out = pairwise_diff(A,dim)
%// New permuting dimensions
new_permute = [dim setdiff(1:ndims(A),dim)];
%// Permuted A and its 2D reshaped version
A_perm = permute(A,new_permute);
A_perm_2d = reshape(A_perm,size(A,dim),[]);
%// Get pairiwse indices for that dimension
N = size(A,dim);
[Y,X] = find(bsxfun(#gt,[1:N]',[1:N])); %//' OR fliplr(nchoosek(1:size(A,dim),2))
%// Get size of new permuted array that would have the length of
%// first dimension equal to number of such pairwise combinations
sz_A_perm = size(A_perm);
sz_A_perm(1) = numel(Y);
%// Get the paiwise differences; reshape to a multidimensiona array of same
%// number of dimensions as the input array
diff_mat = reshape(A_perm_2d(Y,:) - A_perm_2d(X,:),sz_A_perm);
%// Permute back to original dimension sequence as the final output
[~,return_permute] = sort(new_permute);
out = permute(diff_mat,return_permute);
return
So much for a generalization , huh!
This question is related to matlab: find the index of common values at the same entry from two arrays.
Suppose that I have an 1000 by 10000 matrix that contains value 0,1,and 2. Each row are treated as a sample. I want to calculate the pairwise distance between those samples according to the formula d = 1-1/(2p)sum(a/c+b/d) where a,b,c,d can treated as as the row vector of length 10000 according to some definition and p=10000. c and d are probabilities such that c+d=1.
An example of how to find the values of a,b,c,d: suppose we want to find d between sample i and bj, then I look at row i and j.
If kth entry of row i and j has value 2 and 2, then a=2,b=0,c=1,d=0 (I guess I will assign 0/0=0 in this case).
If kth entry of row i and j has value 2 and 1 or vice versa, then a=1,b=0,c=3/4,d=1/4.
The similar assignment will give to the case for 2,0(a=0,b=0,c=1/2,d=1/2),1,1(a=1,b=1,c=1/2,d=1/2),1,0(a=0,b=1,c=1/4,d=3/4),0,0(a=0,b=2,c=0,d=1).
The matlab code I have so far is using for loops for i and j, then find the cases above by using find, then create two arrays for a/c and b/d. This is extremely slow, is there a way that I can improve the efficiency?
Edit: the distance d is the formula given in this paper on page 13.
Provided those coefficients are fixed, then I think I've successfully vectorised the distance function. Figuring out the formulae was fun. I flipped things around a bit to minimise division, and since I wasn't aware of pdist until #horchler's comment, you get it wrapped in loops with the constants factored out:
% m is the data
[n p] = size(m, 1);
distance = zeros(n);
for ii=1:n
for jj=ii+1:n
a = min(m(ii,:), m(jj,:));
b = 2 - max(m(ii,:), m(jj,:));
c = 4 ./ (m(ii,:) + m(jj,:));
c(c == Inf) = 0;
d = 1 - c;
distance(ii,jj) = sum(a.*c + b.*d);
% distance(jj,ii) = distance(ii,jj); % optional for the full matrix
end
end
distance = 1 - (1 / (2 * p)) * distance;
When calling norm on a matrix in MATLAB, it returns what's known as a "matrix norm" (a scalar value), instead of an array of vector norms. Is there any way to obtain the norm of each vector in a matrix without looping and taking advantage of MATLAB's vectorization?
You can compute the norm of each column or row of a matrix yourself by using element-wise arithmetic operators and functions defined to operate over given matrix dimensions (like SUM and MAX). Here's how you could compute some column-wise norms for a matrix M:
twoNorm = sqrt(sum(abs(M).^2,1)); %# The two-norm of each column
pNorm = sum(abs(M).^p,1).^(1/p); %# The p-norm of each column (define p first)
infNorm = max(M,[],1); %# The infinity norm (max value) of each column
These norms can easily be made to operate on the rows instead of the columns by changing the dimension arguments from ...,1 to ...,2.
From version 2017b onwards, you can use vecnorm.
The existing implementation for the two-norm can be improved.
twoNorm = sqrt(sum(abs(M).^2,1)); # The two-norm of each column
abs(M).^2 is going to be calculating a whole bunch of unnecessary square roots which just get squared straightaway.
Far better to do:
twoNorm = sqrt(
sum( real(M .* conj(M)), 1 )
)
This efficiently handles real and complex M.
Using real() ensures that sum and sqrt act over real numbers (rather than complex numbers with 0 imaginary component).
Slight addition to P i's answer:
norm_2 = #(A,dim)sqrt( sum( real(A).*conj(A) , dim) )
allows for
B=magic([2,3])
norm_2( B , 1)
norm_2( B , 2)
or as this if you want a norm_2.m file:
function norm_2__ = norm_2 (A_,dim_)
norm_2__ = sqrt( sum( real(A_).*conj(A_) , dim_) ) ;
end