(************************************************************************) (* * The Coq Proof Assistant / The Coq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* list A -> Prop := | perm_nil: Permutation [] [] | perm_skip x l l' : Permutation l l' -> Permutation (x::l) (x::l') | perm_swap x y l : Permutation (y::x::l) (x::y::l) | perm_trans l l' l'' : Permutation l l' -> Permutation l' l'' -> Permutation l l''. Local Hint Constructors Permutation : core. (** Some facts about [Permutation] *) Theorem Permutation_nil : forall (l : list A), Permutation [] l -> l = []. Proof. intros l HF. remember (@nil A) as m in HF. induction HF; discriminate || auto. Qed. Theorem Permutation_nil_cons : forall (l : list A) (x : A), ~ Permutation nil (x::l). Proof. intros l x HF. apply Permutation_nil in HF; discriminate. Qed. (** Permutation over lists is a equivalence relation *) Theorem Permutation_refl : forall l : list A, Permutation l l. Proof. induction l; constructor. exact IHl. Qed. Instance Permutation_refl' : Proper (Logic.eq ==> Permutation) id. Proof. intros x y Heq; rewrite Heq; apply Permutation_refl. Qed. Theorem Permutation_sym : forall l l' : list A, Permutation l l' -> Permutation l' l. Proof. intros l l' Hperm; induction Hperm; auto. apply perm_trans with (l':=l'); assumption. Qed. Theorem Permutation_trans : forall l l' l'' : list A, Permutation l l' -> Permutation l' l'' -> Permutation l l''. Proof. exact perm_trans. Qed. End Permutation. #[global] Hint Resolve Permutation_refl perm_nil perm_skip : core. (* These hints do not reduce the size of the problem to solve and they must be used with care to avoid combinatoric explosions *) Local Hint Resolve perm_swap perm_trans : core. Local Hint Resolve Permutation_sym Permutation_trans : core. (* This provides reflexivity, symmetry and transitivity and rewriting on morphims to come *) Instance Permutation_Equivalence A : Equivalence (@Permutation A) | 10 := { Equivalence_Reflexive := @Permutation_refl A ; Equivalence_Symmetric := @Permutation_sym A ; Equivalence_Transitive := @Permutation_trans A }. Lemma Permutation_morph_transp A : forall P : list A -> Prop, (forall a b l1 l2, P (l1 ++ a :: b :: l2) -> P (l1 ++ b :: a :: l2)) -> Proper (@Permutation A ==> Basics.impl) P. Proof. intros P HT l1 l2 HP. enough (forall l0, P (l0 ++ l1) -> P (l0 ++ l2)) as IH by (intro; rewrite <- (app_nil_l l2); now apply (IH nil)). induction HP; intuition. rewrite <- (app_nil_l l'), app_comm_cons, app_assoc. now apply IHHP; rewrite <- app_assoc. Qed. Instance Permutation_cons A : Proper (Logic.eq ==> @Permutation A ==> @Permutation A) (@cons A) | 10. Proof. repeat intro; subst; auto using perm_skip. Qed. Section Permutation_properties. Variable A B:Type. Implicit Types a b : A. Implicit Types l m : list A. (** Compatibility with others operations on lists *) Theorem Permutation_in : forall (l l' : list A) (x : A), Permutation l l' -> In x l -> In x l'. Proof. intros l l' x Hperm; induction Hperm; simpl; tauto. Qed. Global Instance Permutation_in' : Proper (Logic.eq ==> @Permutation A ==> iff) (@In A) | 10. Proof. repeat red; intros; subst; eauto using Permutation_in. Qed. Lemma Permutation_app_tail : forall (l l' tl : list A), Permutation l l' -> Permutation (l++tl) (l'++tl). Proof. intros l l' tl Hperm; induction Hperm as [|x l l'|x y l|l l' l'']; simpl; auto. eapply Permutation_trans with (l':=l'++tl); trivial. Qed. Lemma Permutation_app_head : forall (l tl tl' : list A), Permutation tl tl' -> Permutation (l++tl) (l++tl'). Proof. intros l tl tl' Hperm; induction l; [trivial | repeat rewrite <- app_comm_cons; constructor; assumption]. Qed. Theorem Permutation_app : forall (l m l' m' : list A), Permutation l l' -> Permutation m m' -> Permutation (l++m) (l'++m'). Proof. intros l m l' m' Hpermll' Hpermmm'; induction Hpermll' as [|x l l'|x y l|l l' l'']; repeat rewrite <- app_comm_cons; auto. apply Permutation_trans with (l' := (x :: y :: l ++ m)); [idtac | repeat rewrite app_comm_cons; apply Permutation_app_head]; trivial. apply Permutation_trans with (l' := (l' ++ m')); try assumption. apply Permutation_app_tail; assumption. Qed. Global Instance Permutation_app' : Proper (@Permutation A ==> @Permutation A ==> @Permutation A) (@app A) | 10. Proof. repeat intro; now apply Permutation_app. Qed. Lemma Permutation_add_inside : forall a (l l' tl tl' : list A), Permutation l l' -> Permutation tl tl' -> Permutation (l ++ a :: tl) (l' ++ a :: tl'). Proof. intros; apply Permutation_app; auto. Qed. Lemma Permutation_cons_append : forall (l : list A) x, Permutation (x :: l) (l ++ x :: nil). Proof. induction l; intros; auto. simpl. rewrite <- IHl; auto. Qed. Local Hint Resolve Permutation_cons_append : core. Theorem Permutation_app_comm : forall (l l' : list A), Permutation (l ++ l') (l' ++ l). Proof. induction l as [|x l]; simpl; intro l'. rewrite app_nil_r; trivial. rewrite IHl. rewrite app_comm_cons, Permutation_cons_append. now rewrite <- app_assoc. Qed. Local Hint Resolve Permutation_app_comm : core. Lemma Permutation_app_rot : forall l1 l2 l3: list A, Permutation (l1 ++ l2 ++ l3) (l2 ++ l3 ++ l1). Proof. intros l1 l2 l3; now rewrite (app_assoc l2). Qed. Local Hint Resolve Permutation_app_rot : core. Lemma Permutation_app_swap_app : forall l1 l2 l3: list A, Permutation (l1 ++ l2 ++ l3) (l2 ++ l1 ++ l3). Proof. intros. rewrite 2 app_assoc. apply Permutation_app_tail, Permutation_app_comm. Qed. Local Hint Resolve Permutation_app_swap_app : core. Lemma Permutation_app_middle : forall l l1 l2 l3 l4, Permutation (l1 ++ l2) (l3 ++ l4) -> Permutation (l1 ++ l ++ l2) (l3 ++ l ++ l4). Proof. intros l l1 l2 l3 l4 HP. now rewrite Permutation_app_swap_app, HP, Permutation_app_swap_app. Qed. Theorem Permutation_cons_app : forall (l l1 l2:list A) a, Permutation l (l1 ++ l2) -> Permutation (a :: l) (l1 ++ a :: l2). Proof. intros l l1 l2 a H. rewrite H. rewrite app_comm_cons, Permutation_cons_append. now rewrite <- app_assoc. Qed. Local Hint Resolve Permutation_cons_app : core. Lemma Permutation_Add a l l' : Add a l l' -> Permutation (a::l) l'. Proof. induction 1; simpl; trivial. rewrite perm_swap. now apply perm_skip. Qed. Theorem Permutation_middle : forall (l1 l2:list A) a, Permutation (a :: l1 ++ l2) (l1 ++ a :: l2). Proof. auto. Qed. Local Hint Resolve Permutation_middle : core. Lemma Permutation_middle2 : forall l1 l2 l3 a b, Permutation (a :: b :: l1 ++ l2 ++ l3) (l1 ++ a :: l2 ++ b :: l3). Proof. intros l1 l2 l3 a b. apply Permutation_cons_app. rewrite 2 app_assoc. now apply Permutation_cons_app. Qed. Local Hint Resolve Permutation_middle2 : core. Lemma Permutation_elt : forall l1 l2 l1' l2' (a:A), Permutation (l1 ++ l2) (l1' ++ l2') -> Permutation (l1 ++ a :: l2) (l1' ++ a :: l2'). Proof. intros l1 l2 l1' l2' a HP. transitivity (a :: l1 ++ l2); auto. Qed. Theorem Permutation_rev : forall (l : list A), Permutation l (rev l). Proof. induction l as [| x l]; simpl; trivial. now rewrite IHl at 1. Qed. Global Instance Permutation_rev' : Proper (@Permutation A ==> @Permutation A) (@rev A) | 10. Proof. repeat intro; now rewrite <- 2 Permutation_rev. Qed. Theorem Permutation_length : forall (l l' : list A), Permutation l l' -> length l = length l'. Proof. intros l l' Hperm; induction Hperm; simpl; auto. now transitivity (length l'). Qed. Global Instance Permutation_length' : Proper (@Permutation A ==> Logic.eq) (@length A) | 10. Proof. exact Permutation_length. Qed. Global Instance Permutation_Forall (P : A -> Prop) : Proper ((@Permutation A) ==> Basics.impl) (Forall P) | 10. Proof. intros l1 l2 HP. induction HP; intro HF; auto. - inversion_clear HF; auto. - inversion_clear HF as [ | ? ? HF1 HF2]. inversion_clear HF2; auto. Qed. Global Instance Permutation_Exists (P : A -> Prop) : Proper ((@Permutation A) ==> Basics.impl) (Exists P) | 10. Proof. intros l1 l2 HP. induction HP; intro HF; auto. - inversion_clear HF; auto. - inversion_clear HF as [ | ? ? HF1 ]; auto. inversion_clear HF1; auto. Qed. Lemma Permutation_Forall2 (P : A -> B -> Prop) : forall l1 l1' (l2 : list B), Permutation l1 l1' -> Forall2 P l1 l2 -> exists l2' : list B, Permutation l2 l2' /\ Forall2 P l1' l2'. Proof. intros l1 l1' l2 HP. revert l2; induction HP; intros l2 HF; inversion HF as [ | ? b ? ? HF1 HF2 ]; subst. - now exists nil. - apply IHHP in HF2 as [l2' [HP2 HF2]]. exists (b :: l2'); auto. - inversion_clear HF2 as [ | ? b' ? l2' HF3 HF4 ]. exists (b' :: b :: l2'); auto. - apply Permutation_nil in HP1; subst. apply Permutation_nil in HP2; subst. now exists nil. - apply IHHP1 in HF as [l2' [HP2' HF2']]. apply IHHP2 in HF2' as [l2'' [HP2'' HF2'']]. exists l2''; split; auto. now transitivity l2'. Qed. Theorem Permutation_ind_bis : forall P : list A -> list A -> Prop, P [] [] -> (forall x l l', Permutation l l' -> P l l' -> P (x :: l) (x :: l')) -> (forall x y l l', Permutation l l' -> P l l' -> P (y :: x :: l) (x :: y :: l')) -> (forall l l' l'', Permutation l l' -> P l l' -> Permutation l' l'' -> P l' l'' -> P l l'') -> forall l l', Permutation l l' -> P l l'. Proof. intros P Hnil Hskip Hswap Htrans. induction 1; auto. apply Htrans with (x::y::l); auto. apply Hswap; auto. induction l; auto. apply Hskip; auto. apply Hskip; auto. induction l; auto. eauto. Qed. Theorem Permutation_nil_app_cons : forall (l l' : list A) (x : A), ~ Permutation nil (l++x::l'). Proof. intros l l' x HF. apply Permutation_nil in HF. destruct l; discriminate. Qed. Ltac InvAdd := repeat (match goal with | H: Add ?x _ (_ :: _) |- _ => inversion H; clear H; subst end). Ltac finish_basic_perms H := try constructor; try rewrite perm_swap; try constructor; trivial; (rewrite <- H; now apply Permutation_Add) || (rewrite H; symmetry; now apply Permutation_Add). Theorem Permutation_Add_inv a l1 l2 : Permutation l1 l2 -> forall l1' l2', Add a l1' l1 -> Add a l2' l2 -> Permutation l1' l2'. Proof. revert l1 l2. refine (Permutation_ind_bis _ _ _ _ _). - (* nil *) inversion_clear 1. - (* skip *) intros x l1 l2 PE IH. intros. InvAdd; try finish_basic_perms PE. constructor. now apply IH. - (* swap *) intros x y l1 l2 PE IH. intros. InvAdd; try finish_basic_perms PE. rewrite perm_swap; do 2 constructor. now apply IH. - (* trans *) intros l1 l l2 PE IH PE' IH' l1' l2' AD1 AD2. assert (Ha : In a l). { rewrite <- PE. rewrite (Add_in AD1). simpl; auto. } destruct (Add_inv _ _ Ha) as (l',AD). transitivity l'; auto. Qed. Theorem Permutation_app_inv (l1 l2 l3 l4:list A) a : Permutation (l1++a::l2) (l3++a::l4) -> Permutation (l1++l2) (l3 ++ l4). Proof. intros. eapply Permutation_Add_inv; eauto using Add_app. Qed. Theorem Permutation_cons_inv l l' a : Permutation (a::l) (a::l') -> Permutation l l'. Proof. intro. eapply Permutation_Add_inv; eauto using Add_head. Qed. Theorem Permutation_cons_app_inv l l1 l2 a : Permutation (a :: l) (l1 ++ a :: l2) -> Permutation l (l1 ++ l2). Proof. intro. eapply Permutation_Add_inv; eauto using Add_head, Add_app. Qed. Theorem Permutation_app_inv_l : forall l l1 l2, Permutation (l ++ l1) (l ++ l2) -> Permutation l1 l2. Proof. induction l; simpl; auto. intros. apply IHl. apply Permutation_cons_inv with a; auto. Qed. Theorem Permutation_app_inv_r l l1 l2 : Permutation (l1 ++ l) (l2 ++ l) -> Permutation l1 l2. Proof. rewrite 2 (Permutation_app_comm _ l). apply Permutation_app_inv_l. Qed. Lemma Permutation_app_inv_m l l1 l2 l3 l4 : Permutation (l1 ++ l ++ l2) (l3 ++ l ++ l4) -> Permutation (l1 ++ l2) (l3 ++ l4). Proof. intros HP. apply (Permutation_app_inv_l l). transitivity (l1 ++ l ++ l2); auto. transitivity (l3 ++ l ++ l4); auto. Qed. Lemma Permutation_length_1_inv: forall a l, Permutation [a] l -> l = [a]. Proof. intros a l H; remember [a] as m in H. induction H; try (injection Heqm as [= -> ->]); discriminate || auto. apply Permutation_nil in H as ->; trivial. Qed. Lemma Permutation_length_1: forall a b, Permutation [a] [b] -> a = b. Proof. intros a b H. apply Permutation_length_1_inv in H; injection H as [= ->]; trivial. Qed. Lemma Permutation_length_2_inv : forall a1 a2 l, Permutation [a1;a2] l -> l = [a1;a2] \/ l = [a2;a1]. Proof. intros a1 a2 l H; remember [a1;a2] as m in H. revert a1 a2 Heqm. induction H; intros; try (injection Heqm as [= ? ?]; subst); discriminate || (try tauto). apply Permutation_length_1_inv in H as ->; left; auto. apply IHPermutation1 in Heqm as [H1|H1]; apply IHPermutation2 in H1 as []; auto. Qed. Lemma Permutation_length_2 : forall a1 a2 b1 b2, Permutation [a1;a2] [b1;b2] -> a1 = b1 /\ a2 = b2 \/ a1 = b2 /\ a2 = b1. Proof. intros a1 b1 a2 b2 H. apply Permutation_length_2_inv in H as [H|H]; injection H as [= -> ->]; auto. Qed. Lemma Permutation_vs_elt_inv : forall l l1 l2 a, Permutation l (l1 ++ a :: l2) -> exists l' l'', l = l' ++ a :: l''. Proof. intros l l1 l2 a HP. symmetry in HP. apply (Permutation_in a), in_split in HP; trivial. apply in_elt. Qed. Lemma Permutation_vs_cons_inv : forall l l1 a, Permutation l (a :: l1) -> exists l' l'', l = l' ++ a :: l''. Proof. intros l l1 a HP. rewrite <- (app_nil_l (a :: l1)) in HP. apply (Permutation_vs_elt_inv _ _ _ HP). Qed. Lemma Permutation_vs_cons_cons_inv : forall l l' a b, Permutation l (a :: b :: l') -> exists l1 l2 l3, l = l1 ++ a :: l2 ++ b :: l3 \/ l = l1 ++ b :: l2 ++ a :: l3. Proof. intros l l' a b HP. destruct (Permutation_vs_cons_inv HP) as [l1 [l2]]; subst. symmetry in HP. apply Permutation_cons_app_inv in HP. apply (Permutation_in b), in_app_or in HP; [|now apply in_eq]. destruct HP as [(l3 & l4 & ->)%in_split | (l3 & l4 & ->)%in_split]. - exists l3, l4, l2; right. now rewrite <-app_assoc; simpl. - now exists l1, l3, l4; left. Qed. Lemma NoDup_Permutation l l' : NoDup l -> NoDup l' -> (forall x:A, In x l <-> In x l') -> Permutation l l'. Proof. intros N. revert l'. induction N as [|a l Hal Hl IH]. - destruct l'; simpl; auto. intros Hl' H. exfalso. rewrite (H a); auto. - intros l' Hl' H. assert (Ha : In a l') by (apply H; simpl; auto). destruct (Add_inv _ _ Ha) as (l'' & AD). rewrite <- (Permutation_Add AD). apply perm_skip. apply IH; clear IH. * now apply (NoDup_Add AD). * split. + apply incl_Add_inv with a l'; trivial. intro. apply H. + intro Hx. assert (Hx' : In x (a::l)). { apply H. rewrite (Add_in AD). now right. } destruct Hx'; simpl; trivial. subst. rewrite (NoDup_Add AD) in Hl'. tauto. Qed. Lemma NoDup_Permutation_bis l l' : NoDup l -> length l' <= length l -> incl l l' -> Permutation l l'. Proof. intros. apply NoDup_Permutation; auto. - now apply NoDup_incl_NoDup with l. - split; auto. apply NoDup_length_incl; trivial. Qed. Lemma Permutation_NoDup l l' : Permutation l l' -> NoDup l -> NoDup l'. Proof. induction 1; auto. - inversion_clear 1; constructor; eauto using Permutation_in. - inversion_clear 1 as [|? ? H1 H2]. inversion_clear H2; simpl in *. constructor. simpl; intuition. constructor; intuition. Qed. Global Instance Permutation_NoDup' : Proper (@Permutation A ==> iff) (@NoDup A) | 10. Proof. repeat red; eauto using Permutation_NoDup. Qed. Lemma Permutation_repeat x n l : Permutation l (repeat x n) -> l = repeat x n. Proof. revert n; induction l as [|y l IHl] ; simpl; intros n HP; auto. - now apply Permutation_nil in HP; inversion HP. - assert (y = x) as Heq by (now apply repeat_spec with n, (Permutation_in _ HP); left); subst. destruct n; simpl; simpl in HP. + symmetry in HP; apply Permutation_nil in HP; inversion HP. + f_equal; apply IHl. now apply Permutation_cons_inv with x. Qed. Hypothesis eq_dec : forall x y : A, {x = y}+{x <> y}. Lemma Permutation_count_occ l1 l2 : Permutation l1 l2 <-> forall x, count_occ eq_dec l1 x = count_occ eq_dec l2 x. Proof. split. - induction 1 as [ | y l1 l2 HP IHP | y z l | l1 l2 l3 HP1 IHP1 HP2 IHP2 ]; cbn; intros a; auto. + now rewrite IHP. + destruct (eq_dec y a); destruct (eq_dec z a); auto. + now rewrite IHP1, IHP2. - revert l2; induction l1 as [|y l1 IHl1]; cbn; intros l2 Hocc. + replace l2 with (@nil A); auto. symmetry; apply (count_occ_inv_nil eq_dec); intuition. + assert (exists l2' l2'', l2 = l2' ++ y :: l2'') as [l2' [l2'' ->]]. { specialize (Hocc y). destruct (eq_dec y y); intuition. apply in_split, (count_occ_In eq_dec). rewrite <- Hocc; apply Nat.lt_0_succ. } apply Permutation_cons_app, IHl1. intros z; specialize (Hocc z); destruct (eq_dec y z) as [Heq | Hneq]. * rewrite (count_occ_elt_eq _ _ _ Heq) in Hocc. now injection Hocc. * now rewrite (count_occ_elt_neq _ _ _ Hneq) in Hocc. Qed. End Permutation_properties. Section Permutation_map. Variable A B : Type. Variable f : A -> B. Lemma Permutation_map l l' : Permutation l l' -> Permutation (map f l) (map f l'). Proof. induction 1; simpl; eauto. Qed. Global Instance Permutation_map' : Proper (@Permutation A ==> @Permutation B) (map f) | 10. Proof. exact Permutation_map. Qed. Lemma Permutation_map_inv : forall l1 l2, Permutation l1 (map f l2) -> exists l3, l1 = map f l3 /\ Permutation l2 l3. Proof. induction l1; intros l2 HP. - exists nil; split; auto. apply Permutation_nil in HP. destruct l2; auto. inversion HP. - symmetry in HP. destruct (Permutation_vs_cons_inv HP) as [l3 [l4 Heq]]. destruct (map_eq_app _ _ _ _ Heq) as [l1' [l2' [Heq1 [Heq2 Heq3]]]]; subst. destruct (map_eq_cons _ _ Heq3) as [b [l1'' [Heq1' [Heq2' Heq3']]]]; subst. rewrite map_app in HP; simpl in HP. symmetry in HP. apply Permutation_cons_app_inv in HP. rewrite <- map_app in HP. destruct (IHl1 _ HP) as [l3 [Heq1'' Heq2'']]; subst. exists (b :: l3); split; auto. symmetry in Heq2''; symmetry; apply (Permutation_cons_app _ _ _ Heq2''). Qed. Lemma Permutation_image : forall a l l', Permutation (a :: l) (map f l') -> exists a', a = f a'. Proof. intros a l l' HP. destruct (Permutation_map_inv _ HP) as [l'' [Heq _]]. destruct l'' as [ | a' l'']; inversion_clear Heq. now exists a'. Qed. Lemma Permutation_elt_map_inv: forall l1 l2 l3 l4 a, Permutation (l1 ++ a :: l2) (l3 ++ map f l4) -> (forall b, a <> f b) -> exists l1' l2', l3 = l1' ++ a :: l2'. Proof. intros l1 l2 l3 l4 a HP Hf. apply (Permutation_in a), in_app_or in HP; [| now apply in_elt]. destruct HP as [HP%in_split | (x & Heq & ?)%in_map_iff]; trivial; subst. now contradiction (Hf x). Qed. Global Instance Permutation_flat_map (g : A -> list B) : Proper ((@Permutation A) ==> (@Permutation B)) (flat_map g) | 10. Proof. intros l1; induction l1; intros l2 HP. - now apply Permutation_nil in HP; subst. - symmetry in HP. destruct (Permutation_vs_cons_inv HP) as [l' [l'']]; subst. symmetry in HP. apply Permutation_cons_app_inv in HP. rewrite flat_map_app; simpl. rewrite <- (app_nil_l _). apply Permutation_app_middle; simpl. rewrite <- flat_map_app. apply (IHl1 _ HP). Qed. End Permutation_map. Lemma nat_bijection_Permutation n f : bFun n f -> Injective f -> let l := seq 0 n in Permutation (map f l) l. Proof. intros Hf BD. apply NoDup_Permutation_bis; auto using Injective_map_NoDup, seq_NoDup. * now rewrite map_length. * intros x. rewrite in_map_iff. intros (y & <- & Hy'). rewrite in_seq in *. simpl in *. destruct Hy' as (_,Hy'). auto with arith. Qed. Section Permutation_alt. Variable A:Type. Implicit Type a : A. Implicit Type l : list A. (** Alternative characterization of permutation via [nth_error] and [nth] *) Let adapt f n := let m := f (S n) in if le_lt_dec m (f 0) then m else pred m. Let adapt_injective f : Injective f -> Injective (adapt f). Proof. unfold adapt. intros Hf x y EQ. destruct le_lt_dec as [LE|LT]; destruct le_lt_dec as [LE'|LT']. - now apply eq_add_S, Hf. - apply Lt.le_lt_or_eq in LE. destruct LE as [LT|EQ']; [|now apply Hf in EQ']. unfold lt in LT. rewrite EQ in LT. rewrite <- (Lt.S_pred _ _ LT') in LT. elim (Lt.lt_not_le _ _ LT' LT). - apply Lt.le_lt_or_eq in LE'. destruct LE' as [LT'|EQ']; [|now apply Hf in EQ']. unfold lt in LT'. rewrite <- EQ in LT'. rewrite <- (Lt.S_pred _ _ LT) in LT'. elim (Lt.lt_not_le _ _ LT LT'). - apply eq_add_S, Hf. now rewrite (Lt.S_pred _ _ LT), (Lt.S_pred _ _ LT'), EQ. Qed. Let adapt_ok a l1 l2 f : Injective f -> length l1 = f 0 -> forall n, nth_error (l1++a::l2) (f (S n)) = nth_error (l1++l2) (adapt f n). Proof. unfold adapt. intros Hf E n. destruct le_lt_dec as [LE|LT]. - apply Lt.le_lt_or_eq in LE. destruct LE as [LT|EQ]; [|now apply Hf in EQ]. rewrite <- E in LT. rewrite 2 nth_error_app1; auto. - rewrite (Lt.S_pred _ _ LT) at 1. rewrite <- E, (Lt.S_pred _ _ LT) in LT. rewrite 2 nth_error_app2; auto with arith. rewrite <- Minus.minus_Sn_m; auto with arith. Qed. Lemma Permutation_nth_error l l' : Permutation l l' <-> (length l = length l' /\ exists f:nat->nat, Injective f /\ forall n, nth_error l' n = nth_error l (f n)). Proof. split. { intros P. split; [now apply Permutation_length|]. induction P. - exists (fun n => n). split; try red; auto. - destruct IHP as (f & Hf & Hf'). exists (fun n => match n with O => O | S n => S (f n) end). split; try red. * intros [|y] [|z]; simpl; now auto. * intros [|n]; simpl; auto. - exists (fun n => match n with 0 => 1 | 1 => 0 | n => n end). split; try red. * intros [|[|z]] [|[|t]]; simpl; now auto. * intros [|[|n]]; simpl; auto. - destruct IHP1 as (f & Hf & Hf'). destruct IHP2 as (g & Hg & Hg'). exists (fun n => f (g n)). split; try red. * auto. * intros n. rewrite <- Hf'; auto. } { revert l. induction l'. - intros [|l] (E & _); now auto. - intros l (E & f & Hf & Hf'). simpl in E. assert (Ha : nth_error l (f 0) = Some a) by (symmetry; apply (Hf' 0)). destruct (nth_error_split l (f 0) Ha) as (l1 & l2 & L12 & L1). rewrite L12. rewrite <- Permutation_middle. constructor. apply IHl'; split; [|exists (adapt f); split]. * revert E. rewrite L12, !app_length. simpl. rewrite <- plus_n_Sm. now injection 1. * now apply adapt_injective. * intro n. rewrite <- (adapt_ok a), <- L12; auto. apply (Hf' (S n)). } Qed. Lemma Permutation_nth_error_bis l l' : Permutation l l' <-> exists f:nat->nat, Injective f /\ bFun (length l) f /\ (forall n, nth_error l' n = nth_error l (f n)). Proof. rewrite Permutation_nth_error; split. - intros (E & f & Hf & Hf'). exists f. do 2 (split; trivial). intros n Hn. destruct (Lt.le_or_lt (length l) (f n)) as [LE|LT]; trivial. rewrite <- nth_error_None, <- Hf', nth_error_None, <- E in LE. elim (Lt.lt_not_le _ _ Hn LE). - intros (f & Hf & Hf2 & Hf3); split; [|exists f; auto]. assert (H : length l' <= length l') by auto with arith. rewrite <- nth_error_None, Hf3, nth_error_None in H. destruct (Lt.le_or_lt (length l) (length l')) as [LE|LT]; [|apply Hf2 in LT; elim (Lt.lt_not_le _ _ LT H)]. apply Lt.le_lt_or_eq in LE. destruct LE as [LT|EQ]; trivial. rewrite <- nth_error_Some, Hf3, nth_error_Some in LT. assert (Hf' : bInjective (length l) f). { intros x y _ _ E. now apply Hf. } rewrite (bInjective_bSurjective Hf2) in Hf'. destruct (Hf' _ LT) as (y & Hy & Hy'). apply Hf in Hy'. subst y. elim (Lt.lt_irrefl _ Hy). Qed. Lemma Permutation_nth l l' d : Permutation l l' <-> (let n := length l in length l' = n /\ exists f:nat->nat, bFun n f /\ bInjective n f /\ (forall x, x < n -> nth x l' d = nth (f x) l d)). Proof. split. - intros H. assert (E := Permutation_length H). split; auto. apply Permutation_nth_error_bis in H. destruct H as (f & Hf & Hf2 & Hf3). exists f. split; [|split]; auto. intros x y _ _ Hxy. now apply Hf. intros n Hn. rewrite <- 2 nth_default_eq. unfold nth_default. now rewrite Hf3. - intros (E & f & Hf1 & Hf2 & Hf3). rewrite Permutation_nth_error. split; auto. exists (fun n => if le_lt_dec (length l) n then n else f n). split. * intros x y. destruct le_lt_dec as [LE|LT]; destruct le_lt_dec as [LE'|LT']; auto. + apply Hf1 in LT'. intros ->. elim (Lt.lt_irrefl (f y)). eapply Lt.lt_le_trans; eauto. + apply Hf1 in LT. intros <-. elim (Lt.lt_irrefl (f x)). eapply Lt.lt_le_trans; eauto. * intros n. destruct le_lt_dec as [LE|LT]. + assert (LE' : length l' <= n) by (now rewrite E). rewrite <- nth_error_None in LE, LE'. congruence. + assert (LT' : n < length l') by (now rewrite E). specialize (Hf3 n LT). rewrite <- 2 nth_default_eq in Hf3. unfold nth_default in Hf3. apply Hf1 in LT. rewrite <- nth_error_Some in LT, LT'. do 2 destruct nth_error; congruence. Qed. End Permutation_alt. Instance Permutation_list_sum : Proper (@Permutation nat ==> eq) list_sum | 10. Proof. intros l1 l2 HP; induction HP; simpl; intuition. - rewrite 2 (Nat.add_comm x). apply Nat.add_assoc. - now transitivity (list_sum l'). Qed. Instance Permutation_list_max : Proper (@Permutation nat ==> eq) list_max | 10. Proof. intros l1 l2 HP; induction HP; simpl; intuition. - rewrite 2 (Nat.max_comm x). apply Nat.max_assoc. - now transitivity (list_max l'). Qed. Section Permutation_transp. Variable A:Type. (** Permutation definition based on transpositions for induction with fixed length *) Inductive Permutation_transp : list A -> list A -> Prop := | perm_t_refl : forall l, Permutation_transp l l | perm_t_swap : forall x y l1 l2, Permutation_transp (l1 ++ y :: x :: l2) (l1 ++ x :: y :: l2) | perm_t_trans l l' l'' : Permutation_transp l l' -> Permutation_transp l' l'' -> Permutation_transp l l''. Instance Permutation_transp_sym : Symmetric Permutation_transp. Proof. intros l1 l2 HP; induction HP; subst; try (now constructor). now apply (perm_t_trans IHHP2). Qed. Global Instance Permutation_transp_equiv : Equivalence Permutation_transp | 100. Proof. split. - intros l; apply perm_t_refl. - apply Permutation_transp_sym. - intros l1 l2 l3 ;apply perm_t_trans. Qed. Lemma Permutation_transp_cons : forall (x : A) l1 l2, Permutation_transp l1 l2 -> Permutation_transp (x :: l1) (x :: l2). Proof. intros x l1 l2 HP. induction HP. - reflexivity. - rewrite 2 app_comm_cons. apply perm_t_swap. - now transitivity (x :: l'). Qed. Lemma Permutation_Permutation_transp : forall l1 l2 : list A, Permutation l1 l2 <-> Permutation_transp l1 l2. Proof. intros l1 l2; split; intros HP; induction HP; intuition. - now apply Permutation_transp_cons. - rewrite <- (app_nil_l (y :: _)). rewrite <- (app_nil_l (x :: y :: _)). apply perm_t_swap. - now transitivity l'. - apply Permutation_app_head. apply perm_swap. - now transitivity l'. Qed. Lemma Permutation_ind_transp : forall P : list A -> list A -> Prop, (forall l, P l l) -> (forall x y l1 l2, P (l1 ++ y :: x :: l2) (l1 ++ x :: y :: l2)) -> (forall l l' l'', Permutation l l' -> P l l' -> Permutation l' l'' -> P l' l'' -> P l l'') -> forall l1 l2, Permutation l1 l2 -> P l1 l2. Proof. intros P Hr Ht Htr l1 l2 HP; apply Permutation_Permutation_transp in HP. revert Hr Ht Htr; induction HP; intros Hr Ht Htr; auto. apply (Htr _ l'); intuition; now apply Permutation_Permutation_transp. Qed. End Permutation_transp. (* begin hide *) Notation Permutation_app_swap := Permutation_app_comm (only parsing). (* end hide *)