6. Vnitřní reprezentace výrazů, náhodná čísla, zobrazování dat

Vnitřní reprezentace výrazů

Některé výrazy má Mathematica uloženy v paměti v jiném tvaru, než ve kterém se běžně zapisují. Pomocí FullForm[výraz] zjistíme vnitřní reprezentaci zadaného výrazu.

Vnitřní reprezentace aritmetických operací:

FullForm[x+y]

Plus je zabudovaná funkce provádějící sčítání:

Plus[2,5]

Plus může mít libovolný počet argumentů:

FullForm[x+y+z]

FullForm[x*y]

FullForm[x^2]

Odčítání se převádí na násobení mínus jedničkou a sčítání:

FullForm[x-y]

Dělení se převádí na umocňování na mínus jedna a násobení:

FullForm[(x+y)/(x-y)]

TreeForm je analogií FullForm, ale vrací výsledek v grafické podobě ve tvaru stromu (listy jsou argumenty, ostatní vrcholy reprezentují funkce).

TreeForm[(x+y)/(x-y)]

Vnitřní reprezentace seznamu:

FullForm[{1,2,3}]

Vnitřní reprezentace lokálního přepisovacího pravidla:

FullForm[x->y]

Nejjednodušší výrazy jsou tzv. atomy: celá čísla (např. 27), desetinná čísla (např. 3.14), racionální čísla (např. 1/2), komplexní čísla (např. 3+5I), identifikátory (názvy funkcí a proměnných, např. abc) a řetězce (text uzavřený v uvozovkách, např. "žlutý kůň").

Pro vnitřní reprezentaci výrazů platí: Libovolný přípustný výraz je buď atom, nebo má tvar f[(Subscript[a, 1]),(Subscript[a, 2]),…,(Subscript[a, n])], kde n je nezáporné celé číslo a f, (Subscript[a, 1]), …, (Subscript[a, n]) jsou přípustné výrazy. f se nazývá hlavou výrazu, (Subscript[a, 1]),…,(Subscript[a, n]) jsou argumenty výrazu.

Počet argumentů je nejčastěji kladný, ale může být i nulový – např. u funkce RandomReal[], která vrací náhodné číslo z intervalu [0,1].

Hlavou výrazu je nejčastěji identifikátor (např. f, Sin, Plus apod.), ale může jí být libovolný komplikovanější výraz.

Příklad: Definice posloupnosti funkcí jedné proměnné (Subscript[f, n])(x)=((sin (n x))/n).

f[n_][x_]:=Sin[n*x]/n

Pro libovolné n je f[n] funkce jedné proměnné. Výraz f[n][x] má argument x a hlavu f[n].

Plot[{f[1][x],f[2][x],f[4][x]},{x,0,4Pi}]

f[n]'[0]

Clear[f]

Posloupnost funkcí by bylo možné zadat též jako funkci dvou proměnných, někdy je to ale méně praktické:

f[n_,x_]:=Sin[n*x]/n

D[f[n,x],x]/.x->0

Konstrukce výraz[[i]] vrací i-tý argument zadaného výrazu:

f[a,b,c,d][[2]]

(a+b+c+d)[[3]]

(Protože vnitřní reprezentace a+b+c+d je Plus[a,b,c,d] a třetí argument tohoto výrazu je c).

Dvojité hranaté závorky už jsme používali pro přístup k prvkům seznamu:

seznam={"Emil","Cyril","Bedřich","František","Dagmar","Alena"}

seznam[[4]]

Vysvětlení: Vnitřní reprezentace seznamu je List[“Emil”,”Cyril”,”Bedřich”,”František”,”Dagmar”,”Alena”] a seznam[[4]] vrátí čtvrtý argument tohoto výrazu, což je čtvrtý prvek seznamu.

Dvojité hranaté závorky lze využít k získání podvýrazu daného výrazu.

s=Solve[x^4-2x^2-1==0,x]

Jak z tohoto výsledku získat pouze hodnotu třetího kořene?

x/.s[[3]](* 1. řešení *)

s[[3]][[1]][[2]](* 2. řešení *)

s[[3,1,2]] (* ekvivalentní zápis *)

Další příklad (vnitřní reprezentace grafu funkce):

obr=Plot[x^2,{x,-1,1}]

FullForm[obr]

obr[[1,1,1,3,1,2,1]]

Konstrukce výraz[[0]] vrací hlavu zadaného výrazu; ekvivalentně ji můžeme získat pomocí Head[výraz].

