(* ------- smart constructors --------- *)

(* Specifications: *)
Axiom DefEq_conv : forall G D a b A B, DefEq G D a b A -> DefEq G (dom G) A B a_Star -> DefEq G D a b B.
Axiom refl_iso: forall G D phi, PropWff G phi -> Iso G D phi phi.
Axiom sym_iso: forall G D phi1 phi2, Iso G D phi1 phi2 -> Iso G D phi2 phi1.
Axiom trans_iso : forall G D phi1 phi2 phi3, Iso G D phi1 phi2 -> Iso G D phi2 phi3 -> Iso G D phi1 phi3.
Axiom iso_cong : forall G D A A' B B' T T', DefEq G D A A' T -> DefEq G D B B' T -> DefEq G D T T' a_Star ->
Iso G D (Eq A B T) (Eq A' B' T').
Axiom E_PiCong2 :  ∀ (L : atoms) (G : context) (D : available_props) rho (A1 B1 A2 B2 : tm),
DefEq G D A1 A2 a_Star
→ (∀ x : atom,
x `notin` L
→ DefEq ([(x, Tm A1)] ++ G) D (open_tm_wrt_tm B1 (a_Var_f x))
(open_tm_wrt_tm B2 (a_Var_f x)) a_Star)
→ DefEq G D (a_Pi rho A1 B1) (a_Pi rho A2 B2) a_Star.
Axiom E_CPiCong2  : ∀ (L : atoms) (G : context) (D : available_props) (phi1 : constraint)
(A : tm) (phi2 : constraint) (B : tm),
Iso G D phi1 phi2
→ (∀ c : atom,
c `notin` L
→ DefEq ([(c, Co phi1)] ++ G) D (open_tm_wrt_co A (g_Var_f c))
(open_tm_wrt_co B (g_Var_f c)) a_Star)
→ DefEq G D (a_CPi phi1 A) (a_CPi phi2 B) a_Star.
Axiom E_Pi2 : forall L G rho A B,
(∀ x : atom, x `notin` L → Typing ([(x, Tm A)] ++ G) (open_tm_wrt_tm B (a_Var_f x)) a_Star) ->
Typing G (a_Pi rho A B) a_Star.
Axiom E_Abs2 : ∀ (L : atoms) (G : context) (rho : relflag) (a A B : tm),
(∀ x : atom,
x `notin` L → Typing ([(x, Tm A)] ++ G) (open_tm_wrt_tm a (a_Var_f x)) (open_tm_wrt_tm B (a_Var_f x)))
→ (∀ x : atom, x `notin` L → RhoCheck rho x (open_tm_wrt_tm a (a_Var_f x)))
→ Typing G (a_UAbs rho a) (a_Pi rho A B).
Axiom E_Conv2 : ∀ (G : context) (a B A : tm),
Typing G a A → DefEq G (dom G) A B a_Star →
Typing G a B.
Axiom E_CPi2 :  ∀ (L : atoms) (G : context) (phi : constraint) (B : tm),
(∀ c : atom, c `notin` L → Typing ([(c, Co phi)] ++ G) (open_tm_wrt_co B (g_Var_f c)) a_Star) ->
Typing G (a_CPi phi B) a_Star.
Axiom E_CAbs2 : ∀ (L : atoms) (G : context) (a : tm) (phi : constraint) (B : tm),
(∀ c : atom,
c `notin` L → Typing ([(c, Co phi)] ++ G) (open_tm_wrt_co a (g_Var_f c)) (open_tm_wrt_co B (g_Var_f c)))
→ Typing G (a_UCAbs a) (a_CPi phi B).
Axiom E_AbsCong2
: ∀ (L : atoms) (G : context) (D : available_props) (rho : relflag) (b1 b2 A1 B : tm),
(∀ x : atom,
x `notin` L
→ DefEq ([(x, Tm A1)] ++ G) D (open_tm_wrt_tm b1 (a_Var_f x)) (open_tm_wrt_tm b2 (a_Var_f x))
(open_tm_wrt_tm B (a_Var_f x)))
→ (∀ x : atom, x `notin` L → RhoCheck rho x (open_tm_wrt_tm b1 (a_Var_f x)))
→ (∀ x : atom, x `notin` L → RhoCheck rho x (open_tm_wrt_tm b2 (a_Var_f x)))
→ DefEq G D (a_UAbs rho b1) (a_UAbs rho b2) (a_Pi rho A1 B).
Axiom E_CAbsCong2
: ∀ (L : atoms) (G : context) (D : available_props) (a b : tm) (phi1 : constraint)
(B : tm),
(∀ c : atom,
c `notin` L
→ DefEq ([(c, Co phi1)] ++ G) D (open_tm_wrt_co a (g_Var_f c)) (open_tm_wrt_co b (g_Var_f c))
(open_tm_wrt_co B (g_Var_f c))) → DefEq G D (a_UCAbs a) (a_UCAbs b) (a_CPi phi1 B).