Library mathcomp_eulerian.psi_cdindex_tree


From mathcomp Require Import all_ssreflect.
Require Import mmtree psi_core psi_comm psi_descent_v2 psi_descent_thms.
Require Import psi_cdindex_defs psi_cdindex_tree_hlc.

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


Example window_size_psi_ex1 :
  window_size 2 (psi 5 [:: 3; 1; 4; 7; 5; 9; 2; 6]) =
  window_size 2 [:: 3; 1; 4; 7; 5; 9; 2; 6].
Proof. by vm_compute. Qed.

Example window_size_psi_ex2 :
  window_size 5 (psi 2 [:: 3; 1; 4; 7; 5; 9; 2; 6]) =
  window_size 5 [:: 3; 1; 4; 7; 5; 9; 2; 6].
Proof. by vm_compute. Qed.

Example window_size_psi_ex3 :
  window_size 1 (psi 5 [:: 3; 1; 4; 7; 5; 9; 2; 6]) =
  window_size 1 [:: 3; 1; 4; 7; 5; 9; 2; 6].
Proof. by vm_compute. Qed.

Example has_left_child_psi_ex :
  has_left_child 5 (psi 2 [:: 3; 1; 4; 7; 5; 9; 2; 6]) =
  has_left_child 5 [:: 3; 1; 4; 7; 5; 9; 2; 6].
Proof. by vm_compute. Qed.


Lemma window_size_last_fuel :
   fuel w, size w fuel 0 < size w
  window_size_fuel fuel (size w).-1 w = 1.
Proof.
elim⇒ [w Hsz Hne|fuel IH [|a s0] Hsz Hne] //.
  by move: Hsz Hne; case: w.
set s := a :: s0. set j := mm_pos s.
have Hj : j < size s by apply: mm_pos_lt.
have Hj2 : j size s0 by rewrite -ltnS.
rewrite /= -/s -/j.
have Hjn : (size s0 < j) = false
  by apply/negbTE; rewrite -leqNgt.
rewrite Hjn.
case Hjq: (size s0 == j).
  by move/eqP: Hjq ⇒ <-; rewrite /s /= subSn // subnn.
have Hjl : j < size s0
  by rewrite ltn_neqAle eq_sym Hjq /= leqNgt Hjn.
change (window_size_fuel fuel (size s0 - j - 1) (drop j s0) = 1).
have Hsz_ds : size (drop j s0) = size s0 - j by rewrite size_drop.
have H0ds : 0 < size (drop j s0) by rewrite Hsz_ds subn_gt0.
have Hfuel_ok : size (drop j s0) fuel.
  rewrite Hsz_ds; apply: leq_trans (leq_subr _ _) _.
  by rewrite ltnS in Hsz.
have → : size s0 - j - 1 = (size (drop j s0)).-1
  by rewrite Hsz_ds subn1.
exact: IH Hfuel_ok H0ds.
Qed.

Lemma window_size_last w :
  0 < size w
  window_size (size w).-1 w = 1.
Proof.
moveHne; rewrite /window_size.
exact: window_size_last_fuel (leqnn _) Hne.
Qed.


Fixpoint window_size_t (i : nat) (t : mmtree nat) : nat :=
  match t with
  | Leaf ⇒ 0
  | Node l _ r
      if i < size (mmtree_to_seq l) then window_size_t i l
      else if i == size (mmtree_to_seq l) then (size (mmtree_to_seq r)).+1
      else window_size_t (i - (size (mmtree_to_seq l)).+1) r
  end.

Fixpoint has_left_child_t (i : nat) (t : mmtree nat) : bool :=
  match t with
  | Leaffalse
  | Node l _ r
      if i < size (mmtree_to_seq l) then has_left_child_t i l
      else if i == size (mmtree_to_seq l) then 0 < size (mmtree_to_seq l)
      else has_left_child_t (i - (size (mmtree_to_seq l)).+1) r
  end.

