Module infotheo.lib.num_occ
From mathcomp Require Import all_ssreflect fingroup perm zmodp ssralg.Require Import ssr_ext f2.
# Number of occurrences in a tuple
```
N(a | t) == number of occurrences of a in t
N((a,b) | (ta,tb)) == number of occurrences of (a,b) in zip ta tb
```
Reserved Notation "'N(' a '|' t ')'" (format "N( a | t )").
Reserved Notation "'N(' a ',' b '|' ta ',' tb ')'".
Declare Scope num_occ_scope.
Set Implicit Arguments.
Set SsrOldRewriteGoalsOrder.
Unset Strict Implicit.
Import Prenex Implicits.
Local Open Scope tuple_ext_scope.
Local Open Scope nat_scope.
Section num_occ_def.
Variables (A : eqType) (a : A) (t : seq A).
Definition
num_occ
:= count_mem a t.num_occ not a defined object.
End num_occ_def.
Notation "'N(' a '|' t ')'" := (num_occ a t) : num_occ_scope.
Local Open Scope num_occ_scope.
Section num_occ_prop.
Variables (A : eqType) (a : A).
Lemma num_occ0 : N(a | [::]) = 0
Proof.
by []. Qed.
Lemma num_occ_cons x y (t : seq A) : N(x | y :: t) = (x == y) + N(x | t).
Proof.
Lemma filter_pred1_num_occ (t : seq A) : filter (pred1 a) t = nseq N(a | t) a.
Proof.
set lhs := (X in X = _).
rewrite (_ : N(a | t) = size lhs); last by rewrite size_filter.
apply/all_pred1P/all_filterP; by rewrite filter_id.
Qed.
rewrite (_ : N(a | t) = size lhs); last by rewrite size_filter.
apply/all_pred1P/all_filterP; by rewrite filter_id.
Qed.
Lemma num_occ_map_filter (B : finType) (f : B -> A) (s : {set B}) (p : pred A) (pa : p a) :
N(a | [seq f i | i <- enum s & p (f i)]) = N(a | [seq f i | i in s]).
Proof.
Lemma notin_num_occ_0 (t : seq A) : (a \notin t) = (N(a | t) == O).
Proof.
apply/esym.
case/boolP : (a \notin t) => [/count_memPn | ].
rewrite /num_occ; by move=> ->.
apply: contraNF; by move/eqP/count_memPn.
Qed.
case/boolP : (a \notin t) => [/count_memPn | ].
rewrite /num_occ; by move=> ->.
apply: contraNF; by move/eqP/count_memPn.
Qed.
Lemma mem_num_occ_gt0 (t : seq A) : (a \in t) = (0 < N(a | t)).
Proof.
Lemma num_occ_rev (t : seq A) : N(a | t) = N(a | rev t).
Proof.
End num_occ_prop.
Arguments num_occ_map_filter [A] [a] [B] [f] [s] _ _.
Lemma num_occ_sum : forall (t : seq 'F_2), num_occ 1%R t = \sum_(i <- t) i.
Lemma num_occ_sum_bool : forall t : seq bool, N(true | t) = \sum_(i <- t) i.
Proof.
Lemma sum_num_occ_size (A : finType) s : (\sum_(a in A) N(a|s))%nat = size s.
Proof.
elim: s => [|a s IH] /=.
+ by apply: big1_eq.
+ by rewrite big_split /= IH -big_mkcond /= (big_pred1 a) // => x; rewrite eq_sym.
Qed.
+ by apply: big1_eq.
+ by rewrite big_split /= IH -big_mkcond /= (big_pred1 a) // => x; rewrite eq_sym.
Qed.
Lemma num_occ_flatten (A : finType) (a : A) ss :
N(a|flatten ss) = (\sum_(s <- ss) N(a|s))%nat.
Proof.
Section num_occ_tuple.
Lemma num_occ_leq_n {A : eqType} n a (t : n.-tuple A) : N(a | t) <= n.
Proof.
Variables (A : finType) (n : nat) (a : A) (t : n.-tuple A).
Definition
set_occ
:= [set i | t !_ i == a].set_occ not a defined object.
Lemma num_occ_alt : N(a | t) = #| set_occ |.
Proof.
rewrite cardE -sum1_size big_filter /= /num_occ -sum1_count big_tuple.
apply/eq_bigl => i; by rewrite !inE.
Qed.
apply/eq_bigl => i; by rewrite !inE.
Qed.
Lemma num_occ_thead (ta : n.+1.-tuple A) :
N(a | ta) = N(a | [tuple of [:: thead ta]]) + N(a | tbehead ta).
Lemma sum_num_occ_seq1 : \sum_(i in A) N(i | [:: a]) = 1.
Proof.
End num_occ_tuple.
Section num_occ_tuple_prop.
Variable (A : finType) (n : nat) (t : n.-tuple A).
Lemma sum_num_occ_alt : \sum_(a in A) N(a | t) = n.
Proof.
Lemma sum_num_occ_all : \sum_(i < #|A|) N(enum_val i | t) = n.
Proof.
symmetry.
rewrite -{1}sum_num_occ_alt.
rewrite (reindex_onto enum_rank enum_val) /= => [|i _]; last by rewrite enum_valK.
apply: eq_big => x0 ; by rewrite enum_rankK // eqxx.
Qed.
rewrite -{1}sum_num_occ_alt.
rewrite (reindex_onto enum_rank enum_val) /= => [|i _]; last by rewrite enum_valK.
apply: eq_big => x0 ; by rewrite enum_rankK // eqxx.
Qed.
Local Open Scope group_scope.
Lemma num_occ_perm (a : A) (s : 'S_n) : N(a | perm_tuple s t) = N(a | t).
Proof.
rewrite 2!num_occ_alt.
rewrite (_ : set_occ a (perm_tuple s t) = s^-1 @: set_occ a t).
apply/card_imset/perm_inj.
apply/eqP.
rewrite eqEsubset.
apply/andP; split; apply/subsetP => i.
- rewrite in_set => H.
apply/imsetP.
exists (s i); last by rewrite -permM mulgV perm1.
rewrite in_set.
move/eqP : H => <-; by rewrite /perm_tuple tnth_map tnth_ord_tuple.
- rewrite in_set.
case/imsetP => j.
rewrite in_set.
move/eqP => <- ->.
by rewrite tnth_map tnth_ord_tuple permKV.
Qed.
rewrite (_ : set_occ a (perm_tuple s t) = s^-1 @: set_occ a t).
apply/card_imset/perm_inj.
apply/eqP.
rewrite eqEsubset.
apply/andP; split; apply/subsetP => i.
- rewrite in_set => H.
apply/imsetP.
exists (s i); last by rewrite -permM mulgV perm1.
rewrite in_set.
move/eqP : H => <-; by rewrite /perm_tuple tnth_map tnth_ord_tuple.
- rewrite in_set.
case/imsetP => j.
rewrite in_set.
move/eqP => <- ->.
by rewrite tnth_map tnth_ord_tuple permKV.
Qed.
Local Close Scope group_scope.
End num_occ_tuple_prop.
Section num_co_occ_def.
Variables (A B : eqType) (a : A) (b : B) (ta : seq A) (tb : seq B).
Local Open Scope nat_scope.
Definition
num_co_occ
:= N( (a, b) | zip ta tb ).num_co_occ not a defined object.
End num_co_occ_def.
Notation "'N(' a ',' b '|' ta ',' tb ')'" := (num_co_occ a b ta tb) : num_occ_scope.
Section num_co_occ_prop.
Variables (A B : eqType) (a : A) (b : B) (ta : seq A) (tb : seq B).
Lemma num_co_occ1 (a' : A) : N(a, b | [:: a'], [:: b]) = N(a | [:: a']).
Lemma num_co_occ_sym : N(a, b | ta, tb) = N(b, a | tb, ta).
Proof.
End num_co_occ_prop.
Section num_co_occ_tuple.
Variables (A B : finType) (n : nat) (a : A) (b : B) (ta : n.-tuple A) (tb : n.-tuple B).
Definition
set_co_occ
:= [set i | (ta !_ i == a) && (tb !_ i == b)].set_co_occ not a defined object.
Lemma num_co_occ_leq_n : N(a, b | ta, tb) <= n.
Proof.
Lemma num_co_occ_ub : N(a, b | ta, tb) < n.+1.
Proof.
Lemma num_co_occ_alt : N(a, b | ta, tb) = #| set_co_occ |.
Proof.
rewrite /num_co_occ num_occ_alt /set_occ.
apply: eq_card => i.
rewrite !in_set /zip_tuple (tnth_nth (a, b)) nth_zip ?size_tuple //.
by rewrite -2!tnth_nth xpair_eqE.
Qed.
apply: eq_card => i.
rewrite !in_set /zip_tuple (tnth_nth (a, b)) nth_zip ?size_tuple //.
by rewrite -2!tnth_nth xpair_eqE.
Qed.
End num_co_occ_tuple.
Section num_co_occ_tuple_prop.
Variables (A B : finType) (n : nat) (ta : n.-tuple A) (tb : n.-tuple B).
Lemma num_co_occ_sum : \sum_(a : A) \sum_ (b : B) N( a , b | ta , tb) = n.
Proof.
Definition
set_set_co_occ
a :=set_set_co_occ not a defined object.
[set set_co_occ a b ta tb | b in B & [exists i, i \in set_co_occ a b ta tb]].
Lemma cover_set_set_co_occ a : cover (set_set_co_occ a) = set_occ a ta.
Proof.
apply/setP => i.
rewrite cover_imset.
apply/bigcupP.
case : ifP; last by move=> /negP H1 H ; move: H1; apply/negP; case H => {H} y0 ; rewrite 3!in_set => _ /andP [].
rewrite in_set => /eqP Hi.
exists (tb!_i) ; last by rewrite in_set Hi eqxx andTb.
rewrite in_set; apply/andP; split => //.
apply/existsP; exists i; by rewrite in_set Hi eqxx andTb.
Qed.
rewrite cover_imset.
apply/bigcupP.
case : ifP; last by move=> /negP H1 H ; move: H1; apply/negP; case H => {H} y0 ; rewrite 3!in_set => _ /andP [].
rewrite in_set => /eqP Hi.
exists (tb!_i) ; last by rewrite in_set Hi eqxx andTb.
rewrite in_set; apply/andP; split => //.
apply/existsP; exists i; by rewrite in_set Hi eqxx andTb.
Qed.
Lemma trivIset_set_set_co_occ a : trivIset (set_set_co_occ a).
Proof.
apply/trivIsetP => S1 S2; case/imsetP => P1 _ HP1; case/imsetP => P2 _ HP2 HP12.
subst S1 S2.
rewrite /disjoint.
apply/pred0P => m /=.
apply/negP/negP.
rewrite 2!in_set.
move: m.
apply/forallP; rewrite -negb_exists; apply/negP; case/existsP => i /andP [/andP [_ /eqP H1] /andP [_ /eqP H2]]; contradict HP12.
apply/negP/negPn/eqP; by rewrite -H1 -H2.
Qed.
subst S1 S2.
rewrite /disjoint.
apply/pred0P => m /=.
apply/negP/negP.
rewrite 2!in_set.
move: m.
apply/forallP; rewrite -negb_exists; apply/negP; case/existsP => i /andP [/andP [_ /eqP H1] /andP [_ /eqP H2]]; contradict HP12.
apply/negP/negPn/eqP; by rewrite -H1 -H2.
Qed.
Lemma num_co_occ_partial_sum_alt a : \sum_(b : B) N(a , b | ta , tb) = N(a | ta).
Proof.
elim: n ta tb => [x' y' | m IHm x1 y1].
rewrite (tuple0 x') (tuple0 y') num_occ0.
transitivity (\sum_(y0 : B) 0).
by apply: eq_bigr => b _.
by rewrite big_const iter_addn mul0n addn0.
rewrite num_occ_thead.
transitivity (\sum_y0 (N(a, y0 | [tuple thead x1], [tuple thead y1]) +
N(a, y0 | tbehead x1, tbehead y1))).
apply: eq_bigr => i _.
by rewrite {1}/num_co_occ {1}(tuple_eta x1) {1}(tuple_eta y1) /num_co_occ /num_occ /= addn0.
rewrite big_split /=.
move: {IHm}(IHm (tbehead x1) (tbehead y1)) => ->.
congr (_ + _).
rewrite (bigD1 (thead y1)) //= num_co_occ1.
set tmp := \sum_(_ | _) _.
suff : tmp = 0 by move=> ->; rewrite addn0.
rewrite {}/tmp.
transitivity (\sum_(H | H != thead y1) 0).
apply: eq_bigr => b Hb.
apply/eqP.
rewrite /num_co_occ -notin_num_occ_0.
move: Hb; apply: contra => Hb.
case/tnthP : Hb => i.
rewrite (tnth_nth (a, b)) /= (ord1 i) /=.
by case => _ ->.
by rewrite big_const iter_addn mul0n addn0.
Qed.
rewrite (tuple0 x') (tuple0 y') num_occ0.
transitivity (\sum_(y0 : B) 0).
by apply: eq_bigr => b _.
by rewrite big_const iter_addn mul0n addn0.
rewrite num_occ_thead.
transitivity (\sum_y0 (N(a, y0 | [tuple thead x1], [tuple thead y1]) +
N(a, y0 | tbehead x1, tbehead y1))).
apply: eq_bigr => i _.
by rewrite {1}/num_co_occ {1}(tuple_eta x1) {1}(tuple_eta y1) /num_co_occ /num_occ /= addn0.
rewrite big_split /=.
move: {IHm}(IHm (tbehead x1) (tbehead y1)) => ->.
congr (_ + _).
rewrite (bigD1 (thead y1)) //= num_co_occ1.
set tmp := \sum_(_ | _) _.
suff : tmp = 0 by move=> ->; rewrite addn0.
rewrite {}/tmp.
transitivity (\sum_(H | H != thead y1) 0).
apply: eq_bigr => b Hb.
apply/eqP.
rewrite /num_co_occ -notin_num_occ_0.
move: Hb; apply: contra => Hb.
case/tnthP : Hb => i.
rewrite (tnth_nth (a, b)) /= (ord1 i) /=.
by case => _ ->.
by rewrite big_const iter_addn mul0n addn0.
Qed.
Lemma num_co_occ_perm (a : A) (b : B) (s : 'S_n) :
N( a , b | perm_tuple s ta , perm_tuple s tb ) = N( a , b | ta , tb ).
Proof.
End num_co_occ_tuple_prop.
Lemma num_co_occ_num_occ1 {A B : finType} a' b' (a : A) :
\sum_(i in B) N(a, i | [tuple of [:: a']], [tuple of [:: b']]) = (a' == a).
Proof.
case/boolP : (a' == a) => [/eqP ->{a'} | a'a].
- rewrite /num_co_occ /num_occ /= (bigD1 b') //= eqxx /= addn0 add1n; congr S.
rewrite (eq_bigr (fun=> 0)).
by rewrite big_const iter_addn.
move=> b bb'; by rewrite xpair_eqE eqxx /= addn0 eq_sym (negbTE bb').
- rewrite (eq_bigr (fun=> 0)).
by rewrite big_const iter_addn.
move=> b _; by rewrite /num_co_occ /num_occ /= xpair_eqE (negbTE a'a).
Qed.
- rewrite /num_co_occ /num_occ /= (bigD1 b') //= eqxx /= addn0 add1n; congr S.
rewrite (eq_bigr (fun=> 0)).
by rewrite big_const iter_addn.
move=> b bb'; by rewrite xpair_eqE eqxx /= addn0 eq_sym (negbTE bb').
- rewrite (eq_bigr (fun=> 0)).
by rewrite big_const iter_addn.
move=> b _; by rewrite /num_co_occ /num_occ /= xpair_eqE (negbTE a'a).
Qed.
Lemma num_co_occ_num_occ {A B : finType} : forall n (ta : n.-tuple A) (tb : n.-tuple B) a,
\sum_(b in B) N(a, b | ta, tb) = N(a | ta).
Proof.
elim => [ta tb a | n IH ta tb a].
rewrite (tuple0 ta) (tuple0 tb) /= (eq_bigr (fun=> 0)) //.
by rewrite big_const iter_addn !Monoid.simpm.
move: {IH}(IH (tbehead ta) (tbehead tb) a) => IH.
rewrite [in X in _ = X]/num_occ /= in IH.
rewrite (tuple_eta ta) (tuple_eta tb) /= [in RHS]/num_occ.
rewrite (eq_bigr (fun b =>
N(a, b | [:: thead ta], [:: thead tb]) + N(a, b | tbehead ta, tbehead tb))).
by rewrite big_split /= IH num_co_occ_num_occ1.
move=> b' _; by rewrite /num_co_occ num_occ_thead.
Qed.
rewrite (tuple0 ta) (tuple0 tb) /= (eq_bigr (fun=> 0)) //.
by rewrite big_const iter_addn !Monoid.simpm.
move: {IH}(IH (tbehead ta) (tbehead tb) a) => IH.
rewrite [in X in _ = X]/num_occ /= in IH.
rewrite (tuple_eta ta) (tuple_eta tb) /= [in RHS]/num_occ.
rewrite (eq_bigr (fun b =>
N(a, b | [:: thead ta], [:: thead tb]) + N(a, b | tbehead ta, tbehead tb))).
by rewrite big_split /= IH num_co_occ_num_occ1.
move=> b' _; by rewrite /num_co_occ num_occ_thead.
Qed.
Section cansort.
Variable A : finType.
Variable n : nat.
Variable ta : n.-tuple A.
Definition
sum_num_occ
(k : nat) := \sum_(i < #|A| | i < k) N(enum_val i | ta).sum_num_occ not a defined object.
Lemma sum_num_occ_0 : sum_num_occ 0 = 0.
Proof.
Lemma sum_num_occ_rec (k : 'I_#|A|) : sum_num_occ k.+1 = sum_num_occ k + N(enum_val k | ta).
Proof.
rewrite /sum_num_occ (bigD1 k) /=; last by exact: (leqnn k).
rewrite addnC.
apply/eqP; rewrite eqn_add2r; apply/eqP.
apply: eq_bigl => i; by rewrite andbC -ltn_neqAle.
Qed.
rewrite addnC.
apply/eqP; rewrite eqn_add2r; apply/eqP.
apply: eq_bigl => i; by rewrite andbC -ltn_neqAle.
Qed.
Lemma sum_num_occ_sub (k : 'I_#|A|) : sum_num_occ k.+1 - sum_num_occ k = N(enum_val k | ta).
Proof.
rewrite sum_num_occ_rec addnC; symmetry.
by rewrite -{1}(addn0 N(enum_val k | ta)) -(subnn (sum_num_occ k)) addnBA.
Qed.
by rewrite -{1}(addn0 N(enum_val k | ta)) -(subnn (sum_num_occ k)) addnBA.
Qed.
Lemma full_sum_num_occ (k : nat) : #|A| <= k ->
sum_num_occ k = \sum_(i < #|A|) N(enum_val i | ta).
Lemma full_sum_num_occ_n (k : nat) : #|A| <= k -> sum_num_occ k = n.
Proof.
Lemma sum_num_occ_inc_loc (k : nat) : sum_num_occ k <= sum_num_occ k.+1.
Proof.
Lemma sum_num_occ_inc (k l : nat) : k <= l -> sum_num_occ k <= sum_num_occ l.
Proof.
Lemma sum_num_occ_leq_n (k : nat) : sum_num_occ k <= n.
Proof.
have[]:= ltnP k #|A|.
- by move/ltnW/sum_num_occ_inc; rewrite (@full_sum_num_occ_n #|A|).
- by move/full_sum_num_occ_n->.
Qed.
- by move/ltnW/sum_num_occ_inc; rewrite (@full_sum_num_occ_n #|A|).
- by move/full_sum_num_occ_n->.
Qed.
Lemma minn_sum_num_occ_n (k : nat) : minn (sum_num_occ k) n = sum_num_occ k.
Proof.
Lemma min_sum_num_occ (k : nat) : minn (sum_num_occ k) (sum_num_occ k.+1) = sum_num_occ k.
Proof.
Section order_surgery.
Hypothesis ta_cansorted : sorted (@le_rank A) ta.
Lemma set_predleq_size r k l : k + l <= r -> #|[set i : 'I_r | nat_of_ord i \in iota k l]| = l.
Proof.
elim: l => [kr | l IH HSl].
- apply/eqP; rewrite cards_eq0; apply/eqP.
apply/setP => i; by rewrite !inE.
- rewrite addnS in HSl.
have : k + l <= r by apply: (leq_trans _ HSl); apply: leqnSn.
move/IH => Hl.
rewrite -sum1_card (bigD1 (Ordinal HSl)) /=.
rewrite (_ : \sum_(i in [set i0 : 'I_r | nat_of_ord i0 \in iota k l.+1] | _) 1 =
\sum_(i in [set i0 : 'I_r | nat_of_ord i0 \in iota k l]) 1); last first.
apply: eq_bigl => i; rewrite !in_set.
case/boolP : (i != Ordinal HSl) => Hcase.
- rewrite andbT -addn1 iotaD /= mem_cat !inE.
set tmp := _ == _ + _.
suff -> : tmp = false by rewrite orbC.
apply/eqP/eqP.
move: Hcase; apply: contra => /eqP Hcase.
by apply/eqP; apply: val_inj.
- rewrite negbK in Hcase.
move/eqP : Hcase => ->.
by rewrite andbC /= mem_iota /= ltnn andbC.
by rewrite sum1_card Hl add1n.
rewrite in_set in_cons mem_iota /=.
destruct l; first by rewrite addn0; apply/orP; left.
apply/orP; right.
apply/andP; split; by [rewrite addnS ltnS leq_addr | rewrite ltn_add2r].
Qed.
- apply/eqP; rewrite cards_eq0; apply/eqP.
apply/setP => i; by rewrite !inE.
- rewrite addnS in HSl.
have : k + l <= r by apply: (leq_trans _ HSl); apply: leqnSn.
move/IH => Hl.
rewrite -sum1_card (bigD1 (Ordinal HSl)) /=.
rewrite (_ : \sum_(i in [set i0 : 'I_r | nat_of_ord i0 \in iota k l.+1] | _) 1 =
\sum_(i in [set i0 : 'I_r | nat_of_ord i0 \in iota k l]) 1); last first.
apply: eq_bigl => i; rewrite !in_set.
case/boolP : (i != Ordinal HSl) => Hcase.
- rewrite andbT -addn1 iotaD /= mem_cat !inE.
set tmp := _ == _ + _.
suff -> : tmp = false by rewrite orbC.
apply/eqP/eqP.
move: Hcase; apply: contra => /eqP Hcase.
by apply/eqP; apply: val_inj.
- rewrite negbK in Hcase.
move/eqP : Hcase => ->.
by rewrite andbC /= mem_iota /= ltnn andbC.
by rewrite sum1_card Hl add1n.
rewrite in_set in_cons mem_iota /=.
destruct l; first by rewrite addn0; apply/orP; left.
apply/orP; right.
apply/andP; split; by [rewrite addnS ltnS leq_addr | rewrite ltn_add2r].
Qed.
Lemma sum_num_occ_enum_val (k : 'I_#|A|) (l : 'I_n) :
sum_num_occ k <= l < sum_num_occ k.+1 -> ta!_l = enum_val k.
Proof.
move: (ltnSn k).
set k':= {2}k.+1.
move: k' => k'.
elim: k' l k => [l k /= | m IH l k km]; first by rewrite ltn0.
case/boolP : (k < m) => Hcase; first by apply: IH.
rewrite -leqNgt in Hcase.
have : m = k by apply/eqP; rewrite eqn_leq; apply/andP.
rewrite {Hcase} => ?; subst m.
case/andP => [Hlm1 Hlm2].
apply/eqP/negPn/negP; move=> abs.
case/boolP : (lt_rank ta!_l (enum_val k)) => Hcase.
- have Hrank : enum_rank ta!_l < k by rewrite lt_rank_alt enum_valK in Hcase.
have Hcontr : #|[set i | (i==l) || (sum_num_occ (enum_rank ta!_l)<= i < sum_num_occ (enum_rank ta!_l).+1)]| <= N(ta!_l|ta).
rewrite num_occ_alt subset_leq_card // subsetE; apply/pred0P => i /=.
rewrite !in_set /=.
apply/negbTE; rewrite negb_and.
case/boolP : (ta!_i == ta!_l) => ta_il //.
rewrite negb_or; apply/andP; split.
- move: ta_il; apply: contra => /eqP ->; by rewrite eqxx.
- move: ta_il; apply: contra => ta_il.
apply/eqP; rewrite -(enum_rankK (ta!_l)); by apply: IH.
rewrite (_ : #|[set i | (i == l) || (sum_num_occ (enum_rank ta!_l) <= i < sum_num_occ (enum_rank ta!_l).+1)]| = N(ta!_l | ta).+1) in Hcontr; first by rewrite ltnn in Hcontr.
symmetry; rewrite -addn1 sum_num_occ_rec -sum1_card.
rewrite (bigD1 l) /=; last by rewrite in_set; apply/orP; apply: or_introl.
rewrite addnC; apply/eqP; rewrite eqn_add2l; apply/eqP.
transitivity (\sum_(i in [set i0 : 'I_n | nat_of_ord i0 \in iota (sum_num_occ (enum_rank ta!_l)) N(enum_val (enum_rank ta!_l) | ta)]) 1); last first.
apply: eq_bigl => i; rewrite !in_set.
case/boolP : (i != l) => Hcase2.
- rewrite mem_iota.
move/negPf in Hcase2; by rewrite andbT Hcase2 orFb.
- rewrite negbK in Hcase2; move/eqP in Hcase2; subst i.
rewrite andbF mem_iota.
apply/negP; case/andP => H1.
rewrite -sum_num_occ_rec; apply/negP; rewrite -leqNgt.
by rewrite (leq_trans _ Hlm1) // sum_num_occ_inc.
by rewrite sum1_card set_predleq_size enum_rankK // -{2}(enum_rankK ta!_l) -sum_num_occ_rec sum_num_occ_leq_n.
- have {abs} {}Hcase : lt_rank (enum_val k) ta!_l.
rewrite lt_rank_alt; rewrite lt_rank_alt -leqNgt in Hcase.
rewrite ltn_neqAle; apply/andP; split => //.
rewrite enum_valK.
suff : k != enum_rank ta!_l by move=> ->.
apply/negP ; move/eqP.
move=> abs2; symmetry in abs2; rewrite -abs2 enum_rankK {abs2} in abs.
contradict abs ; by apply/negP/negPn/eqP.
move/negP : (ltnn N(enum_val k | ta)) => abs; contradict abs.
rewrite {1}num_occ_alt.
have H : #|[set i | ta!_i == enum_val k]| <= #|[set i : 'I_n | (sum_num_occ k <= i < l)]|.
apply: subset_leq_card.
rewrite subsetE; apply/pred0P => i /=.
rewrite !in_set /=.
apply/negP/negP.
rewrite negb_and negbK.
case/boolP : (sum_num_occ k <= i < l) => Hcase2; first by apply/orP; apply: or_introl.
case/boolP : (l <= i) => Hcase3.
+ rewrite eq_sym; apply: lt_neq_rank.
apply/lt_le_rank_trans; first by apply: Hcase.
apply: sorted_of_tnth_leq => //; [exact/le_rank_trans | exact/le_rank_refl].
+ rewrite -ltnNge in Hcase3.
rewrite Hcase3 andbT -ltnNge {Hcase3} in Hcase2.
apply: lt_neq_rank.
have lt0m : 0 < k.
rewrite ltnNge leqn0 ; apply/eqP => abs2.
contradict Hcase2 ; by rewrite abs2 sum_num_occ_0 ltn0.
have H2 : forall (k' : 'I_#|A|) (l : 'I_n), k'.-1 < k -> l < sum_num_occ k' -> lt_rank ta!_l (enum_val k'). (* nested induction *)
case; elim.
- move=> H0 l0 /= _ abs2 ; contradict abs2 ; by rewrite sum_num_occ_0 ltn0.
- move=> k' HR' HSk l0 /= k'k Hl0.
have Hk' : k' < #|A| by apply: (leq_trans k'k _); apply: ltnW.
apply: (@le_lt_rank_trans _ _ (enum_val (Ordinal Hk'))).
- case/boolP : (l0 < sum_num_occ k') => Hcase3; rewrite /le_rank leq_eqVlt; apply/orP; [apply: or_intror | apply: or_introl].
- rewrite -lt_rank_alt; apply: HR'; by [apply: (leq_ltn_trans (leq_pred _) k'k) | apply: Hcase3].
- rewrite -leqNgt in Hcase3; rewrite (IH _ (Ordinal Hk')) //; by apply/andP.
- rewrite lt_rank_alt !enum_valK; by apply: ltnSn.
apply: H2 ; by [rewrite -{2}(prednK lt0m) ; apply: ltnSn | apply: Hcase2].
rewrite -(subnKC Hlm1) in H.
set lhs := #| _ | in H.
have {}H : lhs <= #|[set i : 'I_n | nat_of_ord i \in iota (sum_num_occ k) (l - sum_num_occ k)]|.
apply/(leq_trans H)/eq_leq.
by apply: eq_card => /= i; rewrite !inE mem_iota.
rewrite set_predleq_size in H; last by rewrite (subnKC Hlm1) ltnW.
apply: (leq_ltn_trans H _).
by rewrite -sum_num_occ_sub /= ltn_sub2r // (leq_ltn_trans Hlm1 Hlm2).
Qed.
set k':= {2}k.+1.
move: k' => k'.
elim: k' l k => [l k /= | m IH l k km]; first by rewrite ltn0.
case/boolP : (k < m) => Hcase; first by apply: IH.
rewrite -leqNgt in Hcase.
have : m = k by apply/eqP; rewrite eqn_leq; apply/andP.
rewrite {Hcase} => ?; subst m.
case/andP => [Hlm1 Hlm2].
apply/eqP/negPn/negP; move=> abs.
case/boolP : (lt_rank ta!_l (enum_val k)) => Hcase.
- have Hrank : enum_rank ta!_l < k by rewrite lt_rank_alt enum_valK in Hcase.
have Hcontr : #|[set i | (i==l) || (sum_num_occ (enum_rank ta!_l)<= i < sum_num_occ (enum_rank ta!_l).+1)]| <= N(ta!_l|ta).
rewrite num_occ_alt subset_leq_card // subsetE; apply/pred0P => i /=.
rewrite !in_set /=.
apply/negbTE; rewrite negb_and.
case/boolP : (ta!_i == ta!_l) => ta_il //.
rewrite negb_or; apply/andP; split.
- move: ta_il; apply: contra => /eqP ->; by rewrite eqxx.
- move: ta_il; apply: contra => ta_il.
apply/eqP; rewrite -(enum_rankK (ta!_l)); by apply: IH.
rewrite (_ : #|[set i | (i == l) || (sum_num_occ (enum_rank ta!_l) <= i < sum_num_occ (enum_rank ta!_l).+1)]| = N(ta!_l | ta).+1) in Hcontr; first by rewrite ltnn in Hcontr.
symmetry; rewrite -addn1 sum_num_occ_rec -sum1_card.
rewrite (bigD1 l) /=; last by rewrite in_set; apply/orP; apply: or_introl.
rewrite addnC; apply/eqP; rewrite eqn_add2l; apply/eqP.
transitivity (\sum_(i in [set i0 : 'I_n | nat_of_ord i0 \in iota (sum_num_occ (enum_rank ta!_l)) N(enum_val (enum_rank ta!_l) | ta)]) 1); last first.
apply: eq_bigl => i; rewrite !in_set.
case/boolP : (i != l) => Hcase2.
- rewrite mem_iota.
move/negPf in Hcase2; by rewrite andbT Hcase2 orFb.
- rewrite negbK in Hcase2; move/eqP in Hcase2; subst i.
rewrite andbF mem_iota.
apply/negP; case/andP => H1.
rewrite -sum_num_occ_rec; apply/negP; rewrite -leqNgt.
by rewrite (leq_trans _ Hlm1) // sum_num_occ_inc.
by rewrite sum1_card set_predleq_size enum_rankK // -{2}(enum_rankK ta!_l) -sum_num_occ_rec sum_num_occ_leq_n.
- have {abs} {}Hcase : lt_rank (enum_val k) ta!_l.
rewrite lt_rank_alt; rewrite lt_rank_alt -leqNgt in Hcase.
rewrite ltn_neqAle; apply/andP; split => //.
rewrite enum_valK.
suff : k != enum_rank ta!_l by move=> ->.
apply/negP ; move/eqP.
move=> abs2; symmetry in abs2; rewrite -abs2 enum_rankK {abs2} in abs.
contradict abs ; by apply/negP/negPn/eqP.
move/negP : (ltnn N(enum_val k | ta)) => abs; contradict abs.
rewrite {1}num_occ_alt.
have H : #|[set i | ta!_i == enum_val k]| <= #|[set i : 'I_n | (sum_num_occ k <= i < l)]|.
apply: subset_leq_card.
rewrite subsetE; apply/pred0P => i /=.
rewrite !in_set /=.
apply/negP/negP.
rewrite negb_and negbK.
case/boolP : (sum_num_occ k <= i < l) => Hcase2; first by apply/orP; apply: or_introl.
case/boolP : (l <= i) => Hcase3.
+ rewrite eq_sym; apply: lt_neq_rank.
apply/lt_le_rank_trans; first by apply: Hcase.
apply: sorted_of_tnth_leq => //; [exact/le_rank_trans | exact/le_rank_refl].
+ rewrite -ltnNge in Hcase3.
rewrite Hcase3 andbT -ltnNge {Hcase3} in Hcase2.
apply: lt_neq_rank.
have lt0m : 0 < k.
rewrite ltnNge leqn0 ; apply/eqP => abs2.
contradict Hcase2 ; by rewrite abs2 sum_num_occ_0 ltn0.
have H2 : forall (k' : 'I_#|A|) (l : 'I_n), k'.-1 < k -> l < sum_num_occ k' -> lt_rank ta!_l (enum_val k'). (* nested induction *)
case; elim.
- move=> H0 l0 /= _ abs2 ; contradict abs2 ; by rewrite sum_num_occ_0 ltn0.
- move=> k' HR' HSk l0 /= k'k Hl0.
have Hk' : k' < #|A| by apply: (leq_trans k'k _); apply: ltnW.
apply: (@le_lt_rank_trans _ _ (enum_val (Ordinal Hk'))).
- case/boolP : (l0 < sum_num_occ k') => Hcase3; rewrite /le_rank leq_eqVlt; apply/orP; [apply: or_intror | apply: or_introl].
- rewrite -lt_rank_alt; apply: HR'; by [apply: (leq_ltn_trans (leq_pred _) k'k) | apply: Hcase3].
- rewrite -leqNgt in Hcase3; rewrite (IH _ (Ordinal Hk')) //; by apply/andP.
- rewrite lt_rank_alt !enum_valK; by apply: ltnSn.
apply: H2 ; by [rewrite -{2}(prednK lt0m) ; apply: ltnSn | apply: Hcase2].
rewrite -(subnKC Hlm1) in H.
set lhs := #| _ | in H.
have {}H : lhs <= #|[set i : 'I_n | nat_of_ord i \in iota (sum_num_occ k) (l - sum_num_occ k)]|.
apply/(leq_trans H)/eq_leq.
by apply: eq_card => /= i; rewrite !inE mem_iota.
rewrite set_predleq_size in H; last by rewrite (subnKC Hlm1) ltnW.
apply: (leq_ltn_trans H _).
by rewrite -sum_num_occ_sub /= ltn_sub2r // (leq_ltn_trans Hlm1 Hlm2).
Qed.
Lemma enum_val_sum_num_occ (k : 'I_#|A|) (l : 'I_n) :
ta!_l = enum_val k -> sum_num_occ k <= l < sum_num_occ k.+1.
Proof.
move=> Hkl; apply/negP => /negP abs.
have : #|[set i | (i == l) || (sum_num_occ k <= i < sum_num_occ k.+1)]| <= N(ta!_l | ta).
rewrite num_occ_alt subset_leq_card // subsetE.
apply/pred0P => /= i /=; rewrite !in_set /=.
case/boolP : (ta!_i == ta!_l) => ta_il //=.
apply/negbTE; rewrite negb_or; apply/andP; split.
- move: ta_il; apply: contra => /eqP ?; subst l; by rewrite eqxx.
- move: ta_il; apply: contra => Hsum_num_occ.
apply/eqP; rewrite Hkl; by apply: sum_num_occ_enum_val.
suff -> : #|[set i | (i == l) || (sum_num_occ k <= i < sum_num_occ k.+1)]| = N(ta!_l | ta).+1.
by rewrite ltnn.
symmetry; rewrite -addn1 sum_num_occ_rec -sum1_card.
rewrite (bigD1 l) /=; last by rewrite in_set; apply/orP; apply: or_introl.
rewrite addnC; apply/eqP; rewrite eqn_add2l; apply/eqP.
transitivity ( \sum_(i in [set i0 : 'I_n | nat_of_ord i0 \in iota (sum_num_occ k) N(enum_val k | ta)]) 1 ).
rewrite sum1_card set_predleq_size; by [rewrite Hkl | rewrite -sum_num_occ_rec; apply: sum_num_occ_leq_n].
apply: eq_bigl => i; rewrite !in_set.
case/boolP : (i != l) => [/negPf |] il.
- by rewrite andbT il orFb mem_iota.
- rewrite negbK in il; move/eqP in il; subst i.
rewrite andbF mem_iota.
apply/negbTE; move: abs; apply: contra.
by rewrite -sum_num_occ_rec.
Qed.
have : #|[set i | (i == l) || (sum_num_occ k <= i < sum_num_occ k.+1)]| <= N(ta!_l | ta).
rewrite num_occ_alt subset_leq_card // subsetE.
apply/pred0P => /= i /=; rewrite !in_set /=.
case/boolP : (ta!_i == ta!_l) => ta_il //=.
apply/negbTE; rewrite negb_or; apply/andP; split.
- move: ta_il; apply: contra => /eqP ?; subst l; by rewrite eqxx.
- move: ta_il; apply: contra => Hsum_num_occ.
apply/eqP; rewrite Hkl; by apply: sum_num_occ_enum_val.
suff -> : #|[set i | (i == l) || (sum_num_occ k <= i < sum_num_occ k.+1)]| = N(ta!_l | ta).+1.
by rewrite ltnn.
symmetry; rewrite -addn1 sum_num_occ_rec -sum1_card.
rewrite (bigD1 l) /=; last by rewrite in_set; apply/orP; apply: or_introl.
rewrite addnC; apply/eqP; rewrite eqn_add2l; apply/eqP.
transitivity ( \sum_(i in [set i0 : 'I_n | nat_of_ord i0 \in iota (sum_num_occ k) N(enum_val k | ta)]) 1 ).
rewrite sum1_card set_predleq_size; by [rewrite Hkl | rewrite -sum_num_occ_rec; apply: sum_num_occ_leq_n].
apply: eq_bigl => i; rewrite !in_set.
case/boolP : (i != l) => [/negPf |] il.
- by rewrite andbT il orFb mem_iota.
- rewrite negbK in il; move/eqP in il; subst i.
rewrite andbF mem_iota.
apply/negbTE; move: abs; apply: contra.
by rewrite -sum_num_occ_rec.
Qed.
Lemma sum_num_occ_is_enum_val (k : 'I_#|A|) (l : 'I_n) :
sum_num_occ k <= l < sum_num_occ k.+1 = (ta!_l == enum_val k).
Proof.
case/boolP : (sum_num_occ k <= l < sum_num_occ k.+1) => Hcase.
- exact/esym/eqP/sum_num_occ_enum_val.
- apply/esym/negbTE;apply: contra Hcase => /eqP; exact: enum_val_sum_num_occ.
Qed.
- exact/esym/eqP/sum_num_occ_enum_val.
- apply/esym/negbTE;apply: contra Hcase => /eqP; exact: enum_val_sum_num_occ.
Qed.
End order_surgery.
End cansort.