Adloun

Logique propositionnelle

Cours complet · OCaml (option informatique), chapitre 17 · prépas MPSI et MP, option informatique

Travailler ce chapitre sur Adloun Exercices corrigés de ce chapitre

<i class="fa-solid fa-compass mr-2" style="color:#9A563B"></i>17.1 Introduction et motivation

La logique propositionnelle manipule des formules construites sur des variables booléennes à l'aide des connecteurs non, et, ou. Savoir si une formule est satisfiable (rendue vraie par un choix de valeurs) est le problème SAT, central en informatique théorique et omniprésent en pratique (vérification, planification, circuits).

Ce chapitre est aussi une synthèse du cours : une formule se modélise par un type somme récursif (chapitre 3), s'évalue par récursion sur sa structure, et sa satisfiabilité se décide par retour sur trace sur les valuations (chapitre 11), à l'aide d'un tableau de booléens (chapitre 5). La logique propositionnelle est le terrain de jeu idéal de la programmation fonctionnelle.

17.2 Représenter une formule

Une formule est : une variable, la négation d'une formule, la conjonction (et) ou la disjonction (ou) de deux formules. C'est un type récursif, comme les arbres du chapitre 3 — d'ailleurs une formule est un arbre.


type formule =
  | Var of int                       (* variable numérotée *)
  | Non of formule
  | Et of formule * formule
  | Ou of formule * formule
Exemple 17.1Une formule et son arbre

La formule s'écrit :


let f = Et (Ou (Var 0, Non (Var 1)), Var 2)

Les feuilles sont les variables Var i, les nœuds internes les connecteurs. La taille de la formule est le nombre de nœuds de cet arbre.

17.3 Évaluer une formule

Une valuation affecte une valeur de vérité à chaque variable ; on la code par un tableau de booléens, v.(i) étant la valeur de la variable i. L'évaluation suit la structure de la formule.


let rec evalue v f =
  match f with
  | Var i -> v.(i)
  | Non g -> not (evalue v g)
  | Et (g, h) -> evalue v g && evalue v h
  | Ou (g, h) -> evalue v g || evalue v h

C'est une récursion sur l'arbre de la formule (chapitre 3) : chaque connecteur se traduit par l'opérateur booléen correspondant. &amp;&amp; et || héritent au passage de l'évaluation paresseuse (chapitre 1).

17.4 Variables et valuations

Pour énumérer les valuations, il faut connaître le nombre de variables. On suppose les variables numérotées 0..n-1 ; n est le plus grand indice plus un.


let rec var_max f =
  match f with
  | Var i -> i
  | Non g -> var_max g
  | Et (g, h) | Ou (g, h) ->
      let a = var_max g and b = var_max h in
      if a >= b then a else b

let nb_variables f = var_max f + 1

Le motif Et (g, h) | Ou (g, h) regroupe les deux connecteurs binaires, traités pareillement (chapitre 3). Avec n variables, il y a valuations possibles.

17.5 Satisfiabilité et tautologie

Définition 17.2Satisfiable, tautologie

Une formule est satisfiable s'il existe au moins une valuation qui la rend vraie ; c'est une tautologie si toute valuation la rend vraie. Une formule est satisfiable si et seulement si sa négation n'est pas une tautologie.

On décide ces propriétés en énumérant les valuations par retour sur trace : on essaie false puis true pour chaque variable.


let satisfiable f =
  let n = nb_variables f in
  let v = Array.make n false in
  let rec essaie i =
    if i = n then evalue v f               (* valuation complète : on teste *)
    else begin
      v.(i) <- false;
      if essaie (i + 1) then true          (* une solution suffit *)
      else begin v.(i) <- true; essaie (i + 1) end
    end
  in
  essaie 0

Complexité : Coût de SAT

