Preskočiť na obsah
coden

Grafy a stromy: štruktúra, na ktorej stojí hľadanie aj neurónové siete

Vrcholy a hrany, stupne, matica susednosti, cesty a komponenty, BFS a Dijkstra, stromy, minimálna kostra a výpočtový graf neurónu — všetko na jednom grafe so siedmimi mestami.

14 minút Matěj Žalmánek 2026-10-15

Séria Základy AI Diel 8 z 52
  1. Mapa umelej inteligencie: čo je čo a ako to do seba zapadá
  2. Stručná história umelej inteligencie: od Turinga po jazykové modely
  3. Dáta, model, tréning, inferencia: základné pojmy na jednom príklade
  4. Ako čítať matematický zápis: symboly, indexy, sumy a kvantifikátory
  5. Množiny a relácie: stavebnica, z ktorej sa skladajú definície v AI
  6. Funkcie a zobrazenia: prečo je každý model v AI funkcia
  7. Logika a dôkazy: pravidlá, podľa ktorých sa v AI uvažuje
  8. Grafy a stromy: štruktúra, na ktorej stojí hľadanie aj neurónové siete
  9. Lineárna algebra pre strojové učenie: vektory, matice a prečo AI hlavne násobí
  10. Derivácie, gradient a reťazové pravidlo: ako model zistí, ktorým smerom sa učiť
  11. Gradientný zostup: ako sa model učí
  12. Čo je pravdepodobnosť: od hodu kockou ku Kolmogorovovým axiómam
  13. Podmienená pravdepodobnosť a Bayesova veta: ako zmeniť odhad, keď sa dozviete niečo nové
  14. Náhodná premenná a distribučná funkcia: jedna funkcia, ktorá o rozdelení povie všetko
  15. Funkcia hustoty a pravdepodobnostná funkcia: prečo má spojitá premenná v bode pravdepodobnosť nula
  16. Stredná hodnota, rozptyl a kovariancia: kde rozdelenie leží, aké je široké a čo s čím súvisí
  17. Prehľad pravdepodobnostných rozdelení: Bernoulliho, binomické, Poissonovo, rovnomerné, normálne a exponenciálne
  18. Zákon veľkých čísel a centrálna limitná veta: prečo sa priemery správajú tak predvídateľne
  19. Štatistika a odhady parametrov: maximálna vierohodnosť, MAP a intervaly spoľahlivosti
  20. Teória informácie: entropia, krížová entropia a KL divergencia — odkiaľ sa berú stratové funkcie
  21. Prehľadávanie stavového priestoru: BFS, DFS, UCS a A* s animáciami
  22. Hry a protivník: minimax, alfa-beta orezávanie a Monte Carlo tree search
  23. Splňovanie obmedzujúcich podmienok: backtracking, propagácia obmedzení a AC-3 na sudoku a mape krajov
  24. Logika a znalostné systémy: dopredné a spätné reťazenie, rezolúcia a expertné systémy
  25. Plánovanie: STRIPS, svet kociek, heuristiky z relaxácie a plánovanie v AI agentoch
  26. Lokálne hľadanie a simulované žíhanie: obchodný cestujúci cez krajské mestá
  27. Genetické algoritmy: populácia, kríženie, mutácia a výber na batohu na výlet
  28. Evolučné stratégie a genetické programovanie: od pravidla jednej pätiny po Keplerov zákon
  29. Optimalizácia mravčou kolóniou: ako feromónová stopa nájde krátku cestu
  30. Optimalizácia rojom častíc: zotrvačnosť, vlastná skúsenosť a skúsenosť roja
  31. Neuroevolúcia: evolúcia váh aj tvaru neurónových sietí a algoritmus NEAT
  32. Fuzzy množiny a funkcie príslušnosti: ako zapísať „trochu teplo“
  33. Fuzzy logika a pravdepodobnosť: prečo „trochu teplo“ neznamená „pravdepodobne teplo“
  34. Fuzzy logika: t-normy, implikácie a pravidlá AK–TAK
  35. Fuzzy riadenie: Mamdani a Sugeno od ventilátora po kyvadlo na vozíku
  36. Fuzzy zhlukovanie: algoritmus fuzzy c-means a body medzi zhlukmi
  37. Neuro-fuzzy systémy (ANFIS): fuzzy pravidlá, ktoré sa učia z dát
  38. Markovove reťazce: prechodová matica, stacionárne rozdelenie a PageRank
  39. Skryté Markovove modely: Viterbiho algoritmus a nepoctivé kasíno
  40. Bayesovské siete: prečo je tráva mokrá a čo z toho vyplýva pre postrekovač
  41. Kalmanov filter: ako z nepresných meraní odhadnúť, kde auto je a ako rýchlo ide
  42. Druhy strojového učenia: s učiteľom, bez učiteľa, s čiastočným učiteľom a ďalšie
  43. Prompty, kontext a RAG: ako modelu dať správne informácie
  44. Variačné autoenkodéry (VAE): nové obrázky zo spojitého latentného priestoru
  45. Generatívne adversariálne siete (GAN): falšovateľ proti detektívovi
  46. Difúzne modely: ako sa z čistého šumu stane obrázok
  47. Markovove rozhodovacie procesy: stavy, akcie, odmeny a Bellmanove rovnice
  48. Q-learning a DQN: učenie hodnoty akcií od tabuľky po neurónovú sieť
  49. Policy gradient a PPO: učenie priamo stratégie
  50. Ako funguje AI agent: jazykový model v slučke s nástrojmi
  51. Programovanie s AI agentmi: zadanie, testy a kontrola
  52. Vyhodnocovanie a bezpečnosť AI systémov: ako merať a ako strážiť

