Vous êtes sur la page 1sur 171

ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Dr. AOUN Oussama

Année Universitaire 2020/2021


Introduction
Classes de langage
 Langages impératifs
séquencement des calculs spécifié
contrôle total du flot d’exécution
objets du langage diversifiés
syntaxe riche (lourde :-))
exemples : Pascal, C, C+, C++, Java, …

 Langages fonctionnels
 tout est fonction
– syntaxe dépouillée
– base mathématique forte : λ-calcul
 contrôle délégué à l’interprète
– utilisation intensive de la récursivité
 exemples : Lisp, Scheme, Haskell, …
Une nouvelle classe : PROgrammation en LOGique

PROgrammation en LOGique
tout est logique
syntaxe simple et dépouillée
base théorique : calcul des prédicats
encore plus de contrôle donné à la machine
récursion
non déterminisme
exemple : Prolog
Objectifs

Utiliser PROLOG

Réaliser un système expert

Résoudre automatiquement des énigmes logiques exprimées en


langage naturel

Résonner en arbre logique

Programmation sous contraintes


RAPPELS DE LOGIQUE POUR PROLOG

Logique des propositions


Logique des prédicats
Unification
LOGIQUE DES PROPOSITIONS
SYNTAXE

 On définit :
 Les propositions : a, b, c, …
 Les constantes : V et F
 Les connecteurs :

 ∧ (conjonction)
 ∨ (disjonction)

 ¬ (négation)

 ⊃ (implication)

7
CONSTRUCTION D’UNE FORMULE

 Une proposition est une formule

 Si
a et b sont des formules, alors ¬a,
a∨b, a∧b, a⊃b sont des formules

8
LOGIQUE DES PROPOSITIONS
SÉMANTIQUE
 Les formules sont interprétées dans {V,F}
 On définit l’interprétation associée à chaque
connecteur grâce aux tables de vérité

9
TABLES DE VÉRITÉ DES CONNECTEURS

A B ¬A A∧B A∨B A⊃B

V V F V V V

V F F F V F

F V V F V V

F F V F F V

10
PROPRIÉTÉS DES FORMULES

 Une formule est valide si elle est toujours vraie


(quelque soit l’interprétation)
 Une formule est consistante s’il existe une
interprétation dans laquelle elle est vraie. Elle est
inconsistante dans le cas contraire
 Problème : étant donnée une formule, est-elle
valide ? consistante ?
 Exemple : que dire de la formule
(a⊃b) ⊃(¬b⊃¬a)

11
DRESSONS LA TABLE DE VÉRITÉ

a b a⊃b ¬b ¬a ¬b⊃¬a (a⊃b)⊃(¬b⊃¬a)


V V V F F V V
V F F V F F V
F V V F V V V
F F V V V V V

12
RÈGLES DE TRANSFORMATION (1)

 a∨¬a (loi du tiers exclu)


 ((a⊃b) ∧a) ⊃ b (modus ponens)
 ((a⊃b) ∧¬b) ⊃ ¬a (modus tollens)
 (a⊃b) ⇔ (¬b ⊃ ¬a) (contraposition)
 ¬¬a ⇔ a (double négation)
 a⊃b ⇔ ¬a ∨ b
 a∨a ⇔ a∧a ⇔ a (idempotence)

13
RÈGLES DE TRANSFORMATION (2)

 Lois de De Morgan :
• ¬(a∨b) ⇔ ¬a ∧ ¬b
• ¬(a∧b) ⇔ ¬a ∨ ¬b
 Commutativité et associativité de ∨ et ∧
 Distributivité de ∨ par rapport à ∧ et de ∧ par
rapport à ∨
 X∧(X∨Y) = X, X∨(X∧Y) = X (absorption)
 X∨(¬X∧Y) = X∨Y

14
UNE ÉNIGME POLICIÈRE

 Un meurtre a été commis au laboratoire, le


corps se trouve dans la salle de conférences…
 On dispose des informations suivantes :
 La secrétaire déclare qu’elle a vu l’ingénieur dans le
couloir qui donne sur la salle de conférences
 Le coup de feu a été tiré dans la salle de
conférences, on l’a donc entendu de toutes les
pièces voisines
 L’ingénieur affirme n’avoir rien entendu
 On souhaite démontrer que :
si la secrétaire dit vrai, alors l’ingénieur ment
15
LOGIQUE DES PRÉDICATS
SYNTAXE
 On définit :
 Les constantes : V et F
 Les connecteurs : ∧ ∨ ¬ ⊃
 Les variables : x, y, z, …
 Les fonctions : f, g, h, …
 Les prédicats : p, q, r, … dont ceux d’arité 0 : a, b, c, …
 Les quantificateurs : ″ , ∃

16
DÉFINITIONS

 Terme :
 Une variable est un terme
 Une constante est un terme
 Si t1, t2, …, tn sont des termes,
alors f(t1,t2,…,tn) est un terme
 Exemple : fils(x)
 Atome :
 Si t1, t2, …, tn sont des termes, et p un prédicat,
alors p(t1,t2,…,tn) est un atome
 Exemple : pere(x,y)

17
CONSTRUCTION D’UNE FORMULE

 V, Fsont des formules


 Un atome est une formule
 Si F1 et F2 sont les formules, alors ¬F1, F1∧F2,
F1∨F2, F1⊃F2 sont des formules
 Si F est une formule, ∀ x F et ∃x F sont
des formule
 Exemples :
 ∀ x pere(x,fils(x))
 ∀ x ∀ y ∀ z (pere(x,y)∧pere(y,z)) ⊃ gpere(x,z)
 Remarque : la logique des propositions est un
cas particulier de la logique des prédicats
18
EXEMPLES DE FORMULES VALIDES

 ∀ x¬A ⇔ ¬ ∃xA
 ∀ xA ⇔¬ ∃x¬A
Comment déterminer qu’une formule
est valide ?

19
DÉFINITIONS
 Littéral
 Un atome est un littéral (positif)
 La négation d’un atome est un littéral (négatif)
 Une clause est une formule qui a la forme d’une
disjonction de littéraux
 Exemple : P(x,y) ∨ ¬Q(z)
 Une clause concrète est une clause sans
variable
 Une clause de Horn est une clause comportant
au plus un littéral positif
On peut toujours transformer une formule en un
ensemble (conjonction) de clauses
20
PRINCIPE DE RÉSOLUTION

 C’est une règle d’inférence qui s’applique aux


clauses
 Principe sur des clauses concrètes :
• G = G1∨G2∨…∨Gn
• H = ¬G1∨H2∨…∨Hm
• K = G2∨…∨Gn ∨ H2∨…∨Hm
K est le résolvant de G et H, on peut l’ajouter à la
conjonction de clauses
 G1 et ¬G1 sont des littéraux complémentaires

21
JUSTIFICATION

(P∨A)∧(¬P∨B)
= (P∧B)∨(A∧¬P) ∨(A∧B)

(P∨A)∧(¬P∨B) ∧(A∨B)
= ((P∧B)∨(A∧¬P) ∨(A∧B))∧(A∨B)
= (A∧P∧B)∨(A∧¬P)∨(A∧B)∨(P∧B)∨(A∧¬P∧B)∨(A∧B)
= (A∧B) ∨(A∧¬P) ∨(P∧B)

22
CAS PARTICULIERS

P et ¬P∨Q se résolvent en Q (modus ponens)


 ¬G∨H et ¬H∨K se résolvent en ¬G∨K
(enchaînement)
 ¬Q et ¬P∨Q se résolvent en ¬P (modus tollens)

23
UTILISATION

 Le principe de résolution est une règle


d’inférence saine, i.e. tout résolvant est une
conséquence logique des deux clauses parentes
 Pour appliquer le principe de résolution à des
clauses non concrètes, on définit l’unification,
afin de rechercher des littéraux complémentaires

24
UNIFICATION

 Deux termes t1 et t2 sont unifiables s’il existe une


substitution σ des variables de t1 et t2 telle que
ο t1 = σ t2
 Exemples :
• pere(X,jean) s’unifie avec pere(Y,Z)
si X|Y et jean|Z
• pere(jean,mere(X)) s’unifie avec pere(Y,mere(pierre))
si jean|Y et X|pierre

25
RÉFUTATION PAR RÉSOLUTION

 Pourprouver que H est une conséquence


logique de G :
 On transforme G et H en ensemble de clauses
 On applique le principe de résolution à
G∧¬H jusqu’à trouver la clause vide (faux)
 Ceprincipe est complet pour les clauses de Horn
(Prolog)

26
ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Dr. AOUN Oussama

Année Universitaire 2020/2021


PROLOG
Historique

1930 Calcul des prédicats (J. Herbrand)


