Library mcertikos.layerlib.ListLemma


Require Import Arith.
Require Import Omega.
Require Export List.
Require Import ZArith.

Open Scope nat_scope.
Lemma x_s1_p1_0:
   x: nat,
    x 1 →
    x - 1 + 1 = x.
Proof.
  intros. rewrite <- NPeano.Nat.add_sub_swap. rewrite plus_comm. rewrite minus_plus. reflexivity.
  omega.
Qed.

Open Scope Z_scope.
Lemma Z_succ_pred:
   x, Z.succ x - 1 = x.
Proof.
  intros. omega.
Qed.

Lemma firstn_length_eq:
   {A} (l : list A),
    firstn (length l) l = l.
Proof.
  induction l. simpl. reflexivity.
  simpl. rewrite IHl. reflexivity.
Qed.

Lemma firstn_cons:
   {A} (l : list A) a,
    firstn (length (a :: l )) (a :: l) = a :: firstn (length l ) l.
Proof.
  intros. simpl. reflexivity.
Qed.

Lemma firstn_cons_n:
   {A} n (l : list A) a,
    firstn (S n) (a :: l) = a :: firstn n l.
Proof.
  intros. simpl. reflexivity.
Qed.

Lemma length_cons:
   {A} (l : list A) a,
    S (length l ) = length ( a :: l ).
Proof.
  simpl. auto.
Qed.

Lemma firstn_overflow:
   {A} (l : list A),
    firstn (S (length l)) l = l.
Proof.
  intros. induction l. reflexivity.
  generalize (firstn_cons_n (length (a :: l)) l a); intros Hlc.
  rewrite Hlc.
  generalize (length_cons l a); intros Hlen. rewrite <- Hlen.
  rewrite IHl. reflexivity.
Qed.

Lemma firstn_overflow_cons:
   {A} n (l : list A),
    firstn (S (n + length l)) l = firstn (n + length l) l.
Proof.
  induction n.
  simpl. destruct l. reflexivity. rewrite <- length_cons. rewrite firstn_overflow.
  generalize (length_cons l a); intros Hlc. rewrite Hlc. rewrite firstn_length_eq. reflexivity.
  intros. induction l. reflexivity.
  rewrite firstn_cons_n. rewrite <- length_cons.
  replace (S n + S (length l))%nat with (S (S n + length l))%nat by omega.
  rewrite IHl. replace (S n + length l)%nat with (S (n + length l)%nat) by omega.
  rewrite (IHn l). rewrite firstn_cons_n. rewrite (IHn l). reflexivity.
Qed.

Lemma firstn_overflow_n:
   {A} n (l : list A),
    firstn (n + length l) l = l.
Proof.
  induction n. simpl. apply firstn_length_eq.
  intros. replace (S n + length l)%nat with (S (n + length l)%nat) by omega.
  rewrite (firstn_overflow_cons n l). rewrite (IHn l). reflexivity.
Qed.

Lemma firstn_nil:
   {A} n,
    firstn n nil = @nil A.
Proof.
  intros. destruct n; auto.
Qed.

Lemma skip_cons_n:
   {A} {n} (l : list A) (x: A),
    skipn n l = skipn (S n) (x :: l).
Proof.
  intros. simpl. reflexivity.
Qed.

Lemma skip_cons_1:
   {A} {n} {l : list A},
    skipn (S n) l = (skipn n (skipn 1 l)).
Proof.
  intros.
  destruct l.
  simpl. destruct n. simpl. reflexivity.
  simpl. reflexivity.
  simpl. reflexivity.
Qed.

Lemma skip1_simpl:
   {A} {a} {tl : list A},
    skipn 1 (a :: tl) = tl.
Proof.
  simpl. auto.
Qed.

Lemma skip0_eq:
   {A} {l : list A},
    skipn 0 l = l.
Proof.
  simpl. reflexivity.
Qed.

Lemma skip1_cons:
   {A} {n} {a} {l : list A},
    skipn n (skipn 1 l) = skipn (S n) (skipn 1 (a :: l )).
Proof.
  intros. rewrite skip1_simpl. rewrite <- skip_cons_1. reflexivity.
Qed.

Lemma skip_dist_1:
   {A} {n} {l : list A},
    skipn (S n) l = (skipn 1 (skipn n l)).
Proof.
  intros. generalize n; clear n.
  induction l; intros.
  simpl. destruct n. simpl. reflexivity.
  simpl. reflexivity.
  rewrite <- skip_cons_n. destruct n. reflexivity. rewrite IHl.
  rewrite <- skip_cons_n. reflexivity.
