SymPy Integrals 模块完整指南:从不定积分、积分变换到多胞体数值积分
【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy
SymPy 的sympy.integrals模块实现了对表达式进行定积分与不定积分计算的完整方法体系,其核心入口integrate函数支持从多项式、有理函数到指数—三角函数组合乃至含误差函数的非初等积分的广泛求值,并提供了 Mellin、Laplace、Fourier、Hankel 等一系列积分变换,以及面向 2D/3D 多胞体的多项式精确积分工具。读完本文,你将掌握integrate的完整调用语法与内部算法调度顺序、各积分变换的数学定义与用法、manualintegrate的"手算"步骤提取能力,以及高斯求积和polytope_integrate的实操细节。
模块概览:integrate是唯一的入口
integrals模块的核心思想非常朴素——把"求积分"这件事封装成一个统一接口:
integrate(f, x)返回不定积分 $\int f,dx$;integrate(f, (x, a, b))返回定积分 $\int_{a}^{b} f,dx$。
从源码看,integrate 定义于 sympy/integrals/integrals.py,其签名中已经暴露了可调度的策略参数:
def integrate(function, *symbols, meijerg=None, conds='piecewise', risch=None, heurisch=None, manual=None, **kwargs):它内部会构造一个未求值的Integral对象,再调用integral.doit(**doit_flags)触发实际计算。也就是说,integrate只是Integral.doit的便捷封装,二者共享同一套算法调度逻辑。
Integral:未求值积分的对象模型
Integral类 继承自AddWithLimits(后者又是ExprWithLimits的子类,与Sum共用一个超类),用于"表示未求值的积分"。它的限元(limit)有三种解释:
(x,)或x—— 不定积分;(x, a)—— "求值点"形式的抽象原函数(结果用a替换x);(x, a, b)—— 定积分。
几个值得注意的行为:
- 如果不给限元,且被积表达式只有一个自由符号,会自动以该符号为积分变量(
Integral(x)等价于Integral(x, x));有多个自由符号时会报错; - 被积函数若定义了
_eval_Integral钩子,Integral.__new__会直接交给该钩子处理,这是其他类自定义积分行为的扩展点; - 对
Poly调用integrate/Integral自 1.6 版本起已被弃用,应改用Poly.integrate(); Integral具有free_symbols属性(返回"求值后仍会存在的符号",例如Integral(x, (x, y, 1)).free_symbols返回{y}),以及as_dummy方法(用于查看不可被subs替换的哑元符号,积分变量本身永远不能被subs更改)。
核心用法示例
>>> from sympy import * >>> init_printing(use_unicode=False) >>> x = Symbol('x') >>> integrate(x**2 + x + 1, x) 3 2 x x -- + -- + x 3 2多项式积分直接给出精确有理系数结果;有理函数也走完全算法:
>>> integrate(x/(x**2+2*x+1), x) 1 log(x + 1) + ----- x + 1指数—多项式组合(教材中需要反复分部积分才能完成的类型)同样一次到位:
>>> integrate(x**2 * exp(x) * cos(x), x) 2 x 2 x x x x *e *sin(x) x *e *cos(x) x e *sin(x) e *cos(x) ------------ + ------------ - x*e *sin(x) + --------- - --------- 2 2 2 2甚至部分非初等积分(涉及误差函数)也能求值:
>>> integrate(exp(-x**2)*erf(x), x) ____ 2 \/ pi *erf (x) -------------- 4定积分的收敛条件处理:conds参数
定积分,尤其是反常积分,往往牵涉收敛条件。conds参数控制这些条件如何返回(对应 integrate 文档字符串中的策略说明):
conds='piecewise'(默认):结果以Piecewise分段函数形式返回;conds='separate':结果为(结果, 收敛条件)元组;conds='none':直接丢弃条件,只返回公式本身。
>>> integrate(x**a*exp(-x), (x, 0, oo)) # 等价于 conds='piecewise' Piecewise((gamma(a + 1), re(a) > -1), (Integral(x**a*exp(-x), (x, 0, oo)), True)) >>> integrate(x**a*exp(-x), (x, 0, oo), conds='none') gamma(a + 1) >>> integrate(x**a*exp(-x), (x, 0, oo), conds='separate') (gamma(a + 1), re(a) > -1)可以看到,当参数不满足re(a) > -1时,默认模式会保留未求值的Integral,而不是给出错误结论。
多重积分与line_integrate
integrate支持一次传入多个变量实现多重积分;若省略变量且被积函数是单变量表达式,会自动对该变量做不定积分。此外模块还提供 line_integrate 计算第一类曲线积分:
>>> from sympy import Curve, line_integrate, E, ln >>> from sympy.abc import x, y, t >>> C = Curve([E**t + 1, E**t - 1], (t, 0, ln(2))) >>> line_integrate(x + y, C, [x, y]) 3*sqrt(2)其内部实现是:对曲线参数求导得到弧长微元,把场函数替换为F(r(t))后乘以 $\sqrt{\sum r_i'(t)^2}$,再对参数做一次定积分。注意该函数要求场函数变量数与曲线维度一致,且曲线参数不能与场变量重名。
内部算法调度:SymPy 如何决定用哪个算法
Integral.doit按固定顺序尝试多种算法,先快后慢,直到得到答案为止。这一调度逻辑在 integrals.py 的策略说明 中有完整描述,总顺序为:
- 定积分且上下限含 $\pm\infty$ 时,优先尝试 Meijer G 函数方法;
- 否则先找原函数(antiderivative),按性能排序:多项式积分最先、Meijer G 倒数第二、启发式 Risch(heurisch)最后;
- 若仍未成功,再无条件尝试 G 函数方法。
meijerg=True/False/None分别表示"只用 G 函数方法""绝不使用 G 函数方法""按上述顺序使用全部方法"(默认None)。
有理函数:Lazard-Rioboo-Trager 与 Horowitz-Ostrogradsky
有理函数积分在 sympy/integrals/rationaltools.py 中实现,属于"存在完全算法"的一类:
- ratint:整体入口,负责有理函数的不定积分;
- ratint_ratpart:Horowitz-Ostrogradsky 算法,先把积分拆成"有理部分 + 对数部分";
- ratint_logpart:Lazard-Rioboo-Trager 算法,处理对数部分(产生 $\log$ 项)。
前面的示例x/(x**2+2*x+1)正是这类算法的产物。
三角与特殊函数
- trigintegrate:通过模式匹配处理三角函数的乘积、幂次等常见形态;
deltaintegrate(在 sympy/integrals/deltafunctions.py 中):处理含DiracDelta的积分;singularityintegrate(在 sympy/integrals/singularityfunctions.py 中):处理含SingularityFunction的积分。
Risch 算法:能证明"不存在初等原函数"的决定性过程
Risch 算法 是求初等函数原函数的通用方法,其强大之处在于它是决策过程:要么算出初等原函数,要么证明其不存在。不过 SymPy 目前只实现了完整算法的一小部分(主要是关于指数和对数的超越部分)。
risch_integrate 的签名给出了可用参数:
def risch_integrate(f, x, extension=None, handle_first='log', separate_integral=False, rewrite_complex=None, conds='piecewise'):关键优势:如果返回的是NonElementaryIntegral(Integral的一个子类),则算法已证明该积分不可能用指数、对数、三角函数、幂函数、有理函数、代数函数及其复合来表示。在integrate中传入risch=True可以只走完整 Risch 算法——这在你只关心"是否存在初等原函数"时很有用,因为默认情况下integrate还会用 G 函数等方法尝试把非初等积分表达为特殊函数。
Meijer G 函数方法:非初等定积分的主力
对于非初等定积分,SymPy 借助 Meijer G 函数:单个 G 函数的不定积分总可计算;两个 G 函数乘积在 $0$ 到 $\infty$ 上的定积分也可计算(详见 g-functions.rst)。integrate的meijerg参数即可开关该策略,其实现位于sympy.integrals.meijerint模块。
Risch-Norman 启发式算法:兜底的最后手段
heurisch 实现了简化版的 Risch 算法(Risch-Norman 算法),与配套的components函数一起,在其它算法全部失败后兜底。它通常最慢,所以排在最后。由于它能覆盖大量普通函数,integrate默认就启用它(heurisch=None表示自动决定)。
积分变换:Mellin、Laplace、Fourier 与 Hankel
sympy.integrals.transforms子模块(源码文件 sympy/integrals/transforms.py)为定积分和积分变换提供专门支持。所有变换类都继承自 IntegralTransform 基类,无法计算时抛出 IntegralTransformError。
| 函数 | 数学定义 | 说明 |
|---|---|---|
mellin_transform(f, x, s) | $F(s)=\int_0^\infty x^{s-1}f(x),dx$ | 输出(F(s), 基本带, 收敛条件)三元组;逆变换inverse_mellin_transform(F, s, x, strip)需给出基本带strip=(a, b) |
laplace_transform(f, t, s) | $F(s)=\int_0^\infty e^{-st}f(t),dt$ | 输出(F(s), 收敛条件, 收敛域);配套laplace_correspondence、laplace_initial_conds辅助处理分段/初值问题 |
fourier_transform(f, x, k) | 酉普通频率 Fourier 变换 | 还有inverse_fourier_transform及内部后端的_fourier_transform |
sine_transform/cosine_transform | 酉普通频率正弦/余弦变换 | 各自配有InverseSineTransform/InverseCosineTransform |
hankel_transform(f, r, k, nu) | $F_\nu(k)=\int_0^\infty f(r)J_\nu(kr),r,dr$ | 核函数为贝塞尔函数 $J_\nu$;配有inverse_hankel_transform |
每个变换都同时提供函数形式(立即计算)与类形式(如MellinTransform、LaplaceTransform、FourierTransform、SineTransform、CosineTransform、HankelTransform及其逆变换类),用于表示未求值的变换、延迟计算或参与符号推导。
需要注意:Fourier 族变换默认给出的是酉普通频率(unitary, ordinary-frequency)约定,与部分文献/教材的角频率约定不同;Laplace 变换默认收敛域约定为 $\mathrm{Re}(s) > 0$ 一侧,且结果中会返回收敛条件。
手算风格积分:manualintegrate与integral_steps
前面所有算法要么基于模式匹配,要么与微积分课上教的方法差异很大。而 manualintegrate 则模拟人工手算的套路(分部积分、换元、三角公式等),其最大价值在于步骤可提取、可复现。
模块内部把每一条积分技术建模为Rule子类(见源码中的规则类层次):ConstantRule、PowerRule、AddRule、URule(换元)、PartsRule(分部积分)、CyclicPartsRule(循环分部积分,用于exp(x)*sin(x)型)、SinRule/CosRule、ExpRule、ReciprocalRule等,规则之间可以嵌套组合成完整的求解步骤树。
用法上:
integrate(f, x, manual=True):只用手算风格算法求值,覆盖范围比完整调度小,但结果形式更贴近教科书;integral_steps(f, x):返回完整的步骤树对象(不自动求值),便于逐条展示"如何手算出来"。
SymPy Gamma 在线服务正是基于这套机制向用户展示逐步推导过程。注意:integral_steps返回的是步骤数据结构,若要得到最终表达式需对其进一步展开处理。
数值积分辅助:高斯求积的节点与权重
当符号积分不可行或不需要精确符号结果时,sympy/integrals/quadrature.py 提供任意阶数、任意精度的高斯求积节点与权重计算,全部为符号精度(n_digits控制精度位数):
gauss_legendre(n, n_digits):区间 $[-1,1]$ 上的 Gauss-Legendre 求积;gauss_laguerre(n, n_digits):半无穷区间 $[0,\infty)$,权重含 $e^{-x}$;gauss_hermite(n, n_digits):全实数轴,权重含 $e^{-x^2}$;gauss_gen_laguerre(n, alpha, n_digits):广义 Laguerre,权重含 $x^\alpha e^{-x}$;gauss_chebyshev_t(n, n_digits)与gauss_chebyshev_u(n, n_digits):第一、二类 Chebyshev 求积;gauss_jacobi(n, alpha, beta, n_digits):Jacobi 求积(Legendre 是其特例);gauss_lobatto(n, n_digits):Lobatto 求积(端点固定参与)。
这些函数返回(x, w)节点与权重对,可直接用于 $\int f(x),dx \approx \sum_i w_i f(x_i)$ 的数值近似。
多胞体(Polytope)上的多项式积分:polytope_integrate
intpoly子模块(源码 sympy/integrals/intpoly.py)实现多项式在 2D/3D 多胞体上的精确积分,算法依据 Chin, Lasserre 与 Sukumar (2015) 的论文。主入口为:
def polytope_integrate(poly, expr=None, *, clockwise=False, max_degree=None):输入表示
- 2D 多边形:直接复用
sympy.geometry.polygon中的Polygon数据结构; - 3D 多面体:最经济的表示是"顶点列表 + 每个面(多边形)的顶点索引列表"。以单位立方体为例:
unit_cube = [[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)], [3, 7, 6, 2], [1, 5, 7, 3], [5, 4, 6, 7], [0, 4, 5, 1], [2, 0, 1, 3], [2, 6, 4, 0]]第一个子列表是顶点表,其余子列表(如[3, 7, 6, 2])按顺序给出构成某个面的顶点索引。
2D 示例
单多项式:
>>> from sympy.integrals.intpoly import * >>> init_printing(use_unicode=False) >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), x) 1/6 >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), x + x*y + y**2) 7/24传入多项式列表并指定max_degree(此时列表中的常数项、浮点系数同样被精确积分):
>>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), [3, x*y + y**2, x**4], max_degree=4) 4 2 {3: 3/2, x : 1/30, x*y + y : 1/8}只给max_degree而不给多项式,则计算所有次数不超过该值的单项式:
>>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), max_degree=3) 2 3 2 3 2 2 {0: 0, 1: 1/2, x: 1/6, x : 1/12, x : 1/20, y: 1/6, y : 1/12, y : 1/20, x*y: 1/24, x*y : 1/60, x *y: 1/60}3D 示例
>>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0), (5, 0, 5), (5, 5, 0), (5, 5, 5)], ... [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0], [3, 1, 0, 2], [0, 4, 6, 2]] >>> polytope_integrate(cube, x**2 + y**2 + z**2 + x*y + y*z + x*z) -21875/4带符号系数(用S(-1)/sqrt(2)构造精确值)的八面体:
>>> octahedron = [[S(-1)/sqrt(2), 0, 0), (0, S(1)/sqrt(2), 0), (0, 0, S(-1)/sqrt(2)), (0, 0, S(1)/sqrt(2)), ... (0, S(-1)/sqrt(2), 0), (S(1)/sqrt(2), 0, 0)], ... [3, 4, 5], [3, 5, 1], [3, 1, 0], [3, 0, 4], [4, 0, 2], [4, 2, 5], [2, 0, 1], [5, 2, 1]] >>> polytope_integrate(octahedron, x**2 + y**2 + z**2 + x*y + y*z + x*z) ___ \/ 2 ----- 20参数说明
poly:Polygon对象(2D)或"顶点列表 + 面索引列表"(3D);expr:被积多项式(一元/二元/三元均可),可以是单个表达式、表达式列表,或省略(此时必须给max_degree,返回全部单项式积分结果字典);max_degree:多项式最高次数,用于限制单项式枚举;clockwise:布尔值,指示多边形顶点是否按顺时针排列,用于内部方向/法向判断。
算法选择速查:遇到积分该怎么下手
| 场景 | 建议 |
|---|---|
| 普通初等函数组合的符号积分 | integrate(f, x)默认完整调度即可 |
| 想确认是否存在初等原函数 | integrate(f, x, risch=True),返回NonElementaryIntegral即证明非初等 |
| 想得到手算风格的步骤 | integral_steps(f, x)或integrate(f, x, manual=True) |
| 0 到 ∞ 的定积分、含特殊函数 | 保持meijerg=None(自动),或meijerg=True强制 G 函数方法 |
| 需要显式收敛条件 | 使用conds参数(默认piecewise) |
| 数值近似 | 用gauss_*系列获取节点与权重后自行加权求和 |
| 多项式在凸/非凸多边形、多面体上的精确积分 | polytope_integrate |
已知局限
该模块仍有大量无法积分的函数(完整 Risch 算法也只实现了指数/对数超越部分,代数部分未覆盖)。若遇到integrate原样返回未求值Integral,原因通常是:该函数确实无初等原函数、所需算法分支尚未实现,或 G 函数改写失败。可以尝试manual=True、heurisch=True或拆分成多个子表达式分别积分来绕过部分限制。
延伸阅读
- g-functions.rst:Meijer G 函数积分方法的详细介绍;
- integrals 模块索引页:本模块的文档导航;
- 核心实现:integrals.py(
integrate/Integral/line_integrate)、transforms.py(积分变换)、rationaltools.py(有理函数)、manualintegrate.py(手算步骤)、quadrature.py(高斯求积)、intpoly.py(多胞体积分); - 对应测试:
sympy/integrals/tests/下的test_integrals.py、test_transforms.py、test_manualintegrate.py、test_intpoly.py等覆盖了本文所有示例与边界情况。
【免费下载链接】sympyA computer algebra system written in pure Python项目地址: https://gitcode.com/GitHub_Trending/sy/sympy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考