<div class="notebook"> <div class="nb-cell markdown" name="md1"> # La logique des familles en Prolog (Introduction à l'IA symbolique et les raisonnements naturels en ProLog) Introduction : Une famille est représentée par une base de faits indiquant les relations entre mère et fille (pour la partie la plus connue de cette famille, regarder la partie droite, c'est une famille connue, pour le reste, c'est un peu de l'invention, mais pas tant). Pour simplifier, seules les mères et filles sont données (rem. : les noms sont donnés en minuscule pour avoir des atomes de ProLog, i.e.: des constantes symboliques) : </div> <div class="nb-cell markdown" name="md21"> ``` charlotte / \ martha caroline / \ / | \ alice ella mary laura carrie | | altha rose ``` </div> <div class="nb-cell program" data-background="true" name="p2"> estFilleDe(martha,charlotte). estFilleDe(alice,martha). estFilleDe(altha,alice). estFilleDe(ella,martha). estFilleDe(caroline,charlotte). estFilleDe(mary,caroline). estFilleDe(laura,caroline). estFilleDe(rose,laura). estFilleDe(carrie,caroline). </div> <div class="nb-cell markdown" name="md2"> Cette base de faits dit qui est la fille de qui : * estfilleDe(XXX,YYY). doit être compris/lu comme XXX est la fille de YYY. </div> <div class="nb-cell markdown" name="md24"> Cette base de faits permet de répondre aux questions usuelles "Est-ce que XXX est la fille de YYY" ? (que la réponse soit positive ou non) </div> <div class="nb-cell query" name="q1"> estFilleDe(caroline,charlotte). </div> <div class="nb-cell query" name="q2"> estFilleDe(caroline,rose). </div> <div class="nb-cell markdown" name="md3"> Cette base permet même de répondre à des questions immédiates "XXX est fille de qui ?" ou (c'est pareil) "De qui XXX est-il la fille ?" </div> <div class="nb-cell query" name="q3"> estFilleDe(caroline,Mere). </div> <div class="nb-cell markdown" name="md23"> En fait, cela introduit le concept de mère. Pour le concept de mère, on peut introduire une liste de faits qui reprend la liste des filles (en mettant les choses à l'envers), mais on peut aussi introduire le prédicat inverse "mere" de la manière suivante (pour trouver la relation entre une mère et sa fille, on peut partir de la fille et remonter à la mère) : </div> <div class="nb-cell program" data-background="true" name="p1"> mere(Mere,Fille) :- estFilleDe(Fille,Mere). </div> <div class="nb-cell markdown" name="md25"> et cela permet de poser la question "XXX est mère de qui ?": </div> <div class="nb-cell query" name="q19"> mere(charlotte,Fille). </div> <div class="nb-cell markdown" name="md27"> On peut aussi poser les questions inverses : "Qu'elle est la fille de XXX ?" (ou "Qu'elle est la mère de XXX ?") : </div> <div class="nb-cell query" name="q4"> estFilleDe(Fille,charlotte). </div> <div class="nb-cell markdown" name="md5"> Cette base de faits permet même de poser la question générale : "Qui est fille de qui ?" </div> <div class="nb-cell query" name="q5"> estFilleDe(Fille,Mere). </div> <div class="nb-cell markdown" name="md6"> ## Et les grand-mère et petites filles ? Pour trouver les parents plus lointains, la requête peut combiner plusieurs questions : "XXX est la fille de qui ? et celle-ci, de qui est-elle la fille ?" </div> <div class="nb-cell query" name="q6"> estFilleDe(rose,Mere), estFilleDe(Mere,GrandMere). </div> <div class="nb-cell markdown" name="md7"> et on peut créer un prédicat petite-fille sur cette base : </div> <div class="nb-cell program" data-background="true" name="p3"> estPetiteFilleDe(Fille,GrandMere) :- estFilleDe(Fille,Mere), estFilleDe(Mere,GrandMere). </div> <div class="nb-cell markdown" name="md8"> Cela permet de poser les questions plus simplement : </div> <div class="nb-cell query" name="q7"> estPetiteFilleDe(rose,GrandMere). </div> <div class="nb-cell markdown" name="md26"> ou la question inverse : "Qui est (/sont) la (/les) petite(/s) fille(/s) de XXX ?" </div> <div class="nb-cell query" name="q20"> estPetiteFilleDe(PetiteFille,charlotte). </div> <div class="nb-cell markdown" name="md4"> ## Proches On va définir la notion de proche, pour celles qui sont les plus proches dans l'arbre généalogique, ce sont donc les mères et les filles, pour une personne XXX ce sont donc ses filles et sa mère. Pour trouver les proches de XXX, il faudrait faire 2 requètes : </div> <div class="nb-cell query" name="q21"> estFilleDe(caroline,Mere). </div> <div class="nb-cell query" name="q22"> estFilleDe(Fille,caroline). </div> <div class="nb-cell markdown" name="md28"> Le concept de "proche" peut s'écrire en 2 temps : </div> <div class="nb-cell program" data-background="true" name="p9"> proche(Fille,Mere) :- estFilleDe(Fille,Mere). proche(Mere,Fille) :- mere(Mere,Fille). </div> <div class="nb-cell query" name="q23"> proche(caroline,Proche). </div> <div class="nb-cell query" name="q25"> proche(Proche,caroline). </div> <div class="nb-cell markdown" name="md29"> Remarque, on aurait pu écrire tout cela avec des X et des Y : </div> <div class="nb-cell program" name="p10"> proche2(X,Y):- estFilleDe(X,Y). proche2(X,Y) :- mere(X,Y). </div> <div class="nb-cell markdown" name="md30"> Cela marche aussi : </div> <div class="nb-cell query" name="q24"> proche2(caroline,Z). </div> <div class="nb-cell markdown" name="md9"> ## Attention aux soeurs ! Pour définir, une relation entre soeurs, on peut imaginer dire que deux individues d'un même mère sont soeurs. Cela donne le prédicat suivant : </div> <div class="nb-cell program" name="p4"> estSoeurDe_(A,B) :- estFilleDe(A,Mere), estFilleDe(B,Mere). </div> <div class="nb-cell markdown" name="md10"> cela permet effectivement de vérifier que deux individus sont soeurs ou pas : </div> <div class="nb-cell query" name="q8"> estSoeurDe_(mary,laura). </div> <div class="nb-cell query" name="q9"> estSoeurDe_(mary,ella). </div> <div class="nb-cell markdown" name="md11"> mais plus étonnant : </div> <div class="nb-cell query" name="q10"> estSoeurDe_(mary,X). </div> <div class="nb-cell markdown" name="md12"> la première réponse est-elle juste ? si on veut vérifier, il n'y a pas d'erreur : </div> <div class="nb-cell query" name="q11"> estSoeurDe_(mary,mary). </div> <div class="nb-cell markdown" name="md13"> et même : </div> <div class="nb-cell query" name="q12"> estSoeurDe_(X,X). </div> <div class="nb-cell markdown" name="md14"> cela semble être une généralité, mais il y a un cas particulier : </div> <div class="nb-cell query" name="q13"> estSoeurDe_(charlotte,charlotte). </div> <div class="nb-cell markdown" name="md15"> c'est peut-être que la logique de la notion de soeur n'est pas si immédiate, il y a peut-être un implicite quand on dit "deux filles d'une même mère sont soeurs", c'est qu'une personne n'est pas double, il faudrait peut-être dire "deux filles différents d'une même mère sont soeurs" (cela sonne étrangement, certes ...) Côté programme, c'est plus clair : </div> <div class="nb-cell program" data-background="true" name="p5"> estSoeurDe(A,B) :- dif(A,B), estFilleDe(A,M), estFilleDe(B,M). </div> <div class="nb-cell markdown" name="md16"> maintenant : </div> <div class="nb-cell query" name="q15"> estSoeurDe(mary,X). </div> <div class="nb-cell query" name="q16"> estSoeurDe(mary,mary). </div> <div class="nb-cell query" name="q14"> estSoeurDe(X,X). </div> <div class="nb-cell markdown" name="md17"> # Au delà, ancêtres et générations Pour aller vraiment au dela de ce que l'on peut faire avec une base de données, on peut regarder si l'on peut définir la notion d'ancêtre (ou de descendance, et orthogonale, de génération) Pour faire vite, un ancêtre, c'est n'importe qui parmi les ascendants, un ascendant direct (parent), un ascendant de degré 2 (grand parent), un ascendant de degré 3, 4, ... autant que l'on veut (grand-grand-parent, grand-grand-grand-parent, ...) Pour englober tous les niveaux d'ancêtre, on peut utiliser la récursivité : </div> <div class="nb-cell program" name="p7"> estDescendanteDe(Fille,Mere) :- estFilleDe(Fille,Mere). estDescendanteDe(Fille,Ancetre) :- estFilleDe(Fille,Mere), estDescendanteDe(Mere,Ancetre). </div> <div class="nb-cell query" name="q17"> estDescendanteDe(rose,QUI). </div> <div class="nb-cell query" name="q18"> estDescendanteDe(Qui,charlotte). </div> <div class="nb-cell markdown" name="md19"> Voilà ! et on doit pouvoir faire quelque chose de similaire pour trouver : * si deux personnes ont un ancètre commun * si deux personnes appartiennent à la même génération * si deux personnes appartiennent à la même famille (et quel est le lien menant de l'un à l'autre) </div> <div class="nb-cell markdown" name="md20"> Mais en 15 minutes, on ne peut pas tout faire ... Bonne suite ! </div> <div class="nb-cell markdown" name="md22"> ## Annexes This notebook pre-loads SWI-Prolog's libraries for _constraint logic programming_. The libraries are: - library(dif) provides sound term inequality. [Documentation](http://www.swi-prolog.org/pldoc/doc_for?object=dif/2) </div> <div class="nb-cell program" data-background="true" name="p8"> :- use_module(library(dif)). % Sound inequality </div> </div>