Library mathcomp_eulerian.psi_cdindex_witness


From mathcomp Require Import all_ssreflect.
Require Import mmtree psi_core psi_comm psi_descent_v2 psi_descent_thms.
Require Import psi_cdindex_core.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.



Definition omega_seq (s : seq nat) : seq nat :=
  [seq k <- iota 0 (foldr maxn 0 s).+1
   | (k \in s) != ((k.+1) \in s)].


Definition is_D_letter (l : cde) : bool :=
  match l with D_lettertrue | _false end.

Definition S_w_seq (w : seq nat) : seq nat :=
  [seq i.-1 | i <- iota 1 (size w).-1
             & is_D_letter (classify_vertex_cde i w)].


Definition check_phi_w_support (w : seq nat) (X : seq bool) : bool :=
  (X \in expand_cde (phi_w w)) ==
  all (fun kk \in omega_seq [seq i <- iota 0 (size w).-1 | nth false X i])
      (S_w_seq w).


Example phi_w_support_ex1 :
  expand_cde (phi_w [:: 2; 1; 3]) = [:: [:: false; true]; [:: true; false]].
Proof. by vm_compute. Qed.

Example S_w_seq_ex1 : S_w_seq [:: 2; 1; 3] = [:: 0].
Proof. by vm_compute. Qed.

Example S_w_seq_ex2 : S_w_seq [:: 1; 3; 2] = [::].
Proof. by vm_compute. Qed.

Example S_w_seq_ex3 : S_w_seq [:: 3; 1; 5; 4; 2; 6] = [:: 0; 3].
Proof. by vm_compute. Qed.

Example S_w_seq_ex4 : S_w_seq [:: 3; 1; 4; 7; 5; 9; 2; 6] = [:: 0; 4].
Proof. by vm_compute. Qed.


Lemma omega_monotone_class_count (n : nat) (S T : seq nat) :
  uniq S uniq T
  {subset omega_seq S omega_seq T}
  
   (w : seq nat), uniq w size w = n
    all (fun kk \in omega_seq S) (S_w_seq w)
    all (fun kk \in omega_seq T) (S_w_seq w).
Proof.
move_ _ Hsub w _ _ /allP Hall.
by apply/allPk Hk; apply: Hsub; apply: Hall.
Qed.



Definition witness_perm (n k : nat) : seq nat :=
  iota 1 k ++ [:: k.+2; k.+1] ++ iota k.+3 (n - k - 2).

Lemma leq_maxn' a b : b a maxn a b = a.
Proof.
moveHba; rewrite /maxn; case Hlt: (a < b).
  by have := leq_ltn_trans Hba Hlt; rewrite ltnn.
by [].
Qed.

Lemma geq_maxn' a b : a b maxn a b = b.
Proof. by moveH; rewrite maxnC; exact: leq_maxn'. Qed.

Lemma geq_minn' a b : a b minn a b = a.
Proof.
moveHab; rewrite /minn; case Hlt: (a < b) ⇒ //.
move: Hlt ⇒ /negbT; rewrite -leqNgtHba.
by apply/eqP; rewrite eqn_leq Hab Hba.
Qed.

Lemma path_leq_last' (s : seq nat) (a : nat) :
  path leq a s a last a s.
