问题描述
我正在尝试替换 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
另一种方法是使用 spdiags
。 spdiags
的一种用途是获取一个矩阵的列并使用它们构建输出矩阵的对角线。您传递要设置的对角线索引、每个对角线的值矩阵以及矩阵大小。
如果我们只为每个对角线传递一个值,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));