====== Cvičení 12, Náhodná čísla, grafický výstup ====== ==== Genealogie ==== * Využijte následující třídu pro reprezentaci rodinných vztahů class Person: def __init__(self, name, sex): self.name = name self.sex = sex self.children = [] self.parents = [] # parents of this node self.partner = None # partner (=husband/wife of this node) def add_child(self, node): self.children.append(node) def add_parent(self, node): self.parents.append(node) def set_partner(self, node): self.partner = node def __str__(self): s = "Female" if self.sex == 'F' else "Male" return self.name + " " + s * Každá osoba může mít více potomků a max. jednoho partnera (manžela/manželku) * Třída by měla obsahovat: * Seznam potomků, odkaz na rodiče, a partnera * Metody pro manipulaci s těmito prvky (např. addChild, setPartner ..) * Vytvořte objekt Tree - genealogický strom, který bude obsahovat seznam všech lidí a bude umět přidávat lidi i vztahy mezi nimi. * Objekt Tree otestujte přidáním 4 objekty: dva partnery a dvě děti. * Otestujte, zda byly vytvořeny správné vazby, tj. aby objekty děti ukazovaly na rodiče a naopak. * Napište funkce pro: * nalezení všech vnuků dané osoby * nalezení všech vnuček dané osoby * nalezení všech babiček dané osoby * Rozšiřte předchozí kód o načítání ze souboru: * na každém řádku je jeden záznam * záznam pro rodiče-děti: 'P name1 name2 sex1 sex2', kde P definuje vztah osoba name1 je rodičem osoby name2 a sex1, sex2 označují pohlaví těchto osob (buď F nebo M) * záznam pro partnery: 'M name1 name2 sex1 sex2', name1 a name2 jsou partneri, sex1, sex2 je F/M Vstupní soubor family.txt: M Jana Jan F M P Jana Martin F M P Jana Robert F M P Robert Gabriel M M P Robert Oleg M M P Robert Ondrej M M P Martin Jiri M M P Martin Rudolf M M P Jan Petra M F P Jan Uxana M F P Uxana Klara F F P Uxana Jakub F M P Uxana Adam F M P Petra Alex F M P A C M M P A D M F P D K F F P C J M M P C I M F P C H M M P B E F F P B F F M P B G F F Schéma rodiny ve family.txt: * Červeně: females * Modrá hrana: partneři {{courses:b3b33alp:cviceni:family.png?800|}} ==== Generování (pseudo)náhodných čísel ==== * Co je to "náhodné" číslo? * Lze generovat náhodná čísla na deterministickém stroji? * Pro generování opravdu náhodný čísel je nutné použít vnější zdroj, např. šum diody, což je ne vždy možné. * Jiné řešení spočívá ve výpočtu takové řady čísel, která se na 'dostatečně krátkém' úseku jeví jako náhodná * Nejčastěji používané: [[https://en.wikipedia.org/wiki/Linear_congruential_generator | LCG ]] === Princip LCG === * Generujeme posloupnost čísel $x_{n+1} = (ax_n + c)\,\, \mathrm{mod}\,\, m $ * kde $x_n$ je předchozí číslo, $x_{n+1}$ je následující číslo * $a,c,m$ jsou konstanty. * $m$ určuje periodu posloupnosti. * Naprogramujte toto LCG s parametry $a=1$, $c=1$, $m=5$. * Pozorujte, co se stane při $m=6$. * Prvnímu číslu posloupnosti říkáme **seed** === Generování náhodných čísel v Pythonu === * Modul **random** * funkce 'random()': generuje náhodné číslo z rovnoměrného rozdělení v rozsahu $<0,1)$. * funkce 'randint(a,b)': náhodné int číslo z rovnoměrného rozdělení v rozsahu $ import random for i in range(10): print(random.random()) import random for i in range(10): print(random.randint(-10,10)) * Python defaultně nastavuje **seed** tohoto generátoru na aktuální čas. * Seed lze nastavit ručně: ''random.seed( cislo )'' ==== Vytváření jednoduché grafiky ==== * Existuje mnoho knihoven realizujících grafiku. * Knihovna Matplotlib: {{http://matplotlib.org/}} * podobné ovládání jako příkaz ''plot'' v Matlabu Hlavním objektem je ''plt'' z modulu ''matplotlib.pyplot'', který poskytuje spoustu metod ke kreslení různých funkcí. import numpy as np import matplotlib.pyplot as plt x = np.arange(0.,10.,0.1) y = np.sin(x) plt.plot(y) plt.show() {{courses:b3b33alp:cviceni:graf1.png?300|}} Všimněte si, ze výsledný graf je na ose 'x' číslován od 0 do 100, neboť to je velikost pole 'y'. Další možností je na zobrazit funkci sinus společně s osou 'x' definovanou dle pole 'x': plt.plot(x,y) {{courses:b3b33alp:cviceni:graf2.png?300|}} A pomocí volání funkcí 'x/ylabel' nastavíme popisky jednotlivých os plt.xlabel('osa x') plt.ylabel('osa y') **Samostatné úsečky:** je třeba zadat pole počátečních x-ových a y-ových souřadnic. plt.plot([x1,x2],[y1,y2],'k-'); **Uložení obrázků** do souboru: příkaz: [[ http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.savefig | savefig ]]. Pro současné ulozeni obrázků do souboru a zobrazení je třeba volat ''savefig'' před příkazem ''show''. plt.savefig('jmeno.png') **Kreslení histogramu** - příkaz [[ http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist | hist ]] import numpy as np import matplotlib.pyplot as plt size = 10000 y = np.random.randn(size) n, bins, patches = plt.hist(y, 50, normed=0, alpha=0.74) plt.savefig('histogram1.png', dpi=600) plt.show() {{courses:b3b33alp:cviceni:histogram1.png?300|}} Poznámka: meze grafu lze určit i ručně příkazem [[ http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.axis | axis ]] plt.axis([-5,5, 0, 0.5]) zobrazí graf na ose 'x' v rozsahu -5,5 a na ose 'y' v rozsahu 0 až 0.5. ==== Úkol 4: zobrazení histogramu ==== * Vygenerujte náhodná čísla z Gaussova rozdělení se střední hodnotou 5 a $\sigma=15$. * Vygenerujte náhodná čísla z Gaussova rozdělení se střední hodnotou 0 a $\sigma=5$. * Zobrazte příslušné histogramy do jednoho grafu ==== Kreslení fraktálů ==== {{courses:b3b33alp:cviceni:fractal_example.png?300}} import numpy as np import matplotlib.pyplot as plt def drawBranch(x, y, length, angle): # Konec rekurze if (length < 0.3): return a1 = 0.15 a2 = -0.15 s = 0.7 l2 = s*length x1 = x + l2 * np.cos(angle) y1 = y + l2 * np.sin(angle) plt.plot([x,x1],[y,y1], 'k-') drawBranch(x1, y1, l2, angle+a1) drawBranch(x1, y1, l2, angle+a2) if __name__ == '__main__': drawBranch(5,0,6,1.57) plt.show() {{courses:b3b33alp:cviceni:fractal_example.png?300}}