Celá osnova série Hotovo: 52 z 83 tém

Čo si odnesiete
  • Čo je graf, stupeň a súvislosť — a ako graf uložiť do počítača.
  • Prečo cesta s najmenej hranami nemusí byť najkratšia a ako to riešia BFS a Dijkstra.
  • Čo je strom, minimálna kostra a prečo je neurónová sieť acyklický graf počítaný tam a späť.

Čo sa hodí vedieť vopred: Množiny a relácie: stavebnica, z ktorej sa skladajú definície v AI

Mapa miest a ciest, sieť priateľov, stavový priestor hry, neurónová sieť aj výpočet, v ktorom sa počíta gradient — to všetko je graf: body spojené čiarami. Grafy sú najuniverzálnejšia štruktúra v informatike a v umelej inteligencii ich stretnete na každom kroku. Stromy sú ich najjednoduchší a najužitočnejší špeciálny prípad.

Celý diel postavíme na jednom grafe so siedmimi mestami A až G a cestami s dĺžkou. Postupne na ňom ukážeme stupne, ako graf uložiť, najkratšie cesty aj minimálnu kostru.

1. Čo je graf

Definícia — graf

Nech V je konečná neprázdna množina; jej prvky nazývame vrcholy.

  1. Neorientovaný graf je dvojica G = (V, E), kde E ⊆ {{u, v} : u, v ∈ V, u ≠ v}; prvky E sú hrany — dvojprvkové podmnožiny V. Vrcholy u, v sú susedné práve vtedy, keď {u, v} ∈ E.
  2. Orientovaný graf je dvojica G = (V, E), kde E ⊆ V × V; hrana je usporiadaná dvojica (u, v) — šípka z u do v. Orientovaný graf je teda relácia na V (pozri diel Množiny a relácie).
  3. Ohodnotený graf je trojica G = (V, E, w), kde (V, E) je graf podľa 1. alebo 2. a w : E → ℝ je funkcia, ktorá každej hrane e ∈ E priradí váhu w(e) (dĺžku, cenu, čas).

Ak nie je povedané inak, je graf v tomto diele neorientovaný.

Laicky povedané

Vrcholy sú „veci“, hrany „vzťahy“ medzi nimi. Pri neorientovanom grafe vzťah platí oboma smermi (cesta), pri orientovanom len jedným (jednosmerka, „sleduje na sociálnej sieti“). Váha je číslo na hrane — koľko kilometrov, koľko eur, koľko minút.

4 2 5 3 7 6 2 4 8 3 5 6 A B C D E F G
Sedem miest a dvanásť ciest; čísla sú dĺžky

2. Stupeň vrcholu

Definícia — stupeň a princíp párnosti

Nech G = (V, E) je neorientovaný graf a v ∈ V. Stupeň vrcholu v je počet hrán, ktoré ho obsahujú (ktoré z neho vychádzajú):

deg(v) = |{e ∈ E : v ∈ e}|.

Veta (o podávaní rúk). Nech G = (V, E) je neorientovaný graf. Potom

∑v ∈ V deg(v) = 2 |E|.

Špeciálne je súčet stupňov v každom neorientovanom grafe párne číslo.

Laicky povedané

Každá hrana má dva konce, takže keď sčítate, koľko hrán vychádza z každého vrcholu, započítate každú hranu presne dvakrát. Preto je súčet stupňov vždy párny.

4 2 5 3 7 6 2 4 8 3 5 6 A 2 B 4 C 4 D 4 E 4 F 4 G 2
Stupeň každého vrcholu

Súčet stupňov je 2 + 4 + 4 + 4 + 4 + 4 + 2 = 24 a hrán je 12, teda 24 = 2 · 12 — presne podľa vety (farby podľa vzorca nižšie). Stupeň má v praxi význam: v sociálnej sieti je to počet priateľov, na webe počet odkazov, a vrcholy s veľkým stupňom bývajú tie najdôležitejšie.

∑v ∈ V deg(v) = 2 · |E|

