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

(* Specifications: *)
(* Challenging lemma: coercible terms have coercible types.   NOTE: this result for AnnDefEq is *not* AnnPropWff G (Eq A B).  *)
Lemma AnnDefEqAnnIso_regularity :
(forall G0 a A, AnnTyping G0 a A -> True ) /\
(forall G0 phi,   AnnPropWff G0 phi -> True ) /\
(forall G D g p1 p2, AnnIso G D g p1 p2 ->
AnnPropWff G p1 /\ AnnPropWff G p2) /\
(forall G D g A B,   AnnDefEq G D g A B ->
exists C1 C2 g', AnnTyping G A C1 /\ AnnTyping G B C2 /\ AnnDefEq G (dom G) g' C1 C2) /\
(forall G0, AnnCtx G0 -> True).
Lemma subst1 : forall b S D a a' x, Par S D a a' -> erased_tm b ->
Par S D (tm_subst_tm_tm a x b) (tm_subst_tm_tm a' x b).
Lemma open1 : forall b S D a a' L, Par S D a a'
-> (forall x, x `notin` L -> erased_tm (open_tm_wrt_tm b (a_Var_f x)))
-> Par S D (open_tm_wrt_tm b a) (open_tm_wrt_tm b a').
Lemma subst2 : forall S D b x, lc_tm b ->
forall a a', Par S D a a' -> Par S D (tm_subst_tm_tm b x a) (tm_subst_tm_tm b x a').
Lemma subst3 : forall S D b b' x,
Par S D b b' ->
forall a a', erased_tm a -> Par S D a a' ->
Par S D (tm_subst_tm_tm b x a) (tm_subst_tm_tm b' x a').
Lemma subst4 : forall S D b x, lc_co b ->
forall a a', Par S D a a' ->
Par S D (co_subst_co_tm b x a) (co_subst_co_tm b x a').
Lemma multipar_subst3 : forall S D b b' x, erased_tm b ->
multipar S D b b' ->
forall a a', erased_tm a -> multipar S D a a' ->
multipar S D (tm_subst_tm_tm b x a) (tm_subst_tm_tm b' x a').
Lemma multipar_subst4 : forall S D b x, lc_co b ->
forall a a', multipar S D a a' ->
multipar S D (co_subst_co_tm b x a) (co_subst_co_tm b x a').
Lemma erased_tm_open_tm_wrt_tm: forall a x, erased_tm a -> erased_tm (open_tm_wrt_tm a (a_Var_f x)).
Hint Resolve erased_tm_open_tm_wrt_tm : erased.
Lemma Par_Pi_exists: ∀ x (G : context) D rho (A B A' B' : tm),
x `notin` fv_tm_tm_tm B -> Par G D A A'
→ Par G D (open_tm_wrt_tm B (a_Var_f x)) B'
→ Par G D (a_Pi rho A B) (a_Pi rho A' (close_tm_wrt_tm x B')).
Lemma Par_CPi_exists:  ∀ c (G : context) D (A B a A' B' a' T T': tm),
c `notin` fv_co_co_tm a -> Par G D A A'
→ Par G D B B' -> Par G D T T'
→ Par G D (open_tm_wrt_co a (g_Var_f c)) (a')
→ Par G D (a_CPi (Eq A B T) a) (a_CPi (Eq A' B' T') (close_tm_wrt_co c a')).
Lemma Par_Abs_exists: ∀ x (G : context) D rho (a a' : tm),
x `notin` fv_tm_tm_tm a
→ Par G D (open_tm_wrt_tm a (a_Var_f x)) a'
→ Par G D (a_UAbs rho a) (a_UAbs rho (close_tm_wrt_tm x a')).
Lemma Par_CAbs_exists: forall c (G : context) D (a a': tm),
c `notin` fv_co_co_tm a
-> Par G D (open_tm_wrt_co a (g_Var_f c)) a'
→ Par G D (a_UCAbs a) (a_UCAbs (close_tm_wrt_co c a')).
Lemma Par_EtaRel_exists : forall (G: context) D a b b' x,
x `notin` union (fv_tm_tm_tm a) (fv_tm_tm_tm b) ->
Par G D b b' ->
(open_tm_wrt_tm a (a_Var_f x)) = a_App b Rel (a_Var_f x) ->
Par G D (a_UAbs Rel a) b'.
Lemma Par_EtaRel_close : forall (G: context) D b b' x,
x `notin` fv_tm_tm_tm b ->
Par G D b b' ->
Par G D (a_UAbs Rel (close_tm_wrt_tm x (a_App b Rel (a_Var_f x)))) b'.
Lemma Par_open_tm_wrt_co_preservation: forall G D B1 B2 c, Par G D (open_tm_wrt_co B1 (g_Var_f c)) B2 -> exists B', B2 = open_tm_wrt_co B' (g_Var_f c) /\ Par G D (open_tm_wrt_co B1 (g_Var_f c)) (open_tm_wrt_co B' (g_Var_f c)).
Lemma Par_open_tm_wrt_tm_preservation: forall G D B1 B2 x, Par G D (open_tm_wrt_tm B1 (a_Var_f x)) B2 -> exists B', B2 = open_tm_wrt_tm B' (a_Var_f x) /\ Par G D (open_tm_wrt_tm B1 (a_Var_f x)) (open_tm_wrt_tm B' (a_Var_f x)).
Lemma multipar_Pi_exists: ∀ x (G : context) D rho (A B A' B' : tm),
lc_tm (a_Pi rho A B) -> x `notin` fv_tm_tm_tm B -> multipar G D A A'
→ multipar G D (open_tm_wrt_tm B (a_Var_f x)) B'
→ multipar G D (a_Pi rho A B) (a_Pi rho A' (close_tm_wrt_tm x B')).
Lemma multipar_Pi_A_proj: ∀ (G : context) D rho (A B A' B' : tm),
lc_tm A -> multipar G D (a_Pi rho A B) (a_Pi rho A' B')
-> multipar G D A A'.
Lemma multipar_Pi_B_proj: ∀ (G : context) D rho (A B A' B' : tm),
multipar G D (a_Pi rho A B) (a_Pi rho A' B')
→ (exists L, forall x, x `notin` L -> multipar G D (open_tm_wrt_tm B (a_Var_f x)) (open_tm_wrt_tm B' (a_Var_f x))).
Lemma multipar_CPi_exists:  ∀ c (G : context) D (A B a T A' B' a' T': tm),
lc_tm (a_CPi (Eq A B T) a) -> c `notin` fv_co_co_tm a -> multipar G D A A'
→ multipar G D B B' -> multipar G D T T'
→ multipar G D (open_tm_wrt_co a (g_Var_f c)) a'
→ multipar G D (a_CPi (Eq A B T) a) (a_CPi (Eq A' B' T') (close_tm_wrt_co c a')).
Lemma multipar_CPi_B_proj:  ∀ (G : context) D (A B a A' B' a' T T': tm),
multipar G D (a_CPi (Eq A B T) a) (a_CPi (Eq A' B' T') a')
→ (exists L, forall c, c `notin` L -> multipar G D (open_tm_wrt_co a (g_Var_f c)) (open_tm_wrt_co a' (g_Var_f c))).
Lemma multipar_CPi_phi_proj:  ∀ (G : context) D (A B a A' B' a' T T': tm),
multipar G D (a_CPi (Eq A B T) a) (a_CPi (Eq A' B' T') a')
-> (multipar G D A A'/\ multipar G D B B' /\ multipar G D T T').
Lemma multipar_Abs_exists: ∀ x (G : context) D rho (a a' : tm),
lc_tm (a_UAbs rho a) -> x `notin` fv_tm_tm_tm a
→ multipar G D (open_tm_wrt_tm a (a_Var_f x)) a'
→ multipar G D (a_UAbs rho a) (a_UAbs rho (close_tm_wrt_tm x a')).
Lemma multipar_CAbs_exists: forall c (G : context) D (a a': tm),
lc_tm (a_UCAbs a) -> c `notin` fv_co_co_tm a
-> multipar G D (open_tm_wrt_co a (g_Var_f c)) a'
→ multipar G D (a_UCAbs a) (a_UCAbs (close_tm_wrt_co c a')).
Lemma multipar_open_tm_wrt_co_preservation: forall G D B1 B2 c, multipar G D (open_tm_wrt_co B1 (g_Var_f c)) B2 -> exists B', B2 = open_tm_wrt_co B' (g_Var_f c) /\ multipar G D (open_tm_wrt_co B1 (g_Var_f c)) (open_tm_wrt_co B' (g_Var_f c)).
Lemma multipar_open_tm_wrt_tm_preservation: forall G D B1 B2 x, multipar G D (open_tm_wrt_tm B1 (a_Var_f x)) B2 -> exists B', B2 = open_tm_wrt_tm B' (a_Var_f x) /\ multipar G D (open_tm_wrt_tm B1 (a_Var_f x)) (open_tm_wrt_tm B' (a_Var_f x)).
Lemma context_Par_irrelevance: forall G1 G2 D1 D2 a a',
Par G1 D1 a a' -> Par G2 D2 a a'.
Lemma multipar_context_independent: forall G1 G2 D A B,  multipar G1 D A B -> multipar G2 D A B.
(* -------------------- weakening stuff for Par ---------------------- *)
Lemma Par_weaken_available :
forall G D a b, Par G D a b -> forall D', D [<=] D' -> Par G D' a b.
Lemma Par_respects_atoms:
forall G D a b, Par G D a b -> forall D', D [=] D' -> Par G D' a b.
Lemma Par_availability_independence: forall G D1 D2 a b, Par G D1 a b -> Par G D2 a b.
Lemma Par_remove_available:
forall G D a b, Par G D a b -> Par G (AtomSetImpl.inter D (dom G)) a b.
Lemma Par_weakening :
forall G0 D a b, Par G0 D a b ->
forall E F G, (G0 = F ++ G) -> Ctx (F ++ E ++ G) ->  Par (F ++ E ++ G) D a b.