21. Symbolický a sympatický SymPy#

Už jsme viděli mnoho nástrojů pro numerické výpočty. Co ale symbolické výpočty? Každý ví, že derivovat umí i cvičená opice, bude to umět i Python? Nečekaná odpověď je ano. Symbolické výpočty naučil Python Ondřej Čertík v balíku SymPy.

Tento notebook byl z (velké) části převzat a přeložen z J.R. Johansson: Lectures on scientific computing with Python - díky.

21.1. Na úvod#

Někteří z vás možná znáte nějaký systém pro počítačovou algebru (Computer Algebra Systems – CAS), např. Maple, Mathematica, Derive, Maxima, Reduce. Pro Python existují dva velké projekty počítačové algebry:

  • SymPy - modul který může být použit v jakémkoli Python programu a je dobře podporován v Jupyter Notebook.

  • Sage - toto je už kompletní (a velice obsáhlý) systém, který si klade za cíl být open source konkurentem komerčním produktům.

My se tady podíváme na některé základní možnosti SymPy.

import matplotlib.pyplot as plt
import numpy as np
import sympy
sympy.init_printing()

21.2. Definujeme symboly#

Pro symbolické výpočty potřebujeme pochopitelně symboly, tak jak jsme zvyklí už z matematiky na základní škole. V Pythonu samotném máme sice proměnné, které jsou v podstatě také symboly, ale operace s nimy se řídí zcela jinými pravidly než potřebujeme pro symbolické výpočty. Naštěstí tu je třída sympy.Symbol.

x = sympy.Symbol('x')
x
../_images/669ddd4c2003baad4e962d1420acd27ca564eab5c8544019353c7a0f103c1fe3.png

Co když napíšeme něco trochu složitějšího.

(sympy.pi + x) / 2
../_images/be8f3e48971ad67f628cfb64ea4c092e536804eb8b8c70afa2c2a5dd749afb1d.png
# co jsme to vůbec dostali za typ
type(_)
sympy.core.add.Add

Můžeme také přičadit symbolům nějaké vlastnosti (to se pak pochopitelně může projevit v dalších výpočtech).

a = sympy.Symbol('a', real=True)
a.is_complex
True
b = sympy.Symbol('b', positive=True)
b.is_real
True
b > 0
../_images/5004d858ef28085441cc944554321d6fb2f51924bc173ad1f20ffbffbb670744.png

Zlomky#

r1 = sympy.Rational(4,5)
r2 = sympy.Rational(5,4)
r1, r2
../_images/c8b7eb07d5c6c0b2822346fea52892e1c4c7aece672f807f2db8f1ad87c69ded.png
r1 + r2
../_images/41ac49d425c323c77b541f6982302d41dd3a2bf94d71c6ea9f2af360c497c2a7.png

21.3. Vyčíslování#

y = (x + sympy.pi)**2

Numerickou hodnotu můžeme získat pomocí funkce N. Často také využijeme metodu subs:

sympy.N(y.subs(x, 2), 5)
../_images/6af12e7a0fc519ed927665aa61dfcafd67627f93e82b717d6ab71f52d7709bae.png

To samé pomocí metody evalf. Pro obojí můžeme zadat počet platných číslic.

sympy.pi.evalf(100)
../_images/6e6e93613d4122b0a936d6dae91ae749aed5f959797c21a584062ed5bc95f925.png

Pokud chceme vytvořit ze symbolického výrazu funkci, použijeme lambdify:

# první argument je seznam proměnných (podobně jako pro lambda funkce)
f_x = sympy.lambdify([x], (x + sympy.pi)**2, 'numpy')
xa = np.linspace(-10, 10)
fix, ax = plt.subplots()
ax.plot(xa, f_x(xa))
[<matplotlib.lines.Line2D at 0x125c4e480>]
../_images/3ecd79898c937dcf46a171371e403ede13edf02be45bbfe00ac72c9e722d17f7.png

21.4. Symbolické úpravy#

Toto je velice důležitá aplikace, která nám může v mnoha případech ušetřit nemálo práce.

Expand a factor#

Začněme pracovat s polynomem, zadaným jako

y = (x+1)*(x+2)*(x+3)
y
../_images/0ff1a0f64867224f74cf81a1907b23db803dbdbc63e95f8cb91683fe89e94a88.png

Polynom rozvineme pomocí expand:

z = sympy.expand(y)
z
../_images/4be717d5d0e4ec536672e14bf1574673cc251739a340df76f79ed879e050e59c.png

Pomocí factor můžeme dostat zpět původní faktorizovaný výraz.

sympy.factor(z)
../_images/0ff1a0f64867224f74cf81a1907b23db803dbdbc63e95f8cb91683fe89e94a88.png

expand můžeme použít i pro trigonometrické funkce:

sympy.expand(sympy.sin(a + b), trig=True)
../_images/f4e177b1ba3c128771b598e8d3798da7291a1c2b93d82156db7ced3d20789949.png

Zjednodušování pomocí simplify#

# tohle by měla být hračka
sympy.simplify(sympy.sin(a)**2 + sympy.cos(a)**2)
../_images/3cbc2a39410e4496fe2189ac1429836e805682b44d5da52a7d19f7785a153cc4.png

