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, после чего стройте графики как всей формулы, так и отдельных извлеченных слагаемых. Такой рабочий процесс одинаково хорошо масштабируется от простых экспонент до решений со специальными функциями.