====== 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}}