# 符号解微分方程 · 分类，然后套已知方法

> 已知函数与它导数的关系，反求这个函数——这就是解微分方程。符号地解 ODE，核心是「先给方程分类，再套那类方程的已知解法」。这一章看 SymPy 的 dsolve、classify_ode，并说清它和数值解 ODE 的分工：能求闭式就符号，求不出就数值。

- 作者：David（道雾轩）
- 专栏：符号计算的艺术（https://daiw.org/manual/symbolic-computing.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/symbolic-computing/symbolic-ode
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 符号解微分方程 · 分类，然后套已知方法

微积分符号版的收官，是应用最广的一块——**微分方程（ODE）**。孪生专栏里我们用 [Euler、RK4 一步步数值逼近](https://daiw.org/manual/numerical-computing/ode-euler-rk)它的解；这一章看另一条路：**符号地、精确地把解的公式求出来**。

## dsolve：直接给出解的公式

已知一个未知函数 $f(x)$ 和它导数之间的关系，`dsolve` 尝试反求 $f(x)$ 的**闭式表达式**：

```python
from sympy import *
x = symbols('x')
f = Function('f')

# f'(x) = f(x):导数等于自身
print(dsolve(f(x).diff(x) - f(x), f(x)))          # Eq(f(x), C1*exp(x))

# f''(x) + f(x) = 0:简谐振动方程
print(dsolve(f(x).diff(x, 2) + f(x), f(x)))       # Eq(f(x), C1*sin(x) + C2*cos(x))
```

第一个：「导数等于自身」的函数是 $f(x)=C_1e^x$——指数增长的本质。第二个：「二阶导等于自身的负数」给出 $C_1\sin x+C_2\cos x$——一切振动的数学原型。注意那些 $C_1,C_2$——**任意常数**，它们让解成为一整个**函数族**（初始条件才能定下具体哪一个）。这些都是**精确的解析解**，不是数值曲线。

## 核心思想：先分类，再对症下药

符号解 ODE 的策略，和人类在习题课上学的**一模一样**：**先看这是「哪一类」方程，再套那一类的标准解法**。

<Callout type="info">
  **解 ODE 没有单一的万能算法，而是一个「分类 + 查方法库」的过程。** 数学家几百年来为**各种类型**的 ODE 发展了专门解法：可分离变量的、一阶线性的、恰当方程、伯努利方程、常系数线性方程…… 每一类有它的招。CAS 做的，就是**先[识别](https://daiw.org/manual/symbolic-computing/substitution-matching)方程属于哪一类（模式匹配！），再调用对应的解法**。

  SymPy 的 `classify_ode` 让你看到它识别出的所有可用类型：

  ```python
  print(classify_ode(f(x).diff(x) - f(x)))
  # ('separable', '1st_exact', '1st_linear', 'Bernoulli', ...)  —— 它认出这方程属于好几类
  ```

  这方程同时是「可分离变量」「一阶线性」「伯努利」…… `dsolve` 会挑一个最合适的解法套用。**「分类 + 套方法」——这又是[模式匹配 + 规则应用](https://daiw.org/manual/symbolic-computing/term-rewriting)的一次现身**：识别形状，然后套对应的重写。
</Callout>

## 关键分工：能符号就符号，不能就数值

符号解 ODE 很强，但有个**硬边界**，而且这个边界比积分那里还常撞上：

<Callout type="warn">
  **绝大多数微分方程，没有初等的闭式解。** 能被 `dsolve` 精确解出的，是那些「恰好落入已知类型」的幸运方程；而现实中的非线性 ODE（流体、天气、三体、大多数工程系统）**根本写不出解析解**——不是 CAS 不行，是这些解**在初等函数里不存在**（和[积分那章](https://daiw.org/manual/symbolic-computing/symbolic-integration)同一种困境）。这时唯一的出路，就是回到孪生专栏的**[数值解](https://daiw.org/manual/numerical-computing/ode-euler-rk)**：Euler、RK4 一步步逼近。

  于是分工清清楚楚：

  | | 符号解（dsolve） | 数值解（RK4 等） |
  | --- | --- | --- |
  | 给出 | **精确的解公式** | 一串近似的数值点 |
  | 适用 | 恰好属于已知类型的方程 | **几乎任何**方程 |
  | 洞察 | 看清解的**结构**（增长？振荡？） | 只见一条具体曲线 |
  | 局限 | 大多数方程解不出 | 有[误差](https://daiw.org/manual/numerical-computing/stiffness)、无通用公式 |

  **能求出闭式，符号解无可替代**（它给你整个函数族和结构洞察）；**求不出，就老老实实数值解**。理解这条边界，才能在符号与数值之间选对工具——这正是[倒数第二章](https://daiw.org/manual/symbolic-computing/symbolic-vs-numeric)要展开的主题。
</Callout>

## 小结与下一站

**符号解 ODE**（`dsolve`）给出**精确的解析解**（$f'=f\to C_1e^x$、$f''+f=0\to C_1\sin x+C_2\cos x$，含任意常数即函数族）。它的内核是**「先[分类](https://daiw.org/manual/symbolic-computing/substitution-matching)、再套已知解法」**（`classify_ode` 能列出识别到的类型），又一次是模式匹配 + 规则应用。但**多数 ODE 没有闭式解**，那时必须回到[数值解](https://daiw.org/manual/numerical-computing/ode-euler-rk)——能符号就符号，不能就数值。

微积分符号版走完（求导、积分、极限级数、ODE）。下一站转向**精确求解**：代数方程的精确根，以及符号线性代数——你会看到一个把孪生专栏「打脸」的漂亮回扣。👉 [解方程：精确的根](https://daiw.org/manual/symbolic-computing/equation-solving)。

## 参考文献

- [1] SymPy 文档.「Solving Differential Equations (dsolve, classify_ode).」https://docs.sympy.org/latest/modules/solvers/ode.html
- [2] Boyce & DiPrima.《Elementary Differential Equations》—— ODE 分类与解法。
- [3] Geddes, Czapor & Labahn.《Algorithms for Computer Algebra》—— 符号 ODE 求解。
