2.Introduction à la logique formelle

La première idée pour "représenter" des connaissances est de se rapprocher d'un système "logique", c'est-à-dire capable de dire le Vrai et le Faux en fonction d'axiomes de bases et de "théorèmes" de dérivation. On retrouve bien sûr la "patte" des mathématiciens logiciens, en particuliers des logiciens grecs, dont le plus célèbre est sans aucun doute Aristote (voir l'encyclopédie Yahoo par exemple).

2.1. Systèmes formels

Pour construire une langue (par exemple le français), on a besoin de 4 choses :

2.1.1. Définition

Pour construire un système formel, nous aurons besoin de 4 choses analogues :

2.1.2. Exemple

Considérons le système "peu" : Questions : Réponses :

EXERCICE :

Q1 : uuuupuueuuuu est-il un théorème ?

Q2: upuuueuuuu ?

Q3: uuuupuuueuuupeuuuuuu ?

Preuves ?

 

2.1.3. Moralité

Pour démontrer qu'une expression est un théorème, nous avons une procédure (développer l'arbre) infaillible, qui répond en 2n/2, n étant la longueur de la chaîne, donc en temps fini.
Par contre, pour démontrer qu'une expression est un non-théorème, il nous faut "tricher". Dans les deux exemples ci-dessus, nous avons fait de l'arithmétique, que faudrait-il faire sur un autre exemple?

Si, pour prouver qu'une expression est un théorème, il "suffit" d'explorer l'ensemble des thèorèmes qui peuvent être générés, il n'est pas possible de faire la même chose pour un non-théorème. En pratique, on utiliserait le raisonnement par l'absurde, en posant que l'expression est un théorème, et en cherchant s'il est possible de trouver les théorèmes qui ont été utilisés avec les règles pour produire ce nouveau théorème.

Supposons pupueuu comme expressoin à décider théorème ou non. Ce théorème peut provenir de l'application de la règle R1 ou R2. La règle R1 ajoute un u au début et à la fin du théorème dérivé. Je ne peux pas enlever un u en début de mot, il ne peut donc y avoir aucun théorème ayant produit celui-ci avec la règle R1. La règle R2 ajoute un u avant et après un e dans un théorème pour en produire un autre. Il est possible de trouver une expression d'origine qui aurait pu produire celle-ci par la règle indiquée : pupeu. Est-ce que cette expression est un théroème ? On peut démontrer facilement que cette expression n'est pas dérivable d'une expression quelconque par la règle R1 ou la règle R2. Il ne peut donc pas s'agir d'un théorème.

 

Donc les notions de "être un théorème" et de "être un non-théorème" ne sont pas symétriques. Notre système "peu" est semi-décidable : nous avons une procédure qui répond "oui" en temps fini, mais pas de procédure pour répondre "non".

(voir le système MU de Hofstadter).

2.1.4. Deuxième exemple

Considérons le système : Questions : Réponses : oui, non, et non, car les deux systèmes sont isomorphes.
Si nous remplaçons "plus " par "+", "egal " par "=", et "un " par "1", l'axiome s'écrit : 1+1=2 , en base 1 (les chiffres romains, concaténation = addition).
R1 se lit : si A=B, alors 1+A=B+1
R2 : si A=B, alors A+1=1+B
Q1 : 2+2=4 est un théorème Q2 : 1+2=4 est un non-théorème Q3 : 1+1+1 ... est-un non-théorème !

2.1.5. Interprétation

Ce que nous venons de manipuler n'est pas un système formel : le symbole "2" ne fait pas partie de l'alphabet. Ce que nous venons de manipuler est l'interprétation du système formel. "1+1+1=3", dans l'interprétation, est vrai, bien que ce soit un non-théorème.
Une interprétation d'un S.F. n'est en général pas équivalente au S.F., c'est-à-dire que les notions de "être un théorème" et "être un non-théorème" d'une part, et de "être vrai" et "être faux" d'autre part, peuvent ne pas se recouvrir.
Cependant, il ne faut pas rejeter l'interprétation : souvenez-vous, si vous avez étudié un peu de Géométrie, la première fois qu'on vous a demandé "démontrer que le triangle ABC est isocèle". Vous avez soigneusement mesuré les deux cotés, et vous avez dit : "Oui, les deux cotés sont égaux". Et l'enseignant vous a répondu : "NON! Ce n'est pas parce que c'est vrai sur la figure que c'est un théorème". Mais vous n'avez pas pour autant cessé de faire des figures pour résoudre les problèmes, parce qu'elles guident le raisonnement. Nous y reviendrons.

