Rapport LMC - Prolog
Transcription
Rapport LMC - Prolog
SIMON Marine & WATRY Florence Universite Henri Poincare Rapport LMC - Prolog Master Informatique Universite Henri Poincaré Nancy 1 Introduction Le but de ce projet est l’implantation d’un programme d’unification avec sept règles prédéfinies : Rename, Simplify,Expand, Check,Orient,Decompose et Clash. Nous décrirons dans ce rapport les différents prédicats que nous avons utilisés dans chaque étapes de la réalisation de notre programme puis nous commenterons quelques exemples significatifs. Ce programme sera implanté en PROLOG. Master Informatique page 1 sur 19 Universite Henri Poincaré Nancy 1 Desciption des prédicats le prédicat unifie(P) occur_check(V,T) Ce prédicat teste si la variable V est contenue dans la variable T. occur_check occur_check(V,T):- compound(T), functor(T,_,A), occur_check_arg(V,T,A). Teste si T est une terme composé et appelle occur_check_arg sur T,V et A qui est l’arité de T. occur_check(V,T):- V==T. Teste si V est T. occur_check_arg occur_check_arg(V,T,1):- arg(1,T,Value), !, occur_check(V,Value). Applique occur_check sur V et le premier argument de T. occur_check_arg(V,T,N):-arg(N,T,Value), occur_check(V,Value); occur_check_arg(V,T,N2), N2 is (N-1). Applique récursivement occur_check sur V et tous les arguments de T. regle(E,R) Ce prédicat définit les différentes règles de transformations R pour une équation E. regle(?=(X,Y),clash):- compound(Y), compound(X), functor(Y,NY,_), functor(X,NX,_), NY \== NX, !. Renvoie clash si X et Y sont des termes composés et si ils n’ont pas le même nom. regle(?=(X,Y),clash):- Master Informatique compound(Y), compound(X), functor(Y,_,AY), functor(X,_,AX), AY \== AX, page 2 sur 19 Universite Henri Poincaré Nancy 1 !. Renvoie clash si X et Y sont des termes composés et si ils n’ont pas le même nombre d’arguments. regle(?=(X,Y),clash):- nonvar(X), nonvar(Y), functor(Y,NY,_), functor(X,NX,_), NY \== NX, !. Renvoie clash si X est Y sont initialisés et s’ils n’ont pas le même nom. regle(?=(X,Y),clash):- nonvar(X), nonvar(Y), functor(Y,_,AY), functor(X,_,AX), AY \== AX, !. Renvoie clash si Y et Y sont initialisés et s’ils n’ont pas le même nombre d’arguments. regle(?=(_,Y),simplify):- atomic(Y), !. Renvoie simplify si Y est une constante. regle(?=(X,Y),decompose):- compound(Y), compound(X), functor(Y,NY,AY), functor(X,NX,AX), NY==NX, AY==AX, !. Renvoie decompose si X et Y sont des termes composés et s’ils ont le même nom et le même nombre d’arguments. regle(?=(X,_),orient):- nonvar(X), !. Renvoie orient si X est une constante. regle(?=(_,Y),rename):- var(Y), !. Renvoie rename si Y est une variable. regle(?=(X,Y),check):- X \== Y, occur_check(X,Y), !. Renvoie check si X est différent de Y et que X apparait dans Y. regle(?=(X,Y),expand):- compound(Y), not(occur_check(X,Y)), !. Renvoie expand si Y est un terme composé et si X n’apparait pas dans Y. Master Informatique page 3 sur 19 Universite Henri Poincaré Nancy 1 reduit(R,E,P,Q,P2,Q1) Ce prédicat applique la régle de réduction R sur l’équation E. P est la liste des équations que l’on veut unifier (sans E). Q est la liste des résultat avant l’application de la règle R sur E. P2 est la nouvelle liste d’equation que l’on veut unifier, après l’application de la règle R sur E . Q1 est la nouvelle liste de résultats. Pour appliquer les règles de transformation, nous avons eu besoin des deux prédicats suivants : liste_arg liste_arg(?=(X,Y),1,L,L2):- arg(1,X,ValueX), arg(1,Y,ValueY), L2=[?=(ValueX,ValueY)|L], !. liste_arg(?=(X,Y),N,L,L2):- N2 is (N-1), arg(N,X,ValueX), arg(N,Y,ValueY), liste_arg(?=(X,Y),N2,[?=(ValueX,ValueY)|L],L2). Ce prédicat permet de récupérer chaque argument de X et Y et de les associer un à un sous la forme Xi ?= Yi et range le résultat dans L2. concat concat([],X,X). concat([X|Q],Y,[X|P]):-concat(Q,Y,P). Ce prédicat permet de concatener deux listes et range le résultat dans le dernier argument. reduit reduit(R,?=(X,Y),P,Q,P2,Q):- R == decompose, echo(system :[?=(X,Y)|P]), nl, echo(R), echo( :?=(X,Y)), nl, functor(X,_,A), liste_arg(?=(X,Y),A,[],L), concat(L,P,P2), !. Si la régle est décompose, on applique liste_arg sur X et Y, on récupère le résultat dans L et on concatène L avec la liste d’équations que l’on veut unifier, P. On stocke le résultat dans P2. reduit(R,?=(X,Y),P,Q,P2,Q1):- R == rename, echo(system :[?=(X,Y)|P]), nl, echo(R), echo( :?=(X,Y)), nl, substitution(P,X,Y,P2), Q1=[X=Y|Q2], substitution2(Q,X,Y,Q2), !. Si la règle est rename, on substitue X par Y dans P et on stocke le résultat dans P2. Puis on substitue X par Y dans Q et on stocke le résultat dans Q2. Et on ajoute le résultat de la règle Rename sur E dans Q2 et on stocke le résultat final dans Q1. Master Informatique page 4 sur 19 Universite Henri Poincaré Nancy 1 reduit(R,?=(X,Y),P,Q,P2,Q1):-R == simplify, echo(system :[?=(X,Y)|P]),nl, echo(R), echo( :?=(X,Y)), nl, substitution(P,X,Y,P2), Q1=[X=Y|Q2], substitution2(Q,X,Y,Q2), !. Si la règle est simplify, on substitue X par Y dans P et on stocke le résultat dans P2. Puis on substitue X par Y dans Q et on stocke le résultat dans Q2. Et on ajoute le résultat de la règle Rename sur E dans Q2 et on stocke le résultat final dans Q1. reduit(R,?=(X,Y),P,Q,P2,Q1):-R == expand, echo(system :[?=(X,Y)|P]), nl, echo(R), echo( :?=(X,Y)), nl, substitution(P,X,Y,P2), Q1=[X=Y|Q2], substitution2(Q,X,Y,Q2), !. Si la règle est expand, on substitue X par Y dans P et on stocke le résultat dans P2. Puis on substitue X par Y dans Q et on stocke le résultat dans Q2. Et on ajoute le résultat de la règle Rename sur E dans Q2 et on stocke le résultat final dans Q1. reduit(R,?=(X,Y),P,Q,[?=(Y,X)|P],Q):- R == orient, echo(system :[?=(X,Y)|P]), nl, echo(R), echo( :?=(X,Y)), nl, !. Si la règle est orient, on inverse l’equation E et on l’ajoute à la nouvelle liste d’équations à unifier P. reduit(R,?=(X,Y),P,Q,P,Q):- R == check, echo(system :[?=(X,Y)|P]), nl, echo(R), echo( :?=(X,Y)), nl, fail, !. Si la règle est check, alors on signale l’echec. Master Informatique page 5 sur 19 Universite Henri Poincaré Nancy 1 reduit(R,?=(X,Y),P,Q,P,Q):- R == clash, echo(system :[?=(X,Y)|P]), nl, echo(R), echo( :?=(X,Y)), nl, fail, !. Si la règle est clash, on signale l’echec. subsitution(P,X,T,P2) Ce prédicat substitue la variable X par la variable T dans la liste P et stocke le résultat dans P2. substitution substitution([],_,_,[]):-!. Cas d’arrêt : liste vide. substitution([?=(A,B)|P],X,T,[?=(A2,B2)|P2]):- substitution_terme(A,X,T,A2), substitution_terme(B,X,T,B2), substitution(P,X,T,P2). On substitue X par T dans A et dans B, qui constituent le premier élement de P, grâce à substitution_terme et on stocke le résultat respectivement dans A2 et B2. On ajoute la nouvelle équation ?=(A2,B2) à P2 qui est le résultat de la substitution de X par T sur P. substitution_terme Le premier paramêtre est le terme sur lequel on veut appliquer la substitution. Le deuxième paramêtre est le terme à substituer par le troisième paramêtre. Le dernier paramêtre est le résultat de la subtitution sur A. substitution_terme(A,X,T,T):- not(compound(A)), A==X, !. Si A n’est pas un terme composé et que A = X alors on renvoie T. substitution_terme(A,X,_,A):- not(compound(A)), A\==X, !. Si A n’est pas composé et que A != X alors on renvoie A. % a terme compose substitution_terme(A,X,T,A2):- compound(A), functor(A,_,AriteA), substitution_arg(A,X,T,AriteA,A2), !. Si A est un terme composé on applique la substitution sur chaque argument de A grâce au prédicat substitution_arg. Master Informatique page 6 sur 19 Universite Henri Poincaré Nancy 1 substitution_arg Le premier paramêtre est le terme sur lequel on veut appliquer la substitution. Le deuxième paramêtre est le terme à substituer par le troisième paramêtre. Le quatrième paramêtre est le numéro de l’argument sur lequel on effectue la substitution. Le dernier paramêtre est le résultat de la subtitution sur A. %substitution pour chaque argument de X substitution_arg(A,X,T,1,A2):- functor(A,Nom,Arite), arg(1,A,Value), substitution_terme(Value,X,T,V), functor(A2,Nom,Arite), arg(1,A2,V), !. On récupère le premier argument de A et on applique la substitution dessus grâce a substitution_terme. On stocke le resultat dans V. On construit le terme A2 a partir du nom et de l’arité de A et on lui fixe V comme premier argument. substitution_arg(A,X,T,N,A2):- functor(A,Nom,Arite), arg(N,A,Value), substitution_terme(Value,X,T,V), functor(A2,Nom,Arite), arg(N,A2,V), N2 is (N-1), substitution_arg(A,X,T,N2,A2). On récupère le Nième argument de A et on applique la substitution dessus grâce a substitution_terme. On stocke le resultat dans V. On construit le terme A2 a partir du nom et de l’arité de A et on lui fixe V comme Nième argument. On appelle récursivement substitution_arg sur A avec N = N-1. substitution2 Ce prédicat gère la substitution pour les équations du type X = Y présentes dans la liste résultat. substitution2([],_,_,[]):-!. Cas d’arrêt : liste vide. substitution2([A=B|P],X,T,[A2=B2|P2]):- substitution_terme(A,X,T,A2), substitution_terme(B,X,T,B2), substitution2(P,X,T,P2). On substitue X par T dans A et dans B, qui constituent le premier élement de P, grâce à substitution_terme et on stocke le résultat respectivement dans A2 et B2. On ajoute la nouvelle équation (A2 = B2) à P2 qui est le résultat de la substitution de X par T sur P. Master Informatique page 7 sur 19 Universite Henri Poincaré Nancy 1 unifie(P) Ce prédicat réalise l’unification sur chaque élement de la liste P. unifieRes Ce prédicat réalise l’unification sur une liste d’équations et stocke le résultat afin de pouvoir l’afficher. unifieRes([],Q):-nl, affiche(Q), !. Cas d’arrêt : liste vide. unifieRes([X|P],Q):- regle(X,R1), reduit(R1,X,P,Q,P2,Q2), unifieRes(P2,Q2). On récupère la règle R associée à X. On applique la réduction sur X avec R. On stocke la nouvelle liste d’équations et la nouvelle liste de résultats obtenues respectivement dans P2 et Q2.On applique récursivement la réduction sur ces deux listes. unifie unifie([]):-!. Cas d’arrêt : liste vide. unifie([X|P]):- regle(X,R1), reduit(R1,X,P,[],P2,Q2), unifieRes(P2,Q2). On récupère la règle R associée à X. On applique la réduction sur X avec R. On stocke la nouvelle liste d’équations et la nouvelle liste de résultats obtenues respectivement dans P2 et Q2.On applique unifie_res sur ces deux listes. Master Informatique page 8 sur 19 Universite Henri Poincaré Nancy 1 Le prédicat Unifie(P,S) Choix premier(P,Q,E,R) Ce prédicat implante la stratégie du choix de la première équation de la liste pour appliquer l'unification. choix_premier([],_,_,_):-!. cas d'arrêt : liste vide choix_premier([E|P],Q,E,R) :- regle(E,R), reduit(R,E,P,Q,P2,Q2), unifieRes(P2,Q2). On récupère la règle associée à la première équation de la liste, E. On applique la réduction sur E avec R. On stocke la nouvelle liste d’équations et la nouvelle liste de résultats obtenues, respectivement dans P2 et Q2. On applique unifieRes sur ces deux listes. Choix_pondere(P,Q,E,R) Ce prédicat implante la stratégie du choix de l'équation dont le poids est le plus fort de la liste dont le poids est le plus fort pour appliquer l'unification. poids(R,K) Ce prédicat fixe un poids K à une règle R. poids(clash,5). poids(check,5). poids(rename,4). poids(simplify,4). poids(orient,3). poids(decompose,2). poids(expand,1). Pour définir le prédicat choix_pondere, nous avons eu besoin d'écrire les prédicats : maximum(P,R,E) Ce prédicat permet de trouver l'equation E dont la règle R à le poids maximum maximum([X],R,X):-regle(X,R),!. Cas d'arrêt : un seul élément dans la liste, c'est donc cet élément qui a le poids maximal, on renvoie cet élément ainsi que sa règle maximum([X,Y|P],R,E):- regle(X,R1), poids(R1,K1), regle(Y,R2), poids(R2,K2), K1>=K2, !, maximum([X|P],R,E). Master Informatique page 9 sur 19 Universite Henri Poincaré Nancy 1 On récupère la règle associée à la première équation de la liste ainsi que le poids associé à cette règle. On fait de même pour la deuxième équation, et on compare les poids de ces deux règles. Si le poids de la première règle est supérieur ou égal à celui de la deuxième règle, on appelle maximum sur la première équation et le reste de la liste (sans la deuxième équation) maximum([X,Y|P],R,E):- regle(X,R1), poids(R1,K1), regle(Y,R2), poids(R2,K2), K1=<K2, !, maximum([Y|P],R,E). On procède comme précedemment : on récupère les règle de la première et de la deuxième équation puis on compare leur poids. Si le poids de la première règleinférieur ou égal à celui de la deuxième règle, on appelle maximum sur la deuxième équation et le reste de la liste (sans la première équation) retire_element(P,X,P2) Ce prédicat retire l'élément X de la liste P et range le résultat dans P2. retire_element([],_,[]):-!. Cas d'arret : liste vide retire_element([Y|P],X,P):- Y == X, !. Cas d'arrêt : On a trouve l'élément X dans la liste, on renvoie le reste de la liste sans X. retire_element([Y|P],X,[Y|P2]):-Y\==X,retire_element(P,X,P2),!. Si la tête de la liste est différente de X, on renvoie la tête de la liste concaténée au résultat de retire_element sur la queue de la liste. choix_pondere(P,Q,E,R) P est la liste d'équation à unifier, Q est le résultat de l'unification, E est la première équation sur laquelle on va appliquer l'unification grâce à sa règle R. choix_pondere([],Q,_,_):- nl, affiche(Q), !. Cas d'arrêt : liste vide choix_pondere(P,Q,E,R):- maximum(P,R,E), retire_element(P,E,P2), reduit(R,E,P2,Q,P3,Q3), choix_pondere(P3,Q3,_,_). On récupère l'équation E dont la règle R a le poids maximal grâce au prédicat maximum, puis on retire l'équation E de la liste des équations à unifier. On applique la réduction sur E grâce à sa règle R et on stocke le résultat dans P3 et Q3 (respectivement la nouvelle liste des équations à unifier et la nouvelle liste de résultats). On appelle récursivement choix_pondere sur P3 et Q3. Master Informatique page 10 sur 19 Universite Henri Poincaré Nancy 1 Unifie(P,S) Ce prédicat applique l'unification sur la liste P en suivant la stratégie S. unifie([],_):-!. Cas d'arrêt : liste vide unifie([X|P],S):- S == choix_premier, choix_premier([X|P],_,_,_). Si S = choix _premier, on appelle choix_premier sur la liste passée en paramètre du prédicat unifie. unifie(P,S):- S == choix_pondere, choix_pondere(P,_,_,_). Si S = choix _pondere, on appelle choix_pondere sur la liste passée en paramètre du prédicat unifie. Unif(P,S) et trace_unif(P,S) Ces predicats permettent respectivement d’inhiber et d’activer l’affichage des règles à chaque étape de l’unification. Predicats d’affichage fournis : set_echo :- assert(echo_on). clr_echo :- retractall(echo_on). echo(T) :- echo_on,!,write(T). echo(_). affiche(L) Ce prédicat permet d’afficher une liste avec retour à la ligne entre chaque élement. affiche([]):- nl, !. affiche([X=Y|P]):- write(X=Y), nl, affiche(P). unif(P,S) unif(P,S):- clr_echo, unifie(P,S). On désactive l’affichage et on lance l’unification. trace_unif(P,S) trace_unif(P,S):- set_echo, unifie(P,S). Nous avons placé des echo(X) aux endroits nécessaires afin d’afficher le nom des règles utilisées, la liste des equations et la liste des résultats. On active l’affichage et on lance l’unification. Master Informatique page 11 sur 19 Universite Henri Poincaré Nancy 1 Interface utilisateur Afin de rendre le programme simple d’utilisation, nous avons conçu un menu où l’utilisateur est guidé tout au long de l’éxecution du programme. Master Informatique page 12 sur 19 Universite Henri Poincaré Nancy 1 interface:- writeln('Unification'), nl, equations(L), strategie(S), avec_trace(B), exec(L,S,B). equations(E):-writeln('entrez vos equations sous la forme [?=(X,Y),?=(Z,T), ...]'), read(E), writef('Vos equations: %w ',[E]), nl, nl. strategie(S):- writeln('tapez 1 si vous voulez utiliser la methode de choix premier'), writeln('tapez 2 si vous voulez utiliser la methode de choix pondere'), read(N), choix(N,S), writef('Vous avez choisi %w ',[S]), nl, nl. choix(1,choix_premier). choix(2,choix_pondere). avec_trace(R):- write('Voulez-vous utiliser la trace ?(y/n) '), read(R). exec([],_,_):-!. exec(L,S,y):- trace_unif(L,S). exec(L,S,n):- unif(L,S). Master Informatique page 13 sur 19 Universite Henri Poincaré Nancy 1 Justification des choix d’implantation et réponses aux questions Justification des choix d’implantation - Nous avons ajouté des arguments à certains des prédicats que l’on nous a demandé d’implanter dans le sujet afin de pouvoir stocker les résultats et de pouvoir les récuperer dans d’autres prédicats. Par exemple : réduit(R,E,P,Q) devient réduit(R,E,P,Q,P2,Q2) où P2 est le résultat de la substitution sur P et Q2 le résultat de la sur Q lors de l’application des règles rename, simplify et expand. - Nous avons choisi de faire ecrire à l’utilisateur directement la liste des équations à unifier car s’il les rentre une à une le lien entre les variables de chaque équation ne se fait pas. Par exemple : si l’utilisateur rentre ?=(f(a),X) puis ?=(Y,X), le premier X et le deuxième ne seront pas considérés comme la même la variable et on obtiendra le résultat : G_123 = f(a) , G_321 = G_546 alors qu’on devrait obtenir : G_123 = f(a) , G_321 = f(a). Réponse aux questions Proposer des strategies possibles autre que choix_premier et choix_pondere. - Une stratégie possible serait de choisir l’équation à unifier de manière aléatoire dans la liste. - Une autre serait de choisir en premier les équations qui engendrent un echec et s’il n’y en pas pas, utiliser la méthode du choix_premier. Master Informatique page 14 sur 19 Universite Henri Poincaré Nancy 1 Master Informatique page 15 sur 19 Universite Henri Poincaré Nancy 1 Tests Cas de succès d’un choix_premier ?- trace_unif([?=(f(X,Y),f(g(Z),h(a))),?=(Z,f(Y))],choix_premier). system:[?=(f(_G601,_G602),f(g(_G604),h(a))),?=(_G604,f(_G602))] decompose:?=(f(_G601,_G602),f(g(_G604),h(a))) system:[?=(_G601,g(_G604)),?=(_G602,h(a)),?=(_G604,f(_G602))] expand:?=(_G601,g(_G604)) system:[?=(_G602,h(a)),?=(_G604,f(_G602))] expand:?=(_G602,h(a)) system:[?=(_G604,f(h(a)))] expand:?=(_G604,f(h(a))) _G604=f(h(a)) _G602=h(a) _G601=g(f(h(a))) true . Cas d’echec d’un choix_premier ?- trace_unif([?=(f(X,Y),f(g(Z),h(a))),?=(Z,f(X))],choix_premier). system:[?=(f(_G231,_G232),f(g(_G234),h(a))),?=(_G234,f(_G231))] decompose:?=(f(_G231,_G232),f(g(_G234),h(a))) system:[?=(_G231,g(_G234)),?=(_G232,h(a)),?=(_G234,f(_G231))] expand:?=(_G231,g(_G234)) system:[?=(_G232,h(a)),?=(_G234,f(g(_G234)))] expand:?=(_G232,h(a)) system:[?=(_G2,f(g(_G2)))] check:?=(_G2,f(g(_G2))) false. Master Informatique page 16 sur 19 Universite Henri Poincaré Nancy 1 Cas d’echec d’un choix_pondere ?- trace_unif([?=(f(X,Y),f(g(Z),h(a))),?=(Z,f(X))],choix_pondere). system:[?=(f(_G231,_G232),f(g(_G234),h(a))),?=(_G234,f(_G231))] decompose:?=(f(_G231,_G232),f(g(_G234),h(a))) system:[?=(_G231,g(_G234)),?=(_G232,h(a)),?=(_G234,f(_G231))] expand:?=(_G231,g(_G234)) system:[?=(_G2,f(g(_G2))),?=(_G1,h(a))] check:?=(_G2,f(g(_G2))) false. Comparaison d’un choix_premier avec un choix_pondere sur la même liste d’équation ?- trace_unif([?=(f(X),f(a)),?=(Y,X)],choix_premier). system:[?=(f(_G1017),f(a)),?=(_G1027,_G1017)] decompose:?=(f(_G1017),f(a)) system:[?=(_G1017,a),?=(_G1027,_G1017)] simplify:?=(_G1017,a) system:[?=(_G1027,a)] simplify:?=(_G1027,a) _G1027=a _G1017=a true ?- trace_unif([?=(f(X),f(a)),?=(Y,X)],choix_pondere). system:[?=(_G241,_G231),?=(f(_G231),f(a))] rename:?=(_G241,_G231) system:[?=(f(_G231),f(a))] decompose:?=(f(_G231),f(a)) system:[?=(_G231,a)] simplify:?=(_G231,a) _G231=a _G241=a true. On constate que rename a bien été appliqué avant decompose dans le cas du choix_pondere, ainsi le poids des règles est bien respecté alors que dans le cas du choix_premier, l’ordre des equations à bien été respecté. Master Informatique page 17 sur 19 Universite Henri Poincaré Nancy 1 Comparaison d’un trace_unif et d’un unif ?- trace_unif([?=(f(X),f(a)),?=(Y,f(X))],choix_premier). system:[?=(f(_G231),f(a)),?=(_G243,f(_G231))] decompose:?=(f(_G231),f(a)) system:[?=(_G231,a),?=(_G243,f(_G231))] simplify:?=(_G231,a) system:[?=(_G243,f(a))] expand:?=(_G243,f(a)) _G243=f(a) _G231=a true. ?- unif([?=(f(X),f(a)),?=(Y,f(X))],choix_premier). _G243=f(a) _G231=a true Lorsqu’on active la trace, les noms des règles appliquées sont affichés ainsi que l’équation sur laquelle la règle est effectuée et entre chaque règle on affiche l’état de la liste d’équations à unifier. Master Informatique page 18 sur 19 Universite Henri Poincaré Nancy 1 Conclusion Ce projet nous a permis de découvrir le langage Prolog et de ce fait l’implantation d’un programme construit à partir de prédicats. La principale difficulté aura été de passer de la programmation objet à la programmation logique, notemment par le fait de ne pas pouvoir instancier de variables. Master Informatique page 19 sur 19