Definition is_internal_t (i : nat) (t : mmtree nat) : bool :=
  (i < size (mmtree_to_seq t)) && (1 < window_size_t i t).

Arguments window_size_t : simpl never.
Arguments has_left_child_t : simpl never.


Lemma window_size_t_Node_lt (l : mmtree nat) x r i :
  i < size (mmtree_to_seq l)
  window_size_t i (Node l x r) = window_size_t i l.
Proof. by rewrite /window_size_t -/window_size_t ⇒ →. Qed.

Lemma window_size_t_Node_eq l x (r : mmtree nat) :
  window_size_t (size (mmtree_to_seq l)) (Node l x r) =
    (size (mmtree_to_seq r)).+1.
Proof. by rewrite /window_size_t -/window_size_t ltnn eqxx. Qed.

Lemma window_size_t_Node_gt (l : mmtree nat) x r i :
  size (mmtree_to_seq l) < i
  window_size_t i (Node l x r) =
    window_size_t (i - (size (mmtree_to_seq l)).+1) r.
Proof.
moveH.
have Hi1 : (i < size (mmtree_to_seq l)) = false
  by apply/negbTE; rewrite -leqNgt; exact: ltnW.
have Hi2 : (i == size (mmtree_to_seq l)) = false
  by apply/eqPHeq; rewrite -Heq ltnn in H.
by rewrite /window_size_t -/window_size_t Hi1 Hi2.
Qed.

Lemma has_left_child_t_Node_lt (l : mmtree nat) x r i :
  i < size (mmtree_to_seq l)
  has_left_child_t i (Node l x r) = has_left_child_t i l.
Proof. by rewrite /has_left_child_t -/has_left_child_t ⇒ →. Qed.

Lemma has_left_child_t_Node_eq l x (r : mmtree nat) :
  has_left_child_t (size (mmtree_to_seq l)) (Node l x r) =
    (0 < size (mmtree_to_seq l)).
Proof. by rewrite /has_left_child_t -/has_left_child_t ltnn eqxx. Qed.

Lemma has_left_child_t_Node_gt (l : mmtree nat) x r i :
  size (mmtree_to_seq l) < i
  has_left_child_t i (Node l x r) =
    has_left_child_t (i - (size (mmtree_to_seq l)).+1) r.
Proof.
moveH.
have Hi1 : (i < size (mmtree_to_seq l)) = false
  by apply/negbTE; rewrite -leqNgt; exact: ltnW.
have Hi2 : (i == size (mmtree_to_seq l)) = false
  by apply/eqPHeq; rewrite -Heq ltnn in H.
by rewrite /has_left_child_t -/has_left_child_t Hi1 Hi2.
Qed.

Lemma size_mmtree_to_seq_node (l : mmtree nat) (x : nat) (r : mmtree nat) :
  size (mmtree_to_seq (Node l x r)) =
    size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1.
Proof. by rewrite /= size_cat /= addnS. Qed.

Lemma has_left_child_t_0 : t, has_left_child_t 0 t = false.
Proof.
elim ⇒ [|l IHl x r _] //=.
rewrite /has_left_child_t -/has_left_child_t.
case Hsl : (0 < size (mmtree_to_seq l)).
  by rewrite IHl.
have → : (0 == size (mmtree_to_seq l)) = true.
  by case: (size (mmtree_to_seq l)) Hsl.
by case: (size (mmtree_to_seq l)) Hsl.
Qed.


Lemma window_size_t_eq : t i,
  valid_mm t
  window_size i (mmtree_to_seq t) = window_size_t i t.
Proof.
elim ⇒ [|l IHl x r IHr] i.
  by rewrite /window_size /window_size_fuel.
caseHmm [Hvl Hvr].
case: (ltngtP i (size (mmtree_to_seq l))) ⇒ Hi.
- by rewrite (ws_bridge_left Hmm Hi) (@window_size_t_Node_lt l x r i Hi) IHl.
- rewrite (ws_bridge_right Hmm Hi) (@window_size_t_Node_gt l x r i Hi).
  rewrite IHr //.
  by rewrite -subnDA addn1.
