Library seq_ext
Require Import Permutation.
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Require Import Init_ext ssrnat_ext.
Declare Scope seq_ext_scope.
Reserved Notation "l |{ a , n )" (at level 59, no associativity).
Set Implicit Arguments.
Unset Strict Implicit.
Lemma tac_not_In_cons {A: Type} l (a1 a2 : A) : ~ List.In a1 (a2 :: nil) -> ~ List.In a1 l ->
~ List.In a1 (a2 :: l).
Proof.
move=> Hhd Htl /= [H|//].
apply Hhd; rewrite H /=; by auto.
Qed.
Lemma tac_not_in_app {A : Type} (l1 l2 : seq A) l :
~ List.In l l1 -> ~ List.In l l2 -> ~ List.In l (l1 ++ l2).
Proof. move=> H1 H2 H. case: (List.in_app_or _ _ _ H); auto. Qed.
Lemma InP {A : Type} x : forall (l : seq A), List.In x l ->
exists l1 l2, l = l1 ++ x :: l2.
Proof.
elim=> // h t IH /= [ ->| /IH [l1 [l2 H]]]; first by exists nil, t.
by exists (h :: l1), l2; rewrite /= H.
Qed.
Lemma In_nth {A : Type} (s: seq A) a i : i < size s -> List.In (nth a s i) s.
Proof.
elim: s a i => // h t IH a /= [ _ |i] /=.
by left.
rewrite ltnS => ti.
by right; apply IH.
Qed.
Lemma incl_app_inv {A : Type} (l1 l2 : seq A) k :
List.incl (l1 ++ l2) k -> List.incl l1 k /\ List.incl l2 k.
Proof. move=> H; split => x Hx; apply H, List.in_or_app; auto. Qed.
Lemma incl_cons_inv_L {A : Type} a (l : seq A) k :
List.incl (a :: l) k -> List.In a k /\ List.incl l k.
Proof.
rewrite (_ : a :: l = (a :: nil) ++ l) //.
case/incl_app_inv.
by intuition.
Qed.
Fixpoint split_n {A : Type} (l : seq A) (n : nat) {struct n} : (seq A * seq A) :=
match n with
| O => (nil, l)
| S m => match l with
| nil => (nil, nil)
| hd :: tl =>
let: (one, two) := split_n tl m in
(hd :: one, two)
end
end.
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Require Import Init_ext ssrnat_ext.
Declare Scope seq_ext_scope.
Reserved Notation "l |{ a , n )" (at level 59, no associativity).
Set Implicit Arguments.
Unset Strict Implicit.
Lemma tac_not_In_cons {A: Type} l (a1 a2 : A) : ~ List.In a1 (a2 :: nil) -> ~ List.In a1 l ->
~ List.In a1 (a2 :: l).
Proof.
move=> Hhd Htl /= [H|//].
apply Hhd; rewrite H /=; by auto.
Qed.
Lemma tac_not_in_app {A : Type} (l1 l2 : seq A) l :
~ List.In l l1 -> ~ List.In l l2 -> ~ List.In l (l1 ++ l2).
Proof. move=> H1 H2 H. case: (List.in_app_or _ _ _ H); auto. Qed.
Lemma InP {A : Type} x : forall (l : seq A), List.In x l ->
exists l1 l2, l = l1 ++ x :: l2.
Proof.
elim=> // h t IH /= [ ->| /IH [l1 [l2 H]]]; first by exists nil, t.
by exists (h :: l1), l2; rewrite /= H.
Qed.
Lemma In_nth {A : Type} (s: seq A) a i : i < size s -> List.In (nth a s i) s.
Proof.
elim: s a i => // h t IH a /= [ _ |i] /=.
by left.
rewrite ltnS => ti.
by right; apply IH.
Qed.
Lemma incl_app_inv {A : Type} (l1 l2 : seq A) k :
List.incl (l1 ++ l2) k -> List.incl l1 k /\ List.incl l2 k.
Proof. move=> H; split => x Hx; apply H, List.in_or_app; auto. Qed.
Lemma incl_cons_inv_L {A : Type} a (l : seq A) k :
List.incl (a :: l) k -> List.In a k /\ List.incl l k.
Proof.
rewrite (_ : a :: l = (a :: nil) ++ l) //.
case/incl_app_inv.
by intuition.
Qed.
Fixpoint split_n {A : Type} (l : seq A) (n : nat) {struct n} : (seq A * seq A) :=
match n with
| O => (nil, l)
| S m => match l with
| nil => (nil, nil)
| hd :: tl =>
let: (one, two) := split_n tl m in
(hd :: one, two)
end
end.
compute an injection of from_list into to_list
Ltac find_indice i l :=
match l with
| nil => fail
| i :: _ => constr:(0)
| _ :: ?tl => let n := find_indice i tl in eval simpl in (n.+1)
end.
Ltac compute_list_injection to_list from_list :=
match from_list with
| @cons ?A ?hd ?tl =>
let hd' := find_indice hd to_list in
let tl' := compute_list_injection to_list tl in
constr : (List.cons hd' tl')
| @nil ?A => constr : (@nil nat)
end.
Goal True.
match goal with
| _ => let x := (compute_list_injection (O::2::3::4::5::nil)%nat (O::2::4::5::nil)%nat) in
idtac x
end.
Abort.
Ltac In_tac :=
match goal with
| |- List.In ?ELT (@cons _ ?ELT ?LT) => apply List.in_eq
| |- List.In ?ELT (@cons _ ?ELT' ?LT) => apply List.in_cons; In_tac
| |- List.In ?ELT nil => fail
end.
Ltac In_list v l :=
match l with
| @cons ?A v ?tl => constr:(true)
| @cons ?A ?hd ?tl => In_list v tl
| @nil ?A => constr:(false)
end.
Ltac incl_tac :=
match goal with
| |- List.incl (?HD :: ?TL) ?L =>
let tmp := In_list HD L in
match tmp with
| true => apply List.incl_cons ;
[ In_tac
|
incl_tac
]
| false => fail
end
| |- List.incl nil ?L =>
by rewrite /=
end.
remove an element according to a predicate on its index
Fixpoint remove_idx {A : Type} (l : seq A) (P : nat -> bool) (idx : nat) :=
match l with
| nil => nil
| hd :: tl =>
match P idx with
| true => remove_idx tl P (S idx)
| false => hd :: remove_idx tl P (S idx)
end
end.
Lemma mem_remove_idx (A : eqType) (h : A) : forall t P i, h \in remove_idx t P i -> h \in t.
Proof.
elim=> // h' t IH P i /=.
case: ifP => /= Pi.
move/IH => ht; by rewrite in_cons ht orbC.
rewrite in_cons; case/orP => [/eqP -> |].
by rewrite in_cons eqxx.
move/IH => ht; by rewrite in_cons ht orbC.
Qed.
Lemma uniq_remove_idx (A : eqType) : forall (l : seq A), uniq l -> forall p i, uniq (remove_idx l p i).
Proof.
elim=> // hd tl IH /=; case/andP; move/negP => Hhd Htl p i; case (p i) => /=.
- by apply IH.
- apply/andP; split; last by apply IH.
apply/negP; contradict Hhd.
by apply: mem_remove_idx Hhd.
Qed.
Ltac compute_positions1 l k idx :=
match l with
| @cons ?A k ?tl =>
let new_idx := constr : (S idx) in
let new_tl := compute_positions1 tl k new_idx in
constr: (@cons nat idx new_tl)
| @cons ?A ?hd ?tl =>
let new_idx := constr : (S idx) in
compute_positions1 tl k new_idx
| _ =>
constr : (@nil nat)
end.
Ltac remove_head_from_tail HD TL :=
let ISDUP := In_list HD TL in
match ISDUP with
| false => constr: (HD :: TL)
| true =>
let POSITIONS := compute_positions1 TL HD O in
let NEW_TL := eval compute in (remove_idx TL (fun x => (x \in POSITIONS)) O) in
let NEW_HDTL := eval compute in (seq.cat NEW_TL (HD :: nil)) in
constr : (NEW_HDTL)
end.
Ltac remove_duplicates LST :=
match LST with
| @cons ?A ?HD ?TL =>
let NEW_TL := remove_duplicates TL in
remove_head_from_tail HD NEW_TL
| @nil ?A => LST
end.
Inductive permutation {A : Type} : seq A -> seq A -> Prop :=
| permutation_nil: permutation nil nil
| permutation_skip x l l' : permutation l l' -> permutation (x::l) (x::l')
| permutation_swap x y l : permutation (y::x::l) (x::y::l)
| permutation_trans l l' l'' : permutation l l' -> permutation l' l'' -> permutation l l''.
Lemma permutation_reflexive {A} : forall (l : seq A), permutation l l.
Proof. elim => //=; try constructor => //=. Qed.
Lemma permutation_symmetric {A} (l l': seq A) : permutation l l' -> permutation l' l.
Proof.
elim => //=; try constructor => //=.
intros; by apply permutation_trans with l'0.
Qed.
Require Export Setoid Relation_Definitions.
Instance permutation_Equivalence A : Equivalence (@permutation A) | 10.
constructor.
exact permutation_reflexive.
exact permutation_symmetric.
exact permutation_trans.
Defined.
Ltac swap_with_head_rec i :=
match i with
| O => apply permutation_swap
| S _ => eapply permutation_trans; [
let n := eval simpl in (i.-1) in
apply permutation_skip;
swap_with_head_rec n | apply permutation_swap]
end.
Ltac swap_with_head i :=
match i with
| O => idtac
| S _ => eapply permutation_trans; [
let n := eval simpl in (i.-1) in
swap_with_head_rec n | idtac]
end.
Ltac setl P :=
match P with
| nil => idtac
| ?hd::?tl =>
let x := fresh in
(set x := hd); setl tl
end.
Ltac Solve_permutation :=
match goal with
| |- permutation ?l1 ?l2 =>
setl l1
end;
match goal with
| |- permutation nil nil => apply permutation_nil
| |- permutation ?l (?hd::_) =>
let A := type of hd in
let i := find_indice hd l in
swap_with_head i; apply permutation_skip; Solve_permutation
end.
Goal permutation [:: 1; 3; 2] [::2; 1; 3].
Solve_permutation.
Abort.
Section disjunction_Prop.
Variable A : Type.
Implicit Type l : seq A.
Definition disj l1 l2 := forall x,
(List.In x l1 -> ~ (List.In x l2)) /\ (List.In x l2 -> ~ (List.In x l1)).
Lemma disj_nil_R l : disj l nil. Proof. move=> x /=; tauto. Qed.
Lemma disj_nil_L l : disj nil l. Proof. move=> x /=; tauto. Qed.
Lemma disj_singl a b : a <> b -> disj (a :: nil) (b :: nil).
Proof.
move=> ab x; split; case => //= ?; subst x; contradict ab; firstorder.
Qed.
Lemma disj_sym h1 h2 : disj h1 h2 -> disj h2 h1.
Proof. rewrite /disj => H x; move: (H x); tauto. Qed.
Lemma disj_not_In L x K : disj K L -> List.In x L -> ~ List.In x K.
Proof. move=> Hinter HIn X; move: (Hinter x); tauto. Qed.
Lemma disj_cons_R x L K : disj K L -> ~ List.In x K -> disj K (x :: L).
Proof.
move=> l1_l2 x_l2; rewrite /disj => z; split => /= [z_l2|].
- contradict x_l2; case: x_l2 => [?|z_l1]; [by subst x | move: (l1_l2 z); tauto].
- case => [?|z_l1]; [by subst z | move: (l1_l2 z); tauto].
Qed.
Lemma disj_cons_L x L K : disj K L -> ~ List.In x L -> disj (x :: K) L.
Proof.
move=> l1_l2 x_l2; rewrite /disj => z; split => /= [|z_l2].
- case => [?|z_l1]; [by subst z | move: (l1_l2 z); tauto].
- contradict x_l2; case: x_l2 => [?|z_l1]; [by subst x | move: (l1_l2 z); tauto].
Qed.
Lemma disj_in_cons_R x L K : disj K L -> List.In x L -> disj K (x :: L).
Proof.
move=> l1_l2 x_l1; rewrite /disj => z; split => [z_l2|] /=.
- move: (proj1 (l1_l2 z) z_l2) => H1; contradict H1.
case: H1; by [move=> ?; subst z | ].
- case.
+ move=> ?; subst z=> ?; move: (l1_l2 x); tauto.
+ move=> z_l1 ?; move: (l1_l2 z); tauto.
Qed.
Lemma disj_cons_inv h1 t1 l2 : disj (h1 :: t1) l2 -> disj t1 l2 /\ ~ List.In h1 l2.
Proof.
move=> H; split => [x | h1_l2].
- rewrite /disj; split=> x_t1 abs; move: (H x) => /=; by firstorder.
- move: (H h1) => /=; by firstorder.
Qed.
Lemma disj_app_inv l k m : disj (l ++ k) m -> disj l m /\ disj k m.
Proof.
move=> H; split=> x; split=> Hx abs; case: (H x) => _.
move/(_ abs). apply. apply List.in_or_app; tauto.
move/(_ Hx). apply. apply List.in_or_app; tauto.
move/(_ abs). apply. apply List.in_or_app; tauto.
move/(_ Hx). apply. apply List.in_or_app; tauto.
Qed.
Lemma disj_app : forall (l k m : seq A), disj l m /\ disj k m -> disj (l ++ k) m.
Proof.
elim => [k m [] // | h t IH k m [H1 H2] /=].
apply disj_cons_L; last first.
move=> X.
apply (proj1 (H1 h)); last by [].
rewrite /=; by auto.
apply IH.
by case/disj_cons_inv : H1.
Qed.
Lemma tac_disj_incl_L l k : disj l k -> forall l', List.incl l' l -> disj l' k.
Proof.
move=> H l' H' x; split=> //=.
- move/H' => Hx abs; move: (H x); tauto.
- move => abs; move/H' => Hx; move: (H x); tauto.
Qed.
Lemma tac_disj_incl_R l k : disj l k -> forall k', List.incl k' k -> disj l k'.
Proof.
move=> H l' H' x; split=> //=.
- move => abs; move/H' => Hx; move: (H x); tauto.
- move/H' => Hx abs; move: (H x); tauto.
Qed.
Lemma disj_incl_LR k' l' k l : disj k' l' -> List.incl k k' -> List.incl l l' -> disj k l.
Proof.
move=> Hinter Hinclk Hincll x; split => // Hx abs.
- apply Hinclk in Hx; apply Hincll in abs; move: (Hinter x); tauto.
- apply Hinclk in abs; apply Hincll in Hx; move: (Hinter x); tauto.
Qed.
End disjunction_Prop.
Ltac disj_remove_duplicates_R :=
match goal with
| |- disj ?L (?HD :: ?TL) =>
let tmp := remove_duplicates (HD :: TL) in
apply (@tac_disj_incl_R _ L tmp)
end.
Ltac disj_remove_duplicates_L :=
match goal with
| |- disj (?HD :: ?TL) _ =>
let tmp := remove_duplicates (HD :: TL) in
apply (@tac_disj_incl_L _ tmp)
end.
Ltac Disj_remove_dup :=
match goal with
| |- disj (_ :: _) (_ :: _) =>
( disj_remove_duplicates_L; last by rewrite /List.incl /=; intuition ) ;
( disj_remove_duplicates_R; last by rewrite /List.incl /=; intuition )
| |- disj (?HD :: ?TL) _ =>
disj_remove_duplicates_L; last by rewrite /List.incl /=; intuition
| |- disj _ (?HD :: ?TL) =>
disj_remove_duplicates_R; last by rewrite /List.incl /=; intuition
end.
Section fold.
Lemma foldl_map {A B C} (f : B -> A -> B) (f' : C -> A) : forall l acc,
foldl f acc (map f' l) = foldl (fun acc hd => f acc (f' hd)) acc l.
Proof. by elim => //=. Qed.
Lemma foldr_map {A B C : Type} (f : A -> B -> B) (f' : C -> A) : forall l a,
foldr f a (map f' l) = foldr (fun h a => f (f' h) a) a l.
Proof. elim=> //= h t IH Hyp; by congr (f _ _). Qed.
Lemma foldl_congr_f {A B} (f f': B -> A -> B) (Hf: forall x y, f x y = f' x y):
forall l acc, foldl f acc l = foldl f' acc l.
Proof. elim => //= hd tl Hind acc; by rewrite Hind Hf. Qed.
Lemma foldl_ext {A : Type} {B : eqType} : forall k a (f f' : A -> B -> A),
(forall x a, x \in k -> f a x = f' a x) ->
foldl f a k = foldl f' a k.
Proof.
elim => // h t IH a f f' H /=.
rewrite H; last by apply mem_head.
apply IH => x a' Hx; apply H.
by rewrite in_cons Hx orbC.
Qed.
Section foldl_monotonic.
Variable (A : Type) (f : nat -> A -> nat).
Lemma foldl_leq_monotonic : (forall a x, a <= f a x) ->
forall l a, a <= foldl f a l.
Proof. move=> Hf; elim => //= h t IH a; by apply (@leq_trans (f a h)). Qed.
Lemma foldl_ltn_monotonic : (forall a x, a < f a x) ->
forall l a, l <> nil -> a < foldl f a l.
Proof.
move=> Hf; elim => //= h t IH a _.
apply (@ltn_leq_trans (f a h)) => //=.
apply foldl_leq_monotonic => //= a' x.
by rewrite ltnW.
Qed.
Lemma foldl_lt f' (Hf : forall x1 x2 y, x1 < x2 -> f x1 y < f' x2 y):
forall l a1 a2, a1 < a2 -> foldl f a1 l < foldl f' a2 l.
Proof. elim=> //= h t IH a1 a2 a12; by apply IH, Hf. Qed.
Lemma foldl_le f' (Hf : forall x1 x2 y, x1 <= x2 -> f x1 y <= f' x2 y) :
forall l a1 a2, a1 <= a2 -> foldl f a1 l <= foldl f' a2 l.
Proof. elim => //= h t IH a1 a2 a12; by apply IH, Hf. Qed.
End foldl_monotonic.
Section fold_maxn.
Lemma acc_foldl_maxn : forall l a, a <= foldl maxn a l.
Proof.
elim => //= h t IH a.
rewrite {2}/maxn.
case: leqP => //= ah.
by rewrite (@leq_trans h) // ltnW.
Qed.
Lemma in_foldl_maxn : forall l x a, x \in l -> x <= foldl maxn a l.
Proof.
elim => //= h t IH x a.
rewrite in_cons; case/orP => [/eqP -> | xt ]; last by apply IH.
rewrite (@leq_trans (maxn a h)) //; last by rewrite acc_foldl_maxn.
by rewrite leq_max orbC leqnn.
Qed.
Lemma foldr_Prop_and {A: eqType} P: forall (l: seq A),
foldr (fun hd acc => acc /\ P hd) True l ->
forall x, x \in l -> P x.
Proof.
elim => //=.
move => hd tl Hind Hyp.
move => x; rewrite in_cons.
move/orP => [] Hx.
- move/eqP: Hx ->.
tauto.
- apply Hind; tauto.
Qed.
End fold_maxn.
End fold.
Section seq_Type.
Lemma take_drop {A}: forall (l: seq A) i j, take j (drop i l) = drop i (take (i + j) l).
Proof.
elim => //=.
move => hd tl Hind i j.
destruct i => //=.
destruct j => //=.
Qed.
Lemma take_take {A}: forall (l: seq A) i j, take i (take (i + j) l) = take i l.
Proof.
elim => //=.
move => hd tl Hind i j.
destruct i => //=; first by rewrite take0.
by rewrite Hind.
Qed.
Lemma all_impl_bool {A: Type} (b1 b2: A -> bool) (Hb1b2: forall x, b1 x ==> b2 x): forall l,
all b1 l ==> all b2 l.
Proof.
elim => //=.
move => hd tl Hind.
move: (Hb1b2 hd); apply/implyP.
move: (Hind); apply/implyP.
case: (all b1 tl); case: (b1 hd); case: (all b2 tl); case: (b2 hd) => //=.
Qed.
Lemma all_impl_prop {A: Type} (b1 b2: A -> bool) (Hb1b2: forall x, b1 x ==> b2 x): forall l,
all b1 l -> all b2 l.
by move => l; apply/implyP; apply all_impl_bool.
Qed.
Lemma in_nseq {A : eqType} : forall n (a x : A), x \in nseq n a -> x = a.
Proof. elim=> // n IH a x /=; rewrite in_cons; case/orP; by [move/eqP | apply IH]. Qed.
Lemma drop_nseq {A : Type} : forall b a (c : A), a <= b ->
drop a (nseq b c) = nseq (b - a) c.
Proof.
elim => [ [] // | b IH [| a]].
move=> c _; by rewrite drop0 subn0.
move=> c ab /=; by rewrite subSS IH.
Qed.
Lemma nseqS {A : Type} n (a : A) : nseq (S n) a = nseq n a ++ [:: a].
Proof. by elim: n => // n /= <-. Qed.
Section rcons_ext.
Variable A : Type.
Lemma cons_rcons : forall (tl: seq A) hd, cons hd tl = rcons (belast hd tl) (last hd tl).
Proof. by elim => //= hd tl Hind hd'; rewrite Hind. Qed.
Lemma rcons_cons_head : forall (tl: seq A) hd, rcons tl hd = cons (head hd tl) (behead (rcons tl hd)).
Proof. by elim => //= hd tl Hind hd'; rewrite Hind. Qed.
Lemma rcons_app : forall (tl: seq A) hd, rcons tl hd = tl ++ hd::nil.
Proof. by elim => //=; move => hd tl Hind hd'; rewrite Hind. Qed.
Lemma case_eq_rcons : forall (P: seq A -> Prop),
(P nil) ->
(forall hd tl, P (rcons hd tl)) ->
forall l, P l.
Proof.
move=> P HPnil HPrcons.
case => //= hd tl.
rewrite cons_rcons.
apply HPrcons.
Qed.
End rcons_ext.
Lemma nth_decomp {A} {a} : forall (l : seq A) i, (size l > i) ->
l = take i l ++ nth a l i :: drop i.+1 l.
Proof.
elim => //= hd tl Hind i Hi.
destruct i => //=; first by rewrite drop0.
by rewrite {1}(Hind i).
Qed.
Lemma take_lt {A} : forall sz' (l1 l2: seq A) sz,
take sz l1 = take sz l2 -> sz' < sz -> take sz' l1 = take sz' l2.
Proof.
elim.
- intros; by rewrite !take0.
- intros.
destruct l1; destruct l2.
+ by [].
+ by destruct sz.
+ by destruct sz.
+ destruct sz => //.
simpl in H0; simpl.
injection H0 => ? ->.
f_equal.
by apply H with sz.
Qed.
Lemma dropS {A} : forall (l : seq A) i, drop (S i) l = drop 1 (drop i l).
Proof. by move=> l i; rewrite drop_drop. Qed.
Lemma dropS' {A} : forall (l : seq A) i, drop (S i) l = drop i (drop 1 l).
Proof. by move=> l a; rewrite drop_drop addn1. Qed.
Lemma drop_dropC {A} : forall i j (l : seq A), drop i (drop j l) = drop j (drop i l).
Proof. by move=> i j l; rewrite drop_drop addnC -drop_drop. Qed.
End seq_Type.
Section cat_ext.
Variable A : Type.
Lemma app_split : forall (l : seq A) k, k <= size l ->
exists l1, exists l2, size l1 = k /\ l = l1 ++ l2.
Proof.
elim.
- move=> [|k]; last by inversion 1.
by exists nil; exists nil.
- move=> hd tl IH [_ | k].
by exists nil, (hd :: tl).
rewrite ltnS => H.
case: {IH}(IH _ H) => l1 [l2 [H1 H2]].
exists (hd :: l1); exists l2; split => /=; by rewrite ?H1 ?H2.
Qed.
Lemma app_app_split_R : forall (l1 l2 k1 k2 : seq A),
l1 ++ l2 = k1 ++ k2 -> size l1 <= size k1 -> exists k1', k1 = l1 ++ k1' /\ l2 = k1' ++ k2.
Proof.
elim.
- move=> l2 k1 k2 H H'; by exists k1.
- move=> a l IH l2 [|h1 t1] //= k2 H H'.
case: H => X H; subst h1.
case: {IH}(IH _ _ _ H H') => k1' [H1 H2].
exists k1'; split => //.
by rewrite H1.
Qed.
Lemma cat_inv : forall (l1 l2 k1 k2 : seq A),
l1 ++ l2 = k1 ++ k2 -> size l1 = size k1 ->
l1 = k1 /\ l2 = k2.
Proof.
move=> l1 l2 k1 k2 H Hlen.
apply app_app_split_R in H; last by rewrite Hlen.
case: H => k1' [Hk1 Hl2]; subst k1 l2.
destruct k1'; first by rewrite cats0.
rewrite size_cat /= in Hlen.
exfalso.
rewrite -plusE in Hlen.
ssromega.
Qed.
End cat_ext.
Section seq_eqType.
Variable A : eqType.
Lemma mem_tail : forall tl hd (x: A), x \in tl -> x \in hd :: tl.
Proof.
elim => //= hd tl Hind hd' x Hin.
by rewrite in_cons Hin orbC.
Qed.
Lemma inP : forall l (x : A), reflect (List.In x l) (x \in l).
Proof.
elim => [x /= | h t IH x].
- rewrite in_nil; by apply ReflectF.
- rewrite /= in_cons; apply: (iffP idP).
+ case/orP => [ /eqP -> | /IH ?]; by auto.
+ case => [-> | /IH ->].
* by rewrite eqxx.
* by rewrite orbC.
Qed.
Lemma filter_mem_cons : forall k (n : A), uniq k -> n \in k ->
filter (mem (cons n [::])) k = cons n [::].
Proof.
elim=> // hd tl IH n /=.
case/andP => Hk1 Hk2.
rewrite in_cons; case/orP.
- move/eqP => X; subst hd.
rewrite /= in_cons eqxx /=.
f_equal.
eapply trans_eq; last by apply filter_pred0.
apply eq_in_filter => x Hx.
rewrite /= in_cons in_nil orbC /=.
apply/eqP => X; subst x.
by rewrite Hx in Hk1.
- move=> Hn.
rewrite /= in_cons in_nil orbC /=.
have X : hd != n.
apply/eqP => X; subst n.
by rewrite Hn in Hk1.
rewrite (negbTE X).
by apply IH.
Qed.
Lemma subset_nil {l : seq A} : {subset nil <= l}. Proof. done. Qed.
Lemma subset_cat (l : seq A) l2 (Hl2 : {subset l2 <= l}):
forall l1, {subset l1 <= l} -> {subset (l1 ++ l2) <= l}.
Proof.
elim => //=.
move => hd tl Hind Hsubset.
move => x Hx.
rewrite in_cons in Hx; move/orP in Hx; inversion_clear Hx.
- apply Hsubset.
rewrite in_cons; apply/orP; left; done.
- apply Hind => //=.
move => y Hy; apply Hsubset.
rewrite in_cons; apply/orP; right; done.
Qed.
Lemma subset_undup : forall (l : seq A), {subset (undup l) <= l}.
Proof.
elim => //=.
move => hd tl Hind.
case: (hd \in tl); intuition.
by move => x Hx; rewrite in_cons; apply/orP; right; apply Hind.
move => x Hx; rewrite in_cons in Hx; move/orP in Hx; rewrite in_cons; apply/orP; inversion_clear Hx; try auto.
Qed.
Lemma notin_unzip1_notin {B : eqType} (x : A) (y : B): forall l,
x \notin unzip1 l -> (x, y) \notin l.
Proof.
move=> l.
apply contra => H.
apply/mapP.
by exists (x, y).
Qed.
Lemma uniq_in_eq {B:eqType} {x} {y1} {y2}: forall (l: seq (A * B)),
uniq (unzip1 l) -> (x, y1) \in l -> (x, y2) \in l -> y1 = y2.
Proof.
elim => //=.
move => [] hd1 hd2 //= tl Hind /andP [] Hnotin Huniq; rewrite !in_cons => /orP Hin1 /orP Hin2.
inversion_clear Hin1; inversion_clear Hin2.
- by move/eqP in H; move/eqP in H0; case: H; case: H0 => *; subst.
- move/eqP in H; case: H => *; subst.
have Hin: hd1 \in unzip1 tl.
+ apply/mapP; exists (hd1, y2); done.
rewrite Hin in Hnotin; done.
- move/eqP in H0; case: H0 => *; subst.
have Hin: hd1 \in unzip1 tl.
+ apply/mapP; exists (hd1, y1); done.
rewrite Hin in Hnotin; done.
- intuition.
Qed.
Lemma uniq_subset_notin {B: eqType} {x} {y} {l: seq (A * B)} (Hl: uniq (unzip1 l)):
forall l',
{subset l' <= l} ->
(x, y) \notin l' ->
(x, y) \in l ->
x \notin unzip1 l'.
Proof.
elim => //=.
move => [] hd1 hd2 //= tl Hind Hsubset Hnotin Hin.
have: (hd1, hd2) \in l /\ {subset tl <= l} by split; [ apply Hsubset; rewrite in_cons; apply/orP; left; done | move => z Hz; apply Hsubset; rewrite in_cons; apply/orP; right; done].
clear Hsubset.
move => [] H Hsubset.
apply/negP => Hin2.
have: (x, y) != (hd1, hd2) /\ (x, y) \notin tl.
- rewrite in_cons negb_or in Hnotin.
move/andP in Hnotin; done.
clear Hnotin; move => [] Hneq Hnotin.
rewrite in_cons in Hin2; move/orP in Hin2; inversion_clear Hin2; last first.
move: (Hind Hsubset Hnotin Hin).
rewrite H0; done.
clear Hind.
move/eqP in H0; subst.
have: y <> hd2.
- move => Heq; rewrite Heq in Hneq; move/eqP in Hneq; tauto.
clear Hneq; move => Hneq.
move: (uniq_in_eq Hl H Hin) => Heq.
by subst.
Qed.
Lemma undup_subset (l: seq A): forall l', {subset l' <= l} -> {subset (undup l') <= l}.
Proof.
elim => //=.
move => hd tl Hind Hsubset.
have Hsubset_tl: {subset tl <= l} by move => x Hx; apply Hsubset; apply/orP; right.
case: (hd \in tl); intuition.
move => x Hx; apply Hsubset.
rewrite in_cons in Hx; move/orP in Hx.
rewrite in_cons; apply/orP.
inversion_clear Hx; try tauto.
right; apply subset_undup; done.
Qed.
Lemma nseq_count :
forall n (a e: A), count (pred1 a) (nseq n e) = n * (a == e).
Proof.
elim; [done | ]; move => n IH a e; simpl.
rewrite mulSn -IH; f_equal.
case_eq (a == e).
- move/idP/eqP; move => ->; f_equal; apply/eqP; reflexivity.
- move/idP => H; f_equal; apply: negbTE; apply/eqP; move => E; subst.
apply: H; apply/eqP; reflexivity.
Qed.
Lemma uniq_belast : forall (l : seq A) e,
uniq (e :: l) -> uniq (belast e l).
Proof.
elim/last_ind => // hd tl _ e.
rewrite belast_rcons /= rcons_uniq mem_rcons in_cons negb_or andbA.
repeat case/andP.
by move=> _ -> _ ->.
Qed.
Lemma memP : forall l (e : A), e \in l ->
exists l1 l2, l = l1 ++ e :: l2 /\ ~ e \in l1.
Proof.
elim => //= hd tl Hind e; rewrite in_cons => Hin.
case/boolP : (e == hd) => [/eqP Heq|/negbTE Hneq].
- subst hd; by exists nil, tl.
- move/orP: Hin => [|Hin]; first by rewrite Hneq.
move: {Hind}(Hind e Hin) => [] l1 [] l2 [] H1 H2.
exists (hd :: l1), l2 => //=; rewrite H1; split => //.
contradict H2.
move: H2; rewrite in_cons => /orP[|//]; by rewrite Hneq.
Qed.
End seq_eqType.
Section flatten_ext.
Variables A B : eqType.
Lemma in_flatten : forall {f: A -> seq B} {x} {y},
y \in f x ->
forall l,
x \in l ->
y \in flatten (map f l).
Proof.
move => f x y Hy.
elim => //=.
move => hd tl Hind.
rewrite inE; move/orP => [] //=.
- by move/eqP => <-; rewrite mem_cat; apply/orP; left.
- move => Hx; rewrite mem_cat; apply/orP; right; apply (Hind Hx).
Qed.
Lemma flatten_in : forall {f: A -> seq B} {x} {l},
x \in flatten (map f l) ->
exists y, x \in f y /\ y \in l.
Proof.
move => f x.
elim => //=.
move => hd tl Hind.
rewrite mem_cat; move/orP => [] //=.
- by move => Hx; exists hd; rewrite inE eq_refl.
- move => Hx; move: {Hind}(Hind Hx) => [] y [] Hy1 Hy2.
exists y; rewrite inE.
split => //=.
by apply/orP; right.
Qed.
Lemma flatten_map: forall {f: A -> B} {l},
flatten (map (map f) l) = map f (flatten l).
Proof.
move => f.
elim => //=.
by move => hd tl; rewrite map_cat => ->.
Qed.
End flatten_ext.
Section inclusion_bool.
Variable A : eqType.
Fixpoint inc (l1 l2 : seq A) :=
if l1 isn't h1 :: t1 then true else if h1 \in l2 then inc t1 l2 else false.
Lemma incP' : forall (l1 l2 : seq A), reflect {subset l1 <= l2} (inc l1 l2).
Proof.
elim => //=.
- by move => l2; apply ReflectT.
- move => hd tl Hind l2.
case: (@idP (hd \in l2)) => Hin.
case: (Hind l2).
+ move => Hsubset; apply ReflectT.
move => x //=; rewrite inE; move /orP => [] //=.
* by move => /eqP ->.
* by move => H; apply Hsubset.
+ move => H.
apply ReflectF.
move => H'; apply H.
move => x Hx.
apply H'.
by rewrite inE; apply /orP; right.
apply ReflectF.
move => Hsubset.
apply Hin.
apply Hsubset.
by rewrite inE; apply /orP; left.
Qed.
Lemma incP (l1 l2 : seq A) : reflect (List.incl l1 l2) (inc l1 l2).
Proof.
apply: (iffP idP).
- move: l1 l2; elim.
+ move=> l2 /= _ x; by inversion 1.
+ move=> h1 t1 IH /= l2.
case: ifP => X //.
move/IH => H x /=.
case=> [h1_x|].
subst x.
by apply/inP.
by apply H.
- move: l1 l2.
elim => // h1 t1 IH l2 /= H.
case: ifP => X.
apply IH => x Hx.
apply H.
rewrite /=; by right.
move: (H h1 (@or_introl _ _ (refl_equal _))).
move/inP.
by rewrite X.
Qed.
Lemma inc_nil_inv : forall (d : seq A), inc d [::] -> d = [::].
Proof. by case. Qed.
Lemma inc_cons_R : forall (h : A) a b, inc a b -> inc a (h :: b).
Proof.
move=> c; elim=> // h t IH b /=.
case: ifP => // h_in_b t_inc_b.
by rewrite in_cons h_in_b orbC /= IH.
Qed.
Lemma inc_refl : forall (k : seq A), inc k k.
Proof. elim=> // h t IH /=; by rewrite in_cons eqxx /= inc_cons_R. Qed.
Lemma inc_app_L : forall (l k : seq A), inc l (l ++ k).
Proof. by elim=> // h t IH k /=; rewrite in_cons eqxx /= inc_cons_R. Qed.
Lemma inc_app_R : forall (l k : seq A), inc l (k ++ l).
Proof. move=> l k. apply/incP' => x Hx; by rewrite mem_cat Hx orbC. Qed.
Lemma inc_trans : forall (l1 : seq A) l2 l3, inc l1 l2 -> inc l2 l3 -> inc l1 l3.
Proof.
elim=> // h t IH l2 l3 /=.
case: ifP => // h_l2 t_l2 l2_l3.
case: ifP.
- move=> h_l3; by apply IH with l2.
- move=> <-.
move/incP' : l2_l3 => l2_l3; exact/l2_l3.
Qed.
Lemma inc_cons_L : forall (x : A) l1 l2, inc (x :: l1) l2 = inc l1 l2 && (x \in l2).
Proof.
move=> x l1 l2; apply/idP/idP => /=.
- by case: ifP => // x_l2 ->.
- by case/andP => /= -> x_l2; case: ifP => // <-.
Qed.
Lemma inc_cons_R_inv : forall l1 (a : A) l2, a \notin l1 -> inc l1 (a :: l2) -> inc l1 l2.
Proof.
elim.
- by move=> a l1 _ _.
- move=> hd tl IH a l2.
rewrite in_cons negb_or; case/andP => H1 H2.
rewrite inc_cons_L.
case/andP => H.
rewrite in_cons.
case/orP => H'.
+ by rewrite eq_sym H' in H1.
+ by rewrite inc_cons_L (IH a).
Qed.
Lemma inc_cons_inv : forall (h : A) t1 t2,
h \notin t1 -> h \notin t2 -> inc (h :: t1) (h :: t2) -> inc t1 t2.
Proof.
move=> k t1 t2 Ht1 Ht2.
rewrite /= in_cons eqxx /=.
by apply inc_cons_R_inv.
Qed.
Lemma inc_filter : forall (l1:seq A) l2, inc l1 l2 -> forall f, inc (filter f l1) (filter f l2).
Proof.
elim => // h t IH l2; rewrite inc_cons_L; case/andP => H1 H2 f /=.
case: ifP => /= f_h.
- case: ifP => [h_l2|<-].
+ by apply IH.
+ move: (mem_filter f h l2); by rewrite f_h H2.
- by apply IH.
Qed.
Lemma inc_filter_L : forall (l1 l2 : seq A),
inc l1 l2 -> forall f : pred A, inc (filter f l1) l2.
Proof.
elim=> // h t IH l2 /=.
case: ifP => // h_in_l2 t_inc_l2 f.
case: ifP => [/= | ].
by rewrite h_in_l2 IH.
by rewrite IH.
Qed.
Lemma inc_seq_filter_imp : forall (k : seq A) (p p': pred A),
(forall x, x \in k -> p x -> p' x ) -> inc (filter p k) (filter p' k).
Proof.
elim => // hd tl IH p p' Himp /=.
case: ifP => X.
+ rewrite /=.
have Y : p' hd.
apply Himp => //.
by rewrite in_cons eqxx.
rewrite Y /= in_cons eqxx /=.
apply inc_cons_R.
apply IH => x Hx.
apply Himp.
by rewrite in_cons Hx orbC.
+ case: ifP => Y.
* apply inc_cons_R, IH.
move=> x Hx Hp; apply Himp => //.
by rewrite in_cons Hx orbC.
* apply IH => //.
move=> x Hx Hp; apply Himp => //.
by rewrite in_cons Hx orbC.
Qed.
End inclusion_bool.
Lemma inc_map_fst (A B : eqType) (l1 l2 : seq (A * B)) :
inc l1 l2 -> inc (map (fun x => fst x) l1) (map (fun x => fst x) l2).
Proof.
move/incP' => H.
apply/incP' => x /mapP[y Hy Hxy].
move/H in Hy.
apply/mapP; by exists y.
Qed.
Lemma inc_iota : forall b b', (b <= b')%nat ->
forall a, inc (iota a b) (iota a b').
Proof.
elim=> // b IH [|b'] //= Hb' a.
rewrite in_cons eqxx /=; by apply inc_cons_R, IH.
Qed.
Lemma incl_iota : forall a n b m, (b <= a)%coq_nat -> (n + (a - b) <= m)%coq_nat ->
List.incl (iota a n) (iota b m).
Proof.
move=> a n b m b_a n_m c /inP; rewrite mem_iota => H.
apply/inP; rewrite mem_iota; apply/andP; split; ssromega.
Qed.
Section disjointness_bool.
Variable A : eqType.
Implicit Type l : seq A.
Fixpoint dis l1 l2 :=
match l1 with
| h :: t => if h \in l2 then false else dis t l2
| nil => true
end.
Lemma disP : forall l1 l2, reflect (disj l1 l2) (dis l1 l2).
Proof.
elim=> /= [l2|h t IH l2].
- by apply ReflectT, disj_nil_L.
- apply: (iffP idP) => [|H].
+ case: ifP => // h_l2 t_l2.
apply disj_cons_L; by [apply/IH | apply/inP; rewrite h_l2].
+ case/(@disj_cons_inv A) : H; move/IH => H.
by move/inP /negbTE=> ->.
Qed.
Lemma dis_inc_L l k : dis l k -> forall l', inc l' l -> dis l' k.
Proof. by move/disP => ? l' /incP ?; apply/disP/tac_disj_incl_L; eauto. Qed.
Lemma dis_inc_R l k : dis l k -> forall k', inc k' k -> dis l k'.
Proof. by move/disP => ? l' /incP ?; apply/disP/tac_disj_incl_R; eauto. Qed.
Lemma dis_inc (l k' k : seq A) : dis l k' -> inc k k' -> dis l k.
Proof. by move=> lk' kk'; apply: dis_inc_R; eauto. Qed.
Lemma dis_cons : forall l' l (x : A), dis (x :: l) l' = dis l l' && ~~ (x \in l').
Proof. move=> l' l x /=; case: ifP=> _; by rewrite andbC. Qed.
Lemma dis_filter : forall l1 l2, dis l1 l2 -> forall f, dis (filter f l1) l2.
Proof.
elim=> // h t IH l2 /=.
case: ifP => // h_l2 t_l2 f.
case: ifP => /=; by rewrite ?h_l2 IH.
Qed.
Lemma dis_filter_split : forall (p q : pred A) l l',
(forall b, (p b -> ~~ q b) /\ (q b -> ~~ p b)) ->
dis (filter p l) (filter q l').
Proof.
move=> p q; elim => // hd tl IH l' H; apply/disP; split=> /=.
- case: ifP => p_hd.
+ have q_hd : ~~ q hd by move: (proj1 (H _) p_hd).
rewrite /=; case=> [hd_x|].
* apply/inP; by rewrite mem_filter negb_and -hd_x q_hd.
* move/negP : q_hd => q_hd Hx.
contradict q_hd.
move/(IH l')/disP : H.
move/(_ x); tauto.
+ case/boolP : (q hd) => [q_hd Z | ? ?];
move/(IH l')/disP : H; move/(_ x); tauto.
- case: ifP => p_hd Hx.
+ apply/inP.
rewrite /= in_cons negb_or.
move/(IH l')/disP : (H) => {IH}.
move/(_ x)/proj2/(_ Hx)/inP => ->.
rewrite andbC /=.
apply/eqP => ?; subst.
have q_hd : ~~ q hd by move: (proj1 (H _) p_hd).
move/inP : Hx.
by rewrite mem_filter (negbTE q_hd).
+ move/(IH l')/disP : H.
by move/(_ x)/proj2/(_ Hx).
Qed.
Lemma dis_sym l l' : dis l l' = dis l' l.
Proof. apply/disP/disP; by move/disj_sym. Qed.
Lemma dis_filter_right l1 l2 : dis l1 (filter (fun x => ~~ (x \in l1)) l2).
Proof.
elim: l2 l1 => /= [l1|h t IH l1].
- by rewrite dis_sym.
- move: (IH l1) => IH'.
case: ifP => //= h_l1.
by rewrite dis_sym /= (negbTE h_l1) dis_sym.
Qed.
Lemma dis_not_in : forall l l' (x : A), x \in l -> dis l l' -> ~~ (x \in l').
Proof.
elim=> // h t IH l' x.
rewrite in_cons.
case/orP => Hx /=.
- move/eqP : Hx => ?; subst h; by case: ifP.
- case: ifP => // h_l' t_l'; by apply IH.
Qed.
Lemma dis_nil_R l : dis l [::]. Proof. by rewrite dis_sym. Qed.
Lemma dis_singl x y : x != y = dis [:: x] [:: y].
Proof. by rewrite /= in_cons in_nil orbC. Qed.
End disjointness_bool.
Lemma dis_seq_singl x n l : x < n -> dis (iota n l) (x :: nil).
Proof.
move=> x_n; apply/disP => x1; split => /=.
move/inP; rewrite mem_iota => ?; ssromega.
case=> // ?; subst x1.
move/inP; rewrite mem_iota => ?; ssromega.
Qed.
Lemma dis_seq_singl2 x n l : n + l <= x -> dis (iota n l) (x :: nil).
Proof.
move=> Hxn; apply/disP => y; split => [/inP /= H1|/=].
rewrite mem_iota in H1; ssromega.
case=> // ?; subst y.
move/inP; rewrite mem_iota => ?; ssromega.
Qed.
Lemma disj_iota_iota a l b k : a + l <= b -> dis (iota a l) (iota b k).
Proof.
move=> H; apply/disP => x1; split => /inP;
rewrite mem_iota => ? /inP; rewrite mem_iota => ?; ssromega.
Qed.
Lemma dis_iota a a' b c : a + b <= a' -> dis (iota a b) (iota a' c).
Proof.
move=> b'b.
apply/disP => x; split.
move/inP.
rewrite mem_iota => Hx.
move/inP.
rewrite mem_iota => ?; by ssromega.
move/inP.
rewrite mem_iota => Hx.
move/inP.
rewrite mem_iota => ?; by ssromega.
Qed.
Ltac dis_iota_tac :=
match goal with
| |- is_true (dis (iota ?a ?b) (?c :: nil)) =>
apply dis_seq_singl; ssromega
| |- is_true (dis (iota ?a ?b) (?c :: nil)) =>
apply dis_seq_singl2; ssromega
| |- is_true (dis (?c :: nil) (iota ?a ?b)) =>
rewrite dis_sym; apply dis_seq_singl; ssromega
| |- is_true (dis (?c :: nil) (iota ?a ?b)) =>
rewrite dis_sym; apply dis_seq_singl2; ssromega
| |- is_true (dis (iota ?a ?b) (iota ?c ?d)) =>
apply disj_iota_iota; ssromega
| |- is_true (dis (?a :: nil) (?b :: nil)) =>
apply dis_singl; ssromega
end.
Section OCamlFind.
Variable A : eqType.
Variable a : pred A.
Fixpoint ocamlfind s := if s is x :: s' then if a x then Some x else ocamlfind s' else None.
Lemma ocamlfind_cons hd tl : a hd -> ocamlfind (hd :: tl) = Some hd.
Proof. move=> H; by rewrite /ocamlfind H. Qed.
Lemma ocamlfind_cons' hd tl : ~ a hd -> ocamlfind (hd :: tl) = ocamlfind tl.
Proof. move/negP => H; by rewrite {1}/ocamlfind -/(ocamlfind tl) (negbTE H). Qed.
Lemma ocamlfind_cons'' hd tl r : ocamlfind (hd :: tl) = Some r -> a hd \/ ocamlfind tl = Some r.
Proof.
rewrite /ocamlfind -/(ocamlfind tl).
case: ifP => X; by auto.
Qed.
Lemma ocamlfind_Some_mem : forall k r, ocamlfind k = Some r -> a r /\ r \in k.
Proof.
elim=> [|hd tl IH] // r.
rewrite {1}/ocamlfind -/(ocamlfind tl).
case: ifP => X.
- case=> Y; subst.
rewrite !in_cons /= eq_refl //=.
- move=> H /=.
apply IH in H.
case:H => H1 H2.
rewrite !in_cons orbC // H2; auto.
Qed.
End OCamlFind.
Fixpoint delete1 {A : eqType} (l : seq A) e : seq A :=
match l with
| nil => nil
| hd::tl =>
if e == hd then tl else hd :: delete1 tl e
end.
Section association_list.
Fixpoint assoc_get {A : eqType} {B : Type} (a : A) (l : seq (A * B)) : option B :=
match l with
| nil => None
| h :: t => if h.1 == a then Some h.2 else assoc_get a t
end.
Lemma assoc_get_in {A B : eqType} : forall (l : seq (A * B)) (a : A) b,
assoc_get a l = Some b -> (a, b) \in l.
Proof.
elim => //=; case=> hd1 hd2 tl Hind /= a b.
case: ifP.
- move/eqP => -> [] ->; rewrite inE => //=; apply/orP; left; apply (eq_refl _).
- by move => _ Hassoc; rewrite inE; apply/orP; right; apply Hind.
Qed.
Lemma in_assoc_get {A B : eqType} : forall (l : seq (A * B)) (a : A) b,
uniq (unzip1 l) ->
(a, b) \in l ->
assoc_get a l = Some b.
Proof.
elim=> // h t IH a b /= /andP[] ht ut.
rewrite in_cons.
case/orP => [/eqP ? | abt].
subst h => /=; by rewrite eqxx.
case: ifP => [/eqP ? | h1a].
exfalso.
subst a.
move/negP : ht; apply.
apply/mapP; by exists (h.1, b).
exact: IH.
Qed.
Lemma assoc_get_subset_in {A B : eqType} (l: seq (A * B)) : forall
(Hl: uniq (unzip1 l)) (l': seq (A * B)) (Hl': {subset l' <= l}) (a: A) (b: B),
(a, b) \in l' ->
assoc_get a l = Some b.
Proof.
move=> Hl l' l'l a b abl'.
apply in_assoc_get => //.
exact: l'l.
Qed.
Lemma assoc_get_delete_neq {A B : eqType} : forall (l : seq (A * B)) a x,
a <> x -> forall y, assoc_get a (filter (predC (pred1 (x, y))) l) = assoc_get a l.
Proof.
elim => //=; case=> h1 h2 t IH a x ax y /=.
case: ifPn => [H1|] /=.
case: ifP => [_ // | H2].
by rewrite IH.
rewrite negbK => /eqP[? ?]; subst x y.
rewrite eq_sym; move/eqP/negbTE : (ax) => ->.
by rewrite IH.
Qed.
Lemma assoc_get_subset {A B : eqType} (l : seq (A * B)) :
forall (Hl : uniq (unzip1 l)) (l' : seq (A * B)) (Hl': {subset l' <= l}) (a : A) (b : B),
assoc_get a l' = Some b ->
assoc_get a l = Some b.
Proof.
move=> Huniq l' Hsubset a b Hassoc.
apply assoc_get_subset_in with l' => //=.
exact: (assoc_get_in Hassoc).
Qed.
Fixpoint assoc_upd {A : eqType} {B : Type} (a : A) (b : B) (l : seq (A * B)) : seq (A * B) :=
match l with
| nil => nil
| hd :: tl => if hd.1 == a then (a, b) :: tl else hd :: assoc_upd a b tl
end.
Lemma assoc_get_upd_eq {A : eqType} {B} : forall (l : seq (A * B)) a b c,
assoc_get a l = Some c ->
assoc_get a (assoc_upd a b l) = Some b.
Proof.
elim => //=.
move => [] hd1 hd2 //= tl Hind a b c H.
case: (hd1 =P a) => H' //=.
- by rewrite eq_refl.
- case: (hd1 =P a) H => H'' //=.
apply Hind.
Qed.
Lemma assoc_get_upd_neq {A : eqType} {B : Type} :
forall (l : seq (A * B)) (a b : A) (c : B),
a <> b -> assoc_get a (assoc_upd b c l) = assoc_get a l.
Proof.
elim=> // h t IH a b c ab /=.
case: ifP => [|Hif].
- move/eqP => ? /=; subst b.
move/eqP in ab.
by rewrite eqtype.eq_sym (negbTE ab).
- case: ifP => [/= -> // |/= ->]; by apply IH.
Qed.
Lemma assoc_get_upd_neq_inv {A : eqType} {B} : forall (l : seq (A*B)) a b c d,
assoc_get a (assoc_upd b c l) = Some d ->
a <> b ->
assoc_get a l = Some d.
Proof.
elim=> // h t IH a b c d /=.
case: ifP => [|Hif].
- move/eqP => <- /= H.
move/eqP.
rewrite eqtype.eq_sym.
move/negbTE => X; by rewrite X in H *.
- move=> /=.
case: ifP => // Hif2.
exact: IH.
Qed.
Lemma assoc_upd_inv {A : eqType} {B : Type} (a : A) :
forall (l : seq (A * B)) b,
assoc_get a l = Some b ->
assoc_upd a b l = l.
Proof.
elim =>//=.
move => [] hd1 hd2 //= tl Hind b.
case: (hd1 =P a) => //=.
- by move => ?; case => ?; subst.
- move => _ H; by rewrite Hind.
Qed.
End association_list.
Section slice.
Definition slice {A : Type} (l : seq A) (a n : nat) := take n (drop a l).
Local Notation "l |{ a , n )" := (slice l a n).
Lemma slice_shift {A} : forall d (l1 l2 : seq A) i1 i2 sz sz',
l1 |{ i1, sz ) = l2 |{ i2, sz) ->
d + sz' < sz ->
l1 |{ i1 + d, sz') = l2 |{ i2 + d, sz').
Proof.
move=> d l1 l2 i1 i2 sz sz' H H0.
rewrite /slice -!drop_drop (drop_dropC i1 d) (drop_dropC i2 d) take_drop (take_drop _ d sz').
congr drop.
by apply take_lt with sz.
Qed.
Lemma size_slice_leq {A : Type} : forall (l : seq A) b a, size (l |{ a , b)) <= b.
Proof.
move=> l b a; rewrite /slice size_take size_drop ltn_subRL.
case: ifP => // /negbT; by rewrite -leqNgt -leq_subLR.
Qed.
Lemma size_slice_exact {A : Type} : forall (l : seq A) (b a : nat),
a + b <= size l -> size (l |{ a, b)) = b.
Proof.
elim.
by case=> //= n [].
move=> h t IH b [|a] /=.
- rewrite add0n leq_eqVlt.
case/orP.
move/eqP => ->.
by rewrite /slice /= size_take ltnn.
by rewrite /slice drop0 size_take /= => ->.
- rewrite addSn => H.
by rewrite /slice /= IH.
Qed.
Lemma slice_app {A : Type} : forall (l : seq A) a b c,
l |{ a, b + c ) = l |{ a, b) ++ l |{ a + b, c).
Proof.
elim=> // h t IH [|a] b c.
- rewrite /slice drop0 take_drop.
rewrite (_ : take b (h :: t) = take b (take (b + c) (h :: t))); last by rewrite take_take.
by rewrite cat_take_drop.
- move=> /=.
exact: IH.
Qed.
Lemma nth_slice {A} (l : seq A) start sz i def (_ : i < sz) :
nth def (slice l start sz) i = nth def l (start + i).
Proof. by rewrite /slice take_drop nth_drop nth_take // ltn_add2l. Qed.
Lemma nth_slices {A} start' sz' (l l' : seq A) start sz i def:
start <= i < start + sz ->
0 < sz <= sz' ->
slice l start sz = slice l' start' sz' ->
nth def l i = nth def l' (start' + (i - start)).
Proof.
move=> /andP Hi /andP Hsz Hl.
have Harith1 : i - start < sz by rewrite ltn_sub_add; tauto.
rewrite {1}(_ : i = start + (i - start)); last by rewrite subnKC //; tauto.
rewrite -(@nth_slice _ _ _ sz _ _) // Hl (@nth_slice _ _ _ sz' _ _) //.
eapply (ltn_leq_trans sz); tauto.
Qed.
Lemma slices_sem {A} (l : seq A) i sz : l = take i l ++ slice l i sz ++ drop (i+sz) l.
Proof. by rewrite /slice take_drop -{1}(take_take _ _ sz) catA !cat_take_drop. Qed.
End slice.
Notation "l |{ a , n )" := (slice l a n) : seq_ext_scope.
Definition map_indices {A : Type} (def : A) (l : seq A) (indices : seq nat) : seq A :=
map (nth def l) indices.
Lemma map_indices_iota {A : Type} {def : A} : forall sz i (l : seq A),
i + sz <= size l ->
map_indices def l (iota i sz) = take sz (drop i l).
Proof.
rewrite /map_indices.
elim => //=.
- move => i l _.
by rewrite take0.
- move => n Hind i l.
destruct i => //=.
+ destruct l => //=.
move => Hlt; rewrite Hind //=; rewrite drop0 //=.
+ destruct l => //=.
move => Hlt; rewrite Hind //=; last by move: Hlt; nat_norm.
rewrite (@drop_nth _ def i l) => //=.
ssromega.
Qed.
Lemma map_indices_self {A : Type} {def : A} (l : seq A) :
map_indices def l (iota O (size l)) = l.
Proof.
rewrite map_indices_iota.
by rewrite drop0 take_size.
by rewrite add0n.
Qed.
Lemma seq_forall_exists :
forall {T : eqType} (P : T -> nat -> Prop),
(forall y i a, P y i -> P y (i + a)) ->
forall (Y : seq T),
(forall y, y \in Y -> exists i : nat, P y i) ->
exists i : nat, forall y, y \in Y -> P y i.
Proof.
move => T P closed.
elim => [ | y0 Y]; [ move => _; exists 0 => y; done | ].
move => IH H; move: (H y0).
rewrite in_cons eq_refl.
case; [ done | ].
move => i0 Pyi0.
have IH' : exists i : nat, forall y : T, y \in Y -> P y i.
- apply: IH => y I; apply: H.
rewrite in_cons; apply/orP; right; assumption.
move: IH => _; case: IH' => i1 IH; exists (maxn i0 i1).
move => y; rewrite in_cons; case/orP.
- move/eqP => I; subst;
have -> : maxn i0 i1 = i0 + (maxn i0 i1 - i0)
by rewrite subnKC; [done | ]; exact: leq_maxl.
apply: closed; assumption.
- move => I.
have -> : maxn i0 i1 = i1 + (maxn i0 i1 - i1)
by rewrite subnKC; [done | ]; exact: leq_maxr.
apply: closed; apply: IH; assumption.
Qed.
Section repeated_take.
Variable A : Type.
Fixpoint takes' (k : nat) (n : nat) (l : seq A) {struct n} : list (seq A) :=
match n with
| O => nil
| S m => take k l :: takes' k (m - (k - 1)) (drop k l)
end.
Definition takes (k : nat) (l : seq A) : seq (seq A) :=
match k with
| O => nil
| S _ => takes' k (size l) l
end.
Lemma takes_nil n : takes n (@nil A) = nil. Proof. by case: n. Qed.
Lemma takes_skipn : forall n (l : seq A) hd tl,
takes n l = hd :: tl -> takes n (drop n l) = tl.
Proof.
move=> [|n] // [|l1 l2] // [|hd1 hd2] // tl [] ?; subst hd1 => Hhd2.
rewrite /= subSS subn0 /= => <-.
by rewrite size_drop.
Qed.
Lemma len_takes' n : forall (l : seq A), size l = n -> forall k q,
n = q * S k -> size (takes' (S k) n l) = q.
Proof.
induction n using Wf_nat.lt_wf_ind.
destruct n as [|n]; first by case=> // _ k [|q].
case=> hd tl // [Hlen] k [|q] //= n_k; rewrite subSS subn0; f_equal.
apply H.
apply/ltP.
rewrite ltnS.
by rewrite leq_subLR leq_addl.
by rewrite size_drop Hlen.
rewrite mulSn addSn in n_k.
case: n_k => ->.
by rewrite mulnC mulSn addnC addnK.
Qed.
Lemma len_takes n : forall (l : seq A), size l = n -> forall k q,
n = q * S k -> size (takes (S k) l) = q.
Proof.
induction n using Wf_nat.lt_wf_ind.
destruct n as [|n]; first by case=> // _ k [|q].
case=> hd tl // [Hlen] k [|q] //= n_k; rewrite subSS subn0; f_equal.
have /ltP Htmp : n - k < S n by rewrite ltnS leq_subLR leq_addl.
move: (H _ Htmp (drop k tl)).
rewrite size_drop Hlen.
move/(_ (refl_equal _) k q).
rewrite /takes.
rewrite size_drop Hlen.
apply.
case : n_k => ->.
by rewrite plusE addnC addnK.
Qed.
Lemma In_takes' : forall n (l : seq A), size l = n -> forall k q,
(n = q * S k) -> forall x, List.In x (takes (S k) l) -> size x = (S k).
Proof.
move=> n; induction n using Wf_nat.lt_wf_ind.
destruct n as [|n]; first by case=> // _ k [|q].
case=> hd tl // [Hlen] k [|q] // n_k x.
rewrite /=; case.
destruct x as [|hx tx]; first by [].
case=> ? ?; subst hx tx => /=.
f_equal.
rewrite size_take Hlen.
rewrite -ltnS n_k.
rewrite mulSn.
destruct q.
rewrite mul0n addn0 ltnn.
by rewrite mul1n in n_k; case: n_k.
rewrite mulnS (addSn q) addnS.
by rewrite leq_addr.
rewrite subSS subn0.
move=> H1.
have /ltP H2 : ((n - k) < S n).
by rewrite ltnS leq_subLR leq_addl.
have H3 : size (drop k tl) = (n - k) by rewrite size_drop Hlen.
apply (H (n - k) H2 (drop k tl) H3 k q).
rewrite /= in n_k.
case: n_k => ->.
by rewrite plusE addnC addnK.
by rewrite /takes size_drop.
Qed.
Lemma In_takes n (l : seq A) : size l = n -> forall k q,
(n = q * k) -> forall x, List.In x (takes k l) -> size x = k.
Proof. move=> Hlen [] //; by apply In_takes'. Qed.
Lemma takes_app : forall t (H : t <> O) (a b : seq A), size a = t ->
takes t (a ++ b) = a :: takes t b.
Proof.
move=> t Ht a b Ha.
destruct t => //= {Ht}.
rewrite (_ : size (a ++ b) = S (t + size b)); last by rewrite size_cat /= Ha /=.
destruct a as [|ha ta] => //.
case: Ha => Ha.
by rewrite /= subSS subn0 drop_cat // take_cat // Ha ltnn subnn take0 cats0 addnC addnK drop0.
Qed.
End repeated_take.
Lemma takes_inj {A : Type} : forall n k nk (l1 l2 : seq A), k <> O ->
nk = (k * n)%nat -> size l1 = nk -> size l2 = nk ->
takes k l1 = takes k l2 -> l1 = l2.
Proof.
elim.
move=> k nk l1 l2 Hk.
rewrite muln0 => ->.
destruct l1 => //.
by destruct l2.
move=> n IH k nk l1 l2 Hk Hnk Hl1 Hl2 H.
rewrite -addn1 mulnDr muln1 in Hnk.
rewrite -(cat_take_drop k l1) -(cat_take_drop k l2).
rewrite -(cat_take_drop k l1) // -(cat_take_drop k l2) // in H.
rewrite (@takes_app _ k) // in H; last by rewrite size_takel // Hl1 Hnk leq_addl.
rewrite (@takes_app _ k) // in H; last by rewrite size_takel // Hl2 Hnk leq_addl.
case: H => H1 H2.
f_equal => //.
apply (IH k (k * n)%nat) => //.
by rewrite size_drop // Hl1 Hnk addnK.
by rewrite size_drop // Hl2 Hnk addnK.
Qed.
Definition injection {A B : Type} (f : A -> B) :=
forall x y, f x = f y -> x = y.
Lemma map_inj (A B : Type) : forall (f : list A -> B), injection f ->
forall n (a b : list (list A)) ,
size a = n -> size b = n ->
map f a = map f b -> a = b.
Proof.
move=> f Hf.
elim => [ | n IH [|ha ta] // [|hb tb] // [Ha] [Hb] /=].
case=> //; by case.
by case => /Hf <- /(IH _ _ Ha Hb) <-.
Qed.
Section flat_map.
Variable A B : Type.
Fixpoint flat_map (f : A -> seq B) l :=
match l with
| [::] => [::]
| x :: t => (f x ++ flat_map f t)
end.
Implicit Type l : seq A.
Implicit Type k : seq B.
Lemma len_flat_map : forall n l m (f : A -> seq B),
(forall a, size (f a) = m) -> size l = n ->
size (flat_map f l) = n * m.
Proof.
elim=> [[]// |n IHn [|h t] // k f f_k [len_t] /=].
by rewrite size_cat (IHn _ k) // f_k.
Qed.
Lemma len_flat_map_inv : forall l q m (f : A -> seq B),
size (flat_map f l) = q * m ->
(forall a, size (f a) = m) ->
m <> O ->
size l = q.
Proof.
elim=> /=.
move=> q k f /esym/eqP.
rewrite muln_eq0.
by case/orP => /eqP -> //.
move=> hd tl IH [|q] k f Hlen H Hk.
rewrite size_cat H /= mul0n in Hlen.
move/eqP in Hlen.
rewrite addn_eq0 in Hlen.
case/andP : Hlen => /eqP Hlen _.
by rewrite Hlen in Hk.
f_equal.
apply IH with k f => //.
rewrite /= size_cat /= H mulSn in Hlen.
move/eqP : Hlen.
by rewrite eqn_add2l => /eqP.
Qed.
Lemma flat_map_inj : forall (f : A -> seq B), injection f ->
(exists k: nat, k <> O /\ forall a, size (f a) = k) ->
forall l1 l2, flat_map f l1 = flat_map f l2 -> l1 = l2.
Proof.
move=> f f_inj [k [Hk Hf]].
elim=> /=.
- case=> //= h2 t2 abs.
suff : False by done.
move: (Hf h2) => abs'.
destruct (f h2) => //.
by subst k.
- move=> h1 t1 IH [|h2 t2] /=.
move: (Hf h1).
destruct (f h1) => //.
move=> ?; by subst k.
move=> H.
apply cat_inv in H; last by rewrite Hf.
rewrite (IH t2); last by tauto.
f_equal.
apply f_inj; tauto.
Qed.
End flat_map.
Fixpoint upd_nth {A : Type} (l : seq A) (n : nat) (v : A) {struct l} : seq A :=
match l with
| nil => nil
| hd :: tl => match n with
| O => v :: tl
| S n' => hd :: upd_nth tl n' v
end
end.
Lemma size_upd_nth {A : Type} : forall n (l : seq A) k (v : A),
size l = n -> size (upd_nth l k v) = n.
Proof. elim => [ [] // | n IHn [|hd tl] // [|k] // v [H] /= ]; by rewrite IHn. Qed.
Lemma upd_nth_cat {A : Type} : forall n l (a : A), size l <= n ->
forall l', upd_nth (l ++ l') n a = l ++ upd_nth l' (n - size l) a.
Proof. elim=> [ [] // | n H [ // |h t]] v H0 l'; by rewrite /= H. Qed.
Lemma upd_nth_cat' (A: Type) : forall n l (a : A), n < size l ->
forall l', upd_nth (l ++ l') n a = (upd_nth l n a) ++ l'.
Proof.
Proof. elim=> [ [] // | n H [ // |h t]] v H0 l'; by rewrite /= H. Qed.
Lemma nth_upd_nth {A : Type} : forall n (a : A) l def,
n < size l -> nth def (upd_nth l n a) n = a.
Proof. elim => [m [|] // | n H m [ // |h t] def_val H0 /=]; by rewrite H. Qed.
Lemma nth_upd_nth' {A : Type} : forall l n n' (a : A) def, n <> n' ->
nth def (upd_nth l n' a) n = nth def l n.
Proof. elim=> [ // |h t IH] [|n] [|n'] m def_val /= H //; rewrite IH // => nn'; by subst. Qed.
Lemma drop_upd_nth {A : Type} : forall l n (a : A) m, (n < m)%nat ->
drop m (upd_nth l n a) = drop m l.
Proof. elim => //= h t IH [|n] /= e [|m] //=; rewrite ltnS => nm; by rewrite IH. Qed.
Lemma take_upd_nth {A:Type} : forall lst n (m:A),
take n (upd_nth lst n m) = take n lst.
Proof. elim => // hd tl IH [|n0] //= m. by rewrite IH. Qed.
Section index_deletion.
Variable A : Type.
Fixpoint idel (n : nat) (l : seq A) {struct l} : seq A :=
if l isn't hd :: tl then nil else
(if n isn't S n' then tl else hd :: idel n' tl).
Lemma size_idel : forall (s : seq A) n, n < size s ->
size (idel n s) = size s - 1.
Proof.
elim => // a l IH [|n] /=.
- by rewrite subn1.
- rewrite ltnS => H0; rewrite IH // -subSn //; exact: leq_ltn_trans H0.
Qed.
Lemma idel_size_last (s : seq A) (a : A) : idel (size s) (s ++ a :: nil) = s.
Proof. elim: s a => // hd tl IH a /=. by rewrite IH. Qed.
Lemma idel_upd_nth (s : seq A) k m : idel k (upd_nth s k m) = idel k s.
Proof. by elim : s k m => // h t IH [|k] //= m; rewrite IH. Qed.
Lemma idel_app : forall k (l1 : seq A), size l1 = k ->
forall l a l2, l = l1 ++ a :: l2 -> idel k l = l1 ++ l2.
Proof.
elim=> [[] // H l a l2 -> // |].
move=> k IHk [|a0 l1] // [H] [|a1 l] // a l2 [-> Hl] /=; congr cons.
exact: IHk Hl.
Qed.
End index_deletion.
Definition idel_last {A : Type} (l : seq A) : seq A :=
match l with
| nil => nil
| _ => idel (size l - 1) l
end.
Lemma size_idel_last {A : Type} : forall n (l : seq A), size l = n ->
size (idel_last l) = n - 1.
Proof.
case => [ [] // | n [|a l] // [len_l]].
by rewrite /idel_last [_ - _]/= subn1 size_idel //= len_l.
Qed.
Lemma size_idel_last' {A : Type} : forall (lst : seq A),
O < size lst -> size (idel_last lst) = size lst - 1.
Proof. move=> lst H; by rewrite (size_idel_last (refl_equal (size lst))). Qed.
Lemma list_split {A : Type} def n (l : seq A) : size l = n ->
forall j, j < n -> exists l1, size l1 = j /\
exists l2, l = l1 ++ nth def l j :: nil ++ l2.
Proof.
move=> ln j jn.
exists (take j l).
rewrite size_takel; last by rewrite ln ltnW.
split => //.
exists (drop j.+1 l).
rewrite -drop_nth //; last by rewrite ln.
by rewrite cat_take_drop.
Qed.
match l with
| nil => nil
| hd :: tl =>
match P idx with
| true => remove_idx tl P (S idx)
| false => hd :: remove_idx tl P (S idx)
end
end.
Lemma mem_remove_idx (A : eqType) (h : A) : forall t P i, h \in remove_idx t P i -> h \in t.
Proof.
elim=> // h' t IH P i /=.
case: ifP => /= Pi.
move/IH => ht; by rewrite in_cons ht orbC.
rewrite in_cons; case/orP => [/eqP -> |].
by rewrite in_cons eqxx.
move/IH => ht; by rewrite in_cons ht orbC.
Qed.
Lemma uniq_remove_idx (A : eqType) : forall (l : seq A), uniq l -> forall p i, uniq (remove_idx l p i).
Proof.
elim=> // hd tl IH /=; case/andP; move/negP => Hhd Htl p i; case (p i) => /=.
- by apply IH.
- apply/andP; split; last by apply IH.
apply/negP; contradict Hhd.
by apply: mem_remove_idx Hhd.
Qed.
Ltac compute_positions1 l k idx :=
match l with
| @cons ?A k ?tl =>
let new_idx := constr : (S idx) in
let new_tl := compute_positions1 tl k new_idx in
constr: (@cons nat idx new_tl)
| @cons ?A ?hd ?tl =>
let new_idx := constr : (S idx) in
compute_positions1 tl k new_idx
| _ =>
constr : (@nil nat)
end.
Ltac remove_head_from_tail HD TL :=
let ISDUP := In_list HD TL in
match ISDUP with
| false => constr: (HD :: TL)
| true =>
let POSITIONS := compute_positions1 TL HD O in
let NEW_TL := eval compute in (remove_idx TL (fun x => (x \in POSITIONS)) O) in
let NEW_HDTL := eval compute in (seq.cat NEW_TL (HD :: nil)) in
constr : (NEW_HDTL)
end.
Ltac remove_duplicates LST :=
match LST with
| @cons ?A ?HD ?TL =>
let NEW_TL := remove_duplicates TL in
remove_head_from_tail HD NEW_TL
| @nil ?A => LST
end.
Inductive permutation {A : Type} : seq A -> seq A -> Prop :=
| permutation_nil: permutation nil nil
| permutation_skip x l l' : permutation l l' -> permutation (x::l) (x::l')
| permutation_swap x y l : permutation (y::x::l) (x::y::l)
| permutation_trans l l' l'' : permutation l l' -> permutation l' l'' -> permutation l l''.
Lemma permutation_reflexive {A} : forall (l : seq A), permutation l l.
Proof. elim => //=; try constructor => //=. Qed.
Lemma permutation_symmetric {A} (l l': seq A) : permutation l l' -> permutation l' l.
Proof.
elim => //=; try constructor => //=.
intros; by apply permutation_trans with l'0.
Qed.
Require Export Setoid Relation_Definitions.
Instance permutation_Equivalence A : Equivalence (@permutation A) | 10.
constructor.
exact permutation_reflexive.
exact permutation_symmetric.
exact permutation_trans.
Defined.
Ltac swap_with_head_rec i :=
match i with
| O => apply permutation_swap
| S _ => eapply permutation_trans; [
let n := eval simpl in (i.-1) in
apply permutation_skip;
swap_with_head_rec n | apply permutation_swap]
end.
Ltac swap_with_head i :=
match i with
| O => idtac
| S _ => eapply permutation_trans; [
let n := eval simpl in (i.-1) in
swap_with_head_rec n | idtac]
end.
Ltac setl P :=
match P with
| nil => idtac
| ?hd::?tl =>
let x := fresh in
(set x := hd); setl tl
end.
Ltac Solve_permutation :=
match goal with
| |- permutation ?l1 ?l2 =>
setl l1
end;
match goal with
| |- permutation nil nil => apply permutation_nil
| |- permutation ?l (?hd::_) =>
let A := type of hd in
let i := find_indice hd l in
swap_with_head i; apply permutation_skip; Solve_permutation
end.
Goal permutation [:: 1; 3; 2] [::2; 1; 3].
Solve_permutation.
Abort.
Section disjunction_Prop.
Variable A : Type.
Implicit Type l : seq A.
Definition disj l1 l2 := forall x,
(List.In x l1 -> ~ (List.In x l2)) /\ (List.In x l2 -> ~ (List.In x l1)).
Lemma disj_nil_R l : disj l nil. Proof. move=> x /=; tauto. Qed.
Lemma disj_nil_L l : disj nil l. Proof. move=> x /=; tauto. Qed.
Lemma disj_singl a b : a <> b -> disj (a :: nil) (b :: nil).
Proof.
move=> ab x; split; case => //= ?; subst x; contradict ab; firstorder.
Qed.
Lemma disj_sym h1 h2 : disj h1 h2 -> disj h2 h1.
Proof. rewrite /disj => H x; move: (H x); tauto. Qed.
Lemma disj_not_In L x K : disj K L -> List.In x L -> ~ List.In x K.
Proof. move=> Hinter HIn X; move: (Hinter x); tauto. Qed.
Lemma disj_cons_R x L K : disj K L -> ~ List.In x K -> disj K (x :: L).
Proof.
move=> l1_l2 x_l2; rewrite /disj => z; split => /= [z_l2|].
- contradict x_l2; case: x_l2 => [?|z_l1]; [by subst x | move: (l1_l2 z); tauto].
- case => [?|z_l1]; [by subst z | move: (l1_l2 z); tauto].
Qed.
Lemma disj_cons_L x L K : disj K L -> ~ List.In x L -> disj (x :: K) L.
Proof.
move=> l1_l2 x_l2; rewrite /disj => z; split => /= [|z_l2].
- case => [?|z_l1]; [by subst z | move: (l1_l2 z); tauto].
- contradict x_l2; case: x_l2 => [?|z_l1]; [by subst x | move: (l1_l2 z); tauto].
Qed.
Lemma disj_in_cons_R x L K : disj K L -> List.In x L -> disj K (x :: L).
Proof.
move=> l1_l2 x_l1; rewrite /disj => z; split => [z_l2|] /=.
- move: (proj1 (l1_l2 z) z_l2) => H1; contradict H1.
case: H1; by [move=> ?; subst z | ].
- case.
+ move=> ?; subst z=> ?; move: (l1_l2 x); tauto.
+ move=> z_l1 ?; move: (l1_l2 z); tauto.
Qed.
Lemma disj_cons_inv h1 t1 l2 : disj (h1 :: t1) l2 -> disj t1 l2 /\ ~ List.In h1 l2.
Proof.
move=> H; split => [x | h1_l2].
- rewrite /disj; split=> x_t1 abs; move: (H x) => /=; by firstorder.
- move: (H h1) => /=; by firstorder.
Qed.
Lemma disj_app_inv l k m : disj (l ++ k) m -> disj l m /\ disj k m.
Proof.
move=> H; split=> x; split=> Hx abs; case: (H x) => _.
move/(_ abs). apply. apply List.in_or_app; tauto.
move/(_ Hx). apply. apply List.in_or_app; tauto.
move/(_ abs). apply. apply List.in_or_app; tauto.
move/(_ Hx). apply. apply List.in_or_app; tauto.
Qed.
Lemma disj_app : forall (l k m : seq A), disj l m /\ disj k m -> disj (l ++ k) m.
Proof.
elim => [k m [] // | h t IH k m [H1 H2] /=].
apply disj_cons_L; last first.
move=> X.
apply (proj1 (H1 h)); last by [].
rewrite /=; by auto.
apply IH.
by case/disj_cons_inv : H1.
Qed.
Lemma tac_disj_incl_L l k : disj l k -> forall l', List.incl l' l -> disj l' k.
Proof.
move=> H l' H' x; split=> //=.
- move/H' => Hx abs; move: (H x); tauto.
- move => abs; move/H' => Hx; move: (H x); tauto.
Qed.
Lemma tac_disj_incl_R l k : disj l k -> forall k', List.incl k' k -> disj l k'.
Proof.
move=> H l' H' x; split=> //=.
- move => abs; move/H' => Hx; move: (H x); tauto.
- move/H' => Hx abs; move: (H x); tauto.
Qed.
Lemma disj_incl_LR k' l' k l : disj k' l' -> List.incl k k' -> List.incl l l' -> disj k l.
Proof.
move=> Hinter Hinclk Hincll x; split => // Hx abs.
- apply Hinclk in Hx; apply Hincll in abs; move: (Hinter x); tauto.
- apply Hinclk in abs; apply Hincll in Hx; move: (Hinter x); tauto.
Qed.
End disjunction_Prop.
Ltac disj_remove_duplicates_R :=
match goal with
| |- disj ?L (?HD :: ?TL) =>
let tmp := remove_duplicates (HD :: TL) in
apply (@tac_disj_incl_R _ L tmp)
end.
Ltac disj_remove_duplicates_L :=
match goal with
| |- disj (?HD :: ?TL) _ =>
let tmp := remove_duplicates (HD :: TL) in
apply (@tac_disj_incl_L _ tmp)
end.
Ltac Disj_remove_dup :=
match goal with
| |- disj (_ :: _) (_ :: _) =>
( disj_remove_duplicates_L; last by rewrite /List.incl /=; intuition ) ;
( disj_remove_duplicates_R; last by rewrite /List.incl /=; intuition )
| |- disj (?HD :: ?TL) _ =>
disj_remove_duplicates_L; last by rewrite /List.incl /=; intuition
| |- disj _ (?HD :: ?TL) =>
disj_remove_duplicates_R; last by rewrite /List.incl /=; intuition
end.
Section fold.
Lemma foldl_map {A B C} (f : B -> A -> B) (f' : C -> A) : forall l acc,
foldl f acc (map f' l) = foldl (fun acc hd => f acc (f' hd)) acc l.
Proof. by elim => //=. Qed.
Lemma foldr_map {A B C : Type} (f : A -> B -> B) (f' : C -> A) : forall l a,
foldr f a (map f' l) = foldr (fun h a => f (f' h) a) a l.
Proof. elim=> //= h t IH Hyp; by congr (f _ _). Qed.
Lemma foldl_congr_f {A B} (f f': B -> A -> B) (Hf: forall x y, f x y = f' x y):
forall l acc, foldl f acc l = foldl f' acc l.
Proof. elim => //= hd tl Hind acc; by rewrite Hind Hf. Qed.
Lemma foldl_ext {A : Type} {B : eqType} : forall k a (f f' : A -> B -> A),
(forall x a, x \in k -> f a x = f' a x) ->
foldl f a k = foldl f' a k.
Proof.
elim => // h t IH a f f' H /=.
rewrite H; last by apply mem_head.
apply IH => x a' Hx; apply H.
by rewrite in_cons Hx orbC.
Qed.
Section foldl_monotonic.
Variable (A : Type) (f : nat -> A -> nat).
Lemma foldl_leq_monotonic : (forall a x, a <= f a x) ->
forall l a, a <= foldl f a l.
Proof. move=> Hf; elim => //= h t IH a; by apply (@leq_trans (f a h)). Qed.
Lemma foldl_ltn_monotonic : (forall a x, a < f a x) ->
forall l a, l <> nil -> a < foldl f a l.
Proof.
move=> Hf; elim => //= h t IH a _.
apply (@ltn_leq_trans (f a h)) => //=.
apply foldl_leq_monotonic => //= a' x.
by rewrite ltnW.
Qed.
Lemma foldl_lt f' (Hf : forall x1 x2 y, x1 < x2 -> f x1 y < f' x2 y):
forall l a1 a2, a1 < a2 -> foldl f a1 l < foldl f' a2 l.
Proof. elim=> //= h t IH a1 a2 a12; by apply IH, Hf. Qed.
Lemma foldl_le f' (Hf : forall x1 x2 y, x1 <= x2 -> f x1 y <= f' x2 y) :
forall l a1 a2, a1 <= a2 -> foldl f a1 l <= foldl f' a2 l.
Proof. elim => //= h t IH a1 a2 a12; by apply IH, Hf. Qed.
End foldl_monotonic.
Section fold_maxn.
Lemma acc_foldl_maxn : forall l a, a <= foldl maxn a l.
Proof.
elim => //= h t IH a.
rewrite {2}/maxn.
case: leqP => //= ah.
by rewrite (@leq_trans h) // ltnW.
Qed.
Lemma in_foldl_maxn : forall l x a, x \in l -> x <= foldl maxn a l.
Proof.
elim => //= h t IH x a.
rewrite in_cons; case/orP => [/eqP -> | xt ]; last by apply IH.
rewrite (@leq_trans (maxn a h)) //; last by rewrite acc_foldl_maxn.
by rewrite leq_max orbC leqnn.
Qed.
Lemma foldr_Prop_and {A: eqType} P: forall (l: seq A),
foldr (fun hd acc => acc /\ P hd) True l ->
forall x, x \in l -> P x.
Proof.
elim => //=.
move => hd tl Hind Hyp.
move => x; rewrite in_cons.
move/orP => [] Hx.
- move/eqP: Hx ->.
tauto.
- apply Hind; tauto.
Qed.
End fold_maxn.
End fold.
Section seq_Type.
Lemma take_drop {A}: forall (l: seq A) i j, take j (drop i l) = drop i (take (i + j) l).
Proof.
elim => //=.
move => hd tl Hind i j.
destruct i => //=.
destruct j => //=.
Qed.
Lemma take_take {A}: forall (l: seq A) i j, take i (take (i + j) l) = take i l.
Proof.
elim => //=.
move => hd tl Hind i j.
destruct i => //=; first by rewrite take0.
by rewrite Hind.
Qed.
Lemma all_impl_bool {A: Type} (b1 b2: A -> bool) (Hb1b2: forall x, b1 x ==> b2 x): forall l,
all b1 l ==> all b2 l.
Proof.
elim => //=.
move => hd tl Hind.
move: (Hb1b2 hd); apply/implyP.
move: (Hind); apply/implyP.
case: (all b1 tl); case: (b1 hd); case: (all b2 tl); case: (b2 hd) => //=.
Qed.
Lemma all_impl_prop {A: Type} (b1 b2: A -> bool) (Hb1b2: forall x, b1 x ==> b2 x): forall l,
all b1 l -> all b2 l.
by move => l; apply/implyP; apply all_impl_bool.
Qed.
Lemma in_nseq {A : eqType} : forall n (a x : A), x \in nseq n a -> x = a.
Proof. elim=> // n IH a x /=; rewrite in_cons; case/orP; by [move/eqP | apply IH]. Qed.
Lemma drop_nseq {A : Type} : forall b a (c : A), a <= b ->
drop a (nseq b c) = nseq (b - a) c.
Proof.
elim => [ [] // | b IH [| a]].
move=> c _; by rewrite drop0 subn0.
move=> c ab /=; by rewrite subSS IH.
Qed.
Lemma nseqS {A : Type} n (a : A) : nseq (S n) a = nseq n a ++ [:: a].
Proof. by elim: n => // n /= <-. Qed.
Section rcons_ext.
Variable A : Type.
Lemma cons_rcons : forall (tl: seq A) hd, cons hd tl = rcons (belast hd tl) (last hd tl).
Proof. by elim => //= hd tl Hind hd'; rewrite Hind. Qed.
Lemma rcons_cons_head : forall (tl: seq A) hd, rcons tl hd = cons (head hd tl) (behead (rcons tl hd)).
Proof. by elim => //= hd tl Hind hd'; rewrite Hind. Qed.
Lemma rcons_app : forall (tl: seq A) hd, rcons tl hd = tl ++ hd::nil.
Proof. by elim => //=; move => hd tl Hind hd'; rewrite Hind. Qed.
Lemma case_eq_rcons : forall (P: seq A -> Prop),
(P nil) ->
(forall hd tl, P (rcons hd tl)) ->
forall l, P l.
Proof.
move=> P HPnil HPrcons.
case => //= hd tl.
rewrite cons_rcons.
apply HPrcons.
Qed.
End rcons_ext.
Lemma nth_decomp {A} {a} : forall (l : seq A) i, (size l > i) ->
l = take i l ++ nth a l i :: drop i.+1 l.
Proof.
elim => //= hd tl Hind i Hi.
destruct i => //=; first by rewrite drop0.
by rewrite {1}(Hind i).
Qed.
Lemma take_lt {A} : forall sz' (l1 l2: seq A) sz,
take sz l1 = take sz l2 -> sz' < sz -> take sz' l1 = take sz' l2.
Proof.
elim.
- intros; by rewrite !take0.
- intros.
destruct l1; destruct l2.
+ by [].
+ by destruct sz.
+ by destruct sz.
+ destruct sz => //.
simpl in H0; simpl.
injection H0 => ? ->.
f_equal.
by apply H with sz.
Qed.
Lemma dropS {A} : forall (l : seq A) i, drop (S i) l = drop 1 (drop i l).
Proof. by move=> l i; rewrite drop_drop. Qed.
Lemma dropS' {A} : forall (l : seq A) i, drop (S i) l = drop i (drop 1 l).
Proof. by move=> l a; rewrite drop_drop addn1. Qed.
Lemma drop_dropC {A} : forall i j (l : seq A), drop i (drop j l) = drop j (drop i l).
Proof. by move=> i j l; rewrite drop_drop addnC -drop_drop. Qed.
End seq_Type.
Section cat_ext.
Variable A : Type.
Lemma app_split : forall (l : seq A) k, k <= size l ->
exists l1, exists l2, size l1 = k /\ l = l1 ++ l2.
Proof.
elim.
- move=> [|k]; last by inversion 1.
by exists nil; exists nil.
- move=> hd tl IH [_ | k].
by exists nil, (hd :: tl).
rewrite ltnS => H.
case: {IH}(IH _ H) => l1 [l2 [H1 H2]].
exists (hd :: l1); exists l2; split => /=; by rewrite ?H1 ?H2.
Qed.
Lemma app_app_split_R : forall (l1 l2 k1 k2 : seq A),
l1 ++ l2 = k1 ++ k2 -> size l1 <= size k1 -> exists k1', k1 = l1 ++ k1' /\ l2 = k1' ++ k2.
Proof.
elim.
- move=> l2 k1 k2 H H'; by exists k1.
- move=> a l IH l2 [|h1 t1] //= k2 H H'.
case: H => X H; subst h1.
case: {IH}(IH _ _ _ H H') => k1' [H1 H2].
exists k1'; split => //.
by rewrite H1.
Qed.
Lemma cat_inv : forall (l1 l2 k1 k2 : seq A),
l1 ++ l2 = k1 ++ k2 -> size l1 = size k1 ->
l1 = k1 /\ l2 = k2.
Proof.
move=> l1 l2 k1 k2 H Hlen.
apply app_app_split_R in H; last by rewrite Hlen.
case: H => k1' [Hk1 Hl2]; subst k1 l2.
destruct k1'; first by rewrite cats0.
rewrite size_cat /= in Hlen.
exfalso.
rewrite -plusE in Hlen.
ssromega.
Qed.
End cat_ext.
Section seq_eqType.
Variable A : eqType.
Lemma mem_tail : forall tl hd (x: A), x \in tl -> x \in hd :: tl.
Proof.
elim => //= hd tl Hind hd' x Hin.
by rewrite in_cons Hin orbC.
Qed.
Lemma inP : forall l (x : A), reflect (List.In x l) (x \in l).
Proof.
elim => [x /= | h t IH x].
- rewrite in_nil; by apply ReflectF.
- rewrite /= in_cons; apply: (iffP idP).
+ case/orP => [ /eqP -> | /IH ?]; by auto.
+ case => [-> | /IH ->].
* by rewrite eqxx.
* by rewrite orbC.
Qed.
Lemma filter_mem_cons : forall k (n : A), uniq k -> n \in k ->
filter (mem (cons n [::])) k = cons n [::].
Proof.
elim=> // hd tl IH n /=.
case/andP => Hk1 Hk2.
rewrite in_cons; case/orP.
- move/eqP => X; subst hd.
rewrite /= in_cons eqxx /=.
f_equal.
eapply trans_eq; last by apply filter_pred0.
apply eq_in_filter => x Hx.
rewrite /= in_cons in_nil orbC /=.
apply/eqP => X; subst x.
by rewrite Hx in Hk1.
- move=> Hn.
rewrite /= in_cons in_nil orbC /=.
have X : hd != n.
apply/eqP => X; subst n.
by rewrite Hn in Hk1.
rewrite (negbTE X).
by apply IH.
Qed.
Lemma subset_nil {l : seq A} : {subset nil <= l}. Proof. done. Qed.
Lemma subset_cat (l : seq A) l2 (Hl2 : {subset l2 <= l}):
forall l1, {subset l1 <= l} -> {subset (l1 ++ l2) <= l}.
Proof.
elim => //=.
move => hd tl Hind Hsubset.
move => x Hx.
rewrite in_cons in Hx; move/orP in Hx; inversion_clear Hx.
- apply Hsubset.
rewrite in_cons; apply/orP; left; done.
- apply Hind => //=.
move => y Hy; apply Hsubset.
rewrite in_cons; apply/orP; right; done.
Qed.
Lemma subset_undup : forall (l : seq A), {subset (undup l) <= l}.
Proof.
elim => //=.
move => hd tl Hind.
case: (hd \in tl); intuition.
by move => x Hx; rewrite in_cons; apply/orP; right; apply Hind.
move => x Hx; rewrite in_cons in Hx; move/orP in Hx; rewrite in_cons; apply/orP; inversion_clear Hx; try auto.
Qed.
Lemma notin_unzip1_notin {B : eqType} (x : A) (y : B): forall l,
x \notin unzip1 l -> (x, y) \notin l.
Proof.
move=> l.
apply contra => H.
apply/mapP.
by exists (x, y).
Qed.
Lemma uniq_in_eq {B:eqType} {x} {y1} {y2}: forall (l: seq (A * B)),
uniq (unzip1 l) -> (x, y1) \in l -> (x, y2) \in l -> y1 = y2.
Proof.
elim => //=.
move => [] hd1 hd2 //= tl Hind /andP [] Hnotin Huniq; rewrite !in_cons => /orP Hin1 /orP Hin2.
inversion_clear Hin1; inversion_clear Hin2.
- by move/eqP in H; move/eqP in H0; case: H; case: H0 => *; subst.
- move/eqP in H; case: H => *; subst.
have Hin: hd1 \in unzip1 tl.
+ apply/mapP; exists (hd1, y2); done.
rewrite Hin in Hnotin; done.
- move/eqP in H0; case: H0 => *; subst.
have Hin: hd1 \in unzip1 tl.
+ apply/mapP; exists (hd1, y1); done.
rewrite Hin in Hnotin; done.
- intuition.
Qed.
Lemma uniq_subset_notin {B: eqType} {x} {y} {l: seq (A * B)} (Hl: uniq (unzip1 l)):
forall l',
{subset l' <= l} ->
(x, y) \notin l' ->
(x, y) \in l ->
x \notin unzip1 l'.
Proof.
elim => //=.
move => [] hd1 hd2 //= tl Hind Hsubset Hnotin Hin.
have: (hd1, hd2) \in l /\ {subset tl <= l} by split; [ apply Hsubset; rewrite in_cons; apply/orP; left; done | move => z Hz; apply Hsubset; rewrite in_cons; apply/orP; right; done].
clear Hsubset.
move => [] H Hsubset.
apply/negP => Hin2.
have: (x, y) != (hd1, hd2) /\ (x, y) \notin tl.
- rewrite in_cons negb_or in Hnotin.
move/andP in Hnotin; done.
clear Hnotin; move => [] Hneq Hnotin.
rewrite in_cons in Hin2; move/orP in Hin2; inversion_clear Hin2; last first.
move: (Hind Hsubset Hnotin Hin).
rewrite H0; done.
clear Hind.
move/eqP in H0; subst.
have: y <> hd2.
- move => Heq; rewrite Heq in Hneq; move/eqP in Hneq; tauto.
clear Hneq; move => Hneq.
move: (uniq_in_eq Hl H Hin) => Heq.
by subst.
Qed.
Lemma undup_subset (l: seq A): forall l', {subset l' <= l} -> {subset (undup l') <= l}.
Proof.
elim => //=.
move => hd tl Hind Hsubset.
have Hsubset_tl: {subset tl <= l} by move => x Hx; apply Hsubset; apply/orP; right.
case: (hd \in tl); intuition.
move => x Hx; apply Hsubset.
rewrite in_cons in Hx; move/orP in Hx.
rewrite in_cons; apply/orP.
inversion_clear Hx; try tauto.
right; apply subset_undup; done.
Qed.
Lemma nseq_count :
forall n (a e: A), count (pred1 a) (nseq n e) = n * (a == e).
Proof.
elim; [done | ]; move => n IH a e; simpl.
rewrite mulSn -IH; f_equal.
case_eq (a == e).
- move/idP/eqP; move => ->; f_equal; apply/eqP; reflexivity.
- move/idP => H; f_equal; apply: negbTE; apply/eqP; move => E; subst.
apply: H; apply/eqP; reflexivity.
Qed.
Lemma uniq_belast : forall (l : seq A) e,
uniq (e :: l) -> uniq (belast e l).
Proof.
elim/last_ind => // hd tl _ e.
rewrite belast_rcons /= rcons_uniq mem_rcons in_cons negb_or andbA.
repeat case/andP.
by move=> _ -> _ ->.
Qed.
Lemma memP : forall l (e : A), e \in l ->
exists l1 l2, l = l1 ++ e :: l2 /\ ~ e \in l1.
Proof.
elim => //= hd tl Hind e; rewrite in_cons => Hin.
case/boolP : (e == hd) => [/eqP Heq|/negbTE Hneq].
- subst hd; by exists nil, tl.
- move/orP: Hin => [|Hin]; first by rewrite Hneq.
move: {Hind}(Hind e Hin) => [] l1 [] l2 [] H1 H2.
exists (hd :: l1), l2 => //=; rewrite H1; split => //.
contradict H2.
move: H2; rewrite in_cons => /orP[|//]; by rewrite Hneq.
Qed.
End seq_eqType.
Section flatten_ext.
Variables A B : eqType.
Lemma in_flatten : forall {f: A -> seq B} {x} {y},
y \in f x ->
forall l,
x \in l ->
y \in flatten (map f l).
Proof.
move => f x y Hy.
elim => //=.
move => hd tl Hind.
rewrite inE; move/orP => [] //=.
- by move/eqP => <-; rewrite mem_cat; apply/orP; left.
- move => Hx; rewrite mem_cat; apply/orP; right; apply (Hind Hx).
Qed.
Lemma flatten_in : forall {f: A -> seq B} {x} {l},
x \in flatten (map f l) ->
exists y, x \in f y /\ y \in l.
Proof.
move => f x.
elim => //=.
move => hd tl Hind.
rewrite mem_cat; move/orP => [] //=.
- by move => Hx; exists hd; rewrite inE eq_refl.
- move => Hx; move: {Hind}(Hind Hx) => [] y [] Hy1 Hy2.
exists y; rewrite inE.
split => //=.
by apply/orP; right.
Qed.
Lemma flatten_map: forall {f: A -> B} {l},
flatten (map (map f) l) = map f (flatten l).
Proof.
move => f.
elim => //=.
by move => hd tl; rewrite map_cat => ->.
Qed.
End flatten_ext.
Section inclusion_bool.
Variable A : eqType.
Fixpoint inc (l1 l2 : seq A) :=
if l1 isn't h1 :: t1 then true else if h1 \in l2 then inc t1 l2 else false.
Lemma incP' : forall (l1 l2 : seq A), reflect {subset l1 <= l2} (inc l1 l2).
Proof.
elim => //=.
- by move => l2; apply ReflectT.
- move => hd tl Hind l2.
case: (@idP (hd \in l2)) => Hin.
case: (Hind l2).
+ move => Hsubset; apply ReflectT.
move => x //=; rewrite inE; move /orP => [] //=.
* by move => /eqP ->.
* by move => H; apply Hsubset.
+ move => H.
apply ReflectF.
move => H'; apply H.
move => x Hx.
apply H'.
by rewrite inE; apply /orP; right.
apply ReflectF.
move => Hsubset.
apply Hin.
apply Hsubset.
by rewrite inE; apply /orP; left.
Qed.
Lemma incP (l1 l2 : seq A) : reflect (List.incl l1 l2) (inc l1 l2).
Proof.
apply: (iffP idP).
- move: l1 l2; elim.
+ move=> l2 /= _ x; by inversion 1.
+ move=> h1 t1 IH /= l2.
case: ifP => X //.
move/IH => H x /=.
case=> [h1_x|].
subst x.
by apply/inP.
by apply H.
- move: l1 l2.
elim => // h1 t1 IH l2 /= H.
case: ifP => X.
apply IH => x Hx.
apply H.
rewrite /=; by right.
move: (H h1 (@or_introl _ _ (refl_equal _))).
move/inP.
by rewrite X.
Qed.
Lemma inc_nil_inv : forall (d : seq A), inc d [::] -> d = [::].
Proof. by case. Qed.
Lemma inc_cons_R : forall (h : A) a b, inc a b -> inc a (h :: b).
Proof.
move=> c; elim=> // h t IH b /=.
case: ifP => // h_in_b t_inc_b.
by rewrite in_cons h_in_b orbC /= IH.
Qed.
Lemma inc_refl : forall (k : seq A), inc k k.
Proof. elim=> // h t IH /=; by rewrite in_cons eqxx /= inc_cons_R. Qed.
Lemma inc_app_L : forall (l k : seq A), inc l (l ++ k).
Proof. by elim=> // h t IH k /=; rewrite in_cons eqxx /= inc_cons_R. Qed.
Lemma inc_app_R : forall (l k : seq A), inc l (k ++ l).
Proof. move=> l k. apply/incP' => x Hx; by rewrite mem_cat Hx orbC. Qed.
Lemma inc_trans : forall (l1 : seq A) l2 l3, inc l1 l2 -> inc l2 l3 -> inc l1 l3.
Proof.
elim=> // h t IH l2 l3 /=.
case: ifP => // h_l2 t_l2 l2_l3.
case: ifP.
- move=> h_l3; by apply IH with l2.
- move=> <-.
move/incP' : l2_l3 => l2_l3; exact/l2_l3.
Qed.
Lemma inc_cons_L : forall (x : A) l1 l2, inc (x :: l1) l2 = inc l1 l2 && (x \in l2).
Proof.
move=> x l1 l2; apply/idP/idP => /=.
- by case: ifP => // x_l2 ->.
- by case/andP => /= -> x_l2; case: ifP => // <-.
Qed.
Lemma inc_cons_R_inv : forall l1 (a : A) l2, a \notin l1 -> inc l1 (a :: l2) -> inc l1 l2.
Proof.
elim.
- by move=> a l1 _ _.
- move=> hd tl IH a l2.
rewrite in_cons negb_or; case/andP => H1 H2.
rewrite inc_cons_L.
case/andP => H.
rewrite in_cons.
case/orP => H'.
+ by rewrite eq_sym H' in H1.
+ by rewrite inc_cons_L (IH a).
Qed.
Lemma inc_cons_inv : forall (h : A) t1 t2,
h \notin t1 -> h \notin t2 -> inc (h :: t1) (h :: t2) -> inc t1 t2.
Proof.
move=> k t1 t2 Ht1 Ht2.
rewrite /= in_cons eqxx /=.
by apply inc_cons_R_inv.
Qed.
Lemma inc_filter : forall (l1:seq A) l2, inc l1 l2 -> forall f, inc (filter f l1) (filter f l2).
Proof.
elim => // h t IH l2; rewrite inc_cons_L; case/andP => H1 H2 f /=.
case: ifP => /= f_h.
- case: ifP => [h_l2|<-].
+ by apply IH.
+ move: (mem_filter f h l2); by rewrite f_h H2.
- by apply IH.
Qed.
Lemma inc_filter_L : forall (l1 l2 : seq A),
inc l1 l2 -> forall f : pred A, inc (filter f l1) l2.
Proof.
elim=> // h t IH l2 /=.
case: ifP => // h_in_l2 t_inc_l2 f.
case: ifP => [/= | ].
by rewrite h_in_l2 IH.
by rewrite IH.
Qed.
Lemma inc_seq_filter_imp : forall (k : seq A) (p p': pred A),
(forall x, x \in k -> p x -> p' x ) -> inc (filter p k) (filter p' k).
Proof.
elim => // hd tl IH p p' Himp /=.
case: ifP => X.
+ rewrite /=.
have Y : p' hd.
apply Himp => //.
by rewrite in_cons eqxx.
rewrite Y /= in_cons eqxx /=.
apply inc_cons_R.
apply IH => x Hx.
apply Himp.
by rewrite in_cons Hx orbC.
+ case: ifP => Y.
* apply inc_cons_R, IH.
move=> x Hx Hp; apply Himp => //.
by rewrite in_cons Hx orbC.
* apply IH => //.
move=> x Hx Hp; apply Himp => //.
by rewrite in_cons Hx orbC.
Qed.
End inclusion_bool.
Lemma inc_map_fst (A B : eqType) (l1 l2 : seq (A * B)) :
inc l1 l2 -> inc (map (fun x => fst x) l1) (map (fun x => fst x) l2).
Proof.
move/incP' => H.
apply/incP' => x /mapP[y Hy Hxy].
move/H in Hy.
apply/mapP; by exists y.
Qed.
Lemma inc_iota : forall b b', (b <= b')%nat ->
forall a, inc (iota a b) (iota a b').
Proof.
elim=> // b IH [|b'] //= Hb' a.
rewrite in_cons eqxx /=; by apply inc_cons_R, IH.
Qed.
Lemma incl_iota : forall a n b m, (b <= a)%coq_nat -> (n + (a - b) <= m)%coq_nat ->
List.incl (iota a n) (iota b m).
Proof.
move=> a n b m b_a n_m c /inP; rewrite mem_iota => H.
apply/inP; rewrite mem_iota; apply/andP; split; ssromega.
Qed.
Section disjointness_bool.
Variable A : eqType.
Implicit Type l : seq A.
Fixpoint dis l1 l2 :=
match l1 with
| h :: t => if h \in l2 then false else dis t l2
| nil => true
end.
Lemma disP : forall l1 l2, reflect (disj l1 l2) (dis l1 l2).
Proof.
elim=> /= [l2|h t IH l2].
- by apply ReflectT, disj_nil_L.
- apply: (iffP idP) => [|H].
+ case: ifP => // h_l2 t_l2.
apply disj_cons_L; by [apply/IH | apply/inP; rewrite h_l2].
+ case/(@disj_cons_inv A) : H; move/IH => H.
by move/inP /negbTE=> ->.
Qed.
Lemma dis_inc_L l k : dis l k -> forall l', inc l' l -> dis l' k.
Proof. by move/disP => ? l' /incP ?; apply/disP/tac_disj_incl_L; eauto. Qed.
Lemma dis_inc_R l k : dis l k -> forall k', inc k' k -> dis l k'.
Proof. by move/disP => ? l' /incP ?; apply/disP/tac_disj_incl_R; eauto. Qed.
Lemma dis_inc (l k' k : seq A) : dis l k' -> inc k k' -> dis l k.
Proof. by move=> lk' kk'; apply: dis_inc_R; eauto. Qed.
Lemma dis_cons : forall l' l (x : A), dis (x :: l) l' = dis l l' && ~~ (x \in l').
Proof. move=> l' l x /=; case: ifP=> _; by rewrite andbC. Qed.
Lemma dis_filter : forall l1 l2, dis l1 l2 -> forall f, dis (filter f l1) l2.
Proof.
elim=> // h t IH l2 /=.
case: ifP => // h_l2 t_l2 f.
case: ifP => /=; by rewrite ?h_l2 IH.
Qed.
Lemma dis_filter_split : forall (p q : pred A) l l',
(forall b, (p b -> ~~ q b) /\ (q b -> ~~ p b)) ->
dis (filter p l) (filter q l').
Proof.
move=> p q; elim => // hd tl IH l' H; apply/disP; split=> /=.
- case: ifP => p_hd.
+ have q_hd : ~~ q hd by move: (proj1 (H _) p_hd).
rewrite /=; case=> [hd_x|].
* apply/inP; by rewrite mem_filter negb_and -hd_x q_hd.
* move/negP : q_hd => q_hd Hx.
contradict q_hd.
move/(IH l')/disP : H.
move/(_ x); tauto.
+ case/boolP : (q hd) => [q_hd Z | ? ?];
move/(IH l')/disP : H; move/(_ x); tauto.
- case: ifP => p_hd Hx.
+ apply/inP.
rewrite /= in_cons negb_or.
move/(IH l')/disP : (H) => {IH}.
move/(_ x)/proj2/(_ Hx)/inP => ->.
rewrite andbC /=.
apply/eqP => ?; subst.
have q_hd : ~~ q hd by move: (proj1 (H _) p_hd).
move/inP : Hx.
by rewrite mem_filter (negbTE q_hd).
+ move/(IH l')/disP : H.
by move/(_ x)/proj2/(_ Hx).
Qed.
Lemma dis_sym l l' : dis l l' = dis l' l.
Proof. apply/disP/disP; by move/disj_sym. Qed.
Lemma dis_filter_right l1 l2 : dis l1 (filter (fun x => ~~ (x \in l1)) l2).
Proof.
elim: l2 l1 => /= [l1|h t IH l1].
- by rewrite dis_sym.
- move: (IH l1) => IH'.
case: ifP => //= h_l1.
by rewrite dis_sym /= (negbTE h_l1) dis_sym.
Qed.
Lemma dis_not_in : forall l l' (x : A), x \in l -> dis l l' -> ~~ (x \in l').
Proof.
elim=> // h t IH l' x.
rewrite in_cons.
case/orP => Hx /=.
- move/eqP : Hx => ?; subst h; by case: ifP.
- case: ifP => // h_l' t_l'; by apply IH.
Qed.
Lemma dis_nil_R l : dis l [::]. Proof. by rewrite dis_sym. Qed.
Lemma dis_singl x y : x != y = dis [:: x] [:: y].
Proof. by rewrite /= in_cons in_nil orbC. Qed.
End disjointness_bool.
Lemma dis_seq_singl x n l : x < n -> dis (iota n l) (x :: nil).
Proof.
move=> x_n; apply/disP => x1; split => /=.
move/inP; rewrite mem_iota => ?; ssromega.
case=> // ?; subst x1.
move/inP; rewrite mem_iota => ?; ssromega.
Qed.
Lemma dis_seq_singl2 x n l : n + l <= x -> dis (iota n l) (x :: nil).
Proof.
move=> Hxn; apply/disP => y; split => [/inP /= H1|/=].
rewrite mem_iota in H1; ssromega.
case=> // ?; subst y.
move/inP; rewrite mem_iota => ?; ssromega.
Qed.
Lemma disj_iota_iota a l b k : a + l <= b -> dis (iota a l) (iota b k).
Proof.
move=> H; apply/disP => x1; split => /inP;
rewrite mem_iota => ? /inP; rewrite mem_iota => ?; ssromega.
Qed.
Lemma dis_iota a a' b c : a + b <= a' -> dis (iota a b) (iota a' c).
Proof.
move=> b'b.
apply/disP => x; split.
move/inP.
rewrite mem_iota => Hx.
move/inP.
rewrite mem_iota => ?; by ssromega.
move/inP.
rewrite mem_iota => Hx.
move/inP.
rewrite mem_iota => ?; by ssromega.
Qed.
Ltac dis_iota_tac :=
match goal with
| |- is_true (dis (iota ?a ?b) (?c :: nil)) =>
apply dis_seq_singl; ssromega
| |- is_true (dis (iota ?a ?b) (?c :: nil)) =>
apply dis_seq_singl2; ssromega
| |- is_true (dis (?c :: nil) (iota ?a ?b)) =>
rewrite dis_sym; apply dis_seq_singl; ssromega
| |- is_true (dis (?c :: nil) (iota ?a ?b)) =>
rewrite dis_sym; apply dis_seq_singl2; ssromega
| |- is_true (dis (iota ?a ?b) (iota ?c ?d)) =>
apply disj_iota_iota; ssromega
| |- is_true (dis (?a :: nil) (?b :: nil)) =>
apply dis_singl; ssromega
end.
Section OCamlFind.
Variable A : eqType.
Variable a : pred A.
Fixpoint ocamlfind s := if s is x :: s' then if a x then Some x else ocamlfind s' else None.
Lemma ocamlfind_cons hd tl : a hd -> ocamlfind (hd :: tl) = Some hd.
Proof. move=> H; by rewrite /ocamlfind H. Qed.
Lemma ocamlfind_cons' hd tl : ~ a hd -> ocamlfind (hd :: tl) = ocamlfind tl.
Proof. move/negP => H; by rewrite {1}/ocamlfind -/(ocamlfind tl) (negbTE H). Qed.
Lemma ocamlfind_cons'' hd tl r : ocamlfind (hd :: tl) = Some r -> a hd \/ ocamlfind tl = Some r.
Proof.
rewrite /ocamlfind -/(ocamlfind tl).
case: ifP => X; by auto.
Qed.
Lemma ocamlfind_Some_mem : forall k r, ocamlfind k = Some r -> a r /\ r \in k.
Proof.
elim=> [|hd tl IH] // r.
rewrite {1}/ocamlfind -/(ocamlfind tl).
case: ifP => X.
- case=> Y; subst.
rewrite !in_cons /= eq_refl //=.
- move=> H /=.
apply IH in H.
case:H => H1 H2.
rewrite !in_cons orbC // H2; auto.
Qed.
End OCamlFind.
Fixpoint delete1 {A : eqType} (l : seq A) e : seq A :=
match l with
| nil => nil
| hd::tl =>
if e == hd then tl else hd :: delete1 tl e
end.
Section association_list.
Fixpoint assoc_get {A : eqType} {B : Type} (a : A) (l : seq (A * B)) : option B :=
match l with
| nil => None
| h :: t => if h.1 == a then Some h.2 else assoc_get a t
end.
Lemma assoc_get_in {A B : eqType} : forall (l : seq (A * B)) (a : A) b,
assoc_get a l = Some b -> (a, b) \in l.
Proof.
elim => //=; case=> hd1 hd2 tl Hind /= a b.
case: ifP.
- move/eqP => -> [] ->; rewrite inE => //=; apply/orP; left; apply (eq_refl _).
- by move => _ Hassoc; rewrite inE; apply/orP; right; apply Hind.
Qed.
Lemma in_assoc_get {A B : eqType} : forall (l : seq (A * B)) (a : A) b,
uniq (unzip1 l) ->
(a, b) \in l ->
assoc_get a l = Some b.
Proof.
elim=> // h t IH a b /= /andP[] ht ut.
rewrite in_cons.
case/orP => [/eqP ? | abt].
subst h => /=; by rewrite eqxx.
case: ifP => [/eqP ? | h1a].
exfalso.
subst a.
move/negP : ht; apply.
apply/mapP; by exists (h.1, b).
exact: IH.
Qed.
Lemma assoc_get_subset_in {A B : eqType} (l: seq (A * B)) : forall
(Hl: uniq (unzip1 l)) (l': seq (A * B)) (Hl': {subset l' <= l}) (a: A) (b: B),
(a, b) \in l' ->
assoc_get a l = Some b.
Proof.
move=> Hl l' l'l a b abl'.
apply in_assoc_get => //.
exact: l'l.
Qed.
Lemma assoc_get_delete_neq {A B : eqType} : forall (l : seq (A * B)) a x,
a <> x -> forall y, assoc_get a (filter (predC (pred1 (x, y))) l) = assoc_get a l.
Proof.
elim => //=; case=> h1 h2 t IH a x ax y /=.
case: ifPn => [H1|] /=.
case: ifP => [_ // | H2].
by rewrite IH.
rewrite negbK => /eqP[? ?]; subst x y.
rewrite eq_sym; move/eqP/negbTE : (ax) => ->.
by rewrite IH.
Qed.
Lemma assoc_get_subset {A B : eqType} (l : seq (A * B)) :
forall (Hl : uniq (unzip1 l)) (l' : seq (A * B)) (Hl': {subset l' <= l}) (a : A) (b : B),
assoc_get a l' = Some b ->
assoc_get a l = Some b.
Proof.
move=> Huniq l' Hsubset a b Hassoc.
apply assoc_get_subset_in with l' => //=.
exact: (assoc_get_in Hassoc).
Qed.
Fixpoint assoc_upd {A : eqType} {B : Type} (a : A) (b : B) (l : seq (A * B)) : seq (A * B) :=
match l with
| nil => nil
| hd :: tl => if hd.1 == a then (a, b) :: tl else hd :: assoc_upd a b tl
end.
Lemma assoc_get_upd_eq {A : eqType} {B} : forall (l : seq (A * B)) a b c,
assoc_get a l = Some c ->
assoc_get a (assoc_upd a b l) = Some b.
Proof.
elim => //=.
move => [] hd1 hd2 //= tl Hind a b c H.
case: (hd1 =P a) => H' //=.
- by rewrite eq_refl.
- case: (hd1 =P a) H => H'' //=.
apply Hind.
Qed.
Lemma assoc_get_upd_neq {A : eqType} {B : Type} :
forall (l : seq (A * B)) (a b : A) (c : B),
a <> b -> assoc_get a (assoc_upd b c l) = assoc_get a l.
Proof.
elim=> // h t IH a b c ab /=.
case: ifP => [|Hif].
- move/eqP => ? /=; subst b.
move/eqP in ab.
by rewrite eqtype.eq_sym (negbTE ab).
- case: ifP => [/= -> // |/= ->]; by apply IH.
Qed.
Lemma assoc_get_upd_neq_inv {A : eqType} {B} : forall (l : seq (A*B)) a b c d,
assoc_get a (assoc_upd b c l) = Some d ->
a <> b ->
assoc_get a l = Some d.
Proof.
elim=> // h t IH a b c d /=.
case: ifP => [|Hif].
- move/eqP => <- /= H.
move/eqP.
rewrite eqtype.eq_sym.
move/negbTE => X; by rewrite X in H *.
- move=> /=.
case: ifP => // Hif2.
exact: IH.
Qed.
Lemma assoc_upd_inv {A : eqType} {B : Type} (a : A) :
forall (l : seq (A * B)) b,
assoc_get a l = Some b ->
assoc_upd a b l = l.
Proof.
elim =>//=.
move => [] hd1 hd2 //= tl Hind b.
case: (hd1 =P a) => //=.
- by move => ?; case => ?; subst.
- move => _ H; by rewrite Hind.
Qed.
End association_list.
Section slice.
Definition slice {A : Type} (l : seq A) (a n : nat) := take n (drop a l).
Local Notation "l |{ a , n )" := (slice l a n).
Lemma slice_shift {A} : forall d (l1 l2 : seq A) i1 i2 sz sz',
l1 |{ i1, sz ) = l2 |{ i2, sz) ->
d + sz' < sz ->
l1 |{ i1 + d, sz') = l2 |{ i2 + d, sz').
Proof.
move=> d l1 l2 i1 i2 sz sz' H H0.
rewrite /slice -!drop_drop (drop_dropC i1 d) (drop_dropC i2 d) take_drop (take_drop _ d sz').
congr drop.
by apply take_lt with sz.
Qed.
Lemma size_slice_leq {A : Type} : forall (l : seq A) b a, size (l |{ a , b)) <= b.
Proof.
move=> l b a; rewrite /slice size_take size_drop ltn_subRL.
case: ifP => // /negbT; by rewrite -leqNgt -leq_subLR.
Qed.
Lemma size_slice_exact {A : Type} : forall (l : seq A) (b a : nat),
a + b <= size l -> size (l |{ a, b)) = b.
Proof.
elim.
by case=> //= n [].
move=> h t IH b [|a] /=.
- rewrite add0n leq_eqVlt.
case/orP.
move/eqP => ->.
by rewrite /slice /= size_take ltnn.
by rewrite /slice drop0 size_take /= => ->.
- rewrite addSn => H.
by rewrite /slice /= IH.
Qed.
Lemma slice_app {A : Type} : forall (l : seq A) a b c,
l |{ a, b + c ) = l |{ a, b) ++ l |{ a + b, c).
Proof.
elim=> // h t IH [|a] b c.
- rewrite /slice drop0 take_drop.
rewrite (_ : take b (h :: t) = take b (take (b + c) (h :: t))); last by rewrite take_take.
by rewrite cat_take_drop.
- move=> /=.
exact: IH.
Qed.
Lemma nth_slice {A} (l : seq A) start sz i def (_ : i < sz) :
nth def (slice l start sz) i = nth def l (start + i).
Proof. by rewrite /slice take_drop nth_drop nth_take // ltn_add2l. Qed.
Lemma nth_slices {A} start' sz' (l l' : seq A) start sz i def:
start <= i < start + sz ->
0 < sz <= sz' ->
slice l start sz = slice l' start' sz' ->
nth def l i = nth def l' (start' + (i - start)).
Proof.
move=> /andP Hi /andP Hsz Hl.
have Harith1 : i - start < sz by rewrite ltn_sub_add; tauto.
rewrite {1}(_ : i = start + (i - start)); last by rewrite subnKC //; tauto.
rewrite -(@nth_slice _ _ _ sz _ _) // Hl (@nth_slice _ _ _ sz' _ _) //.
eapply (ltn_leq_trans sz); tauto.
Qed.
Lemma slices_sem {A} (l : seq A) i sz : l = take i l ++ slice l i sz ++ drop (i+sz) l.
Proof. by rewrite /slice take_drop -{1}(take_take _ _ sz) catA !cat_take_drop. Qed.
End slice.
Notation "l |{ a , n )" := (slice l a n) : seq_ext_scope.
Definition map_indices {A : Type} (def : A) (l : seq A) (indices : seq nat) : seq A :=
map (nth def l) indices.
Lemma map_indices_iota {A : Type} {def : A} : forall sz i (l : seq A),
i + sz <= size l ->
map_indices def l (iota i sz) = take sz (drop i l).
Proof.
rewrite /map_indices.
elim => //=.
- move => i l _.
by rewrite take0.
- move => n Hind i l.
destruct i => //=.
+ destruct l => //=.
move => Hlt; rewrite Hind //=; rewrite drop0 //=.
+ destruct l => //=.
move => Hlt; rewrite Hind //=; last by move: Hlt; nat_norm.
rewrite (@drop_nth _ def i l) => //=.
ssromega.
Qed.
Lemma map_indices_self {A : Type} {def : A} (l : seq A) :
map_indices def l (iota O (size l)) = l.
Proof.
rewrite map_indices_iota.
by rewrite drop0 take_size.
by rewrite add0n.
Qed.
Lemma seq_forall_exists :
forall {T : eqType} (P : T -> nat -> Prop),
(forall y i a, P y i -> P y (i + a)) ->
forall (Y : seq T),
(forall y, y \in Y -> exists i : nat, P y i) ->
exists i : nat, forall y, y \in Y -> P y i.
Proof.
move => T P closed.
elim => [ | y0 Y]; [ move => _; exists 0 => y; done | ].
move => IH H; move: (H y0).
rewrite in_cons eq_refl.
case; [ done | ].
move => i0 Pyi0.
have IH' : exists i : nat, forall y : T, y \in Y -> P y i.
- apply: IH => y I; apply: H.
rewrite in_cons; apply/orP; right; assumption.
move: IH => _; case: IH' => i1 IH; exists (maxn i0 i1).
move => y; rewrite in_cons; case/orP.
- move/eqP => I; subst;
have -> : maxn i0 i1 = i0 + (maxn i0 i1 - i0)
by rewrite subnKC; [done | ]; exact: leq_maxl.
apply: closed; assumption.
- move => I.
have -> : maxn i0 i1 = i1 + (maxn i0 i1 - i1)
by rewrite subnKC; [done | ]; exact: leq_maxr.
apply: closed; apply: IH; assumption.
Qed.
Section repeated_take.
Variable A : Type.
Fixpoint takes' (k : nat) (n : nat) (l : seq A) {struct n} : list (seq A) :=
match n with
| O => nil
| S m => take k l :: takes' k (m - (k - 1)) (drop k l)
end.
Definition takes (k : nat) (l : seq A) : seq (seq A) :=
match k with
| O => nil
| S _ => takes' k (size l) l
end.
Lemma takes_nil n : takes n (@nil A) = nil. Proof. by case: n. Qed.
Lemma takes_skipn : forall n (l : seq A) hd tl,
takes n l = hd :: tl -> takes n (drop n l) = tl.
Proof.
move=> [|n] // [|l1 l2] // [|hd1 hd2] // tl [] ?; subst hd1 => Hhd2.
rewrite /= subSS subn0 /= => <-.
by rewrite size_drop.
Qed.
Lemma len_takes' n : forall (l : seq A), size l = n -> forall k q,
n = q * S k -> size (takes' (S k) n l) = q.
Proof.
induction n using Wf_nat.lt_wf_ind.
destruct n as [|n]; first by case=> // _ k [|q].
case=> hd tl // [Hlen] k [|q] //= n_k; rewrite subSS subn0; f_equal.
apply H.
apply/ltP.
rewrite ltnS.
by rewrite leq_subLR leq_addl.
by rewrite size_drop Hlen.
rewrite mulSn addSn in n_k.
case: n_k => ->.
by rewrite mulnC mulSn addnC addnK.
Qed.
Lemma len_takes n : forall (l : seq A), size l = n -> forall k q,
n = q * S k -> size (takes (S k) l) = q.
Proof.
induction n using Wf_nat.lt_wf_ind.
destruct n as [|n]; first by case=> // _ k [|q].
case=> hd tl // [Hlen] k [|q] //= n_k; rewrite subSS subn0; f_equal.
have /ltP Htmp : n - k < S n by rewrite ltnS leq_subLR leq_addl.
move: (H _ Htmp (drop k tl)).
rewrite size_drop Hlen.
move/(_ (refl_equal _) k q).
rewrite /takes.
rewrite size_drop Hlen.
apply.
case : n_k => ->.
by rewrite plusE addnC addnK.
Qed.
Lemma In_takes' : forall n (l : seq A), size l = n -> forall k q,
(n = q * S k) -> forall x, List.In x (takes (S k) l) -> size x = (S k).
Proof.
move=> n; induction n using Wf_nat.lt_wf_ind.
destruct n as [|n]; first by case=> // _ k [|q].
case=> hd tl // [Hlen] k [|q] // n_k x.
rewrite /=; case.
destruct x as [|hx tx]; first by [].
case=> ? ?; subst hx tx => /=.
f_equal.
rewrite size_take Hlen.
rewrite -ltnS n_k.
rewrite mulSn.
destruct q.
rewrite mul0n addn0 ltnn.
by rewrite mul1n in n_k; case: n_k.
rewrite mulnS (addSn q) addnS.
by rewrite leq_addr.
rewrite subSS subn0.
move=> H1.
have /ltP H2 : ((n - k) < S n).
by rewrite ltnS leq_subLR leq_addl.
have H3 : size (drop k tl) = (n - k) by rewrite size_drop Hlen.
apply (H (n - k) H2 (drop k tl) H3 k q).
rewrite /= in n_k.
case: n_k => ->.
by rewrite plusE addnC addnK.
by rewrite /takes size_drop.
Qed.
Lemma In_takes n (l : seq A) : size l = n -> forall k q,
(n = q * k) -> forall x, List.In x (takes k l) -> size x = k.
Proof. move=> Hlen [] //; by apply In_takes'. Qed.
Lemma takes_app : forall t (H : t <> O) (a b : seq A), size a = t ->
takes t (a ++ b) = a :: takes t b.
Proof.
move=> t Ht a b Ha.
destruct t => //= {Ht}.
rewrite (_ : size (a ++ b) = S (t + size b)); last by rewrite size_cat /= Ha /=.
destruct a as [|ha ta] => //.
case: Ha => Ha.
by rewrite /= subSS subn0 drop_cat // take_cat // Ha ltnn subnn take0 cats0 addnC addnK drop0.
Qed.
End repeated_take.
Lemma takes_inj {A : Type} : forall n k nk (l1 l2 : seq A), k <> O ->
nk = (k * n)%nat -> size l1 = nk -> size l2 = nk ->
takes k l1 = takes k l2 -> l1 = l2.
Proof.
elim.
move=> k nk l1 l2 Hk.
rewrite muln0 => ->.
destruct l1 => //.
by destruct l2.
move=> n IH k nk l1 l2 Hk Hnk Hl1 Hl2 H.
rewrite -addn1 mulnDr muln1 in Hnk.
rewrite -(cat_take_drop k l1) -(cat_take_drop k l2).
rewrite -(cat_take_drop k l1) // -(cat_take_drop k l2) // in H.
rewrite (@takes_app _ k) // in H; last by rewrite size_takel // Hl1 Hnk leq_addl.
rewrite (@takes_app _ k) // in H; last by rewrite size_takel // Hl2 Hnk leq_addl.
case: H => H1 H2.
f_equal => //.
apply (IH k (k * n)%nat) => //.
by rewrite size_drop // Hl1 Hnk addnK.
by rewrite size_drop // Hl2 Hnk addnK.
Qed.
Definition injection {A B : Type} (f : A -> B) :=
forall x y, f x = f y -> x = y.
Lemma map_inj (A B : Type) : forall (f : list A -> B), injection f ->
forall n (a b : list (list A)) ,
size a = n -> size b = n ->
map f a = map f b -> a = b.
Proof.
move=> f Hf.
elim => [ | n IH [|ha ta] // [|hb tb] // [Ha] [Hb] /=].
case=> //; by case.
by case => /Hf <- /(IH _ _ Ha Hb) <-.
Qed.
Section flat_map.
Variable A B : Type.
Fixpoint flat_map (f : A -> seq B) l :=
match l with
| [::] => [::]
| x :: t => (f x ++ flat_map f t)
end.
Implicit Type l : seq A.
Implicit Type k : seq B.
Lemma len_flat_map : forall n l m (f : A -> seq B),
(forall a, size (f a) = m) -> size l = n ->
size (flat_map f l) = n * m.
Proof.
elim=> [[]// |n IHn [|h t] // k f f_k [len_t] /=].
by rewrite size_cat (IHn _ k) // f_k.
Qed.
Lemma len_flat_map_inv : forall l q m (f : A -> seq B),
size (flat_map f l) = q * m ->
(forall a, size (f a) = m) ->
m <> O ->
size l = q.
Proof.
elim=> /=.
move=> q k f /esym/eqP.
rewrite muln_eq0.
by case/orP => /eqP -> //.
move=> hd tl IH [|q] k f Hlen H Hk.
rewrite size_cat H /= mul0n in Hlen.
move/eqP in Hlen.
rewrite addn_eq0 in Hlen.
case/andP : Hlen => /eqP Hlen _.
by rewrite Hlen in Hk.
f_equal.
apply IH with k f => //.
rewrite /= size_cat /= H mulSn in Hlen.
move/eqP : Hlen.
by rewrite eqn_add2l => /eqP.
Qed.
Lemma flat_map_inj : forall (f : A -> seq B), injection f ->
(exists k: nat, k <> O /\ forall a, size (f a) = k) ->
forall l1 l2, flat_map f l1 = flat_map f l2 -> l1 = l2.
Proof.
move=> f f_inj [k [Hk Hf]].
elim=> /=.
- case=> //= h2 t2 abs.
suff : False by done.
move: (Hf h2) => abs'.
destruct (f h2) => //.
by subst k.
- move=> h1 t1 IH [|h2 t2] /=.
move: (Hf h1).
destruct (f h1) => //.
move=> ?; by subst k.
move=> H.
apply cat_inv in H; last by rewrite Hf.
rewrite (IH t2); last by tauto.
f_equal.
apply f_inj; tauto.
Qed.
End flat_map.
Fixpoint upd_nth {A : Type} (l : seq A) (n : nat) (v : A) {struct l} : seq A :=
match l with
| nil => nil
| hd :: tl => match n with
| O => v :: tl
| S n' => hd :: upd_nth tl n' v
end
end.
Lemma size_upd_nth {A : Type} : forall n (l : seq A) k (v : A),
size l = n -> size (upd_nth l k v) = n.
Proof. elim => [ [] // | n IHn [|hd tl] // [|k] // v [H] /= ]; by rewrite IHn. Qed.
Lemma upd_nth_cat {A : Type} : forall n l (a : A), size l <= n ->
forall l', upd_nth (l ++ l') n a = l ++ upd_nth l' (n - size l) a.
Proof. elim=> [ [] // | n H [ // |h t]] v H0 l'; by rewrite /= H. Qed.
Lemma upd_nth_cat' (A: Type) : forall n l (a : A), n < size l ->
forall l', upd_nth (l ++ l') n a = (upd_nth l n a) ++ l'.
Proof.
Proof. elim=> [ [] // | n H [ // |h t]] v H0 l'; by rewrite /= H. Qed.
Lemma nth_upd_nth {A : Type} : forall n (a : A) l def,
n < size l -> nth def (upd_nth l n a) n = a.
Proof. elim => [m [|] // | n H m [ // |h t] def_val H0 /=]; by rewrite H. Qed.
Lemma nth_upd_nth' {A : Type} : forall l n n' (a : A) def, n <> n' ->
nth def (upd_nth l n' a) n = nth def l n.
Proof. elim=> [ // |h t IH] [|n] [|n'] m def_val /= H //; rewrite IH // => nn'; by subst. Qed.
Lemma drop_upd_nth {A : Type} : forall l n (a : A) m, (n < m)%nat ->
drop m (upd_nth l n a) = drop m l.
Proof. elim => //= h t IH [|n] /= e [|m] //=; rewrite ltnS => nm; by rewrite IH. Qed.
Lemma take_upd_nth {A:Type} : forall lst n (m:A),
take n (upd_nth lst n m) = take n lst.
Proof. elim => // hd tl IH [|n0] //= m. by rewrite IH. Qed.
Section index_deletion.
Variable A : Type.
Fixpoint idel (n : nat) (l : seq A) {struct l} : seq A :=
if l isn't hd :: tl then nil else
(if n isn't S n' then tl else hd :: idel n' tl).
Lemma size_idel : forall (s : seq A) n, n < size s ->
size (idel n s) = size s - 1.
Proof.
elim => // a l IH [|n] /=.
- by rewrite subn1.
- rewrite ltnS => H0; rewrite IH // -subSn //; exact: leq_ltn_trans H0.
Qed.
Lemma idel_size_last (s : seq A) (a : A) : idel (size s) (s ++ a :: nil) = s.
Proof. elim: s a => // hd tl IH a /=. by rewrite IH. Qed.
Lemma idel_upd_nth (s : seq A) k m : idel k (upd_nth s k m) = idel k s.
Proof. by elim : s k m => // h t IH [|k] //= m; rewrite IH. Qed.
Lemma idel_app : forall k (l1 : seq A), size l1 = k ->
forall l a l2, l = l1 ++ a :: l2 -> idel k l = l1 ++ l2.
Proof.
elim=> [[] // H l a l2 -> // |].
move=> k IHk [|a0 l1] // [H] [|a1 l] // a l2 [-> Hl] /=; congr cons.
exact: IHk Hl.
Qed.
End index_deletion.
Definition idel_last {A : Type} (l : seq A) : seq A :=
match l with
| nil => nil
| _ => idel (size l - 1) l
end.
Lemma size_idel_last {A : Type} : forall n (l : seq A), size l = n ->
size (idel_last l) = n - 1.
Proof.
case => [ [] // | n [|a l] // [len_l]].
by rewrite /idel_last [_ - _]/= subn1 size_idel //= len_l.
Qed.
Lemma size_idel_last' {A : Type} : forall (lst : seq A),
O < size lst -> size (idel_last lst) = size lst - 1.
Proof. move=> lst H; by rewrite (size_idel_last (refl_equal (size lst))). Qed.
Lemma list_split {A : Type} def n (l : seq A) : size l = n ->
forall j, j < n -> exists l1, size l1 = j /\
exists l2, l = l1 ++ nth def l j :: nil ++ l2.
Proof.
move=> ln j jn.
exists (take j l).
rewrite size_takel; last by rewrite ln ltnW.
split => //.
exists (drop j.+1 l).
rewrite -drop_nth //; last by rewrite ln.
by rewrite cat_take_drop.
Qed.
An append function that removes doubles
Section app_set_function.
Variable A : eqType.
Variable A : eqType.
add an element to a list only if not already include
Fixpoint add_set (a : A) (l : seq A) {struct l} : seq A :=
match l with
| nil => a :: nil
| hd :: tl => if hd == a then l else hd :: add_set a tl
end.
Lemma In_add_set_inv : forall l a b, List.In a (add_set b l) -> a = b \/ List.In a l.
Proof.
elim=> //= [| hd tl IH a b]; first by firstorder.
move Heq : (hd == b) => [] /=.
- case=> Y; by auto.
- case=> Y; auto; move/IH : Y; tauto.
Qed.
Lemma In_add_set_L : forall l a, List.In a (add_set a l).
Proof.
elim=> //= [|hd tl IH a]; first tauto.
move Heq : (hd == a) => [] /=.
- move/eqP : Heq; by auto.
- right; by apply IH.
Qed.
Lemma In_add_set_R : forall l a b, List.In a l -> List.In a (add_set b l).
Proof.
elim=> //= hd tl IH a b; case=> X.
- subst hd.
move Heq : (a == b) => []; rewrite /=; by auto.
- move Heq : (hd == b) => []; rewrite /=; by auto.
Qed.
Lemma incl_add_set k x : List.incl k (add_set x k).
Proof. move=> y Hy. exact: In_add_set_R. Qed.
match l with
| nil => a :: nil
| hd :: tl => if hd == a then l else hd :: add_set a tl
end.
Lemma In_add_set_inv : forall l a b, List.In a (add_set b l) -> a = b \/ List.In a l.
Proof.
elim=> //= [| hd tl IH a b]; first by firstorder.
move Heq : (hd == b) => [] /=.
- case=> Y; by auto.
- case=> Y; auto; move/IH : Y; tauto.
Qed.
Lemma In_add_set_L : forall l a, List.In a (add_set a l).
Proof.
elim=> //= [|hd tl IH a]; first tauto.
move Heq : (hd == a) => [] /=.
- move/eqP : Heq; by auto.
- right; by apply IH.
Qed.
Lemma In_add_set_R : forall l a b, List.In a l -> List.In a (add_set b l).
Proof.
elim=> //= hd tl IH a b; case=> X.
- subst hd.
move Heq : (a == b) => []; rewrite /=; by auto.
- move Heq : (hd == b) => []; rewrite /=; by auto.
Qed.
Lemma incl_add_set k x : List.incl k (add_set x k).
Proof. move=> y Hy. exact: In_add_set_R. Qed.
append two lists using the previous functions
(adding only the elements not already included)
Fixpoint app_set l1 l2 : seq A :=
match l1 with
| nil => l2
| hd :: tl => app_set tl (add_set hd l2)
end.
Lemma in_app_set_or : forall l m a, List.In a (app_set l m) -> List.In a l \/ List.In a m.
Proof.
elim=> //= [| hd tl IH m a H ] ; first by tauto.
case: {IH H}(IH _ _ H); first by firstorder.
case/In_add_set_inv; by firstorder.
Qed.
Lemma in_or_app_set : forall l m a, List.In a l \/ List.In a m -> List.In a (app_set l m).
Proof.
elim=> //=; first tauto.
move=> hd tl IH m a [[-> | H] | H]; apply IH.
- right; exact: In_add_set_L.
- tauto.
- right; exact: In_add_set_R.
Qed.
Lemma disj_app_set l k m : disj (app_set l k) m -> disj l m /\ disj k m.
Proof.
move=> H; split=> x.
- split=> // Hx abs; case: (H x) => H1; apply => //;
apply in_or_app_set; by left.
- split=> // Hx abs; case: (H x) => H1; apply => //;
apply in_or_app_set; by right.
Qed.
Lemma In_app_set_nil l x : List.In x (app_set l nil) -> List.In x l.
Proof. by case/in_app_set_or. Qed.
Lemma disj_app_set_nil l k : disj l k -> disj (app_set l nil) k.
Proof.
move=> H x; split=> //.
move/In_app_set_nil => H1 abs; move: (H x); tauto.
move=> Hx abs.
apply (proj2 (H x)) => //.
by move/In_app_set_nil : abs.
Qed.
Lemma incl_app_set_L l1 l2 : List.incl l1 (app_set l1 l2).
Proof. move=> x Hx. apply in_or_app_set; by auto. Qed.
Lemma incl_app_set_R l1 l2 : List.incl l2 (app_set l1 l2).
Proof. move=> x Hx. apply in_or_app_set; by auto. Qed.
Lemma incl_app_set l1 l2 l3 :
List.incl l1 l3 -> List.incl l2 l3 -> List.incl (app_set l1 l2) l3.
Proof.
move=> H12 H13 a Ha.
apply in_app_set_or in Ha.
case: Ha => Ha.
by apply H12.
by apply H13.
Qed.
Lemma NoDup_add_set : forall l a, List.NoDup l -> List.NoDup (add_set a l).
Proof.
elim=> /= [a _ | hd tl IH a Ha].
- apply List.NoDup_cons => //.
by apply List.NoDup_nil.
- case: ifP => // X.
apply List.NoDup_cons; last first.
apply IH.
by inversion Ha.
case/In_add_set_inv => Y.
subst a.
by rewrite eqxx in X.
by inversion_clear Ha.
Qed.
Lemma NoDup_app_set : forall a b, List.NoDup b -> List.NoDup (app_set a b).
Proof.
elim => // hd tl IH b Hb /=; apply IH.
by apply NoDup_add_set.
Qed.
End app_set_function.
Section Permutation_ext.
Variable A : Type.
Implicit Type l : seq A.
Lemma Permutation_notin l l' x : Permutation l l' -> ~ List.In x l -> ~ List.In x l'.
Proof.
move=> H H'; contradict H'. apply Permutation_sym in H. eapply Permutation_in; eauto.
Qed.
Lemma permut_rotate (a : A) l : Permutation (a :: l) (l ++ a :: nil).
Proof.
apply Permutation_cons_app.
rewrite -List.app_nil_end; by apply Permutation_refl.
Qed.
Lemma Permutation_incl_L l1 l2 k : Permutation l1 l2 -> List.incl l1 k -> List.incl l2 k.
Proof.
move=> Hperm Hincl x Hx; apply Hincl.
apply Permutation_in with l2 => //.
by apply Permutation_sym, Hperm.
Qed.
Lemma Permutation_incl_R l1 l2 k : Permutation l1 l2 -> List.incl k l1 -> List.incl k l2.
Proof.
move=> Hperm Hincl x Hx.
apply Permutation_in with l1; by [apply Hperm | apply Hincl].
Qed.
Lemma incl_refl_Permutation l1 l2 : Permutation l1 l2 -> List.incl l1 l2.
Proof. move=> H x Hxl1; by apply Permutation_in with l1. Qed.
Lemma Permutation_app_cons l l' e : Permutation (l ++ (e :: nil) ++ l') (e :: l ++ l').
Proof. exact/Permutation_sym/Permutation_cons_app/Permutation_refl. Qed.
Lemma Permutation_disj_L k l m : Permutation m l -> disj m k -> disj l k.
Proof.
move=> m_l m_k; split=> [x_l x_k | x_k x_l]; apply (m_k x) => //;
apply Permutation_in with l => //; exact: Permutation_sym.
Qed.
Lemma Permutation_disj_R k l m : Permutation m l -> disj k m -> disj k l.
Proof.
move=> m_l k_m.
apply disj_sym.
apply Permutation_disj_L with m => //.
exact: disj_sym.
Qed.
Lemma Permutation_nth def : forall l k, Permutation k (iota O (size l)) ->
Permutation l (map (fun x => nth def l x) k).
Proof.
elim/last_ind=> [k|t h IH k H].
- rewrite [iota _ _]/=.
move/Permutation_sym; move/Permutation_nil=> -> /=.
by apply Permutation_refl.
- rewrite -cats1.
apply Permutation.perm_trans with
(map (fun x => nth def (t ++ h :: nil) x) (iota O (size t) ++ size t :: nil)); last first.
rewrite -cats1 size_cat /= addnC /= in H.
apply Permutation_map; rewrite -/(iota (size t) 1) -iota_add addn1; exact/Permutation_sym.
+ rewrite map_cat /=.
rewrite nth_cat ltnn subnn /=.
apply Permutation_app => //.
have -> : map (fun x => nth def (t ++ h :: nil) x) (iota 0 (size t)) =
map (fun x => nth def t x) (iota 0 (size t)).
apply eq_in_map => x.
rewrite mem_iota add0n => /andP [ _ xt].
by rewrite nth_cat xt.
apply IH; by apply Permutation_refl.
Qed.
Variable B : Type.
Definition Permutation_preserving (f : seq A -> seq B) :=
forall l1 l2 : list A, Permutation l1 l2 ->
Permutation (f l1) (f l2).
End Permutation_ext.
Lemma Permutation_size {A : Type} (l1 l2 : seq A) : Permutation l1 l2 -> size l1 = size l2.
Proof.
elim => //.
by move=> x l l' _ /= ->.
by move=> {}l1 {}l2 l3 _ ->.
Qed.
Lemma Permutation_cons_cat {A : Type} : forall (l : seq A) (x : A),
Permutation (x :: l) (l ++ [:: x]).
Proof.
elim=> // h t IH x /=.
eapply Permutation_trans.
by apply perm_swap.
by apply perm_skip, IH.
Qed.
Lemma Permutation_app_inv_r {A : Type} :
forall l l1 l2 : seq A, Permutation (l1 ++ l) (l2 ++ l) -> Permutation l1 l2.
Proof.
move=> l l1 l2 H.
move: (Permutation_size H).
rewrite !size_cat => /eqP; rewrite eqn_add2r => /eqP Hn.
elim: l l1 l2 H Hn => //.
by move=> ??; rewrite !cats0.
move=> h t IH l1 l2.
rewrite -cat1s !catA => H Hn.
move: (IH _ _ H).
rewrite !size_cat /= Hn => /(_ (refl_equal _)) => K.
apply Permutation_cons_inv with h.
eapply Permutation.perm_trans.
apply Permutation_cons_cat.
eapply Permutation.perm_trans.
apply K.
apply Permutation_sym.
by apply Permutation_cons_cat.
Qed.
Lemma Permutation_seq_inv : forall (l : seq nat) n, size l <> O ->
Permutation l (iota 0 (S n)) ->
exists l1, exists l2, l = l1 ++ (n :: nil) ++ l2 /\ Permutation (l1 ++ l2) (iota O n).
Proof.
case=> // sh st n _ H.
have /inP : List.In n (sh :: st).
apply Permutation_in with (iota O (S n)).
- by apply Permutation_sym.
- rewrite -addn1 iota_add /= add0n.
apply List.in_or_app; right; simpl; by auto.
case/memP => l1 [l2 [Hl1l2 _]].
exists l1, l2; split; first by [].
apply Permutation_app_inv_r with (n :: nil).
rewrite -{2}/(iota n 1) -iota_add.
apply Permutation.perm_trans with (sh :: st) => //.
rewrite Hl1l2 -catA.
apply Permutation_app.
- by apply Permutation_refl.
- by apply Permutation_sym, permut_rotate.
by rewrite addn1.
Qed.
Ltac Permut n :=
match goal with
| |- (Permutation ?X1 ?X1) => apply Permutation_refl
| |- (Permutation (?X1 :: ?X2) (?X1 :: ?X3)) =>
let newn := eval compute in (size X2) in
(apply perm_skip; Permut newn)
| |- (Permutation (?X1 :: ?X2) ?X3) =>
match eval compute in n with
| 1 => fail
| _ =>
let l0' := constr:(X2 ++ X1 :: nil) in
(apply (@Permutation.perm_trans _ (X1 :: X2) l0' X3);
[ apply permut_rotate | compute; Permut (Peano.pred n) ])
end
end.
Ltac PermutProve :=
match goal with
| |- (Permutation ?X1 ?X2) =>
match eval compute in (size X1 = size X2) with
| (?X1 = ?X1) => Permut X1
end
end.
Section fixpoint_permutation.
Variable A : Type.
Variable eq_dec : forall (a1 a2 : A), {a1 = a2} + {a1 <> a2}.
match l1 with
| nil => l2
| hd :: tl => app_set tl (add_set hd l2)
end.
Lemma in_app_set_or : forall l m a, List.In a (app_set l m) -> List.In a l \/ List.In a m.
Proof.
elim=> //= [| hd tl IH m a H ] ; first by tauto.
case: {IH H}(IH _ _ H); first by firstorder.
case/In_add_set_inv; by firstorder.
Qed.
Lemma in_or_app_set : forall l m a, List.In a l \/ List.In a m -> List.In a (app_set l m).
Proof.
elim=> //=; first tauto.
move=> hd tl IH m a [[-> | H] | H]; apply IH.
- right; exact: In_add_set_L.
- tauto.
- right; exact: In_add_set_R.
Qed.
Lemma disj_app_set l k m : disj (app_set l k) m -> disj l m /\ disj k m.
Proof.
move=> H; split=> x.
- split=> // Hx abs; case: (H x) => H1; apply => //;
apply in_or_app_set; by left.
- split=> // Hx abs; case: (H x) => H1; apply => //;
apply in_or_app_set; by right.
Qed.
Lemma In_app_set_nil l x : List.In x (app_set l nil) -> List.In x l.
Proof. by case/in_app_set_or. Qed.
Lemma disj_app_set_nil l k : disj l k -> disj (app_set l nil) k.
Proof.
move=> H x; split=> //.
move/In_app_set_nil => H1 abs; move: (H x); tauto.
move=> Hx abs.
apply (proj2 (H x)) => //.
by move/In_app_set_nil : abs.
Qed.
Lemma incl_app_set_L l1 l2 : List.incl l1 (app_set l1 l2).
Proof. move=> x Hx. apply in_or_app_set; by auto. Qed.
Lemma incl_app_set_R l1 l2 : List.incl l2 (app_set l1 l2).
Proof. move=> x Hx. apply in_or_app_set; by auto. Qed.
Lemma incl_app_set l1 l2 l3 :
List.incl l1 l3 -> List.incl l2 l3 -> List.incl (app_set l1 l2) l3.
Proof.
move=> H12 H13 a Ha.
apply in_app_set_or in Ha.
case: Ha => Ha.
by apply H12.
by apply H13.
Qed.
Lemma NoDup_add_set : forall l a, List.NoDup l -> List.NoDup (add_set a l).
Proof.
elim=> /= [a _ | hd tl IH a Ha].
- apply List.NoDup_cons => //.
by apply List.NoDup_nil.
- case: ifP => // X.
apply List.NoDup_cons; last first.
apply IH.
by inversion Ha.
case/In_add_set_inv => Y.
subst a.
by rewrite eqxx in X.
by inversion_clear Ha.
Qed.
Lemma NoDup_app_set : forall a b, List.NoDup b -> List.NoDup (app_set a b).
Proof.
elim => // hd tl IH b Hb /=; apply IH.
by apply NoDup_add_set.
Qed.
End app_set_function.
Section Permutation_ext.
Variable A : Type.
Implicit Type l : seq A.
Lemma Permutation_notin l l' x : Permutation l l' -> ~ List.In x l -> ~ List.In x l'.
Proof.
move=> H H'; contradict H'. apply Permutation_sym in H. eapply Permutation_in; eauto.
Qed.
Lemma permut_rotate (a : A) l : Permutation (a :: l) (l ++ a :: nil).
Proof.
apply Permutation_cons_app.
rewrite -List.app_nil_end; by apply Permutation_refl.
Qed.
Lemma Permutation_incl_L l1 l2 k : Permutation l1 l2 -> List.incl l1 k -> List.incl l2 k.
Proof.
move=> Hperm Hincl x Hx; apply Hincl.
apply Permutation_in with l2 => //.
by apply Permutation_sym, Hperm.
Qed.
Lemma Permutation_incl_R l1 l2 k : Permutation l1 l2 -> List.incl k l1 -> List.incl k l2.
Proof.
move=> Hperm Hincl x Hx.
apply Permutation_in with l1; by [apply Hperm | apply Hincl].
Qed.
Lemma incl_refl_Permutation l1 l2 : Permutation l1 l2 -> List.incl l1 l2.
Proof. move=> H x Hxl1; by apply Permutation_in with l1. Qed.
Lemma Permutation_app_cons l l' e : Permutation (l ++ (e :: nil) ++ l') (e :: l ++ l').
Proof. exact/Permutation_sym/Permutation_cons_app/Permutation_refl. Qed.
Lemma Permutation_disj_L k l m : Permutation m l -> disj m k -> disj l k.
Proof.
move=> m_l m_k; split=> [x_l x_k | x_k x_l]; apply (m_k x) => //;
apply Permutation_in with l => //; exact: Permutation_sym.
Qed.
Lemma Permutation_disj_R k l m : Permutation m l -> disj k m -> disj k l.
Proof.
move=> m_l k_m.
apply disj_sym.
apply Permutation_disj_L with m => //.
exact: disj_sym.
Qed.
Lemma Permutation_nth def : forall l k, Permutation k (iota O (size l)) ->
Permutation l (map (fun x => nth def l x) k).
Proof.
elim/last_ind=> [k|t h IH k H].
- rewrite [iota _ _]/=.
move/Permutation_sym; move/Permutation_nil=> -> /=.
by apply Permutation_refl.
- rewrite -cats1.
apply Permutation.perm_trans with
(map (fun x => nth def (t ++ h :: nil) x) (iota O (size t) ++ size t :: nil)); last first.
rewrite -cats1 size_cat /= addnC /= in H.
apply Permutation_map; rewrite -/(iota (size t) 1) -iota_add addn1; exact/Permutation_sym.
+ rewrite map_cat /=.
rewrite nth_cat ltnn subnn /=.
apply Permutation_app => //.
have -> : map (fun x => nth def (t ++ h :: nil) x) (iota 0 (size t)) =
map (fun x => nth def t x) (iota 0 (size t)).
apply eq_in_map => x.
rewrite mem_iota add0n => /andP [ _ xt].
by rewrite nth_cat xt.
apply IH; by apply Permutation_refl.
Qed.
Variable B : Type.
Definition Permutation_preserving (f : seq A -> seq B) :=
forall l1 l2 : list A, Permutation l1 l2 ->
Permutation (f l1) (f l2).
End Permutation_ext.
Lemma Permutation_size {A : Type} (l1 l2 : seq A) : Permutation l1 l2 -> size l1 = size l2.
Proof.
elim => //.
by move=> x l l' _ /= ->.
by move=> {}l1 {}l2 l3 _ ->.
Qed.
Lemma Permutation_cons_cat {A : Type} : forall (l : seq A) (x : A),
Permutation (x :: l) (l ++ [:: x]).
Proof.
elim=> // h t IH x /=.
eapply Permutation_trans.
by apply perm_swap.
by apply perm_skip, IH.
Qed.
Lemma Permutation_app_inv_r {A : Type} :
forall l l1 l2 : seq A, Permutation (l1 ++ l) (l2 ++ l) -> Permutation l1 l2.
Proof.
move=> l l1 l2 H.
move: (Permutation_size H).
rewrite !size_cat => /eqP; rewrite eqn_add2r => /eqP Hn.
elim: l l1 l2 H Hn => //.
by move=> ??; rewrite !cats0.
move=> h t IH l1 l2.
rewrite -cat1s !catA => H Hn.
move: (IH _ _ H).
rewrite !size_cat /= Hn => /(_ (refl_equal _)) => K.
apply Permutation_cons_inv with h.
eapply Permutation.perm_trans.
apply Permutation_cons_cat.
eapply Permutation.perm_trans.
apply K.
apply Permutation_sym.
by apply Permutation_cons_cat.
Qed.
Lemma Permutation_seq_inv : forall (l : seq nat) n, size l <> O ->
Permutation l (iota 0 (S n)) ->
exists l1, exists l2, l = l1 ++ (n :: nil) ++ l2 /\ Permutation (l1 ++ l2) (iota O n).
Proof.
case=> // sh st n _ H.
have /inP : List.In n (sh :: st).
apply Permutation_in with (iota O (S n)).
- by apply Permutation_sym.
- rewrite -addn1 iota_add /= add0n.
apply List.in_or_app; right; simpl; by auto.
case/memP => l1 [l2 [Hl1l2 _]].
exists l1, l2; split; first by [].
apply Permutation_app_inv_r with (n :: nil).
rewrite -{2}/(iota n 1) -iota_add.
apply Permutation.perm_trans with (sh :: st) => //.
rewrite Hl1l2 -catA.
apply Permutation_app.
- by apply Permutation_refl.
- by apply Permutation_sym, permut_rotate.
by rewrite addn1.
Qed.
Ltac Permut n :=
match goal with
| |- (Permutation ?X1 ?X1) => apply Permutation_refl
| |- (Permutation (?X1 :: ?X2) (?X1 :: ?X3)) =>
let newn := eval compute in (size X2) in
(apply perm_skip; Permut newn)
| |- (Permutation (?X1 :: ?X2) ?X3) =>
match eval compute in n with
| 1 => fail
| _ =>
let l0' := constr:(X2 ++ X1 :: nil) in
(apply (@Permutation.perm_trans _ (X1 :: X2) l0' X3);
[ apply permut_rotate | compute; Permut (Peano.pred n) ])
end
end.
Ltac PermutProve :=
match goal with
| |- (Permutation ?X1 ?X2) =>
match eval compute in (size X1 = size X2) with
| (?X1 = ?X1) => Permut X1
end
end.
Section fixpoint_permutation.
Variable A : Type.
Variable eq_dec : forall (a1 a2 : A), {a1 = a2} + {a1 <> a2}.
remove only one occurrence of an element (the Coq standard library remove function removes all of them)
Fixpoint remove1 (a : A) l :=
match l with
| nil => nil
| h :: t => if eq_dec a h then t else h :: remove1 a t
end.
Lemma Permutation_remove1 : forall h1 h h2,
Permutation (remove1 h (h1 ++ h :: h2)) (h1 ++ h2).
Proof.
elim=> [h h2 | hd tl IH h h2] /=.
by case: (eq_dec h h) => // X.
case: (eq_dec h hd) => /= X.
- subst h.
rewrite -/((hd :: nil) ++ h2); by apply Permutation_app_cons.
- by apply perm_skip, IH.
Qed.
Fixpoint fpermut (l k : seq A) :=
match (l,k) with
| (nil, nil) => true
| (h :: t, h' :: t') =>
if eq_dec h h' then
fpermut t t'
else if List.In_dec eq_dec h t' then
fpermut t (h' :: remove1 h t')
else
false
| _ => false
end.
Lemma function_permut_Permutation : forall n (l k : seq A),
size l = n -> fpermut l k -> Permutation l k.
Proof.
elim.
- move=> [] // [] // *; by apply Permutation_refl.
- move=> n IH [|h t] // [|h' t'] // [Hlent] /=.
case: (eq_dec h h') => /= X.
+ subst h'.
move/(IH _ _ Hlent).
by apply perm_skip.
+ case: (List.In_dec eq_dec h t') => /= Y // Z.
case/(@InP A) : (Y) => h1' [h2' H'].
rewrite H' List.app_comm_cons.
apply Permutation_cons_app.
move: {IH}(IH _ _ Hlent Z) => IH.
apply Permutation.perm_trans with (h' :: remove1 h t') => //=.
apply perm_skip.
rewrite H'.
by apply Permutation_remove1.
Qed.
End fixpoint_permutation.
Lemma tail_app {A : Type}: forall (lst lst' : seq A), 0 < size lst ->
List.tail (lst ++ lst') = List.tail lst ++ lst'.
Proof. case=> //= l' H; by inversion H. Qed.
Lemma list_tail { A : Type}: forall def (l : seq A), 0 < size l -> nth def l 0 :: List.tail l = l.
Proof. move=> def. case=> //=. Qed.
Section about_substitution.
Variable A : Type.
Lemma sub_substitution : forall n s0 s1, size (s0 ++ (n :: nil) ++ s1) = S n ->
(forall x, List.In x (s0 ++ s1) -> (x < n)) ->
forall (def e : A) l0 l1 k,
size (l0 ++ (e :: nil) ++ l1) = S n ->
size (k ++ e :: nil) = S n ->
size l0 = size s0 ->
(forall i, i < S n ->
nth def (l0 ++ (e :: nil) ++ l1) i = nth def (k ++ e :: nil) (nth 0 (s0 ++ (n :: nil) ++ s1) i)) ->
(forall i, i < n ->
nth def (l0 ++ l1) i = nth def k (nth 0 (s0 ++ s1) i)).
Proof.
move=> n s0 s1 Hs Hx def e l0 l1 k Hl Hk Hlenl0 H i Hin.
have Hlenk : size k = n by rewrite !size_cat /= in Hk; ssromega.
have [Hi | [Hi | Hi]] : i < size s0 \/ i = size s0 \/ size s0 < i.
case: (PeanoNat.Nat.lt_trichotomy i (size s0)) => [|[->|]].
by left; apply/ltP.
by auto.
by right; right; apply/ltP.
- have {}Hin : i < n.+1 by rewrite ltnW.
move: {H}(H _ Hin) => H.
rewrite nth_cat Hlenl0 Hi in H.
rewrite (_ : nth _ _ i = nth 0 s0 i) in H; last first.
by rewrite nth_cat Hi.
rewrite nth_cat // Hlenk Hx in H; last first.
apply List.in_or_app; left; by apply In_nth.
by rewrite nth_cat Hlenl0 Hi nth_cat Hi.
- destruct s1 as [|hs1 ts1]; subst i.
+ have {}Hs : size s0 = n by rewrite size_cat /= in Hs; ssromega.
by rewrite Hs ltnn in Hin.
+ rewrite -ltnS in Hin.
move: {H}(H _ Hin) => H.
rewrite -{1}Hlenl0 nth_cat ltnn subnn nth_cat ltnn subnn.
rewrite nth_cat Hlenl0 (_ : _.+1 < _ = false) // in H; last first.
apply/negbTE; by rewrite -leqNgt.
rewrite subSn // subnn in H.
rewrite nth_cat ltnn subnn in H.
rewrite nth_cat Hlenk Hx in H; last first.
rewrite nth_cat (_ : _ < _ = false); last first.
apply/negbTE.
by rewrite -leqNgt.
rewrite subSn // subnn /=.
apply List.in_or_app; right; left; by auto.
rewrite nth_cat (_ : _ < _ = false) in H; last first.
apply/negbTE.
by rewrite -leqNgt.
by rewrite H subSn // subnn.
- rewrite -ltnS in Hin.
move: {H}(H _ Hin) => H.
rewrite nth_cat in H.
rewrite (_ : _ < _ = false) in H; last first.
apply/negbTE.
rewrite -leqNgt -ltnS.
rewrite Hlenl0.
by apply (@ltn_trans i).
rewrite nth_cat subSn in H; last by rewrite Hlenl0 ltnW.
rewrite ltnS ltn0 subSS subn0 in H.
rewrite catA in H.
rewrite nth_cat ltnNge ltnW //=; last by rewrite Hlenl0.
rewrite H.
rewrite nth_cat Hlenk Hx; last first.
apply List.in_or_app; right.
rewrite nth_cat size_cat addn1 ltnS ltnNge ltnW //= subSS.
apply In_nth.
rewrite size_cat /= addnS in Hs.
case: Hs => Hs.
rewrite -(ltn_add2r (size s0)).
rewrite subnK; last by rewrite ltnW.
by rewrite addnC Hs.
rewrite nth_cat size_cat addn1 ltnS ltnNge ltnW //= subSS.
by rewrite nth_cat ltnNge ltnW //.
Qed.
Lemma substitution_Permutation : forall n s, size s = n ->
Permutation s (iota O n) ->
forall (def : A) l k, size l = n -> size k = n ->
(forall i, i < n -> nth def l i = nth def k (nth 0 s i)) ->
Permutation l k.
Proof.
elim; first by case=> // _ _ def [] // [] // _ _ _; apply Permutation_refl.
move=> n IH [|sh st] // [len_st] perm_shst def l k len_l len_k bij.
have [s0 [s1 [sh_st perm_s0s1]]] : exists s0, exists s1,
sh :: st = s0 ++ (n :: nil) ++ s1 /\ Permutation (s0 ++ s1) (iota 0 n).
by apply Permutation_seq_inv.
have len_s0s1 : size (s0 ++ s1) = n.
have : size (sh :: st) = S n by rewrite -(List.seq_length (S n) 0); apply Permutation_length.
rewrite sh_st !size_cat add1n addnS; by case.
have len_s0 : size s0 < S n.
have : size (sh :: st) = S n by rewrite -(List.seq_length (S n) 0); apply Permutation_length.
rewrite sh_st !size_cat add1n addnS => <-.
by rewrite ltnS leq_addr.
have [l0 [elt [l1 [l_def len_l0]]]] : exists l0 elt l1,
l = l0 ++ (elt :: nil) ++ l1 /\ size l0 = size s0.
case: (@list_split A def (S n) _ len_l _ len_s0) => l0 [l0_s0 [l1 l_def]].
exists l0; exists (nth def l (length s0)); by exists l1.
have len_l0l1 : size (l0 ++ l1) = n.
rewrite l_def !size_cat /= add1n addnS in len_l.
rewrite size_cat; by case: len_l.
have [k0 k_def] : exists k0, k = k0 ++ elt :: nil.
move: (bij _ len_s0).
rewrite sh_st nth_cat ltnn subnn /= l_def nth_cat len_l0 ltnn subnn /= => ->.
exists (take n k).
rewrite cats1 -take_nth //; last by rewrite len_k.
by rewrite take_oversize // len_k.
have len_k0 : size k0 = n. rewrite k_def size_cat /= addn1 in len_k; by case: len_k.
rewrite l_def k_def.
have IH_hyp : (forall i, i < n -> nth def (l0 ++ l1) i = nth def k0 (nth 0 (s0 ++ s1) i)).
apply sub_substitution with elt => //.
- by rewrite -sh_st // (Permutation_size perm_shst) // size_iota.
- move=> x Hx; move: (Permutation_in _ (perm_s0s1) Hx).
by move/inP; rewrite mem_iota leq0n /= add0n.
- by rewrite -l_def.
- by rewrite -k_def.
- by rewrite -l_def -k_def -sh_st.
move: {IH}(IH _ len_s0s1 perm_s0s1 def _ _ len_l0l1 len_k0 IH_hyp) => IH.
apply Permutation.perm_trans with (elt :: (l0 ++ l1)).
- by apply Permutation_sym, Permutation_cons_app, Permutation_refl.
- apply Permutation.perm_trans with (elt :: k0).
+ by apply perm_skip.
+ apply Permutation_cons_app; rewrite -List.app_nil_end; by apply Permutation_refl.
Qed.
End about_substitution.
Section onth_ext.
Variable A : Type.
Fixpoint onth (n : nat) (l : seq A) : option A :=
match n with
| O => match l with nil => None | h :: _ => Some h end
| S m => match l with nil => None | _ :: t => onth m t end
end.
Lemma onth_nil : forall i, onth i (@nil A) = None.
Proof. by case. Qed.
Lemma onth_In : forall (l : seq A) n a, onth n l = Some a -> List.In a l.
Proof.
elim=> [[] // | h t IH [|n] /= a].
by case; auto.
by move/IH; auto.
Qed.
Lemma onth_Some_inv1 : forall (l : seq A) i v, onth i l = Some v -> i < size l.
Proof. elim=> [[] // | h t IH [ // |i] v /=]; by move/IH => ?. Qed.
Lemma onth_Some_lt : forall (l : seq A) n a, onth n l = Some a -> n < size l.
Proof. by elim=> [[] // | h t IH [|n] //= a /IH]. Qed.
Lemma onth_nth : forall l def (a : A) i, onth i l = Some a -> nth def l i = a.
Proof.
elim.
move=> def a i.
by rewrite onth_nil.
move=> h t IH def a0 [|i] /=.
by case.
move/IH; exact.
Qed.
End onth_ext.
Lemma onth_map : forall {A B : Type} (l : seq A) x v,
onth x l = Some v -> forall f : A -> B, onth x (map f l) = Some (f v).
Proof.
move=> A B; elim => [[] // | h t IH [|x] /= v].
by case=> <-.
by move/IH.
Qed.
Lemma onth_map_Some_inv : forall {A B : Type} (f : A -> B) l i x,
onth i (map f l) = Some x -> exists y, onth i l = Some y /\ f y = x.
Proof.
move=> A B f; elim=> [/= i x | hd tl IH [|i] x /= H].
- by rewrite onth_nil.
- case: H => ?; subst x; by exists hd.
- case/IH : H => y H; by exists y.
Qed.
Lemma onth_map_inv : forall {A B : Type} (f : A -> B) l i b,
onth i (map f l) = Some b -> exists a, onth i l = Some a /\ b = f a.
Proof.
move=> A B f; elim=> /= [i b| h t IH [|i] /=].
by rewrite onth_nil.
move=> b [] <-; by exists h.
move=> b; case/IH => a [H1 H2]; by exists a.
Qed.
Lemma onth_Some_exists : forall {A B: Type} (l : seq A) (l' : seq B),
size l = size l' -> forall n f, n < size l ->
onth n l = Some f -> exists f', onth n l' = Some f'.
Proof.
move=> A B; elim => [[] // _ [] // | ht t IH [|h' t'] //= [t_t'] ].
destruct n as [|n].
move=> f _ _; eexists; reflexivity.
move=> f Hn n_f.
by apply (IH _ t_t' n f) in Hn.
Qed.
match l with
| nil => nil
| h :: t => if eq_dec a h then t else h :: remove1 a t
end.
Lemma Permutation_remove1 : forall h1 h h2,
Permutation (remove1 h (h1 ++ h :: h2)) (h1 ++ h2).
Proof.
elim=> [h h2 | hd tl IH h h2] /=.
by case: (eq_dec h h) => // X.
case: (eq_dec h hd) => /= X.
- subst h.
rewrite -/((hd :: nil) ++ h2); by apply Permutation_app_cons.
- by apply perm_skip, IH.
Qed.
Fixpoint fpermut (l k : seq A) :=
match (l,k) with
| (nil, nil) => true
| (h :: t, h' :: t') =>
if eq_dec h h' then
fpermut t t'
else if List.In_dec eq_dec h t' then
fpermut t (h' :: remove1 h t')
else
false
| _ => false
end.
Lemma function_permut_Permutation : forall n (l k : seq A),
size l = n -> fpermut l k -> Permutation l k.
Proof.
elim.
- move=> [] // [] // *; by apply Permutation_refl.
- move=> n IH [|h t] // [|h' t'] // [Hlent] /=.
case: (eq_dec h h') => /= X.
+ subst h'.
move/(IH _ _ Hlent).
by apply perm_skip.
+ case: (List.In_dec eq_dec h t') => /= Y // Z.
case/(@InP A) : (Y) => h1' [h2' H'].
rewrite H' List.app_comm_cons.
apply Permutation_cons_app.
move: {IH}(IH _ _ Hlent Z) => IH.
apply Permutation.perm_trans with (h' :: remove1 h t') => //=.
apply perm_skip.
rewrite H'.
by apply Permutation_remove1.
Qed.
End fixpoint_permutation.
Lemma tail_app {A : Type}: forall (lst lst' : seq A), 0 < size lst ->
List.tail (lst ++ lst') = List.tail lst ++ lst'.
Proof. case=> //= l' H; by inversion H. Qed.
Lemma list_tail { A : Type}: forall def (l : seq A), 0 < size l -> nth def l 0 :: List.tail l = l.
Proof. move=> def. case=> //=. Qed.
Section about_substitution.
Variable A : Type.
Lemma sub_substitution : forall n s0 s1, size (s0 ++ (n :: nil) ++ s1) = S n ->
(forall x, List.In x (s0 ++ s1) -> (x < n)) ->
forall (def e : A) l0 l1 k,
size (l0 ++ (e :: nil) ++ l1) = S n ->
size (k ++ e :: nil) = S n ->
size l0 = size s0 ->
(forall i, i < S n ->
nth def (l0 ++ (e :: nil) ++ l1) i = nth def (k ++ e :: nil) (nth 0 (s0 ++ (n :: nil) ++ s1) i)) ->
(forall i, i < n ->
nth def (l0 ++ l1) i = nth def k (nth 0 (s0 ++ s1) i)).
Proof.
move=> n s0 s1 Hs Hx def e l0 l1 k Hl Hk Hlenl0 H i Hin.
have Hlenk : size k = n by rewrite !size_cat /= in Hk; ssromega.
have [Hi | [Hi | Hi]] : i < size s0 \/ i = size s0 \/ size s0 < i.
case: (PeanoNat.Nat.lt_trichotomy i (size s0)) => [|[->|]].
by left; apply/ltP.
by auto.
by right; right; apply/ltP.
- have {}Hin : i < n.+1 by rewrite ltnW.
move: {H}(H _ Hin) => H.
rewrite nth_cat Hlenl0 Hi in H.
rewrite (_ : nth _ _ i = nth 0 s0 i) in H; last first.
by rewrite nth_cat Hi.
rewrite nth_cat // Hlenk Hx in H; last first.
apply List.in_or_app; left; by apply In_nth.
by rewrite nth_cat Hlenl0 Hi nth_cat Hi.
- destruct s1 as [|hs1 ts1]; subst i.
+ have {}Hs : size s0 = n by rewrite size_cat /= in Hs; ssromega.
by rewrite Hs ltnn in Hin.
+ rewrite -ltnS in Hin.
move: {H}(H _ Hin) => H.
rewrite -{1}Hlenl0 nth_cat ltnn subnn nth_cat ltnn subnn.
rewrite nth_cat Hlenl0 (_ : _.+1 < _ = false) // in H; last first.
apply/negbTE; by rewrite -leqNgt.
rewrite subSn // subnn in H.
rewrite nth_cat ltnn subnn in H.
rewrite nth_cat Hlenk Hx in H; last first.
rewrite nth_cat (_ : _ < _ = false); last first.
apply/negbTE.
by rewrite -leqNgt.
rewrite subSn // subnn /=.
apply List.in_or_app; right; left; by auto.
rewrite nth_cat (_ : _ < _ = false) in H; last first.
apply/negbTE.
by rewrite -leqNgt.
by rewrite H subSn // subnn.
- rewrite -ltnS in Hin.
move: {H}(H _ Hin) => H.
rewrite nth_cat in H.
rewrite (_ : _ < _ = false) in H; last first.
apply/negbTE.
rewrite -leqNgt -ltnS.
rewrite Hlenl0.
by apply (@ltn_trans i).
rewrite nth_cat subSn in H; last by rewrite Hlenl0 ltnW.
rewrite ltnS ltn0 subSS subn0 in H.
rewrite catA in H.
rewrite nth_cat ltnNge ltnW //=; last by rewrite Hlenl0.
rewrite H.
rewrite nth_cat Hlenk Hx; last first.
apply List.in_or_app; right.
rewrite nth_cat size_cat addn1 ltnS ltnNge ltnW //= subSS.
apply In_nth.
rewrite size_cat /= addnS in Hs.
case: Hs => Hs.
rewrite -(ltn_add2r (size s0)).
rewrite subnK; last by rewrite ltnW.
by rewrite addnC Hs.
rewrite nth_cat size_cat addn1 ltnS ltnNge ltnW //= subSS.
by rewrite nth_cat ltnNge ltnW //.
Qed.
Lemma substitution_Permutation : forall n s, size s = n ->
Permutation s (iota O n) ->
forall (def : A) l k, size l = n -> size k = n ->
(forall i, i < n -> nth def l i = nth def k (nth 0 s i)) ->
Permutation l k.
Proof.
elim; first by case=> // _ _ def [] // [] // _ _ _; apply Permutation_refl.
move=> n IH [|sh st] // [len_st] perm_shst def l k len_l len_k bij.
have [s0 [s1 [sh_st perm_s0s1]]] : exists s0, exists s1,
sh :: st = s0 ++ (n :: nil) ++ s1 /\ Permutation (s0 ++ s1) (iota 0 n).
by apply Permutation_seq_inv.
have len_s0s1 : size (s0 ++ s1) = n.
have : size (sh :: st) = S n by rewrite -(List.seq_length (S n) 0); apply Permutation_length.
rewrite sh_st !size_cat add1n addnS; by case.
have len_s0 : size s0 < S n.
have : size (sh :: st) = S n by rewrite -(List.seq_length (S n) 0); apply Permutation_length.
rewrite sh_st !size_cat add1n addnS => <-.
by rewrite ltnS leq_addr.
have [l0 [elt [l1 [l_def len_l0]]]] : exists l0 elt l1,
l = l0 ++ (elt :: nil) ++ l1 /\ size l0 = size s0.
case: (@list_split A def (S n) _ len_l _ len_s0) => l0 [l0_s0 [l1 l_def]].
exists l0; exists (nth def l (length s0)); by exists l1.
have len_l0l1 : size (l0 ++ l1) = n.
rewrite l_def !size_cat /= add1n addnS in len_l.
rewrite size_cat; by case: len_l.
have [k0 k_def] : exists k0, k = k0 ++ elt :: nil.
move: (bij _ len_s0).
rewrite sh_st nth_cat ltnn subnn /= l_def nth_cat len_l0 ltnn subnn /= => ->.
exists (take n k).
rewrite cats1 -take_nth //; last by rewrite len_k.
by rewrite take_oversize // len_k.
have len_k0 : size k0 = n. rewrite k_def size_cat /= addn1 in len_k; by case: len_k.
rewrite l_def k_def.
have IH_hyp : (forall i, i < n -> nth def (l0 ++ l1) i = nth def k0 (nth 0 (s0 ++ s1) i)).
apply sub_substitution with elt => //.
- by rewrite -sh_st // (Permutation_size perm_shst) // size_iota.
- move=> x Hx; move: (Permutation_in _ (perm_s0s1) Hx).
by move/inP; rewrite mem_iota leq0n /= add0n.
- by rewrite -l_def.
- by rewrite -k_def.
- by rewrite -l_def -k_def -sh_st.
move: {IH}(IH _ len_s0s1 perm_s0s1 def _ _ len_l0l1 len_k0 IH_hyp) => IH.
apply Permutation.perm_trans with (elt :: (l0 ++ l1)).
- by apply Permutation_sym, Permutation_cons_app, Permutation_refl.
- apply Permutation.perm_trans with (elt :: k0).
+ by apply perm_skip.
+ apply Permutation_cons_app; rewrite -List.app_nil_end; by apply Permutation_refl.
Qed.
End about_substitution.
Section onth_ext.
Variable A : Type.
Fixpoint onth (n : nat) (l : seq A) : option A :=
match n with
| O => match l with nil => None | h :: _ => Some h end
| S m => match l with nil => None | _ :: t => onth m t end
end.
Lemma onth_nil : forall i, onth i (@nil A) = None.
Proof. by case. Qed.
Lemma onth_In : forall (l : seq A) n a, onth n l = Some a -> List.In a l.
Proof.
elim=> [[] // | h t IH [|n] /= a].
by case; auto.
by move/IH; auto.
Qed.
Lemma onth_Some_inv1 : forall (l : seq A) i v, onth i l = Some v -> i < size l.
Proof. elim=> [[] // | h t IH [ // |i] v /=]; by move/IH => ?. Qed.
Lemma onth_Some_lt : forall (l : seq A) n a, onth n l = Some a -> n < size l.
Proof. by elim=> [[] // | h t IH [|n] //= a /IH]. Qed.
Lemma onth_nth : forall l def (a : A) i, onth i l = Some a -> nth def l i = a.
Proof.
elim.
move=> def a i.
by rewrite onth_nil.
move=> h t IH def a0 [|i] /=.
by case.
move/IH; exact.
Qed.
End onth_ext.
Lemma onth_map : forall {A B : Type} (l : seq A) x v,
onth x l = Some v -> forall f : A -> B, onth x (map f l) = Some (f v).
Proof.
move=> A B; elim => [[] // | h t IH [|x] /= v].
by case=> <-.
by move/IH.
Qed.
Lemma onth_map_Some_inv : forall {A B : Type} (f : A -> B) l i x,
onth i (map f l) = Some x -> exists y, onth i l = Some y /\ f y = x.
Proof.
move=> A B f; elim=> [/= i x | hd tl IH [|i] x /= H].
- by rewrite onth_nil.
- case: H => ?; subst x; by exists hd.
- case/IH : H => y H; by exists y.
Qed.
Lemma onth_map_inv : forall {A B : Type} (f : A -> B) l i b,
onth i (map f l) = Some b -> exists a, onth i l = Some a /\ b = f a.
Proof.
move=> A B f; elim=> /= [i b| h t IH [|i] /=].
by rewrite onth_nil.
move=> b [] <-; by exists h.
move=> b; case/IH => a [H1 H2]; by exists a.
Qed.
Lemma onth_Some_exists : forall {A B: Type} (l : seq A) (l' : seq B),
size l = size l' -> forall n f, n < size l ->
onth n l = Some f -> exists f', onth n l' = Some f'.
Proof.
move=> A B; elim => [[] // _ [] // | ht t IH [|h' t'] //= [t_t'] ].
destruct n as [|n].
move=> f _ _; eexists; reflexivity.
move=> f Hn n_f.
by apply (IH _ t_t' n f) in Hn.
Qed.