Библиотека Sympy: символьные вычисления в Python

Что такое SymPy? Это библиотека символьной математики языка Python. Она является реальной альтернативой таким математическим пакетам как Mathematica или Maple и обладает очень простым и легко расширяемым кодом. SymPy написана исключительно на языке Python и не требует никаких сторонних библиотек.

Документацию и исходный код этой библиотеки можно найти на ее официальной странице.

Первые шаги с SymPy

Используем SymPy как обычный калькулятор

В библиотеке SymPy есть три встроенных численных типа данных: RealRational и Integer. С Real и Integer все понятно, а класс Rational представляет рациональное число как пару чисел: числитель и знаменатель рациональной дроби. Таким образом, Rational(1, 2) представляет собой 1/2, а, например, Rational(5, 2) — соответственно 5/2.

import sympy as sym
a = sym.Rational(1, 2) # дает 1/2
a * 2 # дает 1

Библиотека SymPy использует библиотеку mpmath, что позволяет производить вычисления с произвольной точностью. Таким образом, ряд констант (например, пи, e), которые в данной библиотеке рассматриваются как символы, могут быть вычислены с любой точностью.

sym.pi**2 # результат pi**2
sym.pi.evalf() # результат 3.14159265358979
(sym.pi + sym.exp(1)).evalf() # результат 5.85987448204884

Как можно заметить, функция evalf() дает на выходе число с плавающей точкой.

В SymPy есть также класс, представляющий такое понятие в математике, как бесконечность. Он обозначается следующим образом: oo.

sym.oo > 99999 # результат True
sym.oo + 1 # результат oo

Символы

В отличие от ряда других систем компьютерной алгебры, в SymPy можно в явном виде задавать символьные переменные. Это происходит следующим образом:

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

После их задания, с ними можно производить различные манипуляции.

x + y + x - y # результат 2*x
(x + y) ** 2 # результат (x + y)**2