- have HiE : i = size (mmtree_to_seq l) by [].
  rewrite HiE (ws_bridge_root Hmm) window_size_t_Node_eq.
  rewrite size_mmtree_to_seq_node addnC.
  by rewrite -addnBA // subnn addn0.
Qed.

Lemma has_left_child_t_eq : t i,
  valid_mm t
  has_left_child i (mmtree_to_seq t) = has_left_child_t i t.
Proof.
elim ⇒ [|l IHl x r IHr] i.
  by rewrite /has_left_child /has_left_child_fuel; case: i.
caseHmm [Hvl Hvr].
case: (ltngtP i (size (mmtree_to_seq l))) ⇒ Hi.
- by rewrite (hlc_bridge_left Hmm Hi) (@has_left_child_t_Node_lt l x r i Hi) IHl.
- rewrite (hlc_bridge_right Hmm Hi) (@has_left_child_t_Node_gt l x r i Hi).
  rewrite IHr //.
  by rewrite -subnDA addn1.
- have HiE : i = size (mmtree_to_seq l) by [].
  by rewrite HiE (hlc_bridge_root Hmm) has_left_child_t_Node_eq.
Qed.

Lemma is_internal_t_eq : t i,
  valid_mm t
  is_internal i (mmtree_to_seq t) = is_internal_t i t.
Proof.
movet i Hv.
by rewrite /is_internal /is_internal_t (window_size_t_eq i Hv).
Qed.


Lemma endpoint_implies_next_t : t k,
  valid_mm t
  k.+1 < size (mmtree_to_seq t)
  ~~ is_internal_t k t has_left_child_t k.+1 t.
Proof.
elim ⇒ [|l IHl x r IHr] k.
  by rewrite /=.
caseHmm [Hvl Hvr].
rewrite size_mmtree_to_seq_nodeHk.
rewrite /is_internal_t size_mmtree_to_seq_node.
case: (ltngtP k (size (mmtree_to_seq l))) ⇒ [Hkl | Hkl | Hkl].
-
  case: (ltngtP k.+1 (size (mmtree_to_seq l))) ⇒ [Hk1l | Hk1l | Hk1l].
  +
    moveHep.
    rewrite (@has_left_child_t_Node_lt l x r k.+1 Hk1l).
    apply: IHl ⇒ //.
    move: Hep.
    have Hkbnd : k < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
      by apply: ltn_addr.
    rewrite Hkbnd /=.
    rewrite (@window_size_t_Node_lt l x r k Hkl).
    by rewrite /is_internal_t Hkl /=.
  +
    exfalso.
    move: Hk1l; rewrite ltnSH1.
    by have := leq_ltn_trans H1 Hkl; rewrite ltnn.
  +
    move_.
    rewrite Hk1l has_left_child_t_Node_eq.
    exact: leq_ltn_trans (leq0n _) Hkl.
-
  have Hk1l : size (mmtree_to_seq l) < k.+1 by exact: ltn_trans Hkl _.
  rewrite (@has_left_child_t_Node_gt l x r k.+1 Hk1l).
  have Hshift : k.+1 - (size (mmtree_to_seq l)).+1 =
                (k - (size (mmtree_to_seq l)).+1).+1
    by rewrite !subSn // ?ltnW //=.
  rewrite HshiftHep.
  have Hk_full : k < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
    by apply: leq_trans (leqnSn _) Hk.
  have Hk1_minus : k.+1 - (size (mmtree_to_seq l)).+1 < size (mmtree_to_seq r).
    rewrite ltn_subLR; last by rewrite ltnS ltnW.
    by rewrite addSn -addnS.
  have Hk_minus : k - (size (mmtree_to_seq l)).+1 < size (mmtree_to_seq r).
    apply: ltn_trans Hk1_minus.
    by rewrite Hshift ltnSn.
  apply: IHr ⇒ //.
  + by rewrite -Hshift.
  + rewrite /is_internal_t Hk_minus /=.
    move: Hep.
    rewrite Hk_full /=.
    by rewrite (@window_size_t_Node_gt l x r k Hkl).
