在前几篇文章中,我们学习了SymPy
基础/高级用法、方程求解、微积分以及向量运算等内容,本节我们学习SymPy
核心内容之一Matrix
矩阵计算(基础)。
传送链接:
「SymPy」符号运算(1) 简介/符号/变量/函数/表达式/等式/不等式/运算符
「SymPy」符号运算(2) 各种形式输出、表达式的化简合并与展开
「SymPy」符号运算(3) (非)线性方程(组)求解、数列求和、连乘、求极限
「SymPy」符号运算(4) 微积分与有限差分
「SymPy」符号运算(5) Vector向量及运算
sympy.matrices
官方文档1:https://docs.sympy.org/latest/tutorials/intro-tutorial/matrices.html?highlight=matrix
SymPy
的矩阵模块具有丰富的矩阵初始化方法,类比于NumPy
中np.ndarray
数组等数据结构的创建方式,Matrix
的初始化方法大同小异。
创建一个矩阵M
,即创建一个Matrxi
实例:
import sympy
from sympy.matrices import Matrix
M = Matrix([[1,0,0], [0,0,0]]);
M
输出:
[ 1 0 0 0 0 0 ] \left[\begin{matrix}1 & 0 & 0\\0 & 0 & 0\end{matrix}\right] [100000]
如果用sympy.pprint()
函数输出,则输出为
[1 0 0]
[ ]
[0 0 0]
Matrices
模块处理的是二维数据,一维带符号的数据可以用Matrix
或上一篇讲过的vector
,高维数据可以用tensor
中的array
,之后会单开一篇讲到。当然三者也是可以相互转换的。
Matrices
创建矩阵时,如果是像上述那样利用两层嵌套列表初始化,则里层括号内的数据为一行。
在刚才创建的矩阵M
的基础上添加一行:
Matrix([M, (0,0,-1)])
# 或者 Matrix([M, [0,0,-1])
输出:
[ 1 0 0 0 0 0 0 0 − 1 ] \left[\begin{matrix}1 & 0 & 0\\0 & 0 & 0\\0 & 0 & -1\end{matrix}\right] 10000000−1
Matrices
也可以创建一维数据集,用两层嵌套列表(两个方括号)创建一行数据得到行向量:
Matrix([[1, 2, 3]])
输出:
[ 1 2 3 ] \left[\begin{matrix}1 & 2 & 3\end{matrix}\right] [123]
而如果只用一个方括号(没有嵌套的列表)产生一维Matrices
,则得到列向量:
Matrix([1, 2, 3])
输出:
[ 1 2 3 ] \left[\begin{matrix}1\\2\\3\end{matrix}\right] 123
给定矩阵维度为 2 × 3 2\times 3 2×3,元素为 1 , 2 , … 6 1, 2, \dots6 1,2,…6,则Matrix
可以自动按照给定的矩阵大小将给定的数据按行优先填充进去:
Matrix(2, 3, [1, 2, 3, 4, 5, 6])
# Matrix(2, 3, [1, 2, 3, 4, 5]) # 报错ValueError,给定的数据总数需要与矩阵大小相容
[ 1 2 3 4 5 6 ] \left[\begin{matrix}1 & 2 & 3\\4 & 5 & 6\end{matrix}\right] [142536]
假设我们想要创建的矩阵为 M a × b M_{a\times b} Ma×b,脚标 a a a和 b b b对应的元素 m a b m_{ab} mab满足二元函数 f ( a , b ) f(a, b) f(a,b) ,则可以将函数名传递给Matirx
函数自动创建矩阵:
def f(a, b):
if a == b:
return 1
elif a > b:
return 2 * a
else:
return 0
# 创建4x4矩阵,元素满足函数f(a, b),其中a,b是整数脚标
Matrix(4, 4, f)
输出:
[ 1 0 0 0 2 1 0 0 4 4 1 0 6 6 6 1 ] \left[\begin{matrix}1 & 0 & 0 & 0\\2 & 1 & 0 & 0\\4 & 4 & 1 & 0\\6 & 6 & 6 & 1\end{matrix}\right] 1246014600160001
lambda
函数用lambda
构造一个二元函数,和前面讲的双变量函数逻辑一样:
# 创建3x4矩阵,元素为 1 - (i+j) % 2,其中i,j是整数脚标
Matrix(3, 4, lambda i,j: 1 - (i+j) % 2)
导入:
from sympy.matrices import Matrix, eye, zeros, ones, diag, GramSchmidt
eye(n)
,单位方阵 n × n n\times n n×nzeros(n)
,零方阵 n × n n\times n n×n;zeros(n, m)
,零矩阵 n × m n\times m n×mones(3)
,一方阵 n × n n\times n n×n;ones(n, m)
,一矩阵 n × m n\times m n×mdiag(a, b, c, ...)
,对角元素为 a , b , c , … a, b, c,\dots a,b,c,…举例:
from sympy.matrices import Matrix, eye, zeros, ones, diag, GramSchmidt
import sympy
eye(5)
输出:
[ 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 ] \left[\begin{matrix}1 & 0 & 0 & 0 & 0\\0 & 1 & 0 & 0 & 0\\0 & 0 & 1 & 0 & 0\\0 & 0 & 0 & 1 & 0\\0 & 0 & 0 & 0 & 1\end{matrix}\right] 1000001000001000001000001
zeros(3, 4)
[ 0 0 0 0 0 0 0 0 0 0 0 0 ] \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 0 & 0 & 0\\0 & 0 & 0 & 0\end{matrix}\right] 000000000000
x, y = sympy.symbols('x y', real = True)
diag(10, Matrix([[x, 4], [6, y]]), eye(2))
[ 10 0 0 0 0 0 x 4 0 0 0 6 y 0 0 0 0 0 1 0 0 0 0 0 1 ] \left[\begin{matrix}10 & 0 & 0 & 0 & 0\\0 & x & 4 & 0 & 0\\0 & 6 & y & 0 & 0\\0 & 0 & 0 & 1 & 0\\0 & 0 & 0 & 0 & 1\end{matrix}\right] 1000000x60004y000001000001
假设有一个 2 × 3 2\times3 2×3的数组, 元素从 1 1 1到 6 6 6,由一维数据填充得到:
from sympy.matrices import Matrix
import sympy
M = Matrix(2, 3, [1, 2, 3, 4, 5, 6])
可以通过一维索引,索引到第3个元素4
M[3]
# 输出: 4
也可以通过二维索引,索引到第2行第2列的元素:
M[1, 1]
# 输出: 5
也可以切片,返回一个矩阵类型的副本,原矩阵不受影响
M[0:2, 0:2]
输出:
[ 1 2 4 5 ] \left[\begin{matrix}1 & 2\\4 & 5\end{matrix}\right] [1425]
type(M[0:2, 0:2])
# 输出:sympy.matrices.dense.MutableDenseMatrix
索引不仅可以“查”,也可以“改”,修改矩阵某一个元素为符号 x x x:
x = sympy.symbols('x')
M[0] = x
M
输出:
[ x 2 3 4 5 6 ] \left[\begin{matrix}x & 2 & 3\\4 & 5 & 6\end{matrix}\right] [x42536]
除了在初始化部分讲过的添加行/列数据的方式外,还可以通过col_insert()
或者row_insert()
添加(返回副本)
from sympy.matrices import Matrix
M = Matrix(3, 3, list(range(9)))
M1 = Matrix([100, 101, 102]) # 列向量
M.col_insert(1, M1)
输出:
[ 0 100 1 2 3 101 4 5 6 102 7 8 ] \left[\begin{matrix}0 & 100 & 1 & 2\\3 & 101 & 4 & 5\\6 & 102 & 7 & 8\end{matrix}\right] 036100101102147258
删除行或列(直接在原矩阵上修改,无返回值)
from sympy.matrices import Matrix
import sympy
M = Matrix(([1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]))
删除第0
行
M.row_del(0)
M
输出:
[ 5 6 7 8 9 10 11 12 13 14 15 16 ] \left[\begin{matrix}5 & 6 & 7 & 8\\9 & 10 & 11 & 12\\13 & 14 & 15 & 16\end{matrix}\right] 5913610147111581216
再删除最后一列:
M.col_del(-1)
M
[ 5 6 7 9 10 11 13 14 15 ] \left[\begin{matrix}5 & 6 & 7\\9 & 10 & 11\\13 & 14 & 15\end{matrix}\right] 59136101471115
有两个矩阵
from sympy.matrices import eye, zeros
M1 = eye(3) # 3x3
M2 = zeros(3, 4) # 3x4
他们具有相同的行数,可以按行把它们拼起来
M1.row_join(M2)
[ 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 ] \left[\begin{matrix}1 & 0 & 0 & 0 & 0 & 0 & 0\\0 & 1 & 0 & 0 & 0 & 0 & 0\\0 & 0 & 1 & 0 & 0 & 0 & 0\end{matrix}\right] 100010001000000000000
另外可以用.col_join()
函数按列聚合矩阵,不再赘述。
算数运算符都可以直接使用:+
, -
, *
, /
, **
数与矩阵相乘时是数乘运算,矩阵与矩阵相乘时是矩阵乘法;乘方同理。
栗子:
from sympy.matrices import Matrix
import sympy
M = Matrix(2, 2, [1, 2, 3, 4])
x = sympy.symbols('x')
# 数乘
x*M
输出:
[ x 2 x 3 x 4 x ] \left[\begin{matrix}x & 2 x\\3 x & 4 x\end{matrix}\right] [x3x2x4x]
# 矩阵乘法
M*M # 或M**2
输出:
[ 7 10 15 22 ] \left[\begin{matrix}7 & 10\\15 & 22\end{matrix}\right] [7151022]
如果相对矩阵内的每个元素做三角函数等特殊函数的运算,可以使用.applyfunc(f)
的方法
def f(x):
return sympy.sin(x)
M.applyfunc(f)
输出:
[ sin ( 1 ) sin ( 2 ) sin ( 3 ) sin ( 4 ) ] \left[\begin{matrix}\sin{\left(1 \right)} & \sin{\left(2 \right)}\\\sin{\left(3 \right)} & \sin{\left(4 \right)}\end{matrix}\right] [sin(1)sin(3)sin(2)sin(4)]
先定义两个列向量v1
, v2
from sympy.matrices import Matrix
import sympy
v1 = Matrix([1,2,3])
v2 = Matrix([4,5,6])
v3 = v1.cross(v2)
v3
[ − 3 6 − 3 ] \left[\begin{matrix}-3\\6\\-3\end{matrix}\right] −36−3
v1.dot(v2)
# 输出: 32
v1.dot(v3)
# 输出: 0
关于Matrix
符号运算与线性代数的内容十分丰富,官方文档中也用了大量篇幅进行讲解,后续将继续介绍…
Meurer A, Smith CP, Paprocki M, Čertík O, Kirpichev SB, Rocklin M, Kumar A, Ivanov S, Moore JK, Singh S, Rathnayake T, Vig S, Granger BE, Muller RP, Bonazzi F, Gupta H, Vats S, Johansson F, Pedregosa F, Curry MJ, Terrel AR, Roučka Š, Saboo A, Fernando I, Kulal S, Cimrman R, Scopatz A. (2017) SymPy: symbolic computing in Python. PeerJ Computer Science 3:e103 https://doi.org/10.7717/peerj-cs.103 ↩︎