基本实现细节¶
坐标系与向量¶
目前,sympy.vector
能够处理笛卡尔(也称为矩形)、球形和其他曲线坐标系。
可以在 sympy.vector
中初始化一个三维笛卡尔坐标系。
>>> from sympy.vector import CoordSys3D
>>> N = CoordSys3D('N')
构造函数的字符串参数表示分配给系统的名称,主要用于打印目的。
一旦定义了坐标系(本质上是一个 CoordSys3D
实例),我们就可以访问其正交单位向量(即 \(\mathbf{\hat{i}}\)、\(\mathbf{\hat{j}}\) 和 \(\mathbf{\hat{k}}\) 向量)以及对应的坐标变量/基标量(即 \(\mathbf{x}\)、\(\mathbf{y}\) 和 \(\mathbf{z}\) 变量)。我们将在后面的章节中讨论坐标变量。
可以通过 i
、j
和 k
属性分别访问 \(X\)、\(Y\) 和 \(Z\) 轴的基向量。
>>> N.i
N.i
>>> type(N.i)
<class 'sympy.vector.vector.BaseVector'>
如上所示,基向量都是名为 BaseVector
的类的实例。
当一个 BaseVector
乘以一个标量(本质上任何 SymPy Expr
),我们得到一个 VectorMul
- 一个基向量和标量的乘积。
>>> 3*N.i
3*N.i
>>> type(3*N.i)
<class 'sympy.vector.vector.VectorMul'>
添加 VectorMul
和 BaseVectors
会导致 VectorAdd
的形成 - 当然,除了特殊情况。
>>> v = 2*N.i + N.j
>>> type(v)
<class 'sympy.vector.vector.VectorAdd'>
>>> v - N.j
2*N.i
>>> type(v - N.j)
<class 'sympy.vector.vector.VectorMul'>
零向量呢?它可以通过分配给类 Vector
的 zero
属性来访问。由于零向量的概念在考虑的坐标系中保持不变,我们在需要这种量时使用 Vector.zero
。
>>> from sympy.vector import Vector
>>> Vector.zero
0
>>> type(Vector.zero)
<class 'sympy.vector.vector.VectorZero'>
>>> N.i + Vector.zero
N.i
>>> Vector.zero == 2*Vector.zero
True
上面显示的所有类 - BaseVector
、VectorMul
、VectorAdd
和 VectorZero
都是 Vector
的子类。
你永远不需要实例化 Vector
的任何子类的对象。使用分配给 CoordSys3D
实例的 BaseVector
实例和(如果需要) Vector.zero
作为构建块,任何类型的向量表达式都可以通过基本的数学运算符 +
、-
、*
和 /
来构造。
>>> v = N.i - 2*N.j
>>> v/3
1/3*N.i + (-2/3)*N.j
>>> v + N.k
N.i + (-2)*N.j + N.k
>>> Vector.zero/2
0
>>> (v/3)*4
4/3*N.i + (-8/3)*N.j
除了基本的数学运算外,还可以对 Vector
执行 dot
和 cross
的向量运算。
>>> v1 = 2*N.i + 3*N.j - N.k
>>> v2 = N.i - 4*N.j + N.k
>>> v1.dot(v2)
-11
>>> v1.cross(v2)
(-1)*N.i + (-3)*N.j + (-11)*N.k
>>> v2.cross(v1)
N.i + 3*N.j + 11*N.k
&
和 ^
运算符分别被重载为 dot
和 cross
方法。
>>> v1 & v2
-11
>>> v1 ^ v2
(-1)*N.i + (-3)*N.j + (-11)*N.k
然而,这不是执行这些操作的推荐方式。使用原始方法使代码更清晰、更易于理解。
除了这些操作,还可以在 sympy.vector
中计算 Vector
实例的外积。稍后会详细介绍。
SymPy 对向量的操作¶
SymPy 的 simplify
、trigsimp
、diff
和 factor
操作在 Vector
对象上工作,使用标准的 SymPy API。
本质上,这些方法作用于提供的向量表达式中的度量数(基向量的系数)。
>>> from sympy.abc import a, b, c
>>> from sympy import sin, cos, trigsimp, diff
>>> v = (a*b + a*c + b**2 + b*c)*N.i + N.j
>>> v.factor()
((a + b)*(b + c))*N.i + N.j
>>> v = (sin(a)**2 + cos(a)**2)*N.i - (2*cos(b)**2 - 1)*N.k
>>> trigsimp(v)
N.i + (-cos(2*b))*N.k
>>> v.simplify()
N.i + (-cos(2*b))*N.k
>>> diff(v, b)
(4*sin(b)*cos(b))*N.k
>>> from sympy import Derivative
>>> Derivative(v, b).doit()
(4*sin(b)*cos(b))*N.k
Integral
也可以与 Vector
实例一起使用,类似于 Derivative
。
>>> from sympy import Integral
>>> v1 = a*N.i + sin(a)*N.j - N.k
>>> Integral(v1, a)
(Integral(a, a))*N.i + (Integral(sin(a), a))*N.j + (Integral(-1, a))*N.k
>>> Integral(v1, a).doit()
a**2/2*N.i + (-cos(a))*N.j + (-a)*N.k
点¶
如前所述,每个坐标系对应一个唯一的原点。点通常在 sympy.vector
中以 Point
类的形式实现。
要访问系统的原点,请使用 CoordSys3D
类的 origin
属性。
>>> from sympy.vector import CoordSys3D
>>> N = CoordSys3D('N')
>>> N.origin
N.origin
>>> type(N.origin)
<class 'sympy.vector.point.Point'>
你可以使用 Point
的 locate_new
方法在空间中实例化新的点。参数包括新 Point
的名称(字符串),以及相对于 ‘父’ Point
的位置向量。
>>> from sympy.abc import a, b, c
>>> P = N.origin.locate_new('P', a*N.i + b*N.j + c*N.k)
>>> Q = P.locate_new('Q', -b*N.j)
类似于 Vector
,用户永远不需要显式实例化一个 Point
对象。这是因为任何空间中的位置(尽管是相对的)都可以通过使用 CoordSys3D
的 origin
作为参考,然后在其上使用 locate_new
以及后续的 Point
实例来指向。
一个 Point
相对于另一个 Point
的位置向量可以使用 position_wrt
方法计算。
>>> P.position_wrt(Q)
b*N.j
>>> Q.position_wrt(N.origin)
a*N.i + c*N.k
此外,可以以元组的形式获取 Point
相对于 CoordSys3D
的 \(X\)、\(Y\) 和 \(Z\) 坐标。这是通过 express_coordinates
方法完成的。
>>> Q.express_coordinates(N)
(a, 0, c)
Dyadics¶
二元张量,或称二元张量,是由一对向量的并置形成的二阶张量。因此,向量的外积导致了二元张量的形成。二元张量已在 sympy.vector
模块中的 Dyadic
类中实现。
再次强调,你永远不需要实例化 Dyadic
对象。向量的外积可以使用 Vector
的 outer
方法来计算。|
运算符已经为 outer
重载。
>>> from sympy.vector import CoordSys3D
>>> N = CoordSys3D('N')
>>> N.i.outer(N.j)
(N.i|N.j)
>>> N.i|N.j
(N.i|N.j)
类似于 Vector
,Dyadic
也有后续子类,如 BaseDyadic
、DyadicMul
、DyadicAdd
。与 Vector
一样,可以从 Dyadic.zero
访问零对偶。
所有基本的数学运算也适用于 Dyadic
。
>>> dyad = N.i.outer(N.k)
>>> dyad*3
3*(N.i|N.k)
>>> dyad - dyad
0
>>> dyad + 2*(N.j|N.i)
(N.i|N.k) + 2*(N.j|N.i)
dot
和 cross
也可以在 Dyadic
实例之间以及 Dyadic
和 Vector
之间(反之亦然)工作 - 根据各自的数学定义。与 Vector
一样,&
和 ^
已被重载用于 dot
和 cross
。
>>> d = N.i.outer(N.j)
>>> d.dot(N.j|N.j)
(N.i|N.j)
>>> d.dot(N.i)
0
>>> d.dot(N.j)
N.i
>>> N.i.dot(d)
N.j
>>> N.k ^ d
(N.j|N.j)