Prohledávání do šířky a do hloubky Jan Hnilica Počítačové modelování 15 1
Prohledávací algoritmy Úkol postupně systematicky prohledat vymezený stavový prostor Stavový prostor (SP) možné stavy a varianty vývoje nějakého procesu (výpočetního, výrobního, herního...) co může být stavovým prostorem? varianty vývoje na šachovnici (hledáme cestu k vítězství) bludiště (hledáme cestu ven) silniční síť (hledáme cestu z A do B)... a mnoho dalších příkladů Co můžeme hledat? nejrychlejší řešení (nejdříve dostupné) optimální řešení všechna řešení alespoň jedno řešení (jakékoliv) Prohledávání do hloubky nebo do šířky oba algoritmy vedou k úplnému prohledání SP, liší se ale pořadím navštívených míst v praxi mezi nimi volíme podle cíle, kterého má být dosaženo (viz dále) Jan Hnilica Počítačové modelování 15 2
Stavový prostor jako strom SP si můžeme představit jako strom (a také se tak v programu často realizuje) kořen stromu = úvodní stav např. výchozí poloha v bludišti synové uzlu U = stavy, do kterých se lze dostat z U pomocí nějakého elementárního kroku elementární krok = např. postup v bludišti na další rozcestí listy = konec cesty východ z bludiště nebo slepá ulička A K H C G I B C D D A B E F G H I J F K L L J E Jan Hnilica Počítačové modelování 15 3
Průchod stromem do hloubky a do šířky cílem je postupně prohledat všechny uzly stromu k dočasnému skladování uzlů použijeme datovou strukturu DS (viz dále) algoritmus: 1. vlož do DS kořen stromu 2. cyklus: dokud DS není prázdná 2a. vyjmi z DS uzel U // uzel U je navštívený 2b. vlož do DS všechny syny uzlu U // např. zprava doleva D B E A F C G použitá datová struktura DS je: zásobník průchod do hloubky uzly navštíveny v pořadí: A, B, D, E, C, F, G fronta průchod do šířky (po vrstvách) uzly navštíveny v pořadí: A, B, C, D, E, F, G Jan Hnilica Počítačové modelování 15 4
Prohledávání do hloubky = backtracking, DFS (depth first search) Algoritmus postupně prohledáváme jednu větev po druhé, postupujeme do hloubky směrem k listům pokud na dané cestě nenajdeme řešení, vracíme se zpět na místo předchozího větvení a vydáme se jinou cestou Realizace rekurzivní funkce nebo cyklus s vlastním zásobníkem Paměťová složitost odpovídá výšce stromu (na zásobníku udržujeme pouze aktuálně prohledávanou cestu) obvykle dobře zvládnutelné Časová složitost odpovídá počtu uzlů ve stromu, které musíme navštívit exponenciálně roste s výškou stromu časově extrémně náročné, použitelné pro malé úlohy Jan Hnilica Počítačové modelování 15 5
Prohledávání do hloubky pro zmírnění časových nároků se používají prořezávání a heuristiky Prořezávání při každém kroku hlouběji k listům zkoušíme průběžně vyhodnotit, jestli daná cesta může vést k nalezení řešení pokud můžeme určit, že cesta vede do slepé uličky, ihned se vracíme a neztrácíme čas jejím rozvíjením ( odřízneme celý podstrom) ne vždy je prořezávání možné, ale pokud ano, dokáže zásadním způsobem snížit časové nároky algoritmu Heuristiky použitelné, pokud hledáme jedno řešení (jakékoliv) princip: přednostně procházíme ty větve, kde tušíme existenci blízkého řešení heuristika = intuitivní odhad, jakou cestou se vydat (kde by se řešení mohlo nalézat) dobrá heuristika výrazné zrychlení, projdeme pouze malou část stromu špatná heuristika nic se neděje, o řešení nepřijdeme (heuristika pouze mění pořadí, ve kterém jsou podstromy procházeny) Příklady prořezávání a heuristik viz dále... Jan Hnilica Počítačové modelování 15 6
Prohledávání do hloubky Luštění Sudoku tabulka 9 9, uvnitř dále rozdělená na 9 bloků 3 3 vyplňujeme čísly 1 9, zadání je částečně předvyplněno omezení: v žádném sloupci, řádku ani bloku se žádné číslo nesmí opakovat Základní řešení (hromotlucké) rekurzivní algoritmus, do každého volného políčka postupně zkoušíme čísla 1 9 po vyplnění celé tabulky vždy otestujeme, zda jsme našli řešení (tzn. zda jsme vytvořili korektní sudoku podle daných omezení) Časová složitost 81 políček, na každém hodnoty 1 9 celkem 9 81 variant nelze prohledat v rozumném čase!!! Urychlení pomocí prořezávání po vyplnění každého políčka ihned otestujeme, zda jsme neporušili pravidla test sloupce, řádku a bloku pokud ano, nemá smysl větev rozvíjet dál ihned návrat o patro výš ušetříme mnoho zbytečné práce, výrazné zrychlení Jan Hnilica Počítačové modelování 15 7
Prohledávání do hloubky Koňská procházka na šachovnici stojí samotný kůň, cílem je nalézt takovou posloupnost tahů, při které kůň postupně proskáče celou šachovnici a na žádné pole přitom neskočí dvakrát Algoritmus z každé pozice postupně zkoušíme provést všechny tahy, které vedou na dosud nenavštívená pole, čímž vznikají nové pozice, které rekurzivně rozvíjíme stejným postupem z dané pozice jsou možné další tahy rekurzivní rozvoj nejsou možné další tahy slepá ulička, návrat o patro výš vždy samozřejmě kontrolujeme, zda jsme nedosáhli řešení Urychlení pomocí heuristiky přednostně provádíme ty tahy, které vedou do omezených pozic (tzn. do pozic s menším počtem možných pokračování) velmi výrazné zrychlení výpočtu (pokud hledáme jedno řešení) Jan Hnilica Počítačové modelování 15 8
Prohledávání do hloubky Koňská procházka Realizace (jedna z možností) šachovnice = 2D pole int [8][8], hodnota políčka = pořadí kroku, kterým jsme na něj přišli rekurzivní funkce, pracující nad jediným polem v paměti (š. předávaná jako parametr) úvod: všechna políčka šachovnice mají hodnotu 0, startovní pozice má hodnotu 1 rozvoj z pozice P na pozici P (další tah): zapsat na P číslo o jedničku vyšší než má P rekurzivní rozvoj pozice P návrat z rozvoje P : ve větvi bylo nalezeno řešení návrat zpět (oznámit čekajícím funkcím nahoře) řešení nalezeno nebylo vrátit na P hodnotu 0 a pokračovat rozvojem jiného tahu informace o nalezeném řešení: např. proměnná typu int, předávaná mezi funkcemi odkazem nebo návratová hodnota samotné rekurzivní funkce Jan Hnilica Počítačové modelování 15 9
Prohledávání do hloubky Koňská procházka jedno z možných řešení (start vlevo nahoře) a b c d e f g h 8 1 4 57 20 41 6 43 22 8 7 34 19 2 5 58 21 40 7 7 6 3 56 35 60 37 42 23 44 6 5 18 33 48 53 46 59 8 39 5 4 49 14 55 36 61 38 45 24 4 3 32 17 52 47 54 27 62 9 3 2 13 50 15 30 11 64 25 28 2 1 16 31 12 51 26 29 10 63 1 a b c d e f g h Jan Hnilica Počítačové modelování 15 10
Prohledávání do šířky = algoritmus vlny, BFS (breadth first search) Algoritmus současně rozvíjíme všechny varianty pokračování řešené úlohy strom výpočtu procházíme do šířky po vrstvách Realizace uzly určené k dalšímu zpracování odkládáme do fronty informace o zpracovávaných uzlech lze také zakódovat do reprezentace stavového prostoru (např. šachovnice = 2D pole, políčka obsahují informaci, zda byla už navštívena, popř. v kolikátém kroku) Paměťová složitost ve frontě uložena celá vrstva, šířka vrstvy s hloubkou exponenciálně roste pro větší hloubky výpočtu paměťově nerealizovatelné Časová složitost = obecně všechny uzly stromu (jako u backtrackingu) algoritmus používáme, pokud chceme nalézt nejrychleji dostupné řešení (BFS vždy jako první najde toto řešení) Jan Hnilica Počítačové modelování 15 11
Prohledávání do šířky Královská procházka král stojí na šachovnici na startovním poli S, jeho úkolem je dostat se na cílové pole C omezení: na některých polích jsou překážky, na tato pole král nesmí vstoupit cílem je zjistit nejmenší možný počet kroků z S na C, případně vypsat cestu start cíl překážka Algoritmus okolo výchozí pozice najdeme a označíme všechna pole, na které král může vstoupit všechny označené pozice souběžně rozvíjíme, tzn. pro každou z nich najdeme všechny dosud nenavštívené sousedy, na které je možné vstoupit a označíme je pro rozvoj v dalším kroku kolem výchozí pozice se v jednotlivých krocích rozlévá vlna, která postupně dojde na cílové pole (nebo nedojde, pokud je král překážkami odříznut od cíle) Jan Hnilica Počítačové modelování 15 12
Prohledávání do šířky Královská procházka start cíl překážka čelo vlny prohledaná oblast 1. krok 2. krok 3. krok 4. krok 5. krok 6. krok 7. krok 8. krok 9. krok jsme u cíle po 9 krocích Jan Hnilica Počítačové modelování 15 13
Prohledávání do šířky Královská procházka Technická realizace šachovnice opět nejlépe jako 2D pole int hodnota políčka = pořadí kroku, kterým se na něj dá dostat uložení aktuálně rozvíjených pozic lineární seznam nebo v každém kroku projít celou šachovnici a nalézt pole s příslušnou hodnotou (nemusíme udržovat lineární seznam, ale přístup k rozvíjeným pozicím je pomalejší) Výpis konkrétní cesty vyžaduje zpětný chod od cílové pozice ke startu v každém kroku postupujeme na pole s hodnotou o jedničku menší (takových polí může být víc, teoreticky je jedno, které zvolíme) Jan Hnilica Počítačové modelování 15 14
Prohledávání do šířky Přelévání vody máme n nádob o definovaných objemech, první je plná, ostatní prázdné cíl: pomocí přelévání vody mezi nádobami dosáhnout požadovaných obsahů vody v jednotlivých nádobách omezení: nádoby nemají žádné rysky, takže jediné povolené operace, při kterých udržíme informaci o obsahu vody v nádobách jsou: úplné vylití nádoby do jiné nádoby úplné naplnění nádoby obsahem (nebo částí obsahu) jiné nádoby úkol: napsat program, který pro zadané objemy nádob vypíše nejkratší posloupnost přelití, kterou se lze dostat do cílového stavu objemy nádob: 10 7 2 úvodní stav: 10 0 0 cílový stav: 5 5 0 Jan Hnilica Počítačové modelování 15 15
Prohledávání do šířky Přelévání vody Řešení v každém kroku současně rozvíjíme všechny stavy vzniklé v předchozím kroku až do nalezení cílového stavu (nebo do zjištění, že nové stavy už vznikat nemůžou úlohu nelze splnit) Realizace stavového prostoru n-rozměrné pole (souřadnice reprezentují aktuální obsahy), prvky pole obsahují pořadí kroku, případně další informace (ze kterého stavu se sem dojde na nejmenší počet kroků...) obecný strom stavů uzly obsahují aktuální obsahy, pointery na syny, případně pointer na otce při rozvoji je dobré dát pozor na duplicitní rozvoj stejných stavů (z A se lze dostat jedním přelitím na B z B se lze dostat zpětným přelitím na A) Vypsání posloupnosti přelití po nalezení cílového stavu zpětný chod stavovým prostorem zpětný chod stromem od listu ke kořeni ( tady se bude hodit ten pointer na otce) Jan Hnilica Počítačové modelování 15 16
Prohledávání do šířky Přelévání vody řešení úlohy 10 7 2 10 0 0 3 7 0 3 5 2 5 5 0 Jan Hnilica Počítačové modelování 15 17
Kdy použít který algoritmus záleží na zadané úloze Prohledávání do hloubky vhodné, pokud je úkolem nalézt všechna řešení optimální řešení nutné prohledat celý strom, což trvá u obou algoritmů stejně dlouho, ale prohledávání do hloubky spotřebuje výrazně méně paměti nebo pokud hledáme libovolné řešení, které je ale ve stromu daleko od kořene (stejný důvod) Prohledávání do šířky při úkolu nalézt nejrychleji dostupné řešení pokud ve velkém stavovém prostoru existuje řešení blízko kořene Jan Hnilica Počítačové modelování 15 18
Minimax algoritmus, který umí "inteligentně" hrát např. piškvorky, dámu, šachy... obecně hry pro dva hráče, ve kterých jsou veškeré informace viditelné na hrací ploše (ne tedy např. karetní hry) Hra dva hráči (černý a bílý) se pravidelně střídají v tazích algoritmus hraje např. v pozici bílého protihráč = člověk (nebo jiný algoritmus) cílem algoritmu je vždy v aktuální herní situaci vybrat nejlepší tah z partie Garry Kasparov vs Deep Blue Jan Hnilica Počítačové modelování 15 19
Minimax Strom hry uzel = stav na šachovnici (kořen je výchozí stav) synové uzlu = možné tahy (vznikají nové stavy) bílé uzly... na tahu je bílý černé uzly... na tahu je černý list = konec hry (výhra jednoho z hráčů nebo remíza) Velikost stromu hry obvykle velká hloubka stromu - hry končí až po desítkách tahů obvykle velký stupen větvení - uzly mívají desítky synů (počet možných tahů z daného stavu) kompletní strom hry bývá velmi rozsáhlý Jan Hnilica Počítačové modelování 15 20
Minimax Hodnota stavu na šachovnici = číslo, vyjadřující např. aktuální herní materiál hráčů, bonusy za výhodné pozice atd. vysoká hodnota výhodná pro bílého nízká hodnota výhodná pro černého Princip algoritmu generuje se strom hry pro daný (omezený) počet tahů dopředu nejdříve se ohodnotí listy stromu uzly ve vyšších patrech získávají hodnotu postupně při průchodu stromem zdola nahoru uzel vždy získá hodnotu toho syna, kterého si daný hráč vybere jako svůj nejlepší tah bílý maximalizuje z možných tahů vybírá ten s nejvyšší hodnotou černý minimalizuje z možných tahů vybírá ten s nejnižší hodnotou v kořeni nakonec bílý vybírá tah s nejvyšší hodnotou Technická realizace strom hry nelze celý vygenerovat a uložit do paměti (ani u malých her) strom se zároveň tvoří a prochází do hloubky, při návratu se uzly ve spodních patrech mažou hodnota v uzlu se průběžně upravuje při návratu z jeho podstromu (v bílém uzlu - pokud se zespoda vrátí hodnota vyšší než prozatím dosažená, v černém naopak) Jan Hnilica Počítačové modelování 15 21
Minimax (demonstrace do hloubky 3 tahů) vybíráme maximum... (provede se levý tah) 4 vybíráme minimum... 4 1 vybíráme maximum... 4 6 1 9 nejdříve ohodnotíme listy... 4 2 6 3 1 9 2 Jan Hnilica Počítačové modelování 15 22
Minimax (nárys funkce) int Minimax(sachovnice * S, int hloubka, int hrac) { // jsme v listu => vracíme hodnotu na šachovnici if (hloubka == 0) return Hodnota(S); // vygenerujeme tahy z aktuální pozice tah tahy[] = VygenerujTahy(S); int hodnota; int nejhodnota = -hrac * ; // postupně vyzkoušíme všechny tahy a zjistíme jejich cenu for (int i = 0; i < pocettahu; i++) { ZahrajTah(S, tahy[i]); hodnota = Minimax(S, hloubka 1, -hrac); ZahrajTahZpet(S, tahy[i]); if (hrac == 1) if (hodnota > nejhodnota) nejhodnota = hodnota; if (hrac == -1) if (hodnota < nejhodnota) nejhodnota = hodnota; } // úklid a návrat do vyšších pater SmazTahy(tahy); return nejhodnota; } Jan Hnilica Počítačové modelování 15 23
Minimax Složitost minimaxu paměť = výška stromu (není problém) čas = počet uzlů stromu hry, exponenciálně roste s hloubkou nutno velmi omezit hloubku prohledávání Možnosti prořezávání subjektivní prořezávání (ztrátové) po několika tazích zhodnotit stav na šachovnici, pozice, které se jeví jako málo nadějné dál nerozvíjíme problém: hodnocení je subjektivní, pouze odhadujeme, jak by se stav mohl rozvinout můžeme odmítnout cesty vedoucí nakonec k vítězství alfa-beta prořezávání (bez ztráty informace) algoritmus doplníme o dva parametry: alfa = maximum, které má ve vyšších patrech k dispozici maximalizující hráč beta = minimum, které má ve vyšších patrech k dispozici minimalizující hráč příklad použití: na tahu je bílý a zjistí, že některý jeho tah má hodnotu > beta okamžitý návrat proč? zkoumáním dalších tahů by mohl hodnotu svého uzlu jen zvětšit, ale minimalizující hráč má někde nahoře k dispozici menší hodnotu, tuto větev si tedy stejně nevybere, tzn. nemá cenu pokračovat Jan Hnilica Počítačové modelování 15 24
Minimax (demonstrace alfa - beta prořezávání) 4 4 1 hodnota < alfa 4 6 1 hodnota > beta 4 2 6 1 Jan Hnilica Počítačové modelování 15 25