ПЗ №6. Символьные вычисления в Python

Хорошевич Павел Александрович

Что такое символьная математика?

NumPy оперирует массивами чисел, Matplotlib строит графики по числовым данным.

Но в математике и физике мы часто работаем с символами и выражениями:

\[x^2 - y^2 = (x - y)(x + y)\]

Символьные вычисления - это преобразования математических выражений в аналитическом виде, без подстановки конкретных чисел.

Модуль SymPy

SymPy - библиотека для символьной математики.

Основные возможности:

  • алгебраические преобразования;

  • решение уравнений и систем уравнений;

  • математический анализ (пределы, производные, интегралы);

  • линейная алгебра (матрицы, определители);

  • теория чисел, комбинаторика;

  • построение графиков функций.

Установка:

pip install sympy

Импорт модуля

По аналогии с NumPy и Pandas, принято использовать псевдоним:

import sympy as sp

Для корректного вывода формул в Jupyter Lab в виде LaTeX:

sp.init_printing()

После этого выражения будут отображаться в виде формул, а не в упрощённом виде.

Создание символов

Символ - это “переменная” в математическом смысле. Создаётся объектом класса Symbol:

x = sp.Symbol('x')
x

Символ передаётся строкой!

x = sp.Symbol(x)    # ОШИБКА
x = sp.Symbol('x')  # правильно

Символ и переменная Python

Имя переменной Python и имя символа могут не совпадать:

a = sp.Symbol('x')
a + a + 1

\(2x + 1\).

Лучше использовать совпадающие имена:

x = sp.Symbol('x')
y = sp.Symbol('y')

Одновременное объявление нескольких символов

Используем функцию symbols() (с маленькой буквы!):

x, y, z = sp.symbols('x y z')

Или через запятую в строке:

a, b, c = sp.symbols('a, b, c')

Арифметические операции с символами

С символами работают обычные операторы Python:

x, y = sp.symbols('x y')
x + y + x

\(2x + y\).

x * (x + y)

\(x(x + y)\).

(x + y) ** 2

\((x + y)^2\).

Автоматическое упрощение

SymPyавтоматически сокращает простые выражения:

x + x + x

\(3x\)

Но сложные выражения остаются в исходном виде:

(x + 2) * (x + 3)

\((x + 2)(x + 3)\)

Чтобы раскрыть скобки - нужно явно вызвать функцию expand.

Функции для обработки выражений

Раскрытие скобок. Функция expand

Функция expand() раскрывает скобки и приводит подобные:

expr = (x + 2) * (x + 3)
sp.expand(expr)

\[x^2 + 5x + 6\]

Более сложный пример:

expr2 = (x + y) ** 3
sp.expand(expr2)

\[x^3 + 3x^2 y + 3x y^2 + y^3\]

Разложение на множители. Функция factor

Функция factor() выполняет обратную операцию:

expr = x**2 - y**2
sp.factor(expr)

\[(x - y)(x + y)\]

expr2 = x**3 + 3*x**2*y + 3*x*y**2 + y**3
sp.factor(expr2)

\[(x + y)^3\]

Упрощение выражения. Функция simplify

Функция simplify() ищет наиболее компактную форму для выражения:

expr = (x + 1)**2 - x**2 - 2*x
sp.simplify(expr)

\[1\]

Полезна для тригонометрических и логарифмических выражений:

expr = sp.sin(x)**2 + sp.cos(x)**2
sp.simplify(expr)

\[1\]

Подстановка значений. Функция subs

Метод subs() подставляет значения в выражение:

expr = x**2 + 2*x*y + y**2
expr.subs(x, 2)

\[4y + 4 + y^2\]

Подстановка нескольких значений - через словарь:

expr.subs({x: 2, y: 3})

\[25\]

Пример решения задачи из физики

Путь при равноускоренном движении: \(s = ut + \dfrac{at^2}{2}\).

s, u, a, t = sp.symbols('s u a t')
formula = u*t + a*t**2 / 2

Найдём путь при \(u = 5\) м/с, \(a = 2\) м/с², \(t = 3\) с:

formula.subs({u: 5, a: 2, t: 3})

\[24\]

Ответ: \(24\) метра.

Решение уравнений. Функция solve

Функция solve() решает уравнения.

SymPy ищет корни выражения, приравниваемого к нулю!

Уравнение \(x - 5 = 7\) нужно переписать: \(x - 5 - 7 = 0\).

x = sp.Symbol('x')
expr = x - 5 - 7
sp.solve(expr)

\[[12]\]

Результат - список корней.

Пример с линейным уравнением

Решим уравнение \(3x + 7 = 22\):

expr = 3*x + 7 - 22
sp.solve(expr)

\[[5]\]

Пример с квадратным уравнением

\(x^2 + 5x + 4 = 0\):

expr = x**2 + 5*x + 4
sp.solve(expr)

\[[-4,\ -1]\]

С параметром dict=True получаем результат в виде словаря:

sp.solve(expr, dict=True)

\[[\{x: -4\},\ \{x: -1\}]\]

Комплексные корни

Уравнение \(x^2 + x + 1 = 0\) не имеет действительных корней:

expr = x**2 + x + 1
sp.solve(expr)

\[\left[-\frac{1}{2} - \frac{\sqrt{3}\,i}{2},\ -\frac{1}{2} + \frac{\sqrt{3}\,i}{2}\right]\]

