1
votes

I have a matrix A in Matlab of dimension mxn composed of zeros and ones, and a matrix J of dimension mx1 reporting some integers from {1,...,n}.

I want to construct a matrix B of dimension mxn such that for

(1) B(1,:)=A(1,:)

(2) for i=2,...,m, B(i,:) is obtained by shifting A(i,:) LEFT circular of a number of positions equal to (J(1)-1)+ (J(2)-1)+...+ (J(i-1)-1)

This code does what I want

m=4;
n=5;
A=[1 0 1 1 0; ...
   0 1 0 0 1; ...
   1 1 0 0 0; ...
   0 0 0 0 1;
J=[2;1;5;8];
B=zeros(m,n);
B(1,:)=A(1,:);

foridx=cumsum(J); %mx1
shift=foridx-(1:1:m).'; %mx1
v=shift(1:m-1); %(m-1)x1

for i=2:m
    B(i,:)=(circshift((A(i,:)).', -v(i-1),1)).';
end

I would like to avoid the final loop. I like the answer here by Divakar but it is for a right circular shift.

Arelevant=A(2:end,:);  
idx0 = mod(bsxfun(@plus,n-v(:),1:n)-1,n);
out = Arelevant(bsxfun(@plus,(idx0*(m-1)),(1:(m-1))'));
B(2:end,:)=out;    

Could you help me to have something similar for a left circular shift?

1
If you use bsxfun you don't really avoid the final loop, bsxfun just hide the loop. - obchardon
Ok, I understand, thank you. So, do you think that the performance is exactly the same as my version? - TEX
To measure performance, test the for loop and bsxfun for the right shift case, your code is much clearer as-as anyway... Otherwise, you maybe just need to change the indexing, from 1:n to -1:-1:-n to shift the other direction. - Wolfie

1 Answers

2
votes

Here is a little trick to perform this operation without loop.

I use an fft in order to shift each line.

m=4;
n=5;
A=[1 0 1 1 0; ...
   0 1 0 0 1; ...
   1 1 0 0 0; ...
   0 0 0 0 1;]
J=[2;1;5;8];

foridx=cumsum(J); %mx1
shift=foridx-(1:1:m).'; %mx1
v=[0;shift(1:m-1)]; %(m-1)x1
L=real(round(ifft(fft(A,[],2) .* exp(2i*pi/n*v*(0:m)) ,[],2))) %left shift
R=real(round(ifft(fft(A,[],2) .* exp(-2i*pi/n*v*(0:m)) ,[],2))) %right shift