1965 Principe de résolution (J. A. Robinson)
1970 Utiliser la logique comme langage de
programmation
clauses de Horn R. Kowalski
Q-systèmes A. Colmerauer
1972 Premier interprète PROLOG (A. Colmerauer et P. Roussel)
Université d’Aix-Marseille
1977 Premier compilateur PROLOG (D. H. D. Warren)
Université d’Édimbourg
1980 Projet japonais de 5e génération

1990 PROLOG évolue vers la Programmation par Contraintes

 Bibliographie
 L. Sterling, E. Shapiro, L’art de Prolog, Masson
 Clocksin, Mellish, Programmer en Prolog, Eyrolles
LE LANGAGE PROLOG

 Langage d’expression des connaissances fondé


sur le langage des prédicats du premier ordre

 Programmation déclarative :
 L’utilisateur définit une base de connaissances
 L’interpréteur Prolog utilise cette base de
connaissances pour répondre à des questions

4
CONSTANTES ET VARIABLES

 Constantes
 Nombres : 12, 3.5
 Atomes
 Chaînes de caractères commençant par une minuscule
 Chaînes de caractères entre " "

 Liste vide []

 Variables
 Chaînes de caractères commençant par une majuscule
 Chaînes de caractères commençant par _

 La variable « indéterminée » : _

5
TROIS SORTES DE CONNAISSANCES :
FAITS, RÈGLES, QUESTIONS

 Faits : P(…). avec P un prédicat


pere(jean, paul).
pere(albert, jean).
Clause de Horn réduite à un littéral positif
 Règles : P(…) :- Q(…), …, R(…).
Grpere(X,Y) :- pere(X,Z), pere(Z,Y).
Clause de Horn complète
 Questions : S(…), …, T(…).
pere(jean,X), mere(annie,X). Clause
de Horn sans littéral positif
6
Le langage

Univers PROLOG

L’univers PROLOG est une base de connaissances décrivant l’état du


monde à l’aide de relations (prédicats) portant sur des entités
(termes)

Un prédicat particulier (=) correspond à l’unification


Le langage

Syntaxe de PROLOG

Considérons l’énoncé
Socrate est un homme
Tout homme est mortel
Socrate est-il mortel ?

Calcul des prédicats Prolog

x, homme(x) homme(socrate).

x, homme(x)  mortel(x) mortel(X) :- homme(X).

?- mortel(socrate).
Le langage

La famille
masculin(tom). % tom est de sexe masculin
masculin(tim).
masculin(bob).
masculin(jim). % «paquet» de clauses

feminin(pam).
feminin(liz).
feminin(ann).
feminin(pat).

enfant(bob,pam).
enfant(bob,tom).
enfant(liz,tom).
enfant(ann,bob).
enfant(pat,bob).
enfant(tim,liz).
enfant(jim,pat).
Le langage

masculin(tom).
masculin(tim).
masculin(bob).
masculin(jim).

Premières requêtes feminin(pam).


feminin(liz).
feminin(ann).
feminin(pat).

enfant(bob,pam).
enfant(bob,tom).
enfant(liz,tom).
Est-ce que pat est un enfant de bob ? enfant(ann,bob).
enfant(pat,bob).
enfant(tim,liz).
enfant(jim,pat).
?- enfant(pat,bob).

Yes

Quels sont les enfants de tom ?

?- enfant(X,tom).

X = bob ;

X = liz ;
Règles Prolog

 Il peut y avoir plusieurs conditions derrière le « :- »,


séparées par des virgules ou des points-virgules
 La virgule correspond à un ET logique (conjonction)
 Le point-virgule correspond à un OU logique (disjonction)
 Exemple :
La relation telle que si on est le père du père ou de la mère de
quelqu’un alors on est son grand-père se traduit par :
grandpere(xavier,yves) :- pere(xavier,joe), pere(joe,yves).
grandemere(xavier,yves) :- pere(xavier,joe),
mere(joe,yves).
ou encore par :
grandpere(xavier,yves) :- pere(xavier,joe), (pere(joe,yves) ; mere(joe,yves)).

1
Constantes vs Variables

 Constantes: commencent par une minuscule ou entre


apostrophes ou entiers ou flottants
 Variables : commencent par une majuscule ou par _
 Servent à dénoter une catégorie d’objets
 Les variables utilisées dans un fait ou une règle sont
universellement quantifiées par Prolog, avec le
quantificateur ∀ (« quel que soit » ou « pour tout »).
 Les variables utilisées dans une requête sont
existentiellement quantifiées par Prolog, avec le
quantificateur ∃ (« existe-t-il »).

1
Variables

 Sont utilisées dans les règles afin de les


généraliser :
– grandpere(xavier,yves) :- pere(xavier,joe), pere(joe,yves).
–grandpere(xavier,yves) :- pere(xavier,joe), mere(joe,yves).
Généralisé par :
– grandpere(X,Y) :- pere(X,Z), (pere(Z,Y) ; mere(Z,Y))

 Peuvent aussi être utilisées dans les faits


Superman est plus fort que tout le monde se traduit par :
plusfort(superman,X).

1
Variable anonyme

 Notée '_' (tiret bas)


 Représente un objet dont on ne souhaite pas
connaître la valeur, c’est une variable muette.
 ?- invite(X,_).
Prolog ne donnera que les valeurs pour X
 Attention, une variable commençant par '_' et de
longueur >= 2 n'est pas muette par défaut en
SWI-Prolog. Activation par :
set_prolog_flag(toplevel_print_anon, false).
1
Exercice

 Exprimer en Prolog les propositions suivantes, identifier


les objets, les faits, les règles
 la chèvre est un animal herbivore
 le loup est un animal cruel
 toute chose cruelle est carnivore
 un animal carnivore mange de la viande et un animal herbivore
mange de l’herbe
 un animal carnivore mange des animaux herbivores
 les carnivores et les herbivores boivent de l’eau
 un animal consomme ce qu’il boit ou ce qu’il mange
 Question : y a-t-il un animal cruel et que consomme-t-il ?
35
Solution possible

animal(chevre). la chèvre est un animal herbivore


herbivore(chevre). le loup est un animal cruel
toute chose cruelle est carnivore
animal(loup). un animal carnivore mange de la viande et un animal
herbivore mange de l’herbe
cruel(loup).
un animal carnivore mange des animaux herbivores
les carnivores et les herbivores boivent de l’eau
carnivore(X) :- cruel(X). un animal consomme ce qu’il boit ou ce qu’il mange
Question : y a-t-il un animal cruel et que consomme-t-il ?
mange(X,viande):- animal(X), carnivore(X).
mange(X,herbe):- animal(X), herbivore(X).
mange(X,Y):- animal(X), animal(Y), carnivore(X),herbivore(Y).

boit(X,eau):- animal(X), (carnivore(X); herbivore(X)).

consomme(X,Y) :- mange(X,Y); boit(X,Y).


?- animal(X), cruel(X), consomme(X,Y).
36
RÉFUTATION PAR RÉSOLUTION

 Programme P
 P1 : Père (charlie, david).
 P2 : pere(henri, charlie).
 P3 : gpere(X,Y) :- pere(X,Z), pere(Z,Y).
 Appel du programme P
 A: gpere(X,Y).
 Réponse : X=henri, Y=david

1
7
GRAPHE DE RÉSOLUTION

A : ¬gpere(X,Y) P3 :
¬pere(X1,Z1)¬pere(Z1,Y1)gpere(X1,Y1)
X|X1
Y|Y1

¬pere(X,Z1)¬pere(Z1,Y) P2 : pere(henri, charlie)


henri|X
charlie|Z1
charlie|X
david|Z1
P1 : pere(charlie, david) ¬pere(charlie, Y)

P1 : pere(charlie, david)
david|Y
¬pere(david, Y)
échec : retour arrière succès de la réfutation
1
8
INTERPRÉTATION PROCÉDURALE : ARBRE ET-OU

gpere(X,Y)
P3
et

pere(X,Z) pere(Z,Y)
ou pere(david,Y) pere(charlie,Y)
P1 P2
ou ou
P1 P2 P1 P2
X=charlie X=henri
Z=david Z=charlie
échec échec Y=david
succès
1
9
MON PROGRAMME (1)
pere(charlie,david).
pere(henri,charlie).
gpere(X,Y) :- pere(X,Z), pere(Z,Y).
lirispc1$ swiprolog
Welcome to SWI-Prolog (Version 3.3.0)
Copyright (c) 1993-1999 University of Amsterdam.
All rights reserved.
For help, use ?- help(Topic). or ?-apropos(Word).
?- [pere].
% pere compiled 0.00 sec, 824 bytes
true.
?- listing.
pere(charlie, david).
pere(henri, charlie).
gpere(A, B) :-
pere(A, C),
pere(C, B).
true. 2
0
MON PROGRAMME (2)
?- pere(charlie,david). ?- gpere(x,y).
true. false.
?- pere(charlie,henri). ?- gpere(X,Y).
false. X = henri
?- pere(X,Y). Y = david
X = charlie
Y = david ?- gpere(henri,X).
true. X = david
?- pere(X,Y). true.
X = charlie ?- halt.
Y = david ; lirispc1$
X = henri
Y = charlie

