Vectorize循环在Matlab中创建三对角矩阵

时间:2013-09-05 22:31:05

标签: matlab for-loop vector matrix vectorization

我有一个for循环创建一个三对角矩阵,如下所示:

m = 5;
Fo = 0.35;

A(1,1) = 1+2*Fo;
A(1,2) = 1+Fo;

for i = 2:m-1
    A(i,i-1) = 1;
    A(i,i) = 2;
    A(i,i+1) = 3;
end

A(m,m-1) = 4;
A(m,m) = 5;

输出为:

A =
    1.7000    1.3500         0         0         0
    1.0000    2.0000    3.0000         0         0
         0    1.0000    2.0000    3.0000         0
         0         0    1.0000    2.0000    3.0000
         0         0         0    4.0000    5.0000

我正在尝试使用以下内容来替换for循环来创建三对角矩阵:

i = 2:m-1;
A(i,i-1) = 1;
A(i,i) = 2;
A(i,i+1) = 3;

不幸的是输出不正确:

A =
    1.7000    1.3500         0         0         0
    1.0000    2.0000    3.0000    3.0000    3.0000
    1.0000    2.0000    3.0000    3.0000    3.0000
    1.0000    2.0000    3.0000    3.0000    3.0000
         0         0         0    4.0000    5.0000

是否可以使用矢量化而不是for-loop创建这样的矩阵?我最终需要创建一个更大更复杂的三对角矩阵,因此希望使用矢量化来加速这个过程。

2 个答案:

答案 0 :(得分:2)

正如路易斯指出的那样,sub2ind能够运作。我想你也可以使用诊断。例如,你可能会这样做:

m = 5;
Fo = 0.35;

d = [1+2*Fo; repmat(2,m - 2,1); 5];
ud = [1+Fo;repmat(3,m-2,1)];
sd = [ones(m-2,1);4];

A = diag(d) + diag(ud,1) + diag(sd,-1)
A =
          1.7         1.35            0            0            0
            1            2            3            0            0
            0            1            2            3            0
            0            0            1            2            3
            0            0            0            4            5

问题是我们在这个组合中做了很多添加,并且大多数添加都是零。不喜欢这种解决方案的另一个原因是它产生了一个完整的矩阵。我不建议一般,但它是一个很好的,直观的直观解决方案。 (顺便说一句,我只是注意到diag的帮助显示了这个解决方案,以创建一个三对角矩阵。)

更好的选择是学习使用稀疏矩阵。三对角矩阵是SPARSE。使用该功能。为此,学习如何使用spdiags,或者至少学习稀疏。

让我们将A构建为稀疏的三对角矩阵。我将使用更大的m值,以便我们可以看到节省的费用。

m = 500;
Fo = 0.35;

d = [1+2*Fo; repmat(2,m - 2,1); 5];
ud = [1+Fo;repmat(3,m-2,1)];
sd = [ones(m-2,1);4];

A = diag(d) + diag(ud,1) + diag(sd,-1);
As = spdiags([[sd;0],d,[0;ud]],[-1 0 1],m,m);

whos A*
  Name        Size               Bytes  Class     Attributes
  A         500x500            2000000  double              
  As        500x500              27976  double    sparse

因此,稀疏形式需要28k存储,而完整版需要2兆字节。

当您开始以稀疏形式使用这些数组时,真正的好处将会出现。例如,使用反斜杠:

y = rand(m,1);

tic,x = A\y;toc
Elapsed time is 0.002847 seconds.

tic,xs = As\y;toc
Elapsed time is 0.000290 seconds.

我想我还应该在MATLAB Central文件交换中找到我自己的代码blktridiag。它真的被设计用于生成块三对角数组,但它也可以解决这个问题,因为我们只有标量块。

Ab = blktridiag(reshape(d,1,1,m),reshape(sd,1,1,m-1),reshape(ud,1,1,m-1));
As - Ab
ans =
   All zero sparse: 500-by-500

最后,正如natan指出的那样,如果你的目标是一个完整的矩阵,那么在给定稀疏矩阵输入的情况下,函数full将会这样做。但是,在许多情况下,稀疏形式将是一个很大的好处。学习使用稀疏矩阵。你会很高兴的。

答案 1 :(得分:1)

您可以使用sub2ind

for循环进行矢量化
m = 5;
Fo = 0.35;

A = zeros(m); % initialize
A(sub2ind([m m],2:m, 1:m-1)) = 1;
A(sub2ind([m m],1:m, 1:m)) = 2;
A(sub2ind([m m],1:m-1, 2:m)) = 3;

A(1,1) = 1+2*Fo;
A(1,2) = 1+Fo;

A(m,m-1) = 4;
A(m,m) = 5;

替换循环的方法的问题是两个索引被认为是定义一个块(两个索引的所有组合),而不是对角线(第一个索引的每个值与第二个中的每个对应值)。