12

Click here to load reader

5 installation de prolog

Embed Size (px)

Citation preview

Page 1: 5 installation de prolog

Mais comment utiliser Prolog !

L’interprète de prolog :

Différents interpréteurs Prolog sont disponibles, aussi bien sous Windows que sous Linux, parmi lesquels :

- SWI-Prolog (www.swi-prolog.org).

- SICStus Prolog (www.sics.se/sicstus).

- Open Prolog (www.cs.tcd.ie/open-prolog).

- GNU-Prolog (http://www.gprolog.org/).

- Visual Prolog (http://www.visual-prolog.com/). … etc.

Dans la suite on va travailler avec l’interpréteur SWI-Prolog, c’est le plus conseillé, d’ailleurs un sondage sur

le site http://www.developpez.com/ le montre très bien.

SWI-Prolog qui est un interpréteur Prolog gratuit et disponible pour Windows et pour Linux.

Pour installer SWI-Prolog sous Windows téléchargez la dernière version stable sur le site

http://www.swi-prolog.org

Ou cliquez sur le lien suivant pour télécharger la version 6.2.2 datant de 2012 :

Télécharger SWI-Prolog 6.2.2 (version 2012) pour Windows :

http://www.gecif.net/articles/linux/swi-prolog.exe

Étapes pour programmer en Prolog :

On va avoir besoin d’un éditeur de texte et de la console SWI-prolog.

1 - Créer un fichier avec Bloc-notes ou WordPad qu’on nommeras par exemple ( exProlog ) avec

l’extension ‘.pl’.

2 - Lancer l’interpréteur SWI-Prolog en cliquant directement sur le fichier ou sinon par la commande

appropriée (généralement pl). Dans le deuxième cas, charger le fichier en tapant « [Le chemin d’accès au

fichier exProlog.pl]. »

Si vous avez mis une majuscule à l’initiale du nom de fichier, vous devrez mettre entre apostrophes :

['ExProlog'].

Le signal d'invite ‘?-‘ attend que vous saisissiez un but que le moteur de résolution Prolog tentera de

satisfaire.

3 - Recharger le fichier après chaque modification.

4 - Pour sortir: halt. ou Ctrl-D

Dans l'interprète, vous pouvez obtenir une aide sur tout prédicat prédéfini à l'aide du prédicat help.

Par example help(halt).

Pour interrompre une exécution problématique (et passer à une autre commande ou question) : Ctrl C

(puis a - pour "abort").

Un manuel de référence très détaillé est disponible sur le site de SWI-Prolog :

(http://www.swi-prolog.org/pldoc/refman/ ).

Page 2: 5 installation de prolog

Sur ce qui vient nous verrons en détails les différentes caractéristiques de Prolog.

Pour l’instant, nous nous contenterons de nous familiariser avec le Langage.

Exemple Pratique :

1 - Éditons un nouveau fichier texte nommé ‘Fichier1’ (avec l’éditeur de test Bloc-Note par exemple) et

enregistrons le avec l’extension .pl.

Voici le code source en Prolog de ce programme qui se contente de déclarer un ensemble de faits :

animal(ours).

animal(chat).

prenom(hypathie).

prenom(alex).

prenom(bissette).

poss_ani(bissette,chat).

poss_ani(alex,chat).

*Veuillez consulter le fichier [Exemples/Fichier1.pl] du CD.

Un tel fichier s’appelle base de faits, parce qu’il regroupe des faits que l’on déclare être vrais.

Voici les faits affirmés par notre programme :

- ours et chat sont des animaux.

- hypathie, alex et bissette sont des prénoms.

2 - Ouvrons le programme source Prolog.pl dans l'interpréteur Prolog en tapant :

[‘CheminD’accès\Fichier1.pl’]. ou consult(‘CheminD’accès\Fichier1’). , l'extension .pl n'est pas

indiquée dans l'instruction consult.

Ceci dit qu’il faut charger le programme.

Nous n'allons pas maintenant "exécuter" le programme comme on le fait d’habitude, mais nous

allons plutôt poser à l'interpréteur Prolog un ensemble de questions pour lesquelles l'interpréteur consultera

les faits et les règles inscrits dans le programme du fichier ‘Fichier1.pl’, nous allons donc interroger notre

base de connaissance. Dans la terminologie Prolog, on les appelle des requêtes ou buts.

Question 1: hypathie est-il un prénom ?

?- prenom(hypathie).

Remarque : On doit Vérifiés en Particulier :

1. Que nous n’avons pas pour l’instant utilisé aucune majuscule.

2. Que tous les faits et votre requête se terminent par un point.

L'interpréteur nous répond true : hypathie est bien un prénom dans la base des faits inscrits dans le

programme.

Question 2: ouria est-il un prénom ?

?- prenom(ouria).

L'interpréteur nous répond false : ouria n'est pas un prénom dans la base des faits inscrits dans le

programme.

Page 3: 5 installation de prolog

Les Variables :

Nous allons introduire la notion de variables.

Question 3: quels sont tous les animaux ?

?- animal(X).

La variable X va prendre pour valeur chaque nom d'animal. Pour passer d'un valeur à une autre il

faut appuyer sur la touche point-virgule. Une fois que la liste est terminée, Prolog la fini par un point. Le

résultat est alors :

X = ours;

X = chat.

Question 4: quels sont tous les prenoms ?

?- prenom(X).

Cette fois la variable X va prendre pour valeur chaque prénom. Le point-virgule permet toujours de

passer d'une réponse à la suivante. Le résultat final est alors :

X = hypathie;

X = alex;

X = bissette.

Question 5: existe-t-il des animaux ?

?- animal(_).

Cette fois l'expression animal(_) sera vraie chaque fois que Prolog rencontre un animal (peu-importe

lequel) dans la base des faits du programme. Comme Prolog rencontre 2 animaux, la réponse à notre

question est :

true ;

true.

Ici, Prolog vérifie l’existence d’une valeur pour cette variable (une substitution) mais ne cherche pas à

énumérer les valeurs Possibles.

Les Conjonctions :

Nous nous sommes pour l’instant limités à satisfaire un seul but à la fois, mais on peut aussi tenter de

les combiner : si l’on entre plusieurs buts séparés par des virgules, Prolog essaiera de tous les satisfaire

simultanément.

?- animal(X),poss_ani(alex,X).

Nous donne bien le X = chat .

?− animal(X) ,prenom(X) .

Nous donne heureusement False.

Maintenant nous allons introduire la notion de Règles:

Exemple 1 : l'arbre généalogique

Les données du problème sont : Alice et Luc sont mariés. Luc est le père de Jean.

La problématique à résoudre est : Qui est la mère de Jean ?

Page 4: 5 installation de prolog

Dans le code source nous indiquons que :

alice est l'épouse de luc

luc est le père de jean

de telles affirmations sont appelées des faits

Puis nous indiquons à Prolog que si un père est marié à une femme, alors cette dernière est la mère du fils :

Une telle déclaration est appelée une règle.

Le symbole :- dans une règle se lit "si".

Le symbole , (virgule) dans une règle se lit "et".

% les faits :

epouse(alice,luc). % alice est l'épouse de luc

pere(luc,jean). % luc est le père de jean

% les règles :

mere(M,E) :- pere(P,E) , epouse(M,P). % M est la mère de E si P est le père de E et si M est l'épouse de P

*Veuillez consulter le fichier [Exemples/Fichier2.pl] du CD.

Remarque : en Prolog tout ce qui suit le caractère % sur une ligne est un commentaire.

Après avoir ouvert le programme dans l'interpréteur Prolog (par la commande consult), posons-lui quelques

questions :

Question 1 : qui est l'épouse de luc ?

?- epouse(X,luc).

X = alice.

Question 2 : qui est l'époux d'alice ? (qui a pour épouse alice)

?- epouse(alice,X).

X = luc.

Question 3 : qui est le père de jean ?

?- pere(X,jean).

X = luc.

Question 4 : qui est le fils de luc ? (qui a pour père luc)

?- pere(luc,X).

X = jean.

Remarque : pour répondre à ces 4 premières questions Prolog n’à utiliser que les faits, sans utiliser la règle

définissant la mère.

Question 5 : qui est la mère de jean ?

?- mere(X,jean).

X = alice.

Question 6 : qui est le fils d'alice ? (qui a pour mère alice)

?- mere(alice,X).

X = jean.

Remarque : pour répondre à ces 2 dernières questions Prolog à utiliser cette fois la règle définissant la

mère.

Page 5: 5 installation de prolog

Question 7 : qui est le fils de jean ? (qui a pour père jean)

?- pere(jean,X).

false.

Question 8 : qui est le fils de lucienne ? (qui a pour mère lucienne)

?- mere(lucienne,X).

false.

Remarque : Prolog n'a pas la réponse à ces 2 dernières questions : il répond alors false.

Question 9 : qui est la mère de qui ?

?- mere(X,Y).

X = alice,

Y = jean.

Question 10 : combien de liens de parenté "mère/fils" existe-t-il ?

?- mere(_,_).

1 seul

true.

Question 11 : existe-t-il une personne qui est sa propre mère ?

?- mere(X,X).

NON

false.

Remarque : en Prolog le nom des variables commencent toujours par une lettre majuscule (exemple : X,

Voiture, NUMERO, etc.).

Pour bien comprendre les étapes de résolution de cette requêtes, SWI-Prolog nous propose

le ‘Débogage’ :

Pour comprendre ce qui se passe, nous allons utiliser les capacités de débogage de SWI-Prolog.

On va entrer la commande :

trace , prenom(X).

Ceci va donc lancer la requête prenom(X)., mais en demandant en plus une trace d’exécution. Prolog

répondra Call: (7) prenom(_G156) ?, ce qui signifie qu’il a projet d’appeler le prédicat prenom avec une

variable comme argument.

Pour savoir quelles sont vos possibilités à ce moment précis, tapons ‘h’. Prolog nous donnera alors la liste des

commandes disponibles. Pour l’instant, nous désirons simplement continuer l’exécution :

Tapons la barre d’espacement (ou enter).

Continuons à suivre pas à pas l’exécution de notre programme en frappant la barre d’espacement,

chaque fois que nécessaire, jusqu’à la fin de l’exécution.

SWI-Prolog (dans sa version pour Windows seulement) propose aussi une version graphique du

débogueur. Dans le menu ‘Debug’ choisissons ‘Graphical Debugger’ (ou tapons simplement guitracer.),

puis relancez la commande trace , prenom(X).

Une belle fenêtre apparaît nous permettant de suivre l’exécution du programme.

Enfin, la commande halt permet de sortir de l'interpréteur Prolog : ?- halt.

Page 6: 5 installation de prolog

Exemple : Soit le programme source suivant : pere(abraham,isaac). pere(isaac,jacob). pere(jacob,joseph). ancetre(X,Y):-pere(X,Y). ancetre(X,Y):-pere(X,Z),ancetre(Z,Y). C’est un programme récursif, et donc la trace va faire apparaître l'arbre des appels. La question est : ?- ancetre(abraham,joseph). La réponse est donc : true Voici donc les étapes que SWI-Prolog exécute avant de nous donner cette réponse : Comme on l’a déjà expliqué, on doit entrer la commande : ?- trace, ancetre(abraham,joseph).

1- Lancement de la trace :

Lorsque le calcul se termine, Prolog este en "mode trace", et le manifeste en demandant [trace] ?- au lieu de ?- Pour revenir à la boucle d'interaction ordinaire, dites : [trace] ?- notrace, nodebug. true. 3 ?-

Page 7: 5 installation de prolog

2- Le littéral-but est considéré comme placé dans une boîte munie de 2 entrées et de 2 sorties (globalement appelées les 4 ports)

Call désigne le lancement de la démonstration Fail signifie que tout espoir de démontrer le but doit être abandonné Exit annonce une démonstration réussie (mais il peut s'en trouver d'autres...) Redo signale qu'on essaie une nouvelle fois de démontrer le but, en essayant la clause suivante dans le paquet de clauses compétent. Dans le cas d'un prédicat évaluable comme tab, write ou nl, Call est immédiatement suivi de Exit. Dans celui d'un prédicat défini par un paquet de clauses, chaque Call vise une clause du paquet, et il est suivi d'une séquence de Calls aux différents littéraux qui composent le corps de la clause. Ces appels correspondent à une descente dans l'arbre des appels récursifs à l'exécuteur, et la profondeur courante est affichée entre parenthèses.

Utilisation des listes :

Les tableaux tels qu'on les connaît dans les langages impératifs n'existent pas en Prolog. Ils sont

remplacés par les listes.

Une liste en Prolog s'écrit entre crochets. Exemple : [a,b,c] est une liste contenant les 3 éléments a, b et

c. A l'intérieur d'une liste les éléments sont séparés par une virgule lorsqu’ils sont énumérés un à un.

La liste vide est représentée par [].

L'opérateur | (barre verticale) permet de définir une liste constituée de :

- Son premier élément (à gauche de l'opérateur |)

- La suite de la liste (c'est une liste, placée à droite de l'opérateur |)

[X|L] est une liste obtenue en ajoutant l'élément X au début de la liste L.

Par exemple les écritures suivantes sont toutes équivalentes : [a|[b,c]] = [a|[b|[c]]] = [a|[b|[c|[]]]] = [a,b,c]

Affichage de tous les éléments d'une liste :

Le programme source est :

afficher_liste([X|L]) :- writeln(X), afficher_liste(L).

Après avoir ouvert ce programme simple dans l'interpréteur Prolog (par la commande consult),

utilisons la fonction afficher_liste :

Question 1 : ?- afficher_liste([a,b,c]).

a

b

c

false.

Question 2 : ?- afficher_liste([a|[b|[c|[]]]]).

a

b

c

false.

Page 8: 5 installation de prolog

Test de l'appartenance à une liste :

Le programme source est :

appartient_a(X,[X|_]).

appartient_a(X,[_|L]) :- appartient_a(X,L).

Après avoir ouvert ce programme simple dans l'interpréteur Prolog (par la commande consult),

utilisons la fonction appartient_a :

Question 1 : ?- appartient_a(a,[a,b,c]).

true

Question 2 : ?- appartient_a(c,[a,b,c]).

true

Question 3 : ?- appartient_a(e,[a,b,c]).

false

Veuillez consulter le fichier [Exemples/Fichier3.pl] du CD.

Utilisation de la coupure :

La coupure est un prédicat prédéfini très important qui a pour effet de stopper la recherche de Prolog

dès qu'il aura trouvé une solution (permettant d’agir sur le comportement de l’interprète Prolog lors du

retour arrière).

Ce prédicat permet de contrôler l'espace de recherche et d'économiser le travail de Prolog en limitant

l'exploration de l'arbre de recherche.

La coupure se note ! (un point d'exclamation) dans la plupart des versions de Prolog.

Rappelons que le prédicat prédéfini is est l'opérateur d'affectation en Prolog : il affecte à la variable de

gauche la valeur de l'expression de droite, après avoir évalué cette expression. Par exemple, X is A+2.

Évalue en un premier temps l'expression A+2 puis affecte le résultat à la variable X.

Example simple:

?- X is 2, Y is X+3.

X = 2,

Y = 5.

Passons à 3 exemples d’utilisation concrète de la coupure en Prolog.

Exemple 1 de la coupure : affichage de tous les entiers de N à 1 dans l'ordre décroissant.

L'idée de base est d'écrire un prédicat afficher(N) qui s'appelle récursivement en passant en

paramètre au prédicat appelé la valeur N-1 :

afficher(N):-writeln(N),K is N-1,afficher(K). *Veuillez consulter le fichier [Exemples/Fichier4.1.pl] du CD.

Page 9: 5 installation de prolog

Le problème est que cet appel récursif ne s'arrête jamais, et affiche toutes les valeurs négatives sans fin :

?- afficher(5).

5

4

.

.

.

-3

-4

.

.

.

etc. sans arrêt ...

Une solution pour arrêter l'affichage en dessous de zéro est de rajouter une condition dans le prédicat

afficher(N) :

afficher(N):-N>0,writeln(N),K is N-1,afficher(K). *Veuillez consulter le fichier [Exemples/Fichier4.2.pl] du CD.

Cela stop en effet l'affichage à 1, mais Prolog répond alors par la négation (false) en sortant lorsque

N=0 car la condition N>0 n'est pas vérifiée :

?- afficher(5).

5

4

3

2

1

false.

La solution pour stopper l'affichage lorsque N=0 tout en répondant positivement (true) est d'utiliser la

coupure : on stoppe positivement la recherche lorsque N=0, c'est-à-dire lorsque le prédicat afficher() reçoit 0

en paramètre :

afficher(0):-!. % ne fait rien et arrête la recherche en répondant true

afficher(N):-writeln(N),K is N-1,afficher(K). % appel récursif du prédicat afficher()

*Veuillez consulter le fichier [Exemples/Fichier4.3.pl] du CD.

Et le résultat est :

?- afficher(5).

5

4

3

2

1

true.

Page 10: 5 installation de prolog

Exemple 2 de la coupure : affichage de tous les éléments d'une liste.

L'idée de base est d'écrire un prédicat afficher([X|Y]) qui affiche le premier élément X puis qui appelle

récursivement le prédicat afficher en lui passant en paramètre le reste Y de la liste:

afficher([X|Y]):-writeln(X),afficher(Y). *Veuillez consulter le fichier [Exemples/Fichier5.1.pl] du CD.

Mais là encore Prolog répond par la négation (false) lorsqu'il n'y a plus rien à afficher, c'est-à-dire

lorsque la liste reçue en paramètre par le prédicat afficher est vide :

?- afficher([a,b,c,d]).

a

b

c

d

false.

La solution consiste donc à préciser grâce à la coupure que si la liste reçue est vide, on arrête la

recherche et on répond positivement :

afficher([]):-!. % arrête si la liste est vide

afficher([X|Y]):-writeln(X),afficher(Y). % appel récursif si la liste n'est pas vide

*Veuillez consulter le fichier [Exemples/Fichier5.2.pl] du CD.

Et le résultat est :

?- afficher([a,b,c,d]).

a

b

c

d

true.

Exemple 3 de la coupure : répétition d'une proposition quelconque.

Le prédicat repeter(N,P) suivant répète N fois la proposition P :

repeter(0,_):-!. % arrête si N=0 quelque soit la proposition P

repeter(N,P):-P,X is N-1,repeter(X,P). % exécute P puis appel récursif

*Veuillez consulter le fichier [Exemples/Fichier6.pl] du CD.

Exemples d'utilisation :

?- repeter(5,write('bonjour ')).

bonjour bonjour bonjour bonjour bonjour

true.

?- repeter(2,repeter(1,writeln('3Info'))).

3Info

3Info

true.

Page 11: 5 installation de prolog

?- repeter(3,(write('prolog'),nl)).

prolog

prolog

prolog

true.

Remarque : Pour passer plusieurs prédicats dans le second paramètre de repeter on les a encadrés par des

parenthèses. le prédicat nl affiche un retour à la ligne sur la sortie standard, il est équivalent à writeln('') :

?- repeter(4,(write('prolog'),writeln(''))).

prolog

prolog

prolog

prolog

true.

Exemple 4 de la coupure : se limiter à la première réponse dans le cas de réponses multiples.

Nous retrouvons un arbre généalogique très simple : jean est le père de 3 enfants :

pere(jean,luc). % jean est le père de luc

pere(jean,remi). % jean est le père de rémi

pere(jean,laurent). % jean est le père de laurent *Veuillez consulter le fichier [Exemples/Fichier7.pl] du CD.

Posons quelques questions à l'interpréteur avec ou sans coupure :

Qui est le père de laurent ? Réponse : jean :

?- pere(X,laurent).

X = jean.

Qui est le fils de jean (qui a pour père jean) ? Réponse : jean a 3 fils luc, rémi et laurent, il y a donc 3

solutions :

?- pere(jean,X).

X = luc ;

X = remi ;

X = laurent.

Rémi a-t-il un père ? Réponse : oui :

?- pere(_,remi).

true.

Jean est-il un père ? Et là encore la réponse est triple puisque l'interpréteur a trouvé 3 fois la réponse à la

question :

?- pere(jean,_).

true ;

true ;

true.

Page 12: 5 installation de prolog

Si on veut juste savoir si Jean est un père ou pas, peu importe le nombre de fils. Dans ce cas on va

poser la question en utilisant la coupure afin de s'arrêter dès la première réponse positive :

?- pere(jean,_),!.

true.

Ainsi l'interpréteur arrête sa recherche dès le premier fils trouvé, sans perdre de temps à se

demander si jean a d'autres fils, ce qui n'a aucune importance pour répondre à la question "Jean est-il un

père ?".

De même, si on pose la question "Qui sont les fils de jean ?" avec une coupure à la fin, l'interpréteur

arrêtera la recherche dès la première solution trouvée :

?- pere(jean,X),!.

X = luc.

La question précédente peut alors se formuler ainsi : "Donnez-moi un fils de jean et un seul, peu importe

lequel".

NB : Nous détaillerons ses points dans les exemples qui suivent.