∑v ∈ V
prejdeme všetky vrcholy — počítame hrany „z pohľadu vrcholov“
deg(v)
pri každom vrchole konce hrán, ktoré sa ho dotýkajú
2
každá hrana {u, v} má dva konce, takže ju súčet stretne dvakrát — raz pri u, raz pri v
|E|
počet hrán — to isté počítanie „z pohľadu hrán“
Na grafe miest: 24 = 2 · 12. Dôkaz je dvojité spočítanie tej istej veci — dvojíc (vrchol, hrana, ktorá ho obsahuje).
Veta — vrcholov nepárneho stupňa je párny počet

Veta. Nech G = (V, E) je neorientovaný graf a L = {v ∈ V : deg(v) je nepárne} množina jeho vrcholov nepárneho stupňa. Potom |L| je párne číslo.

Dôkaz. Rozdeľme súčet stupňov na vrcholy párneho a nepárneho stupňa: ∑v ∈ V deg(v) = ∑v ∈ V ∖ L deg(v) + ∑v ∈ L deg(v). Ľavá strana je podľa vety o podávaní rúk 2|E|, párna; prvý súčet napravo je súčet párnych čísel, teda párny. Druhý teda musí byť tiež párny — a súčet |L| nepárnych čísel je párny práve vtedy, keď |L| je párne. ∎

Preto nejde nakresliť graf s piatimi vrcholmi, z ktorých každý má stupeň 3: súčet 15 by bol nepárny.

3. Ako graf uložiť do počítača

Počítač nevidí obrázok, potrebuje čísla. Zvyčajné sú dve podoby:

  • Matica susednosti — tabuľka |V| × |V|, v bunke (u, v) je váha hrany, alebo 0. Rýchle „je tu hrana?“, ale pamäť rastie ako |V|2.
  • Zoznam susedov — pri každom vrchole zoznam jeho susedov. Pamäť rastie len ako |V| + |E|, čo je pre riedke grafy (sociálna sieť, mapa) obrovský rozdiel.
Definícia — matica susednosti a zoznam susedov

Nech G = (V, E, w) je ohodnotený neorientovaný graf s nenulovými váhami (w(e) ≠ 0 pre všetky e ∈ E) a n = |V| vrcholmi, ktoré očíslujeme: V = {v1, …, vn}. Matica susednosti grafu G je štvorcová matica A ∈ ℝn×n s prvkami (pre i, j = 1, …, n)

Aij = w({vi, vj}), ak {vi, vj} ∈ E;   inak Aij = 0.

Nenulové váhy sú potrebné, aby sa hrana dala odlíšiť od chýbajúcej hrany. Pri neohodnotenom grafe sa namiesto váhy píše 1. Keďže {vi, vj} = {vj, vi}, má neorientovaný graf Aij = Aji, teda A = AT.

Pre v ∈ V označme N(v) množinu jeho susedov:

N(v) = {u ∈ V : {u, v} ∈ E}.

Zoznam susedov je zobrazenie, ktoré každému vrcholu v ∈ V priradí množinu N(v), pri ohodnotenom grafe aj s váhami: {(u, w({u, v})) : u ∈ N(v)}. Platí |N(v)| = deg(v).

ABCDEFG A 4 2 B 4 5 3 7 C 2 5 6 8 D 3 6 2 4 E 7 2 6 3 F 8 4 6 5 G 3 5
Matica susednosti grafu miest — symetrická, pretože cesty vedú oboma smermi
Príklad — koľko miesta zaberie graf miest a cestná sieť

Graf miest: matica má 7 · 7 = 49 buniek, z toho len 24 nenulových (každá cesta dvakrát, nad aj pod uhlopriečkou). Zoznamy susedov majú spolu ∑ deg(v) = 2 · 12 = 24 položiek (farby podľa vety o podávaní rúk vyššie). Riadok B matice je (4, 0, 5, 3, 7, 0, 0) — štyri nenulové čísla, pretože deg(B) = 4.

Cestná sieť s miliónom križovatiek, z každej v priemere 3 cesty: |E| = 106 · 3/2 = 1,5 · 106. Matica má (106)2 = 1012 buniek, zoznamy len 2 · 1,5 · 106 = 3 · 106 položiek — vyše tristotisíckrát menej.

Matica je symetrická podľa uhlopriečky — to je znak neorientovaného grafu. V AI sa matica susednosti používa pri grafových neurónových sieťach, ktoré sa učia priamo na grafoch (molekuly, sociálne siete, cestná sieť).

4. Cesty, cykly a súvislosť

Definícia — cesta, cyklus, súvislosť

