Sage to pakiet matematyczny. Większość wbudowanych weń elementów służy do obliczeń symbolicznych, jednak posiada on również moduły do obliczeń numerycznych. To czyni go konkurentem pakietów takich jak Mathematica, Maple, Magma czy Matlab. Pakiet Sage jest owocem działania projektu, który został zapoczątkowany przez prof. Williama Steina z Uniwersytetu Washingtona w Seattle w 2005 roku. Jest to stosunkowo młody projekt, ale funkcjonalność pakietu jest już bardzo wysoka. Jest to możliwe dzięki połączonej sile działań wielu ludzi i wykorzystaniu istniejących i sprawdzonych rozwiązań oraz dofinansowaniu gigantów takich jak Microsoft, Google, Sun czy Departament Obrony Stanów Zjednoczonych. Obecnie Sage rozwijany jest przez ponad 220 osób z ponad 150 krajów i łączy w sobie ponad 100 wyspecjalizowanych pakietów matematycznych.
Sage może być widziany z różnych ujęć. Po pierwsze jest to dystrybucja Pythona oraz wielu innych pakietów, na przykład Maxima czy R. Po drugie Sage to ujednolicony interfejs programistyczny i graficzny do tych pakietów, pozwalający na wymianę danych i przekazywanie wyników pomiędzy pakietami. Ale Sage to nie tylko opakowanie tego co już gotowe, to również setki tysięcy nowych linii kodu implementującego to, co nie jest dostępne w innych pakietach. Często kod ten powstaje specjalnie dla pakietu Sage po to, by rozszerzyć jego możliwości lub przyśpieszyć pewne funkcje, czy też jako przykłady implementacji zawarte w publikacjach naukowych.
Postaram się dzisiaj przybliżyć nieco pakiet Sage. Prezentację, którą teraz Państwo widzicie można śledzić w internecie pod adresem http://sage.im.pwr.wroc.pl/home/pub/8/, http://www.sagenb.org/home/pub/2687 lub http://alpha.sagenb.org/home/pub/72/. Zanim przejdziemy do poznania pakietu zapoznajmy się jeszcze z pewnym stwierdzeniem, które było jednym z bodźców do stworzenia tego pakietu, otóż
Coraz więcej osób zaczyna podzielać opinię wygłaszaną już jakiś czas przez dr. Joachima Neubüsera, którą jako pierwszy zaczął otwarcie głosić już w 1993 roku. Zamknięte pakiety matematyczne tworzone przez setki ludzi w wielkich firmach sprzedawane są za ogromne pieniądze aby sfinansować dalsze prace. Aby chronić pracę tych ludzi klient kupujący pakiet (zwykle w postaci licencji użytkowania na rok) otrzymuje produkt, w którym nie ma dostępu do kodu, ani informacji o użytych algorytmach. To narusza dwie podstawowe zasady napędzające rozwój matematyki - to, że każde twierdzenie posiada towarzyszący dowód, który możemy zweryfikować i to, że raz czytając o danej metodzie i sprawdzając dowód, przez resztę życia możemy z niej korzystać za darmo. Pakiet matematyczny, tak samo jak twierdzenie, jest narzędziem matematyka - bezkrytyczne ufanie narzędziu, którego poprawności działania nie możemy zweryfikować, lub na które może nas nie być stać za rok, może okazać się poważnym błędem.
Rozwojowi pakietu Sage przyświeca między innymi jeden cel - "zbudowanie samochodu, zamiast ponownego wynalezienia koła". Między innymi z tego powodu na potrzeby pakietu nie został stworzony nowy język, jak to miało miejsce w przypadku pakietu Mathematica czy Matlab. Twórca pakietu Sage zdecydował, że o wiele więcej osiągnie wykorzystując już istniejący, znany, uniwersalny i sprawdzony język. Po krótkiej analizie dostępnych opcji wybór padł na język Python.
Pakiet Sage posiada dwa interfejsy. Po pierwsze, dysponujemy interfejsem z linii komend. Możemy go wywołać i wewnątrz używać pakietu z poziomu interpretera zbliżonego do interpretera IPython czy tekstowych interfejsów innych pakietów matematycznych. Drugi interfejs, to interfejs graficzny przypominający zasadą działania Notebooki znane z pakietów Mathematica czy Maple. Nie dysponujemy tu jednak napisaną na cel pakietu aplikacją. Wybór padł na technologie internetowe - architekturę klient-serwer oraz interfejs oparty o technologie HTML, CSS, JS, \TeX, AJAX, JAVA i wiele pokrewnych. Otwiera to wiele nowych możliwości związanych z centralnymi instalacjami pakietu, nie blokując instalacji i uruchomienia serwera lokalnie dla uzyskania lepszej wydajności.
Ale czy Python to dobry wybór? Spójrzmy na kilka prostych obliczeń.
Hello World! Hello World! |
4 4 |
8 8 |
1/2 1/2 |
Jak widać, nie do końca. Po pierwsze, w Pythonie operator "^" nie służy do potęgowania, używamy zamiast niego operatora "**". Po drugie, 1/2 w języku Python to 0. Twórcy widząc te wady zapisu (z punktu widzenia matematyka) mieli do wyboru trzy wyjścia - zrezygnować z Pythona, zmodyfikować Pythona albo dodać warstwę pomiędzy interfejsem a Pytonem. Oczywisty wybór padł na ostatnią opcję. Wszystko co wpisujemy w komórce jest dodatkowo przetwarzane zanim zostanie wykonane. Możemy przyjrzeć się takiemu zapisowi:
'Integer(2)**Integer(3)' 'Integer(2)**Integer(3)' |
'Integer(1)/Integer(2)' 'Integer(1)/Integer(2)' |
Jak widać liczby, które wpisujemy są tłumaczone na obiekty klasy Integer zanim zostają zapamiętane. Również operator jest przekształcony. Spójrzmy jeszcze jaki jest typ różnych wartości:
<type 'sage.rings.integer.Integer'> <type 'sage.rings.integer.Integer'> |
<type 'sage.rings.rational.Rational'> <type 'sage.rings.rational.Rational'> |
Parser, o którym mowa pozwala również na zaoszczędzenie dużej ilości czasu przy pisaniu bardziej skomplikowanych programów. Spróbujmy wykonać wykres funkcji f(x)=sin(x^2) na przedziale (-\pi,\pi). Możemy to zrobić na przykład tak:
|
|
|
Osoby znające Pythona zauważą, że na pewno nie jest to składnia do jakiej są przyzwyczajeni. Jest to jednak składnia logiczniejsza w zastosowaniu w pakiecie. Po pierwsze, warto zwrócić uwagę na fakt, że po lewej stronie przypisania występuje zapis przypominający wywołanie funkcji oraz nie związana zmienna x. To co się dzieje stanie się jasne, gdy popatrzymy na to, co właściwie zostało wykonane:
'__tmp__=var("x"); f =
symbolic_expression(sin(x**Integer(2))).function(x)'
'__tmp__=var("x"); f = symbolic_expression(sin(x**Integer(2))).function(x)'
|
Jak widać, zmienna x została zdefiniowana jako zmienna symboliczna. Następnie zostało zbudowane wyrażenie symboliczne od niej zależne i przekształcone w funkcję. Spójrzmy na typ zmiennej x:
<type 'sage.symbolic.expression.Expression'> <type 'sage.symbolic.expression.Expression'> |
Jak widać x nie jest tutaj zmienną w rozumieniu zmiennej języka Python. W pakiecie można też używać innych typów niż zmienna Pythona lub zmienna symboliczna, np.:
|
|
Od wystąpienia takiej deklaracji x jest pewnego rodzaju zmienną, będącą generatorem pierścienia R, tutaj R to:
Univariate Polynomial Ring in x over Integer Ring Univariate Polynomial Ring in x over Integer Ring |
a x to:
<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer\ _dense_flint'> <type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'> |
Tutaj x jest zmienną należącego do wielomianów całkowitych. Typ zawiera dodatkowo informację w jakim pakiecie wielomiany te są zaimplementowane (tutaj Flint). Zwykle jeśli taka informacja towarzyszy typowi znaczy to, że mamy do wyboru kilka implementacji. Pomińmy teraz cukier syntaktyczny i stwórzmy S.<y> = ZZ[] ale w innej implementacji:
Univariate Polynomial Ring in y over Integer Ring (using NTL) Univariate Polynomial Ring in y over Integer Ring (using NTL) |
<type 'sage.rings.polynomial.polynomial_integer_dense_ntl.Polynomial_integer_d\ ense_ntl'> <type 'sage.rings.polynomial.polynomial_integer_dense_ntl.Polynomial_integer_dense_ntl'> |
Informacja ta jest oczywiście respektowana przez pakiet. Spójrzmy na miejsce zerowe dwóch wielomianów:
[(1, 1), (-1, 1)] [(1, 1), (-1, 1)] |
[] [] |
W pierwszym przypadku miejscem zerowym jest całkowite 1 oraz -1, w drugim brak miejsc zerowych. Jeśli teraz zdefiniujemy:
Univariate Polynomial Ring in x over Real Field with 53 bits of precision Univariate Polynomial Ring in x over Real Field with 53 bits of precision |
[(-1.00000000000000, 1), (1.00000000000000, 1)] [(-1.00000000000000, 1), (1.00000000000000, 1)] |
[(-1.41421356237310, 1), (1.41421356237310, 1)] [(-1.41421356237310, 1), (1.41421356237310, 1)] |
Uzyskamy inne wyniki, przedstawione w postaci liczb zmiennoprzecinkowych z 53 bitami precyzji.
Rozgraniczenie takie pozwala często na implementację o wiele bardziej wydajnego algorytmu, ponieważ zmienna zawiera w sobie dużo informacji o tym, do czego jej użyjemy. Przejdźmy teraz do praktyczniejszych przykładów zastosowań.
Na początek coś prostego. Znajdźmy miejsca zerowe równania kwadratowego a x^2+b x+c. Najpierw upewnijmy się, że wszystkie użyte oznaczenia są zmiennymi symbolicznymi:
(a, b, c, x) (a, b, c, x) |
Teraz określmy równanie:
|
Pozostaje je rozwiązać. Możemy użyć funkcji solve:
|
Lub równoważnie metody solve:
|
Zapis taki jak powyżej uzyskujemy dzięki funkcji show, w rzeczywistości wynik jest zwykłą listą:
[x == -1/2*(b + sqrt(-4*a*c + b^2))/a, x == -1/2*(b - sqrt(-4*a*c + b^2))/a] [x == -1/2*(b + sqrt(-4*a*c + b^2))/a, x == -1/2*(b - sqrt(-4*a*c + b^2))/a] |
Możemy też sprawdzić, czy rozwiązanie jest prawidłowe. W tym celu podstawimy jedno z nich do równania:
1/4*(b + sqrt(-4*a*c + b^2))^2/a - 1/2*(b + sqrt(-4*a*c + b^2))*b/a + c == 0 1/4*(b + sqrt(-4*a*c + b^2))^2/a - 1/2*(b + sqrt(-4*a*c + b^2))*b/a + c == 0 |
Podobnie jak wiele innych pakietów, Sage sam nie upraszcza obliczeń symbolicznych. Jest to operacja kosztowna, która może okazać się niepotrzebna. Możemy oczywiście zażądać pełnego uproszczenia wyniku:
0 == 0 0 == 0 |
Jeśli jednak jesteśmy pewni, że chcemy zastosować tylko pewne reguły upraszczania, możemy użyć prostszej implementacji:
0 == 0 0 == 0 |
Dokumentacja zawiera dokładny opis, spójrzmy na dokumentację metody simplify_rational:
|
File: /usr/local/sage/sage-4.6.1/devel/sage/sage/symbolic/expression.pyx Type: <type ‘instancemethod’> Definition: rown2.simplify_rational(*args, **kwds) Docstring:
File: /usr/local/sage/sage-4.6.1/devel/sage/sage/symbolic/expression.pyx Type: <type ‘instancemethod’> Definition: rown2.simplify_rational(*args, **kwds) Docstring:
|
Możemy nawet sprawdzić jej kod, choć w tym przypadku jest to tylko przekazanie obliczeń do pakietu Maxima:
|
Niestety, pakiety do obliczeń symbolicznych nie zawsze sobie poradzą. Łatwo znaleźć prosto wyglądające przykłady, na których zarazem Sage, Mathematica i inne pakiety po prostu odmawiają podania wyniku. Przeanalizujmy zadanie znalezienia rozwiązania równania x=sin(x)^2+2 cos(x)^2.
|
[x == sin(x)^2 + 2*cos(x)^2] [x == sin(x)^2 + 2*cos(x)^2] |
Jak widać nie udało się znaleźć rozwiązania. Spróbujmy najpierw uprościć równanie:
|
[x == cos(x)^2 + 1] [x == cos(x)^2 + 1] |
Niestety, dalej nie udało nam się znaleźć odpowiedzi. Spróbujmy jednak zadowolić się rozwiązaniem numerycznym. Przekształćmy nasze równanie na wyrażenie, którego miejsca zerowego będziemy szukać:
|
Jest to prawie funkcja liniowa, ale występuje tutaj też czynnik oscylujący - cos(x)^2. Zastąpmy go minimalną i maksymalną wartością, po czym rozwiążmy powstałe równania:
[x == 1] [x == 1] |
[x == 2] [x == 2] |
Możemy więc wnioskować, że rozwiązanie jest na odcinku (1,2). Spróbujmy znaleźć je numerycznie:
1.1596952618411804 1.1596952618411804 |
Sprawdźmy na rysunku
|
|
Wiemy już, że Sage radzi sobie z równaniami. Spróbujmy teraz policzyć pochodną funkcji
|
Możemy to wykonać na kilka sposobów, zwróćmy uwagę na różnice pomiędzy funkcją a wyrażeniem:
x |--> 2*cos(log(x^2))/x x |--> 2*cos(log(x^2))/x |
2*cos(log(x^2))/x 2*cos(log(x^2))/x |
Możemy policzyć również drugą pochodną:
x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 |
zapis ten jest równoważny kilku innym formom:
x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 |
x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 |
x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 x |--> -4*sin(log(x^2))/x^2 - 2*cos(log(x^2))/x^2 |
To, której formy użyjemy w przypadku funkcji lub wyrażeń jednej zmiennej zależy wyłącznie od nas. W przypadku wielu zmiennych należy podać również zmienne, po której liczymy pochodne, inaczej uzyskamy gradient funkcji. Popatrzmy na kilka obliczeń dla funkcji:
|
(x, y) |--> (cos(x), -sin(y)) (x, y) |--> (cos(x), -sin(y)) |
(x, y) |--> cos(x) (x, y) |--> cos(x) |
(x, y) |--> -sin(y) (x, y) |--> -sin(y) |
(x, y) |--> (cos(x), -sin(y)) (x, y) |--> (cos(x), -sin(y)) |
[(x, y) |--> -sin(x) (x, y) |--> 0] [ (x, y) |--> 0 (x, y) |--> -cos(y)] [(x, y) |--> -sin(x) (x, y) |--> 0] [ (x, y) |--> 0 (x, y) |--> -cos(y)] |
(x, y) |--> sin(x)*cos(y) (x, y) |--> sin(x)*cos(y) |
|
|
Wróćmy teraz do funkcji f:
|
Spróbujmy policzyć całkę:
|
Sprawdźmy teraz, czy obliczenia są prawidłowe:
x |--> sin(2*log(x)) x |--> sin(2*log(x)) |
sin(2*log(x)) - sin(log(x^2)) sin(2*log(x)) - sin(log(x^2)) |
0 0 |
Spróbujmy obliczyć teraz całkę oznaczoną:
Traceback (click to the left of this block for traceback) ... Is t positive, negative, or zero? Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "_sage_input_87.py", line 10, in <module>
exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("dmFyKCd0JykKaCh0KSA9IGludGVncmF0ZShmKHgpLCAoeCwwLHQpKQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
File "", line 1, in <module>
File "/tmp/tmpnRNECm/___code___.py", line 4, in <module>
exec compile(u'__tmp__=var("t"); h = symbolic_expression(integrate(f(x), (x,_sage_const_0 ,t))).function(t)
File "", line 1, in <module>
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/misc/functional.py", line 718, in integral
return x.integral(*args, **kwds)
File "expression.pyx", line 8147, in sage.symbolic.expression.Expression.integral (sage/symbolic/expression.cpp:30866)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/symbolic/integration/integral.py", line 603, in integrate
return definite_integral(expression, v, a, b)
File "function.pyx", line 414, in sage.symbolic.function.Function.__call__ (sage/symbolic/function.cpp:4424)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/symbolic/integration/integral.py", line 174, in _eval_
return integrator(*args)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/symbolic/integration/external.py", line 21, in maxima_integrator
result = expression._maxima_().integrate(v, a, b)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/maxima.py", line 2140, in integral
return I(var, min, max)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1479, in __call__
return self._obj.parent().function_call(self._name, [self._obj] + list(args), kwds)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1378, in function_call
return self.new(s)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1159, in new
return self(code)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1095, in __call__
return cls(self, x, name=name)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1522, in __init__
raise TypeError, x
TypeError: Computation failed since Maxima requested additional constraints (try the command 'assume(t>0)' before integral or limit evaluation, for example):
Is t positive, negative, or zero?
|
Co się stało? Sage zdecydował się nie podawać wyniku ogólnego, ponieważ jego postać zależy od znaku zmiennej t. Załóżmy, że t>0:
|
|
|
Założeń również możemy się pozbywać:
|
|
Traceback (click to the left of this block for traceback) ... Is t positive, negative, or zero? Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "_sage_input_91.py", line 10, in <module>
exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("aW50ZWdyYXRlKGYoeCksICh4LDAsdCkp"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
File "", line 1, in <module>
File "/tmp/tmptElfvc/___code___.py", line 3, in <module>
exec compile(u'integrate(f(x), (x,_sage_const_0 ,t))
File "", line 1, in <module>
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/misc/functional.py", line 718, in integral
return x.integral(*args, **kwds)
File "expression.pyx", line 8147, in sage.symbolic.expression.Expression.integral (sage/symbolic/expression.cpp:30866)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/symbolic/integration/integral.py", line 603, in integrate
return definite_integral(expression, v, a, b)
File "function.pyx", line 414, in sage.symbolic.function.Function.__call__ (sage/symbolic/function.cpp:4424)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/symbolic/integration/integral.py", line 174, in _eval_
return integrator(*args)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/symbolic/integration/external.py", line 21, in maxima_integrator
result = expression._maxima_().integrate(v, a, b)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/maxima.py", line 2140, in integral
return I(var, min, max)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1479, in __call__
return self._obj.parent().function_call(self._name, [self._obj] + list(args), kwds)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1378, in function_call
return self.new(s)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1159, in new
return self(code)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1095, in __call__
return cls(self, x, name=name)
File "/usr/local/sage/sage-4.6.1/local/lib/python2.6/site-packages/sage/interfaces/expect.py", line 1522, in __init__
raise TypeError, x
TypeError: Computation failed since Maxima requested additional constraints (try the command 'assume(t>0)' before integral or limit evaluation, for example):
Is t positive, negative, or zero?
|
Ale to co obliczyliśmy przy konkretnych założeniach nie ulega zmianie:
|
Przy okazji, wyniki możemy prezentować w różnej formie. W formie złożonej (show), w formie \TeX-owej (latex) oraz podstawowej.
t \ {\mapsto}\ \frac{1}{5} \, t \sin\left(2 \, \log\left(t\right)\right)
- \frac{2}{5} \, t \cos\left(2 \, \log\left(t\right)\right)
t \ {\mapsto}\ \frac{1}{5} \, t \sin\left(2 \, \log\left(t\right)\right) - \frac{2}{5} \, t \cos\left(2 \, \log\left(t\right)\right)
|
2/5*sin(2*log(2)) - 4/5*cos(2*log(2)) 2/5*sin(2*log(2)) - 4/5*cos(2*log(2)) |
Wartość taką jak powyżej możemy chcieć przybliżyć numerycznie, by mieć pojęcie o wymiarze wielkości:
0.246445516369856 0.246445516369856 |
0.2464455163698561467625129506897031774298775383654785101319790237781924\ 188652689097225052514345319593 0.2464455163698561467625129506897031774298775383654785101319790237781924188652689097225052514345319593 |
Time: CPU 1.57 s, Wall: 1.57 s Time: CPU 1.57 s, Wall: 1.57 s |
100001 100001 |
Przyjrzyjmy się teraz trochę bardziej skomplikowanym obliczeniom, powiedzmy pakietowi Sage, że x jest funkcją czasu i rozwiążmy proste równanie różniczkowe x'(t)+x(t)-1=0.
|
|
|
Spróbujmy teraz to powtórzyć, ale z warunkiem początkowym x(0)=0.1:
|
Oczywiście, korzystając z warunku początkowego i rozwiązania ogólnego możemy wyznaczyć parametr c.
[c == (-9/10)] [c == (-9/10)] |
(c, t) (c, t) |
[c == (-9/10)] [c == (-9/10)] |
-9/10 -9/10 |
|
Przejdźmy teraz do klasy obliczeń, które mogłoby się wydawać, że wymagają większej siły obliczeniowej:
933262154439441526816992388562667004907159682643816214685929638952175999\ 932299156089414639761565182862536979208272237582511852109168640000000000\ 00000000000000 CPU time: 0.00 s, Wall time: 0.00 s 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 CPU time: 0.00 s, Wall time: 0.00 s |
2^994 * 3^498 * 5^249 * 7^164 * 11^98 * 13^81 * 17^61 * 19^54 * 23^44 * 29^35 * 31^33 * 37^27 * 41^24 * 43^23 * 47^21 * 53^18 * 59^16 * 61^16 * 67^14 * 71^14 * 73^13 * 79^12 * 83^12 * 89^11 * 97^10 * 101^9 * 103^9 * 107^9 * 109^9 * 113^8 * 127^7 * 131^7 * 137^7 * 139^7 * 149^6 * 151^6 * 157^6 * 163^6 * 167^5 * 173^5 * 179^5 * 181^5 * 191^5 * 193^5 * 197^5 * 199^5 * 211^4 * 223^4 * 227^4 * 229^4 * 233^4 * 239^4 * 241^4 * 251^3 * 257^3 * 263^3 * 269^3 * 271^3 * 277^3 * 281^3 * 283^3 * 293^3 * 307^3 * 311^3 * 313^3 * 317^3 * 331^3 * 337^2 * 347^2 * 349^2 * 353^2 * 359^2 * 367^2 * 373^2 * 379^2 * 383^2 * 389^2 * 397^2 * 401^2 * 409^2 * 419^2 * 421^2 * 431^2 * 433^2 * 439^2 * 443^2 * 449^2 * 457^2 * 461^2 * 463^2 * 467^2 * 479^2 * 487^2 * 491^2 * 499^2 * 503 * 509 * 521 * 523 * 541 * 547 * 557 * 563 * 569 * 571 * 577 * 587 * 593 * 599 * 601 * 607 * 613 * 617 * 619 * 631 * 641 * 643 * 647 * 653 * 659 * 661 * 673 * 677 * 683 * 691 * 701 * 709 * 719 * 727 * 733 * 739 * 743 * 751 * 757 * 761 * 769 * 773 * 787 * 797 * 809 * 811 * 821 * 823 * 827 * 829 * 839 * 853 * 857 * 859 * 863 * 877 * 881 * 883 * 887 * 907 * 911 * 919 * 929 * 937 * 941 * 947 * 953 * 967 * 971 * 977 * 983 * 991 * 997 CPU time: 0.03 s, Wall time: 0.03 s 2^994 * 3^498 * 5^249 * 7^164 * 11^98 * 13^81 * 17^61 * 19^54 * 23^44 * 29^35 * 31^33 * 37^27 * 41^24 * 43^23 * 47^21 * 53^18 * 59^16 * 61^16 * 67^14 * 71^14 * 73^13 * 79^12 * 83^12 * 89^11 * 97^10 * 101^9 * 103^9 * 107^9 * 109^9 * 113^8 * 127^7 * 131^7 * 137^7 * 139^7 * 149^6 * 151^6 * 157^6 * 163^6 * 167^5 * 173^5 * 179^5 * 181^5 * 191^5 * 193^5 * 197^5 * 199^5 * 211^4 * 223^4 * 227^4 * 229^4 * 233^4 * 239^4 * 241^4 * 251^3 * 257^3 * 263^3 * 269^3 * 271^3 * 277^3 * 281^3 * 283^3 * 293^3 * 307^3 * 311^3 * 313^3 * 317^3 * 331^3 * 337^2 * 347^2 * 349^2 * 353^2 * 359^2 * 367^2 * 373^2 * 379^2 * 383^2 * 389^2 * 397^2 * 401^2 * 409^2 * 419^2 * 421^2 * 431^2 * 433^2 * 439^2 * 443^2 * 449^2 * 457^2 * 461^2 * 463^2 * 467^2 * 479^2 * 487^2 * 491^2 * 499^2 * 503 * 509 * 521 * 523 * 541 * 547 * 557 * 563 * 569 * 571 * 577 * 587 * 593 * 599 * 601 * 607 * 613 * 617 * 619 * 631 * 641 * 643 * 647 * 653 * 659 * 661 * 673 * 677 * 683 * 691 * 701 * 709 * 719 * 727 * 733 * 739 * 743 * 751 * 757 * 761 * 769 * 773 * 787 * 797 * 809 * 811 * 821 * 823 * 827 * 829 * 839 * 853 * 857 * 859 * 863 * 877 * 881 * 883 * 887 * 907 * 911 * 919 * 929 * 937 * 941 * 947 * 953 * 967 * 971 * 977 * 983 * 991 * 997 CPU time: 0.03 s, Wall time: 0.03 s |
|
920271755026045466855962781668256054307294052810239793953285763517412985\ 262323501978822916547103339332198764311128926694429965192014469337180574\ 258854255101965669713692722439368861237049443900118466267242229358838809\ 496460215546742114497122936318794382420922229797018587870350451317915617\ 184990942766797810155029441933075045772129188981041614489343545384206438\ 995186836592262593125170223430127680062490663477743842242002004914231357\ 899486287124678626100600066102278733540933447719703464029124680195026177\ 412964857500689657276787365748796835192363570613191348609145244276270764\ 465804777408575949440508551447566418811489630464191115045309280131652547\ 731782793747141150484980319367430611463990946023472819466195667158678183\ 681130408875817996838721729445775753916663228712954510481120704923859087\ 275241592392223665876910286300131474621294645735699401736284697581755151\ 900016413451408993670931908590802671856117921704294651978579681174352991\ 410791557056622496173369118595092855785844134417338169649142692589187435\ 301742615221458864914330678814703958326474085781955660425664604942849123\ 726120485051272439872545976606903238042522371480831216853001064737946906\ 898017475046619462994720059814429480949267645638531717278315386109140567\ 421507374975384275021240249642090800336572787686941682199463463099066866\ 702204042926855402821066676615841472011557402435218180206292340119241672\ 141006748199826744593298451761269206891815323035747468238859771982766512\ 554781263236924319788525197851803361705413947686093663891147724061366833\ 494127467087092245969359401102159299184733830143890656327648052676575908\ 655135939782442443116808542177355365928232190011995697704315727188881084\ 528176142957772556227153624081222658008489322761962675453544265567233476\ 857358975517683731089773908740330164186182660688614126800469264172995743\ 679921180655438244719647115856821466186517301168907732792274321379544884\ 573350740004120158204881150331945483918135267242867162717503464701181877\ 399958004314416087296985163324282563458624844066236399562733354725457411\ 347627828347256593033627186674151973687980402192233716371343312564266298\ 874305195901960277032311918990723575237081597193774377829718464719281814\ 341332773477437283460627207869478917449115162489982657581564116298023459\ 732495270075351700956243598913730840133454971118265085585706676644886436\ 331834764264219387054191767502487300255270790939231320204783038516420542\ 008888313103784838110884255487585083733240938734797302734376936793420810\ 867020185209718779670927269908884747550412550772822753523086679809536245\ 524746452957745548238178302717520159051754876562006809869627325035982116\ 186671112647935832871470323287962444698515988848621901187755088113589185\ 457016501136471407349024158013999313263656227842088073986822774216895311\ 418550769982898380687461265543773217506522881285332749712463895138180510\ 378178497047690889118184846592767949868064656342862993393444237184906674\ 722873849811294966439997475566061223014020274110963671727713854372115721\ 224489228469570767118124546455721433201289716309063821673453815865659403\ 167483160827068775845409484961883982333993500194238336824233008140594931\ 590134175918949793856506343243088419472771218165592793359389269115106835\ 490432906902871027335713152227618464826154317860618134546336344159741794\ 139420247061299867257344715523461677386135094707607583386378705799210071\ 685144173415484815139532963734550586141746926780137597372467246969311252\ 404574068882891540550303875935489428805492623836212595940806996986432453\ 55453826567378500963781681659096276126857969078217677288980 CPU time: 1.47 s, Wall time: 1.47 s 92027175502604546685596278166825605430729405281023979395328576351741298526232350197882291654710333933219876431112892669442996519201446933718057425885425510196566971369272243936886123704944390011846626724222935883880949646021554674211449712293631879438242092222979701858787035045131791561718499094276679781015502944193307504577212918898104161448934354538420643899518683659226259312517022343012768006249066347774384224200200491423135789948628712467862610060006610227873354093344771970346402912468019502617741296485750068965727678736574879683519236357061319134860914524427627076446580477740857594944050855144756641881148963046419111504530928013165254773178279374714115048498031936743061146399094602347281946619566715867818368113040887581799683872172944577575391666322871295451048112070492385908727524159239222366587691028630013147462129464573569940173628469758175515190001641345140899367093190859080267185611792170429465197857968117435299141079155705662249617336911859509285578584413441733816964914269258918743530174261522145886491433067881470395832647408578195566042566460494284912372612048505127243987254597660690323804252237148083121685300106473794690689801747504661946299472005981442948094926764563853171727831538610914056742150737497538427502124024964209080033657278768694168219946346309906686670220404292685540282106667661584147201155740243521818020629234011924167214100674819982674459329845176126920689181532303574746823885977198276651255478126323692431978852519785180336170541394768609366389114772406136683349412746708709224596935940110215929918473383014389065632764805267657590865513593978244244311680854217735536592823219001199569770431572718888108452817614295777255622715362408122265800848932276196267545354426556723347685735897551768373108977390874033016418618266068861412680046926417299574367992118065543824471964711585682146618651730116890773279227432137954488457335074000412015820488115033194548391813526724286716271750346470118187739995800431441608729698516332428256345862484406623639956273335472545741134762782834725659303362718667415197368798040219223371637134331256426629887430519590196027703231191899072357523708159719377437782971846471928181434133277347743728346062720786947891744911516248998265758156411629802345973249527007535170095624359891373084013345497111826508558570667664488643633183476426421938705419176750248730025527079093923132020478303851642054200888831310378483811088425548758508373324093873479730273437693679342081086702018520971877967092726990888474755041255077282275352308667980953624552474645295774554823817830271752015905175487656200680986962732503598211618667111264793583287147032328796244469851598884862190118775508811358918545701650113647140734902415801399931326365622784208807398682277421689531141855076998289838068746126554377321750652288128533274971246389513818051037817849704769088911818484659276794986806465634286299339344423718490667472287384981129496643999747556606122301402027411096367172771385437211572122448922846957076711812454645572143320128971630906382167345381586565940316748316082706877584540948496188398233399350019423833682423300814059493159013417591894979385650634324308841947277121816559279335938926911510683549043290690287102733571315222761846482615431786061813454633634415974179413942024706129986725734471552346167738613509470760758338637870579921007168514417341548481513953296373455058614174692678013759737246724696931125240457406888289154055030387593548942880549262383621259594080699698643245355453826567378500963781681659096276126857969078217677288980 CPU time: 1.47 s, Wall time: 1.47 s |
Jak widać te skomplikowane na pierwszy rzut oka obliczenia nie stanowią problemu. Przejdźmy teraz do kilku wizualizacji. Widzieliśmy już kilka trików związanych z grafiką. Mamy oczywiście dużo możliwości kontroli opcji wyświetlania:
|
|
CPU time: 27.16 s, Wall time: 40.05 s CPU time: 27.16 s, Wall time: 40.05 s
|
Click to the left again to hide and once more to show the dynamic interactive window |
|
|
|
|
|
|
Click to the left again to hide and once more to show the dynamic interactive window |
|
|
Jak widać, mamy do dyspozycji sporo możliwości. Wiele osób zarzuca językowi Python, że jest wolny i może nie nadawać się do trudnych obliczeń. Autorzy pakietu to rozumieją i dostarczają zintegrowane metody optymalizacji. Najpopularniejszą jest Cython. Cython to modyfikacja rozwiązania PyRex, tłumacząca kod składniowo zbliżony do kodu Pythona na C i podłączająca wynik w locie. Poniżej przedstawiony jest przykład ilustrujący różnicę wydajności pomiędzy Pythonem zawartym w Sageu a Cythonem. W przypadku tym obliczamy sumę częściową szeregu geometrycznego, naiwnie wykonując sumowanie
|
|
Time: CPU 20.26 s, Wall: 20.31 s Time: CPU 20.26 s, Wall: 20.31 s |
Time: CPU 1.84 s, Wall: 1.84 s Time: CPU 1.84 s, Wall: 1.84 s |
Dodatkowo, jeśli nasze obliczenia mogą być wywołane niezależne dla różnych elementów listy, w bardzo prosty sposób możemy wykorzystać obliczenia wielowątkowe:
|
|
<generator object __call__ at 0xcbbfe14> <generator object __call__ at 0xcbbfe14> |
[(((1,), {}), 1), (((2,), {}), 4), (((3,), {}), 9), (((4,), {}), 16)]
[(((1,), {}), 1), (((2,), {}), 4), (((3,), {}), 9), (((4,), {}), 16)]
|
[1, 4, 9, 16] [1, 4, 9, 16] |
[] [] |
Dzięki dostępnym możliwościom optymalizacji znanych jest wiele przykładów, w których Sage jest o wiele szybszy niż konkurencja:
Te różnice w szybkości przekładają się bezpośrednio na jeszcze większe różnice w przypadku operacji złożonych.
Ważnym pakietu Sage jest integracja z innymi pakietami. Zacznijmy od pakietu statystycznego R. Postaramy się stworzyć funkcję lm wyznaczającą krzywą regresji na płaszczyźnie na podstawie danych punktów.
[1] 0.59047450 0.79568355 -1.14404062 0.28586726 0.01249535 0.10794379 0.90248881 -2.16837694 [9] 0.82525428 2.00835592 [1] 0.59047450 0.79568355 -1.14404062 0.28586726 0.01249535 0.10794379 0.90248881 -2.16837694 [9] 0.82525428 2.00835592 |
<class 'sage.interfaces.r.RElement'> <class 'sage.interfaces.r.RElement'> |
[0.59047449999511503, 0.79568355018906001, -1.14404061847399, 0.28586726491841202, 0.0124953462070257, 0.10794379455711101, 0.90248881154446503, -2.1683769384016101, 0.82525427922093797, 2.00835591894915] [0.59047449999511503, 0.79568355018906001, -1.14404061847399, 0.28586726491841202, 0.0124953462070257, 0.10794379455711101, 0.90248881154446503, -2.1683769384016101, 0.82525427922093797, 2.00835591894915] |
|
|
|
|
|
|
|
|
Call:
lm(formula = sage179)
Coefficients:
(Intercept) x
0.04433 4.96566
Call:
lm(formula = sage179)
Coefficients:
(Intercept) x
0.04433 4.96566
|
{'_Names': ['(Intercept)', 'x'], 'DATA': [0.0443253366825773,
4.9656562440455296]}
{'_Names': ['(Intercept)', 'x'], 'DATA': [0.0443253366825773, 4.9656562440455296]}
|
|
|
|
Jesteśmy gotowi do stworzenia naszej funkcji. Ale jak zauważyliśmy całość zmian wykonywana jest w jednym interpreterze R. Jeśli kilka funkcji by z niego korzystało, moglibyśmy wpaść w konflikty. W tym celu stworzymy nowy interpreter. Niestety, przez przypadek nadpisaliśmy ważną dla pakietu R instrukcję:
<class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field'> <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field'> |
Całe szczęście nic straconego:
<class 'sage.interfaces.r.R'> <class 'sage.interfaces.r.R'> |
|
|
2*x + 0.999999999999999 2*x + 0.999999999999999 |
Spróbujmy teraz wykorzystać naszą funkcję dla danych losowanych poza pakietem R. Skorzystamy z biblioteki Numpy:
|
|
|
W wersji 4.6.1 występuje niewielki błąd powodujący, że wyświetlanie dokumentacji pakietu R nie jest możliwe, ale patch to naprawiający (#10860) czeka już na weryfikację. Na potrzeby tej prezentacji pakiet został uzupełniony o wyżej wymienioną poprawkę. Aby zastosować poprawkę wystarczy wykonać operację patch -p1 < ../(#ticket ID).patch wewnątrz katalogu sage/devel, a następnie wywołać komendę sage -b, które powoduje uaktualnienie wszystkich plików do odpowiednich wersji. W pakiecie Sage jest wiele innych elementów ułatwiających jego modyfikację, między innymi zintegrowany jest z pakietem Mercurial.
Niestety, błąd ten jest naprawiony tylko na serwerze http://sage.im.pwr.wroc.pl/.
Traceback (click to the left of this block for traceback) ...
Traceback (most recent call last):
File "
' + preamble + ' '
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 116: ordinal not in range(128)
' + s + ' |
Jeśli na komputerze, na którym zainstalowany jest Sage dysponujemy licencją na dany pakiet (np.: Mathematica, Matlab, Maple), możemy używać go z poziomu tego samego interfejsu i w taki sam sposób jak pakiety dołączone standardowo do Sagea. Spójrzmy na przykład wykorzystujący pakiet Mathematica:
Pi 2
Sqrt[--] FresnelS[Sqrt[--]]
2 Pi
Pi 2
Sqrt[--] FresnelS[Sqrt[--]]
2 Pi
|
1 - Cos[1] 1 - Cos[1] |
<class 'sage.interfaces.mathematica.MathematicaElement'> <class 'sage.interfaces.mathematica.MathematicaElement'> |
-cos(1) + 1 -cos(1) + 1 |
<type 'sage.symbolic.expression.Expression'> <type 'sage.symbolic.expression.Expression'> |
Jak widać możliwości są ogromne. Na koniec małe podsumowanie
Dziękuję za uwagę, może jakieś pytania?
|
|