Как повторить вектор по диагонали в Matlab

я хотел бы повторить вектора A длиной n по диагонали m раз, чтобы получить (n+m-1) x m матрица B. В качестве примера скажем A = [a;b;c;d], m = 4. Это должно привести к

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]

любые предложения по быстрому способу достижения этого? blkdiag(repmat(A,1,m)) не помогает мне в этом деле, так как создает (n*m) x m матрица.

в конце концов, я на самом деле просто интересуюсь матричным продуктом D третьей матрицы C С B:

D=C*B

если вы видите другой вариант получить D для определения B, Я был бы признателен. Но решение проблемы выше сделало бы меня очень счастливым, а также! n и m будет довольно большой, кстати.

спасибо!

3 ответов


неуклюжий, но общий однострочный

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) )

возвращает:

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

альтернативно улучшенная, общая версия решение rubenvb

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

в обоих случаях A может быть либо строка или вектор-столбец.

более быстрое решение (фактор 2x) является первым с spdiags!


Edit: еще более неуклюжий, но до 10x быстрее (это зависит от n, m), чем toeplitzподход:

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

потому что @mathematician1975 слишком ленив, чтобы написать правильный ответ.

Matlab имеет функцию для этого, называемую toeplitz

вы бы назвали это так:

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

Вы можете играть с нуля, чтобы сформировать матрицу так, как вы хотите.


полное решение, без матрицы B, это сделать свертку каждой строки C С A. вы можете сделать это с помощью цикла for:

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

Я думаю, что это можно сделать и без цикла, путем 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