(* ------------------------------------------- *)
(* In the case of a binding term, prepare the environment in the goal for a use of the induction hypothesis *)
Ltac prepare_env :=
match goal with
[ |- context[ (?x' ~ (?S (?sub ?a1 ?x ?A))) ++ map (?tm_subst_tm_sort ?a1 ?x) ?F ++ ?G ] ] =>
rewrite -app_assoc;
replace (x' ~ (S (sub a1 x A)) ++  map (tm_subst_tm_sort a1 x) F) with
(map (tm_subst_tm_sort a1 x) (x' ~ S A ++ F)); eauto using map_app
end.
(* Find a binding for a prop in a well-formed context and invert it. *)
Ltac binds_PropWff_inversion :=
let wff := fresh in
match goal with
[ bind_c : binds ?c (Co (Eq ?a ?b ?A)) ?G0 |- _ ] =>
move: (@binds_to_AnnPropWff G0 _ _ _ _ ltac:(eauto with ctx_wff) bind_c) => wff;
inversion wff; subst
end.

(* Specifications: *)
Lemma ann_tm_substitution_mutual :
(forall G0 b B (H : AnnTyping G0 b B),
forall G a A, AnnTyping G a A ->
forall F x, G0 = (F ++ (x ~ Tm A) ++ G) ->
AnnTyping (map (tm_subst_tm_sort a x) F ++ G)
(tm_subst_tm_tm a x b)
(tm_subst_tm_tm a x B)) /\
(forall G0 phi (H : AnnPropWff G0 phi),
forall G a A, AnnTyping G a A ->
forall F x, G0 = (F ++ (x ~ Tm A) ++ G) ->
AnnPropWff (map (tm_subst_tm_sort a x) F ++ G)
(tm_subst_tm_constraint a x phi)) /\
(forall G0 D g p1 p2 (H : AnnIso G0 D g p1 p2),
forall G a A, AnnTyping G a A ->
forall F x, G0 = (F ++ (x ~ Tm A) ++ G) ->
AnnIso (map (tm_subst_tm_sort a x) F ++ G)
D
(tm_subst_tm_co a x g)
(tm_subst_tm_constraint a x p1)
(tm_subst_tm_constraint a x p2)) /\
(forall  G0 D g A B (H : AnnDefEq G0 D g A B),
forall G a A0, AnnTyping G a A0 ->
forall F x, G0 = (F ++ (x ~ Tm A0) ++ G) ->
AnnDefEq (map (tm_subst_tm_sort a x) F ++ G)
D
(tm_subst_tm_co a x g)
(tm_subst_tm_tm a x A)
(tm_subst_tm_tm a x B)) /\
(forall G0 (H : AnnCtx G0),
forall G a A, AnnTyping G a A ->
forall F x, G0 = (F ++ (x ~ Tm A) ++ G) ->
AnnCtx (map (tm_subst_tm_sort a x) F ++ G)).
Lemma ann_co_substitution_mutual :
(forall G0 b B, AnnTyping G0 b B ->
forall G D g A1 A2 A3 F c,
G0 = (F ++ (c ~ Co (Eq A1 A2 A3)) ++ G)
-> AnnDefEq G D g A1 A2
-> AnnTyping (map (co_subst_co_sort g c) F ++ G)
(co_subst_co_tm g c b) (co_subst_co_tm g c B)) /\
(forall  G0 phi (H : AnnPropWff G0 phi),
forall G D g A1 A2 A3 F c,
G0 = (F ++ (c ~ Co (Eq A1 A2 A3)) ++ G)
-> AnnDefEq G D g A1 A2
-> AnnPropWff (map (co_subst_co_sort g c) F ++ G) (co_subst_co_constraint g c phi)) /\
(forall G0 D0 g1 p1 p2 (H : AnnIso G0 D0 g1 p1 p2),
forall G D g A1 A2 A3 F c,
G0 = (F ++ (c ~ Co (Eq A1 A2 A3)) ++ G)
-> AnnDefEq G D g A1 A2
-> AnnIso (map (co_subst_co_sort g c) F ++ G)
(union D (remove c D0))
(co_subst_co_co g c g1)
(co_subst_co_constraint g c p1)
(co_subst_co_constraint g c p2)) /\
(forall G0 D0 g1 A B (H : AnnDefEq G0 D0 g1 A B),
forall G D g F c A1 A2 A3,
G0 = (F ++ (c ~ Co (Eq A1 A2 A3)) ++ G)
-> AnnDefEq G D g A1 A2
-> AnnDefEq (map (co_subst_co_sort g c) F ++ G) (union D (remove c D0))
(co_subst_co_co g c g1)
(co_subst_co_tm g c A) (co_subst_co_tm g c B)) /\
(forall  G0 (H : AnnCtx G0),
forall G D g F c A1 A2 A3,
G0 = (F ++ (c ~ Co (Eq A1 A2 A3)) ++ G)
-> AnnDefEq G D g A1 A2
-> AnnCtx (map (co_subst_co_sort g c) F ++ G)).