Nech G = (V, E) je neorientovaný graf a u, v ∈ V.

  1. Cesta z u do v je postupnosť vrcholov (v0, v1, …, vk), k ≥ 0, taká, že v0 = u,   vk = v,   vi ≠ vj pre i ≠ j,   {vi−1, vi} ∈ E pre i = 1, …, k. Jej dĺžka je k (počet hrán); v ohodnotenom grafe (V, E, w) je to súčet váh ∑i=1k w({vi−1, vi}).
  2. Cyklus je postupnosť vrcholov (v0, v1, …, vk) s k ≥ 3, v ktorej sú v0, …, vk−1 navzájom rôzne, vk = v0 a {vi−1, vi} ∈ E pre i = 1, …, k — cesta, ktorá sa po aspoň troch hranách vráti do východiskového vrcholu.
  3. G je súvislý práve vtedy, keď ∀u, v ∈ V existuje cesta z u do v.
  4. Definujme reláciu ∼ na V: u ∼ v práve vtedy, keď existuje cesta z u do v. Je to ekvivalencia (reflexívna vďaka ceste dĺžky 0, symetrická obrátením cesty, tranzitívna, pretože zo spojenia dvoch ciest sa dá vybrať cesta). Jej triedy ekvivalencie sú komponenty súvislosti G; tvoria teda rozklad V (pozri diel Množiny a relácie).

Graf je teda súvislý práve vtedy, keď má jediný komponent súvislosti.

Laicky povedané

Cesta je trasa, ktorá nikde nejde dvakrát cez to isté miesto. Cyklus je okruh. Súvislý graf je taký, kde sa dá dostať odkiaľkoľvek kamkoľvek; inak sa rozpadne na „ostrovy“ — komponenty.

1 2 3 4 5 6 7 8
Graf s tromi komponentmi súvislosti

5. Najkratšie cesty

Úloha „ako sa čo najrýchlejšie dostať z A do G“ je hľadanie najkratšej cesty — a to je presne to, čo robili algoritmy z dielu o prehľadávaní stavového priestoru. Záleží však na tom, čo meriame.

Definícia — vzdialenosť v grafe

Nech G = (V, E, w) je ohodnotený neorientovaný graf s nezápornými váhami, w : E → [0, ∞), a u, v ∈ V. Pre cestu π označme w(π) = ∑e ∈ π w(e) jej dĺžku (súčet váh jej hrán). Vzdialenosť vrcholov u a v je

d(u, v) = min {w(π) : π je cesta z u do v},   ak existuje aspoň jedna taká cesta; inak d(u, v) = ∞.

Minimum existuje, pretože ciest v konečnom grafe je konečne veľa. Pre neohodnotený graf berieme w(e) = 1 pre všetky e ∈ E; vzdialenosť je potom najmenší počet hrán cesty z u do v.

d(u, v) = minπ : u → v ∑e ∈ π w(e)

d(u, v)
jedno číslo pre dvojicu vrcholov — to, čo algoritmus hľadá
minπ
ciest z u do v býva veľa; nás zaujíma tá najlepšia, preto minimum cez všetky
∑e ∈ π
dĺžka cesty sa skladá z hrán, ktoré na nej ležia — sčítame ich
w(e)
váha jednej hrany (kilometre); pri BFS je každá rovná 1 a súčet potom počíta hrany
Pre A a G: cesta A–B–E–G má súčet 4 + 7 + 3 = 14, cesta A–B–D–E–G 4 + 3 + 2 + 3 = 12 — a menšia už žiadna nie je, teda d(A, G) = 12.

Keď nás zaujíma počet hrán, stačí prehľadávanie do šírky: najprv susedia A, potom ich susedia… Číslo nad vrcholom je vzdialenosť od A v hranách:

4 2 5 3 7 6 2 4 8 3 5 6 A 0 B 1 C 1 D 2 E 2 F 2 G 3
Prehľadávanie do šírky z A: vrstvy podľa počtu hrán
from collections import deque

def bfs(sousede, start):
    d = {start: 0}
    fronta = deque([start])
    while fronta:
        u = fronta.popleft()              # najprv ten, kto prišiel najskôr
        for v in sousede[u]:
            if v not in d:                # prvá návšteva = najmenší počet hrán
                d[v] = d[u] + 1
                fronta.append(v)
    return d

Z A tak dostaneme vrstvy: B, C vo vzdialenosti 1; D, E, F vo vzdialenosti 2; G vo vzdialenosti 3. Každý vrchol sa z frontu vyberie raz a každá hrana sa prezrie dvakrát (z oboch koncov), takže BFS beží v čase úmernom |V| + |E|.

Do G vedú tri hrany (napríklad A–B–E–G). Keď ale počítame dĺžku ciest, potrebujeme Dijkstrov algoritmus — vždy pokračuje z najbližšieho doteraz neuzavretého vrcholu. Číslo nad vrcholom je teraz najkratšia vzdialenosť v kilometroch a zvýraznená je najkratšia cesta do G:

4 2 5 3 7 6 2 4 8 3 5 6 A 0 B 4 C 2 D 7 E 9 F 10 G 12
Dijkstrov algoritmus z A: najkratšia cesta do G má dĺžku 12

