So here’s the code! Given a list of ground truth identities `ids`

we first generate the unique identities `uids`

, just to know the number of classes. For each class, we count the number of data points that belong to the class `sum(uids(k) == ids)`

and generate a matrix of all ones.

To find negative pairs, we create a block diagonal matrix using the all ones matrices from each class, and then simply logically negate it to get a 1 in the position of out-of-class points and 0 in in-class points. Selecting a lower triangular after this simply removes the duplicate pairs. `tril(~blkdiag(onesmats{:}))`

.

For the positive pairs, we need to have a 1 in the intra-class, and to remove duplicates we again use the upper triangular matrix, negate it thus keeping a lower triangular without the diagonal 😉 `~triu(ones(X))`

. All pairs can be found by directly concatenating the matrices as block diagonals.

uids = unique(ids);

for k = 1:length(uids)

onesmats{k} = ones(sum(uids(k) == ids));

pospairmat{k} = ~triu(onesmats{k});

end

[pospairs(:, 1), pospairs(:, 2)] = find(blkdiag(pospairmat{:}));

[negpairs(:, 1), negpairs(:, 2)] = find(tril(~blkdiag(onesmats{:})));

Finally a simple `[x, y] = find()`

allows to get the row, column indices to find the pairs. Suggestions for shorter, faster and smarter techniques is more than welcome in the comments.

PS: The code assumes that the `ids`

are sorted, i.e. features of the same class occur next to each other. If this is not your case, it’s easy to do it just by running a sort and re-indexing the feature vectors.