21.5. Derivace a integrály#

SymPy umí symbolicky derivovat (je tedy aspoň tak dobrý jako cvičená opice) a i integrovat.

y = (x**2 + sympy.sin(x))**2
y
../_images/1b1c88f4ec393b27033700e62a6b06921930c81de5aeb0834a21ee84800f0f5a.png
sympy.diff(y, x)
../_images/e32c87b2225b61f7ef752b92cb89b36121965a421ffef66befdeb42ea6ceaa31.png

Derivovat můžeme i funkce více proměnných.

x = sympy.Symbol('x')
y = sympy.Symbol('y')
z = sympy.cos(y) * (x**3 + 2*x**2*y)
z
../_images/4b33ae2e3c134054f8f7d3091a4ca65486179e3ed49a3ea9dc2c5e8c92e05a23.png

Tohle spočítá

\(\displaystyle \frac{{{{\rm{d}}^3}z}}{{{\rm{d}}x{\rm{d}}{y^2}}} \)

sympy.diff(z, x, 1, y, 2)
../_images/6b6e84cada1006df2c9a5a5909c842048d96f542f203ed65fa74d958ce1b9649.png

Integrace#

f = sympy.sin(x * y) * sympy.cos(x)
f
../_images/dbe9da14769bac2009569985cf1f947d3202976f302a7d3512fb7665f18be095.png
sympy.integrate(f, x)
\[\begin{split}\displaystyle \begin{cases} \frac{\cos^{2}{\left(x \right)}}{2} & \text{for}\: y = -1 \\- \frac{\cos^{2}{\left(x \right)}}{2} & \text{for}\: y = 1 \\- \frac{y \cos{\left(x \right)} \cos{\left(x y \right)}}{y^{2} - 1} - \frac{\sin{\left(x \right)} \sin{\left(x y \right)}}{y^{2} - 1} & \text{otherwise} \end{cases}\end{split}\]
sympy.integrate(f, y)
\[\begin{split}\displaystyle \left(\begin{cases} - \frac{\cos{\left(x y \right)}}{x} & \text{for}\: x \neq 0 \\0 & \text{otherwise} \end{cases}\right) \cos{\left(x \right)}\end{split}\]

21.6. Generace kódu#

Automatická generace kódu vlastnost, kterou oceníme ve chvíli, kdy cheme implementovat naše analytické výsledky v numerické simulaci. Místo abychom začali ručně přepisovat do programovacího jazyka jako je např. Fortran nebo C, může SymPy tuto nezábavnou práci udělat za nás. Navíc při tom neudělá chyby (pravděpodobně).

Pozor, tento module je work in progress.

# řekněme že chceme někde použít tento výsledek
f = sympy.sin( x * y**2) * sympy.exp(y)
f
../_images/782727ff6f2e4a10dfca8bf16e1cf9b51ecef8730d275d64d2acf0fd81220a5c.png
import sympy.utilities.codegen
f_source = sympy.utilities.codegen.codegen(("f_fortran", f), "F95", "f_fortran")
print(f_source[0][1])
!******************************************************************************
!*                      Code generated with SymPy 1.13.3                      *
!*                                                                            *
!*              See http://www.sympy.org/ for more information.               *
!*                                                                            *
!*                       This file is part of 'project'                       *
!******************************************************************************

REAL*8 function f_fortran(x, y)
implicit none
REAL*8, intent(in) :: x
REAL*8, intent(in) :: y

f_fortran = exp(y)*sin(x*y**2)

end function
f_source = sympy.utilities.codegen.codegen(("f_C", f), "C", "f_C")
print(f_source[0][1])
/******************************************************************************
 *                      Code generated with SymPy 1.13.3                      *
 *                                                                            *
 *              See http://www.sympy.org/ for more information.               *
 *                                                                            *
 *                       This file is part of 'project'                       *
 ******************************************************************************/
#include "f_C.h"
#include <math.h>

double f_C(double x, double y) {

   double f_C_result;
   f_C_result = exp(y)*sin(x*pow(y, 2));
   return f_C_result;

}

21.7. Další možnosti SymPy#

Ukázali jsme si základy práce se symbolickými výpočty pomocí SymPy. Není v našich silách ukázat, co všechno SymPy umí – je toho opravdu hodně. Přehled můžeme získat, podívame-li se na obsah v dokumentaci:

  • SymPy Core

  • Combinatorics Module

  • Number Theory

  • Concrete Mathematics

  • Numerical evaluation

  • Functions Module

  • Geometry Module

  • Geometric Algebra Module

  • Geometric Algebra Module for SymPy

  • Extended LaTeXModule for SymPy

  • Symbolic Integrals

  • Numeric Integrals

  • Logic Module

  • Matrices

  • Mpmath

  • Polynomials Manipulation Module

  • Printing System

  • Plotting Module

  • Pyglet Plotting Module

  • Assumptions module

  • Term rewriting

  • Series Expansions

  • Sets

  • Simplify

  • Details on the Hypergeometric Function Expansion Module

  • Statistics

  • Stats

  • ODE

  • PDE

  • Solvers

  • Tensor Module

  • Utilities

  • Parsing input

  • Physics Module

  • Category Theory Module

  • Differential Geometry Module

  • Contributions to docs