HyPre.util.VectorPair

From Coq Require Import
     Lia
     Lists.List.
From Coq Require Import Program.Equality.

From HyPre Require Import Tac.

From HyPre Require Export
     ListExtra
     MonoidHomomorphism
     VectorExtra.
(* TODO Prove all the vectorpair lemmas *)

Lemma k_leq_2k {k} : k <= k+k.
Proof.
  clear. lia.
Qed.

Definition fst_vec {k} {X : Type} : Vector.t X (k+k) -> Vector.t X k
  := fun xt => Vector.rev (Vector.take k k_leq_2k (Vector.rev xt)).

Definition snd_vec {k} {X : Type} : Vector.t X (k+k) -> Vector.t X k
  := Vector.take k k_leq_2k.

Definition nth_pair {k} {X : Type} (i : Fin.t k) : Vector.t X (k+k) -> X * X
  := fun xt => (Vector.nth (fst_vec xt) i, Vector.nth (snd_vec xt) i).

Lemma x_minus_lt_k {k} : forall x, x < k+k -> x - k < k.
Proof.
  clear. lia.
Qed.

Definition depair_i {k} (i : Fin.t (k+k)) : bool * Fin.t k
  := let i_sig := Fin.to_nat i in
     let i1 := proj1_sig i_sig in
     let i2 := proj2_sig i_sig in
     match Compare_dec.lt_dec i1 k with
     | left H => (false, Fin.of_nat_lt H)
     | right _ => (true, Fin.of_nat_lt (x_minus_lt_k i1 i2))
     end.

Definition is_fst {k} (i : Fin.t (k+k)) : bool
  := let (r,_) := depair_i i in r.

