Iti0210lab8
Teadmusbaas Prologis
Sissejuhatus
Proovime Prologis teha teadmusbaasi, mis võimaldab teha järeldusi kollimaailma kohta. Kollimaailm on kirjeldatud õpikus [AIMA] 7.2.

Teadmusbaas peaks koosnema kahest osast:
- reeglid, mis kirjeldavad, kuidas kollimaailm töötab
- faktid, mis kirjeldavad, mida kollimaailmas tegutsev agent seni teinud ja kogenud on
Ehk siis vaatame mingit kindlat ajahetke nagu näiteks joonisel:
Teeme järeldusi selle ajahetkel kohta. Minimaalselt peaks saama järeldada, kas mingi ruut on turvaline, järgmine samm oleks järeldada, mis on õige järgmine käik.
Abiks
- http://learnprolognow.org
- Adventure in Prolog
- Lihtsaid katsetusi saab teha veebis, ilma midagi installimata: SWISH.
- Arvutiklassis on olemas SWI-Prolog. Linuxi jaoks soovitaks GNU Prologi, mis on antud ülesande jaoks täiesti piisav.
- SWI-Prologis pane faililaiendiks ".pl". Siis käsitleb SWI-Prolog seda kui Prologi koodi, muidu võivad menüüdest vajalikud asjad puudu olla.
Mõned lihtsamad reeglid:
person(sokrates). % Sokrates on inimene mortal(X):- % kõik inimesed on surelikud person(X). mortal(X):- % teine reegel surelikkuse kohta. Prolog vaatab ükshaaval kõiki reegleid dead(X). dead(platon). % veel üks fakt
Kui me teeme päringu ?- mortal(platon). või ?- mortal(sokrates)., siis mõlemale saame vastuseks "yes" (või midagi analoogset, sõltuvalt Prologi versioonist). ?- dead(sokrates). annab aga vastuse "no", kuna selle kohta otsest fakti, ega ka sobivat reeglit ei eksisteeri.
Rekursiivne reegel:
% faktid parent(john,paul). % paul on johni vanem parent(paul,tom). % tom on pauli vanem parent(tom,mary). % mary on tomi vanem % reegel: esivanema leidmine ancestor(X,Y):- % baasjuhtum. Kui Y on X otsene vanem, siis ta ongi kohe esivanem parent(X,Y). ancestor(X,Y):- % rekursiivne reegel parent(X,Z), % Valime mingi Z-i, kes on X-i vanem ja vaatame, kas temale ancestor(Z,Y). % on võimalik rekursiivselt esivanemat leida. Z esivanem on ka X esivanem.
Prologis on küll sisse ehitatud debugger, aga esialgu võib vigade otsimise jaoks lihtsam olla teksti välja trükkida. See näeb välja protseduurilise programmeerimise moodi, aga write/1 ja nl/0 on lihtsalt loogikapredikaadid, mille väärtus on alati true.
mortal(X):-
write('kas X on inimene?'), nl,
person(X).
mortal(X):-
write('kas X on surnud?'), nl,
dead(X).
Cut ("!") on kasulik, kui tahetakse otsingut varakult lõpetada. Näiteks, kui ma teen eelnevate näidete puhul
päringu ?- mortal(X)., pakutakse mulle nii Sokratest, kui Platonit. Kui ma tean ette, et mind huvitab ainult üks vastus, siis ma võin teha nii:
existmortal(X):-
mortal(X),
!. % Kui Prolog ühe sobiva X väärtuse on leidnud ja siia kohta jõudnud
% siis ta rohkem enam ei proovi.
Eituse jaoks on sümbol "\+" (siin on pikem seletus):
deceased(X):- mortal(X), \+ alive(X). mortal(mccartney). mortal(lennon). alive(mccartney).
Kui mingit asja tahetakse dünaamiliselt modifitseerida, siis tuleb seda Prologile ette deklareerida.
:- dynamic(person/1).
Peale seda query ?- retract(person(sokrates)). õnnestub.
Kui mingi predikaat on dünaamiline, siis saab selle kohta ka reegleid teha, ilma et predikaat ise oleks defineeritud. Alljärgnev on OK, isegi kui breeze fakte Prologi andmebaasis ei leidu:
:- dynamic(breeze/1). agentpos(1, 1, 1). % agent asus ajahetkel 1 kohal 1, 1 breezy(X, Y):- % koordinaat X, Y on tuuline, kui agentpos(X, Y, T), % agent on kohal X, Y ajahetkel T ja breeze(T). % agent tajub tuuletõmmet ajahetkel T
Alakriips on anonüümne muutuja (meid ei huvita, mis ta väärtus on):
visited(X, Y) :- agentpos(X, Y, _). % agendi positsioon mingil suvalisel ajahetkel oli X, Y
Tuleb tähelepanelik olla, mis on tundmatud muutujad ja mis on teadmusbaasist tuletatavad.
nopit(X, Y) :- % saab küsida nopit(X, Y). visited(L, Y), X is L + 1, % kui X on tundmatu, siis arvutatakse ta visited(L, Y) abil leitud L-ist \+ breezy(L, Y). nopit_katki(X, Y) :- % nopit_katki(X, Y) annab vea. Suudab ainult kontollida väiteid nagu nopit_katki(1,2). visited(L, Y), L is X - 1, % kui X on tundmatu, siis Prolog L-i väärtust kontrollida ei oska :-( \+ breezy(L, Y).