-
  have Hk_full : k < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
    by apply: leq_trans (leqnSn _) Hk.
  rewrite Hk_full /=.
  rewrite Hkl window_size_t_Node_eq.
  case Hszr : (size (mmtree_to_seq r)) ⇒ [|n0] /=.
  - move_.
    by exfalso; move: Hk; rewrite Hkl Hszr addn1 ltnn.
  - by [].
Qed.


Lemma LR_pred_is_endpoint_t : t i,
  valid_mm t
  0 < i is_internal_t i t has_left_child_t i t
  ~~ is_internal_t i.-1 t.
Proof.
elim ⇒ [|l IHl x r IHr] i.
  by [].
caseHmm [Hvl Hvr] Hi0 Hint Hlc.
move: Hint Hlc; rewrite /is_internal_t.
rewrite size_mmtree_to_seq_node.
case: (ltngtP i (size (mmtree_to_seq l))) ⇒ [Hil | Hil | Hil].
-
  rewrite (@window_size_t_Node_lt l x r i Hil).
  rewrite (@has_left_child_t_Node_lt l x r i Hil).
  have Hibd : i < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
    by exact: ltn_addr.
  rewrite Hibd /= ⇒ Hwin Hlc.
  have Hint_l : is_internal_t i l by rewrite /is_internal_t Hil /=.
  have IH := IHl _ Hvl Hi0 Hint_l Hlc.
  have Hi1l : i.-1 < size (mmtree_to_seq l)
    by apply: leq_ltn_trans (leq_pred _) Hil.
  rewrite (@window_size_t_Node_lt l x r i.-1 Hi1l).
  have Hi1bd : i.-1 < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
    by exact: ltn_addr.
  rewrite Hi1bd /=.
  by move: IH; rewrite /is_internal_t Hi1l /=.
-
  rewrite (@window_size_t_Node_gt l x r i Hil).
  rewrite (@has_left_child_t_Node_gt l x r i Hil).
  case Hibd : (i < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1);
    last by [].
  rewrite /= ⇒ Hwin Hlc.
  set i' := i - (size (mmtree_to_seq l)).+1.
  have Hi'_lt : i' < size (mmtree_to_seq r).
    rewrite /i' ltn_subLR; last exact: Hil.
    by rewrite addSn -addnS.
  case Ei1 : (i.-1 == size (mmtree_to_seq l)).
  +
    move/eqP: Ei1Ei1.
    have Hi_eq : i = (size (mmtree_to_seq l)).+1
      by rewrite -Ei1 (prednK Hi0).
    have Hi'0 : i' = 0 by rewrite /i' Hi_eq subnn.
    by exfalso; rewrite -/i' Hi'0 has_left_child_t_0 in Hlc.
  +
    have Hi1_gt : size (mmtree_to_seq l) < i.-1.
      rewrite ltn_neqAle eq_sym Ei1 /=.
      by rewrite -ltnS prednK //; exact: ltnW.
    rewrite (@window_size_t_Node_gt l x r i.-1 Hi1_gt).
    have Hi1bd' : i.-1 < size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
      by apply: leq_ltn_trans (leq_pred _) Hibd.
    rewrite Hi1bd' /=.
    have Hi'0 : 0 < i'.
      rewrite /i' subn_gt0.
      rewrite ltn_neqAle.
      apply/andP; split.
        apply/eqPHeq.
        move/eqP: Ei1; apply.
        by rewrite -Heq /=.
      by [].
    have Hint_r : is_internal_t i' r
      by rewrite /is_internal_t Hi'_lt /=.
    have IH := IHr _ Hvr Hi'0 Hint_r Hlc.
    have Hi1_shift : i.-1 - (size (mmtree_to_seq l)).+1 = i'.-1
      by rewrite /i' predn_sub.
    rewrite Hi1_shift.
    move: IH; rewrite /is_internal_t.
    have Hi'1_lt : i'.-1 < size (mmtree_to_seq r)
      by apply: leq_ltn_trans (leq_pred _) Hi'_lt.
    by rewrite Hi'1_lt /=.
