Class Inhabitant (A: Type) := default : A.
Instance Inhabitant_Z : Inhabitant Z := 0.
Instance Inhabitant_nat : Inhabitant nat := O.
Instance Inhabitant_positive : Inhabitant positive := 1%positive.
Instance Inhabitant_list {T: Type} : Inhabitant (list T) := @nil T.
Instance Inhabitant_fun {T1 T2: Type} {H: Inhabitant T2} : Inhabitant (T1->T2) := fun _ => H.
Instance Inhabitant_Prop : Inhabitant Prop := False.
Instance Inhabitant_bool : Inhabitant bool := false.
Instance Inhabitant_pair {T1 T2 : Type} {x1: Inhabitant T1} {x2: Inhabitant T2} : Inhabitant (T1*T2)%type := (x1,x2).
Hint Rewrite @ZtoNat_Zlength : norm.
Definition Zlength' := @Zlength.
Ltac pose_Zlength_nonneg1 T A :=
lazymatch goal with
| H:  0 <= @Zlength T A |- _ => idtac
| H:  0 <= @Zlength T A /\ _ |- _ => idtac
| |- _ => pose proof (@Zlength_nonneg T A)
end;
(* the next three lines are to avoid blowups in the change command *)
let x := fresh "x" in set (x:= @Zlength T A) in *;
let y := fresh "y" in set (y := @Zlength) in x;
fold @Zlength' in y; subst y; subst x.
Ltac pose_Zlength_nonneg :=
repeat
match goal with
| |- context [@Zlength ?T ?A] => pose_Zlength_nonneg1 T A
| H: context [@Zlength ?T ?A] |- _ => pose_Zlength_nonneg1 T A
end;
unfold Zlength' in *.
Ltac list_solve := autorewrite with sublist; pose_Zlength_nonneg; omega.
Definition Znth {X}{d: Inhabitant X} n (xs: list X) :=
if (zlt n 0) then default else nth (Z.to_nat n) xs d.
Hint Rewrite
(@Znth_map Z _) (@Znth_map nat _) (@Znth_map positive _)
using (auto; rewrite ?Zlength_map in *; omega) : sublist.
(* Add these in a later file where things are in scope ... Hint Rewrite (Znth_map Int.zero) (Znth_map Vundef) using (auto; rewrite ?Zlength_map in *; omega) : sublist. *)
Hint Rewrite @app_nil_l @app_nil_r : sublist.
(*****   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.
(* not this version! Lemma sublist_list_repeat {A} i j k (v:A) (I: 0<=i) (IJK: (Z.to_nat i <= Z.to_nat j <= k)%nat): sublist i j (list_repeat k v) = list_repeat (Z.to_nat (j-i)) v. *)
Hint Rewrite @sublist_nil' using list_solve: sublist.
Hint Rewrite @app_nil_l : sublist.
Hint Rewrite @Zlength_rev : sublist.
Hint Rewrite @sublist_rejoin' using list_solve : sublist.
(*Hint Rewrite @Zlength_list_repeat'  : sublist.*)
Hint Rewrite @Znth_list_repeat_inrange : sublist.
Hint Rewrite @Zlength_cons @Zlength_nil: sublist.
Hint Rewrite @list_repeat_0: sublist.
Hint Rewrite <- @app_nil_end : sublist.
Hint Rewrite @Zlength_app: sublist.
Hint Rewrite @Zlength_map: sublist.
Hint Rewrite @Zlength_list_repeat using list_solve: sublist.
Hint Rewrite Z.sub_0_r Z.add_0_l Z.add_0_r : sublist.
Hint Rewrite @Zlength_sublist using list_solve: sublist.
Hint Rewrite Z.max_r Z.max_l using omega : sublist.
Hint Rewrite Z.min_r Z.min_l using omega : sublist.
Hint Rewrite Z.add_simpl_r Z.sub_add Z.sub_diag : sublist.
Hint Rewrite @sublist_sublist using list_solve : sublist.
Hint Rewrite @sublist_app1 using list_solve : sublist.
Hint Rewrite @sublist_app2 using list_solve : sublist.
Hint Rewrite @sublist_list_repeat  using list_solve : sublist.
Hint Rewrite @sublist_same using list_solve : sublist.
Hint Rewrite Z.add_simpl_l : sublist.
Hint Rewrite Z.add_add_simpl_l_l Z.add_add_simpl_l_r
Z.add_add_simpl_r_l Z.add_add_simpl_r_r : sublist.
Hint Rewrite Z.add_0_r : sublist.
Hint Rewrite @app_Znth1 using list_solve : sublist.
Hint Rewrite @app_Znth2 using list_solve : sublist.
Hint Rewrite @Znth_sublist using list_solve : sublist.
Hint Rewrite @upd_Znth_Zlength using list_solve : sublist.
Hint Rewrite @sublist_nil : sublist.
intros.
split; induction l1; intros.
inv H. destruct l2; inv H0. auto.
split. auto. simpl in H2. inv H2.
constructor; auto.
split. inv H. constructor; auto. apply IHl1 in H3.
intuition.
inv H. apply IHl1 in H3. intuition.
simpl. intuition.
simpl. constructor.
destruct H. inv H. auto.
apply IHl1. intuition.
inv H0; auto.
Qed.
Hint Rewrite @upd_Znth_app1 using list_solve : sublist.
Hint Rewrite @upd_Znth_app2 using list_solve : sublist.

Lemma map_list_repeat: forall {A B} (f: A->B) n (x:A), map f (list_repeat n x) = list_repeat n (f x).