On explore jusqu'à valuations : coût exponentiel dans le pire cas. Aucun algorithme connu ne fait essentiellement mieux en général — SAT est le problème NP-complet emblématique. Le retour sur trace, avec un peu d'élagage (le || paresseux s'arrête à la première solution), reste l'approche de base.

<i class="fa-solid fa-dumbbell mr-2" style="color:#2E7559"></i>17.6 Exercices résolus

Niveau (application directe du cours)

Exercice 1 : Évaluer

Avec f = Et (Ou (Var 0, Non (Var 1)), Var 2), évaluer f sous la valuation x0 = false, x1 = false, x2 = true.

Démonstration

let v = [| false; false; true |]
(* evalue v f : Ou (false, not false) = Ou(false, true) = true ; Et(true, true) = true *)

evalue v f vaut true : Var 0 est false, Non (Var 1) est true, leur ou est true ; Var 2 est true ; le et final est true.

Exercice 2 : Nombre de variables

Écrire nb_variables et l'appliquer à f ci-dessus.

Démonstration

let rec var_max f =
  match f with
  | Var i -> i
  | Non g -> var_max g
  | Et (g, h) | Ou (g, h) ->
      let a = var_max g and b = var_max h in if a >= b then a else b

let nb_variables f = var_max f + 1

La plus grande variable de f est Var 2, donc nb_variables f = 3. On suppose les variables numérotées sans trou de 0 à n-1.

Exercice 3 : Taille d'une formule

Écrire taille f : le nombre de nœuds (variables et connecteurs) de la formule.

Démonstration

let rec taille f =
  match f with
  | Var _ -> 1
  | Non g -> 1 + taille g
  | Et (g, h) | Ou (g, h) -> 1 + taille g + taille h

Récursion sur l'arbre : une feuille compte 1, un connecteur unaire 1 + sa sous-formule, un binaire 1 + les deux. C'est la fonction taille des arbres du chapitre 3, adaptée.

Niveau (raisonnement intermédiaire)

Exercice 4 : Satisfiabilité

Écrire satisfiable f et l'appliquer à Et (Var 0, Non (Var 0)).

Démonstration

let satisfiable f =
  let n = nb_variables f in
  let v = Array.make n false in
  let rec essaie i =
    if i = n then evalue v f
    else begin
      v.(i) <- false;
      if essaie (i + 1) then true
      else begin v.(i) <- true; essaie (i + 1) end
    end
  in
  essaie 0

satisfiable (Et (Var 0, Non (Var 0))) vaut false : aucune valuation ne rend x0 et not x0 simultanément vrais — c'est une contradiction.

Exercice 5 : Tautologie

Écrire tautologie f et vérifier que Ou (Var 0, Non (Var 0)) (le tiers exclu) en est une.

Démonstration

let tautologie f =
  let n = nb_variables f in
  let v = Array.make n false in
  let rec essaie i =
    if i = n then evalue v f
    else begin
      v.(i) <- false;
      essaie (i + 1) && (v.(i) <- true; essaie (i + 1))
    end
  in
  essaie 0

Toute valuation doit rendre la formule vraie : le &amp;&amp; exige les deux branches (x_i faux et vrai) et s'arrête au premier échec. tautologie (Ou (Var 0, Non (Var 0))) vaut true. On a aussi tautologie f = not (satisfiable (Non f)).

Exercice 6 : Nombre de modèles

Écrire nb_modeles f : le nombre de valuations qui satisfont f.

Démonstration

let nb_modeles f =
  let n = nb_variables f in
  let v = Array.make n false in
  let rec compte i =
    if i = n then (if evalue v f then 1 else 0)
    else begin
      v.(i) <- false;
      let a = compte (i + 1) in
      v.(i) <- true;
      a + compte (i + 1)
    end
  in
  compte 0

On parcourt l'arbre des valuations en additionnant les contributions (comme le comptage de sous-ensembles du chapitre 11), au lieu de s'arrêter à la première. Une tautologie a modèles, une contradiction .

Niveau (approfondissement)

Exercice 7 : Équivalence

Écrire equivalentes f g : f et g ont-elles la même valeur sous toute valuation ?

Démonstration

let equivalentes f g =
  let n =
    let a = var_max f and b = var_max g in (if a >= b then a else b) + 1
  in
  let v = Array.make n false in
  let rec verifie i =
    if i = n then evalue v f = evalue v g
    else begin
      v.(i) <- false;
      verifie (i + 1) && (v.(i) <- true; verifie (i + 1))
    end
  in
  verifie 0

On prend le nombre de variables couvrant les deux formules, puis on vérifie l'égalité evalue v f = evalue v g sur chaque valuation. C'est une tautologie déguisée (celle de f &lt;-&gt; g).

Exercice 8 : Implication et contraposée

On définit l'implication par implique a b = Ou (Non a, b). Vérifier que a =&gt; b et sa contraposée (not b) =&gt; (not a) sont équivalentes.

Démonstration

let implique a b = Ou (Non a, b)

let f = implique (Var 0) (Var 1)                       (* x0 => x1 *)
let g = implique (Non (Var 1)) (Non (Var 0))           (* (non x1) => (non x0) *)
(* equivalentes f g  vaut  true *)

On construit les deux formules avec implique, puis equivalentes f g confirme par énumération qu'elles ont la même table de vérité : une implication équivaut toujours à sa contraposée. Représenter les connecteurs dérivés (=&gt;, &lt;-&gt;) par des combinaisons des trois de base est une technique récurrente.

Exercice 9 : Substitution

Écrire substitue f x g : la formule obtenue en remplaçant chaque occurrence de Var x par la formule g dans f.

Démonstration

let rec substitue f x g =
  match f with
  | Var i -> if i = x then g else Var i
  | Non h -> Non (substitue h x g)
  | Et (a, b) -> Et (substitue a x g, substitue b x g)
  | Ou (a, b) -> Ou (substitue a x g, substitue b x g)

Récursion sur la structure : on descend dans la formule et l'on remplace les feuilles Var x par g, en reconstruisant un nouvel arbre (les formules sont immuables). La substitution est l'opération de base de la réécriture de formules.

Exercice 10 : Trouver un modèle

Écrire trouve_modele f : bool array option qui renvoie une valuation satisfaisant f (Some v), ou None si f est insatisfiable.

Démonstration

let trouve_modele f =
  let n = nb_variables f in
  let v = Array.make n false in
  let rec essaie i =
    if i = n then (if evalue v f then Some (Array.copy v) else None)
    else begin
      v.(i) <- false;
      match essaie (i + 1) with
      | Some m -> Some m
      | None -> v.(i) <- true; essaie (i + 1)
    end
  in
  essaie 0

C'est satisfiable qui, au lieu de renvoyer true, rapporte la valuation trouvée — d'où le Array.copy v (chapitre 5) pour figer une copie indépendante de v (qui, mutable, continue d'évoluer). C'est le squelette d'un solveur SAT : explorer, et reconstruire la solution le long des choix réussis (chapitre 11).

Synthèse du chapitre (à retenir)
  • Une formule est un type somme récursif (Var, Non, Et, Ou) : un arbre, traité par récursion (chapitre 3).
  • Évaluer sous une valuation (bool array) : chaque connecteur devient l'opérateur booléen correspondant.
  • Satisfiable (existe une valuation vraie) / tautologie (toutes vraies) ; lien : tautologie f = not (satisfiable (Non f)).
  • On décide par retour sur trace sur les valuations (chapitre 11) : || paresseux pour SAT, &amp;&amp; pour la tautologie, addition pour compter les modèles.
  • SAT est exponentiel dans le pire cas (NP-complet).
  • Connecteurs dérivés (=&gt;, &lt;-&gt;) par combinaison des trois de base ; substitution et équivalence par récursion / énumération.

17.7 Exercices d'entraînement

Légende : application directe, raisonnement intermédiaire, approfondissement ; signale un classique incontournable. La numérotation prolonge celle des dix exercices résolus.

Thème A — Manipuler les formules.
Thème B — Sémantique.
Thème C — Transformations.
Thème D — Vers un solveur.

Continuer sur Adloun : animation, QCM, fiches, exercices