(* ---------------------------------------------- *)

(* Specifications: *)
Lemma erase_a_Const : forall G0 a0 A0 A1 T,
erase a0 = a_Const T ->
binds T (Cs A1) an_toplevel ->
AnnTyping G0 a0 A0   ->
exists g, AnnDefEq G0 (dom G0) g A0 A1.
Lemma erase_capp :
forall AB0 C G, AnnTyping G AB0 C -> forall A, erase AB0 = (a_CApp A g_Triv) ->
exists a1 g0 g D, erase AB0 = erase (a_CApp a1 g0) /\ erase a1 = A /\
AnnTyping G (a_CApp a1 g0) D /\ AnnDefEq G (dom G) g C D.
Lemma An_AppCong2 : ∀ (G : context) (D : available_props) rho (g1 g2 : co)
(a1 a2 b1 b2 A B : tm),
AnnDefEq G D g1 a1 b1
→ AnnDefEq G D g2 a2 b2
→ AnnTyping G (a_App a1 rho a2) A
→ AnnTyping G (a_App b1 rho b2) B
→ AnnDefEq G D (g_AppCong g1 rho g2) (a_App a1 rho a2) (a_App b1 rho b2).
Lemma An_CAppCong2 :
∀ (G : context) (D : available_props) (g1 g2 g3 : co) (a1 b1 a2 b2 a3 b3 A B : tm),
AnnDefEq G D g1 a1 b1
→ AnnDefEq G (dom G) g2 a2 b2
→ AnnDefEq G (dom G) g3 a3 b3
→ AnnTyping G (a_CApp a1 g2) A
→ AnnTyping G (a_CApp b1 g3) B
→ AnnDefEq G D (g_CAppCong g1 g2 g3) (a_CApp a1 g2) (a_CApp b1 g3).
Lemma An_Trans'
: ∀ (G : context) (D : available_props) (g1 g2 : co)
(a b a1 : tm),
AnnDefEq G D g1 a a1
→ AnnDefEq G D g2 a1 b
→ exists g, AnnDefEq G D g a b .
Lemma An_Sym'
: ∀ (G : context) (D : available_props) (g : co) (a b : tm),
AnnDefEq G D g b a → exists g, AnnDefEq G D g a b.
Lemma An_Refl_Star : forall G D a b A,
erase a = erase b -> AnnTyping G b a_Star ->
AnnTyping G a A -> erase A = a_Star ->
exists g, AnnDefEq G D g a b.
Lemma An_IsoRefl2_derivable  : ∀ (G : context) (D : available_props) (phi1 phi2 : constraint),
AnnPropWff G phi1
→ AnnPropWff G phi2
→ erase_constraint phi1 = erase_constraint phi2 →
exists g,
AnnIso G D g phi1 phi2.
Lemma An_Pi_exists2
: ∀ (x : atom) (G : list (atom * sort)) (rho : relflag) (A B : tm),
x `notin` union (dom G) (fv_tm_tm_tm B)
→ AnnTyping ([(x, Tm A)] ++ G) (open_tm_wrt_tm B (a_Var_f x)) a_Star
→ AnnTyping G (a_Pi rho A B) a_Star.
Lemma An_Abs_exists2
: ∀ (x : atom) (G : context) (rho : relflag) (A a B : tm),
x `notin` union (dom G) (union (fv_tm_tm_tm a) (fv_tm_tm_tm B))
→ AnnTyping ([(x, Tm A)] ++ G) (open_tm_wrt_tm a (a_Var_f x)) (open_tm_wrt_tm B (a_Var_f x))
→ RhoCheck rho x (erase_tm (open_tm_wrt_tm a (a_Var_f x)))
→ AnnTyping G (a_Abs rho A a) (a_Pi rho A B).
Lemma An_CPi_exists2
: ∀ (c : atom) (G : context) (phi : constraint) (B : tm),
c `notin` union (dom G) (fv_co_co_tm B)
→ AnnTyping ([(c, Co phi)] ++ G) (open_tm_wrt_co B (g_Var_f c)) a_Star
→ AnnTyping G (a_CPi phi B) a_Star.
Lemma An_CAbs_exists2
: ∀ (c : atom) (G : context) (phi : constraint) (a B : tm),
c `notin` union (dom G) (union (fv_co_co_tm a) (fv_co_co_tm B))
→ AnnTyping ([(c, Co phi)] ++ G) (open_tm_wrt_co a (g_Var_f c)) (open_tm_wrt_co B (g_Var_f c))
→ AnnTyping G (a_CAbs phi a) (a_CPi phi B).
Lemma An_Fam2 :  ∀ (G : context) (F : tyfam) (A a : tm),
AnnCtx G
→ binds F (Ax a A) an_toplevel
→ AnnTyping G (a_Fam F) A.
Lemma An_AbsCong_exists2
: ∀ (x1 x2 : atom) (G : context) (D : available_props) (rho : relflag) (g1 g2 : co)
(A1 b1 A2 b3 b2 B : tm),
x1 `notin` union (dom G) (union (fv_tm_tm_tm b1) (union (fv_tm_tm_tm b2) (fv_tm_tm_co g2)))
→ x2 `notin` union (dom G) (union (fv_tm_tm_tm b2) (union (fv_tm_tm_tm b3) (fv_tm_tm_co g1)))
→ AnnDefEq G D g1 A1 A2
→ AnnDefEq ([(x1, Tm A1)]++ G) D (open_co_wrt_tm g2 (a_Var_f x1))
(open_tm_wrt_tm b1 (a_Var_f x1)) (open_tm_wrt_tm b2 (a_Var_f x1))
→ open_tm_wrt_tm b3 (a_Var_f x2) = open_tm_wrt_tm b2 (a_Conv (a_Var_f x2) (g_Sym g1))
→ AnnTyping G A2 a_Star
→ RhoCheck rho x1 (erase_tm (open_tm_wrt_tm b1 (a_Var_f x1)))
→ RhoCheck rho x2 (erase_tm (open_tm_wrt_tm b3 (a_Var_f x2)))
→ AnnTyping G (a_Abs rho A1 b2) B
→ AnnDefEq G D (g_AbsCong rho g1 g2) (a_Abs rho A1 b1) (a_Abs rho A2 b3).
Lemma An_CPiCong_exists2
: ∀ (c : atom) (G : context) (D : available_props)
(g1 g3 : co) (phi1 : constraint) (B1 : tm)
(phi2 : constraint) (B3 B2 : tm),
AnnIso G D g1 phi1 phi2
→ c
`notin` (union (dom G)
(union D
(union (fv_co_co_tm B2)
(union (fv_co_co_tm B1)
(union (fv_co_co_co g3)
(union (fv_co_co_co g1)
(fv_co_co_tm B3)))))))
→ AnnDefEq ([(c, Co phi1)] ++ G) D
(open_co_wrt_co g3 (g_Var_f c))
(open_tm_wrt_co B1 (g_Var_f c))
(open_tm_wrt_co B2 (g_Var_f c))
→ open_tm_wrt_co B3 (g_Var_f c) =
open_tm_wrt_co B2 (g_Cast (g_Var_f c) (g_Sym g1))
→ AnnTyping G (a_CPi phi1 B1) a_Star
→ AnnTyping G (a_CPi phi1 B2) a_Star
→ AnnDefEq G D (g_CPiCong g1 g3) (a_CPi phi1 B1) (a_CPi phi2 B3).