使用 Python 进行符号数学

作者:Joey Bernard

许多编程语言都包含库来执行更复杂的数学运算。您可以进行统计、数值分析或处理大数字。符号数学是许多编程语言难以处理的一个主题。但是,如果您使用 Python,您可以使用 sympy,即符号数学库。Sympy 正在不断开发中,其目标是成为一个功能齐全的计算机代数系统 (CAS)。它也完全用 Python 编写,因此您无需安装任何额外的要求。如果您想要最新版本,您可以下载源代码 tarball 或 git 仓库。大多数发行版也为那些不太关心前沿技术的用户提供了 sympy 的软件包。安装完成后,您将能够通过两种方式访问 sympy 库。您可以像使用任何其他库一样使用 import 语句来访问它。但是,sympy 还提供了一个名为 isympy 的二进制文件,该文件模仿了 ipython。

在最简单的模式下,sympy 可以用作计算器。Sympy 内置支持三种数字类型:float、rational 和 integer。Float 和 integer 是直观的,但 rational 是什么?有理数由分子和分母组成。因此,Rational(5,2) 等价于 5/2。还支持复数。复数的虚部用常量 I 标记。因此,一个基本的复数是


a + b*I

您可以使用 "im" 获取虚部,使用 "re" 获取实部。当函数需要处理复数时,您需要明确告知函数。例如,当进行基本展开时,您会得到


exp(I*x).expand() exp(I*x)

要获得实际的展开式,您需要告诉 expand 它正在处理复数。这将看起来像


exp(I*x).expand(complex=True)

所有标准的算术运算符(如加法、乘法和乘方)都可用。所有常用的函数也可用,如三角函数、特殊函数等等。特殊常数(如 e 和 pi)在 sympy 中被符号化处理。它们实际上不会评估为数字,因此像 "1+pi" 这样的表达式仍然是 "1+pi"。您实际上必须显式使用 evalf 才能获得数值。还有一个名为 oo 的类,它表示无穷大的概念——在进行更复杂的数学运算时非常方便。

虽然这很有用,但 CAS 的真正威力在于执行符号数学运算的能力,例如微积分或解方程。大多数其他 CAS 会在您使用符号变量时自动创建它们。在 sympy 中,这些符号实体以类的形式存在,因此您需要显式创建它们。您可以使用以下方法创建它们


x = Symbol('x')
y = Symbol('y')

如果您一次要定义多个符号,您可以使用


x,y = symbols('x', 'y')

然后,您可以在其他操作中使用它们,例如查看方程。例如


(x+y)**2

然后,您可以对这些方程应用操作,例如展开它


((x+y)**2).expand()
x**2 + 2*x*y + y**2

您还可以使用替换运算符将这些变量替换为其他变量,甚至数字。例如


((x+y)**2).subs(x,1)
(1+y)**2

您也可以分解或组合更复杂的方程。例如,假设您有以下方程


(x+1)/(x-1)

然后,您可以使用以下方法进行部分分式分解


apart((x+1)/(x-1),x)
1 + 2/(x-1)

您可以使用以下方法将事物重新组合在一起


together(1 + 2/(x-1))
(x+1)/(x-1)

当处理三角函数时,您需要告知 expandtogether 等运算符。例如,您可以使用


sin(x+y).expand(trig=True)
sin(x)*cos(y) + sin(y)*cos(x)

CAS 的真正大用例是微积分。微积分是科学计算的支柱,并在许多情况下使用。微积分的基本思想之一是极限。Sympy 提供了一个名为 limit 的函数来处理这个问题。您需要提供一个函数、一个变量以及极限要计算趋近的值。因此,如果您想计算 (sin(x)/x) 在 x 趋近于 0 时的极限,您将使用


limit(sin(x)/x, x, 0)
1

由于 sympy 提供了无穷大对象,您可以计算极限趋近于无穷大的情况。因此,您可以计算


limit(1/x, x, oo)
0

Sympy 还允许您进行微分。它可以理解基本多项式以及三角函数。如果您想对 sin(x) 求导,那么您可以使用


x = Symbol('x')
diff(sin(x), x)

cos(x)

您可以通过向 diff 函数调用添加一个额外的参数来计算高阶导数。因此,计算 (x**2) 的一阶导数可以使用


