anon
anon

Reputation:

Reshaping vector in MATLAB

I am trying to implement BlockLMS with a single for loop in MATLAB. For this purpose, given a vector u, I am trying to create a table of the form

U = [u(k)     u(k+1)     u(k+2)  ...    u(k+n)
     u(k-1)   u(k)       ...     ...    u(k+n-1)
     ...      ...        ...     ...    ...
     u(k-n)   u(k-n+1)   ...     ...    u(k)]

where n is a constant and k is a variable which changes with each for loop, assuming k > n at all times. What I have accomplished so far is this:

index = meshgrid(0:-1:1-n)' + meshgrid(1:n);
for i = 2:q
    % calculate k
    U = u(k + index);
    % rest of code goes here
end

which, although it works, is sadly very slow and does not suit my needs. Is there a more efficient way to achieve this result?

Upvotes: 3

Views: 123

Answers (3)

Stewie Griffin
Stewie Griffin

Reputation: 14939

This should work:

k = 20;     % Example k
n = 5;      % Example n < k

u = 1:50;   % Example vector

[x, y] = meshgrid(0:n,k:-1:k-n);
U = u(x+y)   % Use x+y as index
U =

   20   21   22   23   24   25
   19   20   21   22   23   24
   18   19   20   21   22   23
   17   18   19   20   21   22
   16   17   18   19   20   21
   15   16   17   18   19   20

As you can see, the top left corner is element number k, the top right is element number k+n, the bottom left is k-n and the bottom right is element k.

Upvotes: 4

Divakar
Divakar

Reputation: 221584

That operation has a lot of replications. So, to exploit that very nature, here's one approach using repmat and a little help from bsxfun's masking capability -

mask = bsxfun(@ge,(1:2*n+1)',n+1:-1:1) & bsxfun(@ge,(2*n+1:-1:1)',1:n+1)
sliced_u = u(k+n:-1:k-n)
repvals = repmat(sliced_u(:),1,n+1)
out = reshape(repvals(mask),n+1,[])

The way one could describe this approach would be to see the desired output's columns as one place shifted up as we traverse to the right when a columnar version of the input u is replicated along the columns. The rest of the work is to offset the one place shifting along the columns, which is done with the bsxfun's masking to cutoff the upper and lower triangular regions to give us the final output.

Performance : This idea has been exploited before for a similar problem in this solution and I expect similar performance numbers here.


As another approach and thinking straight-forward, one could just use bsxfun to get the 2D indices and then index into u for the final output, like so -

out = u(bsxfun(@plus,(k:-1:k-n)',0:n))

Upvotes: 4

bla
bla

Reputation: 26069

You can use the one-liner built in toeplitz

 toeplitz(20:-1:15,20:25)

ans =

20    21    22    23    24    25
19    20    21    22    23    24
18    19    20    21    22    23
17    18    19    20    21    22
16    17    18    19    20    21
15    16    17    18    19    20

Or, in a more generic way:

f = @(k,n)toeplitz(k:-1:k-n,k:k+n)

and then you can just write U=u(f(k,n)) to get the generic form in the question. But check if that is indeed faster than your for loop.

EDIT: the inner machinery of toeplitz is bsxfun, so I guess unless you realize it in lower level c\fortran, this is as good as it gets. Check edit toeplitz and see how it is implemented...

Upvotes: 6

Related Questions