2025, Dec 07 15:02
Извлечение частей общего решения ОДУ в Sympy и их визуализация
Показываем, как в Sympy получать отдельные слагаемые общего решения ОДУ через args, подставлять константы интегрирования с subs и строить графики без копирования
Извлечение частей общего решения ОДУ в Sympy без копирования и вставки
Когда Sympy решает линейное ОДУ, она возвращает символическое выражение, которое обычно представляет собой сумму базисных решений, умноженных на константы интегрирования. Именно такие части удобно по отдельности визуализировать и анализировать, но решатель отдает одну формулу вида C1*exp(-z*sqrt(-e)) + C2*exp(z*sqrt(-e)). Практический вопрос в том, как обратиться к отдельным слагаемым прямо в возвращаемом объекте и построить их графики без ручного копирования.
Минимальный воспроизводимый пример
Следующий фрагмент задает простое ОДУ второго порядка, решает его и печатает правую часть решения:
import sympy as sp
u = sp.Symbol('u')
lam = sp.Symbol('lam')
g = sp.Function('g')
ode = sp.diff(g(u), u, 2) + lam * g(u)
res = sp.dsolve(ode, g(u))
print(res.rhs)
В этом случае правая часть — сумма двух экспонент, каждая умножена на константу интегрирования.
Что именно возвращается и почему это неудобно «резать на куски»
Объект в res.rhs — это выражение Sympy. Оно описывает все общее решение как единое символическое дерево. Пытаться индексировать res.rhs напрямую не получится, потому что это не список Python, а именно выражение. Чтобы выбрать отдельные слагаемые, нужно обратиться к внутренним операндам выражения.
Прямой доступ к слагаемым
Sympy предоставляет доступ к компонентам символического выражения через атрибут args. Для суммы в args лежат слагаемые по порядку, поэтому их можно извлечь по индексу и обрабатывать независимо.
# просматриваем отдельные части правой части (RHS)
print(res.rhs.args[0]) # первое слагаемое
print(res.rhs.args[1]) # второе слагаемое
Так вы получаете каждую часть общего решения без каких‑либо копий.
От символических частей к графикам
Чтобы визуализировать отдельное слагаемое или все решение целиком, обычно нужно подставить численные значения констант интегрирования. Это делается методом subs, после чего выражение можно передать в plot.
# зафиксируем константы интегрирования и построим график полного решения
C1, C2 = sp.symbols("C1 C2")
full_expr = res.rhs.subs({C1: 2, C2: 3})
sp.plot(full_expr, (u, 0, 10))
Если задача — построить график одного элемента общего решения, получите его через args и подставьте только соответствующую константу:
# построим график только первого слагаемого с выбранным значением константы
first_term = res.rhs.args[0]
one_piece = first_term.subs({C1: 1})
sp.plot(one_piece, (u, 0, 10))
Тот же подход работает и когда решатель возвращает специальные функции. Например, если решение имеет вид C1*airyai(-e + z) + C2*airybi(-e + z), вы так же можете обратиться к частям через .args[0] и .args[1], а затем подставить численные значения для C1 или C2 перед построением графика.
Почему это важно
При программном исследовании множества ОДУ не хочется вручную вырезать куски из напечатанных строк. Если относиться к результату решателя как к настоящему символическому объекту, можно выборочно брать слагаемые, фиксировать константы и строить графики или выполнять преобразования предсказуемо и повторяемо. Это экономит время и снижает риск ошибок, особенно когда в решениях появляются специальные функции, такие как функции Эйри.
Итоги
Обращайтесь к внутренним частям решения Sympy через атрибут args, а не попыткой «нарезать» выражение. Подставляйте численные значения констант интегрирования с помощью subs, после чего стройте графики как всей формулы, так и отдельных извлеченных слагаемых. Такой рабочий процесс одинаково хорошо масштабируется от простых экспонент до решений со специальными функциями.