Programowanie Wykład 7 - Inne moduły wspierające obliczenia numeryczne Plan wykładu: SymPy Zmienne symboliczne Liczby zespolone Liczby wymierne Obliczenia numeryczne Wyrażenia algebraiczne Wyrażenia wymierne Pochodne i całki Sumy i iloczyny Granice Szeregi Algebra liniowa Równania i układy równań W stronę fizyki - mechanika kwantowa i operatory niekomutujące Inne przydatne biblioteki Materiały do wykładu: http://www.sympy.org/en/index.html\ (http://www.sympy.org/en/index.html\) wykład J.R. Johanssona "Scientific Python" dostępny pod adresem http://github.com/jrjohansson/scientific-python-lectures (http://github.com/jrjohansson/scientific-pythonlectures) In []: %pylab inline Populating the interactive namespace from numpy and matplotlib SymPy SymPy to pythonowy moduł do obliczeń symbolicznych. In []: from sympy import * Jeśli chcemy, aby wyniki były formatowane w stylu A E LT X -a, musimy wykonać następujące polecenie: In [2]: init_printing() http://localhost:8888/notebooks/7_sympy.ipynb /20
Zmienne symboliczne Klasa Symbol służy do stworzenia symboli dla zmiennych, z którymi zamierzamy pracować: In [3]: 2*x --------------------------------------------------------------------- ------ NameError Traceback (most recent call last) <ipython-input-3-a77620b7b5d> in <module>() ----> 2*x NameError: name 'x' is not defined In [4]: x = Symbol('x') In [5]: 2*x Out[5]: 2x In [5]: (pi + x)**2 Out[5]: (x + π) 2 In [6]: # możemy również określić kilka symboli naraz a, b, c = symbols("a, b, c") In [7]: type(a) Out[7]: sympy.core.symbol.symbol Dodatkowo, do definicji symbolu możemy dodawać pewne założenia: In [8]: x = Symbol('x', real=true) http://localhost:8888/notebooks/7_sympy.ipynb 2/20
In [9]: x.is_imaginary Out[9]: False In [0]: x = Symbol('x', positive=true) In []: x > 0 Out[]: True Liczby zespolone Jednostę urojoną w SymPy oznaczamy literą I: In [2]: +*I Out[2]: + i In [3]: I**2 Out[3]: In [4]: (x * I + )**2 Out[4]: (ix + ) 2 Liczby wymierne Oprócz liczb całkowitych i rzeczywistych w SymPy mamy do dyspozycji liczby wymierne: In [5]: r = Rational(4,5) r2 = Rational(5,4) http://localhost:8888/notebooks/7_sympy.ipynb 3/20
In [6]: r Out[6]: 4 5 In [7]: r+r2 Out[7]: 4 20 In [8]: r/r2 Out[8]: 6 25 Obliczenia numeryczne SymPy pozwala przeprowadzać obliczenia o dowolnej precyzji. Czasami jednak będziemy potrzebować numerycznej wartości uzyskanych wyników. Do tego służy funkcja evalf (lub N), która jako dodatkowy argument przyjmuje liczbę cyfr po przecinku w wyniku numerycznym: In [9]: pi.evalf(n=50) Out[9]: 3.45926535897932384626433832795028849769399375 In [20]: y = (x + pi)**2 y Out[20]: (x + π) 2 In [2]: N(y, 5) # same as evalf Out[2]: (x + 3.46) 2 W powyższych wyrażeniach możemy również podstawić jakąś wartość za x: http://localhost:8888/notebooks/7_sympy.ipynb 4/20
In [22]: y.subs(x,.5) Out[22]: (.5 + π) 2 In [23]: N(y.subs(x,.5)) Out[23]: 2.544382368587 Funkcja subs moze posłużyć również do zamiany zmiennych symbolicznych: In [24]: y.subs(x, a+pi) Out[24]: (a + 2π) 2 Wyrażenia algebraiczne In [25]: (x+)*(x+2)*(x+3) Out[25]: (x + ) (x + 2) (x + 3) In [26]: expand((x+)*(x+2)*(x+3)) Out[26]: x 3 + 6 x 2 + x + 6 Funkcja expand pozwala również rozwijac wyrażenia trygonometryczne: In [27]: sin(a+b) Out[27]: sin (a + b) http://localhost:8888/notebooks/7_sympy.ipynb 5/20
In [28]: expand(sin(a+b), trig=true) Out[28]: sin (a) cos (b) + sin (b) cos (a) Operacja odwrotna: In [29]: factor(x**3 + 6 * x**2 + *x + 6) Out[29]: (x + ) (x + 2) (x + 3) Do upraszczania wyrażeń służy funkcja simplify (możemy również spróbować trigsimp, powsimp, logcombine etc.): In [30]: # w przypadku prostych iloczynów nie ma spektakularnych wyników simplify((x+)*(x+2)*(x+3)) Out[30]: (x + ) (x + 2) (x + 3) In [3]: # simplify używa tożsamosci trygonometrycznych simplify(sin(a)**2 + cos(a)**2) Out[3]: In [32]: simplify(cos(x)/sin(x)) Out[32]: tan (x) Wyrażenia wymierne In [33]: f = /((a+)*(a+2)) http://localhost:8888/notebooks/7_sympy.ipynb 6/20
In [34]: f Out[34]: (a + ) (a + 2) In [35]: apart(f) Out[35]: + a + 2 In [36]: a + f2 = /(a+2) + /(a+3) In [37]: f2 Out[37]: a + 3 + In [38]: Out[38]: a + 2 together(f2) 2a + 5 (a + 2) (a + 3) Pochodne i całki Różniczkowanie jest proste: In [39]: y Out[39]: (x + π) 2 http://localhost:8888/notebooks/7_sympy.ipynb 7/20
In [40]: diff(y**2, x) Out[40]: 4(x + π) 3 Pochodne wyższych rzędów: In [4]: diff(y**2, x, x) Out[4]: 2(x + π) 2 In [42]: diff(y**2, x, 2) # inna możliwość Out[42]: 2(x + π) 2 Pochodne funkcji wielu zmiennych - obliczmy np. d 3 f dxdy 2 dla funkcji zdefiniowanej poniżej: In [43]: x, y, z = symbols("x,y,z") In [44]: f = sin(x*y) + cos(y*z) In [45]: diff(f, x,, y, 2) Out[45]: x (xy cos (xy) + 2 sin (xy)) Całkowanie jest równie proste: In [46]: f Out[46]: sin (xy) + cos (yz) http://localhost:8888/notebooks/7_sympy.ipynb 8/20
In [47]: integrate(f, x) Out[47]: 0 x cos (yz) + { cos (xy) y for y = 0 otherwise Możemy również obliczać całki oznaczone: In [48]: integrate(f, (x, -, )) Out[48]: 2 cos (yz) oraz całki niewłaściwe: In [49]: integrate(exp(-x**2), (x, -oo, oo)) Out[49]: π Przy tym symbol oo oznacza w SymPy. Sumy i iloczyny In [50]: n = Symbol("n") In [5]: #najpierw symbolicznie Sum(/n**2, (n,, 0)) Out[5]: 0 n= n 2 In [52]: #a teraz wartość numeryczna Sum(/n**2, (n,, 0)).evalf() Out[52]:.549767736654 http://localhost:8888/notebooks/7_sympy.ipynb 9/20
In [53]: #coś mniej trywialnego Sum(/n**2, (n,, oo)).evalf() Out[53]:.64493406684823 In [54]: Product(n, (n,, 0)) # 0! Out[54]: 0 n= n In [55]: Product(n,(n,,0)).evalf() Out[55]: 3628800.0 Granice In [56]: limit(sin(x)/x, x, 0) Out[56]: Jak wiadomo, pochodna jest zdefiniowana jako: df (x, y) dx = lim h 0 f (x + h, y) f (x, y) h Sprawdźmy zatem poprawnośc działania funkcji diff: In [57]: f Out[57]: sin (xy) + cos (yz) In [58]: diff(f, x) Out[58]: y cos (xy) http://localhost:8888/notebooks/7_sympy.ipynb 0/20
In [59]: h = Symbol("h") In [60]: limit((f.subs(x, x+h) - f)/h, h, 0) Out[60]: y cos (xy) Możliwe jest oczywiście wyznaczanie granic jednostronnych: In [6]: limit(/x, x, 0, dir="+") Out[6]: In [62]: limit(/x, x, 0, dir="-") Out[62]: Szeregi In [63]: series(exp(x), x) Out[63]: x 2 + x + + + + + ( x 6 ) 2 x 3 6 x 4 24 Domyślnie funkcje rozwijane są w szereg w otoczeniu punktu x 5 20 x = 0, jednak możemy to zmienić: In [64]: series(exp(x), x, ) Out[64]: e e + e (x ) + + + + + 2 (x e )2 6 (x e )3 24 (x e )4 20 (x )5 ( (x Podobnie, możemy określić ile wyrazów rozwinięcia zostanie wyliczone: http://localhost:8888/notebooks/7_sympy.ipynb /20
In [65]: series(exp(x), x,, 0) Out[65]: e e + e (x ) + + + + + 2 (x e )2 6 (x e )3 24 (x e )4 20 (x e )5 720 ( e + + ( ; x 362880 (x )9 (x ) 0 Rozwinięcie w szereg zawiera w sobie informację na temat rzędu przybliżenia. Jest to przydatne w różnego rodzaju obliczeniach: In [66]: s = cos(x).series(x, 0, 5) s Out[66]: x 2 + + ( x 5 ) 2 In [67]: x 4 24 s2 = sin(x).series(x, 0, 2) s2 Out[67]: x + ( x 2 ) In [68]: expand(s * s2) Out[68]: x + ( x 2 ) Przy pomocy removeo usuniemy informację o przybliżeniu: In [69]: expand(s.removeo() * s2.removeo()) Out[69]: x 5 24 x 3 2 + x Ale wówczas nie będzie to już poprawne przybliżenie cos(x) sin(x) do wyrazów 5-tego rzędu: http://localhost:8888/notebooks/7_sympy.ipynb 2/20
In [70]: (cos(x)*sin(x)).series(x, 0, 6) Out[70]: 2x 3 x + + ( x 6 ) 3 2x 5 5 Algebra liniowa Macierze tworzymy przy pomocy klasy Matrix: In [7]: m, m2, m2, m22 = symbols("m, m2, m2, m22") b, b2 = symbols("b, b2") In [72]: A = Matrix([[m, m2],[m2, m22]]) A Out[72]: m m 2 [ m 2 m 22 ] In [73]: b = Matrix([[b], [b2]]) b Out[73]: b [ b 2 ] Podstawowe operacje na macierzach: In [74]: A**2 Out[74]: m 2 + m 2 m 2 m m 2 + m 2 m 22 [ m m 2 + m 2 m 22 m 2 m 2 + m 2 ] 22 http://localhost:8888/notebooks/7_sympy.ipynb 3/20
In [75]: A * b Out[75]: b m + b 2 m 2 [ b m 2 + b 2 m 22 ] Wyznacznik i macierz odwrotna: In [76]: A.det() Out[76]: m m 22 m 2 m 2 In [77]: A.inv() Out[77]: m m + 2 m 2 m 2 m ( m 22 2 m 2 ) m 2 m m m ( m 22 2 m 2 ) m m 2 m m ( m 22 2 m 2 ) m m m 22 2 m 2 m In [78]: simplify(a*a.inv()) Out[78]: 0 [ 0 ] Równania i układy równań In [79]: solve(x**2 -, x) Out[79]: [, ] http://localhost:8888/notebooks/7_sympy.ipynb 4/20
In [80]: solve(x**4 - x**2 -, x) Out[80]: 5 5 5 i +, i +, +, 2 2 2 2 2 2 5 + 2 2 Układ równań podajemy jako listę: In [8]: solve([x + y -, x - y - ], [x,y]) Out[8]: {x :, y : 0} To rzeczywiście obliczenia symboliczne: In [82]: solve([x + y - a, x - y - c], [x,y]) Out[82]: { x : a + c, y : a 2 2 c 2 2 } W stronę fizyki - mechanika kwantowa i operatory niekomutujące In [83]: from sympy.physics.quantum import * In [84]: Ket('psi') Out[84]: ψ In [85]: Bra('psi') Out[85]: ψ http://localhost:8888/notebooks/7_sympy.ipynb 5/20
In [86]: u = Ket('0') d = Ket('') a, b = symbols('alpha beta', complex=true) In [87]: phi = a * u + sqrt(-abs(a)**2) * d; phi Out[87]: α 0 + α 2 + In [88]: Dagger(phi) Out[88]: α 0 + α 2 + In [89]: Dagger(phi) * d Out[89]: ( α 0 + α 2 + ) Ostatnie wyrażenie możemy rozwinąć za pomocą qapply: In [90]: qapply(dagger(phi) * d) Out[90]: 0 + α 2 + α In [9]: qapply(dagger(phi) * u) Out[9]: Operatory: 0 0 + α 2 + 0 α In [92]: A = Operator('A') B = Operator('B') http://localhost:8888/notebooks/7_sympy.ipynb 6/20
In [93]: #komutują czy nie? A * B == B * A Out[93]: False In [94]: #działania na operatorach expand((a+b)**3) Out[94]: ABA + A B 2 + A 2 B + A 3 + BAB + B A 2 + B 2 A + B 3 In [95]: #komutator c = Commutator(A,B) c Out[95]: [A, B] Metoda doit służy to wyliczenia komutatora: In [96]: c.doit() Out[96]: AB BA Możemy oczywiście mieszać operatory z liczbami zespolonymi: In [97]: c = Commutator(a * A, b * B) c Out[97]: αβ [A, B] Metoda expand z argumentem commutator=true służy do rozwinięcia komutatora: In [98]: c = Commutator(A+B, A*B) c.expand(commutator=true) Out[98]: [A, B] B + A [A, B] http://localhost:8888/notebooks/7_sympy.ipynb 7/20
In [99]: #sprzężenie komutatora Dagger(Commutator(A, B)) Out[99]: [ A, B ] In [00]: #antykomutator ac = AntiCommutator(A,B) In [0]: ac.doit() Out[0]: AB + BA Jako przykład rozważmy kwadratury pola elektromagnetycznego, które można wyrazić przy pomocy operatorów kreacji i anihilacji w następujący sposób: x = (a + a )/ 2 p = i(a a )/ 2 In [02]: #operator położenia X = (A + Dagger(A))/sqrt(2) X Out[02]: 2 2 ( A + A) In [03]: #operator pędu P = -I * (A - Dagger(A))/sqrt(2) P Out[03]: 2 i ( A + 2 A) Komutator kwadratur wynosi: http://localhost:8888/notebooks/7_sympy.ipynb 8/20
In [04]: Commutator(X, P).expand(commutator=True).expand(commutator=True) Out[04]: i[ A, A] Ponieważ [A, A ] = otrzymaliśmy dobrze znaną, kanoniczną relację [x, p] = i SymPy nie upraszcza jednak wyniku, ponieważ nie zna komutatora operatorów kreacji i anihilacji. Możemy jednak przekształcić wynik sami: In [05]: _.subs(commutator(a,dagger(a)),) Out[05]: i Inne przydatne biblioteki RPy2 (http://rpy.sourceforge.net/ (http://rpy.sourceforge.net/)) - interfejs do pakietu statystycznego R w Pythonie StatsModels (http://statsmodels.sourceforge.net/ (http://statsmodels.sourceforge.net/)) - jeszcze jeden pakiet do analizy statystycznej Pandas (http://pandas.pydata.org/ (http://pandas.pydata.org/)) - moduł do analizy danych NetworkX (https://networkx.github.io/ (https://networkx.github.io/)) - analiza sieci złożonych PyWavelets (http://www.pybytes.com/pywavelets/ (http://www.pybytes.com/pywavelets/)) - dyskretne transformaty falkowe PyGSL (http://pygsl.sourceforge.net/ (http://pygsl.sourceforge.net/)) - interfejs do biblioteki GSL GMPy (https://code.google.com/p/gmpy/ (https://code.google.com/p/gmpy/)) - obliczenia z dowolną precyzją FiPy (http://www.ctcms.nist.gov/fipy/ (http://www.ctcms.nist.gov/fipy/)) - rozwiązywanie równań różniczkowych cząstkowych metodą objętości skończonych scikit-learn (http://scikit-learn.org/stable/ (http://scikit-learn.org/stable/)) - uczenie maszynowe i drążenie danych SimPy (http://scikit-learn.org/stable/ (http://scikit-learn.org/stable/)) - symulator zdarzeń dyskretnych QuTiP (http://qutip.org/ (http://qutip.org/)) - mechanika kwantowa w Pythonie Więcej pod adresem https://wiki.python.org/moin/numericandscientific (https://wiki.python.org/moin/numericandscientific) http://localhost:8888/notebooks/7_sympy.ipynb 9/20
http://localhost:8888/notebooks/7_sympy.ipynb 20/20