TP Bases de données avancées ENSEIRB

Petit Système Expert - Bases de faits connus

 

Sujet

L'exercice s'inspire de Adventure in Prolog de Dennis Merritt. On se propose de réaliser un petit système expert qui identifie un animal en utilisant des règles et en questionnant l’utilisateur. En fait, toute autre idée est la bienvenue, sous réserve que vous puissiez exprimer les règles de déduction de ce domaine particulier, et les sujets classiques ne manque pas: système de classification, diagnostique de panne, suggestion d'achat, diagnostique médical, prise de décision concernant une demande de crédit,...

 

  1. Voici des pour un exemple très classique  qui permet de reconnaître un animal (chacun peut en modifier ou en ajouter quelques unes).

    1. SI (animal a poils)  ALORS (animal est mammifère)
    2. SI (animal donne lait)  ALORS (animal est mammifère)
    3. SI (animal mange viande)  ALORS (animal est carnivore)
    4. SI (animal a dents pointues) ET (animal a griffes) ET (animal a yeux vers avant) ALORS (animal est carnivore)
    5. SI (animal est mammifère) ET (animal a sabots)  ALORS  (animal est ongulé)
    6. SI (animal est mammifère) ET (animal n’est pas carnivore)  ALORS  (animal est ongulé)
    7. SI (animal est mammifère) ET (animal est carnivore) ET (animal est couleur brune) ET (animal a tâches sombres)  ALORS  (animal est guépard)
    8. SI (animal est mammifère) ET (animal est carnivore) ET (animal a couleur brune) ET (animal a raies noires)  ALORS (animal est tigre)
    9. SI (animal est ongulé) ET (animal a long cou) ET (animal a longues pattes) ET (animal a tâches sombres)  ALORS (animal est girafe)
    10. SI (animal est ongulé) ET (animal a raies noires)  ALORS  (animal est zèbre)
    11. SI (animal a plumes)  ALORS (animal est oiseau)
    12. SI (animal vole) ET (animal ponds oeufs)  ALORS (animal est oiseau)
    13. SI (animal est oiseau) ET (animal ne vole pas) ET (animal a long cou) ET (animal a longues pattes) ET (animal est noir et blanc) ALORS (animal est autruche)
    14. SI (animal est oiseau) ET (animal ne vole pas) ET (animal nage) ET (animal est noir et blanc)  ALORS (animal est pingouin)
    15. SI (animal est oiseau) ET (animal est carnivore)  ALORS (animal est aigle).

  2. Une fois choisi les relations qui permettent d’exprimer de telles règles, on peut les utiliser en ajoutant à ces règles des faits comme (X est carnivore) et (X est oiseau) qui doivent donner X=aigle --- ou aigle(jaco) suivant la modélisation choisie.
  3. Prolog permet d’ajouter des faits à la base dans la fenêtre d’interrogation avec la commande assert.
    ?- assert(oiseau(jaco)).
    Yes

    Ce qui vous permet déjà de tester les règles codées.
  4. On peut améliorer le système en faisant en sorte qu’il demande les informations qu’il n’arrive pas à déduire
    carnivore(X):- ask(carnivore, X).
  5. Cette première version de ask/2 ne fait que vérifier si carnivore(X) est vrai ou faux (on pourra utiliser une constante "oui" ou "yes" - pas de chaîne de caractère svp):
    1. on se sert pour cela de read/1 qui lit un terme Prolog (suivi d’un point, bien sûr !)
    2. et de write/1 qui affiche une chaîne de caractères .
  6. Le système expert pose alors la même question encore et toujours, chaque fois qu’il la rencontre dans sa tentative de résoudre le problème posé. Redéfinir ask/2 de manière à éviter ce problème en utilisant les prédicats assert/1 et known/3 qui vérife si un fait n’est pas déjà connu. Si c’est connu et vrai, ask/2 est vrai, si le résultat et connu et faux ask/2 est faux, et sinon, et seulement dans ce dernier cas, ask demande la réponse. On pourra utilisera la coupure cut/0 qui permet de ne pas remonter (et si on n’y arrive pas on pourra utiliser  not/1 qui échoue si son argument réussit).
  7. Pour les questions, il est mieux d’utiliser des menus qui spécifient les valeurs possibles. Définir menuask/3 qui précède comme ask/2 mais affiche la question, puis sur chaque ligne le numéro de la réponse et sa signification. Si le numéro est possible cela fait comme ask/2, mais sinon la question est posée de nouveau.
  8. (un peu plus difficile et optionnel) Améliorer le système afin qu'on puisse demander lorsque le système pose une question pourquoi il la pose et qu'alors celui-ci donne le but courant et la règle qu'il tente d'appliquer.
  9. (encore plus difficile et toujours optionnel) Améliorer le système afin que l'utilisateur puisse 1) réfuter qu'un animal est celui proposé par le système et 2) entrer à ce moment là des caractéristiques de l'animal et des règles associées .

Indications

  1. Pour Prolog se reférer aux liens donnés sur la page du cours.
  2. Regrouper les clauses définissant un même prédicat.
  3. Pour modifier les clauses d'un prédicat lors de l'interaction avec l'utilsiateur, il faut l'avoir déclaré comme dynamique:
    % en tête de fichier pour known à 3 places
    :-dynamic(known/3).

  4. Plus spécifiquement pourra utiliser (mais ce n'est pas nécessaire) T=..[U,X] qui associe à la variable T le terme U(X) qu'ensuite on peut faire évaluer.
  5. Un petit exemple d'un programme similaire qui n'est pas la solution (il fonctionne mais ne fait pas tout à fait ce qu'il faut)
    liste_animaux([chat,chien,cheval,oiseau]).
    animal(X):-liste_animaux(L),member(P,L),T=..[P,X],T, write('je pense que '), write(X),write(' est un '),write(P).
    %on peut écrire call(T) au lieu de T
    chien(X):-peau(poils,X),taille(U,X), U<100.
    chat(X):-oreilles(pointues,X),peau(poils,X),taille(U,X), U<30.
    cheval(X):-oreilles(pointues,X),peau(poils,X),taille(U,X), U>150,U<300.
    oiseau(X):-peau(plumes,X). oreilles(Y,X):-ask(oreilles,Y,X).
    peau(Y,X):-ask(peau,Y,X).
    taille(Y,X):-ask(taille,Y,X).
    % ask repond de suite quand le résultat est connu = déjà dans la base.

    ask(U,Y,X):-known(U,Y,X).
    ask(oreilles,Y,X):-not(known(oreilles,_,X)),write('comment sont les oreilles de '), write(X), writeln(' pointues/tombantes/inexistantes'), read(Y),assert(known(oreilles,Y,X)).
    % sans tout dire, voici une quand même une petite amélioration: xs
    %
    si on a Y à la place de _ le programme peut
    % reposer la question pour une autre valeur de Y (disons pointues)
    % alors que le système sait déjà que
    c'est inexistantes
    ask(peau,Y,X):-not(known(peau,_,X)),write('de quoi est couverte la peau de '), write(X), writeln(' poils/plumes'),read(Y),assert(known(peau,Y,X)).
    ask(taille,Y,X):-not(known(taille,_,X)),write('quelle est la taille en cm de ' ), writeln(X), read(Y),assert(known(taille,Y,X)).