(x+y)[[0]]

Head[x+y]

I atomy mají hlavu:

Head[1.0]

Konstrukce Apply[nová hlava,výraz] vezme zadaný výraz, změní jeho hlavu na nová hlava a vrátí výsledek.

Apply[Plus,Range[100]]

Vysvětlení: Range[100] dává seznam {1,2,...,100}. Jeho vnitřní reprezentace je List[1,2,...,100]. Apply změní hlavu tohoto výrazu z List na Plus a výsledkem je součet všech prvků seznamu, tj. čísel 1 až 100.

Místo Apply[nová hlava,výraz] můžeme zkráceně  psát nová hlava@@výraz.

Plus@@Range[100]

Co vrátí následující příkaz?

Apply[Times,Range[10]]

Připomeňme si funkci FactorInteger, která vrací prvočíselný rozklad zadaného čísla. Výsledkem je seznam dvojic tvaru {prvočíslo,exponent}.

FactorInteger[811575]

Zkusme vyřešit obrácenou úlohu: Máme seznam dvojic uvedeného typu a chceme z něj dostat původní číslo (tj. např. ze seznamu {{3,2},{5,2},{3607,1}} chceme dostat opět 811575).

Příkaz Transpose převede seznam dvojic tvaru {prvočíslo,exponent} na seznam obsahující seznam všech prvočísel a seznam všech exponentů (obecně: Transpose převádí n-tici k-prvkových seznamů na k-tici n-prvkových seznamů - rozmyslete si, jak to souvisí se skutečností, že Transpose vrací transponovanou matici):

Transpose[%]

Nyní stačí každé prvočíslo umocnit na příslušný exponent:

Power@@%

A takto vzniklá čísla mezi sebou vynásobíme:

Times@@%

Zde je funkce, která provádí všechny výše uvedené operace:

inverseFactorInteger[s_]:=Times@@(Power@@Transpose[s])

Zkouška:

inverseFactorInteger[{{3,2},{5,2},{3607,1}}]

Clear[inverseFactorInteger]

Alternativní způsoby zápisu výrazů

Místo f[výraz] lze ekvivalentně psát výraz // f. Tento způsob zápisu se často používá ve spojení s funkcemi jako jsou N, TableForm nebo MatrixForm (často se soustředíme na zadávaný výraz a až nakonec přemýšlíme o tom, jakým způsobem chceme zobrazit výsledek).

Sin[1] //N

Table[Expand[(a+b)^n],{n,1,5}] // TableForm

IdentityMatrix[3] // MatrixForm

Místo f[výraz] lze ekvivalentně psát f@výraz. Například následující konstrukce je ekvivalentní s N[Sin[Sqrt[2]]]:

N@Sin@Sqrt@2

Zápis se zavináči bývá užitečný u komplikovaných výrazů – není potřeba hlídat správné spárování levých a pravých hranatých závorek.

Místo f[výraz1,výraz2] lze ekvivalentně psát výraz1~f~výraz2. Např. následující konstrukce je ekvivalentní s Join[{a,b},{e,f,g}], ale zápis s vlnkami vypadá pěkně symetricky:

{a,b}~Join~{e,f,g}

Náhodná čísla

Funkce RandomReal generuje náhodná desetinná čísla; má několik variant:

RandomReal[] (* náhodné desetinné číslo z intervalu [0,1] *)

RandomReal[{1,10}] (* náhodné desetinné číslo ze zadaného intervalu *)

RandomReal[{1,10},5] (* větší počet náhodných desetinných čísel ze zadaného intervalu *)

Funkce RandomInteger generuje náhodná celá čísla, používá se stejně jako RandomReal.
Funkce RandomPrime generuje jedno nebo více náhodných prvočísel ze zadaného intervalu.

RandomChoice náhodně vybírá prvky ze zadaného seznamu (jde o výběr s opakováním):

RandomChoice[{a,b,c},5]

Podobně se používá RandomSample, ale jde o výběr bez opakování (tj. počet vybíraných prvků musí být menší nebo roven délce seznamu).

RandomSample[Range[49],7] (* Sedm různých náhodných čísel od 1 do 49 *)

Nezadáme-li počet vybíraných prvků, dostaneme náhodnou permutaci seznamu:

RandomSample[Range[20]] (* náhodná permutace čísel 1 až 20 *)

Obsahuje-li zadaný seznam více kopií jednoho prvku, pak se i na výstupu může objevit více kopií (maximálně tolik, kolik jich bylo v zadaném seznamu):

