Программирование и научные вычисления на языке Python/§19

Хотя численные методы, некоторые из которых описаны в предыдущих уроках, и находят широкое применение, большей точностью и наглядностью обладают символьные вычисления, которые работают с математическими выражениями, собственно, как и предполагает математика, как с последовательностями символов. Системы, занимающиеся символьными вычислениями, называют также системами компьютерной алгебры. Примерами таких систем служат известные математические среды Maple, Mathcad, Mathematica, Maxima и т. д. В качестве инструмента символьных вычислений мы рассмотрим библиотеку SymPy.

SymPy представляет собой библиотеку символьных вычислений, которая в конечной цели стремится стать полноценной системой компьютерной алгебры, сохраняя при этом как можно более простой код, ясный для понимания и дальнейших изменений и дополнений. SymPy написан исключительно на Python и не требует никаких других библиотек. Установка SymPy происходит аналогично другим продуктам, рассмотренным ранее.

isympy править

Если вы уже используете для своих научных экспериментов IPython, то для вас окажется приятным тот факт, что в SymPy для него имеется обертка — isympy, запуск которой в консоли позволяет упростить некоторые стандартные действия относительно переменных и представлять данные на выходе в удобном для понимания формате записи:


leo@leo:~$ isympy
Python 2.6.5 console for SymPy 0.6.6

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z = symbols('xyz')
>>> k, m, n = symbols('kmn', integer=True)
>>> f, g, h = map(Function, 'fgh')

Documentation can be found at http://sympy.org/

In [1]: (1/cos(x)).series(x, 0, 10)
Out[1]: 
     2      4       6        8           
    x    5x    61x    277x            
1 + ── + ──── + ───── + ────── + O(x**10)
    2     24     720     8064


Далее в уроке, в зависимости от удобства представления, одни данные будут показаны как при работе в стандартном IDLE, другие — как при работе в isympy.


Калькулятор править

SymPy содержит три встроенных числовых типа: Real, Rational и Integer. Класс Rational отвечает за дроби, любую пару целых чисел он определяет как числитель и знаменатель, далее над дробями можно производить типичные действия: умножать, делить, складывать и так далее, при этом например:


>>> from sympy import *
>>> a = Rational(1,2)

>>> a
1/2

>>> a*2
1

>>> Rational(2)**50/Rational(10)**50
1/88817841970012523233890533447265625


# при этом:
>>> 1/2
0
>>> 1.0/2
0.5


# можно использовать математические константы
>>> pi**2
pi**2

>>> pi.evalf()
3.14159265358979

>>> (pi+exp(1)).evalf()
5.85987448204884


# а также и символ для бесконечности
>>> oo > 99999
True
>>> oo + 1
oo


Символы править

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


>>> from sympy import *
>>> x = Symbol('x')
>>> y = Symbol('y')


Теперь вы можете играть с ними:


>>> x+y+x-y
2*x

>>> (x+y)**2
(x + y)**2

>>> ((x+y)**2).expand()
2*x*y + x**2 + y**2


И заменять их другими символами или числами, используя конструкцию subs(old, new):


>>> ((x+y)**2).subs(x, 1)
(1 + y)**2

>>> ((x+y)**2).subs(x, y)
4*y**2

Разложение на элементарные править

Для разложения дроби на элементарные используется apart(expr, x):


In [1]: 1/( (x+2)*(x+1) )
Out[1]:
       1
───────────────
(2 + x)*(1 + x)

In [2]: apart(1/( (x+2)*(x+1) ), x)
Out[2]:
  1       1
───── - ─────
1 + x   2 + x

In [3]: (x+1)/(x-1)
Out[3]:
-(1 + x)
────────
 1 - x

In [4]: apart((x+1)/(x-1), x)
Out[4]:
      2
1 - ─────
    1 - x


Чтобы снова представить их в виде одной дроби together(expr, x):


In [7]: together(1/x + 1/y + 1/z)
Out[7]:
x*y + x*z + y*z
───────────────
     x*y*z

In [8]: together(apart((x+1)/(x-1), x), x)
Out[8]:
-1 - x
──────
1 - x

In [9]: together(apart(1/( (x+2)*(x+1) ), x), x)
Out[9]:
       1
