سؤال

I would like to repeat a vector A of length n on a diagonal m times to obtain a (n+m-1) x m matrix B. As an example let's say A = [a;b;c;d], m = 4. This should result in

B = 
[a 0 0 0;
 b a 0 0;
 c b a 0;
 d c b a;
 0 d c b;
 0 0 d c;
 0 0 0 d]

Any suggestions for a fast way to achieve this? blkdiag(repmat(A,1,m)) does not help me in this case as it creates a (n*m) x m matrix.

In the end I am actually just interested in the matrix product D of a third matrix C with B:

D=C*B

If you see another option to obtain D without having to generate B, I would appreciate it. But a solution for the problem above would make me very happy as well! n and m will be quite big by the way.

Thanks!

هل كانت مفيدة؟

المحلول 2

A clumsy, but generic one-liner

n = 3;      %number of elements in A;
m = 5;      %repetitions
A = (1:n);  

B = full( spdiags( repmat(A(:),1,m)' , 1-(1:n) , n+m-1, m) )

returns:

B =

     1     0     0     0     0
     2     1     0     0     0
     3     2     1     0     0
     0     3     2     1     0
     0     0     3     2     1
     0     0     0     3     2
     0     0     0     0     3

Alternatively an improved, generic version of rubenvb's solution

B = toeplitz( [A(:);zeros(m-1,1)] , zeros(1,m) )

in both cases A can be either a row or column vector.

The faster solution (factor 2x) is the first one with spdiags!


Edit: even clumsier, but up to 10x faster (it depends on n,m) than the toeplitz-approach:

B = reshape( [repmat([A(:);zeros(m,1)],m-1,1) ; A3(:)] ,[],m ) 

نصائح أخرى

Because @mathematician1975 is too lazy to write a proper answer.

Matlab has a function for this, called toeplitz

You would call it like this:

c=[1;2;3;4;0;0;0];
r=[0, 0, 0, 0];
toeplitz(c,r)

ans =

   1   0   0   0
   2   1   0   0
   3   2   1   0
   4   3   2   1
   0   4   3   2
   0   0   4   3
   0   0   0   4

You can play with the zeroes to shape the matrix the way you want it.

Total solution, without matrix B, is to do convolution of each row of C with A. you can do it by for loop:

for k=1:size(C,1)
   D(k,:)=conv(C(k,:),A');
end
D=D(:,length(A)-1:end-length(A)+1);    % elliminate the convolution edges

I think it can be done also without the loop, by arrayfun:

k=1:size(C,1);
D=arrayfun(@(x) conv(C(x,:),A'), k);
D=D(:,length(A)-1:end-length(A)+1);    % elliminate the convolution edges
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top