(*****   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_sublist: forall {A} lo hi lo' hi' (al: list A), 0 <= lo <= hi -> hi <= hi'-lo' -> 0 <= lo' <= hi' -> hi' <= Zlength al -> sublist lo hi (sublist lo' hi' al) = sublist (lo+lo') (hi+lo') al. *)
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_firstn {A} (l:list A) i: sublist 0 i l = firstn (Z.to_nat i) l.
Lemma sublist0_app1 {A} i (al bl:list A): 0<= i <= Zlength al ->
sublist 0 i (al ++ bl) = sublist 0 i al.
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.