1 Plánovací systémy Jako další samostatnou kategorii umělé inteligence můžeme vyčlenit oblast plánovacích úloh. Ne vždy jsou úlohy z této třídy řazeny mezi plánování, někdy mohou některé úlohy zapadnout do kategorie hledání řešení, jindy jsou zařazeny mezi speciální expertní systémy. Zde ale bude kategorie plánovacích úloh vyčleněna samostatně. Proč tomu tak je, hned uvidíme. Pokud se podíváme na úlohy hledání řešení, máme obvykle daný problém popsaný docela precizně a jen na základě vlastních kritérií v něm hledáme řešení pro naše zadání. Zkusmesialenastůlvysypatkostkydominaahnedseocitámevezcela jiné pozici. Nemáme graf. Máme krátké spoje pro dvojice čísel, ale jaká bude výsledná cesta se ukáže až během hry. Ataktobudeivtétokapitole.Budemesezabývatstavovýmiveličinami, popisujícími stav našeho problému, nebo modelu(obecněji stavu světa). A pro transformování stavu z aktuálního do cílového budeme používat různé akce, které mohou měnit stav jedné či více stavových veličin současně. 1.1 Příklady plánovacích úloh Než se pustíme do vysvětlování realizace plánovacích systémů, ukažme si několik nejznámějších úloh, pro které se plánovací systémy používají. Jde o takzvané dobřeznámé problémy.jejichpraktickápodobaalebývávelmi odlišná. Opiceabanán. Jdeoúlohu,kdysevdanémprostorupohybujeopice,někdejezavěšenýbanánaopicenanějnedosáhne.Vprostorujeovšemtakéžidle, kterousiopicemůžepřinéstpodbanán,apokudnanivyleze,bude moci banán utrhnout. Tutoúlohusipronašeúčelypřevedemepozdějinaproblémrobotbedna- vypínač. Koza,vlk,zelíapřevozník. V našich krajích úloha známá pro většinu lidí již od základní školy. Převozník má za úkol převézt přes řeku všechny tři uvedené věci, na loďku je však schopen vždy naložit jen jedinou. Na břehu ovšem nesmí zůstatbezdozorukozasezelím,nebovlkskozou. Otecadvasynovésemajípřepravitpřesřeku. Vtomtopřípadějeproblémvtom,želoďkauvezejen100kg.Každý zesynůvážíprávě50kgaotecpřesně100kg.jaksedostanouvšichni přes řeku? 1
3misionářia3lidožrouti. Opětsemusívšichnipřepravitpřesřekunalodi,kteráuvezejendvě osoby. Na žádném břehu však nesmí nikdy zůstat lidožrouti v převaze. 15puzzle Známý čtverec rozdělený na 4 4 políčka, vyplněný čísly 1 až 15. Jedno volné políčko dává možnost čísly posouvat a seřadit je vzestupně či sestupně. Hanojské věže. Máme na sobě naskládané kameny dle velikosti. Naším úkolem je přeložit celý sloupec na jiné místo, přičemž smíme vždy přesouvat jen jediný kámen a nesmíme položit kámen větší na menší. K dispozici máme jen jediné pomocné odkládací místo. Nádoby9la4l. Mámedvěnádoby,9la4l.Nádobynemajístupnici,smímejevylévat adolévatdoplna.možnojenádobyipřelévat,alebuďjenvšepřelít, nebo dolít do plna. 3mince. Nastoleleží3mincehlavounahoru.Otáčenímvždydvoumincísoučasně otočte všechny mince hlavou dolů. A ve výčtu bychom mohli pokračovat složitějšími úlohami. 1.2 GPS- General Problem Solver Prvním systémům předcházala celá řada experimentů. Jeden z prvních systémů vznikl tak, že se lidé řešící některé hlavolamy pokusili slovně formulovat své myšlenkové postupy. Vznikly z toho tři základní postupové kroky: Analýza prostředků a cílů. Plánování. Aplikace metody pokus omyl. Podívejme se, co si pod jednotlivými kroky představit. Mějme příklad na obrázku 1. Pokud chceme, aby robot rozsvítil světlo, musí si přesunout bednudomístostim3,vyléztnaniarozsvítit. Máme-li provést první krok pro vytvoření plánovacího systému, musíme tento problém popsat stavovými veličinami a ke každé veličině přiřadit akci, která bude danou veličinu modifikovat. V Prologu bude výsledek analýzy následující: 2
% Popis stavovych velicin stav( robot_v, m1 ). stav( robot_na, zemi ). stav( bedna_v, m2 ). stav( svetlo, nesviti ). % Prirazeni dvojic - planovaci akce a promenne akce( robot_v, jdi ). akce( robot_na, vylez ). akce( bedna_v, presun ). akce( svetlo, prepni ). Mámetedyčtyřistavovéveličiny-robotv,robotna,bednav,svetlo. Pro každou veličinu bude jediná akce, která ji bude modifikovat- jdi, vylez, presun, prepni. Možná si položíte otázku, proč jsme nepřiřadili ke každé proměnné a jejímu stavu i akci? V tomto jednoduchém připadě by to asi teoreticky možné bylo,alevpřípadě,kdysedanástavováproměnnásmíměnitvíceakcemi, už bychom se ocitli v problémech. V této chvíli můžeme přistoupit k druhému kroku plánování. Pro každou akci musíme specifikovat, jak bude stav proměnných modifikovat a za jakých podmínek budou jednotlivé akce proveditelné. Naše čtyři akce mohou vypadat asi následovně: % Prechod robota do jine mistnosti jdi( Kam ) :- cil( robot_na, zemi ), retract( stav( robot_v, _ ) ), assert( stav( robot_v, Kam ) ),!. % Vylezeni na bednu vylez( Naco ) :- stav( bedna_v, Kde ), cil( robot_v, Kde ), retract( stav( robot_na, _ ) ), assert( stav( robot_na, Naco ) ),!. % Prepnuti vypinace. 3
prepni( S ) :- cil( bedna_v, m3 ), cil( robot_na, bedne ), retract( stav( svetlo, _ ) ), assert( stav( svetlo, S ) ),!. % Presun bedny do jine mistnosti presun( Kam ) :- cil( robot_na, zemi ), stav( bedna_v, Kde ), cil( robot_v, Kde ), retract( stav( bedna_v, _ ) ), retract( stav( robot_v, _ ) ), assert( stav( bedna_v, Kam ) ), assert( stav( robot_v, Kam ) ),!. Všimnětesi,ževakcijdiapresunjsmesizjednodušiliprůchodmezi místnostmi. Jde totiž o hledání řešení a to není v této kapitole podstatné. S takto vytvořenými akcemi se můžeme pustit do posledního bodu, aplikovat jednotlivé akce metodou pokus omyl. Tím se dostáváme k jádru systému GPS, kdy budeme aplikovat jednotlivéakcesicenaslepo,alesamozřejměvpořadí,abysestavsvětaměnil souvisle. Akce na sebe tedy musí navazovat(jako kostky v dominu). Implementace pro náš problém robota je následující: cil( Prom, Stav ) :- stav( Prom, Stav ),!. cil( Prom, Stav ) :- akce( Prom, Akce ), X =.. [ Akce, Stav ], X, write( Akce ), write( => ), write( Prom ), write( - ), write( Stav ), nl, cil( Prom, Stav ),!. Budeme se pokoušet postupně provádět jednotlivé akce, při rekurzi se akce budou řetězit a pokud se dostaneme do cílového stavu, hledání se ukončí. Strom řešení se bude zcela zřejmě rozvíjet do hloubky. Když už máme celý systém sestavený, můžeme ho vyzkoušet. Zadejme mu postupně několik úkolů a sledujme, co se stane. Úkoly mohou být následující: cil(robotv,m4). 4
cil(bednav,m1). cil(svetlo,sviti). cil(bednav,m2). cil( svetlo, nesviti). Výpis výsledků plánování bude přímo při komunikaci v příkazovém řádku interpretu Prologu následující:?- cil( robot_v, m4 ). jdi => robot_v - m4?- cil( bedna_v, m1 ). jdi => robot_v - m2 presun => bedna_v - m1?- cil( svetlo, sviti ). presun => bedna_v - m3 vylez => robot_na - bedne prepni => svetlo - sviti?- cil( bedna_v, m2 ). vylez => robot_na - zemi presun => bedna_v - m2?- cil( svetlo, nesviti ). presun => bedna_v - m3 vylez => robot_na - bedne prepni => svetlo - nesviti?- Robot postupně plní naše příkazy a v každém kroku se vypisují provedené akce. Našemu jednoduchému problému odpovídá i snadné řešení jednotlivých úkolů. Možná někoho překvapí univerzální chování akce vylez a prepni. Ale pokud se podíváme na jejich zdrojový kód, zjistíme, že i při této jednoduchosti je možno zachovat dostatečnou univerzalitu. 5
m1 m2 vypinac robot bedna m3 m4 Obrázek 1: Popis situace v problému robot bedna vypínač 1.3 STRIPS- Standford Research Institute Problem Solver Metoda STRIPS je výsledkem výzkumného úkolu, jehož záměrem bylo navrhnout univerzálnější plánovací systém, aby nebylo vždy nutno programovat každou plánovací akci pro nově zadaný problém. K jakému závěru autoři dospěli, si můžeme odvodit i sami. Podívámeli se na akce robota v předchozím systému GPS, snadno rozpoznáme tři opakující se kroky. Nejprve podmínky, za jakých může být akce provedena, pak se z modelu světa odeberou již neplatné hodnoty stavových veličin a nahradí se novými. STRIPS bude tedy velmi podobný systému GPS. Jen akce budou definovány jako uspořádaná trojice: akce a =[P a, S a, N a ], kde mají jednotlivé položky následující význam: P a jemnožinapodmíneknutnýchkprovedení akce a, S a obsahujemnožinuhodnotstavovýchveličin,kterébudouzestavusvěta odstraněny, N a obsahujemnožinuhodnotstavovýchveličin,kterésedostavusvěta provedením akce a přidají. V jazyce Prolog bude popis akcí vypadat následovně: akce( název, [ seznam podmínek ], [ seznam hodnot pro odebrání ], [ seznam nových hodnot ] ). 6
Popis systému postavíme na příkladu řešení problému robota podle obrázku 1. Akce navrhneme jako trojice seznamů a snadno vyřešíme i korektní průchod mezi místnostmi. Popis problému pro systém STRIPS bude následující: % pocatecni stav stav0 :- retractall( stav( _, _ ) ), assert( stav( robot_v, m1 ) ), assert( stav( robot_na, zemi ) ), assert( stav( bedna_v, m2 ) ), assert( stav( svetlo, nesviti ) ). :-stav0. % pruchody mezi mistnostmi pruchod( m1, m4 ). pruchod( m2, m4 ). pruchod( m3, m4 ). % obousmerne propojeni mistnosti spojeni( X, Y ) :- pruchod( X, Y ). spojeni( X, Y ) :- pruchod( Y, X ). % planovaci akce - ( nazev, [ podminky ], [ odeber ], [ pridej ] ). akce( jdi( X, Y ), [ spojeni( X, Y ), stav( robot_na, zemi ), stav( robot_v, X ) ], [ stav( robot_v, X ) ], [ stav( robot_v, Y ) ] ). akce( presun( X, Y ), [ spojeni( X, Y ), stav( robot_na, zemi ), stav( robot_v, X ), stav( bedna_v, X ) ], [ stav( robot_v, X ), stav( bedna_v, X ) ], [ stav( robot_v, Y ), stav( bedna_v, Y ) ] ). akce( vylez, [ stav( bedna_v, X ), stav( robot_v, X ) ], [ stav( robot_v, X ), stav( robot_na, zemi ) ], [ stav( robot_na, bedne ) ] ). akce( slez, [ stav( bedna_v, X ), stav( robot_na, bedne ) ], [ stav( robot_na, bedne ) ], [ stav( robot_na, zemi ), stav( robot_v, X ) ] ). akce( rozsvit, 7
[ stav( bedna_v, m3 ), stav( robot_na, bedne ) ], [ stav( svetlo, nesviti ) ], [ stav( svetlo, sviti ) ] ). akce( zhasni, [ stav( bedna_v, m3 ), stav( robot_na, bedne ) ], [ stav( svetlo, sviti ) ], [ stav( svetlo, nesviti ) ] ). K takto popsaným akcím již můžeme přidat jádro systému STRIPS. Jeho podstatou je vybírat takové akce, které svým provedením dosáhnou cílového stavu(prakticky to znamená, že hodnota stavové veličiny musí být obsažena ve třetím seznamu popisu akce). Tímto krokem se dostaneme do stavu předchozího a od tohoto stavu dále pokračujeme v plánování až do aktuálního stavu. Strom řešení je v tomto případě rozvíjen od stavu cílového k aktuálnímu. Pokud tedy systém nalezne souvislou posloupnost akcí, tak je provede. Implementace tohoto jednoduchého principu je následující: % plneni jednoho cile cil( C ) :- C. % cil je splnen cil( C ) :- rozpracovano( C ),!, fail. % cil je rozpracovan cil( C ) :- assertu( rozpracovano( C ) ), % zaznamename cil jako rozpracovany akce( Akce, Podm, Pryc, Pridat ), % vyber akce member( C, Pridat ), % overeni, zda akce povede k cili cile( Podm ), % splneni podminek odeber_seznam( Pryc ), % odstranime neplatne stavy pridej_seznam( Pridat ), % pridame nove stavy retractu( rozpracovano( C ) ), % splneny cil jiz neni rozpracovan vsechny_stavy( X ), % zaznamename provedenou akci assertu( plan( provedeno( Akce, X ) ) ). start( X ) :- retractall( rozpracovano( _ ) ), retractall( plan( _ ) ), cil( X ), planovani. Vlastní princip systému STRIPS je prakticky zahrnut v pěti řádcíchvýběr akce, ověření, zda akce povede k cíli, splnění podmínek a změna stavu světa. Predikát start použijeme pro spuštění plánování. Nyní už zbývá jen několik pomocných predikátů, kterými si pomůžeme při zpracovávání seznamů stavových veličin a plnění seznamu podmínek. 8
% pomocne predikaty % plneni seznamu cilu cile( [] ). cile( [ H T ] ) :- cil( H ), cile( T ). % pridani seznamu stavu pridej_seznam( [] ). pridej_seznam( [ H T ] ) :- assertu( H ), pridej_seznam( T ). % odebrani seznamu stavu odeber_seznam( [] ). odeber_seznam( [ H T ] ) :- retractu( H ), odeber_seznam( T ). % vypis planu planovani :- write( ), nl, stav( X, Y ), write( stav( X, Y ) ), nl, fail. planovani :- nl, write( ), nl, nl, fail. planovani :- plan( provedeno( A, X ) ), write( A ), write( => ), nl, write( ), write( X ), nl, fail. planovani :-!. % stav vsech stavovych velicin do seznamu vsechny_stavy( _ ) :- retractall( svet( _ ) ), assert( svet( [] ) ), fail. vsechny_stavy( _ ) :- stav( X, Y ), retract( svet( S ) ), assert( svet( [ [ X, Y ] S ] ) ), fail. vsechny_stavy( S ) :- retract( svet( S ) ). 9
Teď, když máme celý systém pohromadě, můžeme začít s plánováním. Zkusíme systému zadat několik jednoduchých úkolů a podíváme se na nalezená řešení. Zkusíme zadat tyto úkoly: start(stav(robotv,m3)). start(stav(robotna,bedne)). start(stav(svetlo,sviti)). start(stav(robotv,m1)). Chování systému přímo v interpretu Prologu bude následující:?- start( stav( robot_v, m3 ) ). stav(robot_na, zemi) stav(bedna_v, m2) stav(svetlo, nesviti) stav(robot_v, m3) jdi(m1, m4) => [[robot_v, m4], [svetlo, nesviti], [bedna_v, m2], [robot_na, zemi]] jdi(m4, m3) => [[robot_v, m3], [svetlo, nesviti], [bedna_v, m2], [robot_na, zemi]]?- start( stav( robot_na, bedne ) ). stav(bedna_v, m2) stav(svetlo, nesviti) stav(robot_na, bedne) jdi(m3, m4) => [[robot_v, m4], [svetlo, nesviti], [bedna_v, m2], [robot_na, zemi]] jdi(m4, m2) => [[robot_v, m2], [svetlo, nesviti], [bedna_v, m2], [robot_na, zemi]] vylez => [[robot_na, bedne], [svetlo, nesviti], [bedna_v, m2]] 10
?- start( stav( svetlo, sviti ) ). stav(bedna_v, m3) stav(robot_na, bedne) stav(svetlo, sviti) jdi(m4, m1) => [[robot_v, m1], [robot_na, zemi], [svetlo, nesviti], [bedna_v, m2]] jdi(m1, m4) => [[robot_v, m4], [robot_na, zemi], [svetlo, nesviti], [bedna_v, m2]] jdi(m4, m2) => [[robot_v, m2], [robot_na, zemi], [svetlo, nesviti], [bedna_v, m2]] jdi(m2, m4) => [[robot_v, m4], [robot_na, zemi], [svetlo, nesviti], [bedna_v, m2]] slez => [[robot_v, m2], [robot_na, zemi], [svetlo, nesviti], [bedna_v, m2]] vylez => [[robot_na, bedne], [svetlo, nesviti], [bedna_v, m2]] slez => [[robot_v, m2], [robot_na, zemi], [svetlo, nesviti], [bedna_v, m2]] presun(m2, m4) => [[bedna_v, m4], [robot_v, m4], [robot_na, zemi], [svetlo, nesviti]] presun(m4, m1) => [[bedna_v, m1], [robot_v, m1], [robot_na, zemi], [svetlo, nesviti]] presun(m1, m4) => [[bedna_v, m4], [robot_v, m4], [robot_na, zemi], [svetlo, nesviti]] presun(m4, m3) => [[bedna_v, m3], [robot_v, m3], [robot_na, zemi], [svetlo, nesviti]] vylez => [[robot_na, bedne], [bedna_v, m3], [svetlo, nesviti]] rozsvit => [[svetlo, sviti], [robot_na, bedne], [bedna_v, m3]]?- start( stav( robot_v, m1 ) ). stav(svetlo, sviti) stav(bedna_v, m3) stav(robot_na, zemi) stav(robot_v, m1) 11
slez => [[robot_v, m3], [robot_na, zemi], [svetlo, sviti], [bedna_v, m3]] jdi(m3, m4) => [[robot_v, m4], [robot_na, zemi], [bedna_v, m3], [svetlo, sviti]] jdi(m4, m1) => [[robot_v, m1], [robot_na, zemi], [bedna_v, m3], [svetlo, sviti]]?- 1.4 Řešeníproblémudvounádob9la4l Podívejme se ještě na řešení jednoho úkolu s použitím systému GPS a STRIPS. Přiklad dvou nádob je výhodný jako praktická ukázka. Má jen dvěstavovéveličiny,ztomůževéstkpředstavě,žecelýproblémbudejednodušší, než příklad s robotem. Analýza však rychle odhalí, že se objevují drobné komplikace. Upozorníme na ně, během realizace. 1.4.1 GPS-dvěnádoby Stavové veličiny si zjednodušíme jako jedinou dvojici čísel a výsledek analýzy a plánování bude následující: % pocatecni stav sveta stav( 0, 0 ). % 9l, 4l % seznam akci - vsechny akce modifikuji stav % neni proto potreba definovat dvojice (akce - promenna) akce( dolej1 ). akce( dolej2 ). akce( vylej1 ). akce( vylej2 ). akce( prelej12 ). akce( prelej21 ). % preliti z X do Y, kdy YM je maximum Y. % vysledek jde do X1, Y1 prelej( X, Y, YM, X1, Y1 ) :- Z is YM - Y, Z > 0, % volne misto v Y min( X, Z, Z2 ), % ceho je mene? vody nebo mista? X1 is X - Z2, Y1 is Y + Z2,!. % planovaci akce 12
% doliti dolej1( _, Y, 9, Y ). dolej2( X, _, X, 4 ). % vyliti vylej1( _, Y, 0, Y ). vylej2( X, _, X, 0 ). % prelivani prelej12( X, Y, X1, Y1 ) :- prelej( X, Y, 4, X1, Y1 ). prelej21( X, Y, X1, Y1 ) :- prelej( Y, X, 9, Y1, X1 ). Zde je asi na místě, objasnit funkci predikátu prelej. Jak jednoduše odpovědět na otázku, kolik vody můžeme přelít z první do druhé nádoby? Záležínatom,čehojeméně:buďkapalinyvprvnínádobě,nebovolného místa v nádobě druhé. Dále narazíme při aplikaci postupu pokus omyl na problém zacyklení. Systém začne nádoby naplňovat a vylévat a k žádnému výsledku nedospěje. Musíme proto rozvoj stromu řešení trochu usměrnit. To lze snadno udělat dvěma způsoby: sledovat stavy světa a nepřipustit stav, který už dříve byl, nebo omezit hloubku stromu řešení. První metoda je efektivnější, druhá jednodušší. Podívejme se na výsledné řešení: % jadro GPS - s omezenim, kdy stav sveta se nesmi opakovat cil( C ) :- C. cil( C ) :- akce( A ), stav( X, Y ), D =.. [ A, X, Y, X1, Y1 ], % vyber akci % vytvoreni volani akce D, % vyvolani akce assertb( bylo( X1, Y1 ) ), % nesmi se opakovat stav sveta % evidence planu akci assertu( plan( provedeno( A, stav( X1, Y1 ) ) ) ), retractu( stav( X, Y ) ), % zmena stavu sveta assertu( stav( X1, Y1 ) ), cil( C ). % navrat do stavu 0 stav0 :- 13
retractall( bylo( _, _ ) ), retractall( plan( _ ) ), retractall( stav( _, _ ) ), assert( stav( 0, 0 ) ). % spusteni hledani reseni % Priklad: % start( stav( 5, 0 ) ). % start( stav( 0, 1 ) ). % start( stav( 3, 0 ) ). % start( stav( 7, 0 ) ). start( C ) :- stav0, cil( C ), planovani. % ********************************************************* % jadro GPS s omezenim na pocet kroku rozvoje stromu reseni ciln( C, _ ) :- C. ciln( C, N ) :- N > 0, akce( A ), % vyber akci stav( X, Y ), D =.. [ A, X, Y, X1, Y1 ], % vytvoreni dotazu D, % volani akce assertu( plan( provedeno( [ N, A ], stav( X1, Y1 ) ) ) ), retractu( stav( X, Y ) ), % zmena stavu sveta assertu( stav( X1, Y1 ) ), N1 is N - 1, ciln( C, N1 ). % rekurze % spusteni hledani reseni s omezeni rozvoje stromu reseni % pouziti stejne jako start(...) omezeni( 12 ). startn( C ) :- stav0, omezeni( N ), ciln( C, N ), 14
planovani. % ********************************************************* % pomocne predikaty min( A, B, C ) :- A < B,!, C = A;!, C = B. % vypis planu planovani :- stav( X, Y ), write( ), nl, write( stav( X, Y ) ), nl, nl, write( ), nl, fail. planovani :- plan( provedeno( A, X ) ), write( A ), write( => ), write( X ), nl, fail. planovani :-!. Teď systém vyzkoušíme:?- start( stav( 2, 0 ) ). stav(2, 0) dolej1 => stav(9, 0) dolej2 => stav(9, 4) vylej1 => stav(0, 4) prelej21 => stav(4, 0) dolej2 => stav(4, 4) prelej21 => stav(8, 0) dolej2 => stav(8, 4) prelej21 => stav(9, 3) vylej1 => stav(0, 3) prelej21 => stav(3, 0) dolej2 => stav(3, 4) prelej21 => stav(7, 0) dolej2 => stav(7, 4) prelej21 => stav(9, 2) vylej1 => stav(0, 2) prelej21 => stav(2, 0) 15
?- start( stav( 3, 0 ) ). stav(3, 0) dolej1 => stav(9, 0) dolej2 => stav(9, 4) vylej1 => stav(0, 4) prelej21 => stav(4, 0) dolej2 => stav(4, 4) prelej21 => stav(8, 0) dolej2 => stav(8, 4) prelej21 => stav(9, 3) vylej1 => stav(0, 3) prelej21 => stav(3, 0)?- startn( stav( 5, 0 ) ). stav(5, 0) [12, dolej1] => stav(9, 0) [11, dolej1] => stav(9, 0) [10, dolej1] => stav(9, 0) [9, dolej1] => stav(9, 0) [8, dolej1] => stav(9, 0) [7, dolej1] => stav(9, 0) [6, dolej1] => stav(9, 0) [5, dolej1] => stav(9, 0) [4, dolej1] => stav(9, 0) [3, dolej1] => stav(9, 0) [2, prelej12] => stav(5, 4) [1, vylej2] => stav(5, 0)?- startn( stav( 6, 0 ) ). stav(6, 0) [12, dolej1] => stav(9, 0) [11, dolej1] => stav(9, 0) 16
[10, dolej1] => stav(9, 0) [9, dolej1] => stav(9, 0) [8, prelej12] => stav(5, 4) [7, vylej2] => stav(5, 0) [6, prelej12] => stav(1, 4) [5, vylej2] => stav(1, 0) [4, prelej12] => stav(0, 1) [3, dolej1] => stav(9, 1) [2, prelej12] => stav(6, 4) [1, vylej2] => stav(6, 0)?- 1.4.2 STRIPS- dvě nádoby A pro úplnost ještě varianta dvou nádob řešená v systému STRIPS. Popis akcí a jádro systému i s pomocnými predikáty bude následující: % pocatecni stav stav( 0, 0 ). % 9l, 4l % preliti z nadoby Y1 do nadoby X1 - odhad predchoziho stavu % X1, Y1 - pocatecni stav nadob % MX - maximum nadoby X % X, Y - vysledek prelej( X, Y, MX, X1, Y1 ) :- ZX is MX - X1, min( ZX, Y1, M ),!, % mensi je volne misto v X1 % nebo aktualni obsah Y1? M >= 0, % prelit bylo mozno jen kladny pocet X is X1 + M, Y is Y1 - M, X =< MX, % nesmime preplnit X Y >= 0. % a vylit Y vic nez do 0 % planovaci akce % nema smysl vylivat poloprazdne nadoby, viz. trace... akce( vylit1, [ stav( 9, Y ) ], [ stav( 9, Y ) ], 17
[ stav( 0, Y ) ] ). akce( vylit2, [ stav( X, 4 ) ], [ stav( X, 4 ) ], [ stav( X, 0 ) ] ). % doliva se vzdy do plna akce( dolit1, [ stav( 0, Y ) ], [ stav( 0, Y ) ], [ stav( 9, Y ) ] ). akce( dolit2, [ stav( X, 0 ) ], [ stav( X, 0 ) ], [ stav( X, 4 ) ] ). % prelivani akce( prelit21( X, Y, X1, Y1 ), [ prelej( Y, X, 4, Y1, X1 ), stav( X, Y ) ], [ stav( X, Y ) ], [ stav( X1, Y1 ) ] ). akce( prelit12( X, Y, X1, Y1 ), [ prelej( X, Y, 9, X1, Y1 ), stav( X, Y ) ], [ stav( X, Y ) ], [ stav( X1, Y1 ) ] ). % plneni jednoho cile cil( C ) :- C. cil( C ) :- rozpracovano( C ),!, fail. cil( C ) :- assertu( rozpracovano( C ) ), akce( Akce, Podm, Pryc, Pridat ), member( C, Pridat ), cile( Podm ), odeber_seznam( Pryc ), pridej_seznam( Pridat ), retractu( rozpracovano( C ) ), stav( X, Y ), assertu( plan( provedeno( Akce, stav( X, Y ) ) ) ). % navrat do stavu 0 stav0 :- retractall( stav( _, _ ) ), 18
assert( stav( 0, 0 ) ). % spusteni hledani start( X ) :- stav0, retractall( rozpracovano( _ ) ), retractall( plan( _ ) ), cil( X ), planovani. % ******************************************************* % pomocne predikaty % minimum ze dvou cisel min( X, Y, M ) :- X < Y, M is X,! ; M is Y,!. % plneni seznamu cilu cile( [] ). cile( [ H T ] ) :- cil( H ), cile( T ). % pridani seznamu cilu pridej_seznam( [] ). pridej_seznam( [ H T ] ) :- assertu( H ), pridej_seznam( T ). % odebrani seznamu cilu odeber_seznam( [] ). odeber_seznam( [ H T ] ) :- retractu( H ), odeber_seznam( T ). % vypis planu planovani :- stav( X, Y ), write( ), nl, write( stav( X, Y ) ), nl, nl, write( ), nl, fail. planovani :- plan( provedeno( A, X ) ), write( A ), write( => ), write( X ), nl, fail. planovani :-!. 19
A výsledné chování systému:?- start( stav( 5, 0 ) ). stav(5, 0) dolit2 => stav(0, 4) dolit1 => stav(9, 4) vylit2 => stav(9, 0) prelit12(9, 0, 5, 4) => stav(5, 4) vylit2 => stav(5, 0)?- start( stav( 0, 1 ) ). stav(0, 1) dolit1 => stav(9, 0) dolit2 => stav(9, 4) vylit1 => stav(0, 4) prelit21(0, 4, 4, 0) => stav(4, 0) dolit2 => stav(4, 4) prelit21(4, 4, 8, 0) => stav(8, 0) dolit2 => stav(8, 4) prelit21(8, 4, 9, 3) => stav(9, 3) vylit1 => stav(0, 3) prelit21(0, 3, 3, 0) => stav(3, 0) dolit2 => stav(3, 4) prelit21(3, 4, 7, 0) => stav(7, 0) dolit2 => stav(7, 4) prelit21(7, 4, 9, 2) => stav(9, 2) vylit1 => stav(0, 2) prelit21(0, 2, 2, 0) => stav(2, 0) dolit2 => stav(2, 4) prelit21(2, 4, 6, 0) => stav(6, 0) dolit2 => stav(6, 4) prelit21(6, 4, 9, 1) => stav(9, 1) vylit1 => stav(0, 1)?- start( stav( 3, 0 ) ). 20
stav(3, 0) dolit2 => stav(0, 4) dolit1 => stav(9, 4) vylit2 => stav(9, 0) prelit12(9, 0, 5, 4) => stav(5, 4) vylit2 => stav(5, 0) prelit12(5, 0, 1, 4) => stav(1, 4) vylit2 => stav(1, 0) prelit12(1, 0, 0, 1) => stav(0, 1) dolit1 => stav(9, 1) prelit12(9, 1, 6, 4) => stav(6, 4) vylit2 => stav(6, 0) prelit12(6, 0, 2, 4) => stav(2, 4) vylit2 => stav(2, 0) prelit12(2, 0, 0, 2) => stav(0, 2) dolit1 => stav(9, 2) prelit12(9, 2, 7, 4) => stav(7, 4) vylit2 => stav(7, 0) prelit12(7, 0, 3, 4) => stav(3, 4) vylit2 => stav(3, 0)?- start( stav( 7, 0 ) ). stav(7, 0) dolit2 => stav(0, 4) dolit1 => stav(9, 4) vylit2 => stav(9, 0) prelit12(9, 0, 5, 4) => stav(5, 4) vylit2 => stav(5, 0) prelit12(5, 0, 1, 4) => stav(1, 4) vylit2 => stav(1, 0) prelit12(1, 0, 0, 1) => stav(0, 1) dolit1 => stav(9, 1) prelit12(9, 1, 6, 4) => stav(6, 4) vylit2 => stav(6, 0) prelit12(6, 0, 2, 4) => stav(2, 4) vylit2 => stav(2, 0) prelit12(2, 0, 0, 2) => stav(0, 2) dolit1 => stav(9, 2) 21
prelit12(9, 2, 7, 4) => stav(7, 4) vylit2 => stav(7, 0)?- 2 Cvičení Plánovacím systémům jsou věnována 3 cvičení. Během této doby si každý student nejen ověří fungování prezentovaných příkladů, ale pokusí se algoritmizovat libovolný jednoduchý plánovací problém. 2.1 Ověření plánování s robotem a s dvojicí nádob První z trojice cvičení je věnováno úvodu do problematiky. Seznámení se z oběma plánovacími algoritmy GPS a Strips. Ověření dosažitelnosti všech stavů. Modifikace plánovacích aktivit, testování možných změn chování. 2.2 Výběr vlastního problému Druhé cvičení bude věnováno výběru problému, který si bude každý sám implementovat. Zvážení a konzultace náročnosti daného problému. Výběr vhodnějšího plánovacího systému. Zvážení, zda je lepší postupovat v daném případě od počátečního stavu do cílového, či obráceně, od cíle k počátku. 2.3 Odladění a prezentace plánovacího algoritmu Třetí cvičení věnované plánování bude zaměřeno na doladění, testování a prezentování vlastního systému. 22