───────────────
(2 + x)*(1 + x)


Пределы править

Пределы в SymPy определяются очень просто. Чтобы найти предел функции f(x) при x -> 0, необходимо так и записать limit(f(x), x, 0):


>>> from sympy import *
>>> x=Symbol("x")
>>> limit(sin(x)/x, x, 0)
1


Естественно, можно использовать и предел в бесконечности:


>>> limit(x, x, oo)
oo

>>> limit(1/x, x, oo)
0

>>> limit(x**x, x, 0)
1


Дифференцирование править

Любое SymPy выражение можно продифференцировать, используя diff(func, var):


>>> from sympy import *
>>> x = Symbol('x')
>>> diff(sin(x), x)
cos(x)
>>> diff(sin(2*x), x)
2*cos(2*x)

>>> diff(tan(x), x)
1 + tan(x)**2


По определению производной вы можете проверить правильность решения:


>>> limit((tan(x+y)-tan(x))/y, y, 0)
1 + tan(x)**2


Вторые, третьи и так далее производные можно найти с помощью diff(func, var, n):


>>> diff(sin(2*x), x, 1)
2*cos(2*x)

>>> diff(sin(2*x), x, 2)
-4*sin(2*x)

>>> diff(sin(2*x), x, 3)
-8*cos(2*x)


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

Используем метод .series(var, point, order):


>>> from sympy import *
>>> x = Symbol('x')
>>> cos(x).series(x, 0, 10)
1 - x**2/2 + x**4/24 - x**6/720 + x**8/40320 + O(x**10)
>>> (1/cos(x)).series(x, 0, 10)
1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + 277*x**8/8064 + O(x**10)


Другой простой пример:


from sympy import Symbol, pprint

x = Symbol("x")
y = Symbol("y")

e = 1/(x + y)
s = e.series(x, 0, 5)

print(s)
pprint(s)


дает нам после запуска:


1/y + x**2*y**(-3) + x**4*y**(-5) - x*y**(-2) - x**3*y**(-4) + O(x**5)
     2    4         3
1   x    x    x    x
 + ── + ── - ── - ── + O(x**5)
y    3    5    2    4
    y    y    y    y


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

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


>>> from sympy import *
>>> x, y = symbols('xy')


Интегралы от элементарных функций:


>>> integrate(6*x**5, x)
x**6
>>> integrate(sin(x), x)
-cos(x)
>>> integrate(log(x), x)
-x + x*log(x)
>>> integrate(2*x + sinh(x), x)
cosh(x) + x**2


И от специальных:


>>> integrate(exp(-x**2)*erf(x), x)
pi**(1/2)*erf(x)**2/4


Можно найти и определенный интеграл:


>>> integrate(x**3, (x, -1, 1))
0
>>> integrate(sin(x), (x, 0, pi/2))
1
>>> integrate(cos(x), (x, -pi/2, pi/2))
2


Или несобственный интеграл:


>>> integrate(exp(-x), (x, 0, oo))
1
>>> integrate(log(x), (x, 0, 1))
-1


Комплексные числа править

>>> from sympy import Symbol, exp, I
>>> x = Symbol("x")
>>> exp(I*x).expand()
exp(I*x)
>>> exp(I*x).expand(complex=True)
I*exp(-im(x))*sin(re(x)) + cos(re(x))*exp(-im(x))
>>> x = Symbol("x", real=True)
>>> exp(I*x).expand(complex=True)
I*sin(x) + cos(x)


Функции править

Тригонометрические править

In [1]: sin(x+y).expand(trig=True)
Out[1]: cos(x)*sin(y) + cos(y)*sin(x)

In [2]: cos(x+y).expand(trig=True)
Out[2]: cos(x)*cos(y) - sin(x)*sin(y)

In [3]: sin(I*x)
Out[3]: *sinh(x)

In [4]: sinh(I*x)
Out[4]: *sin(x)

In [5]: asinh(I)
Out[5]:
π*
───
 2

In [6]: asinh(I*x)
Out[6]: *asin(x)

In [15]: sin(x).series(x, 0, 10)
Out[15]:
     3     5     7       9
    x     x     x       x
x - ── + ─── - ──── + ────── + O(x**10)
    6    120   5040   362880