RandomSample[{a,a,a,b,b,b},4]

Náhodná čísla generovaná výše uvedenými funkcemi nejsou ve skutečnosti náhodná, ale pouze pseudonáhodná. Algoritmus pro generování těchto čísel je navržen tak, aby čísla ve všech ohledech vypadala jako náhodná. Činnost algoritmu lze ovlivnit zadáním tzv. semínka – čísla, které jednoznačně určuje generovanou posloupnost.

Následující příkaz dává při opakovaném vyhodnocení pokaždé jiný výstup:

RandomReal[{0,1},10]

Nastavením semínka pomocí funkce SeedRandom dosáhneme toho, že RandomReal bude pokaždé generovat stejný výstup:

SeedRandom[1]; RandomReal[{0,1},10]

Zobrazování diskrétních dat

Seznamy hodnot

Zobrazení posloupnosti funkčních hodnot:

DiscretePlot[(-1)^n/n,{n,1,15}]

Vzhled obrázku lze (podobně jako u Plot) modifikovat pomocí voleb; kompletní seznam lze najít v dokumentaci.

DiscretePlot[(-1)^n/n,{n,1,15},Joined->True,PlotStyle->Brown,BaseStyle->{FontFamily->"Arial",FontSize->12}]

Zobrazení libovolné konečné posloupnosti reálných hodnot:

data=RandomReal[{0,1},25]

ListPlot[data]

ListPlot[data,PlotStyle->{PointSize[Medium],Red}]

ListLinePlot spojuje po sobě jdoucí body úsečkami; používá se stejně jako ListPlot.

ListLinePlot[data,PlotMarkers->Automatic]

ListPlot[{{(Subscript[x, 1]),(Subscript[y, 1])},...,{(Subscript[x, n]),(Subscript[y, n])}}] (případně ListLinePlot) zobrazí body v rovině se zadanými souřadnicemi.

deficitCR={{2000,46.1},{2001,67.7},{2002,45.7},{2003,109.1},{2004,93.5},{2005,56.4},{2006,97.3},{2007,66.4},{2008,19.4},{2009,192.2},{2010,156.4},{2011,142.8},{2012,101},{2013,81.3},{2014,77.8},{2015,62.8},{2016,-61.8},{2017,6.2},{2018,-2.9},{2019,28.5},{2020,367.5}};

ListPlot[deficitCR]

ListPlot[deficitCR,Filling->Axis,FillingStyle->Black,PlotStyle->{Blue,PointSize[Large]},Ticks->{Range[2000,2020,2],Automatic},BaseStyle->{FontFamily->"Arial",FontSize->12},PlotLabel->"Deficit státního rozpočtu ČR (miliardy Kč)"]

Funkce generující vrcholy pravidelného n-úhelníku:

polygon[n_]:=Table[{Cos[(k*2*Pi)/n], Sin[(k*2*Pi)/n]},{k,0,n}]

ListLinePlot[polygon[8],AspectRatio->Automatic]

ListLinePlot[{polygon[4],polygon[8],polygon[16]},AspectRatio->Automatic]

ListLogPlot je varianta ListPlot s logaritmickým měřítkem na svislé ose. Hodí se např. pro zobrazování rychle rostoucích posloupností.

ListPlot[Range[10]!]

ListLogPlot[Range[10]!]

Ekvivalentně pomocí volby ScalingFunctions:

ListPlot[Range[10]!,ScalingFunctions->"Log"]

Matice

ArrayPlot a MatrixPlot je dvojice funkcí pro grafické zobrazování matic. Tyto funkce se liší především ve způsobu, kterým převádějí čísla z matice na barvy.

m=Table[i+j-9,{i,1,8},{j,1,8}]

MatrixForm[m]

ArrayPlot přiřazuje barvy podle absolutních hodnot prvků matice. Minimální hodnota je převedena na bílou barvu, maximální hodnota na černou:

ArrayPlot[m]

U MatrixPlot jsou nuly bíle, kladné hodnoty v teplých barvách a záporné ve studených:

MatrixPlot[m]

Příklad použití: Pokus o rekonstrukci vrstevnic funkce dvou proměnných z matice funkčních hodnot:

m=Table[Sin[x y/100],{x,-50,50},{y,-50,50}];

MatrixPlot[m]

Barevné schéma můžeme změnit, např. pomocí ColorFunction:

MatrixPlot[m,ColorFunction->"SunsetColors"]