4

Say I have an n by d matrix A and I want to permute the entries of some columns. To do this, I compute permutations of 1 ... n as

idx1 = randperm(n)'
idx2 = randperm(n)'

Then I could do:

A(:,1) = A(idx1,1)
A(:,2) = A(idx2,2)

However, I dont want to do this using a for-loop, as it'll be slow. Say I have an n by d matrix A and an n by d index matrix IDX that specifies the permutations, is there a quicker equivalent of the following for-loop:

for i = 1:d
    A(:,i) = A(IDX(:,i),i);
end
Divakar
  • 218,885
  • 19
  • 262
  • 358
Eric12345
  • 257
  • 1
  • 9

2 Answers2

5

Using linear-indexing with the help of bsxfun -

[n,m] = size(A);
newA = A(bsxfun(@plus,IDX,[0:m-1]*n))
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • Thank you, very nice. I guess I underestimated the loop, as it takes about the same processing time. But your solution is more elegant and once again `bsxfun` turns out to be the solution. I should check that one more often! – Eric12345 Jan 26 '16 at 15:23
  • @EricSchols Yes, it's the memory access that's killing us. Vectorized access aren't known to be any faster than loopy memory accesses when it comes to MATLAB, unless if we are performing some operation, in which case a vectorized op could be coupled with it for perf improvement. Here's a sort of detailed study I was able to do on `bsxfun` : [`Comparing BSXFUN and REPMAT`](http://stackoverflow.com/questions/29719674/comparing-bsxfun-and-repmat). It gives a good look at which mathematical operations could benefit on performance. – Divakar Jan 26 '16 at 15:28
0

I guess another rather stupid way to do it is with cellfun, stupid because you have to convert it into a cell and then convert it back, but it is there anyways.

N=ones(d,1)*n; %//create a vector of d length with each element = n
M=num2cell(N); %//convert it into a cell
P=cellfun(@randperm, M,'uni',0); %//cellfun applys randperm to each cell
res = cell2mat(P); %//Convert result back into a matrix (since results are numeric).

This also allows randperm of type Char and String, but the cell2mat will not work for those cases, results are in Cell Array format instead.

for d = 5, n = 3:
>> res =

 1     3     2
 1     2     3
 2     3     1
 3     1     2
 3     2     1
GameOfThrows
  • 4,510
  • 2
  • 27
  • 44