comment up next how to end end

9. Seznamy II

  1. Metody 'split' a 'join'
  2. Matice
  3. Modul Numpy
  4. Testem podnícený rozvoj
  5. Náhodná čísla
  6. Náhodný výběr
  7. Seznam náhodných čísel
  8. Četnost
  9. Vytvoření úseků
  10. Matplotlib
  11. Glosář
  12. Cvičení

9.1 Metody 'split' a 'join'

Umíme z řetězce vytvořit seznam (list(arg)) a ze seznamu řetězec (str(arg)), dokonce to umíme udělat jedním tahem:

>>> str (list("Žabička"))
"['Ž', 'a', 'b', 'i', 'č', 'k', 'a']"

Chceme-li z rozsypaného čaje sestavit zase žabičku, musíme použít funkci join :

>>> frog = list("Žabička")
>>> frog
['Ž', 'a', 'b', 'i', 'č', 'k', 'a']
>>> "".join(frog)
'Žabička'
>>>

Funkce split rozloží řetězec na seznam slov:

>>> song = "The rain in Spain..."
>>> song.split()
['The', 'rain', 'in', 'Spain...']
>>> 

Vhodně vybraný argument, nazvaný oddělovač (separátor), může být použit jako hranice mezi oddělenými úseky. Následující příklad používá jako oddělovač řetězec ai:

>>> song.split(sep='ai')
['The r', 'n in Sp','n...']
Případně:
>>> "abrakadabra".split("a", 2)
['', 'br', 'kadabra'] 

Všimněte si, že zadaný separátor se ve vytvořeném seznamu neobjevuje.

Metoda join  i  split přijímá dva argumenty: seznam řetězců a hodnotu separátoru. Implicitní hodnotou separátoru u metody split je mezera: split().

>>> words = ['crunchy', 'raw', 'unboned', 'real', 'dead', 'frog']
>>> " ".join(words)
'crunchy raw unboned real dead frog'
>>> "**".join(words)
'crunchy**raw**unboned**real**dead**frog'

9.2 Matice

K vyjádření matic se často používají vnořené seznamy. Například, matice o rozměru 3x3 (3 řádky x 3 sloupce):

může být vyjádřena jako seznam s vnořenými seznamy stejné délky. Jednotlivé vnořené seznamy prezentují příslušné řádky matice:

>>> matrix = [[1, 2, 3], 
...           [4, 5, 6], 
...           [7, 8, 9]]

Tentýž zápis v úspornějším provedení:
>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

V maticovém počtu lze tyto vnořené seznamy označit jako řádkové matice, neboli vektory.

Řádek matice vybereme jako prvek vnějšího seznamu (indexy počínají nulou):

>>> matrix[1]
[4, 5, 6]

Položku určitého řádku označíme indexem řádku a indexem položky:

>>> matrix[1][1]
5

Práce s maticemi vyžaduje specifické znalosti maticového počtu. Na rozdíl od algebry v něm například obecně neplatí komutativní zákon: A*B != B*A; platí ale A+B == B+A.

Násobení matice A o velikosti m (řádků) x n (sloupců) maticí B o velikosti n (řádků) x p (sloupců) je možné v případě, že počet sloupců (n) matice A souhlasí s počtem řádků (n) matice B. Rozměr výsledné matice je m x p.

Pokud je tato podmínka splněna, lze prvek c(i,j) matice C = A*B určit jako algebraický součet součinů prvků z i-tého řádku matice A s prvky z i-tého sloupce matice B, jak je naznačeno v tomto schematu:

| 1 2 | * | 5 6 |     1*5 + 2*7 | 1*6 + 2*8     | 19 22 |
|     |   |     |  =  ----------|----------  =  |       |
| 3 4 |   | 7 8 |     3*5 + 4*7 | 5*6 + 4*8     | 43 50 |