21
ORDRE DES RÉPONSES

pere(charlie, david). ?- parents(X,Y,Z).


pere(henri, charlie).
pere(david, luc). X = david
Y = charlie
mere(sophie, charlie). Z = anne ;
mere(anne, david).
X = charlie
parents(E, P, M) :- Y = henri
pere(P, E), Z = sophie ;
mere(M, E).
false.

Prolog parcourt le paquet de clauses de haut en bas,


chaque clause étant parcourue de gauche à droite
22
EXERCICES

 On définit le programme suivant :


b(1). b(2). c(3). c(4). d(5). d(6).
a(X,Y,Z) :- b(X), c(Y), d(Z).
 Donner toutes les réponses à la requête a(X,Y,Z) dans
l’ordre où Prolog les fournit.

23
L’ÉNIGME POLICIÈRE EN PROLOG

 On dispose des informations suivantes :


 La secrétaire déclare qu’elle a vu l’ingénieur dans le
couloir qui donne sur la salle de conférences
 Le coup de feu a été tiré dans la salle de conférences,
on l’a donc entendu de toutes les pièces voisines
 L’ingénieur affirme n’avoir rien entendu

 On souhaite démontrer que si la secrétaire dit


vrai, alors l’ingénieur ment

24
L’ÉNIGME POLICIÈRE EN PROLOG

 Ordre1 : un individu entend un bruit s’il se trouve


dans une pièce voisine de celle où le bruit a été
produit
entend(Ind,Bruit) :- lieu(Ind,Piece1), lieu(Bruit,Piece2),
voisin(Piece1,Piece2).

 Faits relatifs à l’énigme :


voisin(couloir,salle_de_conf).
lieu(coup_de_feu,salle_de_conf).
lieu(ingenieur,couloir) :- secretaire_dit_vrai.
ingenieur_ment :- entend(ingenieur,coup_de_feu).
25
L’ÉNIGME POLICIÈRE EN PROLOG

 Hypothèse
secretaire_dit_vrai.
 Pour la démonstration, on pose la requête :
ingenieur_ment.

26
Commentaires dans un programme
Prolog

 Commentaire sur plusieurs lignes


/* lignes
de commentaires
l’interprète ignore
le texte entre slash étoile et étoile slash
*/
 Commentaire sur une seule ligne
% l’interprète ignore le texte après le caractère pourcent

2
7
Structures de données

 Objets atomiques : atomes, nombres, variables et


chaines de caractères
 Prolog connaît aussi les listes : listes de valeurs
entre [ ], exemple : [a, 2, c]
 Il existe aussi une structure de données plus
complexe appelée arbre Prolog ou structure
Prolog, ainsi que des dictionnaires.

2
8
Chaines de caractères

 En Prolog, les chaines de caractères sont notées


entre " "
 Les chaines sont considérées comme des
éléments atomiques, mais ne sont pas des
atomes.
 Il existe des prédicats prédéfinis permettant la
manipulation des chaines.

2
9
ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Dr. AOUN Oussama

Année Universitaire 2020/2021


Opérations arithmétiques
et logiques

2
Les expressions arithmétiques

 Prolog connaît les entiers et les nombres flottants.


 Il n’y a pas de valeur maximale pour les entiers !
 Les expressions arithmétiques sont construites à
partir de nombres, de variables et d'opérateurs
arithmétiques.
 L’évaluation d’une expression se fait par
l’utilisation de l'opérateur is par exemple dans
X is 3 - 2.

3
Expressions arithmétiques

 Opérations habituelles :
