Adloun

Probleme – Un évaluateur, un compteur de modèles, un testeur de tautologie

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 20 — Logique propositionnelle

Énoncé

On travaille avec le type formule étendu par Vrai et Faux (exercice 20.5).

Corrigé

1. Les modèles.


(* Toutes les valuations sur vs. Il y en a 2^|vs|.
   Précondition : vs sans doublon. *)
let rec valuations = function
  | [] -> [[]]
  | p :: reste ->
      List.concat_map (fun l -> [(p, true) :: l; (p, false) :: l])
                      (valuations reste)

(* La valeur que la liste d'association l donne à p ; false par défaut,
   ce qui ne sert jamais si l porte toutes les variables de la formule. *)
let lire l p = try List.assoc p l with Not_found -> false

(* Liste des modèles de f, comme listes d'association sur variables f.
   Précondition : aucune. Postcondition : le résultat contient exactement
   les valuations v de variables f telles que [[f]]_v = V. *)
let modeles f =
  List.filter (fun l -> evalue (lire l) f) (valuations (variables f))

2. Les trois prédicats.


let nb_variables f = List.length (variables f)
let satisfiable f = modeles f <> []
let tautologie f =
  List.for_all (fun l -> evalue (lire l) f) (valuations (variables f))
let antilogie f = not (satisfiable f)

Un seul parcours suffit, et il ne faut surtout pas le faire trois fois. Chacun des trois prédicats est un quantificateur sur la même table : pour la satisfiabilité, pour la tautologie, et l'antilogie est la négation du premier. Écrits comme ci-dessus, satisfiable et tautologie s'arrêtent dès qu'ils savent — List.for_all rend false au premier contre-modèle. C'est le même bénéfice que la paresse du chapitre chap:langage-c, et c'est ce que perd la version qui construit d'abord toute la liste.

3. La grille complète pour modeles.

Spécification. Entrée : une formule . Sortie : la liste des valuations sur qui satisfont , chacune donnée comme liste d'association. Aucune précondition.

Terminaison. valuations récurre sur une liste strictement plus courte : variant la longueur de la liste. evalue récurre sur un sous-arbre strict : induction structurelle. List.filter parcourt une liste finie. Tout termine.

Correction. Par récurrence sur : valuations [] rend [[]], l'unique valuation vide ; et si valuations reste énumère les valuations sur reste sans répétition, alors préfixer chacune par puis par en donne , deux à deux distinctes, et toutes. La correction de evalue est celle du cours (induction structurelle, la fonction reproduit la définition). Le filtre garde donc exactement les modèles.

Complexité. listes de longueur , construites en . Chaque évaluation coûte nœuds, chacun consultant List.assoc en . Total : en temps, et en espace — c'est là que le bât blesse, car on matérialise la table.

Complexité : La table ne se stocke pas, elle se parcourt

Pour , la liste des valuations pèse déjà des dizaines de gigaoctets, alors que le parcours n'aurait besoin que de booléens à la fois. La leçon vaut au-delà de ce chapitre : quand une énumération est exponentielle, on l'écrit en itérateur et jamais en liste. Ici, tautologie écrite avec List.for_all sur valuations garde ce défaut ; la version correcte énumère par récursion sans construire la liste.

4. Le piège du comptage. L'écriture List.length (modeles f) = 1 lsl n est fausse pour deux raisons distinctes, et il faut les nommer toutes les deux.

D'abord, elle est coûteuse pour rien : elle calcule tous les modèles avant de conclure, là où un seul contre-modèle suffirait. Sur une formule qui échoue à la première ligne, on paie au lieu de .

Ensuite, et c'est plus grave, n y désigne quoi ? Si c'est nb_variables f, le test est correct mais fragile ; si c'est un nombre de variables fixé par le contexte — celui d'un ensemble de formules, par exemple —, le test devient faux : a modèles sur ses propres variables et sur , et elle est tautologique dans les deux cas. Le nombre de modèles n'a de sens que relativement à un ensemble de variables déclaré. La formulation par n'a pas ce défaut : elle ne mentionne aucun nombre.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.