如何在Matlab中沿对角线重复向量

6

我想要将长度为n的向量A在对角线上重复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矩阵。

最终,我实际上只对第三个矩阵CB的矩阵乘积D感兴趣:

D=C*B

如果您有其他方法可以获得D而不必生成B,我会很感激。但是解决上述问题的方案也会让我很高兴!顺便说一下,nm会非常大。谢谢!

3
看起来像是一个转置后的托普利茨矩阵。我相信Matlab有一个生成托普利茨矩阵的函数,这可能对你有用。 - mathematician1975
@julian,我的方法对你有用吗?如果m和n的值很高,它可以节省创建矩阵B并在那里乘以所有零的时间...我只是好奇它是否有效... - Adiel
3个回答

7

因为@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

你可以通过调整零来塑造矩阵的形状,以达到你想要的效果。

1
这并不是懒惰,我只是无法回忆起参数是什么 - 我总是觉得写注释比发布错误的答案要好!你还是得到了我的赞 +1。 - mathematician1975

5
一个笨拙但通用的一行代码
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 可以是行向量或列向量。

更快的解决方案(速度提高了2倍)是使用spdiags


编辑:即使笨拙,但比 toeplitz 方法快多达10倍(取决于n,m):

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

很遗憾,spdiags 无法处理向量。 - julian
@julian:看看我最后的编辑,这个解决方案比toeplitz方法快一点。 - Robert Seifert
确实,对于我非常高的m和n值,你最后一行比toeplitz快,虽然只是稍微快了一点。谢谢! - julian

2

不使用矩阵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

就我所见,卷积只有在对称的A(例如[a b b a])上才能给出所需的结果。我的A实际上是对称的,所以这不是问题。你的for循环比rubenvb的解决方案慢得多,但实际上比你的arrayfun版本稍快一些,必须扩展为:colNoise = cell2mat(arrayfun(@(x) conv(C(x,:), A', 'valid')', k, 'UniformOutput', 0))' - julian
valid 保存了您消除边缘的最后一行。由于输出是向量而不是标量,因此 UniformOutput 是必需的。即使我更改了数据格式并因此可以摆脱所有 "'",这仍然会更慢。但还是非常感谢您的建议。 - julian
当然,我在第一条评论中指的是 D 而不是 colNoise... 这是复制粘贴错误... - julian
这是有趣的,它比将B构建为不同矩阵并进行乘法运算要慢。也许是因为conv函数还填充了零,所以没有节省任何东西。我不明白为什么它对于非对称的A不起作用。我知道通常arrayfun比for循环慢,但有时人们喜欢它,也许它看起来更“干净”、清晰或聪明... :) - Adiel
conv 函数将向量一侧的元素与另一个向量对应侧的元素相乘。而我之前提出的算法是将同一侧的元素相乘。对于对称向量,这并不重要。我刚刚发现了 conv2 函数,可以非常简洁地解决我的问题:D=conv2(C, A, 'valid')。有趣的是,即使使用这种方法,它的执行时间也比 thewaywewalk 的方法长... - julian
你说得对,应该写成 D(k,:)=conv(C(k,:),flipud(A)');。或者用 corr,它与 conv 类似,但不会颠倒元素的顺序。conv2 也可以吗?我认为你需要对每一行进行一维卷积,而不是二维卷积... - Adiel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接