diff(x**2, x, 1)
2*x

而二阶导数可以使用


diff(x**2, x, 2)
2

Sympy 提供了计算微分方程解的功能。您可以使用 diff 函数定义微分方程。例如


f(x).diff(x,x) + f(x)

其中 f(x) 是感兴趣的函数,而 diff(x,x) 对 f(x) 关于 x 求二阶导数。要解这个方程,您可以使用函数 dsolve


dsolve(f(x).diff(x,x) + f(x), f(x))
f(x) = C1*cos(x) + C2*sin(x)

这是科学计算中非常常见的任务。

微分的反义词是积分。Sympy 提供对不定积分和定积分的支持。您可以使用以下方法积分基本函数


integrate(sin(x), x)
-cos(x)

您也可以积分特殊函数。例如


integrate(exp(-x**2)*erf(x), x)

可以通过向积分添加极限来计算定积分。如果您从 0 到 pi/2 积分 sin(x),您将使用


integrate(sin(x), (x, 0, pi/2))
1

Sympy 还可以处理一些反常积分。例如


integrate(exp(x), (x, 0, oo))
1

有时,方程过于复杂而无法进行解析处理。在这些情况下,您需要生成级数展开并计算近似值。Sympy 提供了运算符 series 来执行此操作。例如,如果您想要 cos(x) 在 0 附近的四阶级数展开,您将使用


cos(x).series(x, 0, 4)
1 - (x**2)/2 + (x**4)/24

Sympy 通过使用 Matrix 类来处理线性代数。如果您只处理数字,您可以使用


Matrix([[1,0], [0,1]])

如果需要,您可以显式定义矩阵的维度。这将看起来像


Matrix(2, 2, [1, 0, 0, 1])

您也可以在矩阵中使用符号变量


x = Symbol('x')
y = Symbol('y')
A = Matrix([[1,x], [y,1]])

创建矩阵后,您可以对其进行操作。有函数可以执行点积、叉积或计算行列式。向量只是由一行或一列组成的矩阵。

如果您无法以可以使用的形式打印出您正在做的事情,那么进行所有这些计算有点浪费。最基本的输出是使用 print 命令生成的。如果您想修饰一下,可以使用 pprint 命令。此命令执行一些 ASCII 美化打印,使用 ASCII 字符来显示积分符号等内容。如果您想生成可以在已发表的文章中使用的输出,您可以让 sympy 生成 LaTeX 输出。这是通过 latex 函数完成的。简单地使用普通函数将生成通用的 LaTeX 输出。例如


latex(x**2)
x^{2}

但是,您可以手动输入特殊情况的模式。如果您想生成内联 LaTeX,您可以使用


latex(x**2, mode='inline')
$x^{2}$

您可以使用以下方法生成完整的 LaTeX 方程输出


latex(x**2, mode='equation')
\begin{equation}x^{2}\end{equation}

最后,让我们看看一些可能出现的问题。首先要考虑的是等号。单个等号是赋值运算符,而两个等号用于相等性测试。相等性测试仅适用于实际相等性,而不适用于符号相等性。因此,测试以下内容将返回 false


(x+1)**2 == x**2 + 2*x + 1

如果您想测试两个方程是否相等,您需要从另一个方程中减去一个方程,并通过仔细使用 expandsimplifytrigsimp,查看是否最终得到 0。Sympy 不使用默认的 Python int 和 float,因为它提供了更多的控制。如果表达式仅包含数字,则使用默认的 Python 类型。如果您想使用 sympy 数据类型,您可以使用函数 sympify()S()。因此,使用 Python 数据类型,您会得到


6.2 -> 6.2000000000000002

而 sympy 数据类型给出


S(6.2) -> 6.20000000000000

表达式在 sympy 中是不可变的。应用于它们的任何函数都不会更改表达式本身,而是返回新的表达式。

本文仅触及了 sympy 最基本的元素。但是,我希望您已经看到它在进行科学计算中非常有用。通过使用 isympy 控制台,您可以灵活地进行交互式科学分析和工作。如果某些功能尚不存在,请记住它正在积极开发中,并且还要记住,您可以随时参与并提供帮助。

加载 Disqus 评论