Qed.

Lemma skip1_comm:
   {A} {l : list A} {n},
    skipn n (skipn 1 l) = skipn 1 (skipn n l).
Proof.
  intros.
  rewrite <- skip_cons_1, <- skip_dist_1.
  trivial.
Qed.

Lemma skipn_cons:
   {A} {n} {l : list A} {x: A},
    skipn n l = x ::
    skipn (S n) l = .
Proof.
  induction n.
  intros. simpl. simpl in H. rewrite H. reflexivity.
  induction l. inversion 1.
  intros. simpl in H. apply IHn in H.
  destruct as [| v l´´].
  destruct l. simpl. reflexivity.
  simpl. simpl in H. assumption.
  rewrite <- skip_cons_n. assumption.
Qed.

Lemma firstn_skip1_cons:
   {A} {n} {l : list A} {a: A},
    firstn n l = skipn 1%nat (firstn (S n) (a::l)).
Proof.
  simpl. auto.
Qed.

Lemma firstn_dest:
   {A} {n} {l : list A} {a: A},
    firstn (S n) (a::l) = a :: firstn n l.
Proof.
  simpl. auto.
Qed.

Lemma list_eq_cons:
   {A} {l1 l2 : list A} {a : A},
    a :: l1 = a :: l2
    l1 = l2.
Proof.
  intros.
  inversion H. trivial.
Qed.

Lemma list_eq_dest:
   {A} {l1 l2 : list A} {a : A},
    l1 = l2
    a :: l1 = a :: l2.
Proof.
  intros. rewrite H. reflexivity.
Qed.

Lemma skipn_firstnp1:
   {A} n (l tl : list A) (x: A),
    skipn n l = x :: tl
    firstn (S n) l = (firstn n l) ++ x :: nil.
Proof.
  induction n.
  - simpl. intros. rewrite H. reflexivity.
  - induction l. inversion 1.
    intros. rewrite firstn_dest. rewrite firstn_dest. rewrite <- app_comm_cons.
    apply list_eq_dest. simpl in H. apply IHn in H. assumption.
Qed.

Lemma non_nil_list: {A} {l : list A},
    l nil h t, l = h :: t.
Proof.
  destruct l.
  intros H. contradiction H; trivial.
  intros H. repeat econstructor.
Qed.

Lemma list_non_nil: {A} {l : list A},
    ( h t, l = h :: t) → l nil.
Proof.
  destruct l.
  intros H. destruct H as (h & t & H). discriminate H.
  intros H. inversion 1.
Qed.

Lemma skipn_nil:
   {A} {n}, skipn n nil = @nil A.
Proof.
  intros. destruct n; simpl; reflexivity.
Qed.

Lemma length_firstn_skipn:
   {A} n (l : list A),
    (length (firstn n l) + length (skipn n l))%nat = length l.
Proof.
  intros.
  rewrite <- app_length with (l := firstn n l ) ( := skipn n l ).
  rewrite firstn_skipn. reflexivity.
Qed.

Lemma length_firstn_eq:
   {A} n (l : list A),
    (length l - length (firstn n l) = length l - n) % nat.
Proof.
  intros.
  rewrite firstn_length.
  assert (Hcase: (length l < n length l n)%nat) by omega.
  destruct Hcase as [Hx | Hx]; generalize Hx.
  - intros Hlt. rewrite min_r by omega.
    rewrite minus_diag. rewrite not_le_minus_0 by omega. reflexivity.
  - intros Hge. rewrite min_l by omega. reflexivity.
Qed.

Lemma length_skipn:
   {A} n (l : list A),
    length (skipn n l) = (length l - n)%nat.
Proof.
  intros.
  rewrite <- length_firstn_eq.
  generalize (length_firstn_skipn n l); intros Hlfs.
  rewrite <- Hlfs. omega.
Qed.

Lemma length_skipn_lt:
   {A} n (l : list A),
    (n < length l) % nat
    (length (skipn n l) > 0) % nat.
Proof.
  intros.
  rewrite length_skipn.
  omega.
Qed.

Lemma length_not_nil:
   {A} (l : list A),
    (length l > 0) % nat
    l nil.
Proof.
  intros.
  destruct l eqn: Hl. inversion H.
  discriminate.
Qed.

Lemma skipn_lt:
   {A} (l : list A) (n: nat),
    (n < length l)%nat
    skipn n l nil.
Proof.
  intros.
  apply length_not_nil.
  apply length_skipn_lt.
  assumption.
