Hlavní navigace

SymPy: knihovna pro symbolické výpočty zapsané přímo v Pythonu

24. 5. 2022
Doba čtení: 22 minut

Sdílet

 Autor: SimPy
Python se v současnosti využívá v mnoha různých oblastech IT. Jednou z těchto oblastí jsou numerické výpočty (NumPy), ovšem je možné ho použít i pro symbolické výpočty: zjednodušování výrazů, symbolickou derivaci a integraci a podobně.

Obsah

1. SymPy: knihovna pro symbolické výpočty zapsané přímo v Pythonu

2. Čím se liší knihovna SymPy od podobně koncipovaných nástrojů

3. Instalace knihovny Sympy

4. Zjednodušování konstantních výrazů

5. Funkce sympy.pprint pro formátovaný výstup

6. Výrazy s proměnnými

7. Výrazy s větším množstvím proměnných

8. Zjednodušování výrazů s proměnnými

9. Polynomy a další výrazy s mocninami

10. Úprava výrazů funkcí sympy.factor – rozklad polynomu na kořenové činitele

11. Úprava výrazů funkcí sympy.expand – roznásobení závorek

12. Nalezení kořenů kvadratické rovnice

13. Hledání kořenů pro určitou proměnnou

14. Symbolická derivace

15. Ukázka derivace složitějšího výrazu

16. Symbolická integrace

17. Integrace složitějších výrazů

18. Obsah druhé části článku

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. SymPy: knihovna pro symbolické výpočty zapsané přímo v Pythonu

Jak jsme si již řekli v perexu dnešního článku, je programovací jazyk Python používán v mnoha různorodých oblastech IT, od (řekněme) řízení blikání LED na jednodeskových mikropočítačích přes řízení datových pipeline až po oblast strojového učení a umělé inteligence. Poměrně často se setkáme s použitím Pythonu při zpracování numerických dat, kde se typicky používá kombinace knihoven NumPy+Matplotlib, nebo (možná i častěji) Jupyter Notebook + NumPy + Matplotlib. Knihovna NumPy je přitom určena především pro provádění numerických výpočtů nad vektory, maticemi a nad n-rozměrnými poli.

V některých případech je ovšem vyžadována i manipulace s celými matematickými výrazy, například se zápisem polynomu atd. Jedná se typicky o symbolické výpočty, kde výsledkem není konkrétní numerická hodnota (či vektor hodnot), ale jiný výraz. Příkladem takových problémů je zjednodušování výrazů, hledání kořenů kvadratických rovnic, faktorizace polynomů, symbolická derivace, symbolická integrace, výpočet limit atd. Jedním z nástrojů, které tyto manipulace se symboly podporují, je knihovna nazvaná SymPy, jež je založená (jak již ostatně její název napovídá) na Pythonu. SymPy jde dokonce tak daleko, že jednotlivé výrazy jsou přímo zapsány jako výrazy programovacího jazyka Python, se všemi výhodami, které toto řešení přináší. Výsledkem činnosti SymPy jsou většinou výrazy, které mohou být vytištěny na terminál či ve formě kvalitního „2D“ výstupu provedeného TeXem.

2. Čím se liší knihovna Sympy od podobně koncipovaných nástrojů?