SymPy работает в поле комплексных чисел автоматически. Мнимая единица обозначается в коде как I.

Выражение одной переменной через другие

Найдём \(t\) из формулы \(s = ut + \dfrac{at^2}{2}\):

s, u, a, t = sp.symbols('s u a t')
expr = u*t + a*t**2/2 - s
sp.solve(expr, t)

\[\left[\frac{-u - \sqrt{2as + u^2}}{a},\ \frac{-u + \sqrt{2as + u^2}}{a}\right]\]

Указываем вторым аргументом, какую переменную ищем.

Системы линейных уравнений

\[\begin{cases} 2x + 3y = 6 \\ 3x + 2y = 12 \end{cases}\]

Переносим всё в левую часть:

x, y = sp.symbols('x y')
eq1 = 2*x + 3*y - 6
eq2 = 3*x + 2*y - 12
sp.solve((eq1, eq2), dict=True)

\[\left[\left\{x: \frac{24}{5},\ y: -\frac{6}{5}\right\}\right]\]

Проверка решения

Подставим найденные значения обратно:

soln = sp.solve((eq1, eq2), dict=True)[0]
eq1.subs(soln)

\[0\]

eq2.subs(soln)

\[0\]

Оба выражения обратились в ноль - решение верно.

Тригонометрические уравнения

Решим \(\sin(x) = \dfrac{1}{2}\):

x = sp.Symbol('x')
expr = sp.sin(x) - sp.Rational(1, 2)
sp.solve(expr, x)

\[\left[\frac{\pi}{6},\ \frac{5\pi}{6}\right]\]

sp.Rational(1, 2) - дробь \(\frac{1}{2}\), а не 0.5.

Преобразование строк. Функция sympify

Преобразуем строку в выражение SymPy:

s = "x**2 + 3*x + 2"
expr = sp.sympify(s)
expr

\[x^2 + 3x + 2\]

sp.factor(expr)

\[(x + 1)(x + 2)\]

Построение графиков в SymPy

В Matplotlib для построения графика функции нужно было создать массивы x и y. В SymPy достаточно выражения:

x = sp.Symbol('x')
sp.plot(2*x + 3)

График функции

График с заданным диапазоном

Ограничим \(x\) отрезком \([-5,\ 5]\):

sp.plot(2*x + 3, (x, -5, 5)) # (символ, нижняя_граница, верхняя_граница)

График функции

Подписи и заголовок

Именованные параметры title, xlabel, ylabel:

sp.plot(
    2*x + 3,
    (x, -5, 5),
    title='Линейная функция',
    xlabel='x',
    ylabel='y = 2x + 3'
)

График квадратичной функции

Парабола \(y = x^2 - 4\):

sp.plot(x**2 - 4, (x, -5, 5), title='Парабола')

График функции

Тригонометрические функции

sp.plot(sp.sin(x), (x, -2*sp.pi, 2*sp.pi), title='y = sin(x)')

График функции

sp.pi - символ числа \(\pi\).

Несколько функций на одном графике

Передаём несколько выражений в plot():

sp.plot(2*x + 3, 3*x + 1, (x, -5, 5))

Графики функций

Настройка цветов и легенда

p = sp.plot(
    2*x + 3, 3*x + 1,
    (x, -5, 5),
    legend=True,
    show=False
)
p[0].line_color = 'b'   # первая линия - синяя
p[1].line_color = 'r'   # вторая - красная
p.show()
  • show=False - не показывать график сразу;
  • p[0], p[1] - обращение к отдельным линиям;
  • доступные цвета: 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w'.

Пример: точка пересечения графиков

Найдём пересечение \(y = 2x + 3\) и \(y = 3x + 1\) аналитически:

x = sp.Symbol('x')
eq = (2*x + 3) - (3*x + 1)
sp.solve(eq)

\[[2]\]

При \(x = 2\): \(y = 2 \cdot 2 + 3 = 7\). Точка пересечения: \((2,\ 7)\).

Точка пересечения графиков

Связь SymPy с другими научными библиотеками

Связь SymPy и NumPy

SymPy - символьные, NumPy - числовые вычисления.

Численное значение выражения можно получить с помощью функции evalf:

expr = sp.sqrt(2) + sp.pi
expr.evalf()

\[4.55580621596148\]

evalf() - аналог float() для символьных выражений. Можно указать точность:

sp.pi.evalf(50)

Связь SymPy и Matplotlib

Для более тонкой настройки графиков можно конвертировать SymPy-выражение в функцию Python:

import numpy as np
import matplotlib.pyplot as plt

f = sp.lambdify(x, sp.sin(x) + x**2/10, 'numpy')
x_vals = np.linspace(-5, 5, 200)
plt.plot(x_vals, f(x_vals))
plt.grid(True)
plt.show()

lambdify() создаёт быструю численную функцию из символьного выражения.

Рассмотренные функции

Задача Функция / метод
Объявить символ sp.Symbol('x'), sp.symbols('x y z')
Раскрыть скобки sp.expand()
Разложить на множители sp.factor()
Упростить sp.simplify()
Подставить значение .subs({x: 2})
Получить число .evalf()
Преобразовать строку sp.sympify()
Решить уравнение sp.solve()
Построить график sp.plot()