Rozměr výsledné matice ab je tedy dán počtem řádků matice a ( m rows = len(a)) a počtem sloupců matice b (p cols = len(b[0])).

a = [[1, 2, 3], [4, 5, 6]]              # 2 řádky, 3 sloupce:   a(2,3)
b = [[7, 8], [9, 2], [3,1]]             # 3 řádky, 2 sloupce:   b(3,2)
ab = a * b = [[34, 15], [91], [48]]     # 2 řádky, 2 sloupce:  ab(2,2)

# ab(0,0)= 1*7 + 2*9 + 3*3 = 34   
# ab(1,1)= 4*8 + 5*2 + 6*1 = 48

Výpočet součinu matic lze provést trojím použitím idiomu for i in range(len(...)):

def matrix_mult (m1, m2):
    result = [[0 for row in range(len(m1))]     # maketa matice
                 for col in range(len(m2[0]))]
    for i in range(len(m1)):                    # rows in m1        
        for j in range(len(m2[0])):             # cols in m2  
            for k in range(len(m2)):            # rows in m2
               
                result[i][j] += m1[i][k] * m2[k][j] 
    return result
========= RESTART: F:\Codetest\HowTo\matice\Test.py ========
>>> a = [[1,2,3], [4,5,6]]
>>> b = [[7,8], [9,1], [2,3]]
>>> matrix_mult(a,b)
[[31, 19], [85, 55]]

Sevřenější tvar má toto řešení s komprehencí seznamu a s vestavěnými funkcemi sum a zip:

def matrix_mult (m1, m2):
    # interní pojmenování: m1_r, m2_c
    # *m2 je sběrný parametr (sloupec druhé matice)
    
    return [[sum(x * y
             for x, y in zip(m1_r, m2_c))
             for m2_c in zip(*m2)]
             for m1_r in m1]

Nejsnazší práci s maticemi poskytuje modul NumPy.


9.3 Modul Numpy

Aplikaci Numpy je nutné nejprve instalovat. Ve Windows s instalovaným programem Python s aplikací pip to je jednoduché:

C:\> pip install numpy

Knihovnu Numpy je nutné importovat do aktuálního pracovního prostředí Pythonu:

>>> import numpy as np

Numpy používá vlastní formát kolektoru, zvaný array neboli pole. Prvky tohoto kolektoru musí být homogenní - to jest, musí být stejného typu.
Datový typ pole může být jedno- (1D, vektor), dvě- (2D, matice), tři- (3D, tenzor) i více (nD) dimenzionální.
Dimenzím se v Numpy říká osy (axes). Velikost pole je vyjádřen atributem shape (tvar), což je entice celých čísel, která vyjadřují délky jednotivých os (dimenzí).

Array v Numpy vytvoříme ze seznamu příkazem np.array() :

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> a[1][2]
7
>>> a.shape
(2,4)                   # počet os = počtu prvků v entici

Uvedené pole má dvě osy (je to tedy matice) o délkách 2 a 4 položky. Pro přístup k vybranému prvku matice lze použít indexy (počínající nulou).

Součin dvou matic je v Numpy líbezně prostý:
>>> a = np.array([[1,2,3], [4,5,6]])
>>> b = np.array([[7,8], [9,1], [2,3]])
>>> c = np.matmul(a, b)
>>> c.shape
(2, 2)
>>> print(c)
[[31, 19],
 [85, 55]]

Protože solidnější popis práce s modulem Numpy přesahuje rámec tohoto tutoriálu, odkazuji případné zájemce na tuto webovou stránku.


9.4 Testem podnícený rozvoj

Testem podnícený rozvoj (Test-driven development - TDD) je způsob vyvíjení programu, při kterém se postupuje po malých, automaticky ověřovaných krocích.

Tento postup si ukážeme na sestavení funkce, která vytvoří matici m * n  (rows krát columns). Při tomto postupu použijeme doctesty, které jsme poznali již v odstavci 4.8.

