数组
数组是编程语言中用于复杂计算的基本数据结构,而从数学和物理上的应用来看,不同维度的数组,对应着不同类别的代数空间,即一维数组对应向量;二维对应矩阵,高维对应张量。在sympy中,与高维数组相关的大部分函数,都封装在tensor中,但支持从从sympy中直接导入
import sympy
from sympy import print_latex
from sympy import Array
a1 = Array([[1, 2], [3, 4], [5, 6]])
a1.shape # (3,2)
a1.rank() # 2阶张量
print_latex(a1)
a 1 = [ 1 2 3 4 5 6 ] a_1 = \left[\begin{matrix}1 & 2\\3 & 4\\5 & 6\end{matrix}\right] a1= 135246
Array类型的元素也可以是符号,示例如下
from sympy.abc import *
a2 = Array([[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]])
a2.shape # (2,2,2)
a2.rank() # 3阶张量
print_latex(a2)
a 2 = [ [ x y z x z ] [ 1 x y 1 x x y ] ] a_2=\left[\begin{matrix}\left[\begin{matrix}x & y\\z & x z\end{matrix}\right] & \left[\begin{matrix}1 & x y\\\frac{1}{x} & \frac{x}{y}\end{matrix}\right]\end{matrix}\right] a2=[[xzyxz][1x1xyyx]]
张量乘法
相同维度的数组,可以直接进行元素之间的加减乘除,其中加减法无需多言,但乘法却相对复杂。除了元素之间可以进行乘法计算,将数组看成向量和矩阵,也可以进行矩阵乘法的计算,示例如下
[ c d ] [ a b ] = [ c a c b d a d b ] [ a b ] [ c d ] = a c + b d \begin{bmatrix}c\\d\end{bmatrix}\begin{bmatrix}a&b\end{bmatrix} =\begin{bmatrix}ca&cb\\ da&db\end{bmatrix}\quad \begin{bmatrix}a&b\end{bmatrix} \begin{bmatrix}c\\d\end{bmatrix}=ac+bd [cd][ab]=[cadacbdb][ab][cd]=ac+bd
若将向量看作张量,那么前者是张量乘法,后者则是在乘法之后进行了缩并操作。在sympy中,tensorproduct即为张量乘法,tensorcontraction则为缩并
from sympy import tensorproduct, tensorcontraction
A = Array([a,b])
B = Array([c,d])
p = tensorproduct(A, B)
print(sympy.latex(p))
t = tensorcontraction(p, (0,1))
print_latex(t) # ac + bd
其中,tensorcontraction的第二个参数 ( 0 , 1 ) (0,1) (0,1)表示被缩并的轴。
求导
sympy中实现了derive_by_array函数,这个函数可以作用在普通的标量函数表达式上,示例如下
from sympy import derive_by_array
from sympy import sin, exp
ex1 = derive_by_array(sin(x*y), x)
print_latex(ex1)
ex2 = derive_by_array(sin(x*y), [x, y, z])
print_latex(ex2)
ex1和ex2的输出分别是
∂ sin ( x y ) ∂ x = y cos ( x y ) ∇ sin ( x y ) = [ y cos ( x y ) x cos ( x y ) 0 ] \frac{\partial\sin (xy)}{\partial x} = y \cos{\left(x y \right)}\\ \nabla\sin(xy)=\left[\begin{matrix}y \cos{\left(x y \right)} & x \cos{\left(x y \right)} & 0\end{matrix}\right] ∂x∂sin(xy)=ycos(xy)∇sin(xy)=[ycos(xy)xcos(xy)0]
下面定义一阶张量 A m = [ e x , sin ( y z ) , t ] A^m=[e^x, \sin(yz), t] Am=[ex,sin(yz),t],以及 x n = [ x , y , z ] x^n=[x,y,z] xn=[x,y,z],则 B n m = ∂ A m ∂ x n B^{nm}=\frac{\partial A^m}{\partial x^n} Bnm=∂xn∂Am,可以计算如下
xn = [x, y, z]
Am = [exp(x), sin(y*z), 0]
Bnm = derive_by_array(Am, xn)
print_latex(Bnm)
结果如下
[ e x 0 0 0 z cos ( y z ) 0 0 y cos ( y z ) 0 ] \left[\begin{matrix}e^{x} & 0 & 0\\0 & z \cos{\left(y z \right)} & 0\\0 & y \cos{\left(y z \right)} & 0\end{matrix}\right] ex000zcos(yz)ycos(yz)000
如果对运算结果进行缩并,那么就可以得到 A m A^m Am场的散度
div = tensorcontraction(Bnm, (0,1))
print_latex(div)
z cos ( y z ) + e x z \cos{\left(y z \right)} + e^{x} zcos(yz)+ex
即
∇ ( e x , sin ( y z ) , t ) = ∂ e x ∂ x + ∂ sin ( y z ) ∂ y + 0 ∂ z = z cos ( y z ) + e x \nabla (e^x, \sin(yz), t)=\frac{\partial e^x}{\partial x}+\frac{\partial \sin(yz)}{\partial y}+\frac{0}{\partial z}=z \cos{\left(y z \right)} + e^{x} ∇(ex,sin(yz),t)=∂x∂ex+∂y∂sin(yz)+∂z0=zcos(yz)+ex
矢量、矩阵和张量
如果只是从数据结构出发,那么数组和张量是等价的,而矢量、矩阵则为其特例。但在具体的物理应用中,矢量、向量、张量则可能存在数据结构之外的含义。所以sympy中额外给出了这三种数据结构。
首先,矢量从编程角度来说是一维数组,但在物理中,则可用于描述指代有方向的物理量。以三维矢量为例,往往用 i ^ , j ^ , k ^ \hat i,\hat j,\hat k i^,j^,k^或者 e ^ x , e ^ y , e ^ z \hat e_x, \hat e_y, \hat e_z e^x,e^y,e^z来代表 x , y , z x,y,z x,y,z这三个轴向的单位矢量。正因如此,sympy中提供了专门的三维矢量坐标coordSys3D
from sympy.vector import CoordSys3D
N = CoordSys3D('N')
v = (x*y + x*z)*N.i + (y**2 + y*z)*N.j
print_latex(v)
( x y + x z ) i ^ N + ( y 2 + y z ) j ^ N \left(x y + x z\right)\mathbf{\hat{i}_{N}} + \left(y^{2} + y z\right)\mathbf{\hat{j}_{N}} (xy+xz)i^N+(y2+yz)j^N
其次,矩阵除了作为一种数据组织形式外,也有丰富的物理内涵,可以表示刚体旋转等,并且在图像处理领域有着广泛应用。sympy也为其单独提供了Matrix类型
from sympy.matrices import Matrix
M = Matrix([[1,0,0], [0,0,0]])
print_latex(M)
print_latex(Matrix([M, (0, 0, -1)]))
print_latex(Matrix([[1, 2, 3]]))
print_latex(Matrix([1, 2, 3]))
m = Matrix(3,4, lambda i,j : i**2+j**2)
print_latex(m)
其中 m m m是通过lambda表达式创建的矩阵,其每个元素都遵照给定函数的规则而创建,效果如下
[ 1 0 0 0 0 0 ] [ 1 0 0 0 0 0 0 0 − 1 ] [ 1 2 3 ] [ 1 2 3 ] [ 0 1 4 9 1 2 5 10 4 5 8 13 ] \left[\begin{matrix}1 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\quad \left[\begin{matrix}1 & 0 & 0\\0 & 0 & 0\\0 & 0 & -1\end{matrix}\right]\quad\left[\begin{matrix}1 & 2 & 3\end{matrix}\right]\quad \left[\begin{matrix}1\\2\\3\end{matrix}\right]\quad \left[\begin{matrix}0 & 1 & 4 & 9\\1 & 2 & 5 & 10\\4 & 5 & 8 & 13\end{matrix}\right] [100000] 10000000−1 [123] 123 01412545891013
Array类型提供了tomatrix方法,可以将二维数组输出为Matrix类型,但高阶数组将会报错
a1.tomatrix() # 返回Matrix数据
a2.tomatrix() # 报错
最后,张量在广义相对论中也有着频繁的使用,和高维数组相比,除了在形式上多了类似 μ ν \mu\nu μν之类的上下指标外,还有协变、逆变的区别,并且基于此提供了协变导数、逆变导数等运算,sympy中为此提供了TensorIndexType类型,其初始化参数有
- name : 张量类型的名字
- dummy_name : 张量指标的名字
- dim : 维度,可以是符号、整数或者None
- eps_dim : epsilon张量的维度
- metric_symmetry : 对称性
- metric_name : 矩阵名字
实例如下
from sympy.tensor.tensor import TensorIndexType
Lorentz = TensorIndexType('Lorentz', dummy_name='L')
Lorentz.metric