Logique de base en Coq

La flèche ou implication

Type Prop et ->

L'objet fondamental du système Coq est le type (on dit qu'il est basé sur la théorie des types ). Tous les objets que l'on manipule ont un certain type. Le type Prop, parfois aussi noté ℙ dans certaines interfaces, est celui des propositions, c'est-à-dire des énoncés mathématiques que l'on peut chercher à prouver ou à réfuter.

La commande Check permet d'imprimer le type d'un terme. Appuyer sur Ctrl+↓ (si vous utilisez coqide) ou Alt+↓ (si vous utilisez la version web ) pour faire interpréter la prochaine ligne à Coq. Voir le résultat dans la fenêtre en bas à droite.

Les énoncés 2 + 2 = 4 et 2 + 2 = 5 sont tous deux de type Prop, peu importe qu'ils soient prouvables ou non.

Étant données deux propositions P et Q, on peut en former une nouvelle, P -> Q (lire : «  P flèche Q » ou «  P implique Q »). Intuitivement, dans la logique de Coq, la proposition P -> Q signifie « si P, alors Q » ou, plus précisément, « je sais construire une preuve de Q à partir d'une preuve de P. » Remarque : La notation usuelle des mathématiques pour « P implique Q » est P ⇒ Q. Continuez à l'utilisez lors de vos cours plus classiques de mathématiques.

Première preuve

Nous allons maintenant énoncer et prouver un premier théorème. Exécuter pas à pas cette preuve pour bien voir les modifications dans le contexte et le but. En Coq, les commentaires sont écrits entre (* ... *). Ici, comme à beaucoup d'autres endroits de ce cours, ils sont destinés à vous montrer la preuve « mathématique » très détaillée correspondant à la preuve en Coq.

Ce premier théorème énonce que, quelle que soit la proposition P, on a P -> P. Cela peut paraître évident, mais en Coq il faut tout prouver !

Sans entrer dans tous les détails, quelques commentaires s'imposent :

  • imp_refl est le nom que nous avons choisi pour ce théorème.
  • La preuve se trouve entre les mots-clés Proof. et Qed.
  • Lorsque vous avez fait interpréter à Coq la ligne Proof., vous avez vu apparaître en haut à droite de l'écran une fenêtre qui décrit l'état de la preuve .
  • Cet état contient deux parties séparées par une ligne horizontale. En dessous de cette ligne se trouve le but : c'est ce qu'il faut démontrer. Au-dessus de cette ligne se trouve le contexte : un ensemble de variables et d'hypothèses qu'on peut utiliser pour prouver le but.
  • Les éléments de la preuve intros et exact sont appelés des tactiques de preuve. Ils font évoluer l'état de la preuve.
  • Lorsque l'évaluation par Coq atteint Qed., Coq vérifie que la preuve est correcte et dans le cas contraire affiche un message d'erreur.
  • Petit point de syntaxe : en Coq, les commandes et les tactiques se terminent toujours par un point.
Pour pouvoir passer à la suite, il faut avoir vraiment bien compris que
  • intros nom_de_variable. introduit une nouvelle variable dans le contexte en supprimant un quantificateur universel (un « pour tout » en français, forall en Coq ou le symbole ).
  • intros nom_d_hypothese. introduit une nouvelle hypothèse dans le contexte en supprimant la première implication, à gauche, du but.
  • exact nom_d_hypothese. dit que l'hypothèse nom_d_hypothese est une preuve du but. Si besoin, exécuter de nouveau la preuve et bien regarder l'évolution de l'état de la preuve.

Exercice : à vous de remplir la preuve suivante !

Lorsque Coq vous indique que la preuve est terminée, vous devez remplacer la ligne Admitted. par Qed.. C'est vraiment facile, on veut juste s'assurer que vous avez compris la preuve précédente et mémorisé ses tactiques.

Plusieurs flèches à la suite

En Coq, lorsqu'on ne met pas de parenthèses dans une expression avec des ->, c'est comme s'il y en avait à droite : P -> Q -> R est la même proposition que P -> (Q -> R).

Exercice : Prouver le théorème suivant.

Exercice : Prouver le théorème suivant.

Remarque importante : Après avoir introduit toutes les variables et toutes les hypothèses dans ces deux derniers exercices, les contextes sont exactement les mêmes. En fait, plutôt que de penser à P -> Q -> R comme ( P implique que ( Q implique R)), il vaut mieux y voir « si Pet Q, alors R », ou encore, « si j'ai une preuve de P et une preuve de Q, alors je sais construire une preuve de R ».

Appliquer une implication

Maintenant qu'on a vu comment prouver (introduire) une implication, on va voir comment on utilise (élimine, applique) une implication.

Revenons sur la tactique apply. Si la formule à prouver est Q et qu'une hypothèse H a la forme P -> Q, alors l'utilisation de apply H. entraîne le changement du but en P. Ceci est conforme à la règle appelée syllogisme ou modus ponens qui dit que de P -> Q et P, on peut déduire Q.

  • Socrate est un homme. ( P)
  • Tous les hommes sont mortels. ( P -> Q)
  • Donc Socrate est mortel. ( Q)