Proof.
elim: s a ⇒ [//|x s IH] a /= /andP [Hax Hp].
exact: leq_trans Hax (IH _ Hp).
Qed.

Lemma foldr_maxn_path' (s : seq nat) (a : nat) :
  path leq a s foldr maxn a s = last a s.
Proof.
elim: s a ⇒ [//|x s IH] a /= /andP [Hax Hps].
case: s IH Hps ⇒ [|y s] IH Hps.
  by rewrite /= leq_maxn'.
have Hxy : x y
  by move: Hps ⇒ /= /andP [].
have Hps' : path leq y s
  by move: Hps ⇒ /= /andP [].
have Hay : a y := leq_trans Hax Hxy.
have Hpay : path leq a (y :: s)
  by rewrite /= Hay.
rewrite (IH a Hpay).
apply: geq_maxn'.
exact: leq_trans Hxy
  (@path_leq_last' s y Hps').
Qed.

Lemma foldr_minn_ge' (a : nat) (s : seq nat) :
  all (fun xa x) s foldr minn a s = a.
Proof.
elim: s ⇒ [//|x s IH].
rewrite /= ⇒ /andP [Hax Hs].
rewrite IH // minnC geq_minn' //.
Qed.

Lemma all_le_iota' m n :
  all (fun xm x) (iota m.+1 n).
Proof.
apply/allPx; rewrite mem_iota ⇒ /andP [Hm _]; exact: ltnW.
Qed.

Lemma min_pos_iota' m n : min_pos (iota m n.+1) = 0.
Proof.
rewrite /min_pos /= foldr_minn_ge' ?all_le_iota' //.
by rewrite /= eqxx.
Qed.

Lemma path_iota' m n : path leq m (iota m.+1 n).
Proof. elim: n m ⇒ [//|n IH] m /=. by rewrite leqnSn IH. Qed.

Lemma last_iota' m n : last m (iota m.+1 n) = m + n.
Proof.
case: n ⇒ [|n]; first by rewrite addn0.
by rewrite -nth_last size_iota nth_iota // addnS.
Qed.

Lemma foldr_maxn_iota' m n :
  foldr maxn m (iota m.+1 n) = m + n.
Proof.
case: n ⇒ [|n]; first by rewrite addn0.
rewrite (@foldr_maxn_path' (iota m.+1 n.+1) m);
  last exact: path_iota'.
exact: last_iota'.
Qed.

Lemma max_pos_iota' m n :
  max_pos (iota m n.+1) = n.
Proof.
rewrite /max_pos.
rewrite [head 0 _]/= [behead _]/= foldr_maxn_iota'.
have → : iota m n.+1 = iota m n ++ [:: m + n].
  rewrite -addn1 iotaD /=.
  by [].
rewrite index_cat.
have Hnotin : (m + n) \notin iota m n.
  rewrite mem_iota; apply/negP ⇒ /andP [_ Hlt].
  by rewrite addnC ltn_add2l ltnn in Hlt.
rewrite (negbTE Hnotin) size_iota /= eqxx /=.
by rewrite addn0.
Qed.

Lemma mm_pos_iota' m n : mm_pos (iota m n.+1) = 0.
Proof. by rewrite /mm_pos min_pos_iota' max_pos_iota'. Qed.


Lemma size_witness_perm n k :
  k + 2 < n size (witness_perm n k) = n.
Proof.
moveHkn.
rewrite /witness_perm !size_cat !size_iota /=.
rewrite addnA -subnDA.
by rewrite subnKC // ltnW.
Qed.

Lemma iota_mem_range m l i : i \in iota m l m i < m + l.
Proof. by rewrite mem_iota. Qed.

Lemma witness_perm_uniq n k :
  k + 2 < n uniq (witness_perm n k).
Proof.
moveHkn.
rewrite /witness_perm.
rewrite cat_uniq iota_uniq.
apply/and3P; split⇒ //.
-
  apply/hasPnx; rewrite mem_catHx.
  rewrite mem_iota negb_and.
  apply/orP; right.
  rewrite -leqNgt addnC addn1.
  case/orP: HxHx.
  + rewrite !inE in Hx; case/orP: Hx ⇒ /eqP →.
    × exact: leqnSn.
    × exact: leqnn.
  + rewrite mem_iota in Hx; case/andP: HxHx3 _.
    apply: leq_trans _ Hx3.
    by exact: leq_trans (leqnSn _) (leqnSn _).
rewrite cat_uniq iota_uniq /=.
apply/and3P; split⇒ //.
-
  rewrite andbT /= inE.
  by rewrite eqSS (gtn_eqF (ltnSn _)).
-
  apply/hasPnx; rewrite mem_iota ⇒ /andP [Hx3 _].
  rewrite !inE; apply/norP; split; apply/eqPHabs;
    rewrite Habs in Hx3.
  by rewrite ltnn in Hx3.
  by rewrite ltnNge leqnSn in Hx3.
Qed.



Definition check_strict_witness (n k : nat) : bool :=
  let w := witness_perm n k in
  uniq w && (size w == n) && (S_w_seq w == [:: k]).


Example check_sw_3_0 : check_strict_witness 3 0.
Proof. by vm_compute. Qed.
Example check_sw_4_0 : check_strict_witness 4 0.
Proof. by vm_compute. Qed.
Example check_sw_4_1 : check_strict_witness 4 1.
Proof. by vm_compute. Qed.
Example check_sw_5_0 : check_strict_witness 5 0.
Proof. by vm_compute. Qed.
Example check_sw_5_1 : check_strict_witness 5 1.
Proof. by vm_compute. Qed.
Example check_sw_5_2 : check_strict_witness 5 2.
Proof. by vm_compute. Qed.

Lemma check_strict_witness_correct n k :
  check_strict_witness n k
   w : seq nat,
    uniq w size w = n S_w_seq w = [:: k].
Proof.
rewrite /check_strict_witness.
case/andP ⇒ /andP [Huniq /eqP Hsz] /eqP HSw.
by (witness_perm n k).
Qed.

Lemma has_left_child_iota m l i :
  has_left_child i (iota m l) = false.
Proof.
elim: l m i ⇒ [m i | l IH m [|i]].
- by rewrite /= /has_left_child.
- by rewrite has_left_child_cons mm_pos_iota'.
- rewrite has_left_child_cons mm_pos_iota' /=.
  rewrite subn1 drop0 /=.
  exact: IH.
Qed.

Lemma foldr_minn_all_gt' (a : nat) (s : seq nat) :
  ( x, x \in s a < x) foldr minn a s = a.
Proof.
elim: s ⇒ [//|b s IH] Hall.
have Hab : a < b by apply: Hall; rewrite inE eqxx.
have Hs : x, x \in s a < x
  by movex Hx; apply: Hall; rewrite inE Hx orbT.
rewrite /= IH // minnC; apply/minn_idPl; exact: ltnW.
Qed.

Lemma mm_pos_min_first a s :
  ( x, x \in s a < x)
  mm_pos (a :: s) = 0.
Proof.
moveHall.
rewrite /mm_pos /min_pos /max_pos /=.
rewrite foldr_minn_all_gt' //.
rewrite /= eqxx.
done.
Qed.

Lemma min_pos_core k m :
  min_pos ([:: k.+2; k.+1] ++ iota k.+3 m) = 1.
Proof.
rewrite /min_pos /=.
have → : foldr minn k.+2 (iota k.+3 m) = k.+2.
  apply: foldr_minn_all_gt'x.
  by rewrite mem_iota ⇒ /andP [].
have → : minn k.+1 k.+2 = k.+1 by apply/minn_idPl.
have → : (k.+2 == k.+1) = false by rewrite eqSS (gtn_eqF (ltnSn _)).
by rewrite eqxx.
Qed.

Lemma max_pos_core_gt0 k m :
  0 < m
  0 < max_pos ([:: k.+2; k.+1] ++ iota k.+3 m).
Proof.
case: m ⇒ [//|m] _.
rewrite /max_pos /=.
have Hge : k.+3
  maxn k.+1 (maxn k.+3 (foldr maxn k.+2 (iota k.+4 m))).
  by apply: leq_trans (leq_maxl _ _) (leq_maxr _ _).
rewrite eq_sym (gtn_eqF Hge).
by [].
Qed.

Lemma mm_pos_core k m :
  0 < m
  mm_pos ([:: k.+2; k.+1] ++ iota k.+3 m) = 1.
Proof.
moveHm.
rewrite /mm_pos min_pos_core.
by have := max_pos_core_gt0 k Hm; case: (max_pos _).
Qed.


Lemma hlc_core_not1 k m i :
  0 < m i != 1
  has_left_child i
    ([:: k.+2; k.+1] ++ iota k.+3 m) = false.
Proof.
moveHm Hne.
case: i Hne ⇒ [|[|i]] Hne.
- exact: has_left_child_0.
- by rewrite eqxx in Hne.
- rewrite (has_left_child_cons i.+2 k.+2
    (k.+1 :: iota k.+3 m)).
  change (k.+2 :: k.+1 :: iota k.+3 m) with
    ([:: k.+2; k.+1] ++ iota k.+3 m).
  rewrite mm_pos_core //.
  rewrite /= drop0.
  exact: has_left_child_iota.
Qed.

Lemma hlc_core_1 k m :
  0 < m
  has_left_child 1 ([:: k.+2; k.+1] ++ iota k.+3 m) = true.
Proof.
moveHm.
rewrite (has_left_child_cons 1 k.+2 (k.+1 :: iota k.+3 m)).
change (k.+2 :: k.+1 :: iota k.+3 m) with
  ([:: k.+2; k.+1] ++ iota k.+3 m).
by rewrite mm_pos_core.
Qed.

Lemma ws_core_1 k m :
  0 < m
  window_size 1
    ([:: k.+2; k.+1] ++ iota k.+3 m) = m.+1.
Proof.
moveHm.
rewrite (window_size_cons 1 k.+2 (k.+1 :: iota k.+3 m)).
change (k.+2 :: k.+1 :: iota k.+3 m) with
  ([:: k.+2; k.+1] ++ iota k.+3 m).
rewrite mm_pos_core //.
rewrite !size_cat /= size_iota.
by [].
Qed.

Lemma S_w_seq_core k m :
  0 < m
  S_w_seq ([:: k.+2; k.+1] ++ iota k.+3 m) =
  [:: 0].
Proof.
moveHm.
set core := [:: k.+2; k.+1] ++ iota k.+3 m.
have Hsz : size core = m.+2
  by rewrite /core !size_cat /= size_iota.
rewrite /S_w_seq Hsz.
have HD1 : is_D_letter (classify_vertex_cde 1 core) = true.
  rewrite /classify_vertex_cde /is_internal Hsz /=.
  rewrite ws_core_1 // hlc_core_1 //.
  by rewrite ltnS Hm.
have HnD : i, 1 i i m.+1 i != 1
  is_D_letter (classify_vertex_cde i core) = false.
  movei Hi1 Him Hne.
  rewrite /classify_vertex_cde.
  case Hint : (is_internal i core) ⇒ //=.
  by rewrite hlc_core_not1.
have → : iota 1 m.+1 = 1 :: iota 2 m by [].
rewrite /= HD1 /=.
suff → : [seq i <- iota 2 m
   | is_D_letter (classify_vertex_cde i core)] = [::] by [].
apply/nilP; rewrite /nilp size_filter.
rewrite (eq_in_count (a2 := pred0)); first by rewrite count_pred0.
movei Hi /=.
move: Hi; rewrite mem_iota ⇒ /andP [Hi2 Him2].
have Hi_pos : 0 < i by exact: ltnW Hi2.
have Hi_le : i m.+1 by rewrite -ltnS.
have Hi_ne1 : i != 1 by rewrite neq_ltn Hi2 orbT.
by rewrite HnD.
Qed.

Lemma S_w_seq_witness_k0 n :
  3 n
  S_w_seq (witness_perm n 0) = [:: 0].
Proof.
case: n ⇒ [|[|[|n]]] // _.
rewrite /witness_perm /=.
have → : [:: 2, 1, 3 & iota 4 n] = [:: 2; 1] ++ iota 3 n.+1 by [].
by apply: (S_w_seq_core 0); apply: ltn0Sn.
Qed.

Lemma classify_skip_mm0 i a rest :
  mm_pos (a :: rest) = 0 0 < i
  classify_vertex_cde i (a :: rest) =
  classify_vertex_cde (i - 1) rest.
Proof.
moveHmm Hi.
rewrite /classify_vertex_cde /is_internal.
rewrite (window_size_cons i a rest)
  -/(mm_pos (a :: rest)) Hmm.
rewrite (has_left_child_cons i a rest)
        -/(mm_pos (a :: rest)) Hmm.
have → : (i < 0) = false by rewrite ltn0.
have → : (i == 0) = false by case: i Hi.
rewrite !subn0 /= !drop0.
have → : (i < (size rest).+1) =
  (i - 1 < size rest).
  by case: i Hi ⇒ //= i _;
     rewrite subSS subn0 ltnS.
done.
Qed.

Lemma S_w_seq_shift a rest :
  mm_pos (a :: rest) = 0
  S_w_seq (a :: rest) =
  [seq x.+1 | x <- S_w_seq rest].
Proof.
moveHmm.
rewrite /S_w_seq /=.
rewrite (eq_in_filter
  (a2 := fun iis_D_letter (classify_vertex_cde (i - 1) rest))); last first.
  movei; rewrite mem_iota ⇒ /andP [Hi _].
  by rewrite (classify_skip_mm0 Hmm Hi).
have iota_S : l m, iota m.+1 l = [seq j.+1 | j <- iota m l].
  by elim⇒ [|l IH] m //=; rewrite IH.
have → : iota 1 (size rest) = [seq j.+1 | j <- iota 0 (size rest)]
  by exact: iota_S.
rewrite filter_map -!map_comp.
rewrite (eq_filter (a2 := fun jis_D_letter (classify_vertex_cde j rest))); last first.
  by movej /=; rewrite subn1 /=.
rewrite (eq_map (g := id)); last first.
  by movej /=.
rewrite map_id.
case Hsz : (size rest) ⇒ [|m] /=.
  by [].
have HE : is_D_letter (classify_vertex_cde 0 rest) = false.
  rewrite /classify_vertex_cde.
  by case: ifP ⇒ //= _; rewrite has_left_child_0.
rewrite HE /=.
rewrite -[LHS]map_id.
apply/eq_in_mapj Hj.
rewrite mem_filter mem_iota in Hj.
case/andP: Hj_ /andP [Hj _].
by case: j Hj.
Qed.

Lemma drop1_witness_map_succ n k :
  k.+4 n
  drop 1 (witness_perm n k.+1) =
  [seq i.+1 | i <- witness_perm n.-1 k].
Proof.
case: n ⇒ [|n] //= Hkn.
rewrite /witness_perm /=.
rewrite drop0.
rewrite !map_cat /=.
have → : [seq i.+1 | i <- iota 1 k] = iota 2 k.
  rewrite (eq_map (g := addn 1)); last by movei; rewrite addnC addn1.
  by rewrite -iotaDl.
have → : [seq i.+1 | i <- iota k.+3 (n - k - 2)] =
  iota k.+4 (n - k - 2).
  rewrite (eq_map (g := addn 1)); last by movei; rewrite addnC addn1.
  by rewrite -[k.+4]/(1 + k.+3) -iotaDl.
have → : n.+1 - k.+1 - 2 = n - k - 2.
  by rewrite subSS.
done.
Qed.

Lemma map_succ_order_iso (s : seq nat) :
  uniq s
   p q, p < size s q < size s
  (nth 0 s p < nth 0 s q) =
  (nth 0 [seq i.+1 | i <- s] p < nth 0 [seq i.+1 | i <- s] q).
Proof.
moveHu p q Hp Hq.
by rewrite !(nth_map 0) // ltnS ltnS.
Qed.

Lemma classify_map_succ (s : seq nat) i :
  uniq s
  classify_vertex_cde i [seq j.+1 | j <- s] =
  classify_vertex_cde i s.
Proof.
moveHu.
rewrite /classify_vertex_cde /is_internal.
rewrite size_map.
case Hi : (i < size s) ⇒ /=; last by [].
have Hsz : size s = size [seq j.+1 | j <- s]
  by rewrite size_map.
have Hu2 : uniq [seq j.+1 | j <- s].
  rewrite map_inj_uniq // ⇒ a b []; done.
have Horder p q : p < size s q < size s
    (nth 0 [seq j.+1 | j <- s] p < nth 0 [seq j.+1 | j <- s] q) =
    (nth 0 s p < nth 0 s q).
  moveHp Hq.
  by rewrite (nth_map 0 _ _ Hp) (nth_map 0 _ _ Hq) ltnS.
rewrite (window_size_order_iso i (esym Hsz) Hu2 Hu); last first.
  movep q Hp Hq; rewrite -Hsz in Hp Hq.
  by rewrite Horder.
rewrite (has_left_child_order_iso i (esym Hsz) Hu2 Hu); last first.
  movep q Hp Hq; rewrite -Hsz in Hp Hq.
  by rewrite Horder.
done.
Qed.

Lemma S_w_seq_map_succ (s : seq nat) :
  uniq s
  S_w_seq [seq j.+1 | j <- s] = S_w_seq s.
Proof.
moveHu.
rewrite /S_w_seq size_map.
congr map.
apply: eq_filteri.
by rewrite (classify_map_succ _ Hu).
Qed.

Lemma mm_pos_witness k n :
  0 < k k.+3 n
  mm_pos (witness_perm n k) = 0.
Proof.
case: k ⇒ [//|k] _ Hkn.
rewrite /witness_perm.
have → : iota 1 k.+1 = 1 :: iota 2 k by [].
rewrite cat_cons.
apply: mm_pos_min_firstx.
rewrite !mem_cat !inE.
case/orP⇒ [|H].
- by rewrite mem_iota ⇒ /andP [H _].
- case/orP: H ⇒ [|H2].
  + by case/orP⇒ /eqP →.
  + by rewrite mem_iota in H2; case/andP: H2H _; apply: ltn_trans H.
Qed.

Lemma S_w_seq_witness_perm n k :
  k.+3 n S_w_seq (witness_perm n k) = [:: k].
Proof.
move: n.
elim: k ⇒ [|k IHk] n Hkn.
- exact: S_w_seq_witness_k0.
- have Hk1 : 0 < k.+1 by [].
  have Hmm : mm_pos (witness_perm n k.+1) = 0.
    exact: mm_pos_witness Hk1 Hkn.
  have Hw : witness_perm n k.+1 =
    head 0 (witness_perm n k.+1)
      :: behead (witness_perm n k.+1).
    rewrite /witness_perm /=; done.
  rewrite {1}Hw S_w_seq_shift; last first.
    by rewrite -Hw.
  have Hd1 : behead (witness_perm n k.+1) =
    drop 1 (witness_perm n k.+1).
    by rewrite /witness_perm /= drop0.
  rewrite Hd1 drop1_witness_map_succ; last exact: Hkn.
  have Hn : 0 < n by apply: leq_trans Hkn.
  have Hn1 : k.+3 n.-1.
    by rewrite -ltnS prednK //; apply: Hkn.
  rewrite S_w_seq_map_succ; last first.
    apply: witness_perm_uniq.
    by rewrite addn2.
  by rewrite IHk.
Qed.

Lemma strict_witness_exists :
   (n : nat) (k : nat),
  k < n.-2
   w : seq nat,
    uniq w size w = n S_w_seq w = [:: k].
Proof.
moven k Hkn.
(witness_perm n k); split; [|split].
- apply: witness_perm_uniq.
  by rewrite addn2;
     case: n Hkn ⇒ [//|[//|n]] /=.
- apply: size_witness_perm.
  by rewrite addn2;
     case: n Hkn ⇒ [//|[//|n]] /=.
- apply: S_w_seq_witness_perm.
  by case: n Hkn ⇒ [|[|n]] //=;
     rewrite ltnS.
Qed.

Example strict_witness_ex1 :
  S_w_seq [:: 2; 1; 3] = [:: 0].
Proof. by vm_compute. Qed.

Example strict_witness_ex2 :
  S_w_seq [:: 1; 3; 2; 4] = [:: 1].
Proof. by vm_compute. Qed.

Example strict_witness_ex3 :
  S_w_seq [:: 2; 1; 3; 4; 5] = [:: 0].
Proof. by vm_compute. Qed.