In [16]: sinh(x).series(x, 0, 10)
Out[16]:
     3     5     7       9
    x     x     x       x
x + ── + ─── + ──── + ────── + O(x**10)
    6    120   5040   362880

In [17]: asin(x).series(x, 0, 10)
Out[17]:
     3      5      7       9
    x    3*x    5*x    35*x
x + ── + ──── + ──── + ───── + O(x**10)
    6     40    112     1152

In [18]: asinh(x).series(x, 0, 10)
Out[18]:
     3      5      7       9
    x    3*x    5*x    35*x
x - ── + ──── - ──── + ───── + O(x**10)
    6     40    112     1152


Сферические гармоники править

In [1]: from sympy.abc import theta, phi

In [2]: Ylm(1, 0, theta, phi)
Out[2]:
  ⎽⎽⎽
╲╱ 3 *cos(θ)
────────────
      ⎽⎽⎽
  2*╲╱ π

In [3]: Ylm(1, 1, theta, phi)
Out[3]:
   ⎽⎽⎽           *φ
-╲╱ 6 *sin(θ)*
────────────────────
          ⎽⎽⎽
      4*╲╱ π

In [4]: Ylm(2, 1, theta, phi)
Out[4]:
   ⎽⎽⎽⎽                  *φ
-╲╱ 30 *sin(θ)*cos(θ)*
────────────────────────────
              ⎽⎽⎽
          4*╲╱ π


Факториалы и гамма-функции править

In [1]: x = Symbol("x")

In [2]: y = Symbol("y", integer=True)

In [3]: factorial(x)
Out[3]: Γ(1 + x)

In [4]: factorial(y)
Out[4]: y!

In [5]: factorial(x).series(x, 0, 3)
Out[5]:
                    2           2    2  2
                   x *EulerGamma    π *x
1 - x*EulerGamma + ────────────── + ───── + O(x**3)
                         2            12


Дзета-функция Римана править

In [18]: zeta(4, x)
Out[18]: ζ(4, x)

In [19]: zeta(4, 1)
Out[19]:
 4
π
──
90

In [20]: zeta(4, 2)
Out[20]:
      4
     π
-1 + ──
     90

In [21]: zeta(4, 3)
Out[21]:
        4
  17   π
- ── + ──
  16   90


Многочлены править

Полиномы Чебышева, Лежандра, Эрмита:


In [1]: chebyshevt(2, x)
Out[1]:
        2
-1 + 2*x

In [2]: chebyshevt(4, x)
Out[2]:
       2      4
1 - 8*x  + 8*x

In [3]: legendre(2, x)
Out[3]:
          2
       3*x
-1/2 + ────
        2

In [4]: legendre(8, x)
Out[4]:
           2         4         6         8
 35   315*x    3465*x    3003*x    6435*x
─── - ────── + ─────── - ─────── + ───────
128     32        64        32       128

In [5]: assoc_legendre(2, 1, x)
Out[5]:
        ⎽⎽⎽⎽⎽⎽⎽⎽
             2
-3*x*╲╱  1 - x

In [6]: assoc_legendre(2, 2, x)
Out[6]:
       2
3 - 3*x

In [7]: hermite(3, x)
Out[7]:
           3
-12*x + 8*x


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

In [1]: f(x).diff(x, x) + f(x)
Out[1]:
   2
  d
─────(f(x)) + f(x)
dx dx

In [2]: dsolve(f(x).diff(x, x) + f(x), f(x))
Out[2]: C*sin(x) + C*cos(x)


Алгебраические уравнения править

In [3]: solve(x**4 - 1, x)
Out[3]: [, 1, -1, -]

In [4]: solve([x + 5*y - 2, -3*x + 6*y - 15], [x, y])
Out[4]: {y: 1, x: -3}


Линейная алгебра править

Матрицы создаются как экземпляры специального класса:


>>> from sympy import Matrix
>>> Matrix([[1,0], [0,1]])
[1, 0]
[0, 1]


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


>>> x = Symbol('x')
>>> y = Symbol('y')
>>> A = Matrix([[1,x], [y,1]])
>>> A
[1, x]
[y, 1]

>>> A**2
[1 + x*y,     2*x]
[    2*y, 1 + x*y]


