Bardziej Zaawansowane Tematy

Transkrypt

Bardziej Zaawansowane Tematy
5.Bardziej zaawansowane tematy.
Ÿ Programowanie rekursywne i dynamiczne
Programy rekursywne to programy które "odwo uj si do siebie samych". W Mathematice bardzo atwo
jest programowa rekursywnie cho w przeciwe stwie do j zyków programistycznych takich jak LISP
(do których j zyk Mathematiki ma pewne podobie stwo) Mathematica nie jest zoptymalizowana do tego
celu i nie uwa nie napisane programy rekursywne mog by bardzo powolne. Jednym ze sposobów
przyspieszenia ich jest metoda zwana "programowaniem dynamicznym", lub, bardziej precyzyjnie,
metoda "funkcji które zapami tuj swoje warto ci". Jest to bardzo po yteczna metoda któr naj atwiej
zrozumie rozpatruj c przyk ady jej u ycia.
ã Szybkie obliczanie liczb Fibonacciego.
Liczby Fibonacciego s rozwi zaniami równania rekursywnego
aHnL ‡ aHn - 2L + aHn - 1L
aH0L ‡ 0
aH1L ‡ 1
Funkcja RSolve rozwi zuje wiele równa tego typu:
a@nD . RSolve@8a@nD Š a@n - 1D + a@n - 2D, a@0D Š 0, a@1D Š 1<, a@nD, nD@@1DD
Fibonacci@nD
Fibonacci@nD to po prostu zakodowana n-ta liczba Fibonacciego. Aby zobaczy
FunctionExpand:
definicj
u wyamy
FunctionExpand@Fibonacci@nDD
1
n
1
K1 +
5
5O
n
2
-
2
cosHΠ nL
1+
5
Teraz spróbujemy sami zdefiniowa
"zwyczajna rekursja".
liczby Fibonacciego. Zrobimy to na dwa sposoby. Pierwszy, to
Fib1@0D = 0; Fib1@1D = 1;
Fib1@n_D := Fib1@n - 1D + Fib1@n - 2D
Timing@Fib1@30DD
81.85534, 832 040<
Niestety, to podej cie jest bardzo powolne i ju
obliczenie 30tej liczby Fibonacciego zabiera
zauwa aln ilo
czasu. Nast pnie u yjemy "programowania dynamicznego". Na pierwszy rzut oka
definicja wygl da dziwnie. Nale y zwróci uwag na równoczesne u ycie := i =.
2
5. Bardziej Zaawansowane Tematy1.nb
Niestety, to podej cie jest bardzo powolne i ju
obliczenie 30tej liczby Fibonacciego zabiera
zauwa aln ilo
czasu. Nast pnie u yjemy "programowania dynamicznego". Na pierwszy rzut oka
definicja wygl da dziwnie. Nale y zwróci uwag na równoczesne u ycie := i =.
Clear@Fib2D
Fib2@0D = 0; Fib2@1D = 1;
Fib2@n_D := Fib2@nD = Fib2@n - 1D + Fib2@n - 2D
Timing@Fib2@30DD
80.000266, 832 040<
Tym razem dzia a to b yskawicznie.
Co si dzieje podczas wykonywanie tych dwóch definicji-programów mo na prze ledzi
funkcji Trace. Ro nic wida wyra nie:
za pomoc
Trace@Fib1@5DD
8Fib1@5D, Fib1@5 - 1D + Fib1@5 - 2D, 885 - 1, 4<, Fib1@4D,
Fib1@4 - 1D + Fib1@4 - 2D, 884 - 1, 3<, Fib1@3D, Fib1@3 - 1D + Fib1@3 - 2D,
883 - 1, 2<, Fib1@2D, Fib1@2 - 1D + Fib1@2 - 2D, 882 - 1, 1<, Fib1@1D, 1<,
882 - 2, 0<, Fib1@0D, 0<, 1 + 0, 1<, 883 - 2, 1<, Fib1@1D, 1<, 1 + 1, 2<,
884 - 2, 2<, Fib1@2D, Fib1@2 - 1D + Fib1@2 - 2D, 882 - 1, 1<, Fib1@1D, 1<,
882 - 2, 0<, Fib1@0D, 0<, 1 + 0, 1<, 2 + 1, 3<,
885 - 2, 3<, Fib1@3D, Fib1@3 - 1D + Fib1@3 - 2D,
883 - 1, 2<, Fib1@2D, Fib1@2 - 1D + Fib1@2 - 2D, 882 - 1, 1<, Fib1@1D, 1<,
882 - 2, 0<, Fib1@0D, 0<, 1 + 0, 1<, 883 - 2, 1<, Fib1@1D, 1<, 1 + 1, 2<, 3 + 2, 5<
Widzimy e Fib1 wielkorotnie powtarza te same obliczenia.
W przypadku Fib2 pierwsze oblicznie i nast pne s zupe nie inne. Najpierw usu my jesze raz Fib2 i
definiujmy funkcj od pocz tku:
Clear@Fib2D
Fib2@0D = 0; Fib2@1D = 1;
Fib2@n_D := Fib2@nD = Fib2@n - 1D + Fib2@n - 2D
Trace@Fib2@5DD
8Fib2@5D, Fib2@5D = Fib2@5 - 1D + Fib2@5 - 2D,
8885 - 1, 4<, Fib2@4D, Fib2@4D = Fib2@4 - 1D + Fib2@4 - 2D,
8884 - 1, 3<, Fib2@3D, Fib2@3D = Fib2@3 - 1D + Fib2@3 - 2D,
8883 - 1, 2<, Fib2@2D, Fib2@2D = Fib2@2 - 1D + Fib2@2 - 2D,
8882 - 1, 1<, Fib2@1D, 1<, 882 - 2, 0<, Fib2@0D, 0<, 1 + 0, 1<,
Fib2@2D = 1, 1<, 883 - 2, 1<, Fib2@1D, 1<, 1 + 1, 2<, Fib2@3D = 2, 2<,
884 - 2, 2<, Fib2@2D, 1<, 2 + 1, 3<, Fib2@4D = 3, 3<,
885 - 2, 3<, Fib2@3D, 2<, 3 + 2, 5<, Fib2@5D = 5, 5<
Teraz wywo ajmy Fib2 jeszcze raz, tym razem dla n = 6:
5. Bardziej Zaawansowane Tematy1.nb
Trace@Fib2@6DD
8Fib2@6D, Fib2@6D = Fib2@6 - 1D + Fib2@6 - 2D,
8886 - 1, 5<, Fib2@5D, 5<, 886 - 2, 4<, Fib2@4D, 3<, 5 + 3, 8<, Fib2@6D = 8, 8<
Widzimy wyra nie
oblicza .
e Mathematica zapami ta a warto ci Fib2@nD dla n £ 5 i wi cej nie musia a ich
Mo emy tak e sprawdzi bezpo rednio co Matheamtica wie o Fib1 i Fib2
? Fib1
Global`Fib1
Fib1@0D = 0
Fib1@1D = 1
Fib1@n_D := Fib1@n - 1D + Fib1@n - 2D
? Fib2
Global`Fib2
Fib2@0D = 0
Fib2@1D = 1
Fib2@2D = 1
Fib2@3D = 2
Fib2@4D = 3
Fib2@5D = 5
Fib2@n_D := Fib2@nD = Fib2@n - 1D + Fib2@n - 2D
Oczywi cie to du y zysk w szybko ci w obliczeniach dzi ki u yciu programowania dynamicznego ma
pewien koszt w u ytej pami ci. Pami mo emy odzyska przez:
Clear@Fib2D
Imperatywne (proceduralne) i funkcyjne programowanie
Dotychczas rozwa ali my dwa paradygmaty programowania u ywane w Mathematice: programowanie
oparte na regu ach oraz funkcyjne. Teraz przejdziemy do programowania proceduralnego zwanego
tak e imperatywnym. Jest to oczywi cie najbardziej powszechny paradygmat programowania, odaj cy
dosy wiernie sposób dzia ania wi kszo ci wspó czesnych komputerów. Typowe dla tego paradygmatu
jest przypisywanie warto ci zmiennym i u ywanie p tli w celu zmiany tych warto ci. Zaczniejmy od
przyk adu.
3
4
5. Bardziej Zaawansowane Tematy1.nb
Clear@xD
x = 1; x = x + 1; x = x + 1; x = x + 1; x = x + 1; x = x + 1; x = x + 1;
Zauwa my e nie otrzymali my adengo wyniku. Tymniemniej x ma oczekiwan warto .
x
7
Przyjrzyjmy si formie wewn trznej (FullForm) obliczanego wyra enia:
FullForm@Hold@x = 1; x = x + 1; x = x + 1; x = x + 1; x = x + 1; x = x + 1; x = x + 1;DD
Hold@CompoundExpression@Set@x, 1D, Set@x, Plus@x, 1DD, Set@x, Plus@x, 1DD,
Set@x, Plus@x, 1DD, Set@x, Plus@x, 1DD, Set@x, Plus@x, 1DD, Set@x, Plus@x, 1DD, NullDD
Zauwa my e Mathematica automatycznie daje nam warto ostatniego wyra enia w ComposedExpression. Je li wi c nie chcemy tego wyra enia otrzyma , u ywamy ostatniego argumentu Null.
W wielu proceduralnych j zykach warto ci zmiennej x nie zwracana o ile nie u yje si Return[x] lub
Print[x]. Poniewa Mathematica zawsze zwraca warto
obliczanego wyra enia, Return[x] s u y do
zupe nie innego celu. Je li na ko cu p tli w programie napisanym w Mathematice widzimy Return[x]
(zamiast prostego x) mo emy by prawie pewni e autor nauczy si programowa w j zyku Fortran (lub
C) i nadal pisze
programy w tym j zyku. Nie jest to najbardziej wydajne i eleganckie podej cie do programowania w
Mathematice ale dzia a! Teraz powtórzymy to samo u ywaj c p tli Do. Zauwa my e sama p tla Do nic
nie zwraca - dla tego na ko cu kodu umie cili my x :
Clear@xD
x = 1; Do@x = x + 1, 86<D; x
7
To samo mo na zapisa
nieco krócej:
x = 1; Do@x ++, 86<D; x
7
Mathematica ma tak e inne p tle, np. While i For. Ogólnie lepiej stara si ich unika poniewa
zazwyczaj mo na uzyska w Mathematice znacznie lepsze wyniki pod wzgl dem szybko ci u ywaj c
funkcyjnych konstrukcji Nest, Fold, FixedPoint i Accumulate. Jest to, oczywi cie, zwiazane z natur
Mathematiki, nie z programowaniem w ogólno ci. Nawet w Mathematice ró nica w szybko ci programów napisanych proceduralnie i funkcyjnie znika w sytuacjach w których udaje si u y tzw. kompilacji.
Ÿ Zmienne Lokalne
Je li w programie przypisujemy zmiennym warto ci i zmieniamy je, musimy zwraca szczegu n uwag
aby przypdakowo nie zmieni warto ci zmiennych które chciali my zachowa . Najprostszym sposobem
zabezpieczenia si przed tak ewentualno ci jest u ywanie lokalnych zmiennych. Mathematica ma
trzy podstawowe konstrukcje lokalizuj ce zmienne: Block, Module and With. Ka da z nich dzia a inaczej
i ma swoje silne i s abe strony.
5. Bardziej Zaawansowane Tematy1.nb
Je li w programie przypisujemy zmiennym warto ci i zmieniamy je, musimy zwraca szczegu n uwag
aby przypdakowo nie zmieni warto ci zmiennych które chciali my zachowa . Najprostszym sposobem
zabezpieczenia si przed tak ewentualno ci jest u ywanie lokalnych zmiennych. Mathematica ma
trzy podstawowe konstrukcje lokalizuj ce zmienne: Block, Module and With. Ka da z nich dzia a inaczej
i ma swoje silne i s abe strony.
? Block
Block@8x, y, … <, exprD specifies that expr is to be evaluated with local values for the symbols x, y, … .
Block@8x = x0 , … <, exprD defines initial local values for x, … . ‡
Najpierw prosty przyk ad lokalizacji przez Block. Przypisujemy zmiennej x warto 3. Wewn trz Block
zmieniamy jej warto na 1. Widzimy e "na zewn trz" warto x nie uleg a zmianie.
x = 3; Block@8x<, x = 1D
1
x
3
Dok adnie tak samo zachowa si Module
? Module
Module@8x, y, … <, exprD specifies that occurrences of the symbols x, y, … in expr should be treated as local.
Module@8x = x0 , … <, exprD defines initial values for x, … . ‡
x = 3; Module@8x, y, z = 1<, x = 5; y = x + zD
6
x
3
Block and Module dzia aj zupe nie inaczej. Kiedy lokalizujemy zmienn u ywaj c Block jej warto jest
najpierw zapisana, potem tymczasowo odebrana wraz z wszystkimi atrybutami zmiennej, i na koniec, po
wyj ciu z Block oryginalna warto zostaje przywrócona zmiennej. W przypadku Module nazwy zmiennych s zmienione wewn trz Module, tak e nie konfliktuj z zewn trznymi. W przeciwie swie do
Module i Block, wszystkie lokalne zmienne w With musz mie przypisane warto ci pocz tkowe:
With@8x = 1, y = 2<, x + yD
3
Nast pnie, zauwa my jedn cech która odró nia Module i With od Block. W tych pierwszych inicializacja (przypisanie warto ci pocz tkowych) dla wszystkich zmiennych odbywa si niezale nie:
ClearAll@ f D
5
6
5. Bardziej Zaawansowane Tematy1.nb
g@x_ListD := Module@8u = Length@xD, v = u + 1<, vD
g@81, 2, 3<D
1+u
ClearAll@gD
g@x_ListD := With@8u = Length@xD, v = u + 1<, vD
g@81, 2, 3<D
1+u
Block zachowuje si inaczej:
g@x_ListD := Block@8u = Length@xD, v = u + 1<, vD
g@81, 2, 3<D
4
A oto inny wa ny przyk ad ilustruj cy ró nic mi dzy Block i Module:
foo := x
x = 1; foo
1
Block@8x = 2<, fooD
2
Chocia foo by o zdefiniowane na zewn trz struktury Block, jego warto
Module zachowuje si inaczej:
zmienia a si wewn trz Block.
foo
1
Module@8x = 2<, fooD
1
A wi c, ewaluacja wewnatrz Module zale na jest tylko od oryginalnej definicji zmiennej czy funkcji, co
nie jest prawd w przypadku Blocku.
5. Bardziej Zaawansowane Tematy1.nb
Ÿ P tle i funkcyja iteracji
Programy napisane wed ug imperatywnego paradygmatu zmieniaj warto ci przypisane jakiej zmiennej, po czym, aby otrzyma warto zmiennej nale y j jawnie ewaluowa . Rozwa my prosty przyk ad
u ywaj cy p teli Do:
Timing@x = 1; Do@x ++, 820 000<D; xD
80.011248, 20 001<
Teraz zrobimy to samo w paradygmie funkcyjnej. Programuj c w tym stylu u ywamy funkcji które
zwracaj swoje warto ci zamiast zmienia warto jakiej zmiennej. Zamiast p teli u ywamy funkcji
których argumentami s funkcje. Przyk adem takiej funkcji jest Nest:
? Nest
Nest@ f , expr, nD gives an expression with f applied n times to expr. ‡
Nest@ f , a, 4D
f@f@f@f@aDDDD
Jest tak e blisko spokrewniona funkcja NestList
? NestList
NestList@ f , expr, nD gives a list of the results of applying f to expr 0 through n times. ‡
NestList@ f , a, 4D
8a, f@aD, f@f@aDD, f@f@f@aDDD, f@f@f@f@aDDDD<
Zamiast u ywa p tli Do jak powy ej, uzyskujemy ten sam wynik programuj c funkcyjnie:
Nest@ð + 1 &, 1, 20 000D  Timing
80.000682, 20 001<
Zauwa my du
ró nic w szybko ci.
FoldList@ f , a, 8b, c, d, e<D
8a, f@a, bD, f@f@a, bD, cD, f@f@f@a, bD, cD, dD, f@f@f@f@a, bD, cD, dD, eD<
Pierwszy argument FoldList musi by funkcj dwóch argumentów. Poni sze przyk ady ilustruj dzia anie
FoldList:
7
8
5. Bardziej Zaawansowane Tematy1.nb
FoldList@Plus, 0, 8a, b, c, d<D
80, a, a + b, a + b + c, a + b + c + d<
FoldList@Times, 1, 8a, b, c, d<D
81, a, a b, a b c, a b c d<
Zwró my uwag na jeszcze jedn funkcj tego typu:
? Accumulate
Accumulate@listD gives a list of the successive accumulated totals of elements in list. ‡
Accumulate@8a, b, c, d, e<D
8a, a + b, a + b + c, a + b + c + d, a + b + c + d + e<
Oczywi cie ten sam wynik mo na uzyska przy pomocy bardziej ogólnej funkcji FoldList:
FoldList@Plus, 0, 8a, b, c, d, e<D
80, a, a + b, a + b + c, a + b + c + d, a + b + c + d + e<
Jednak e, bardziej wyspecializowana funkcja Accumulate, jest szybsza w dzia aniu na numerycznych
argumentach:
ls = RandomInteger@81, 100<, 81000<D;
a = HAccumulate@lsD;  TimingL
80.000056, Null<
b = HRest@FoldList@Plus, 0, lsDD;  TimingL
80.000853, Null<
First@bD  First@aD
15.2321
Last@aD Š Last@bD
True
Wi ksza szybko
wyspecializowanych funkcji w porównaniu z bardziej ogólnymi jest wa nym elementem w programowaniu w Mathematice.
5. Bardziej Zaawansowane Tematy1.nb
Wi ksza szybko
wyspecializowanych funkcji w porównaniu z bardziej ogólnymi jest wa nym elementem w programowaniu w Mathematice.
http:reference.wolfram.commathematicatutorial
ApplyingFunctionsRepeatedly.html
Ÿ Block i zmienne globalne.
Block jest najcz ciej u ywany w celu tymczasowej zmiany warto ci zmiennych globalnych. Na
przyk ad, globalna zmienna $RecursionLimit ma domy ln warto :
$RecursionLimit
256
Oznacza to e p tla w której d ugo rekursji przekroczy 256 kroków zostanie autmatycznie zatrzymana.
Oczywi cie ma to u atwi wy apywanie b dów programistycznych które bez tego ograniczenia prowadzi yby do niesko czonych p tli. Czasem jednak to ogranicznie jest nie wygodne. Dla przyk adu, wró my
jeszcze raz do dobrze znanej nam definicji:
Clear@FibD
Fib@1D = 1; Fib@2D = 1; Fib@n_D := Fib@nD = Fib@n - 1D + Fib@n - 2D;
Spróbyjmy
Fib@3000D
$RecursionLimit::reclim : Recursion depth of 256 exceeded. ‡
$RecursionLimit::reclim : Recursion depth of 256 exceeded. ‡
54 122 222 371 037 658 776 676 579 571 233 761 483 351 206 693 809 497
Hold@Fib@2745 - 1D + Fib@2745 - 2DD +
87 571 595 343 018 854 458 033 386 304 178 158 174 356 588 264 390 370
Hold@Fib@2746 - 1D + Fib@2746 - 2DD
Ograniczenie zmiennej $RecursionLimit do 256 powoduje e nasz kod nie chce dzia a . Mog iby my
zmieni $RecursionLimit do wiekszej liczby albo ca kowicie go usun robi c go równym ¥, ale robi c
to nara amy si na nieprzyjemne konsekwencje w przysz o ci. Du o lepiej jest zmieni tymczasowo
warto
$RecursionLimit za pomoc Block. Zanim jednak to zrobimy musimy usun
wszystkie
definicje Fib bo Mathematica zapami ta a "zatrzymane" warto ci.
Clear@FibD
Fib@1D = 1; Fib@2D = 1; Fib@n_D := Fib@nD = Fib@n - 1D + Fib@n - 2D;
9
10
5. Bardziej Zaawansowane Tematy1.nb
Block@8$RecursionLimit = ¥<, Fib@3000DD
410 615 886 307 971 260 333 568 378 719 267 105 220 125 108 637 369 252 408 885 430 926 905 „
584 274 113 403 731 330 491 660 850 044 560 830 036 835 706 942 274 588 569 362 145 476 „
502 674 373 045 446 852 160 486 606 292 497 360 503 469 773 453 733 196 887 405 847 255 „
290 082 049 086 907 512 622 059 054 542 195 889 758 031 109 222 670 849 274 793 859 539 „
133 318 371 244 795 543 147 611 073 276 240 066 737 934 085 191 731 810 993 201 706 776 „
838 934 766 764 778 739 502 174 470 268 627 820 918 553 842 225 858 306 408 301 661 862 „
900 358 266 857 238 210 235 802 504 351 951 472 997 919 676 524 004 784 236 376 453 347 „
268 364 152 648 346 245 840 573 214 241 419 937 917 242 918 602 639 810 097 866 942 392 „
015 404 620 153 818 671 425 739 835 074 851 396 421 139 982 713 640 679 581 178 458 198 „
658 692 285 968 043 243 656 709 796 000
Zauwa my e globalna warto
$RecursionLimit pozostaje nie zmieniona:
$RecursionLimit
256
Przyk ad: Symulacja Ruchu Browna
Jako przyk ad u ycia funkcji FoldList, NestList i Accumulate podajemy konstrukcj symulacji ruchu
Browna (procesu Wienera). W Mathematice 9 konstrukcja staje si du o atwiejsza dzi ki nowym
wbudowanym funkcjom RandomFunction i WienerProcess. Kod który podajemy poni ej dzia a w
wersjach wy szych ni 6.
ã Jedna cie ka
cie k ruchu Browna (przebyt w czasie 1) przybli amy przez losowe b dzenie z n krokami, gdzie
ka dy krok jest liczb rzeczywist o rozk adzie normalnym z redni 0 i standardowym odchyleniem
1
n
. Jest szereg sposobów zaprogramowanie tego w Mathematice. Podajemy trzy
1. Accumulate (najszybsza metoda)
BrownianMotion@n_D := Accumulate@Prepend@RandomReal@NormalDistribution@0, Sqrt@1  nDD, 8n<D, 0DD
2. FoldList (powolniejsza)
BrownianMotion@n_D:=FoldList@Plus,0,RandomReal@NormalDistribution@0,Sqrt@1nDD,8n<DD
3. NestList (jeszcze powolniejsza)
5. Bardziej Zaawansowane Tematy1.nb
11
BrownianMotion@n_D:=NestList@ð+RandomReal@NormalDistribution@0,Sqrt@1nDDD&,0,nD
ListLinePlot@BrownianMotion@2000D, DataRange ® 80, 1<D
0.5
0.2
0.4
0.6
0.8
1.0
-0.5
ã Wiele cie ek
Clear@BrownianMotionD
BrownianMotion@time_, steps_, paths_D := Transpose@Accumulate@Join@8ConstantArray@0, pathsD<,
Transpose@RandomReal@NormalDistribution@0, Sqrt@time  stepsDD, 8paths, steps<DDDDD
ListLinePlot@BrownianMotion@1, 100, 10D, DataRange ® 80, 1<, PlotRange ® AllD
1
0.2
-1
-2
0.4
0.6
0.8
1.0
12
5. Bardziej Zaawansowane Tematy1.nb
Manipulate@BlockRandom@SeedRandom@rD;
ListLinePlot@BrownianMotion@time, steps, pathsD, DataRange ® 80, time<, PlotRange ® 8-2, 2<DD,
88steps, 100, "number of steps"<, 10, 300, 1, Appearance ® "Labeled"<,
88paths, 10, "number of paths"<, 1, 50, 1, Appearance ® "Labeled"<,
88time, 1, "time"<, 0.5, 10, Appearance ® "Labeled"<,
88r, 0, ""<, Button@"randomize", r = RandomInteger@2 ^ 64 - 1DD &<,
SaveDefitition ® True, Initialization ¦
HBrownianMotion@time_, steps_, paths_D := Transpose@Accumulate@Join@8ConstantArray@0, pathsD<,
RandomReal@NormalDistribution@0, Sqrt@time  stepsDD, 8steps, paths<DDDDLD
number of steps
138
number of paths
13
time
1
randomize
2
1
0.2
0.4
0.6
0.8
1.0
-1
-2
http:reference.wolfram.commathematicatutorialPseudorandomNumbers.html

Podobne dokumenty