Najkratšia cesta A–B–D–E–G má štyri hrany, teda viac než trojhranová cesta z BFS, ale dĺžku len 12. Cesta A–B–E–G by merala 4 + 7 + 3 = 14 (farby podľa vzorca vzdialenosti vyššie). Menej krokov neznamená kratšiu cestu — presne tento rozdiel medzi BFS a UCS sme videli na bludisku s blatom.

Dijkstrov algoritmus krok za krokom

Algoritmus si pri každom vrchole drží odhad d[v] — dĺžku najlepšej doteraz nájdenej cesty. Na začiatku je d[A] = 0 a všade inde ∞. Potom opakuje: vezmi neuzavretý vrchol s najmenším odhadom, uzavri ho a skús cezeň zlepšiť odhady susedov. Tomuto zlepšeniu sa hovorí relaxácia hrany:

d[v] ← min( d[v], d[u] + w(u, v) )

d[v]
doterajšia najlepšia známa dĺžka do v; zostane, ak nová cesta nie je lepšia — odhad sa nikdy nezhorší
d[u]
dĺžka do práve uzavretého u — tá je už určite najkratšia, takže na nej môžeme stavať
w(u, v)
posledný úsek z u do v; spolu s d[u] je to dĺžka kandidátskej cesty „cez u“
Odhad je vždy dĺžka nejakej skutočnej cesty, takže zhora ohraničuje vzdialenosť; relaxácia ho len sťahuje nadol.
import heapq

def dijkstra(sousede, start):
    d = {v: float("inf") for v in sousede}
    d[start] = 0
    hotove = set()
    halda = [(0, start)]
    while halda:
        du, u = heapq.heappop(halda)          # neuzavretý vrchol s najmenším d
        if u in hotove:
            continue
        hotove.add(u)                         # d[u] je teraz definitívne
        for v, w in sousede[u]:
            if du + w < d[v]:                 # relaxácia hrany (u, v)
                d[v] = du + w
                heapq.heappush(halda, (d[v], v))
    return d

Na grafe miest z A vyzerá priebeh takto. Riadok ukazuje odhady po uzavretí vrcholu v prvom stĺpci; tučne sú vzdialenosti, ktoré sú už definitívne:

krokuzavretýd[A]d[B]d[C]d[D]d[E]d[F]d[G]
1A042∞∞∞∞
2C0428∞10∞
3B04271110∞
4D0427910∞
5E042791012
6F042791012
7G042791012

Farby zodpovedajú členom relaxácie vyššie. V treťom kroku sa odhad D zlepší z 8 (cez C: 2 + 6) na 7 (cez B: 4 + 3) a vo štvrtom odhad E z 11 (cez B: 4 + 7) na 9 (cez D: 7 + 2). G dostane 9 + 3 = 12 a už sa nezmení: cesta cez F by merala 10 + 5 = 15.

Veta — Dijkstra je správny pre nezáporné váhy

Veta. Nech G = (V, E, w) je ohodnotený graf s nezápornými váhami, w : E → [0, ∞), štart ∈ V východiskový vrchol a d[·] odhady Dijkstrovho algoritmu spusteného zo štartu (opis vyššie). Potom pre každý vrchol u v okamihu, keď ho algoritmus uzavrie, platí

d[u] = d(štart, u).

Prečo: každá iná cesta do u musí niekde prvýkrát opustiť množinu uzavretých vrcholov, a to cez vrchol x, ktorého odhad je ≥ d[u] (inak by sme vybrali x, nie u). Zvyšok cesty z x do u má nezápornú dĺžku, takže celá cesta nie je kratšia než d[u]. ∎

So zápornou hranou táto úvaha padá — „zvyšok cesty“ by mohol dĺžku skrátiť. Pre záporné váhy je preto potrebný iný algoritmus (Bellman–Ford).

6. Stromy

Definícia — strom a koreňový strom

Nech G = (V, E) je neorientovaný graf.

  1. G je les práve vtedy, keď neobsahuje žiadny cyklus (každý jeho komponent súvislosti je potom strom).
  2. G je strom práve vtedy, keď je súvislý a neobsahuje žiadny cyklus.

Veta. Nech G = (V, E) je neorientovaný graf s n = |V| ≥ 1 vrcholmi. Potom sú nasledujúce tvrdenia ekvivalentné:

  1. G je strom;
  2. G je súvislý a |E| = n − 1;
  3. G neobsahuje cyklus a |E| = n − 1;
  4. ∀u, v ∈ V existuje práve jedna cesta z u do v.

Koreňový strom je dvojica (T, r), kde T = (V, E) je strom a r ∈ V vyznačený vrchol, koreň. Pre v ∈ V:

  1. hĺbka h(v) je dĺžka (počet hrán) jedinej cesty z r do v; špeciálne h(r) = 0;
  2. deti vrcholu v sú jeho susedia smerom od koreňa, t. j. vrcholy množiny {u ∈ N(v) : h(u) = h(v) + 1}; v je ich rodič;
  3. v je list práve vtedy, keď nemá žiadne dieťa.
Laicky povedané