Над матрицами можно производить практически любые действия линейной алгебры, о чем можно ознакомиться из соответствующего раздела документации и действий над матрицами с помощью модуля mpmath.


Сопоставление с образцом править

Сопоставление с образцом (англ. Pattern matching) — метод анализа списков или других структур данных на наличие в них заданных образцов. для проведения сопоставления используется метод .match(), с использованием объекта класса Wild. Метод возвращает словарь с соответствующим решением:

>>> from sympy import *
>>> x = Symbol('x')
>>> p = Wild('p')
>>> (5*x**2).match(p*x**2)
{p_: 5}

>>> q = Wild('q')
>>> (x**2).match(p*x**q)
{p_: 1, q_: 2}


Если сопоставление не дает результатов, возвращается объект None:


>>> x = Symbol('x')
>>> p = Wild('p', exclude=[1,x])
>>> print (x+1).match(x+p) # 1 is excluded
None
>>> print (x+1).match(p+1) # x is excluded
None
>>> print (x+1).match(x+2+p) # -1 is not excluded
{p_: -1}


Печать править

Существует несколько способов того как выражения могут быть выведены на экран.


Стандартный print править

Привычный вывод str(expression):


>>> from sympy import Integral
>>> from sympy.abc import x
>>> print x**2
x**2
>>> print 1/x
1/x
>>> print Integral(x**2, x)
Integral(x**2, x)


Pretty printing править

Формат, по которому работает isympy по умолчанию в виде псевдографического ascii-форматирования. Немного больше примеров здесь.


>>> from sympy import Integral, pprint
>>> from sympy.abc import x
>>> pprint(x**2)
 2
x
>>> pprint(1/x)
1
-
x
>>> pprint(Integral(x**2, x))
  /
 |
 |  2
 | x  dx
 |
/


Для того, чтобы сделать pprint по умолчанию в стандартном интерпретаторе, производим следующую процедуру:


>>> from sympy import *
>>> import sys
>>> sys.displayhook = pprint
>>> var("x")
x
>>> x**3/3
 3
x
--
3
>>> Integral(x**2, x)
  /
 |
 |  2
 | x  dx
 |
/


Python printing править

>>> from sympy.printing.python import python
>>> from sympy import Integral
>>> from sympy.abc import x
>>> print python(x**2)
x = Symbol('x')
e = x**2
>>> print python(1/x)
x = Symbol('x')
e = 1/x
>>> print python(Integral(x**2, x))
x = Symbol('x')
e = Integral(x**2, x)


LaTeX printing править

LaTeX — наиболее популярный набор макрорасширений системы компьютерной вёрстки TeX, который облегчает набор сложных документов.


>>> from sympy import Integral, latex
>>> from sympy.abc import x
>>> latex(x**2)
x^{2}
>>> latex(x**2, mode='inline')
$x^{2}$
>>> latex(x**2, mode='equation')
\begin{equation}x^{2}\end{equation}
>>> latex(x**2, mode='equation*')
\begin{equation*}x^{2}\end{equation*}
>>> latex(1/x)
\frac{1}{x}
>>> latex(Integral(x**2, x))
\int x^{2}\,dx


MathML править

MathML (от англ. Mathematical Markup Language, язык математической разметки) — это приложение XML, используемое для представления математических символов и формул в документах WWW. MathML рекомендован математической группой W3C.


>>> from sympy.printing.mathml import mathml
>>> from sympy import Integral, latex
>>> from sympy.abc import x
>>> print mathml(x**2)
<apply><power/><ci>x</ci><cn>2</cn></apply>
>>> print mathml(1/x)
<apply><power/><ci>x</ci><cn>-1</cn></apply>


sympy.printing править

Кроме того, как видно из рассмотрения python printing доступен модуль sympy.printing. Интересные функции, доступные в этом модуле:

  • pretty(expr), pretty_print(expr), pprint(expr): возвращают expr в pretty-формате, как показано выше;
  • latex(expr), print_latex(expr): возвращают expr в LaTeX представлении;
  • mathml(expr), print_mathml(expr): то же для MathML;
  • print_gtk(expr): выводит expr в Gtkmathview — GTK виджет, показывающий MathML код.


Что дальше править

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


Ссылки править