Skip to content

Commit 71f8d1a

Browse files
authored
Refactor proof code (#7)
2 parents f42a973 + 53ec0f7 commit 71f8d1a

File tree

11 files changed

+556
-690
lines changed

11 files changed

+556
-690
lines changed

BetaEquivalence.thy

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
theory BetaEquivalence
2+
imports Semantics
3+
begin
4+
5+
lemma beta_same[simp]: "\<lbrakk> e1 \<longrightarrow>* e1' ; beta_nf e1 \<rbrakk> \<Longrightarrow> e1 = e1'"
6+
by (induction e1 e1' rule: Steps.induct) (auto simp: beta_nf_def)
7+
8+
fun path :: "term \<Rightarrow> term list \<Rightarrow> term \<Rightarrow> bool" where
9+
"path a [] b \<longleftrightarrow> a = b \<or> Step a b"
10+
| "path a (x#xs) b \<longleftrightarrow> Step a x \<and> path x xs b"
11+
12+
lemma path_snoc: "\<lbrakk> path a xs b ; Step b c \<rbrakk> \<Longrightarrow> path a (xs@[b]) c \<or> path a xs c"
13+
by (induction a xs b arbitrary: c rule: path.induct) auto
14+
15+
lemma Steps_concat: "\<lbrakk> e2 \<longrightarrow>* e3 ; e1 \<longrightarrow>* e2 \<rbrakk> \<Longrightarrow> e1 \<longrightarrow>* e3"
16+
apply (induction e2 e3 arbitrary: e1 rule: Steps.induct)
17+
using Steps.simps by blast+
18+
19+
lemma Steps_path: "a \<longrightarrow>* b \<longleftrightarrow> (\<exists>p. path a p b)"
20+
proof
21+
assume "a \<longrightarrow>* b"
22+
then show "\<exists>p. path a p b"
23+
proof (induction a b rule: Steps.induct)
24+
case (refl e)
25+
then have "path e [] e" by simp
26+
then show ?case by blast
27+
next
28+
case (trans e1 e2 e3)
29+
then obtain xs where "path e1 xs e2" by blast
30+
then have "path e1 (xs@[e2]) e3 \<or> path e1 xs e3" using trans(2) path_snoc by simp
31+
then show ?case by blast
32+
qed
33+
next
34+
assume "\<exists>p. path a p b"
35+
then obtain p where "path a p b" by blast
36+
then show "a \<longrightarrow>* b"
37+
proof (induction a p b rule: path.induct)
38+
case (1 a b)
39+
then show ?case using Steps.intros by auto
40+
next
41+
case (2 a x xs b)
42+
then have a: "a \<longrightarrow>* x" using Steps.intros by auto
43+
from 2 have b: "x \<longrightarrow>* b" by simp
44+
show ?case using Steps_concat[OF b a] .
45+
qed
46+
qed
47+
48+
lemma Steps_fwd_induct[consumes 1, case_names refl trans]:
49+
assumes "a \<longrightarrow>* b"
50+
and "\<And>x. P x x" "\<And>x y z. y \<longrightarrow>* z \<Longrightarrow> P y z \<Longrightarrow> Step x y \<Longrightarrow> P x z"
51+
shows "P a b"
52+
proof -
53+
from assms(1) obtain p where P: "path a p b" using Steps_path by blast
54+
then show ?thesis
55+
proof (induction a p b rule: path.induct)
56+
case (1 a b)
57+
then show ?case
58+
proof (cases "a = b")
59+
case True
60+
then show ?thesis using assms(2) by simp
61+
next
62+
case False
63+
then have 1: "Step a b" using 1 by simp
64+
have 2: "b \<longrightarrow>* b" using Steps.refl by simp
65+
show ?thesis using assms(3)[OF 2 assms(2) 1] .
66+
qed
67+
next
68+
case (2 a x xs b)
69+
then have 1: "P x b" by simp
70+
from 2 have 3: "x \<longrightarrow>* b" using Steps_path by auto
71+
from 2 have 4: "Step a x" by simp
72+
show ?case using assms(3)[OF 3 1 4] .
73+
qed
74+
qed
75+
76+
lemma beta_equivalence: "\<lbrakk> e1 \<longrightarrow>* e1' ; e2 \<longrightarrow>* e2' ; e1 = e2 ; beta_nf e1' ; beta_nf e2' \<rbrakk> \<Longrightarrow> e1' = e2'"
77+
proof (induction e1 e1' arbitrary: e2 e2' rule: Steps_fwd_induct)
78+
case (refl x)
79+
then show ?case by simp
80+
next
81+
case (trans x y z)
82+
then show ?case by (metis Steps.simps Steps_path beta_same path.elims(2) Step_deterministic)
83+
qed
84+
85+
end

Defs.thy

Lines changed: 17 additions & 419 deletions
Large diffs are not rendered by default.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ RUN for t in Nominal2 FinFun; do \
1212

1313
RUN ./Isabelle/bin/isabelle build -o system_heaps -b Nominal2
1414

15-
COPY ROOT Defs.thy Soundness.thy ./
15+
COPY ROOT *.thy ./

Lemmas.thy

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
theory Lemmas
2+
imports Syntax Defs
3+
begin
4+
5+
(* atom x \<sharp> t' \<Longrightarrow> atom x \<sharp> subst t' x t *)
6+
lemma fresh_subst_term: "atom x \<sharp> e' \<Longrightarrow> atom x \<sharp> subst_term e' x e"
7+
by (nominal_induct e avoiding: x e' rule: term.strong_induct) auto
8+
lemma fresh_subst_type: "atom a \<sharp> \<tau> \<Longrightarrow> atom a \<sharp> subst_type \<tau> a \<sigma>"
9+
by (nominal_induct \<sigma> avoiding: a \<tau> rule: \<tau>.strong_induct) auto
10+
lemma fresh_subst_term_type: "atom a \<sharp> \<tau> \<Longrightarrow> atom a \<sharp> subst_term_type \<tau> a e"
11+
by (nominal_induct e avoiding: a \<tau> rule: term.strong_induct) (auto simp: fresh_subst_type)
12+
13+
(* atom c \<sharp> t \<Longrightarrow> subst t' x t = subst t' c ((x \<leftrightarrow> c) \<bullet> t) *)
14+
lemma subst_term_var_name: "atom c \<sharp> e \<Longrightarrow> subst_term e' x e = subst_term e' c ((x \<leftrightarrow> c) \<bullet> e)"
15+
proof (nominal_induct e avoiding: c x e' rule: term.strong_induct)
16+
case (Let y \<tau> e1 e2)
17+
then show ?case by (smt flip_fresh_fresh fresh_Pair fresh_at_base(2) list.set(1) list.set(2) no_vars_in_ty singletonD subst_term.simps(7) term.fresh(7) term.perm_simps(7))
18+
qed (auto simp: flip_fresh_fresh fresh_at_base)
19+
lemma subst_type_var_name: "atom c \<sharp> \<sigma> \<Longrightarrow> subst_type \<tau> a \<sigma> = subst_type \<tau> c ((a \<leftrightarrow> c) \<bullet> \<sigma>)"
20+
by (nominal_induct \<sigma> avoiding: c a \<tau> rule: \<tau>.strong_induct) (auto simp: fresh_at_base)
21+
lemma subst_term_type_var_name: "atom c \<sharp> e \<Longrightarrow> subst_term_type \<tau> a e = subst_term_type \<tau> c ((a \<leftrightarrow> c) \<bullet> e)"
22+
proof (nominal_induct e avoiding: c a \<tau> rule: term.strong_induct)
23+
case (Lam x \<tau>1 e)
24+
then show ?case
25+
by (smt flip_fresh_fresh fresh_Pair fresh_at_base(2) list.set(1) list.set(2) singletonD subst_term_type.simps(3) subst_type_var_name term.fresh(5) term.perm_simps(5))
26+
next
27+
case (Let x \<tau>1 e1 e2)
28+
then show ?case
29+
by (smt flip_def fresh_Pair fresh_at_base(2) list.set(1) list.set(2) singletonD subst_term_type.simps(7) subst_type_var_name swap_fresh_fresh term.fresh(7) term.perm_simps(7))
30+
qed (auto simp: flip_fresh_fresh fresh_at_base subst_type_var_name)
31+
32+
(* [[atom a]]lst. t = [[atom a2]]lst. t2 \<Longrightarrow> subst t' a t = subst t' a2 t2 *)
33+
lemma subst_term_same: "[[atom a]]lst. e = [[atom a']]lst. e' \<Longrightarrow> subst_term t a e = subst_term t a' e'"
34+
by (metis Abs1_eq_iff(3) flip_commute subst_term_var_name)
35+
lemma subst_type_same: "[[atom a]]lst. e = [[atom a']]lst. e' \<Longrightarrow> subst_type \<tau> a e = subst_type \<tau> a' e'"
36+
by (metis Abs1_eq_iff(3) flip_commute subst_type_var_name)
37+
lemma subst_term_type_same: "[[atom a]]lst. e = [[atom a']]lst. e' \<Longrightarrow> subst_term_type \<tau> a e = subst_term_type \<tau> a' e'"
38+
by (metis Abs1_eq_iff(3) flip_commute subst_term_type_var_name)
39+
40+
(* atom x \<sharp> \<Gamma> \<Longrightarrow> \<not>isin (B x _) \<Gamma> *)
41+
lemma fresh_not_isin_tyvar: "atom a \<sharp> \<Gamma> \<Longrightarrow> \<not>isin (BTyVar a) \<Gamma>"
42+
apply (induction \<Gamma>) apply simp
43+
by (metis binder.fresh(2) binder.strong_exhaust fresh_Cons fresh_at_base(2) isin.simps(4) isin.simps(5))
44+
lemma fresh_not_isin_var: "atom x \<sharp> \<Gamma> \<Longrightarrow> \<not>isin (BVar x \<tau>) \<Gamma>"
45+
apply (induction \<Gamma>) apply simp
46+
by (metis (mono_tags, lifting) binder.fresh(1) binder.strong_exhaust fresh_Cons fresh_at_base(2) isin.simps(2) isin.simps(3))
47+
48+
(* atom x \<sharp> t \<Longrightarrow> subst t' x t = t *)
49+
lemma fresh_subst_term_same: "atom x \<sharp> e \<Longrightarrow> subst_term e' x e = e"
50+
proof (induction e' x e rule: subst_term.induct)
51+
case (2 y e x \<tau> e2)
52+
then show ?case using fresh_PairD(2) fresh_at_base(2) by fastforce
53+
next
54+
case (7 y e x \<tau> e1 e2)
55+
then show ?case using fresh_PairD(2) fresh_at_base(2) by fastforce
56+
qed auto
57+
58+
lemma fresh_subst_type_same: "atom a \<sharp> \<sigma> \<Longrightarrow> subst_type \<tau> a \<sigma> = \<sigma>"
59+
proof (induction \<tau> a \<sigma> rule: subst_type.induct)
60+
case (4 b \<tau> a \<sigma>)
61+
then show ?case
62+
using fresh_Pair fresh_at_base(2) fresh_def list.set(1) list.set(2) subst_type.simps(4) by fastforce
63+
qed auto
64+
65+
lemma fresh_subst_term_type_same: "atom a \<sharp> e \<Longrightarrow> subst_term_type \<tau> a e = e"
66+
proof (induction \<tau> a e rule: subst_term_type.induct)
67+
case (4 b \<tau> a e2)
68+
then show ?case
69+
by (simp add: "4.hyps" fresh_Pair fresh_at_base(2))
70+
qed (auto simp: fresh_subst_type_same)
71+
72+
(* misc *)
73+
lemma fv_supp_subset: "fv_\<tau> \<tau> \<subseteq> supp \<tau>"
74+
by (induction \<tau> rule: \<tau>.induct) (auto simp: \<tau>.supp \<tau>.fv_defs)
75+
76+
lemma subst_type_order: "\<lbrakk> atom b \<sharp> \<tau>' ; atom b \<sharp> a \<rbrakk> \<Longrightarrow> subst_type \<tau>' a (subst_type \<tau> b \<sigma>') = subst_type (subst_type \<tau>' a \<tau>) b (subst_type \<tau>' a \<sigma>')"
77+
proof (nominal_induct \<sigma>' avoiding: a b \<tau> \<tau>' rule: \<tau>.strong_induct)
78+
case (TyVar x)
79+
then show ?case using fresh_at_base(2) fresh_subst_type_same by auto
80+
next
81+
case (TyForall x1 x2a)
82+
then show ?case
83+
by (smt flip_at_simps(1) flip_at_simps(2) flip_commute fresh_Pair fresh_subst_type fresh_subst_type_same subst_type.eqvt subst_type.simps(4) subst_type_var_name)
84+
qed (auto simp: fresh_subst_type)
85+
86+
end

Nominal2_Lemmas.thy

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
theory Nominal2_Lemmas
2+
imports Main "Nominal2.Nominal2"
3+
begin
4+
5+
lemma Abs_lst_rename:
6+
fixes a c::"'a::at" and e::"'e::fs"
7+
assumes "atom c \<sharp> e"
8+
shows "[[atom a]]lst. e = [[atom c]]lst. (a \<leftrightarrow> c) \<bullet> e"
9+
proof -
10+
from assms have 1: "atom c \<notin> supp e - set [atom a]" by (simp add: fresh_def)
11+
have 2: "atom a \<notin> supp e - set [atom a]" by simp
12+
show ?thesis using Abs_swap2[OF 2 1] by (simp add: flip_def)
13+
qed
14+
15+
lemma eqvt_at_deep:
16+
assumes fresh: "atom a \<sharp> (x, e)" "atom c \<sharp> (x, e)"
17+
and eqvt_at: "eqvt_at f (x, e, e2)"
18+
shows "(a \<leftrightarrow> c) \<bullet> f (x, e, e2) = f (x, e, (a \<leftrightarrow> c) \<bullet> e2)"
19+
proof -
20+
have 1: "(a \<leftrightarrow> c) \<bullet> f (x, e, e2) = f ((a \<leftrightarrow> c) \<bullet> (x, e, e2))" using eqvt_at eqvt_at_def by blast
21+
have 2: "(a \<leftrightarrow> c) \<bullet> (x, e, e2) = (x, e, (a \<leftrightarrow> c) \<bullet> e2)" using fresh fresh_Pair flip_fresh_fresh by fastforce
22+
23+
show ?thesis using 1 2 by argo
24+
qed
25+
26+
lemma Abs_lst_rename_deep:
27+
fixes a c::"'a::at" and x::"'b::fs" and e::"'c::fs" and e2::"'d::fs" and f::"'b * 'c * 'd \<Rightarrow> 'e::fs"
28+
assumes fresh: "atom c \<sharp> f (x, e, e2)" "atom c \<sharp> (x, e)" "atom a \<sharp> (x, e)"
29+
and eqvt_at: "eqvt_at f (x, e, e2)"
30+
shows "[[atom a]]lst. f (x, e, e2) = [[atom c]]lst. f (x, e, (a \<leftrightarrow> c) \<bullet> e2)"
31+
proof -
32+
have 1: "[[atom a]]lst. f (x, e, e2) = [[atom c]]lst. (a \<leftrightarrow> c) \<bullet> f (x, e, e2)" by (rule Abs_lst_rename[OF fresh(1)])
33+
have 2: "(a \<leftrightarrow> c) \<bullet> f (x, e, e2) = f (x, e, (a \<leftrightarrow> c) \<bullet> e2)" by (rule eqvt_at_deep[OF fresh(3) fresh(2) eqvt_at])
34+
show ?thesis using 1 2 by argo
35+
qed
36+
37+
lemma Abs_lst_rename_both:
38+
fixes a c::"'a::at" and e e'::"'b::fs"
39+
assumes fresh: "atom c \<sharp> (y, e, y', e')"
40+
and equal: "[[atom y]]lst. e = [[atom y']]lst. e'"
41+
shows "(y \<leftrightarrow> c) \<bullet> e = (y' \<leftrightarrow> c) \<bullet> e'"
42+
proof -
43+
from assms have "(y \<leftrightarrow> c) \<bullet> ([[atom y]]lst. e) = (y' \<leftrightarrow> c) \<bullet> ([[atom y']]lst. e')" by auto
44+
then have "[[atom c]]lst. (y \<leftrightarrow> c) \<bullet> e = [[atom c]]lst. (y' \<leftrightarrow> c) \<bullet> e'" by auto
45+
then show ?thesis using Abs1_eq(3) by blast
46+
qed
47+
48+
lemma Abs_sumC:
49+
fixes y y'::"'a::at" and x x'::"'b::fs" and e e'::"'c::fs" and e2 e2'::"'d::fs" and f::"'b * 'c * 'd \<Rightarrow> 'e::fs"
50+
assumes fresh: "atom y \<sharp> (x, e)" "atom y' \<sharp> (x', e')"
51+
and eqvt_at: "eqvt_at f (x, e, e2)" "eqvt_at f (x', e', e2')"
52+
and equal: "[[atom y]]lst. e2 = [[atom y']]lst. e2'" "x = x'" "e = e'"
53+
shows "[[atom y]]lst. f (x, e, e2) = [[atom y']]lst. f (x', e', e2')"
54+
proof -
55+
obtain c::"'a" where "atom c \<sharp> (y, y', e, e', x, x', e2, e2', f (x, e, e2), f (x', e', e2'))" using obtain_fresh by blast
56+
then have c: "atom c \<sharp> f (x, e, e2)" "atom c \<sharp> (x, e)" "atom c \<sharp> f (x', e', e2')" "atom c \<sharp> (x', e')" "atom c \<sharp> (y, e2, y', e2')" using fresh_Pair by auto
57+
58+
have 1: "[[atom y]]lst. f (x, e, e2) = [[atom c]]lst. f (x, e, (y \<leftrightarrow> c) \<bullet> e2)" by (rule Abs_lst_rename_deep[OF c(1) c(2) fresh(1) eqvt_at(1)])
59+
have 2: "[[atom y']]lst. f (x', e', e2') = [[atom c]]lst. f (x', e', (y' \<leftrightarrow> c) \<bullet> e2')" by (rule Abs_lst_rename_deep[OF c(3) c(4) fresh(2) eqvt_at(2)])
60+
have 3: "(y \<leftrightarrow> c) \<bullet> e2 = (y' \<leftrightarrow> c) \<bullet> e2'" by (rule Abs_lst_rename_both[OF c(5) equal(1)])
61+
62+
show ?thesis using 1 2 3 equal by argo
63+
qed
64+
65+
end

ROOT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
session Lambda = HOL + sessions "HOL-Eisbach" Nominal2
22
theories
3-
Defs
3+
BetaEquivalence
44
Soundness

Semantics.thy

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
theory Semantics
2+
imports Syntax Defs Lemmas
3+
begin
4+
5+
no_notation HOL.implies (infixr "\<longrightarrow>" 25)
6+
7+
inductive Step :: "term \<Rightarrow> term \<Rightarrow> bool" ("_ \<longrightarrow> _" 25) where
8+
ST_BetaI: "\<lbrakk> is_value v \<rbrakk> \<Longrightarrow> App (\<lambda> x : \<tau> . e) v \<longrightarrow> subst_term v x e"
9+
10+
| ST_AppI: "\<lbrakk> e1 \<longrightarrow> e2 \<rbrakk> \<Longrightarrow> App e1 e \<longrightarrow> App e2 e"
11+
12+
| ST_App2I: "\<lbrakk> is_value v ; e1 \<longrightarrow> e2 \<rbrakk> \<Longrightarrow> App v e1 \<longrightarrow> App v e2"
13+
14+
| ST_SubstI: "\<lbrakk> is_value v \<rbrakk> \<Longrightarrow> Let x \<tau> v e \<longrightarrow> subst_term v x e"
15+
16+
| ST_LetI: "\<lbrakk> e1 \<longrightarrow> e2 \<rbrakk> \<Longrightarrow> Let x \<tau> e1 e \<longrightarrow> Let x \<tau> e2 e"
17+
18+
| ST_BetaTI: "TyApp (\<Lambda> a . e) \<tau> \<longrightarrow> subst_term_type \<tau> a e"
19+
20+
| ST_AppTI: "\<lbrakk> e1 \<longrightarrow> e2 \<rbrakk> \<Longrightarrow> TyApp e1 \<tau> \<longrightarrow> TyApp e2 \<tau>"
21+
equivariance Step
22+
nominal_inductive Step .
23+
24+
inductive Steps :: "term \<Rightarrow> term \<Rightarrow> bool" (infix "\<longrightarrow>*" 70) where
25+
refl: "e \<longrightarrow>* e"
26+
| trans: "\<lbrakk> e1 \<longrightarrow>* e2 ; e2 \<longrightarrow> e3 \<rbrakk> \<Longrightarrow> Steps e1 e3"
27+
28+
definition beta_nf :: "term \<Rightarrow> bool" where
29+
"beta_nf e \<equiv> \<nexists>e'. e \<longrightarrow> e'"
30+
31+
definition stuck :: "term \<Rightarrow> bool" where
32+
"stuck e \<equiv> \<not>is_value e \<and> beta_nf e"
33+
34+
lemma value_beta_nf: "is_value v \<Longrightarrow> beta_nf v"
35+
apply (cases v rule: term.exhaust)
36+
using Step.cases beta_nf_def by fastforce+
37+
38+
lemma Step_deterministic: "\<lbrakk> e \<longrightarrow> e1 ; e \<longrightarrow> e2 \<rbrakk> \<Longrightarrow> e1 = e2"
39+
proof (induction e e1 arbitrary: e2 rule: Step.induct)
40+
case (ST_BetaI v x \<tau> e)
41+
from ST_BetaI(2) show ?case
42+
proof cases
43+
case (ST_BetaI y e')
44+
then show ?thesis using subst_term_same by blast
45+
next
46+
case (ST_AppI e')
47+
then show ?thesis using Step.cases by fastforce
48+
next
49+
case (ST_App2I e')
50+
then show ?thesis using ST_BetaI value_beta_nf beta_nf_def by blast
51+
qed
52+
next
53+
case (ST_AppI e1 e2 e)
54+
from ST_AppI(3) show ?case
55+
apply cases
56+
using ST_AppI Step.cases value_beta_nf beta_nf_def by fastforce+
57+
next
58+
case (ST_App2I v e1 e2)
59+
from ST_App2I(4) show ?case
60+
apply cases
61+
using ST_App2I.hyps(2) value_beta_nf beta_nf_def apply blast
62+
using ST_App2I.hyps(1) value_beta_nf beta_nf_def apply blast
63+
using ST_App2I value_beta_nf beta_nf_def by auto
64+
next
65+
case (ST_SubstI v x e)
66+
from ST_SubstI(2) show ?case
67+
proof cases
68+
case (ST_SubstI x e)
69+
then show ?thesis using subst_term_same by blast
70+
next
71+
case (ST_LetI e2 x e)
72+
then show ?thesis using ST_SubstI.hyps value_beta_nf beta_nf_def by blast
73+
qed
74+
next
75+
case (ST_LetI t1 t2 x \<tau> e)
76+
from ST_LetI(3) show ?case
77+
apply cases
78+
using ST_LetI value_beta_nf beta_nf_def by auto
79+
next
80+
case (ST_BetaTI a e \<tau>)
81+
then show ?case
82+
proof cases
83+
case (ST_BetaTI b e')
84+
then show ?thesis using subst_term_type_same by blast
85+
next
86+
case (ST_AppTI e2)
87+
then show ?thesis using is_value.simps(3) value_beta_nf beta_nf_def by blast
88+
qed
89+
next
90+
case (ST_AppTI e1 e2 \<tau>)
91+
from ST_AppTI(3) show ?case
92+
apply cases
93+
using ST_AppTI value_beta_nf beta_nf_def by auto
94+
qed
95+
96+
end

0 commit comments

Comments
 (0)