1

I have a vectorb with 30 entries.

I want to avoid using a for loop to construct a matrix like this:

enter image description here

where b_i is the i-th entry of the vector b.

For example, define the vector

b = [2 6 -7 3 1 -4 -1  1 11  8 -4  9  2  0  2 -1  0  4  4  4  2 -4  2  5  1 3  2 -1  1 -2]

where I tried by using for loop is:

A = zeros(5,5);
for i = 1:5
    A(i) = b(i+5);
    A(i+5) = b(i+6);
    A(i+10) = b(i+7);
    A(i+15) = b(i+8);
    A(i+20) = b(i+9);
end

The result is

enter image description here

Is there a faster and more general method to generate this matrix?

Wolfie
  • 27,562
  • 7
  • 28
  • 55
nam
  • 215
  • 2
  • 11
  • 1
    Though this does not remove your loop, you can replace its contents with `A(i:5:i+20) = b(i+5:i+9);`. This more easily generalizes to other sizes. – buzjwa Sep 12 '17 at 11:29

3 Answers3

6

You can use toeplitz:

A=fliplr(toeplitz(b(10:14),b(10:-1:6))

A =

-4    -1     1    11     8
-1     1    11     8    -4
 1    11     8    -4     9
11     8    -4     9     2
 8    -4     9     2     0

By the way, the indices here are 6 to 14 as in your example, and not 7 to 15 as in the picture. You can change it to your preferred purpose.

Adiel
  • 3,071
  • 15
  • 21
  • Functions like `teoplitz` always seems like black magic, neat suggestion. Do you have a methodology for visualising how these indices are generated (other than trial and error)? – Wolfie Sep 12 '17 at 11:38
  • 2
    @Wolfie hmm... it is black magic. :) The methodology is very simple- the first vector is the first column, and the second vector is first raw. All the rest are diagonals copies... – Adiel Sep 12 '17 at 11:40
3

Your instinct is to avoid for loops. This is a good intuition to develop as a MATLAB programmer, but it's not always the quickest option. As can be seen in my answer to a very similar question, a for loop may be the quickest way to generate this type of matrix.


Possibly the shortest method to write would use hankel

A = b(hankel(7:11, 11:15));

Output:

>> ans =

    -1     1    11     8    -4
     1    11     8    -4     9
    11     8    -4     9     2
     8    -4     9     2     0
    -4     9     2     0     2

Equivalent result (but quicker processing as seen in the previously linked answer)

A = hankel(b(7:11), b(11:15));

As Adiel said, there is a difference between the indices you showed in the image of the matrix and the indices you used to create your example. This uses the former.

Wolfie
  • 27,562
  • 7
  • 28
  • 55
2

Not as nice as using toeplitz, but a bit clearer to see what's going on:

b = [2 6 -7 3 1 -4 -1  1 11  8 -4  9  2  0  2 -1  0  4  4  4  2 -4  2  5  1 3  2 -1  1 -2];
n = 5; % window size
% StartIdx = 4; % Starting index of your window
AddVec = repelem(1:n,5)+StartIdx; % create addition vector
IdxVec = repmat(1:n,1,n); % Initialise index vector
IdxVec = AddVec+IdxVec; % add to let the window "slide"
c = b(IdxVec); % create a new vector
d = reshape(c,n,[]) % Reshape to get the desired matrix

d =

     6    -7     3     1    -4
    -7     3     1    -4    -1
     3     1    -4    -1     1
     1    -4    -1     1    11
    -4    -1     1    11     8

Note that I didn't use a starting index in my run of the matrix. Adjust that parameter according to your needs.

Adriaan
  • 17,741
  • 7
  • 42
  • 75