Qed.

Lemma skipn_length:
   {A} (l : list A),
    skipn (length l) l = nil.
Proof.
  induction l; simpl; auto.
Qed.

Lemma skipn_S_length:
   {A} (l : list A),
    skipn (S (length l)) l = nil.
Proof.
  intros. rewrite skip_dist_1. rewrite skipn_length. reflexivity.
Qed.

Lemma skipn_overflow:
   {A} (l : list A) (n: nat),
    skipn (n + length l) l = nil.
Proof.
  intros. induction n. simpl. apply skipn_length.
  rewrite plus_Sn_m. rewrite skip_dist_1. rewrite IHn. reflexivity.
Qed.

Lemma skipn_ge:
   {A} (l : list A) (n: nat),
    (n length l)%nat
    skipn n l = nil.
Proof.
  intros.
  pose (m := (n - length l)%nat).
  assert (n = (m + length l)%nat) by (unfold m; omega).
  rewrite H0. apply skipn_overflow.
Qed.

Lemma in_skipn:
   {A} (n: nat) (l : list A) a,
    In a (skipn n l) →
    In a l.
Proof.
  induction n. auto.
  induction l. auto.
  simpl. intros.
  right. apply IHn. assumption.
Qed.

Lemma last_tl:
   {A: Type} l (h: A) d,
    l nil
    last (h :: l) d = last l d.
Proof.
  induction l.
  - simpl. intros. contradict H. reflexivity.
  - simpl. intros. reflexivity.
Qed.

Lemma forall_list:
   A P {l : list A} e,
    Forall P l
    In e l
    P e.
Proof.
  intros.
  destruct (Forall_forall P l).
  apply H1; assumption.
Qed.

Lemma forall_list_skipn:
   A P {l : list A} n e,
    Forall P l
    In e (skipn n l) →
    P e.
Proof.
  intros.
  apply in_skipn in H0.
  apply forall_list with (l :=l); assumption.
Qed.

Definition isChar (x: Z) :=
  0 x 255.

Lemma forall_erange:
   {l } n e,
    Forall isChar l
    In e (skipn n l) →
    isChar e.
Proof.
  intros.
  apply forall_list_skipn with (l :=l) (n:=n); assumption.
Qed.

Lemma forall_skipn_hd_erange:
   {l } n e tl,
    Forall isChar l
    skipn n l = e :: tl
    isChar e.
Proof.
  intros.
  assert (In e (skipn n l)).
  {
    rewrite H0.
    constructor. reflexivity.
  }
  apply (@forall_erange l n e); assumption.
Qed.

Lemma forall_hd:
   {A} {P} {e} {tl: list A},
    Forall P (e :: tl) →
    P e.
Proof.
  intros. inversion H. subst.
  assumption.
Qed.

Lemma forall_tl:
   {A} {P} {e} {tl : list A},
    Forall P (e :: tl) →
    Forall P tl.
Proof.
  intros.
  inversion H. assumption.
Qed.

Lemma forall_last:
   {A} {l: list A} {P} {d},
    Forall P l
    P d
    P (last l d).
Proof.
  induction l.
  - simpl. auto.
  - intros. destruct l.
    + simpl. apply forall_hd in H. assumption.
    + rewrite last_tl. apply forall_tl in H.
      generalize (IHl P d H H0). auto.
      firstorder.
Qed.

Lemma Zlength_lt:
   {A} i (l : list A),
    0 i < Zlength l
    (Z.to_nat i < length l)%nat.
Proof.
  intros. rewrite Zlength_correct in H.
  destruct H. assert (Hl: 0 Z.of_nat (length l)) by omega.
  generalize (Z2Nat.inj_lt i (Z.of_nat (length l)) H Hl); intros.
  apply H1 in H0. rewrite Nat2Z.id in H0. assumption.
Qed.

Lemma Zlength_le:
   {A} i (l : list A),
    0 i Zlength l
    (Z.to_nat i length l)%nat.
Proof.
  intros. rewrite Zlength_correct in H.
  destruct H. assert (Hl: 0 Z.of_nat (length l)) by omega.
  generalize (Z2Nat.inj_le i (Z.of_nat (length l)) H Hl); intros.
  apply H1 in H0. rewrite Nat2Z.id in H0. assumption.
Qed.

Lemma skip_1_tl:
   {A} n (ls tls: list A) h,
    skipn n ls = h :: tls
    skipn (S n) ls = tls.
Proof.
  intros.
  rewrite skip_dist_1.
  simpl.
  rewrite H.
  trivial.
