diff options
Diffstat (limited to 'theories/Lists/List.v')
-rw-r--r-- | theories/Lists/List.v | 1047 |
1 files changed, 796 insertions, 251 deletions
diff --git a/theories/Lists/List.v b/theories/Lists/List.v index f5a12b09..3cba090f 100644 --- a/theories/Lists/List.v +++ b/theories/Lists/List.v @@ -1,15 +1,16 @@ (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) -(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *) +(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) -Require Import Le Gt Minus Bool Setoid. +Require Setoid. +Require Import PeanoNat Le Gt Minus Bool. Set Implicit Arguments. - +(* Set Universe Polymorphism. *) (******************************************************************) (** * Basics: definition of polymorphic lists and some operations *) @@ -20,6 +21,16 @@ Set Implicit Arguments. Open Scope list_scope. +(** Standard notations for lists. +In a special module to avoid conflicts. *) +Module ListNotations. +Notation " [ ] " := nil (format "[ ]") : list_scope. +Notation " [ x ] " := (cons x nil) : list_scope. +Notation " [ x ; .. ; y ] " := (cons x .. (cons y nil) ..) : list_scope. +End ListNotations. + +Import ListNotations. + Section Lists. Variable A : Type. @@ -28,44 +39,31 @@ Section Lists. Definition hd (default:A) (l:list A) := match l with - | nil => default + | [] => default | x :: _ => x end. Definition hd_error (l:list A) := match l with - | nil => error + | [] => error | x :: _ => value x end. Definition tl (l:list A) := match l with - | nil => nil + | [] => nil | a :: m => m end. (** The [In] predicate *) Fixpoint In (a:A) (l:list A) : Prop := match l with - | nil => False + | [] => False | b :: m => b = a \/ In a m end. End Lists. - -(** Standard notations for lists. -In a special module to avoid conflict. *) -Module ListNotations. -Notation " [ ] " := nil : list_scope. -Notation " [ x ] " := (cons x nil) : list_scope. -Notation " [ x ; .. ; y ] " := (cons x .. (cons y nil) ..) : list_scope. -End ListNotations. - -Import ListNotations. - -(** ** Facts about lists *) - Section Facts. Variable A : Type. @@ -89,6 +87,24 @@ Section Facts. left; exists a, tail; reflexivity. Qed. + Lemma hd_error_tl_repr : forall l (a:A) r, + hd_error l = Some a /\ tl l = r <-> l = a :: r. + Proof. destruct l as [|x xs]. + - unfold hd_error, tl; intros a r. split; firstorder discriminate. + - intros. simpl. split. + * intros (H1, H2). inversion H1. rewrite H2. reflexivity. + * inversion 1. subst. auto. + Qed. + + Lemma hd_error_some_nil : forall l (a:A), hd_error l = Some a -> l <> nil. + Proof. unfold hd_error. destruct l; now discriminate. Qed. + + Theorem length_zero_iff_nil (l : list A): + length l = 0 <-> l=[]. + Proof. + split; [now destruct l | now intros ->]. + Qed. + (** *** Head and tail *) Theorem hd_error_nil : hd_error (@nil A) = None. @@ -119,6 +135,12 @@ Section Facts. simpl; auto. Qed. + Theorem not_in_cons (x a : A) (l : list A): + ~ In x (a::l) <-> x<>a /\ ~ In x l. + Proof. + simpl. intuition. + Qed. + Theorem in_nil : forall a:A, ~ In a []. Proof. unfold not; intros a H; inversion_clear H. @@ -130,7 +152,7 @@ Section Facts. subst a; auto. exists [], l; auto. destruct (IHl H) as (l1,(l2,H0)). - exists (a::l1), l2; simpl; f_equal; auto. + exists (a::l1), l2; simpl. apply f_equal. auto. Qed. (** Inversion *) @@ -173,7 +195,7 @@ Section Facts. Qed. Theorem app_nil_r : forall l:list A, l ++ [] = l. - Proof. + Proof. induction l; simpl; f_equal; auto. Qed. @@ -228,10 +250,8 @@ Section Facts. intros. injection H. intro. - cut ([] = l ++ a0 :: l0); auto. - intro. - generalize (app_cons_not_nil _ _ _ H1); intro. - elim H2. + assert ([] = l ++ a0 :: l0) by auto. + apply app_cons_not_nil in H1 as []. Qed. Lemma app_inj_tail : @@ -240,22 +260,20 @@ Section Facts. induction x as [| x l IHl]; [ destruct y as [| a l] | destruct y as [| a l0] ]; simpl; auto. - intros a b H. - injection H. - auto. - intros a0 b H. - injection H; intros. - generalize (app_cons_not_nil _ _ _ H0); destruct 1. - intros a b H. - injection H; intros. - cut ([] = l ++ [a]); auto. - intro. - generalize (app_cons_not_nil _ _ _ H2); destruct 1. - intros a0 b H. - injection H; intros. - destruct (IHl l0 a0 b H0). - split; auto. - rewrite <- H1; rewrite <- H2; reflexivity. + - intros a b H. + injection H. + auto. + - intros a0 b H. + injection H as H1 H0. + apply app_cons_not_nil in H0 as []. + - intros a b H. + injection H as H1 H0. + assert ([] = l ++ [a]) by auto. + apply app_cons_not_nil in H as []. + - intros a0 b H. + injection H as <- H0. + destruct (IHl l0 a0 b H0) as (<-,<-). + split; auto. Qed. @@ -360,13 +378,12 @@ Section Elts. Lemma nth_in_or_default : forall (n:nat) (l:list A) (d:A), {In (nth n l d) l} + {nth n l d = d}. - (* Realizer nth_ok. Program_all. *) Proof. - intros n l d; generalize n; induction l; intro n0. - right; case n0; trivial. - case n0; simpl. - auto. - intro n1; elim (IHl n1); auto. + intros n l d; revert n; induction l. + - right; destruct n; trivial. + - intros [|n]; simpl. + * left; auto. + * destruct (IHl n); auto. Qed. Lemma nth_S_cons : @@ -395,60 +412,132 @@ Section Elts. unfold nth_default; induction n; intros [ | ] ?; simpl; auto. Qed. + (** Results about [nth] *) + Lemma nth_In : forall (n:nat) (l:list A) (d:A), n < length l -> In (nth n l d) l. - Proof. unfold lt; induction n as [| n hn]; simpl. - destruct l; simpl; [ inversion 2 | auto ]. - destruct l as [| a l hl]; simpl. - inversion 2. - intros d ie; right; apply hn; auto with arith. + - destruct l; simpl; [ inversion 2 | auto ]. + - destruct l as [| a l hl]; simpl. + * inversion 2. + * intros d ie; right; apply hn; auto with arith. + Qed. + + Lemma In_nth l x d : In x l -> + exists n, n < length l /\ nth n l d = x. + Proof. + induction l as [|a l IH]. + - easy. + - intros [H|H]. + * subst; exists 0; simpl; auto with arith. + * destruct (IH H) as (n & Hn & Hn'). + exists (S n); simpl; auto with arith. Qed. Lemma nth_overflow : forall l n d, length l <= n -> nth n l d = d. Proof. induction l; destruct n; simpl; intros; auto. - inversion H. - apply IHl; auto with arith. + - inversion H. + - apply IHl; auto with arith. Qed. Lemma nth_indep : forall l n d d', n < length l -> nth n l d = nth n l d'. Proof. - induction l; simpl; intros; auto. - inversion H. - destruct n; simpl; auto with arith. + induction l. + - inversion 1. + - intros [|n] d d'; simpl; auto with arith. Qed. Lemma app_nth1 : forall l l' d n, n < length l -> nth n (l++l') d = nth n l d. Proof. induction l. - intros. - inversion H. - intros l' d n. - case n; simpl; auto. - intros; rewrite IHl; auto with arith. + - inversion 1. + - intros l' d [|n]; simpl; auto with arith. Qed. Lemma app_nth2 : forall l l' d n, n >= length l -> nth n (l++l') d = nth (n-length l) l' d. Proof. - induction l. - intros. - simpl. - destruct n; auto. - intros l' d n. - case n; simpl; auto. - intros. - inversion H. - intros. - rewrite IHl; auto with arith. + induction l; intros l' d [|n]; auto. + - inversion 1. + - intros; simpl; rewrite IHl; auto with arith. + Qed. + + Lemma nth_split n l d : n < length l -> + exists l1, exists l2, l = l1 ++ nth n l d :: l2 /\ length l1 = n. + Proof. + revert l. + induction n as [|n IH]; intros [|a l] H; try easy. + - exists nil; exists l; now simpl. + - destruct (IH l) as (l1 & l2 & Hl & Hl1); auto with arith. + exists (a::l1); exists l2; simpl; split; now f_equal. Qed. + (** Results about [nth_error] *) + Lemma nth_error_In l n x : nth_error l n = Some x -> In x l. + Proof. + revert n. induction l as [|a l IH]; intros [|n]; simpl; try easy. + - injection 1; auto. + - eauto. + Qed. + Lemma In_nth_error l x : In x l -> exists n, nth_error l n = Some x. + Proof. + induction l as [|a l IH]. + - easy. + - intros [H|H]. + * subst; exists 0; simpl; auto with arith. + * destruct (IH H) as (n,Hn). + exists (S n); simpl; auto with arith. + Qed. + + Lemma nth_error_None l n : nth_error l n = None <-> length l <= n. + Proof. + revert n. induction l; destruct n; simpl. + - split; auto. + - split; auto with arith. + - split; now auto with arith. + - rewrite IHl; split; auto with arith. + Qed. + + Lemma nth_error_Some l n : nth_error l n <> None <-> n < length l. + Proof. + revert n. induction l; destruct n; simpl. + - split; [now destruct 1 | inversion 1]. + - split; [now destruct 1 | inversion 1]. + - split; now auto with arith. + - rewrite IHl; split; auto with arith. + Qed. + + Lemma nth_error_split l n a : nth_error l n = Some a -> + exists l1, exists l2, l = l1 ++ a :: l2 /\ length l1 = n. + Proof. + revert l. + induction n as [|n IH]; intros [|x l] H; simpl in *; try easy. + - exists nil; exists l. injection H; clear H; intros; now subst. + - destruct (IH _ H) as (l1 & l2 & H1 & H2). + exists (x::l1); exists l2; simpl; split; now f_equal. + Qed. + + Lemma nth_error_app1 l l' n : n < length l -> + nth_error (l++l') n = nth_error l n. + Proof. + revert l. + induction n; intros [|a l] H; auto; try solve [inversion H]. + simpl in *. apply IHn. auto with arith. + Qed. + + Lemma nth_error_app2 l l' n : length l <= n -> + nth_error (l++l') n = nth_error l' (n-length l). + Proof. + revert l. + induction n; intros [|a l] H; auto; try solve [inversion H]. + simpl in *. apply IHn. auto with arith. + Qed. (*****************) (** ** Remove *) @@ -541,19 +630,29 @@ Section Elts. match l with | [] => 0 | y :: tl => - let n := count_occ tl x in - if eq_dec y x then S n else n + let n := count_occ tl x in + if eq_dec y x then S n else n end. (** Compatibility of count_occ with operations on list *) - Theorem count_occ_In (l : list A) (x : A) : In x l <-> count_occ l x > 0. + Theorem count_occ_In l x : In x l <-> count_occ l x > 0. Proof. induction l as [|y l]; simpl. - split; [destruct 1 | apply gt_irrefl]. - destruct eq_dec as [->|Hneq]; rewrite IHl; intuition. Qed. - Theorem count_occ_inv_nil (l : list A) : + Theorem count_occ_not_In l x : ~ In x l <-> count_occ l x = 0. + Proof. + rewrite count_occ_In. unfold gt. now rewrite Nat.nlt_ge, Nat.le_0_r. + Qed. + + Lemma count_occ_nil x : count_occ [] x = 0. + Proof. + reflexivity. + Qed. + + Theorem count_occ_inv_nil l : (forall x:A, count_occ l x = 0) <-> l = []. Proof. split. @@ -563,27 +662,20 @@ Section Elts. - now intros ->. Qed. - Lemma count_occ_nil : forall (x : A), count_occ [] x = 0. - Proof. - intro x; simpl; reflexivity. - Qed. - - Lemma count_occ_cons_eq : forall (l : list A) (x y : A), x = y -> count_occ (x::l) y = S (count_occ l y). + Lemma count_occ_cons_eq l x y : + x = y -> count_occ (x::l) y = S (count_occ l y). Proof. - intros l x y H; simpl. - destruct (eq_dec x y); [reflexivity | contradiction]. + intros H. simpl. now destruct (eq_dec x y). Qed. - Lemma count_occ_cons_neq : forall (l : list A) (x y : A), x <> y -> count_occ (x::l) y = count_occ l y. + Lemma count_occ_cons_neq l x y : + x <> y -> count_occ (x::l) y = count_occ l y. Proof. - intros l x y H; simpl. - destruct (eq_dec x y); [contradiction | reflexivity]. + intros H. simpl. now destruct (eq_dec x y). Qed. End Elts. - - (*******************************) (** * Manipulating whole lists *) (*******************************) @@ -739,6 +831,33 @@ Section ListOps. End Reverse_Induction. + (*************************) + (** ** Concatenation *) + (*************************) + + Fixpoint concat (l : list (list A)) : list A := + match l with + | nil => nil + | cons x l => x ++ concat l + end. + + Lemma concat_nil : concat nil = nil. + Proof. + reflexivity. + Qed. + + Lemma concat_cons : forall x l, concat (cons x l) = x ++ concat l. + Proof. + reflexivity. + Qed. + + Lemma concat_app : forall l1 l2, concat (l1 ++ l2) = concat l1 ++ concat l2. + Proof. + intros l1; induction l1 as [|x l1 IH]; intros l2; simpl. + + reflexivity. + + rewrite IH; apply app_assoc. + Qed. + (***********************************) (** ** Decidable equality on lists *) (***********************************) @@ -759,15 +878,20 @@ End ListOps. (************) Section Map. - Variables A B : Type. + Variables (A : Type) (B : Type). Variable f : A -> B. Fixpoint map (l:list A) : list B := match l with - | nil => nil - | cons a t => cons (f a) (map t) + | [] => [] + | a :: t => (f a) :: (map t) end. + Lemma map_cons (x:A)(l:list A) : map (x::l) = (f x) :: (map l). + Proof. + reflexivity. + Qed. + Lemma in_map : forall (l:list A) (x:A), In x l -> In (f x) (map l). Proof. @@ -815,6 +939,25 @@ Section Map. destruct l; simpl; reflexivity || discriminate. Qed. + (** [map] and count of occurrences *) + + Hypothesis decA: forall x1 x2 : A, {x1 = x2} + {x1 <> x2}. + Hypothesis decB: forall y1 y2 : B, {y1 = y2} + {y1 <> y2}. + Hypothesis Hfinjective: forall x1 x2: A, (f x1) = (f x2) -> x1 = x2. + + Theorem count_occ_map x l: + count_occ decA l x = count_occ decB (map l) (f x). + Proof. + revert x. induction l as [| a l' Hrec]; intro x; simpl. + - reflexivity. + - specialize (Hrec x). + destruct (decA a x) as [H1|H1], (decB (f a) (f x)) as [H2|H2]. + * rewrite Hrec. reflexivity. + * contradiction H2. rewrite H1. reflexivity. + * specialize (Hfinjective H2). contradiction H1. + * assumption. + Qed. + (** [flat_map] *) Definition flat_map (f:A -> list B) := @@ -826,7 +969,7 @@ Section Map. Lemma in_flat_map : forall (f:A->list B)(l:list A)(y:B), In y (flat_map f l) <-> exists x, In x l /\ In y (f x). - Proof. + Proof using A B. induction l; simpl; split; intros. contradiction. destruct H as (x,(H,_)); contradiction. @@ -843,6 +986,21 @@ Section Map. End Map. +Lemma flat_map_concat_map : forall A B (f : A -> list B) l, + flat_map f l = concat (map f l). +Proof. +intros A B f l; induction l as [|x l IH]; simpl. ++ reflexivity. ++ rewrite IH; reflexivity. +Qed. + +Lemma concat_map : forall A B (f : A -> B) l, map f (concat l) = concat (map (map f) l). +Proof. +intros A B f l; induction l as [|x l IH]; simpl. ++ reflexivity. ++ rewrite map_app, IH; reflexivity. +Qed. + Lemma map_id : forall (A :Type) (l : list A), map (fun x => x) l = l. Proof. @@ -869,7 +1027,7 @@ Qed. (************************************) Section Fold_Left_Recursor. - Variables A B : Type. + Variables (A : Type) (B : Type). Variable f : A -> B -> A. Fixpoint fold_left (l:list B) (a0:A) : A := @@ -893,10 +1051,8 @@ End Fold_Left_Recursor. Lemma fold_left_length : forall (A:Type)(l:list A), fold_left (fun x _ => S x) l 0 = length l. Proof. - intro A. - cut (forall (l:list A) n, fold_left (fun x _ => S x) l n = n + length l). - intros. - exact (H l 0). + intros A l. + enough (H : forall n, fold_left (fun x _ => S x) l n = n + length l) by exact (H 0). induction l; simpl; auto. intros; rewrite IHl. simpl; auto with arith. @@ -907,7 +1063,7 @@ Qed. (************************************) Section Fold_Right_Recursor. - Variables A B : Type. + Variables (A : Type) (B : Type). Variable f : B -> A -> A. Variable a0 : A. @@ -939,29 +1095,17 @@ End Fold_Right_Recursor. Qed. Theorem fold_symmetric : - forall (A:Type) (f:A -> A -> A), - (forall x y z:A, f x (f y z) = f (f x y) z) -> - (forall x y:A, f x y = f y x) -> - forall (a0:A) (l:list A), fold_left f l a0 = fold_right f a0 l. + forall (A : Type) (f : A -> A -> A), + (forall x y z : A, f x (f y z) = f (f x y) z) -> + forall (a0 : A), (forall y : A, f a0 y = f y a0) -> + forall (l : list A), fold_left f l a0 = fold_right f a0 l. Proof. - destruct l as [| a l]. - reflexivity. - simpl. - rewrite <- H0. - generalize a0 a. - induction l as [| a3 l IHl]; simpl. - trivial. - intros. - rewrite H. - rewrite (H0 a2). - rewrite <- (H a1). - rewrite (H0 a1). - rewrite IHl. - reflexivity. + intros A f assoc a0 comma0 l. + induction l as [ | a1 l ]; [ simpl; reflexivity | ]. + simpl. rewrite <- IHl. clear IHl. revert a1. induction l; [ auto | ]. + simpl. intro. rewrite <- assoc. rewrite IHl. rewrite IHl. auto. Qed. - - (** [(list_power x y)] is [y^x], or the set of sequences of elts of [y] indexed by elts of [x], sorted in lexicographic order. *) @@ -1075,6 +1219,21 @@ End Fold_Right_Recursor. | x :: tl => if f x then Some x else find tl end. + Lemma find_some l x : find l = Some x -> In x l /\ f x = true. + Proof. + induction l as [|a l IH]; simpl; [easy| ]. + case_eq (f a); intros Ha Eq. + * injection Eq as ->; auto. + * destruct (IH Eq); auto. + Qed. + + Lemma find_none l : find l = None -> forall x, In x l -> f x = false. + Proof. + induction l as [|a l IH]; simpl; [easy|]. + case_eq (f a); intros Ha Eq x IN; [easy|]. + destruct IN as [<-|IN]; auto. + Qed. + (** [partition] *) Fixpoint partition (l:list A) : list A * list A := @@ -1084,6 +1243,53 @@ End Fold_Right_Recursor. if f x then (x::g,d) else (g,x::d) end. + Theorem partition_cons1 a l l1 l2: + partition l = (l1, l2) -> + f a = true -> + partition (a::l) = (a::l1, l2). + Proof. + simpl. now intros -> ->. + Qed. + + Theorem partition_cons2 a l l1 l2: + partition l = (l1, l2) -> + f a=false -> + partition (a::l) = (l1, a::l2). + Proof. + simpl. now intros -> ->. + Qed. + + Theorem partition_length l l1 l2: + partition l = (l1, l2) -> + length l = length l1 + length l2. + Proof. + revert l1 l2. induction l as [ | a l' Hrec]; intros l1 l2. + - now intros [= <- <- ]. + - simpl. destruct (f a), (partition l') as (left, right); + intros [= <- <- ]; simpl; rewrite (Hrec left right); auto. + Qed. + + Theorem partition_inv_nil (l : list A): + partition l = ([], []) <-> l = []. + Proof. + split. + - destruct l as [|a l' _]. + * intuition. + * simpl. destruct (f a), (partition l'); now intros [= -> ->]. + - now intros ->. + Qed. + + Theorem elements_in_partition l l1 l2: + partition l = (l1, l2) -> + forall x:A, In x l <-> In x l1 \/ In x l2. + Proof. + revert l1 l2. induction l as [| a l' Hrec]; simpl; intros l1 l2 Eq x. + - injection Eq as <- <-. tauto. + - destruct (partition l') as (left, right). + specialize (Hrec left right eq_refl x). + destruct (f a); injection Eq as <- <-; simpl; tauto. + Qed. + End Bool. @@ -1094,14 +1300,14 @@ End Fold_Right_Recursor. (******************************************************) Section ListPairs. - Variables A B : Type. + Variables (A : Type) (B : Type). (** [split] derives two lists from a list of pairs *) Fixpoint split (l:list (A*B)) : list A * list B := match l with - | nil => (nil, nil) - | (x,y) :: tl => let (g,d) := split tl in (x::g, y::d) + | [] => ([], []) + | (x,y) :: tl => let (left,right) := split tl in (x::left, y::right) end. Lemma in_split_l : forall (l:list (A*B))(p:A*B), @@ -1479,6 +1685,61 @@ Section Cutting. End Cutting. +(**********************************************************************) +(** ** Predicate for List addition/removal (no need for decidability) *) +(**********************************************************************) + +Section Add. + + Variable A : Type. + + (* [Add a l l'] means that [l'] is exactly [l], with [a] added + once somewhere *) + Inductive Add (a:A) : list A -> list A -> Prop := + | Add_head l : Add a l (a::l) + | Add_cons x l l' : Add a l l' -> Add a (x::l) (x::l'). + + Lemma Add_app a l1 l2 : Add a (l1++l2) (l1++a::l2). + Proof. + induction l1; simpl; now constructor. + Qed. + + Lemma Add_split a l l' : + Add a l l' -> exists l1 l2, l = l1++l2 /\ l' = l1++a::l2. + Proof. + induction 1. + - exists nil; exists l; split; trivial. + - destruct IHAdd as (l1 & l2 & Hl & Hl'). + exists (x::l1); exists l2; split; simpl; f_equal; trivial. + Qed. + + Lemma Add_in a l l' : Add a l l' -> + forall x, In x l' <-> In x (a::l). + Proof. + induction 1; intros; simpl in *; rewrite ?IHAdd; tauto. + Qed. + + Lemma Add_length a l l' : Add a l l' -> length l' = S (length l). + Proof. + induction 1; simpl; auto with arith. + Qed. + + Lemma Add_inv a l : In a l -> exists l', Add a l' l. + Proof. + intro Ha. destruct (in_split _ _ Ha) as (l1 & l2 & ->). + exists (l1 ++ l2). apply Add_app. + Qed. + + Lemma incl_Add_inv a l u v : + ~In a l -> incl (a::l) v -> Add a u v -> incl l u. + Proof. + intros Ha H AD y Hy. + assert (Hy' : In y (a::u)). + { rewrite <- (Add_in AD). apply H; simpl; auto. } + destruct Hy'; [ subst; now elim Ha | trivial ]. + Qed. + +End Add. (********************************) (** ** Lists without redundancy *) @@ -1492,31 +1753,187 @@ Section ReDun. | NoDup_nil : NoDup nil | NoDup_cons : forall x l, ~ In x l -> NoDup l -> NoDup (x::l). - Lemma NoDup_remove_1 : forall l l' a, NoDup (l++a::l') -> NoDup (l++l'). + Lemma NoDup_Add a l l' : Add a l l' -> (NoDup l' <-> NoDup l /\ ~In a l). Proof. - induction l; simpl. - inversion_clear 1; auto. - inversion_clear 1. - constructor. - contradict H0. - apply in_or_app; destruct (in_app_or _ _ _ H0); simpl; tauto. - apply IHl with a0; auto. + induction 1 as [l|x l l' AD IH]. + - split; [ inversion_clear 1; now split | now constructor ]. + - split. + + inversion_clear 1. rewrite IH in *. rewrite (Add_in AD) in *. + simpl in *; split; try constructor; intuition. + + intros (N,IN). inversion_clear N. constructor. + * rewrite (Add_in AD); simpl in *; intuition. + * apply IH. split; trivial. simpl in *; intuition. Qed. - Lemma NoDup_remove_2 : forall l l' a, NoDup (l++a::l') -> ~In a (l++l'). + Lemma NoDup_remove l l' a : + NoDup (l++a::l') -> NoDup (l++l') /\ ~In a (l++l'). Proof. - induction l; simpl. - inversion_clear 1; auto. - inversion_clear 1. - contradict H0. - destruct H0. - subst a0. - apply in_or_app; right; red; auto. - destruct (IHl _ _ H1); auto. + apply NoDup_Add. apply Add_app. + Qed. + + Lemma NoDup_remove_1 l l' a : NoDup (l++a::l') -> NoDup (l++l'). + Proof. + intros. now apply NoDup_remove with a. + Qed. + + Lemma NoDup_remove_2 l l' a : NoDup (l++a::l') -> ~In a (l++l'). + Proof. + intros. now apply NoDup_remove. + Qed. + + Theorem NoDup_cons_iff a l: + NoDup (a::l) <-> ~ In a l /\ NoDup l. + Proof. + split. + + inversion_clear 1. now split. + + now constructor. + Qed. + + (** Effective computation of a list without duplicates *) + + Hypothesis decA: forall x y : A, {x = y} + {x <> y}. + + Fixpoint nodup (l : list A) : list A := + match l with + | [] => [] + | x::xs => if in_dec decA x xs then nodup xs else x::(nodup xs) + end. + + Lemma nodup_In l x : In x (nodup l) <-> In x l. + Proof. + induction l as [|a l' Hrec]; simpl. + - reflexivity. + - destruct (in_dec decA a l'); simpl; rewrite Hrec. + * intuition; now subst. + * reflexivity. + Qed. + + Lemma NoDup_nodup l: NoDup (nodup l). + Proof. + induction l as [|a l' Hrec]; simpl. + - constructor. + - destruct (in_dec decA a l'); simpl. + * assumption. + * constructor; [ now rewrite nodup_In | assumption]. + Qed. + + Lemma nodup_inv k l a : nodup k = a :: l -> ~ In a l. + Proof. + intros H. + assert (H' : NoDup (a::l)). + { rewrite <- H. apply NoDup_nodup. } + now inversion_clear H'. + Qed. + + Theorem NoDup_count_occ l: + NoDup l <-> (forall x:A, count_occ decA l x <= 1). + Proof. + induction l as [| a l' Hrec]. + - simpl; split; auto. constructor. + - rewrite NoDup_cons_iff, Hrec, (count_occ_not_In decA). clear Hrec. split. + + intros (Ha, H) x. simpl. destruct (decA a x); auto. + subst; now rewrite Ha. + + split. + * specialize (H a). rewrite count_occ_cons_eq in H; trivial. + now inversion H. + * intros x. specialize (H x). simpl in *. destruct (decA a x); auto. + now apply Nat.lt_le_incl. + Qed. + + Theorem NoDup_count_occ' l: + NoDup l <-> (forall x:A, In x l -> count_occ decA l x = 1). + Proof. + rewrite NoDup_count_occ. + setoid_rewrite (count_occ_In decA). unfold gt, lt in *. + split; intros H x; specialize (H x); + set (n := count_occ decA l x) in *; clearbody n. + (* the rest would be solved by omega if we had it here... *) + - now apply Nat.le_antisymm. + - destruct (Nat.le_gt_cases 1 n); trivial. + + rewrite H; trivial. + + now apply Nat.lt_le_incl. + Qed. + + (** Alternative characterisations of being without duplicates, + thanks to [nth_error] and [nth] *) + + Lemma NoDup_nth_error l : + NoDup l <-> + (forall i j, i<length l -> nth_error l i = nth_error l j -> i = j). + Proof. + split. + { intros H; induction H as [|a l Hal Hl IH]; intros i j Hi E. + - inversion Hi. + - destruct i, j; simpl in *; auto. + * elim Hal. eapply nth_error_In; eauto. + * elim Hal. eapply nth_error_In; eauto. + * f_equal. apply IH; auto with arith. } + { induction l as [|a l]; intros H; constructor. + * intro Ha. apply In_nth_error in Ha. destruct Ha as (n,Hn). + assert (n < length l) by (now rewrite <- nth_error_Some, Hn). + specialize (H 0 (S n)). simpl in H. discriminate H; auto with arith. + * apply IHl. + intros i j Hi E. apply eq_add_S, H; simpl; auto with arith. } + Qed. + + Lemma NoDup_nth l d : + NoDup l <-> + (forall i j, i<length l -> j<length l -> + nth i l d = nth j l d -> i = j). + Proof. + split. + { intros H; induction H as [|a l Hal Hl IH]; intros i j Hi Hj E. + - inversion Hi. + - destruct i, j; simpl in *; auto. + * elim Hal. subst a. apply nth_In; auto with arith. + * elim Hal. subst a. apply nth_In; auto with arith. + * f_equal. apply IH; auto with arith. } + { induction l as [|a l]; intros H; constructor. + * intro Ha. eapply In_nth in Ha. destruct Ha as (n & Hn & Hn'). + specialize (H 0 (S n)). simpl in H. discriminate H; eauto with arith. + * apply IHl. + intros i j Hi Hj E. apply eq_add_S, H; simpl; auto with arith. } + Qed. + + (** Having [NoDup] hypotheses bring more precise facts about [incl]. *) + + Lemma NoDup_incl_length l l' : + NoDup l -> incl l l' -> length l <= length l'. + Proof. + intros N. revert l'. induction N as [|a l Hal N IH]; simpl. + - auto with arith. + - intros l' H. + destruct (Add_inv a l') as (l'', AD). { apply H; simpl; auto. } + rewrite (Add_length AD). apply le_n_S. apply IH. + now apply incl_Add_inv with a l'. + Qed. + + Lemma NoDup_length_incl l l' : + NoDup l -> length l' <= length l -> incl l l' -> incl l' l. + Proof. + intros N. revert l'. induction N as [|a l Hal N IH]. + - destruct l'; easy. + - intros l' E H x Hx. + destruct (Add_inv a l') as (l'', AD). { apply H; simpl; auto. } + rewrite (Add_in AD) in Hx. simpl in Hx. + destruct Hx as [Hx|Hx]; [left; trivial|right]. + revert x Hx. apply (IH l''); trivial. + * apply le_S_n. now rewrite <- (Add_length AD). + * now apply incl_Add_inv with a l'. Qed. End ReDun. +(** NoDup and map *) + +(** NB: the reciprocal result holds only for injective functions, + see FinFun.v *) + +Lemma NoDup_map_inv A B (f:A->B) l : NoDup (map f l) -> NoDup l. +Proof. + induction l; simpl; inversion_clear 1; subst; constructor; auto. + intro H. now apply (in_map f) in H. +Qed. (***********************************) (** ** Sequence of natural numbers *) @@ -1558,149 +1975,252 @@ Section NatSeq. auto with arith. Qed. + Lemma in_seq len start n : + In n (seq start len) <-> start <= n < start+len. + Proof. + revert start. induction len; simpl; intros. + - rewrite <- plus_n_O. split;[easy|]. + intros (H,H'). apply (Lt.lt_irrefl _ (Lt.le_lt_trans _ _ _ H H')). + - rewrite IHlen, <- plus_n_Sm; simpl; split. + * intros [H|H]; subst; intuition auto with arith. + * intros (H,H'). destruct (Lt.le_lt_or_eq _ _ H); intuition. + Qed. + + Lemma seq_NoDup len start : NoDup (seq start len). + Proof. + revert start; induction len; simpl; constructor; trivial. + rewrite in_seq. intros (H,_). apply (Lt.lt_irrefl _ H). + Qed. + End NatSeq. +Section Exists_Forall. -(** * Existential and universal predicates over lists *) + (** * Existential and universal predicates over lists *) -Inductive Exists {A} (P:A->Prop) : list A -> Prop := - | Exists_cons_hd : forall x l, P x -> Exists P (x::l) - | Exists_cons_tl : forall x l, Exists P l -> Exists P (x::l). -Hint Constructors Exists. + Variable A:Type. -Lemma Exists_exists : forall A P (l:list A), - Exists P l <-> (exists x, In x l /\ P x). -Proof. -split. -induction 1; firstorder. -induction l; firstorder; subst; auto. -Qed. + Section One_predicate. + + Variable P:A->Prop. + + Inductive Exists : list A -> Prop := + | Exists_cons_hd : forall x l, P x -> Exists (x::l) + | Exists_cons_tl : forall x l, Exists l -> Exists (x::l). -Lemma Exists_nil : forall A (P:A->Prop), Exists P nil <-> False. -Proof. split; inversion 1. Qed. + Hint Constructors Exists. -Lemma Exists_cons : forall A (P:A->Prop) x l, - Exists P (x::l) <-> P x \/ Exists P l. -Proof. split; inversion 1; auto. Qed. + Lemma Exists_exists (l:list A) : + Exists l <-> (exists x, In x l /\ P x). + Proof. + split. + - induction 1; firstorder. + - induction l; firstorder; subst; auto. + Qed. + Lemma Exists_nil : Exists nil <-> False. + Proof. split; inversion 1. Qed. + + Lemma Exists_cons x l: + Exists (x::l) <-> P x \/ Exists l. + Proof. split; inversion 1; auto. Qed. + + Lemma Exists_dec l: + (forall x:A, {P x} + { ~ P x }) -> + {Exists l} + {~ Exists l}. + Proof. + intro Pdec. induction l as [|a l' Hrec]. + - right. now rewrite Exists_nil. + - destruct Hrec as [Hl'|Hl']. + * left. now apply Exists_cons_tl. + * destruct (Pdec a) as [Ha|Ha]. + + left. now apply Exists_cons_hd. + + right. now inversion_clear 1. + Qed. -Inductive Forall {A} (P:A->Prop) : list A -> Prop := - | Forall_nil : Forall P nil - | Forall_cons : forall x l, P x -> Forall P l -> Forall P (x::l). + Inductive Forall : list A -> Prop := + | Forall_nil : Forall nil + | Forall_cons : forall x l, P x -> Forall l -> Forall (x::l). + + Hint Constructors Forall. + + Lemma Forall_forall (l:list A): + Forall l <-> (forall x, In x l -> P x). + Proof. + split. + - induction 1; firstorder; subst; auto. + - induction l; firstorder. + Qed. + + Lemma Forall_inv : forall (a:A) l, Forall (a :: l) -> P a. + Proof. + intros; inversion H; trivial. + Qed. + + Lemma Forall_rect : forall (Q : list A -> Type), + Q [] -> (forall b l, P b -> Q (b :: l)) -> forall l, Forall l -> Q l. + Proof. + intros Q H H'; induction l; intro; [|eapply H', Forall_inv]; eassumption. + Qed. + + Lemma Forall_dec : + (forall x:A, {P x} + { ~ P x }) -> + forall l:list A, {Forall l} + {~ Forall l}. + Proof. + intro Pdec. induction l as [|a l' Hrec]. + - left. apply Forall_nil. + - destruct Hrec as [Hl'|Hl']. + + destruct (Pdec a) as [Ha|Ha]. + * left. now apply Forall_cons. + * right. now inversion_clear 1. + + right. now inversion_clear 1. + Qed. + + End One_predicate. + + Lemma Forall_Exists_neg (P:A->Prop)(l:list A) : + Forall (fun x => ~ P x) l <-> ~(Exists P l). + Proof. + rewrite Forall_forall, Exists_exists. firstorder. + Qed. + + Lemma Exists_Forall_neg (P:A->Prop)(l:list A) : + (forall x, P x \/ ~P x) -> + Exists (fun x => ~ P x) l <-> ~(Forall P l). + Proof. + intro Dec. + split. + - rewrite Forall_forall, Exists_exists; firstorder. + - intros NF. + induction l as [|a l IH]. + + destruct NF. constructor. + + destruct (Dec a) as [Ha|Ha]. + * apply Exists_cons_tl, IH. contradict NF. now constructor. + * now apply Exists_cons_hd. + Qed. + + Lemma Forall_Exists_dec (P:A->Prop) : + (forall x:A, {P x} + { ~ P x }) -> + forall l:list A, + {Forall P l} + {Exists (fun x => ~ P x) l}. + Proof. + intros Pdec l. + destruct (Forall_dec P Pdec l); [left|right]; trivial. + apply Exists_Forall_neg; trivial. + intro x. destruct (Pdec x); [now left|now right]. + Qed. + + Lemma Forall_impl : forall (P Q : A -> Prop), (forall a, P a -> Q a) -> + forall l, Forall P l -> Forall Q l. + Proof. + intros P Q H l. rewrite !Forall_forall. firstorder. + Qed. + +End Exists_Forall. + +Hint Constructors Exists. Hint Constructors Forall. -Lemma Forall_forall : forall A P (l:list A), - Forall P l <-> (forall x, In x l -> P x). -Proof. -split. -induction 1; firstorder; subst; auto. -induction l; firstorder. -Qed. +Section Forall2. -Lemma Forall_inv : forall A P (a:A) l, Forall P (a :: l) -> P a. -Proof. -intros; inversion H; trivial. -Defined. + (** [Forall2]: stating that elements of two lists are pairwise related. *) -Lemma Forall_rect : forall A (P:A->Prop) (Q : list A -> Type), - Q [] -> (forall b l, P b -> Q (b :: l)) -> forall l, Forall P l -> Q l. -Proof. -intros A P Q H H'; induction l; intro; [|eapply H', Forall_inv]; eassumption. -Defined. + Variables A B : Type. + Variable R : A -> B -> Prop. -Lemma Forall_impl : forall A (P Q : A -> Prop), (forall a, P a -> Q a) -> - forall l, Forall P l -> Forall Q l. -Proof. - intros A P Q Himp l H. - induction H; firstorder. -Qed. + Inductive Forall2 : list A -> list B -> Prop := + | Forall2_nil : Forall2 [] [] + | Forall2_cons : forall x y l l', + R x y -> Forall2 l l' -> Forall2 (x::l) (y::l'). -(** [Forall2]: stating that elements of two lists are pairwise related. *) + Hint Constructors Forall2. -Inductive Forall2 A B (R:A->B->Prop) : list A -> list B -> Prop := - | Forall2_nil : Forall2 R [] [] - | Forall2_cons : forall x y l l', - R x y -> Forall2 R l l' -> Forall2 R (x::l) (y::l'). -Hint Constructors Forall2. + Theorem Forall2_refl : Forall2 [] []. + Proof. intros; apply Forall2_nil. Qed. + + Theorem Forall2_app_inv_l : forall l1 l2 l', + Forall2 (l1 ++ l2) l' -> + exists l1' l2', Forall2 l1 l1' /\ Forall2 l2 l2' /\ l' = l1' ++ l2'. + Proof. + induction l1; intros. + exists [], l'; auto. + simpl in H; inversion H; subst; clear H. + apply IHl1 in H4 as (l1' & l2' & Hl1 & Hl2 & ->). + exists (y::l1'), l2'; simpl; auto. + Qed. -Theorem Forall2_refl : forall A B (R:A->B->Prop), Forall2 R [] []. -Proof. exact Forall2_nil. Qed. + Theorem Forall2_app_inv_r : forall l1' l2' l, + Forall2 l (l1' ++ l2') -> + exists l1 l2, Forall2 l1 l1' /\ Forall2 l2 l2' /\ l = l1 ++ l2. + Proof. + induction l1'; intros. + exists [], l; auto. + simpl in H; inversion H; subst; clear H. + apply IHl1' in H4 as (l1 & l2 & Hl1 & Hl2 & ->). + exists (x::l1), l2; simpl; auto. + Qed. -Theorem Forall2_app_inv_l : forall A B (R:A->B->Prop) l1 l2 l', - Forall2 R (l1 ++ l2) l' -> - exists l1' l2', Forall2 R l1 l1' /\ Forall2 R l2 l2' /\ l' = l1' ++ l2'. -Proof. - induction l1; intros. - exists [], l'; auto. - simpl in H; inversion H; subst; clear H. - apply IHl1 in H4 as (l1' & l2' & Hl1 & Hl2 & ->). - exists (y::l1'), l2'; simpl; auto. -Qed. + Theorem Forall2_app : forall l1 l2 l1' l2', + Forall2 l1 l1' -> Forall2 l2 l2' -> Forall2 (l1 ++ l2) (l1' ++ l2'). + Proof. + intros. induction l1 in l1', H, H0 |- *; inversion H; subst; simpl; auto. + Qed. +End Forall2. -Theorem Forall2_app_inv_r : forall A B (R:A->B->Prop) l1' l2' l, - Forall2 R l (l1' ++ l2') -> - exists l1 l2, Forall2 R l1 l1' /\ Forall2 R l2 l2' /\ l = l1 ++ l2. -Proof. - induction l1'; intros. - exists [], l; auto. - simpl in H; inversion H; subst; clear H. - apply IHl1' in H4 as (l1 & l2 & Hl1 & Hl2 & ->). - exists (x::l1), l2; simpl; auto. -Qed. +Hint Constructors Forall2. -Theorem Forall2_app : forall A B (R:A->B->Prop) l1 l2 l1' l2', - Forall2 R l1 l1' -> Forall2 R l2 l2' -> Forall2 R (l1 ++ l2) (l1' ++ l2'). -Proof. - intros. induction l1 in l1', H, H0 |- *; inversion H; subst; simpl; auto. -Qed. +Section ForallPairs. -(** [ForallPairs] : specifies that a certain relation should + (** [ForallPairs] : specifies that a certain relation should always hold when inspecting all possible pairs of elements of a list. *) -Definition ForallPairs A (R : A -> A -> Prop) l := - forall a b, In a l -> In b l -> R a b. + Variable A : Type. + Variable R : A -> A -> Prop. -(** [ForallOrdPairs] : we still check a relation over all pairs + Definition ForallPairs l := + forall a b, In a l -> In b l -> R a b. + + (** [ForallOrdPairs] : we still check a relation over all pairs of elements of a list, but now the order of elements matters. *) -Inductive ForallOrdPairs A (R : A -> A -> Prop) : list A -> Prop := - | FOP_nil : ForallOrdPairs R nil - | FOP_cons : forall a l, - Forall (R a) l -> ForallOrdPairs R l -> ForallOrdPairs R (a::l). -Hint Constructors ForallOrdPairs. + Inductive ForallOrdPairs : list A -> Prop := + | FOP_nil : ForallOrdPairs nil + | FOP_cons : forall a l, + Forall (R a) l -> ForallOrdPairs l -> ForallOrdPairs (a::l). -Lemma ForallOrdPairs_In : forall A (R:A->A->Prop) l, - ForallOrdPairs R l -> - forall x y, In x l -> In y l -> x=y \/ R x y \/ R y x. -Proof. - induction 1. - inversion 1. - simpl; destruct 1; destruct 1; repeat subst; auto. - right; left. apply -> Forall_forall; eauto. - right; right. apply -> Forall_forall; eauto. -Qed. + Hint Constructors ForallOrdPairs. + Lemma ForallOrdPairs_In : forall l, + ForallOrdPairs l -> + forall x y, In x l -> In y l -> x=y \/ R x y \/ R y x. + Proof. + induction 1. + inversion 1. + simpl; destruct 1; destruct 1; repeat subst; auto. + right; left. apply -> Forall_forall; eauto. + right; right. apply -> Forall_forall; eauto. + Qed. -(** [ForallPairs] implies [ForallOrdPairs]. The reverse implication is true + (** [ForallPairs] implies [ForallOrdPairs]. The reverse implication is true only when [R] is symmetric and reflexive. *) -Lemma ForallPairs_ForallOrdPairs : forall A (R:A->A->Prop) l, - ForallPairs R l -> ForallOrdPairs R l. -Proof. - induction l; auto. intros H. - constructor. - apply <- Forall_forall. intros; apply H; simpl; auto. - apply IHl. red; intros; apply H; simpl; auto. -Qed. + Lemma ForallPairs_ForallOrdPairs l: ForallPairs l -> ForallOrdPairs l. + Proof. + induction l; auto. intros H. + constructor. + apply <- Forall_forall. intros; apply H; simpl; auto. + apply IHl. red; intros; apply H; simpl; auto. + Qed. -Lemma ForallOrdPairs_ForallPairs : forall A (R:A->A->Prop), - (forall x, R x x) -> - (forall x y, R x y -> R y x) -> - forall l, ForallOrdPairs R l -> ForallPairs R l. -Proof. - intros A R Refl Sym l Hl x y Hx Hy. - destruct (ForallOrdPairs_In Hl _ _ Hx Hy); subst; intuition. -Qed. + Lemma ForallOrdPairs_ForallPairs : + (forall x, R x x) -> + (forall x y, R x y -> R y x) -> + forall l, ForallOrdPairs l -> ForallPairs l. + Proof. + intros Refl Sym l Hl x y Hx Hy. + destruct (ForallOrdPairs_In Hl _ _ Hx Hy); subst; intuition. + Qed. +End ForallPairs. (** * Inversion of predicates over lists based on head symbol *) @@ -1767,3 +2287,28 @@ Notation AllS := Forall (only parsing). (* was formerly in TheoryList *) Hint Resolve app_nil_end : datatypes v62. (* end hide *) + +Section Repeat. + + Variable A : Type. + Fixpoint repeat (x : A) (n: nat ) := + match n with + | O => [] + | S k => x::(repeat x k) + end. + + Theorem repeat_length x n: + length (repeat x n) = n. + Proof. + induction n as [| k Hrec]; simpl; rewrite ?Hrec; reflexivity. + Qed. + + Theorem repeat_spec n x y: + In y (repeat x n) -> y=x. + Proof. + induction n as [|k Hrec]; simpl; destruct 1; auto. + Qed. + +End Repeat. + +(* Unset Universe Polymorphism. *) |