coq-en-stock/dm1-AVRILLON.v

551 lines
13 KiB
Coq
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(* L3 IF, 2021-2022, cours Théorie de la Programmation, DM 1.
À rendre en déposant le fichier nommé DM1-nomdefamille.v sur le portail des études
pour le 7 octobre à 23h59 au plus tard.
À faire seul(e). Vous pouvez solliciter les chargés de TP, H. Déprés et E. Hazard,
ou D. Hirschkoff sur discord (ou par mail) si vous avez des questions.
On sintéresse ici à une représentation dune liste à laide de deux listes.
Pour simplifier, on ne considérera que des listes dentiers naturels (list nat) en Coq.
Lintuition est que lon “pointe” un endroit dans la liste (entre deux entiers),
avec dun côté ce qui est avant, et de lautre ce qui est après.
On convient que le couple (l1,l2) représente la liste commençant par la liste l1
à lenvers, suivie de la liste l2. Par exemple, le couple ([2;4], [5]) représente
la liste [4;2;5], le pointeur étant entre le 2 et le 5.
Les couples ([2], [4;5]), ([], [2;4;5]) et ([5;4;2],[]) représentent également la même liste.
Ce fichier sert de trame à votre devoir : il sagit de le renvoyer rempli.
Dans les solutions que vous proposez, il faut sastreindre à ne pas parcourir inutilement
les listes, avec lidée quajouter un élément à une liste (opérateur ::) a un coût,
et déconstruire une liste (récupérer la tête et la queue de la liste, si celle-ci nest pas
vide) a également un coût.
Comme évoqué ci-dessus, une liste dentiers peut avoir plusieurs représentations équivalentes.
Lorsquon a le choix, on privilégiera la représentation avec “un maximum déléments
à droite” (intuitivement parce que la liste de droite est celle qui est à lendroit),
mais on ne va pas samuser à parcourir des bouts de liste uniquement pour en faire
basculer certains à droite.
*)
(************************************************************************************)
(* Nous faisons appel à la librairie sur les listes.
Commencez par lire la documentation sur cette librairie, certains des
résultats qui y sont prouvés pourront vous être utiles :
https://coq.inria.fr/library/Coq.Lists.List.html
*)
Require Export List.
(* On introduit des incantations récupérées du livre "Software Foundations",
de B. Pierce et al., pour utiliser les notations habituelles avec les crochets *)
Notation "x :: l" := (cons x l)
(at level 60, right associativity).
Notation "[ ]" := nil.
Notation "[ x ; .. ; y ]" := (cons x .. (cons y nil) ..).
(* La représentation des listes sur laquelle on travaille pour ce DM : *)
Definition dl : Set := (list nat)*(list nat).
Definition sizetwo := fun d : dl => length (fst d) + length (snd d).
(* Des listes de nat aux dl *)
Definition init : (list nat)-> dl := fun l => ([],l).
(* Des dl aux listes de nat.
Définissez t2o "directement", sans faire appel à
des fonctions définies dans la librairie List. *)
Fixpoint t2o (l1 l2: list nat) := match l1 with
| [] => l2
| e::s => t2o s (e::l2)
end.
(* Utilisez t2o pour définir la fonction suivante, qui est l'"inverse"
de init. *)
Definition two2one : dl -> list nat := fun ll =>
match ll with
| (l1,l2) => t2o l1 l2
end.
(*******************************************************************************)
Require Export Arith. (* pour connaître des lemmes ci-dessous *)
(* On introduit la fonction suivante *)
Fixpoint compare_lists l1 l2 :=
match l1,l2 with
| nil,nil => true
| x::xs, y::ys => if Nat.eq_dec x y then compare_lists xs ys else false
| _,_ => false end.
(* La fonction compare_lists fait un if-then-else, en se servant de Nat.eq_dec : *)
Check Nat.eq_dec.
(* Nat.eq_dec
: forall n m : nat, {n = m} + {n <> m} *)
(* La notation { .. } + { .. } correspond à une "disjonction dans Set", sur
laquelle on peut faire un if-then-else. Cette notation s'appuie sur le type
sumbool de Coq.
Vous pouvez par exemple utiliser la commande *)
Search sumbool lt.
(* pour voir l'ensemble des lemmes que connaît Coq faisant intervenir lt et sumbool. *)
Lemma compare_lists_cons_nil : forall (a: nat) (l: list nat), compare_lists (a::l) [] = false.
intros.
simpl.
reflexivity.
Qed.
Lemma compare_lists_cons_nil_r : forall (a: nat) (l: list nat), compare_lists [] (a::l) = false.
intros.
simpl.
reflexivity.
Qed.
Lemma compare_lists_nil : forall (l: list nat), compare_lists l [] = true -> l=[].
induction l.
simpl.
trivial.
intro HH.
rewrite (compare_lists_cons_nil a l) in HH.
inversion HH.
Qed.
Lemma compare_lists_nil_r : forall (l: list nat), compare_lists [] l = true -> l=[].
induction l.
simpl.
trivial.
intro HH.
rewrite (compare_lists_cons_nil_r a l) in HH.
inversion HH.
Qed.
Check IF_then_else.
Check (Nat.eq_dec 0 1).
Check sumbool.
Lemma compare_lists_ind : forall l l' a b,
(compare_lists (a::l) (b::l')) = true -> ((a=b) /\ (compare_lists l l')=true).
intros.
unfold compare_lists in H; fold compare_lists in H.
destruct (Nat.eq_dec a b).
split.
assumption.
assumption.
inversion H.
Qed.
Lemma compare_lists_tt : forall l' l l'',
compare_lists l l' = true -> compare_lists l' l'' = true ->
compare_lists l l'' = true.
induction l' as [ | b lb ].
intros.
apply (compare_lists_nil l) in H.
apply (compare_lists_nil_r l'') in H0.
rewrite H.
rewrite H0.
simpl.
reflexivity.
intro.
case l as [ | a la].
intros.
rewrite compare_lists_cons_nil_r in H.
inversion H.
case l'' as [ | c lc ].
intros.
inversion H0.
intros H1 H2.
apply compare_lists_ind in H1.
apply compare_lists_ind in H2.
destruct H1.
destruct H2.
subst a c.
simpl.
destruct (Nat.eq_dec b b).
apply IHlb.
assumption.
assumption.
destruct n.
reflexivity.
Qed.
Lemma compare_lists_t : forall l1 l2 l3,
compare_lists l1 l2 = true -> compare_lists l2 l3 = true ->
compare_lists l1 l3 = true.
intros.
apply (compare_lists_tt l2 l1 l3).
assumption.
assumption.
Qed.
(* symétrie *)
Lemma compare_lists_s : forall l1 l2,
compare_lists l1 l2 = true -> compare_lists l2 l1 = true.
induction l1.
intros.
apply compare_lists_nil_r in H.
rewrite H.
simpl.
reflexivity.
induction l2.
intro HH.
rewrite compare_lists_cons_nil in HH.
inversion HH.
intro H.
apply compare_lists_ind in H.
destruct H.
subst a0.
destruct (Nat.eq_dec a a).
simpl.
destruct (Nat.eq_dec a a).
apply IHl1.
assumption.
apply n in e.
inversion e.
contradiction.
Qed.
(* reflexivité *)
Lemma compare_lists_r : forall l, compare_lists l l = true.
induction l.
simpl. reflexivity.
simpl. destruct (Nat.eq_dec a a).
assumption.
contradiction.
Qed.
Definition compare_dl : dl -> dl -> bool :=
fun d1 d2 => compare_lists (two2one d1) (two2one d2).
(* Sans surprise, le calcul qui est effectué par compare_lists en renvoyant
un bool correspond à l'égalité sur les list nat : c'est prouvé par les deux
lemmes suivants. *)
Lemma compare_bool_Prop : forall l1 l2, compare_lists l1 l2 = true -> l1=l2.
induction l1.
intro l2.
case l2.
simpl. reflexivity.
intros.
rewrite compare_lists_cons_nil_r in H.
inversion H.
induction l2.
intro HH.
rewrite compare_lists_cons_nil in HH.
inversion HH.
intro H.
apply compare_lists_ind in H.
destruct H.
subst a0.
apply IHl1 in H0.
subst l2.
reflexivity.
Qed.
Lemma compare_Prop_bool : forall l1 l2, l1=l2 -> compare_lists l1 l2 = true.
induction l1.
intros.
subst l2.
simpl. reflexivity.
induction l2.
intro H. inversion H.
intros.
inversion H.
apply IHl1 in H2.
subst a0.
simpl.
destruct (Nat.eq_dec a a).
apply compare_lists_r.
contradiction.
Qed.
(* Définissez une fonction qui calcule le retournement d'une liste. *)
Definition rev2 : dl -> dl := fun dd => match dd with
| (lg, ld) => (ld,lg)
end.
Lemma petit_cons : forall (a:nat) (l:list nat), (a::l) = ([a] ++ l).
intros.
simpl.
reflexivity.
Qed.
Lemma dl_def : forall lg ld, (t2o lg ld) = (List.rev lg ++ ld).
induction lg.
simpl. reflexivity.
simpl. intro ld.
rewrite IHlg.
rewrite app_ass.
rewrite petit_cons.
reflexivity.
Qed.
Lemma rev2_two2one_ll : forall lg ld,
compare_lists (List.rev (t2o lg ld)) (two2one (rev2 ((lg,ld))))=true.
simpl.
induction lg.
simpl.
induction ld.
simpl. reflexivity.
simpl. rewrite dl_def. apply compare_lists_r.
induction ld.
simpl.
rewrite dl_def.
apply (compare_Prop_bool (rev (rev lg ++ [a])) (a::lg)).
cut ([a] = rev [a]).
intro H.
rewrite H.
rewrite distr_rev.
rewrite rev_involutive.
rewrite rev_involutive.
simpl. reflexivity.
simpl. reflexivity.
apply compare_Prop_bool.
apply compare_bool_Prop in IHld.
rewrite dl_def.
rewrite dl_def.
rewrite dl_def in IHld.
rewrite dl_def in IHld.
rewrite <- (rev_involutive (a0::ld)).
rewrite distr_rev.
rewrite rev_involutive.
rewrite rev_involutive.
rewrite <- (rev_involutive ld) in IHld.
rewrite <- (distr_rev (rev ld) (a::lg)) in IHld.
rewrite rev_involutive in IHld.
rewrite rev_involutive in IHld.
reflexivity.
Qed.
(* Pour prouver le lemme suivant, vous pouvez introduire des lemmes
intermédiaires, et aussi vous appuyer sur la librairie List de Coq
(n'oubliez pas que ++ est une notation pour la fonction app). *)
Lemma rev2_two2one : forall d,
compare_lists (List.rev (two2one d)) (two2one (rev2 d))=true.
induction d as [ lg ld ].
apply rev2_two2one_ll.
Qed.
(* Retirer un élément d'une liste *)
(*
Définir une fonction rid : dl -> nat -> dl, qui retire un élément d'une liste
s'il le trouve, et renvoie la liste inchangée sinon.
Si l'élément apparaît plusieurs fois dans la liste, on n'en retire qu'une seule copie.
Veillez à prendre en compte les recommandations ci-dessus à propos du fait que l'on
évite de parcourir inutilement des bouts de liste, et que l'on préfère que
"ça penche à droite" plutôt qu'à gauche.
*)
Fixpoint ridelle l n := match l with
| nil => (nil, false)
| e::s => if Nat.eq_dec n e then (s, true) else
match (ridelle s n) with
| (ss, b) => (e::ss, b)
end
end.
Definition rid ll n := match ll with
| (lg, ld) => match (ridelle lg n) with
| (sg, b) => if Bool.bool_dec b true then (sg,ld) else
match (ridelle ld n) with
| (sd, bb) => (sg,sd)
end
end
end.
Definition fst (ll: list nat * bool) := match ll with
| (lg, ld) => lg
end.
(*
Définir une fonction rid_sorted : dl -> nat -> dl, qui fait comme rid2, à ceci près
que l'on suppose que la liste passée en argument (et représentée avec un dl) est triée.*)
Definition rid_sorted ll n := match ll with
| (lg, ld) => match lg with
| nil => (nil, fst (ridelle ld n))
| e::s => if Bool.bool_dec (e<?n) true then (lg, fst (ridelle ld n)) else (fst (ridelle lg n), ld)
end
end.
(* Relation inductive entre listes. *)
(* Définir une relation inductive dont l'intention est qu'elle coïncide avec compare_dl.
Il n'est pas autorisé de faire appel à des fonctions définies ci-dessus dans la
définition de same. *)
Inductive same : dl -> dl -> Prop :=
| same_nil : same ([],[]) ([],[])
| same_decale : forall lg ld a dd, same (a::lg,ld) dd -> same (lg, a::ld) dd
| same_cons : forall lg ld lg' ld' a, same (lg, ld) (lg',ld') -> same (lg, a::ld) (lg', a::lg)
| same_s : forall dd dd', same dd dd' -> same dd' dd.
Lemma cons_toi_meme : forall (l:list nat) (a:nat), l=(a::l) -> False.
intros.
induction l.
inversion H.
inversion H.
subst.
apply IHl in H2.
apply H2.
Qed.
Lemma same_nil_plus : forall ld ld', same ([], ld) ([], ld') -> ld=ld'.
Abort.
(*
induction ld.
intro ld'.
induction ld'.
reflexivity.
intro H.
inversion H.
subst.
reflexivity.
subst.
case ld'.
reflexivity.
intros.
intro H.
inversion H.
intros.
inversion H.
subst. reflexivity.
subst. apply IHld in H1. subst. reflexivity.
Qed.*)
Lemma same_left : forall l l', same ([],l) ([],l') -> l=l'.
Abort.
(* On prouve ensuite que compare_dl et same coïncident. *)
Lemma same_first_equal : forall lg ld lg' ld', same (lg,ld) (lg',ld') -> lg=lg' -> ld=ld'.
intros lg.
induction ld.
intro lg'.
induction ld'.
reflexivity.
intros. subst.
induction lg'.
induction ld'.
exfalso. inversion H. subst.
inversion H.
subst. reflexivity.
subst.
apply cons_toi_meme in H4. exfalso. apply H4.
subst. induction lg'.
inversion H2.
subst. reflexivity.
subst. apply same_nil in H1.
subst. reflexivity.
inversion H
Qed.
Theorem same_compare :
forall d1 d2, same d1 d2 -> compare_dl d1 d2 = true.
induction d1 as [lg ld].
induction lg.
intros.
unfold compare_dl.
simpl.
induction d2 as [lg' ld'].
simpl.
induction lg'.
simpl.
apply same_first_equal in H.
apply compare_Prop_bool.
assumption.
reflexivity.
simpl.
inversion H.
intro d2.
induction d2 as [ lg' ld' ].
induction lg'.
intro H.
inversion H. subst.
unfold compare_dl.
simpl.
destruct (Nat.eq_dec a a).
apply compare_lists_r.
contradiction.
intro H.
inversion H. subst lg' ld' a0 ld0 lg0.
unfold compare_dl.
apply compare_lists_r.
subst ld' lg lg0 ld0 a1.
rename a0 into b; rename lg' into lg.
unfold compare_dl.
unfold two2one.
simpl.
apply compare_lists_r.
Qed.
Theorem compare_same :
forall d1 d2, compare_dl d1 d2 = true -> same d1 d2.
induction d1 as [lg ld].
induction lg.
induction d2 as [lg' ld'].
intro H.
unfold compare_dl in H.
unfold two2one in H.
simpl in H.
apply compare_bool_Prop in H.
induction lg'.
simpl in H. subst. apply same_idem.
simpl in H. subst.
unfold t2o in H.
Qed.
(* fin du DM ***************************************************************)