1

I'm struggling to vectorise a function which performs a somewhat pairwise difference between two vectors x = 2xN and v = 2xM, for some arbitrary N, M. I have this to work when N = 1, although, I would like to vectorise this function to apply to inputs with N arbitrary.

Indeed, what I want this function to do is for each column of x find the normed difference between x(:,column) (a 2x1) and v (a 2xM).

A similar post is this, although I haven't been able to generalise it.

Current implementation

function mat = vecDiff(x,v)

diffVec = bsxfun(@minus, x, v);
mat = diffVec ./ vecnorm(diffVec);

Example

x =
     1
     1

v = 
     1     3     5
     2     4     6

----
vecDiff(x,v) =
         0   -0.5547   -0.6247
   -1.0000   -0.8321   -0.7809

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
spaceman
  • 115
  • 4
  • 1
    Note that loops are not slow anymore in MATLAB, as the JIT compiler often does the job of accelerating them for you. I'd say first try with loops, no need to optimize if its not needed. – Ander Biguri Apr 19 '22 at 12:31
  • 1
    [Also note that `bsxfun()` is largely obsolete.](https://stackoverflow.com/a/70107893/5211833). A simple `x-v` should suffice nowadays, bearing in mind `x` to be a row and `y` a column vector, or vice-versa. – Adriaan Apr 19 '22 at 13:02

2 Answers2

2

Suppose your two input matrices are A (a 2 x N matrix) and B (a 2 x M matrix), where each column represents a different observation (note that this is not the traditional way to represent data).

Note that the output will be of the size N x M x 2. out = zeros(N, M, 2);

We can find the distance between them using the builtin function pdist2.

dists = pdist2(A.', B.'); (with the transpositions required for the orientation of the matrices)

To get the individual x and y distances, the easiest way I can think of is using repmat:

xdists = repmat(A(1,:).', 1, M) - repmat(B(1,:), N, 1);
ydists = repmat(A(2,:).', 1, M) - repmat(B(2,:), N, 1);

And we can then normalise this by the distances found earlier:

out(:,:,1) = xdists./dists; 
out(:,:,2) = ydists./dists;

This returns a matrix out where the elements at position (i, j, :) are the components of the normed distance between A(:,i) and B(:,j).

magnesium
  • 304
  • 1
  • 8
2

Your approach can be adapted as follows to suit your needs:

  1. Permute the dimensions of either x or v so that its number of columns becomes the third dimension. I'm choosing v in the code below.
  2. This lets you exploit implicit expansion (or equivalently bsxfun) to compute a 2×M×N array of differences, where M and N are the numbers of columns of x and v.
  3. Compute the vector-wise (2-)norm along the first dimension and use implicit expansion again to normalize this array:
x = [1 4 2 -1; 1 5 3 -2];
v = [1 3 5; 2 4 6];
diffVec = x - permute(v, [1 3 2]);
diffVec = diffVec./vecnorm(diffVec, 2, 1);

You may need to apply permute differently if you want the dimensions of the output in another order.

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147