diff -r aabbf8c4de80 -r c170dcbe6c9d src/HOL/Nominal/Examples/Crary.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/Nominal/Examples/Crary.thy Tue Jan 16 13:59:08 2007 +0100 @@ -0,0 +1,1358 @@ +(* "$Id$" *) +(* *) +(* Formalisation of the chapter *) +(* Logical Relations and a Case Study in Equivalence *) +(* Checking *) +(* by Crary. *) +(* Formalisation by Julien Narboux and Christian Urban*) + +theory Crary + imports "Nominal" +begin + +atom_decl name + +nominal_datatype ty = TBase + | TUnit + | Arrow "ty" "ty" ("_\_" [100,100] 100) + +nominal_datatype trm = Unit + | Var "name" + | Lam "\name\trm" ("Lam [_]._" [100,100] 100) + | App "trm" "trm" + | Const "nat" + +(* FIXME: the next lemma needs to be in Nominal.thy *) +lemma eq_eqvt: + fixes pi::"name prm" + and x::"'a::pt_name" + shows "pi\(x=y) = (pi\x=pi\y)" + apply(simp add: perm_bool perm_bij) + done + +lemma in_eqvt: + fixes pi::"name prm" + and x::"'a::pt_name" + assumes "x\X" + shows "pi\x \ pi\X" + using assms by (perm_simp add: pt_set_bij1a[OF pt_name_inst, OF at_name_inst]) + +lemma set_eqvt: + fixes pi::"name prm" + and xs::"('a::pt_name) list" + shows "pi\(set xs) = set (pi\xs)" + by (perm_simp add: pt_list_set_pi[OF pt_name_inst]) + +(* End of library *) + +lemma perm_ty[simp]: + fixes T::"ty" + and pi::"name prm" + shows "pi\T = T" + by (induct T rule: ty.induct_weak) (simp_all) + +lemma fresh_ty[simp]: + fixes x::"name" + and T::"ty" + shows "x\T" + by (simp add: fresh_def supp_def) + +lemma ty_cases: + fixes T::ty + shows "(\ T1 T2. T=T1\T2) \ T=TUnit \ T=TBase" +apply (induct T rule:ty.induct_weak) +apply (auto) +done + +text {* Size Functions *} + +instance ty :: size .. + +nominal_primrec + "size (TBase) = 1" + "size (TUnit) = 1" + "size (T1\T2) = size T1 + size T2" +by (rule TrueI)+ + +instance trm :: size .. + +nominal_primrec + "size (Unit) = 1" + "size (Var x) = 1" + "size (Lam [x].t) = size t + 1" + "size (App t1 t2) = size t1 + size t2" + "size (Const n) = 1" +apply(finite_guess add: fs_name1 perm_nat_def)+ +apply(perm_full_simp add: perm_nat_def) +apply(simp add: fs_name1) +apply(rule TrueI)+ +apply(simp add: fresh_nat)+ +apply(fresh_guess add: fs_name1 perm_nat_def)+ +done + +lemma ty_size_greater_zero[simp]: + fixes T::"ty" + shows "size T > 0" +by (nominal_induct rule:ty.induct) (simp_all) + +text {* valid contexts *} + +inductive2 + valid :: "(name \ 'a::pt_name) list \ bool" +where + v_nil[intro]: "valid []" + | v_cons[intro]: "\valid \;a\\\ \ valid ((a,\)#\)" + +lemma valid_eqvt: + fixes pi:: "name prm" + assumes a: "valid \" + shows "valid (pi\\)" + using a + by (induct) (auto simp add: fresh_bij) + +inductive_cases2 + valid_cons_elim_auto[elim]:"valid ((x,T)#\)" + +text {* typing judgements for trms *} + +inductive2 + typing :: "(name\ty) list\trm\ty\bool" (" _ \ _ : _ " [60,60,60] 60) +where + t_Var[intro]: "\valid \; (x,T)\set \\\ \ \ Var x : T" +| t_App[intro]: "\\ \ e1 : T1\T2; \ \ e2 : T1\\ \ \ App e1 e2 : T2" +| t_Lam[intro]: "\x\\; (x,T1)#\ \ t : T2\ \ \ \ Lam [x].t : T1\T2" +| t_Const[intro]: "valid \ \ \ \ Const n : TBase" +| t_Unit[intro]: "valid \ \ \ \ Unit : TUnit" + +lemma typing_valid: + assumes "\ \ t : T" + shows "valid \" + using assms + by (induct) (auto) + +lemma typing_eqvt : + fixes pi::"name prm" + assumes "\ \ t : T" + shows "(pi\\) \ (pi\t) : T" + using assms + apply(induct) + apply(auto simp add: fresh_bij set_eqvt valid_eqvt) + apply(rule t_Var) + apply(drule valid_eqvt) + apply(assumption) + apply(drule in_eqvt) + apply(simp add: set_eqvt) + done + +text {* Inversion lemmas for the typing judgment *} + +declare trm.inject [simp add] +declare ty.inject [simp add] + +inductive_cases2 t_Lam_elim_auto[elim]: "\ \ Lam [x].t : T" +inductive_cases2 t_Var_elim_auto[elim]: "\ \ Var x : T" +inductive_cases2 t_App_elim_auto[elim]: "\ \ App x y : T" +inductive_cases2 t_Const_elim_auto[elim]: "\ \ Const n : T" +inductive_cases2 t_Unit_elim_auto[elim]: "\ \ Unit : TUnit" + +declare trm.inject [simp del] +declare ty.inject [simp del] + +lemma typing_induct_strong + [consumes 1, case_names t_Var t_App t_Lam t_Const t_Unit]: + fixes P::"'a::fs_name \ (name\ty) list \ trm \ ty \bool" + and x :: "'a::fs_name" + assumes a: "\ \ e : T" + and a1: "\\ x T c. \valid \; (x,T)\set \\ \ P c \ (Var x) T" + and a2: "\\ e1 T1 T2 e2 c. + \\ \ e1 : T1\T2 ; \c. P c \ e1 (T1\T2); \ \ e2 : T1 ; \c. P c \ e2 T1\ + \ P c \ (App e1 e2) T2" + and a3: "\x \ T1 t T2 c. + \x\(\,c); (x,T1)#\ \ t : T2 ; \c. P c ((x,T1)#\) t T2\ + \ P c \ (Lam [x].t) (T1\T2)" + and a4: "\\ n c. valid \ \ P c \ (Const n) TBase" + and a5: "\\ c. valid \ \ P c \ Unit TUnit" + shows "P c \ e T" +proof - + from a have "\(pi::name prm) c. P c (pi\\) (pi\e) T" + proof (induct) + case (t_Var \ x T pi c) + have "valid \" by fact + then have "valid (pi\\)" by (simp only: valid_eqvt) + moreover + have "(x,T)\set \" by fact + then have "pi\(x,T)\pi\(set \)" by (simp only: pt_set_bij[OF pt_name_inst, OF at_name_inst]) + then have "(pi\x,T)\set (pi\\)" by (simp add: set_eqvt) + ultimately show "P c (pi\\) (pi\(Var x)) T" using a1 by simp + next + case (t_App \ e1 T1 T2 e2 pi c) + thus "P c (pi\\) (pi\(App e1 e2)) T2" using a2 by (simp, blast intro: typing_eqvt) + next + case (t_Lam x \ T1 t T2 pi c) + obtain y::"name" where fs: "y\(pi\x,pi\\,pi\t,c)" by (erule exists_fresh[OF fs_name1]) + let ?sw = "[(pi\x,y)]" + let ?pi' = "?sw@pi" + have f0: "x\\" by fact + have f1: "(pi\x)\(pi\\)" using f0 by (simp add: fresh_bij) + have f2: "y\?pi'\\" by (auto simp add: pt_name2 fresh_left calc_atm perm_pi_simp) + have pr1: "(x,T1)#\ \ t : T2" by fact + then have "(?pi'\((x,T1)#\)) \ (?pi'\t) : T2" by (simp only: typing_eqvt) + moreover + have ih1: "\c. P c (?pi'\((x,T1)#\)) (?pi'\t) T2" by fact + ultimately have "P c (?pi'\\) (Lam [y].(?pi'\t)) (T1\T2)" using fs f2 a3 + by (simp add: calc_atm) + then have "P c (?sw\pi\\) (?sw\(Lam [(pi\x)].(pi\t))) (T1\T2)" + by (simp del: append_Cons add: calc_atm pt_name2) + moreover have "(?sw\pi\\) = (pi\\)" + by (rule perm_fresh_fresh) (simp_all add: fs f1) + moreover have "(?sw\(Lam [(pi\x)].(pi\t))) = Lam [(pi\x)].(pi\t)" + by (rule perm_fresh_fresh) (simp_all add: fs f1 fresh_atm abs_fresh) + ultimately show "P c (pi\\) (pi\(Lam [x].t)) (T1\T2)" + by simp + next + case (t_Const \ n pi c) + thus "P c (pi\\) (pi\(Const n)) (TBase)" using a4 by (simp, blast intro: valid_eqvt) + next + case (t_Unit \ pi c) + thus "P c (pi\\) (pi\Unit) (TUnit)" using a5 by (simp, blast intro: valid_eqvt) + qed + then have "P c (([]::name prm)\\) (([]::name prm)\e) T" by blast + then show "P c \ e T" by simp +qed + +text {* capture-avoiding substitution *} + +fun + lookup :: "(name\trm) list \ name \ trm" +where + "lookup [] X = Var X" + "lookup ((Y,T)#\) X = (if X=Y then T else lookup \ X)" + +lemma lookup_eqvt: + fixes pi::"name prm" + and \::"(name\trm) list" + and X::"name" + shows "pi\(lookup \ X) = lookup (pi\\) (pi\X)" +by (induct \) + (auto simp add: perm_bij) + +lemma lookup_fresh: + fixes z::"name" + assumes "z\\" "z\x" + shows "z \lookup \ x" +using assms +by (induct rule: lookup.induct) (auto simp add: fresh_list_cons) + +lemma lookup_fresh': + assumes "z\\" + shows "lookup \ z = Var z" +using assms +by (induct rule: lookup.induct) + (auto simp add: fresh_list_cons fresh_prod fresh_atm) + +consts + psubst :: "(name\trm) list \ trm \ trm" ("_<_>" [60,100] 100) + +nominal_primrec + "\<(Var x)> = (lookup \ x)" + "\<(App t1 t2)> = App (\) (\)" + "x\\ \ \<(Lam [x].t)> = Lam [x].(\)" + "\<(Const n)> = Const n" + "\<(Unit)> = Unit" +apply(finite_guess add: fs_name1 lookup_eqvt)+ +apply(perm_full_simp) +apply(simp add: fs_name1) +apply(rule TrueI)+ +apply(simp add: abs_fresh)+ +apply(fresh_guess add: fs_name1 lookup_eqvt)+ +done + +abbreviation + subst :: "trm \ name \ trm \ trm" ("_[_::=_]" [100,100,100] 100) +where + "t[x::=t'] \ ([(x,t')])" + +lemma subst[simp]: + shows "(Var x)[y::=t'] = (if x=y then t' else (Var x))" + and "(App t1 t2)[y::=t'] = App (t1[y::=t']) (t2[y::=t'])" + and "x\(y,t') \ (Lam [x].t)[y::=t'] = Lam [x].(t[y::=t'])" + and "Const n[y::=t'] = Const n" + and "Unit [y::=t'] = Unit" + by (simp_all add: fresh_list_cons fresh_list_nil) + +lemma subst_eqvt: + fixes pi::"name prm" + and t::"trm" + shows "pi\(t[x::=t']) = (pi\t)[(pi\x)::=(pi\t')]" + by (nominal_induct t avoiding: x t' rule: trm.induct) + (perm_simp add: fresh_bij)+ + +lemma subst_rename: + fixes c::"name" + and t1::"trm" + assumes a: "c\t1" + shows "t1[a::=t2] = ([(c,a)]\t1)[c::=t2]" + using a + apply(nominal_induct t1 avoiding: a c t2 rule: trm.induct) + apply(simp add: trm.inject calc_atm fresh_atm abs_fresh perm_nat_def)+ + done + +lemma fresh_psubst: + fixes z::"name" + and t::"trm" + assumes "z\t" "z\\" + shows "z\(\)" +using assms +by (nominal_induct t avoiding: z \ t rule: trm.induct) + (auto simp add: abs_fresh lookup_fresh) + +lemma fresh_subst'': + fixes z::"name" + and t1::"trm" + and t2::"trm" + assumes "z\t2" + shows "z\t1[z::=t2]" +using assms +by (nominal_induct t1 avoiding: t2 z rule: trm.induct) + (auto simp add: abs_fresh fresh_nat fresh_atm) + +lemma fresh_subst': + fixes z::"name" + and t1::"trm" + and t2::"trm" + assumes "z\[y].t1" "z\t2" + shows "z\t1[y::=t2]" +using assms +by (nominal_induct t1 avoiding: y t2 z rule: trm.induct) + (auto simp add: abs_fresh fresh_nat fresh_atm) + +lemma fresh_subst: + fixes z::"name" + and t1::"trm" + and t2::"trm" + assumes "z\t1" "z\t2" + shows "z\t1[y::=t2]" +using assms fresh_subst' +by (auto simp add: abs_fresh) + +lemma fresh_psubst_simpl: + assumes "x\t" + shows "(x,u)#\ = \" +using assms +proof (nominal_induct t avoiding: x u \ rule: trm.induct) + case (Lam y t x u) + have fs: "y\\" "y\x" "y\u" by fact + moreover have "x\ Lam [y].t" by fact + ultimately have "x\t" by (simp add: abs_fresh fresh_atm) + moreover have ih:"\n T. n\t \ ((n,T)#\) = \" by fact + ultimately have "(x,u)#\ = \" by auto + moreover have "(x,u)#\ = Lam [y]. ((x,u)#\)" using fs + by (simp add: fresh_list_cons fresh_prod) + moreover have " \ = Lam [y]. (\)" using fs by simp + ultimately show "(x,u)#\ = \" by auto +qed (auto simp add: fresh_atm abs_fresh) + +text {* Equivalence (defined) *} + +inductive2 + equiv_def :: "(name\ty) list\trm\trm\ty\bool" ("_ \ _ == _ : _" [60,60] 60) +where + Q_Refl[intro]: "\ \ t : T \ \ \ t == t : T" +| Q_Symm[intro]: "\ \ t == s : T \ \ \ s == t : T" +| Q_Trans[intro]: "\\ \ s == t : T; \ \ t == u : T\ \ \ \ s == u : T" +| Q_Abs[intro]: "\x\\; (x,T1)#\ \ s2 == t2 : T2\ \ \ \ Lam [x]. s2 == Lam [x]. t2 : T1 \ T2" +| Q_App[intro]: "\\ \ s1 == t1 : T1 \ T2 ; \ \ s2 == t2 : T1\ \ \ \ App s1 s2 == App t1 t2 : T2" +| Q_Beta[intro]: "\x\(\,s2,t2); (x,T1)#\ \ s12 == t12 : T2 ; \ \ s2 == t2 : T1\ + \ \ \ App (Lam [x]. s12) s2 == t12[x::=t2] : T2" +| Q_Ext[intro]: "\x\(\,s,t); (x,T1)#\ \ App s (Var x) == App t (Var x) : T2\ + \ \ \ s == t : T1 \ T2" + +lemma equiv_def_valid: + assumes "\ \ t == s : T" + shows "valid \" +using assms by (induct,auto elim:typing_valid) + +lemma equiv_def_eqvt: + fixes pi::"name prm" + assumes a: "\ \ s == t : T" + shows "(pi\\) \ (pi\s) == (pi\t) : T" +using a +apply(induct) +apply(auto intro: typing_eqvt valid_eqvt simp add: fresh_bij subst_eqvt) +apply(rule_tac x="pi\x" in Q_Ext) +apply(simp add: fresh_bij)+ +done + +lemma equiv_def_strong_induct + [consumes 1, case_names Q_Refl Q_Symm Q_Trans Q_Abs Q_App Q_Beta Q_Ext]: + fixes c::"'a::fs_name" + assumes a0: "\ \ s == t : T" + and a1: "\\ t T c. \ \ t : T \ P c \ t t T" + and a2: "\\ t s T c. \\ \ t == s : T; \d. P d \ t s T\ \ P c \ s t T" + and a3: "\\ s t T u c. + \\ \ s == t : T; \d. P d \ s t T; \ \ t == u : T; \d. P d \ t u T\ + \ P c \ s u T" + and a4: "\x \ T1 s2 t2 T2 c. \x\\; x\c; (x,T1)#\ \ s2 == t2 : T2; \d. P d ((x,T1)#\) s2 t2 T2\ + \ P c \ (Lam [x].s2) (Lam [x].t2) (T1\T2)" + and a5: "\\ s1 t1 T1 T2 s2 t2 c. + \\ \ s1 == t1 : T1\T2; \d. P d \ s1 t1 (T1\T2); + \ \ s2 == t2 : T1; \d. P d \ s2 t2 T1\ \ P c \ (App s1 s2) (App t1 t2) T2" + and a6: "\x \ T1 s12 t12 T2 s2 t2 c. + \x\(\,s2,t2); x\c; (x,T1)#\ \ s12 == t12 : T2; \d. P d ((x,T1)#\) s12 t12 T2; + \ \ s2 == t2 : T1; \d. P d \ s2 t2 T1\ + \ P c \ (App (Lam [x].s12) s2) (t12[x::=t2]) T2" + and a7: "\x \ s t T1 T2 c. + \x\(\,s,t); (x,T1)#\ \ App s (Var x) == App t (Var x) : T2; + \d. P d ((x,T1)#\) (App s (Var x)) (App t (Var x)) T2\ + \ P c \ s t (T1\T2)" + shows "P c \ s t T" +proof - + from a0 have "\(pi::name prm) c. P c (pi\\) (pi\s) (pi\t) T" + proof(induct) + case (Q_Refl \ t T pi c) + then show "P c (pi\\) (pi\t) (pi\t) T" using a1 by (simp add: typing_eqvt) + next + case (Q_Symm \ t s T pi c) + then show "P c (pi\\) (pi\s) (pi\t) T" using a2 by (simp only: equiv_def_eqvt) + next + case (Q_Trans \ s t T u pi c) + then show " P c (pi\\) (pi\s) (pi\u) T" using a3 by (blast intro: equiv_def_eqvt) + next + case (Q_App \ s1 t1 T1 T2 s2 t2 pi c) + then show "P c (pi\\) (pi\App s1 s2) (pi\App t1 t2) T2" using a5 + by (simp, blast intro: equiv_def_eqvt) + next + case (Q_Ext x \ s t T1 T2 pi c) + then show "P c (pi\\) (pi\s) (pi\t) (T1\T2)" using a7 + apply - + apply(simp) + apply(rule_tac x="pi\x" in a7) + apply(simp add: fresh_bij) + apply(drule equiv_def_eqvt) + apply(simp)+ + done + next + case (Q_Abs x \ T1 s2 t2 T2 pi c) + obtain y::"name" where fs: "y\(pi\x,pi\s2,pi\t2,pi\\,c)" by (rule exists_fresh[OF fs_name1]) + let ?sw="[(pi\x,y)]" + let ?pi'="?sw@pi" + have f1: "x\\" by fact + have f2: "(pi\x)\(pi\\)" using f1 by (simp add: fresh_bij) + have f3: "y\?pi'\\" using f1 by (auto simp add: pt_name2 fresh_left calc_atm perm_pi_simp) + have pr1: "(x,T1)#\ \ s2 == t2 : T2" by fact + then have "?pi'\((x,T1)#\) \ (?pi'\s2) == (?pi'\t2) : T2" by (rule equiv_def_eqvt) + then have "((y,T1)#(?pi'\\)) \ (?pi'\s2) == (?pi'\t2) : T2" by (simp add: calc_atm) + moreover + have ih1: "\c. P c (?pi'\((x,T1)#\)) (?pi'\s2) (?pi'\t2) T2" by fact + then have "\c. P c ((y,T1)#(?pi'\\)) (?pi'\s2) (?pi'\t2) T2" by (simp add: calc_atm) + ultimately have "P c (?pi'\\) (?pi'\Lam [x].s2) (?pi'\Lam [x].t2) (T1\T2)" using a4 f3 fs + by (simp add: calc_atm) + then have "P c (?sw\pi\\) (?sw\Lam [(pi\x)].(pi\s2)) (?sw\Lam [(pi\x)].(pi\t2)) (T1\T2)" + by (simp del: append_Cons add: calc_atm pt_name2) + moreover have "(?sw\(pi\\)) = (pi\\)" + by (rule perm_fresh_fresh) (simp_all add: fs f2) + moreover have "(?sw\(Lam [(pi\x)].(pi\s2))) = Lam [(pi\x)].(pi\s2)" + by (rule perm_fresh_fresh) (simp_all add: fs f2 abs_fresh) + moreover have "(?sw\(Lam [(pi\x)].(pi\t2))) = Lam [(pi\x)].(pi\t2)" + by (rule perm_fresh_fresh) (simp_all add: fs f2 abs_fresh) + ultimately have "P c (pi\\) (Lam [(pi\x)].(pi\s2)) (Lam [(pi\x)].(pi\t2)) (T1\T2)" by simp + then show "P c (pi\\) (pi\Lam [x].s2) (pi\Lam [x].t2) (T1\T2)" by simp + next + case (Q_Beta x \ s2 t2 T1 s12 t12 T2 pi c) + obtain y::"name" where fs: "y\(pi\x,pi\s12,pi\t12,pi\s2,pi\t2,pi\\,c)" + by (rule exists_fresh[OF fs_name1]) + let ?sw="[(pi\x,y)]" + let ?pi'="?sw@pi" + have f1: "x\(\,s2,t2)" by fact + have f2: "(pi\x)\(pi\(\,s2,t2))" using f1 by (simp add: fresh_bij) + have f3: "y\(?pi'\(\,s2,t2))" using f1 + by (auto simp add: pt_name2 fresh_left calc_atm perm_pi_simp fresh_prod) + have pr1: "(x,T1)#\ \ s12 == t12 : T2" by fact + then have "?pi'\((x,T1)#\) \ (?pi'\s12) == (?pi'\t12) : T2" by (rule equiv_def_eqvt) + then have "((y,T1)#(?pi'\\)) \ (?pi'\s12) == (?pi'\t12) : T2" by (simp add: calc_atm) + moreover + have ih1: "\c. P c (?pi'\((x,T1)#\)) (?pi'\s12) (?pi'\t12) T2" by fact + then have "\c. P c ((y,T1)#(?pi'\\)) (?pi'\s12) (?pi'\t12) T2" by (simp add: calc_atm) + moreover + have pr2: "\ \ s2 == t2 : T1" by fact + then have "(?pi'\\) \ (?pi'\s2) == (?pi'\t2) : T1" by (rule equiv_def_eqvt) + moreover + have ih2: "\c. P c (?pi'\\) (?pi'\s2) (?pi'\t2) T1" by fact + ultimately have "P c (?pi'\\) (?pi'\(App (Lam [x].s12) s2)) (?pi'\(t12[x::=t2])) T2" + using a6 f3 fs by (simp add: subst_eqvt calc_atm) + then have "P c (?sw\pi\\) (?sw\(App (Lam [(pi\x)].(pi\s12)) (pi\s2))) + (?sw\((pi\t12)[(pi\x)::=(pi\t2)])) T2" + by (simp del: append_Cons add: calc_atm pt_name2 subst_eqvt) + moreover have "(?sw\(pi\\)) = (pi\\)" + by (rule perm_fresh_fresh) (simp_all add: fs[simplified] f2[simplified]) + moreover have "(?sw\(App (Lam [(pi\x)].(pi\s12)) (pi\s2))) = App (Lam [(pi\x)].(pi\s12)) (pi\s2)" + by (rule perm_fresh_fresh) (simp_all add: fs[simplified] f2[simplified] abs_fresh) + moreover have "(?sw\((pi\t12)[(pi\x)::=(pi\t2)])) = ((pi\t12)[(pi\x)::=(pi\t2)])" + by (rule perm_fresh_fresh) + (simp_all add: fs[simplified] f2[simplified] fresh_subst fresh_subst'') + ultimately have "P c (pi\\) (App (Lam [(pi\x)].(pi\s12)) (pi\s2)) ((pi\t12)[(pi\x)::=(pi\t2)]) T2" + by simp + then show "P c (pi\\) (pi\App (Lam [x].s12) s2) (pi\t12[x::=t2]) T2" by (simp add: subst_eqvt) + qed + then have "P c (([]::name prm)\\) (([]::name prm)\s) (([]::name prm)\t) T" by blast + then show "P c \ s t T" by simp +qed + +text {* Weak head reduction *} + +inductive2 + whr_def :: "trm\trm\bool" ("_ \ _" [80,80] 80) +where + QAR_Beta[intro]: "App (Lam [x]. t12) t2 \ t12[x::=t2]" +| QAR_App[intro]: "t1 \ t1' \ App t1 t2 \ App t1' t2" + +declare trm.inject [simp add] +declare ty.inject [simp add] + +inductive_cases2 whr_Gen[elim]: "t \ t'" +inductive_cases2 whr_Lam[elim]: "Lam [x].t \ t'" +inductive_cases2 whr_App_Lam[elim]: "App (Lam [x].t12) t2 \ t" +inductive_cases2 whr_Var[elim]: "Var x \ t" +inductive_cases2 whr_Const[elim]: "Const n \ t" +inductive_cases2 whr_App[elim]: "App p q \ t" +inductive_cases2 whr_Const_Right[elim]: "t \ Const n" +inductive_cases2 whr_Var_Right[elim]: "t \ Var x" +inductive_cases2 whr_App_Right[elim]: "t \ App p q" + +declare trm.inject [simp del] +declare ty.inject [simp del] + +text {* Weak head normalization *} + +abbreviation + nf :: "trm \ bool" ("_ \|" [100] 100) +where + "t\| \ \(\ u. t \ u)" + +inductive2 + whn_def :: "trm\trm\bool" ("_ \ _" [80,80] 80) +where + QAN_Reduce[intro]: "\s \ t; t \ u\ \ s \ u" +| QAN_Normal[intro]: "t\| \ t \ t" + +lemma whr_eqvt: + fixes pi::"name prm" + assumes a: "t \ t'" + shows "(pi\t) \ (pi\t')" + using a + apply(induct) + apply(auto simp add: subst_eqvt fresh_bij) + done + +lemma whn_eqvt: + fixes pi::"name prm" + assumes a: "t \ t'" + shows "(pi\t) \ (pi\t')" + using a + apply(induct) + apply(rule QAN_Reduce) + apply(rule whr_eqvt) + apply(assumption)+ + apply(rule QAN_Normal) + apply(auto) + apply(drule_tac pi="rev pi" in whr_eqvt) + apply(perm_simp) + done + +text {* Algorithmic term equivalence and algorithmic path equivalence *} + +inductive2 + alg_equiv :: "(name\ty) list\trm\trm\ty\bool" ("_ \ _ <=> _ : _" [60,60] 60) +and + alg_path_equiv :: "(name\ty) list\trm\trm\ty\bool" ("_ \ _ \ _ : _" [60,60] 60) +where + QAT_Base[intro]: "\s \ p; t \ q; \ \ p \ q : TBase \ \ \ \ s <=> t : TBase" +| QAT_Arrow[intro]: "\x\\; x\s; x\t; (x,T1)#\ \ App s (Var x) <=> App t (Var x) : T2\ + \ \ \ s <=> t : T1 \ T2" +| QAT_One[intro]: "valid \ \ \ \ s <=> t : TUnit" +| QAP_Var[intro]: "\valid \;(x,T) \ set \\ \ \ \ Var x \ Var x : T" +| QAP_App[intro]: "\\ \ p \ q : T1 \ T2; \ \ s <=> t : T1 \ \ \ \ App p s \ App q t : T2" +| QAP_Const[intro]: "valid \ \ \ \ Const n \ Const n : TBase" + +lemma alg_equiv_alg_path_equiv_eqvt: + fixes pi::"name prm" + shows "\ \ s <=> t : T \ (pi\\) \ (pi\s) <=> (pi\t) : T" + and "\ \ p \ q : T \ (pi\\) \ (pi\p) \ (pi\q) : T" +apply(induct rule: alg_equiv_alg_path_equiv.inducts) +apply(auto intro: whn_eqvt simp add: fresh_bij valid_eqvt) +apply(rule_tac x="pi\x" in QAT_Arrow) +apply(auto simp add: fresh_bij) +apply(rule QAP_Var) +apply(simp add: valid_eqvt) +apply(simp add: pt_list_set_pi[OF pt_name_inst, symmetric]) +apply(perm_simp add: pt_set_bij1a[OF pt_name_inst, OF at_name_inst]) +done + +lemma alg_equiv_alg_path_equiv_strong_induct + [case_names QAT_Base QAT_Arrow QAT_One QAP_Var QAP_App QAP_Const]: + fixes c::"'a::fs_name" + assumes a1: "\s p t q \ c. \s \ p; t \ q; \ \ p \ q : TBase; \d. P2 d \ p q TBase\ + \ P1 c \ s t TBase" + and a2: "\x \ s t T1 T2 c. + \x\\; x\s; x\t; x\c; (x,T1)#\ \ App s (Var x) <=> App t (Var x) : T2; + \d. P1 d ((x,T1)#\) (App s (Var x)) (App t (Var x)) T2\ + \ P1 c \ s t (T1\T2)" + and a3: "\\ s t c. valid \ \ P1 c \ s t TUnit" + and a4: "\\ x T c. \valid \; (x,T) \ set \\ \ P2 c \ (Var x) (Var x) T" + and a5: "\\ p q T1 T2 s t c. + \\ \ p \ q : T1\T2; \d. P2 d \ p q (T1\T2); \ \ s <=> t : T1; \d. P1 d \ s t T1\ + \ P2 c \ (App p s) (App q t) T2" + and a6: "\\ n c. valid \ \ P2 c \ (Const n) (Const n) TBase" + shows "(\ \ s <=> t : T \P1 c \ s t T) \ (\' \ s' \ t' : T' \ P2 c \' s' t' T')" +proof - + have "(\ \ s <=> t : T \ (\c (pi::name prm). P1 c (pi\\) (pi\s) (pi\t) T)) \ + (\' \ s' \ t' : T' \ (\c (pi::name prm). P2 c (pi\\') (pi\s') (pi\t') T'))" + proof(induct rule: alg_equiv_alg_path_equiv.induct) + case (QAT_Base s q t p \) + then show "\c (pi::name prm). P1 c (pi\\) (pi\s) (pi\t) TBase" + apply(auto) + apply(rule_tac p="pi\q" and q="pi\p" in a1) + apply(simp_all add: whn_eqvt alg_equiv_alg_path_equiv_eqvt) + done + next + case (QAT_Arrow x \ s t T1 T2) + show ?case + proof (rule allI, rule allI) + fix c::"'a::fs_name" and pi::"name prm" + obtain y::"name" where fs: "y\(pi\s,pi\t,pi\\,c)" by (rule exists_fresh[OF fs_name1]) + let ?sw="[(pi\x,y)]" + let ?pi'="?sw@pi" + have f0: "x\\" "x\s" "x\t" by fact + then have f1: "x\(\,s,t)" by simp + have f2: "(pi\x)\(pi\(\,s,t))" using f1 by (simp add: fresh_bij) + have f3: "y\?pi'\(\,s,t)" using f1 + by (simp only: pt_name2 fresh_left, auto simp add: perm_pi_simp calc_atm) + then have f3': "y\?pi'\\" "y\?pi'\s" "y\?pi'\t" by (auto simp add: fresh_prod) + have pr1: "(x,T1)#\ \ App s (Var x) <=> App t (Var x) : T2" by fact + then have "(?pi'\((x,T1)#\)) \ (?pi'\(App s (Var x))) <=> (?pi'\(App t (Var x))) : T2" + by (simp only: alg_equiv_alg_path_equiv_eqvt) + then have "(y,T1)#(?pi'\\) \ (App (?pi'\s) (Var y)) <=> (App (?pi'\t) (Var y)) : T2" + by (simp add: calc_atm) + moreover + have ih1: "\c (pi::name prm). P1 c (pi\((x,T1)#\)) (pi\App s (Var x)) (pi\App t (Var x)) T2" + by fact + then have "\c. P1 c (?pi'\((x,T1)#\)) (?pi'\App s (Var x)) (?pi'\App t (Var x)) T2" + by auto + then have "\c. P1 c ((y,T1)#(?pi'\\)) (App (?pi'\s) (Var y)) (App (?pi'\t) (Var y)) T2" + by (simp add: calc_atm) + ultimately have "P1 c (?pi'\\) (?pi'\s) (?pi'\t) (T1\T2)" using a2 f3' fs by simp + then have "P1 c (?sw\pi\\) (?sw\pi\s) (?sw\pi\t) (T1\T2)" + by (simp del: append_Cons add: calc_atm pt_name2) + moreover have "(?sw\(pi\\)) = (pi\\)" + by (rule perm_fresh_fresh) (simp_all add: fs[simplified] f2[simplified]) + moreover have "(?sw\(pi\s)) = (pi\s)" + by (rule perm_fresh_fresh) (simp_all add: fs[simplified] f2[simplified]) + moreover have "(?sw\(pi\t)) = (pi\t)" + by (rule perm_fresh_fresh) (simp_all add: fs[simplified] f2[simplified]) + ultimately show "P1 c (pi\\) (pi\s) (pi\t) (T1\T2)" by (simp) + qed + next + case (QAT_One \ s t) + then show "\c (pi::name prm). P1 c (pi\\) (pi\s) (pi\t) TUnit" + by (auto intro!: a3 simp add: valid_eqvt) + next + case (QAP_Var \ x T) + then show "\c (pi::name prm). P2 c (pi \ \) (pi \ Var x) (pi \ Var x) T" + apply(auto intro!: a4 simp add: valid_eqvt) + apply(simp add: pt_list_set_pi[OF pt_name_inst, symmetric]) + apply(perm_simp add: pt_set_bij1a[OF pt_name_inst, OF at_name_inst]) + done + next + case (QAP_App \ p q T1 T2 s t) + then show "\c (pi::name prm). P2 c (pi\\) (pi\App p s) (pi\App q t) T2" + by (auto intro!: a5 simp add: alg_equiv_alg_path_equiv_eqvt) + next + case (QAP_Const \ n) + then show "\c (pi::name prm). P2 c (pi\\) (pi\Const n) (pi\Const n) TBase" + by (auto intro!: a6 simp add: valid_eqvt) + qed + then have "(\ \ s <=> t : T \ P1 c (([]::name prm)\\) (([]::name prm)\s) (([]::name prm)\t) T) \ + (\' \ s' \ t' : T' \ P2 c (([]::name prm)\\') (([]::name prm)\s') (([]::name prm)\t') T')" + by blast + then show ?thesis by simp +qed + +(* post-processing of the strong induction principle *) +(* extracts the strong_inducts-version from strong_induct *) + +setup {* + PureThy.add_thmss + [(("alg_equiv_alg_path_equiv_strong_inducts", + ProjectRule.projects (ProofContext.init (the_context())) [1,2] + (thm "alg_equiv_alg_path_equiv_strong_induct")), [])] #> snd +*} + +declare trm.inject [simp add] +declare ty.inject [simp add] + +inductive_cases2 whn_inv_auto[elim]: "t \ t'" + +inductive_cases2 alg_equiv_Base_inv_auto[elim]: "\ \ s<=>t : TBase" +inductive_cases2 alg_equiv_Arrow_inv_auto[elim]: "\ \ s<=>t : T1 \ T2" + +inductive_cases2 alg_path_equiv_Base_inv_auto[elim]: "\ \ s\t : TBase" +inductive_cases2 alg_path_equiv_Unit_inv_auto[elim]: "\ \ s\t : TUnit" +inductive_cases2 alg_path_equiv_Arrow_inv_auto[elim]: "\ \ s\t : T1 \ T2" + +inductive_cases2 alg_path_equiv_Var_left_inv_auto[elim]: "\ \ Var x \ t : T" +inductive_cases2 alg_path_equiv_Var_left_inv_auto'[elim]: "\ \ Var x \ t : T'" +inductive_cases2 alg_path_equiv_Var_right_inv_auto[elim]: "\ \ s \ Var x : T" +inductive_cases2 alg_path_equiv_Var_right_inv_auto'[elim]: "\ \ s \ Var x : T'" +inductive_cases2 alg_path_equiv_Const_left_inv_auto[elim]: "\ \ Const n \ t : T" +inductive_cases2 alg_path_equiv_Const_right_inv_auto[elim]: "\ \ s \ Const n : T" +inductive_cases2 alg_path_equiv_App_left_inv_auto[elim]: "\ \ App p s \ t : T" +inductive_cases2 alg_path_equiv_App_right_inv_auto[elim]: "\ \ s \ App q t : T" +inductive_cases2 alg_path_equiv_Lam_left_inv_auto[elim]: "\ \ Lam[x].s \ t : T" +inductive_cases2 alg_path_equiv_Lam_right_inv_auto[elim]: "\ \ t \ Lam[x].s : T" + +declare trm.inject [simp del] +declare ty.inject [simp del] + +text {* Subcontext. *} + +abbreviation + "sub" :: "(name\ty) list \ (name\ty) list \ bool" (" _ \ _ " [55,55] 55) +where + "\1 \ \2 \ (\a \. (a,\)\set \1 \ (a,\)\set \2) \ valid \2" + +lemma alg_equiv_valid: + shows "\ \ s <=> t : T \ valid \" and "\ \ s \ t : T \ valid \" +by (induct rule : alg_equiv_alg_path_equiv.inducts, auto) + +lemma algorithmic_monotonicity: + fixes \':: "(name\ty) list" + shows "\ \ s <=> t : T \ \\\' \ \' \ s <=> t : T" + and "\ \ s \ t : T \ \\\' \ \' \ s \ t : T" +proof (nominal_induct \ s t T and \ s t T avoiding: \' rule: alg_equiv_alg_path_equiv_strong_inducts) + case (QAT_Arrow x \ s t T1 T2 \') + have fs:"x\\" "x\s" "x\t" by fact + have h1:"(x,T1)#\ \ App s (Var x) <=> App t (Var x) : T2" by fact + have h2:"\\\'" by fact + have ih:"\\'. \(x,T1)#\ \ \'\ \ \' \ App s (Var x) <=> App t (Var x) : T2" by fact + have "x\\'" by fact + then have sub:"(x,T1)#\ \ (x,T1)#\'" using h2 by auto + then have "(x,T1)#\' \ App s (Var x) <=> App t (Var x) : T2" using ih by auto + then show "\' \ s <=> t : T1\T2" using sub fs by auto +qed (auto) + +text {* Logical equivalence. *} + +function log_equiv :: "((name\ty) list \ trm \ trm \ ty \ bool)" + ("_ \ _ is _ : _" [60,60,60,60] 60) +where + "\ \ s is t : TUnit = valid \" + | "\ \ s is t : TBase = \ \ s <=> t : TBase" + | "\ \ s is t : (T1 \ T2) = (valid \ \ (\\' s' t'. \\\' \ \' \ s' is t' : T1 \ (\' \ (App s s') is (App t t') : T2)))" +apply (auto simp add: ty.inject) +apply (subgoal_tac "(\ T1 T2. b=T1 \ T2) \ b=TUnit \ b=TBase" ) +apply (force) +apply (rule ty_cases) +done + +termination +apply(relation "measure (\(_,_,_,T). size T)") +apply(auto) +done + +lemma log_equiv_valid: + assumes "\ \ s is t : T" + shows "valid \" +using assms +by (induct rule: log_equiv.induct,auto elim: alg_equiv_valid) + +lemma logical_monotonicity : + fixes T::ty + assumes "\ \ s is t : T" "\\\'" + shows "\' \ s is t : T" +using assms +proof (induct arbitrary: \' rule: log_equiv.induct) + case (2 \ s t \') + then show "\' \ s is t : TBase" using algorithmic_monotonicity by auto +next + case (3 \ s t T1 T2 \') + have h1:"\ \ s is t : T1\T2" by fact + have h2:"\\\'" by fact + { + fix \'' s' t' + assume "\'\\''" "\'' \ s' is t' : T1" + then have "\'' \ (App s s') is (App t t') : T2" using h1 h2 by auto + } + then show "\' \ s is t : T1\T2" using h2 by auto +qed (auto) + +lemma forget: + fixes x::"name" + and L::"trm" + assumes a: "x\L" + shows "L[x::=P] = L" + using a + by (nominal_induct L avoiding: x P rule: trm.induct) + (auto simp add: fresh_atm abs_fresh) + +lemma subst_fun_eq: + fixes u::trm + assumes h:"[x].t1 = [y].t2" + shows "t1[x::=u] = t2[y::=u]" +proof - + { + assume "x=y" and "t1=t2" + then have ?thesis using h by simp + } + moreover + { + assume h1:"x \ y" and h2:"t1=[(x,y)] \ t2" and h3:"x \ t2" + then have "([(x,y)] \ t2)[x::=u] = t2[y::=u]" by (simp add: subst_rename) + then have ?thesis using h2 by simp + } + ultimately show ?thesis using alpha h by blast +qed + +lemma psubst_empty[simp]: + shows "[] = t" + by (nominal_induct t rule: trm.induct) (auto simp add: fresh_list_nil) + +lemma psubst_subst_psubst: + assumes h:"c \ \" + shows "\[c::=s] = (c,s)#\" + using h + apply(nominal_induct t avoiding: \ c s rule: trm.induct) + apply(auto simp add: fresh_list_cons fresh_atm forget lookup_fresh lookup_fresh' fresh_psubst) + done + +lemma subst_fresh_simpl: + assumes "x\\" + shows "\ = Var x" + using assms + by (induct \ arbitrary: x, auto simp add:fresh_list_cons fresh_prod fresh_atm) + +lemma psubst_subst_propagate: + assumes "x\\" + shows "\ = \[x::=\]" +using assms +proof (nominal_induct t avoiding: x u \ rule: trm.induct) + case (Var n x u \) + { assume "x=n" + moreover have "x\\" by fact + ultimately have "\ = \[x::=\]" using subst_fresh_simpl by auto + } + moreover + { assume h:"x\n" + then have "x\Var n" by (auto simp add: fresh_atm) + moreover have "x\\" by fact + ultimately have "x\\" using fresh_psubst by blast + then have " \[x::=\] = \" using forget by auto + then have "\ = \[x::=\]" using h by auto + } + ultimately show ?case by auto +next + case (Lam n t x u \) + have fs:"n\x" "n\u" "n\\" "x\\" by fact + have ih:"\ y s \. y\\ \ ((\<(t[y::=s])>) = ((\)[y::=(\)]))" by fact + have "\ <(Lam [n].t)[x::=u]> = \" using fs by auto + then have "\ <(Lam [n].t)[x::=u]> = Lam [n]. \" using fs by auto + moreover have "\ = \[x::=\]" using ih fs by blast + ultimately have "\ <(Lam [n].t)[x::=u]> = Lam [n].(\[x::=\])" by auto + moreover have "Lam [n].(\[x::=\]) = (Lam [n].\)[x::=\]" using fs fresh_psubst by auto + ultimately have "\<(Lam [n].t)[x::=u]> = (Lam [n].\)[x::=\]" using fs by auto + then show "\<(Lam [n].t)[x::=u]> = \[x::=\]" using fs by auto +qed (auto) + +lemma fresh_subst_fresh: + assumes "a\e" + shows "a\t[a::=e]" +using assms +by (nominal_induct t avoiding: a e rule: trm.induct) + (auto simp add: fresh_atm abs_fresh fresh_nat) + +lemma path_equiv_implies_nf: + assumes "\ \ s \ t : T" + shows "s \|" and "t \|" +using assms +by (induct rule: alg_equiv_alg_path_equiv.inducts (2)) (simp, auto) + +lemma path_equiv_implies_nf: + shows "\ \ s <=> t : T \ True" + and "\ \ s \ t : T \ s \|" + "\ \ s \ t : T \ t \|" + apply (induct rule: alg_equiv_alg_path_equiv.inducts) + apply auto + done + +lemma main_lemma: + shows "\ \ s is t : T \ \ \ s <=> t : T" and "\ \ p \ q : T \ \ \ p is q : T" +proof (nominal_induct T arbitrary: \ s t p q rule:ty.induct) + case (Arrow T1 T2) + { + case (1 \ s t) + have ih1:"\\ s t. \ \ s is t : T2 \ \ \ s <=> t : T2" by fact + have ih2:"\\ s t. \ \ s \ t : T1 \ \ \ s is t : T1" by fact + have h:"\ \ s is t : T1\T2" by fact + obtain x::name where fs:"x\(\,s,t)" by (erule exists_fresh[OF fs_name1]) + have "valid \" using h log_equiv_valid by auto + then have v:"valid ((x,T1)#\)" using fs by auto + then have "(x,T1)#\ \ Var x \ Var x : T1" by auto + then have "(x,T1)#\ \ Var x is Var x : T1" using ih2 by auto + then have "(x,T1)#\ \ App s (Var x) is App t (Var x) : T2" using h v by auto + then have "(x,T1)#\ \ App s (Var x) <=> App t (Var x) : T2" using ih1 by auto + then show "\ \ s <=> t : T1\T2" using fs by (auto simp add: fresh_prod) + next + case (2 \ p q) + have h:"\ \ p \ q : T1\T2" by fact + have ih1:"\\ s t. \ \ s \ t : T2 \ \ \ s is t : T2" by fact + have ih2:"\\ s t. \ \ s is t : T1 \ \ \ s <=> t : T1" by fact + { + fix \' s t + assume "\\\'" and hl:"\' \ s is t : T1" + then have "\' \ p \ q : T1 \ T2" using h algorithmic_monotonicity by auto + moreover have "\' \ s <=> t : T1" using ih2 hl by auto + ultimately have "\' \ App p s \ App q t : T2" by auto + then have "\' \ App p s is App q t : T2" using ih1 by auto + } + moreover have "valid \" using h alg_equiv_valid by auto + ultimately show "\ \ p is q : T1\T2" by auto + } +next + case TBase + { case 2 + have h:"\ \ s \ t : TBase" by fact + then have "s \|" and "t \|" using path_equiv_implies_nf by auto + then have "s \ s" and "t \ t" by auto + then have "\ \ s <=> t : TBase" using h by auto + then show "\ \ s is t : TBase" by auto + } +qed (auto elim:alg_equiv_valid) + +corollary corollary_main: + assumes "\ \ s \ t : T" + shows "\ \ s <=> t : T" +using assms main_lemma by blast + +lemma algorithmic_symmetry_aux: + shows "(\ \ s <=> t : T \ \ \ t <=> s : T) \ (\ \ s \ t : T \ \ \ t \ s : T)" +by (rule alg_equiv_alg_path_equiv.induct,auto) + +lemma algorithmic_symmetry: + assumes "\ \ s <=> t : T" + shows "\ \ t <=> s : T" +using assms by (simp add: algorithmic_symmetry_aux) + +lemma algorithmic_path_symmetry: + assumes "\ \ s \ t : T" + shows "\ \ t \ s : T" +using assms by (simp add: algorithmic_symmetry_aux) + +lemma red_unicity : + assumes "x \ a" "x \ b" + shows "a=b" + using assms +apply (induct arbitrary: b) +apply (erule whr_App_Lam) +apply (clarify) +apply (rule subst_fun_eq) +apply (force) +apply (force) +apply (erule whr_App) +apply (blast)+ +done + +lemma nf_unicity : + assumes "x \ a" "x \ b" + shows "a=b" + using assms +proof (induct arbitrary: b) + case (QAN_Reduce x t a b) + have h:"x \ t" "t \ a" by fact + have ih:"\b. t \ b \ a = b" by fact + have "x \ b" by fact + then obtain t' where "x \ t'" and hl:"t' \ b" using h by auto + then have "t=t'" using h red_unicity by auto + then show "a=b" using ih hl by auto +qed (auto) + +lemma Q_eqvt : + fixes pi:: "(name \ name) list" + shows "\ \ s <=> t : T \ (pi\\) \ (pi\s) <=> (pi\t) : T" + and "\ \ s \ t : T \ (pi\\) \ (pi\s) \ (pi\t) : T" +using assms +proof (induct rule:alg_equiv_alg_path_equiv.inducts) + case (QAP_Var \ x T) + then have "pi\(x,T) \ (pi\(set \))" using in_eqvt by blast + then have "(pi\x,T) \ (set (pi\\))" using set_eqvt perm_ty by auto + moreover have "valid \" by fact + ultimately show ?case using valid_eqvt by auto +next + case (QAT_Arrow x \ s t T1 T2) + then have h:"((pi\x)\(pi\\))" "((pi\x)\(pi\s))" "((pi\x)\(pi\t))" using fresh_bij by auto + have "(pi\((x,T1)#\)) \ pi \ (App s (Var x)) <=> pi \ (App t (Var x)) : T2" by fact + then have "(pi\((x,T1)#\)) \ (App (pi\s) (Var (pi\x))) <=> (App (pi\t) (Var (pi\x))) : T2" by auto + moreover have "pi\((x,T1)#\) = (pi\x,pi\T1)#(pi\\)" by auto + ultimately have "((pi\x,T1)#(pi\\)) \ (App (pi\s) (Var (pi\x))) <=> (App (pi\t) (Var (pi\x))) : T2" using perm_ty by auto + then show ?case using h by auto +qed (auto elim:whn_eqvt valid_eqvt) + +(* FIXME this lemma should not be here I am reinventing the wheel I guess *) + +lemma perm_basic[simp]: + fixes x y ::name +shows "[(x,y)]\y = x" +using assms using calc_atm by perm_simp + +lemma Q_Arrow_strong_inversion: + assumes fs:"x\\" "x\t" "x\u" and h:"\ \ t <=> u : T1\T2" + shows "(x,T1)#\ \ App t (Var x) <=> App u (Var x) : T2" +proof - +obtain y where fs2:"y\\" "y\u" "y\t" and "(y,T1)#\ \ App t (Var y) <=> App u (Var y) : T2" using h by auto +then have "([(x,y)]\((y,T1)#\)) \ [(x,y)]\ App t (Var y) <=> [(x,y)]\ App u (Var y) : T2" using Q_eqvt by blast +then show ?thesis using fs fs2 by (perm_simp) +qed + +lemma fresh_context[rule_format]: + fixes \ :: "(name\ty)list" + and a :: "name" + assumes "a\\" + shows "\(\\::ty. (a,\)\set \)" +using assms by(induct \, auto simp add: fresh_prod fresh_list_cons fresh_atm) + +lemma type_unicity_in_context: + fixes \ :: "(name\ty)list" + and pi:: "name prm" + and a :: "name" + and \ :: "ty" + assumes "valid \" and "(x,T1) \ set \" and "(x,T2) \ set \" + shows "T1=T2" +using assms by (induct \, auto dest!: fresh_context) + +(* + +Warning: This lemma is false. + +lemma algorithmic_type_unicity: + shows "\ \ \ s <=> t : T ; \ \ s <=> u : T' \ \ T = T'" + and "\ \ \ s \ t : T ; \ \ s \ u : T' \ \ T = T'" + +Here is the counter example : +\ \ Const n <=> Const n : Tbase and \ \ Const n <=> Const n : TUnit + +*) + +lemma algorithmic_path_type_unicity: + shows "\ \ \ s \ t : T ; \ \ s \ u : T' \ \ T = T'" +proof (induct arbitrary: u T' rule:alg_equiv_alg_path_equiv.inducts(2) [of _ _ _ _ _ "%a b c d . True" ]) + case (QAP_Var \ x T u T') + have "\ \ Var x \ u : T'" by fact + then have "u=Var x" and "(x,T') \ set \" by auto + moreover have "valid \" "(x,T) \ set \" by fact + ultimately show "T=T'" using type_unicity_in_context by auto +next + case (QAP_App \ p q T1 T2 s t u T2') + have ih:"\u T. \ \ p \ u : T \ T1\T2 = T" by fact + have "\ \ App p s \ u : T2'" by fact + then obtain r t T1' where "u = App r t" "\ \ p \ r : T1' \ T2'" by auto + then have "T1\T2 = T1' \ T2'" by auto + then show "T2=T2'" using ty.inject by auto +qed (auto) + +lemma algorithmic_transitivity: + shows "\ \ \ s <=> t : T ; \ \ t <=> u : T \ \ \ \ s <=> u : T" + and "\ \ \ s \ t : T ; \ \ t \ u : T \ \ \ \ s \ u : T" +proof (nominal_induct \ s t T and \ s t T avoiding: u rule: alg_equiv_alg_path_equiv_strong_inducts) + case (QAT_Base s p t q \ u) + have h:"s \ p" "t \ q" by fact + have ih:"\u. \ \ q \ u : TBase \ \ \ p \ u : TBase" by fact + have "\ \ t <=> u : TBase" by fact + then obtain r q' where hl:"t \ q'" "u \ r" "\ \ q' \ r : TBase" by auto + moreover have eq:"q=q'" using nf_unicity hl h by auto + ultimately have "\ \ p \ r : TBase" using ih by auto + then show "\ \ s <=> u : TBase" using hl h by auto +next + case (QAT_Arrow x \ s t T1 T2 u) + have fs:"x\\" "x\s" "x\t" by fact + moreover have h:"\ \ t <=> u : T1\T2" by fact + moreover then obtain y where "y\\" "y\t" "y\u" and "(y,T1)#\ \ App t (Var y) <=> App u (Var y) : T2" by auto + moreover have fs2:"x\u" by fact + ultimately have "(x,T1)#\ \ App t (Var x) <=> App u (Var x) : T2" using Q_Arrow_strong_inversion by blast + moreover have ih:"\ v. (x,T1)#\ \ App t (Var x) <=> v : T2 \ (x,T1)#\ \ App s (Var x) <=> v : T2" by fact + ultimately have "(x,T1)#\ \ App s (Var x) <=> App u (Var x) : T2" by auto + then show "\ \ s <=> u : T1\T2" using fs fs2 by auto +next + case (QAP_App \ p q T1 T2 s t u) + have h1:"\ \ p \ q : T1\T2" by fact + have ih1:"\u. \ \ q \ u : T1\T2 \ \ \ p \ u : T1\T2" by fact + have "\ \ s <=> t : T1" by fact + have ih2:"\u. \ \ t <=> u : T1 \ \ \ s <=> u : T1" by fact + have "\ \ App q t \ u : T2" by fact + then obtain r T1' v where ha:"\ \ q \ r : T1'\T2" and hb:"\ \ t <=> v : T1'" and eq:"u = App r v" by auto + moreover have "\ \ q \ p : T1\T2" using h1 algorithmic_path_symmetry by auto + ultimately have "T1'\T2 = T1\T2" using algorithmic_path_type_unicity by auto + then have "T1' = T1" using ty.inject by auto + then have "\ \ s <=> v : T1" "\ \ p \ r : T1\T2" using ih1 ih2 ha hb by auto + then show "\ \ App p s \ u : T2" using eq by auto +qed (auto) + +lemma algorithmic_weak_head_closure: + shows "\\ \ s <=> t : T ; s' \ s; t' \ t\ \ \ \ s' <=> t' : T" +by (nominal_induct \ s t T avoiding: s' t' + rule: alg_equiv_alg_path_equiv_strong_inducts(1) [of _ _ _ _ "%a b c d e. True"]) + (auto) + +lemma logical_symmetry: + assumes "\ \ s is t : T" + shows "\ \ t is s : T" +using assms by (nominal_induct arbitrary: \ s t rule:ty.induct, auto simp add: algorithmic_symmetry) + +lemma logical_transitivity: + assumes "\ \ s is t : T" "\ \ t is u : T" + shows "\ \ s is u : T" +using assms +proof (nominal_induct arbitrary: \ s t u rule:ty.induct) + case TBase + then show "\ \ s is u : TBase" by (auto elim: algorithmic_transitivity) +next + case (Arrow T1 T2 \ s t u) + have h1:"\ \ s is t : T1 \ T2" by fact + have h2:"\ \ t is u : T1 \ T2" by fact + have ih1:"\\ s t u. \\ \ s is t : T1; \ \ t is u : T1\ \ \ \ s is u : T1" by fact + have ih2:"\\ s t u. \\ \ s is t : T2; \ \ t is u : T2\ \ \ \ s is u : T2" by fact + { + fix \' s' u' + assume hsub:"\\\'" and hl:"\' \ s' is u' : T1" + then have "\' \ u' is s' : T1" using logical_symmetry by blast + then have "\' \ u' is u' : T1" using ih1 hl by blast + then have "\' \ App t u' is App u u' : T2" using h2 hsub by auto + moreover have "\' \ App s s' is App t u' : T2" using h1 hsub hl by auto + ultimately have "\' \ App s s' is App u u' : T2" using ih2 by blast + } + moreover have "valid \" using h1 alg_equiv_valid by auto + ultimately show "\ \ s is u : T1 \ T2" by auto +qed (auto) + +lemma logical_weak_head_closure: + assumes "\ \ s is t : T" "s' \ s" "t' \ t" + shows "\ \ s' is t' : T" +using assms +apply (nominal_induct arbitrary: \ s t s' t' rule:ty.induct) +apply (auto simp add: algorithmic_weak_head_closure) +apply (blast) +done + +lemma logical_weak_head_closure': + assumes "\ \ s is t : T" "s' \ s" + shows "\ \ s' is t : T" +using assms +proof (nominal_induct arbitrary: \ s t s' rule:ty.induct) + case (TBase \ s t s') + then show ?case by force +next + case (TUnit \ s t s') + then show ?case by auto +next + case (Arrow T1 T2 \ s t s') + have h1:"s' \ s" by fact + have ih:"\\ s t s'. \\ \ s is t : T2; s' \ s\ \ \ \ s' is t : T2" by fact + have h2:"\ \ s is t : T1\T2" by fact + then have hb:"\\' s' t'. \\\' \ \' \ s' is t' : T1 \ (\' \ (App s s') is (App t t') : T2)" by auto + { + fix \' s2 t2 + assume "\\\'" and "\' \ s2 is t2 : T1" + then have "\' \ (App s s2) is (App t t2) : T2" using hb by auto + moreover have "(App s' s2) \ (App s s2)" using h1 by auto + ultimately have "\' \ App s' s2 is App t t2 : T2" using ih by auto + } + moreover have "valid \" using h2 log_equiv_valid by auto + ultimately show "\ \ s' is t : T1\T2" by auto +qed + +abbreviation + log_equiv_subst :: "(name\ty) list \ (name\trm) list \ (name\trm) list \ (name\ty) list \ bool" + ("_ \ _ is _ over _" [60,60] 60) +where + "\' \ \ is \ over \ \ valid \' \ (\ x T. (x,T) \ set \ \ \' \ \ is \ : T)" + +lemma logical_pseudo_reflexivity: + assumes "\' \ t is s over \" + shows "\' \ s is s over \" +proof - + have "\' \ t is s over \" by fact + moreover then have "\' \ s is t over \" using logical_symmetry by blast + ultimately show "\' \ s is s over \" using logical_transitivity by blast +qed + +lemma logical_subst_monotonicity : + fixes \::"(name\ty) list" + and \'::"(name\ty) list" + and \''::"(name\ty) list" + assumes "\' \ s is t over \" "\'\\''" + shows "\'' \ s is t over \" + using assms logical_monotonicity by blast + +lemma equiv_subst_ext : + assumes h1:"\' \ \ is \ over \" and h2:"\' \ s is t : T" and fs:"x\\" + shows "\' \ (x,s)#\ is (x,t)#\ over (x,T)#\" +using assms +proof - +{ + fix y U + assume "(y,U) \ set ((x,T)#\)" + moreover + { + assume "(y,U) \ set [(x,T)]" + then have "\' \ (x,s)#\ is (x,t)#\ : U" by auto + } + moreover + { + assume hl:"(y,U) \ set \" + then have "\ y\\" by (induct \) (auto simp add: fresh_list_cons fresh_atm fresh_prod) + then have hf:"x\ Var y" using fs by (auto simp add: fresh_atm) + then have "(x,s)#\ = \" "(x,t)#\ = \" using fresh_psubst_simpl by blast+ + moreover have "\' \ \ is \ : U" using h1 hl by auto + ultimately have "\' \ (x,s)#\ is (x,t)#\ : U" by auto + } + ultimately have "\' \ (x,s)#\ is (x,t)#\ : U" by auto +} +moreover have "valid \'" using h2 log_equiv_valid by blast +ultimately show "\' \ (x,s)#\ is (x,t)#\ over (x,T)#\" by auto +qed + +theorem fundamental_theorem: + assumes "\ \ t : T" "\' \ \ is \ over \" + shows "\' \ \ is \ : T" +using assms +proof (nominal_induct avoiding:\' \ \ rule: typing_induct_strong) +case (t_Lam x \ T1 t2 T2 \' \ \) +have fs:"x\\" "x\\" "x\\" by fact +have h:"\' \ \ is \ over \" by fact +have ih:"\ \' \ \. \' \ \ is \ over (x,T1)#\ \ \' \ \ is \ : T2" by fact +{ + fix \'' s' t' + assume "\'\\''" and hl:"\''\ s' is t' : T1" + then have "\'' \ \ is \ over \" using logical_subst_monotonicity h by blast + then have "\'' \ (x,s')#\ is (x,t')#\ over (x,T1)#\" using equiv_subst_ext hl fs by blast + then have "\'' \ (x,s')#\ is (x,t')#\ : T2" using ih by auto + then have "\''\\[x::=s'] is \[x::=t'] : T2" using psubst_subst_psubst fs by simp + moreover have "App (Lam [x].\) s' \ \[x::=s']" by auto + moreover have "App (Lam [x].\) t' \ \[x::=t']" by auto + ultimately have "\''\ App (Lam [x].\) s' is App (Lam [x].\) t' : T2" + using logical_weak_head_closure by auto +} +moreover have "valid \'" using h by auto +ultimately show "\' \ \ is \ : T1\T2" using fs by auto +qed (auto) + + +theorem fundamental_theorem_2: + assumes h1: "\ \ s == t : T" + and h2: "\' \ \ is \ over \" + shows "\' \ \ is \ : T" +using h1 h2 +proof (nominal_induct \ s t T avoiding: \' \ \ rule: equiv_def_strong_induct) + case (Q_Refl \ t T \' \ \) + have "\ \ t : T" by fact + moreover have "\' \ \ is \ over \" by fact + ultimately show "\' \ \ is \ : T" using fundamental_theorem by blast +next + case (Q_Symm \ t s T \' \ \) + have "\' \ \ is \ over \" by fact + moreover have ih:"\ \' \ \. \' \ \ is \ over \ \ \' \ \ is \ : T" by fact + ultimately show "\' \ \ is \ : T" using logical_symmetry by blast +next + case (Q_Trans \ s t T u \' \ \) + have ih1:"\ \' \ \. \' \ \ is \ over \ \ \' \ \ is \ : T" by fact + have ih2:"\ \' \ \. \' \ \ is \ over \ \ \' \ \ is \ : T" by fact + have h:"\' \ \ is \ over \" by fact + then have "\' \ \ is \ over \" using logical_pseudo_reflexivity by auto + then have "\' \ \ is \ : T" using ih2 by auto + moreover have "\' \ \ is \ : T" using ih1 h by auto + ultimately show "\' \ \ is \ : T" using logical_transitivity by blast +next + case (Q_Abs x \ T1 s2 t2 T2 \' \ \) + have fs:"x\\" by fact + have fs2: "x\\" "x\\" by fact + have h1:"(x,T1)#\ \ s2 == t2 : T2" by fact + have h2:"\' \ \ is \ over \" by fact + have ih:"\\' \ \. \' \ \ is \ over (x,T1)#\ \ \' \ \ is \ : T2" by fact + { + fix \'' s' t' + assume "\'\\''" and hl:"\''\ s' is t' : T1" + then have "\'' \ \ is \ over \" using h2 logical_subst_monotonicity by blast + then have "\'' \ (x,s')#\ is (x,t')#\ over (x,T1)#\" using equiv_subst_ext hl fs by blast + then have "\'' \ (x,s')#\ is (x,t')#\ : T2" using ih by blast + then have "\''\ \[x::=s'] is \[x::=t'] : T2" using fs2 psubst_subst_psubst by auto + moreover have "App (Lam [x]. \) s' \ \[x::=s']" + and "App (Lam [x].\) t' \ \[x::=t']" by auto + ultimately have "\'' \ App (Lam [x]. \) s' is App (Lam [x].\) t' : T2" + using logical_weak_head_closure by auto + } + moreover have "valid \'" using h2 by auto + ultimately have "\' \ Lam [x].\ is Lam [x].\ : T1\T2" by auto + then show "\' \ \ is \ : T1\T2" using fs2 by auto +next + case (Q_App \ s1 t1 T1 T2 s2 t2 \' \ \) + then show "\' \ \ is \ : T2" by auto +next + case (Q_Beta x \ T1 s12 t12 T2 s2 t2 \' \ \) + have h:"\' \ \ is \ over \" by fact + have fs:"x\\" by fact + have fs2:"x\\" "x\\" by fact + have ih1:"\\' \ \. \' \ \ is \ over \ \ \' \ \ is \ : T1" by fact + have ih2:"\\' \ \. \' \ \ is \ over (x,T1)#\ \ \' \ \ is \ : T2" by fact + have "\' \ \ is \ : T1" using ih1 h by auto + then have "\' \ (x,\)#\ is (x,\)#\ over (x,T1)#\" using equiv_subst_ext h fs by blast + then have "\' \ (x,\)#\ is (x,\)#\ : T2" using ih2 by auto + then have "\' \ \[x::=\] is \[x::=\] : T2" using fs2 psubst_subst_psubst by auto + then have "\' \ \[x::=\] is \ : T2" using fs2 psubst_subst_propagate by auto + moreover have "App (Lam [x].\) (\) \ \[x::=\]" by auto + ultimately have "\' \ App (Lam [x].\) (\) is \ : T2" + using logical_weak_head_closure' by auto + then show "\' \ \ is \ : T2" using fs2 by simp +next + case (Q_Ext x \ s t T1 T2 \' \ \) + have h2:"\' \ \ is \ over \" by fact + have fs:"x\\" "x\s" "x\t" by fact + have ih:"\\' \ \. \' \ \ is \ over (x,T1)#\ \ \' \ \ is \ : T2" + by fact + { + fix \'' s' t' + assume hsub:"\'\\''" and hl:"\''\ s' is t' : T1" + then have "\'' \ \ is \ over \" using h2 logical_subst_monotonicity by blast + then have "\'' \ (x,s')#\ is (x,t')#\ over (x,T1)#\" using equiv_subst_ext hl fs by blast + then have "\'' \ (x,s')#\ is (x,t')#\ : T2" using ih by blast + then have "\'' \ App (((x,s')#\)) (((x,s')#\)<(Var x)>) is App ((x,t')#\) ((x,t')#\<(Var x)>) : T2" by auto + then have "\'' \ App ((x,s')#\) s' is App ((x,t')#\) t' : T2" by auto + then have "\'' \ App (\) s' is App (\) t' : T2" using fs fresh_psubst_simpl by auto + } + moreover have "valid \'" using h2 by auto + ultimately show "\' \ \ is \ : T1\T2" by auto +qed + +theorem completeness: + assumes "\ \ s == t : T" + shows "\ \ s <=> t : T" +using assms +proof - + { + fix x T + assume "(x,T) \ set \" "valid \" + then have "\ \ Var x is Var x : T" using main_lemma by blast + } + moreover have "valid \" using equiv_def_valid assms by auto + ultimately have "\ \ [] is [] over \" by auto + then have "\ \ [] is [] : T" using fundamental_theorem_2 assms by blast + then have "\ \ s is t : T" by simp + then show "\ \ s <=> t : T" using main_lemma by simp +qed + +(* Soundness is left as an exercise - like in the book*) + +(* +theorem soundness: + shows "\ \ \ s <=> t : T ; \ \ t : T ; \ \ s : T \ \ \ \ s == t : T" + and "\ \ \ s \ t : T ; \ \ t : T ; \ \ s : T \ \ \ \ s == t : T" +*) + +end +