REVENIR SUR LA NOTION D'INTERPRETATION

2.1.6. Synthèse

Considérons un système formel quelconque, et l'ensemble (qui peut être infini) des expressions qu'on peut engendrer dans ce système en appliquant le procédé de formation des expressions. Nous pouvons partitionner cet ensemble en : les expressions qui sont des théorèmes, et celles qui sont des non-théorèmes.
Nous pouvons également partitionner cet ensemble en : ce qu'une procédure peut démontrer en temps fini, et ce qu'elle ne peut pas :
Si la partie ND est vide, le système est dit décidable. Si la partie TND est vide, il est semi-décidable. Si aucune partie n'est vide, il est indécidable.
Nous pouvons par ailleurs partitionner l'ensemble en : les expressions dont l'interprétation est "vrai", et celles dont l'interprétation est "faux" :
Si la partie TF n'est pas vide, nous dirons que notre interprétation est sans intérêt. On montre en revanche que la partie NTV n'est, en général, pas vide.
Lorsqu'une proposition "manifestement vraie" ne peut être démontrée, on est donc en droit de se demander dans laquelle de ces zones on se trouve. Un cas célèbre était la conjecture de Fermat, qui a tenu les mathématiciens en échec pendant trois siècles : il n'existe pas d'entiers positifs x, y et z, et d'entier n supérieur à 2, tels que xn+yn=zn .

2.2. Application aux systèmes à base de connaissances

2.2.1. Un système d'aide au voyageur

alphabet
distance.<.2km
distance.<.300km
aller.à.pied
prendre.le.train
prendre.l'avion
avoir.le.téléphone
aller.à.l'agence
téléphoner.à.l'agence
acheter.un.billet
durée.>.2.jours
être.fonctionnaire
(
)
non (négation)
^ (et, ou conjonction)
-> (implique)
procédé de
formation des
expressions
expression <= symbole
expression <= ( expression )
expression <= non expression 
expression <= expression1 ^ expression2
expression <= expression1 -> expression2
axiomes
R1 : distance.<.2km -> aller.à.pied
R2 : ((non distance.<.2km) ^ distance.<.300km) -> 
       prendre.le.train
R3 : (non distance.<.300km) -> prendre.l'avion
R4 : (acheter.un.billet ^ avoir.le.téléphone) -> 
       téléphoner.à.l'agence
R5 : (acheter.un.billet ^ (non avoir.le.téléphone)) -> 
       aller.à.l'agence