Strom je graf, v ktorom nie je žiadny okruh — medzi dvoma miestami vedie vždy práve jedna trasa. Rodokmeň, priečinky na disku, vetvenie rozhodovania. Stačí ubrať jedinú hranu a strom sa rozpadne; stačí jednu pridať a vznikne cyklus.

V AI sú stromy všade. Rozhodovací strom klasifikuje sériou otázok od koreňa k listu. Algoritmy prehľadávania stavajú strom hľadania — strom BFS a DFS z dielu o prehľadávaní je presne toto. A šachový program prepočítava strom hry, v ktorom sú vrcholy pozície a hrany ťahy.

Veta — strom s n vrcholmi má n − 1 hrán (dôkaz indukciou)

Veta. Nech T = (V, E) je strom s n = |V| ≥ 1 vrcholmi. Potom |E| = n − 1.

Lema: nech T je strom s aspoň dvoma vrcholmi. Potom T má list, t. j. vrchol stupňa 1. Dôkaz lemy: vezmeme najdlhšiu cestu v strome; jej koncový vrchol nemôže mať ďalšieho suseda mimo cesty (cesta by sa dala predĺžiť), ani na ceste (vznikol by cyklus) — má teda stupeň 1.

Dôkaz vety indukciou podľa n. Základ: strom s 1 vrcholom má 0 hrán. Krok: v strome s n + 1 vrcholmi odoberme list aj s jeho jedinou hranou. Zvyšok je stále súvislý a bez cyklov, teda strom s n vrcholmi, a podľa indukčného predpokladu má n − 1 hrán. Pôvodný strom ich mal o jednu viac, n. ∎

Strom hľadania rastie rýchlo. Ak má každý vrchol b detí (vetvenie), je v hĺbke k práve bk vrcholov a v celom strome do hĺbky d:

N(b, d) = ∑k=0d bk = bd+1 − 1/b − 1

N(b, d)
koľko vrcholov musí prehľadávanie v najhoršom prípade prejsť — teda koľko ho to stojí času aj pamäte
∑k=0d
sčítame po poschodiach, od koreňa (k = 0) až po najhlbšie poschodie d
bk
každý z vrcholov poschodia k − 1 má b detí, takže počet sa s každým poschodím násobí b
bd+1 − 1/b − 1
súčet geometrického radu v uzavretom tvare (pre b ≥ 2); ukazuje, že posledné poschodie preváži všetky predchádzajúce dohromady
Šach má v priemere asi b ≈ 35 ťahov na pozíciu. Na štyri ťahy dopredu (d = 4): 354 = 1 500 625 pozícií v poslednom poschodí a N(35, 4) = 355 − 1/34 = 1 544 761 v celom strome — 97 % pripadá na posledné poschodie.

7. Minimálna kostra

Definícia — kostra a Kruskalov algoritmus

Nech G = (V, E, w) je súvislý ohodnotený neorientovaný graf.

  1. Kostra grafu G je graf T = (V, F) s F ⊆ E, ktorý je strom — obsahuje všetky vrcholy G a len niektoré jeho hrany.
  2. Váha kostry je w(T) = ∑e ∈ F w(e).
  3. Kostra T je minimálna práve vtedy, keď w(T) ≤ w(T′) pre každú kostru T′ grafu G.

Kruskalov algoritmus.

  • Vstup: súvislý ohodnotený neorientovaný graf G = (V, E, w) s m = |E| hranami.
  • Výstup: množina hrán F ⊆ E taká, že (V, F) je minimálna kostra G.
  1. Zoraď hrany vzostupne podľa váhy: e1, …, em s w(e1) ≤ … ≤ w(em).
  2. Polož F := ∅.
  3. Pre i = 1, …, m: ak graf (V, F ∪ {ei}) neobsahuje cyklus, polož F := F ∪ {ei}; inak hranu ei vynechaj.
  4. Vráť F.

Zastavenie: algoritmus skončí po prejdení všetkých m hrán (smie skončiť skôr, len čo |F| = |V| − 1). Ide o pažravý algoritmus — v každom kroku berie najľahšiu prípustnú hranu a rozhodnutie už nemení — a predsa vždy nájde minimálnu kostru (veta nižšie).

Laicky povedané

Chcete prepojiť všetky mestá elektrickým vedením čo najlacnejšie. Stačí, aby sa dalo dostať odkiaľkoľvek kamkoľvek — okruhy sú zbytočné. Beriete najkratšie úseky ako prvé a vynecháte tie, ktoré by uzavreli okruh.

4 2 5 3 7 6 2 4 8 3 5 6 A B C D E F G
Kruskalov algoritmus pridáva hrany od najkratšej; kostra má dĺžku 18

Kostra má 6 hrán pre 7 vrcholov — presne n − 1, ako hovorí veta o stromoch — a celkovú dĺžku 18. Šesť zvyšných ciest algoritmus odmietol, pretože by vytvorili cyklus.