addition (+), soustraction (-),
multiplication (*), division entière (//),
division flottante (/), modulo (mod), puissance(^)
 Fonctions mathématiques prédéfinies :
abs(X), log(X), sqrt(X), exp(X), sign(X), random(X), sin(X),
cos(X), tan(X), min(X,Y), max(X,Y), pi, etc.
Exemples :
?- X is 2^20, Y is exp(1) ?- X is sin(pi/2), Y is cos(pi).
X = 1048576, X = 1.0,
Y = 2.718281828459045, Y = -1.0.
?- Z is random(100)+100. ?- S1 is sign(20), S2 is sign(-12).
Z = 151. S1 = 1, 7
S2 = -1.
Expressions arithmétiques

 Les expressions sont représentées par


des arbres Prolog
 Opérateur binaire infixé : figure entre ses 2
arguments et désigne un arbre binaire
X +Y
+

X Y

 Opérateur unaire préfixé : figure avant son


argument et désigne un arbre unaire
-X -

8
X
Les expressions arithmétiques

 Expressions et unification : attention à certaines


tentatives d’unification
 la tentative d’unification entre 3+2 et 5 échouera. En
effet, l’expression 3+2 est un arbre alors que 5 est un
nombre.
 L'évaluation des expressions ne fait pas partie de
l’algorithme d’unification.
?- 2+3 = 5.
false.

6
Les prédicats de comparaison

 Comparaison des expressions arithmétiques


 X =:= Y se traduit par X est égal à Y
 X =\= Y se traduit par X est différent de Y
 X<Y
 X =< Y
 X>Y
 X >= Y
Il y a évaluation puis comparaison.
?- 5 = 3 + 2.
false
?- 5 =:= 3 + 2.
true
7
Comparaison et unification de termes

 Comparer deux termes :


 T1==T2 réussit si T1 est identique à T2
 T1\==T2 réussit si T1 n’est pas identique à T2
 T1=T2 réussit si T1 s’unifie avec T2
 T1\=T2 réussit si T1 n’est pas unifiable à T2
Exemples :
?- f(X)==f(x).
false.
?- f(X)=f(x).
X = x.
?- f(X)\=f(x).
false.
?- f(X)\==f(x).
true. 11
Fonctions de vérification de type

 var, nonvar
?- var(X). ?- var(X), nonvar(3).
true. true.
?- X=2,var(X). ?- nonvar(X).
false. false.

 integer, float, number


?- float(exp(1)). ?- X is sign(-2.3), integer(X).
false. false.
?- X is exp(1), float(X), number(X). ?- X is sign(-2.3).
X = 2.718281828459045. X = -1.0.

 atom, string, atomic


?- atom(toto). ?- atom(3). ?- string('toto').
true. false. false.
?- atomic(toto). ?- atomic(3). ?- string("toto").
12
true. true. true.
Exercice

 Donnez les réponses de Prolog aux requêtes suivantes


?- X is 9 mod 4.
X = 1
?- X = 9 mod 4.
X = 9 mod 4
?- X == 9 mod 4.
False.
?- f(x) =:= X+3.
ERROR: Arithmetic: `f(x)' is not a function
?- f(X) = X+3.
false
?- f(X) = f(X+3).
X = X+3 13
Exercice

 Donnez les réponses de Prolog aux requêtes suivantes


?- X = 1+1+1, Y = X.
X = Y, Y = 1+1+1.
?- X = 1+1+1, Y is X.
X = 1+1+1, Y = 3.
?- X is X+1.
ERROR: Arguments are not sufficiently instantiated
?- X is 2, X is X+1.
false
?- X is 2, X1 is X+1.
X = 2, X1 = 3.

11
Les opérations d’Entrée / Sortie

12
Les entrées-sorties

 Affichage sur l'écran


 Enregistrement dans un fichier
 Lecture à partir du clavier
 Lecture d’un fichier

13
Affichage de termes

 write(1+2)
 affiche 1+2
 write(X)
 Si X n’est pas instanciée, affiche X sous la forme _2451 qui
est le nom interne de la variable.
 Affiche la valeur de X si X est instanciée.
 nl permet de passer à la ligne (nl/0)
 tab(N) affiche N espaces (tab/1)
Exemple :
?- write(3+4), nl, tab(10), write("hello !").
3+4
hello !
true. 14
Affichage de termes

 writeln/1 est équivalent à write suivi de nl


?- writeln("hello"), writeln("world !").
hello
world !
true.

 display/1 agit comme write/1 mais en affichant la


représentation sous forme d’arbre.
?- writeln(3*4+(6-(a+3))), display(3*4+(6-(a+3))).
3*4+(6-(a+3))
+(*(3,4),-(6,+(a,3)))
true.
15
Affichage de termes

 writeq/1 affiche la valeur d’un terme telle qu’elle


est représentée en Prolog :
?- write('hello world').
hello world
true.
?- writeq('hello world').
'hello world'
true.
?- write("hello world").
hello world
true.
?- writeq("hello world").
"hello world"
true.

16
Affichage d’un caractère

 put/1 s’utilise en donnant un caractère en argument,


quelle que soit sa forme : code Unicode, atome, chaine de
longueur 1 :
?- put(97).
a
true.
?- put(a).
a
true.
?- put("a").
a
true.
?- ?- put(0x2660),put(0x2663),put(0x2665),put(0x2666).
♠♣♥♦
true. 20
Affichages des chaines

 Dans les anciennes versions de Swi-Prolog et dans d’autres


interprètes Prolog, la chaîne est représentée par la liste des
codes ASCII ou Unicode des caractères la composant.
?- write("toto").
[116,111,116,111]
true.
 Depuis la version 7 de Swi-Prolog gère les chaines de
manière analogue aux autres langages de programmation,
une chaine est un objet atomique.
?- atomic("toto").
true.
?- atom("toto").
false.
 Pour retrouver l’ancienne représentation des chaines :
set_prolog_flag(double_quotes, codes).
18
Saisie de données

 Lecture de termes :
read/1 admet n’importe quel terme en argument.
read lit un terme au clavier et l’unifie avec son argument. Le
terme lu doit être obligatoirement suivi d’un point. Certains
interprètes Prolog affichent un signe d’invite lorsque le
prédicat read/1 est utilisé, c’est le cas de Swi-Prolog.
Exemple :
?- read(X).
|: a(1,2).
X = a(1,2).
?- read(A).
|: toto.
A = toto.
?- read(A).
|: "toto".
A = "toto". 19
Saisie de données

 Lecture d’un caractère :


 get/1 prend en argument un terme unifié avec le code
Unicode du caractère lu. L’argument est une variable,
qui prendra pour valeur le code Unicode du caractère
lu. get/1 ne lit que les caractères affichables, pour les
autres caractères (tabulation, retour à la ligne, etc.)
utiliser get_single_char/1.
?- get(A).
|: a
A = 97.

20
Fichiers

• Un fichier peut être ouvert en lecture (read) ou


écriture (write ou append).
• En écriture :
• mode write : son contenu est effacé avant que Prolog y
écrive.
• mode append : Prolog écrira à partir de la fin du fichier.
• Ouverture d’un fichier : prédicat open/3
• argument 1 : nom du fichier
• argument 2 : mode d’ouverture write, append ou read
• argument 3 : variable qui va recevoir un identificateur de fichier
appelé flux ou stream.
21
Fichiers

 Les prédicats read, write, writeq, writeln, get, put,


admettent un second argument : le flux identifiant le
fichier.
 Ex : writeq(Flux, X). où Flux est un identificateur de fichier
 Ex : read(Flux,X), get(Flux, X)
 Fermeture du fichier : prédicat close/1 qui prend en
argument le flux associé au fichier.
 Le prédicat get0/2 permet de lire tous les caractères
d’un fichiers, y compris les tabulations, et caractères
de fin de ligne. 22
Exemple d’usage d’un fichier

ecrire(T) :-
open('a.pl', append, Flux), /* ouverture du fichier a.pl */
write(Flux, T), nl(Flux), /* enregistrement de T */
close(Flux). /* fermeture du fichier */

?- ecrire('etoile(soleil).'). /* ajout de etoile(soleil). au fichier a.pl */

23
SYMBOLES FONCTIONNELS

 Lafonction « femme de Jean » est différente du


prédicat femme(marie,jean).
nom(femme(jean),marie).
age(femme(jean),25).
 On peut parler de la femme de jean, mais pas la
« calculer »

25
PROGRAMMATION RÉCURSIVE

 Un programme récursif est un programme qui


s’appelle lui-même

 Exemple : factorielle
 factorielle(1) = 1 (Cas d’arrêt)
 factorielle(n) = n * factorielle(n-1) si n≠1

Appel récursif
 En Prolog, un prédicat est récursif si au moins une de
26
ses règles associées réfère à lui-même.
Intérêt de la récursion

 Permet d'exprimer de manière succincte un


processus réitéré n fois
 Expl : Exprimer la relation de descendance
 Non récursif : Nombre infini de règles
descend(X,Y):- enfant(X,Y).
descend(X,Y):- enfant(X,Z), enfant(Z,Y).
descend(X,Y):- enfant(X,Z), enfant(Z,A), enfant(A,Y). ...

 Récursif : Deux règles


descend(X,Y):- enfant(X,Y).
descend(X,Y):- enfant(X,Z), descend(Z,Y).
27
Le cas de base

 Sans cas de base, la récursion ne s'arrête pas


p :-p.

?- p.

 Il faut placer le cas de base avant la relation de


récurrence dans la règle, sinon pas d'arrêt
descend(X,Y):- descend(X,Z), enfant(Z,Y).
descend(X,Y):- enfant(X,Y).
enfant(sami,ali).

?- descend(marie,paul).
39
ERROR: Stack limit (1.0Gb) exceeded
Exercice

 Ecrire l’arbre de recherche pour la requête


?- descend(marie,paul).
Avec la base :
descend(X,Y):- enfant(X,Y).
descend(X,Y):- enfant(X,Z), descend(Z,Y).
enfant(sami,ali).

 Trouvez-vous problématique la réécriture suivante du


prédicat descend ?
descend(X,Y):- enfant(X,Y).
descend(X,Y):- descend(X,Z), descend(Z,Y).
29
POUR ÉCRIRE UN PROGRAMME RÉCURSIF

 Il faut :
 Choisir sur quoi faire l’appel récursif
 Choisir comment passer du résultat de l’appel récursif
au résultat que l’on cherche (relation de récurrence)
 Choisir le(s) cas d’arrêt

30
BOUCLAGE
maries(jean, sophie). maries(jean, sophie).
maries(philippe, maries(philippe,
stephanie). stephanie).
maries(A, B) :- sont_maries(A, B) :-
maries(B, A). maries(A, B).
sont_maries(A, B) :-
?- maries(jean,sophie). maries(B, A).
true.
?- maries(sophie,jean).
true.
?- maries(X,Y).
?- sont_maries(X,Y).
X = jean
X = jean
Y = sophie ;
Y = sophie ;
X = philippe
X = philippe
Y = stephanie ;
Y = stephanie ;
X = sophie
X = sophie
Y = jean ;
Y = jean ;
X = stephanie
X = stephanie
Y = philippe ;
Y = philippe ;
false.
X = jean
?-
Y = sophie ;
19
...
UN EXEMPLE : FACTORIELLE (1)
?- trace, fact(3,R).
fact(1, 1). Call: (8) fact(3, _G237) ? creep
^ Call: (9) _G308 is 3-1 ? creep
fact(N, R) :- ^ Exit: (9) 2 is 3-1 ? creep
Nm1 is N-1, Call: (9) fact(2, _G306) ? creep
^ Call: (10) _G311 is 2-1 ? creep
fact(Nm1, Rnm1), ^ Exit: (10) 1is 2-1 ? creep
R is Rnm1*N. Call: (10) fact(1, _G309) ? creep
Exit: (10) fact(1, 1) ? creep
^ Call: (10) _G314 is 2*1 ? creep
^ Exit: (10)2is 2*1 ? creep
Exit: (9) fact(2, 2) ? creep
^ Call: (9) _G237 is 3*2 ? creep
?- fact(5,R). ^ Exit: (9) 6 is 3*2 ? creep
R = 120 ; Exit: (8) fact(3, 6) ? creep
R = 6 ;
ERROR: Out of local Redo: (10) fact(1, _G309) ? creep
stack ^ Call: (11) _G314 is 1-1 ? creep
^ Exit: (11) 0 is 1-1 ? creep
Exception: (36,276) Call: (11) fact(0, _G312) ? creep
_G4661 is-36263-1 ? ^ Call: (12) _G317 is 0-1 ? creep
^ Exit: (12) -1 is 0-1 ? creep
abort Call: (12) fact(-1, _G315) ? creep
% Execution Aborted ^ Call: (13) _G320 is-1-1 ? creep
^ Exit: (13) -2 is-1-1 ? creep

21
Il faut faire des cas exclusifs
UN EXEMPLE : FACTORIELLE (2)
fact(1, 1).
fact(N, R) :- ?- 5 is X-1.
fact(Nm1, Rnm1), ERROR: Arguments
are not
Nm1 is N-1, sufficiently
R is Rnm1*N. instantiated
% Execution
Aborted
?- fact(3,R).
?- plus(3,2,5).
ERROR: Arguments are not
sufficiently instantiated true.
^ Exception: (9) 1 is ?- plus(X,2,5).
_G241-1 ? creep X = 3
Exception: (8) true.
fact(_G241, _G255) ? creep
Exception: (7) fact(3,
_G195) ? creep
% Execution Aborted
33
UNE FACTORIELLE AVEC ACCUMULATEUR
^ Call: (9) _G308 is 3-1 ? creep
fact(N,R) :- fact(N,1,R).
^ Exit: (9) 2 is 3-1 ? creep
Call: (9) fact(2, 3, _G234) ?
fact(1,R,R). creep
fact(N,I,R) :- N>1, Call: (10) 2>1 ? creep
Nm1 is N-1, Exit: (10) 2>1 ? creep
NewI is N*I, ^ Call: (10) _G311 is 3*2 ?
fact(Nm1,NewI,R). creep
^ Exit: (10) 6 is 3*2 ? creep
^ Call: (10) _G314 is 2-1 ?
?- trace, fact(3,N). creep
Call: (7) fact(3, _G234) ? ^ Exit: (10) 1 is 2-1 ? creep
creep Call: (10) fact(1, 6, _G234) ?
Call: (8) fact(3, 1, _G234) creep
? creep Call: (11) 1>1 ? creep
Call: (9) 3>1 ? creep Fail: (11) 1>1 ? creep
Exit: (9) 3>1 ? creep Redo: (10) fact(1, 6, _G234) ?
^ Call: (9) _G305 is 1*3 ? creep
creep Exit: (10) fact(1, 6, 6) ?
^ Exit: (9) 3 is 1*3 ? creep creep
34
N = 6
ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Prof. AOUN Oussama

Année Universitaire 2020/2021


Les Listes

2
Les Listes

 Une liste est une suite de termes entre crochets,


ordonnée ou non, séparés par des virgules :
 La suite e1, e2, …, eN est représentée en Prolog par la
liste [e1, e2, …. , eN]
 Exemples :
 suite des variables X et Y est représentée par [X,Y]
 suite fraises, tarte, glace par [fraises, tarte, glace]
 Liste vide : [ ]
 Une liste peut contenir n fois le même élément : [a, a]
3
Unification de liste

 Exemple de programme menu :


entrees([artichauts, crevettes, oeufs]).
viandes([grillade_de_boeuf, poulet]).
poissons([sole, loup]).
desserts([glace, tarte, fraises]).
 Et si on pose la question :
entrees(E).
 Par unification, Prolog trouve la solution suivante :
E= [artichauts, crevettes, oeufs]

 Nous pouvons donc unifier une liste et une variable.

4
Découpage Tête Queue

 La notation [X|Y] représente une liste non-vide dont la


tête (le 1er élément) est X et la queue (le reste de la
liste) est Y.
 Cela constitue la base de l’utilisation des listes dans les
programmes Prolog.
 | symbole spécial décomposant la liste en Tête et Queue :
[Tête | Queue] correspond à [Car | Cdr ] (cf. Scheme)
 [a, b, c] ≡ [a | [b | [c | [ ] ] ] ]
 La tête est un élément et la queue est une liste :
?- [a, b] = [X|Y].
X = a, Y = [b].
5
Contenu d'une liste

 Une liste peut contenir des :


 Constantes (atomes, nombres, chaines)
 Variables
 Termes complexes
 Listes

6
Listes et sous-listes

 Modification du programme menu :


 On veut poursuivre le regroupement des données.
 Liste unique qui regrouperait tous les mets du menu
 L= [artichauts, crevettes, … , fraises]
 Cette représentation n’est pas adéquate car il n’y a pas de
distinction entre entrée, plat ou dessert.
 Il est donc nécessaire de découper la liste en sous-listes qui
rassembleront les entrées, plats et desserts. La sous-liste des
plats sera elle-même divisée en deux parties, les viandes et
les poissons.
 Cela nous donne la structure :
L = [ [artichauts, crevettes, oeufs], [grillade_de_boeuf, poulet],
[sole, loup], [glace, tarte, fraises] ]
L est de la forme : L = [L1, L2, L3, L4]
Ou L = [E, V, P, D] 64
LISTES

 Liste vide : [ ]

 Cas général : [Tete|Queue]


[a,b,c]  [a|[b|[c|[ ]]]]

8
EXEMPLES

 [X|L] = [a,b,c]  X = a, L = [b,c]


 [X|L] = [a]  X = a, L = []
 [X|L] = []  échec
 [X,Y]=[a,b,c]  échec
 [X,Y|L]=[a,b,c]  X = a, Y = b, L = [c]
 [X|L]=[X,Y|L2]  L=[Y|L2]

9
Exercice

 Dire si les expressions suivantes unifient et comment :


?- [X|Y] = [jean, marie, leo, lea].
?- [X|Y] = [].
?- [X|Y] = [a].
?- [X|Y] = [[], dort(jean), [2], [], Z].
?- [X,Y|W]=[[], dort(jean), [2], [], Z].
?- [_,X,_,Y|_] = [[], dort(jean), [2], [], Z].
?- [_,_,_,[ _|X ]|_] = [1,2, dort(jean), [2,3], [],
Z].

10
Elément d'une liste (1)

 Nous avons besoin de pouvoir considérer les


éléments d’une liste de façon individuelle, par
exemple pour récupérer un élément particulier.
 Supposons que l’on dispose du prédicat :
element_de(X,L) capable d’extraire un objet X d’une liste L.

11
Elément d'une liste (2)

 Nous voulons adapter le programme suivant aux listes :


menu(X, Y, Z) :- entree(X), plat(Y), dessert(Z).
plat(X) :- viande(X).
plat(X) :- poisson(X).
 Si on définit les entrées par une liste au lieu de faits
simples, ce programme échouera. Il faut donc le modifier.
 Pour cela nous allons donner une définition du prédicat
entree (le fait d'être une entrée) basée sur entrees (la
liste des entrées).

12
Elément d'une liste (3)

 On utilise la propriété suivante : X est une entrée, si X


est un élément quelconque de la liste des entrées.
On peut donc écrire :
entree(X) :- entrees(E), element_de(X, E).
 Et de façon analogue :
viande(X) :- viandes(V), element_de(X, V).
poisson(X) :- poissons(P), element_de(X, P).
dessert(X) :- desserts(D), element_de(X, D).

13
Accès aux éléments (1)
element_de(X, [X|_]).
element_de(X, [_|Q]) :- element_de(X, Q).

 Nous recherchons les règles qui vont assurer le


fonctionnement du prédicat element_de(X, L) qui signifie
que X est l’un des éléments de L.
 On sait que toute liste L peut se décomposer
simplement en deux parties, la tête et la queue de
liste représentées sous la forme [T|Q].
Cela nous conduit à distinguer deux cas :
 X est élément de L si X est la tête de [T|Q] : X = T.

 X est élément de L si X est élément de la queue de


[T|Q] : X est élément de Q.
69
Accès aux éléments (3)

element_de(X, [X|_]). (R1)


element_de(X, [_|Q]) :- element_de(X, Q). (R2)

 On interprète ces deux règles de la façon


suivante :
 R1 : X est élément de toute liste qui commence par X.
 R2 : X est élément de toute liste, si il est élément de
sa queue.
 Il s’agit donc d’un appel récursif. La plupart des
problèmes sur les listes ont des solutions mettant
en jeu la récursivité.
15
Récursivité et Arrêt (1)
element_de(X, [X|_]). (R1)
element_de(X, [_|Q]) :- element_de(X, Q). (R2)

On observe deux types de règles et deux types d'arrêt :


 Une ou plusieurs règles provoquent la récursivité, généralement
sur des données assez simples, et assurent le déroulement de
l’itération. Dans notre exemple, il s’agit de la règle R2.

 Une ou plusieurs règles stoppent la séquence d’appels récursifs.


Appelés en général les cas de base. Dans notre exemple, c’est
R1 qui s’en charge.
 Sauf impératif contraire, les règles d'arrêt sont placées en tête.
16
Récursivité et Arrêt (2)
(R1) element_de(X, [X|_]).
(R2) element_de(X, [_|Q]) :- element_de(X, Q).

 Il apparaît deux types d'arrêt :


 Un arrêt explicite. Par exemple, dans R1, l'identité
entre l'élément cherché et la tête de la liste fournie, ce
qu’expriment les notations X et [X|_]
 Un arrêt implicite. En particulier par la rencontre d’un
terme impossible à démontrer.
 Il existe cependant une forme d’erreur pour laquelle
ces deux blocages se révèlent insuffisants, c’est la
rencontre de listes infinies. 72
Utilisation du prédicat

element_de(X, [X|_]).
element_de(X, [_|Q]) :- element_de(X, Q).
?- element_de(X,[artichauts, crevettes, oeufs]).
X = artichauts ;
X = crevettes ;
X = oeufs ;
false.

Le prédicat element_de est un prédicat prédéfini en Prolog, il


possède le nom de member

18
LE PRÉDICAT MEMBER

 Le prédicat appart est prédéfini en Prolog


 Il est très utile :
?- member(c,[a,z,e,c,r,t]).
true
 ?- member(X,[a,z,e,r,t]).
X = a ; X = z ; X = e ; X = r ; X = t.
?- member([3,V],[[4,a],[2,n],[3,f],[7,g]]).
V=f.

19
Parcours d’une liste

 Cas de base :
parcours([],v). v = valeur associée à la liste vide
 Cas général :
parcours([T|Q],R):- parcours(Q,RI), R is f(RI,T).
R est calculé à partir de RI et de T

20
SOMME DES D’UNE LISTE DE NOMBRES
ÉLÉMENTS

/* somme(L, S) L liste de nb donnée, S nb résultat */


somme([],0).
somme([X|L],N) :- somme(L,R), N is R+X.

?- somme([1,2,3,5],N).
N = 11
Exercice

Ecrire le prédicat nbpairs/2 qui prend en premier


argument une liste d'entiers et produit en second
argument le nombre d’entiers pairs de la liste.
Exemple d'utilisation:
?- nbpairs([5,4,1,12,3],N).
N = 2.

22
Solution de l'exercice

nbpairs([], 0).
nbpairs([T|Q], N) :- T mod 2 =:= 0, nbpairs(Q, N1), N is N1+1.
nbpairs([T|Q], N) :- T mod 2 =:= 1, nbpairs(Q, N).

23
UTILISATION DU PRÉDICAT APPEND

 append est le prédicat prédéfini pour la concaténation de


listes : append(?List1, ?List2, ?List3).
?- append([a,b,c],[d,e],L).
L = [a, b, c, d, e]
 append est complètement symétrique et peut être utilisé
pour d’autres opérations :
 Trouver tous les découpages d’une liste en 2 sous-listes:
?- append(L1,L2,[a,b,c,d]).
L1 = [], L2 = [a, b, c, d] ;
L1 = [a], L2 = [b, c, d] ;
L1 = [a, b], L2 = [c, d] ;
L1 = [a, b, c], L2 = [d] ;
L1 = [a, b, c, d], L2 = []

24
append : autres utilisations possibles

 Trouver le dernier élément d’une liste :


?- append(_,[X],[a,b,c,d]).
X = d
 Découper une liste :
?- append(L2,L3,[b,c,a,d,e]), append(L1,[a],L2).
L2 = [b, c, a]
L3 = [d, e]
L1 = [b, c]

25
Construction d’une liste au moyen d’une
liste auxiliaire appelée « accumulateur »(2)

Problème : Ecrire un prédicat inverser qui inverse l’ordre


des éléments d’une liste donnée.
 Soit D une liste donnée, R est la liste D inversée.

 Nous allons introduire une liste auxiliaire pour y ranger les


éléments énumérés au fur et à mesure de leur parcours.
 Le prédicat inverser aura donc 3 arguments:
(1) la liste à inverser,
(2) la liste auxiliaire,
(3) la liste inversée
26
Construction d’une liste au moyen d’une liste auxiliaire
« accumulateur » (3)

 On obtient les règles suivantes :


inverser([],L,L).
inverser([X|Y],L,R) :- inverser(Y,[X|L],R).
 Interprétation de ces deux règles :
 Inverser la liste vide, à partir de la liste auxiliaire L, a pour résultat
la liste L.
 Inverser la liste [X|Y], à partir de la liste auxiliaire L, donne la liste
résultat R, si inverser la liste Y, à partir de la liste auxiliaire [X|L],
donne cette même liste R.

16
Construction d’une liste au moyen d’une liste auxiliaire
« accumulateur » (4)

 Si l’on souhaite disposer d’un prédicat inverser/2 qui


ne mentionne que les listes donnée et résultat, on peut
introduire le prédicat suivant :
inverser(L,R) :- inverser(L,[],R).
inverser([], L, L).
inverser([X|Y], L, R) :- inverser(Y, [X|L], R).
 Exécution :
?- inverser([a,b,c], [], R).
R = [c, b, a]
?- inverser([a,b,c],R).
R = [c, b, a]

17
Prédicats prédéfinis sur les listes
Quelques prédicats prédéfinis
sur les listes
 Dans la documentation Prolog :
- les arguments consultés sont précédés d'un +
- les arguments élaborés sont précédés d'un -
-les arguments qui peuvent être soit consultés,
soit élaborés (suivant le sens de l'unification)
sont précédées d'un ?
Exemple : numlist(+Min, +Max, -List).
?- numlist(2,8,L).
L = [2, 3, 4, 5, 6, 7, 8]

30
Prédicats simplifiant la manipulation des listes (1)
is_list(+Terme) réussit si Terme est une liste
?- is_list([a,b,c]).
true.
length/2 permet d’obtenir la longueur d’une liste :
?- length([a,b,c],L). ?- length([a,b,c],4).
L = 3. false.
?- length(L,3).
L = [_3648, _3654, _3660].
member(?Element, ?Liste) réussit si Element s’unifie avec un élément de Liste. Prédicat
utilisé principalement pour énumérer les membres de la liste :
?- member(E,[a,b,c]). ?- member(d,[a,b,c]).
E = a ; false
E = b ; ?- member(b,[a,b,c]).
E = c. true
memberchk(?Element, ?Liste) permet de vérifier si Element appartient à Liste:
?- memberchk(d,[a,b,c]). ?- memberchk(X,[a,b,c]).
false. X = a.
?- memberchk(b,[a,b,c]).
true.
31
Prédicats simplifiant la manipulation des listes (2)
last(?Liste, ?Last) permet de sélectionner le dernier élément d’une liste.
?- last([a,b,c],X).
X = c.
nth0(?I, ?Liste, ?Elem) permet de sélectionner Elem l’élément d’indice I de Liste, lepremier
élément ayant l’indice 0 :
?- nth0(3,[a,b,c,d,e],E).
E = d.
nth0 permet aussi d’obtenir le ou les indice(s) d’un élément donné dans une liste :
?- nth0(I,[a,b,c,b,d,e],b).
I = 1 ;
I = 3
nth1(?I, ?Liste, ?Elem) fonctionne exactement comme nth0, mais l’indice du premier élément
de la liste est 1 :
?- nth1(3,[a,b,c,d,e],E). ?- nth1(I,[a,b,c,b,d,e],b).
E = c. I = 2 ;
I = 4
select(?Elem,?Liste,?Reste) fonctionne comme member mais en plus unifie Reste avec Liste
privée de Elem (permet de sélectionner un élément et le supprimer de la liste) :
?- select(b,[a,b,c,d,b,a],L). ?- select(E,[a,b,c],R).
L = [a, c, d, b, a] ; E = a, R = [b, c] ;
L = [a, b, c, d, a] ; E = b, R = [a, c] ; 21
false. E = c, R = [a, b].
Prédicats simplifiant la manipulation des listes (3)
flatten(+Liste1, -Liste2) applanit Liste1 et unifie le résultat dans Liste2 :
?- flatten([a,[[],b],[[c],d,e]],L).
L = [a, b, c, d, e].
reverse(+Liste1, -Liste2) inverse l'ordre des éléments de Liste1 et unifie le résultat dans Liste2 :
?- reverse([a, b, c, d, e],L).
L = [e, d, c, b, a].
sumlist(+Liste, -Somme) unifie Somme avec la somme de tous les éléments de Liste (numériques):
?- sumlist([3.4,12,17.2,3],S).
S = 35.6
permutation(?Liste1, ?Liste2) vrai si Liste2 est une permutation de Liste1 ; permet également d'énumérer
toutes les permutations possibles de Liste1 ou Liste2.
?- permutation([a,b,c],P). ?- permutation([a,b,c],[c,a,b]).
P = [a, b, c] ; true
P = [a, c, b] ;
P = [b, a, c] ;
P = [b, c, a] ;
P = [c, a, b] ;
P = [c, b, a] ;
false.
msort(+Liste, -Triee) trie les éléments de Liste pour créer Triée :
?- msort([12,3,-7,9,-3,17,11,10,3,9,6,18],L),writeln(L).
[-7,-3,3,3,6,9,9,10,11,12,17,18]
L = [-7, -3, 3, 3, 6, 9, 9, 10, 11|...].

33
Conversions entre atomes chaines
et listes
atom_chars(?Atom, ?Liste) unifie un atome avec la liste des atomes caractères qui le composent :
?- atom_chars(bonjour,L). ?- atom_chars(X,[b, o, n, j, o, u, r]).
L = [b, o, n, j, o, u, r]. X = bonjour.
string_chars(?String, ?Liste) unifie une chaine avec la liste des atomes caractères qui le
composent :
?- string_chars("hello",L). ?- string_chars(C,[h, e, l, l, o]).
L = [h, e, l, l, o]. C = "hello".
atom_string(?Atom, ?String) unifie un atome avec la chaine des caractères qui le composent :
?- atom_string(foo, Z). ?- atom_string(A,"hello world!").
Z = "foo". A = 'hello world!'.
number_string(?Number, ?String) unifie un nombre avec la chaine des caractères qui le composent:
?- number_string(3.14159265,S). ?- number_string(N,"3.14159265").
S = "3.14159265". N = 3.14159265.
string_codes(?String, ?Codes) unifie une chaine avec la liste des codes des caractères de la chaine:
?- string_codes("hello",L). ?- string_codes(S,[104, 101, 108, 108, 111]).
L = [104, 101, 108, 108, 111]. S = "hello".
atomics_to_string(+List, -String) convertit une liste d’éléments atomiques en une chaine :
?- atomics_to_string([hello, ' ', "world ", 33],S).
25
S = "hello world 33".
ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Dr. AOUN Oussama

Année Universitaire 2020/2021


 Les structures de données
 Les graphes
 Les arbres

2
Les graphes en Prolog
 Graphe
 Ensemble de sommets (ou nœuds) reliés par des arcs
(graphe orienté) ou des arêtes (graphe non orienté).
 Permet de modéliser de nombreuses situations concrètes
comme par exemple : des liaisons routières, des flux, des
tâches à ordonner, etc.

B B

A C A C

D D
Graphe orienté Graphe non orienté
3
Représentation des graphes

 Une manière simple de représenter un graphe en


Prolog est de décrire
 Les arcs qui relient les sommets et leurs caractéristiques
 Les sommets et leur caractéristiques

B arc(a,b,5).
2 arc(b,c,2).
5
arc(a,d,3).
A C arc(c,d,2).
3 3 arc(d,c,3).
2 sommet(a).
D sommet(b).
sommet(c).
Graphe orienté sommet(d).
4
Exemple : des figures à colorier
Problème posé :
 On veut colorier les zones des
figures, de sorte que deux zones
adjacentes n’aient pas la même
couleur. Figure 1

 On peut représenter ces figures


B C
par des graphes :
A
 Les sommets représentent les zones
D E F
de la figure
 Les arêtes relient deux zones Figure 2

adjacentes
5
Exemple : des figures à colorier
 Les sommets représentent les
zones de la figure
B C
 Les arêtes relient deux zones
A
adjacentes
D E F

B Figure 2

B
A C
A
C
E D
Figure 1

F D
E
6
Exemple : des figures à colorier
réalisation en Prolog
B
 Représentation des 2 figures en Prolog
zones(figure1,[a,b,c,d,e]).
zones(figure2,[a,b,c,d,e,f]). A C
arete(figure1,a,b).
arete(figure1,a,c).
arete(figure1,a,d). E D
arete(figure1,a,e).
arete(figure1,b,c). Figure 1
arete(figure1,b,d).
arete(figure1,c,d).
arete(figure1,d,e).
B
arete(figure2,a,b). A
arete(figure2,a,c).
arete(figure2,a,d).
arete(figure2,a,e).
C
arete(figure2,a,f).
arete(figure2,b,c).
arete(figure2,b,d).
arete(figure2,c,f).
arete(figure2,d,e).
F D
arete(figure2,e,f).
E
8
aretes(Fig,L):- findall([X,Y], arete(Fig,X,Y), L). Figure 2
Exemple : des figures à colorier
réalisation en Prolog
 On veut écrire le prédicat coloriage/2 B
qui, à partir du nom de la figure,
donne un coloriage possible à l’aide A C
des couleurs disponibles
E D
 Le résultat est une liste de couples Figure 1
[zone, couleur]
?- coloriage(figure1,L).
L = [[e, vert], [d, rouge], [c, bleu], [b, vert], [a, jaune]]

8
Exemple : des figures à colorier
réalisation en Prolog
Programme de coloriage :
 adjacent/3 : prédicat indiquant si 2 sommets (zones) sont
adjacent(e)s dans la figure donnée.
adjacent(Fig,X,Y):- arete(Fig,X,Y); arete(Fig,Y,X).
dans la figure Fig, X adjacent à Y si une arête les relie.
 conflit/3 : prédicat indiquant s’il y a conflit de coloriage
entre les zones Z1 et Z2 d’une figure.
conflit(Fig,[Z1,C1],[Z2,C2]):- adjacent(Fig,Z1,Z2), C1==C2.
ou plus simplement :
conflit(Fig,[Z1,C],[Z2,C]):- adjacent(Fig,Z1,Z2).

9
Exemple : des figures à colorier
réalisation en Prolog
 noconflit/3 : prédicat indiquant si la couleur d’une zone n’est
pas en conflit avec les couleurs déjà sélectionnées pour les
autres zones (liste de doublets)
noconflit(Fig,X,[]).
noconflit(Fig,X,[P|F]):- \+conflit(Fig,X,P)), noconflit(Fig,X,F).
 coloriage : coloriage de la figure Fig
coloriage(Fig,L):- zones(Fig,Zones), colorier(Fig,Zones,[],L).
L est une liste de doublets [zone, couleur].
 colorier : trouve la liste des couleurs de chaque zone de la
figure
colorier(_,[],L,L).
colorier(Fig,[Z|F],L,R):- couleur(C), noconflit(Fig,[Z,C],L),
colorier(Fig,F,[[Z,C]|L],R).

10
Les Arbres en Prolog
Eléments abordés :
 Arbres n-aires et arbres binaires

 Représentation des arbres en Prolog

 Parcours d’arbres

14
Les Arbres
 Les arbres sont des graphes particuliers.
 Les arbres, comme les listes, permettent de
représenter un nombre variable de données
 Le principal avantage des arbres est qu’ils
permettent d’organiser les données selon un
ordre partiel.
 Exemples d’arbres :
 Arbre généalogique
 Sommaire d’un livre, hiérarchie de répertoires
 Arbre de dérivation d’une phrase d’un langage défini
15
par une grammaire
Exemples d’arbres

+
A

*
B -
H

C +
E A 7
L

5
F X
G
14
Représentations graphiques d’un
arbre
Racine A

B D H

C E K L

F G J

15
Représentations graphiques d’un
arbre
Racine A

B D H

C E K L

F G J

Feuilles
16
Définition d’un Arbre
 Un Arbre est un ensemble non vide structuré comme suit :
 un des éléments est désigné comme étant la « racine » de l’arbre
 il existe une partition sur les éléments restants, et chaque classe de cette
partition est elle-même un arbre : on parle des sous-arbres de la racine.
 Si le nombre de sous-arbres est variable, l’arbre est dit n-aire.
 L’ensemble représenté par un arbre est la réunion d’un élément (la
racine) et des sous-arbres qui lui sont directement associés.
 Chaque élément de l’ensemble structuré en arbre est appelé un nœud.
A tout nœud est associée une information élémentaire.
 Pour décrire les relations entre les nœuds on utilise la terminologie de la
généalogie, un nœud est donc le père de ses fils.
 Le degré d’un nœud est le nombre de ses fils. On distingue :
 les nœuds non terminaux de degré non nul
 les nœuds terminaux ou feuilles, de degré nul.
17
Arbre binaire
 Un arbre binaire est un arbre pour lequel tout
nœud a au plus deux fils.
 Un arbre binaire est un ensemble fini qui est
soit vide, soit composé d’une racine et de deux
sous-arbres binaires appelés sous-arbre
gauche et sous-arbre droit.
 On peut donc dire qu’un arbre binaire est :
 soit l’arbre vide
 soit un nœud qui a exactement deux sous-arbres
éventuellement vides 18
Représentation des arbres
binaires en Prolog
 Nous choisissons d’utiliser les listes pour
représenter les arbres binaires
 Un arbre vide sera représenté par la liste vide []
 Un nœud sera représenté par une liste de 3 éléments :
 le premier est la valeur portée par le nœud,
 le deuxième son sous-arbre gauche,
 le troisième son sous-arbre droit.

19
Exemple de représentation d’un
arbre binaire en Prolog
6

4 12

1 8 14

Cet arbre binaire ordonné est représenté par la liste suivante :


[6, [4, [1, [], [] ], [8, [7, [], [] ], [] ] ], [12, [], [14,[],[] ] ] ]

20
Parcours d’arbres
 Un arbre contient un ensemble de données.
 Pour utiliser ces données, on peut parcourir l’arbre
 en largeur
6

On parcourt l’arbre
par niveaux : d’abord 4 12
la racine, puis les
nœuds de niveau
inférieur, et ainsi de 1 8 14
suite

7
21
Parcours d’arbres
 Un arbre contient un ensemble de données.
 Pour utiliser ces données, il faut parcourir l’arbre
 en profondeur
6
On visite d’abord le
sous-arbre gauche,
4 12
ensuite la racine, puis
le sous-arbre droit

1 8 14

7
22
Exemples de parcours en
profondeur
 Calcul de la somme des nœuds d’un arbre
binaire de nombres
somme([],0).
somme([N, G, D], S) :- somme(G, N1), somme(D,N2),
S is N+N1+N2.

23
Exemples de parcours d’un arbre
binaire
 Affichage des nœuds d’un arbre binaire
 Dans l’ordre du parcours en profondeur (infixé)
afficher([]).
afficher([N, G, D]) :- afficher(G), write(N), afficher(D).
 Dans l’ordre préfixé : racine puis les sous-arbres
afficher([]).
afficher([N, G, D]) :- write(N), afficher(G), afficher(D).
 Dans l’ordre postfixé : les sous-arbres puis la racine
afficher([]).
afficher([N, G, D]) :- afficher(G), afficher(D), write(N).

24
Exemples de construction d’un
arbre binaire
 A partir d’un arbre, créer un arbre qui représente
la somme des valeurs des sous-arbres

6 52

4 12 20 26

1 8 14
1 15 14

7 7
25
Arbre représentant la somme des
valeurs des sous-arbres : analyse
Cas possibles Arbre construit
R
R

R R’ R’ = R + somme des élts de g

g G

R R’ R’ = R + somme des élts de d

d D

R R’ R’ = R + somme des élts de g


+ somme des élts de d
g d G D racine(G) = somme des élts de g
racine(D) = somme des élts de d
28
Exemples de construction d’un
arbre binaire
 A partir d’un arbre, créer un arbre qui représente la
somme des valeurs des sous-arbres
 Soit creer_som/2 ce prédicat :
creer_som([],[]).
creer_som([N,[],[]], [N,[],[]]).
creer_som([N,G,[]], [NR, [NG,FG,FD], []]):- creer_som(G,[NG,FG,FD]), NR is N+NG.
creer_som([N,[],D], [NR, [], [ND,FG,FD]]):- creer_som(D,[ND,FG,FD]), NR is N+ND.
creer_som([N,G,D], [NR, [NG,FG1,FD1], [ND,FG2,FD2]]):-
creer_som(G,[NG,FG1,FD1]), creer_som(D,[ND,FG2,FD2]), NR is N+ND+NG.

27
Une autre manière de représenter
les arbres binaires en Prolog
 Un arbre binaire peut être représenté par le terme
de suivant: t(SousArbreG, Racine, SousArbreD).
9

4 12

1 8 14

 t( t( t(nil, 1, nil), 4, t( t(nil, 7, nil), 8, nil) ), 9, t(nil, 12, t(nil, 14, nil) ) )
 Arbre vide : nil 28
ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Dr. AOUN Oussama

Année Universitaire 2020/2021


Résolution d’un type de
problèmes de logique

Les intégrammes
Les intégrammes
 Les intégrammes appelés parfois logigrammes
sont un type de casse-tête logique.
 On donne un certain nombre d'indices, desquels
il faudra déduire l'intégralité des relations entre
tous les éléments.

3
Exemple d’intégramme simple

Max, Eric et Luc habitent chacun une maison différente. Ils


possèdent chacun un animal domestique distinct.
On sait que :
 Max a un chat.
 Eric n’habite pas en pavillon.
 Luc habite un studio, il n’a pas le cheval.
La problématique à résoudre est :
 Qui habite le château et qui a le poisson ?

Question : comment représenter le problème en Prolog ?

4
Modélisation : les faits
% les maisons :
maison(studio).
maison(pavillon).
maison(château).
% les animaux :
animal(chat).
animal(cheval).
animal(poisson).

5
Modélisation : les règles
% le prédicat habitation représente la relation
% entre une personne, sa maison et son animal :
% Max a un chat :
habitation(max,M,chat) :- maison(M).
% Eric n’habite pas en pavillon :
habitation(eric,M,A) :- maison(M), M\==pavillon, animal(A).
% Luc habite un studio, il n’a pas le cheval :
habitation(luc,studio,A):-animal(A),A\==cheval.

6
Résolution du problème :
prédicat résoudre
% avec ses 4 éléments inconnus resoudre :-
habitation(max,MM,chat),
Astuce : habitation(eric,ME,AE),
habitation(luc,studio,AL),
% le prédicat resoudre décrit l’ensemble du problème à résoudre
et affiche la solution :

MM \== studio, MM \== ME, ME \== studio,


is_set([MM,ME,studio]),
AE \== chat, AE \== AL, AL \== chat,
is_set([chat,AE,AL]),
write(max),write(' '),write(MM),write(' '),writeln(chat),
write(eric),write(' '),write(ME),write(' '),writeln(AE),
write(luc),write(' '),write(studio),write(' '),writeln(AL).

7
Interrogeons Prolog

?- resoudre.
max pavillon chat
eric chateau cheval
luc studio poisson
true ;
false.

8
On souhaite maintenant résoudre
l’intégramme suivant
Dans une rue 3 maisons voisines sont de couleurs différentes :
rouge, bleue et verte. Des personnes de nationalités différentes
vivent dans ces maisons et elles ont chacune un animal de
compagnie différent.
Les données du problème sont :
 l'anglais vit dans la maison rouge.
 le jaguar est l'animal de l'espagnol.
 le japonais vit à droite de la maison du possesseur de l'escargot.
 le possesseur de l'escargot vit à gauche de la maison bleue.
La problématique à résoudre est :
 Qui possède le serpent ?

9
Modélisation du problème
 On va représenter la solution par une liste de 3
termes, chaque terme aura la forme suivante :
maison(couleur,nationalité,animal)
 Le programme Prolog ne contient qu’un prédicat :
serpent(N, Rue) :- …
 N représente la nationalité du possesseur du serpent
 Rue représente la solution complète, c’est-à-dire la liste
de 3 termes maison(couleur,nationalité,animal)

10
Solution
serpent(N, Rue) :-
% Rue est représentée par une liste de 3 maisons :
length(Rue,3),
% il y a une maison rouge, une maison bleue et une maison verte :
member(maison(rouge,_,_),Rue),
member(maison(bleue,_,_),Rue),
member(maison(verte,_,_),Rue),
% l'anglais vit dans la maison rouge :
member(maison(rouge,anglais,_),Rue),
% le jaguar est l'animal de l'espanol :
member(maison(_,espagnol,jaguar),Rue),
% le japonais vit à droite de la maison du possesseur de l'escargot :
nextto(maison(_,_,escargot),maison(_,japonais,_),Rue),
% le possesseur de l'escargot vit à gauche de la maison bleue :
nextto(maison(_,_,escargot),maison(bleue,_,_),Rue),
% le troisième animal est un serpent :
member(maison(_,N,serpent),Rue).

11
Interrogeons Prolog
?- serpent(N,Rue).
N = japonais,
Rue = [maison(rouge, anglais, escargot),
maison(bleue, japonais, serpent),
maison(verte, espagnol, jaguar)]
Utilisons cette modélisation pour le
problème précédent
resoudre2(S):-
% il y a 3 habitations: studio, chateau, pavillon (non ordonnés)
S = [habitation(_,studio,_), habitation(_,chateau,_),
habitation(_,pavillon,_)],
% il y a un poisson
member(habitation(_,_,poisson),S),
% il y a un cheval
member(habitation(_,_,cheval),S),
% Max a un chat
member(habitation(max,_,chat),S),
% Eric n’habite pas en pavillon :
member(habitation(eric,HE,_),S), HE \== pavillon,
% Luc habite un studio, il n’a pas le cheval :
member(habitation(luc,studio,AL),S), AL \== cheval.

61
Interrogeons Prolog
?- resoudre2(S).
S = [habitation(luc, studio, poisson),
habitation(eric, chateau, cheval),
habitation(max, pavillon, chat)]
ENSEM

COURS DE
Programmation
logique et
contrainte
Enseignant : Dr. AOUN Oussama

Année Universitaire 2020/2021


La programmation logique avec
contraintes
Le module clpfd de SWI-Prolog permet de programmer avec
contraintes.

Le code source (il charge le module clpfd puis définit les contraintes sur la
variable X) :
:-use_module(library(clpfd)).
solution(L):-
L=[X],
X in 1..5,
X#>2,
labeling([],L).
La programmation logique avec
contraintes
Le module clpfd de SWI-Prolog permet de programmer avec
contraintes.
Appelons le prédicat solution dans l'interpréteur Prolog :
?- solution(L).
L = [3] ;
L = [4] ;
L = [5].

Prolog nous ressort les 3 solutions du problèmes :


les entiers 3, 4 et 5.
La programmation logique avec
contraintes
Ajoutons une nouvelle contraintes afin de limiter les solutions possibles :
:-use_module(library(clpfd)).
solution(L):-
L=[X],
X in 1..5,
X#>2,
X#=<3,
labeling([],L).

Cette fois il n'y a qu'une seule solution : X=3


?- solution(L).
L = [3].
La programmation logique avec
contraintes
Principe d'un programme logique avec contraites :
Le programme est composé d'un seul prédicat solution contenant 3 parties :

1 - la déclaration de toutes les variables du problème dans une liste L


2 - l'écriture des différentes contraintes liant toutes les variables
3 - l'appel du predicat labelling pour la recherche des solution
La programmation logique avec
contraintes
Exercice : On cherche 2 entiers X et Y tels que 2X+4Y=20 et 7X+8Y=52. Les 2 variables à
rechercher sont X et Y.

Vous aimerez peut-être aussi