SymPy 1.13 中文文档(七)
按类型解决输出
solve() 函数的输出看起来非常笨重,因为它可能表现出任意返回六种不同类型的输出(除了引发错误)。这些原因是历史性的,倾向于人类互动而不是程序化使用。输出类型将取决于方程的类型(及其输入方式)以及提供的符号数量(及其提供方式)。
>>> from sympy import sqrt, exp, solve, Symbol, Eq >>> from sympy.abc import x, y, z, a, b
solve()函数尝试找到尽可能多的符号值,使得给定的每个表达式等于零。输出的格式可以通过使用dict或set关键字来控制:>>> solve(x - 1, dict=True) [{x: 1}] >>> solve([x**2 - y, x + y - 6], set=True) ([x, y], {(-3, 9), (2, 4)})下面的讨论说明了在不使用这些关键字时获得的输出的解释。
空列表
当没有解时,返回一个空列表。
>>> solve(sqrt(x) + 1) # or solve(sqrt(x) + 1, dict=True) [] >>> solve(sqrt(x) + 1, set=True) ([x], set())
值列表
当解决符号在上下文中明确时,给出一个值列表,因为 a)方程是单变量的或者 b)单个符号被指定为感兴趣的。
>>> solve(x**2 - 4) [-2, 2] >>> solve(x - y - 1, x) [y + 1]
单一字典
当方程作为列表传递并且所有符号在给定的方程中均为线性时,结果为单个字典,键为符号,值为这些符号的解。注意:如果对于指定的符号存在未确定系数的解,则会自动生成这样的系统以解决单个方程(不作为列表传递)。如果这不是预期的结果,请将表达式作为列表传递。
>>> solve([x + y - 2, x - y + 2], x, y) {x: 0, y: 2} >>> eq = a*x - 2*x + b - 5 >>> solve(eq, {a, b}) # undetermined coefficients {a: 2, b: 5} >>> solve([eq], {a, b}) # algebraic {a: -b/x + (2*x + 5)/x}
元组列表
列表中的每个元组按给定顺序给出符号的解。当 a)方程列表包含至少一个非线性方程或 b)符号列表按照明确定义的顺序给出时,使用此格式。(这也是在使用标志
set=True时返回的集合中元组的格式。)>>> solve(x - 1, x, y) # more than one symbol [(1, y)] >>> solve([x**2], x) # list with nonlinear equation [(0,)] >>> solve([x**2 - 1], x) [(-1,), (1,)] >>> solve([x**2 - y, x - 3], x, y) # nonlinear and multiple symbols [(3, 9)]
字典列表
当表达式不是单变量或列表中存在非线性表达式且符号顺序可能会因 a)未传递符号或 b)符号被传递为集合而产生歧义时,返回字典列表。(这也是使用
dict=True选择的格式。)>>> solve(x - y) [{x: y}] >>> solve([exp(x) - 1, x*(x - 1)]) [{x: 0}] >>> system = [x + y - z, x**2 - y + z, exp(z) + 1/x + 1/y - 2] >>> sol = solve(system[:2]); sol [{x: -1, y: z + 1}, {x: 0, y: z}]字典仅包含与键不同的值。在上述最后一个示例中,字典中没有
z的键,因为仅两个三个方程不足以确定其值。然而,这些解可以用于消除第三个方程中的变量,从而给出可以解决(可能是数值上的)以获得仅需猜测单个值而不是三个值的全解的单变量关系。>>> from sympy import nsolve >>> [system[-1].subs(s) for s in sol] [exp(z) - 3 + 1/(z + 1), exp(z) + zoo + 1/z] >>> z_eq = _[0] >>> zsol = nsolve(z_eq, 1); zsol 0.906425478894557 >>> sol0 = {k: v.subs(z, zsol) for k, v in sol[0].items()} >>> sol0[z] = zsol; sol0 {x: -1, y: 1.90642547889456, z: 0.906425478894557}
布尔或关系
当将一个与
Equality不同的关系表达式作为要解析的表达式时,返回一个布尔表达式。可能会返回一个单个的(Equality)或更复杂的关系表达式。在这里使用solve()相当于将方程组和符号传递给reduce_inequalities()(并且dict、set和check标志将被忽略)。>>> solve([x**2 > 4, x > 0]) (2 < x) & (x < oo)>>> from sympy import Unequality as Ne >>> solve([x**2 - 4, Ne(x, -2)]) Eq(x, 2)任何返回的(Equality)可以转换为字典:
>>> {_.lhs: _.rhs} {x: 2}
SymPy 专题
原文:
docs.sympy.org/latest/explanation/special_topics/index.html
此系列文档的目的是为了向 SymPy 的用户提供一些不完全是教程或比教程更长的主题。随着 SymPy 的发展和用户发现更多 SymPy 在更高级主题中的应用方式,这些文档希望填补一个空白。
-
有限差分逼近导数
-
介绍
-
使用 SymPy 矩阵的直接方法
-
-
SymPy 对象的分类
-
类
-
种类
-
集合和假设
-
函数
-
导数的有限差分逼近
原文:
docs.sympy.org/latest/explanation/special_topics/finite_diff_derivatives.html
引言
在数值分析和计算物理中,导数的有限差分逼近非常重要。在本教程中,我们展示如何使用 SymPy 计算不同精度的逼近值。希望这些笔记能对需要在某种语言中编写代码且需要高效生成各种逼近公式的研究人员有所帮助。
为了明确符号,我们首先声明:我们设想存在一个关于单变量 (x) 的连续函数 (F),其具有所需的所有导数。我们在实轴上均匀地以间隔 (h) 采样 (x) 值。在大多数情况下,我们希望 (h) 在某种意义上足够小。可以关于某一点 (x_{0}) 展开 (F(x)) 的泰勒级数展开式。令 (x = x_{0} + h)。那么泰勒展开式为
[F(x_{0}+h) = F(x_{0}) + \big(\frac{dF}{dx}\big){x{0}} * h + \frac{1}{2!} \big(\frac{d^{2}F }{dx^{2}}\big){x{0}}* h² + \frac{1}{3!} \big(\frac{d^{3}F }{dx^{3}}\big){x{0}}* h³ + ...]
为简化表示,我们现在定义一组系数 (c_{n}),其中
[c_{n} := \frac{1}{n!} \big(\frac{d^{n}F }{dx^{n}}\big){x{0}}.]
现在我们的级数形式如下:
[F(x_{0}+h) = F(x_{0}) + c_{1} * h + c_{2}* h² + c_{3}* h³ + ...]
我们将仅使用有限网格上的数值 (x_{i}),其中 (i) 从 (1,...,N),以及在这些网格点上对应的函数 (F) 的数值 (F_{i})。因此问题在于如何生成 (F) 的导数的近似值,条件是我们只能使用大小为 (N) 的有限对 ((x_{i},F_{i})) 的子集。
接下来使用 SymPy 进行操作,以制定给定阶数导数的逼近并评估其精度。首先,我们使用 SymPy 通过一种常见但效率较低的方法推导逼近值。稍后,我们将利用其他 SymPy 函数来更高效地完成这项工作。
使用 SymPy 矩阵的直接方法
如果我们令 (x_{0} = x_{i}),在 (x_{i+1}=x_{i}+ h) 处评估级数,并截断所有高于 (O(h¹)) 的项,我们可以解出单一系数 (c_{1}),从而获得一阶导数的近似值:
[\big(\frac{dF}{dx}\big){x{0}} \approx \frac{F_{i+1} - F_{i}}{h} + O(h)]
这里的 (O(h)) 是指 (h) 级数中的最低阶项。这确立了导数逼近是一阶精度的事实。换句话说,如果我们只能使用两对 ((x_{i},F_{i})) 和 ((x_{i+1},F_{i+1})),我们得到一个“一阶精度”的导数逼近。
除了 ((x_{i},F_{i})) 外,我们接下来使用 ((x_{i+1},F_{i+1})) 和 ((x_{i+2},F_{i+2})) 两个点。然后我们有两个方程:
[F_{i+1} = F_{i} + c_{1}* h + \frac{1}{2}*c_{2}*h² + \frac{1}{3!}*c_{3}h³ + ...][F_{i+2} = F_{i} + c_{1} (2h) + \frac{1}{2}c_{2}(2h)² + \frac{1}{3!}c_{3}(2h)³ + ...]
如果我们再次想要找到第一阶导数((c_{1})),我们可以通过消除涉及 (c_{2}) 的项来实现这一点。我们展示如何使用 SymPy 完成这一过程。
>>> from __future__ import print_function
>>> from sympy import *
>>> x, x0, h = symbols('x, x_0, h')
>>> Fi, Fip1, Fip2 = symbols('F_{i}, F_{i+1}, F_{i+2}')
>>> n = 3 # there are the coefficients c_0=Fi, c_1=dF/dx, c_2=d**2F/dx**2
>>> c = symbols('c:3')
>>> def P(x, x0, c, n):
... return sum( ((1/factorial(i))*c[i] * (x-x0)**i for i in range(n)) )
右手边的向量:
>>> R = Matrix([[Fi], [Fip1], [Fip2]])
现在我们构造一个矩阵,其中包含多项式 P 中 (c_i) 的系数。
在 (x_i) 处评估的 (c_i) 的系数:
>>> m11 = P(x0 , x0, c, n).diff(c[0])
>>> m12 = P(x0 , x0, c, n).diff(c[1])
>>> m13 = P(x0 , x0, c, n).diff(c[2])
在 (x_i + h) 处评估的 (c_i) 的系数:
>>> m21 = P(x0+h, x0, c, n).diff(c[0])
>>> m22 = P(x0+h, x0, c, n).diff(c[1])
>>> m23 = P(x0+h, x0, c, n).diff(c[2])
在 (x_i + 2*h) 处评估的 (c_i) 的系数:
>>> m31 = P(x0+2*h, x0, c, n).diff(c[0])
>>> m32 = P(x0+2*h, x0, c, n).diff(c[1])
>>> m33 = P(x0+2*h, x0, c, n).diff(c[2])
在这种情况下,系数矩阵是 3x3 的:
>>> M = Matrix([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]])
(c_i) 的三个方程的矩阵形式是 M*X = R:
解决方案通过直接反转 3x3 矩阵 M 获得:
>>> X = M.inv() * R
注意,所有三个系数构成了解。所需的第一阶导数是系数 (c_1),即 X[1]。
>>> print(together(X[1]))
(4*F_{i+1} - F_{i+2} - 3*F_{i})/(2*h)
计算另一个三点近似的第一阶导数是有益的,除了在 (x_i) 处居中近似,因此使用 (x_{i-1})、(x_{i}) 和 (x_{i+1}) 三个点。这里是使用“暴力方法”完成这个过程的方法:
>>> from __future__ import print_function
>>> from sympy import *
>>> x, x0, h = symbols('x, x_i, h')
>>> Fi, Fim1, Fip1 = symbols('F_{i}, F_{i-1}, F_{i+1}')
>>> n = 3 # there are the coefficients c_0=Fi, c_1=dF/h, c_2=d**2F/h**2
>>> c = symbols('c:3')
>>> # define a polynomial of degree n
>>> def P(x, x0, c, n):
... return sum( ((1/factorial(i))*c[i] * (x-x0)**i for i in range(n)) )
>>> # now we make a matrix consisting of the coefficients
>>> # of the c_i in the nth degree polynomial P
>>> # coefficients of c_i evaluated at x_i
>>> m11 = P(x0 , x0, c, n).diff(c[0])
>>> m12 = P(x0 , x0, c, n).diff(c[1])
>>> m13 = P(x0 , x0, c, n).diff(c[2])
>>> # coefficients of c_i evaluated at x_i - h
>>> m21 = P(x0-h, x0, c, n).diff(c[0])
>>> m22 = P(x0-h, x0, c, n).diff(c[1])
>>> m23 = P(x0-h, x0, c, n).diff(c[2])
>>> # coefficients of c_i evaluated at x_i + h
>>> m31 = P(x0+h, x0, c, n).diff(c[0])
>>> m32 = P(x0+h, x0, c, n).diff(c[1])
>>> m33 = P(x0+h, x0, c, n).diff(c[2])
>>> # matrix of the coefficients is 3x3 in this case
>>> M = Matrix([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]])
现在我们有了系数矩阵,接下来形成右侧并通过反转 (M) 解决:
>>> # matrix of the function values...actually a vector of right hand sides
>>> R = Matrix([[Fi], [Fim1], [Fip1]])
>>> # matrix form of the three equations for the c_i is M*X = R
>>> # solution directly inverting the 3x3 matrix M:
>>> X = M.inv() * R
>>> # note that all three coefficients make up the solution
>>> # the first derivative is coefficient c_1 which is X[1].
>>> print("The second-order accurate approximation for the first derivative is: ")
The second-order accurate approximation for the first derivative is:
>>> print(together(X[1]))
(F_{i+1} - F_{i-1})/(2*h)
这两个例子展示了如何使用 SymPy 直接找到二阶精确的一阶导数。第一个例子使用了 (x_i)、(x_{i+1}) 和 (x_{i+2}) 所有三点的 (x) 和 (F) 值,而第二个例子仅使用了 (x_{i-1}) 和 (x_{i+1}) 两点的 (x) 值,因此效率更高一些。
从这两个简单的例子中可以得出一个一般规则,即如果想要一阶导数精确到 (O(h^{n})),那么在逼近多项式中需要 n+1 个函数值(通过函数 (P(x,x0,c,n)) 提供)。
现在让我们评估中心差分结果的精确性,看看如何确定它确实是二阶的。为此,我们将 (dF/dx) 的结果代入更高阶多项式的展开式中,看看我们得到什么。为此,我们制作了一组八个系数 d,并用它们执行检查:
>>> d = symbols('c:8')
>>> dfdxcheck = (P(x0+h, x0, d, 8) - P(x0-h, x0, d, 8))/(2*h)
>>> print(simplify(dfdxcheck)) # so the appropriate cancellation of terms involving `h` happens
c1 + c3*h**2/6 + c5*h**4/120 + c7*h**6/5040
因此,我们看到导数确实是 (c_1),下一个阶数的级数为 (h²)。
然而,当试图生成高阶(如 6 或 8 阶)的导数近似时,通常很快会变得相当乏味,尽管这种方法确实有效,并且使用现有方法肯定比手动计算要少费力。
正如我们在上面的讨论中看到的,对于第一导数的简单中心近似只使用 ((x_{i},F_{i})) 对的两个点值。这在遇到域中的最后一个点时就会出现问题,比如在 (i=N) 处。由于我们的中心导数近似会使用点 ((x_{N+1},F_{N+1})) 处的数据,我们可以看到导数公式将无法工作。那么,该怎么办呢?嗯,处理这个问题的简单方法是为这最后一个点设计一个使用我们有值的点的不同公式。这就是所谓的向后差分公式。为了得到它,我们可以使用同样的直接方法,但现在使用三个点 ((x_{N},F_{N}))、((x_{N-1},F_{N-1})) 和 ((x_{N-2},F_{N-2})) 并在 ((x_{N},F_{N})) 处进行近似。以下是使用 SymPy 完成它的方法:
>>> from __future__ import print_function
>>> from sympy import *
>>> x, xN, h = symbols('x, x_N, h')
>>> FN, FNm1, FNm2 = symbols('F_{N}, F_{N-1}, F_{N-2}')
>>> n = 8 # there are the coefficients c_0=Fi, c_1=dF/h, c_2=d**2F/h**2
>>> c = symbols('c:8')
>>> # define a polynomial of degree d
>>> def P(x, x0, c, n):
... return sum( ((1/factorial(i))*c[i] * (x-x0)**i for i in range(n)) )
现在我们制作一个矩阵,其中包含 (c_i) 在第 (d) 次多项式 (P) 系数在 (x_i, x_{i-1}) 和 (x_{i+1}) 处的系数:
>>> m11 = P(xN , xN, c, n).diff(c[0])
>>> m12 = P(xN, xN, c, n).diff(c[1])
>>> m13 = P(xN , xN, c, n).diff(c[2])
>>> # coefficients of c_i evaluated at x_i - h
>>> m21 = P(xN-h, xN, c, n).diff(c[0])
>>> m22 = P(xN-h, xN, c, n).diff(c[1])
>>> m23 = P(xN-h, xN, c, n).diff(c[2])
>>> # coefficients of c_i evaluated at x_i + h
>>> m31 = P(xN-2*h, xN, c, n).diff(c[0])
>>> m32 = P(xN-2*h, xN, c, n).diff(c[1])
>>> m33 = P(xN-2*h, xN, c, n).diff(c[2])
接下来,我们构造 (3 \times 3) 系数矩阵:
>>> M = Matrix([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]])
>>> # matrix of the function values...actually a vector of right hand sides
>>> R = Matrix([[FN], [FNm1], [FNm2]])
然后我们反转 (M) 并写出 (3 \times 3) 系统的解。
三个方程式 (c_i) 的矩阵形式是 (M*C = R)。通过直接求逆 (M) 来获得解决方案:
>>> X = M.inv() * R
第一导数是系数 (c_1),即 (X[1])。因此,第一导数的二阶精确逼近是:
>>> print("The first derivative centered at the last point on the right is:")
The first derivative centered at the last point on the right is:
>>> print(together(X[1]))
(-4*F_{N-1} + F_{N-2} + 3*F_{N})/(2*h)
当然,我们可以为点集合左端的点 ((x_{1},F_{1})) 的导数值设计类似的公式,该公式以 ((x_{2},F_{2})) 和 ((x_{3},F_{3})) 的值为基础。
此外,我们注意到输出适合 Fortran、C 等格式的示例在上述示例中可能已经完成。
接下来,我们展示如何执行这些以及许多其他导数的离散化,但使用一种更有效的方法,最初由本特·弗恩伯格(Bengt Fornberg)提出,并已纳入 SymPy 中。
有限差分
有限差分权重
SymPy 对象的分类
原文:
docs.sympy.org/latest/explanation/special_topics/classification.html
SymPy 对象分类的几种方法。
类
就像 Python 中的任何其他对象一样,SymPy 表达式是一个类的实例。您可以使用内置的type()函数获取对象的类,并使用isinstance()函数进行检查。
>>> from sympy import Add
>>> from sympy.abc import x,y
>>> type(x + y)
<class 'sympy.core.add.Add'>
>>> isinstance(x + y, Add)
True
类仅代表对象的程序结构,并且不能区分它们之间的数学差异。例如,数字的积分和矩阵的积分都具有Integral类,尽管前者是数字,后者是矩阵。
>>> from sympy import MatrixSymbol, Integral
>>> A = MatrixSymbol('A', 2, 2)
>>> type(Integral(1, x))
<class 'sympy.integrals.integrals.Integral'>
>>> type(Integral(A, x))
<class 'sympy.integrals.integrals.Integral'>
种类
种类指示表达式表示什么数学对象。您可以使用.kind属性检索表达式的种类。
>>> Integral(1, x).kind
NumberKind
>>> Integral(A, x).kind
MatrixKind(NumberKind)
这个结果表明Integral(1, x)是一个数字,而Integral(A, x)是一个带有数字元素的矩阵。
由于类不能保证捕获这种差异,对象的种类非常重要。例如,如果您正在构建一个仅设计用于数字工作的函数或类,则应考虑使用NumberKind过滤参数,以便用户不会轻易传递不受支持的对象,例如Integral(A, x)。
出于性能考虑,种类系统中未实现集合论。例如,
NumberKind不能区分实数和复数。>>> from sympy import pi, I >>> pi.kind NumberKind >>> I.kind NumberKindSymPy 的
Set和种类是不兼容的。>>> from sympy import S >>> from sympy.core.kind import NumberKind >>> S.Reals.is_subset(S.Complexes) True >>> S.Reals.is_subset(NumberKind) Traceback (most recent call last): ... ValueError: Unknown argument 'NumberKind'
集合和假设
如果您想以严格的数学方式对对象进行分类,您可能需要使用 SymPy 的集合和假设。
>>> from sympy import ask, Q
>>> S.One in S.Reals
True
>>> ask(Q.even(2*x), Q.odd(x))
True
更多信息请参见assumptions模块和sets模块。
函数
func是对象的头,并且用于递归遍历表达式树。
>>> Add(x + y).func
<class 'sympy.core.add.Add'>
>>> Add(x + x).func
<class 'sympy.core.mul.Mul'>
>>> Q.even(x).func
<class 'sympy.assumptions.assume.AppliedPredicate'>
如您所见,生成的头可能是一个类,也可能是另一个 SymPy 对象。在使用此属性对对象进行分类时,请牢记这一点。详细信息请参见高级表达式操作。
活动弃用列表
原文:
docs.sympy.org/latest/explanation/active-deprecations.html
此页面列出了 SymPy 代码库中的所有活动弃用。请参阅弃用政策页面,了解 SymPy 的弃用政策说明以及贡献者如何弃用内容的说明。
特别是,SymPy 的弃用政策要求在包含弃用功能的首个主要发布版本之后至少保留1 year。此后,将可能从 SymPy 中移除弃用功能,需要更新代码以使用替代功能以继续工作。
在弃用期间,每当使用弃用功能时,将打印 SymPyDeprecationWarning 消息。建议用户更新其代码,使其不再使用弃用功能,具体方法如下所述,适用于每个给定的弃用。
消除 SymPy 弃用警告
要消除 SymPy 的弃用警告,请使用warnings模块添加过滤器。例如:
import warnings
from sympy.utilities.exceptions import SymPyDeprecationWarning
warnings.filterwarnings(
# replace "ignore" with "error" to make the warning raise an exception.
# This useful if you want to test you aren't using deprecated code.
"ignore",
# message may be omitted to filter all SymPyDeprecationWarnings
message=r"(?s).*<regex matching the warning message>",
category=SymPyDeprecationWarning,
module=r"<regex matching your module>"
)
这里的(?s).*<regex matching the warning message>是匹配警告消息的正则表达式。例如,要过滤有关sympy.printing的警告,可以使用message=r"(?s).*sympy\.printing"。前导的(?s).*是因为警告模块会将message与警告消息的开头匹配,而典型的警告消息跨越多行。
<regex matching your module> 应为与使用弃用代码的模块匹配的正则表达式。建议包括此内容,以避免将相同警告也应用于不相关的模块。
可以使用相同模式将 SymPyDeprecationWarning 替换为错误,以便测试不使用弃用代码。要执行此操作,请在上述示例中将 "ignore" 替换为 "error"。您还可以省略 message,以便将其应用于所有 SymPyDeprecationWarning 警告。
如果您使用 pytest,可以使用pytest 警告过滤功能来忽略 SymPyDeprecationWarning 或将其转换为错误。
注意
Python -W flag 和 PYTHONWARNINGS 环境变量 无法用于过滤 SymPy 弃用警告(请参阅 Ned Batchelder 的此篇博文和 SymPy 的此问题了解详细信息)。您需要添加类似上述的 warnings 过滤器或使用 pytest 来过滤 SymPy 弃用警告。
版本 1.13
弃用机制 Body 类
sympy.physics.mechanics 模块中的 Body 类已被弃用。它最初用于支持关节框架,但由于既表示刚体又表示粒子而导致多种问题。Body 现已完全由 RigidBody 和 Particle 替代。以前,只需使用 Body 类即可创建简单的刚体或粒子:
>>> from sympy import symbols
>>> from sympy.physics.mechanics import Body
>>> Body("rigid_body")
rigid_body
>>> Body("particle", mass=symbols("m"))
particle
现在应使用 RigidBody 和 Particle 类创建:
>>> from sympy.physics.mechanics import RigidBody, Particle
>>> RigidBody("rigid_body")
rigid_body
>>> Particle("particle")
particle
``` ### 弃用的力学 JointsMethod
`sympy.physics.mechanics` 模块中的 `JointsMethod` 类已被弃用。它最初用于支持关节框架,但由于设计上的限制已被完全替换。以前,可以构建仅由体和关节组成的系统,然后由 `JointsMethod` 解析到后端,例如 `KanesMethod` 以形成运动方程。
```py
>>> from sympy import symbols
>>> from sympy.physics.mechanics import (
... Body, JointsMethod, PinJoint, PrismaticJoint)
>>> g, l = symbols("g l")
>>> wall = Body("wall")
>>> cart = Body("cart")
>>> pendulum = Body("Pendulum")
>>> slider = PrismaticJoint("s", wall, cart, joint_axis=wall.x)
>>> pin = PinJoint("j", cart, pendulum, joint_axis=cart.z,
... child_point=l * pendulum.y)
>>> pendulum.masscenter.set_vel(pendulum.frame, 0)
>>> cart.apply_force(-g * cart.mass * wall.y)
>>> pendulum.apply_force(-g * pendulum.mass * wall.y)
>>> method = JointsMethod(wall, slider, pin)
>>> method.form_eoms()
Matrix([
[ Pendulum_mass*l*u_j(t)**2*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_j(t), t) - (Pendulum_mass + cart_mass)*Derivative(u_s(t), t)],
[-Pendulum_mass*g*l*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_s(t), t) - (Pendulum_izz + Pendulum_mass*l**2)*Derivative(u_j(t), t)]])
JointsMethod 的替代方案是 System,可用于形成相同小车摆杆的运动方程,如下所示:
>>> from sympy import symbols
>>> from sympy.physics.mechanics import (
... Particle, PinJoint, PrismaticJoint, RigidBody, System)
>>> g, l = symbols("g l")
>>> wall = RigidBody("wall")
>>> cart = RigidBody("cart")
>>> pendulum = RigidBody("Pendulum")
>>> slider = PrismaticJoint("s", wall, cart, joint_axis=wall.x)
>>> pin = PinJoint("j", cart, pendulum, joint_axis=cart.z,
... child_point=l * pendulum.y)
>>> system = System.from_newtonian(wall)
>>> system.add_joints(slider, pin)
>>> system.apply_uniform_gravity(-g * wall.y)
>>> system.form_eoms()
Matrix([
[ Pendulum_mass*l*u_j(t)**2*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_j(t), t) - (Pendulum_mass + cart_mass)*Derivative(u_s(t), t)],
[-Pendulum_mass*g*l*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_s(t), t) - (Pendulum_izz + Pendulum_mass*l**2)*Derivative(u_j(t), t)]])
``` ### 弃用的矩阵混合类
矩阵混合类已弃用。以前的 `Matrix` 类(又名 `MutableDenseMatrix`)通过继承层次结构创建,看起来像:
```py
class MatrixRequired:
class MatrixShaping(MatrixRequired):
class MatrixSpecial(MatrixRequired):
class MatrixProperties(MatrixRequired):
class MatrixOperations(MatrixRequired):
class MatrixArithmetic(MatrixRequired):
class MatrixCommon(
MatrixArithmetic,
MatrixOperations,
MatrixProperties,
MatrixSpecial,
MatrixShaping):
class MatrixDeterminant(MatrixCommon):
class MatrixReductions(MatrixDeterminant):
class MatrixSubspaces(MatrixReductions):
class MatrixEigen(MatrixSubspaces)
class MatrixCalculus(MatrixCommon):
class MatrixDeprecated(MatrixCommon):
class MatrixBase(MatrixDeprecated,
MatrixCalculus,
MatrixEigen,
MatrixCommon,
Printable):
class RepMatrix(MatrixBase):
class DenseMatrix(RepMatrix):
class MutableRepMatrix(RepMatrix):
class MutableDenseMatrix(DenseMatrix, MutableRepMatrix):
自 SymPy 1.13 起,所有类都已简化,以上 MatrixBase 的类被合并在一起,层次结构如下:
class MatrixBase(Printable):
class RepMatrix(MatrixBase):
class DenseMatrix(RepMatrix):
class MutableRepMatrix(RepMatrix):
class MutableDenseMatrix(DenseMatrix, MutableRepMatrix):
像 MatrixRequired 等矩阵混合类仍然可用,因为下游代码可能正在对这些类进行子类化,但这些类均已弃用,并将在未来版本的 SymPy 中移除。对这些类的子类化已被弃用,任何这样做的代码应修改为不再子类化它们。
使用 isinstance 与 MatrixCommon 这样的类也已被弃用,例如 isinstance(M, MatrixCommon)。任何使用此方法的代码应改为使用 isinstance(M, Matrixbase),这也适用于先前的 SymPy 版本。
更一般地,导入 sympy.matrices.common 或 sympy.matrices.matrices 模块中的任何内容都已弃用,这些模块将在未来的 SymPy 发布中移除。
这一变更的原因是复杂的继承层次结构使得很难改进大多数用户的 Matrix,同时仍提供可以作为子类的所有这些类。由于这些混合类不再作为 Matrix 的一部分使用,它们在 SymPy 中不再起任何作用,移除现在未使用的代码将简化代码库。### sympify() 中的字符串回退
sympify 函数过去会将未识别的对象转换为字符串并重试 sympification。这在 SymPy 1.6 中已弃用,并在 SymPy 1.13 中移除。
sympify() 的行为是,sympify(expr) 尝试各种方法将 expr 转换为 SymPy 对象。以前,如果所有这些方法都失败了,它会取 str(expr) 并尝试使用 parse_expr() 进行解析。这个字符串回退功能在 SymPy 1.6 中已弃用,并在 SymPy 1.13 中删除。
这种行为存在几个问题:
-
它可能会严重影响性能。例如,参见问题 #18056 和 #15416,在这些问题中,它导致了高达 100 倍的减速。问题在于 SymPy 函数会自动对其参数调用
sympify。每当一个函数被传递一个sympify不知道如何转换为 SymPy 对象的东西,例如一个 Python 函数类型,它会将字符串传递给parse_expr()。这比默认发生的直接转换慢得多。这在库代码中使用sympify()而不是_sympify()(或等效的sympify(strict=True))时特别发生。在某个时候,对所有库代码使用strict=True将成为默认设置,但这是一个更难的变更,参见 harder change to make。 -
使用
eval可能会引起安全问题,因为字符串是被求值的,并且对象可以在其__repr__中返回任意字符串。参见github.com/sympy/sympy/pull/12524。 -
它一开始就不是很有用。仅仅因为一个对象的字符串形式可以解析为 SymPy 表达式并不意味着它应该以这种方式解析。这通常适用于自定义数值类型,但是一个对象的 repr 可以是任何东西。例如,如果一个对象的字符串形式看起来像一个有效的 Python 标识符,它将被解析为
Symbol。
有很多方法可以使自定义对象在 sympify() 内部工作。
-
首先,如果一个对象旨在与其他 SymPy 表达式一起工作,它应该从
Basic(或Expr)继承。如果是这样,sympify()将直接返回它,因为它已经是一个有效的 SymPy 对象。 -
对于您控制的对象,可以添加
_sympy_方法。sympify docstring 中有一个示例。 -
对于您无法控制的对象,您可以向
sympy.core.sympify.converter字典中添加自定义转换器。sympify()的文档字符串中也有一个示例。 ### 弃用 DMP.rep 属性。
Poly 的内部类型是 DMP 类,之前可以用来作为多项式系数的列表访问:
>>> from sympy import symbols, Poly
>>> x = symbols('x')
>>> p = Poly(x**2 + 2*x + 3)
>>> p
Poly(x**2 + 2*x + 3, x, domain='ZZ')
>>> p.rep
DMP([1, 2, 3], ZZ)
>>> p.rep.rep
[1, 2, 3]
自 SymPy 1.13 版本开始,DMP 类型可以由以下两个子类之一实现:
-
DMP_Python类似于之前的DMP类型,并且其内部表示为列表的形式。 -
DUP_Flint封装了来自 python-flint 的 Flint 多项式。
DUP_Flint 类型没有类似于 DMP_Python 的列表属性。访问 .rep 仍会生成一个列表,但现在会生成弃用警告。
不再使用 .rep,而是使用返回等效列表的 DMP.to_list() 方法:
>>> p.rep.to_list()
[1, 2, 3]
.to_list() 方法在 SymPy 的早期版本中也是可用的,其行为没有改变。 ### 弃用 pkgdata 模块
sympy.utilities.pkdata 模块已经被废弃并将被移除。在 SymPy 中它已不再使用,也不适合任何下游代码使用。请使用标准库中的 importlib.resources 模块。 ### 弃用 Eq.rewrite(Add)
可以像 eq = Eq(x, y) 一样重写 eq.rewrite(Add) 以得到 x - y 已经被废弃,现在应该写成 eq.lhs - eq.rhs。考虑到显式使用 lhs 和 rhs 的清晰度,不再认为需要替换属性/方法,并且将此功能包含在重写装置中导致期望布尔值的节点重写为表达式时失败。 ### 弃用标记,注释,填充,图类的矩形
包含用户提供的数值数据以添加到绘图上的 markers, annotations, fill, rectangles 属性已被弃用。新的实现将用户提供的数值数据保存到适当的数据系列中,可以轻松地由 MatplotlibBackend 处理。用户不应直接设置这些属性,而应将同名关键字参数传递给绘图函数。
支持的行为是将关键字参数传递给绘图函数,这对 SymPy 的所有版本(1.13 之前和之后)都适用:
p = plot(x,
markers=[{"args":[[0, 1], [0, 1]], "marker": "*", "linestyle": "none"}],
annotations=[{"text": "test", "xy": (0, 0)}],
fill={"x": [0, 1, 2, 3], "y1": [0, 1, 2, 3]},
rectangles=[{"xy": (0, 0), "width": 5, "height": 1}])
设置绘图对象的属性已被弃用,并将引发警告:
p = plot(x, show=False)
p.markers = [{"args":[[0, 1], [0, 1]], "marker": "*", "linestyle": "none"}]
p.annotations = [{"text": "test", "xy": (0, 0)}]
p.fill = {"x": [0, 1, 2, 3], "y1": [0, 1, 2, 3]}
p.rectangles = [{"xy": (0, 0), "width": 5, "height": 1}]
p.show()
引入此弃用的动机:Plot 类的实现表明,可以在 MatplotlibBackend 类中添加属性和硬编码的 if 语句来为用户提供更多功能,例如添加水平线、垂直线或条形图等。然而,这样做等于重复造轮子:绘图库已经实现了必要的 API。没有必要硬编码这些内容。绘图模块应该便于可视化符号表达式。添加自定义数值数据的最佳方法是检索由绘图模块创建的图,并使用特定绘图库的 API。例如:
# plot symbolic expression
p = plot(cos(x))
# retrieve Matplotlib's figure and axes object
fig, ax = p._backend.fig, p._backend.ax[0]
# add the desired numerical data using Matplotlib's API
ax.plot([0, 1, 2], [0, 1, -1], "*")
ax.axhline(0.5)
# visualize the figure
fig
``` ### 移动的力学函数
随着`sympy.physics.mechanics`模块中引入一些新对象如`Inertia`和负载对象,一些函数从`sympy.physics.mechanics.functions`已移动到新模块。这消除了一些循环导入错误,并使得通过函数名和模块名之间的对等性更容易导航源代码。以下函数已移动:
+ `inertia` 已经移动到 `sympy.physics.mechanics.inertia`
+ `inertia_of_point_mass` 已经移动到 `sympy.physics.mechanics.inertia`
+ `gravity` 已经移动到 `sympy.physics.mechanics.loads`
之前可以从 `sympy.physics.mechanics.functions` 导入函数:
```py
>>> from sympy.physics.mechanics.functions import inertia, inertia_of_point_mass, gravity
现在应该从 sympy.physics.mechanics 导入它们:
>>> from sympy.physics.mechanics import inertia, inertia_of_point_mass
>>> from sympy.physics.mechanics.loads import gravity
``` ### 带模数整数的有序比较如 `a < b`
SymPy 的`GF`域表示模数整数。以前可以用像 `a < b` 这样的有序比较来比较它们:
```py
>>> from sympy import GF
>>> F5 = GF(5)
>>> F5(2) < F5(3)
True
当设置的地面类型为flint时,这将导致TypeError。当地面类型不是flint时,这些比较现在已弃用:它们仍然有效,但在使用时会给出弃用警告。
模数整数或有限域的有序比较是没有意义的,因为这些不是有序域:
>>> e = F5(4)
>>> e + 1 > e
False
``` ### `ModularInteger.to_int()` 方法
SymPy 的`GF`域用于模数整数,例如`GF(n)`是模数`n`的整数,并且可以像这样使用:
```py
>>> from sympy import GF
>>> K = GF(5)
>>> a = K(7)
>>> a
2 mod 5
模数整数域的元素有一个自 SymPy 1.13 版起已弃用的to_int()方法:
>>> # this is deprecated:
>>> a.to_int()
2
相反,实现等效行为的首选方法是使用域上的方法(自 SymPy 1.13 版起添加)或者可能更好的是调用 int:
>>> K.to_int(a)
2
>>> int(a)
2
这两种转换为int的方法并不等效。域GF(p)可以使用symmetric=True或symmetric=False定义。这种差异会影响to_int方法的行为:
>>> KS = GF(5, symmetric=True)
>>> KU = GF(5, symmetric=False)
>>> [KS.to_int(KS(n)) for n in range(10)]
[0, 1, 2, -2, -1, 0, 1, 2, -2, -1]
>>> [KU.to_int(KU(n)) for n in range(10)]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
>>> [int(KS(n)) for n in range(10)]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
>>> [int(KU(n)) for n in range(10)]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
所以如果 symmetric=True(这是默认值),to_int 方法有时会返回负整数。如果 symmetric=False 或者使用 int(a) 方法,返回的结果总是非负整数。还要注意,int(a) 的行为在 SymPy 1.13 中已更改:在先前的版本中,它等同于 a.to_int()。为了编写在所有 SymPy 版本中行为一致的代码,您可以:
-
使用
symmetric=False并使用int(a)。 -
定义一个函数,如
def to_int(K, a): if hasattr(K, 'to_int'): return K.to_int(a) else: return a.to_int()
这种改变的原因是,这样做可以使用 python-flint 的 nmod 作为 GF(p) 的元素的替代(更快)实现。不可能向 python-flint 的 nmod 类型添加 to_int 方法,或者通过在 nmod 实例中存储数据来捕获 symmetric=True/False 的等价物。弃用和移除 to_int 方法并改变 int 方法的行为意味着元素实例没有任何取决于域是否被视为“对称”的行为。相反,“对称”的概念现在纯粹是域对象自身的属性,而不是元素的属性,因此取决于这一点的 to_int 方法必须是一个域方法而不是元素方法。### 将 ntheory 中的符号函数移至 functions
ntheory 中的以下符号函数已经移动到 functions:
-
sympy.ntheory.factor_.divisor_sigma -
sympy.ntheory.factor_.primenu -
sympy.ntheory.factor_.primeomega -
sympy.ntheory.factor_.reduce_totient -
sympy.ntheory.factor_.totient -
sympy.ntheory.generate.primepi -
sympy.partitions_.npartitions -
sympy.ntheory.residue_ntheory.jacobi_symbol -
sympy.ntheory.residue_ntheory.legendre_symbol -
sympy.ntheory.residue_ntheory.mobius
从顶层导入这些函数的代码,比如 from sympy import mobius 仍然可以正常工作。但是从完全合格的模块导入这些函数的代码,比如 from sympy.ntheory import mobius 或者 from sympy.ntheory.residue_ntheory import mobius 现在会看到一个弃用警告。这些函数的新位置在 sympy.functions 中,但是导入它们的预期方式仍然是从顶层,比如 from sympy import mobius。
ntheory 中的以下符号函数已经移动到 functions,但无法在顶层导入。
sympy.ntheory.factor_.udivisor_sigma
以下函数从 functions 移动到 ntheory,因为它们是数值函数。
-
sympy.functions.combinatorial.numbers.carmichael.is_carmichael -
sympy.functions.combinatorial.numbers.carmichael.find_carmichael_numbers_in_range -
sympy.functions.combinatorial.numbers.carmichael.find_first_n_carmichaels
如果你在使用这些函数,请从
>>> from sympy import carmichael
>>> carmichael.is_carmichael(561)
True
到
>>> from sympy import is_carmichael
>>> is_carmichael(561)
True
版本 1.12
ManagedProperties 元类
ManagedProperties元类以前是Basic的元类。现在Basic不再使用元类,因此其元类只是type。任何以前子类化Basic并希望使用元类的代码都需要子类化ManagedProperties以使用相关的元类。ManagedProperties的唯一相关方法已移至Basic.__init_subclass__。由于ManagedProperties不再作为Basic的元类使用,并且不再做任何有用的事情,因此此类代码现在可以仅仅子类化type来代替任何元类。### 新关节坐标格式
泛化坐标和泛化速度的格式,即关节在sympy.physics.mechanics模块中的类型和自动生成的名称,已经发生了变化。数据类型已从list改变为Matrix,与KanesMethod中泛化坐标的类型相同。PinJoint和PrismaticJoint的泛化坐标和泛化速度的自动命名也已更改为q_<joint.name>和u_<joint.name>。以前,每个关节都有一个独特的模板来自动生成这些名称。### 新关节中间框架
sympy.physics.mechanics模块中关节轴的定义已更改。现在,不再使用参数parent_axis和child_axis来自动确定关节轴和中间参考框架,而是关节现在同时使用了父体和子体的中间框架参数,即parent_interframe和child_interframe。这意味着您现在可以完全定义两个体的关节附着点和框架。此外,如果像PinJoint这样的关节有特定的关节轴,例如旋转发生的轴线,则可以使用joint_axis参数来指定此轴。此设置的优势在于可以更准确地定义从父体到子体的变换。
例如,假设您想要一个PinJoint来使子体绕parent.z轴和-child.z轴旋转。以前指定这个关节的方式是:
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_axis=parent.z,
... child_axis=-child.z)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)), 0],
[-sin(q_pin(t)), cos(q_pin(t)), 0],
[ 0, 0, -1]])
检查此矩阵时,您会注意到对于theta_pin = 0,子体围绕parent.y轴旋转(\pi)弧度。在新定义中,我们可以看到得到相同结果,但这次我们还指定了这个确切的旋转:
>>> from sympy import pi
>>> from sympy.physics.mechanics import Body, PinJoint, ReferenceFrame
>>> parent, child, = Body('parent'), Body('child')
>>> int_frame = ReferenceFrame('int_frame')
>>> int_frame.orient_axis(child.frame, child.y, pi)
>>> pin = PinJoint('pin', parent, child, joint_axis=parent.z,
... child_interframe=int_frame)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)), 0],
[-sin(q_pin(t)), cos(q_pin(t)), 0],
[ 0, 0, -1]])
但是,如果您喜欢废弃参数对齐框架的功能,那么您仍然可以通过向parent_interframe和child_interframe提供向量来使用此功能,然后这些向量将被定向,以便在中间框架中表示的关节轴与给定向量对齐:
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_interframe=parent.z,
... child_interframe=-child.z)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)), 0],
[-sin(q_pin(t)), cos(q_pin(t)), 0],
[ 0, 0, -1]])
```### 关节附着点参数变更
在 `sympy.physics.mechanics` 中指定关节附着点的参数名已更改为 `parent_point` 和 `child_point`,即 `parent_joint_pos` 和 `child_joint_pos`。这是因为这些参数现在也可以是 `Point` 对象,因此它们可以与 `parent_point` 和 `child_point` 属性完全相同。
例如,假设您希望 `PinJoint` 在父级中被定位在 `parent.frame.x` 处相对于质心,在子级中为 `-child.frame.x`。以前指定这一点的方式是:
```py
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_joint_pos=parent.frame.x,
... child_joint_pos=-child.frame.x)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x
现在你可以用同样的方式来处理
>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_point=parent.frame.x,
... child_point=-child.frame.x)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x
或者
>>> from sympy.physics.mechanics import Body, PinJoint, Point
>>> parent, child = Body('parent'), Body('child')
>>> parent_point = parent.masscenter.locatenew('parent_point', parent.frame.x)
>>> child_point = child.masscenter.locatenew('child_point', -child.frame.x)
>>> pin = PinJoint('pin', parent, child, parent_point=parent_point,
... child_point=child_point)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x
版本 1.11
模块 sympy.tensor.array.expressions.conv_* 重命名为 sympy.tensor.array.expressions.from_*
为了避免可能与模块同名函数的命名和制表完成冲突,sympy.tensor.array.expressions 中所有名称以 conv_* 开头的模块已重命名为 from_*。 ### 新的 Mathematica 代码解析器
在模块 sympy.parsing.mathematica 中定义的旧 Mathematica 代码解析器已被弃用。应改用具有新的更全面解析器的 parse_mathematica 函数。
Mathematica 解析器的 parse_mathematica 函数中不可用的 additional_translations 参数。应在使用 SymPy 的 .replace() 或 .subs() 方法转换后,指定将 Mathematica 表达式转换为 SymPy 表达式的附加转换规则。如果翻译器无法识别 Mathematica 表达式的逻辑含义,则将返回类似 Mathematica 的完整形式,使用 SymPy 的 Function 对象来编码语法树的节点。
例如,假设您希望 F 是一个返回最大值乘以最小值的函数,以前指定此转换的方法是:
>>> from sympy.parsing.mathematica import mathematica
>>> mathematica('F[7,5,3]', {'F[*x]': 'Max(*x)*Min(*x)'})
21
现在你可以用同样的方式做到
>>> from sympy.parsing.mathematica import parse_mathematica
>>> from sympy import Function, Max, Min
>>> parse_mathematica("F[7,5,3]").replace(Function("F"), lambda *x: Max(*x)*Min(*x))
21
``` ### `carmichael` 中冗余的静态方法
在 `~.carmichael` 中的一些静态方法只是其他函数的包装器。例如,代替 `carmichael.is_perfect_square` 使用 `sympy.ntheory.primetest.is_square`,代替 `carmichael.is_prime` 使用 `~.isprime`。最后,`carmichael.divides` 可以替换为检查
```py
n % p == 0
``` ### 对 `HadamardProduct`、`MatAdd` 和 `MatMul` 的 `check` 参数
这个参数可以用来传递给 `~.HadamardProduct`、`~.MatAdd` 和 `~.MatMul` 的错误值,从而导致后续问题。`check` 参数将被移除,并且参数将始终被检查正确性,即参数是矩阵或矩阵符号。
## 版本 1.10
### 一些遍历函数已经移动
一些遍历函数已经移动。具体来说,这些函数
+ `bottom_up`
+ `interactive_traversal`
+ `postorder_traversal`
+ `preorder_traversal`
+ `use`
已移动到不同的 SymPy 子模块。
这些函数应该从顶级的 `sympy` 命名空间中使用,比如
```py
sympy.preorder_traversal
或者
from sympy import preorder_traversal
通常情况下,最终用户应该使用顶级 sympy 命名空间中存在的任何函数。如果一个名称在顶级命名空间中,不应依赖于其特定的 SymPy 子模块,因为由于内部重构,函数可能会移动。 ### sympy.core.trace
追踪对象 sympy.core.trace.Tr() 已经移至 sympy.physics.quantum.trace.Tr()。这是因为它仅在 sympy.physics.quantum 子模块中使用,所以将其放在那里比放在核心模块中更合适。 ### sympy.core.compatibility 子模块
sympy.core.compatibility 子模块已经被弃用。
此子模块最初仅用于内部使用。由于 SymPy 不再支持 Python 2,因此此模块已不再必要,并且剩余的辅助函数已移至 SymPy 代码库中更方便的位置。
此模块中的一些函数现在可以从顶级 SymPy 命名空间中获取,即,
sympy.ordered
sympy.default_sort_key
或
from sympy import ordered, default_sort_key
通常情况下,最终用户应该使用顶级 sympy 命名空间中存在的任何函数。如果一个名称在顶级命名空间中,不应依赖于其特定的 SymPy 子模块,因为由于内部重构,函数可能会移动:
sympy.core.compatibility 中剩余的函数仅供内部 SymPy 使用,不应该被用户代码使用。
此外,这两个函数 ordered 和 default_sort_key 也曾在 sympy.utilities.iterables 中,但它们也已经从那里移动。
版本 1.9
expr_free_symbols
各种 SymPy 对象的 expr_free_symbols 属性已经被弃用。
expr_free_symbols 被设计为表示像 MatrixElement 和 Indexed 这样的索引对象作为自由符号。这旨在使自由符号的导数工作。然而,现在即使不使用该方法也能正常工作:
>>> from sympy import Indexed, MatrixSymbol, diff
>>> a = Indexed("A", 0)
>>> diff(a**2, a)
2*A[0]
>>> X = MatrixSymbol("X", 3, 3)
>>> diff(X[0, 0]**2, X[0, 0])
2*X[0, 0]
这是一个通用属性,旨在解决一个非常具体的问题,但它增加了不必要的抽象层。
-
对于已经具有结构化“非表达式”节点的对象,如果需要,可以直接专注于表达式节点,例如。
>>> from sympy import Derivative, symbols, Function >>> x = symbols('x') >>> f = Function('f') >>> Derivative(f(x), x).expr f(x)引入此属性会在请求自由符号时鼓励不精确的思考,因为它允许从对象的特定节点获取符号而不必指定节点。
-
该属性被错误地添加到
AtomicExpr,因此数字被返回为expr_free_symbols:>>> S(2).expr_free_symbols 2 -
应用这个概念来定义
Subs.expr_free_symbols是错误的:它增加了点的expr_free_symbols但是点是一个Tuple,因此没有添加任何内容。 -
它在代码库中除了在不同 iating
Subs对象的上下文中未被使用外,这表明它并非通用用途,这也由以下事实确认: -
它是在未进行具体测试的情况下添加的,除了引入它的
Subs对象的导数测试外。
更多讨论请参见问题#21494。 ### sympy.stats.sample(numsamples=n)
sympy.stats.sample()的numsamples参数已弃用。
numsamples使得sample()返回大小为numsamples的列表,例如:
>>> from sympy.stats import Die, sample
>>> X = Die('X', 6)
>>> sample(X, numsamples=3)
[3, 2, 3]
然而,用户可以通过列表推导轻松实现此功能。
>>> [sample(X) for i in range(3)]
[5, 4, 3]
此外,它与size参数重复,使得sample返回一个具有给定形状的 NumPy 数组。
>>> sample(X, size=(3,))
array([6, 6, 1])
历史上,SymPy 1.7 中更改了sample,使其返回迭代器而不是样本值。因此,添加了一个numsamples参数来指定迭代器的长度。
然而,由于在问题#21563中讨论的混乱,这种新行为被撤销了。现在,如果需要迭代器,则应使用sample_iter。因此,sample()不再需要numsamples参数。 ### sympy.polys.solvers.RawMatrix
RawMatrix类已弃用。RawMatrix类是Matrix的子类,其使用域元素而不是Expr作为矩阵的元素。这违反了Matrix的关键内部不变量,并且这种子类化限制了对Matrix类的改进。
SymPy 唯一文档化使用RawMatrix类的部分是 Smith 正常形式代码,现在已更改为使用DomainMatrix。建议任何使用RawMatrix以前的 Smith 正常形式代码的人切换到使用问题#21402中显示的DomainMatrix。稍后将添加更好的 Smith 正常形式 API。 ### 非Expr对象在矩阵中
在 SymPy 1.8 及更早版本中,可以在Matrix中放置非Expr元素,并且矩阵元素可以是任意的 Python 对象:
>>> M = Matrix([[(1, 2), {}]])
这并不实用,实际上并不起作用,例如:
>>> M + M
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'Dict' and 'Dict'
允许此功能的主要原因是 SymPy 代码库中有许多Matrix子类希望使用 polys 模块中的对象,例如:
-
RawMatrix(见上文)在solve_lin_sys中被使用,这是heurisch的一部分,并且也被smith_normal_form使用。NewMatrix类使用域元素作为矩阵的元素,而不是Expr。 -
NewMatrix在holonomic模块中被使用,并且还使用域元素作为矩阵的元素。 -
PolyMatrix将Poly和Expr混合作为矩阵元素,并被risch使用。
所有这些矩阵子类都以不同的方式损坏,并且引入了 DomainMatrix (#20780, #20759, #20621, #19882, #18844) 提供了所有情况的更好解决方案。以前的 PR 已经移除了这些其他用例对 Matrix 的依赖 (#21441, #21427, #21402),现在 #21496 已经废弃了在 Matrix 中使用非Expr元素的做法。
这一变更使得可以改进 Matrix 类的内部,但可能对一些下游用例产生影响,这些用例可能与 SymPy 代码库中使用非Expr元素的 Matrix 使用方式类似。如果希望用类似域元素和域对象可以为其提供的元素替换使用 Matrix 的代码,请使用 DomainMatrix。或者,如果目标只是打印支持,则可能可以使用 TableForm。
没有清楚的建议可以在此处替换,除非了解更多关于用例的信息。如果不清楚如何更新您的代码,请提出问题或写信到我们的邮件列表,以便讨论。 ### 绘图对象的 get_segments 属性
Line2DBaseSeries 中实现的 get_segments 方法用于将 x 和 y 两个坐标列表转换为 Matplotlib 的 LineCollection 绘制线段所需的段列表。
由于段列表仅由 Matplotlib 需要(例如,Bokeh、Plotly、Mayavi、K3D 只需要坐标列表),因此这一改变已经移至 MatplotlibBackend 类内部。
注意之前,get_points() 方法总是返回均匀采样的点,这意味着当使用 get_points() 和 Matplotlib 绘图时,一些函数未能正确绘制。
要避免这个问题,可以使用get_segments()方法,它使用自适应采样,并可以与 Matplotlib 的LineCollection一起使用。但是,现在也可以使用get_points()进行自适应采样。可以使用get_data()方法。### sympy.physics.matrices中的mdft函数
sympy.physics.matrices.mdft()函数已弃用。可以用sympy.matrices.expressions.fourier中的DFT类替换。
特别是,用DFT(n).as_explicit()替换mdft(n)。例如:
>>> from sympy.physics.matrices import mdft
>>> mdft(3) # DEPRECATED
Matrix([
[sqrt(3)/3, sqrt(3)/3, sqrt(3)/3],
[sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3, sqrt(3)*exp(2*I*pi/3)/3],
[sqrt(3)/3, sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]])
>>> from sympy.matrices.expressions.fourier import DFT
>>> DFT(3)
DFT(3)
>>> DFT(3).as_explicit()
Matrix([
[sqrt(3)/3, sqrt(3)/3, sqrt(3)/3],
[sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3, sqrt(3)*exp(2*I*pi/3)/3],
[sqrt(3)/3, sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]])
这种变化是因为sympy.physics子模块只应包含与物理有关的内容,但离散傅立叶变换矩阵是一个更一般的数学概念,因此最好放在sympy.matrices模块中。此外,DFT类是一个矩阵表达式,这意味着它可以未评估并支持符号形状。### SparseMatrix._smat和DenseMatrix._mat私有属性
Matrix的._mat属性和SparseMatrix的._smat属性已弃用。
Matrix和SparseMatrix的内部表示已更改为#21626中的DomainMatrix,因此不再可能将可变列表/字典暴露为突变Matrix的一种方式。新的.flat()方法可以使用,它返回一个新列表,不能用于突变Matrix本身。可以使用.todok()方法而不是._smat。
请注意,这些属性在 SymPy 1.9 中已更改为返回只读副本,因此依赖于突变它们的任何代码将会失败。此外,这些属性在技术上始终是私有的(它们以下划线开头),因此用户代码在第一次使用它们时不应该真的使用它们。### Matrix 的 laplace_transform 与 noconds=False
在版本 1.9 之前,在一个带有noconds=False(默认情况)的Matrix上调用laplace_transform()会导致元组的矩阵:
>>> from sympy import laplace_transform, symbols, eye
>>> t, z = symbols('t z')
>>> laplace_transform(eye(2), t, z)
Matrix([
[(1/z, 0, True), (0, 0, True)],
[ (0, 0, True), (1/z, 0, True)]])
但是,Matrix仅设计用于与Expr对象一起工作(见上面的 Matrix 中的非 Expr 对象)。
为了避免这种情况,可以使用noconds=True来移除收敛条件。
>>> laplace_transform(eye(2), t, z, noconds=True)
Matrix([
[1/z, 0],
[ 0, 1/z]])
或者使用legacy_matrix=False来返回新的行为,即在第一个参数中返回矩阵,并将收敛条件组合为整个矩阵的单一条件。
>>> laplace_transform(eye(2), t, z, legacy_matrix=False)
(Matrix([
[1/z, 0],
[ 0, 1/z]]), 0, True)
当此废弃项被移除时,legacy_matrix=False行为将成为默认值,但标志将保留以确保兼容性。
版本 1.8
sympy.printing.theanocode
Theano已停止,并分支成一个名为Aesara的新项目。sympy.printing.theanocode模块已重命名为sympy.printing.aesaracode,并且所有对应的函数也已重命名(例如,theano_code已重命名为aesara_code(),TheanoPrinter已重命名为AesaraPrinter等)。 ### sympy.assumptions.handlers.AskHandler和相关方法
Predicate经历了重大设计变化。先前,其处理程序是AskHandler类的列表,并通过add_handler()和remove_handler()函数进行注册。现在,其处理程序是一个multipledispatch实例,并通过register()或register_many()方法进行注册。用户必须定义一个谓词类来引入新的谓词。
先前,处理程序是通过以下方式定义和注册的:
class AskPrimeHandler(AskHandler):
@staticmethod
def Integer(expr, assumptions):
return expr.is_prime
register_handler('prime', AskPrimeHandler)
应该更改为这样:
# Predicate definition.
# Not needed if you are registering the handler to existing predicate.
class PrimePredicate(Predicate):
name = 'prime'
Q.prime = PrimePredicate()
# Handler registration
@Q.prime.register(Integer)
def _(expr, assumptions):
return expr.is_prime
见 GitHub 问题#20209。
版本 1.7.1
使用RandomIndexedSymbol调用sympy.stats.StochasticProcess.distribution
sympy.stats的distribution方法曾接受RandomIndexedSymbol(即按时间戳索引的随机过程),但现在应仅在时间戳下调用。
例如,如果您有
>>> from sympy import symbols
>>> from sympy.stats import WienerProcess
>>> W = WienerProcess('W')
>>> t = symbols('t', positive=True)
以前这样可以工作
W.distribution(W(t)) # DEPRECATED
现在应该这样调用
>>> W.distribution(t)
NormalDistribution(0, sqrt(t))
这一更改是作为存储只有sympy.stats中的Basic对象的.args的更改的一部分进行的。有关详情,请参见问题#20078。
版本 1.7
sympy.stats.DiscreteMarkovChain.absorbing_probabilities()
absorbing_probabilites方法名称拼写错误。正确的拼写是absorbing_probabilities()(“absorbing probabilities”)应该被使用。
函数sympy.utilities.misc.find_executable()已被弃用。而应使用标准库中自 Python 3.3 起就存在的shutil.which()函数,这更为强大。### sympy.diffgeom中的可变属性
多个部分在sympy.diffgeom中已更新,不再可变,这与 SymPy 其他部分使用的不可变设计更匹配。
-
传递给
CoordSystem的符号名称字符串已被弃用。相反,您应该明确地传递带有适当假设的符号,例如,而不是CoordSystem(name, patch, ['x', 'y']) # DEPRECATED使用
CoordSystem(name, patch, symbols('x y', real=True)) -
类似地,
names关键字参数已重命名为symbols,应为符号列表。 -
Manifold.patches属性已被弃用。应该单独跟踪补丁。 -
Patch.coord_systems属性已被弃用。应该单独跟踪坐标系。 -
CoordSystem.transforms属性,CoordSystem.connect_to()方法以及CoordSystem.coord_tuple_transform_to()方法已被弃用。应使用CoordSystem类构造函数的relations关键字以及CoordSystem.transformation()和CoordSystem.transform()方法(参见CoordSystem的文档字符串以获取示例)。###sympy.printing.pretty.stringpict.prettyForm和sympy.printing.pretty.pretty_symbology.xstr函数的unicode参数和属性
sympy.printing.pretty.pretty_symbology.xstr函数以及sympy.printing.pretty.stringpict.prettyForm的unicode参数和属性都是为了支持 Python 2 的 Unicode 行为而存在的。由于 Python 3 中 Unicode 字符串是默认的,这些不再需要。应将xstr()替换为str(),省略prettyForm的unicode参数,并用prettyForm.s属性替换prettyForm.unicode属性。### 将参数作为lambdify的set传递
传递函数参数作为lambdify的集合已被弃用。应作为列表或元组传递它们。例如,而不是
lambdify({x, y}, x + 2*y) # WRONG
使用
lambdify((x, y), x + 2*y) # RIGHT
这是因为集合是无序的。 例如,在上面的示例中,lambidfy无法知道它是否以{x, y}或{y, x}调用。 因此,当作为集合传递参数时,lambdify必须猜测它们的顺序,如果猜测错误,将导致函数不正确。 ### 核心运算符不再接受非 Expr 参数
核心操作类Add,Mul和Pow现在不能直接使用非Expr子类的对象构造。
Expr是所有表示标量数值数量的 SymPy 类的超类。 例如,sin,Symbol和Add都是Expr的子类。 但是,SymPy 中的许多对象不是Expr,因为它们表示其他类型的数学对象。 例如,Set,Poly和Boolean都不是Expr。 这些对象在Add,Mul和Pow内部没有数学意义,这些类专门用于表示标量复数的加法,乘法和指数运算。
可以手动构造这些类的一个对象,但通常会导致错误。 例如
Mul(1, Tuple(2)) # This is deprecated
可以工作并创建Tuple(2),但仅因为Mul始终将 (1 \cdot x = x) 视为“欺骗”。 如果您尝试
Mul(2, Tuple(2)) # This is deprecated
它失败并引发异常
AttributeError: 'Tuple' object has no attribute 'as_coeff_Mul'
因为它尝试在Tuple对象上调用Expr的方法,而Tuple对象没有所有Expr方法(因为它不是Expr的子类)。
如果要在非Expr对象上使用+,*或**操作,请直接使用运算符,而不是使用Mul,Add或Pow。 如果需要函数版本,可以使用lambda或operator模块。
版本 1.6
各种 sympy.utilities 子模块已迁移
以下子模块已更名。
-
sympy.utilities.benchmarking→sympy.testing.benchmarking -
sympy.utilities.pytest→sympy.testing.pytest -
sympy.utilities.randtests→sympy.core.random -
sympy.utilities.runtests→sympy.testing.runtests -
sympy.utilities.tmpfiles→sympy.testing.tmpfiles###sympy.testing.randtest
sympy.testing.randtest 已经弃用。其中的函数已移至 sympy.core.random。以下函数已移动。
-
sympy.testing.randtest.random_complex_number→sympy.core.random.random_complex_number -
sympy.testing.randtest.verify_numerically→sympy.core.random.verify_numerically -
sympy.testing.randtest.test_derivative_numerically→sympy.core.random.test_derivative_numerically -
sympy.testing.randtest._randrange→sympy.core.random._randrange -
sympy.testing.randtest._randint→sympy.core.random._randint### 在二进制操作中混合Poly和非多项式表达式
在之前的 SymPy 版本中,Poly 是 Expr 的子类,但现在它已被更改为只是 Basic 的子类。这意味着某些以前与 Poly 一起工作的功能现在已弃用,因为它们仅设计用于与 Expr 对象一起使用。
这包括使用二进制操作组合 Poly 和 Expr 对象,例如
Poly(x)*sin(x) # DEPRECATED
要实现此功能,可以通过使用 Expr.as_poly() 将非 Poly 操作数显式转换为 Poly,或者通过使用 Poly.as_expr() 将 Poly 操作数转换为 Expr,具体取决于你想要的结果类型。 ### sympy.combinatorics.Permutation 的 print_cyclic 标志
sympy.combinatorics.Permutation 的 print_cyclic 属性控制排列打印为循环还是数组。可以通过设置 Permutation.print_cyclic = True 或 Permutation.print_cyclic = False 来实现。然而,这种控制打印方式的方法并不好,因为它是一个全局标志,而打印不应该依赖于全局行为。
相反,用户应该使用相应打印机的 perm_cyclic 标志。配置此项的最简单方法是在调用 init_printing() 时设置该标志,例如
>>> from sympy import init_printing
>>> init_printing(perm_cyclic=False) # Makes Permutation print in array form
>>> from sympy.combinatorics import Permutation
>>> Permutation(1, 2)(3, 4)
⎛0 1 2 3 4⎞
⎝0 2 1 4 3⎠
Permutation 的文档字符串详细介绍了 perm_cyclic 标志。### 使用 integrate 和 Poly
在之前的 SymPy 版本中,Poly 是 Expr 的子类,但现在已更改为仅是 Basic 的子类。这意味着某些以前与 Poly 一起工作的东西现在已经过时,因为它们只设计用于与 Expr 对象一起使用。
包括使用 Poly 调用 integrate() 或 Integral。
要对 Poly 进行积分,使用 Poly.integrate() 方法。要将积分计算为 Expr 对象,请首先调用 Poly.as_expr() 方法。
另请参阅 在二元操作中混合多项式和非多项式表达式 上方。### 使用 Eq 参数创建不定积分 Integral
将 Eq() 对象传递给 integrate() 在积分为不定积分的情况下已经过时。这是因为如果 (f(x) = g(x)),那么一般来说 (\int f(x),dx = \int g(x),dx) 是不成立的,这是由于任意常数(integrate 不包括这些常数)。
如果要创建不定积分的等式,请明确使用 Eq(integrate(f(x), x), integrate(g(x), x))。
如果已经有一个等式对象 eq,可以使用 Eq(integrate(eq.lhs, x), integrate(eq.rhs, x))。
版本 1.5
Tensor.fun_eval 和 Tensor.__call__
TensExpr.fun_eval 和 Tensor.__call__(即调用张量来评估它)已经过时。应该使用 Tensor.substitute_indices() 方法。这一变更是因为 fun_eval 被认为是一个令人困惑的名称,并且使用函数评估被认为是既令人困惑又危险的。### TensorType
TensorType类已弃用。请使用tensor_heads()代替。TensorType类除了更短地创建TensorHead对象之外,没有其他用途。
另请参阅下面的 The tensorhead() function。 ### TensorIndexType的dummy_fmt参数
TensorIndexType的dummy_fmt关键字参数已弃用。设置dummy_fmt='L'将导致_dummy_fmt='L_%d',这是令人困惑并且使用过时的字符串格式化。应改用dummy_name。这个改变是因为dummy_name是一个更清晰的名称。 ### TensorIndexType的metric参数
TensorIndexType的metric关键字参数已弃用。名称metric在某些地方指“度量对称性”,在其他地方指“度量张量”,存在歧义。
应使用metric_symmetry关键字或TensorIndexType.set_metric()方法。 ### TensorIndexType的get_kronecker_delta()和get_epsilon()方法
TensorIndexType的get_kronecker_delta()和get_epsilon()方法已弃用。分别使用TensorIndexType.delta和TensorIndexType.epsilon属性。 ### tensorsymmetry()函数
sympy.tensor中的tensorsymmetry()函数已经被弃用。请使用TensorSymmetry类构造函数替代。
TensorSymmetry优于tensorsymmetry(),因为后者
-
没有额外的功能
-
涉及晦涩的 Young 表
-
不是
TensorSymmetry类的成员 ###tensorhead()函数
tensorhead()函数已弃用,建议使用tensor_heads()代替。tensor_heads()与 SymPy 的其他命名(例如,Symbol和symbols()或TensorIndex和tensor_indices())更一致。它也不使用 Young 表来表示对称性。 ### 集合的is_EmptySet属性
Set 对象的is_EmptySet属性已弃用。而是使用
from sympy import S
s is S.EmptySet
或者
s.is_empty
不同之处在于如果集合是否为空未知时,s.is_empty可能返回None。 ### ProductSet(iterable)
将单个可迭代对象作为ProductSet的第一个参数已被弃用。应该使用ProductSet(*iterable)创建产品集,或者作为每个单独的参数。例如
>>> from sympy import ProductSet
>>> sets = [{i} for i in range(3)]
>>> ProductSet(*sets)
ProductSet({0}, {1}, {2})
>>> ProductSet({1, 2}, {1})
ProductSet({1, 2}, {1})
之所以这样做是因为集合本身可以是可迭代的,而集合的集合也是允许的。但是,单个可迭代对象的产品集在数学上应该是该集合本身(或更确切地说,该集合的元素的一元组的集合)。自动去嵌套单个可迭代对象使得无法表示这种对象,并且在传递 1 个参数时,使得ProductSet不能正确推广。另一方面,在旧代码路径中,如果第一个参数是集合,则对其进行不同处理与处理其他类型的可迭代对象(当前弃用的代码路径)会导致行为混乱。### 在sympy.physics.mechanics中的set_potential_energy方法
sympy.physics.mechanics.particle.Particle和sympy.physics.mechanics.rigidbody.RigidBody的set_potential_energy()方法已被弃用。
相反,应该设置Particle.potential_energy和RigidBody.potential_energy属性来设置势能,例如
P.potential_energy = scalar
这一变更是为了更符合 Python 风格,使用@property方法的设置器和获取器,而不是显式的set_方法。### 在ConditionSet中使用集合表示条件
在ConditionSet中使用集合表示条件已被弃用。应该使用布尔值代替。这是因为条件在数学上是布尔值,而在此上下文中使用集合会引起歧义。
要修复此弃用问题,请替换
ConditionSet(symbol, set_condition)
使用
ConditionSet(symbol, And(*[Eq(lhs, 0) for lhs in set_condition]))
例如,
ConditionSet((x, y), {x + 1, x + y}, S.Reals) # DEPRECATED
会变成
ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals)
```### `sympy.polys.multivariate_resultants.DixonResultant`的`max_degree`和`get_upper_degree`属性
`DixonResultant`的`max_degree`属性和`get_upper_degree()`方法已被弃用。详细信息请参见问题[#17749](https://github.com/sympy/sympy/pull/17749)。### 对于`Lambda`,第一个参数不是元组而是其他可迭代对象
使用非元组作为`Lambda`的第一个参数已被弃用。如果参数不是元组,请首先将其转换为元组,如`Lambda(tuple(args), expr)`。
这样做是因为`Lambda`能够支持通用的元组解包,例如
```py
>>> from sympy import Lambda, symbols
>>> x, y, z = symbols('x y z')
>>> f = Lambda((x, (y, z)), x + y + z)
>>> f(1, (2, 3))
6
``` ### `differentiate_finite` 的 `evaluate` 标志
`differentiate_finite()` 的 `evaluate` 标志已弃用。
`differentiate_finite(expr, x, evaluate=True)` 在计算差分之前会展开中间导数。但通常这不是你想要的,因为它不符合乘积法则。
如果你确实需要这种行为,你可以用以下方式模拟它:
```py
diff(expr, x).replace(
lambda arg: arg.is_Derivative,
lambda arg: arg.as_finite_difference())
参见问题讨论 #17881。
版本 1.4
TensorIndexType.data 和相关方法
TensorIndexType.data 属性已弃用,以及使用它的几个方法,包括 get_matrix(),__getitem__()(索引),__iter__()(迭代),_components_data_full_destroy() 和 __pow__()(**)方法。在张量对象上存储数据是一种设计缺陷,并不符合 SymPy 的其余工作方式。
取而代之的是应该使用 TensExpr.replace_with_arrays() 方法。
术语表
这一页是 SymPy 文档中使用的各种术语的术语表。该术语表主要用于特定于 SymPy 的术语。有关更一般的 Python 术语,请参阅Python 术语表。数学术语仅在 SymPy 中具有特定含义时包含在此处。有关一般数学定义,请参考其他来源,如Wikipedia或MathWorld,以及特定 SymPy 函数文档中的参考资料。
反导数
函数 (f(x)) 关于 (x) 的一个反导数是一个函数 (F(x)),使得 (\frac{d}{dx}F(x) = f(x).) 有时也称为 (f(x)) 的“不定积分”,并写作 (\int f(x),dx.) 在 SymPy 中,可以用integrate()计算反导数。请注意,某些来源称之为 (f(x)) 的“原函数”,但 SymPy 中不使用此术语,因为它不像“反导数”一样被普遍使用,并且“原函数”在数学和SymPy中有其他含义。
args
SymPy 表达式的*args* 属性是用于创建它的顶级子表达式的元组。它们是用于创建表达式的类的参数。任何表达式的 args 可以通过 .args 属性获取。例如,(1 + x*y).args 是 (1, x*y),因为它等于 Add(1, x*y)。args 与 func 一起完全定义了一个表达式。可以通过反复使用 .args 来遍历表达式树并提取 SymPy 表达式的任何子表达式。通过 func 和 args,始终可以准确重建任何 SymPy 表达式,即 expr.func(*expr.args) == expr 对于任何 SymPy 表达式 expr 都是真实的。一个表达式的 args 可能是空元组 (),这意味着表达式是一个原子。
Assumptions
Assumptions 是对符号或表达式的一组谓词,定义其可以取的可能值集合。一些假设的示例包括 positive、real 和 integer。假设在逻辑上相互关联,例如,一个 integer 的假设自动意味着 real。假设使用三值逻辑系统,其中谓词可以是 True、False 或 None。
假设可以是假设或查询。例如,一个符号 x 可能通过将其定义为 x = symbols('x', positive=True) 来假设为正数。然后可以在包含此符号的表达式上查询一个假设,如 (x + 1).is_real,在这种情况下将返回 True。
如果在符号上没有假设,则默认情况下假设符号是一般复数。设置假设是重要的,因为某些简化只在受限域内数学上成立,例如,(\sqrt{x²} = x) 对一般复数 (x) 不成立,但当 (x) 是正数时成立。除非表达式的所有允许值都符合其假设,否则 SymPy 函数不会对表达式执行操作。
SymPy 有两个独立的假设系统,它们彼此紧密相关。在第一个系统中,有时被称为“旧假设”,因为它更老,假设是在符号对象上假设并使用 is_*属性查询。在第二个系统中,有时被称为“新假设”,假设是使用像Q.positive这样的单独谓词对象假设的,并使用ask()函数查询。较新的假设系统能够支持更复杂的查询,但也不像较旧的那样发展得好。目前大多数 SymPy 用户应该偏好较旧的假设系统。
查看假设指南了解更多关于假设的细节。
原子
一个原子是一个表达式,其 args 是空元组()。原子是表达式树的叶子节点。例如,如果一个函数使用递归来遍历表达式树使用args,那么原子表达式将是递归的基本情况。
请注意,类Atom有时被用作原子表达式的基类,但不要求原子表达式必须是这个类的子类。表达式要成为原子表达式的唯一要求是它的 args 为空。
自动简化
自动简化 指的是在类构造函数内部自动进行的任何简化。例如,在 Add 构造函数中,x + x 会自动简化为 2*x。与手动 简化 不同,自动简化只能通过设置 evaluate=False 来禁用 (参见 未评估)。通常进行自动简化是为了使表达式 规范化。过度的自动简化是不鼓励的,因为这样做会使表达式无法表示为非简化形式,除非使用 evaluate=False 等技巧,而且在类构造函数中这样做通常是一件昂贵的事情。相比之下,通常更倾向于进行手动 简化/规范化。
基本
基本 是所有 SymPy 表达式的超类。它定义了 SymPy 表达式所需的基本方法,比如 args,func,equality,immutability,以及一些有用的表达式操作函数,比如 替换。大多数 SymPy 类将会作为更具体的 Basic 子类,比如 布尔,表达式,函数,或 矩阵 进行子类化。通常情况下,如果一个对象不是 Basic 实例,它就不能在 SymPy 函数中使用,除非可以通过 sympify() 转换为一个。
布尔
布尔 是 logic 模块中类的基类。Boolean 实例代表布尔代数中的逻辑谓词,并且可以被视为具有“真”或“假”值 (注意 Boolean 对象不使用 三值逻辑,而是使用 假设)。
绑定符号
表达式中的一个 symbol 如果是bound,则表示它不是 free。一个 bound 符号可以被新符号替换,得到的表达式仍然在数学上等价。例子包括定积分中的积分变量和Subs中的替换变量。有时用 dummy 符号表示 bound 符号,但它们不总是Dummy对象,而Dummy对象也不总是 bound 符号。
规范形式
规范化
表达式通常可以用多种数学等价的方式写出。规范形式是表达式的一种单一写法,所有等价的表达式都可以转换为这种形式。将表达式放入规范形式称为规范化。通常规范形式是唯一的,并具有使其更易于处理的属性。例如,有理函数的常见规范形式是(\frac{p}{q}),其中(p)和(q)是无公因式的展开多项式。
代码生成
代码生成指的是将 SymPy 表达式转换为特定语言或库的代码,以便进行数值评估的过程。SymPy 支持几十种语言和库的代码生成,包括 C、C++、Fortran 和 NumPy。
核心
核心是包含所有 SymPy 对象使用的重要功能的子模块。这包括 Basic 和 Expr 基类,如Add、Mul和Pow等类,以及假设。
哑元
dummy symbol 是一个符号,即使它与同名的其他 dummy 符号不相等,也会自动返回其自身。dummy 符号用于当函数需要返回带有新符号的表达式时,以避免意外与同名的 symbol 冲突。可以使用Dummy创建 dummy 符号。
方程
方程是具有等号 (=) 的 expression。在 SymPy 中,方程使用Eq类表示。方程不是使用==运算符创建的。==运算符执行两个表达式之间的结构相等性检查,并始终返回True或False。相比之下,符号方程可能是 unevaluated 的。方程被视为 booleans,因为它们在数学上表示一个谓词值,即真或假。
_eval_*
Basic 和 Expr 上的各种方法可以通过特殊的*_eval_**方法在子类中定义。例如,对象可以通过定义_eval_derivative方法来定义在diff()函数中如何处理它。使用的_eval_*方法是替代重写方法本身,以便在基类上定义的方法在调度到_eval_*方法之前进行预处理。
evalf
*evalf*是每个 Expr 对象上的方法,用于将其评估为浮点数值,或者如果表达式包含 symbols,则将表达式的常数部分转换为数值。.n()方法和N()函数都是evalf的简写。 evalf代表“evaluate floating-point”。 evalf在内部使用 mpmath 来对表达式进行任意精度评估。
评估
评估可以指:
-
将 expression 转换为数值的过程(见 evalf)
-
创建表达式时发生的自动简化过程(参见 Unevaluated)。
-
将表达式中的一个或多个 symbols 用数值或使用 substitution 替换的过程。
Expr
*Expr*是所有代数 SymPy 表达式的超类。它本身是 Basic 的子类。可以在Add、Mul或Pow中的 SymPy 表达式应该是Expr的子类。并非所有 SymPy 类都是Expr的子类,例如,布尔对象是 Basic,但不是Expr,因为布尔表达式在像Add或Mul这样的类中没有数学意义。
表达式
任何 SymPy 对象,即任何 Basic 的实例,都可以称为表达式。有时,“表达式”一词保留给 Expr 对象,这些是代数表达式。表达式不应与方程混淆,后者是表示数学等式的特定类型的表达式。
表达树
表达树是树的表达式。每个表达式都是从较小的表达式构建而成的树。表达树的节点是表达式,每个节点的子节点是构成该表达式的直接子表达式。或者,可以将表达树视为一棵树,其中非叶节点是函数,叶节点是原子。例如,教程中展示了一个表达式树的示例。通过递归遍历 args,可以获得任何 SymPy 表达式的表达树。请注意,由于 SymPy 表达式是不可变的,并且严格按照结构相等性处理,因此也可以将表达树视为是DAG,其中相同的子表达式在图中只表示一次。
自由符号
表达式中的符号如果数学上依赖于该符号的值,则为自由。也就是说,如果该符号被替换为一个新符号,结果将是不同的表达式。不是自由的符号是绑定的。可以通过free_symbols属性访问表达式的自由符号。
func
*func*属性是 expression 的函数,可以通过expr.func获取。这通常与type(expr)相同,但在某些情况下可能会有所不同,因此在重建具有 args 的表达式时,应优先使用expr.func而不是type(expr)。每个 SymPy 表达式都可以使用func和args完全重建,即expr.func(*expr.args) == expr对于任何 SymPy 表达式expr都将始终为真。
函数
函数可能指:
-
数学函数,即将域中的值映射到范围中的某些内容。有时,包含 symbol 的 expression 在口语上称为“函数”,因为该符号可以使用 substitution 替换为值,从而 evaluating 表达式。这种用法是口语化的,因为必须使用
subs方法来执行替换,而不是典型的 Python 函数调用语法,并且它不具体说明表达式是哪些变量的函数,因此通常应优先使用术语“expression”,除非某些内容确实是函数。可以使用Lambda将表达式转换为可以使用 Pythonf(x)语法调用的函数对象。 -
SymPy Function 类的一个实例。
-
Python 函数,即使用
def关键字定义的函数。 Python 函数不是 symbolic,因为它们必须始终返回一个值,因此不能是 unevaluated。
Function(类)
*Function*是 SymPy 中符号函数的基类。这包括常见函数如sin()和exp(),特殊函数如zeta()和hyper(),以及积分函数如primepi()和divisor_sigma()。函数类总是符号化,这意味着当传递一个符号,如f(x)时,它们通常保持未评估状态。并非所有符号表达式类都是Function子类,例如,像Add和Mul这样的核心类不是Function子类。
Function也可以用于通过传递函数的字符串名称(如Function('f'))创建一个未定义函数。
并非所有 SymPy 中的函数都是符号Function类;有些只是始终返回值的 Python 函数。例如,大多数简化函数(如 simplify())无法以符号形式表示。
Immutable
在 Python 中,如果对象无法原地修改,则称其为不可变。为了改变一个不可变对象,必须创建一个新的对象。在 SymPy 中,所有的基础对象都是不可变的。这意味着所有操作表达式的函数都会返回一个新的表达式,并且不会改变原始对象。对表达式进行操作不会改变引用该表达式的其他对象或表达式。这也意味着任何两个相等的对象完全可以互换,并且可以被视为同一个对象,即使它们在内存中是两个不同的对象。不可变性使得更容易维护代码的心智模型,因为没有隐藏状态。SymPy 对象的不可变性也意味着它们是可哈希的,可以用作字典键。
交互式
交互 使用指的是在交互式 REPL 环境中使用 SymPy,例如 Python 提示符、isympy、IPython 或 Jupyter 笔记本。在交互式使用 SymPy 时,所有命令由用户实时输入,并显示所有中间结果。交互 使用与程序化 使用相对应,后者是指代码写入文件,然后作为脚本执行或作为较大 Python 库的一部分。一些 SymPy 习惯用法仅推荐在交互式使用时使用,当在程序化使用时被视为反模式。例如,在交互式使用 SymPy 时运行 from sympy import * 是方便的,但在程序化使用时通常不建议,应优先显式导入名称 import sympy。
is_*
在 SymPy 中以 is_ 开头并使用小写名称的属性查询对象的给定假设(注意:有少数属性是例外,因为它们不使用假设系统,请参阅假设指南)。例如,x.is_integer 将查询 x 的 integer 假设。使用大写名称的 is_* 属性测试对象是否是给定类的实例。有时相同名称将同时存在于小写和大写属性中,但它们代表不同的事物。例如,只有当 x 是 Integer 的实例时,x.is_Integer 才为 True,而 x.is_integer 只有在 x 是假设系统中的 integer 时才为 True,如 x = symbols('x', integer=True)。一般建议不使用 is_Capitalized 属性。它们存在是为了历史目的,但是使用 isinstance() 可以达到同样的效果。另请参阅 Number。
isympy
isympy 是一个与 SymPy 一起提供的命令,它在命令行上启动一个交互会话,导入所有 SymPy 名称并启用打印功能。默认情况下,安装时使用 IPython。
类型
SymPy 对象的类型表示其代表的数学对象的种类。对象的类型可以通过 kind 属性访问。例如,NumberKind 代表复数,MatrixKind 代表其他某种矩阵,以及 BooleanKind 代表布尔谓词。SymPy 对象的类型与其 Python 类型不同,因为有时一个单一的 Python 类型可能代表许多不同种类的对象。例如,Matrix 可能是复数矩阵,也可能是某些其他值环中的对象矩阵。详见 SymPy 对象的分类页面关于类型的分类了解更多详情。
lamda
“Lamda” 只是希腊字母lambda的另一种拼写方式。在 SymPy 中有时会使用这个拼写,因为在 Python 中 lambda 是一个保留关键字,所以表示 λ 的符号必须取别的名字。
lambdify()
lambdify() 是一个函数,将 SymPy 表达式转换为可以进行数值评估的 Python 函数,通常使用类似 NumPy 的数值库。
矩阵
矩阵 是 SymPy 用于表示矩阵的一组类。SymPy 有几个内部类用于表示矩阵,取决于矩阵是否是符号化的(MatrixExpr)、显式的、可变的或不可变的、稠密的或稀疏的,以及底层元素的类型是什么,但通常统称为“矩阵”。
mpmath
mpmath 是一个纯 Python 库,用于任意精度数值计算。它是 SymPy 的一个硬依赖。mpmath 能够计算数值函数至任意精度位数。每当 SymPy 对表达式进行数值评估时(例如使用 evalf),mpmath 就在幕后发挥作用。
数值
数值 表示或算法直接操作数值输入。它与 符号 表示或算法相对,后者可以处理未求值形式的对象。通常数值算法与符号算法有很大不同。例如,数值求解常微分方程通常意味着使用像 Runge–Kutta 这样的算法来在给定初始条件下找到一组数值点,而符号求解常微分方程(例如使用 SymPy 的 dsolve())意味着数学上操纵常微分方程以生成一个 符号 方程,该方程表示解。符号常微分方程的解可能包含符号常数,这些符号常数可以表示任何数值。数值算法通常围绕浮点数引起的问题设计,如精度损失和数值稳定性,而符号算法则不涉及这些问题,因为它们可以精确计算。
大多数科学库,如 NumPy 或 SciPy,严格是数值的,意味着这些库中的函数只能操作特定的数值输入。它们无法处理 SymPy 表达式,因为它们的算法不是设计用于符号输入。SymPy 主要关注符号函数,将纯数值代码留给像 NumPy 这样的其他工具。然而,SymPy 通过工具如 代码生成 和 lambdify() 与数值库进行接口。
Number
Number 可以指 SymPy 中的两种东西:
-
类
Number是显式数值(Integer、Rational和Float)的基类。符号数值常量如pi不是Number的实例。 -
小写的 "number",例如
is_number属性,指的是可以 evalfed 成显式Number的任何 表达式。这包括像pi这样的符号常数。注意,is_number不是 假设 系统的一部分。
对于 is_Number 和 is_number 属性,这种区别非常重要。x.is_Number 将检查 x 是否是 Number 类的一个实例。
oo
*oo*是 SymPy 表示正无穷大的对象。它以这种方式拼写,作为两个小写字母 O,因为它类似于符号(\infty)且易于输入。另见 zoo。
Polys
polys指的是sympy.polys子模块,它实现了多项式操作的基本数据结构和算法。polys 是 SymPy 的关键部分(虽然通常不被认为是核心的一部分),因为许多基本的符号操作可以表示为对多项式的操作。SymPy 中的许多算法在内部使用多项式。例如,factor()是对多项式因式分解算法的一种封装,这些算法在多项式中实现。polys 中的类使用高效的数据结构实现,并且不像 SymPy 中的其他类一样,不是 Basic 的子类。
打印
打印指的是将一个表达式转换为可以在屏幕上查看的形式。打印通常也用于指代代码生成。SymPy 有几个打印机,可以使用不同格式表示表达式。一些更常见的打印机是字符串打印机(str()),漂亮的打印机(pprint()),LaTeX 打印机(latex())和代码打印机。
关系
关系是一个表达式,它是符号 等式(比如(a=b)),或者一个象征着“小于”((a<b))的符号不等式。等式((=))和不等式((\neq))的关系是用Eq和Ne创建的。例如,Eq(x, 0)表示(x=0)。这些应该用于代替==或!=,因为这些用于结构而不是象征性的相等。不等关系可以直接使用<,<=,>和>=来创建,比如x < 0。
S
SymPy 中的*S*对象有两个用途:
-
它将所有单例类作为属性保存。SymPy 中的一些特殊类被设计为单例化,意味着它们始终只有一个实例。这是一种优化方法,可以节省内存。例如,
Integer(0)只有一个实例,可以通过S.Zero获取。 -
它充当 sympify() 的缩写,即
S(a)等同于sympify(a)。这在将整数转换为 SymPy 整数以避免在表达式中使用 Python 整数进行除法时非常有用(参见 教程的注意事项部分)。
简化
简化(不要与 sympify 混淆)指的是将一个 表达式 转换为另一个在数学上等价但在某种意义上“更简单”的表达式的过程。“简单”的形容词实际上并不十分明确。什么算简单取决于具体的用例和个人审美观。
SymPy 函数 simplify() 根据启发式方法尝试各种简化算法,以找到表达式的“更简单”形式。如果你对“简化”想要什么并不是特别确定,它可能是一个不错的选择。但如果你对想要应用的简化有一个具体的想法,通常最好使用一个或多个目标化的 简化函数,这些函数对表达式应用非常具体的数学操作。
解决
求解器
对于 解 一个 方程 或方程组意味着找到一组 表达式,当给定的 符号 被它们替换时,方程(们)为真。例如,对于方程 (x² = 1) 关于 (x) 的解是集合 ({-1, 1})。SymPy 可以使用不同的 求解器 函数来解决不同类型的方程。例如,代数方程可以用 solve() 解决,微分方程可以用 dsolve() 解决,等等。
SymPy 通常使用“solve”和“solvers”来表示这种意义上的方程求解。它不用于“解决问题”的意义。例如,通常会更倾向于说“计算一个积分”或“评估一个积分”,而不是“解决一个积分”,来表示使用函数 integrate() 进行符号积分。
结构相等性
两个 SymPy 对象如果作为表达式相等,则它们被认为是结构相等的,即它们具有相同的表达式树。在 SymPy 中,两个结构相等的表达式被认为是相同的,因为所有 SymPy 表达式都是不可变的。结构相等可以通过==操作符来检查,它总是返回True或False。符号等式可以用Eq来表示。
通常,如果两个表达式是相同的类,并且(递归地)具有相同的 args,那么它们就是结构相等的。两个表达式可能在数学上是相同的,但在结构上不相等。例如,(x + 1)**2 和 x**2 + 2*x + 1 在数学上是相等的,但它们在结构上不相等,因为前者是一个 Pow,其 args 包括一个Add 和一个Integer,而后者是一个Add,其 args 包括一个Pow,一个Mul 和一个Integer。
两个表面上不同的表达式,如果它们经过规范化后变成相同的形式,那么它们就是结构相等的。例如,x + y 和 y + x 结构上是相等的,因为Add 构造器会自动排序其参数,使它们变成相同的形式。
子表达式
子表达式 是一个包含在较大表达式中的表达式。子表达式出现在表达式树的某处。对于Add和Mul项,当确定什么是子表达式时,可以考虑交换律和结合律。例如,x + y 有时可能被认为是 x + y + z 的子表达式,即使Add(x, y)的表达式树不是Add(x, y, z)的直接子节点。
替换
替换是指用另一个表达式替换 expression 内部的 symbol 或 subexpression 的行为。在 SymPy 中有不同的方法执行替换,包括subs、replace和xreplace。这些方法可能因是否只使用严格的 structural equality 或在确定子表达式在表达式中出现的位置时利用数学知识而有所不同。替换是将表达式视为数学 function 并在某点评估的标准方法。
符号
符号表示一个数学对象的表示,在运行时部分或完全未评估。它可能包括以命名的 symbolic constants 代替显式数值。符号表示通常与 numeric 表示形成对比。符号表达是数学上精确的,与通常舍入以适应浮点值的数值表示相对。符号表示数学对象的表达可能意识到这些对象的数学属性,并能够利用这些属性简化为等效的符号表达式。SymPy 的目标是表示和操作代表各种数学对象的符号表达式。
一些来源使用术语“分析解”或“闭合形式”来指代“符号”的概念,但这种术语在 SymPy 中不使用。如果在 SymPy 中使用,“分析”将指代解析函数的特性,在 SymPy 中 solve 仅指特定类型的符号操作。“闭合形式”在 SymPy 中通常指数学上的意义,而“符号”通常指的是数学概念如何实现的实现细节,并与相同数学概念的 numeric 实现形成对比。
Symbol
*Symbol*是符号对象的类。符号代表表达式中的单个数学变量。Symbol类是 Expr 的子类,是 atomic 的。一个Symbol包含一个名称,可以是任何字符串,以及 assumptions。符号通常使用Symbol构造函数或symbols()函数定义。具有相同名称和假设的两个 Symbols 被认为是 equal 的。Symbols 通常被隐式地假设是彼此独立或常数。常量、变量和参数都由 Symbols 表示。在给定的 SymPy 函数中,通常通过 Symbols 的使用方式来区分它们。
sympify()
sympify()(不要与simplify()混淆)是将非 SymPy 对象转换为 SymPy 对象的函数。sympify()的结果将是 Basic 的一个实例。可以被sympified的对象包括本地 Python 数值类型如int和float,可以解析为 SymPy 表达式的字符串以及包含sympifiable对象的可迭代对象(详见sympify()的文档了解更多信息)。
因为所有 SymPy 表达式必须是 Basic 的实例,所有 SymPy 函数和操作在其输入上会隐式调用sympify()。例如,x + 1会隐式调用sympify(1)将 Python int类型的1转换为 SymPy 的Integer。接受 SymPy 表达式的函数通常应该在其参数上调用sympify(),以确保它们在输入不是 SymPy 类型时也能正常工作。
三值逻辑
三值逻辑是一种具有三个值 True、False 和 None 的逻辑。有时它也被称为模糊逻辑,尽管在数学文献中这个术语也有不同的含义,因此“三值逻辑”更受推荐。True 和 False 的作用与通常的二值谓词逻辑相同。None 是一个额外的术语,表示“未知”、“不可计算”或“可以是 True 或 False”(从哲学上讲这些是不同的概念,但逻辑上它们完全相同)。None 的语义是在逻辑操作中吸收其他术语,每当如果将其替换为 True 或 False 结果将会不同时。例如,None OR False 是 None,但 None OR True 是 True,因为谓词是 True,无论 None “实际上”代表 True 还是 False。在使用通常的 Python 逻辑运算符如 and、or 和 not 时,必须小心处理三值逻辑,因为 None 为假。有关如何使用三值逻辑编码的更多详细信息,请参阅符号和模糊布尔值指南。
假设系统使用三值逻辑表示未知的假设。例如,如果在给定的假设下 x.is_positive 可能是 None,因为 x 可以是正数或负数。请注意,由布尔子类定义的谓词逻辑表示标准的二值逻辑,而不是三值逻辑。
未定义函数
未定义函数是函数的一种,在其上没有定义数学属性。它始终保持未评估,例如 f(x)。通过将函数的字符串名称传递给 Function,例如 f = Function('f'),可以创建未定义函数。在处理 ODEs 时,通常使用未定义函数。未定义函数还是制造符号的最简单方法,这些符号在数学上依赖于其他符号。例如,如果 f = Function('f') 和 x = Symbol('x'),那么 SymPy 将知道 f(x) 取决于 x,这意味着例如导数 diff(f(x), x) 不会被评估为 0。
未评估
如果自动化简在创建表达式时被禁用,则表达式是未评估的。通常通过设置 evaluate=False,使用 with evaluate(False) 或使用 UnevaluatedExpr 来完成这一点。虽然支持未评估表达式,但有时会导致意外行为,因为表达式未正确规范化。
术语未评估有时也用来表示当其参数是符号的时,表达式不会评估为特定值。
zoo
zoo 代表复无穷,即Riemann 球面的北极。它这样拼写的原因是,“z-oo”,其中“z”通常用于复变量的符号,而 oo 则是 SymPy 用于正无穷的符号。
API 参考
本节包含 SymPy 模块、函数、类和方法的摘要。sympy核心子包中实现的所有函数和对象在下面都有文档。
基础
包含基础模块操作的描述。子类别包括:基础概念,操作,假设,函数,简化,微积分,求解器,以及其他一些子类别。
代码生成
包含生成可编译和可执行代码的方法描述。
逻辑
包含逻辑和集合模块的方法详细信息。
矩阵
讨论了矩阵、张量和向量模块的方法。
数论
文档了数论模块的方法。
物理
包含物理方法的文档。
实用工具
包含多个实用模块方法的文档字符串。子类别包括:交互式,解析,打印,测试,实用工具。
主题
包含多个模块的方法文档字符串。子类别包括:绘图,多项式,几何,范畴论,密码学,微分,Holonomic,李代数,和统计。
基础
目录
-
假设
-
询问
-
假设
-
细化
-
谓词
-
-
微积分
-
组合数学
-
分割
-
排列
-
置换群
-
多面体
-
普鲁弗序列
-
子集
-
格雷码
-
命名群
-
伽罗瓦群
-
群的数量
-
实用工具
-
群构造器
-
测试工具
-
张量标准化
-
有限呈现群
-
多环群
-
-
函数
-
初等
-
组合
-
枚举
-
特殊
-
-
积分
-
使用 Meijer G-函数计算积分
-
积分
-
-
级数
-
级数展开
-
序列
-
傅立叶级数
-
形式幂级数
-
序列极限
-
-
简化
-
简化
-
超几何展开
-
傅宏光的三角简化
-
-
求解器
-
丢番图方程
-
不等式求解器
-
常微分方程
-
偏微分方程
-
求解器
-
解集
-
-
abc
-
代数
-
具体
-
核心
-
离散
-
数值评估
-
数值计算
-
术语重写