How not to feel bored – 1

Библиотека для символьных вычислений sympy

Основы sympy

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

  • на Windows: зайти в Anaсonda Command Prompt и ввести в нём pip install sympy

  • на MacOS или Linux: открыть терминал и ввести в нём pip install sympy.

Когда библиотека установлена, полезно проверить, что всё прошло, как нужно. Импортируем sympy:

In [1]:
import sympy

Теперь, когда убедились в том, что библиотека импортируется, импортируем все её функции сразу, чтобы не вводить название библиотеки каждый раз при вызове функций:

In [2]:
from sympy import *

Библиотека sympy (сокращение от Symbolic Python) – библиотека для символьных вычислений в Python. Что такое символьные вычисления? В отличие от обычных вычислений (разделить одну числовую переменную на другую, сложить два числа), в таких вычислениях мы работаем с переменными как с символами. Так, мы можем сообщить Python, что строка "x", преобразованная особым образом, это не обычная строка в Python (текст), а переменная в том смысле, в котором мы понимаем её в математике. То есть, мы можем записать выражение "2x(x+1)" и Python будет понимать, что можно не только поставить на место x любое число и посчитать результат, но и работать с такой строкой как с математическим выражением: раскрывать скобки, упрощать, находить производную, считать её значение в точке и так далее.

Рассмотрим пример. Сообщим Python, чтобы далее он воспринимал x и y в выражениях как математические переменные:

In [3]:
x, y = symbols("x y")

Посмотрим на них:

In [4]:
x
Out[4]:
x
In [5]:
y
Out[5]:
y

А теперь на выражения, их содержащие:

In [6]:
2 * x
Out[6]:
2*x
In [7]:
x ** 2 + y ** 2
Out[7]:
x**2 + y**2

Обратите внимание: теперь x и y вводятся без кавычек! Python и так понимает, что мы имеем в виду те x и y, которые мы зафиксировали в symbols(). Если бы этого не сделали, он бы относился к ним как к обычным переменным и в случае, если бы мы не присвоили им значения, выдавал бы ошибку вида NameError: name 'x' is not defined.

Выведем выражение на экран в более красивом виде:

In [8]:
pprint(x ** 2 + y ** 2)
 2    2
x  + y 

Или в ещё более красивом виде (LaTeX-style):

In [9]:
init_printing() # для красивого вида последующих выражений
In [10]:
x ** 2 + y ** 2
Out[10]:
$$x^{2} + y^{2}$$
In [11]:
(x + y) ** 2 - x/y
Out[11]:
$$- \frac{x}{y} + \left(x + y\right)^{2}$$

Теперь попробуем сохранить какое-нибудь математическое выражение и поподставлять в него значения x и y:

In [12]:
expr = (x + y)**2
expr
Out[12]:
$$\left(x + y\right)^{2}$$
In [13]:
expr.subs(x, 2)  # x=2
Out[13]:
$$\left(y + 2\right)^{2}$$
In [14]:
expr.subs(y, 8) # y=8
Out[14]:
$$\left(x + 8\right)^{2}$$

А теперь всё сразу:

In [15]:
expr.subs({x: 4, y:5}) # x=4, y=5
Out[15]:
$$81$$

Оно ещё и посчиталось! Для вычисления значения выражения можно использовать специальный метод evalf() (от evaluate function):

In [16]:
expr2 = 3 * x ** 2 + 5 / y
expr2
Out[16]:
$$3 x^{2} + \frac{5}{y}$$
In [17]:
expr2.evalf(subs={x:2, y:4})
Out[17]:
$$13.25$$

Теперь посмотрим на что-то более интересное. Посмотрим, как с помощью sympy можно упрощать выражения:

In [18]:
primer1 = 3 * (x - 2 * x) + 5 * x
In [19]:
primer1.simplify()  # упростили!
Out[19]:
$$2 x$$
In [20]:
primer2 = (x + y) * 2
primer2.simplify() # тоже упростили
Out[20]:
$$2 x + 2 y$$

Или раскрывать скобки по известным формулам:

In [21]:
p = (x + y) ** 2
In [22]:
p.expand()
Out[22]:
$$x^{2} + 2 x y + y^{2}$$
In [23]:
q = (x + y) ** 3
q.expand()
Out[23]:
$$x^{3} + 3 x^{2} y + 3 x y^{2} + y^{3}$$

И даже по тригонометрическим формулам:

In [24]:
trig = sin(2 * x)
In [25]:
expand_trig(trig)
Out[25]:
$$2 \sin{\left (x \right )} \cos{\left (x \right )}$$

Производные и решения уравнений в sympy

Для начала найдём простенькую производную первого порядка (первую производную) некоторой функции $f(x)$:

In [26]:
fx = x ** 3 + 2* x + 1/x 
fx
Out[26]:
$$x^{3} + 2 x + \frac{1}{x}$$
In [27]:
fx.diff(x) # дифференцируем по x
Out[27]:
$$3 x^{2} + 2 - \frac{1}{x^{2}}$$

Вопрос: как найти значение производной в точке, если совместить .diff() и .evalf()?

Найдем производную второго порядка (вторую производную):

In [28]:
fx.diff(x, 2) # вторая производная по x
Out[28]:
$$2 \left(3 x + \frac{1}{x^{3}}\right)$$

А теперь рассмотрим функцию от двух переменных:

In [29]:
fu = x ** y + y ** 3
fu
Out[29]:
$$x^{y} + y^{3}$$

И найдем частные производные по x и y:

In [30]:
fu.diff(x)
Out[30]:
$$\frac{x^{y} y}{x}$$
In [31]:
fu.diff(y)
Out[31]:
$$x^{y} \log{\left (x \right )} + 3 y^{2}$$

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

In [32]:
solve(2 * x ** 2 - 1) # 2x^2 -1
Out[32]:
$$\left [ - \frac{\sqrt{2}}{2}, \quad \frac{\sqrt{2}}{2}\right ]$$

Теперь совместим: найдём производную и приравняем её к нулю:

In [33]:
f = sqrt(16 - 4 * x - x ** 2)
f
Out[33]:
$$\sqrt{- x^{2} - 4 x + 16}$$
In [34]:
dv = f.diff(x)
dv
Out[34]:
$$\frac{- x - 2}{\sqrt{- x^{2} - 4 x + 16}}$$
In [35]:
solve(dv) # приравниваем результат к 0
Out[35]:
$$\left [ -2\right ]$$

Так как вообще ответов может быть несколько, результат выдаётся в виде списка. Извлечём из него единственный элемент.

In [36]:
solve(dv)[0]
Out[36]:
$$-2$$

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

In [37]:
dv2 = f.diff(x, 2)
dv2
Out[37]:
$$- \frac{\frac{\left(x + 2\right)^{2}}{- x^{2} - 4 x + 16} + 1}{\sqrt{- x^{2} - 4 x + 16}}$$
In [38]:
dv2.evalf(subs={x:-2})
Out[38]:
$$-0.223606797749979$$

В точке $-2$ значение второй производной меньше нуля. Полученная точка является точкой экстремума, а именно, точкой максимума функции. Конечно, в данном случае можно было обойтись и без этого, просто посмотреть на знаки значений производной функции при $x > -2$ и $x<-2$, но это вы можете проделать самостоятельно.