Logikai programozás
description
Transcript of Logikai programozás
Logikai programozás
Prolog
Programnyelvek
imperatív deklaratív
funkcionális logikai
Logikai reprezentáció logikai program Predikátumok konstans argumentumokkal tények
pl. anyja(‘Diana’,’Andrew’). Horn-klóz szabály/klóz
a pozitív literál: B – következmény a klóz feje
a feltételek a klóz törzse
x, y [(apja(x,y) anyja(x,y)) szuloje(x,y)] szuloje(X,Y):-apja(X,Y). szuloje(X,Y):-anyja(X,Y).
Kérdések célok x szuloje(x,Andrew) ?-szuloje(X,Andrew).
Logikai program ‘objektumai’
Állítások Tények
konstansok vagy univerzális változók Predikátumok vagy relációk Kérdések/Célok Szabályok – Horn-klózok
Ezekben: termek Egyszerű Összetett
Termek
egyszerű term változó
nagybetűvel v. _ jellel kezdődnek _Valtozo: érdektelen: ha egy mondatban csak egyetlen
előfordulása (singleton) állandó (konstans) - atomok
név ’ ’ között, speciális jelsorozatok is! (pl. =<) 4 különleges név: ; (or, else,elseif), ! (cut), [ ] (nil), {} (empty)
szám egész lebegőpontos
- összetett term: struktúra = funktor alakjuk f(t1,…., tn) változómentes term: alapterm
Típusok és osztályozó eljárások
változók – var/1 nem változók – nonvar/1
struktúrák – compound/1 egyszerűek – atomic/1
atom – atom/1 szám – number/1
egész – integer/1 lebegőpontos – float/1
minden típus – any/1
Példák
1. A1 Fifi mindenhova követi Jánost. A2 János a parkban van. B Hol van Fifi?
2. Londoni metróhálózat
Hol van Fifi?
HelyenVan(‘Fifi’,X):-HelyenVan(‘János’,X).
HelyenVan(‘János’,park). Hol van Fifi?
?-HelyenVan(‘Fifi’,Y).
Londoni metró
Tények Összekapcsolt állomások:
közvetlen szomszédok osszekapcsolt(Allomas1, Allomas2, Vonal).
osszekapcsolt(bond_street,oxford_circus,central).osszekapcsolt(oxford_circus,tottenham_court_road,central).osszekapcsolt(bond_street,green_park,jubilee).osszekapcsolt(green_park,charing_cross,jubilee).osszekapcsolt(green_park,piccadilly_circus,piccadilly).osszekapcsolt(piccadilly_circus,leicester_square,piccadilly)
.osszekapcsolt(green_park,oxford_circus,victoria).osszekapcsolt(oxford_circus,piccadilly_circus,bakerloo).osszekapcsolt(piccadilly_circus,charing_cross,bakerloo).osszekapcsolt(tottenham_court_road,leicester_square,northern
).osszekapcsolt(leicester_square,charing_cross,northern).
Szabályok
Egymáshoz közeli állomások: azonos vonalon, köztük legfeljebb 1 állomás
ha közvetlenül össze vannak kapcsolva
kozel(X,Y):-osszekapcsolt(X,Y,L). vagy ha van egy Z állomás, amelyik össze van
kapcsolva X-szel és Y-nal is ugyanazon a vonalon
kozel(X,Y):-osszekapcsolt(X,Z,L),osszekapcsolt(Z,Y,L).
Kérdések
Milyen állomások vannak közel a Bond Streethez??- kozel(bond_street,A).
Milyen állomások vannak egymás mellett a Central vonalon??- osszekapcsolt(A,B,central).
Kérdések megválaszolása
Bizonyítási feladat Predikátumok egyesítésével = illesztésével Legáltalánosabb egyesítő helyettesítéssel Felülről lefele bizonyítás
A célsorozatból a legbaloldalibb célt választjuk A cél atomi formuláival egyesítünk állításfejeket (tény v.
szabály) ha ténnyel egyesítünk: kiejtjük a részcélt ha szabállyal egyesítünk: a szabály törzse lesz az új részcél 1 ilyen lépés: célredukciós lépés
Ha az összes részcélt kiejtettük, bebizonyítottuk a célt Ha több szabályfej is egyesíthető a részcéllal a
levezetések faszerűen elágazhatnak
Bizonyítás
Keresési fa/Levezetési fa gyökere: eredeti cél csúcsok: részcélok levelek: megoldáslevelek (üres célok) vagy fail-levelek
Legbal részcélkiválasztási módszer Végtelen levezetési fákat eredményezhet A bejárás legjobb módja a problémától függ! Prolog: szándékos döntés, memóriakihasználás
érdekésben A klózokat megfelelően rendezve általában
kiküszöbölhető a végtelen fa
A keresési fa építése
Redukciós lépés: egy célsorozatot és egy klózt kap bemenetként. 1. A klóz minden változóját új változóra cseréljük. 2. A célsorozatot felbontjuk első hívásra és maradékra. 3. Az első hívást egyesítjük a klózfejjel. 4. A szükséges behelyettesítéseket elvégezzük a klóz
törzsén és a célsorozat maradékán. 5. Ha a hívás és a klózfej nem egyesíthető, akkor a
redukciós lépés meghiúsul.
A keresési fa felépítése Megoldás megkeresése
1. Megkeressük az eljárás 1. olyan klózát, amelyre a redukciós lépés sikeresen lefut.
Ha nincs ilyen klóz, akkor visszalépés történik (vagy meghiúsulás, ha nem lehet visszalépni)
visszalépés = keresünk egy másik állításfejet, amely az előző részcéllal esetleg egyesíthető lesz
Ha sikerült az egyesítés, és megoldást kaptunk, akkor kiírjuk, és megkérdezzük a felhasználót, kér-e újabb megoldást.
Ha kér: visszalépés, és az 1. ponttól folytatjuk Ha nem megoldás volt, akkor a klóz törzséből új célsorozat
lesz. 2. Ha nem volt visszalépés, akkor az új célsorozat
predikátumát keressük: 1. lépés Visszalépés: mindig az eggyel feljebbi szintre
Egyesítési/illesztési algoritmus
Legáltalánosabb egyesítő helyettesítés keresése változót lehet helyettesíteni
változóval állandóval funktorral
állandót lehet helyettesíteni ugyanazzal az állandóval (pl. ‘Izsák’ – ‘Izsák’)
funktort lehet helyettesíteni funktorral
HA aritásuk és nevük megegyezik: paramétereiket illesztjük
Kérdések megválaszolása
?- osszekapcsolt(A,B,central).
?- kozel(bond_street,A).
Aritmetikai műveletek
Prolog eljárások – név/aritás Használhatjuk őket infix pozícióban is = / 2
A = B beépített eljáráshívás akkor és csak akkor sikerül, ha a két argumentuma egyesíthető
is / 2 Az X is Kif hívás a Kif aritmetikai kifejezés értékét
egyesíti X-szel. Pl. az 1*2+3 értékét így számíthatjuk ki: ? - X is 1*2+3. X=5 ? ; no
+, -, *, /, mod, // (egész osztás)
Metalogikai predikátumok
Aritmetikai műveletek, beépített eljárások =<, >=, <, >, =:=, =\= +, -, *, /, mod, // Csak aritmetikai kifejezések lehetnek az
argumentumok is/2 predikátumnak a jobb oldalán csak
aritmetikai kifejezés állhat
Termek összehasonlítása
Illesztéssel =/2 \=/2
Illesztés nélkül == \==
Rendezés: Változók, lebegőpontos, egész, név, összetett term Név: ASCII kód szerint Összetett termek: aritás, név, paraméterek neve
Termek összehasonlítása
U V U = V U \= V U == V U \== V U is V U =:= V U =\= V
1 2 nem igen nem igen nem nem igen
a b nem igen nem igen hiba hiba hiba
1+2 +(1,2) igen nem igen nem nem igen nem
1+2 2+1 nem igen nem igen nem igen nem
1+2 3 nem igen nem igen nem igen nem
3 1+2 nem igen nem igen igen igen nem
X 1+2 X=1+2 nem nem igen X=3 hiba hiba
X Y X=Y nem nem igen hiba hiba hiba
X X igen nem igen nem hiba hbia hiba
„Ciklusok” Prologban
Ciklus megvalósítása: rekurzióval Az eljárás saját magára hivatkozik
int faktorialis(int n)
{
if(n <= 1)
return 1;
return n * faktorialis(n-1);
}
Elérhetőség definiálása
B állomás akkor elérhető A állomásról, ha el lehet jutni A-ból B-be (akár átszállásokkal) össze vannak kapcsolva közvetlenül van egy A1 állomás, ahonnan B állomás
elérhető
Tényekkelelerheto(bond_street,charing_cross).elerheto(bond_street,green_park).elerheto(bond_street,leicester_square).elerheto(bond_street,oxford_circus).elerheto(bond_street,piccadilly_circus).elerheto(bond_street,tottenham_court_road).elerheto(green_park,charing_cross).elerheto(green_park,leicester_square).elerheto(green_park,oxford_circus).elerheto(green_park,piccadilly_circus).elerheto(green_park,tottenham_court_road).elerheto(leicester_square,charing_cross).elerheto(oxford_circus,charing_cross).elerheto(oxford_circus,leicester_square).elerheto(oxford_circus,piccadilly_circus).elerheto(oxford_circus,tottenham_court_road).elerheto(piccadilly_circus,charing_cross).elerheto(piccadilly_circus,leicester_square).elerheto(tottenham_court_road,charing_cross).elerheto(tottenham_court_road,leicester_square).
Rekurzió
Elérhető egy állomás egy másikból, ha több másik állomást érintve eljuthatunk egyikből a másikba
1. megoldás (nem praktikus):elerheto0(X,Y):- osszekapcsolt(X,Z,L).
elerheto1(X,Y):- osszekapcsolt(X,Z,L1), osszekapcsolt(Z,Y,L2).
elerheto2(X,Y,Z1,Z2):- osszekapcsolt (X,Z1,L1), osszekapcsolt(Z1,Z2,L2), osszekapcsolt(Z2,Y,L3).
Rekurzív szabályokkal
össze vannak kapcsolva közvetlenül
elerheto(X,Y):-osszekapcsolt(X,Y,L).
vagy van egy A1 állomás, ahonnan B állomás elérhető
elerheto(X,Y):-osszekapcsolt(X,Z,L),
elerheto(Z,Y).
Rekurzív szabályok
Szabály törzsében szerepel a fejben levő predikátum
Rekurzió ne legyen végtelen: nemnegatív, monoton csökkenő függvényt kell
találni itt a függvény: a még feldolgozandó út hossza
a fában (azaz a közbülső állomások száma egyre csökken, amíg közvetlenül össze nincsenek kapcsolva)
ökölszabály: A nem rekurzív klózokat a rekurzívak elé! – jobbrekurzív programok
Struktúrák
Funktorok, összetett termek Több objektumból álló szerkezetek
reprezentálására Beépített és saját definiálás
Beépített példák aritmetikai műveletek: +, -, *, /, mod … függvények: cos, sin, sqrt, …
Utak két állomás közöttSaját struktúrák (listák) Út A és B állomás között: ha B állomás
elérhető A-ból, akkor a közöttük elhelyezkedő állomások listája az út hossza 0, ha közvetlenül össze vannak
kapcsolva – nincsut konstanssal jelöljük az 1 hosszú, Z állomáson át vezető út: ut(Z) 2 hosszú, Z1 és Z2 állomáson át vezető út: ut(Z1,Z2)
…
Utak meghatározása (max. 2 hosszú)
elerheto1(X,Y,nincsut):-osszekapcsolt(X,Y,L).
elerheto1(X,Y,ut(Z)):- osszekapcsolt(X,Z,L1),osszekapcsolt(Z,Y,L2).
elerheto1(X,Y,ut(Z1,Z2)):- osszekapcsolt(X,Z1,L1),osszekapcsolt(Z1,Z2,L2),osszekapcsolt(Z2,Y,L3).
?-elerheto1(oxford_circus, charing_cross, R)
Megoldások
?-elerheto1(oxford_circus, charing_cross, R)
R = ut(piccadilly_circus) ;
R = ut(tottenham_court_road, leicester_square) ;
R = ut(piccadilly_circus, leicester_square) ;
No
Rekurzív megoldással
%rekurzioval
elerheto_ut2(X,Y,nincsut):-osszekapcsolt(X,Y,L).
%E: elso allomas, M: ut maradeka
elerheto_ut2(X,Y,ut(E,M)):-osszekapcsolt(X,E,L),
elerheto_ut2(E,Y,M).
Megoldások
Listák
az ut funktor megfelel a ./2 beépített funktornak: „ listaépítő” funktor
Lista: összetett adatszerkezet .(E, M) struktúrát [E | M] alakban is írhatjuk
E: lista első eleme (feje), M: a lista maradéka (törzse/farka)
az [X1, X2, …, Xn | [] alakból a [] elhagyható lista jelölése: [1, 2, 3] - ez a .(1, .(2, .(3,[])))
lista
Listák
Közönséges adattípus
% :- type list(T) ---> .(T, list(T)) ; [].
Valódi Üres: [] Nem üres
Részleges Konstruktora: ./2
Lista építése
.(X, Xs) konstruktort [X | Xs] alakban is írhatjuk az [X1, X2, …, Xn | [] alakból a [] elhagyható lista jelölése: [1, 2, 3] - ez a .(1, .(2, .(3,[])))
lista
Utak keresése listával
elerheto2(X,Y,[]):-osszekapcsolt(X,Y,L).
elerheto2(X,Y,[Z|R]):-osszekapcsolt(X,Z,L),
elerheto2(Z,Y,R).
%kerdes: min. 2 hosszu utakat keres
%?- elerheto2(bond_street,
piccadilly_circus,[A,B|C]).
Termek összehasonlítása
Beépített predikátumok Relációs műveletek: <,>,=<,=> Egyenlőség vizsgálata:
=, \= termek egyenlőségének vizsgálata és egyesítése
==, \== termek egyenlőségének vizsgálata egyesítés nélkül
=:=, =\= aritmetikai kifejezések egyenlőségének vizsgálata
Egyesítés (értékadás) is/2
term egyesítése aritmetikai kifejezéssel jobb oldalon csak behelyettesített változó!
Elágazás
Szabály törzsében( ha -> akkor
; különben
) ha, akkor, különben: Prolog
célsorozatok Feltétel elágazás nélkül:(ha-> akkor) (egyenértékű ezzel:(ha -> akkor; fail) )
Másodfokú egyenlet megoldóképlete
zerus0(A,B,C,X):-X is ((-B+sqrt(B*B-4*A*C))/2*A).zerus0(A,B,C,X):-X is ((-B-sqrt(B*B-4*A*C))/2*A). Hibaellenőrzéssel (1. módszer):zerus1(A,B,C,X):-diszkriminans1(A,B,C,Y),Y>=0,X is
(-B+sqrt(B*B-4*A*C)/2*A). Hibaellenőrzés elágazással:zerus2(A,B,C,X):-
diszkriminans2(A,B,C,Y),(Y>=0 -> X is (-B+sqrt(B*B-4*A*C)/2*A);write('Nincs megoldas')).
Tagadás
X = Y X illeszthető Y-nal
X nem illeszthető Y-nal
% X \= Y : X nem illeszthető Y-nal
X \=Y :- (X=Y -> fail ; true).
Tagadás
hallgató(‘Péter’).
hallgató(‘János’).
hallgató(‘Jakab’).
nős(‘Péter’).
nős(‘József’).
nőtlen_hallgató(X) :- hallgató(X), nőtlen(X).
nőtlen(X) : - (nős(X)->fail; true). VAGYnem(nős(X)) :- (nős(X)->fail; true).
Tagadás sémája
nem(P):- (P -> fail; true). Metapredikátum
Egy szabályfej formális paramétere metacél (azaz pl. egy másik predikátum)
Pl. nem(P)
nőtlen_hallgató(X) :- hallgató(X), nem(nős(X)).
Beépített Prolog predikátum: \+
\+/1 négy tulajdonsága:
1. Sohasem hagy maga után választási pontot
2. Függetlenül a P céltól, sosem példányosítja annak változóit
3. nem(P) pontosan akkor sikeres, ha P keresési fája véges, és nem tartalmaz megoldást
4. nem(P) pontosan akkor hiúsul meg, ha P keresési fája tartalmaz megoldást, de az első megoldás előtt nincs végtelen ág.
Keresési tér csökkentése: jobbrekurzió
Nem jobbrekurzív megoldás:
length([],0).
length([H|T],N):-length(T,M),N is M+1. Jobbrekurzív megoldás (akkumulátorral):
inicializálás
length_acc(L,N):-length_acc(L,0,N). eredmény visszaadása
length_acc([],N,N). számítás
length_acc([H|T],N0,N):-N1 is N0+1,length_acc(T,N1,N).
Keresési tér csökkentése: vágás
beépített eljárás: ! mindig sikeresen lefut a szülő céltól kezdve lefele levágja a keresési
fa egyéb ágait, és megszünteti a választási pontokat
zöld/piros vágó Oka:
egy megoldásra szorítkozni egy klóz preferálása
Vágás
cél szülője: az őt tartalmazó klóz fejével illesztett cél p:-q, r. q:-s, t, u.
q(X):-s(X).
q(X):-t(X).
r(X):-s(X), !.
r(X):-t(X).
s(a).
s(b).
t(c). célok: ?-q(Y). és ?-r(Y).
Vágás
Tények:apja(‘Charles’,’Andrew’).anyja(‘Diana’,’Andrew’).szuloje(X,Y):-apja(X,Y),!.szuloje(X,Y):-anyja(X,Y).
Kérdések: Kinek a szülője Charles?
?-szuloje(‘Charles’,Gy). – zöld vágó Kik Andrew szülei?
?-szuloje(Sz,’Andrew’). – piros vágó
Feladat
Gyerek SzülőIzsák ÁbrahámIsmael ÁbrahámJákób IzsákÉzsau IzsákJózsef JákóbBenjámin JákóbJúda JákóbIzsák SáraIsmael HágárJákób RebekaÉzsau RebekaJózsef RáhelBenjámin RáhelRáhel LábánLea RáhelJúda LeaRúben Lea
Kinek ki a nagyszülője?
C nyelvű megoldás
SQL megoldás
Create View Nagyszulok
As select fiatal.gyerek as unoka, oreg.szulo as nagyszulo
From szulok fiatal, szulok gyerek
Where fiatal.szulo=oreg.gyerek;
Select nagyszulo, unoka from Nagyszulok;
Prolog megoldás
%apja(X,Y). - X az Y apjaapja(’Ábrahám’,’Izsák’).apja(’Ábrahám’,’Ismael’).apja(’Izsák’,’Jákób’).apja(’Izsák’,’Ézsau’).apja(’Jákób’,’József’).apja(’Jákób’,’Benjámin’).apja(’Jákób’,’Júda’).apja(’Lábán’,’Ráhel’).apja(’Lábán’,’Lea’).
%anyja(X,Y). – X az Y anyja
anyja(’Sára’,’Izsák’).
anyja(’Hágár’,’Ismael’).
anyja(’Rebeka’,’Jákób’).
anyja(’Rebeka’,’Ézsau’).
anyja(’Ráhel’,’József’).
anyja(’Ráhel’,’Benjámin’).
anyja(’Lea’,’Júda’).
anyja(’Lea’,’Rúben’).
%szülője(X,Y) – X az Y szülője
szülője(X,Y) :- apja(X,Y).
szülője(X,Y):- anyja(X,Y).
%nagyszülője(X,Y) – X az Y nagyszülője
nagyszülője(X,Y) :- szülője(X,Z), szülője(Z,Y).
Kérdések
Ki Izsák apja? Kik Jákób gyerekei? Kik Ábrahám unokái? Ki kinek az apja?
| ? – apja(’Ábrahám’,’Izsák’).
yes
| ?- apja(’Ábrahám’, X).
X=’Izsák’ ? ;
X=’Ismael’ ? ;
no
| ? – apja(X,’Izsák’).
X=’Ábrahám’ ?;
no
| ? – apja(X,Y).
X='Ábrahám', Y='Izsák' ? ;
X=’Ábrahám’, Y=’Ismael’ ? ;
…
Kérdések
Ki Izsák apja? | ? – apja(X, ‘Izsák’).
Kik Jákób gyerekei?/Kinek az apja Jákób? | ? – apja(‘Jákób’,X).
Kik Ábrahám unokái? | ? – nagyszülő(‘Ábrahám’,X).
Ki kinek az apja? | ? – apja(X,Y).
Egyszerű példa
Kérdés: Ki Izsák apja? | ?- apja(X,’Izsák’). Illesztés:
keresünk egy olyan klózt, amelyben az apja predikátum a fej
apja(‘Ábrahám’,’Izsák’). megpróbáljuk az argumentumokat illeszteni:
helyettesíteni X=Ábrahám
visszalépünk és újabb megoldást keresünk: nincs
Aritmetikai műveletek
Prolog eljárások – név/aritás Használhatjuk őket infix pozícióban is = / 2
A = B beépített eljáráshívás akkor és csak akkor sikerül, ha a két argumentuma egyesíthető
is / 2 Az X is Kif hívás a Kif aritmetikai kifejezés értékét
egyesíti X-szel. Pl. az 1*2+3 értékét így számíthatjuk ki: ? - X is 1*2+3. X=5 ? ; no
+, -, *, /, mod, // (egész osztás)
Vezérlésmódosítás
Ciklus helyett rekurzió Elágazás –VAGY kapcsolat
p(X) :- q(X), r(X).
p(X):- s(X).
p(X) :-
( q(X), r(X)
; s(X)
).
Elágazás – VAGY kapcsolat
beléphet(X) :- látogató(X), van_engedélye(X).
beléphet(X):- dolgozó(X).
beléphet(X) :-
( látogató(X), van_engedélye(X)
; dolgozó(X)
).
Metalogikai predikátumok
Aritmetikai műveletek, beépített eljárások =<, >=, <, >, =:=, =\= +, -, *, /, mod, // Csak aritmetikai kifejezések lehetnek az
argumentumok is/2 predikátumnak a jobb oldalán csak
aritmetikai kifejezés állhat
Termek összehasonlítása
Illesztéssel =/2 \=/2
Illesztés nélkül == \==
Rendezés: Változók, lebegőpontos, egész, név, összetett term Név: ASCII kód szerint Összetett termek: aritás, név, paraméterek neve
Rekurzív keresés
%member(X,Xs) :- X elem az Xs listának
member(X, [X | _Xs]).
%igaz, ha az 1. elem X
member(X, [_X | Xs]) :- member(X, Xs).
%ha X nem az első elem, akkor igaz, ha Xs-nek tagja
Eredmény fokozatos közelítése
%append(Xs, Ys, XsYs) :- A 2 első lista összefűzöttje az XsYs lista
append([], Ys, Ys).
%ha az első lista üres, akkor az eredmény maga a második lista
append([X | Xs], Ys, [X | Zs]) :- append(Xs, Ys, Zs).
Akkumulátor módszer
%rev_app(Xs,Ys,Zs):- Az Xs lista fordítottját fűzi össze Ys-sel
rev_app([],Ys,Ys).
rev_app([X|Xs], Ys,Zs) :- rev_app(Xs, [X|Ys],Zs).
%az Xs lista fordítottjának és az Ys összefűzöttje
Általánosítás
%reverse(Xs,Ys) :- Az Xs lista fordítottja az Ys
reverse(Xs,Ys) :- rev_app(Xs,[],Ys).
Nincs benne
%nincs_benne(Xs,Y) :- Az Xs listán nem található Y.
nincs_benne([],_Y).
nincs_benne([X|Xs],Y) :-
( X =Y -> fail
; nincs_benne(Xs,Y)
).
NSTO programok
Not Subject To Occurs Check egyesítés: v helyettesítése t-vel, HA v nem szerepel t-ben
Prolog nem ellenőrzi 1. Az állításfejben és a vele kapcsolatos kérdésekben
is paraméterként csak egyszerű termek (állandók és változók) használatosak
2. Az állításfej nem tartalmaz kettőzött változót (minden vált. egyszer fordul elő)
3. Az állításra vonatkozó célok nem tartalmaznak kettőzött változót.