Pour passer à la suite, vous devez vraiment avoir compris comme la tactique apply agit sur le but, si besoin en exécutant de nouveau la preuve précédente.

Exercice : Prouver le théorème suivant.

Les sous-buts

Il arrive très souvent qu'une tactique crée des sous-buts (en anglais subgoals ), comme dans cette preuve du théorème suivant.

Remarque : la preuve de l'exemple précédent est volontaire idiote pour vous montrer comment des sous-buts peuvent être générés. Seriez-vous capable de trouver une preuve beaucoup plus courte ?

Exercice : Prouver le théorème suivant.

Exercice : Prouver le théorème suivant.

Conjonction /\

Le « et logique » aussi appelé opérateur de conjonction est noté en Coq /\. Si P et Q sont deux propositions, alors P /\ Q est une proposition dont une preuve est à la fois une preuve de P et une preuve de Q.

Utiliser une conjonction : destruct

Pour décomposer une preuve de P /\ Q en une preuve de P et une preuve de Q, on utilise la tactique destruct.

Noter la syntaxe avec crochets pour destruct une proposition conjonctive : la tactique destruct H as [H1 H2] a détruit l'hypothèse H (elle n'est plus présente dans le contexte) et a ajouté les deux nouvelles hypothèses H1 et H2, qui sont, respectivement une preuve de P et une preuve de Q.

Exercice : Prouver le théorème suivant.

Les «  intro patterns  »

Les preuves pouvant être longues, les concepteurs de Coq essaient continuellement de nous faciliter la tâche avec des constructions qui font gagner du temps. Les intro pattern sont des transformations que l'on peut faire dès l'introduction de nouvelles hypothèses. Ici, au lieu d'écrire intros H suivi directement de destruct H as [H1 H2] il est possible d'écrire simplement intros [H1 H2] et l'hypothèse est directement introduite et détruite. La preuve de proj1 peut donc s'écrire en deux tactiques :

Exercice : Prouver le théorème suivant en utilisant un «  intro pattern  ».

Prouver une conjonction : split

Prouver P /\ Q se fait en deux étapes : il faut une preuve de P et une preuve de Q. Ceci se fait avec la tactique split.

Exercice : Prouver le théorème suivant.

Remarque : comme pour -> l'opérateur /\ est "associatif à droite" en Coq, ce qui signifie que P /\ Q /\ R dénote en fait P /\ (Q /\ R). Comme on va le voir ci-dessous, ceci n'a pas tellement d'importance ici.

Exercice : Prouver le théorème suivant.

Disjonction \/

En Coq, le « ou logique », aussi appelée opérateur de disjonction, est noté \/. Une preuve de P \/ Q est une preuve de P ou une preuve de Q.

Prouver une disjonction : left et right

Pour pouvoir prouver une disjonction (par exemple P \/ Q) en logique intuitionniste, il faut dire explicitement si l'on donne une preuve de l'opérande de gauche (ici P) ou de celui de droite (ici Q). Ceci se fait avec les tactiques left et right.

Attention : Le fait de choisir left ou right est en général important et doit être fait le plus tard possible (lorsque vous avez tous les éléments pour choisir). Si vous vous sentez bloqué dans la preuve, il peut être intéressant de revenir en arrière et d'essayer de prouver l'autre côté.

Exercice : Prouver le théorème suivant.

Exercice : Prouver le théorème suivant.

Utiliser une disjonction : destruct

Pour utiliser une disjonction (par exemple une preuve de P \/ Q), on doit faire une preuve par cas :

  • Dans un premier temps, on prouve le but sous l'hypothèse que l'opérande de gauche (ici P) est prouvée.
  • Dans un second temps, on prouve le but sous l'hypothèse que l'opérande de droite (ici Q) est prouvée. Ceci se fait encore avec la tactique destruct.

Exercice : Prouver le théorème suivant.

De la même manière que pour /\, on peut utiliser un «  intro pattern  » pour détruire une disjonction directement.

On peut même mettre des «  intro patterns  » dans des «  intro patterns  »

Bilan

Vient la partie la plus importante, il faut que tout ce que vous avez appris cette semaine soit acquis pour les suivantes. Nous avons rencontré (dans cet ordre), les tactiques suivantes :
  • intros une variable universellement quantifiée dans le but
  • intros une hypothèse lorsque le but est une implication
  • exact
  • apply une preuve d'une implication
  • destruct une preuve d'une conjonction
  • split
  • destruct une preuve d'une disjonction
  • left et right (Remarque encourageante, nous avons vu la moitié environ des tactiques utilisées dans ce cours.) Vous devez écrire une fiche décrivant le rôle de chaque tactique, un exemple de syntaxe, et la façon dont elle modifie l'état de la preuve (contexte et/ou but).
Nous avons aussi rencontré (dans cet ordre) des connecteurs logiques :
  • implication ->
  • conjonction /\
  • disjonction \/ Vous devez écrire, pour chacun d'entre eux, son sens « intuitif », la façon dont on le prouve et la façon dont on l'utilise dans une preuve.
Enfin, vous devez savoir utiliser un théorème déjà prouvé dans une autre preuve et comprendre qu'on peut laisser à Coq certains « trous » qu'il peut remplir avec l'unification.