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.commathematicatutorial 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@1nDD,8n<DD 3. NestList (jeszcze powolniejsza) 5. Bardziej Zaawansowane Tematy1.nb 11 BrownianMotion@n_D:=NestList@ð+RandomReal@NormalDistribution@0,Sqrt@1nDDD&,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.commathematicatutorialPseudorandomNumbers.html