-
  rewrite Hil window_size_t_Node_eq has_left_child_t_Node_eq.
  have Hibd : size (mmtree_to_seq l) <
                size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
    by rewrite -[X in X < _]addn0 ltn_add2l.
  rewrite Hibd /=.
  move_ Hsl_pos.
  have Hi1l : (size (mmtree_to_seq l)).-1 < size (mmtree_to_seq l)
    by rewrite -ltnS prednK.
  rewrite (@window_size_t_Node_lt l x r _ Hi1l).
  have Hi1bd : (size (mmtree_to_seq l)).-1 <
                 size (mmtree_to_seq l) + (size (mmtree_to_seq r)).+1
    by apply: leq_ltn_trans (leq_pred _) Hibd.
  rewrite Hi1bd /=.
  rewrite -(window_size_t_eq _ Hvl) -ltnNge.
  by rewrite (window_size_last Hsl_pos).
Qed.


Lemma endpoint_implies_next_has_left_child :
   (k : nat) (w : seq nat),
    uniq w k.+1 < size w ~~ is_internal k w has_left_child k.+1 w.
Proof.
movek w Huniq Hk1 Hep.
have Hroundtrip : mmtree_to_seq (mmtree_of_seq_mm w) = w
  by exact: mmtree_of_seq_mmK.
have Hv : valid_mm (mmtree_of_seq_mm w) by exact: valid_mm_build.
rewrite -Hroundtrip.
rewrite (has_left_child_t_eq _ Hv).
apply: endpoint_implies_next_t ⇒ //.
- by rewrite Hroundtrip.
- by rewrite -(is_internal_t_eq _ Hv) Hroundtrip.
Qed.

Lemma LR_pred_is_endpoint :
   (i : nat) (w : seq nat),
    uniq w 0 < i is_internal i w
    has_left_child i w ~~ is_internal i.-1 w.
Proof.
movei w Huniq Hi0 Hint Hlc.
have Hroundtrip : mmtree_to_seq (mmtree_of_seq_mm w) = w
  by exact: mmtree_of_seq_mmK.
have Hv : valid_mm (mmtree_of_seq_mm w) by exact: valid_mm_build.
rewrite -Hroundtrip (is_internal_t_eq _ Hv).
apply: LR_pred_is_endpoint_t ⇒ //.
- by rewrite -(is_internal_t_eq _ Hv) Hroundtrip.
- by rewrite -(has_left_child_t_eq _ Hv) Hroundtrip.
Qed.

Example endpoint_next_has_left_child_ex :
  has_left_child 1 [:: 3; 1; 5; 4; 2; 6].
Proof. by vm_compute. Qed.

Example endpoint_next_has_left_child_ex2 :
  has_left_child 4 [:: 3; 1; 5; 4; 2; 6].
Proof. by vm_compute. Qed.

Example LR_pred_is_endpoint_ex :
  ~~ is_internal 0 [:: 3; 1; 5; 4; 2; 6].
Proof. by vm_compute. Qed.

Example LR_pred_is_endpoint_ex2 :
  ~~ is_internal 3 [:: 3; 1; 5; 4; 2; 6].
Proof. by vm_compute. Qed.

Example LR_pred_is_endpoint_ex3 :
  ~~ is_internal 4 [:: 3; 1; 4; 7; 5; 9; 2; 6].
Proof. by vm_compute. Qed.