Creating a Matrix from Distances between Vectors
Show older comments
I start with a 3 x 46 array where each 3 x1 column in the array is viewed as a position vector of a point, let's say the first vector in the array is p_1, the next one is p_2.
I also have a 3 x 100 array, which I am viewing as the position vectors of 100 points (where these points are always of a lower 'radius' than the points in the 3 x 46 array). I basically need to create a matrix which looks as follows, where each distance is the row vector obtained by vector subtraction of the two vectors:
[Distance from p_1 to first vector in the 3 x 100 array Distance from p_1 to second vector etc ]
[Distance from p_2 to first vector in the 3 x 100 array Distance from p_2 to second vector etc ]
[ Distance from p_3 ..... ]
and so on, until all the positions in the 3 x 46 array are covered, let me know if my intention is not clear.
Accepted Answer
More Answers (1)
So from your description you actually want to find and store the vectors that go from each point in the first matix to each point in the second matrix. Here is a way you could do that
m = 46
n = 100
A = rand(3,m)
B = rand(3,n)
% preallocate 3d matrix to hold results
C = zeros(m,3,n);
% loop through columns of A calculating "distance" vectors and storing
% them
for k = 1:m
C(k,:,:) = B - A(:,k);
end
% to look, for example, at "distance vectors" from the 3rd column of A to all of the
% columns of B you can use
disp(squeeze(C(3,:,:)))
Note, the squeeze function gets rid of extraneous single dimension in multidimensional arrays, which would otherwise make it difficult to see the result
If instead you just want the scalar Euclidean distance from each point in A to each point in B, you could do the following
D = zeros(m,n);
for k = 1:m
D(k,:) = vecnorm(B - A(:,k));
end
If you wanted both you could put both calculations in the same loop.
It may be possible to vectorize this further and eliminate the loop, but it is not immediately obvious to me how to do this. Maybe someone else has a suggestion.
8 Comments
Tom
on 8 Aug 2019
I think this should be at least close to what you want. You should proof read the actual formulae to make sure.
% with 3d result for each pairing
% preallocate 4d array to hold results
J = zeros(m,n,3,3);
for i = 1:m
r = B - A(:,k);
rnorm = vecnorm(r);
for j = 1:n
J(i,j,:,:) =1/(8*pi*0.7*sqrt(2/pi))*(eye(3)/rnorm(j)+(r(:,j)'*r(:,j))/rnorm(j)^3);
end
end
So now to see the 3d result from the pairing between the ith column of A and jth column of B you would look at J(i,j,:,:)
We will see if Guillaume can get rid of one or both of these loops using his approach, would be a good challenge. Unless you are doing huge matrices or performance is otherwise crucial I think the looping will be OK. Still nice if it could be vectorized.
Tom
on 8 Aug 2019
Sorry there's a typo there. I cut and pasted from my earlier example, but now the index for the elements of A is i not k so instead you should have
m = 4
n = 5
A = rand(3,m)
B = rand(3,n)
% with 3d result for each pairing
% preallocate 4d array to hold results
J = zeros(m,n,3,3);
for i = 1:m
r = B - A(:,i);
rnorm = vecnorm(r);
for j = 1:n
J(i,j,:,:) =1/(8*pi*0.7*sqrt(2/pi))*(eye(3)/rnorm(j)+(r(:,j)'*r(:,j))/rnorm(j)^3);
end
end
Note you will have to adjust m and n for your case. I just wanted a small example here so you could see the results
Jon
on 8 Aug 2019
I don't know what your application is so I can't give you any advice on whether you want to define the "distance" vectors as P-S or S-P. I don't think it changes the main logic that I outlined. If I'm understanding correctly it just changes some algebraic signs.
You could probably work out how to permute the 4d array that I have obtained above to get the 3n x 3m array that you want. Otherwise, here is how you can store it this way in the first place. You should check the details, to make sure it is right, but this should give you enough of an idea to go on.
m = 4
n = 5
A = rand(3,m)
B = rand(3,n)
% with 3d result for each pairing
% preallocate 2d array to hold results
J = zeros(n*3,m*3);
for i = 1:m
r = B - A(:,i);
rnorm = vecnorm(r);
for j = 1:n
startRow = (j-1)*3 + 1; % starting row where this 3x3 result is stored
startCol = (i-1)*3 + 1; % starting column where this 3x3 result is stored
J(startRow:startRow+2,startCol:startCol+2) = ...
1/(8*pi*0.7*sqrt(2/pi))*(eye(3)/rnorm(j)+(r(:,j)'*r(:,j))/rnorm(j)^3);
end
end
Tom
on 9 Aug 2019
Guillaume
on 9 Aug 2019
Working in N-D is no more harder than working in 2-D. And in your case it would make it much easier to find the matrix related to a pair of point. You can either have the indices of the points as the first 2 indices, so:
distmat = squeeze(J(p1, p2, :, :)); %3x3 distance matrix between A(:, p1) and B(:, p2)
or as the last 2 indices:
distmat = J(:, :, p1, p2); %3x3 distance matrix between A(:, p1) and B(:, p2)
Storing the same in a 2D array, it's a lot less clear:
distmat = J((p1-1)*3 + (1:3), (p2-1)*3 + (1:3));
Another option, as I suggested is to store the matrices in a 2D cell array, in which case:
distmat = J{p1, p2};
The disadvantage of cell arrays is the memory and speed overhead. For an easy way to do this, see comment to my answer.
Categories
Find more on Matrix Indexing in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!