Nejprve pro tuto funkci sestavime test a uložíme do souboru ch09_matrices.py:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]       
    """ 

if  __name__ == '__main__':
    import doctest 
    doctest.testmod()  

Provedení skriptu skončí neúspěchem:

********************************************************
File "matrices.py", line 3, in __main__.make_matrix
Failed example:
    make_matrix(3, 5)
Expected:
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Got nothing
********************************************************
1 items had failures:
   1 of   1 in __main__.make_matrix
***Test Failed*** 1 failures.

Test nebyl úspěšný proto, že tělo funkce obsahuje pouze dokumentační řetězec a žádný příkaz return, takže je vráceno Got nothing. Náš test nám naznačuje, že jsme chtěli vrátit matici se samými nulami ve třech řadách a pěti sloupcích.

Při použití TDD zpravidla píšeme ten nejjednodušší kód, který projde testem, v našem případě to je příkaz return:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]       
    """ 
    return [[0, 0, 0, 0, 0], [0, 0,0, 0, 0], [0, 0, 0, 0, 0]]

Při provedení tohoto skriptu rovněž neobstojíme i když dostáváme nominálně stejný ale formálně různý výsledek, lišící se v tom, že citované seznamy jsou různě dlouhé, ten druhý je delší o mezery mezi jednotlivými položkami - doctesty se někdy chovají podivně.

Doplníme tedy mezery do seznamu v dokumentačním řetězci a spuštěním skriptu si ověříme, že tentokrát je všechno v pořádku (no response)
Rozteče argumentů příkazu return upravovat nemusíme, příkaz si je upraví sám.

Uvědomíme si ale, že funkce make_matrix vrací stále týž výsledek, což zajisté není to, co jsme zamýšleli. Ověříme si to přidáním dalšího testu:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]      
    >>> make_matrix(4,2)
    [[0, 0], [0, 0], [0, 0], [0, 0]]
    """ 
    return [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

Vida:

*********************************************************
File "matrices.py", line 5, in __main__.make_matrix
Failed example:
    make_matrix(4, 2)
Expected:
    [[0, 0], [0, 0], [0, 0], [0, 0]]
Got:
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
*********************************************************
1 items had failures:
   2 of   2 in __main__.make_matrix
***Test Failed*** 1 failures.

Tato technika se nazývá testem podnícená, protože se snažíme upravovat kód tak, abychom prošli testem. Motivováni nezdařeným pokusem, můžeme nyní zkusit obecnější řešení:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]       
    >>> make_matrix(4,2)
    [[0, 0], [0, 0], [0, 0], [0, 0]]  
    """ 
    return [[0]* columns]* rows

Řešení formálně neuspokojí proceduru doctestu. Jevově jsou oba řádky stejné ale interně se budou zřejmě lišit počtem připojených (neviditelných) mezer. Řekněmež, že nám to nevadí.