С символами можно производить преобразования с использованием некоторых операторов языка Python. А именно, арифметических (+-```***) и логических (&|, ~) .

Библиотека SymPy позволяет задавать форму вывода результатов на экран. Обычно мы используем формат такого вида:

sym.init_printing(use_unicode=False, wrap_line=True)

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

SymPy способна на сложные алгебраические преобразования. Здесь мы рассмотрим наиболее востребованные из них, а именно раскрытие скобок и упрощение выражений.

Раскрытие скобок

Чтобы раскрыть скобки в алгебраических выражениях, используйте следующий синтаксис:

sym.expand((x + y) ** 3) 

𝑥3+3𝑥2𝑦+3𝑥𝑦2+𝑦3

3 * x * y ** 2 + 3 * y * x ** 2 + x ** 3 + y ** 3

𝑥3+3𝑥2𝑦+3𝑥𝑦2+𝑦3

При помощи ключевого слова можно добавить поддержку работы с комплексными переменными, а также раскрытие скобок в тригонометрических функциях.

sym.expand(x + y, complex=True)#результат re(𝑥)+re(𝑦)+𝑖im(𝑥)+𝑖im(𝑦)
sym.expand(sym.cos(x + y), trig=True)
# результат −sin(𝑥)sin(𝑦)+cos(𝑥)cos(𝑦)

Упрощение выражений

Если вы хотите привести выражение к более простому виду (возможно, сократить какие-то члены), то используйте функцию simplify.

sym.simplify((x + x * y) / x) # результат y + 1

Также надо сказать, что для определенных видов математических функций существуют альтернативные, более конкретные функции для упрощения выражений. Так, для упрощения степенных функций есть функция powsimp, для тригонометрических —trigsimp, а для логарифмических — logcombineradsimp.

Вычисления

Вычисления пределов

Для вычисления пределов в SymPy предусмотрен очень простой синтаксис, а именно limit(function, variable, point). Например, если вы хотите вычислить предел функции f(x), где x -> 0, то надо написать limit(f(x), x, 0).

sym.limit(sym.sin(x) / x, x, 0) # результат 1

Также можно вычислять пределы, которые стремятся к бесконечности.

sym.limit(x, x, sym.oo) # результат oo
sym.limit(1 / x, x, sym.oo) # результат 0
sym.limit(x ** x, x, 0) # результат 1

Дифференцирование

Для дифференцирования выражений в SymPy есть функция diff(func, var). Ниже даны примеры ее работы.

sym.diff(sym.sin(x), x) # результат cos(𝑥)
sym.diff(sym.sin(2 * x), x) # результат 2cos(2𝑥)
sym.diff(sym.tan(x), x)

tan2(𝑥)+1

Проверим результат последней функции при помощи определения производной через предел.

sym.limit((sym.tan(x + y) - sym.tan(x)) / y, y, 0)

tan2(𝑥)+1 Результат тот же.

Также при помощи этой же функции могут быть вычислены производные более высоких порядков. Синтаксис функции будет следующим: diff(func, var, n). Ниже приведено несколько примеров.

sym.diff(sym.sin(2 * x), x, 1) # результат 2cos(2𝑥)
sym.diff(sym.sin(2 * x), x, 2) # результат −4sin(2𝑥)
sym.diff(sym.sin(2 * x), x, 3) # результат −8cos(2𝑥)

Разложение в ряд

Для разложения выражения в ряд Тейлора используется следующий синтаксис: series(expr, var).

sym.series(sym.cos(x), x)

1−𝑥2/2+𝑥4/24+𝑂(𝑥6)

sym.series(1/sym.cos(x), x)

1+𝑥2/2+5𝑥4/24+𝑂(𝑥6)

Интегрирование

В SymPy реализована поддержка определенных и неопределенных интегралов при помощи функции integrate(). Интегрировать можно элементарные, трансцендентные и специальные функции. Интегрирование осуществляется с помощью расширенного алгоритма Риша-Нормана. Также используются различные эвристики и шаблоны. Вот примеры интегрирования элементарных функций:

sym.integrate(sym.sin(x), x) # результат −cos(𝑥)
sym.integrate(sym.log(x), x) # результат 𝑥log(𝑥)−𝑥

Также несложно посчитать интеграл и от специальных функций. Возьмем, например, функцию Гаусса:

sym.integrate(sym.exp(-x ** 2) * sym.erf(x), x)

Результат вычисления можете посмотреть сами. Вот примеры вычисления определенных интегралов.

sym.integrate(x**3, (x, -1, 1)) # результат 0
sym.integrate(sym.sin(x), (x, 0, sym.pi / 2)) # результат 1
sym.integrate(sym.cos(x), (x, -sym.pi / 2, sym.pi / 2)) 
# результат 2

Также можно вычислять определенные интегралы с бесконечными пределами интегрирования (несобственные интегралы).

sym.integrate(sym.exp(-x), (x, 0, sym.oo)) # результат 1

Решение уравнений

При помощи SymPy можно решать алгебраические уравнения с одной или несколькими переменными. Для этого используется функция solveset().

sym.solveset(x ** 4 - 1, x) # результат {−1,1,−𝑖,𝑖}

Как можно заметить, первое выражение функции solveset() приравнивается к 0 и решается относительно х. Также возможно решать некоторые уравнения с трансцендентными функциями.

sym.solveset(sym.exp(x) + 1, x) # результат {𝑖(2𝑛𝜋+𝜋)|𝑛∈ℤ}

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

SymPy способна решать широкий класс полиномиальных уравнений. Также при помощи данной библиотеки можно решать и системы уравнений. При этом переменные, относительно которых должна быть разрешена система, передаются в виде кортежа во втором аргументе функции solve(), которая используется для таких задач.

solution = sym.solve((x + 5 * y - 2, -3 * x + 6 * y - 15), (x, y))
solution[x], solution[y] # результат (-3, 1) 

Факторизация

Другим мощным методом исследования полиномиальных уравнений является факторизация многочленов (то есть представление многочлена в виде произведения многочленов меньших степеней). Для этого в SymPy предусмотрена функция factor(), которая способна производить факторизацию очень широкого класса полиномов.

f = x ** 4 - 3 * x ** 2 + 1
sym.factor(f)

(𝑥2−𝑥−1)(𝑥2+𝑥−1)

sym.factor(f, modulus=5)

(𝑥−2)2(𝑥+2)2

Булевы уравнения

Также в SymPy реализована возможность решения булевых уравнений, что по сути означает проверку булевого выражения на истинность. Для этого используется функция satisfiable().

sym.satisfiable(x & y) # результат {x: True, y: True}

Данный результат говорит нам о том, что выражение (x & y) будет истинным тогда и только тогда, когда x и y истинны. Если выражение не может быть истинным ни при каких значениях переменных, то функция вернет результат False.

sym.satisfiable(x & ~x) # результат False

Линейная алгебра

Матрицы

Матрицы в SymPy создаются как экземпляры класса Matrix:

sym.Matrix([[1, 0], [0, 1]])

[10]
[01]

В отличие от NumPy, мы можем использовать в матрицах символьные переменные:

x, y = sym.symbols('x, y')
A = sym.Matrix([[1, x], [y, 1]])
A

[1 𝑦]
[𝑥 1]

И производить с ними разные манипуляции:

A**2

[𝑥𝑦+1 2𝑦]
[2𝑥 𝑥𝑦+1]

Дифференциальные уравнения

При помощи библиотеки SymPy можно решать некоторые обыкновенные дифференциальные уравнения. Для этого используется функция dsolve(). Для начала нам надо задать неопределенную функцию. Это можно сделать, передав параметр cls=Function в функцию symbols().

f, g = sym.symbols('f g', cls=sym.Function)

Теперь f и g заданы как неопределенные функции. мы можем в этом убедиться, просто вызвав f(x).

f(x) # результат 𝑓(𝑥)
f(x).diff(x, x) + f(x)

𝑓(𝑥)+𝑑2/𝑑𝑥2𝑓(𝑥)

Теперь решим следующее дифференциальное уравнение:

sym.dsolve(f(x).diff(x, x) + f(x), f(x))
# результат 𝑓(𝑥)=𝐶1sin(𝑥)+𝐶2cos(𝑥)

Чтобы улучшить решаемость и помочь этой функции в поиске решения, можно передавать в нее определенные ключевые аргументы. Например, если мы видим, что это уравнение с разделяемыми переменными, то мы можем передать в функцию аргумент hint='separable'.

sym.dsolve(sym.sin(x) * sym.cos(f(x)) + sym.cos(x) * sym.sin(f(x)) * f(x).diff(x), f(x), hint='separable') 
# результат [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), 
#            acos(C1/cos(x)))]