Príklad — Kruskal na grafe miest hranu po hrane

Hrany zoradené podľa dĺžky (prijaté tučne): A–C (2), D–E (2), B–D (3), E–G (3), A–B (4), D–F (4), B–C (5), F–G (5), C–D (6), E–F (6), B–E (7), C–F (8).

Prvých šesť hrán sa prijme: A–C a D–E spoja dvojice, B–D pridá B k D–E, E–G pridá G a A–B prepojí skupinu {A, C} so skupinou {B, D, E, G}. D–F pripojí posledný vrchol F. Teraz sú už všetky vrcholy v jednom komponente, takže každá ďalšia hrana by spojila dva vrcholy toho istého komponentu — uzavrela by cyklus a algoritmus ju odmietne.

Dĺžka kostry: 2 + 2 + 3 + 3 + 4 + 4 = 18.

def kruskal(vrcholy, hrany):
    rodic = {v: v for v in vrcholy}           # každý vrchol je zatiaľ sám za seba

    def koren(v):                             # zástupca komponentu, v ktorom v leží
        while rodic[v] != v:
            v = rodic[v]
        return v

    kostra = []
    for u, v, w in sorted(hrany, key=lambda h: h[2]):
        ku, kv = koren(u), koren(v)
        if ku == kv:
            continue                          # u a v sú už spojené: hrana by uzavrela cyklus
        rodic[ku] = kv                        # zlúčenie dvoch komponentov
        kostra.append((u, v, w))
    return kostra
Veta — prečo pažravý postup funguje (vlastnosť rezu)

Nech G = (V, E, w) je súvislý ohodnotený neorientovaný graf. Rez je rozdelenie vrcholov na dve neprázdne časti S a V ∖ S, kde ∅ ≠ S ⊊ V. Hrana {u, v} ∈ E vedie cez rez práve vtedy, keď |{u, v} ∩ S| = 1 (jeden koniec v S, druhý mimo).

Veta. Nech (S, V ∖ S) je rez grafu G a e je hrana, ktorá vedie cez rez a má najmenšiu váhu zo všetkých hrán vedúcich cez tento rez. Potom existuje minimálna kostra G, ktorá hranu e obsahuje.

Dôkaz: vezmime ľubovoľnú minimálnu kostru T; ak obsahuje e, sme hotoví. Inak uvažujme T bez e. Pridaním e vznikne cyklus a ten musí rez prekročiť ešte raz, nejakou hranou f. Odobraním f dostaneme opäť kostru, s váhou w(T) + w(e) − w(f) ≤ w(T), pretože w(e) ≤ w(f). Je teda tiež minimálna a e obsahuje. ∎

Kruskal prijme hranu len vtedy, keď spája dva rôzne komponenty — a je to najľahšia hrana cez rez „jeden z tých komponentov proti zvyšku“, pretože všetky ľahšie už spracoval.

8. Acyklické grafy a výpočet neurónovej siete

Definícia — DAG a topologické usporiadanie

Nech G = (V, E) je orientovaný graf, E ⊆ V × V, s n = |V| vrcholmi.

  1. Orientovaný cyklus je postupnosť vrcholov (v0, v1, …, vk), k ≥ 1, taká, že (vi−1, vi) ∈ E pre i = 1, …, k a vk = v0 — po šípkach sa dá vrátiť do východiskového vrcholu.
  2. G je orientovaný acyklický graf (DAG) práve vtedy, keď neobsahuje žiadny orientovaný cyklus.
  3. Topologické usporiadanie grafu G je bijekcia π : V → {1, …, n} (poradie vrcholov) taká, že ∀(u, v) ∈ E : π(u) < π(v), t. j. každá hrana vedie zľava doprava — u je v poradí pred v.

Veta. Nech G = (V, E) je orientovaný graf. Potom G má topologické usporiadanie práve vtedy, keď je acyklický.

Laicky povedané

DAG je graf závislostí, v ktorom sa nič netočí v kruhu: najprv obuť ponožky, potom topánky. Topologické usporiadanie je poradie, v ktorom sa dá všetko urobiť tak, aby každý krok mal pripravené to, od čoho závisí.

Takto počíta každá neurónová sieť. Tu je výpočet jediného neurónu ŷ = σ(w · x + b) a jeho chyby L(ŷ, y) ako výpočtový graf: vstupy vľavo, operácie ako vrcholy, šípky ukazujú, čo od čoho závisí. Čísla sú topologické poradie:

x 1 w 2 b 3 y 4 · 5 + 6 σ 7 L 8
Výpočtový graf neurónu a jeho topologické poradie x → w → b → y → · → + → σ → L

Sieť počíta dopredu v topologickom poradí — najprv súčin, potom súčet, sigmoidu a chybu. A keď sa potom učí, ide tým istým grafom dozadu: spätné šírenie chyby (backpropagation) prechádza vrcholy v obrátenom topologickom poradí a v každom použije reťazové pravidlo. Knižnice ako PyTorch si tento graf stavajú samy pri každom výpočte. Mimochodom, aj graf nadväzností modulov v osnove tejto série je DAG.