R6 : prendre.l'avion -> acheter.un.billet
R7 : (durée.>.2.jours ^ être.fonctionnaire) ->
       (non prendre.l'avion)
F1 : (non distance.<.300km)
F2 : avoir.le.téléphone
règle de
dérivation
Si A est un théorème, et si
A -> B est un théorème, alors
B est un théorème
Cette règle est connue sous le nom de "modus ponens"
Les Ri ont été obtenues de l'"expert" par le processus de développement incrémental (cf. 3. 1.). C'est la mémoire à long terme, ou base de connaissances du système ; on ne les modifiera que si on y détecte une erreur.
Les Fj représentent un problème qu'on va soumettre au système. C'est sa mémoire à court terme, ou base de faits.
Ni la BdC ni la BdF ne sont programmées : elles sont mises telles quelles dans le système. Le seul programme est le moteur d'inférence, qui réifie la règle de dérivation :
ça marche
tant que ça marche
  ça ne marche pas
  boucle sur les Ri
    boucle sur les Fj
      si Ri est de la forme "Fj -> Fk"
        ajouter Fk à la BdF
        ça marche
      finsi
    finboucle
  finboucle
fintant
Traditionnellement, on représente le système par la "tête de Mickey" :

2.2.2. Déroulement

Lançons le système :
ça ne marche pas
R1 et F1 : rien
R1 et F2 : rien
R2 et F1 : rien
R2 et F2 : rien
R3 et F1 : F3 (prendre.l'avion) et ça marche
R3 et F2 : rien
R3 et F3 : rien
...
R6 et F3 : F4 (acheter.un.billet) et ça marche
...
R7 et F4 : rien
ça ne marche pas
R1 et F1 : rien
R1 et F2 : rien
R1 et F3 : rien
R1 et F4 : rien
...
R4 et F4 et F2 : F5 (téléphoner.à.l'agence)
NON! C'est vrai dans l'interprétation, mais ce n'est pas un théorème du système formel ! Nous n'avons pas écrit, et encore moins programmé :
règle de
dérivation
Si A est un théorème, et si
B est un théorème, alors
A ^ B est un théorème
La distinction entre "et" et "^" n'est pas un snobisme, pas plus que celle que nous faisons entre "si...alors..." et "->" . Corrigeons :
ça marche
tant que ça marche
  ça ne marche pas
  boucle sur les Ri
    boucle sur les Fj
      si Ri est de la forme "Fj -> Fk"
        ajouter Fk à la BdF
        ça marche
      sinon
        boucle sur les Fl
          si Ri est de la forme "Fj ^ Fl ->..."
            ajouter Fm = (Fj ^ Fl) à la BdF
            ça marche
          finsi
        finboucle
      finsi
    finboucle
  finboucle
fintant
Relançons le système :
ça ne marche pas
modus ponens avec R3 et F1 : F3 (prendre.l'avion) et ça marche
modus ponens avec R6 et F3 : F4 (acheter.un.billet) et ça marche
ça ne marche pas
règle du "et" avec F4 et F2 : F5 (acheter.un.billet ^ avoir.le.téléphone) 
                                 et ça marche
ça ne marche pas
modus ponens avec R4 et F5 : F6 (téléphoner.à.l'agence) et ça marche
ça ne marche pas
arrêt
NON! C'est vrai en Logique, mais pas en Informatique ! Notre programme va continuer à produire :
modus ponens avec R3 et F1 : F7 (prendre.l'avion) et ça marche
...
Notre programme ne donne pas la solution en temps fini, car il boucle. Pour éviter cela, nous marquons les Fj au fur et à mesure que nous les utilisons :
ça marche
tant que ça marche
  ça ne marche pas
  boucle sur les Ri
    boucle sur les Fj non marqués
      si Ri est de la forme "Fj -> Fk"
        ajouter Fk à la BdF
        marquer Fj
        ça marche
      sinon
        boucle sur les Fl
          si Ri est de la forme "Fj ^ Fl ->..."
            ajouter Fm = (Fj ^ Fl) à la BdF
            marquer Fj
            ça marche
          finsi
        finboucle
      finsi
    finboucle
  finboucle
fintant
A présent, le programme est correct, et donne la réponse en temps fini, quel que soit l'ordre dans lequel nous écrivons les Ri et les Fj. Nous avons donc réalisé notre objectif : nous pouvons exprimer nos connaissances sans les programmer.

2.2.3. Autre exemple

Reprenons le même système, en changeant un peu la base de faits :
axiomes
R1 : distance.<.2km -> aller.à.pied
R2 : ((non distance.<.2km) ^ distance.<.300km) -> 
       prendre.le.train
R3 : (non distance.<.300km) -> prendre.l'avion
R4 : (acheter.un.billet ^ avoir.le.téléphone) -> 
       téléphoner.à.l'agence
R5 : (acheter.un.billet ^ (non avoir.le.téléphone)) -> 
       aller.à.l'agence
R6 : prendre.l'avion -> acheter.un.billet
R7 : (durée.>.2.jours ^ être.fonctionnaire) ->
       (non prendre.l'avion)
F1 : (non distance.<.300km)
F2 : avoir.le.téléphone
F3 : durée.>.2.jours
F4 : être.fonctionnaire
Lançons le système :
modus ponens avec R3 et F1 : F5 (prendre.l'avion)
modus ponens avec R6 et F5 : F6 (acheter.un.billet)
règle du "et" avec F3 et F4 : F7 (durée.>.2.jours ^ être.fonctionnaire)
règle du "et" avec F4 et F2 : F5 (acheter.un.billet ^ avoir.le.téléphone) 
modus ponens avec R4 et F5 : F6 (téléphoner.à.l'agence)
modus ponens avec R7 et F7 : F8 (non prendre.l'avion)
L'"expert" va s'insurger : notre système a déduit, d'une part, qu'il fallait prendre l'avion (F5), et d'autre part qu'il ne fallait pas (F8).
Alors, sous réserve d'un stockage des déductions, nous pouvons interroger le système :
Q : pourquoi F5?
R : modus ponens avec R3 et F1
Q : pourquoi F8 ?
R : modus ponens avec R7 et F7
Q : pourquoi F7?
R : ègle du "et" avec F3 et F4
Nous savons à présent que l'erreur provient d'une contradiction entre R3 et R7, que nous montrons à l'expert. Comment corriger? En supprimant R3, et en le remplaçant par les bons axiomes, ceux qui traitent tous les cas. Où placer les nouveaux axiomes? N'importe où.
La mise au point ne coute pas $4000, parce que :

2.2.4. Terminologie

Dorénavant, nous appellerons "règles" les axiomes de type Ri, c'est-à-dire les axiomes qui contiennent "->", et qui forment la BdC. C'est regrettable, car cela entretient une confusion avec les règles de dérivation, mais c'est l'usage.
Une règle a une partie gauche (LHS) et une partie droite (RHS).
La LHS est une conjonction de prémisses, c'est-à-dire que les prémisses sont reliées par des ^. La partie droite est une conjonction de conséquents.
En Prolog, la partie droite est à gauche, et il n'y a qu'un conséquent.

2.3. Généralisations

2.3.1. De 0 à 0+

Reprenons notre S.F., avec une nouvelle base de faits :
F1 : distance.=.500km
F2 : avoir.le.téléphone
Il ne se passe rien. Le système ne sait pas, à partir du symbole distance.=.500km , affirmer
(non distance.<.300km) . Pour que cela soit possible, il faudrait "casser l'atome" :

Terminologie : Nous avons quitté le Calcul des Propositions, ou Logique d'ordre 0, pour une Logique que nous appellerons "0+", dans laquelle apparaissent des "trucs valuables", des constantes, et des prédicats. Le prix à payer est de programmer la sémantique des prédicats, c'est-à-dire d'écrire un programme capable, par exemple, de remplacer "distance = 500km" par "non distance < 300km". D'où la verrue sur le nez de Mickey.

2.3.2. De 0+ à 1

Supposons que le système me "dise" d'aller à l'agence. Ce serait bien qu'il me dise aussi comment aller à l'agence, sachant que la distance est de 1,5km. Mais il ne peut pas, parce que "distance" n'est pas une variable : si j'écrase "distance = 500km" par "distance = 1,5km", je vais obtenir des résultats contradictoires.
Solution : dupliquer le système :
axiomes
R1 : distance.destination < 2km -> aller.à.pied.destination
R1a : distance.agence < 2km -> aller.à.pied.agence
R2 : ((non distance.destination < 2km) 
       ^ distance.destination < 300km) -> 
       prendre.le.train.destination
R2a : ((non distance.agence < 2km) 
       ^ distance.agence < 300km) -> prendre.le.train.agence
...
F1 : distance.destination = 500km
F2 : distance.agence = 1,5km
F3 : non avoir.le.téléphone
Mais supposons maintenant que je veuille travailler sur n objets : je ne peux pas "n-pliquer" mon système. Il faut que je puisse écrire :
R1 : quelle que soit la destination, distance(destination) < 2km -> aller.à.pied(destination)
destination devient alors une variable, et j'ai introduit d'autre part "quelle que soit", qu'on appelle le quantificateur universel, noté .
Je suis à présent en Calcul des Prédicats du Premier Ordre, ou "Logique d'Ordre 1". Mon moteur d'inférence va se compliquer, puisqu'il va devoir chercher, non plus à faire coller un "F" avec la partie gauche d'un "R", mais chercher quelles valeurs des variables permettent cet appariement.

2.3.3. De 1 à 2

Pour définir qu'une relation R est transitive, il suffit d'écrire :
R (x y z (xRy) ^ (yRz) -> (xRz)) -> transitive (R))
Mais on n'a pas le droit! En effet, on fait porter le quantificateur universel sur "R", une variable de relation, alors qu'on n'a le droit de le faire porter que sur une variable d'individu.
On passe alors à la Logique d'Ordre 2... mais ceci est une autre histoire.

2.3.4. Du monotone au non monotone

Supposons à présent que j'écrive :
fenêtre.ouverte ^ courant.d'air -> fermer.la.fenêtre
"fermer.la.fenêtre" est un théorème, qui doit s'entendre : "il faut fermer la fenêtre". Mais ce qui m'interesserait, c'est qu'un robot domotique dispose de telles connaissances, et qu'il aille effectivement fermer la fenêtre avec ses petites mains. "fermer.la.fenêtre" devient alors une action. Mais si mon robot ferme la fenêtre, il y aura contradiction entre l'état du monde et sa Base de Faits, qui contiendra encore "fenêtre.ouverte". Donc, il faut compléter :
fenêtre.ouverte ^ courant.d'air -> fermer.la.fenêtre ^ non fenêtre.ouverte
Ce qui revient à écrire : A ^ ... -> non A ^ ...
Or toute la Logique repose sur l'interdiction d'une telle formule !
Nous créons donc (dans les années 70), les Logiques non monotones, dans lesquelles cela n'est plus interdit. (non monotone, par analogie avec l'Analyse : le nombre de théorèmes n'est plus une fonction non-décroissante du temps).
Nous gagnons en puissance d'expression, mais nous perdons quelque chose de très important : la certitude de terminer en temps fini. En effet, la même situation peut se reproduire (quelqu'un ré-ouvre la fenêtre), et il faudra appliquer à nouveau la même règle aux mêmes faits ; nous ne pouvons donc plus marquer comme au 2.2.2., et donc le système peut boucler.
On remarquera que cette notion de monotonie/non-monotonie est indépendante de l'Ordre de la Logique considérée :

2.3.5. Du non monotone au temporel

Si je dis à présent à mon robot :
oeuf.cru ^ eau.froide -> allumer.le.gaz
Dans 3 minutes, je pourrai affirmer "non oeuf.cru". Mais pendant ces trois minutes? Donc je vais programmer mon système pour qu'il ne fasse aucune déduction à ce propos pendant 3mn. On entre dans les Logiques temporelles.
Si je dis maintenant :
non en.stock(article) ^ besoin(article) -> commander(article)
c'est pareil, sauf que je ne sais pas quand arrivera le livreur.

2.3.6. Du bi-valué au flou

Jusqu'à présent, nous appuyant sur les S.F., dans lesquels une expression est, ou n'est pas, un théorème, nous ne nous sommes intéressés qu'au "vrai" et au "faux". Or, dans la vraie vie, les choses ne sont pas si simples. Il y a des choses dont nous ne savons pas si elles sont vraies ou fausses. On peut donc souhaiter manipuler les 3 valeurs : (V ? F).
Mais cela peut encore sembler trop étroit : on peut avoir besoin d'une graduation plus fine : (Vrai Probable Inconnu Improbable Faux). Et puis pourquoi ne pas continuer? On peut considérer l'intervalle continu [-1 +1]. Mais c'est encore simpliste : à une notion donnée, on peut associer une certitude, comprise entre -1 et +1, et une précision, comprise entre 0 et 1. On entre alors dans le domaine des Logiques floues (fuzzy).

Le problème devient alors :
Si A -> B avec une certitude CR et une précision PR,
et si A est connu avec CA et PA,
on peut en déduire B, mais combien valent CB et PB?

2.3.7. Et après

Jusqu'ici, nous sommes restés "objectifs". Si à présent nous voulons introduire "l'homme dans la boucle", nous pouvons envisager des opérateurs tels que "X croit que Y est vrai", "X sait que Y est vrai", etc. Avec des règles plus ou moins contraignantes. Par exemple, "nul n'est censé ignorer la loi" s'écrira : X A, A -> sait(X A).

2.4. Synthèse

Il n'y a pas une Logique, mais un grand nombre de Logiques. Lorsque vous décidez de résoudre un problème en faisant appel à des connaissances, la première chose à faire est de vous situer dans l'espace à 4 dimensions ci-dessus,... et de regarder si le moteur d'inférence correspondant existe.