Qed.

Lemma skip_nth_eq:
   {A} n (l tl : list A) h default,
    skipn n l = h :: tl
    nth n l default = h.
Proof.
  induction n. simpl. intros. rewrite H. simpl. reflexivity.
  induction l. simpl. inversion 1.
  rewrite <- skip_cons_n. intros. simpl.
  generalize (IHn l tl h default H). auto.
Qed.

Lemma skipn_skipn:
   {A} n m (l : list A),
    skipn n (skipn m l) = skipn (n + m) l.
Proof.
  induction n. simpl. trivial.
  destruct l. repeat rewrite skipn_nil. reflexivity.
  rewrite skip_dist_1. rewrite (IHn m (a :: l)).
  rewrite <- skip_dist_1. simpl. reflexivity.
Qed.

Lemma skipn_append:
   {A} n (l1 l2: list A),
    (n length l1)%nat
    skipn n (l1 ++ l2) = skipn n l1 ++ l2.
Proof.
  induction n.
  - intros. simpl. reflexivity.
  - intros. destruct l1. simpl in H. inversion H.
    simpl. apply IHn. simpl in H. omega.
Qed.

Lemma skipn_less:
   {A} n l (h: A) z,
    skipn n (h :: l) = z ::
    skipn n l = .
Proof.
  induction n.
  - intros. simpl in ×. inversion H. reflexivity.
  - intros. simpl in ×. destruct l. rewrite skipn_nil in H. inversion H.
    apply IHn in H. assumption.
Qed.

Lemma eq_imply_le:
   x y: Z, x = yx y.
Proof. intros. omega. Qed.

Lemma skipn_length_tail:
   {A} (l tl : list A),
    skipn (length l) (l ++ tl) = tl.
Proof.
  intros. induction l. simpl. reflexivity.
  simpl. assumption.
Qed.

Lemma skipn_gt_tail:
   {A} n (l tl : list A),
    (n < length l )%nat
    skipn n l ++ tl = skipn n (l ++ tl).
Proof.
  induction n. simpl. reflexivity.
  intros. simpl. destruct l. inversion H. simpl.
  apply IHn. simpl in H. omega.
Qed.

Lemma skipn_ge_tail:
   {A} n (l tl : list A),
    (n length l )%nat
    skipn n l ++ tl = skipn n (l ++ tl).
Proof.
  intros.
  assert (Hcase: n = length l (n < length l)%nat) by omega.
  destruct Hcase as [Hcase1 | Hcase1]; generalize Hcase1.
  {
    intros. subst. rewrite skipn_length_tail. rewrite skipn_length. reflexivity.
  }
  {
    intros. apply skipn_gt_tail. assumption.
  }
Qed.

Lemma last_cons_eq:
   {A} (a z default: A) (tl : list A),
    nth (length (a :: tl)) (z :: a :: tl) default = nth (length tl) (a :: tl) default.
Proof.
  intros. simpl. reflexivity.
Qed.

Lemma last_nth_eq:
   {A} (tl : list A) (z default : A),
    nth (length tl) (z :: tl) default = last (z :: tl) default.
Proof.
  induction tl. simpl. reflexivity. intros.
  generalize (last_cons_eq a z default tl); intros Hlc.
  rewrite Hlc. generalize (IHtl a default); intros Hihtl.
  rewrite Hihtl. reflexivity.
Qed.

Lemma zlength_to_length:
   {A} (l : list A),
    (Z.to_nat (Zlength l )) = length l.
Proof.
  intros. rewrite Zlength_correct. rewrite Nat2Z.id. reflexivity.
Qed.

Lemma length_to_zlength:
   {A} (l : list A),
    (Z.of_nat (length l )) = Zlength l.
Proof.
  intros. rewrite <- Zlength_correct. reflexivity.
Qed.

Lemma Zlength_ge_0:
   {A} (l : list A),
    0 Zlength l.
Proof.
  intros. induction l. rewrite Zlength_nil. omega.
  rewrite Zlength_cons. omega.
Qed.

Lemma app_Zlength:
   {A} (l1 l2 : list A),
    Zlength (l1 ++ l2) = Zlength l1 + Zlength l2.
Proof.
  intros. rewrite Zlength_correct. rewrite app_length. rewrite Nat2Z.inj_add.
  repeat rewrite Zlength_correct. reflexivity.
Qed.

Lemma list_gt_0:
   {A: Type} (ls: list A), 0 Zlength ls.
