(*****   SUBLIST  ******)

Definition sublist {A} (lo hi: Z) (al: list A) : list A :=
  firstn (Z.to_nat (hi-lo)) (skipn (Z.to_nat lo) al).Definition upd_Znth {A} (i: Z) (al: list A) (x: A): list A :=
   sublist 0 i al ++ x :: sublist (i+1) (Zlength al) al.

(* Specifications: *)
Lemma sublist_sublist {A} i j k m (l:list A): 0<=m -> 0<=k <=i -> i <= j-m -> sublist k i (sublist m j l) = sublist (k+m) (i+m) l.
Lemma sublist_rejoin: forall {A} lo mid hi (al: list A), 0 <= lo <= mid -> mid <= hi <= Zlength al -> sublist lo mid al ++ sublist mid hi al = sublist lo hi al.
Lemma sublist_map: forall {A B} (F: A -> B) lo hi (al: list A), sublist lo hi (map F al) = map F (sublist lo hi al).
Lemma map_sublist: forall {A B} (F: A -> B) lo hi (al: list A), map F (sublist lo hi al) = sublist lo hi (map F al).
Lemma sublist_len_1: forall {A}{d: Inhabitant A} i (al: list A), 0 <= i < Zlength al -> sublist i (i+1) al = Znth i al :: nil.
Lemma Znth_cons_sublist: forall {A}{d: Inhabitant A} i (al: list A) bl, 0 <= i < Zlength al -> Znth i al :: bl = sublist i (i+1) al ++ bl.
Lemma Zlength_sublist: forall {A} lo hi (al: list A), 0 <= lo <= hi -> hi <= Zlength al -> Zlength (sublist lo hi al) = hi-lo.
Lemma sublist_same_gen: forall {A} lo hi (al: list A), lo = 0 -> hi >= Zlength al -> sublist lo hi al = al.
Lemma sublist_same: forall {A} lo hi (al: list A), lo = 0 -> hi = Zlength al -> sublist lo hi al = al.
Lemma Znth_sublist: forall {A}{d: Inhabitant A} lo i hi (al: list A), 0 <= lo -> 0 <= i < hi-lo -> Znth i (sublist lo hi al) = Znth (i+lo) al.
Lemma rev_sublist: forall {A} lo hi (al: list A), 0 <= lo <= hi -> hi <= Zlength al -> rev (sublist lo hi al) = sublist (Zlength al - hi) (Zlength al - lo) (rev al).
Lemma sublist_nil: forall {A} lo (al: list A), sublist lo lo al = nil.
Lemma sublist_nil_gen : forall {A} (l : list A) i j, j <= i -> sublist i j l = [].
Lemma sublist_rev: forall {A} lo hi (al: list A), 0 <= lo <= hi -> hi <= Zlength al -> sublist lo hi (rev al) = rev (sublist (Zlength al - hi) (Zlength al - lo) al).
Lemma sublist_app: forall {A} lo hi (al bl: list A), 0 <= lo <= hi -> hi <= Zlength al + Zlength bl -> sublist lo hi (al++bl) = sublist (Z.min lo (Zlength al)) (Z.min hi (Zlength al)) al ++ sublist (Z.max (lo-Zlength al) 0) (Z.max (hi-Zlength al) 0) bl.
Lemma sublist_split: forall {A} lo mid hi (al: list A), 0 <= lo <= mid -> mid <= hi <= Zlength al -> sublist lo hi al = sublist lo mid al ++ sublist mid hi al.
Lemma sublist_last_1 : forall {A}{d: Inhabitant A} lo hi (al : list A), 0 <= lo <= hi -> hi + 1 <= Zlength al -> sublist lo (hi + 1) al = sublist lo hi al ++ [Znth hi al].
Lemma Zlen_le_1_rev: forall {A} (al: list A), Zlength al <= 1 -> rev al = al.
Lemma skipn_0: forall A (l: list A), skipn 0 l = l.
Lemma sublist_1_cons {A} l (v:A) n: sublist 1 n (v::l) = sublist 0 (n-1) l.
Lemma sublist_nil': forall (A : Type) (lo lo': Z) (al : list A), lo=lo' -> sublist lo lo' al = [].
Lemma sublist_skip {A} (l:list A) i : 0<=i -> sublist i (Zlength l) l = skipn (Z.to_nat i) l.
Lemma sublist_firstn {A} (l:list A) i: sublist 0 i l = firstn (Z.to_nat i) l.
Lemma sublist_app1: forall (A : Type) (k i : Z) (al bl : list A), 0 <= k <= i -> i <= Zlength al -> sublist k i (al ++ bl) = sublist k i al.
Lemma sublist0_app1 {A} i (al bl:list A): 0<= i <= Zlength al -> sublist 0 i (al ++ bl) = sublist 0 i al.
Lemma sublist_app2 {A} i j (al bl:list A): 0<=Zlength al <= i-> sublist i j (al ++ bl) = sublist (i-Zlength al) (j-Zlength al) bl.
Lemma sublist_sublist0 {A} i j k (l:list A): 0<=k -> k<=i<=j -> sublist k i (sublist 0 j l) = sublist k i l.
Lemma sublist_sublist00 {A} i j (l:list A): 0<=i<=j -> sublist 0 i (sublist 0 j l) = sublist 0 i l.
Lemma skipn_list_repeat: forall A k n (a: A), (k <= n)%nat -> skipn k (list_repeat n a) = list_repeat (n-k) a.
Lemma sublist_list_repeat {A} i j k (v:A) (I: 0<=i) (IJK: i <= j <= k): sublist i j (list_repeat (Z.to_nat k) v) = list_repeat (Z.to_nat (j-i)) v.
Lemma Zlength_list_repeat: forall {A} n (x: A), 0 <= n -> Zlength (list_repeat (Z.to_nat n) x) = n.
Lemma list_repeat_0: forall {A} (x:A), list_repeat (Z.to_nat 0) x = nil.
Lemma Znth_list_repeat_inrange: forall {A}{d: Inhabitant A} i n (a: A), (0 <= i < n)%Z -> Znth i (list_repeat (Z.to_nat n) a) = a.
Lemma firstn_nil {A} n: firstn n (nil:list A) = nil.
Lemma firstn_In {A} (x:A): forall l n, In x (firstn n l) -> In x l.
Lemma skipn_In {A} (x:A): forall l n, In x (skipn n l) -> In x l.
Lemma sublist_In {A} lo hi data (x:A) (I:In x (sublist lo hi data)): In x data.
Lemma Zlength_list_repeat' {A} n (v:A): Zlength (list_repeat n v) = Z.of_nat n.
Lemma sublist0_app2 {A : Type} i (al bl : list A): Zlength al <= i <= Zlength al + Zlength bl -> sublist 0 i (al ++ bl) = al ++ sublist 0 (i - Zlength al) bl.
Lemma sublist_rejoin': forall {A} lo mid mid' hi (al: list A), mid=mid' -> 0 <= lo <= mid -> mid' <= hi <= Zlength al -> sublist lo mid al ++ sublist mid' hi al = sublist lo hi al.
Lemma subsub1: forall a b : Z, (a-(a-b)) = b.
Lemma sublist_app': forall {A} lo hi (al bl: list A), 0 <= lo <= Zlength al -> 0 <= hi-Zlength al <= Zlength bl -> sublist lo hi (al++bl) = sublist lo (Zlength al) al ++ sublist 0 (hi-Zlength al) bl.
Lemma upd_Znth_Zlength {A} i (l:list A) v: 0<=i < Zlength l -> Zlength (upd_Znth i l v) = Zlength l.
Lemma upd_Znth_map {A B} (f:A -> B) i l v: upd_Znth i (map f l) (f v) = map f (upd_Znth i l v).
Lemma upd_Znth_lookup K {A}{d: Inhabitant A}: forall l (L:Zlength l = K) i j (v:A) (I: 0<=i<K) (J: 0<=j<K), (i=j /\ Znth i (upd_Znth j l v) = v) \/ (i<>j /\ Znth i (upd_Znth j l v) = Znth i l).
Lemma upd_Znth_lookup' K {A}{d: Inhabitant A}: forall l (L:Zlength l = K) i (I: 0<=i<K) j (J: 0<=j<K) (v:A), Znth i (upd_Znth j l v) = if zeq i j then v else Znth i l.
Lemma upd_Znth_char {A} n l1 (v:A) l2 w: Zlength l1=n -> upd_Znth n (l1 ++ v :: l2) w = l1 ++ w :: l2.
Lemma upd_Znth_same {A}{d: Inhabitant A}: forall i l u, 0<= i< Zlength l -> Znth i (upd_Znth i l u) = u.
Lemma upd_Znth_diff {A}{d: Inhabitant A}: forall i j l u, 0<= i< Zlength l -> 0<= j< Zlength l -> i<>j -> Znth i (upd_Znth j l u) = Znth i l.
Lemma upd_Znth_app1 {A} i l1 l2 (I: 0 <= i < Zlength l1) (v:A): upd_Znth i (l1++l2) v = upd_Znth i l1 v ++ l2.
Lemma upd_Znth_app2 {A} (l1 l2:list A) i v: Zlength l1 <= i <= Zlength l1 + Zlength l2 -> upd_Znth i (l1 ++ l2) v = l1 ++ upd_Znth (i-Zlength l1) l2 v.
Lemma upd_Znth0 {A} (l:list A) v: upd_Znth 0 l v = v :: sublist 1 (Zlength l) l.
Lemma sublist_upd_Znth_l: forall {A} (l: list A) i lo hi v, 0 <= lo <= hi -> hi <= i < Zlength l -> sublist lo hi (upd_Znth i l v) = sublist lo hi l.
Lemma sublist_upd_Znth_r: forall {A} (l: list A) i lo hi v, 0 <= i < lo -> lo <= hi <= Zlength l -> sublist lo hi (upd_Znth i l v) = sublist lo hi l.
Lemma sublist_upd_Znth_lr: forall {A} (l: list A) i lo hi v, 0 <= lo <= i-> i < hi <= Zlength l -> sublist lo hi (upd_Znth i l v) = upd_Znth (i - lo) (sublist lo hi l) v.
Lemma list_repeat_app': forall {A: Type} a b (x:A), 0 <= a -> 0 <= b -> list_repeat (Z.to_nat a) x ++ list_repeat (Z.to_nat b) x = list_repeat (Z.to_nat (a+b)) x.
Lemma Znth_overflow: forall {A}{d: Inhabitant A} i (al: list A), i >= Zlength al -> Znth i al = d.
Lemma Znth_underflow: forall {A}{d: Inhabitant A} i (al: list A), i < 0 -> Znth i al = d.
Lemma Znth_outofbounds: forall {A}{d: Inhabitant A} i (al: list A), (i < 0 \/ i >= Zlength al) -> Znth i al = d.
Lemma sublist_one: forall {A}{d: Inhabitant A} lo hi (al: list A), 0 <= lo -> hi <= Zlength al -> lo+1=hi -> sublist lo hi al = Znth lo al :: nil.
Lemma Forall_app : forall {A} P (l1 l2 :list A), Forall P (l1 ++ l2) <-> Forall P l1 /\ Forall P l2.
Lemma Forall_firstn: forall A (f: A -> Prop) n l, Forall f l -> Forall f (firstn n l).
Lemma Forall_skipn: forall A (f: A -> Prop) n l, Forall f l -> Forall f (skipn n l).
Lemma Forall_map: forall {A B} (f: B -> Prop) (g: A -> B) al, Forall f (map g al) <-> Forall (Basics.compose f g) al.
Lemma Forall_sublist: forall {A} (f: A -> Prop) lo hi al, Forall f al -> Forall f (sublist lo hi al).
Lemma map_list_repeat: forall {A B} (f: A->B) n (x:A), map f (list_repeat n x) = list_repeat n (f x).
Lemma Zlength_sublist_correct: forall {A} (l: list A) (lo hi: Z), 0 <= lo <= hi -> hi <= Zlength l -> Zlength (sublist lo hi l) = hi - lo.
Lemma Zlength_sublist_incorrect: forall {A} (l: list A) (lo hi: Z), 0 <= lo < hi -> hi > Zlength l -> Zlength (sublist lo hi l) < hi - lo.
Lemma nth_Znth {A} {d: Inhabitant A}: forall n (xs:list A), 0 <= n < Zlength xs -> (nth (Z.to_nat n) xs d) = (Znth n xs).