Induction structurelle

From Wikipedia, the free encyclopedia

En mathématiques et davantage en informatique, la définition récursive ou induction structurelle est un procédé de définition conjointe d'un type (classe ou ensemble) et d'objets (éléments) qui le compose au moyen de règles de construction (constructeurs) qui agencent ou structurent ces objets.

L'on peut ainsi définir des nombres, des listes, des arbres, des relations, et plus généralement, toute structure mathématique (langage, système, …). En permettant par le même principe de définir un prédicat total[pas clair] i.e. qui est défini partout, l'induction structurelle est aussi une méthode de démonstration d'une propriété sur une structure.

Caractéristiques

La définition récursives se distingue de la "macro" et de la définition algébrique en cela qu'elle est la seule créatrice d'objets. La « macro » n'est qu'un raccourci de langage (i.e., une notation), alors que la définition algébrique « quotiente » ou contraint et restreint un type préexistant ((en) carier) au moyen d'axiomes. En revanche, la définition inductive engendre ex nihilo ses objets. Les règles de construction sont donc procréatrice.

Ainsi contrairement à l'axiome, les règles de construction d'une récurrence bien fondée ne peuvent créer l'incohérence.

De plus, tout objet appartient à une génération. Dans le cas le plus général, cette génération est un entier ou un ordinal. Le nombre de générations peut donc être , fini … nulle (types vide) ou ne pas être.

La validité de l'induction découle du caractère bijectif du procédé de procréation :

  • injectivité : à construction différente, objet différent ;
  • surjectivité : tout objet a une construction.

L'induction structurelle est une généralisation de la récurrence traditionnelle.

Exemples

Les fonctions définies par récurrence structurelle généralisent les fonctions définies par récurrence sur les entiers.

Les listes

Les listes sont définies comme étant

  • soit la liste vide ,
  • soit la liste obtenue par la mise en tête d'une liste d'un élément , ce qui donne .

La fonction qui définit la longueur d'une liste par induction :

  • .

La fonction qui concatène deux listes et

On peut démontrer la proposition suivante :

On procède par induction sur après avoir introduit

Cas de base ()

Cas inductif ()

On cherche à monter que

On dispose de l'hypothèse d'induction suivante

Donc

Donc , par définition de

Donc , par définition de

Donc , par définition de

Les arbres binaires

Considérons les arbres binaires définis ainsi :

  • pour l'arbre vide,
  • B B pour un arbre non vide ayant pour sous-arbre gauche B et pour sous-arbre droit B.