Definition vec_k_comm {k k' : nat} {X : Type} (x : Vector.t X (k+k')) : Vector.t X (k'+k).
Proof.
  rewrite PeanoNat.Nat.add_comm.
  exact x.
Defined.

Lemma to_kk_snd_vec {k} {X : Type} (x y : Vector.t X k)
  : snd_vec (Vector.append y x) = y.
Proof.
  unfold snd_vec.
  rewrite Vector.take_app.
  reflexivity.
Qed.

Lemma to_kk_fst_vec {k} {X : Type} (x y : Vector.t X k)
  : fst_vec (Vector.append y x) = x.
Proof.
  setoid_rewrite <-vec_rev_rev with (xv:=x).
  setoid_rewrite <-vec_rev_rev with (xv:=y).
  unfold fst_vec.
  eapply vec_rev_rev_eq.
  rewrite vec_append_rev.
  rewrite vec_rev_rev.
  rewrite vec_rev_rev.
  specialize (to_kk_snd_vec (X:=X) (k:=k)) as Q.
  unfold snd_vec in Q.
  rewrite vec_rev_rev.
  eapply Q.
Qed.

Lemma snd_vec_const {k} {X : Type} (x : X)
  : snd_vec (Vector.const x (k+k)) = Vector.const x k.
Proof.
  unfold snd_vec.
  eapply vec_take_const.
Qed.

Lemma fst_vec_const {k} {X : Type} (x : X)
  : fst_vec (Vector.const x (k+k)) = Vector.const x k.
Proof.
  unfold fst_vec.
  rewrite vec_rev_const.
  rewrite vec_take_const.
  rewrite vec_rev_const.
  reflexivity.
Qed.

Lemma snd_vec_map2 {k} {X Y Z : Type} (f : X -> Y -> Z) (x y : Vector.t _ (k+k))
  : snd_vec (Vector.map2 f x y) = Vector.map2 f (snd_vec x) (snd_vec y).
Proof.
  unfold snd_vec.
  eapply vec_take_map2.
Qed.

Lemma fst_vec_map2 {k} {X Y Z : Type} (f : X -> Y -> Z) (x y : Vector.t _ (k+k))
  : fst_vec (Vector.map2 f x y) = Vector.map2 f (fst_vec x) (fst_vec y).
Proof.
  unfold fst_vec.
  rewrite <-vec_rev_map2.
  rewrite vec_rev_map2.
  eapply vec_eq_rev_rev.
  eapply vec_take_map2.
Qed.

Lemma depair_i_nlt {k} (i : Fin.t (k+k)) j
  : (true, j) = depair_i i -> not (proj1_sig (Fin.to_nat i) < k).
Proof.
  intros.
  unfold depair_i in H.
  destruct (Compare_dec.lt_dec (proj1_sig (Fin.to_nat i)) k).
  - congruence.
  - assumption.
Qed.

Lemma depair_i_lt {k} (i : Fin.t (k+k)) j
  : (false, j) = depair_i i -> (proj1_sig (Fin.to_nat i) < k).
Proof.
  intros.
  unfold depair_i in H.
  destruct (Compare_dec.lt_dec (proj1_sig (Fin.to_nat i)) k).
  - assumption.
  - congruence.
Qed.

Lemma vec_take_nth {k n} {X : Type} (H : k <= n) (a : Vector.t X n) (i : Fin.t n) (j : Fin.t k)
  : proj1_sig (Fin.to_nat j) = proj1_sig (Fin.to_nat i) -> Vector.take k H a [[j]] = a [[i]].
Proof.
  revert j.
  revert dependent n.
  dependent induction k;intros.
  - inversion j.
  - dependent destruction a.
    + inversion H.
    + dependent destruction i; dependent destruction j.
      * cbn.
        reflexivity.
      * exfalso.
        cbn in H0. destruct (Fin.to_nat j).
        cbn in H0.
        congruence.
      * cbn in H0.
        destruct (Fin.to_nat i) eqn:E.
        cbn in H0.
        congruence.
      * cbn. cbn in H0.
        destruct (Fin.to_nat i) eqn:Ei.
        destruct (Fin.to_nat j) eqn:Ej.
        cbn in H0.
        eapply IHk.
        rewrite Ei,Ej.
        cbn.
        lia.
Qed.

Lemma snd_vec_nth {k} {X : Type} (a : Vector.t X (k+k)) i j
  : (false, j) = depair_i i -> snd_vec a [[j]] = a[[i]].
Proof.
  dependent destruction k;intros.
  - inversion j.
  - unfold depair_i in H.
    match goal with [H: _ = match ?x with _=>_ end |- _] => destruct x end.
    + inversion H.
      unfold snd_vec.
      eapply vec_take_nth.
      cbn.
      rewrite Fin.to_nat_of_nat.
      cbn.
      reflexivity.
    + congruence.
Qed.

Lemma fst_vec_nth {k} {X : Type} (a : Vector.t X (k+k)) i j
  : (true, j) = depair_i i -> fst_vec a [[j]] = a[[i]].
Proof.
  dependent destruction k;intros.
  - inversion j.
  - unfold depair_i in H.
    match goal with [H: _ = match ?x with _=>_ end |- _] => destruct x end.
    + congruence.
    + inversion H.
      unfold fst_vec.
      progress cbn in n.
      assert (S k <= proj1_sig (Fin.to_nat i)) as Q by (cbn;lia).
      progress cbn in Q.
      progress cbn in H.
      match goal with [Q: _ <= proj1_sig ?x |-_] => destruct x as [i' ?] eqn:E end.
      cbn in Q.
      match goal with [|- Vector.rev _ [[ ?x ]] = _] => cbn_this x end.
      clear H n.
      assert (S (k + k) - i' < S k + S k) as Hlt by lia.
      setoid_rewrite <-vec_rev_nth with (i:=Fin.of_nat_lt Hlt) (a:=a);cycle 1.
      * rewrite Fin.to_nat_of_nat.
        cbn.
        rewrite E.
        cbn.
        destruct i';lia.
      * assert (S k + k - i' < S k) as Hlt'.
        {
          destruct i'. lia.
          lia.
        }
        setoid_rewrite vec_rev_nth with (j:=Fin.of_nat_lt Hlt');cycle 1.
        -- setoid_rewrite Fin.to_nat_of_nat.
           cbn.
           destruct i';[inversion Q|].
           lia.
        -- setoid_rewrite vec_take_nth.
           reflexivity.
           setoid_rewrite Fin.to_nat_of_nat.
           cbn.
           reflexivity.
Qed.

Section with_kMH.
  Context {k : nat}.
  Context `{MH : MonoidHomomorphism}.

  Global Instance MapVecMonHom
    : MonoidHomomorphism (Vector.map hom (n:=k)).
  Proof.
    econstructor.
    - intros.
      cbn.
      rewrite vec_map_map2.
      rewrite <-vec_map2_fun_app.
      eapply vec_map2_ext.
      setoid_rewrite homomorph.
      reflexivity.
    - cbn.
      rewrite vec_map_const.
      rewrite homomorph_unit.
      reflexivity.
  Qed.
End with_kMH.

Section with_kM.
  Context {k : nat}.

  Definition vpl_to_kk (v : Vector.t (nat * nat) k)
    := Vector.append (Vector.map snd v) (Vector.map fst v).

  Global Instance to_kk_hom
    : MonoidHomomorphism vpl_to_kk.
  Proof.
    econstructor.
    - intros.
      unfold vpl_to_kk.
      unfold monoid_plus at 3. unfold MonVecMon.
      setoid_rewrite vec_map2_app.
      f_equal.
      + setoid_rewrite vec_map_map2.
        setoid_rewrite <-vec_map2_fun_app.
        eapply vec_map2_ext.
        intros.
        destruct x, y. cbn.
        reflexivity.
      + setoid_rewrite vec_map_map2.
        setoid_rewrite <-vec_map2_fun_app.
        eapply vec_map2_ext.
        intros.
        destruct x, y. cbn.
        reflexivity.
    - cbn.
      setoid_rewrite vec_map_const.
      cbn.
      eapply vec_append_const.
  Qed.
End with_kM.
Arguments MapVecMonHom _ {_ _ _ _} _ {_}.

Section with_kXY.
  Context {X Y : Type}.
  Context {k : nat}.

  Definition pair_len (xy : list X * list Y) := let (x,y) := xy in (length x, length y).

  Global Instance pair_len_hom
    : MonoidHomomorphism pair_len.
  Proof.
    econstructor.
    - intros.
      destruct m1 as [m11 m12]. destruct m2 as [m21 m22].
      cbn.
      setoid_rewrite app_length.
      reflexivity.
    - cbn.
      reflexivity.
  Qed.

  Definition vpl_len (v : Vector.t (list X * list Y) k)
    := Vector.map pair_len v.

  Global Instance vpl_len_hom
    : MonoidHomomorphism vpl_len.
  Proof.
    econstructor.
    - intros.
      unfold vpl_len.
      specialize (MapVecMonHom k pair_len) as Q.
      eapply Q.
    - cbn.
      rewrite vec_map_const.
      cbn.
      reflexivity.
  Qed.

  Definition vpl_len_kk (v : Vector.t (list X * list Y) k)
    := vpl_to_kk (vpl_len v).

  Global Instance vpl_len_kk_hom
    : @MonoidHomomorphism _ _ (MonVecMon _) (MonVecMon _) vpl_len_kk.
  Proof.
    econstructor.
    - intros.
      unfold vpl_len_kk.
      setoid_rewrite homomorph.
      generalize (vpl_len m1) as v1.
      generalize (vpl_len m2) as v2.
      intros.
      eapply to_kk_hom.
    - cbn.
      setoid_rewrite Vector.map_map.
      setoid_rewrite vec_map_const.
      rewrite vec_append_const.
      cbn.
      reflexivity.
  Qed.
End with_kXY.

From HyPre Require Export VectorList.

Lemma vpl_len_kk_snd_vec {k} {X Y : Type} (a : Vector.t (list X * list Y) k)
  : snd_vec (vpl_len_kk a) = vl_len (Vector.map snd a).
Proof.
  unfold snd_vec, vpl_len_kk, vl_len, vpl_to_kk, vpl_len.
  setoid_rewrite Vector.take_app.
  dependent induction a.
  - cbn.
    reflexivity.
  - cbn.
    f_equal.
    + unfold pair_len.
      destruct h;cbn.
      reflexivity.
    + eapply IHa.
Qed.

Lemma vpl_len_kk_fst_vec {k} {X Y : Type} (x : Vector.t (list X * list Y) k)
  : fst_vec (vpl_len_kk x) = vl_len (Vector.map fst x).
Proof.
  unfold fst_vec, vpl_len_kk, vl_len, vpl_to_kk, vpl_len.
  rewrite <-vec_append_rev.
  rewrite Vector.take_app.
  rewrite vec_rev_rev.
  dependent induction x;cbn.
  - reflexivity.
  - f_equal.
    + unfold pair_len.
      destruct h;cbn.
      reflexivity.
    + eapply IHx.
Qed.

Import VectorListNotations.

(*Lemma vec_map2_map2 {k} {X Y Z W : Type} (f : X -> Y -> Z) (g : Z -> Z -> W) x1 x2 y1 y2
  : Vector.map2 g (Vector.map2 f x1 y1) (Vector.map2 f x2 y2) = Vector.map2 (fun x y => g (f x y)) x y.*)


Lemma vec_pair_fg {k} {T : Type -> Type} {X Y : Type}
      (x1 x2 : Vector.t (T X) k) (y1 y2 : Vector.t (T Y) k)
      (f : T X * T Y -> T X * T Y -> T X * T Y) (g : forall Z, T Z -> T Z -> T Z)
  : (forall a1 a2 b1 b2, f (a1,b1) (a2,b2) = (g X a1 a2, g Y b1 b2))
    -> Vector.map2 f (Vector.map2 pair x1 y1) (Vector.map2 pair x2 y2)
    = Vector.map2 pair (Vector.map2 (g X) x1 x2) (Vector.map2 (g Y) y1 y2).
Proof.
  intros H.
  dependent induction x1;
    dependent destruction x2;
    dependent destruction y1;
    dependent destruction y2;
    cbn.
  - reflexivity.
  - f_equal.
    + eapply H.
    + eapply IHx1;eauto.
Qed.

Lemma t_combine_monoid_plus {k} {X Y : Type} (x1 x2 : Vector.t (list X) k) (y1 y2 : Vector.t (list Y) k)
  : monoid_plus (t_combine x1 y1) (t_combine x2 y2) = t_combine (x1 +vl+ x2) (y1 +vl+ y2).
Proof.
  eapply vec_pair_fg.
  clear.
  intros.
  cbn.
  reflexivity.
Qed.

Lemma vec_map2_fst {k} {X Y : Type} (xt : Vector.t X k) (yt : Vector.t Y k)
  : Vector.map2 (fun x _ => x) xt yt = xt.
Proof.
  dependent induction xt;dependent destruction yt;cbn.
  - reflexivity.
  - f_equal.
    eapply IHxt.
Qed.

Lemma vec_map2_snd {k} {X Y : Type} (xt : Vector.t X k) (yt : Vector.t Y k)
  : Vector.map2 (fun _ y => y) xt yt = yt.
Proof.
  dependent induction xt;dependent destruction yt;cbn.
  - reflexivity.
  - f_equal.
    eapply IHxt.
Qed.

Lemma vpl_to_kk_t_combine {k} (a b : Vector.t nat k)
  : vpl_to_kk (t_combine a b) = Vector.append b a.
Proof.
  unfold vpl_to_kk, t_combine.
  setoid_rewrite vec_map_map2.
  cbn.
  rewrite vec_map2_fst.
  rewrite vec_map2_snd.
  reflexivity.
Qed.

Lemma vpl_len_t_combine {k} {X Y : Type} (x : Vector.t (list X) k) (y : Vector.t (list Y) k)
  : vpl_len (t_combine x y) = t_combine (vl_len x) (vl_len y).
Proof.
  unfold vpl_len,t_combine.
  rewrite vec_map_map2.
  unfold vl_len.
  rewrite <-vec_map2_fun_app.
  unfold pair_len.
  reflexivity.
Qed.

Lemma to_kk_self {k} {X : Type} (x : Vector.t X (k+k))
  : Vector.append (snd_vec x) (fst_vec x) = x.
Proof.
  unfold snd_vec, fst_vec.
  eapply list_eq_vec_eq.
  setoid_rewrite Vector.to_list_append.
  setoid_rewrite Vector.to_list_rev.
  setoid_rewrite vec_to_list_take.
  setoid_rewrite Vector.to_list_rev.
  setoid_rewrite firstn_rev.
  rewrite rev_involutive.
  rewrite Vector.length_to_list.
  replace (k + k - k) with k by lia.
  eapply firstn_skipn.
Qed.

Lemma vpl_len_kk_eq_inv {k} {X Y : Type} (a b : Vector.t (list X * list Y) k)
  : vpl_len_kk a = vpl_len_kk b
    -> vl_len (Vector.map fst a) = vl_len (Vector.map fst b) /\ vl_len (Vector.map snd a) = vl_len (Vector.map snd b).
Proof.
  intros.
  setoid_rewrite <-vpl_len_kk_fst_vec.
  setoid_rewrite <-vpl_len_kk_snd_vec.
  split;f_equal;assumption.
Qed.

Import MonoidHomomorphismNotations.

Lemma vec_map2_map2_inj {k} {X Y Z : Type} (f : X -> Y -> Z) (xt1 xt2 yt1 yt2 : Vector.t _ k)
      (Hinj : forall x1 x2 y1 y2, f x1 y1 = f x2 y2 -> x1 = x2 /\ y1 = y2)
      (Hmap : Vector.map2 f xt1 yt1 = Vector.map2 f xt2 yt2)
  : xt1 = xt2 /\ yt1 = yt2.
Abort.

Lemma vpl_len_kk_plus_eq1 {k} {X Y : Type} (a1 a2 b1 b2 : Vector.t (list X * list Y) k)
  : a2 +m+ a1 = b2 +m+ b1 -> vpl_len_kk a1 = vpl_len_kk b1 -> a1 = b1 /\ a2 = b2.
Proof.
  intros.
  cbn in H.
  eapply vpl_len_kk_eq_inv in H0.
  unfold vl_len in H0.
  setoid_rewrite Vector.map_map in H0.
  destruct H0 as [Q1 Q2].
  revert a2 b1 b2 H Q1 Q2.
  dependent induction a1;
    dependent destruction a2;
    dependent destruction b1;
    dependent destruction b2;
    cbn;intros.
  - split;reflexivity.
  - destruct h0,h1,h2,h.
    dependent destruction H.
    cbn in Q1,Q2.
    dependent destruction Q1;dependent destruction Q2.
    eapply length_app_eq in x1;eauto.
    eapply length_app_eq in x2;eauto.
    specialize (IHa1 a2 b1 b2).
    exploit IHa1.
    split;f_equal;firstorder.
    all:f_equal;firstorder.
Qed.

Lemma vec_map2_map_1 {k} {X X' Y Z : Type} (f : X' -> Y -> Z) (g : X -> X') (xt yt : Vector.t _ k)
  : Vector.map2 (fun x y => f (g x) y) xt yt = Vector.map2 (fun x y => f x y) (Vector.map g xt) yt.
Proof.
  dependent induction xt; dependent destruction yt;cbn.
  - reflexivity.
  - f_equal.
    eapply IHxt.
Qed.

Lemma vec_map2_map_2 {k} {X Y Y' Z : Type} (f : X -> Y' -> Z) (g : Y -> Y') (xt yt : Vector.t _ k)
  : Vector.map2 (fun x y => f x (g y)) xt yt = Vector.map2 (fun x y => f x y) xt (Vector.map g yt).
Proof.
  dependent induction xt; dependent destruction yt;cbn.
  - reflexivity.
  - f_equal.
    eapply IHxt.
Qed.

Lemma vl_len_le_v1 {k} {X : Type} (a : Vector.t (list X) k) v1 v2
  (Hvl : vl_len a = v1 +m+ v2)
  : Vector.Forall2 (fun x y => x <= length y) v1 a.
Proof.
  revert v1 v2 Hvl.
  dependent induction a;
    dependent destruction v1;
    dependent destruction v2;
    cbn;intros.
  - econstructor.
  - dependent destruction Hvl.
    econstructor.
    + lia.
    + eauto.
Qed.

Lemma vl_len_le_v2 {k} {X : Type} (a : Vector.t (list X) k) v1 v2
  (Hvl : vl_len a = v1 +m+ v2)
  : Vector.Forall2 (fun x y => x <= length y) v2 a.
Proof.
  revert v1 v2 Hvl.
  dependent induction a;
    dependent destruction v1;
    dependent destruction v2;
    cbn;intros.
  - econstructor.
  - dependent destruction Hvl.
    econstructor.
    + lia.
    + eauto.
Qed.

Global Instance fst_vec_MonHom (k : nat)
  : MonoidHomomorphism (fst_vec (k:=k)).
Proof.
  econstructor.
  - intros.
    unfold fst_vec.
    setoid_rewrite vec_rev_map2.
    setoid_rewrite vec_take_map2.
    setoid_rewrite vec_rev_map2.
    reflexivity.
  - unfold fst_vec.
    cbn.
    setoid_rewrite vec_rev_const.
    setoid_rewrite vec_take_const.
    eapply vec_rev_const.
Qed.

Global Instance snd_vec_MonHom (k : nat)
  : MonoidHomomorphism (snd_vec (k:=k)).
Proof.
  econstructor.
  - intros.
    unfold snd_vec.
    cbn.
    setoid_rewrite vec_take_map2.
    reflexivity.
  - unfold snd_vec.
    cbn.
    setoid_rewrite vec_take_const.
    reflexivity.
Qed.

Lemma vpl_len_kk_le_v1_fst {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
      (Hvpl : vpl_len_kk a = v1 +m+ v2)
  : Vector.Forall2 (fun x y => x <= length y) (fst_vec v1) (Vector.map fst a).
Proof.
  eapply f_equal with (f:=fst_vec) in Hvpl.
  rewrite vpl_len_kk_fst_vec in Hvpl.
  unfold vpl_len_kk, vpl_to_kk in Hvpl.
  rewrite homomorph in Hvpl.
  eapply vl_len_le_v1.
  eassumption.
Qed.

Lemma vpl_len_kk_le_v1_snd {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
      (Hvpl : vpl_len_kk a = v1 +m+ v2)
  : Vector.Forall2 (fun x y => x <= length y) (snd_vec v1) (Vector.map snd a).
Proof.
  eapply f_equal with (f:=snd_vec) in Hvpl.
  rewrite vpl_len_kk_snd_vec in Hvpl.
  unfold vpl_len_kk, vpl_to_kk in Hvpl.
  rewrite homomorph in Hvpl.
  eapply vl_len_le_v1.
  eassumption.
Qed.

Lemma vpl_len_kk_le_v2_fst {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
      (Hvpl : vpl_len_kk a = v1 +m+ v2)
  : Vector.Forall2 (fun x y => x <= length y) (fst_vec v2) (Vector.map fst a).
Proof.
  eapply f_equal with (f:=fst_vec) in Hvpl.
  rewrite vpl_len_kk_fst_vec in Hvpl.
  unfold vpl_len_kk, vpl_to_kk in Hvpl.
  rewrite homomorph in Hvpl.
  eapply vl_len_le_v2.
  eassumption.
Qed.

Lemma vpl_len_kk_le_v2_snd {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
      (Hvpl : vpl_len_kk a = v1 +m+ v2)
  : Vector.Forall2 (fun x y => x <= length y) (snd_vec v2) (Vector.map snd a).
Proof.
  eapply f_equal with (f:=snd_vec) in Hvpl.
  rewrite vpl_len_kk_snd_vec in Hvpl.
  unfold vpl_len_kk, vpl_to_kk in Hvpl.
  rewrite homomorph in Hvpl.
  eapply vl_len_le_v2.
  eassumption.
Qed.

Lemma len_nat_min_eq {k} {X : Type} (a : Vector.t X k) v f
  (Hfa : Vector.Forall2 (fun x y => x <= f y) v a)
  : Vector.map2 (fun x y => Nat.min x (f y)) v a = v.
Proof.
  dependent induction Hfa;cbn.
  - reflexivity.
  - f_equal.
    + lia.
    + eauto.
Qed.

Lemma vpl_len_kk_surj_v1 {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
  : vpl_len_kk a = v1 +m+ v2
    -> let a1 := Vector.map2 (fun (ij : nat * nat) x => let (i,j) := ij in
                                                (firstn i (fst x), firstn j (snd x))
                            )
                            (Vector.map2 pair (fst_vec v1) (snd_vec v1))
                            a in
      vpl_len_kk a1 = v1.
Proof.
  intros.
  subst a1.
  unfold vpl_len_kk,vpl_len,vpl_to_kk.
  unfold pair_len.
  setoid_rewrite vec_map_map2.
  setoid_rewrite vec_map_map2.
  match goal with |- Vector.append (Vector.map2 ?x _ _) _ = _
                  => rewrite vec_map2_ext with (g:=fun i y => length (firstn (snd i) (snd y))) end.
  match goal with |- Vector.append (Vector.map2 ?x _ _) _ = _
                  => setoid_rewrite vec_map2_ext with (g:=fun i y => length (firstn (fst i) (fst y))) at 2 end.
  2,3:intros;destruct x;cbn;reflexivity.
  set (v:=Vector.map2 pair (fst_vec v1) (snd_vec v1)).
  set (f:=fun (A:Type) i (y : list A) => length (firstn i y)).
  assert ((fun (i : nat * nat) (y : list X * list Y) => length (firstn (snd i) (snd y)))
          = (fun i y => f Y (snd i) (snd y))) as Fy by reflexivity.
  assert ((fun (i : nat * nat) (y : list X * list Y) => length (firstn (fst i) (fst y)))
          = (fun i y => f X (fst i) (fst y))) as Fx by reflexivity.
  rewrite Fy,Fx.
  rewrite vec_map2_map_1 with (f:=fun x y => f Y x (snd y)) (g:=snd).
  rewrite vec_map2_map_1 with (f:=fun x y => f X x (fst y)) (g:=fst).
  rewrite vec_map2_map_2 with (f:=fun x y => f Y x y) (g:=snd).
  rewrite vec_map2_map_2 with (f:=fun x y => f X x y) (g:=fst).
  subst v.
  setoid_rewrite vec_map_map2.
  cbn.
  rewrite vec_map2_fst.
  rewrite vec_map2_snd.
  setoid_rewrite vec_map2_ext with (g:=fun x y => Nat.min x (length y)).
  2,3: intros; eapply firstn_length.
  setoid_rewrite len_nat_min_eq.
  - eapply to_kk_self.
  - eapply vpl_len_kk_le_v1_snd;eauto.
  - eapply vpl_len_kk_le_v1_fst;eauto.
Qed.

Lemma vpl_len_kk_surj_v2 {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
  : vpl_len_kk a = v1 +m+ v2
    -> let a2 := Vector.map2 (fun (ij : nat * nat) x => let (i,j) := ij in
                                                (skipn i (fst x), skipn j (snd x))
                            )
                            (Vector.map2 pair (fst_vec v1) (snd_vec v1))
                            a in
      vpl_len_kk a2 = v2.
Proof.
  intros.
  subst a2.
  unfold vpl_len_kk,vpl_len,vpl_to_kk.
  unfold pair_len.
  setoid_rewrite vec_map_map2.
  setoid_rewrite vec_map_map2.
  match goal with |- Vector.append (Vector.map2 ?x _ _) _ = _
                  => rewrite vec_map2_ext with (g:=fun i y => length (skipn (snd i) (snd y))) end.
  match goal with |- Vector.append (Vector.map2 ?x _ _) _ = _
                  => setoid_rewrite vec_map2_ext with (g:=fun i y => length (skipn (fst i) (fst y))) at 2 end.
  2,3:intros;destruct x;cbn;reflexivity.
  set (v:=Vector.map2 pair (fst_vec v1) (snd_vec v1)).
  setoid_rewrite vec_map2_ext with (f:=fun i y => length (skipn (snd i) (snd y))) (g:=fun i y => length (snd y) - snd i).
  setoid_rewrite vec_map2_ext with (g:=fun i y => length (fst y) - fst i) at 2.
  2,3: intros; now eapply skipn_length.
  set (f:=fun (A : Type) i (y : list A) => length y - i).
  assert ((fun (i : nat * nat) (y : list X * list Y) => length (snd y) - snd i)
          = (fun i y => f Y (snd i) (snd y))) as Fy by reflexivity.
  assert ((fun (i : nat * nat) (y : list X * list Y) => length (fst y) - fst i)
          = (fun i y => f X (fst i) (fst y))) as Fx by reflexivity.
  rewrite Fy,Fx.
  rewrite vec_map2_map_1 with (f:=fun x y => f Y x (snd y)) (g:=snd).
  rewrite vec_map2_map_1 with (f:=fun x y => f X x (fst y)) (g:=fst).
  rewrite vec_map2_map_2 with (f:=fun x y => f Y x y) (g:=snd).
  rewrite vec_map2_map_2 with (f:=fun x y => f X x y) (g:=fst).
  subst f.
  setoid_rewrite vec_map2_map_2 with (f:=fun x y => y - x) (g:=@length _).
  setoid_rewrite <-vec_map2_app.
  enough (Vector.map2 (fun x y => y - x) v1 (vpl_len_kk a) = v2).
  {
    rewrite <-H0.
    f_equal.
    - subst v.
      setoid_rewrite vec_map_map2.
      cbn.
      rewrite vec_map2_fst.
      rewrite vec_map2_snd.
      eapply to_kk_self.
    - unfold vpl_len_kk, vpl_to_kk, vpl_len.
      setoid_rewrite Vector.map_map.
      unfold pair_len.
      f_equal.
      + eapply Vector.map_ext.
        intros.
        destruct a0;cbn.
        reflexivity.
      + eapply Vector.map_ext.
        intros.
        destruct a0;cbn.
        reflexivity.
  }
  rewrite H.
  clear.
  eapply list_eq_vec_eq.
  rewrite vec_to_list_map2.
  setoid_rewrite vec_to_list_map2.
  specialize (Vector.length_to_list _ _ v1) as Q1.
  specialize (Vector.length_to_list _ _ v2) as Q2.
  rewrite <-Q2 in Q1.
  clear Q2.
  revert Q1.
  generalize (Vector.to_list v1).
  generalize (Vector.to_list v2).
  intro l.
  induction l;intros;cbn.
  - destruct l;cbn in Q1;[|congruence].
    cbn.
    reflexivity.
  - destruct l0;cbn in Q1;[congruence|].
    cbn.
    f_equal.
    + lia.
    + eapply IHl.
      lia.
Qed.

Lemma vec_map4_eq13_eq24_ext {A B E : Type}
      (f f' : A -> B -> A -> B -> E) {n : nat}
      (H : forall a' b', f a' b' a' b' = f' a' b' a' b')
      (a : Vector.t A n) (b : Vector.t B n)
  : map4 f a b a b = map4 f' a b a b.
Proof.
  dependent induction a;
    dependent destruction b;
    cbn.
  - reflexivity.
  - f_equal.
    + eapply H.
    + eapply IHa.
Qed.

Lemma vec_map4_eq13_eq24_map2 {A B E : Type}
      (f : A -> B -> A -> B -> E) {n : nat}
      (a : Vector.t A n) (b : Vector.t B n)
  : map4 f a b a b = Vector.map2 (fun a' b' => f a' b' a' b') a b.
Proof.
  dependent induction a;
    dependent destruction b;
    cbn.
  - reflexivity.
  - f_equal.
    eapply IHa.
Qed.

Lemma vpl_len_kk_surj_aeq {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
  : vpl_len_kk a = v1 +m+ v2
    -> let a1 := Vector.map2 (fun (ij : nat * nat) x => let (i,j) := ij in
                                                (firstn i (fst x), firstn j (snd x))
                            )
                            (Vector.map2 pair (fst_vec v1) (snd_vec v1))
                            a in
      let a2 := Vector.map2 (fun (ij : nat * nat) x => let (i,j) := ij in
                                                (skipn i (fst x), skipn j (snd x))
                            )
                            (Vector.map2 pair (fst_vec v1) (snd_vec v1))
                            a in
      a = a1 +m+ a2.
Proof.
  intros.
  subst a1 a2.
  setoid_rewrite vec_map2_map2_map4.
  rewrite vec_map4_eq13_eq24_map2.
  setoid_rewrite vec_map2_ext with (g:=fun _ x => x).
  - rewrite vec_map2_snd.
    reflexivity.
  - clear.
    intros.
    destruct x as [i j].
    cbn.
    setoid_rewrite firstn_skipn.
    symmetry.
    eapply surjective_pairing.
Qed.

Lemma vpl_len_kk_surj_eq' {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
  : vpl_len_kk a = v1 +m+ v2
    -> let a1 := Vector.map2 (fun (ij : nat * nat) x => let (i,j) := ij in
                                                (firstn i (fst x), firstn j (snd x))
                            )
                            (Vector.map2 pair (fst_vec v1) (snd_vec v1))
                            a in
      let a2 := Vector.map2 (fun (ij : nat * nat) x => let (i,j) := ij in
                                                (skipn i (fst x), skipn j (snd x))
                            )
                            (Vector.map2 pair (fst_vec v1) (snd_vec v1))
                            a in
      vpl_len_kk a1 = v1 /\ vpl_len_kk a2 = v2 /\ a = a1 +m+ a2.
Proof.
  intros.
  split_conj.
  - eapply vpl_len_kk_surj_v1;eauto.
  - eapply vpl_len_kk_surj_v2;eauto.
  - eapply vpl_len_kk_surj_aeq;eauto.
Qed.

Lemma vpl_len_kk_surj_eq {k} {X Y : Type} (a : Vector.t (list X * list Y) k) v1 v2
  : vpl_len_kk a = v1 +m+ v2 -> exists a1 a2, vpl_len_kk a1 = v1 /\ vpl_len_kk a2 = v2 /\ a = a1 +m+ a2.
Proof.
  intros.
  eexists;eexists.
  eapply vpl_len_kk_surj_eq'.
  assumption.
Qed.

Lemma vec_app_unit1 {k n} (a : Vector.t _ k) (b : Vector.t _ n)
  : Vector.append a b = monoid_unit -> a = monoid_unit.
Proof.
  revert b.
  dependent induction a;
    intros;
    cbn.
  - split;reflexivity.
  - cbn in H.
    dependent destruction H.
    f_equal.
    eapply IHa;eauto.
Qed.

Lemma vec_app_unit2 {k n} (a : Vector.t _ k) (b : Vector.t _ n)
  : Vector.append a b = monoid_unit -> b = monoid_unit.
Proof.
  revert b.
  dependent induction a;cbn;intros.
  - assumption.
  - eapply IHa.
    dependent destruction H.
    assumption.
Qed.

Lemma vpl_len_zero_zero {k} {X Y : Type} (a : Vector.t (list X * list Y) k)
  : vpl_len a = monoid_unit -> a = monoid_unit.
Proof.
  dependent induction a;intros;cbn.
  - reflexivity.
  - dependent destruction H.
    f_equal.
    + unfold pair_len in x.
      destruct h.
      inversion x.
      rewrite H0 in H1.
      f_equal; eapply length_zero_iff_nil;eauto.
    + eapply IHa;eauto.
Qed.

Lemma vec_map_unit_nat {k} (a : Vector.t (nat * nat) k)
  : Vector.map fst a = monoid_unit -> Vector.map snd a = monoid_unit -> a = monoid_unit.
Proof.
  intros.
  setoid_rewrite t_combine_self at 1.
  setoid_rewrite H.
  setoid_rewrite H0.
  unfold t_combine.
  clear.
  induction k;cbn.
  - reflexivity.
  - f_equal.
    eapply IHk.
Qed.

Lemma vpl_len_kk_zero_zero {k} {X Y : Type} (a : Vector.t (list X * list Y) k)
  : vpl_len_kk a = monoid_unit -> a = monoid_unit.
Proof.
  intros.
  unfold vpl_len_kk,vpl_to_kk in H.
  eapply vec_app_unit1 in H as Q1.
  eapply vec_app_unit2 in H as Q2.
  eapply vec_map_unit_nat in Q2;eauto.
  eapply vpl_len_zero_zero;eauto.
Qed.

Definition vec_unzip {k} {X Y : Type} (vp : Vector.t (X * Y) k) : Vector.t X k * Vector.t Y k.
Proof.
  dependent induction vp.
  - econstructor;econstructor.
  - destruct IHvp as [IHx IHy].
    destruct h as [x y].
    econstructor;econstructor.
    all:eauto.
Defined.

Definition vec_zip {k} {X Y : Type} (x : Vector.t X k) (y : Vector.t Y k) : Vector.t (X * Y) k.
Proof.
  dependent induction x;
    dependent destruction y.
  - econstructor.
  - econstructor.
    + econstructor;eauto.
    + eapply IHx;eauto.
Defined.

Lemma vec_unzip_cons {k} {X Y : Type} (vp : Vector.t (X * Y) k) x y
  : vec_unzip (Vector.cons _ (x,y) _ vp)
    = (Vector.cons _ x _ (fst (vec_unzip vp)) , Vector.cons _ y _ (snd (vec_unzip vp))).
Proof.
  revert x y.
  dependent induction vp;intros.
  - cbn.
    reflexivity.
  - destruct h.
    specialize (IHvp x0 y0).
    setoid_rewrite IHvp.
    match goal with |- _ = ?x => cbn_this x end.
    cbn.
    match goal with [|- (match match ?x with _=>_ end with _=>_ end) = _]
                    => rewrite surjective_pairing with (p:=x) end.
    f_equal.
Qed.

Lemma vec_zip_cons {k} {X Y : Type} (xt : Vector.t X k) (yt : Vector.t Y k) x y
  : vec_zip (Vector.cons _ x _ xt) (Vector.cons _ y _ yt) = Vector.cons _ (x,y) _ (vec_zip xt yt).
Proof.
  dependent induction xt;
    dependent destruction yt.
  - cbn.
    reflexivity.
  - cbn.
    f_equal.
Qed.

Lemma vec_zip_unzip {k} {X Y : Type} (vp : Vector.t (X * Y) k)
  : let (x,y) := vec_unzip vp in vec_zip x y = vp.
Proof.
  rewrite surjective_pairing with (p:=vec_unzip vp).
  dependent induction vp.
  - cbn.
    reflexivity.
  - destruct h.
    rewrite vec_unzip_cons.
    unfold fst at 1.
    unfold snd at 1.
    rewrite vec_zip_cons.
    f_equal.
    eapply IHvp.
Qed.

Lemma vec_unzip_eq_map {k} {X Y : Type} (xyt : Vector.t _ k)
  : vec_unzip xyt
    = (Vector.map fst xyt, Vector.map (@snd X Y) xyt).
Proof.
  dependent induction xyt.
  - econstructor.
  - destruct h.
    setoid_rewrite vec_unzip_cons.
    setoid_rewrite IHxyt.
    unfold fst at 1.
    unfold snd at 1.
    cbn.
    reflexivity.
Qed.

Lemma vec_unzip_map2 {k} {X Y Z1 Z2 : Type} (f : X -> Y -> Z1 * Z2) (xt yt : Vector.t _ k)
  : vec_unzip (Vector.map2 f xt yt)
    = (Vector.map2 (fun x y => fst (f x y)) xt yt, Vector.map2 (fun x y => snd (f x y)) xt yt).
Proof.
  setoid_rewrite <-vec_map_map2.
  setoid_rewrite vec_unzip_eq_map.
  reflexivity.
Qed.

Lemma vec_unzip_fst {k} {X Y : Type} (xt : Vector.t (X * Y) k)
  : fst (vec_unzip xt) = Vector.map fst xt.
Proof.
  rewrite vec_unzip_eq_map.
  unfold fst at 1.
  reflexivity.
Qed.

Lemma vec_unzip_snd {k} {X Y : Type} (xt : Vector.t (X * Y) k)
  : snd (vec_unzip xt) = Vector.map snd xt.
Proof.
  rewrite vec_unzip_eq_map.
  unfold snd at 1.
  reflexivity.
Qed.