Nolan Conaway
Nolan Conaway

Reputation: 2757

MATLAB pairwise differences in Nth dimension

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?

Upvotes: 1

Views: 287

Answers (1)

Divakar
Divakar

Reputation: 221524

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!

Upvotes: 1

Related Questions