如何在SymPy中用向量替换矩阵的对角元素?

3

我有一个向量X,是这样创建的:

from sympy import *

x1 = Symbol('x1')
x2 = Symbol('x2')
x3 = Symbol('x3')

X = Matrix([x1, x2, x3])

我还有一个矩阵myMat,其中只包含数字1:

myMat = ones(3, 3)

Matrix([
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])

现在我想用我的向量X替换矩阵的对角线;我想要的结果看起来像这样:

Matrix([
[x1, 1, 1],
[1, x2, 1],
[1, 1, x3]])

当然,我可以使用for循环来完成:

for ind, el in enumerate(X):
    myMat[ind, ind] = el

但我想知道是否有更聪明的方法来直接访问这个矩阵的对角线。虽然我可以计算矩阵的迹,但我找不到一种用类似于myMat.diag = X的方式替换对角线元素的方法。有没有办法做到这一点?
编辑
@Emilien给了我正确的方向,因此我接受了这个答案。在此答案的基础上,我还发布了自己的解决方案,它利用了sympynumpy,并在一行中解决了问题:我的答案
4个回答

3
我建议将 sympy.matrices.dense.MutableDenseMatrix 转换为 numpy.ndarray,在所有操作完成后再重新转换回来。类似这样:
import numpy as np 
from sympy import *

x1 = Symbol('x1')
x2 = Symbol('x2')
x3 = Symbol('x3')

X = Matrix([x1,x2,x3])
myMat = ones(3,3)


myMat1 = np.array(myMat)
myMat1[range(3),range(3)] = np.array(X).reshape(myMat1.shape[0])

myMat = Matrix(myMat1)

>> Matrix([
[x1,  1,  1],
[ 1, x2,  1],
[ 1,  1, x3]])

3
您可以使用对角矩阵和单位矩阵来构建它,但我不确定在性能方面是否更好,但如果您正在查看代码并且希望更容易理解,则可能更容易理解。
x1, x2, x3 = symbols('x1 x2 x3')
mat = diag(x1,x2,x3)-eye(3)+ones(3)

或者

l = symbols('x1 x2 x3')
mat = diag(*l)-eye(3)+ones(3)

好的,我会尽力为您进行翻译。

另一种巧妙的解决方案,可能不太易读:

l = symbols('x1 x2 x3')
Matrix(3, 3, lambda i,j: l[i] if i==j else 1)

最后,如果您不希望修改原始内容

l = symbols('x1 x2 x3')
M = Matrix(([1,2,3],[4,5,6],[7,8,9]))
M = Matrix(3, 3, lambda i,j: l[i] if i==j else M[i,j])

看起来不错,谢谢(我也点赞了)。有没有办法直接将向量X传递给diag函数?我处理的向量要大得多,因此像这样键入它会很痛苦。问题还在于如何替换矩阵中的对角线元素,如果矩阵中还有其他值。有什么好的想法吗? - Cleb
如果对角线上不只有1,您可以使用反转的eye矩阵(对角线上为0,其他位置为1)进行逐项乘法运算。 - Mathiou
是的,这被称为元组解包。此外,如果您想保留原始值(不仅仅是特定值),我找到了一个解决方案。我无法弄清楚如何在lambda函数中“传递”i!=j的情况,因此与for循环相比可能不是非常高效。 - Emilien

1
在 @Emilien 的答案的基础上,我们可以这样做:
import sympy as sp
import numpy as np

x1 = sp.Symbol('x1')
x2 = sp.Symbol('x2')
x3 = sp.Symbol('x3')
X = sp.Matrix([x1, x2, x3])

myM = 4 * sp.ones(3, 3)

所以,我的M看起来像这样:

myM

Matrix([
[4, 4, 4],
[4, 4, 4],
[4, 4, 4]])

现在的命令是:
sp.diag(*X) + myM - sp.diag(*np.diag(myM))

得到期望的结果:

Matrix([
[x1,  4,  4],
[ 4, x2,  4],
[ 4,  4, x3]])

那会使用 sympynumpy 中不同的diag功能,分别创建矩阵;在sympy中,diag使用向量作为输入创建矩阵,将该向量的元素作为矩阵的对角线。
sp.diag(*X)

Matrix([
[x1,  0,  0],
[ 0, x2,  0],
[ 0,  0, x3]])

在numpy中,diag返回矩阵的对角线:
np.diag(myM)
array([4, 4, 4], dtype=object)

1
啊,非常好。我认为那应该是被接受的答案了 ;) - Emilien
@Emilien:嗯,如果有更好的答案,我不喜欢接受自己的答案;你的努力应该得到回报 : )。但是我在我的问题中放了一个编辑,然后人们可以决定他们想要走哪条路(例如,如果他们没有numpy可用,你创建这个矩阵的方式会更好)。 - Cleb

-4
如果您使用某个库函数来查找对角线,我可以百分之百确定该库函数将使用“for”循环。只需运行一个嵌套的for循环,其中i变化范围为1到Row.Count,j变化范围为1到Columns.count。对角线是i=j的位置。在那里做任何您想做的事情。下面是示例,您可以理解一下。
for (i=1; i<= Rows.Count; i++)
     for (j=1; j<= Columns.Count; j++)
          if (i==j)
          {
            // Do your Thing
          }
     end
 end

谢谢您的建议,但那不像是Python,并且并没有真正回答我的问题,因为我已经有一个使用for循环的版本了。顺便说一句:我没有投反对票... - Cleb
即使您已经给出了负面评价,我只是在说如果您使用任何内置函数,它将使用“for”循环来执行。因此,最好的方法是使用for循环。这是我的观点,也许是错误的。希望您能得到更有用的答案。 - Abhishek Kumar

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