Objectif du TP

Verifier formellement en Coq les proprietes du langage MusicFunk concu dans le TP1 : le retrograde est une involution, la transposition conserve le nombre de notes, l'augmentation multiplie la duree.

Lien avec le cours

Tester qu'un programme fonctionne, c'est bien ; prouver qu'il fonctionne toujours, c'est mieux !

Partie A — Representation Coq des melodies (1h)

Types de donnees

(* Les notes de la gamme *)
Inductive note : Type :=
  | C | D | E | F | G | A | B.

(* Une melody est un arbre inductif *)
Inductive melody : Type :=
  | Silence : nat -> melody
  | Note    : note -> nat -> melody
  | Seq     : melody -> melody -> melody
  | Rep     : melody -> nat -> melody.
Simplification

La duree est un nat (nombre de noires) au lieu d'un float. Cette simplification rend les preuves plus accessibles.

Fonctions de base

Fixpoint duree_totale (m : melody) : nat :=
  match m with
  | Silence d => d
  | Note _ _ => 1
  | Seq m1 m2 => duree_totale m1 + duree_totale m2
  | Rep m n => n * duree_totale m
  end.

Fixpoint nb_notes (m : melody) : nat :=
  match m with
  | Silence _ => 0
  | Note _ _ => 1
  | Seq m1 m2 => nb_notes m1 + nb_notes m2
  | Rep m n => n * nb_notes m
  end.

Partie B — Preuves des transformations (1.5h)

Transposition preserve le nombre de notes

Fixpoint transpose_nat (st : nat) (m : melody) : melody :=
  match m with
  | Silence d => Silence d
  | Note n o => Note n o
  | Seq m1 m2 => Seq (transpose_nat st m1) (transpose_nat st m2)
  | Rep m n => Rep (transpose_nat st m) n
  end.

Lemma transpose_preserves_notes : forall st m,
  nb_notes (transpose_nat st m) = nb_notes m.
Proof.
  intros st m.
  induction m as [| n o | m1 IH1 m2 IH2 | m n IH].
  - simpl. reflexivity.
  - simpl. reflexivity.
  - simpl. rewrite IH1. rewrite IH2. reflexivity.
  - simpl. rewrite IH. reflexivity.
Qed.

Retrograde est une involution

Fixpoint retrograde (m : melody) : melody :=
  match m with
  | Silence d => Silence d
  | Note n o => Note n o
  | Seq m1 m2 => Seq (retrograde m2) (retrograde m1)
  | Rep m n => Rep (retrograde m) n
  end.

Lemma retrograde_involutive : forall m,
  retrograde (retrograde m) = m.
Proof.
  intro m.
  induction m as [| n o | m1 IH1 m2 IH2 | m n IH].
  - simpl. reflexivity.
  - simpl. reflexivity.
  - simpl. rewrite IH1. rewrite IH2. reflexivity.
  - simpl. rewrite IH. reflexivity.
Qed.

Augmentation multiplie la duree

Fixpoint augmenter (k : nat) (m : melody) : melody :=
  match m with
  | Silence d => Silence (k * d)
  | Note n o => Note n o
  | Seq m1 m2 => Seq (augmenter k m1) (augmenter k m2)
  | Rep m n => Rep (augmenter k m) n
  end.

Lemma augmenter_duree : forall k m,
  duree_totale (augmenter k m) = k * duree_totale m.
Proof.
  intros k m.
  induction m as [| n o | m1 IH1 m2 IH2 | m n IH].
  - simpl. lia.
  - simpl. lia.
  - simpl. rewrite IH1. rewrite IH2. lia.
  - simpl. rewrite IH. lia.
Qed.

Partie C — Proprietes de composition (0.5h)

(* Silence 0 est l'element neutre de Seq *)
Lemma seq_nil_r : forall m,
  Seq m (Silence 0) = m.
Proof.
  intro m. reflexivity.
Qed.

(* Repeter 1 fois = identite *)
Lemma rep_1 : forall m,
  Rep m 1 = m.
Proof.
  intro m. reflexivity.
Qed.

(* nb_notes est additif sur Seq *)
Lemma nb_notes_seq : forall m1 m2,
  nb_notes (Seq m1 m2) = nb_notes m1 + nb_notes m2.
Proof.
  intros m1 m2. reflexivity.
Qed.

Partie D — Proprietes avancees (1h)

(* Retrograde preserve la duree totale *)
Lemma retrograde_preserves_duree : forall m,
  duree_totale (retrograde m) = duree_totale m.
Proof.
  intro m.
  induction m as [| n o | m1 IH1 m2 IH2 | m n IH].
  - simpl. reflexivity.
  - simpl. reflexivity.
  - simpl. rewrite IH1. rewrite IH2. lia.
  - simpl. rewrite IH. lia.
Qed.

(* Retrograde preserve le nombre de notes *)
Lemma retrograde_preserves_notes : forall m,
  nb_notes (retrograde m) = nb_notes m.
Proof.
  intro m.
  induction m as [| n o | m1 IH1 m2 IH2 | m n IH].
  - simpl. reflexivity.
  - simpl. reflexivity.
  - simpl. rewrite IH1. rewrite IH2. lia.
  - simpl. rewrite IH. lia.
Qed.

Synthese

ProprieteLemme CoqPreuve
Transposition conserve nb_notestranspose_preserves_notesinduction
Retrograde est une involutionretrograde_involutiveinduction
Augmentation multiplie la dureeaugmenter_dureeinduction + lia
Repetition 1 = identiterep_1reflexivite
Duree additive sur Seqduree_seqreflexivite
Retrograde preserve dureeretrograde_preserves_dureeinduction + lia
Retrograde preserve notesretrograde_preserves_notesinduction + lia
Rendu

Le fichier music_funk.v contenant toutes les definitions et preuves. Chaque theoreme doit etre accepte par Coq (pas de Admitted).