SymPy-1-13-中文文档-十三-
SymPy 1.13 中文文档(十三)
矩阵类别
class sympy.matrices.kind.MatrixKind(element_kind=NumberKind)
SymPy 中所有矩阵的类别。
此类的基本类是MatrixBase
和MatrixExpr
,但任何表示矩阵的表达式都可以具有这种类别。
参数:
元素类别:类别
元素类型。默认是
sympy.core.kind.NumberKind
,表示矩阵只包含数字。
示例
任何矩阵类的实例均具有MatrixKind
类别:
>>> from sympy import MatrixSymbol
>>> A = MatrixSymbol('A', 2, 2)
>>> A.kind
MatrixKind(NumberKind)
表示矩阵的表达式可能不是 Matrix 类的实例,但它将具有MatrixKind
类别:
>>> from sympy import MatrixExpr, Integral
>>> from sympy.abc import x
>>> intM = Integral(A, x)
>>> isinstance(intM, MatrixExpr)
False
>>> intM.kind
MatrixKind(NumberKind)
使用isinstance()
检查是否为MatrixKind
,无需指定元素类型。使用is
来检查包括元素类型的类别:
>>> from sympy import Matrix
>>> from sympy.core import NumberKind
>>> from sympy.matrices import MatrixKind
>>> M = Matrix([1, 2])
>>> isinstance(M.kind, MatrixKind)
True
>>> M.kind is MatrixKind(NumberKind)
True
另请参见
sympy.core.kind.NumberKind
,sympy.core.kind.UndefinedKind
,sympy.core.containers.TupleKind
,sympy.sets.sets.SetKind
__weakref__
对对象的弱引用列表
密集矩阵
sympy.matrices.dense.Matrix
别名 MutableDenseMatrix
class sympy.matrices.dense.DenseMatrix
基于 DomainMatrix 的矩阵实现作为内部表示
LDLdecomposition(hermitian=True)
返回矩阵 A 的 LDL 分解 (L, D),使得当 hermitian 标志为 True 时,L * D * L.H == A;当 hermitian 为 False 时,L * D * L.T == A。此方法消除了平方根的使用。此外,确保 L 的所有对角线条目都为 1。如果 hermitian 为 True,则 A 必须是 Hermite 正定矩阵;否则必须是对称矩阵。
示例
>>> from sympy import Matrix, eye
>>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
>>> L, D = A.LDLdecomposition()
>>> L
Matrix([
[ 1, 0, 0],
[ 3/5, 1, 0],
[-1/5, 1/3, 1]])
>>> D
Matrix([
[25, 0, 0],
[ 0, 9, 0],
[ 0, 0, 9]])
>>> L * D * L.T * A.inv() == eye(A.rows)
True
矩阵可以有复数条目:
>>> from sympy import I
>>> A = Matrix(((9, 3*I), (-3*I, 5)))
>>> L, D = A.LDLdecomposition()
>>> L
Matrix([
[ 1, 0],
[-I/3, 1]])
>>> D
Matrix([
[9, 0],
[0, 4]])
>>> L*D*L.H == A
True
另请参阅
sympy.matrices.dense.DenseMatrix.cholesky
,sympy.matrices.matrixbase.MatrixBase.LUdecomposition
,QRdecomposition
as_immutable()
返回此矩阵的不可变版本
as_mutable()
返回此矩阵的可变版本
示例
>>> from sympy import ImmutableMatrix
>>> X = ImmutableMatrix([[1, 2], [3, 4]])
>>> Y = X.as_mutable()
>>> Y[1, 1] = 5 # Can set values in Y
>>> Y
Matrix([
[1, 2],
[3, 5]])
cholesky(hermitian=True)
返回矩阵 A 的 Cholesky 分解 L,使得当 hermitian 标志为 True 时,L * L.H == A;当 hermitian 为 False 时,L * L.T == A。
如果 hermitian 为 True,则 A 必须是 Hermite 正定矩阵;如果为 False,则必须是对称矩阵。
示例
>>> from sympy import Matrix
>>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11)))
>>> A.cholesky()
Matrix([
[ 5, 0, 0],
[ 3, 3, 0],
[-1, 1, 3]])
>>> A.cholesky() * A.cholesky().T
Matrix([
[25, 15, -5],
[15, 18, 0],
[-5, 0, 11]])
矩阵可以有复数条目:
>>> from sympy import I
>>> A = Matrix(((9, 3*I), (-3*I, 5)))
>>> A.cholesky()
Matrix([
[ 3, 0],
[-I, 2]])
>>> A.cholesky() * A.cholesky().H
Matrix([
[ 9, 3*I],
[-3*I, 5]])
当矩阵非正定时,非 Hermite Cholesky 分解可能是有用的。
>>> A = Matrix([[1, 2], [2, 1]])
>>> L = A.cholesky(hermitian=False)
>>> L
Matrix([
[1, 0],
[2, sqrt(3)*I]])
>>> L*L.T == A
True
另请参阅
sympy.matrices.dense.DenseMatrix.LDLdecomposition
,sympy.matrices.matrixbase.MatrixBase.LUdecomposition
,QRdecomposition
lower_triangular_solve(rhs)
解决 Ax = B
,其中 A 是一个下三角矩阵。
另请参阅
upper_triangular_solve
, gauss_jordan_solve
, cholesky_solve
, diagonal_solve
, LDLsolve
, LUsolve
, QRsolve
, pinv_solve
, cramer_solve
upper_triangular_solve(rhs)
解决Ax = B
,其中 A 是上三角矩阵。
另见
lower_triangular_solve
, gauss_jordan_solve
, cholesky_solve
, diagonal_solve
, LDLsolve
, LUsolve
, QRsolve
, pinv_solve
, cramer_solve
class sympy.matrices.dense.MutableDenseMatrix(*args, **kwargs)
simplify(**kwargs)
对矩阵元素应用简化操作。
这是一个 M.applyfunc(lambda x: simplify(x, ratio, measure))的快捷方式。
另见
sympy.simplify.simplify.simplify
class sympy.matrices.immutable.ImmutableDenseMatrix(*args, **kwargs)
创建矩阵的不可变版本。
示例
>>> from sympy import eye, ImmutableMatrix
>>> ImmutableMatrix(eye(3))
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
>>> _[0, 0] = 42
Traceback (most recent call last):
...
TypeError: Cannot set values of ImmutableDenseMatrix
稀疏矩阵
稀疏矩阵类参考文档
sympy.matrices.sparse.SparseMatrix
别名为MutableSparseMatrix
class sympy.matrices.sparse.MutableSparseMatrix(*args, **kwargs)
不可变稀疏矩阵类参考文档
class sympy.matrices.immutable.ImmutableSparseMatrix(*args, **kwargs)
创建不可变版本的稀疏矩阵。
示例
>>> from sympy import eye, ImmutableSparseMatrix
>>> ImmutableSparseMatrix(1, 1, {})
Matrix([[0]])
>>> ImmutableSparseMatrix(eye(3))
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
>>> _[0, 0] = 42
Traceback (most recent call last):
...
TypeError: Cannot set values of ImmutableSparseMatrix
>>> _.shape
(3, 3)
稀疏工具
原文链接:
docs.sympy.org/latest/modules/matrices/sparsetools.html
sympy.matrices.sparsetools._doktocsr()
将稀疏矩阵转换为压缩稀疏行(CSR)格式。
参数:
A:按键(行,列)排序的非零元素
JA:JA[i] 是与 A[i]对应的列
IA:IA[i] 包含 A 中第一个非零元素的索引
对于行[i]的非零元素数。因此,IA[i+1] - IA[i] 给出行[i]的非零元素数。IA 的长度始终比矩阵中的行数多 1。
示例
>>> from sympy.matrices.sparsetools import _doktocsr
>>> from sympy import SparseMatrix, diag
>>> m = SparseMatrix(diag(1, 2, 3))
>>> m[2, 0] = -1
>>> _doktocsr(m)
[[1, 2, -1, 3], [0, 1, 0, 2], [0, 1, 2, 4], [3, 3]]
sympy.matrices.sparsetools._csrtodok()
将 CSR 表示转换为 DOK 表示。
示例
>>> from sympy.matrices.sparsetools import _csrtodok
>>> _csrtodok([[5, 8, 3, 6], [0, 1, 2, 1], [0, 0, 2, 3, 4], [4, 3]])
Matrix([
[0, 0, 0],
[5, 8, 0],
[0, 0, 3],
[0, 6, 0]])
sympy.matrices.sparsetools.banded(**kwargs)
从描述矩阵对角线的给定字典返回稀疏矩阵。键为正值表示上对角线,负值表示主对角线以下。值可以是:
-
表达式或单参数函数,
-
值的列表或元组,
-
矩阵
如果没有给出尺寸,则返回的矩阵大小将足够大,以包含提供的最大非零值。
Kwargs
矩阵的对角线;如果计算
未给出。
矩阵的列数;如果计算
未给出。
示例
>>> from sympy import banded, ones, Matrix
>>> from sympy.abc import x
如果元组中给出了显式值,则矩阵将自动调整大小以包含所有值,否则将单个值填充到整个对角线上:
>>> banded({1: (1, 2, 3), -1: (4, 5, 6), 0: x})
Matrix([
[x, 1, 0, 0],
[4, x, 2, 0],
[0, 5, x, 3],
[0, 0, 6, x]])
接受单个参数的函数可用于根据对角线索引(从 0 开始)填充对角线。必须提供矩阵的大小(或形状)以获得超过 1x1 的矩阵:
>>> s = lambda d: (1 + d)**2
>>> banded(5, {0: s, 2: s, -2: 2})
Matrix([
[1, 0, 1, 0, 0],
[0, 4, 0, 4, 0],
[2, 0, 9, 0, 9],
[0, 2, 0, 16, 0],
[0, 0, 2, 0, 25]])
放置在对角线上的矩阵的对角线将与指定的对角线重合:
>>> vert = Matrix([1, 2, 3])
>>> banded({0: vert}, cols=3)
Matrix([
[1, 0, 0],
[2, 1, 0],
[3, 2, 1],
[0, 3, 2],
[0, 0, 3]])
>>> banded(4, {0: ones(2)})
Matrix([
[1, 1, 0, 0],
[1, 1, 0, 0],
[0, 0, 1, 1],
[0, 0, 1, 1]])
如果指定的大小无法容纳所有值的整数倍,则会引发错误。这里,行被指定为奇数(但需要偶数才能容纳对角线上的 2x2 非对角线元素):
>>> banded({0: 2, 1: ones(2)}, rows=5)
Traceback (most recent call last):
...
ValueError:
sequence does not fit an integral number of times in the matrix
在这里,提供了偶数行…但是正方形矩阵也有偶数列。正如我们在上一个示例中看到的,需要奇数行:
>>> banded(4, {0: 2, 1: ones(2)}) # trying to make 4x4 and cols must be odd
Traceback (most recent call last):
...
ValueError:
sequence does not fit an integral number of times in the matrix
避免计算行数的方法是将矩阵元素封装在元组中,并指示所需的元素数量放在右边:
>>> banded({0: 2, 2: (ones(2),)*3})
Matrix([
[2, 0, 1, 1, 0, 0, 0, 0],
[0, 2, 1, 1, 0, 0, 0, 0],
[0, 0, 2, 0, 1, 1, 0, 0],
[0, 0, 0, 2, 1, 1, 0, 0],
[0, 0, 0, 0, 2, 0, 1, 1],
[0, 0, 0, 0, 0, 2, 1, 1]])
如果给定的条目写入了多个值,将引发错误。这里,如果将它们放置在第一个对角线上,这些 1 将与主对角线重叠:
>>> banded({0: (2,)*5, 1: (ones(2),)*3})
Traceback (most recent call last):
...
ValueError: collision at (1, 1)
通过在全一的 2x2 矩阵左下角放置 0,可以避免碰撞:
>>> u2 = Matrix([
... [1, 1],
... [0, 1]])
>>> banded({0: [2]*5, 1: [u2]*3})
Matrix([
[2, 1, 1, 0, 0, 0, 0],
[0, 2, 1, 0, 0, 0, 0],
[0, 0, 2, 1, 1, 0, 0],
[0, 0, 0, 2, 1, 0, 0],
[0, 0, 0, 0, 2, 1, 1],
[0, 0, 0, 0, 0, 0, 1]])
不可变矩阵
原文链接:
docs.sympy.org/latest/modules/matrices/immutablematrices.html
在 SymPy 中,标准的Matrix
类是可变的。出于性能考虑这一点非常重要,但这也意味着标准矩阵不能很好地与 SymPy 的其他部分交互。这是因为大多数 SymPy 类继承自不可变的Basic
对象。
ImmutableDenseMatrix
类的使命是解决性能/可变性与安全性/不可变性之间的张力。不可变矩阵几乎可以完成普通矩阵的所有功能,但它们继承自Basic
,因此可以更自然地与 SymPy 的其他部分交互。ImmutableMatrix
还继承自MatrixExpr
,允许它与 SymPy 的矩阵表达式模块自由交互。
通过调用构造函数,您可以将任何类似于矩阵的对象转换为ImmutableMatrix
。
>>> from sympy import Matrix, ImmutableMatrix
>>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> M[1, 1] = 0
>>> IM = ImmutableMatrix(M)
>>> IM
Matrix([
[1, 2, 3],
[4, 0, 6],
[7, 8, 9]])
>>> IM[1, 1] = 5
Traceback (most recent call last):
...
TypeError: Can not set values in Immutable Matrix. Use Matrix instead.
ImmutableMatrix 类参考
sympy.matrices.immutable.ImmutableMatrix
是 ImmutableDenseMatrix
的别名。
class sympy.matrices.immutable.ImmutableDenseMatrix(*args, **kwargs)
创建一个矩阵的不可变版本。
示例
>>> from sympy import eye, ImmutableMatrix
>>> ImmutableMatrix(eye(3))
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
>>> _[0, 0] = 42
Traceback (most recent call last):
...
TypeError: Cannot set values of ImmutableDenseMatrix
矩阵表达式
矩阵表达式模块允许用户编写如下语句
>>> from sympy import MatrixSymbol, Matrix
>>> X = MatrixSymbol('X', 3, 3)
>>> Y = MatrixSymbol('Y', 3, 3)
>>> (X.T*X).I*Y
X**(-1)*X.T**(-1)*Y
>>> Matrix(X)
Matrix([
[X[0, 0], X[0, 1], X[0, 2]],
[X[1, 0], X[1, 1], X[1, 2]],
[X[2, 0], X[2, 1], X[2, 2]]])
>>> (X*Y)[1, 2]
X[1, 0]*Y[0, 2] + X[1, 1]*Y[1, 2] + X[1, 2]*Y[2, 2]
其中X
和Y
是MatrixSymbol
,而不是标量符号。
支持矩阵表达式的导数。一个矩阵关于另一个矩阵的导数通常是一个四维数组,但如果一些维度是平凡的或对角的,导数算法将尝试将结果表示为矩阵表达式:
>>> a = MatrixSymbol("a", 3, 1)
>>> b = MatrixSymbol("b", 3, 1)
>>> (a.T*X**2*b).diff(X)
a*b.T*X.T + X.T*a*b.T
>>> X.diff(X)
PermuteDims(ArrayTensorProduct(I, I), (3)(1 2))
最后的输出是一个数组表达式,因为返回的符号是四维的。
矩阵表达式核心参考
class sympy.matrices.expressions.MatrixExpr(*args, **kwargs)
矩阵表达式的超类
MatrixExprs 表示在特定基础内表示的抽象矩阵,线性变换。
示例
>>> from sympy import MatrixSymbol
>>> A = MatrixSymbol('A', 3, 3)
>>> y = MatrixSymbol('y', 3, 1)
>>> x = (A.T*A).I * A * y
参见
MatrixSymbol
,MatAdd
,MatMul
,Transpose
,Inverse
property T
矩阵转置
as_coeff_Mul(rational=False)
高效提取乘积的系数。
as_explicit()
返回一个明确表示元素的密集矩阵
返回一个类型为 ImmutableDenseMatrix 的对象。
示例
>>> from sympy import Identity
>>> I = Identity(3)
>>> I
I
>>> I.as_explicit()
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
参见
as_mutable
返回可变矩阵类型
as_mutable()
返回一个密集的可变矩阵,其元素明确表示
示例
>>> from sympy import Identity
>>> I = Identity(3)
>>> I
I
>>> I.shape
(3, 3)
>>> I.as_mutable()
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
参见
as_explicit
返回 ImmutableDenseMatrix
equals(other)
测试矩阵之间的逐元素相等性,可能是不同类型的矩阵
>>> from sympy import Identity, eye
>>> Identity(3).equals(eye(3))
True
static from_index_summation(expr, first_index=None, last_index=None, dimensions=None)
将具有明确求和索引的矩阵表达式解析为没有索引的矩阵表达式,如果可能的话。
此转换以数学符号表示:
(\sum_{j=0}^{N-1} A_{i,j} B_{j,k} \Longrightarrow \mathbf{A}\cdot \mathbf{B})
可选参数first_index
:指定用作表达式起始的自由索引。
示例
>>> from sympy import MatrixSymbol, MatrixExpr, Sum
>>> from sympy.abc import i, j, k, l, N
>>> A = MatrixSymbol("A", N, N)
>>> B = MatrixSymbol("B", N, N)
>>> expr = Sum(A[i, j]*B[j, k], (j, 0, N-1))
>>> MatrixExpr.from_index_summation(expr)
A*B
检测到转置:
>>> expr = Sum(A[j, i]*B[j, k], (j, 0, N-1))
>>> MatrixExpr.from_index_summation(expr)
A.T*B
检测迹:
>>> expr = Sum(A[i, i], (i, 0, N-1))
>>> MatrixExpr.from_index_summation(expr)
Trace(A)
更复杂的表达式:
>>> expr = Sum(A[i, j]*B[k, j]*A[l, k], (j, 0, N-1), (k, 0, N-1))
>>> MatrixExpr.from_index_summation(expr)
A*B.T*A.T
class sympy.matrices.expressions.MatrixSymbol(name, n, m)
矩阵对象的符号表示
创建一个 SymPy 符号来表示一个矩阵。此矩阵具有形状,并可包含在矩阵表达式中
示例
>>> from sympy import MatrixSymbol, Identity
>>> A = MatrixSymbol('A', 3, 4) # A 3 by 4 Matrix
>>> B = MatrixSymbol('B', 4, 3) # A 4 by 3 Matrix
>>> A.shape
(3, 4)
>>> 2*A*B + Identity(3)
I + 2*A*B
class sympy.matrices.expressions.MatAdd(*args, evaluate=False, check=None, _sympify=True)
矩阵表达式的和
MatAdd 继承自并像 SymPy Add 操作
示例
>>> from sympy import MatAdd, MatrixSymbol
>>> A = MatrixSymbol('A', 5, 5)
>>> B = MatrixSymbol('B', 5, 5)
>>> C = MatrixSymbol('C', 5, 5)
>>> MatAdd(A, B, C)
A + B + C
class sympy.matrices.expressions.MatMul(*args, evaluate=False, check=None, _sympify=True)
矩阵表达式的乘积
示例
>>> from sympy import MatMul, MatrixSymbol
>>> A = MatrixSymbol('A', 5, 4)
>>> B = MatrixSymbol('B', 4, 3)
>>> C = MatrixSymbol('C', 3, 6)
>>> MatMul(A, B, C)
A*B*C
class sympy.matrices.expressions.MatPow(base, exp, evaluate=False, **options)
sympy.matrices.expressions.hadamard_product(*matrices)
返回矩阵的逐元素(又名 Hadamard)乘积。
示例
>>> from sympy import hadamard_product, MatrixSymbol
>>> A = MatrixSymbol('A', 2, 3)
>>> B = MatrixSymbol('B', 2, 3)
>>> hadamard_product(A)
A
>>> hadamard_product(A, B)
HadamardProduct(A, B)
>>> hadamard_product(A, B)[0, 1]
A[0, 1]*B[0, 1]
class sympy.matrices.expressions.HadamardProduct(*args, evaluate=False, check=None)
矩阵表达式的逐元素乘积
示例
矩阵符号的 Hadamard 乘积:
>>> from sympy import hadamard_product, HadamardProduct, MatrixSymbol
>>> A = MatrixSymbol('A', 5, 5)
>>> B = MatrixSymbol('B', 5, 5)
>>> isinstance(hadamard_product(A, B), HadamardProduct)
True
注意
这是一个简单存储其参数而不进行评估的符号对象。要实际计算乘积,请使用函数 hadamard_product()
或 HadamardProduct.doit
class sympy.matrices.expressions.HadamardPower(base, exp)
矩阵表达式的逐元素乘幂
参数:
base:标量或矩阵
exp:标量或矩阵
注意事项
有四种可用的哈达玛乘方的定义。让我们将 (A, B) 视为 ((m, n)) 矩阵,(a, b) 视为标量。
矩阵的标量乘方:
[\begin{split}A^{\circ b} = \begin{bmatrix} A_{0, 0}^b & A_{0, 1}^b & \cdots & A_{0, n-1}^b \ A_{1, 0}^b & A_{1, 1}^b & \cdots & A_{1, n-1}^b \ \vdots & \vdots & \ddots & \vdots \ A_{m-1, 0}^b & A_{m-1, 1}^b & \cdots & A_{m-1, n-1}^b \end{bmatrix}\end{split}]
矩阵的标量乘方:
[\begin{split}a^{\circ B} = \begin{bmatrix} a^{B_{0, 0}} & a^{B_{0, 1}} & \cdots & a^{B_{0, n-1}} \ a^{B_{1, 0}} & a^{B_{1, 1}} & \cdots & a^{B_{1, n-1}} \ \vdots & \vdots & \ddots & \vdots \ a^{B_{m-1, 0}} & a^{B_{m-1, 1}} & \cdots & a^{B_{m-1, n-1}} \end{bmatrix}\end{split}]
矩阵的矩阵乘方:
[\begin{split}A^{\circ B} = \begin{bmatrix} A_{0, 0}^{B_{0, 0}} & A_{0, 1}^{B_{0, 1}} & \cdots & A_{0, n-1}^{B_{0, n-1}} \ A_{1, 0}^{B_{1, 0}} & A_{1, 1}^{B_{1, 1}} & \cdots & A_{1, n-1}^{B_{1, n-1}} \ \vdots & \vdots & \ddots & \vdots \ A_{m-1, 0}^{B_{m-1, 0}} & A_{m-1, 1}^{B_{m-1, 1}} & \cdots & A_{m-1, n-1}^{B_{m-1, n-1}} \end{bmatrix}\end{split}]
标量的标量乘方:
[a^{\circ b} = a^b]
class sympy.matrices.expressions.Inverse(mat, exp=-1)
矩阵表达式的乘法逆
这是一个简单存储其参数而不进行评估的符号对象。要实际计算逆矩阵,请使用矩阵的 .inverse()
方法。
示例
>>> from sympy import MatrixSymbol, Inverse
>>> A = MatrixSymbol('A', 3, 3)
>>> B = MatrixSymbol('B', 3, 3)
>>> Inverse(A)
A**(-1)
>>> A.inverse() == Inverse(A)
True
>>> (A*B).inverse()
B**(-1)*A**(-1)
>>> Inverse(A*B)
(A*B)**(-1)
class sympy.matrices.expressions.Transpose(*args, **kwargs)
矩阵表达式的转置。
这是一个简单存储其参数而不进行评估的符号对象。要实际计算转置,请使用 transpose()
函数或矩阵的 .T
属性。
示例
>>> from sympy import MatrixSymbol, Transpose, transpose
>>> A = MatrixSymbol('A', 3, 5)
>>> B = MatrixSymbol('B', 5, 3)
>>> Transpose(A)
A.T
>>> A.T == transpose(A) == Transpose(A)
True
>>> Transpose(A*B)
(A*B).T
>>> transpose(A*B)
B.T*A.T
class sympy.matrices.expressions.Trace(mat)
矩阵迹
表示矩阵表达式的迹。
示例
>>> from sympy import MatrixSymbol, Trace, eye
>>> A = MatrixSymbol('A', 3, 3)
>>> Trace(A)
Trace(A)
>>> Trace(eye(3))
Trace(Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]))
>>> Trace(eye(3)).simplify()
3
class sympy.matrices.expressions.FunctionMatrix(rows, cols, lamda)
使用一个函数(Lambda
)表示矩阵,该函数根据每个矩阵条目的坐标给出输出。
参数:
rows:非负整数。可以是符号。
cols:非负整数。可以是符号。
lamda:函数、Lambda 或字符串
如果它是 SymPy 的
Function
或Lambda
实例,则应能接受表示矩阵坐标的两个参数。如果它是一个纯粹包含 Python
lambda
语义的字符串,则由 SymPy 解析器解释,并转换为 SymPy 的Lambda
实例。
示例
从 Lambda
创建 FunctionMatrix
:
>>> from sympy import FunctionMatrix, symbols, Lambda, MatPow
>>> i, j, n, m = symbols('i,j,n,m')
>>> FunctionMatrix(n, m, Lambda((i, j), i + j))
FunctionMatrix(n, m, Lambda((i, j), i + j))
从 SymPy 函数创建 FunctionMatrix
:
>>> from sympy import KroneckerDelta
>>> X = FunctionMatrix(3, 3, KroneckerDelta)
>>> X.as_explicit()
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
从 SymPy 未定义函数创建 FunctionMatrix
:
>>> from sympy import Function
>>> f = Function('f')
>>> X = FunctionMatrix(3, 3, f)
>>> X.as_explicit()
Matrix([
[f(0, 0), f(0, 1), f(0, 2)],
[f(1, 0), f(1, 1), f(1, 2)],
[f(2, 0), f(2, 1), f(2, 2)]])
从 Python lambda
创建 FunctionMatrix
:
>>> FunctionMatrix(n, m, 'lambda i, j: i + j')
FunctionMatrix(n, m, Lambda((i, j), i + j))
矩阵乘积的惰性求值示例:
>>> Y = FunctionMatrix(1000, 1000, Lambda((i, j), i + j))
>>> isinstance(Y*Y, MatPow) # this is an expression object
True
>>> (Y**2)[10,10] # So this is evaluated lazily
342923500
注意事项
该类提供了一种用最稀疏方式表示序列形式的极度密集矩阵的替代方法。
class sympy.matrices.expressions.PermutationMatrix(perm)
一个置换矩阵
参数:
perm:置换
矩阵使用的置换。
置换确定矩阵大小的大小。
参阅
sympy.combinatorics.permutations.Permutation
文档,了解如何创建置换对象的详细信息。
示例
>>> from sympy import Matrix, PermutationMatrix
>>> from sympy.combinatorics import Permutation
创建置换矩阵:
>>> p = Permutation(1, 2, 0)
>>> P = PermutationMatrix(p)
>>> P = P.as_explicit()
>>> P
Matrix([
[0, 1, 0],
[0, 0, 1],
[1, 0, 0]])
置换矩阵的行和列:
>>> M = Matrix([0, 1, 2])
>>> Matrix(P*M)
Matrix([
[1],
[2],
[0]])
>>> Matrix(M.T*P)
Matrix([[2, 0, 1]])
另请参阅
sympy.combinatorics.permutations.Permutation
class sympy.matrices.expressions.MatrixPermute(mat, perm, axis=0)
用于置换矩阵行或列的符号表示。
参数:
perm:置换,置换矩阵
用于置换矩阵的置换。置换可以调整为合适的大小,
axis:0 或 1
要与之一起置换的轴。如果为(0),它将置换矩阵行。如果为(1),它将置换矩阵列。
注意事项
这遵循与sympy.matrices.matrixbase.MatrixBase.permute()
中使用的相同符号。
示例
>>> from sympy import Matrix, MatrixPermute
>>> from sympy.combinatorics import Permutation
置换矩阵的行:
>>> p = Permutation(1, 2, 0)
>>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> B = MatrixPermute(A, p, axis=0)
>>> B.as_explicit()
Matrix([
[4, 5, 6],
[7, 8, 9],
[1, 2, 3]])
置换矩阵的列:
>>> B = MatrixPermute(A, p, axis=1)
>>> B.as_explicit()
Matrix([
[2, 3, 1],
[5, 6, 4],
[8, 9, 7]])
另请参阅
sympy.matrices.matrixbase.MatrixBase.permute
class sympy.matrices.expressions.Identity(n)
矩阵单位矩阵 I - 乘法单位元素
示例
>>> from sympy import Identity, MatrixSymbol
>>> A = MatrixSymbol('A', 3, 5)
>>> I = Identity(3)
>>> I*A
A
class sympy.matrices.expressions.ZeroMatrix(m, n)
矩阵零 0 - 加法单位元素
示例
>>> from sympy import MatrixSymbol, ZeroMatrix
>>> A = MatrixSymbol('A', 3, 5)
>>> Z = ZeroMatrix(3, 5)
>>> A + Z
A
>>> Z*A.T
0
class sympy.matrices.expressions.CompanionMatrix(poly)
多项式的符号伴随矩阵。
示例
>>> from sympy import Poly, Symbol, symbols
>>> from sympy.matrices.expressions import CompanionMatrix
>>> x = Symbol('x')
>>> c0, c1, c2, c3, c4 = symbols('c0:5')
>>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x)
>>> CompanionMatrix(p)
CompanionMatrix(Poly(x**5 + c4*x**4 + c3*x**3 + c2*x**2 + c1*x + c0,
x, domain='ZZ[c0,c1,c2,c3,c4]'))
class sympy.matrices.expressions.MatrixSet(n, m, set)
MatrixSet 表示形状为(n, m)的矩阵集合。
示例
>>> from sympy.matrices import MatrixSet
>>> from sympy import S, I, Matrix
>>> M = MatrixSet(2, 2, set=S.Reals)
>>> X = Matrix([[1, 2], [3, 4]])
>>> X in M
True
>>> X = Matrix([[1, 2], [I, 4]])
>>> X in M
False
块矩阵
块矩阵允许您使用较小的子块构建较大的矩阵。它们可以与MatrixExpr
或ImmutableMatrix
对象一起使用。
class sympy.matrices.expressions.blockmatrix.BlockMatrix(*args, **kwargs)
块矩阵是由其他矩阵组成的矩阵。
子矩阵存储在 SymPy 矩阵对象中,但作为矩阵表达式的一部分访问。
>>> from sympy import (MatrixSymbol, BlockMatrix, symbols,
... Identity, ZeroMatrix, block_collapse)
>>> n,m,l = symbols('n m l')
>>> X = MatrixSymbol('X', n, n)
>>> Y = MatrixSymbol('Y', m, m)
>>> Z = MatrixSymbol('Z', n, m)
>>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]])
>>> print(B)
Matrix([
[X, Z],
[0, Y]])
>>> C = BlockMatrix([[Identity(n), Z]])
>>> print(C)
Matrix([[I, Z]])
>>> print(block_collapse(C*B))
Matrix([[X, Z + Z*Y]])
一些矩阵可能由块的行组成,每行中的矩阵具有相同的高度,并且所有行具有相同的总列数,但在每行中的每个矩阵中不具有相同数量的列。在这种情况下,矩阵不是块矩阵,并且应通过 Matrix 进行实例化。
>>> from sympy import ones, Matrix
>>> dat = [
... [ones(3,2), ones(3,3)*2],
... [ones(2,3)*3, ones(2,2)*4]]
...
>>> BlockMatrix(dat)
Traceback (most recent call last):
...
ValueError:
Although this matrix is comprised of blocks, the blocks do not fill
the matrix in a size-symmetric fashion. To create a full matrix from
these arguments, pass them directly to Matrix.
>>> Matrix(dat)
Matrix([
[1, 1, 2, 2, 2],
[1, 1, 2, 2, 2],
[1, 1, 2, 2, 2],
[3, 3, 3, 4, 4],
[3, 3, 3, 4, 4]])
另请参阅
sympy.matrices.matrixbase.MatrixBase.irregular
LDUdecomposition()
返回一个 2x2 块矩阵的块 LDU 分解。
返回:
(L, D, U):矩阵
L:下三角矩阵 D:对角矩阵 U:上三角矩阵
引发:
ShapeError
如果块矩阵不是 2x2 矩阵
NonInvertibleMatrixError
如果矩阵“A”是不可逆的
示例
>>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse
>>> m, n = symbols('m n')
>>> A = MatrixSymbol('A', n, n)
>>> B = MatrixSymbol('B', n, m)
>>> C = MatrixSymbol('C', m, n)
>>> D = MatrixSymbol('D', m, m)
>>> X = BlockMatrix([[A, B], [C, D]])
>>> L, D, U = X.LDUdecomposition()
>>> block_collapse(L*D*U)
Matrix([
[A, B],
[C, D]])
另请参阅
sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition
, sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition
LUdecomposition()
返回 2x2 块矩阵的块 LU 分解
返回:
(L, U):矩阵
L:下对角矩阵 U:上对角矩阵
抛出:
ShapeError
如果块矩阵不是 2x2 矩阵
NonInvertibleMatrixError
如果矩阵“A”是非可逆的
示例
>>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse
>>> m, n = symbols('m n')
>>> A = MatrixSymbol('A', n, n)
>>> B = MatrixSymbol('B', n, m)
>>> C = MatrixSymbol('C', m, n)
>>> D = MatrixSymbol('D', m, m)
>>> X = BlockMatrix([[A, B], [C, D]])
>>> L, U = X.LUdecomposition()
>>> block_collapse(L*U)
Matrix([
[A, B],
[C, D]])
参见
sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition
, sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition
UDLdecomposition()
返回 2x2 块矩阵的块 UDL 分解
返回:
(U, D, L):矩阵
U:上对角矩阵 D:对角矩阵 L:下对角矩阵
抛出:
ShapeError
如果块矩阵不是 2x2 矩阵
NonInvertibleMatrixError
如果矩阵“D”是非可逆的
示例
>>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse
>>> m, n = symbols('m n')
>>> A = MatrixSymbol('A', n, n)
>>> B = MatrixSymbol('B', n, m)
>>> C = MatrixSymbol('C', m, n)
>>> D = MatrixSymbol('D', m, m)
>>> X = BlockMatrix([[A, B], [C, D]])
>>> U, D, L = X.UDLdecomposition()
>>> block_collapse(U*D*L)
Matrix([
[A, B],
[C, D]])
参见
sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition
, sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition
schur(mat='A', generalized=False)
返回 2x2 块矩阵的舒尔补
参数:
mat:字符串,可选
用于计算舒尔补的矩阵。“默认情况下使用“A”
generalized:布尔值,可选
如果为 True,则返回使用摩尔-彭罗斯逆的广义舒尔补
返回:
M:矩阵
舒尔补矩阵
抛出:
ShapeError
如果块矩阵不是 2x2 矩阵
NonInvertibleMatrixError
如果给定的矩阵是非可逆的
示例
>>> from sympy import symbols, MatrixSymbol, BlockMatrix
>>> m, n = symbols('m n')
>>> A = MatrixSymbol('A', n, n)
>>> B = MatrixSymbol('B', n, m)
>>> C = MatrixSymbol('C', m, n)
>>> D = MatrixSymbol('D', m, m)
>>> X = BlockMatrix([[A, B], [C, D]])
默认的舒尔补是使用“A”进行评估的
>>> X.schur()
-C*A**(-1)*B + D
>>> X.schur('D')
A - B*D**(-1)*C
非可逆矩阵的舒尔补没有定义。相反,可以计算使用摩尔-彭罗斯逆的广义舒尔补。为此,必须将 generalized
设置为 True
。
>>> X.schur('B', generalized=True)
C - D*(B.T*B)**(-1)*B.T*A
>>> X.schur('C', generalized=True)
-A*(C.T*C)**(-1)*C.T*D + B
参见
sympy.matrices.matrixbase.MatrixBase.pinv
参考文献
[R608]
transpose()
返回矩阵的转置。
示例
>>> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix
>>> from sympy.abc import m, n
>>> X = MatrixSymbol('X', n, n)
>>> Y = MatrixSymbol('Y', m, m)
>>> Z = MatrixSymbol('Z', n, m)
>>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]])
>>> B.transpose()
Matrix([
[X.T, 0],
[Z.T, Y.T]])
>>> _.transpose()
Matrix([
[X, Z],
[0, Y]])
class sympy.matrices.expressions.blockmatrix.BlockDiagMatrix(*mats)
一个带有块矩阵的稀疏矩阵
示例
>>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols
>>> n, m, l = symbols('n m l')
>>> X = MatrixSymbol('X', n, n)
>>> Y = MatrixSymbol('Y', m, m)
>>> BlockDiagMatrix(X, Y)
Matrix([
[X, 0],
[0, Y]])
注意事项
如果您想获取单独的对角块,请使用 get_diag_blocks()
。
参见
sympy.matrices.dense.diag
get_diag_blocks()
返回矩阵的对角块列表。
示例
>>> from sympy import BlockDiagMatrix, Matrix
>>> A = Matrix([[1, 2], [3, 4]])
>>> B = Matrix([[5, 6], [7, 8]])
>>> M = BlockDiagMatrix(A, B)
如何从块对角矩阵获取对角块:
>>> diag_blocks = M.get_diag_blocks()
>>> diag_blocks[0]
Matrix([
[1, 2],
[3, 4]])
>>> diag_blocks[1]
Matrix([
[5, 6],
[7, 8]])
sympy.matrices.expressions.blockmatrix.block_collapse(expr)
评估块矩阵表达式
>>> from sympy import MatrixSymbol, BlockMatrix, symbols, Identity, ZeroMatrix, block_collapse
>>> n,m,l = symbols('n m l')
>>> X = MatrixSymbol('X', n, n)
>>> Y = MatrixSymbol('Y', m, m)
>>> Z = MatrixSymbol('Z', n, m)
>>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]])
>>> print(B)
Matrix([
[X, Z],
[0, Y]])
>>> C = BlockMatrix([[Identity(n), Z]])
>>> print(C)
Matrix([[I, Z]])
>>> print(block_collapse(C*B))
Matrix([[X, Z + Z*Y]])
矩阵正则形式
原文链接:
docs.sympy.org/latest/modules/matrices/normalforms.html
sympy.matrices.normalforms.smith_normal_form(m, domain=None)
返回矩阵 (m) 在环 (domain) 上的 Smith 正则形式。这只适用于环是主理想域的情况。
示例
>>> from sympy import Matrix, ZZ
>>> from sympy.matrices.normalforms import smith_normal_form
>>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]])
>>> print(smith_normal_form(m, domain=ZZ))
Matrix([[1, 0, 0], [0, 10, 0], [0, 0, -30]])
sympy.matrices.normalforms.hermite_normal_form(A, *, D=None, check_rank=False)
计算整数矩阵 A 的 Hermite 正则形式。
参数:
A : (m \times n) 整数 Matrix
。
D : int, 可选
假设 (W) 是 A 的 HNF。如果事先已知,可提供正整数 D,它是 (\det(W)) 的任意倍数。在这种情况下,如果 A 的秩也是 (m),那么我们可以使用另一种算法,该算法在 mod D 下工作,以防止系数膨胀。
check_rank : 布尔值, 可选 (默认为 False)
基本假设是,如果您传递了 D 的值,则已相信 A 的秩是 (m),因此我们不会浪费时间为您检查它。如果您希望进行检查(并且如果检查失败,则使用普通的非模 D 算法),则将 check_rank 设置为
True
。
返回:
Matrix
矩阵 A 的 Hermite 正则形式。
引发:
DMDomainError
如果矩阵的域不是 ZZ。
DMShapeError
如果使用 mod D 算法但矩阵的行数多于列数。
示例
>>> from sympy import Matrix
>>> from sympy.matrices.normalforms import hermite_normal_form
>>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]])
>>> print(hermite_normal_form(m))
Matrix([[10, 0, 2], [0, 15, 3], [0, 0, 2]])
参考文献
[R647]
Cohen, H. 计算代数数论课程. (见算法 2.4.5 和 2.4.8。)
张量
一个用于处理包括张量在内的带有指数的符号对象的模块。
内容
-
N 维数组
-
N 维数组表达式
-
索引对象
-
方法
-
张量
-
张量运算符
N 维数组
SymPy 的 N 维数组模块。
提供了四个类来处理 N 维数组,根据稠密/稀疏(即是否将所有元素或仅非零元素存储在内存中)和可变/不可变的组合(不可变类是 SymPy 对象,但在创建后不能更改)。
示例
以下示例展示了Array
的使用。这是ImmutableDenseNDimArray
的缩写,即一个不可变的稠密 N 维数组,其他类似。
可以检测嵌套列表和元组的形状来构造数组
>>> from sympy import Array
>>> a1 = Array([[1, 2], [3, 4], [5, 6]])
>>> a1
[[1, 2], [3, 4], [5, 6]]
>>> a1.shape
(3, 2)
>>> a1.rank()
2
>>> from sympy.abc import x, y, z
>>> a2 = Array([[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]])
>>> a2
[[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]]
>>> a2.shape
(2, 2, 2)
>>> a2.rank()
3
或者可以传递一个 1 维数组,然后是一个形状元组:
>>> m1 = Array(range(12), (3, 4))
>>> m1
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
>>> m2 = Array(range(12), (3, 2, 2))
>>> m2
[[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
>>> m2[1,1,1]
7
>>> m2.reshape(4, 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
切片支持:
>>> m2[:, 1, 1]
[3, 7, 11]
按元素求导:
>>> from sympy.abc import x, y, z
>>> m3 = Array([x**3, x*y, z])
>>> m3.diff(x)
[3*x**2, y, 0]
>>> m3.diff(z)
[0, 0, 1]
与其他 SymPy 表达式的乘法是按元素应用的:
>>> (1+x)*m3
[x**3*(x + 1), x*y*(x + 1), z*(x + 1)]
若要对 N 维数组的每个元素应用函数,请使用applyfunc
:
>>> m3.applyfunc(lambda x: x/2)
[x**3/2, x*y/2, z/2]
N 维数组可以通过tolist()
方法转换为嵌套列表:
>>> m2.tolist()
[[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]]
>>> isinstance(m2.tolist(), list)
True
如果秩为 2,可以用tomatrix()
将它们转换为矩阵:
>>> m1.tomatrix()
Matrix([
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
乘积和收缩
数组(A_{i_1,\ldots,i_n})和(B_{j_1,\ldots,j_m})之间的张量积创建定义为组合数组(P = A \otimes B)的张量积,定义为
(P_{i_1,\ldots,i_n,j_1,\ldots,j_m} := A_{i_1,\ldots,i_n}\cdot B_{j_1,\ldots,j_m}.)
可通过tensorproduct(...)
获得:
>>> from sympy import Array, tensorproduct
>>> from sympy.abc import x,y,z,t
>>> A = Array([x, y, z, t])
>>> B = Array([1, 2, 3, 4])
>>> tensorproduct(A, B)
[[x, 2*x, 3*x, 4*x], [y, 2*y, 3*y, 4*y], [z, 2*z, 3*z, 4*z], [t, 2*t, 3*t, 4*t]]
如果不想立即计算张量积,可以使用ArrayTensorProduct
,它创建一个未评估的张量积表达式:
>>> from sympy.tensor.array.expressions import ArrayTensorProduct
>>> ArrayTensorProduct(A, B)
ArrayTensorProduct([x, y, z, t], [1, 2, 3, 4])
在ArrayTensorProduct
上调用.as_explicit()
相当于直接调用tensorproduct(...)
:
>>> ArrayTensorProduct(A, B).as_explicit()
[[x, 2*x, 3*x, 4*x], [y, 2*y, 3*y, 4*y], [z, 2*z, 3*z, 4*z], [t, 2*t, 3*t, 4*t]]
秩为 1 的数组与矩阵的张量积创建一个秩为 3 的数组:
>>> from sympy import eye
>>> p1 = tensorproduct(A, eye(4))
>>> p1
[[[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]], [[y, 0, 0, 0], [0, y, 0, 0], [0, 0, y, 0], [0, 0, 0, y]], [[z, 0, 0, 0], [0, z, 0, 0], [0, 0, z, 0], [0, 0, 0, z]], [[t, 0, 0, 0], [0, t, 0, 0], [0, 0, t, 0], [0, 0, 0, t]]]
现在,要获取(A_0 \otimes \mathbf{1}),可以通过切片访问(p_{0,m,n}):
>>> p1[0,:,:]
[[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]]
张量收缩对指定的轴求和,例如收缩位置(a)和(b)意味着
(A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies \sum_k A_{i_1,\ldots,k,\ldots,k,\ldots,i_n})
请记住,Python 索引从零开始,因此要收缩第 a 和第 b 个轴,需要指定(a-1)和(b-1)
>>> from sympy import tensorcontraction
>>> C = Array([[x, y], [z, t]])
矩阵的迹等价于一个秩为 2 的数组的收缩:
(A_{m,n} \implies \sum_k A_{k,k})
>>> tensorcontraction(C, (0, 1))
t + x
要创建一个表示不立即评估的张量收缩的表达式,请使用ArrayContraction
,如果跟随.as_explicit()
,则等效于tensorcontraction(...)
:
>>> from sympy.tensor.array.expressions import ArrayContraction
>>> ArrayContraction(C, (0, 1))
ArrayContraction([[x, y], [z, t]], (0, 1))
>>> ArrayContraction(C, (0, 1)).as_explicit()
t + x
矩阵乘积等价于两个秩为 2 的数组的张量积,然后收缩第 2 和第 3 个轴(在 Python 中索引轴号为 1、2)。
(A_{m,n}\cdot B_{i,j} \implies \sum_k A_{m, k}\cdot B_{k, j})
>>> D = Array([[2, 1], [0, -1]])
>>> tensorcontraction(tensorproduct(C, D), (1, 2))
[[2*x, x - y], [2*z, -t + z]]
可以验证矩阵乘积是等价的:
>>> from sympy import Matrix
>>> Matrix([[x, y], [z, t]])*Matrix([[2, 1], [0, -1]])
Matrix([
[2*x, x - y],
[2*z, -t + z]])
或者等价地
>>> C.tomatrix()*D.tomatrix()
Matrix([
[2*x, x - y],
[2*z, -t + z]])
对角线操作符
tensordiagonal
函数的行为方式与 tensorcontraction
类似,但连接的索引不进行求和,例如对位置 (a) 和 (b) 进行对角化意味着
(A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies A_{i_1,\ldots,k,\ldots,k,\ldots,i_n} \implies \tilde{A}{i_1,\ldots,i,i_{a+1},\ldots,i_{b-1},i_{b+1},\ldots,i_n,k})
其中 (\tilde{A}) 是在位置 (a) 和 (b) 移动到最后索引位置的 (A) 的对角化数组等价物。
比较收缩和对角运算符之间的差异:
>>> from sympy import tensordiagonal
>>> from sympy.abc import a, b, c, d
>>> m = Matrix([[a, b], [c, d]])
>>> tensorcontraction(m, [0, 1])
a + d
>>> tensordiagonal(m, [0, 1])
[a, d]
简而言之,tensordiagonal
不会对加和进行求和。
通过数组导数
常规的导数操作可以扩展到支持对数组进行导数,前提是该数组中的所有元素都是符号或适合导数计算的表达式。
由数组定义的导数如下:给定数组 (A_{i_1, \ldots, i_N}) 和数组 (X_{j_1, \ldots, j_M}),数组的导数将返回由新数组 (B) 定义的新数组
(B_{j_1,\ldots,j_M,i_1,\ldots,i_N} := \frac{\partial A_{i_1,\ldots,i_N}}{\partial X_{j_1,\ldots,j_M}})
函数 derive_by_array
执行这样的操作:
>>> from sympy import derive_by_array
>>> from sympy.abc import x, y, z, t
>>> from sympy import sin, exp
对标量而言,其行为与普通导数完全相同:
>>> derive_by_array(sin(x*y), x)
y*cos(x*y)
标量由数组基础推导:
>>> derive_by_array(sin(x*y), [x, y, z])
[y*cos(x*y), x*cos(x*y), 0]
通过数组基础进行的导数:(B^{nm} := \frac{\partial A^m}{\partial x^n})
>>> basis = [x, y, z]
>>> ax = derive_by_array([exp(x), sin(y*z), t], basis)
>>> ax
[[exp(x), 0, 0], [0, z*cos(y*z), 0], [0, y*cos(y*z), 0]]
收缩结果数组:(\sum_m \frac{\partial A^m}{\partial x^m})
>>> tensorcontraction(ax, (0, 1))
z*cos(y*z) + exp(x)
类:
class sympy.tensor.array.ImmutableDenseNDimArray(iterable, shape=None, **kwargs)
class sympy.tensor.array.ImmutableSparseNDimArray(iterable=None, shape=None, **kwargs)
class sympy.tensor.array.MutableDenseNDimArray(iterable=None, shape=None, **kwargs)
class sympy.tensor.array.MutableSparseNDimArray(iterable=None, shape=None, **kwargs)
函数:
sympy.tensor.array.derive_by_array(expr, dx)
由数组导数。支持数组和标量。
数组表达式的等价运算符是 array_derive
。
解释
给定数组 (A_{i_1, \ldots, i_N}) 和数组 (X_{j_1, \ldots, j_M}),此函数将返回由新数组 (B) 定义的新数组
(B_{j_1,\ldots,j_M,i_1,\ldots,i_N} := \frac{\partial A_{i_1,\ldots,i_N}}{\partial X_{j_1,\ldots,j_M}})
示例:
>>> from sympy import derive_by_array
>>> from sympy.abc import x, y, z, t
>>> from sympy import cos
>>> derive_by_array(cos(x*t), x)
-t*sin(t*x)
>>> derive_by_array(cos(x*t), [x, y, z, t])
[-t*sin(t*x), 0, 0, -x*sin(t*x)]
>>> derive_by_array([x, y**2*z], [[x, y], [z, t]])
[[[1, 0], [0, 2*y*z]], [[0, y**2], [0, 0]]]
sympy.tensor.array.permutedims(expr, perm=None, index_order_old=None, index_order_new=None)
对数组的索引进行排列。
参数指定索引的排列。
数组表达式的等价运算符是 PermuteDims
,可用于保持表达式不被求值。
示例:
>>> from sympy.abc import x, y, z, t
>>> from sympy import sin
>>> from sympy import Array, permutedims
>>> a = Array([[x, y, z], [t, sin(x), 0]])
>>> a
[[x, y, z], [t, sin(x), 0]]
>>> permutedims(a, (1, 0))
[[x, t], [y, sin(x)], [z, 0]]
如果数组是二阶的,可以使用 transpose
:
>>> from sympy import transpose
>>> transpose(a)
[[x, t], [y, sin(x)], [z, 0]]
高维度的示例:
>>> b = Array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
>>> permutedims(b, (2, 1, 0))
[[[1, 5], [3, 7]], [[2, 6], [4, 8]]]
>>> permutedims(b, (1, 2, 0))
[[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
指定与前几行相同排列的另一种方法是将旧和新索引作为列表或字符串传递:
>>> permutedims(b, index_order_old="cba", index_order_new="abc")
[[[1, 5], [3, 7]], [[2, 6], [4, 8]]]
>>> permutedims(b, index_order_old="cab", index_order_new="abc")
[[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
Permutation
对象也是允许的:
>>> from sympy.combinatorics import Permutation
>>> permutedims(b, Permutation([1, 2, 0]))
[[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
另请参阅:
sympy.tensor.array.expressions.array_expressions.PermuteDims
sympy.tensor.array.tensorcontraction(array, *contraction_axes)
在指定轴上收缩类似数组对象。
数组表达式的等价运算符是 ArrayContraction
,可用于保持表达式不被求值。
示例:
>>> from sympy import Array, tensorcontraction
>>> from sympy import Matrix, eye
>>> tensorcontraction(eye(3), (0, 1))
3
>>> A = Array(range(18), (3, 2, 3))
>>> A
[[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]], [[12, 13, 14], [15, 16, 17]]]
>>> tensorcontraction(A, (0, 2))
[21, 30]
可以通过适当的 tensorcontraction
和 tensorproduct
组合来模拟矩阵乘法
>>> from sympy import tensorproduct
>>> from sympy.abc import a,b,c,d,e,f,g,h
>>> m1 = Matrix([[a, b], [c, d]])
>>> m2 = Matrix([[e, f], [g, h]])
>>> p = tensorproduct(m1, m2)
>>> p
[[[[a*e, a*f], [a*g, a*h]], [[b*e, b*f], [b*g, b*h]]], [[[c*e, c*f], [c*g, c*h]], [[d*e, d*f], [d*g, d*h]]]]
>>> tensorcontraction(p, (1, 2))
[[a*e + b*g, a*f + b*h], [c*e + d*g, c*f + d*h]]
>>> m1*m2
Matrix([
[a*e + b*g, a*f + b*h],
[c*e + d*g, c*f + d*h]])
另请参阅:
sympy.tensor.array.expressions.array_expressions.ArrayContraction
sympy.tensor.array.tensorproduct(*args)
标量或类数组对象之间的张量积。
数组表达式的等效运算符是ArrayTensorProduct
,可以用来保持表达式不求值。
示例
>>> from sympy.tensor.array import tensorproduct, Array
>>> from sympy.abc import x, y, z, t
>>> A = Array([[1, 2], [3, 4]])
>>> B = Array([x, y])
>>> tensorproduct(A, B)
[[[x, y], [2*x, 2*y]], [[3*x, 3*y], [4*x, 4*y]]]
>>> tensorproduct(A, x)
[[x, 2*x], [3*x, 4*x]]
>>> tensorproduct(A, B, B)
[[[[x**2, x*y], [x*y, y**2]], [[2*x**2, 2*x*y], [2*x*y, 2*y**2]]], [[[3*x**2, 3*x*y], [3*x*y, 3*y**2]], [[4*x**2, 4*x*y], [4*x*y, 4*y**2]]]]
在两个矩阵上应用此函数将导致一个秩为 4 的数组。
>>> from sympy import Matrix, eye
>>> m = Matrix([[x, y], [z, t]])
>>> p = tensorproduct(eye(3), m)
>>> p
[[[[x, y], [z, t]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[x, y], [z, t]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[x, y], [z, t]]]]
参见
sympy.tensor.array.expressions.array_expressions.ArrayTensorProduct
sympy.tensor.array.tensordiagonal(array, *diagonal_axes)
对指定轴上的类数组对象进行对角化。
这相当于将表达式乘以克罗内克三角形单位化的轴。
对角线索引被放在轴的末尾。
数组表达式的等效运算符是ArrayDiagonal
,可以用来保持表达式不求值。
示例
tensordiagonal
对二维数组的轴 0 和 1 的作用等效于矩阵的对角线:
>>> from sympy import Array, tensordiagonal
>>> from sympy import Matrix, eye
>>> tensordiagonal(eye(3), (0, 1))
[1, 1, 1]
>>> from sympy.abc import a,b,c,d
>>> m1 = Matrix([[a, b], [c, d]])
>>> tensordiagonal(m1, [0, 1])
[a, d]
对于高维数组,被对角化的维度将被追加移除,并作为最后的单一维度追加:
>>> A = Array(range(18), (3, 2, 3))
>>> A
[[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]], [[12, 13, 14], [15, 16, 17]]]
>>> tensordiagonal(A, (0, 2))
[[0, 7, 14], [3, 10, 17]]
>>> from sympy import permutedims
>>> tensordiagonal(A, (0, 2)) == permutedims(Array([A[0, :, 0], A[1, :, 1], A[2, :, 2]]), [1, 0])
True
参见
sympy.tensor.array.expressions.array_expressions.ArrayDiagonal
N 维数组表达式
原文链接:
docs.sympy.org/latest/modules/tensor/array_expressions.html
数组表达式是表示 N 维数组的表达式,而不对它们进行评估。这些表达式以某种方式表示对 N 维数组的操作的抽象语法树。
每个 N 维数组运算符都有对应的数组表达式对象。
对应表:
Array operator | Array expression operator |
---|---|
tensorproduct | ArrayTensorProduct |
tensorcontraction | ArrayContraction |
tensordiagonal | ArrayDiagonal |
permutedims | PermuteDims |
示例
ArraySymbol
对象是矩阵模块中 MatrixSymbol
对象的 N 维等效物。
>>> from sympy.tensor.array.expressions import ArraySymbol
>>> from sympy.abc import i, j, k
>>> A = ArraySymbol("A", (3, 2, 4))
>>> A.shape
(3, 2, 4)
>>> A[i, j, k]
A[i, j, k]
>>> A.as_explicit()
[[[A[0, 0, 0], A[0, 0, 1], A[0, 0, 2], A[0, 0, 3]],
[A[0, 1, 0], A[0, 1, 1], A[0, 1, 2], A[0, 1, 3]]],
[[A[1, 0, 0], A[1, 0, 1], A[1, 0, 2], A[1, 0, 3]],
[A[1, 1, 0], A[1, 1, 1], A[1, 1, 2], A[1, 1, 3]]],
[[A[2, 0, 0], A[2, 0, 1], A[2, 0, 2], A[2, 0, 3]],
[A[2, 1, 0], A[2, 1, 1], A[2, 1, 2], A[2, 1, 3]]]]
在数组表达式中可以添加组件明确的数组:
>>> from sympy import Array
>>> from sympy import tensorproduct
>>> from sympy.tensor.array.expressions import ArrayTensorProduct
>>> a = Array([1, 2, 3])
>>> b = Array([i, j, k])
>>> expr = ArrayTensorProduct(a, b, b)
>>> expr
ArrayTensorProduct([1, 2, 3], [i, j, k], [i, j, k])
>>> expr.as_explicit() == tensorproduct(a, b, b)
True
从索引明确形式构建数组表达式
数组表达式是索引隐式的。这意味着它们不使用任何索引来表示数组操作。函数 convert_indexed_to_array( ... )
可以用来将索引明确的表达式转换为数组表达式。它接受两个参数作为输入:索引明确表达式和索引的顺序:
>>> from sympy.tensor.array.expressions import convert_indexed_to_array
>>> from sympy import Sum
>>> A = ArraySymbol("A", (3, 3))
>>> B = ArraySymbol("B", (3, 3))
>>> convert_indexed_to_array(A[i, j], [i, j])
A
>>> convert_indexed_to_array(A[i, j], [j, i])
PermuteDims(A, (0 1))
>>> convert_indexed_to_array(A[i, j] + B[j, i], [i, j])
ArrayAdd(A, PermuteDims(B, (0 1)))
>>> convert_indexed_to_array(Sum(A[i, j]*B[j, k], (j, 0, 2)), [i, k])
ArrayContraction(ArrayTensorProduct(A, B), (1, 2))
矩阵的数组表达式形式的对角线:
>>> convert_indexed_to_array(A[i, i], [i])
ArrayDiagonal(A, (0, 1))
矩阵的数组表达式形式的迹:
>>> convert_indexed_to_array(Sum(A[i, i], (i, 0, 2)), [i])
ArrayContraction(A, (0, 1))
与矩阵的兼容性
数组表达式可以与矩阵模块中的对象混合使用:
>>> from sympy import MatrixSymbol
>>> from sympy.tensor.array.expressions import ArrayContraction
>>> M = MatrixSymbol("M", 3, 3)
>>> N = MatrixSymbol("N", 3, 3)
在数组表达式形式中表示矩阵乘积:
>>> from sympy.tensor.array.expressions import convert_matrix_to_array
>>> expr = convert_matrix_to_array(M*N)
>>> expr
ArrayContraction(ArrayTensorProduct(M, N), (1, 2))
可以将表达式转换回矩阵形式:
>>> from sympy.tensor.array.expressions import convert_array_to_matrix
>>> convert_array_to_matrix(expr)
M*N
在剩余的轴上添加第二次收缩以获得 (M \cdot N) 的迹:
>>> expr_tr = ArrayContraction(expr, (0, 1))
>>> expr_tr
ArrayContraction(ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), (0, 1))
通过调用 .doit()
展开表达式并移除嵌套的数组收缩操作:
>>> expr_tr.doit()
ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2))
获取数组表达式的显式形式:
>>> expr.as_explicit()
[[M[0, 0]*N[0, 0] + M[0, 1]*N[1, 0] + M[0, 2]*N[2, 0], M[0, 0]*N[0, 1] + M[0, 1]*N[1, 1] + M[0, 2]*N[2, 1], M[0, 0]*N[0, 2] + M[0, 1]*N[1, 2] + M[0, 2]*N[2, 2]],
[M[1, 0]*N[0, 0] + M[1, 1]*N[1, 0] + M[1, 2]*N[2, 0], M[1, 0]*N[0, 1] + M[1, 1]*N[1, 1] + M[1, 2]*N[2, 1], M[1, 0]*N[0, 2] + M[1, 1]*N[1, 2] + M[1, 2]*N[2, 2]],
[M[2, 0]*N[0, 0] + M[2, 1]*N[1, 0] + M[2, 2]*N[2, 0], M[2, 0]*N[0, 1] + M[2, 1]*N[1, 1] + M[2, 2]*N[2, 1], M[2, 0]*N[0, 2] + M[2, 1]*N[1, 2] + M[2, 2]*N[2, 2]]]
在数组表达式形式中表示矩阵的迹:
>>> from sympy import Trace
>>> convert_matrix_to_array(Trace(M))
ArrayContraction(M, (0, 1))
>>> convert_matrix_to_array(Trace(M*N))
ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2))
表示矩阵的转置(将表达为轴的排列):
>>> convert_matrix_to_array(M.T)
PermuteDims(M, (0 1))
计算导数数组表达式:
>>> from sympy.tensor.array.expressions import array_derive
>>> d = array_derive(M, M)
>>> d
PermuteDims(ArrayTensorProduct(I, I), (3)(1 2))
验证导数是否与使用明确矩阵计算的形式相对应:
>>> d.as_explicit()
[[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 1, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 1], [0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [1, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 1], [0, 0, 0]]], [[[0, 0, 0], [0, 0, 0], [1, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 1]]]]
>>> Me = M.as_explicit()
>>> Me.diff(Me)
[[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 1, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 1], [0, 0, 0], [0, 0, 0]]], [[[0, 0, 0], [1, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 1], [0, 0, 0]]], [[[0, 0, 0], [0, 0, 0], [1, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 1]]]]
class sympy.tensor.array.expressions.ArrayTensorProduct(*args, **kwargs)
用于表示数组类对象的张量积的类。
class sympy.tensor.array.expressions.ArrayContraction(expr, *contraction_indices, **kwargs)
这个类用来表示数组在代码打印机易于处理的形式中的收缩。
class sympy.tensor.array.expressions.ArrayDiagonal(expr, *diagonal_indices, **kwargs)
用于表示对角线操作符的类。
解释
在二维数组中返回对角线,这看起来像是这样的操作:
(A_{ij} \rightarrow A_{ii})
两个二维数组 (A \otimes B) 的张量积的轴 1 和 2(第二和第三)的对角线是
(\Big[ A_{ab} B_{cd} \Big]{abcd} \rightarrow \Big[ A B_{id} \Big]_{adi})
在这个最后的例子中,数组表达式已从 4 维降至 3 维。请注意,没有进行收缩,而是对对角线引入了新的索引 (i),收缩会将数组降至 2 维。
注意,对角化的维度会添加为新的维度放在索引的末尾。
class sympy.tensor.array.expressions.PermuteDims(expr, permutation=None, index_order_old=None, index_order_new=None, **kwargs)
用于表示数组轴的排列的类。
示例
>>> from sympy.tensor.array import permutedims
>>> from sympy import MatrixSymbol
>>> M = MatrixSymbol("M", 3, 3)
>>> cg = permutedims(M, [1, 0])
对象 cg
表示 M
的转置,如排列 [1, 0]
将通过交换其索引作用于它:
(M_{ij} \Rightarrow M_{ji})
当转换回矩阵形式时,这一点显而易见:
>>> from sympy.tensor.array.expressions.from_array_to_matrix import convert_array_to_matrix
>>> convert_array_to_matrix(cg)
M.T
>>> N = MatrixSymbol("N", 3, 2)
>>> cg = permutedims(N, [1, 0])
>>> cg.shape
(2, 3)
有可选参数可作为排列的替代品使用:
>>> from sympy.tensor.array.expressions import ArraySymbol, PermuteDims
>>> M = ArraySymbol("M", (1, 2, 3, 4, 5))
>>> expr = PermuteDims(M, index_order_old="ijklm", index_order_new="kijml")
>>> expr
PermuteDims(M, (0 2 1)(3 4))
>>> expr.shape
(3, 1, 2, 5, 4)
张量积的排列被简化,以达到标准形式:
>>> from sympy.tensor.array import tensorproduct
>>> M = MatrixSymbol("M", 4, 5)
>>> tp = tensorproduct(M, N)
>>> tp.shape
(4, 5, 3, 2)
>>> perm1 = permutedims(tp, [2, 3, 1, 0])
参数 (M, N)
已经排序并简化了排列,表达式等效:
>>> perm1.expr.args
(N, M)
>>> perm1.shape
(3, 2, 5, 4)
>>> perm1.permutation
(2 3)
数组形式的排列已从 [2, 3, 1, 0]
简化为 [0, 1, 3, 2]
,因为张量积 (M) 和 (N) 的参数已经交换:
>>> perm1.permutation.array_form
[0, 1, 3, 2]
我们可以嵌套第二个排列:
>>> perm2 = permutedims(perm1, [1, 0, 2, 3])
>>> perm2.shape
(2, 3, 5, 4)
>>> perm2.permutation.array_form
[1, 0, 3, 2]
索引对象
定义索引对象的模块。
类IndexedBase
、Indexed
和Idx
表示矩阵元素M[i, j]
如下图所示:
1) The Indexed class represents the entire indexed object.
|
___|___
' '
M[i, j]
/ \__\______
| |
| |
| 2) The Idx class represents indices; each Idx can
| optionally contain information about its range.
|
3) IndexedBase represents the 'stem' of an indexed object, here `M`.
The stem used by itself is usually taken to represent the entire
array.
Indexed
对象上可以有任意数量的索引。这些基础对象中未实现任何转换属性,但支持重复索引的隐式收缩。
注意,对于复杂(即非原子)整数表达式作为索引的支持有限。(在未来版本中应进行改进。)
示例
要表示上述矩阵元素示例,您可以这样写:
>>> from sympy import symbols, IndexedBase, Idx
>>> M = IndexedBase('M')
>>> i, j = symbols('i j', cls=Idx)
>>> M[i, j]
M[i, j]
乘积中的重复索引意味着求和,因此要使用Indexed
对象来表示矩阵向量乘积:
>>> x = IndexedBase('x')
>>> M[i, j]*x[j]
M[i, j]*x[j]
如果索引对象将转换为基于组件的数组,例如使用代码打印机或自动包装框架,则还需要提供(符号或数值)维度。可以通过在构建IndexedBase
时传递可选的形状参数来完成:
>>> dim1, dim2 = symbols('dim1 dim2', integer=True)
>>> A = IndexedBase('A', shape=(dim1, 2*dim1, dim2))
>>> A.shape
(dim1, 2*dim1, dim2)
>>> A[i, j, 3].shape
(dim1, 2*dim1, dim2)
如果IndexedBase
对象没有形状信息,则假定数组大小与其索引的范围一样大:
>>> n, m = symbols('n m', integer=True)
>>> i = Idx('i', m)
>>> j = Idx('j', n)
>>> M[i, j].shape
(m, n)
>>> M[i, j].ranges
[(0, m - 1), (0, n - 1)]
可与以下进行比较:
>>> A[i, 2, j].shape
(dim1, 2*dim1, dim2)
>>> A[i, 2, j].ranges
[(0, m - 1), None, (0, n - 1)]
要分析索引表达式的结构,可以使用get_indices()
和get_contraction_structure()
方法:
>>> from sympy.tensor import get_indices, get_contraction_structure
>>> get_indices(A[i, j, j])
({i}, {})
>>> get_contraction_structure(A[i, j, j])
{(j,): {A[i, j, j]}}
查看相应的文档字符串以详细了解输出。
class sympy.tensor.indexed.Idx(label, range=None, **kw_args)
表示整数索引作为Integer
或整数表达式。
有多种方法可以创建Idx
对象。构造函数接受两个参数:
label
整数或符号用于标记索引。
range
可选地可以将范围指定为
-
Symbol
或整数:被解释为维度。下界和上界分别设置为0
和range - 1
。 -
tuple
:两个元素分别解释为范围的下限和上限。
注意:范围的边界假定为整数或无穷大(允许使用 oo 和-oo 指定无界范围)。如果边界给定为n
,则n.is_integer
不能返回 false。
为方便起见,如果标签是字符串,则自动转换为整数符号。(注意:不会对范围或维度参数进行此转换。)
示例
>>> from sympy import Idx, symbols, oo
>>> n, i, L, U = symbols('n i L U', integer=True)
如果标签是字符串,则创建一个整数Symbol
,且边界都是None
:
>>> idx = Idx('qwerty'); idx
qwerty
>>> idx.lower, idx.upper
(None, None)
可以指定上界和下界:
>>> idx = Idx(i, (L, U)); idx
i
>>> idx.lower, idx.upper
(L, U)
当只给出单个边界时,它被解释为维度,下界默认为 0:
>>> idx = Idx(i, n); idx.lower, idx.upper
(0, n - 1)
>>> idx = Idx(i, 4); idx.lower, idx.upper
(0, 3)
>>> idx = Idx(i, oo); idx.lower, idx.upper
(0, oo)
property label
返回Idx
对象的标签(整数或整数表达式)。
示例
>>> from sympy import Idx, Symbol
>>> x = Symbol('x', integer=True)
>>> Idx(x).label
x
>>> j = Symbol('j', integer=True)
>>> Idx(j).label
j
>>> Idx(j + 1).label
j + 1
property lower
返回Idx
的下界。
示例
>>> from sympy import Idx
>>> Idx('j', 2).lower
0
>>> Idx('j', 5).lower
0
>>> Idx('j').lower is None
True
property upper
返回Idx
的上界。
示例
>>> from sympy import Idx
>>> Idx('j', 2).upper
1
>>> Idx('j', 5).upper
4
>>> Idx('j').upper is None
True
class sympy.tensor.indexed.Indexed(base, *args, **kw_args)
表示具有索引的数学对象。
>>> from sympy import Indexed, IndexedBase, Idx, symbols
>>> i, j = symbols('i j', cls=Idx)
>>> Indexed('A', i, j)
A[i, j]
建议通过索引IndexedBase
创建Indexed
对象:IndexedBase('A')[i, j]
而不是Indexed(IndexedBase('A'), i, j)
。
>>> A = IndexedBase('A')
>>> a_ij = A[i, j] # Prefer this,
>>> b_ij = Indexed(A, i, j) # over this.
>>> a_ij == b_ij
True
property base
返回Indexed
对象的IndexedBase
。
示例
>>> from sympy import Indexed, IndexedBase, Idx, symbols
>>> i, j = symbols('i j', cls=Idx)
>>> Indexed('A', i, j).base
A
>>> B = IndexedBase('B')
>>> B == B[i, j].base
True
property indices
返回 Indexed
对象的索引。
示例
>>> from sympy import Indexed, Idx, symbols
>>> i, j = symbols('i j', cls=Idx)
>>> Indexed('A', i, j).indices
(i, j)
property ranges
返回带有每个索引的下限和上限范围的元组列表。
如果索引未定义数据成员的上限和下限,则列表中的相应位置包含None
而不是元组。
示例
>>> from sympy import Indexed,Idx, symbols
>>> Indexed('A', Idx('i', 2), Idx('j', 4), Idx('k', 8)).ranges
[(0, 1), (0, 3), (0, 7)]
>>> Indexed('A', Idx('i', 3), Idx('j', 3), Idx('k', 3)).ranges
[(0, 2), (0, 2), (0, 2)]
>>> x, y, z = symbols('x y z', integer=True)
>>> Indexed('A', x, y, z).ranges
[None, None, None]
property rank
返回 Indexed
对象的秩。
示例
>>> from sympy import Indexed, Idx, symbols
>>> i, j, k, l, m = symbols('i:m', cls=Idx)
>>> Indexed('A', i, j).rank
2
>>> q = Indexed('A', i, j, k, l, m)
>>> q.rank
5
>>> q.rank == len(q.indices)
True
property shape
返回每个索引的维度列表。
维度是数组的属性,而不是索引的属性。但是,如果 IndexedBase
未定义形状属性,则假定索引的范围对应于数组的形状。
>>> from sympy import IndexedBase, Idx, symbols
>>> n, m = symbols('n m', integer=True)
>>> i = Idx('i', m)
>>> j = Idx('j', m)
>>> A = IndexedBase('A', shape=(n, n))
>>> B = IndexedBase('B')
>>> A[i, j].shape
(n, n)
>>> B[i, j].shape
(m, m)
class sympy.tensor.indexed.IndexedBase(label, shape=None, *, offset=0, strides=None, **kw_args)
表示索引对象的基础或干扰
IndexedBase
类表示一个包含元素的数组。该类的主要目的是允许方便地创建 Indexed
类的对象。IndexedBase
的__getitem__
方法返回 Indexed
的实例。单独使用,即没有索引,IndexedBase
类可以用作例如矩阵方程的标记,类似于使用 Symbol
类可以做的事情。但是,IndexedBase
类增加了 Symbol
实例不可用的功能:
IndexedBase
对象可以选择性地存储形状信息。这可用于检查数组的一致性和 numpy 广播的条件。(TODO)IndexedBase
对象实现了语法糖,允许使用重复索引的隐式求和来轻松表示数组操作。IndexedBase
对象象征着一个数学结构,相当于数组,因此被用于代码生成和自动编译和包装。
>>> from sympy.tensor import IndexedBase, Idx
>>> from sympy import symbols
>>> A = IndexedBase('A'); A
A
>>> type(A)
<class 'sympy.tensor.indexed.IndexedBase'>
当 IndexedBase
对象接收到索引时,它返回一个带有命名轴的数组,由 Indexed
对象表示:
>>> i, j = symbols('i j', integer=True)
>>> A[i, j, 2]
A[i, j, 2]
>>> type(A[i, j, 2])
<class 'sympy.tensor.indexed.Indexed'>
IndexedBase
构造函数接受一个可选的形状参数。如果给定,则会覆盖索引中的任何形状信息。(但不覆盖索引范围!)
>>> m, n, o, p = symbols('m n o p', integer=True)
>>> i = Idx('i', m)
>>> j = Idx('j', n)
>>> A[i, j].shape
(m, n)
>>> B = IndexedBase('B', shape=(o, p))
>>> B[i, j].shape
(o, p)
假设可以与关键字参数一起指定,方式与 Symbol
相同:
>>> A_real = IndexedBase('A', real=True)
>>> A_real.is_real
True
>>> A != A_real
True
假设也可以通过使用 Symbol
初始化 IndexedBase
来继承:
>>> I = symbols('I', integer=True)
>>> C_inherit = IndexedBase(I)
>>> C_explicit = IndexedBase('I', integer=True)
>>> C_inherit == C_explicit
True
property label
返回 IndexedBase
对象的标签。
示例
>>> from sympy import IndexedBase
>>> from sympy.abc import x, y
>>> IndexedBase('A', shape=(x, y)).label
A
property offset
返回 IndexedBase
对象的偏移量。
当将 2D Indexed
对象展开为 1D 形式时,添加到结果索引的值。用于代码生成。
示例
>>> from sympy.printing import ccode
>>> from sympy.tensor import IndexedBase, Idx
>>> from sympy import symbols
>>> l, m, n, o = symbols('l m n o', integer=True)
>>> A = IndexedBase('A', strides=(l, m, n), offset=o)
>>> i, j, k = map(Idx, 'ijk')
>>> ccode(A[i, j, k])
'A[l*i + m*j + n*k + o]'
property shape
返回 IndexedBase
对象的形状。
示例
>>> from sympy import IndexedBase, Idx
>>> from sympy.abc import x, y
>>> IndexedBase('A', shape=(x, y)).shape
(x, y)
注意:如果指定了 IndexedBase
的形状,它将覆盖索引给出的任何形状信息。
>>> A = IndexedBase('A', shape=(x, y))
>>> B = IndexedBase('B')
>>> i = Idx('i', 2)
>>> j = Idx('j', 1)
>>> A[i, j].shape
(x, y)
>>> B[i, j].shape
(2, 1)
property strides
返回 IndexedBase
对象的步进方案。
通常,这是一个元组,表示遍历数组时在相应维度上要采取的步数。为了代码生成的目的,也可以使用 strides='C'
和 strides='F'
。
strides='C'
意味着代码打印器将按行主序展开,而'F'
表示按列主序展开。
方法
原文链接:
docs.sympy.org/latest/modules/tensor/index_methods.html
包含对 IndexedBase、Indexed 和 Idx 对象操作的模块
-
检查形状符合度
-
确定结果表达式中的索引
等等。
此模块中的方法可以通过调用 Expr 对象上的方法来实现。当事物稳定下来时,这可能是一个有用的重构。
sympy.tensor.index_methods.get_contraction_structure(expr)
确定expr
的虚指数并描述其结构
通过dummy,我们指的是求和索引。
表达式的结构如下确定并描述:
-
描述了 Indexed 对象的符合求和,其中键是求和索引,相应的值是所有适用求和的项的集合。SymPy 表达式树中的所有 Add 对象都是这样描述的。
-
对于 SymPy 表达式树中所有不是 Add 类型的节点,适用以下规则:
如果节点发现其参数中有缩并,则该节点本身将作为字典中的一个键存储。对于该键,相应的值是一个字典列表,每个字典是对 get_contraction_structure()递归调用的结果。该列表仅包含非平凡深层次缩并的字典,省略了只有一个键为 None 的字典。
注意
字典键中包含的表达式表示了多级索引缩并。嵌套字典显示了嵌套缩并,并可能包含来自更深层级的字典。在实际计算中,必须首先计算最深层嵌套级别的求和,以便外部表达式可以访问生成的索引对象。
示例
>>> from sympy.tensor.index_methods import get_contraction_structure
>>> from sympy import default_sort_key
>>> from sympy.tensor import IndexedBase, Idx
>>> x, y, A = map(IndexedBase, ['x', 'y', 'A'])
>>> i, j, k, l = map(Idx, ['i', 'j', 'k', 'l'])
>>> get_contraction_structure(x[i]*y[i] + A[j, j])
{(i,): {x[i]*y[i]}, (j,): {A[j, j]}}
>>> get_contraction_structure(x[i]*y[j])
{None: {x[i]*y[j]}}
缩并因子的乘积导致表示内部缩并的嵌套字典。
>>> d = get_contraction_structure(x[i, i]*y[j, j])
>>> sorted(d.keys(), key=default_sort_key)
[None, x[i, i]*y[j, j]]
在这种情况下,产品没有缩并:
>>> d[None]
{x[i, i]*y[j, j]}
因子首先进行缩并:
>>> sorted(d[x[i, i]*y[j, j]], key=default_sort_key)
[{(i,): {x[i, i]}}, {(j,): {y[j, j]}}]
带括号的 Add 对象也作为嵌套字典返回。括号内的项是包含参数之间缩并的 Mul,因此它将作为结果中的键。它存储了对 Add 表达式进行递归调用后得到的字典。
>>> d = get_contraction_structure(x[i]*(y[i] + A[i, j]*x[j]))
>>> sorted(d.keys(), key=default_sort_key)
[(A[i, j]*x[j] + y[i])*x[i], (i,)]
>>> d[(i,)]
{(A[i, j]*x[j] + y[i])*x[i]}
>>> d[x[i]*(A[i, j]*x[j] + y[i])]
[{None: {y[i]}, (j,): {A[i, j]*x[j]}}]
在底数或指数中具有缩并的幂也将作为字典中的键,映射到来自递归调用的结果列表:
>>> d = get_contraction_structure(A[j, j]**A[i, i])
>>> d[None]
{A[j, j]**A[i, i]}
>>> nested_contractions = d[A[j, j]**A[i, i]]
>>> nested_contractions[0]
{(j,): {A[j, j]}}
>>> nested_contractions[1]
{(i,): {A[i, i]}}
上述示例中用字符串表示的缩并结构描述可能看起来很复杂,但迭代处理起来很容易:
>>> from sympy import Expr
>>> for key in d:
... if isinstance(key, Expr):
... continue
... for term in d[key]:
... if term in d:
... # treat deepest contraction first
... pass
... # treat outermost contactions here
sympy.tensor.index_methods.get_indices(expr)
确定表达式expr
的外部索引。
通过outer,我们指的是非求和索引。返回一个集合和一个字典。集合包含外部索引,字典包含索引对称性的信息。
示例
>>> from sympy.tensor.index_methods import get_indices
>>> from sympy import symbols
>>> from sympy.tensor import IndexedBase
>>> x, y, A = map(IndexedBase, ['x', 'y', 'A'])
>>> i, j, a, z = symbols('i j a z', integer=True)
确定总表达式的索引,重复的索引意味着求和,例如矩阵 A 的迹:
>>> get_indices(A[i, i])
(set(), {})
在多项式情况下,要求项具有相同的外部索引。否则将引发 IndexConformanceException 异常。
>>> get_indices(x[i] + A[i, j]*y[j])
({i}, {})
异常:
IndexConformanceException
表示术语不兼容,例如。
>>> get_indices(x[i] + y[j])
(...)
IndexConformanceException: Indices are not consistent: x(i) + y(j)
警告
外部指数的概念递归应用,从最深层开始。这意味着括号内部的虚数被假定首先求和,以便优雅地处理以下表达式:
>>> get_indices((x[i] + A[i, j]*y[j])*x[j])
({i, j}, {})
这是正确的,可能看起来方便,但你需要小心,因为如果要求,SymPy 会愉快地.expand()
这个乘积。结果表达式将混合外部的j
与括号内部的虚数,使其成为不同的表达式。为了安全起见,最好通过为所有应分开的收缩使用唯一的指数来避免这种模棱两可的情况。
张量
class sympy.tensor.tensor.TensorIndexType(name, dummy_name=None, dim=None, eps_dim=None, metric_symmetry=1, metric_name='metric', **kwargs)
张量指标类型由其名称和度规确定。
参数:
name:张量类型的名称
dummy_name:虚指标的头部名称
dim:维度,可以是符号、整数或 None
eps_dim:epsilon
张量的维度
metric_symmetry:表示度规对称性的整数或 None
表示无度规
metric_name:度规张量的名称字符串
注意
metric_symmetry
参数的可能值为:
1
:度规张量完全对称0
:度规张量没有指标对称性-1
:度规张量完全反对称None
:没有度规张量(度规等于None
)
默认情况下,度规假定为对称的。也可以通过 .set_metric()
方法设置自定义张量。
如果有度规,则使用度规来提升和降低指标。
在非对称度规的情况下,将采用以下提升和降低约定:
psi(a) = g(a, b)*psi(-b); chi(-a) = chi(b)*g(-b, -a)
由此可以轻松找到:
g(-a, b) = delta(-a, b)
其中 delta(-a, b) = delta(b, -a)
是 Kronecker delta
(参见 TensorIndex
关于指标约定)。对于反对称度规,还有以下等式:
g(a, -b) = -delta(a, -b)
如果没有度规,则无法提升或降低指标;例如,SU(N)
的定义表示的指标是“协变的”,共轭表示是“逆变的”;对于 N > 2
,它们是线性独立的。
如果 dim
是整数,则 eps_dim
默认等于 dim
;否则可以分配(用于简单的尺寸正规化);如果 eps_dim
不是整数,则 epsilon
为 None
。
示例
>>> from sympy.tensor.tensor import TensorIndexType
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> Lorentz.metric
metric(Lorentz,Lorentz)
属性
metric |
(度规张量) |
---|---|
delta |
(Kronecker delta ) |
epsilon |
(Levi-Civita epsilon 张量) |
data |
((已弃用) 用于在指定基础上添加 ndarray 值的属性) |
class sympy.tensor.tensor.TensorIndex(name, tensor_index_type, is_up=True)
表示张量指标
参数:
name:指标的名称,或者 True
表示自动分配
tensor_index_type:指标的 TensorIndexType
is_up:逆变指标的标志(默认为 True
)
注意
张量指标遵循爱因斯坦求和约定进行缩并。
指标可以是逆变形式或协变形式;在后一种情况下,索引名称前加 -
。向协变(is_up=False
)索引添加 -
使其变为逆变。
虚指标的名称默认为 tensor_inde_type.dummy_name
,后跟下划线和数字。
类似于 symbols
,可以使用 tensor_indices(s, typ)
一次创建多个逆变指标,其中 s
是名称字符串。
示例
>>> from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorHead, tensor_indices
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> mu = TensorIndex('mu', Lorentz, is_up=False)
>>> nu, rho = tensor_indices('nu, rho', Lorentz)
>>> A = TensorHead('A', [Lorentz, Lorentz])
>>> A(mu, nu)
A(-mu, nu)
>>> A(-mu, -rho)
A(mu, -rho)
>>> A(mu, -mu)
A(-L_0, L_0)
属性
name |
|
---|---|
tensor_index_type |
|
is_up |
class sympy.tensor.tensor.TensorHead(name, index_types, symmetry=None, comm=0)
张量的张量头。
参数:
name:张量的名称
index_types:TensorIndexType 的列表
symmetry:张量的 TensorSymmetry
comm:对易群号
注意事项
与symbols
类似,可以使用tensorhead(s, typ, sym=None, comm=0)
函数创建多个TensorHead
,其中s
是名称的字符串,sym
是单项张量对称性(参见tensorsymmetry
)。
TensorHead
属于一个对易群,由符号和数字comm
定义(参见_TensorManager.set_comm
);对易群中的张量具有相同的对易性质;默认情况下,comm
为0
,表示对易张量的群。
示例
定义一个完全反对称的二阶张量:
>>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> asym2 = TensorSymmetry.fully_symmetric(-2)
>>> A = TensorHead('A', [Lorentz, Lorentz], asym2)
示例中使用 ndarray 值,假定分配给TensorHead
对象的组件数据处于完全逆变表示。如果需要分配表示非完全协变张量值的组件数据,请参阅其他示例。
>>> from sympy.tensor.tensor import tensor_indices
>>> from sympy import diag
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> i0, i1 = tensor_indices('i0:2', Lorentz)
指定一个替换字典以跟踪在张量表达式中使用的数组进行替换。TensorIndexType
与用于缩并的度规相关联(以完全协变形式):
>>> repl = {Lorentz: diag(1, -1, -1, -1)}
让我们看一些与电磁张量的组件一起工作的示例:
>>> from sympy import symbols
>>> Ex, Ey, Ez, Bx, By, Bz = symbols('E_x E_y E_z B_x B_y B_z')
>>> c = symbols('c', positive=True)
让我们定义(F),一个反对称张量:
>>> F = TensorHead('F', [Lorentz, Lorentz], asym2)
让我们更新字典,包含用于替换的矩阵:
>>> repl.update({F(-i0, -i1): [
... [0, Ex/c, Ey/c, Ez/c],
... [-Ex/c, 0, -Bz, By],
... [-Ey/c, Bz, 0, -Bx],
... [-Ez/c, -By, Bx, 0]]})
现在可以检索电磁张量的逆变形式:
>>> F(i0, i1).replace_with_arrays(repl, [i0, i1])
[[0, -E_x/c, -E_y/c, -E_z/c], [E_x/c, 0, -B_z, B_y], [E_y/c, B_z, 0, -B_x], [E_z/c, -B_y, B_x, 0]]
和混合的逆变-协变形式:
>>> F(i0, -i1).replace_with_arrays(repl, [i0, -i1])
[[0, E_x/c, E_y/c, E_z/c], [E_x/c, 0, B_z, -B_y], [E_y/c, -B_z, 0, B_x], [E_z/c, B_y, -B_x, 0]]
粒子的能量-动量可以表示为:
>>> from sympy import symbols
>>> P = TensorHead('P', [Lorentz], TensorSymmetry.no_symmetry(1))
>>> E, px, py, pz = symbols('E p_x p_y p_z', positive=True)
>>> repl.update({P(i0): [E, px, py, pz]})
分别是逆变和协变分量:
>>> P(i0).replace_with_arrays(repl, [i0])
[E, p_x, p_y, p_z]
>>> P(-i0).replace_with_arrays(repl, [-i0])
[E, -p_x, -p_y, -p_z]
1-索引张量的收缩:
>>> expr = P(i0)*P(-i0)
>>> expr.replace_with_arrays(repl, [])
E**2 - p_x**2 - p_y**2 - p_z**2
属性
name |
|
---|---|
index_types |
|
rank |
(索引的总数) |
symmetry |
|
comm |
(对易群) |
commutes_with(other)
如果self
和other
对易,则返回0
,如果它们反对易,则返回1
。
如果self
和other
既不对易也不反对易,则返回None
。
sympy.tensor.tensor.tensor_heads(s, index_types, symmetry=None, comm=0)
从字符串(s)返回一系列TensorHead
class sympy.tensor.tensor.TensExpr(*args)
张量表达式的抽象基类
注意事项
张量表达式是由张量形成的表达式;目前将张量的和分布开来。
TensExpr
可以是TensAdd
或TensMul
。
TensMul
对象由分量张量的乘积组成,并包括一个系数,这是一个 SymPy 表达式。
在内部表示中,收缩的指标由(ipos1, ipos2, icomp1, icomp2)
表示,其中icomp1
是具有逆变指标的分量张量的位置,ipos1
是该分量张量中指标所占的插槽。
因此,在内部表示中,收缩的指标是无名的。
get_matrix()
已弃用:请勿使用。
如果组件数据可用且 ndarray 维度不超过 2,则返回 ndarray 组件数据作为矩阵。
replace_with_arrays(replacement_dict, indices=None)
用数组替换张量表达式。最终的数组将对应于按照indices
排列的 N 维数组。
参数:
replacement_dict
包含张量替换规则的字典。
indices
与该数组读取相关的索引顺序。如果未传递任何值,则将使用原始索引顺序。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices
>>> from sympy.tensor.tensor import TensorHead
>>> from sympy import symbols, diag
>>> L = TensorIndexType("L")
>>> i, j = tensor_indices("i j", L)
>>> A = TensorHead("A", [L])
>>> A(i).replace_with_arrays({A(i): [1, 2]}, [i])
[1, 2]
由于‘indices’是可选的,因此如果不需要特定的索引顺序,我们也可以通过这种方式调用 replace_with_arrays:
>>> A(i).replace_with_arrays({A(i): [1, 2]})
[1, 2]
>>> expr = A(i)*A(j)
>>> expr.replace_with_arrays({A(i): [1, 2]})
[[1, 2], [2, 4]]
对于缩并,指定TensorIndexType
的度量L
的协变形式:
>>> expr = A(i)*A(-i)
>>> expr.replace_with_arrays({A(i): [1, 2], L: diag(1, -1)})
-3
数组的对称化:
>>> H = TensorHead("H", [L, L])
>>> a, b, c, d = symbols("a b c d")
>>> expr = H(i, j)/2 + H(j, i)/2
>>> expr.replace_with_arrays({H(i, j): [[a, b], [c, d]]})
[[a, b/2 + c/2], [b/2 + c/2, d]]
反对称化的数组:
>>> expr = H(i, j)/2 - H(j, i)/2
>>> repl = {H(i, j): [[a, b], [c, d]]}
>>> expr.replace_with_arrays(repl)
[[0, b/2 - c/2], [-b/2 + c/2, 0]]
同一表达式也可以读作通过反转i
和j
来进行转置:
>>> expr.replace_with_arrays(repl, [j, i])
[[0, -b/2 + c/2], [b/2 - c/2, 0]]
class sympy.tensor.tensor.TensAdd(*args, **kw_args)
张量的和。
参数:
free_args:自由指标的列表
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_heads, tensor_indices
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> a, b = tensor_indices('a,b', Lorentz)
>>> p, q = tensor_heads('p,q', [Lorentz])
>>> t = p(a) + q(a); t
p(a) + q(a)
示例,将组件数据添加到张量表达式中:
>>> from sympy import symbols, diag
>>> x, y, z, t = symbols("x y z t")
>>> repl = {}
>>> repl[Lorentz] = diag(1, -1, -1, -1)
>>> repl[p(a)] = [1, 2, 3, 4]
>>> repl[q(a)] = [x, y, z, t]
以下是:22 - 32 - 22 - 72 ==> -58
>>> expr = p(a) + q(a)
>>> expr.replace_with_arrays(repl, [a])
[x + 1, y + 2, z + 3, t + 4]
属性
args |
(加法因子的元组) |
---|---|
rank |
(张量的秩) |
free_args |
(按排序顺序列出的自由指标的列表) |
canon_bp()
使用 Butler-Portugal 算法进行单项对称性下的规范化。
contract_metric(g)
使用度量g
升降指标。
参数:
g:度量
contract_all:如果为真,则消除所有已缩并的g
。
注释
请参见TensorIndexType
的文档字符串以获取缩并约定。
class sympy.tensor.tensor.TensMul(*args, **kw_args)
张量的乘积。
参数:
coeff:张量的 SymPy 系数
args
注释
args[0]
:组分张量的TensorHead
的列表。
args[1]
:(索引,位置,分量)的列表,其中ind
是自由指标,ipos
是icomp
-th 分量张量中ind
的插槽位置。
args[2]
:表示虚指标的元组列表。(ipos1, ipos2, icomp1, icomp2)
指示协变虚指标在icomp1
-th 组分张量的第ipos1
个插槽位置;相应的逆变指标在icomp2
-th 组分张量的第ipos2
个插槽位置。
属性
components |
(组分张量的TensorHead 的列表) |
---|---|
types |
(非重复的TensorIndexType 的列表) |
free |
(索引,位置,分量)的列表,请参见注释。 |
dum |
(ipos1,ipos2,icomp1,icomp2)的列表,请参见注释。 |
ext_rank |
(计算虚指标的张量秩) |
rank |
(张量的秩) |
coeff |
(张量的 SymPy 系数) |
free_args |
(按排序顺序列出的自由指标的列表) |
is_canon_bp |
(如果张量处于规范形式则为True ) |
canon_bp()
使用 Butler-Portugal 算法进行单项对称性下的规范化。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorSymmetry
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
>>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2))
>>> t = A(m0,-m1)*A(m1,-m0)
>>> t.canon_bp()
-A(L_0, L_1)*A(-L_0, -L_1)
>>> t = A(m0,-m1)*A(m1,-m2)*A(m2,-m0)
>>> t.canon_bp()
0
contract_metric(g)
使用度量g
升降指标。
参数:
g:度量
注释
请参见TensorIndexType
的文档字符串以获取缩并约定。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
>>> g = Lorentz.metric
>>> p, q = tensor_heads('p,q', [Lorentz])
>>> t = p(m0)*q(m1)*g(-m0, -m1)
>>> t.canon_bp()
metric(L_0, L_1)*p(-L_0)*q(-L_1)
>>> t.contract_metric(g).canon_bp()
p(L_0)*q(-L_0)
get_free_indices() → list[TensorIndex]
返回张量的自由指标列表。
解释
索引按组分张量中出现的顺序列出。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
>>> g = Lorentz.metric
>>> p, q = tensor_heads('p,q', [Lorentz])
>>> t = p(m1)*g(m0,m2)
>>> t.get_free_indices()
[m1, m0, m2]
>>> t2 = p(m1)*g(-m1, m2)
>>> t2.get_free_indices()
[m2]
get_indices()
返回张量的索引列表。
解释
索引按组分张量中出现的顺序列出。虚指标被赋予一个不会与自由指标名称冲突的名称。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz)
>>> g = Lorentz.metric
>>> p, q = tensor_heads('p,q', [Lorentz])
>>> t = p(m1)*g(m0,m2)
>>> t.get_indices()
[m1, m0, m2]
>>> t2 = p(m1)*g(-m1, m2)
>>> t2.get_indices()
[L_0, -L_0, m2]
perm2tensor(g, is_canon_bp=False)
返回与排列g
对应的张量。
更多详细信息,请参见 TIDS
中具有相同名称的方法。
sorted_components()
返回一个具有排序组件的张量积。
split()
返回一个张量列表,其乘积为 self
。
解释
不同张量组件之间的虚指标被用来表示相同名称的自由指标。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz)
>>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2))
>>> t = A(a,b)*B(-b,c)
>>> t
A(a, L_0)*B(-L_0, c)
>>> t.split()
[A(a, L_0), B(-L_0, c)]
sympy.tensor.tensor.canon_bp(p)
巴特勒-葡萄牙规范化。详见组合学模块的 tensor_can.py
。
sympy.tensor.tensor.riemann_cyclic_replace(t_r)
将黎曼张量替换为等效表达式。
R(m,n,p,q) -> 2/3*R(m,n,p,q) - 1/3*R(m,q,n,p) + 1/3*R(m,p,n,q)
sympy.tensor.tensor.riemann_cyclic(t2)
用满足循环恒等式的等效表达式替换每个黎曼张量。
这个技巧在 Cadabra 参考指南中讨论过。
示例
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, riemann_cyclic, TensorSymmetry
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz)
>>> R = TensorHead('R', [Lorentz]*4, TensorSymmetry.riemann())
>>> t = R(i,j,k,l)*(R(-i,-j,-k,-l) - 2*R(-i,-k,-j,-l))
>>> riemann_cyclic(t)
0
class sympy.tensor.tensor.TensorSymmetry(*args, **kw_args)
张量的单项对称性(即任何对称或反对称的索引置换)。有关相关术语,请参阅组合学模块的 tensor_can.py
部分。
参数:
bsgs:元组 (base, sgs)
张量的对称性的 BSGS
注释
一个张量可以通过其 BSGS 提供任意单项对称性。多项对称性,如黎曼张量的循环对称性(即比安基恒等式),不包括在内。有关如何生成一般索引置换群的 BSGS 的信息,请参见组合学模块。可以使用内置方法生成简单的对称性。
示例
定义一个二阶对称张量
>>> from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorHead
>>> Lorentz = TensorIndexType('Lorentz', dummy_name='L')
>>> sym = TensorSymmetry(get_symmetric_group_sgs(2))
>>> T = TensorHead('T', [Lorentz]*2, sym)
注意,使用内置的 TensorSymmetry 方法也可以完成相同的工作
>>> sym2 = TensorSymmetry.fully_symmetric(2)
>>> sym == sym2
True
另请参阅
sympy.combinatorics.tensor_can.get_symmetric_group_sgs
属性
base |
(BSGS 的基础) |
---|---|
generators |
(BSGS 的生成器) |
rank |
(张量的阶) |
classmethod direct_product(*args)
返回一个 TensorSymmetry
对象,它是完全(反)对称索引排列组的直积。
注释
一些 (*args)
的示例:(1)
矢量,相当于 TensorSymmetry.fully_symmetric(1)
(2)
有 2 个对称索引的张量,相当于 .fully_symmetric(2)
(-2)
有 2 个反对称索引的张量,相当于 .fully_symmetric(-2)
(2, -2)
第一个 2 个索引交换,最后 2 个反交换的张量 (1, 1, 1)
有 3 个索引且没有任何对称性的张量
classmethod fully_symmetric(rank)
返回一个完全对称(如果 pyrank``<0) TensorSymmetry object for ``abs(rank)
索引则反对称)的张量。
classmethod no_symmetry(rank)
返回一个 rank
没有对称性的张量对称性对象。
classmethod riemann()
返回黎曼张量的单调对称性。
sympy.tensor.tensor.tensorsymmetry(*args)
返回一个 TensorSymmetry
对象。此方法已弃用,请使用 TensorSymmetry.direct_product()
或 .riemann()
替代。
解释
可以使用 BSGS 表示任何单项槽对称性群的张量。
args
可以是 BSGS args[0]
的基础 args[1]
的 sgs
通常张量位于(直积的)对称群的表示中;args
可以是表示 Young 表的形状列表的列表。
注释
例如:[[1]]
向量 [[1]*n]
秩为 n
的对称张量 [[n]]
秩为 n
的反对称张量 [[2, 2]]
黎曼张量的单项对称性 [[1],[1]]
向量向量 [[2],[1],[1]
(反对称张量)向量*向量
注意,对于形状 [2, 2]
,我们只与黎曼张量的单项对称性相关联;这是符号滥用,因为形状 [2, 2]
通常对应于由单项对称性和循环对称性特征化的不可约表示。
class sympy.tensor.tensor.TensorType(*args, **kwargs)
张量类型类。已弃用,请改用 tensor_heads()
。
参数:
index_types:张量索引的 TensorIndexType
列表
symmetry:张量的 TensorSymmetry
属性
index_types |
|
---|---|
symmetry |
|
types |
(无重复的 TensorIndexType 列表) |
class sympy.tensor.tensor._TensorManager
类用于管理张量属性。
注意
张量属于张量交换群;每个群有一个标签 comm
;有预定义的标签:
0
张量与任何其他张量交换
1
张量彼此反交换
2
张量不交换,与 comm=0
的张量分开
可以使用 set_comm
定义其他组;这些组中的张量与 comm=0
的张量交换;默认情况下,它们不与任何其他组交换。
clear()
清除 TensorManager。
comm_i2symbol(i)
返回与交换群编号对应的符号。
comm_symbols2i(i)
获取与 i
对应的交换群编号。
i
可以是符号、数字或字符串。
如果 i
还没有定义其交换群编号,则设置为其交换群编号。
get_comm(i, j)
返回交换群编号 i, j
的交换参数
见 _TensorManager.set_comm
set_comm(i, j, c)
设置交换群 i, j
的交换参数 c
。
参数:
i, j:表示交换群的符号
c:群交换编号
注意
i, j
可以是符号、字符串或数字,除了 0, 1
和 2
分别保留给交换、反交换张量和与任何其他组不交换的张量。对于其余情况,请使用此方法设置交换规则;默认情况下 c=None
。
交换群编号 c
分配给与交换群符号对应的群;可以为
0 交换
1 反交换
None 无交换属性
示例
G
和 GH
与自己不交换,彼此之间交换;A 是交换的。
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorManager, TensorSymmetry
>>> Lorentz = TensorIndexType('Lorentz')
>>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz)
>>> A = TensorHead('A', [Lorentz])
>>> G = TensorHead('G', [Lorentz], TensorSymmetry.no_symmetry(1), 'Gcomm')
>>> GH = TensorHead('GH', [Lorentz], TensorSymmetry.no_symmetry(1), 'GHcomm')
>>> TensorManager.set_comm('Gcomm', 'GHcomm', 0)
>>> (GH(i1)*G(i0)).canon_bp()
G(i0)*GH(i1)
>>> (G(i1)*G(i0)).canon_bp()
G(i1)*G(i0)
>>> (G(i1)*A(i0)).canon_bp()
A(i0)*G(i1)
set_comms(*args)
设置符号 i, j
的交换群编号 c
。
参数:
args:(i, j, c)
的序列
张量运算符
class sympy.tensor.toperators.PartialDerivative(expr, *variables)
张量表达式的偏导数。
示例
>>> from sympy.tensor.tensor import TensorIndexType, TensorHead
>>> from sympy.tensor.toperators import PartialDerivative
>>> from sympy import symbols
>>> L = TensorIndexType("L")
>>> A = TensorHead("A", [L])
>>> B = TensorHead("B", [L])
>>> i, j, k = symbols("i j k")
>>> expr = PartialDerivative(A(i), A(j))
>>> expr
PartialDerivative(A(i), A(j))
PartialDerivative
对象的行为类似张量表达式:
>>> expr.get_indices()
[i, -j]
注意求导变量的价度与打印的相反:A(j)
打印为协变,但导数的指标实际上是逆变的,即 -j
。
指标可以被缩并:
>>> expr = PartialDerivative(A(i), A(i))
>>> expr
PartialDerivative(A(L_0), A(L_0))
>>> expr.get_indices()
[L_0, -L_0]
方法 .get_indices()
总是返回所有指标(即使是缩并的)。如果只需要未缩并的指标,请调用 .get_free_indices()
:
>>> expr.get_free_indices()
[]
嵌套偏导数被展开:
>>> expr = PartialDerivative(PartialDerivative(A(i), A(j)), A(k))
>>> expr
PartialDerivative(A(i), A(j), A(k))
>>> expr.get_indices()
[i, -j, -k]
用数组值替换导数:
>>> from sympy.abc import x, y
>>> from sympy import sin, log
>>> compA = [sin(x), log(x)*y**3]
>>> compB = [x, y]
>>> expr = PartialDerivative(A(i), B(j))
>>> expr.replace_with_arrays({A(i): compA, B(i): compB})
[[cos(x), 0], [y**3/x, 3*y**2*log(x)]]
返回的数组由 ((i, -j)) 索引。
注意其他 SymPy 模块在导数结果中将求导变量的指标放在被导变量的指标之前。例如:
>>> expr.get_free_indices()
[i, -j]
>>> from sympy import Matrix, Array
>>> Matrix(compA).diff(Matrix(compB)).reshape(2, 2)
[[cos(x), y**3/x], [0, 3*y**2*log(x)]]
>>> Array(compA).diff(Array(compB))
[[cos(x), y**3/x], [0, 3*y**2*log(x)]]
这些是 PartialDerivative
的转置,因为矩阵和数组模块在导数结果中将指标 (-j) 放在 (i) 前面。用指标顺序 (-j, i)
读取的数组确实是用指标顺序 (i, -j)
读取的同一数组的转置。通过指定 .replace_with_arrays
的指标顺序,可以得到兼容的表达式:
>>> expr.replace_with_arrays({A(i): compA, B(i): compB}, [-j, i])
[[cos(x), y**3/x], [0, 3*y**2*log(x)]]
矢量
矢量模块提供了基本的矢量数学和相对于 3D 笛卡尔坐标系的微分计算工具。此文档概述了提供的所有功能及相关 API。
矢量指南
-
介绍
-
基本实现细节
-
关于坐标系的更多信息
-
标量和矢量场功能
-
使用的一般示例
-
矢量积分的应用
-
矢量 API
-
sympy.vector 中的基本类(文档字符串)
-
定向器类(文档字符串)
-
sympy.vector 中的基本函数(文档字符串)
-
矢量的参考资料
[Dyadics]
[DyadicProducts]
en.wikipedia.org/wiki/Dyadic_product
[DelOperator]
引言
本页提供了对 sympy.vector
模块功能的简要概述。
矢量和标量
在矢量数学中,我们处理两种类型的量:标量和矢量。
标量是仅具有大小而没有方向的实体。标量量的例子包括质量、电荷、温度、距离等。
另一方面,矢量是由大小和方向特征的实体。矢量量的例子包括位移、速度、磁场等。
标量可以仅用一个数字表示,例如 300 K 的温度。另一方面,加速度等矢量量通常用矢量表示。给定一个矢量 (\mathbf{V}),相应量的大小可以计算为矢量本身的大小 (\Vert \mathbf{V} \Vert),而方向则由原矢量方向上的单位矢量指定,(\mathbf{\hat{V}} = \frac{\mathbf{V}}{\Vert \mathbf{V} \Vert})。
例如,考虑位移为 ((3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}})) 米的情况,其中,按照标准惯例,(\mathbf{\hat{i}})、(\mathbf{\hat{j}}) 和 (\mathbf{\hat{k}}) 分别表示沿 (\mathbf{X})、(\mathbf{Y}) 和 (\mathbf{Z}) 轴的单位向量。因此,可以得出行程为 (\Vert 3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}} \Vert) 米 = (5\sqrt{2}) 米。行进方向由单位向量 (\frac{3}{5\sqrt{2}}\mathbf{\hat{i}} + \frac{4}{5\sqrt{2}}\mathbf{\hat{j}} + \frac{5}{5\sqrt{2}}\mathbf{\hat{k}}) 给出。
坐标系
坐标系是用来定义 n 维空间中方向和位置概念的抽象数学实体。本模块处理的是三维空间,传统的 (X)、(Y) 和 (Z) 轴分别相对于每个坐标系定义。
每个坐标系还有一个称为“原点”的特殊参考点。这一点在引用三维空间中的位置或计算相对于系统的预定义点的坐标时使用。
这是一个相当知名的概念:在空间中没有绝对的位置或方向的概念。任何给定的坐标系都定义了一个独特的“视角”,用来量化位置和方向。因此,即使我们假设所有系统都使用相同的测量单位,矢量和标量量的表达也会根据某个观察者使用的坐标系而有所不同。
考虑空间中的两点(P)和(Q)。假设单位在整个过程中是通用的,这两点之间的距离不变,无论在哪个坐标系中进行测量。然而,每个点的三维坐标以及任一点相对于另一点的位置矢量并不会保持不变。事实上,除非它们是在考虑某一位置和测量者的方向(本质上是坐标系)的情况下进行测量,否则这两个量根本就没有意义。
因此,很明显,坐标系的方向和位置(原点)定义了不同量如何相对于它来表达。这两个属性都不能在绝对尺度上进行测量,而是相对于另一个坐标系来测量。一个系统相对于另一个系统的方向是使用旋转矩阵来测量的,而相对位置可以通过一个系统原点到另一个系统原点的位置矢量来量化。
场
场是可以作为位置的函数在空间的任何地方指定的矢量或标量数量(注意,通常场也可能依赖于时间和其他自定义变量)。由于我们在本模块中只处理三维空间,因此场被定义为与坐标系中位置对应的(x)、(y)和(z)坐标的函数。在这里,(x)、(y)和(z)充当定义一般点位置的标量变量。
例如,三维空间中的温度(温度场)可以写成(T(x, y, z)) – 位置的标量函数。在电磁学中,标量场的一个例子是电势。
类似地,可以将矢量场定义为空间中任意点位置((x, y, z))的矢量函数。
例如,地球上的每一个点都可以被认为处于地球的重力场中。我们可以通过每个空间点处的加速度大小和方向(即单位质量的力)(\vec g(x, y, z)) 来指定该场。
举例来说,考虑一个三维空间中形式为(2{x}^{2}y)的电势场。相应的保守电场可以计算为电势函数的梯度,并表示为(4xy\mathbf{\hat{i}} + 2{x}{2}\mathbf{\hat{j}})。该电场的大小反过来可以表示为形如(\sqrt{4{x} + 16{x}{2}{y}{2}})的标量场。
基本实现细节
坐标系和向量
目前,sympy.vector
能够处理笛卡尔(也称为矩形)、球面和其他曲线坐标系。
可以在 sympy.vector
中初始化 3D 笛卡尔坐标系。
>>> 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
实例。
可以使用position_wrt
方法计算一个Point
相对于另一个Point
的位置向量。
>>> P.position_wrt(Q)
b*N.j
>>> Q.position_wrt(N.origin)
a*N.i + c*N.k
此外,可以通过express_coordinates
方法获取相对于CoordSys3D
的Point
的(X)、(Y)和(Z)坐标,以元组的形式表示。
>>> Q.express_coordinates(N)
(a, 0, c)
二阶张量
二阶张量,或者说二阶张量,是由向量对并列形成的。因此,向量的外积导致二阶张量的形成。在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)
更多关于坐标系的内容
现在我们来看看如何在 sympy.vector
中初始化新的坐标系,通过用户定义的方式相对于已有系统进行变换。
定位新系统
我们已经知道 CoordSys3D
的 origin
属性对应于表示其原点参考点的 Point
实例。
考虑一个坐标系 (N)。假设我们想定义一个新系统 (M),其原点相对于 (N) 的原点位于 (\mathbf{3\hat{i} + 4\hat{j} + 5\hat{k}}) 处。换句话说,从 (N) 的角度看,(M) 的原点坐标是 ((3, 4, 5))。此外,这也意味着从 (M) 的角度看,(N) 的原点坐标是 ((-3, -4, -5))。
这可以通过编程方式实现如下 -
>>> from sympy.vector import CoordSys3D
>>> N = CoordSys3D('N')
>>> M = N.locate_new('M', 3*N.i + 4*N.j + 5*N.k)
>>> M.position_wrt(N)
3*N.i + 4*N.j + 5*N.k
>>> N.origin.express_coordinates(M)
(-3, -4, -5)
值得注意的是,(M) 的方向与 (N) 的方向相同。这意味着:(N) 相对于 (M) 的旋转矩阵,以及反过来,都等于维度为 3x3 的单位矩阵。locate_new
方法初始化一个 CoordSys3D
,它在空间中只是平移,而不重新定向,相对于“父”系统。
初始化新系统
与‘定位’新系统类似,sympy.vector
还允许初始化新的 CoordSys3D
实例,这些实例以用户定义的方式相对于现有系统定向。
假设您有一个坐标系 (A)。
>>> from sympy.vector import CoordSys3D
>>> A = CoordSys3D('A')
您希望初始化一个新的坐标系 (B),该坐标系相对于 (A) 的 Z 轴旋转了一个角度 (\theta)。
>>> from sympy import Symbol
>>> theta = Symbol('theta')
方向如下图所示:
有两种方法可以实现这一点。
直接使用 CoordSys3D 方法
这是最简单、最干净且推荐的方法。
>>> B = A.orient_new_axis('B', theta, A.k)
这使用所需的方位信息初始化(B),相对于(A)。
CoordSys3D
在其 API 中提供了以下直接定向方法-
-
orient_new_axis
-
orient_new_body
-
orient_new_space
-
orient_new_quaternion
请查看本模块文档中给出的CoordSys3D
类 API,以详细了解它们的功能和所需的参数。
使用Orienter
和orient_new
方法
您首先需要初始化一个AxisOrienter
实例来存储旋转信息。
>>> from sympy.vector import AxisOrienter
>>> axis_orienter = AxisOrienter(theta, A.k)
然后使用orient_new
方法应用它,以获得(B)。
>>> B = A.orient_new('B', axis_orienter)
orient_new
还允许您使用多个Orienter
实例定向新系统,这些实例以可迭代形式提供。旋转/定向按照Orienter
实例在可迭代中出现的顺序应用于新系统。
>>> from sympy.vector import BodyOrienter
>>> from sympy.abc import a, b, c
>>> body_orienter = BodyOrienter(a, b, c, 'XYZ')
>>> C = A.orient_new('C', (axis_orienter, body_orienter))
sympy.vector
API 为定向目的提供以下四个Orienter
类:
-
AxisOrienter
-
BodyOrienter
-
SpaceOrienter
-
QuaternionOrienter
请参考本模块文档中各类的 API,了解更多信息。
在上述每个示例中,新坐标系的原点与“父”系统的原点重合。
>>> B.position_wrt(A)
0
要计算任何坐标系相对于另一个坐标系的旋转矩阵,请使用rotation_matrix
方法。
>>> B = A.orient_new_axis('B', a, A.k)
>>> B.rotation_matrix(A)
Matrix([
[ cos(a), sin(a), 0],
[-sin(a), cos(a), 0],
[ 0, 0, 1]])
>>> B.rotation_matrix(B)
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
定位和定向新系统
如果您想要初始化一个不仅在预定义方式下定向的新系统,还在父系统中进行了平移,该怎么办?
每个orient_new_<定向方法>
方法以及orient_new
方法都支持location
关键字参数。
如果将Vector
作为此kwarg
的值提供,那么新系统的原点将自动定义为相对于父坐标系的该位置向量。
因此,定向方法也作为支持新系统定向+定位的方法。
>>> C = A.orient_new_axis('C', a, A.k, location=2*A.j)
>>> C.position_wrt(A)
2*A.j
>>> from sympy.vector import express
>>> express(A.position_wrt(C), C)
(-2*sin(a))*C.i + (-2*cos(a))*C.j
后面详述express
函数。
转换新系统
创建用户定义系统的最一般方法是在CoordSys3D
中使用transformation
参数。在这里,我们可以定义任何转换方程。如果我们对某些不同于笛卡尔坐标系的典型曲线坐标系感兴趣,我们也可以使用一些预定义的坐标系。也可以通过设置适当的转换方程来平移或旋转系统。
>>> from sympy.vector import CoordSys3D
>>> from sympy import sin, cos
>>> A = CoordSys3D('A', transformation='spherical')
>>> B = CoordSys3D('A', transformation=lambda x,y,z: (x*sin(y), x*cos(y), z))
在CoordSys3D
中还有专用方法create_new
,其工作方式类似于locate_new
、orient_new_axis
等方法。
>>> from sympy.vector import CoordSys3D
>>> A = CoordSys3D('A')
>>> B = A.create_new('B', transformation='spherical')
在不同坐标系中的量的表达式
向量和二元向量
正如前面提到的,同一向量在不同坐标系中具有不同的表达式。通常,标量表达式和二阶张量也是如此。
sympy.vector
支持使用 express
函数在不同的坐标系中表达向量/标量量。
在本节中,假定以下初始化:
>>> from sympy.vector import CoordSys3D, express
>>> from sympy.abc import a, b, c
>>> N = CoordSys3D('N')
>>> M = N.orient_new_axis('M', a, N.k)
用户可以使用 express
将 Vector
实例表示为用户定义的系统。
>>> v1 = N.i + N.j + N.k
>>> express(v1, M)
(sin(a) + cos(a))*M.i + (-sin(a) + cos(a))*M.j + M.k
>>> v2 = N.i + M.j
>>> express(v2, N)
(1 - sin(a))*N.i + (cos(a))*N.j
除了 Vector
实例外,express
还支持重新表达标量(一般的 SymPy Expr
)和 Dyadic
对象。
express
还接受第二个坐标系,用于重新表达 Dyadic
实例。
>>> d = 2*(M.i | N.j) + 3* (M.j | N.k)
>>> express(d, M)
(2*sin(a))*(M.i|M.i) + (2*cos(a))*(M.i|M.j) + 3*(M.j|M.k)
>>> express(d, M, N)
2*(M.i|N.j) + 3*(M.j|N.k)
坐标变量
坐标系的原点位置不影响 BaseVector
实例的重新表达。但它确实影响了在不同系统中表达 BaseScalar
实例的方式。
BaseScalar
实例是坐标‘符号’,用于表示 sympy.vector
中向量/标量场的定义中使用的变量。
例如,考虑在系统 (N) 中定义的标量场 (\mathbf{{T}{N}(x, y, z) = x + y + z})。因此,在坐标为 ((a, b, c)) 的点处,该场的值为 (a + b + c)。现在考虑系统 (R),其原点相对于 (N) 位于 ((1, 2, 3))(无方向变化)。在 (R) 中坐标为 ((a, b, c)) 的点,在 (N) 中的坐标为 ((a + 1, b + 2, c + 3))。因此,在系统 (R) 中,(\mathbf{{T}{N}}) 的表达式变为 (\mathbf{{T}_{R}}(x, y, z) = x + y + z + 6)。
如果向量/标量/二态表达式中存在坐标变量,则可以通过将 express
的 variables
关键字参数设置为 True
来在给定坐标系中重新表达它们。
上述示例,以编程方式完成,看起来像这样 -
>>> R = N.locate_new('R', N.i + 2*N.j + 3*N.k)
>>> T_N = N.x + N.y + N.z
>>> express(T_N, R, variables=True)
R.x + R.y + R.z + 6
其他依赖表达式的方法
Vector
的 to_matrix
方法和 Point
的 express_coordinates
方法在提供不同坐标系时返回不同结果。
>>> P = R.origin.locate_new('P', a*R.i + b*R.j + c*R.k)
>>> P.express_coordinates(N)
(a + 1, b + 2, c + 3)
>>> P.express_coordinates(R)
(a, b, c)
>>> v = N.i + N.j + N.k
>>> v.to_matrix(M)
Matrix([
[ sin(a) + cos(a)],
[-sin(a) + cos(a)],
[ 1]])
>>> v.to_matrix(N)
Matrix([
[1],
[1],
[1]])
标量和向量场功能
在 sympy.vector 中的实现
标量和向量场
在 sympy.vector
中,每个 CoordSys3D
实例都分配了与 (X)、(Y) 和 (Z) 轴对应的基向量。这些可以分别通过名为 i
、j
和 k
的属性访问。因此,要定义相对于给定框架 (\mathbf{R}) 的形式为 (3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}}) 的向量 (\mathbf{v}),您需要执行
>>> from sympy.vector import CoordSys3D
>>> R = CoordSys3D('R')
>>> v = 3*R.i + 4*R.j + 5*R.k
向量数学和与向量相关的基本微积分运算已经在本模块文档的早期部分详细说明。
另一方面,基本标量(或坐标变量)实现在一个称为 BaseScalar
的特殊类中,并且为每个坐标系分配一个,从 (X)、(Y) 到 (Z) 的每个轴。这些坐标变量用于在三维空间中形成向量或标量场的表达式。对于系统 R
,(X)、(Y) 和 (Z) 的 BaseScalars
实例可以分别使用 R.x
、R.y
和 R.z
表达式访问。
因此,要生成前述电势场 (2{x}^{2}y) 的表达式,您需要执行
>>> from sympy.vector import CoordSys3D
>>> R = CoordSys3D('R')
>>> electric_potential = 2*R.x**2*R.y
>>> electric_potential
2*R.x**2*R.y
注意,BaseScalar
实例可以像任何其他 SymPy Symbol
一样使用,只是它们存储与其对应的坐标系和轴的信息。
标量场可以像任何其他 SymPy 表达式一样处理,适用于任何数学/微积分功能。因此,要针对 (x)(即 R.x
)不同电势,您将使用 diff
方法。
>>> from sympy.vector import CoordSys3D
>>> R = CoordSys3D('R')
>>> electric_potential = 2*R.x**2*R.y
>>> from sympy import diff
>>> diff(electric_potential, R.x)
4*R.x*R.y
值得注意的是,在表达式中有 BaseScalar
意味着‘场’随位置(在三维空间中)变化。严格来说,一个简单的 Expr
没有 BaseScalar
仍然是一个场,尽管是常量。
类似于标量场,随位置变化的向量场也可以使用测量数字表达式中的 BaseScalar
构造。
>>> from sympy.vector import CoordSys3D
>>> R = CoordSys3D('R')
>>> v = R.x**2*R.i + 2*R.x*R.z*R.k
Del 算子
Del 或 ‘Nabla’ 算子 - 写作 (\mathbf{\nabla}),通常称为向量微分算子。根据其在数学表达式中的用法,它可以表示标量场的梯度、向量场的散度或向量场的旋度。
本质上,(\mathbf{\nabla}) 在技术上不是一个‘算子’,而是一个便捷的数学符号,用于表示前述任一场操作。
在 sympy.vector
中,(\mathbf{\nabla}) 已经实现为 Del()
类。此类的实例独立于坐标系。因此,(\mathbf{\nabla}) 算子可以作为 Del()
访问。
下面是使用 Del()
类的一个示例。
>>> from sympy.vector import CoordSys3D, Del
>>> C = CoordSys3D('C')
>>> delop = Del()
>>> gradient_field = delop(C.x*C.y*C.z)
>>> gradient_field
(Derivative(C.x*C.y*C.z, C.x))*C.i + (Derivative(C.x*C.y*C.z, C.y))*C.j
+ (Derivative(C.x*C.y*C.z, C.z))*C.k
可以使用 SymPy 的doit()
例程计算上述表达式。
>>> gradient_field.doit()
C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k
在sympy.vector
中详细描述了使用(\mathbf{\nabla})符号的方法。
场算子和相关函数
这里我们描述了实现在sympy.vector
中的一些基本场相关功能。
旋度
一个旋度是描述三维空间中矢量微小旋转的数学算子。方向由右手法则(沿着旋转轴)确定,大小由旋转的大小确定。
在 3D 笛卡尔坐标系中,三维矢量(\mathbf{F})的旋度,表示为(\nabla \times \mathbf{F}),由以下给出:
(\nabla \times \mathbf{F} = \left(\frac{\partial F_z}{\partial y} - \frac{\partial F_y}{\partial z}\right) \mathbf{\hat{i}} + \left(\frac{\partial F_x}{\partial z} - \frac{\partial F_z}{\partial x}\right) \mathbf{\hat{j}} + \left(\frac{\partial F_y}{\partial x} - \frac{\partial F_x}{\partial y}\right) \mathbf{\hat{k}})
其中(F_x)表示矢量(\mathbf{F})的(X)分量。
可以通过两种方式在sympy.vector
中计算矢量场的旋度。
通过使用Del()
类之一
>>> from sympy.vector import CoordSys3D, Del
>>> C = CoordSys3D('C')
>>> delop = Del()
>>> delop.cross(C.x*C.y*C.z*C.i).doit()
C.x*C.y*C.j + (-C.x*C.z)*C.k
>>> (delop ^ C.x*C.y*C.z*C.i).doit()
C.x*C.y*C.j + (-C.x*C.z)*C.k
或者通过使用专用函数
>>> from sympy.vector import curl
>>> curl(C.x*C.y*C.z*C.i)
C.x*C.y*C.j + (-C.x*C.z)*C.k
散度
散度是一个矢量算子,用于测量矢量场在给定点的源或汇的大小,用带符号的标量表示。
散度算子在对矢量进行操作后总是返回一个标量。
在 3D 笛卡尔坐标系中,三维矢量(\mathbf{F})的散度,表示为(\nabla\cdot\mathbf{F}),由以下给出:
(\nabla\cdot\mathbf{F} = \frac{\partial U}{\partial x} + \frac{\partial V}{\partial y} + \frac{\partial W}{\partial z })
其中(U)、(V)和(W)分别表示(\mathbf{F})的(X)、(Y)和(Z)分量。
可以通过两种方式在sympy.vector
中计算矢量场的散度。
通过使用Del()
类之一
>>> from sympy.vector import CoordSys3D, Del
>>> C = CoordSys3D('C')
>>> delop = Del()
>>> delop.dot(C.x*C.y*C.z*(C.i + C.j + C.k)).doit()
C.x*C.y + C.x*C.z + C.y*C.z
>>> (delop & C.x*C.y*C.z*(C.i + C.j + C.k)).doit()
C.x*C.y + C.x*C.z + C.y*C.z
或者通过使用专用函数
>>> from sympy.vector import divergence
>>> divergence(C.x*C.y*C.z*(C.i + C.j + C.k))
C.x*C.y + C.x*C.z + C.y*C.z
梯度
考虑三维空间中的标量场(f(x, y, z))。该场的梯度定义为相对于(X)、(Y)和(Z)轴的(f)的 3 个偏导数的矢量。
在 3D 笛卡尔坐标系中,标量场(f)的散度(\nabla f)由以下给出 -
(\nabla f = \frac{\partial f}{\partial x} \mathbf{\hat{i}} + \frac{\partial f}{\partial y} \mathbf{\hat{j}} + \frac{\partial f}{\partial z} \mathbf{\hat{k}})
可以通过两种方式在sympy.vector
中计算矢量场的散度。
通过使用Del()
类之一
>>> from sympy.vector import CoordSys3D, Del
>>> C = CoordSys3D('C')
>>> delop = Del()
>>> delop.gradient(C.x*C.y*C.z).doit()
C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k
>>> delop(C.x*C.y*C.z).doit()
C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k
或者通过使用专用函数
>>> from sympy.vector import gradient
>>> gradient(C.x*C.y*C.z)
C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k
方向导数
除了上述三种常见的 (\mathbf{\nabla}) 应用外,在 sympy.vector
中还可以计算相对于 Vector
的场的方向导数。
按定义,场 (\mathbf{F}) 沿着向量 (v) 在点 (x) 处的方向导数表示 (\mathbf{F}) 在速度 (v) 下通过 (x) 移动的瞬时变化率。数学上表示为:((\vec{v} \cdot \nabla) , \mathbf{F}(x))。
可以使用 Del()
类在 sympy.vector
中计算矢量和标量场的方向导数。
>>> from sympy.vector import CoordSys3D, Del
>>> C = CoordSys3D('C')
>>> delop = Del()
>>> vel = C.i + C.j + C.k
>>> scalar_field = C.x*C.y*C.z
>>> vector_field = C.x*C.y*C.z*C.i
>>> (vel.dot(delop))(scalar_field)
C.x*C.y + C.x*C.z + C.y*C.z
>>> (vel & delop)(vector_field)
(C.x*C.y + C.x*C.z + C.y*C.z)*C.i
或者通过使用专用函数
>>> from sympy.vector import directional_derivative
>>> directional_derivative(C.x*C.y*C.z, 3*C.i + 4*C.j + C.k)
C.x*C.y + 4*C.x*C.z + 3*C.y*C.z
正交曲线坐标系中的场算子
vector
包支持在不同类型的正交曲线坐标系中进行计算。为了实现这一点,使用缩放因子(也称为拉梅系数)来表达在所需类型的坐标系中计算 curl
、divergence
或 gradient
。
例如,如果我们想在柱坐标系中计算 gradient
,我们只需创建适当的坐标系。
>>> from sympy.vector import CoordSys3D
>>> c = CoordSys3D('c', transformation='cylindrical', variable_names=("r", "theta", "z"))
>>> gradient(c.r*c.theta*c.z)
c.theta*c.z*c.i + c.z*c.j + c.r*c.theta*c.k
保守场与无旋场
在矢量微积分中,保守场是某些标量场的梯度的场。保守场具有其沿任意路径的线积分仅依赖于端点,并且与所走路径无关的特性。保守向量场也被称为‘无旋场’,因为保守场的旋度始终为零。
在物理学中,保守场代表在能量守恒的物理系统中的力。
要检查在 sympy.vector
中矢量场是否为保守场,可以使用 is_conservative
函数。
>>> from sympy.vector import CoordSys3D, is_conservative
>>> R = CoordSys3D('R')
>>> field = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k
>>> is_conservative(field)
True
>>> curl(field)
0
另一方面,一个无旋场是一个矢量场,在空间中所有点的散度都为零。
要检查在 sympy.vector
中矢量场是否为无旋场,可以使用 is_solenoidal
函数。
>>> from sympy.vector import CoordSys3D, is_solenoidal
>>> R = CoordSys3D('R')
>>> field = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k
>>> is_solenoidal(field)
True
>>> divergence(field)
0
标量势函数
我们先前提到,每个保守场可以定义为某些标量场的梯度。这个标量场也称为与前述保守场对应的‘标量势场’。
sympy.vector
中的 scalar_potential
函数计算给定三维空间中保守向量场对应的标量势场 - 当然要减去额外的积分常数。
使用示例 -
>>> from sympy.vector import CoordSys3D, scalar_potential
>>> R = CoordSys3D('R')
>>> conservative_field = 4*R.x*R.y*R.z*R.i + 2*R.x**2*R.z*R.j + 2*R.x**2*R.y*R.k
>>> scalar_potential(conservative_field, R)
2*R.x**2*R.y*R.z
将非保守向量场作为参数提供给 scalar_potential
会引发 ValueError
。
与保守矢量场对应的标量势差,或简称为“势差”,可以定义为其标量势函数在空间中两点处值的差异。这在计算与保守函数相关的线积分中非常有用,因为它仅取决于路径的端点。
在 sympy.vector
中,这种计算是如何执行的。
>>> from sympy.vector import CoordSys3D, Point
>>> from sympy.vector import scalar_potential_difference
>>> R = CoordSys3D('R')
>>> P = R.origin.locate_new('P', 1*R.i + 2*R.j + 3*R.k)
>>> vectfield = 4*R.x*R.y*R.i + 2*R.x**2*R.j
>>> scalar_potential_difference(vectfield, R, R.origin, P)
4
如果提供的是标量表达式而不是矢量场,则 scalar_potential_difference
返回空间中两个给定点处标量场值的差异。
使用范例
本节详细说明了使用 sympy.vector
包解决向量数学/微积分中的两个基本问题。
四边形问题
问题
OABC 是三维空间中的任意四边形。P 是 OA 的中点,Q 是 AB 的中点,R 是 BC 的中点,S 是 OC 的中点。证明 PQ 平行于 SR
解决方案
此问题的解决方法展示了Point
的使用,以及Vector
的基本操作。
定义一个坐标系
>>> from sympy.vector import CoordSys3D
>>> Sys = CoordSys3D('Sys')
将点 O 定义为 Sys 的原点。我们可以毫不失误地这样做。
>>> O = Sys.origin
以 O 为基础定义点 A
>>> from sympy import symbols
>>> a1, a2, a3 = symbols('a1 a2 a3')
>>> A = O.locate_new('A', a1*Sys.i + a2*Sys.j + a3*Sys.k)
同样根据问题定义点 B 和 C
>>> b1, b2, b3 = symbols('b1 b2 b3')
>>> B = O.locate_new('B', b1*Sys.i + b2*Sys.j + b3*Sys.k)
>>> c1, c2, c3 = symbols('c1 c2 c3')
>>> C = O.locate_new('C', c1*Sys.i + c2*Sys.j + c3*Sys.k)
P 是 OA 的中点。让我们相对于 O 定位它(你也可以相对于 A 定义它)。
>>> P = O.locate_new('P', A.position_wrt(O) + (O.position_wrt(A) / 2))
同样根据问题定义点 Q、R 和 S。
>>> Q = A.locate_new('Q', B.position_wrt(A) / 2)
>>> R = B.locate_new('R', C.position_wrt(B) / 2)
>>> S = O.locate_new('R', C.position_wrt(O) / 2)
现在计算以 PQ 和 SR 指定的方向的向量。
>>> PQ = Q.position_wrt(P)
>>> SR = R.position_wrt(S)
计算叉乘
>>> PQ.cross(SR)
0
由于叉乘是零向量,所以这两个向量必须是平行的,从而证明 PQ || SR。
Del 操作符的第三个乘积法则
看见
[WikiDel]
问题
证明第三条规则 - (\nabla \cdot (f \vec v) = f (\nabla \cdot \vec v) + \vec v \cdot (\nabla f))
解决方案
从一个坐标系开始
>>> from sympy.vector import CoordSys3D, Del
>>> delop = Del()
>>> C = CoordSys3D('C')
标量场 (f) 和向量场 (\vec v) 的测量数都是一般坐标系统的坐标变量的函数。因此,以这种方式定义 SymPy 函数。
>>> from sympy import symbols, Function
>>> v1, v2, v3, f = symbols('v1 v2 v3 f', cls=Function)
v1
、v2
和 v3
分别是向量场的 (X)、(Y) 和 (Z) 分量。
将向量场定义为vfield
,标量场定义为sfield
。
>>> vfield = v1(C.x, C.y, C.z)*C.i + v2(C.x, C.y, C.z)*C.j + v3(C.x, C.y, C.z)*C.k
>>> ffield = f(C.x, C.y, C.z)
使用 Del()
构建方程左侧的表达式。
>>> lhs = (delop.dot(ffield * vfield)).doit()
同样,RHS 也将被定义。
>>> rhs = ((vfield.dot(delop(ffield))) + (ffield * (delop.dot(vfield)))).doit()
现在,为了证明乘积法则,我们只需要使左手边和右手边的展开和简化版本相等,这样 SymPy 表达式就匹配了。
>>> lhs.expand().simplify() == rhs.expand().doit().simplify()
True
因此,可以使用 sympy.vector
来证明上述第三个乘积法则的一般形式。