如何替换八度矩阵中的第k对角线?

问题描述

我正在尝试替换 Octave 中矩阵的子对角线和超对角线。

这是我使用的代码

A=[-3 -2 -1 0 1 2 3;0.1 0.2 0.2 0.5 0.6 -0.1 0]'
P=zeros(4,4)

for (k=1:7)
  j=A(k,1)
  diag(P,j)=A(k,2)
end

这是我得到的错误:diag(0,_): 下标必须是整数 1 到 (2^63)-1 或逻辑数

但是所有的小部分都没问题。 diag(P,-3) 工作正常,但是当我要求在循环中替换时它拒绝了!

我该怎么办?这是:diag(P,j)=e,不是替代超对角线和次对角线的正确代码吗?

解决方法

您收到错误的原因是 diag(P,j) 不是对 P 对角线的引用,它是一个返回该对角线上值的函数。因此,您正在做的是将值 A(k,2) 分配给函数的返回值,并且由于它从未分配给变量名称,因此该值丢失并且没有任何变化。

要修复您的循环,您需要在 P 中提供索引并分配给这些索引。一种方法是使用逻辑索引来告诉 MATLAB P 中的哪些值要更改。例如,

P = zeros(4)
M = logical(diag([1,1,1],-1))
P(M) = 3

给我们

P =

   0   0   0   0
   0   0   0   0
   0   0   0   0
   0   0   0   0

M =

  0  0  0  0
  1  0  0  0
  0  1  0  0
  0  0  1  0

P =

   0   0   0   0
   3   0   0   0
   0   3   0   0
   0   0   3   0

不幸的是,我们无法同时指定我们要创建的对角线结果矩阵的大小,因此我们必须在创建之前计算对角线上的元素数量.

A=[-3 -2 -1 0 1 2 3;0.1 0.2 0.2 0.5 0.6 -0.1 0].'   

n=4;   % Number of rows/columns in P... 
       % If we want a non-square matrix,we'll have to do more math
P=zeros(n);

for k=1:2*n-1   % Remove hardcoded values to make the code more general.
  j=A(k,1);
  diag_length = n-abs(j);
  M=diag(true(1,diag_length),j);   % Create logical array with true on jth diagonal
  P(M)=A(k,2);
end

结果是:

P =

   0.5000   0.6000  -0.1000        0
   0.2000   0.5000   0.6000  -0.1000
   0.2000   0.2000   0.5000   0.6000
   0.1000   0.2000   0.2000   0.5000

另一种方法是使用 spdiagsspdiags 的一种用途是获取一个矩阵的列并使用它们构建输出矩阵的对角线。您传递要设置的对角线索引、每个对角线的值矩阵以及矩阵大小。

如果我们只为每个对角线传递一个值,spdiags 将只设置一个值,因此我们将不得不复制输入向量 n 次。 (spdiags 会很乐意扔掉值,但不会填充它们。)

A=[-3 -2 -1 0 1 2 3;0.1 0.2 0.2 0.5 0.6 -0.1 0].'
n = 4;

diag_idx = A(:,1).';   % indices of diagonals
diag_val = A(:,2).';   % corresponding values
diag_val = repmat(diag_val,n,1);   % duplicate values n times

P = spdiags(diag_val,diag_idx,n);
P = full(P);

最后一行是因为 spdiags 创建了一个稀疏矩阵。 full 把它变成一个正则矩阵。 P 的最终值是您所期望的:

P =

   0.5000   0.6000  -0.1000        0
   0.2000   0.5000   0.6000  -0.1000
   0.2000   0.2000   0.5000   0.6000
   0.1000   0.2000   0.2000   0.5000

当然,如果您喜欢单行,您可以将所有这些命令组合在一起。

P = full(spdiags(repmat(A(:,2).',1),A(:,1).',n));