On peut définir la fonction taille (le nombre de nœuds internes de l'arbre binaire) :

  • taille() = 0
  • taille(B B) = taille(B) + taille(B) + 1

Principes

Premier principe d'induction

Sur , le premier principe d'induction, permet, en montrant une propriété sur un cas de base et la conservation de cette propriété de manière héréditaire, de montrer la propriété pour tous les entiers naturels si le cas de base est .

Premier principe d'induction [1]  Soit un prédicat (une propriété) dépendant de l'entier . Si les deux conditions suivantes sont vérifiées :

  • () est vrai
  • ()

alors est vrai.

() s'appelle l'étape de base de l'induction, elle affirme que est vrai.

() s'appelle l'étape héréditaire ou inductive, elle affirme pour tout que si est vrai alors est vrai aussi[1].

Deuxième principe d'induction

Lorsque l'on a des cas plus complexes, que l'on ait besoin d'utiliser pour montrer , il est plus pratique d'utiliser le second principe d'induction.

Deuxième principe d'induction [1]  Soit une propriété dépendant de l'entier . Si la proposition suivante est vérifiée :

  • ()

alors est vraie.

L'étape de base est cachée dans .

Sur , les deux principes d'induction sont équivalents, mais seul le deuxième principe d'induction se généralise à des ensembles ordonnés plus généraux[1].

Définition par induction structurelle

Considérons une structure définie par des constructeurs d'arité . Les constructeurs d'arité 0 sont des constantes.

La définition par induction structurelle d'une fonction s'écrit pour chaque constructeur

est une expression qui dépend de i'. On remarque que si est une constante, la définition est celle d'un cas de base:

Raisonnement par induction structurelle

Le schéma de démonstration qu'une propriété P est valide sur toute une structure se présente sous la forme d'une règle d'inférence pour chaque constructeur

Il faut donc faire une démonstration d'« hérédité » pour chaque constructeur.

Le cas des entiers naturels

Le cas des entiers naturels est celui où il y a deux constructeurs: 0 d'arité 0 (donc une constante) et succ (autrement dit +1) d'arité 1. La récurrence traditionnelle se réduit donc à une récurrence structurelle sur ces deux constructeurs.

La coinduction

Grossièrement la coinduction étend l'induction en offrant la possibilité d'omettre les éléments initiaux (le jardin d'éden).

Par exemple, omettre la liste vide, transforme la liste en flux ((en) stream). : Un flux de trucs est un truc qui s'ajoute à un flux de trucs.

Outils mathématiques et informatiques

Les système, langages et logiciels supportant à des degrés divers cette fonctionnalité sont nombreux.

L'induction structurelle dans les assistants de preuve

Un assistant de preuve est un logiciel permettant l'écriture et la vérification de preuves mathématiques. L'induction structurelle étant une technique de preuve très utilisée, les assistants de preuves supportent souvent l'écriture de telles preuves.

L'induction structurelle en Rocq

Rocq permet l'écriture de types inductifs qui représentent les ensembles inductifs. Rocq va alors générer automatiquement un principe d'induction associé à ce type.

Formalisation de l'exemple sur les listes

On commence par définir l'ensemble inductif où l'on retrouve les deux façons de construire un objet de type liste, la liste vide et la concaténation d'un élément et d'une liste.

Inductive list {A : Type} :=
    | nil
    | cons (head : A) (tail : list).

On définit deux notations afin que notre code se rapproche de l'écriture de l'exemple :

Notation "[]" := (nil).
Notation "head :: tail" := (cons head tail).

On définit les fonctions length et concat

Fixpoint length {A : Type} (l : @list A) : nat :=
    match l with
    | [] => 0
    | head :: tail => 1 + length tail
    end.|lang=Rocq
Fixpoint concat {A : Type} (l1 : @list A) (l2 : @list A) : @list A :=
    match l1 with
    | [] => l2
    | head :: tail => head :: (concat tail l2)
    end.

Enfin, on peut formaliser la preuve que la taille de la liste issue de la concaténation est bien la somme des tailles des listes en entrée.

Goal forall (A : Type) (l1 l2: @list A), 
        length (concat l1 l2) = length l1 + length l2.
Proof. intros A l1 l2.  
    induction l1 as [{{!}} a l1 IHl1].
    + simpl. reflexivity.
    + simpl. f_equal.
      apply IHl1.
Qed.

Le cas de base de l'induction se montre bien en utilisation la réflexivité de l'égalité après avoir évalué concat sur l1 vide.

Le cas inductif se montre bien principalement en utilisant l'hypothèse d'induction IHl1.

Principe d'induction généré par Rocq

Pour chaque ensemble inductif, définition Inductive ma_def en rocq, un principe d'induction enregistré dans la variable ma_def_ind. On peut l'afficher à l'aide de la commande Check list_ind. pour les listes de l'exemple précédent.

list_ind : forall (A : Type) (P : list -> Prop),
    P [] ->
    (forall (head : A) (tail : list), P tail -> P (head :: tail)) ->
        forall l : list, P l

On retrouve bien une propriété proche du premier principe d'induction, pour toute propriété , si la propriété est vérifiée sur la liste vide (cas de base), et que sachant qu'elle est vérifiée pour une liste, elle l'est encore si on lui rajoute un élément (cas inductif), alors, elle est vérifiée pour toute liste.

Preuve générée du principe d'induction

On peut alors se demander si le principe d'induction généré par Rocq est admis en axiome ou s'il est lui-même prouvé par l'assistant de preuve. On est dans le second cas, Rocq génère une preuve du principe d'induction.

Cette génération est un exemple d'application de la correspondance de Curry-Howard. En effet, pour prouver le principe d'induction, on va exhiber une fonction récursive terminant et ayant pour type le principe d'induction.

Pour les listes, on cherche à exhiber la fonction prenant une propriété sur les listes, la preuve que est vérifiée sur la liste vide, la preuve du cas inductif et une liste quelconque et doit renvoyer la preuve que est vérifiée sur .

Si l'on peut exhiber une telle fonction, alors, il est suffisant de disposer de et , les preuves du cas de base et du cas inductif, afin de pouvoir prouver la propriété sur toutes les listes. En effet, on a simplement à appliquer cette fonction.

Voici la fonction générée pour le principe d'induction des listes :

fun (A : Type)
    (P : list -> Prop)
    (Pnil : P [])
    (Pcons : forall (head : A) (tail : list), P tail -> P (head :: tail)) 
=> fix F (l : list) : P l :=
    match l with
    | [] => Pnil
    | head :: tail => Pcons head tail (F tail)
    end

Ici la fonction récursive termine immédiatement, le variant étant la taille de la liste .

Bibliographie

Références

Voir aussi

Related Articles

Wikiwand AI