Ako nájsť topologické poradie

Vstupný stupeň vrcholu v orientovaného grafu (V, E), deg−(v) = |{u ∈ V : (u, v) ∈ E}|, je počet šípok, ktoré do v vedú — počet vecí, od ktorých v závisí. Kahnov algoritmus opakovane berie vrchol, ktorý už na nič nečaká:

from collections import deque

def topologicke(vrcholy, hrany):
    vstupni = {v: 0 for v in vrcholy}
    for u, v in hrany:
        vstupni[v] += 1
    fronta = deque(v for v in vrcholy if vstupni[v] == 0)   # vstupy: od ničoho nezávisia
    poradi = []
    while fronta:
        u = fronta.popleft()
        poradi.append(u)
        for a, b in hrany:
            if a == u:
                vstupni[b] -= 1                   # u je hotové, b čaká o jednu vec menej
                if vstupni[b] == 0:
                    fronta.append(b)
    return poradi if len(poradi) == len(vrcholy) else None  # None: graf má cyklus

Na grafe neurónu dá poradie x, w, b, y, ·, +, σ, L: najprv štyri vstupy, potom súčin, súčet, sigmoida a strata. Keď má graf cyklus, vrcholy na cykle na seba čakajú navzájom, vstupný stupeň im nikdy neklesne na nulu a do poradia sa nedostanú — odtiaľ posledný riadok.

Príklad — prechod grafom neurónu tam a späť

Vstupy x = 2, w = 0,5, b = −1, správna odpoveď y = 1, strata L = (ŷ − y)2, σ(z) = 1/1 + e−z.

Dopredu (v topologickom poradí): w · x = 1; z = 1 + (−1) = 0; ŷ = σ(0) = 0,5; L = (0,5 − 1)2 = 0,25.

Dozadu (v obrátenom poradí; farby podľa rozboru reťazového pravidla nižšie): ∂L/∂ŷ = 2(ŷ − y) = −1; ∂ŷ/∂z = σ(z)(1 − σ(z)) = 0,25; ∂L/∂z = −1 · 0,25 = −0,25; ∂L/∂b = ∂L/∂z · 1 = −0,25; ∂L/∂w = ∂L/∂z · ∂z/∂w = −0,25 · 2 = −0,5 (∂z/∂w = x = 2).

Obe derivácie sú záporné: zväčšením w aj b sa strata zmenší — sieť sa posunie k odpovedi 1.

∂L/∂w = ∂L/∂ŷ · ∂ŷ/∂z · ∂z/∂w

∂L/∂w
ako citlivo reaguje chyba na váhu — podľa toho sa váha pri učení posunie
∂L/∂ŷ
hrana σ → L: o koľko sa zmení chyba, keď sa zmení výstup; počíta sa prvá, pretože L je v poradí posledná
∂ŷ/∂z
hrana + → σ: ako sigmoida prenáša zmenu svojho vstupu
∂z/∂w
hrany w → · → +: zmena súčtu na jednotku váhy, teda x
Jeden činiteľ za každú hranu na ceste od w k L. Keby z w do L viedlo ciest viac, príspevky všetkých ciest sa sčítajú. Na príklade: −1 · 0,25 · 2 = −0,5.

9. Grafy v umelej inteligencii

  • Stavový priestor je graf: stavy sú vrcholy, akcie hrany s cenou. Prehľadávanie je hľadanie cesty v grafe.
  • Výpočtové grafy neurónových sietí sú DAG; tréning je prechod tam a späť.
  • Znalostné grafy ukladajú fakty ako hrany „Praha — je hlavné mesto — Česko“ a vyhľadávače z nich skladajú odpovede.
  • Bayesovské siete sú DAG pravdepodobnostných závislostí — dostaneme sa k nim v module o pravdepodobnostných modeloch.
  • Grafové neurónové siete sa učia priamo na grafoch: predpovedajú vlastnosti molekúl, dopravu alebo odporúčania.

10. Zhrnutie

  • Graf je množina vrcholov a hrán; hrany môžu mať smer a váhu. Súčet stupňov je dvojnásobok počtu hrán.
  • Graf sa ukladá maticou susednosti, alebo zoznamom susedov — ten je pre riedke grafy oveľa úspornejší.
  • BFS nájde cestu s najmenej hranami, Dijkstra najkratšiu podľa váh — a to nemusí byť to isté.
  • Strom je súvislý graf bez cyklov s n − 1 hranami; minimálnu kostru nájde pažravý Kruskalov algoritmus.
  • Neurónová sieť je výpočtový DAG: dopredu sa počíta v topologickom poradí, gradient dozadu.

Máte na to iný názor? Napíšte na support@coden-app.com.

Agent na vašom počítači, ovládaný z telefónu