1

Consider three row vectors in Matlab, A, B, C, each with size 1xJ. I want to construct a matrix D of size Kx3 listing every triplets (a,b,c) such that:

  • a is the position in A of A(a).

  • b is the position in B of B(b).

  • A(a)-B(b) is an element of C.

  • c is the position in C of A(a)-B(b).

  • A(a) and B(b) are different from Inf, -Inf.

For example,

A=[-3 3 0 Inf -Inf];
B=[-2 2 0 Inf -Inf];
C=[Inf -Inf -1 1 0];
D=[1 1 3;   %-3-(-2)=-1
   2 2 4;   % 3-2=1
   3 3 5];  % 0-0=0

I would like this code to be efficient, because in my real example I have to repeat it many times.

This question relates to my previous question here, but now I'm looking for the positions of the elements.

TEX
  • 2,249
  • 20
  • 43
  • This could become very computationally expensive if `A` and `B` become large, are there any constraints on what the values could be or how big these are? Otherwise there could quickly become lots of possible pairings of elements of `A` and `B` to test – Wolfie Oct 07 '21 at 13:11

1 Answers1

1

You can use combvec (or any number of alternatives) to get all pairings of indices a and b for the corresponding arrays A and B. Then it's simply a case of following your criteria

  1. Find the differences
  2. Check which differences are in C
  3. Remove elements you don't care about

Like so:

% Generate all index pairings
D = combvec( 1:numel(A), 1:numel(B) ).';
% Calculate deltas
delta = A(D(:,1)) - B(D(:,2));
delta = delta(:); % make it a column
% Get delta index in C (0 if not present)
[~,D(:,3)] = ismember(delta,C);
% If A or B are inf then the delta is Inf or NaN, remove these
idxRemove = isinf(delta) | isnan(delta) | D(:,3) == 0;
D(idxRemove,:) = [];

For your example, this yields the expected results from the question.

You said that A and B are at most 7 elements long, so you have up to 49 pairings to check. This isn't too bad, but readers should be careful that the pairings can grow quickly for larger inputs.

Wolfie
  • 27,562
  • 7
  • 28
  • 55
  • Thanks. I think this would work as well (taking inspiration from my previous question) `[a, b] = ndgrid(A(~isinf(A)), B(~isinf(B)));` `[indAB, indC] = ismember(a-b, C);` `[posA, posB]=find(indAB);` `posC=nonzeros(indC);` `D = [posA posB posC];` – TEX Oct 07 '21 at 14:11
  • 1
    This looks like pretty much the same logic, but you're filtering out the `inf` values up front, doing the `delta` in-line, and using `find` to get the non-zero indices output from `ismember`. So yes without running it myself that looks fine – Wolfie Oct 07 '21 at 14:28