Proof.
  intros; induction ls.
  - unfold Zlength; simpl; omega.
  - rewrite Zlength_cons. omega.
Qed.

Lemma length_ge_1:
   {T: Type} (c: T) (stl: list T),
    (1 length (c :: stl))%nat.
Proof.
  intros. simpl. induction stl.
  simpl. omega.
  simpl. omega.
Qed.

Lemma Zlength_ge_1:
   {T: Type} (c: T) (stl: list T),
    1 Zlength (c :: stl).
Proof.
  intros.
  rewrite <- (Z2Nat.id 1).
  rewrite <- (Z2Nat.id (Zlength (c :: stl))).
  apply inj_le.
  rewrite zlength_to_length.
  replace (Z.to_nat 1) with 1%nat.
  apply length_ge_1.
  vm_compute. reflexivity.
  apply (Zlength_ge_0 (c :: stl)).
  omega.
Qed.

Lemma list_hd_eq:
   {A: Type} (a b: A) (l1 l2: list A),
    a :: l1 = b :: l2
    a = b.
Proof.
  intros.
  inversion H. reflexivity.
Qed.

Lemma list_tl_eq:
   {A: Type} (a b: A) (l1 l2: list A),
    a :: l1 = b :: l2
    l1 = l2.
Proof.
  intros.
  inversion H. reflexivity.
Qed.

Lemma skipn_cons_not_nil:
   {A: Type} n (h: A) l,
    skipn n l nil
    skipn n (h :: l) nil.
Proof.
  induction n.
  intros. simpl. contradict H. inversion H.
  intros. simpl. destruct l. contradict H. rewrite skipn_nil. reflexivity.
  generalize H. simpl. apply (IHn a l).
Qed.

Lemma skipn_cons_relation:
   {A: Type} n (h: A) x l,
    skipn n l = x ::
     y, skipn n (h :: l) = y :: x :: .
Proof.
  induction n.
  intros. simpl. simpl in H. h. rewrite H. reflexivity.
  intros. simpl. destruct l.
  - simpl in H. inversion H.
  - simpl in H. apply (IHn a x l H).
Qed.

Lemma skipn_last:
   {A: Type} l (h: A) d,
    skipn (length l) (h :: l) = last (h :: l) d :: nil.
Proof.
  induction l.
  - simpl. intros. reflexivity.
  - simpl. intros.
    rewrite (IHl a d). simpl. reflexivity.
Qed.

Lemma last_concat: (A : Type) (l1 l2: list A) (d: A),
                     l2 nillast (l1 ++ l2) d = last l2 d.
Proof.
  intro.
  induction l1.
  simpl.
  intros.
  reflexivity.
  simpl.
  intros.
  case_eq (l1 ++ l2); intros.
  apply app_eq_nil in H0.
  destruct H0.
  contradiction.
  rewrite <- H0.
  eapply IHl1; eauto.
Qed.

Lemma skipn_remains:
   {A} (ls: list A) m,
    (0 < m)%nat
    ls nil
     h tl, skipn (length ls - m) ls = h :: tl.
Proof.
  induction ls.
  - simpl. intros. contradiction H0. reflexivity.
  - intros. simpl.
    destruct m.
    + omega.
    + assert (Hlm: (length ls m)%nat (length ls > m)%nat) by omega.
      destruct Hlm as [Hlm | Hlm].
      × replace (length ls - m)%nat with 0%nat by omega.
        simpl. a, ls. reflexivity.
      × replace (length ls - m)%nat with (S (length ls - S m))%nat by omega.
        simpl.
        destruct ls eqn: Hls.
        {
          simpl in Hlm. omega.
        }
        {
          apply (IHls (S m)). omega. intro Hx. inversion Hx.
        }
Qed.

Lemma skipn_cons_exists:
   {A} (ls: list A) n h tl a,
    skipn n ls = h :: tl
     h0, skipn n (a :: ls) = h0 :: h :: tl.
Proof.
  induction ls.
  - intros. rewrite skipn_nil in H. inversion H.
  - intros. destruct n.
    + simpl in ×. a0. rewrite H. reflexivity.
    + simpl in ×. apply IHls. assumption.
Qed.

Lemma nth_error_valid_length:
   {T} l n (v: T),
    nth_error l n = value v
    (length l > n)%nat.
Proof.
  induction l.
  - simpl. intros n v. destruct n; simpl; inversion 1.
  - simpl. induction n.
    + simpl. intros v H. omega.
    + intros v H. apply gt_n_S.
      simpl in H. apply (IHl n v H).
Qed.