3. 表达式化简的常用策略与函数

在符号计算中,“化简”并不是一个把表达式变得“更短”的单一操作,而是一组目标不同、方向各异的变换。同一个表达式,用 simplify 可能得到紧凑的分式,用 expand 会展开成多项式,用 factor 又会回到因式乘积。因此,本节的核心不是记住函数名,而是建立“看形态、选策略、验结果”的判断力:先判断表达式属于哪一类结构,再选择能暴露该结构的变换,最后用数值代入或结构比对确认变换是否达到目的。

五个核心函数各自在做什么

以 SymPy 为例,常用化简函数的分工可以这样理解。simplify 是一个“综合尝试器”,它会调用多种规则并挑选它认为最简单的形式,适合作为兜底手段,但代价是速度较慢、结果不完全可预测。expand 专门做展开:把乘积、幂、部分分式等拆成和式,适合观察各项系数、做逐项比较或准备后续合并同类项。factor 是 expand 的反方向,把多项式还原为因式乘积,适合求根、约分和判断零点。trigsimp 面向三角恒等式,把正余弦、正切、双曲函数之间的冗余组合压缩。powsimp 处理幂的合并与拆分,例如把 x**a*x**b 合并为 x**(a+b),或在需要时反向拆开。

需要强调的是,这些函数并非互斥的“正确答案”,而是不同的观察视角。选择哪一个,取决于你接下来要做什么:要解方程就倾向 factor,要比较系数就倾向 expand,要验证恒等式就倾向 trigsimp 或 simplify。

表达式形态 → 化简策略 → 目标形式 表达式形态 多项式乘积 (x+1)(x-2) 和式多项式 x² - x - 2 三角组合 sin²x + cos²x 同底幂相乘 xᵃ · xᵇ 分式/根式混合 (x²-1)/(x-1) 化简函数 expand 展开为和式 factor 还原为因式乘积 trigsimp 压缩三角恒等式 powsimp 合并/拆分同底幂 simplify 综合兜底尝试 目标形式 逐项系数可见 x² - x - 2 零点/约分清晰 (x+1)(x-2) 恒等式最简 1 指数合并 xᵃ⁺ᵇ 约去公因子 x + 1 同一表达式可沿不同路径变换,选择依据是“下一步要做什么”

同一表达式的三条化简路径

设表达式为 E = (x + 1)*(x - 2) + (x - 1)**2。先看三条路径的差异。

路径一,直接 expand:

import sympy as sp
x = sp.symbols('x')
E = (x + 1)*(x - 2) + (x - 1)**2
print(sp.expand(E))        # 2*x**2 - 2*x - 1
print(sp.factor(sp.expand(E)))  # 无法在有理数域进一步分解

展开后得到 2*x**2 - 2*x - 1,各项系数一目了然,但判别式 Δ = 4 + 8 = 12 不是完全平方数,因此在有理数域上不可约,factor 不会给出更紧凑的乘积形式。这说明“展开后再因式分解”并不总能得到更简形式。

路径二,先 simplify 再观察:

print(sp.simplify(E))      # 2*x**2 - 2*x - 1
print(sp.expand(E) == sp.simplify(E))  # True

本例中 simplify 与 expand 结果一致,因为表达式本身就是多项式,没有分式或三角结构可供压缩。simplify 的价值在更复杂的混合表达式上才会显现。

路径三,构造一个能体现差异的对照表达式 F = (x**2 - 1)/(x - 1):

F = (x**2 - 1)/(x - 1)
print(sp.simplify(F))   # x + 1
print(sp.factor(x**2 - 1))  # (x - 1)*(x + 1)
print(sp.cancel(F))     # x + 1

这里 simplify 和 cancel 都约去了公因子 (x - 1),得到 x + 1;而 factor 只作用于分子,得到 (x - 1)*(x + 1),并未完成约分。可见“因式分解”和“约分”是两个动作,前者是后者的前置条件,但不能替代后者。实际使用中,分式化简应优先考虑 cancel 或 simplify,而不是单独用 factor。

三角与幂:专用函数的不可替代性

对 T = sp.sin(x)**2 + sp.cos(x)**2 + sp.sin(x)*sp.cos(x),trigsimp 会先把平方和压成 1,得到 1 + sin(x)*cos(x);若再配合 expand_trig 或 rewrite,还能进一步写成 1 + sin(2x)/2。而 simplify 对同一表达式通常也能得到相近结果,但耗时更长,且在不同版本中可能给出不同形式。因此在三角场景中,明确知道目标恒等式时,直接用 trigsimp 更可控。

对幂表达式 P = x**a * x**b / x**(a + b - 1),powsimp(P) 会合并同底幂,得到 x(在符号假设允许合并的前提下)。若符号未声明为正,SymPy 可能保留原式或给出带条件的合并结果,这时需要用 symbols('x', positive=True) 明确假设。这一点是初学者最容易忽略的:化简结果依赖符号假设,同一表达式在不同假设下可能得到不同形式,甚至“化简失败”。

判断化简是否成功的实用方法:把候选结果与原始表达式在若干随机数值点上做 evalf 比对,若差值在数值误差范围内一致,说明变换在代数上等价;再结合结构目标(是否出现因式、是否约去公因子、是否合并幂)判断是否“更简”。

建立选择策略的初步判断力

综合以上示例,可以形成一张简明的判断顺序。第一步看结构:是多项式、分式、三角还是幂表达式。第二步看目的:要系数就 expand,要零点就 factor,要约分就 cancel 或 simplify,要恒等式就 trigsimp,要合并幂就 powsimp。第三步看假设:符号的正负、是否整数,会直接影响合并与开方是否合法。第四步做验证:数值代入比对,避免“看起来更短但不等价”的陷阱。

表达式形态首选函数典型目标注意事项
多项式乘积expand逐项系数、后续合并展开后项数可能暴增
和式多项式factor求根、约分前置有理数域上未必可约
分式cancel / simplify约去公因子单用 factor 不完成约分
三角组合trigsimp压缩为最简恒等式可配合 rewrite 换形式
同底幂powsimp合并或拆分指数依赖符号正性假设
混合复杂式simplify兜底尝试较慢,结果不完全可预测

最后要提醒的是,化简没有全局最优解。“更简”是相对于目标而言的:对求解方程,因式形式更简;对数值求值,展开形式可能更稳定;对展示恒等式,三角压缩形式更直观。掌握这些函数的差异,本质上是在掌握“用哪种视角看表达式”的能力,而这正是后续自动求导结果整理与人工复核的基础。