微积分¶
本节介绍如何在 SymPy 中执行基本微积分任务,例如导数、积分、极限和级数展开。如果您不熟悉本节中任何部分的数学知识,可以跳过。
>>> from sympy import *
>>> x, y, z = symbols('x y z')
>>> init_printing(use_unicode=True)
导数¶
要进行求导,请使用 diff
函数。
>>> diff(cos(x), x)
-sin(x)
>>> diff(exp(x**2), x)
⎛ 2⎞
⎝x ⎠
2⋅x⋅ℯ
diff
可以一次执行多个求导。要进行多次求导,将变量传递多次,次数与您想要求导的次数相同,或者在变量之后传递一个数字。例如,以下两个示例都将计算 \(x^4\) 的三阶导数。
>>> diff(x**4, x, x, x)
24⋅x
>>> diff(x**4, x, 3)
24⋅x
您也可以对多个变量进行求导。只需按顺序传递每个导数,使用与单变量导数相同的语法。例如,以下每个示例都将计算 \(\frac{\partial^7}{\partial x\partial y^2\partial z^4} e^{x y z}\)。
>>> expr = exp(x*y*z)
>>> diff(expr, x, y, y, z, z, z, z)
3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z
x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ
>>> diff(expr, x, y, 2, z, 4)
3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z
x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ
>>> diff(expr, x, y, y, z, 4)
3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z
x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ
diff
也可作为方法调用。两种调用 diff
的方式完全相同,仅为方便起见提供。
>>> expr.diff(x, y, y, z, 4)
3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z
x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ
要创建未计算的导数,请使用 Derivative
类。它的语法与 diff
相同。
>>> deriv = Derivative(expr, x, y, y, z, 4)
>>> deriv
7
∂ ⎛ x⋅y⋅z⎞
──────────⎝ℯ ⎠
4 2
∂z ∂y ∂x
要计算未计算的导数,请使用 doit
方法。
>>> deriv.doit()
3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z
x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ
这些未计算的对象对于延迟导数的计算或打印目的很有用。它们还用于 SymPy 不知道如何计算表达式的导数时(例如,如果它包含未定义的函数,这些函数在 求解微分方程 部分中描述)。
可以使用元组 (x, n)
创建未指定阶数的导数,其中 n
是相对于 x
的导数阶数。
>>> m, n, a, b = symbols('m n a b')
>>> expr = (a*x + b)**m
>>> expr.diff((x, n))
n
∂ ⎛ m⎞
───⎝(a⋅x + b) ⎠
n
∂x
积分¶
要计算积分,请使用 integrate
函数。积分有两种类型:定积分和不定积分。要计算不定积分,即反导数或原函数,只需在表达式后传递变量。
>>> integrate(cos(x), x)
sin(x)
请注意,SymPy 不包含积分常数。如果你需要它,可以自己添加一个,或者将你的问题重新表述为微分方程,并使用 dsolve
来求解它,这将添加常数(参见 求解微分方程)。
要计算定积分,请传递参数 (integration_variable, lower_limit, upper_limit)
。例如,要计算
我们将执行以下操作
>>> integrate(exp(-x), (x, 0, oo))
1
与不定积分一样,你可以传递多个极限元组来执行多重积分。例如,要计算
执行以下操作
>>> integrate(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo))
π
如果 integrate
无法计算积分,它将返回一个未计算的 Integral
对象。
>>> expr = integrate(x**x, x)
>>> print(expr)
Integral(x**x, x)
>>> expr
⌠
⎮ x
⎮ x dx
⌡
与 Derivative
一样,你可以使用 Integral
创建未计算的积分。要稍后计算此积分,请调用 doit
。
>>> expr = Integral(log(x)**2, x)
>>> expr
⌠
⎮ 2
⎮ log (x) dx
⌡
>>> expr.doit()
2
x⋅log (x) - 2⋅x⋅log(x) + 2⋅x
integrate
使用功能强大的算法来计算定积分和不定积分,这些算法一直在改进,包括启发式模式匹配类型算法、Risch 算法 的部分实现,以及使用 Meijer G 函数 的算法,该算法可用于计算以特殊函数表示的积分,尤其是定积分。以下是一些 integrate
功能强大的示例。
>>> integ = Integral((x**4 + x**2*exp(x) - x**2 - 2*x*exp(x) - 2*x -
... exp(x))*exp(x)/((x - 1)**2*(x + 1)**2*(exp(x) + 1)), x)
>>> integ
⌠
⎮ ⎛ 4 2 x 2 x x⎞ x
⎮ ⎝x + x ⋅ℯ - x - 2⋅x⋅ℯ - 2⋅x - ℯ ⎠⋅ℯ
⎮ ──────────────────────────────────────── dx
⎮ 2 2 ⎛ x ⎞
⎮ (x - 1) ⋅(x + 1) ⋅⎝ℯ + 1⎠
⌡
>>> integ.doit()
x
⎛ x ⎞ ℯ
log⎝ℯ + 1⎠ + ──────
2
x - 1
>>> integ = Integral(sin(x**2), x)
>>> integ
⌠
⎮ ⎛ 2⎞
⎮ sin⎝x ⎠ dx
⌡
>>> integ.doit()
⎛√2⋅x⎞
3⋅√2⋅√π⋅S⎜────⎟⋅Γ(3/4)
⎝ √π ⎠
──────────────────────
8⋅Γ(7/4)
>>> integ = Integral(x**y*exp(-x), (x, 0, oo))
>>> integ
∞
⌠
⎮ y -x
⎮ x ⋅ℯ dx
⌡
0
>>> integ.doit()
⎧ Γ(y + 1) for re(y) > -1
⎪
⎪∞
⎪⌠
⎨⎮ y -x
⎪⎮ x ⋅ℯ dx otherwise
⎪⌡
⎪0
⎩
最后一个示例返回了一个 Piecewise
表达式,因为积分只有在 \(\Re(y) > -1.\) 时才会收敛。
数值积分¶
数值积分是数学分析中的一种方法,用于估计函数在简化范围内的定积分。SymPy 不仅支持符号积分,还支持数值积分。它利用 mpmath
库的精度功能来提高数值积分计算的精度。
>>> from sympy import Integral, Symbol, sqrt
>>> x = Symbol('x')
>>> integral = Integral(sqrt(2)*x, (x, 0, 1))
>>> integral
1
⌠
⎮ √2⋅x dx
⌡
0
>>> integral.evalf()
0.707106781186548
要以指定精度计算积分
>>> integral.evalf(50)
0.70710678118654752440084436210484903928483593768847
当符号积分不切实际或不可能时,数值积分成为一种可行的方法。这种方法允许通过数值技术计算积分,即使在处理无限区间或被积函数时也是如此。
>>> Integral(exp(-(x ** 2)), (x, -oo, oo)).evalf()
1.77245385090552
>>> Integral(1 / sqrt(x), (x, 0, 1)).evalf()
2.00000000000000
极限¶
SymPy 可以使用 limit
函数计算符号极限。计算
的语法是 limit(f(x), x, x0)
。
>>> limit(sin(x)/x, x, 0)
1
只要评估点是奇点,就应该使用 limit
而不是 subs
。即使 SymPy 有对象来表示 \(\infty\),使用它们进行评估也不可靠,因为它们不跟踪诸如增长率之类的东西。此外,诸如 \(\infty - \infty\) 和 \(\frac{\infty}{\infty}\) 之类的东西返回 \(\mathrm{nan}\)(非数字)。例如
>>> expr = x**2/exp(x)
>>> expr.subs(x, oo)
nan
>>> limit(expr, x, oo)
0
与 Derivative
和 Integral
一样,limit
有一个未计算的对应项,即 Limit
。要计算它,请使用 doit
。
>>> expr = Limit((cos(x) - 1)/x, x, 0)
>>> expr
⎛cos(x) - 1⎞
lim ⎜──────────⎟
x─→0⁺⎝ x ⎠
>>> expr.doit()
0
要仅在一侧评估极限,请将 '+'
或 '-'
作为第四个参数传递给 limit
。例如,要计算
执行以下操作
>>> limit(1/x, x, 0, '+')
∞
与以下不同
>>> limit(1/x, x, 0, '-')
-∞
级数展开¶
SymPy 可以计算函数在某一点周围的渐近级数展开式。要计算 \(f(x)\) 在点 \(x = x_0\) 附近以 \(x^n\) 阶展开的表达式,请使用 f(x).series(x, x0, n)
。可以省略 x0
和 n
,在这种情况下,将使用默认值 x0=0
和 n=6
。
>>> expr = exp(sin(x))
>>> expr.series(x, 0, 4)
2
x ⎛ 4⎞
1 + x + ── + O⎝x ⎠
2
末尾的 \(O\left(x^4\right)\) 项表示 \(x=0\) 处的 Landau 阶项(不要与计算机科学中使用的大 O 符号混淆,后者通常表示 \(x\) 处的 Landau 阶项,其中 \(x \rightarrow \infty\))。这意味着所有 x 项的幂大于或等于 \(x^4\) 都被省略了。可以在 series
之外创建和操作阶项。它们会自动吸收高阶项。
>>> x + x**3 + x**6 + O(x**4)
3 ⎛ 4⎞
x + x + O⎝x ⎠
>>> x*O(1)
O(x)
如果你不想要阶项,请使用 removeO
方法。
>>> expr.series(x, 0, 4).removeO()
2
x
── + x + 1
2
O
符号支持任意极限点(除 0 之外)
>>> exp(x - 6).series(x, x0=6)
2 3 4 5
(x - 6) (x - 6) (x - 6) (x - 6) ⎛ 6 ⎞
-5 + ──────── + ──────── + ──────── + ──────── + x + O⎝(x - 6) ; x → 6⎠
2 6 24 120
有限差分¶
到目前为止,我们已经研究了具有解析导数和原函数的表达式。但是,如果我们想要一个表达式来估计曲线的导数,而我们没有它的闭合形式表示,或者我们还没有知道它的函数值,该怎么办?一种方法是使用有限差分方法。
使用有限差分进行微分最简单的方法是使用 differentiate_finite
函数
>>> f, g = symbols('f g', cls=Function)
>>> differentiate_finite(f(x)*g(x))
-f(x - 1/2)⋅g(x - 1/2) + f(x + 1/2)⋅g(x + 1/2)
如果你已经有一个 Derivative
实例,你可以使用 as_finite_difference
方法生成任意阶导数的近似值
>>> f = Function('f')
>>> dfdx = f(x).diff(x)
>>> dfdx.as_finite_difference()
-f(x - 1/2) + f(x + 1/2)
这里,使用最小点数(1 阶导数为 2 个点)在 x 周围用步长为 1 的等距方式进行评估,对一阶导数进行近似。我们可以使用任意步长(可能包含符号表达式)
>>> f = Function('f')
>>> d2fdx2 = f(x).diff(x, 2)
>>> h = Symbol('h')
>>> d2fdx2.as_finite_difference([-3*h,-h,2*h])
f(-3⋅h) f(-h) 2⋅f(2⋅h)
─────── - ───── + ────────
2 2 2
5⋅h 3⋅h 15⋅h
如果你只对评估权重感兴趣,可以手动执行此操作
>>> finite_diff_weights(2, [-3, -1, 2], 0)[-1][-1]
[1/5, -1/3, 2/15]
请注意,我们只需要 finite_diff_weights
返回的最后一个子列表中的最后一个元素。原因是该函数还会生成用于较低阶导数和使用较少点的权重(有关详细信息,请参见 finite_diff_weights
的文档)。
如果直接使用 finite_diff_weights
看起来很复杂,而 Derivative
实例的 as_finite_difference
方法不够灵活,则可以使用 apply_finite_diff
,它以 order
、x_list
、y_list
和 x0
作为参数
>>> x_list = [-3, 1, 2]
>>> y_list = symbols('a b c')
>>> apply_finite_diff(1, x_list, y_list, 0)
3⋅a b 2⋅c
- ─── - ─ + ───
20 4 5