Alternativní řešení téže úlohy má tuto skladbu:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]       
    >>> make_matrix(4,2)
    [[0, 0], [0, 0], [0, 0], [0, 0]]
    """ 
    matrix = []
    for row  in range(rows):
        matrix += [[0]* columns]
    return matrix

Použití TDD nám při našem programátorském snažení přináší několik výhod:

Funkci make_matrix(r,c) můžeme použít v cvičení 9.11.2 pro vytvoření výchozí (nulové) matice při sčítání (odčítání) matic:

def add_matrix (m1, m2):
   mx = make_matrix(len(m1), len(m1[0]))

9.5 Náhodná čísla

Většina počítačových programů provádí při každém spuštění totéž, takže říkáme, že jsou deterministické.

Determinismus je obvykle dobrá věc, protože můžeme předpokládat, že stejný výpočet povede ke stejnému výsledku. U některých aplikacích si však přejeme, aby počítač byl nepředvídatelný. Hry jsou zřejmým příkladem, ale těch příkladů může být více.

Ukazuje se, že napsat program se skutečně nepředvídatelným chováním není snadné, ale jsou způsoby, kterak jej učinit alespoň zdánlivě nedeterministickým. Jedním ze způsobů je použití náhodných čísel. Python poskytuje vestavěnou funkci, která generuje pseudonáhodná čísla, která nejsou náhodná v přísně matematickém smyslu, ale pro naše účely postačí.

Modul random obsahuje funkci zvanou random, která vrací desetinné číslo v rozsahu [0.0, 1.0). Pokaždé, když voláme funkci random, dostaneme jednu "náhodnou" hodnotu mezi nulou včetně a méně než jedničkou. Více náhodných hodnot můžeme vygenerovat pomocí funkce se smyčkou:

import random
def rand(high):   # high is an integer
    for i in range(high): 
        x = random.random()
    print(x*high)

Náhodná čísla mezi nulou a zadanou mezí high, získáme násobením generovaných čísel x hodnotou high.

9.6 Náhodný výběr

Podobným problémem jako vytvoření náhodného čísla je provedení náhodného výběru. Ten lze provést pomocí funkce choice z modulu random:

>>> from random import choice
>>> fokus = ["asi", "jo", ("a"*3),  [12, sum], "pět"]
>>> choice(fokus)
[12, < built-in function sum>]
>>> choice(fokus)
'jo'

Jak vidno, elementy výběrového seznamu (nebo entice či setu) mohou být hodnoty různého typu.

9.7 Seznam náhodných čísel

V prvním kroku vygenerujeme seznam náhodných čísel funkcí randomList. Funkce přijme jako argument celé číslo n a vrátí seznam náhodných čísel. Začíná se seznamem s n nulami. Při každém cyklu smyčky se jedna z položek nahradí náhodným číslem. Výstupní hodnotou je odkaz na dokončený seznam.
Parametr n je požadovaný počet náhodných čísel v intervalu od nuly do jedné.

def randomList(n):    
    s = [0] * n                    # počáteční seznam s nulami
    for i in range(n):             # náhrada nul za náhodné číslo
        s[i] = random.random()
    return s                       # seznam 'n' náhodných čísel

Pomocí této funkce vytvoříme seznam se šesti položkami:

>>> randomList(6)
[0.5199466739572948, 0.452751456638563,
 0.41454566096564627,
 0.7953941766158702, 0.3872848065377861,
 0.9080198286105817]  

Předpokládá se, že náhodná čísla, generovaná systémovou funkcí random jsou rovnoměrně rozdělena, to znamená, že výskyt každé hodnoty má (limitně) stejnou pravděpodobnost.

Rozdělíme-li celý interval možných náhodných hodnot do stejně velikých úseků, a spočítáme-li výskyt náhodných hodnot v jednotlivých úsecích, měl by tento výskyt být všude přibližně stejný.

Tento předpoklad si můžeme ověřit napsáním programu, který rozdělí hodnoty do úseků a určí počet výskytů v jednotlivých úsecích, neboli jejich četnost.

9.8 Vytvoření úseků

Označíme-li počet úseků jménem numBuckets a vyjdeme ze skutečnosti, že rozpětí hodnot náhodných čísel má interval 0.0 až 1.0, potom velikost jednoho úseku (bucketWidth) určíme jako podíl 1.0 / numBuckets.

K výpočtu mezí jednotlivých úseků použijeme smyčku. Proměnná i smyčky for počítá s rozpětím nula až (numBuckets-1):

bucketWidth = 1.0 / numBuckets
for i in range(numBuckets):
    low = i * bucketWidth
    high = low + bucketWidth
    print(low, "to", high)

Při výpočtu dolní meze jednotlivého úseku (kyblíku) násobíme proměnnou smyčky podílem na jeden kyblík. Horní mez je o bucketWidth vyšší.

Pro numBuckets = 8 například, jsou rozsahy výstupů následující:

0.0 to 0.125
0.125 to 0.25
0.25 to 0.375
0.375 to 0.5
0.5 to 0.625
0.625 to 0.75
0.75 to 0.875
0.875 to 1.0

9.9 Četnost

Chceme procházet vygenerovaným seznamem náhodných čísel a určovat, kolik náhodných čísel (v intervalu od 0.0 do 1.0) zapadne do některého ze stanovených úseků (buckets). Řešení této úlohy si ukážeme ve dvou variantách:

Opakované traverzování seznamem

Vyjedeme z konstrukce ve cvičení 6.19.2:

count = 0
for char in fruit:
    if char == 'a':
        count = count + 1
print(count)

V prvním kroku nahradíme jména char, fruit označením num a list.

V druhém kroku změníme předmět prověřování. Nezajímá nás výskyt písmen ale chceme vědět, zda se hodnota proměnné num (aktuálně prověřované náhodné číslo) nalézá mezi příslušnými hodnotami low a high.

count = 0
for num in list:
    if low < num < high:
        count = count + 1
print(count)

V posledním kroku zapouzdříme upravený kód do funkce zvané inBucket. Jejími parametry bude seznam všech náhodných čísel list a meze úseků low a high.

def inBucket(list, low, high):
    count = 0
    for num in list:
        if low < num < high:
            count = count + 1
    return count

Právě odvozenou funkci použijeme jako pomocnou funkci v dalším výpočtu.

Pro záznam výskytů náhodných čísel v jednotlivých úsecích vytvoříme seznam výskyty - coby vícečetné počítadlo:

numBuckets = 8                       # počet úseků 
výskyty = [0] * numBuckets           # počáteční seznam s nulami
bucketWidth = 1.0 / numBuckets       # číselný rozsah jednoho intervalu
list = randomList(n)                 # seznam - viz odst. 9.7
for i in range(numBuckets):          # pro každý kyblík určit:
    low = i * bucketWidth            # dolní mez intervalu
    high = low + bucketWidth         # horní mez intervalu
    výskyty[i] = inBucket(list, low, high)    # viz **
print(výskyty)     # ** náhrada nul počtem příslušných náhodných čísel

K hladkému provedení výše uvedeného skriptu musí mít interpret Pythonu k disposici importovaný modul random a definice funcí randomList a inBucket.
Nejlépe to zajistíme tak, že založíme soubor buckets.py, do něhož vše potřebné vložíme (včetně  import random  na začátku).

Z výše uvedeného skriptu vytvoříme funkci buckets_a(n,b), když vypustíme řádek numBuckets = 8 a provedeme patřičné odsazení následujících řádků. V těle funkce nahradíme název numBuckets parametrem b.
Soubor uložíme a když v interaktivní konzole IDLE provedeme volání count(1000, 8), získáme takovýto seznam s četnostmi výskytů:

[138, 124, 128, 118, 130, 117, 114, 131]

Tato čísla jsou docela blízká číslu 0.125*1000=125 jak jsme si přáli. Generátor pseudonáhodných čísel nám tedy funguje.

Jednorázové řešení

I když nám tento program chodí, mohl by chodit ještě lépe. Pokaždé, když volá funkci inBucket, prochází opakovaně celým seznamem. S větším počtem kyblíků jde o značný počet cyklů.

Lepší by bylo projít seznamem jen jednou a pro každou hodnotu náhodného čísla určit rovnou index úseku (neboli index položky seznamu výskyty), do kterého náhodné číslo i spadá.

Idea výhodnějšího řešení spočívá v tom, že náhodné číslo i násobíme počtem úseků b. Protože náhodná čísla jsou v rozpětí 0.0 až 1.0, je součin i*b v rozpětí 0.0 až b. Zaokrouhlíme-li každý součin na celé číslo ( int (i * b) ), získáme index položky seznamu výskyty, kam posuzovaná hodnota patří - této položce zvětšíme stav počítadla.

Vytvořenou funkci buckets_b(n,b) přidáme do souboru buckets.py.

def buckets_b(n,b):
    výskyty = [0] * b           # akumulátor
    list = randomList(n)        # volání funkce
    for i in list:
        index = int(i * b)      # zaokrouhlení dolů          
        výskyty[index] = výskyty[index] + 1
    print(výskyty)

Poznámka: Seznamuu výskytů se říká frekvenční tabulka, jejímž grafickým zobrazením je sloupcový graf, zvaný histogram.


9.12   Matplotlib

Pouze pro zvídavé

V odstavcích 9.8 a 9.9 je popisováno, jak lze rozdělit pole náhodných čísel [0,1) na intervaly (bucketWidth) a určit počet výskytů náhodných čísel v daném intervalu(výskyty).

Tento soubor čísel (frekvenční tabulku) je možné graficky znázornit histogramem, vytvořeným pomocí knihovny Matplotlib.   Uwaga - je to docela velký macek!

python -m pip install -U matplotlib

Podrobný popis práce s tímto nástrojem lze nalézt například zde.


9.13   Glosář

testem podnícený rozvoj (test-driven development, TDD)
Postup při programování, při kterém se dospěje k žádanému cíli přes řadu malých, postupných kroků, jež jsou ověřovány jednotkovými testy.
blok (block)
Skupina po sobě jsoucích příkazů se stejným odsazením.
histogram
Seznam celých čísel, udávajících četnost výskytu nějaké skutečnosti.
vnoření (nesting)
Jedna programová struktura vnořená do druhé, jako je podmíněný příkaz ve větvi jiného podmíněného příkazu.

9.14   Cvičení

  1. Pro následující doctesty vytvořte záhlaví a těla funkcí, které přidají řádek, případně sloupec do zadané matice. Můžete vyzkoušet postup TDD z odstavce 9.3:
    def add_row (matrix): 
        """
        >>> m = [[0,0], [0,0]] 
        >>> add_row(m)    
        [[0, 0], [0, 0], [0, 0]]
        >>> n = [[3, 2, 5], [1, 4, 7]]
        >>> add_row(n)
        [[3,2,5], [1,4,7], [0,0,0]]
        >>> n
        [[3,2,5], [1,4,7]]
        """
    def add_column (matrix): 
        """
        >>> m = [[0,0], [0,0]] 
        >>> add_column(m)    
        [[0,0,0], [0,0,0]]
        >>> n = [[3,2], [5,1], [4,7]]
        >>> add_column(n)
        [[3,2,0], [5,1,0], [4,7,0]]
        >>> n
        [[3,2], [5,1], [4,7]]
        """
    

    Všimněte si, že poslední doctesty v každé funkci ověřují, že add_row a add_column jsou funkce čisté.

  2. Napište funkci add_matrices(m1, m2), která vrátí novou matici, jež je součtem matic m1 a m2. Sečíst dvě matice znamená sečíst hodnoty odpovídajících členů. Můžete předpokládat, že matice m1 a m2 mají stejnou velikost.
    def add_matrices (m1, m2): 
        """
        >>> a = [[1,2], [3,4]]
        >>> b = [[2,2], [2,2]] 
        >>> add_matrices(a, b)    
        [[3,4], [5,6]]
        >>> c = [[8,2], [3,4], [5,7]]
        >>> d = [[3,2], [9,2], [10,12]]
        >>> add_matrices(c, d)
        [[11,4], [12,6], [15,19]]
        >>> c
        [[8,2], [3,4], [5,7]]
        >>> d
        [[3,2], [9,2], [10,12]]
        """
    
    Poslední dva doctesty opět potvrzují, že add_matrices je čistá funkce.
  3. Napište funkci scalar_mult(n, m), která násobí matici m skalárem n. Doplňte tělo funkce a ujistěte se, že projde doctesty.
    def scalar_mult (n, m): 
        """
        >>> a = [[1,2], [3,4]]
        >>> scalar_mult(3, a)    
        [[3, 6], [9, 12]]
        >>> b = [[3,5,7], [1,1,1], [0,2,0], [2,2,3]]
        >>> scalar_mult(10, b)
        [[30, 50, 70], [10, 10, 10], [0, 20, 0], [20, 20, 30]]
        >>> b
        [[3, 5, 7], [1, 1, 1], [0, 2, 0], [2, 2, 3]] 
        """
    
  4. Na základě získané zkušenosti zkuste násobit matici maticí.
    def matrix_mult (m1, m2): 
        """
        >>> matrix_mult([[1,2], [3,4]], [[5,6], [7,8]])
        [[19, 22], [43, 50]]
        >>> matrix_mult([[1,2,3], [4,5,6]], [[7,8], [9,1], [2,3]])
        [[31, 19], [85, 55]]
        >>> matrix_mult([[7,8], [9,1], [2,3]], [[1,2,3], [4,5,6]])
        [[39, 54, 69], [13, 23, 33], [14, 19, 24]]
        """
    
  5. Početní operace s maticemi v příkladech 1 až 4 proveďte i prostřednictvím aplikace Numpy.

  6. Pro lepší porozumění booleovským výrazům jsou dobré pravdivostní tabulky. Dva booleovské výrazy jsou logicky rovnocenné tehdy a jen tehdy, mají-li stejné pravdivostní tabulky.
    Následující skript vytiskne pravdivostní tabulku pro libovolný booleovský výraz s proměnnou p a q.
    expression = input("Zadej booleovský výraz \ 
                        pro 'p' a 'q' : " )
    print(" p    q    %s"   % expression)
    delka = len(" p    q    %s"   % expression)
    print(delka* "=")
    
    for p in True, False:
        for q in True, False:
            print("%-7s %-7s %-7s" % (p, q, eval(expression)))
    
    Tento skript použijeme pro osvojení booleovských výrazů. Uložte program do souboru bool_table.py, importujte jej do konzoly interpreta a zadejte 'p or q'. Měl byste dostat následující výstup:
      p       q      p or q
    ------------------------
    True    True      True
    True    False     True
    False   True      True
    False   False     False
    
  7. Nyní, když víme že kód pracuje, zabalíme jej pro lepší použití do funkce (a uložíme do truth_table.py):
    def truth_table(expression): 
        print(" p    q    %s"   % expression)
        delka = len(" p    q    %s"   % expression)
        print(delka* "=")
    
        for p in True, False:
            for q in True, False:
                print("%-7s %-7s %-7s" % (p, q, eval(expression)))
    
    Funkci zavoláme z konzoly IDLE:
    >>> truth_table ("p or q")
     
      p       q      p or q
    ------------------------
    True    True      True
    True    False     True
    False   True      True
    False   False     False
    
    Vyzkoušejte si fci truth_table na následujících booleovských výrazech a zapište si pravdivostní tabulky:
    1.   not (p or q)
    2.   p and q
    3.   not (p and q)
    4.   not(p) or not(q)
    5.   not(p) and not(q)

    Které výrazy jsou logicky eqvivalentní?

  8. Napište fci is_divisible(num,f), která přijme celá čísla jako argument a podle situace vytiskne "Toto číslo je dělitelné číslem f" nebo "Toto číslo neni dělitelné číslem f".
    Uložte ji do souboru isDivisible.py a řešte v IDLE. Výstup může vypadat takto:

    >>> is_divisible(20,4)
    Toto číslo je dělitelné číslem 4
    >>> is_divisible(21,8)
    Toto číslo neni dělitelné číslem 8
    

    Při řešení použijete podmínky if ... :, else: a vyberete si jeden z existujících způsobů dělení: normální a/b, celočíselné a//b a dělení se zbytkem (modulo) a%b.

comment up next how to end end