Дифуравнения символьно: dsolve
В разделе про SciPy мы решали дифуры численно — траекторией из точек. SymPy решает их символьно, выдавая точную формулу решения.
dsolve — функция SymPy для символьного решения дифференциальных уравнений: возвращает решение в виде формулы
y(x) = ....
Численно vs символьно: две картины
Численный solve_ivp из SciPy даёт числа: «при t=2 величина равна 36.79». Символьный dsolve даёт формулу: «y(t) = C·e^(−0.5t)». Формула мощнее: в неё можно подставить любое t, проанализировать поведение, продифференцировать. Но символьно решаются далеко не все дифуры — только определённые типы.
Решаем радиоактивный распад символьно
То самое уравнение y' = −k·y из урока про ОДУ. Численно мы получали приближение; символьно — точную экспоненту:
import sympy as sp
t = sp.symbols("t")
k = sp.symbols("k", positive=True)
y = sp.Function("y")
# уравнение y'(t) = -k * y(t)
eq = sp.Eq(y(t).diff(t), -k * y(t))
solution = sp.dsolve(eq, y(t))
print(solution) # Eq(y(t), C1*exp(-k*t))
# с начальным условием y(0) = 100:
sol_ic = sp.dsolve(eq, y(t), ics={y(0): 100})
print(sol_ic) # Eq(y(t), 100*exp(-k*t))
SymPy вывел точное решение y(t) = 100·e^(−kt) — ту самую формулу, которую численный метод лишь приближал. Теперь её можно вычислить в любой точке без накопления ошибок.
Проверим формулу численно «руками»
SymPy утверждает: решение y' = −0.5y, y(0)=100 — это y(t) = 100·e^(−0.5t). Проверим, что эта формула и впрямь удовлетворяет уравнению (производная равна −0.5·y) на чистом Python:
import math
def y(t):
return 100 * math.exp(-0.5 * t)
# численно дифференцируем формулу в точке t=3
h = 1e-6
t0 = 3.0
y_prime = (y(t0 + h) - y(t0 - h)) / (2 * h)
print("y'(3) численно :", round(y_prime, 6))
print("-0.5 * y(3) :", round(-0.5 * y(t0), 6))
print("Совпадают? :", abs(y_prime - (-0.5 * y(t0))) < 1e-4)
Вывод:
y'(3) численно : -11.156508 -0.5 * y(3) : -11.156508 Совпадают? : True
Формула удовлетворяет уравнению: производная решения равна −0.5·y в каждой точке. SymPy не просто угадал — он вывел и доказал решение.
Что dsolve умеет и не умеет
| Тип уравнения | dsolve |
| Линейные с постоянными коэффициентами | решает всегда |
| Разделяющиеся переменные | обычно решает |
| Многие классические типы (Бернулли, Риккати…) | часто решает |
| Произвольные нелинейные | часто не может — нужен численный метод |
Как работает под капотом
dsolve работает как умный «классификатор»: он распознаёт тип уравнения (разделяющиеся переменные, линейное, однородное, точное и т.д.) и применяет соответствующий известный метод решения из учебника по дифурам. Для каждого типа есть свой алгоритм: для линейных с постоянными коэффициентами — характеристическое уравнение, для разделяющихся — интегрирование обеих частей. Если ни один распознанный тип не подходит, SymPy честно сообщает, что решить символьно не может. Это фундаментально: большинство «реальных» нелинейных дифуров не имеют решения в замкнутой форме вообще — для них существует только численный путь (SciPy solve_ivp).
Частые ошибки
- Забыть
Function. Неизвестная функция объявляется черезy = Function("y"), а в уравнении пишетсяy(t), а не простоy. - Ждать решения для любого дифура. Большинство нелинейных уравнений символьно не решаются — это нормально, переходите к численному методу.
- Путать
C1с числом. Без начальных условий решение содержит произвольные константы; задайтеics, чтобы их определить.
Итог
dsolveрешает дифуравнения символьно — выдаёт формулуy(x)=..., а не числа.- Начальные условия задаются через
ics, определяя константы. - Работает для распознаваемых типов (линейные, разделяющиеся и др.); произвольные нелинейные — численно.
- Формула мощнее траектории: точна в любой точке, поддаётся анализу.