Ve skutečnosti existuje poměrně velké množství nástrojů určených pro manipulaci s matematickými výrazy, tedy pro jejich zjednodušení, rozklad polynomů na kořenové činitele, výpočet kořenů polynomů, symbolický výpočet limit, derivací, integrací atd. Některé z těchto nástrojů jsou vypsány v následující tabulce (zdrojem je v tomto případě tabulka získaná ze stránky https://en.wikipedia.org/wi­ki/List_of_computer_algebra_sys­tems#General):

Produkt
Axiom
Cadabra
CoCoA
Derive
Erable
Fermat
FORM
FriCAS
GAP
GiNaC
KANT/KASH
LiveMath
Macaulay2
Macsyma
Magma
Magnus
Maple
Mathcad
Mathematica
Mathics
Mathomatic
Maxima
MuMATH
MuPAD
OpenAxiom
PARI/GP
Reduce
Scilab
SageMath
SINGULAR
SMath
Symbolic
Symbolic (ovšem odlišný produkt)
SICMUtils
SymPy
TI-Nspire CAS
Wolfram Alpha
Xcas/Giac
Yacas

Ovšem knihovna SymPy se od mnoha těchto nástrojů odlišuje v jednom zajímavém bodě. Mnoho ostatních nástrojů je založeno na doménově specifickém jazyce, což znamená, že se uživatel musí učit další (novou) syntaxi a sémantiku. V tomto ohledu je tedy zpracování matematických výrazů relativně izolováno. Naproti tomu se v SymPy výrazy zapisují přímo v Pythonu, což je pro uživatele znalého alespoň základů tohoto jazyka mnohdy mnohem jednodušší. Navíc je tak umožněna velmi dobrá integrace s dalšími nástroji, například s Jupyter Notebookem.

3. Instalace knihovny Sympy

Knihovna Sympy je nabízena přes PyPi, takže její instalace by měla být jednoduchá a přímočará. Knihovnu nainstalujeme pro aktuálně přihlášeného uživatele následujícím způsobem:

$ pip3 install --user sympy
 
Collecting sympy
  Downloading sympy-1.10.1-py3-none-any.whl (6.4 MB)
     |████████████████████████████████| 6.4 MB 2.0 MB/s
Collecting mpmath>=0.19
  Downloading mpmath-1.2.1-py3-none-any.whl (532 kB)
     |████████████████████████████████| 532 kB 36.8 MB/s
Installing collected packages: mpmath, sympy
Successfully installed mpmath-1.2.1 sympy-1.10.1
Poznámka: povšimněte si, že jedinou závislostí je knihovna mpmath, s níž se ještě na stránkách Roota setkáme.

Základní kontrolu instalace provedeme jednoduše – přímo v interpretru Pythonu:

$ python
 
Python 3.9.12 (main, Mar 25 2022, 00:00:00)
[GCC 11.2.1 20220127 (Red Hat 11.2.1-9)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Test, zda je možné naimportovat balíček sympy a zobrazit k němu nápovědu:

>>> import sympy
>>> help(sympy)
 
Help on package sympy:
 
NAME
    sympy
 
DESCRIPTION
    SymPy is a Python library for symbolic mathematics. It aims to become a
    full-featured computer algebra system (CAS) while keeping the code as simple
    as possible in order to be comprehensible and easily extensible.  SymPy is
    written entirely in Python. It depends on mpmath, and other external libraries
    may be optionally for things like plotting support.
 
    See the webpage for more information and documentation:
 
        https://sympy.org
 
PACKAGE CONTENTS
    abc
    algebras (package)
    assumptions (package)
    benchmarks (package)
    calculus (package)
    categories (package)
    ...
    ...
    ...

4. Zjednodušování konstantních výrazů

Po (doufejme, že úspěšné) instalaci knihovny Sympy si postupně ukážeme některé její zajímavé a taktéž užitečné vlastnosti. Tato knihovna nabízí definice mnoha matematických funkcí (s mnoha z nich se setkáme později), které jsou při předání konstant automaticky vyhodnoceny, což asi není nic překvapivého. Zajímavé ovšem je, že dojde i ke zjednodušení výsledků výpočtů tak, aby byly co nejvíce čitelné. Ostatně podívejme se na příklad výpočtu druhé odmocniny pro vstupy od 0 do 9:

import sympy as sp
 
for i in range(0, 10):
    print(i, sp.sqrt(i))

Výsledkem bude v některých případech odpověď typu „odmocnina z hodnoty x“, ovšem pokud je možné odmocninu vypočítat a výsledkem bude celé číslo, je vráceno toto číslo. Popř. je dokonce v případě odmocniny z osmi vrácen součin celočíselné konstanty a „kratší“ odmocniny:

0 0
1 1
2 sqrt(2)
3 sqrt(3)
4 2
5 sqrt(5)
6 sqrt(6)
7 sqrt(7)
8 2*sqrt(2)
9 3
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy01.py.

To ovšem není vše, protože se zkrácení týká i složitějších výrazů, zde konkrétně součet odmocniny s celým číslem:

import sympy as sp
 
for i in range(0, 10):
    print(i, sp.sqrt(i) + 5)
0 5
1 6
2 sqrt(2) + 5
3 sqrt(3) + 5
4 7
5 sqrt(5) + 5
6 sqrt(6) + 5
7 sqrt(7) + 5
8 2*sqrt(2) + 5
9 8
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy02.py.

5. Funkce sympy.pprint pro formátovaný výstup

Výše uvedená dvojice příkladů používala pro vytištění matematických výrazů přímo standardní funkci print, která výraz vytiskne na jediném řádku. Ovšem typické matematické výrazy jsou „dvourozměrné“, navíc s množstvím speciálních symbolů. Knihovna Sympy podporuje kvalitní výstup přes TeX, který lze přímo použít v článcích atd. Ovšem i při tisku na běžný terminál dokáže do jisté míry napodobit klasický matematický způsob zápisu. Pro tento účel se používá funkce pprint neboli „pretty print“:

import sympy as sp
 
for i in range(0, 10):
    print(i, end = "   ")
    sp.pprint(sp.sqrt(i))

Takto upravený první demonstrační příklad nyní provede výtisk stejných zjednodušených výrazů, ovšem v čitelnější podobě. Předpokládá se použití terminálu s podporou Unicode:

0   0
1   1
2   √2
3   √3
4   2
5   √5
6   √6
7   √7
8   2⋅√2
9   3
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy03.py.

Podobně tomu bude v případě úpravy druhého příkladu s poněkud složitějším výrazem s odmocninou a součtem:

import sympy as sp
 
for i in range(0, 10):
    print(i, end = "   ")
    sp.pprint(sp.sqrt(i) + 5)

S následujícím výsledkem:

0   5
1   6
2   √2 + 5
3   √3 + 5
4   7
5   √5 + 5
6   √6 + 5
7   √7 + 5
8   2⋅√2 + 5
9   8
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy04.py.

6. Výrazy s proměnnými

Velká síla knihovny Sympy spočívá v její schopnosti manipulace s výrazy, v nichž jsou použity proměnné. Tyto výrazy se přitom mohou zapsat přímo v Pythonu – není nutné je zapisovat do řetězců či použít nějaký speciální DSL (doménově specifický jazyk). Je zde pouze jediný (a to zcela pochopitelný) háček: nejdříve je totiž nutné každou proměnnou zkonstruovat jako objekt typu „symbol“. Provádí se to následujícím způsobem:

x = sp.symbols('x')

Po provedení předchozího příkazu je vytvořena nová proměnná x, která je ve skutečnosti objektem následujícího typu:

>>> type(x)
<class 'sympy.core.symbol.Symbol'>

To je důležité, protože v Pythonu je možné pro objekty (instance nějaké konkrétní třídy) přetížit všechny operátory a umožnit tak zápis výrazů, které již nebudou přímo vyhodnoceny interpretrem (jakoby se například jednalo o součet celých čísel či spojení řetězců), ale knihovnou Sympy. Podívejme se na jednoduchý příklad, v němž je vytvořena nová hodnota typu „výraz“:

import sympy as sp
 
x = sp.symbols('x')
expression = 2*x + 1
print(expression)

Výsledek je vypsán jako výraz:

2*x + 1
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy05.py.

Nepatrnou úpravou dosáhneme „matematického“ stylu výpisu, což u takto jednoduchého výrazu pouze znamená náhradu hvězdičky za symbol součinu:

import sympy as sp
 
x = sp.symbols('x')
expression = 2*x + 1
sp.pprint(expression)

Výsledek:

2⋅x + 1
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy06.py.

7. Výrazy s větším množstvím proměnných

V praxi se pochopitelně setkáme spíše s výrazy, v nichž je použito větší množství proměnných, nikoli proměnná jediná. Všechny tyto proměnné je nejprve nutné zkonstruovat nám již známou funkcí sympy.symbols. Aby nebylo nutné každou proměnnou konstruovat zvlášť, podporuje funkce sympy.symbols předání řetězce s větším množstvím proměnných. Potom se vrátí stejné množství zkonstruovaných objektů.

Příklad konstrukce tří proměnných a jejich použití ve výrazu, který tyto proměnné používá:

import sympy as sp
 
x,y,z = sp.symbols('x,y,z')
expression = 2*x + 3*y - 1/z
print(expression)

Tento příklad provedl standardní „terminálový“ výstup s výrazem zapsaným na jediném řádku:

2*x + 3*y - 1/z
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy07.py.

Podobně si ovšem můžeme vynutit výstup v matematické notaci; postačuje použít nám již známou funkci sympy.pprint:

import sympy as sp
 
x,y,z = sp.symbols('x,y,z')
expression = 2*x + 3*y - 1/z
sp.pprint(expression)

Nyní bude výsledek přece jen více odpovídat matematické notaci, pochopitelně s ohledem na omezení terminálu:

            1
2⋅x + 3⋅y - ─
            z
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy08.py.

8. Zjednodušování výrazů s proměnnými

Knihovna Sympy dokáže zjednodušit i výrazy s proměnnou či dokonce s větším množstvím proměnných. Pokud prozatím zůstaneme u jednoduchých výrazů s lineárními členy, může zjednodušení výrazu s jedinou proměnnou vypadat takto:

import sympy as sp
 
x = sp.symbols('x')
expression = 2*x + 1 + 3*x + 10
sp.pprint(expression)

Výsledek:

5⋅x + 11
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy09.py.

Pochopitelně si můžeme otestovat i výrazy s více proměnnými. A aby to nebylo tak jednoduché, použijeme zde zlomky:

import sympy as sp
 
x,y,z = sp.symbols('x,y,z')
expression = 2*x + 3*y + 3*x + y + 1/z + 3/z
sp.pprint(expression)

Výsledek nyní bude vypadat následovně:

            4
5⋅x + 4⋅y + ─
            z
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy10.py.

9. Polynomy a další výrazy s mocninami

V SymPy lze pochopitelně zapisovat i polynomy, ovšem musíme mít na paměti, že umocnění se zapisuje s využitím operátoru ** a nikoli operátoru ^, jenž má v Pythonu odlišný význam (a SymPy se snaží být sémanticky kompatibilní s Pythonem). Podívejme se na způsob zápisu polynomu dvou proměnných:

import sympy as sp
 
x,y = sp.symbols('x,y')
expression = x**2 - y**2
sp.pprint(expression)

Na terminál je tento výraz zapsán následovně:

 2    2
x  - y
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy12.py.

Musíme si však dát pozor na to, abychom definovali všechny proměnné použité v zápisu polynomu:

import sympy as sp
 
x = sp.symbols('x')
expression = x**2 - y**2
sp.pprint(expression)

Zde jsme zapomněli na proměnnou y, což je detekováno:

  File "/root/Python-3.10.2/sympy06.py", line 4, in <module>
    expression = x**2 - y**2
NameError: name 'y' is not defined
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy11.py.

Zápis složitějšího výrazu (nikoli polynomu) s operací umocnění:

import sympy as sp
 
x = sp.symbols('x')
expression = x**1/1 + x**3/3 + x**5/5 + 2**(x/2+1)
sp.pprint(expression)

Nyní je výstup na terminál již na samotné hranici čitelnosti (ovšem příště si ukážeme výstup přes TeX do grafické podoby):

 x
 ─ + 1    5    3
 2       x    x
2      + ── + ── + x
         5    3
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy13.py.

10. Úprava výrazů funkcí sympy.factor – rozklad polynomu na kořenové činitele

Funkce nazvaná sympy.factor slouží k rozkladu polynomu na kořenové činitele (faktorizaci). Podívejme se na typický školní příklad, konkrétně na úpravu polynomu x2-y2:

import sympy as sp
 
x,y = sp.symbols('x,y')
expression = sp.factor(x**2 - y ** 2)
sp.pprint(expression)

Výsledkem je rozklad na dva kořenové činitele (což je až na pořadí jediná možná faktorizace):

(x - y)⋅(x + y)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy14.py.

Odlišný příklad, tentokrát faktorizace polynomu x2-2×+1:

import sympy as sp
 
x = sp.symbols('x')
expression = sp.factor(x**2 - 2*x + 1)

Výsledkem je součin dvou stejných kořenových činitelů, což lze ovšem zapsat i s využitím mocniny:

       2
(x - 1)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu je dostupný na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy15.py.

11. Úprava výrazů funkcí sympy.expand – roznásobení závorek

Často se setkáme i s opačnou operací, tedy konkrétně s roznásobením všech závorek, s případným dalším zjednodušením výsledku. V předchozí kapitole byl výsledkem faktorizace polynom zapsaný ve tvaru (x-y)(x+y). Nyní si tedy necháme závorky roznásobit:

import sympy as sp
 
x,y = sp.symbols('x,y')
expression = sp.expand((x-y) * (x+y))
sp.pprint(expression)

Výsledkem bude:

 2    2
x  - y

Odlišný příklad s polynomem zapsaným ve tvaru (x+y)(x+y):

import sympy as sp
 
x,y = sp.symbols('x,y')
expression = sp.expand((x+y) * (x+y))
sp.pprint(expression)

Výsledkem je tento tvar výrazu:

 2            2
x  + 2⋅x⋅y + y

A konečně se podívejme na výraz s trojicí proměnných:

import sympy as sp
 
x,y,z = sp.symbols('x,y,z')
expression = sp.expand((x-y) * (x+y) * (x+z) * (y-z))
sp.pprint(expression)

Roznásobením a následnými úpravami vznikne výraz:

 3      3      2        2  2      3      2      3      2  2
x ⋅y - x ⋅z + x ⋅y⋅z - x ⋅z  - x⋅y  + x⋅y ⋅z - y ⋅z + y ⋅z

12. Nalezení kořenů kvadratické rovnice

Další velmi užitečnou funkcí, kterou v knihovně SymPy nalezneme, je funkce nazvaná solve:

Help on function solve in module sympy.solvers.solvers:
 
solve(f, *symbols, **flags)
    Algebraically solves equations and systems of equations.
 
    Explanation
    ===========
 
    Currently supported:
        - polynomial
        - transcendental
        - piecewise combinations of the above
        - systems of linear and polynomial equations
        - systems containing relational expressions

Jak je z předchozího popisu zřejmé, slouží tato funkce k mnoha účelům. My si ukážeme její použití při hledání kořenů kvadratické rovnice. Ta může být zadána s využitím numerických nebo i symbolických (pojmenovaných) konstant:

from sympy import solve, symbols, pprint
 
a, b, c, x = symbols('a,b,c,x')
 
f = a*x**2 + b*x + c
 
pprint(f)
 
solution = solve(f, x)
pprint(solution)

Tento demonstrační příklad nejprve po svém spuštění vypíše vstupní rovnici a následně i její kořeny; zde pochopitelně v symbolické podobě (konkrétní hodnoty a, b a c nejsou zadány):

   2
a⋅x  + b⋅x + c
 
⎡        _____________          _____________⎤
⎢       ╱           2          ╱           2 ⎥
⎢-b - ╲╱  -4⋅a⋅c + b    -b + ╲╱  -4⋅a⋅c + b  ⎥
⎢─────────────────────, ─────────────────────⎥
⎣         2⋅a                    2⋅a         ⎦

Pokud se předchozí výsledek nezobrazil přesně v uvedené podobě, může to znamenat, že terminál není nastaven na použití Unicode. Můžeme tedy provést přepnutí do „ASCII režimu“:

from sympy import solve, symbols, pprint, init_printing
 
init_printing(use_unicode=False)
 
a, b, c, x = symbols('a,b,c,x')
 
f = a*x**2 + b*x + c
 
pprint(f)
 
solution = solve(f, x)
pprint(solution)

Nyní budou kořeny vypsány s využitím ASCII znaků:

   2
a*x  + b*x + c
 
         _____________          _____________
        /           2          /           2
 -b - \/  -4*a*c + b    -b + \/  -4*a*c + b
[---------------------, ---------------------]
          2*a                    2*a

13. Hledání kořenů pro určitou proměnnou

V případě, že je použit polynom s větším množstvím proměnných, lze si ve druhém parametru funkce solve zvolit, pro jakou proměnnou mají být kořeny nalezeny. Opět se podívejme na jednoduchý příklad s polynomem s proměnnými nazvanými x a y:

from sympy import solve, symbols, pprint
 
a, b, c, d, e, x, y = symbols('a,b,c,d,e,x,y')
 
f = a*x**2 + b*x + c*y**2 + d*y + e
 
pprint(f)
 
solution = solve(f, x)
pprint(solution)
 
solution = solve(f, y)
pprint(solution)

Ze zdrojového kódu je zřejmé, že se kořeny hledají nejprve pro proměnnou x a podruhé pro y:

   2            2
a⋅x  + b⋅x + c⋅y  + d⋅y + e
 
⎡        ___________________________________          ___________________________________⎤
⎢       ╱          2                      2          ╱          2                      2 ⎥
⎢-b - ╲╱  - 4⋅a⋅c⋅y  - 4⋅a⋅d⋅y - 4⋅a⋅e + b    -b + ╲╱  - 4⋅a⋅c⋅y  - 4⋅a⋅d⋅y - 4⋅a⋅e + b  ⎥
⎢───────────────────────────────────────────, ───────────────────────────────────────────⎥
⎣                    2⋅a                                          2⋅a                    ⎦
 
⎡        ___________________________________          ___________________________________⎤
⎢       ╱          2                      2          ╱          2                      2 ⎥
⎢-d - ╲╱  - 4⋅a⋅c⋅x  - 4⋅b⋅c⋅x - 4⋅c⋅e + d    -d + ╲╱  - 4⋅a⋅c⋅x  - 4⋅b⋅c⋅x - 4⋅c⋅e + d  ⎥
⎢───────────────────────────────────────────, ───────────────────────────────────────────⎥
⎣                    2⋅c                                          2⋅c                    ⎦

14. Symbolická derivace

V knihovně SymPy nalezneme i podporu pro symbolickou derivaci, tj. pro derivaci výrazu, jejímž výsledkem je další výraz (nejedná se tedy o numerické – přibližné – řešení). Derivace se vypočítá funkcí nazvanou diff:

Help on function diff in module sympy.core.function:
 
diff(f, *symbols, **kwargs)
    Differentiate f with respect to symbols.
 
    Explanation
    ===========
 
    This is just a wrapper to unify .diff() and the Derivative class; its
    interface is similar to that of integrate().  You can use the same
    shortcuts for multiple variables as with Derivative.  For example,
    diff(f(x), x, x, x) and diff(f(x), x, 3) both return the third derivative
    of f(x).
 
    You can pass evaluate=False to get an unevaluated Derivative class.  Note
    that if there are 0 symbols (such as diff(f(x), x, 0), then the result will
    be the function (the zeroth derivative), even if evaluate=False.

Vyzkoušejme si nyní zderivovat polynom se dvěma proměnnými. Prvním výpočtem bude derivace podle x, druhým derivace podle y:

from sympy import diff, symbols, pprint
 
a, b, c, d, e, x, y = symbols('a,b,c,d,e,x,y')
 
f = a*x**2 + b*x + c*y**2 + d*y + e
 
pprint(f)
 
diff1 = diff(f, x)
pprint(diff1)
 
diff2 = diff(f, y)
pprint(diff2)

Výsledek by měl vypadat následovně:

   2            2
a⋅x  + b⋅x + c⋅y  + d⋅y + e
 
2⋅a⋅x + b
 
2⋅c⋅y + d

15. Ukázka derivace složitějšího výrazu

Symbolická derivace je realizována s využitím pouze několika známých a jednoduchých pravidel, která lze relativně snadno přepsat do podoby algoritmu. Není tedy překvapivé, že symbolicky derivovat můžeme i poměrně složité výrazy, což je ostatně patrné i z následujícího demonstračního příkladu:

from sympy import *
 
a, b, c, d, e, x, y = symbols('a,b,c,d,e,x,y')
 
f = a*sin(x**2) / b*cos(y**2) + c*sqrt(x+y*d) + e
 
pprint(f)
 
diff1 = diff(f, x)
pprint(diff1)
 
diff2 = diff(f, y)
pprint(diff2)

Výsledek derivace výrazu s goniometrickými funkcemi i odmocninou podle proměnné x a y vypadá následovně (na prvním řádku je jen opis výrazu v matematické notaci):

     ⎛ 2⎞    ⎛ 2⎞
a⋅sin⎝x ⎠⋅cos⎝y ⎠       _________
───────────────── + c⋅╲╱ d⋅y + x  + e
        b
 
         ⎛ 2⎞    ⎛ 2⎞
2⋅a⋅x⋅cos⎝x ⎠⋅cos⎝y ⎠         c
───────────────────── + ─────────────
          b                 _________
                        2⋅╲╱ d⋅y + x

 
           ⎛ 2⎞    ⎛ 2⎞
  2⋅a⋅y⋅sin⎝x ⎠⋅sin⎝y ⎠        c⋅d
- ───────────────────── + ─────────────
            b                 _________
                          2⋅╲╱ d⋅y + x

16. Symbolická integrace

Vzhledem k tomu, že knihovna SymPy podporuje symbolickou derivaci výrazů, můžeme očekávat i podporu pro symbolickou integraci, a to jak neurčitým, tak určitým integrálem. Pro tento účel slouží funkce nazvaná integrate, která je relativně komplikovaná a její různé varianty budou popsány příště (dnes se prozatím seznámíme pouze se základní funkcionalitou):

Help on function integrate in module sympy.integrals.integrals:
 
integrate(*args, meijerg=None, conds='piecewise', risch=None, heurisch=None, manual=None, **kwargs)
    integrate(f, var, ...)
 
    .. deprecated:: 1.6
 
       Using ``integrate()`` with :class:`~.Poly` is deprecated. Use
       :meth:`.Poly.integrate` instead. See :ref:`deprecated-integrate-poly`.
 
    Explanation
    ===========
 
    Compute definite or indefinite integral of one or more variables
    using Risch-Norman algorithm and table lookup. This procedure is
    able to handle elementary algebraic and transcendental functions
    and also a huge class of special functions, including Airy,
    Bessel, Whittaker and Lambert.
 
    var can be:
    
    - a symbol                   -- indefinite integration
    - a tuple (symbol, a)        -- indefinite integration with result
                                    given with ``a`` replacing ``symbol``
    - a tuple (symbol, a, b)     -- definite integration
 
    Several variables can be specified, in which case the result is
    multiple integration. (If var is omitted and the integrand is
    univariate, the indefinite integral in that variable will be performed.)
 
    Indefinite integrals are returned without terms that are independent
    of the integration variables. (see examples)
 
    Definite improper integrals often entail delicate convergence
    conditions. Pass conds='piecewise', 'separate' or 'none' to have
    these returned, respectively, as a Piecewise function, as a separate
    result (i.e. result will be a tuple), or not at all (default is
    'piecewise').
 
    **Strategy**

Vyzkoušejme si nyní výpočet neurčitého integrálu jednoduchého polynomu zapsaného ve tvaru ax+b. Integrovat budeme pro x (resp. dx):

from sympy import integrate, symbols, pprint
 
a, b, x = symbols('a,b,x')
 
f = a*x + b
 
pprint(f)
 
solution = integrate(f, x)
pprint(solution)

Tento skript nejdříve vypíše původní tvar polynomu a následně i výsledek integrace:

a⋅x + b
 
   2
a⋅x
──── + b⋅x
 2
Poznámka: otestování výsledku je snadné – postačí provést derivaci výsledného výrazu a porovnat ji se vstupem.

17. Integrace složitějších výrazů

Pokusme se o integraci složitějšího výrazu s proměnnými x a y. Funkci integrate se předává i symbol, pro který má být integrál spočten:

from sympy import integrate, symbols, pprint
 
a, b, c, d, e, x, y = symbols('a,b,c,d,e,x,y')
 
f = a*x**2 + b*x + c*y**2 + d*y + e
 
pprint(f)
 
solution = integrate(f, x)
pprint(solution)
 
solution = integrate(f, y)
pprint(solution)

Vstupem je polynom, takže integraci lze snadno provést i ručně a ověřit si tak výsledky dodané knihovnou SymPy:

Linux tip

   2            2
a⋅x  + b⋅x + c⋅y  + d⋅y + e
 
   3      2
a⋅x    b⋅x      ⎛   2          ⎞
──── + ──── + x⋅⎝c⋅y  + d⋅y + e⎠
 3      2
 
   3      2
c⋅y    d⋅y      ⎛   2          ⎞
──── + ──── + y⋅⎝a⋅x  + b⋅x + e⎠
 3      2

18. Obsah druhé části článku

Prozatím jsme si popsali pouze základní funkcionalitu poskytovanou knihovnou SymPy. Příště si ukážeme některé další vlastnosti této potenciálně velmi užitečné knihovny – řešení kvadratických rovnic s komplexními kořeny, hledání kořenů složitějších polynomů, hledání nulových bodů periodických funkcí atd. Popíšeme si i výpočet určitých integrálů a limit.

19. Repositář s demonstračními příklady

Zdrojové kódy všech prozatím popsaných demonstračních příkladů určených pro programovací jazyk Python 3 byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Demonstrační příklad Stručný popis příkladu Cesta
1 sympy01.py zjednodušování konstantního výrazu s odmocninou https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy01.py
2 sympy02.py zjednodušování konstantních výrazů https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy02.py
3 sympy03.py čitelný výpis výrazů funkcí sympy.pprint https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy03.py
4 sympy04.py čitelný výpis výrazů funkcí sympy.pprint, složitější výsledky https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy04.py
5 sympy05.py deklarace a „terminálový“ výpis jednoduchého výrazu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy05.py
6 sympy06.py deklarace a „matematický“ výpis jednoduchého výrazu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy06.py
7 sympy07.py výraz s větším množstvím proměnných (zlomek) https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy07.py
8 sympy08.py výraz s větším množstvím proměnných (zlomek) https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy08.py
9 sympy09.py zjednodušení výrazu s jedinou proměnnou https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy09.py
10 sympy10.py zjednodušení výrazu se třemi proměnnými a se zlomky https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy10.py
11 sympy11.py pokus o použití nedefinované proměnné https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy11.py
12 sympy12.py výraz x2-y2 https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy12.py
13 sympy13.py složitější výraz s několika členy https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy13.py
14 sympy14.py faktorizace výrazu x2-y2 https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy14.py
15 sympy15.py faktorizace výrazu x2-2× + 1 https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy15.py
16 sympy16.py expanze výrazu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy16.py
17 sympy17.py expanze (roznásobení závorek) složitějšího výrazu se dvěma proměnnými https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy17.py
18 sympy18.py expanze (roznásobení závorek) složitějšího výrazu se třemi proměnnými https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy18.py
19 sympy19.py řešení kvadratické rovnice https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy19.py
20 sympy20.py řešení kvadratické rovnice, odlišná forma výstupu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy20.py
21 sympy21.py řešení kvadratické rovnice se dvěma neznámými https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy21.py
22 sympy22.py výpočet derivace polynomu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy22.py
23 sympy23.py výpočet derivace složitějšího výrazu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy23.py
24 sympy24.py výpočet integrace polynomu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy24.py
25 sympy25.py výpočet integrace složitějšího polynomu https://github.com/tisnik/most-popular-python-libs/blob/master/sympy/sympy25.py

20. Odkazy na Internetu

  1. SymPy
    https://www.sympy.org/en/index.html
  2. SymPy na PyPi
    https://pypi.org/project/sympy/
  3. mpmath
    https://mpmath.org/
  4. mpmath na PyPi
    https://pypi.org/project/mpmath/
  5. Symbolic Maths in Python
    https://alexandrugris.git­hub.io/maths/2017/04/30/sym­bolic-maths-python.html
  6. SymPy shell
    https://live.sympy.org/
  7. Symbolic programming
    https://en.wikipedia.org/wi­ki/Symbolic_programming
  8. Symbolic language (programming)
    https://en.wikipedia.org/wi­ki/Symbolic_language_(pro­gramming)
  9. Computer algebra
    https://en.wikipedia.org/wi­ki/Computer_algebra
  10. Common Lisp: A Gentle Introduction to Symbolic Computation
    https://www.cs.cmu.edu/~dst/LispBook/
  11. List of computer algebra systems
    https://en.wikipedia.org/wi­ki/List_of_computer_algebra_sys­tems
  12. Polynom
    https://cs.wikipedia.org/wiki/Polynom

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.