Initial commit.
authorurbanc
Mon, 07 Nov 2005 15:19:03 +0100
changeset 18106 836135c8acb2
parent 18105 4c9c081a416b
child 18107 ee6b4d3af498
Initial commit.
src/HOL/Nominal/Examples/CR.thy
src/HOL/Nominal/Examples/Lam_substs.thy
src/HOL/Nominal/Examples/Lambda_mu.thy
src/HOL/Nominal/Examples/SN.thy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Nominal/Examples/CR.thy	Mon Nov 07 15:19:03 2005 +0100
@@ -0,0 +1,952 @@
+
+theory cr
+imports lam_substs
+begin
+
+lemma forget[rule_format]: 
+  shows "a\<sharp>t1 \<longrightarrow> t1[a::=t2] = t1"
+proof (nominal_induct t1 rule: lam_induct)
+  case (Var a t2 b) 
+  show ?case by (simp, simp add: fresh_atm)
+next 
+  case App
+  thus ?case by (simp add: fresh_prod)
+next
+  case (Lam a t2 c t)
+  have i: "\<forall>a b. a\<sharp>t \<longrightarrow>  t[a::=b] = t" by fact
+  have "c\<sharp>(a,t2)" by fact
+  hence a: "a\<noteq>c" and b: "c\<sharp>t2" by (auto simp add: fresh_prod fresh_atm)
+  show ?case
+  proof 
+    assume "a\<sharp>Lam [c].t" 
+    hence "a\<sharp>t" using a by (force simp add: abs_fresh)
+    hence "t[a::=t2] = t" using i by simp
+    thus "(Lam [c].t)[a::=t2] = Lam [c].t" using a b by (simp add: alpha)
+  qed
+qed
+
+lemma forget[rule_format]: 
+  shows "a\<sharp>t1 \<longrightarrow> t1[a::=t2] = t1"
+apply (nominal_induct t1 rule: lam_induct)
+apply(auto simp add: abs_fresh fresh_atm fresh_prod)
+done
+
+lemma fresh_fact[rule_format]: 
+  fixes   b :: "name"
+  and    a  :: "name"
+  and    t1 :: "lam"
+  and    t2 :: "lam" 
+  shows "a\<sharp>t1\<longrightarrow>a\<sharp>t2\<longrightarrow>a\<sharp>(t1[b::=t2])"
+proof (nominal_induct t1 rule: lam_induct)
+  case (Var a b t2 c) 
+  show ?case by (simp)
+next
+  case App 
+  thus ?case by (simp add: fresh_prod)
+next
+  case (Lam a b t2 c t)
+  have  i: "\<forall>(a::name) b t2. a\<sharp>t\<longrightarrow>a\<sharp>t2\<longrightarrow>a\<sharp>(t[b::=t2])" by fact
+  have "c\<sharp>(a,b,t2)" by fact
+  hence b: "c\<noteq>a \<and> c\<noteq>b \<and> c\<sharp>t2" by (simp add: fresh_prod fresh_atm) 
+  show ?case 
+  proof (intro strip)
+    assume a1: "a\<sharp>t2"
+    assume a2: "a\<sharp>Lam [c].t"
+    hence "a\<sharp>t" using b by (force simp add: abs_fresh)
+    hence "a\<sharp>t[b::=t2]" using a1 i by simp
+    thus "a\<sharp>(Lam [c].t)[b::=t2]" using b by (simp add: abs_fresh)
+  qed
+qed
+
+lemma fresh_fact[rule_format]: 
+  fixes   b :: "name"
+  and    a  :: "name"
+  and    t1 :: "lam"
+  and    t2 :: "lam" 
+  shows "a\<sharp>t1\<longrightarrow>a\<sharp>t2\<longrightarrow>a\<sharp>(t1[b::=t2])"
+apply(nominal_induct t1 rule: lam_induct)
+apply(auto simp add: abs_fresh fresh_prod fresh_atm)
+done
+
+lemma subs_lemma:  
+  fixes x::"name"
+  and   y::"name"
+  and   L::"lam"
+  and   M::"lam"
+  and   N::"lam"
+  shows "x\<noteq>y\<longrightarrow>x\<sharp>L\<longrightarrow>M[x::=N][y::=L] = M[y::=L][x::=N[y::=L]]"
+proof (nominal_induct M rule: lam_induct)
+  case (Var L N x y z) (* case 1: Variables*)
+  show ?case
+  proof (intro strip)
+    assume a1: "x\<noteq>y"
+    and    a2: "x\<sharp>L"
+    show "Var z[x::=N][y::=L] = Var z[y::=L][x::=N[y::=L]]" (is "?LHS = ?RHS")
+    proof -
+      have "z=x \<or> (z\<noteq>x \<and> z=y) \<or> (z\<noteq>x \<and> z\<noteq>y)" by force 
+      moreover (*Case 1.1*)
+      { assume c1: "z=x"
+	have c1l: "?LHS = N[y::=L]"    using c1    by simp
+	have c1r: "?RHS = N[y::=L]"    using c1 a1 by simp
+	from c1l and c1r have "?LHS = ?RHS"  by simp
+      }
+      moreover (*Case 1.2*)
+      { assume c2: "z\<noteq>x \<and> z=y"
+	have c2l: "?LHS = L"               using c2 by force
+	have c2r: "?RHS = L[x::=N[y::=L]]" using c2 by force
+	have c2x: "L[x::=N[y::=L]] = L"    using a2 by (simp add: forget)
+	from c2l and c2r and c2x have "?LHS = ?RHS" by simp
+      }
+      moreover (*Case 1.3*)
+      { assume c3: "z\<noteq>x \<and> z\<noteq>y"
+	have c3l: "?LHS = Var z" using c3 by force
+	have c3r: "?RHS = Var z" using c3 by force
+	from c3l and c3r have "?LHS = ?RHS" by simp
+      }
+      ultimately show "?LHS = ?RHS" by blast
+    qed
+  qed
+next
+  case (Lam L N x y z M1) (* case 2: lambdas *)
+  assume f1: "z\<sharp>(L,N,x,y)"
+  from f1 have f2: "z \<sharp> N[y::=L]" by (simp add: fresh_fact fresh_prod)
+  show ?case
+  proof (intro strip)
+    assume  a1: "x\<noteq>y"
+    and     a2: "x\<sharp>L"
+    show "(Lam [z].M1)[x::=N][y::=L] = (Lam [z].M1)[y::=L][x::=N[y::=L]]" (is "?LHS=?RHS") 
+    proof -
+      have "?LHS = Lam [z].(M1[x::=N][y::=L])"             using f1 
+	by (simp add: fresh_prod fresh_atm)
+      also have "\<dots> = Lam [z].(M1[y::=L][x::=N[y::=L]])"   using a1 a2 Lam(2)  by simp
+      also have "\<dots> = (Lam [z].(M1[y::=L]))[x::=N[y::=L]]" using f1 f2 
+	by (simp add: fresh_prod fresh_atm)
+      also have "\<dots> = ?RHS" using f1 by (simp add: fresh_prod fresh_atm)
+      finally show "?LHS = ?RHS" .
+    qed
+  qed
+next
+  case (App L N x y M1 M2) (* case 3: applications *)
+  show ?case
+  proof (intro strip)
+    assume a1: "x\<noteq>y"
+    and    a2: "x\<sharp>L"
+    from a1 a2 App show "(App M1 M2)[x::=N][y::=L] = (App M1 M2)[y::=L][x::=N[y::=L]]" by simp
+  qed
+qed
+
+lemma subs_lemma: 
+  fixes x::"name"
+  and   y::"name"
+  and   L::"lam"
+  and   M::"lam"
+  and   N::"lam"
+  shows "x\<noteq>y\<longrightarrow>x\<sharp>L\<longrightarrow>M[x::=N][y::=L] = M[y::=L][x::=N[y::=L]]"
+proof (nominal_induct M rule: lam_induct)
+  case (Var L N x y z) (* case 1: Variables*)
+  show ?case
+  proof -
+    have "z=x \<or> (z\<noteq>x \<and> z=y) \<or> (z\<noteq>x \<and> z\<noteq>y)" by force
+    thus "x\<noteq>y\<longrightarrow>x\<sharp>L\<longrightarrow>Var z[x::=N][y::=L] = Var z[y::=L][x::=N[y::=L]]" 
+    using forget by force
+  qed
+next
+  case (Lam L N x y z M1) (* case 2: lambdas *)
+  assume f1: "z\<sharp>(L,N,x,y)" 
+  hence f2: "z\<sharp>N[y::=L]" by (simp add: fresh_fact fresh_prod)
+  show ?case
+  proof (intro strip)
+    assume a1: "x\<noteq>y"
+    and    a2: "x\<sharp>L"
+    show "(Lam [z].M1)[x::=N][y::=L] = (Lam [z].M1)[y::=L][x::=N[y::=L]]" (is "?LHS=?RHS") 
+    proof -
+      have "?LHS = Lam [z].(M1[x::=N][y::=L])" using f1 by (simp add: fresh_prod fresh_atm)
+      also have "\<dots> = Lam [z].(M1[y::=L][x::=N[y::=L]])"   using a1 a2 Lam(2)  by simp
+      also have "\<dots> = ?RHS" using f1 f2 by (simp add: fresh_prod fresh_atm)
+      finally show "?LHS = ?RHS" .
+    qed
+  qed
+next
+  case (App L N x y M1 M2) (* case 3: applications *)
+  thus "x\<noteq>y\<longrightarrow>x\<sharp>L\<longrightarrow>(App M1 M2)[x::=N][y::=L] = (App M1 M2)[y::=L][x::=N[y::=L]]" by simp
+qed
+
+lemma subs_lemma:  
+  fixes x::"name"
+  and   y::"name"
+  and   L::"lam"
+  and   M::"lam"
+  and   N::"lam"
+  shows "x\<noteq>y\<longrightarrow>x\<sharp>L\<longrightarrow>M[x::=N][y::=L] = M[y::=L][x::=N[y::=L]]"
+apply(nominal_induct M rule: lam_induct)
+apply(auto simp add: fresh_fact forget fresh_prod fresh_atm)
+done
+
+lemma subst_rename[rule_format]: 
+  fixes  c  :: "name"
+  and    a  :: "name"
+  and    t1 :: "lam"
+  and    t2 :: "lam"
+  shows "c\<sharp>t1 \<longrightarrow> (t1[a::=t2] = ([(c,a)]\<bullet>t1)[c::=t2])"
+proof (nominal_induct t1 rule: lam_induct)
+  case (Var a c t2 b)
+  show "c\<sharp>(Var b) \<longrightarrow> (Var b)[a::=t2] = ([(c,a)]\<bullet>(Var b))[c::=t2]" by (simp add: calc_atm fresh_atm)
+next
+  case App thus ?case by (force simp add: fresh_prod)
+next
+  case (Lam a c t2 b s)
+  have i: "\<forall>a c t2. c\<sharp>s \<longrightarrow> (s[a::=t2] = ([(c,a)]\<bullet>s)[c::=t2])" by fact
+  have f: "b\<sharp>(a,c,t2)" by fact
+  from f have a:"b\<noteq>c" and b: "b\<noteq>a" and c: "b\<sharp>t2" by (simp add: fresh_prod fresh_atm)+
+  show "c\<sharp>Lam [b].s \<longrightarrow> (Lam [b].s)[a::=t2] = ([(c,a)]\<bullet>(Lam [b].s))[c::=t2]" (is "_ \<longrightarrow> ?LHS = ?RHS")
+  proof
+    assume "c\<sharp>Lam [b].s"
+    hence "c\<sharp>s" using a by (force simp add: abs_fresh)
+    hence d: "s[a::=t2] = ([(c,a)]\<bullet>s)[c::=t2]" using i by simp
+    have    "?LHS = Lam [b].(s[a::=t2])" using b c by simp
+    also have "\<dots> = Lam [b].(([(c,a)]\<bullet>s)[c::=t2])" using d by simp
+    also have "\<dots> = (Lam [b].([(c,a)]\<bullet>s))[c::=t2]" using a c by simp
+    also have "\<dots> = ?RHS" using a b by (force simp add: calc_atm)
+    finally show "?LHS = ?RHS" by simp
+  qed
+qed
+
+lemma subst_rename[rule_format]: 
+  fixes  c  :: "name"
+  and    a  :: "name"
+  and    t1 :: "lam"
+  and    t2 :: "lam"
+  shows "c\<sharp>t1 \<longrightarrow> (t1[a::=t2] = ([(c,a)]\<bullet>t1)[c::=t2])"
+apply(nominal_induct t1 rule: lam_induct)
+apply(auto simp add: calc_atm fresh_atm fresh_prod abs_fresh)
+done
+
+section {* Beta Reduction *}
+
+consts
+  Beta :: "(lam\<times>lam) set"
+syntax 
+  "_Beta"       :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<longrightarrow>\<^isub>\<beta> _" [80,80] 80)
+  "_Beta_star"  :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<longrightarrow>\<^isub>\<beta>\<^sup>* _" [80,80] 80)
+translations 
+  "t1 \<longrightarrow>\<^isub>\<beta> t2" \<rightleftharpoons> "(t1,t2) \<in> Beta"
+  "t1 \<longrightarrow>\<^isub>\<beta>\<^sup>* t2" \<rightleftharpoons> "(t1,t2) \<in> Beta\<^sup>*"
+inductive Beta
+  intros
+  b1[intro!]: "s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (App s1 t)\<longrightarrow>\<^isub>\<beta>(App s2 t)"
+  b2[intro!]: "s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (App t s1)\<longrightarrow>\<^isub>\<beta>(App t s2)"
+  b3[intro!]: "s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (Lam [a].s1)\<longrightarrow>\<^isub>\<beta> (Lam [(a::name)].s2)"
+  b4[intro!]: "(App (Lam [(a::name)].s1) s2)\<longrightarrow>\<^isub>\<beta>(s1[a::=s2])"
+
+lemma eqvt_beta: 
+  fixes pi :: "name prm"
+  and   t  :: "lam"
+  and   s  :: "lam"
+  shows "t\<longrightarrow>\<^isub>\<beta>s \<Longrightarrow> (pi\<bullet>t)\<longrightarrow>\<^isub>\<beta>(pi\<bullet>s)"
+  apply(erule Beta.induct)
+  apply(auto)
+  done
+
+lemma beta_induct_aux[rule_format]:
+  fixes  P :: "lam \<Rightarrow> lam \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    t :: "lam"
+  and    s :: "lam"
+  assumes a: "t\<longrightarrow>\<^isub>\<beta>s"
+  and a1:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App s1 t) (App s2 t) x"
+  and a2:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App t s1) (App t s2) x"
+  and a3:    "\<And>x (a::name) s1 s2. 
+              a\<sharp>x \<Longrightarrow> s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (Lam [a].s1) (Lam [a].s2) x"
+  and a4:    "\<And>x (a::name) t1 s1. a\<sharp>(s1,x) \<Longrightarrow> P (App (Lam [a].t1) s1) (t1[a::=s1]) x"
+  shows "\<forall>x (pi::name prm). P (pi\<bullet>t) (pi\<bullet>s) x"
+using a
+proof (induct)
+  case b1 thus ?case using a1 by (simp, blast intro: eqvt_beta)
+next
+  case b2 thus ?case using a2 by (simp, blast intro: eqvt_beta)
+next
+  case (b3 a s1 s2)
+  assume j1: "s1 \<longrightarrow>\<^isub>\<beta> s2"
+  assume j2: "\<forall>x (pi::name prm). P (pi\<bullet>s1) (pi\<bullet>s2) x"
+  show ?case 
+  proof (simp, intro strip)
+    fix pi::"name prm" and x::"'a::fs_name"
+     have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>s1,pi\<bullet>s2,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>x" and f3: "c\<sharp>(pi\<bullet>s1)" and f4: "c\<sharp>(pi\<bullet>s2)"
+      by (force simp add: fresh_prod fresh_atm)
+    have x: "P (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>s1)) (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>s2)) x"
+      using a3 f2 j1 j2 by (simp, blast intro: eqvt_beta)
+    have alpha1: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>s1))) = (Lam [(pi\<bullet>a)].(pi\<bullet>s1))" using f1 f3
+      by (simp add: lam.inject alpha)
+    have alpha2: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>s2))) = (Lam [(pi\<bullet>a)].(pi\<bullet>s2))" using f1 f3
+      by (simp add: lam.inject alpha)
+    show " P (Lam [(pi\<bullet>a)].(pi\<bullet>s1)) (Lam [(pi\<bullet>a)].(pi\<bullet>s2)) x"
+      using x alpha1 alpha2 by (simp only: pt_name2)
+  qed
+next
+  case (b4 a s1 s2)
+  show ?case
+  proof (simp add: subst_eqvt, intro strip)
+    fix pi::"name prm" and x::"'a::fs_name" 
+    have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>s1,pi\<bullet>s2,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>(pi\<bullet>s2,x)" and f3: "c\<sharp>(pi\<bullet>s1)" and f4: "c\<sharp>(pi\<bullet>s2)"
+      by (force simp add: fresh_prod fresh_atm)
+    have x: "P (App (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>s1)) (pi\<bullet>s2)) ((([(c,pi\<bullet>a)]@pi)\<bullet>s1)[c::=(pi\<bullet>s2)]) x"
+      using a4 f2 by (blast intro!: eqvt_beta)
+    have alpha1: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>s1))) = (Lam [(pi\<bullet>a)].(pi\<bullet>s1))" using f1 f3
+      by (simp add: lam.inject alpha)
+    have alpha2: "(([(c,pi\<bullet>a)]@pi)\<bullet>s1)[c::=(pi\<bullet>s2)] = (pi\<bullet>s1)[(pi\<bullet>a)::=(pi\<bullet>s2)]"
+      using f3 by (simp only: subst_rename[symmetric] pt_name2)
+    show "P (App (Lam [(pi\<bullet>a)].(pi\<bullet>s1)) (pi\<bullet>s2)) ((pi\<bullet>s1)[(pi\<bullet>a)::=(pi\<bullet>s2)]) x"
+      using x alpha1 alpha2 by (simp only: pt_name2)
+  qed
+qed
+
+
+lemma beta_induct[case_names b1 b2 b3 b4]:
+  fixes  P :: "lam \<Rightarrow> lam \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    t :: "lam"
+  and    s :: "lam"
+  and    x :: "'a::fs_name"
+  assumes a: "t\<longrightarrow>\<^isub>\<beta>s"
+  and a1:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App s1 t) (App s2 t) x"
+  and a2:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App t s1) (App t s2) x"
+  and a3:    "\<And>x (a::name) s1 s2. 
+              a\<sharp>x \<Longrightarrow> s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (Lam [a].s1) (Lam [a].s2) x"
+  and a4:    "\<And>x (a::name) t1 s1. 
+              a\<sharp>(s1,x) \<Longrightarrow> P (App (Lam [a].t1) s1) (t1[a::=s1]) x"
+  shows "P t s x"
+using a a1 a2 a3 a4
+by (auto intro!: beta_induct_aux[of "t" "s" "P" "[]" "x", simplified])
+
+section {* One-Reduction *}
+
+consts
+  One :: "(lam\<times>lam) set"
+syntax 
+  "_One"       :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<longrightarrow>\<^isub>1 _" [80,80] 80)
+  "_One_star"  :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<longrightarrow>\<^isub>1\<^sup>* _" [80,80] 80)
+translations 
+  "t1 \<longrightarrow>\<^isub>1 t2" \<rightleftharpoons> "(t1,t2) \<in> One"
+  "t1 \<longrightarrow>\<^isub>1\<^sup>* t2" \<rightleftharpoons> "(t1,t2) \<in> One\<^sup>*"
+inductive One
+  intros
+  o1[intro!]:      "M\<longrightarrow>\<^isub>1M"
+  o2[simp,intro!]: "\<lbrakk>t1\<longrightarrow>\<^isub>1t2;s1\<longrightarrow>\<^isub>1s2\<rbrakk> \<Longrightarrow> (App t1 s1)\<longrightarrow>\<^isub>1(App t2 s2)"
+  o3[simp,intro!]: "s1\<longrightarrow>\<^isub>1s2 \<Longrightarrow> (Lam [(a::name)].s1)\<longrightarrow>\<^isub>1(Lam [a].s2)"
+  o4[simp,intro!]: "\<lbrakk>s1\<longrightarrow>\<^isub>1s2;t1\<longrightarrow>\<^isub>1t2\<rbrakk> \<Longrightarrow> (App (Lam [(a::name)].t1) s1)\<longrightarrow>\<^isub>1(t2[a::=s2])"
+
+lemma eqvt_one: 
+  fixes pi :: "name prm"
+  and   t  :: "lam"
+  and   s  :: "lam"
+  shows "t\<longrightarrow>\<^isub>1s \<Longrightarrow> (pi\<bullet>t)\<longrightarrow>\<^isub>1(pi\<bullet>s)"
+  apply(erule One.induct)
+  apply(auto)
+  done
+
+lemma one_induct_aux[rule_format]:
+  fixes  P :: "lam \<Rightarrow> lam \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    t :: "lam"
+  and    s :: "lam"
+  assumes a: "t\<longrightarrow>\<^isub>1s"
+  and a1:    "\<forall>x t. P t t x"
+  and a2:    "\<forall>x t1 t2 s1 s2. 
+              (t1\<longrightarrow>\<^isub>1t2 \<and> (\<forall>z. P t1 t2 z) \<and> s1\<longrightarrow>\<^isub>1s2 \<and> (\<forall>z. P s1 s2 z)) 
+              \<longrightarrow> P (App t1 s1) (App t2 s2) x"
+  and a3:    "\<forall>x (a::name) s1 s2. (a\<sharp>x \<and> s1\<longrightarrow>\<^isub>1s2 \<and> (\<forall>z. P s1 s2 z)) 
+             \<longrightarrow>  P (Lam [a].s1) (Lam [a].s2) x"
+  and a4:    "\<forall>x (a::name) t1 t2 s1 s2. 
+              (a\<sharp>(s1,s2,x) \<and> t1\<longrightarrow>\<^isub>1t2 \<and> (\<forall>z. P t1 t2 z) \<and> s1\<longrightarrow>\<^isub>1s2 \<and> (\<forall>z. P s1 s2 z)) 
+              \<longrightarrow> P (App (Lam [a].t1) s1) (t2[a::=s2]) x"
+  shows "\<forall>x (pi::name prm). P (pi\<bullet>t) (pi\<bullet>s) x"
+using a
+proof (induct)
+  case o1 show ?case using a1 by force
+next
+  case (o2 s1 s2 t1 t2) 
+  thus ?case using a2 by (simp, blast intro: eqvt_one)
+next
+  case (o3 a t1 t2)
+  assume j1: "t1 \<longrightarrow>\<^isub>1 t2"
+  assume j2: "\<forall>x (pi::name prm). P (pi\<bullet>t1) (pi\<bullet>t2) x"
+  show ?case 
+  proof (simp, intro strip)
+    fix pi::"name prm" and x::"'a::fs_name"
+     have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>t1,pi\<bullet>t2,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>x" and f3: "c\<sharp>(pi\<bullet>t1)" and f4: "c\<sharp>(pi\<bullet>t2)"
+      by (force simp add: fresh_prod fresh_atm)
+    have x: "P (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>t1)) (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>t2)) x"
+      using a3 f2 j1 j2 by (simp, blast intro: eqvt_one)
+    have alpha1: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t1))) = (Lam [(pi\<bullet>a)].(pi\<bullet>t1))" using f1 f3
+      by (simp add: lam.inject alpha)
+    have alpha2: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t2))) = (Lam [(pi\<bullet>a)].(pi\<bullet>t2))" using f1 f3
+      by (simp add: lam.inject alpha)
+    show " P (Lam [(pi\<bullet>a)].(pi\<bullet>t1)) (Lam [(pi\<bullet>a)].(pi\<bullet>t2)) x"
+      using x alpha1 alpha2 by (simp only: pt_name2)
+  qed
+next
+case (o4 a s1 s2 t1 t2)
+  assume j0: "t1 \<longrightarrow>\<^isub>1 t2"
+  assume j1: "s1 \<longrightarrow>\<^isub>1 s2"
+  assume j2: "\<forall>x (pi::name prm). P (pi\<bullet>t1) (pi\<bullet>t2) x"
+  assume j3: "\<forall>x (pi::name prm). P (pi\<bullet>s1) (pi\<bullet>s2) x"
+  show ?case
+  proof (simp, intro strip)
+    fix pi::"name prm" and x::"'a::fs_name" 
+    have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>t1,pi\<bullet>t2,pi\<bullet>s1,pi\<bullet>s2,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>(pi\<bullet>s1,pi\<bullet>s2,x)" and f3: "c\<sharp>(pi\<bullet>t1)" and f4: "c\<sharp>(pi\<bullet>t2)"
+      by (force simp add: fresh_prod at_fresh[OF at_name_inst])
+    have x: "P (App (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>t1)) (pi\<bullet>s1)) ((([(c,pi\<bullet>a)]@pi)\<bullet>t2)[c::=(pi\<bullet>s2)]) x"
+      using a4 f2 j0 j1 j2 j3 by (simp, blast intro!: eqvt_one)
+    have alpha1: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t1))) = (Lam [(pi\<bullet>a)].(pi\<bullet>t1))" using f1 f3
+      by (simp add: lam.inject alpha)
+    have alpha2: "(([(c,pi\<bullet>a)]@pi)\<bullet>t2)[c::=(pi\<bullet>s2)] = (pi\<bullet>t2)[(pi\<bullet>a)::=(pi\<bullet>s2)]"
+      using f4 by (simp only: subst_rename[symmetric] pt_name2)
+    show "P (App (Lam [(pi\<bullet>a)].(pi\<bullet>t1)) (pi\<bullet>s1)) ((pi\<bullet>t2)[(pi\<bullet>a)::=(pi\<bullet>s2)]) x"
+      using x alpha1 alpha2 by (simp only: pt_name2)
+  qed
+qed
+
+lemma one_induct[rule_format, case_names o1 o2 o3 o4]:
+  fixes  P :: "lam \<Rightarrow> lam \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    t :: "lam"
+  and    s :: "lam"
+  and    x :: "'a::fs_name"
+  assumes a: "t\<longrightarrow>\<^isub>1s"
+  and a1:    "\<And>x t. P t t x"
+  and a2:    "\<And>x t1 t2 s1 s2. 
+              t1\<longrightarrow>\<^isub>1t2 \<Longrightarrow> (\<And>z. P t1 t2 z) \<Longrightarrow> s1\<longrightarrow>\<^isub>1s2 \<Longrightarrow> (\<And>z. P s1 s2 z) \<Longrightarrow> 
+              P (App t1 s1) (App t2 s2) x"
+  and a3:    "\<And>x (a::name) s1 s2. a\<sharp>x \<Longrightarrow> s1\<longrightarrow>\<^isub>1s2 \<Longrightarrow> (\<And>z. P s1 s2 z) 
+              \<Longrightarrow> P (Lam [a].s1) (Lam [a].s2) x"
+  and a4:    "\<And>x (a::name) t1 t2 s1 s2. 
+              a\<sharp>(s1,s2,x) \<Longrightarrow> t1\<longrightarrow>\<^isub>1t2 \<Longrightarrow> (\<And>z. P t1 t2 z) \<Longrightarrow> s1\<longrightarrow>\<^isub>1s2 \<Longrightarrow> (\<And>z. P s1 s2 z) 
+              \<Longrightarrow> P (App (Lam [a].t1) s1) (t2[a::=s2]) x"
+  shows "P t s x"
+using a a1 a2 a3 a4
+by (auto intro!: one_induct_aux[of "t" "s" "P" "[]" "x", simplified])
+
+lemma fresh_fact'[rule_format]:  
+  shows "a\<sharp>t2 \<longrightarrow> a\<sharp>(t1[a::=t2])" 
+proof (nominal_induct t1 rule: lam_induct)
+  case (Var a t2 b) 
+  show ?case by (cases "b=a") (force simp add: at_fresh[OF at_name_inst])+ 
+next
+  case App
+  thus ?case by (simp add: fresh_prod)
+next
+  case (Lam a t2 c t) 
+  from Lam(1) have "c\<noteq>a \<and> c\<sharp>t2" by (simp add: fresh_prod fresh_atm) 
+  thus ?case using Lam(2) by (force simp add: abs_fresh)
+qed
+
+lemma one_fresh_preserv[rule_format]:
+  fixes    t :: "lam"
+  and      s :: "lam"
+  and      a :: "name"
+  assumes a: "t\<longrightarrow>\<^isub>1s"
+  shows "a\<sharp>t \<longrightarrow> a\<sharp>s"
+using a
+proof (induct)
+  case o1 show ?case by simp
+next
+  case o2 thus ?case by (simp add: fresh_prod)
+next
+  case (o3 c s1 s2)
+  assume i: "a\<sharp>s1 \<longrightarrow>  a\<sharp>s2"
+  show ?case
+  proof (intro strip, cases "a=c")
+    assume "a=c" 
+    thus "a\<sharp>Lam [c].s2" by (simp add: abs_fresh)
+  next
+    assume b: "a\<noteq>c" and "a\<sharp>Lam [c].s1"
+    hence "a\<sharp>s1" by (simp add: abs_fresh)
+    hence "a\<sharp>s2" using i by simp
+    thus "a\<sharp>Lam [c].s2" using b by (simp add: abs_fresh) 
+  qed
+next 
+  case (o4 c t1 t2 s1 s2)
+  assume i1: "a\<sharp>t1 \<longrightarrow> a\<sharp>t2"
+     and i2: "a\<sharp>s1 \<longrightarrow> a\<sharp>s2"
+  show "a\<sharp>App (Lam [c].s1) t1 \<longrightarrow> a\<sharp>s2[c::=t2]"
+  proof
+    assume "a\<sharp>App (Lam [c].s1) t1"
+    hence c1: "a\<sharp>Lam [c].s1" and c2: "a\<sharp>t1" by (simp add: fresh_prod)+
+    from c2 i1 have c3: "a\<sharp>t2" by simp
+    show "a\<sharp>s2[c::=t2]"
+    proof (cases "a=c")
+      assume "a=c"
+      thus "a\<sharp>s2[c::=t2]" using c3 by (simp add: fresh_fact')
+    next
+      assume d1: "a\<noteq>c"
+      from c1 d1 have "a\<sharp>s1" by (simp add: abs_fresh)
+      hence "a\<sharp>s2" using i2 by simp
+      thus "a\<sharp>s2[c::=t2]" using c3 by (simp add: fresh_fact)
+    qed
+  qed
+qed
+
+lemma one_abs: 
+  fixes    t :: "lam"
+  and      t':: "lam"
+  and      a :: "name"
+  shows "(Lam [a].t)\<longrightarrow>\<^isub>1t'\<Longrightarrow>\<exists>t''. t'=Lam [a].t'' \<and> t\<longrightarrow>\<^isub>1t''"
+  apply(ind_cases "(Lam [a].t)\<longrightarrow>\<^isub>1t'")
+  apply(auto simp add: lam.distinct lam.inject alpha)
+  apply(rule_tac x="[(a,aa)]\<bullet>s2" in exI)
+  apply(rule conjI)
+  apply(rule pt_bij2[OF pt_name_inst, OF at_name_inst, symmetric])
+  apply(simp)
+  apply(rule pt_name3)
+  apply(rule at_ds5[OF at_name_inst])
+  apply(frule_tac a="a" in one_fresh_preserv)
+  apply(assumption)
+  apply(rule conjI)
+  apply(simp add: pt_fresh_left[OF pt_name_inst, OF at_name_inst])
+  apply(simp add: calc_atm)
+  apply(force intro!: eqvt_one)
+  done
+
+lemma one_app: 
+  "App t1 t2 \<longrightarrow>\<^isub>1 t' \<Longrightarrow> 
+  (\<exists>s1 s2. t' = App s1 s2 \<and> t1 \<longrightarrow>\<^isub>1 s1 \<and> t2 \<longrightarrow>\<^isub>1 s2) \<or> 
+  (\<exists>a s s1 s2. t1 = Lam [a].s \<and> t' = s1[a::=s2] \<and> s \<longrightarrow>\<^isub>1 s1 \<and> t2 \<longrightarrow>\<^isub>1 s2)" 
+  apply(ind_cases "App t1 s1 \<longrightarrow>\<^isub>1 t'")
+  apply(auto simp add: lam.distinct lam.inject)
+  done
+
+lemma one_red: 
+  "App (Lam [a].t1) t2 \<longrightarrow>\<^isub>1 M \<Longrightarrow>
+  (\<exists>s1 s2. M = App (Lam [a].s1) s2 \<and> t1 \<longrightarrow>\<^isub>1 s1 \<and> t2 \<longrightarrow>\<^isub>1 s2) \<or> 
+  (\<exists>s1 s2. M = s1[a::=s2] \<and> t1 \<longrightarrow>\<^isub>1 s1 \<and> t2 \<longrightarrow>\<^isub>1 s2)" 
+  apply(ind_cases "App (Lam [a].t1) s1 \<longrightarrow>\<^isub>1 M")
+  apply(simp_all add: lam.inject)
+  apply(force)
+  apply(erule conjE)
+  apply(drule sym[of "Lam [a].t1"])
+  apply(simp)
+  apply(drule one_abs)
+  apply(erule exE)
+  apply(simp)
+  apply(force simp add: alpha)
+  apply(erule conjE)
+  apply(simp add: lam.inject alpha)
+  apply(erule disjE)
+  apply(simp)
+  apply(force)
+  apply(simp)
+  apply(rule disjI2)
+  apply(rule_tac x="[(a,aa)]\<bullet>t2a" in exI)
+  apply(rule_tac x="s2" in exI)
+  apply(auto)
+  apply(subgoal_tac "a\<sharp>t2a")(*A*)
+  apply(simp add: subst_rename)
+  (*A*)
+  apply(force intro: one_fresh_preserv)
+  apply(force intro: eqvt_one)
+  done
+
+(* first case in Lemma 3.2.4*)
+
+lemma one_subst_aux[rule_format]:
+  fixes    M :: "lam"
+  and      N :: "lam"
+  and      N':: "lam"
+  and      x :: "name"
+  shows "N\<longrightarrow>\<^isub>1N'\<longrightarrow>M[x::=N] \<longrightarrow>\<^isub>1 M[x::=N']"
+proof (nominal_induct M rule: lam_induct)
+  case (Var N N' x y) 
+  show "N\<longrightarrow>\<^isub>1N' \<longrightarrow> Var y[x::=N] \<longrightarrow>\<^isub>1 Var y[x::=N']" by (cases "x=y", auto)
+next
+  case (App N N' x P Q) (* application case - third line *)
+  thus "N\<longrightarrow>\<^isub>1N' \<longrightarrow> (App P Q)[x::=N] \<longrightarrow>\<^isub>1  (App P Q)[x::=N']" using o2 by simp
+next 
+  case (Lam N N' x y P) (* abstraction case - fourth line *)
+  thus "N\<longrightarrow>\<^isub>1N' \<longrightarrow> (Lam [y].P)[x::=N] \<longrightarrow>\<^isub>1 (Lam [y].P)[x::=N']" using o3 
+    by (simp add: fresh_prod fresh_atm)
+qed
+
+lemma one_subst_aux[rule_format]:
+  fixes    M :: "lam"
+  and      N :: "lam"
+  and      N':: "lam"
+  and      x :: "name"
+  shows "N\<longrightarrow>\<^isub>1N'\<longrightarrow>M[x::=N] \<longrightarrow>\<^isub>1 M[x::=N']"
+apply(nominal_induct M rule: lam_induct)
+apply(auto simp add: fresh_prod fresh_atm)
+done
+
+lemma one_subst[rule_format]: 
+  fixes    M :: "lam"
+  and      M':: "lam"
+  and      N :: "lam"
+  and      N':: "lam"
+  and      x :: "name"
+  assumes a: "M\<longrightarrow>\<^isub>1M'" 
+  shows "N\<longrightarrow>\<^isub>1N' \<longrightarrow> M[x::=N]\<longrightarrow>\<^isub>1M'[x::=N']" 
+using a
+proof (nominal_induct M M' rule: one_induct)
+  case (o1 x N N' M)
+  show ?case by (simp add: one_subst_aux)
+next
+  case (o2 x N N' M1 M2 N1 N2)
+  thus ?case by simp
+next
+  case (o3 x N N' a M1 M2)
+  thus ?case by (simp add: fresh_prod fresh_atm)
+next
+  case (o4 N N' x a M1 M2 N1 N2)
+  assume e3: "a\<sharp>(N1,N2,N,N',x)"
+  show ?case
+  proof  
+    assume a1: "N\<longrightarrow>\<^isub>1N'"
+    have "(App (Lam [a].M1) N1)[x::=N] = App (Lam [a].(M1[x::=N])) (N1[x::=N])" 
+      using e3 by (simp add: fresh_prod fresh_atm)
+    also have "App (Lam [a].(M1[x::=N])) (N1[x::=N]) \<longrightarrow>\<^isub>1 M2[x::=N'][a::=N2[x::=N']]" 
+      using  o4 a1 by force
+    also have "M2[x::=N'][a::=N2[x::=N']] = M2[a::=N2][x::=N']" 
+      using e3 by (simp add: subs_lemma fresh_prod fresh_atm)
+    ultimately show "(App (Lam [a].M1) N1)[x::=N] \<longrightarrow>\<^isub>1 M2[a::=N2][x::=N']" by simp
+  qed
+qed
+
+lemma one_subst[rule_format]: 
+  assumes a: "M\<longrightarrow>\<^isub>1M'" 
+  shows "N\<longrightarrow>\<^isub>1N' \<longrightarrow> M[x::=N]\<longrightarrow>\<^isub>1M'[x::=N']" 
+using a
+apply(nominal_induct M M' rule: one_induct)
+apply(auto simp add: one_subst_aux subs_lemma fresh_prod fresh_atm)
+done
+
+lemma diamond[rule_format]:
+  fixes    M :: "lam"
+  and      M1:: "lam"
+  assumes a: "M\<longrightarrow>\<^isub>1M1" 
+  shows "\<forall>M2. (M\<longrightarrow>\<^isub>1M2) \<longrightarrow> (\<exists>M3. M1\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  using a
+proof (induct)
+  case (o1 M) (* case 1 --- M1 = M *)
+  show "\<forall>M2. M\<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. M\<longrightarrow>\<^isub>1M3 \<and>  M2\<longrightarrow>\<^isub>1M3)" by force
+next
+  case (o4 x Q Q' P P') (* case 2 --- a beta-reduction occurs*)
+  assume i1: "\<forall>M2. Q \<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. Q'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  assume i2: "\<forall>M2. P \<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. P'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  show "\<forall>M2. App (Lam [x].P) Q\<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. P'[x::=Q']\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  proof (intro strip)
+    fix M2
+    assume "App (Lam [x].P) Q \<longrightarrow>\<^isub>1 M2"
+    hence "(\<exists>P' Q'. M2 = App (Lam [x].P') Q' \<and> P\<longrightarrow>\<^isub>1P' \<and> Q\<longrightarrow>\<^isub>1Q') \<or> 
+           (\<exists>P' Q'. M2 = P'[x::=Q'] \<and> P\<longrightarrow>\<^isub>1P' \<and> Q\<longrightarrow>\<^isub>1Q')" by (simp add: one_red)
+    moreover (* subcase 2.1 *)
+    { assume "\<exists>P' Q'. M2 = App (Lam [x].P') Q' \<and> P\<longrightarrow>\<^isub>1P' \<and> Q\<longrightarrow>\<^isub>1Q'"
+      then obtain P'' and Q'' where 
+	b1: "M2=App (Lam [x].P'') Q''" and b2: "P\<longrightarrow>\<^isub>1P''" and b3: "Q\<longrightarrow>\<^isub>1Q''" by force
+      from b2 i2 have "(\<exists>M3. P'\<longrightarrow>\<^isub>1M3 \<and> P''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain P''' where
+	c1: "P'\<longrightarrow>\<^isub>1P'''" and c2: "P''\<longrightarrow>\<^isub>1P'''" by force
+      from b3 i1 have "(\<exists>M3. Q'\<longrightarrow>\<^isub>1M3 \<and> Q''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain Q''' where
+	d1: "Q'\<longrightarrow>\<^isub>1Q'''" and d2: "Q''\<longrightarrow>\<^isub>1Q'''" by force
+      from c1 c2 d1 d2 
+      have "P'[x::=Q']\<longrightarrow>\<^isub>1P'''[x::=Q'''] \<and> App (Lam [x].P'') Q'' \<longrightarrow>\<^isub>1 P'''[x::=Q''']" 
+	by (force simp add: one_subst)
+      hence "\<exists>M3. P'[x::=Q']\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" using b1 by force
+    }
+    moreover (* subcase 2.2 *)
+    { assume "\<exists>P' Q'. M2 = P'[x::=Q'] \<and> P\<longrightarrow>\<^isub>1P' \<and> Q\<longrightarrow>\<^isub>1Q'"
+      then obtain P'' Q'' where
+	b1: "M2=P''[x::=Q'']" and b2: "P\<longrightarrow>\<^isub>1P''" and  b3: "Q\<longrightarrow>\<^isub>1Q''" by force
+      from b2 i2 have "(\<exists>M3. P'\<longrightarrow>\<^isub>1M3 \<and> P''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain P''' where
+	c1: "P'\<longrightarrow>\<^isub>1P'''" and c2: "P''\<longrightarrow>\<^isub>1P'''" by force
+      from b3 i1 have "(\<exists>M3. Q'\<longrightarrow>\<^isub>1M3 \<and> Q''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain Q''' where
+	d1: "Q'\<longrightarrow>\<^isub>1Q'''" and d2: "Q''\<longrightarrow>\<^isub>1Q'''" by force
+      from c1 c2 d1 d2 
+      have "P'[x::=Q']\<longrightarrow>\<^isub>1P'''[x::=Q'''] \<and> P''[x::=Q'']\<longrightarrow>\<^isub>1P'''[x::=Q''']" 
+	by (force simp add: one_subst)
+      hence "\<exists>M3. P'[x::=Q']\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" using b1 by force
+    }
+    ultimately show "\<exists>M3. P'[x::=Q']\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" by blast
+  qed
+next
+  case (o2 Q Q' P P') (* case 3 *)
+  assume i0: "P\<longrightarrow>\<^isub>1P'"
+  assume i1: "\<forall>M2. Q \<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. Q'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  assume i2: "\<forall>M2. P \<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. P'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  show "\<forall>M2. App P Q\<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. App P' Q'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  proof (intro strip)
+    fix M2
+    assume "App P Q \<longrightarrow>\<^isub>1 M2"
+    hence "(\<exists>P'' Q''. M2 = App P'' Q'' \<and> P\<longrightarrow>\<^isub>1P'' \<and> Q\<longrightarrow>\<^isub>1Q'') \<or> 
+           (\<exists>x P' P'' Q'. P = Lam [x].P' \<and> M2 = P''[x::=Q'] \<and> P'\<longrightarrow>\<^isub>1 P'' \<and> Q\<longrightarrow>\<^isub>1Q')" 
+      by (simp add: one_app[simplified])
+    moreover (* subcase 3.1 *)
+    { assume "\<exists>P'' Q''. M2 = App P'' Q'' \<and> P\<longrightarrow>\<^isub>1P'' \<and> Q\<longrightarrow>\<^isub>1Q''"
+      then obtain P'' and Q'' where 
+	b1: "M2=App P'' Q''" and b2: "P\<longrightarrow>\<^isub>1P''" and b3: "Q\<longrightarrow>\<^isub>1Q''" by force
+      from b2 i2 have "(\<exists>M3. P'\<longrightarrow>\<^isub>1M3 \<and> P''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain P''' where
+	c1: "P'\<longrightarrow>\<^isub>1P'''" and c2: "P''\<longrightarrow>\<^isub>1P'''" by force
+      from b3 i1 have "(\<exists>M3. Q'\<longrightarrow>\<^isub>1M3 \<and> Q''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain Q''' where
+	d1: "Q'\<longrightarrow>\<^isub>1Q'''" and d2: "Q''\<longrightarrow>\<^isub>1Q'''" by force
+      from c1 c2 d1 d2 
+      have "App P' Q'\<longrightarrow>\<^isub>1App P''' Q''' \<and> App P'' Q'' \<longrightarrow>\<^isub>1 App P''' Q'''" by force
+      hence "\<exists>M3. App P' Q'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" using b1 by force
+    }
+    moreover (* subcase 3.2 *)
+    { assume "\<exists>x P1 P'' Q''. P = Lam [x].P1 \<and> M2 = P''[x::=Q''] \<and> P1\<longrightarrow>\<^isub>1 P'' \<and> Q\<longrightarrow>\<^isub>1Q''"
+      then obtain x P1 P1'' Q'' where
+	b0: "P=Lam [x].P1" and b1: "M2=P1''[x::=Q'']" and 
+        b2: "P1\<longrightarrow>\<^isub>1P1''" and  b3: "Q\<longrightarrow>\<^isub>1Q''" by force
+      from b0 i0 have "\<exists>P1'. P'=Lam [x].P1' \<and> P1\<longrightarrow>\<^isub>1P1'" by (simp add: one_abs)
+      then obtain P1' where g1: "P'=Lam [x].P1'" and g2: "P1\<longrightarrow>\<^isub>1P1'" by force 
+      from g1 b0 b2 i2 have "(\<exists>M3. (Lam [x].P1')\<longrightarrow>\<^isub>1M3 \<and> (Lam [x].P1'')\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain P1''' where
+	c1: "(Lam [x].P1')\<longrightarrow>\<^isub>1P1'''" and c2: "(Lam [x].P1'')\<longrightarrow>\<^isub>1P1'''" by force
+      from c1 have "\<exists>R1. P1'''=Lam [x].R1 \<and> P1'\<longrightarrow>\<^isub>1R1" by (simp add: one_abs)
+      then obtain R1 where r1: "P1'''=Lam [x].R1" and r2: "P1'\<longrightarrow>\<^isub>1R1" by force
+      from c2 have "\<exists>R2. P1'''=Lam [x].R2 \<and> P1''\<longrightarrow>\<^isub>1R2" by (simp add: one_abs)
+      then obtain R2 where r3: "P1'''=Lam [x].R2" and r4: "P1''\<longrightarrow>\<^isub>1R2" by force
+      from r1 r3 have r5: "R1=R2" 
+	by (simp add: lam.inject alpha)
+      from b3 i1 have "(\<exists>M3. Q'\<longrightarrow>\<^isub>1M3 \<and> Q''\<longrightarrow>\<^isub>1M3)" by simp
+      then obtain Q''' where
+	d1: "Q'\<longrightarrow>\<^isub>1Q'''" and d2: "Q''\<longrightarrow>\<^isub>1Q'''" by force
+      from g1 r2 d1 r4 r5 d2 
+      have "App P' Q'\<longrightarrow>\<^isub>1R1[x::=Q'''] \<and> P1''[x::=Q'']\<longrightarrow>\<^isub>1R1[x::=Q''']" by (simp add: one_subst)
+      hence "\<exists>M3. App P' Q'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" using b1 by force
+    }
+    ultimately show "\<exists>M3. App P' Q'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" by blast
+  qed
+next
+  case (o3 x P P') (* case 4 *)
+  assume i1: "P\<longrightarrow>\<^isub>1P'"
+  assume i2: "\<forall>M2. P \<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. P'\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  show "\<forall>M2. (Lam [x].P)\<longrightarrow>\<^isub>1M2 \<longrightarrow> (\<exists>M3. (Lam [x].P')\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3)"
+  proof (intro strip)
+    fix M2
+    assume "(Lam [x].P)\<longrightarrow>\<^isub>1 M2"
+    hence "\<exists>P''. M2=Lam [x].P'' \<and> P\<longrightarrow>\<^isub>1P''" by (simp add: one_abs)
+    then obtain P'' where b1: "M2=Lam [x].P''" and b2: "P\<longrightarrow>\<^isub>1P''" by force
+    from i2 b1 b2 have "\<exists>M3. (Lam [x].P')\<longrightarrow>\<^isub>1M3 \<and> (Lam [x].P'')\<longrightarrow>\<^isub>1M3" by force
+    then obtain M3 where c1: "(Lam [x].P')\<longrightarrow>\<^isub>1M3" and c2: "(Lam [x].P'')\<longrightarrow>\<^isub>1M3" by force
+    from c1 have "\<exists>R1. M3=Lam [x].R1 \<and> P'\<longrightarrow>\<^isub>1R1" by (simp add: one_abs)
+    then obtain R1 where r1: "M3=Lam [x].R1" and r2: "P'\<longrightarrow>\<^isub>1R1" by force
+    from c2 have "\<exists>R2. M3=Lam [x].R2 \<and> P''\<longrightarrow>\<^isub>1R2" by (simp add: one_abs)
+    then obtain R2 where r3: "M3=Lam [x].R2" and r4: "P''\<longrightarrow>\<^isub>1R2" by force
+    from r1 r3 have r5: "R1=R2" 
+      by (simp add: lam.inject alpha)
+    from r2 r4 have "(Lam [x].P')\<longrightarrow>\<^isub>1(Lam [x].R1) \<and> (Lam [x].P'')\<longrightarrow>\<^isub>1(Lam [x].R2)" 
+      by (simp add: one_subst)
+    thus "\<exists>M3. (Lam [x].P')\<longrightarrow>\<^isub>1M3 \<and> M2\<longrightarrow>\<^isub>1M3" using b1 r5 by force
+  qed
+qed
+
+lemma one_abs_cong: 
+  fixes a :: "name"
+  assumes a: "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2" 
+  shows "(Lam [a].t1)\<longrightarrow>\<^isub>\<beta>\<^sup>*(Lam [a].t2)"
+  using a
+proof induct
+  case 1 thus ?case by force
+next
+  case (2 y z) 
+  thus ?case by (force dest: b3 intro: rtrancl_trans)
+qed
+
+lemma one_pr_congL: 
+  assumes a: "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2" 
+  shows "App t1 s\<longrightarrow>\<^isub>\<beta>\<^sup>* App t2 s"
+  using a
+proof induct
+  case 1 thus ?case by (force)
+next
+  case 2 thus ?case by (force dest: b1 intro: rtrancl_trans)
+qed
+  
+lemma one_pr_congR: 
+  assumes a: "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2" 
+  shows "App s t1 \<longrightarrow>\<^isub>\<beta>\<^sup>* App s t2"
+using a
+proof induct
+  case 1 thus ?case by (force)
+next 
+  case 2 thus ?case by (force dest: b2 intro: rtrancl_trans)
+qed
+
+lemma one_pr_cong: 
+  assumes a1: "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2" 
+  and a2: "s1\<longrightarrow>\<^isub>\<beta>\<^sup>*s2" 
+  shows "App t1 s1\<longrightarrow>\<^isub>\<beta>\<^sup>* App t2 s2"
+proof -
+  have b1: "App t1 s1 \<longrightarrow>\<^isub>\<beta>\<^sup>* App t2 s1" using a1 by (rule one_pr_congL)
+  have b2: "App t2 s1 \<longrightarrow>\<^isub>\<beta>\<^sup>* App t2 s2" using a2 by (rule one_pr_congR)
+  show ?thesis using b1 and b2 by (force intro: rtrancl_trans)
+qed
+
+lemma one_beta_star: 
+  assumes a: "(t1\<longrightarrow>\<^isub>1t2)" 
+  shows "(t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2)"
+  using a
+proof induct
+  case o1 thus ?case by (force)
+next
+  case o2 thus ?case by (force intro!: one_pr_cong)
+next
+  case o3 thus ?case by (force intro!: one_abs_cong)
+next 
+  case (o4 a s1 s2 t1 t2)
+  have a1: "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2" and a2: "s1\<longrightarrow>\<^isub>\<beta>\<^sup>*s2" .
+  have c1: "(App (Lam [a].t2) s2) \<longrightarrow>\<^isub>\<beta> (t2 [a::= s2])" by (rule b4)
+  from a1 a2 have c2: "App (Lam [a].t1 ) s1 \<longrightarrow>\<^isub>\<beta>\<^sup>* App (Lam [a].t2 ) s2" 
+    by (force intro!: one_pr_cong one_abs_cong)
+  show ?case using c1 c2 by (force intro: rtrancl_trans)
+qed
+ 
+lemma one_star_abs_cong: 
+  fixes a :: "name"
+  assumes a: "t1\<longrightarrow>\<^isub>1\<^sup>*t2" 
+  shows "(Lam  [a].t1)\<longrightarrow>\<^isub>1\<^sup>* (Lam [a].t2)"
+  using a
+proof induct
+  case 1 thus ?case by (force)
+next
+  case 2 thus ?case by (force intro: rtrancl_trans)
+qed
+
+lemma one_star_pr_congL: 
+  assumes a: "t1\<longrightarrow>\<^isub>1\<^sup>*t2" 
+  shows "App t1 s\<longrightarrow>\<^isub>1\<^sup>* App t2 s"
+  using a
+proof induct
+  case 1 thus ?case by (force)
+next
+  case 2 thus ?case by (force intro: rtrancl_trans)
+qed
+
+lemma one_star_pr_congR: 
+  assumes a: "t1\<longrightarrow>\<^isub>1\<^sup>*t2" 
+  shows "App s t1 \<longrightarrow>\<^isub>1\<^sup>* App s t2"
+  using a
+proof induct
+  case 1 thus ?case by (force)
+next
+  case 2 thus ?case by (force intro: rtrancl_trans)
+qed
+
+lemma beta_one_star: 
+  assumes a: "t1\<longrightarrow>\<^isub>\<beta>t2" 
+  shows "t1\<longrightarrow>\<^isub>1\<^sup>*t2"
+  using a
+proof induct
+  case b1 thus ?case by (force intro!: one_star_pr_congL)
+next
+  case b2 thus ?case by (force intro!: one_star_pr_congR)
+next
+  case b3 thus ?case by (force intro!: one_star_abs_cong)
+next
+  case b4 thus ?case by (force)
+qed
+
+lemma trans_closure: 
+  shows "(t1\<longrightarrow>\<^isub>1\<^sup>*t2) = (t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2)"
+proof
+  assume "t1 \<longrightarrow>\<^isub>1\<^sup>* t2"
+  thus "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t2"
+  proof induct
+    case 1 thus ?case by (force)
+  next
+    case 2 thus ?case by (force intro: rtrancl_trans simp add: one_beta_star)
+  qed
+next
+  assume "t1 \<longrightarrow>\<^isub>\<beta>\<^sup>* t2" 
+  thus "t1\<longrightarrow>\<^isub>1\<^sup>*t2"
+  proof induct
+    case 1 thus ?case by (force)
+  next
+    case 2 thus ?case by (force intro: rtrancl_trans simp add: beta_one_star)
+  qed
+qed
+
+lemma cr_one:
+  assumes a: "t\<longrightarrow>\<^isub>1\<^sup>*t1" 
+  and b: "t\<longrightarrow>\<^isub>1t2"
+  shows "\<exists>t3. t1\<longrightarrow>\<^isub>1t3 \<and> t2\<longrightarrow>\<^isub>1\<^sup>*t3"
+proof -
+  have stronger: "\<forall>t2. t\<longrightarrow>\<^isub>1t2\<longrightarrow>(\<exists>t3. t1\<longrightarrow>\<^isub>1t3\<and>t2\<longrightarrow>\<^isub>1\<^sup>*t3)"
+    using a 
+  proof induct
+    case 1 show ?case by (force)
+  next
+    case (2 s1 s2)
+    assume b: "s1 \<longrightarrow>\<^isub>1 s2"
+    assume h: "\<forall>t2. t \<longrightarrow>\<^isub>1 t2 \<longrightarrow> (\<exists>t3. s1 \<longrightarrow>\<^isub>1 t3 \<and> t2 \<longrightarrow>\<^isub>1\<^sup>* t3)"
+    show ?case
+    proof (rule allI, rule impI)
+      fix t2
+      assume  c: "t \<longrightarrow>\<^isub>1 t2"
+      show "(\<exists>t3.  s2 \<longrightarrow>\<^isub>1 t3 \<and>  t2 \<longrightarrow>\<^isub>1\<^sup>* t3)" 
+      proof -
+	from c h have "(\<exists>t3. s1 \<longrightarrow>\<^isub>1 t3 \<and> t2 \<longrightarrow>\<^isub>1\<^sup>* t3)" by force
+	then obtain t3 where c1: "s1 \<longrightarrow>\<^isub>1 t3"
+                         and c2: "t2 \<longrightarrow>\<^isub>1\<^sup>* t3" by (force)
+	have "(\<exists>t4. s2 \<longrightarrow>\<^isub>1 t4 \<and> t3 \<longrightarrow>\<^isub>1 t4)" using b c1 by (force intro: diamond)
+	thus ?thesis using c2 by (force intro: rtrancl_trans)
+      qed
+    qed
+  qed
+  from a b stronger show ?thesis by force
+qed
+
+
+lemma cr_one_star: 
+  assumes a: "t\<longrightarrow>\<^isub>1\<^sup>*t2"
+      and b: "t\<longrightarrow>\<^isub>1\<^sup>*t1"
+    shows "(\<exists>t3. t1\<longrightarrow>\<^isub>1\<^sup>*t3\<and>t2\<longrightarrow>\<^isub>1\<^sup>*t3)"
+using a
+proof induct
+  case 1
+  show ?case using b by force
+next 
+  case (2 s1 s2)
+  assume d: "s1 \<longrightarrow>\<^isub>1 s2"
+  assume "\<exists>t3.  t1 \<longrightarrow>\<^isub>1\<^sup>* t3 \<and>  s1 \<longrightarrow>\<^isub>1\<^sup>* t3"
+  then obtain t3 where f1: "t1 \<longrightarrow>\<^isub>1\<^sup>* t3"
+                   and f2: "s1 \<longrightarrow>\<^isub>1\<^sup>* t3" by force
+  from cr_one d f2 have "\<exists>t4. t3\<longrightarrow>\<^isub>1t4 \<and> s2\<longrightarrow>\<^isub>1\<^sup>*t4" by force
+  then obtain t4 where g1: "t3\<longrightarrow>\<^isub>1t4"
+                   and g2: "s2\<longrightarrow>\<^isub>1\<^sup>*t4" by force
+  have "t1\<longrightarrow>\<^isub>1\<^sup>*t4" using f1 g1 by (force intro: rtrancl_trans)
+  thus ?case using g2 by (force)
+qed
+  
+lemma cr_beta_star: 
+  assumes a1: "t\<longrightarrow>\<^isub>\<beta>\<^sup>*t1" 
+  and a2: "t\<longrightarrow>\<^isub>\<beta>\<^sup>*t2" 
+  shows "(\<exists>t3. t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t3\<and>t2\<longrightarrow>\<^isub>\<beta>\<^sup>*t3)"
+proof -
+  from a1 have b1: "t\<longrightarrow>\<^isub>1\<^sup>*t1" by (simp add: trans_closure[symmetric])
+  from a2 have b2: "t\<longrightarrow>\<^isub>1\<^sup>*t2" by (simp add: trans_closure[symmetric])
+  from b1 and b2 have c: "\<exists>t3. (t1\<longrightarrow>\<^isub>1\<^sup>*t3 \<and> t2\<longrightarrow>\<^isub>1\<^sup>*t3)" by (force intro!: cr_one_star) 
+  from c obtain t3 where d1: "t1\<longrightarrow>\<^isub>1\<^sup>*t3" and d2: "t2\<longrightarrow>\<^isub>1\<^sup>*t3" by force
+  from d1 have e1: "t1\<longrightarrow>\<^isub>\<beta>\<^sup>*t3" by (simp add: trans_closure)
+  from d2 have e2: "t2\<longrightarrow>\<^isub>\<beta>\<^sup>*t3" by (simp add: trans_closure)
+  show ?thesis using e1 and e2 by (force)
+qed
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Nominal/Examples/Lam_substs.thy	Mon Nov 07 15:19:03 2005 +0100
@@ -0,0 +1,1561 @@
+
+theory lam_substs
+imports "../nominal" 
+begin
+
+atom_decl name 
+
+nominal_datatype lam = Var "name"
+                     | App "lam" "lam"
+                     | Lam "\<guillemotleft>name\<guillemotright>lam" ("Lam [_]._" [100,100] 100)
+
+section {* strong induction principles for lam *}
+
+lemma lam_induct_aux:
+  fixes P :: "lam \<Rightarrow> 'a \<Rightarrow> bool"
+  and   f :: "'a \<Rightarrow> name set"
+  assumes fs: "\<And>x. finite (f x)"
+      and h1: "\<And>x a. P (Var  a) x"  
+      and h2: "\<And>x t1 t2. (\<forall>z. P t1 z) \<Longrightarrow> (\<forall>z. P t2 z) \<Longrightarrow> P (App t1 t2) x" 
+      and h3: "\<And>x a t. a\<notin>f x \<Longrightarrow> (\<forall>z. P t z) \<Longrightarrow> P (Lam [a].t) x"
+  shows "\<forall>(pi::name prm) x. P (pi\<bullet>t) x"
+proof (induct rule: lam.induct_weak)
+  case (Lam a t)
+  assume i1: "\<forall>(pi::name prm) x. P (pi\<bullet>t) x" 
+  show ?case
+  proof (intro strip, simp add: abs_perm)
+    fix x::"'a" and pi::"name prm"
+    have f: "\<exists>c::name. c\<sharp>(f x,pi\<bullet>a,pi\<bullet>t)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: supp_prod fs_name1 
+          at_fin_set_supp[OF at_name_inst, OF fs] fs)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>(f x)" and f3: "c\<sharp>(pi\<bullet>t)" 
+      by (force simp add: fresh_prod at_fresh[OF at_name_inst])
+    have g: "Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t)) = Lam [(pi\<bullet>a)].(pi\<bullet>t)" using f1 f3
+      by (simp add: lam.inject alpha)
+    from i1 have "\<forall>x. P (([(c,pi\<bullet>a)]@pi)\<bullet>t) x" by force
+    hence i1b: "\<forall>x. P ([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t)) x" by (simp add: pt_name2[symmetric])
+    with h3 f2 have "P (Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t))) x" 
+      by (auto simp add: fresh_def at_fin_set_supp[OF at_name_inst, OF fs])
+    with g show "P (Lam [(pi\<bullet>a)].(pi\<bullet>t)) x" by simp
+  qed
+qed (auto intro: h1 h2)
+
+lemma lam_induct'[case_names Fin Var App Lam]: 
+  fixes P :: "lam \<Rightarrow> 'a \<Rightarrow> bool"
+  and   x :: "'a"
+  and   t :: "lam"
+  and   f :: "'a \<Rightarrow> name set"
+  assumes fs: "\<And>x. finite (f x)"
+  and     h1: "\<And>x a. P (Var  a) x" 
+  and     h2: "\<And>x t1 t2. (\<forall>z. P t1 z)\<Longrightarrow>(\<forall>z. P t2 z)\<Longrightarrow>P (App t1 t2) x" 
+  and     h3: "\<And>x a t. a\<notin>f x \<Longrightarrow> (\<forall>z. P t z)\<Longrightarrow> P (Lam [a].t) x"
+  shows  "P t x"
+proof - 
+  from fs h1 h2 h3 have "\<forall>(pi::name prm) x. P (pi\<bullet>t) x" by (rule lam_induct_aux, auto)
+  hence "P (([]::name prm)\<bullet>t) x" by blast
+  thus "P t x" by simp
+qed
+
+lemma lam_induct[case_names Var App Lam]: 
+  fixes P :: "lam \<Rightarrow> ('a::fs_name) \<Rightarrow> bool"
+  and   x :: "'a::fs_name"
+  and   t :: "lam"
+  assumes h1: "\<And>x a. P (Var  a) x" 
+  and     h2: "\<And>x t1 t2. (\<forall>z. P t1 z)\<Longrightarrow>(\<forall>z. P t2 z)\<Longrightarrow>P (App t1 t2) x" 
+  and     h3: "\<And>x a t. a\<sharp>x \<Longrightarrow> (\<forall>z. P t z)\<Longrightarrow> P (Lam [a].t) x"
+  shows  "P t x"
+by (rule lam_induct'[of "\<lambda>x. ((supp x)::name set)" "P"], 
+    simp_all add: fs_name1 fresh_def[symmetric], auto intro: h1 h2 h3)
+
+types 'a f1_ty  = "name\<Rightarrow>('a::pt_name)"
+      'a f2_ty  = "'a\<Rightarrow>'a\<Rightarrow>('a::pt_name)"
+      'a f3_ty  = "name\<Rightarrow>'a\<Rightarrow>('a::pt_name)"
+
+lemma f3_freshness_conditions:
+  fixes f3::"('a::pt_name) f3_ty"
+  and   y ::"name prm \<Rightarrow> 'a::pt_name"
+  and   a ::"name"
+  and   pi1::"name prm"
+  and   pi2::"name prm"
+  assumes a: "finite ((supp f3)::name set)"
+  and     b: "finite ((supp y)::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "\<exists>(a''::name). a''\<sharp>(\<lambda>a'. f3 a' (y (pi1@[(a,pi2\<bullet>a')]))) \<and> 
+                       a''\<sharp>(\<lambda>a'. f3 a' (y (pi1@[(a,pi2\<bullet>a')]))) a''" 
+proof -
+  from c obtain a' where d0: "a'\<sharp>f3" and d1: "\<forall>(y::'a::pt_name). a'\<sharp>f3 a' y" by force
+  have "\<exists>(a''::name). a''\<sharp>(f3,a,a',pi1,pi2,y)" 
+    by (rule at_exists_fresh[OF at_name_inst],  simp add: supp_prod fs_name1 a b)
+  then obtain a'' where d2: "a''\<sharp>f3" and d3: "a''\<noteq>a'" and d3b: "a''\<sharp>(f3,a,pi1,pi2,y)" 
+    by (auto simp add: fresh_prod at_fresh[OF at_name_inst])
+  have d3c: "a''\<notin>((supp (f3,a,pi1,pi2,y))::name set)" using d3b by (simp add: fresh_def)
+  have d4: "a''\<sharp>f3 a'' (y (pi1@[(a,pi2\<bullet>a'')]))"
+  proof -
+    have d5: "[(a'',a')]\<bullet>f3 = f3" 
+      by (rule pt_fresh_fresh[OF pt_name_inst, OF at_name_inst, OF d2, OF d0]) 
+    from d1 have "\<forall>(y::'a::pt_name). ([(a'',a')]\<bullet>a')\<sharp>([(a'',a')]\<bullet>(f3 a' y))"
+      by (simp add: pt_fresh_bij[OF pt_name_inst, OF at_name_inst])
+    hence "\<forall>(y::'a::pt_name). a''\<sharp>(f3 a'' ([(a'',a')]\<bullet>y))" using d3 d5 
+      by (simp add: at_calc[OF at_name_inst] pt_fun_app_eq[OF pt_name_inst, OF at_name_inst])
+    hence "a''\<sharp>(f3 a'' ([(a'',a')]\<bullet>((rev [(a'',a')])\<bullet>(y (pi1@[(a,pi2\<bullet>a'')])))))" by force
+    thus ?thesis by (simp only: pt_pi_rev[OF pt_name_inst, OF at_name_inst])
+  qed
+  have d6: "a''\<sharp>(\<lambda>a'. f3 a' (y (pi1@[(a,pi2\<bullet>a')])))"
+  proof -
+    from a b have d7: "finite ((supp (f3,a,pi1,pi2,y))::name set)" by (simp add: supp_prod fs_name1)
+    have e: "((supp (f3,a,pi1,pi2,y))::name set) supports (\<lambda>a'. f3 a' (y (pi1@[(a,pi2\<bullet>a')])))" 
+      by (supports_simp add: perm_append)
+    from e d7 d3c show ?thesis by (rule supports_fresh)
+  qed
+  from d6 d4 show ?thesis by force
+qed
+
+lemma f3_freshness_conditions_simple:
+  fixes f3::"('a::pt_name) f3_ty"
+  and   y ::"name prm \<Rightarrow> 'a::pt_name"
+  and   a ::"name"
+  and   pi::"name prm"
+  assumes a: "finite ((supp f3)::name set)"
+  and     b: "finite ((supp y)::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "\<exists>(a''::name). a''\<sharp>(\<lambda>a'. f3 a' (y (pi@[(a,a')]))) \<and> a''\<sharp>(\<lambda>a'. f3 a' (y (pi@[(a,a')]))) a''" 
+proof -
+  from c obtain a' where d0: "a'\<sharp>f3" and d1: "\<forall>(y::'a::pt_name). a'\<sharp>f3 a' y" by force
+  have "\<exists>(a''::name). a''\<sharp>(f3,a,a',pi,y)" 
+    by (rule at_exists_fresh[OF at_name_inst],  simp add: supp_prod fs_name1 a b)
+  then obtain a'' where d2: "a''\<sharp>f3" and d3: "a''\<noteq>a'" and d3b: "a''\<sharp>(f3,a,pi,y)" 
+    by (auto simp add: fresh_prod at_fresh[OF at_name_inst])
+  have d3c: "a''\<notin>((supp (f3,a,pi,y))::name set)" using d3b by (simp add: fresh_def)
+  have d4: "a''\<sharp>f3 a'' (y (pi@[(a,a'')]))"
+  proof -
+    have d5: "[(a'',a')]\<bullet>f3 = f3" 
+      by (rule pt_fresh_fresh[OF pt_name_inst, OF at_name_inst, OF d2, OF d0]) 
+    from d1 have "\<forall>(y::'a::pt_name). ([(a'',a')]\<bullet>a')\<sharp>([(a'',a')]\<bullet>(f3 a' y))"
+      by (simp add: pt_fresh_bij[OF pt_name_inst, OF at_name_inst])
+    hence "\<forall>(y::'a::pt_name). a''\<sharp>(f3 a'' ([(a'',a')]\<bullet>y))" using d3 d5 
+      by (simp add: at_calc[OF at_name_inst] pt_fun_app_eq[OF pt_name_inst, OF at_name_inst])
+    hence "a''\<sharp>(f3 a'' ([(a'',a')]\<bullet>((rev [(a'',a')])\<bullet>(y (pi@[(a,a'')])))))" by force
+    thus ?thesis by (simp only: pt_pi_rev[OF pt_name_inst, OF at_name_inst])
+  qed
+  have d6: "a''\<sharp>(\<lambda>a'. f3 a' (y (pi@[(a,a')])))"
+  proof -
+    from a b have d7: "finite ((supp (f3,a,pi,y))::name set)" by (simp add: supp_prod fs_name1)
+    have "((supp (f3,a,pi,y))::name set) supports (\<lambda>a'. f3 a' (y (pi@[(a,a')])))" 
+      by (supports_simp add: perm_append)
+    with d7 d3c show ?thesis by (simp add: supports_fresh)
+  qed
+  from d6 d4 show ?thesis by force
+qed
+
+lemma f3_fresh_fun_supports:
+  fixes f3::"('a::pt_name) f3_ty"
+  and   a ::"name"
+  and   pi1::"name prm"
+  and   y ::"name prm \<Rightarrow> 'a::pt_name"
+  assumes a: "finite ((supp f3)::name set)"
+  and     b: "finite ((supp y)::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "((supp (f3,a,y))::name set) supports (\<lambda>pi. fresh_fun (\<lambda>a'. f3 a' (y (pi@[(a,a')]))))"
+proof (auto simp add: "op supports_def" perm_fun_def expand_fun_eq fresh_def[symmetric])
+  fix b::"name" and c::"name" and pi::"name prm"
+  assume b1: "b\<sharp>(f3,a,y)"
+  and    b2: "c\<sharp>(f3,a,y)"
+  from b1 b2 have b3: "[(b,c)]\<bullet>f3=f3" and t4: "[(b,c)]\<bullet>a=a" and t5: "[(b,c)]\<bullet>y=y"
+    by (simp_all add: pt_fresh_fresh[OF pt_name_inst, OF at_name_inst] fresh_prod)
+  let ?g = "\<lambda>a'. f3 a' (y (([(b,c)]\<bullet>pi)@[(a,a')]))"
+  and ?h = "\<lambda>a'. f3 a' (y (pi@[(a,a')]))"
+  have a0: "finite ((supp (f3,a,[(b,c)]\<bullet>pi,y))::name set)" using a b 
+    by (simp add: supp_prod fs_name1)
+  have a1: "((supp (f3,a,[(b,c)]\<bullet>pi,y))::name set) supports ?g" by (supports_simp add: perm_append)
+  hence a2: "finite ((supp ?g)::name set)" using a0 by (rule supports_finite)
+  have a3: "\<exists>(a''::name). a''\<sharp>?g \<and> a''\<sharp>(?g a'')"
+    by (rule f3_freshness_conditions_simple[OF a, OF b, OF c])
+  have "((supp (f3,a,y))::name set) \<subseteq> (supp (f3,a,[(b,c)]\<bullet>pi,y))" by (force simp add: supp_prod)
+  have a4: "[(b,c)]\<bullet>?g = ?h" using b1 b2
+    by (simp add: fresh_prod, perm_simp add: perm_append)
+  have "[(b,c)]\<bullet>(fresh_fun ?g) = fresh_fun ([(b,c)]\<bullet>?g)" 
+    by (simp add: fresh_fun_equiv[OF pt_name_inst, OF at_name_inst, OF a2, OF a3])
+  also have "\<dots> = fresh_fun ?h" using a4 by simp
+  finally show "[(b,c)]\<bullet>(fresh_fun ?g) = fresh_fun ?h" .
+qed
+
+lemma f3_fresh_fun_supp_finite:
+  fixes f3::"('a::pt_name) f3_ty"
+  and   a ::"name"
+  and   pi1::"name prm"
+  and   y ::"name prm \<Rightarrow> 'a::pt_name"
+  assumes a: "finite ((supp f3)::name set)"
+  and     b: "finite ((supp y)::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "finite ((supp (\<lambda>pi. fresh_fun (\<lambda>a'. f3 a' (y (pi@[(a,a')])))))::name set)"
+proof -
+  have "((supp (f3,a,y))::name set) supports (\<lambda>pi. fresh_fun (\<lambda>a'. f3 a' (y (pi@[(a,a')]))))"
+    using a b c by (rule f3_fresh_fun_supports)
+  moreover
+  have "finite ((supp (f3,a,y))::name set)" using a b by (simp add: supp_prod fs_name1) 
+  ultimately show ?thesis by (rule supports_finite)
+qed
+
+(*
+types 'a recT  = "'a f1_ty \<Rightarrow> 'a f2_ty \<Rightarrow> 'a f3_ty \<Rightarrow> ((lam\<times>name prm\<times>('a::pt_name)) set)"
+
+consts
+  rec :: "('a::pt_name) recT"
+
+inductive "rec f1 f2 f3"
+intros
+r1: "(Var a,pi,f1 (pi\<bullet>a))\<in>rec f1 f2 f3" 
+r2: "\<lbrakk>finite ((supp y1)::name set);(t1,pi,y1)\<in>rec f1 f2 f3; 
+      finite ((supp y2)::name set);(t2,pi,y2)\<in>rec f1 f2 f3\<rbrakk> 
+      \<Longrightarrow> (App t1 t2,pi,f2 y1 y2)\<in>rec f1 f2 f3"
+r3: "\<lbrakk>finite ((supp y)::name set);\<forall>a'. ((t,pi@[(a,a')],y)\<in>rec f1 f2 f3)\<rbrakk> 
+      \<Longrightarrow> (Lam [a].t,pi,fresh_fun (\<lambda>a'. f3 a' y))\<in>rec f1 f2 f3"
+
+*)
+
+(*
+types 'a recT  = "'a f1_ty \<Rightarrow> 'a f2_ty \<Rightarrow> 'a f3_ty \<Rightarrow> (lam\<times>(name prm \<Rightarrow> ('a::pt_name))) set"
+
+consts
+  rec :: "('a::pt_name) recT"
+
+inductive "rec f1 f2 f3"
+intros
+r1: "(Var a,\<lambda>pi. f1 (pi\<bullet>a))\<in>rec f1 f2 f3" 
+r2: "\<lbrakk>finite ((supp y1)::name set);(t1,y1)\<in>rec f1 f2 f3; 
+      finite ((supp y2)::name set);(t2,y2)\<in>rec f1 f2 f3\<rbrakk> 
+      \<Longrightarrow> (App t1 t2,\<lambda>pi. f2 (y1 pi) (y2 pi))\<in>rec f1 f2 f3"
+r3: "\<lbrakk>finite ((supp y)::name set);(t,y)\<in>rec f1 f2 f3\<rbrakk> 
+      \<Longrightarrow> (Lam [a].t,fresh_fun (\<lambda>a' pi. f3 a' (y (pi@[(a,a')]))))\<in>rec f1 f2 f3"
+*)
+
+term lam_Rep.Var
+term lam_Rep.Lam
+
+consts nthe :: "'a nOption \<Rightarrow> 'a"
+primrec
+ "nthe (nSome x) = x"
+
+types 'a recT  = "'a f1_ty \<Rightarrow> 'a f2_ty \<Rightarrow> 'a f3_ty \<Rightarrow> (lam\<times>(name prm \<Rightarrow> ('a::pt_name))) set"
+
+(*
+consts fn :: "'a f1_ty \<Rightarrow> 'a f2_ty \<Rightarrow> 'a f3_ty \<Rightarrow> lam_Rep \<Rightarrow> ('a::pt_name)"
+
+primrec
+"fn f1 f2 f3 (lam_Rep.Var a)     = f1 a"
+"fn f1 f2 f3 (lam_Rep.App t1 t2) = f2 (fn f1 f2 f3 t1) (fn f1 f2 f3 t2)"
+"fn f1 f2 f3 (lam_Rep.Lam f)     = fresh_fun (\<lambda>a'. f3 a' (fn f1 f2 f3 (fn' (f a'))))"
+*)
+
+consts
+  rec :: "('a::pt_name) recT"
+
+inductive "rec f1 f2 f3"
+intros
+r1: "(Var a,\<lambda>pi. f1 (pi\<bullet>a))\<in>rec f1 f2 f3" 
+r2: "\<lbrakk>finite ((supp y1)::name set);(t1,y1)\<in>rec f1 f2 f3; 
+      finite ((supp y2)::name set);(t2,y2)\<in>rec f1 f2 f3\<rbrakk> 
+      \<Longrightarrow> (App t1 t2,\<lambda>pi. f2 (y1 pi) (y2 pi))\<in>rec f1 f2 f3"
+r3: "\<lbrakk>finite ((supp y)::name set);(t,y)\<in>rec f1 f2 f3\<rbrakk> 
+      \<Longrightarrow> (Lam [a].t,\<lambda>pi. fresh_fun (\<lambda>a'. f3 a' (y (pi@[(a,a')]))))\<in>rec f1 f2 f3"
+
+constdefs
+  rfun' :: "'a f1_ty \<Rightarrow> 'a f2_ty \<Rightarrow> 'a f3_ty \<Rightarrow> lam \<Rightarrow> name prm \<Rightarrow> ('a::pt_name)" 
+  "rfun' f1 f2 f3 t \<equiv> (THE y. (t,y)\<in>rec f1 f2 f3)"
+
+  rfun :: "'a f1_ty \<Rightarrow> 'a f2_ty \<Rightarrow> 'a f3_ty \<Rightarrow> lam \<Rightarrow> ('a::pt_name)" 
+  "rfun f1 f2 f3 t \<equiv> rfun' f1 f2 f3 t ([]::name prm)"
+
+lemma rec_prm_eq[rule_format]:
+  fixes f1 ::"('a::pt_name) f1_ty"
+  and   f2 ::"('a::pt_name) f2_ty"
+  and   f3 ::"('a::pt_name) f3_ty"
+  and   t  ::"lam"
+  and   y  ::"name prm \<Rightarrow> ('a::pt_name)"
+  shows "(t,y)\<in>rec f1 f2 f3 \<Longrightarrow> (\<forall>(pi1::name prm) (pi2::name prm). pi1 \<sim> pi2 \<longrightarrow> (y pi1 = y pi2))"
+apply(erule rec.induct)
+apply(auto simp add: pt3[OF pt_name_inst])
+apply(rule_tac f="fresh_fun" in arg_cong)
+apply(auto simp add: expand_fun_eq)
+apply(drule_tac x="pi1@[(a,x)]" in spec)
+apply(drule_tac x="pi2@[(a,x)]" in spec)
+apply(force simp add: prm_eq_def pt2[OF pt_name_inst])
+done
+
+(* silly helper lemma *)
+lemma rec_trans: 
+  fixes f1 ::"('a::pt_name) f1_ty"
+  and   f2 ::"('a::pt_name) f2_ty"
+  and   f3 ::"('a::pt_name) f3_ty"
+  and   t  ::"lam"
+  and   y  ::"name prm \<Rightarrow> ('a::pt_name)"
+  assumes a: "(t,y)\<in>rec f1 f2 f3"
+  and     b: "y=y'"
+  shows   "(t,y')\<in>rec f1 f2 f3"
+using a b by simp
+
+
+lemma rec_prm_equiv:
+  fixes f1 ::"('a::pt_name) f1_ty"
+  and   f2 ::"('a::pt_name) f2_ty"
+  and   f3 ::"('a::pt_name) f3_ty"
+  and   t  ::"lam"
+  and   y  ::"name prm \<Rightarrow> ('a::pt_name)"
+  and   pi ::"name prm"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a: "(t,y)\<in>rec f1 f2 f3"
+  shows "(pi\<bullet>t,pi\<bullet>y)\<in>rec (pi\<bullet>f1) (pi\<bullet>f2) (pi\<bullet>f3)"
+using a
+proof (induct)
+  case (r1 c)
+  let ?g ="pi\<bullet>(\<lambda>(pi'::name prm). f1 (pi'\<bullet>c))"
+  and ?g'="\<lambda>(pi'::name prm). (pi\<bullet>f1) (pi'\<bullet>(pi\<bullet>c))"
+  have "?g'=?g" 
+  proof (auto simp only: expand_fun_eq perm_fun_def)
+    fix pi'::"name prm"
+    let ?h = "((rev pi)\<bullet>(pi'\<bullet>(pi\<bullet>c)))"
+    and ?h'= "(((rev pi)\<bullet>pi')\<bullet>c)"
+    have "?h' = ((rev pi)\<bullet>pi')\<bullet>((rev pi)\<bullet>(pi\<bullet>c))" 
+      by (simp add: pt_rev_pi[OF pt_name_inst, OF at_name_inst])
+    also have "\<dots> = ?h"
+      by (simp add: pt_perm_compose[OF pt_name_inst, OF at_name_inst,symmetric])
+    finally show "pi\<bullet>(f1 ?h) = pi\<bullet>(f1 ?h')" by simp
+  qed
+  thus ?case by (force intro: rec_trans rec.r1)
+next
+  case (r2 t1 t2 y1 y2)
+  assume a1: "finite ((supp y1)::name set)"
+  and    a2: "finite ((supp y2)::name set)"
+  and    a3: "(pi\<bullet>t1,pi\<bullet>y1) \<in> rec (pi\<bullet>f1) (pi\<bullet>f2) (pi\<bullet>f3)"
+  and    a4: "(pi\<bullet>t2,pi\<bullet>y2) \<in> rec (pi\<bullet>f1) (pi\<bullet>f2) (pi\<bullet>f3)"
+  from a1 a2 have a1': "finite ((supp (pi\<bullet>y1))::name set)" and a2': "finite ((supp (pi\<bullet>y2))::name set)"
+    by (simp_all add: pt_supp_finite_pi[OF pt_name_inst, OF at_name_inst])
+  let ?g ="pi\<bullet>(\<lambda>(pi'::name prm). f2 (y1 pi') (y2 pi'))"
+  and ?g'="\<lambda>(pi'::name prm). (pi\<bullet>f2) ((pi\<bullet>y1) pi') ((pi\<bullet>y2) pi')"
+  have "?g'=?g" by  (simp add: expand_fun_eq perm_fun_def pt_rev_pi[OF pt_name_inst, OF at_name_inst])
+  thus ?case using a1' a2' a3 a4 by (force intro: rec.r2 rec_trans)
+next
+  case (r3 a t y)
+  assume a1: "finite ((supp y)::name set)"
+  and    a2: "(pi\<bullet>t,pi\<bullet>y) \<in> rec (pi\<bullet>f1) (pi\<bullet>f2) (pi\<bullet>f3)"
+  from a1 have a1': "finite ((supp (pi\<bullet>y))::name set)" 
+    by (simp add: pt_supp_finite_pi[OF pt_name_inst, OF at_name_inst])
+  let ?g ="pi\<bullet>(\<lambda>(pi'::name prm). fresh_fun (\<lambda>a'. f3 a' (y (pi'@[(a,a')]))))"
+  and ?g'="(\<lambda>(pi'::name prm). fresh_fun (\<lambda>a'. (pi\<bullet>f3) a' ((pi\<bullet>y) (pi'@[((pi\<bullet>a),a')]))))"
+  have "?g'=?g" 
+  proof (auto simp add: expand_fun_eq perm_fun_def pt_rev_pi[OF pt_name_inst, OF at_name_inst] 
+                        perm_append)
+    fix pi'::"name prm"
+    let ?h  = "\<lambda>a'. pi\<bullet>(f3 ((rev pi)\<bullet>a') (y (((rev pi)\<bullet>pi')@[(a,(rev pi)\<bullet>a')])))"
+    and ?h' = "\<lambda>a'. f3 a' (y (((rev pi)\<bullet>pi')@[(a,a')]))"
+    have fs_f3: "finite ((supp f3)::name set)" using f by (simp add: supp_prod)
+    have fs_h': "finite ((supp ?h')::name set)"
+    proof -
+      have "((supp (f3,a,(rev pi)\<bullet>pi',y))::name set) supports ?h'" 
+	by (supports_simp add: perm_append)
+      moreover
+      have "finite ((supp (f3,a,(rev pi)\<bullet>pi',y))::name set)" using a1 fs_f3 
+	by (simp add: supp_prod fs_name1)
+      ultimately show ?thesis by (rule supports_finite)
+    qed
+    have fcond: "\<exists>(a''::name). a''\<sharp>?h' \<and> a''\<sharp>(?h' a'')"
+      by (rule f3_freshness_conditions_simple[OF fs_f3, OF a1, OF c])
+    have "fresh_fun ?h = fresh_fun (pi\<bullet>?h')"
+      by (simp add: perm_fun_def pt_rev_pi[OF pt_name_inst, OF at_name_inst])
+    also have "\<dots> = pi\<bullet>(fresh_fun ?h')"
+      by (simp add: fresh_fun_equiv[OF pt_name_inst, OF at_name_inst, OF fs_h', OF fcond])
+    finally show "fresh_fun ?h = pi\<bullet>(fresh_fun ?h')" .
+  qed
+  thus ?case using a1' a2 by (force intro: rec.r3 rec_trans)
+qed
+
+lemma rec_perm:
+  fixes f1 ::"('a::pt_name) f1_ty"
+  and   f2 ::"('a::pt_name) f2_ty"
+  and   f3 ::"('a::pt_name) f3_ty"
+  and   pi1::"name prm"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a: "(t,y)\<in>rec f1 f2 f3"
+  shows "(pi1\<bullet>t, \<lambda>pi2. y (pi2@pi1))\<in>rec f1 f2 f3"
+proof -
+  have lem: "\<forall>(y::name prm\<Rightarrow>('a::pt_name))(pi::name prm). 
+             finite ((supp y)::name set) \<longrightarrow> finite ((supp (\<lambda>pi'. y (pi'@pi)))::name set)"
+  proof (intro strip)
+    fix y::"name prm\<Rightarrow>('a::pt_name)" and pi::"name prm"
+    assume  "finite ((supp y)::name set)"
+    hence "finite ((supp (y,pi))::name set)" by (simp add: supp_prod fs_name1)      
+    moreover
+    have  "((supp (y,pi))::name set) supports (\<lambda>pi'. y (pi'@pi))" 
+      by (supports_simp add: perm_append)
+    ultimately show "finite ((supp (\<lambda>pi'. y (pi'@pi)))::name set)" by (simp add: supports_finite)
+  qed
+from a
+show ?thesis
+proof (induct)
+  case (r1 c)
+  show ?case
+    by (auto simp add: pt2[OF pt_name_inst], rule rec.r1)
+next
+  case (r2 t1 t2 y1 y2)
+  thus ?case using lem by (auto intro!: rec.r2) 
+next
+  case (r3 c t y)
+  assume a0: "(t,y)\<in>rec f1 f2 f3"
+  and    a1: "finite ((supp y)::name set)"
+  and    a2: "(pi1\<bullet>t,\<lambda>pi2. y (pi2@pi1))\<in>rec f1 f2 f3"
+  from f have f': "finite ((supp f3)::name set)" by (simp add: supp_prod)
+  show ?case
+  proof(simp)
+    have a3: "finite ((supp (\<lambda>pi2. y (pi2@pi1)))::name set)" using lem a1 by force
+    let ?g' = "\<lambda>(pi::name prm). fresh_fun (\<lambda>a'. f3 a' ((\<lambda>pi2. y (pi2@pi1)) (pi@[(pi1\<bullet>c,a')])))"
+    and ?g  = "\<lambda>(pi::name prm). fresh_fun (\<lambda>a'. f3 a' (y (pi@[(pi1\<bullet>c,a')]@pi1)))"
+    and ?h  = "\<lambda>(pi::name prm). fresh_fun (\<lambda>a'. f3 a' (y (pi@pi1@[(c,a')])))"
+    have eq1: "?g = ?g'" by simp
+    have eq2: "?g'= ?h" 
+    proof (auto simp only: expand_fun_eq)
+      fix pi::"name prm"
+      let ?q  = "\<lambda>a'. f3 a' (y ((pi@[(pi1\<bullet>c,a')])@pi1))"
+      and ?q' = "\<lambda>a'. f3 a' (y (((pi@pi1)@[(c,(rev pi1)\<bullet>a')])))"
+      and ?r  = "\<lambda>a'. f3 a' (y ((pi@pi1)@[(c,a')]))"
+      and ?r' = "\<lambda>a'. f3 a' (y (pi@(pi1@[(c,a')])))"
+      have eq3a: "?r = ?r'" by simp
+      have eq3: "?q = ?q'"
+      proof (auto simp only: expand_fun_eq)
+	fix a'::"name"
+	have "(y ((pi@[(pi1\<bullet>c,a')])@pi1)) =  (y (((pi@pi1)@[(c,(rev pi1)\<bullet>a')])))" 
+	  proof -
+	    have "((pi@[(pi1\<bullet>c,a')])@pi1) \<sim> ((pi@pi1)@[(c,(rev pi1)\<bullet>a')])"
+	    by (force simp add: prm_eq_def at_append[OF at_name_inst] 
+                   at_calc[OF at_name_inst] at_bij[OF at_name_inst] 
+                   at_pi_rev[OF at_name_inst] at_rev_pi[OF at_name_inst])
+	    with a0 show ?thesis by (rule rec_prm_eq)
+	  qed
+	thus "f3 a' (y ((pi@[(pi1\<bullet>c,a')])@pi1)) = f3 a' (y (((pi@pi1)@[(c,(rev pi1)\<bullet>a')])))" by simp
+      qed
+      have fs_a: "finite ((supp ?q')::name set)"
+      proof -
+	have "((supp (f3,c,(pi@pi1),(rev pi1),y))::name set) supports ?q'" 
+	  by (supports_simp add: perm_append fresh_list_append fresh_list_rev)
+	moreover
+	have "finite ((supp (f3,c,(pi@pi1),(rev pi1),y))::name set)" using f' a1
+	  by (simp add: supp_prod fs_name1)
+	ultimately show ?thesis by (rule supports_finite)
+      qed
+      have fs_b: "finite ((supp ?r)::name set)"
+      proof -
+	have "((supp (f3,c,(pi@pi1),y))::name set) supports ?r" 
+	  by (supports_simp add: perm_append fresh_list_append)
+	moreover
+	have "finite ((supp (f3,c,(pi@pi1),y))::name set)" using f' a1
+	  by (simp add: supp_prod fs_name1)
+	ultimately show ?thesis by (rule supports_finite)
+      qed
+      have c1: "\<exists>(a''::name). a''\<sharp>?q' \<and> a''\<sharp>(?q' a'')"
+	by (rule f3_freshness_conditions[OF f', OF a1, OF c])
+      have c2: "\<exists>(a''::name). a''\<sharp>?r \<and> a''\<sharp>(?r a'')"
+	by (rule f3_freshness_conditions_simple[OF f', OF a1, OF c])
+      have c3: "\<exists>(d::name). d\<sharp>(?q',?r,(rev pi1))" 
+	by (rule at_exists_fresh[OF at_name_inst], 
+            simp only: finite_Un supp_prod fs_a fs_b fs_name1, simp)
+      then obtain d::"name" where d1: "d\<sharp>?q'" and d2: "d\<sharp>?r" and d3: "d\<sharp>(rev pi1)" 
+	by (auto simp only: fresh_prod)
+      have eq4: "(rev pi1)\<bullet>d = d" using d3 by (simp add: at_prm_fresh[OF at_name_inst])
+      have "fresh_fun ?q = fresh_fun ?q'" using eq3 by simp
+      also have "\<dots> = ?q' d" using fs_a c1 d1 
+	by (simp add: fresh_fun_app[OF pt_name_inst, OF at_name_inst])
+      also have "\<dots> = ?r d" using fs_b c2 d2 eq4
+	by (simp add: fresh_fun_app[OF pt_name_inst, OF at_name_inst])
+      also have "\<dots> = fresh_fun ?r" using fs_b c2 d2 
+	by (simp add: fresh_fun_app[OF pt_name_inst, OF at_name_inst])
+      finally show "fresh_fun ?q = fresh_fun ?r'" by simp
+    qed
+    from a3 a2 have "(Lam [(pi1\<bullet>c)].(pi1\<bullet>t), ?g')\<in>rec f1 f2 f3" by (rule rec.r3)
+    thus "(Lam [(pi1\<bullet>c)].(pi1\<bullet>t), ?h)\<in>rec f1 f2 f3" using eq2 by simp
+  qed
+qed
+qed    
+
+lemma rec_perm_rev:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a: "(pi\<bullet>t,y)\<in>rec f1 f2 f3"
+  shows "(t, \<lambda>pi2. y (pi2@(rev pi)))\<in>rec f1 f2 f3"
+proof - 
+  from a have "((rev pi)\<bullet>(pi\<bullet>t),\<lambda>pi2. y (pi2@(rev pi)))\<in>rec f1 f2 f3"
+    by (rule rec_perm[OF f, OF c])
+  thus ?thesis by (simp add: pt_rev_pi[OF pt_name_inst, OF at_name_inst])
+qed
+
+
+lemma rec_unique:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a: "(t,y)\<in>rec f1 f2 f3"
+  shows "\<forall>(y'::name prm\<Rightarrow>('a::pt_name))(pi::name prm).
+         (t,y')\<in>rec f1 f2 f3 \<longrightarrow> y pi = y' pi"
+using a
+proof (induct)
+  case (r1 c)
+  show ?case 
+   apply(auto)
+   apply(ind_cases "(Var c, y') \<in> rec f1 f2 f3")
+   apply(simp_all add: lam.distinct lam.inject)
+   done
+next
+  case (r2 t1 t2 y1 y2)
+  thus ?case 
+    apply(clarify)
+    apply(ind_cases "(App t1 t2, y') \<in> rec f1 f2 f3") 
+    apply(simp_all (no_asm_use) only: lam.distinct lam.inject) 
+    apply(clarify)
+    apply(drule_tac x="y1" in spec)
+    apply(drule_tac x="y2" in spec)
+    apply(auto)
+    done
+next
+  case (r3 c t y)
+  assume i1: "finite ((supp y)::name set)"
+  and    i2: "(t,y)\<in>rec f1 f2 f3"
+  and    i3: "\<forall>(y'::name prm\<Rightarrow>('a::pt_name))(pi::name prm).
+              (t,y')\<in>rec f1 f2 f3 \<longrightarrow> y pi = y' pi"
+  from f have f': "finite ((supp f3)::name set)" by (simp add: supp_prod)
+  show ?case 
+  proof (auto)
+    fix y'::"name prm\<Rightarrow>('a::pt_name)" and pi::"name prm"
+    assume i4: "(Lam [c].t, y') \<in> rec f1 f2 f3"
+    from i4 show "fresh_fun (\<lambda>a'. f3 a' (y (pi@[(c,a')]))) = y' pi"
+    proof (cases, simp_all add: lam.distinct lam.inject, auto)
+      fix a::"name" and t'::"lam" and y''::"name prm\<Rightarrow>('a::pt_name)"
+      assume i5: "[c].t = [a].t'"
+      and    i6: "(t',y'')\<in>rec f1 f2 f3"
+      and    i6':"finite ((supp y'')::name set)"
+      let ?g = "\<lambda>a'. f3 a' (y  (pi@[(c,a')]))"
+      and ?h = "\<lambda>a'. f3 a' (y'' (pi@[(a,a')]))"
+      show "fresh_fun ?g = fresh_fun ?h" using i5
+      proof (cases "a=c")
+	case True
+	assume i7: "a=c"
+	with i5 have i8: "t=t'" by (simp add: alpha)
+	show "fresh_fun ?g = fresh_fun ?h" using i3 i6 i7 i8 by simp
+      next
+	case False
+	assume i9: "a\<noteq>c"
+	with i5[symmetric] have i10: "t'=[(a,c)]\<bullet>t" and i11: "a\<sharp>t" by (simp_all add: alpha)
+	have r1: "finite ((supp ?g)::name set)" 
+	proof -
+	  have "((supp (f3,c,pi,y))::name set) supports ?g" 
+	    by (supports_simp add: perm_append)
+	  moreover
+	  have "finite ((supp (f3,c,pi,y))::name set)" using f' i1
+	    by (simp add: supp_prod fs_name1)
+	  ultimately show ?thesis by (rule supports_finite)
+	qed
+	have r2: "finite ((supp ?h)::name set)" 
+	proof -
+	  have "((supp (f3,a,pi,y''))::name set) supports ?h" 
+	    by (supports_simp add: perm_append)
+	  moreover
+	  have "finite ((supp (f3,a,pi,y''))::name set)" using f' i6'
+	    by (simp add: supp_prod fs_name1)
+	  ultimately show ?thesis by (rule supports_finite)
+	qed
+	have c1: "\<exists>(a''::name). a''\<sharp>?g \<and> a''\<sharp>(?g a'')"
+	  by (rule f3_freshness_conditions_simple[OF f', OF i1, OF c])
+	have c2: "\<exists>(a''::name). a''\<sharp>?h \<and> a''\<sharp>(?h a'')"
+	  by (rule f3_freshness_conditions_simple[OF f', OF i6', OF c])
+	have "\<exists>(d::name). d\<sharp>(?g,?h,t,a,c)" 
+	  by (rule at_exists_fresh[OF at_name_inst], 
+              simp only: finite_Un supp_prod r1 r2 fs_name1, simp)
+	then obtain d::"name" 
+	  where f1: "d\<sharp>?g" and f2: "d\<sharp>?h" and f3: "d\<sharp>t" and f4: "d\<noteq>a" and f5: "d\<noteq>c" 
+	  by (force simp add: fresh_prod at_fresh[OF at_name_inst] at_fresh[OF at_name_inst])
+	have g1: "[(a,d)]\<bullet>t = t" 
+	  by (rule pt_fresh_fresh[OF pt_name_inst, OF at_name_inst, OF i11, OF f3]) 
+	from i6 have "(([(a,c)]@[(a,d)])\<bullet>t,y'')\<in>rec f1 f2 f3" using g1 i10 by (simp only: pt_name2)
+	hence "(t, \<lambda>pi2. y'' (pi2@(rev ([(a,c)]@[(a,d)]))))\<in>rec f1 f2 f3"
+	  by (simp only: rec_perm_rev[OF f, OF c])
+	hence g2: "(t, \<lambda>pi2. y'' (pi2@([(a,d)]@[(a,c)])))\<in>rec f1 f2 f3" by simp
+	have "distinct [a,c,d]" using i9 f4 f5 by force
+	hence g3: "(pi@[(c,d)]@[(a,d)]@[(a,c)]) \<sim> (pi@[(a,d)])"
+	  by (force simp add: prm_eq_def at_calc[OF at_name_inst] at_append[OF at_name_inst])
+	have "fresh_fun ?g = ?g d" using r1 c1 f1
+	  by (simp add: fresh_fun_app[OF pt_name_inst, OF at_name_inst])
+	also have "\<dots> = f3 d ((\<lambda>pi2. y'' (pi2@([(a,d)]@[(a,c)]))) (pi@[(c,d)]))" using i3 g2 by simp 
+	also have "\<dots> = f3 d (y'' (pi@[(c,d)]@[(a,d)]@[(a,c)]))" by simp
+	also have "\<dots> = f3 d (y'' (pi@[(a,d)]))" using i6 g3 by (simp add: rec_prm_eq)
+	also have "\<dots> = fresh_fun ?h" using r2 c2 f2
+	  by (simp add: fresh_fun_app[OF pt_name_inst, OF at_name_inst])
+	finally show "fresh_fun ?g = fresh_fun ?h" .
+      qed
+    qed
+  qed
+qed
+
+lemma rec_total_aux:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "\<exists>(y::name prm\<Rightarrow>('a::pt_name)). ((t,y)\<in>rec f1 f2 f3) \<and> (finite ((supp y)::name set))"
+proof (induct t rule: lam.induct_weak)
+  case (Var c)
+  have a1: "(Var c,\<lambda>(pi::name prm). f1 (pi\<bullet>c))\<in>rec f1 f2 f3" by (rule rec.r1)
+  have a2: "finite ((supp (\<lambda>(pi::name prm). f1 (pi\<bullet>c)))::name set)"
+  proof -
+    have "((supp (f1,c))::name set) supports (\<lambda>(pi::name prm). f1 (pi\<bullet>c))" by (supports_simp)
+    moreover have "finite ((supp (f1,c))::name set)" using f by (simp add: supp_prod fs_name1)
+    ultimately show ?thesis by (rule supports_finite)
+  qed
+  from a1 a2 show ?case by force
+next
+  case (App t1 t2)
+  assume "\<exists>y1. (t1,y1)\<in>rec f1 f2 f3 \<and> finite ((supp y1)::name set)"
+  then obtain y1::"name prm \<Rightarrow> ('a::pt_name)"
+    where a11: "(t1,y1)\<in>rec f1 f2 f3" and a12: "finite ((supp y1)::name set)" by force
+  assume "\<exists>y2. (t2,y2)\<in>rec f1 f2 f3 \<and> finite ((supp y2)::name set)"
+  then obtain y2::"name prm \<Rightarrow> ('a::pt_name)"
+    where a21: "(t2,y2)\<in>rec f1 f2 f3" and a22: "finite ((supp y2)::name set)" by force
+  
+  have a1: "(App t1 t2,\<lambda>(pi::name prm). f2 (y1 pi) (y2 pi))\<in>rec f1 f2 f3"
+    using a12 a11 a22 a21 by (rule rec.r2)
+  have a2: "finite ((supp (\<lambda>(pi::name prm). f2 (y1 pi) (y2 pi)))::name set)"
+  proof -
+    have "((supp (f2,y1,y2))::name set) supports (\<lambda>(pi::name prm). f2 (y1 pi) (y2 pi))" 
+      by (supports_simp)
+    moreover have "finite ((supp (f2,y1,y2))::name set)" using f a21 a22 
+      by (simp add: supp_prod fs_name1)
+    ultimately show ?thesis by (rule supports_finite)
+  qed
+  from a1 a2 show ?case by force
+next
+  case (Lam a t)
+  assume "\<exists>y. (t,y)\<in>rec f1 f2 f3 \<and> finite ((supp y)::name set)"
+  then obtain y::"name prm \<Rightarrow> ('a::pt_name)"
+    where a11: "(t,y)\<in>rec f1 f2 f3" and a12: "finite ((supp y)::name set)" by force
+  from f have f': "finite ((supp f3)::name set)" by (simp add: supp_prod)
+  have a1: "(Lam [a].t,\<lambda>(pi::name prm). fresh_fun (\<lambda>a'. f3 a' (y (pi@[(a,a')]))))\<in>rec f1 f2 f3"
+    using a12 a11 by (rule rec.r3)
+  have a2: "finite ((supp (\<lambda>pi. fresh_fun (\<lambda>a'. f3 a' (y (pi@[(a,a')])))))::name set)" 
+    using f' a12 c by (rule f3_fresh_fun_supp_finite)
+  from a1 a2 show ?case by force
+qed
+
+lemma rec_total:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "\<exists>(y::name prm\<Rightarrow>('a::pt_name)). ((t,y)\<in>rec f1 f2 f3)"
+proof -
+  have "\<exists>y. ((t,y)\<in>rec f1 f2 f3) \<and> (finite ((supp y)::name set))"
+    by (rule rec_total_aux[OF f, OF c])
+  thus ?thesis by force
+qed
+
+lemma rec_function:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "\<exists>!y. (t,y)\<in>rec f1 f2 f3"
+proof 
+  case goal1
+  show ?case by (rule rec_total[OF f, OF c])
+next
+  case (goal2 y1 y2)
+  assume a1: "(t,y1)\<in>rec f1 f2 f3" and a2: "(t,y2)\<in>rec f1 f2 f3"
+  hence "\<forall>pi. y1 pi = y2 pi" using rec_unique[OF f, OF c] by force
+  thus ?case by (force simp add: expand_fun_eq) 
+qed
+  
+lemma theI2':
+  assumes a1: "P a" 
+  and     a2: "\<exists>!x. P x" 
+  and     a3: "P a \<Longrightarrow> Q a"
+  shows "Q (THE x. P x)"
+apply(rule theI2)
+apply(rule a1)
+apply(subgoal_tac "\<exists>!x. P x")
+apply(auto intro: a1 simp add: Ex1_def)
+apply(fold Ex1_def)
+apply(rule a2)
+apply(subgoal_tac "x=a")
+apply(simp)
+apply(rule a3)
+apply(assumption)
+apply(subgoal_tac "\<exists>!x. P x")
+apply(auto intro: a1 simp add: Ex1_def)
+apply(fold Ex1_def)
+apply(rule a2)
+done
+
+lemma rfun'_equiv:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  and   pi::"name prm"
+  and   t ::"lam"  
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "pi\<bullet>(rfun' f1 f2 f3 t) = rfun' (pi\<bullet>f1) (pi\<bullet>f2) (pi\<bullet>f3) (pi\<bullet>t)"
+apply(auto simp add: rfun'_def)
+apply(subgoal_tac "\<exists>y. (t,y)\<in>rec f1 f2 f3 \<and> finite ((supp y)::name set)")
+apply(auto)
+apply(rule sym)
+apply(rule_tac a="y" in theI2')
+apply(assumption)
+apply(rule rec_function[OF f, OF c])
+apply(rule the1_equality)
+apply(rule rec_function)
+apply(subgoal_tac "finite ((supp (f1,f2,f3))::name set)")
+apply(simp add: supp_prod)
+apply(simp add: pt_supp_finite_pi[OF pt_name_inst, OF at_name_inst])
+apply(rule f)
+apply(subgoal_tac "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)")
+apply(auto)
+apply(rule_tac x="pi\<bullet>a" in exI)
+apply(auto)
+apply(simp add: pt_fresh_bij[OF pt_name_inst, OF at_name_inst])
+apply(drule_tac x="(rev pi)\<bullet>x" in spec)
+apply(subgoal_tac "(pi\<bullet>f3) (pi\<bullet>a) x  = pi\<bullet>(f3 a ((rev pi)\<bullet>x))")
+apply(simp add: pt_fresh_bij[OF pt_name_inst, OF at_name_inst])
+apply(subgoal_tac "pi\<bullet>(f3 a ((rev pi)\<bullet>x)) = (pi\<bullet>f3) (pi\<bullet>a) (pi\<bullet>((rev pi)\<bullet>x))")
+apply(simp)
+apply(simp add: pt_pi_rev[OF pt_name_inst, OF at_name_inst])
+apply(simp add: pt_fun_app_eq[OF pt_name_inst, OF at_name_inst])
+apply(rule c)
+apply(rule rec_prm_equiv)
+apply(rule f, rule c, assumption)
+apply(rule rec_total_aux)
+apply(rule f)
+apply(rule c)
+done
+
+lemma rfun'_supports:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "((supp (f1,f2,f3,t))::name set) supports (rfun' f1 f2 f3 t)"
+proof (auto simp add: "op supports_def" fresh_def[symmetric])
+  fix a::"name" and b::"name"
+  assume a1: "a\<sharp>(f1,f2,f3,t)"
+  and    a2: "b\<sharp>(f1,f2,f3,t)"
+  from a1 a2 have "[(a,b)]\<bullet>f1=f1" and "[(a,b)]\<bullet>f2=f2" and "[(a,b)]\<bullet>f3=f3" and "[(a,b)]\<bullet>t=t"
+    by (simp_all add: pt_fresh_fresh[OF pt_name_inst, OF at_name_inst] fresh_prod)
+  thus "[(a,b)]\<bullet>(rfun' f1 f2 f3 t) = rfun' f1 f2 f3 t"
+    by (simp add: rfun'_equiv[OF f, OF c])
+qed
+
+lemma rfun'_finite_supp:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "finite ((supp (rfun' f1 f2 f3 t))::name set)"
+apply(rule supports_finite)
+apply(rule rfun'_supports[OF f, OF c])
+apply(subgoal_tac "finite ((supp (f1,f2,f3))::name set)")
+apply(simp add: supp_prod fs_name1)
+apply(rule f)
+done
+
+lemma rfun'_prm:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  and   pi1::"name prm"
+  and   pi2::"name prm"
+  and   t ::"lam"  
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "rfun' f1 f2 f3 (pi1\<bullet>t) pi2 = rfun' f1 f2 f3 t (pi2@pi1)"
+apply(auto simp add: rfun'_def)
+apply(subgoal_tac "\<exists>y. (t,y)\<in>rec f1 f2 f3 \<and> finite ((supp y)::name set)")
+apply(auto)
+apply(rule_tac a="y" in theI2')
+apply(assumption)
+apply(rule rec_function[OF f, OF c])
+apply(rule_tac a="\<lambda>pi2. y (pi2@pi1)" in theI2')
+apply(rule rec_perm)
+apply(rule f, rule c)
+apply(assumption)
+apply(rule rec_function)
+apply(rule f)
+apply(rule c)
+apply(simp)
+apply(rule rec_total_aux)
+apply(rule f)
+apply(rule c)
+done
+
+lemma rfun_Var:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "rfun f1 f2 f3 (Var c) = (f1 c)"
+apply(auto simp add: rfun_def rfun'_def)
+apply(subgoal_tac "(THE y. (Var c, y) \<in> rec f1 f2 f3) = (\<lambda>(pi::name prm). f1 (pi\<bullet>c))")(*A*)
+apply(simp)
+apply(rule the1_equality)
+apply(rule rec_function)
+apply(rule f)
+apply(rule c)
+apply(rule rec.r1)
+done
+
+lemma rfun_App:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "rfun f1 f2 f3 (App t1 t2) = (f2 (rfun f1 f2 f3 t1) (rfun f1 f2 f3 t2))"
+apply(auto simp add: rfun_def rfun'_def)
+apply(subgoal_tac "(THE y. (App t1 t2, y)\<in>rec f1 f2 f3) = 
+      (\<lambda>(pi::name prm). f2 ((rfun' f1 f2 f3 t1) pi) ((rfun' f1 f2 f3 t2) pi))")(*A*)
+apply(simp add: rfun'_def)
+apply(rule the1_equality)
+apply(rule rec_function[OF f, OF c])
+apply(rule rec.r2)
+apply(rule rfun'_finite_supp[OF f, OF c])
+apply(subgoal_tac "\<exists>y. (t1,y)\<in>rec f1 f2 f3")
+apply(erule exE, simp add: rfun'_def)
+apply(rule_tac a="y" in theI2')
+apply(assumption)
+apply(rule rec_function[OF f, OF c])
+apply(assumption)
+apply(rule rec_total[OF f, OF c])
+apply(rule rfun'_finite_supp[OF f, OF c])
+apply(subgoal_tac "\<exists>y. (t2,y)\<in>rec f1 f2 f3")
+apply(auto simp add: rfun'_def)
+apply(rule_tac a="y" in theI2')
+apply(assumption)
+apply(rule rec_function[OF f, OF c])
+apply(assumption)
+apply(rule rec_total[OF f, OF c])
+done 
+
+lemma rfun_Lam_aux1:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "rfun f1 f2 f3 (Lam [a].t) = fresh_fun (\<lambda>a'. f3 a' (rfun' f1 f2 f3 t ([]@[(a,a')])))"
+apply(simp add: rfun_def rfun'_def)
+apply(subgoal_tac "(THE y. (Lam [a].t, y)\<in>rec f1 f2 f3) = 
+        (\<lambda>(pi::name prm). fresh_fun(\<lambda>a'. f3 a' ((rfun' f1 f2 f3 t) (pi@[(a,a')]))))")(*A*)
+apply(simp add: rfun'_def[symmetric])
+apply(rule the1_equality)
+apply(rule rec_function[OF f, OF c])
+apply(rule rec.r3)
+apply(rule rfun'_finite_supp[OF f, OF c])
+apply(subgoal_tac "\<exists>y. (t,y)\<in>rec f1 f2 f3")
+apply(erule exE, simp add: rfun'_def)
+apply(rule_tac a="y" in theI2')
+apply(assumption)
+apply(rule rec_function[OF f, OF c])
+apply(assumption)
+apply(rule rec_total[OF f, OF c])
+done
+
+lemma rfun_Lam_aux2:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a: "b\<sharp>(a,t,f1,f2,f3)"
+  shows "rfun f1 f2 f3 (Lam [b].([(a,b)]\<bullet>t)) = f3 b (rfun f1 f2 f3 ([(a,b)]\<bullet>t))"
+proof -
+  from f have f': "finite ((supp f3)::name set)" by (simp add: supp_prod)
+  have eq1: "rfun f1 f2 f3 (Lam [b].([(a,b)]\<bullet>t)) = rfun f1 f2 f3 (Lam [a].t)"
+  proof -
+    have "Lam [a].t = Lam [b].([(a,b)]\<bullet>t)" using a
+      by (force simp add: lam.inject alpha fresh_prod at_fresh[OF at_name_inst]
+             pt_swap_bij[OF pt_name_inst, OF at_name_inst] 
+             pt_fresh_left[OF pt_name_inst, OF at_name_inst] at_calc[OF at_name_inst])
+    thus ?thesis by simp
+  qed
+  let ?g = "(\<lambda>a'. f3 a' (rfun' f1 f2 f3 t ([]@[(a,a')])))"
+  have a0: "((supp (f3,a,([]::name prm),rfun' f1 f2 f3 t))::name set) supports ?g"
+    by (supports_simp add: perm_append)
+  have a1: "finite ((supp (f3,a,([]::name prm),rfun' f1 f2 f3 t))::name set)"
+    using f' by (simp add: supp_prod fs_name1 rfun'_finite_supp[OF f, OF c])
+  from a0 a1 have a2: "finite ((supp ?g)::name set)"
+    by (rule supports_finite)
+  have c0: "finite ((supp (rfun' f1 f2 f3 t))::name set)"
+    by (rule rfun'_finite_supp[OF f, OF c])
+  have c1: "\<exists>(a''::name). a''\<sharp>?g \<and> a''\<sharp>(?g a'')"
+    by (rule f3_freshness_conditions_simple[OF f', OF c0, OF c])
+  have c2: "b\<sharp>?g"
+  proof -
+    have fs_g: "finite ((supp (f1,f2,f3,t))::name set)" using f
+      by (simp add: supp_prod fs_name1)
+    have "((supp (f1,f2,f3,t))::name set) supports (rfun' f1 f2 f3 t)"
+      by (simp add: rfun'_supports[OF f, OF c])
+    hence c3: "b\<sharp>(rfun' f1 f2 f3 t)" using fs_g 
+    proof(rule supports_fresh, simp add: fresh_def[symmetric])
+      show "b\<sharp>(f1,f2,f3,t)" using a by (simp add: fresh_prod)
+    qed
+    show ?thesis 
+    proof(rule supports_fresh[OF a0, OF a1], simp add: fresh_def[symmetric])
+      show "b\<sharp>(f3,a,([]::name prm),rfun' f1 f2 f3 t)" using a c3
+	by (simp add: fresh_prod fresh_list_nil)
+    qed
+  qed
+  (* main proof *)
+  have "rfun f1 f2 f3 (Lam [b].([(a,b)]\<bullet>t)) = rfun f1 f2 f3 (Lam [a].t)" by (simp add: eq1)
+  also have "\<dots> = fresh_fun ?g" by (rule rfun_Lam_aux1[OF f, OF c])
+  also have "\<dots> = ?g b" using c2
+    by (rule fresh_fun_app[OF pt_name_inst, OF at_name_inst, OF a2, OF c1])
+  also have "\<dots> = f3 b (rfun f1 f2 f3 ([(a,b)]\<bullet>t))"
+    by (simp add: rfun_def rfun'_prm[OF f, OF c])
+  finally show "rfun f1 f2 f3 (Lam [b].([(a,b)]\<bullet>t)) = f3 b (rfun f1 f2 f3 ([(a,b)]\<bullet>t))" .
+qed
+
+
+lemma rfun_Lam:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a: "b\<sharp>(f1,f2,f3)"
+  shows "rfun f1 f2 f3 (Lam [b].t) = f3 b (rfun f1 f2 f3 t)"
+proof -
+  have "\<exists>(a::name). a\<sharp>(b,t)"
+    by (rule at_exists_fresh[OF at_name_inst], simp add: supp_prod fs_name1)
+  then obtain a::"name" where a1: "a\<sharp>b" and a2: "a\<sharp>t" by (force simp add: fresh_prod)
+  have "rfun f1 f2 f3 (Lam [b].t) = rfun f1 f2 f3 (Lam [b].(([(a,b)])\<bullet>([(a,b)]\<bullet>t)))"
+    by (simp add: pt_swap_bij[OF pt_name_inst, OF at_name_inst])
+  also have "\<dots> = f3 b (rfun f1 f2 f3 (([(a,b)])\<bullet>([(a,b)]\<bullet>t)))" 
+  proof(rule rfun_Lam_aux2[OF f, OF c])
+    have "b\<sharp>([(a,b)]\<bullet>t)" using a1 a2
+      by (simp add: pt_fresh_left[OF pt_name_inst, OF at_name_inst] at_calc[OF at_name_inst] 
+        at_fresh[OF at_name_inst])
+    thus "b\<sharp>(a,[(a,b)]\<bullet>t,f1,f2,f3)" using a a1 by (force simp add: fresh_prod at_fresh[OF at_name_inst])
+  qed
+  also have "\<dots> = f3 b (rfun f1 f2 f3 t)" by (simp add: pt_swap_bij[OF pt_name_inst, OF at_name_inst])
+  finally show ?thesis .
+qed
+  
+lemma rec_unique:
+  fixes fun::"lam \<Rightarrow> ('a::pt_name)"
+  and   f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  and     a1: "\<forall>c. fun (Var c) = f1 c" 
+  and     a2: "\<forall>t1 t2. fun (App t1 t2) = f2 (fun t1) (fun t2)" 
+  and     a3: "\<forall>a t. a\<sharp>(f1,f2,f3) \<longrightarrow> fun (Lam [a].t) = f3 a (fun t)"
+  shows "fun t = rfun f1 f2 f3 t"
+(*apply(nominal_induct t rule: lam_induct')*)
+apply (rule lam_induct'[of "\<lambda>_. ((supp (f1,f2,f3))::name set)" "\<lambda>t _. fun t = rfun f1 f2 f3 t"])
+(* finite support *)
+apply(rule f)
+(* VAR *)
+apply(simp add: a1 rfun_Var[OF f, OF c, symmetric])
+(* APP *)
+apply(simp add: a2 rfun_App[OF f, OF c, symmetric])
+(* LAM *)
+apply(fold fresh_def)
+apply(simp add: a3 rfun_Lam[OF f, OF c, symmetric])
+done
+
+lemma rec_function:
+  fixes f1::"('a::pt_name) f1_ty"
+  and   f2::"('a::pt_name) f2_ty"
+  and   f3::"('a::pt_name) f3_ty"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name). a\<sharp>f3 a y)"
+  shows "(\<exists>!(fun::lam \<Rightarrow> ('a::pt_name)).
+              (\<forall>c.     fun (Var c)     = f1 c) \<and> 
+              (\<forall>t1 t2. fun (App t1 t2) = f2 (fun t1) (fun t2)) \<and> 
+              (\<forall>a t.   a\<sharp>(f1,f2,f3) \<longrightarrow> fun (Lam [a].t) = f3 a (fun t)))"
+apply(rule_tac a="\<lambda>t. rfun f1 f2 f3 t" in ex1I)
+(* existence *)
+apply(simp add: rfun_Var[OF f, OF c])
+apply(simp add: rfun_App[OF f, OF c])
+apply(simp add: rfun_Lam[OF f, OF c])
+(* uniqueness *)
+apply(auto simp add: expand_fun_eq)
+apply(rule rec_unique[OF f, OF c])
+apply(force)+
+done
+
+(* "real" recursion *)
+
+types 'a f1_ty' = "name\<Rightarrow>('a::pt_name)"
+      'a f2_ty' = "lam\<Rightarrow>lam\<Rightarrow>'a\<Rightarrow>'a\<Rightarrow>('a::pt_name)"
+      'a f3_ty' = "lam\<Rightarrow>name\<Rightarrow>'a\<Rightarrow>('a::pt_name)"
+
+constdefs
+  rfun_gen' :: "'a f1_ty' \<Rightarrow> 'a f2_ty' \<Rightarrow> 'a f3_ty' \<Rightarrow> lam \<Rightarrow> (lam\<times>'a::pt_name)" 
+  "rfun_gen' f1 f2 f3 t \<equiv> (rfun 
+                             (\<lambda>(a::name). (Var a,f1 a)) 
+                             (\<lambda>r1 r2. (App (fst r1) (fst r2), f2 (fst r1) (fst r2) (snd r1) (snd r2))) 
+                             (\<lambda>(a::name) r. (Lam [a].(fst r),f3 (fst r) a (snd r)))
+                           t)"
+
+  rfun_gen :: "'a f1_ty' \<Rightarrow> 'a f2_ty' \<Rightarrow> 'a f3_ty' \<Rightarrow> lam \<Rightarrow> 'a::pt_name" 
+  "rfun_gen f1 f2 f3 t \<equiv> snd(rfun_gen' f1 f2 f3 t)"
+
+
+
+lemma f1'_supports:
+  fixes f1::"('a::pt_name) f1_ty'"
+  shows "((supp f1)::name set) supports (\<lambda>(a::name). (Var a,f1 a))"
+  by (supports_simp)
+
+lemma f2'_supports:
+  fixes f2::"('a::pt_name) f2_ty'"
+  shows "((supp f2)::name set) supports 
+                         (\<lambda>r1 r2. (App (fst r1) (fst r2), f2 (fst r1) (fst r2) (snd r1) (snd r2)))"
+  by (supports_simp add: perm_fst perm_snd)  
+
+lemma f3'_supports:
+  fixes f3::"('a::pt_name) f3_ty'"
+  shows "((supp f3)::name set) supports (\<lambda>(a::name) r. (Lam [a].(fst r),f3 (fst r) a (snd r)))"
+by (supports_simp add: perm_fst perm_snd)
+
+lemma fcb': 
+  fixes f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  shows  "\<exists>a.  a \<sharp> (\<lambda>a r. (Lam [a].fst r, f3 (fst r) a (snd r))) \<and>
+                (\<forall>y.  a \<sharp> (Lam [a].fst y, f3 (fst y) a (snd y)))"
+using c f
+apply(auto)
+apply(rule_tac x="a" in exI)
+apply(auto simp add: abs_fresh fresh_prod)
+apply(rule supports_fresh)
+apply(rule f3'_supports)
+apply(simp add: supp_prod)
+apply(simp add: fresh_def)
+done
+
+lemma fsupp':
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  shows "finite((supp
+          (\<lambda>a. (Var a, f1 a),
+           \<lambda>r1 r2.
+              (App (fst r1) (fst r2),
+               f2 (fst r1) (fst r2) (snd r1) (snd r2)),
+           \<lambda>a r. (Lam [a].fst r, f3 (fst r) a (snd r))))::name set)"
+using f
+apply(auto simp add: supp_prod)
+apply(rule supports_finite)
+apply(rule f1'_supports)
+apply(assumption)
+apply(rule supports_finite)
+apply(rule f2'_supports)
+apply(assumption)
+apply(rule supports_finite)
+apply(rule f3'_supports)
+apply(assumption)
+done
+
+lemma rfun_gen'_fst:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)" 
+  and     c: "(\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y))"
+  shows "fst (rfun_gen' f1 f2 f3 t) = t"
+apply (rule lam_induct'[of "\<lambda>_. ((supp (f1,f2,f3))::name set)" "\<lambda>t _. fst (rfun_gen' f1 f2 f3 t) = t"])
+apply(simp add: f)
+apply(unfold rfun_gen'_def)
+apply(simp only: rfun_Var[OF fsupp'[OF f],OF fcb'[OF f, OF c]])
+apply(simp)
+apply(simp only: rfun_App[OF fsupp'[OF f],OF fcb'[OF f, OF c]])
+apply(simp)
+apply(fold fresh_def)
+apply(auto)
+apply(rule trans)
+apply(rule_tac f="fst" in arg_cong)
+apply(rule rfun_Lam[OF fsupp'[OF f],OF fcb'[OF f, OF c]])
+apply(auto simp add: fresh_prod)
+apply(rule supports_fresh)
+apply(rule f1'_supports)
+apply(subgoal_tac "finite ((supp (f1,f2,f3))::name set)")
+apply(simp add: supp_prod)
+apply(rule f)
+apply(simp add: fresh_def)
+apply(rule supports_fresh)
+apply(rule f2'_supports)
+apply(subgoal_tac "finite ((supp (f1,f2,f3))::name set)")
+apply(simp add: supp_prod)
+apply(rule f)
+apply(simp add: fresh_def)
+apply(rule supports_fresh)
+apply(rule f3'_supports)
+apply(subgoal_tac "finite ((supp (f1,f2,f3))::name set)")
+apply(simp add: supp_prod)
+apply(rule f)
+apply(simp add: fresh_def)
+done
+
+lemma rfun_gen'_Var:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  shows "rfun_gen' f1 f2 f3 (Var c) = (Var c, f1 c)"
+apply(simp add: rfun_gen'_def)
+apply(simp add: rfun_Var[OF fsupp'[OF f],OF fcb'[OF f, OF c]])
+done
+
+lemma rfun_gen'_App:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  shows "rfun_gen' f1 f2 f3 (App t1 t2) = 
+                (App t1 t2, f2 t1 t2 (rfun_gen f1 f2 f3 t1) (rfun_gen f1 f2 f3 t2))"
+apply(simp add: rfun_gen'_def)
+apply(rule trans)
+apply(rule rfun_App[OF fsupp'[OF f],OF fcb'[OF f, OF c]])
+apply(fold rfun_gen'_def)
+apply(simp_all add: rfun_gen'_fst[OF f, OF c])
+apply(simp_all add: rfun_gen_def)
+done
+
+lemma rfun_gen'_Lam:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  and     a: "b\<sharp>(f1,f2,f3)"
+  shows "rfun_gen' f1 f2 f3 (Lam [b].t) = (Lam [b].t, f3 t b (rfun_gen f1 f2 f3 t))"
+using a f
+apply(simp add: rfun_gen'_def)
+apply(rule trans)
+apply(rule rfun_Lam[OF fsupp'[OF f],OF fcb'[OF f, OF c]])
+apply(auto simp add: fresh_prod)
+apply(rule supports_fresh)
+apply(rule f1'_supports)
+apply(simp add: supp_prod)
+apply(simp add: fresh_def)
+apply(rule supports_fresh)
+apply(rule f2'_supports)
+apply(simp add: supp_prod)
+apply(simp add: fresh_def)
+apply(rule supports_fresh)
+apply(rule f3'_supports)
+apply(simp add: supp_prod)
+apply(simp add: fresh_def)
+apply(fold rfun_gen'_def)
+apply(simp_all add: rfun_gen'_fst[OF f, OF c])
+apply(simp_all add: rfun_gen_def)
+done
+
+lemma rfun_gen_Var:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  shows "rfun_gen f1 f2 f3 (Var c) = f1 c"
+apply(unfold rfun_gen_def)
+apply(simp add: rfun_gen'_Var[OF f, OF c])
+done
+
+lemma rfun_gen_App:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  shows "rfun_gen f1 f2 f3 (App t1 t2) = f2 t1 t2 (rfun_gen f1 f2 f3 t1) (rfun_gen f1 f2 f3 t2)"
+apply(unfold rfun_gen_def)
+apply(simp add: rfun_gen'_App[OF f, OF c])
+apply(simp add: rfun_gen_def)
+done
+
+lemma rfun_gen_Lam:
+  fixes f1::"('a::pt_name) f1_ty'"
+  and   f2::"('a::pt_name) f2_ty'"
+  and   f3::"('a::pt_name) f3_ty'"
+  assumes f: "finite ((supp (f1,f2,f3))::name set)"
+  and     c: "\<exists>(a::name). a\<sharp>f3 \<and> (\<forall>(y::'a::pt_name) t. a\<sharp>f3 t a y)"
+  and     a: "b\<sharp>(f1,f2,f3)"
+  shows "rfun_gen f1 f2 f3 (Lam [b].t) = f3 t b (rfun_gen f1 f2 f3 t)"
+using a
+apply(unfold rfun_gen_def)
+apply(simp add: rfun_gen'_Lam[OF f, OF c])
+apply(simp add: rfun_gen_def)
+done
+
+instance nat :: pt_name
+apply(intro_classes)
+apply(simp_all add: perm_nat_def)
+done
+
+constdefs 
+  depth_Var :: "name \<Rightarrow> nat"
+  "depth_Var \<equiv> \<lambda>(a::name). 1"
+  
+  depth_App :: "nat \<Rightarrow> nat \<Rightarrow> nat"
+  "depth_App \<equiv> \<lambda>n1 n2. (max n1 n2)+1"
+
+  depth_Lam :: "name \<Rightarrow> nat \<Rightarrow> nat"
+  "depth_Lam \<equiv> \<lambda>(a::name) n. n+1"
+
+  depth_lam :: "lam \<Rightarrow> nat"
+  "depth_lam \<equiv> rfun depth_Var depth_App depth_Lam"
+
+lemma supp_depth_Var:
+  shows "((supp depth_Var)::name set)={}"
+  apply(simp add: depth_Var_def)
+  apply(simp add: supp_def)
+  apply(simp add: perm_fun_def)
+  apply(simp add: perm_nat_def)
+  done
+
+lemma supp_depth_App:
+  shows "((supp depth_App)::name set)={}"
+  apply(simp add: depth_App_def)
+  apply(simp add: supp_def)
+  apply(simp add: perm_fun_def)
+  apply(simp add: perm_nat_def)
+  done
+
+lemma supp_depth_Lam:
+  shows "((supp depth_Lam)::name set)={}"
+  apply(simp add: depth_Lam_def)
+  apply(simp add: supp_def)
+  apply(simp add: perm_fun_def)
+  apply(simp add: perm_nat_def)
+  done
+ 
+
+lemma fin_supp_depth:
+  shows "finite ((supp (depth_Var,depth_App,depth_Lam))::name set)"
+  using supp_depth_Var supp_depth_Lam supp_depth_App
+by (simp add: supp_prod)
+
+lemma fresh_depth_Lam:
+  shows "\<exists>(a::name). a\<sharp>depth_Lam \<and> (\<forall>n. a\<sharp>depth_Lam a n)"
+apply(rule exI)
+apply(rule conjI)
+apply(simp add: fresh_def supp_depth_Lam)
+apply(auto simp add: depth_Lam_def)
+apply(unfold fresh_def)
+apply(simp add: supp_def)
+apply(simp add: perm_nat_def)
+done
+
+lemma depth_Var:
+  shows "depth_lam (Var c) = 1"
+apply(simp add: depth_lam_def)
+apply(simp add: rfun_Var[OF fin_supp_depth, OF fresh_depth_Lam])
+apply(simp add: depth_Var_def)
+done
+
+lemma depth_App:
+  shows "depth_lam (App t1 t2) = (max (depth_lam t1) (depth_lam t2))+1"
+apply(simp add: depth_lam_def)
+apply(simp add: rfun_App[OF fin_supp_depth, OF fresh_depth_Lam])
+apply(simp add: depth_App_def)
+done
+
+lemma depth_Lam:
+  shows "depth_lam (Lam [a].t) = (depth_lam t)+1"
+apply(simp add: depth_lam_def)
+apply(rule trans)
+apply(rule rfun_Lam[OF fin_supp_depth, OF fresh_depth_Lam])
+apply(simp add: fresh_def supp_prod supp_depth_Var supp_depth_App supp_depth_Lam)
+apply(simp add: depth_Lam_def)
+done
+
+
+(* substitution *)
+
+constdefs 
+  subst_Var :: "name \<Rightarrow>lam \<Rightarrow> name \<Rightarrow> lam"
+  "subst_Var b t \<equiv> \<lambda>a. (if a=b then t else (Var a))"
+  
+  subst_App :: "name \<Rightarrow> lam \<Rightarrow> lam \<Rightarrow> lam \<Rightarrow> lam"
+  "subst_App b t \<equiv> \<lambda>r1 r2. App r1 r2"
+
+  subst_Lam :: "name \<Rightarrow> lam \<Rightarrow> name \<Rightarrow> lam \<Rightarrow> lam"
+  "subst_Lam b t \<equiv> \<lambda>a r. Lam [a].r"
+
+  subst_lam :: "name \<Rightarrow> lam \<Rightarrow> lam \<Rightarrow> lam"
+  "subst_lam b t \<equiv> rfun (subst_Var b t) (subst_App b t) (subst_Lam b t)"
+
+
+lemma supports_subst_Var:
+  shows "((supp (b,t))::name set) supports (subst_Var b t)"
+apply(supports_simp add: subst_Var_def)
+apply(rule impI)
+apply(drule pt_bij1[OF pt_name_inst, OF at_name_inst])
+apply(simp add: pt_fresh_fresh[OF pt_name_inst, OF at_name_inst])
+done
+
+lemma supports_subst_App:
+  shows "((supp (b,t))::name set) supports subst_App b t"
+by (supports_simp add: subst_App_def)
+
+lemma supports_subst_Lam:
+  shows "((supp (b,t))::name set) supports subst_Lam b t"
+  by (supports_simp add: subst_Lam_def)
+
+
+lemma fin_supp_subst:
+  shows "finite ((supp (subst_Var b t,subst_App b t,subst_Lam b t))::name set)"
+apply(auto simp add: supp_prod)
+apply(rule supports_finite)
+apply(rule supports_subst_Var)
+apply(simp add: fs_name1)
+apply(rule supports_finite)
+apply(rule supports_subst_App)
+apply(simp add: fs_name1)
+apply(rule supports_finite)
+apply(rule supports_subst_Lam)
+apply(simp add: fs_name1)
+done
+
+lemma fresh_subst_Lam:
+  shows "\<exists>(a::name). a\<sharp>(subst_Lam b t)\<and> (\<forall>y. a\<sharp>(subst_Lam b t) a y)"
+apply(subgoal_tac "\<exists>(c::name). c\<sharp>(b,t)")
+apply(auto)
+apply(rule_tac x="c" in exI)
+apply(auto)
+apply(rule supports_fresh)
+apply(rule supports_subst_Lam)
+apply(simp_all add: fresh_def[symmetric] fs_name1)
+apply(simp add: subst_Lam_def)
+apply(simp add: abs_fresh)
+apply(rule at_exists_fresh[OF at_name_inst])
+apply(simp add: fs_name1)
+done
+
+lemma subst_Var:
+  shows "subst_lam b t (Var a) = (if a=b then t else (Var a))"
+apply(simp add: subst_lam_def)
+apply(auto simp add: rfun_Var[OF fin_supp_subst, OF fresh_subst_Lam])
+apply(auto simp add: subst_Var_def)
+done
+
+lemma subst_App:
+  shows "subst_lam b t (App t1 t2) = App (subst_lam b t t1) (subst_lam b t t2)"
+apply(simp add: subst_lam_def)
+apply(auto simp add: rfun_App[OF fin_supp_subst, OF fresh_subst_Lam])
+apply(auto simp add: subst_App_def)
+done
+
+lemma subst_Lam:
+  assumes a: "a\<sharp>(b,t)"
+  shows "subst_lam b t (Lam [a].t1) = Lam [a].(subst_lam b t t1)"
+using a
+apply(simp add: subst_lam_def)
+apply(subgoal_tac "a\<sharp>(subst_Var b t,subst_App b t,subst_Lam b t)")
+apply(auto simp add: rfun_Lam[OF fin_supp_subst, OF fresh_subst_Lam])
+apply(simp (no_asm) add: subst_Lam_def)
+apply(auto simp add: fresh_prod)
+apply(rule supports_fresh)
+apply(rule supports_subst_Var)
+apply(simp_all add: fs_name1 fresh_def[symmetric] fresh_prod)
+apply(rule supports_fresh)
+apply(rule supports_subst_App)
+apply(simp_all add: fs_name1 fresh_def[symmetric] fresh_prod)
+apply(rule supports_fresh)
+apply(rule supports_subst_Lam)
+apply(simp_all add: fs_name1 fresh_def[symmetric] fresh_prod)
+done
+
+lemma subst_Lam':
+  assumes a: "a\<noteq>b"
+  and     b: "a\<sharp>t"
+  shows "subst_lam b t (Lam [a].t1) = Lam [a].(subst_lam b t t1)"
+apply(rule subst_Lam)
+apply(simp add: fresh_prod a b fresh_atm)
+done
+
+consts
+  subst_syn  :: "lam \<Rightarrow> name \<Rightarrow> lam \<Rightarrow> lam" ("_[_::=_]" [100,100,100] 900)
+translations 
+  "t1[a::=t2]" \<rightleftharpoons> "subst_lam a t2 t1"
+
+declare subst_Var[simp]
+declare subst_App[simp]
+declare subst_Lam[simp]
+declare subst_Lam'[simp]
+
+lemma subst_eqvt[simp]:
+  fixes pi:: "name prm"
+  and   t1:: "lam"
+  and   t2:: "lam"
+  and   a :: "name"
+  shows "pi\<bullet>(t1[a::=t2]) = (pi\<bullet>t1)[(pi\<bullet>a)::=(pi\<bullet>t2)]"
+apply(nominal_induct t1 rule: lam_induct)
+apply(auto)
+apply(auto simp add: perm_bij fresh_prod fresh_atm)
+apply(subgoal_tac "(aa\<bullet>ab)\<sharp>(aa\<bullet>a,aa\<bullet>b)")(*A*)
+apply(simp) 
+apply(simp add: perm_bij fresh_prod fresh_atm pt_fresh_bij[OF pt_name_inst, OF at_name_inst]) 
+done
+
+lemma subst_supp: "supp(t1[a::=t2])\<subseteq>(((supp(t1)-{a})\<union>supp(t2))::name set)"
+apply(nominal_induct t1 rule: lam_induct)
+apply(auto simp add: lam.supp supp_atm fresh_prod abs_supp)
+apply(blast)
+apply(blast)
+done
+
+(* parallel substitution *)
+
+
+consts
+  "dom_sss" :: "(name\<times>lam) list \<Rightarrow> (name list)"
+primrec
+  "dom_sss []    = []"
+  "dom_sss (x#\<theta>) = (fst x)#(dom_sss \<theta>)" 
+
+consts
+  "apply_sss"  :: "(name\<times>lam) list \<Rightarrow> name \<Rightarrow> lam" (" _ < _ >" [80,80] 80)
+primrec  
+"(x#\<theta>)<a>  = (if (a = fst x) then (snd x) else \<theta><a>)" 
+
+
+lemma apply_sss_eqvt[rule_format]:
+  fixes pi::"name prm"
+  shows "a\<in>set (dom_sss \<theta>) \<longrightarrow> pi\<bullet>(\<theta><a>) = (pi\<bullet>\<theta>)<pi\<bullet>a>"
+apply(induct_tac \<theta>)
+apply(auto)
+apply(simp add: pt_bij[OF pt_name_inst, OF at_name_inst])
+done
+
+lemma dom_sss_eqvt[rule_format]:
+  fixes pi::"name prm"
+  shows "((pi\<bullet>a)\<in>set (dom_sss \<theta>)) =  (a\<in>set (dom_sss ((rev pi)\<bullet>\<theta>)))"
+apply(induct_tac \<theta>)
+apply(auto)
+apply(simp_all add: pt_rev_pi[OF pt_name_inst, OF at_name_inst])
+apply(simp_all add: pt_pi_rev[OF pt_name_inst, OF at_name_inst])
+done
+
+constdefs 
+  psubst_Var :: "(name\<times>lam) list \<Rightarrow> name \<Rightarrow> lam"
+  "psubst_Var \<theta> \<equiv> \<lambda>a. (if a\<in>set (dom_sss \<theta>) then \<theta><a> else (Var a))"
+  
+  psubst_App :: "(name\<times>lam) list \<Rightarrow> lam \<Rightarrow> lam \<Rightarrow> lam"
+  "psubst_App \<theta> \<equiv> \<lambda>r1 r2. App r1 r2"
+
+  psubst_Lam :: "(name\<times>lam) list \<Rightarrow> name \<Rightarrow> lam \<Rightarrow> lam"
+  "psubst_Lam \<theta> \<equiv> \<lambda>a r. Lam [a].r"
+
+  psubst_lam :: "(name\<times>lam) list \<Rightarrow> lam \<Rightarrow> lam"
+  "psubst_lam \<theta> \<equiv> rfun (psubst_Var \<theta>) (psubst_App \<theta>) (psubst_Lam \<theta>)"
+
+lemma supports_psubst_Var:
+  shows "((supp \<theta>)::name set) supports (psubst_Var \<theta>)"
+  by (supports_simp add: psubst_Var_def apply_sss_eqvt dom_sss_eqvt)
+
+lemma supports_psubst_App:
+  shows "((supp \<theta>)::name set) supports psubst_App \<theta>"
+  by (supports_simp add: psubst_App_def)
+
+lemma supports_psubst_Lam:
+  shows "((supp \<theta>)::name set) supports psubst_Lam \<theta>"
+  by (supports_simp add: psubst_Lam_def)
+
+lemma fin_supp_psubst:
+  shows "finite ((supp (psubst_Var \<theta>,psubst_App \<theta>,psubst_Lam \<theta>))::name set)"
+apply(auto simp add: supp_prod)
+apply(rule supports_finite)
+apply(rule supports_psubst_Var)
+apply(simp add: fs_name1)
+apply(rule supports_finite)
+apply(rule supports_psubst_App)
+apply(simp add: fs_name1)
+apply(rule supports_finite)
+apply(rule supports_psubst_Lam)
+apply(simp add: fs_name1)
+done
+
+lemma fresh_psubst_Lam:
+  shows "\<exists>(a::name). a\<sharp>(psubst_Lam \<theta>)\<and> (\<forall>y. a\<sharp>(psubst_Lam \<theta>) a y)"
+apply(subgoal_tac "\<exists>(c::name). c\<sharp>\<theta>")
+apply(auto)
+apply(rule_tac x="c" in exI)
+apply(auto)
+apply(rule supports_fresh)
+apply(rule supports_psubst_Lam)
+apply(simp_all add: fresh_def[symmetric] fs_name1)
+apply(simp add: psubst_Lam_def)
+apply(simp add: abs_fresh)
+apply(rule at_exists_fresh[OF at_name_inst])
+apply(simp add: fs_name1)
+done
+
+lemma psubst_Var:
+  shows "psubst_lam \<theta> (Var a) = (if a\<in>set (dom_sss \<theta>) then \<theta><a> else (Var a))"
+apply(simp add: psubst_lam_def)
+apply(auto simp add: rfun_Var[OF fin_supp_psubst, OF fresh_psubst_Lam])
+apply(auto simp add: psubst_Var_def)
+done
+
+lemma psubst_App:
+  shows "psubst_lam \<theta> (App t1 t2) = App (psubst_lam \<theta> t1) (psubst_lam \<theta> t2)"
+apply(simp add: psubst_lam_def)
+apply(auto simp add: rfun_App[OF fin_supp_psubst, OF fresh_psubst_Lam])
+apply(auto simp add: psubst_App_def)
+done
+
+lemma psubst_Lam:
+  assumes a: "a\<sharp>\<theta>"
+  shows "psubst_lam \<theta> (Lam [a].t1) = Lam [a].(psubst_lam \<theta> t1)"
+using a
+apply(simp add: psubst_lam_def)
+apply(subgoal_tac "a\<sharp>(psubst_Var \<theta>,psubst_App \<theta>,psubst_Lam \<theta>)")
+apply(auto simp add: rfun_Lam[OF fin_supp_psubst, OF fresh_psubst_Lam])
+apply(simp (no_asm) add: psubst_Lam_def)
+apply(auto simp add: fresh_prod)
+apply(rule supports_fresh)
+apply(rule supports_psubst_Var)
+apply(simp_all add: fs_name1 fresh_def[symmetric] fresh_prod)
+apply(rule supports_fresh)
+apply(rule supports_psubst_App)
+apply(simp_all add: fs_name1 fresh_def[symmetric] fresh_prod)
+apply(rule supports_fresh)
+apply(rule supports_psubst_Lam)
+apply(simp_all add: fs_name1 fresh_def[symmetric] fresh_prod)
+done
+
+declare psubst_Var[simp]
+declare psubst_App[simp]
+declare psubst_Lam[simp]
+
+consts
+  psubst_syn  :: "lam \<Rightarrow> (name\<times>lam) list \<Rightarrow> lam" ("_[<_>]" [100,100] 900)
+translations 
+  "t[<\<theta>>]" \<rightleftharpoons> "psubst_lam \<theta> t"
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Nominal/Examples/Lambda_mu.thy	Mon Nov 07 15:19:03 2005 +0100
@@ -0,0 +1,122 @@
+
+theory lambda_mu 
+imports "../nominal" 
+begin
+
+section {* Mu-Calculus from Gavin's cilmu-Paper*}
+
+atom_decl var mvar
+
+nominal_datatype trm = Var   "var" 
+                     | Lam  "\<guillemotleft>var\<guillemotright>trm"   ("Lam [_]._" [100,100] 100)
+                     | App  "trm" "trm" 
+                     | Pss  "mvar" "trm"
+                     | Act  "\<guillemotleft>mvar\<guillemotright>trm"  ("Act [_]._" [100,100] 100)
+
+section {* strong induction principle *}
+
+lemma trm_induct_aux:
+  fixes P :: "trm \<Rightarrow> 'a \<Rightarrow> bool"
+  and   f1 :: "'a \<Rightarrow> var set"
+  and   f2 :: "'a \<Rightarrow> mvar set"
+  assumes fs1: "\<And>x. finite (f1 x)"
+      and fs2: "\<And>x. finite (f2 x)"
+      and h1: "\<And>k x. P (Var x) k"  
+      and h2: "\<And>k x t. x\<notin>f1 k \<Longrightarrow> (\<forall>l. P t l) \<Longrightarrow> P (Lam [x].t) k" 
+      and h3: "\<And>k t1 t2. (\<forall>l. P t1 l) \<Longrightarrow> (\<forall>l. P t2 l) \<Longrightarrow> P (App t1 t2) k" 
+      and h4: "\<And>k a t1. (\<forall>l. P t1 l) \<Longrightarrow> P (Pss a t1) k" 
+      and h5: "\<And>k a t1. a\<notin>f2 k \<Longrightarrow> (\<forall>l. P t1 l) \<Longrightarrow> P (Act [a].t1) k"
+  shows "\<forall>(pi1::var prm) (pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t)) k"
+proof (induct rule: trm.induct_weak)
+  case (goal1 a)
+  show ?case using h1 by simp
+next
+  case (goal2 x t)
+  assume i1: "\<forall>(pi1::var prm)(pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t)) k" 
+  show ?case
+  proof (intro strip, simp add: abs_perm)
+    fix pi1::"var prm" and pi2::"mvar prm" and k::"'a"
+    have f: "\<exists>c::var. c\<sharp>(f1 k,pi1\<bullet>(pi2\<bullet>x),pi1\<bullet>(pi2\<bullet>t))"
+      by (rule at_exists_fresh[OF at_var_inst], simp add: supp_prod fs_var1 
+          at_fin_set_supp[OF at_var_inst, OF fs1] fs1)
+    then obtain c::"var" 
+      where f1: "c\<noteq>(pi1\<bullet>(pi2\<bullet>x))" and f2: "c\<sharp>(f1 k)" and f3: "c\<sharp>(pi1\<bullet>(pi2\<bullet>t))" 
+      by (force simp add: fresh_prod at_fresh[OF at_var_inst])
+    have g: "Lam [c].([(c,pi1\<bullet>(pi2\<bullet>x))]\<bullet>(pi1\<bullet>(pi2\<bullet>t))) = Lam [(pi1\<bullet>(pi2\<bullet>x))].(pi1\<bullet>(pi2\<bullet>t))" using f1 f3
+      by (simp add: trm.inject alpha)
+    from i1 have "\<forall>k. P (([(c,pi1\<bullet>(pi2\<bullet>x))]@pi1)\<bullet>(pi2\<bullet>t)) k" by force
+    hence i1b: "\<forall>k. P ([(c,pi1\<bullet>(pi2\<bullet>x))]\<bullet>(pi1\<bullet>(pi2\<bullet>t))) k" by (simp add: pt_var2[symmetric])
+    with h3 f2 have "P (Lam [c].([(c,pi1\<bullet>(pi2\<bullet>x))]\<bullet>(pi1\<bullet>(pi2\<bullet>t)))) k" 
+      by (auto simp add: fresh_def at_fin_set_supp[OF at_var_inst, OF fs1])
+    with g show "P (Lam [(pi1\<bullet>(pi2\<bullet>x))].(pi1\<bullet>(pi2\<bullet>t))) k" by simp 
+  qed
+next 
+  case (goal3 t1 t2)
+  assume i1: "\<forall>(pi1::var prm)(pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t1)) k" 
+  assume i2: "\<forall>(pi1::var prm)(pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t2)) k"
+  show ?case 
+  proof (intro strip)
+    fix pi1::"var prm" and pi2::"mvar prm" and k::"'a"
+    from h3 i1 i2 have "P (App (pi1\<bullet>(pi2\<bullet>t1)) (pi1\<bullet>(pi2\<bullet>t2))) k" by force
+    thus "P (pi1\<bullet>(pi2\<bullet>(App t1 t2))) k" by simp
+  qed
+next
+  case (goal4 b t)
+  assume i1: "\<forall>(pi1::var prm)(pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t)) k" 
+  show ?case 
+  proof (intro strip)
+    fix pi1::"var prm" and pi2::"mvar prm" and k::"'a"
+    from h4 i1 have "P (Pss (pi1\<bullet>(pi2\<bullet>b)) (pi1\<bullet>(pi2\<bullet>t))) k" by force
+    thus "P (pi1\<bullet>(pi2\<bullet>(Pss b t))) k" by simp
+  qed
+next
+  case (goal5 b t)
+  assume i1: "\<forall>(pi1::var prm)(pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t)) k" 
+  show ?case
+  proof (intro strip, simp add: abs_perm)
+    fix pi1::"var prm" and pi2::"mvar prm" and k::"'a"
+    have f: "\<exists>c::mvar. c\<sharp>(f2 k,pi1\<bullet>(pi2\<bullet>b),pi1\<bullet>(pi2\<bullet>t))"
+      by (rule at_exists_fresh[OF at_mvar_inst], simp add: supp_prod fs_mvar1 
+          at_fin_set_supp[OF at_mvar_inst, OF fs2] fs2)
+    then obtain c::"mvar" 
+      where f1: "c\<noteq>(pi1\<bullet>(pi2\<bullet>b))" and f2: "c\<sharp>(f2 k)" and f3: "c\<sharp>(pi1\<bullet>(pi2\<bullet>t))" 
+      by (force simp add: fresh_prod at_fresh[OF at_mvar_inst])
+    have g: "Act [c].(pi1\<bullet>([(c,pi1\<bullet>(pi2\<bullet>b))]\<bullet>(pi2\<bullet>t))) = Act [(pi1\<bullet>(pi2\<bullet>b))].(pi1\<bullet>(pi2\<bullet>t))" using f1 f3
+      by (simp add: trm.inject alpha, simp add: dj_cp[OF cp_mvar_var_inst, OF dj_var_mvar])
+    from i1 have "\<forall>k. P (pi1\<bullet>(([(c,pi1\<bullet>(pi2\<bullet>b))]@pi2)\<bullet>t)) k" by force
+    hence i1b: "\<forall>k. P (pi1\<bullet>([(c,pi1\<bullet>(pi2\<bullet>b))]\<bullet>(pi2\<bullet>t))) k" by (simp add: pt_mvar2[symmetric])
+    with h5 f2 have "P (Act [c].(pi1\<bullet>([(c,pi1\<bullet>(pi2\<bullet>b))]\<bullet>(pi2\<bullet>t)))) k" 
+      by (auto simp add: fresh_def at_fin_set_supp[OF at_mvar_inst, OF fs2])
+    with g show "P (Act [(pi1\<bullet>(pi2\<bullet>b))].(pi1\<bullet>(pi2\<bullet>t))) k" by simp 
+  qed
+qed
+
+lemma trm_induct'[case_names Var Lam App Pss Act]:
+  fixes P :: "trm \<Rightarrow> 'a \<Rightarrow> bool"
+  and   f1 :: "'a \<Rightarrow> var set"
+  and   f2 :: "'a \<Rightarrow> mvar set"
+  assumes fs1: "\<And>x. finite (f1 x)"
+      and fs2: "\<And>x. finite (f2 x)"
+      and h1: "\<And>k x. P (Var x) k"  
+      and h2: "\<And>k x t. x\<notin>f1 k \<Longrightarrow> (\<forall>l. P t l) \<Longrightarrow> P (Lam [x].t) k" 
+      and h3: "\<And>k t1 t2. (\<forall>l. P t1 l) \<Longrightarrow> (\<forall>l. P t2 l) \<Longrightarrow> P (App t1 t2) k" 
+      and h4: "\<And>k a t1. (\<forall>l. P t1 l) \<Longrightarrow> P (Pss a t1) k" 
+      and h5: "\<And>k a t1. a\<notin>f2 k \<Longrightarrow> (\<forall>l. P t1 l) \<Longrightarrow> P (Act [a].t1) k"
+  shows "P t k"
+proof -
+  have "\<forall>(pi1::var prm)(pi2::mvar prm) k. P (pi1\<bullet>(pi2\<bullet>t)) k"
+  using fs1 fs2 h1 h2 h3 h4 h5 by (rule trm_induct_aux, auto)
+  hence "P (([]::var prm)\<bullet>(([]::mvar prm)\<bullet>t)) k" by blast
+  thus "P t k" by simp
+qed
+
+lemma trm_induct[case_names Var Lam App Pss Act]: 
+  fixes P :: "trm \<Rightarrow> ('a::{fs_var,fs_mvar}) \<Rightarrow> bool"
+  assumes h1: "\<And>k x. P (Var x) k"  
+      and h2: "\<And>k x t. x\<sharp>k \<Longrightarrow> (\<forall>l. P t l) \<Longrightarrow> P (Lam [x].t) k" 
+      and h3: "\<And>k t1 t2. (\<forall>l. P t1 l) \<Longrightarrow> (\<forall>l. P t2 l) \<Longrightarrow> P (App t1 t2) k" 
+      and h4: "\<And>k a t1. (\<forall>l. P t1 l) \<Longrightarrow> P (Pss a t1) k" 
+      and h5: "\<And>k a t1. a\<sharp>k \<Longrightarrow> (\<forall>l. P t1 l) \<Longrightarrow> P (Act [a].t1) k"
+  shows  "P t k"
+by (rule trm_induct'[of "\<lambda>x. ((supp x)::var set)" "\<lambda>x. ((supp x)::mvar set)" "P"], 
+    simp_all add: fs_var1 fs_mvar1 fresh_def[symmetric], auto intro: h1 h2 h3 h4 h5)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Nominal/Examples/SN.thy	Mon Nov 07 15:19:03 2005 +0100
@@ -0,0 +1,902 @@
+
+theory sn
+imports lam_substs  Accessible_Part
+begin
+
+(* Strong normalisation according to the P&T book by Girard et al *)
+
+section {* Beta Reduction *}
+
+lemma subst_rename[rule_format]: 
+  fixes  c  :: "name"
+  and    a  :: "name"
+  and    t1 :: "lam"
+  and    t2 :: "lam"
+  shows "c\<sharp>t1 \<longrightarrow> (t1[a::=t2] = ([(c,a)]\<bullet>t1)[c::=t2])"
+apply(nominal_induct t1 rule: lam_induct)
+apply(auto simp add: calc_atm fresh_atm fresh_prod abs_fresh)
+done
+
+lemma forget[rule_format]: 
+  shows "a\<sharp>t1 \<longrightarrow> t1[a::=t2] = t1"
+apply (nominal_induct t1 rule: lam_induct)
+apply(auto simp add: abs_fresh fresh_atm fresh_prod)
+done
+
+lemma fresh_fact[rule_format]: 
+  fixes   b :: "name"
+  and    a  :: "name"
+  and    t1 :: "lam"
+  and    t2 :: "lam" 
+  shows "a\<sharp>t1\<longrightarrow>a\<sharp>t2\<longrightarrow>a\<sharp>(t1[b::=t2])"
+apply(nominal_induct t1 rule: lam_induct)
+apply(auto simp add: abs_fresh fresh_prod fresh_atm)
+done
+
+lemma subs_lemma:  
+  fixes x::"name"
+  and   y::"name"
+  and   L::"lam"
+  and   M::"lam"
+  and   N::"lam"
+  shows "x\<noteq>y\<longrightarrow>x\<sharp>L\<longrightarrow>M[x::=N][y::=L] = M[y::=L][x::=N[y::=L]]"
+apply(nominal_induct M rule: lam_induct)
+apply(auto simp add: fresh_fact forget fresh_prod fresh_atm)
+done
+
+lemma id_subs: "t[x::=Var x] = t"
+apply(nominal_induct t rule: lam_induct)
+apply(simp_all add: fresh_atm)
+done
+
+consts
+  Beta :: "(lam\<times>lam) set"
+syntax 
+  "_Beta"       :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<longrightarrow>\<^isub>\<beta> _" [80,80] 80)
+  "_Beta_star"  :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<longrightarrow>\<^isub>\<beta>\<^sup>* _" [80,80] 80)
+translations 
+  "t1 \<longrightarrow>\<^isub>\<beta> t2" \<rightleftharpoons> "(t1,t2) \<in> Beta"
+  "t1 \<longrightarrow>\<^isub>\<beta>\<^sup>* t2" \<rightleftharpoons> "(t1,t2) \<in> Beta\<^sup>*"
+inductive Beta
+  intros
+  b1[intro!]: "s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (App s1 t)\<longrightarrow>\<^isub>\<beta>(App s2 t)"
+  b2[intro!]: "s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (App t s1)\<longrightarrow>\<^isub>\<beta>(App t s2)"
+  b3[intro!]: "s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (Lam [a].s1)\<longrightarrow>\<^isub>\<beta> (Lam [(a::name)].s2)"
+  b4[intro!]: "(App (Lam [(a::name)].s1) s2)\<longrightarrow>\<^isub>\<beta>(s1[a::=s2])"
+
+lemma eqvt_beta: 
+  fixes pi :: "name prm"
+  and   t  :: "lam"
+  and   s  :: "lam"
+  shows "t\<longrightarrow>\<^isub>\<beta>s \<Longrightarrow> (pi\<bullet>t)\<longrightarrow>\<^isub>\<beta>(pi\<bullet>s)"
+  apply(erule Beta.induct)
+  apply(auto)
+  done
+
+lemma beta_induct_aux[rule_format]:
+  fixes  P :: "lam \<Rightarrow> lam \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    t :: "lam"
+  and    s :: "lam"
+  assumes a: "t\<longrightarrow>\<^isub>\<beta>s"
+  and a1:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App s1 t) (App s2 t) x"
+  and a2:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App t s1) (App t s2) x"
+  and a3:    "\<And>x (a::name) s1 s2. 
+              a\<sharp>x \<Longrightarrow> s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (Lam [a].s1) (Lam [a].s2) x"
+  and a4:    "\<And>x (a::name) t1 s1. a\<sharp>(s1,x) \<Longrightarrow> P (App (Lam [a].t1) s1) (t1[a::=s1]) x"
+  shows "\<forall>x (pi::name prm). P (pi\<bullet>t) (pi\<bullet>s) x"
+using a
+proof (induct)
+  case b1 thus ?case using a1 by (simp, blast intro: eqvt_beta)
+next
+  case b2 thus ?case using a2 by (simp, blast intro: eqvt_beta)
+next
+  case (b3 a s1 s2)
+  assume j1: "s1 \<longrightarrow>\<^isub>\<beta> s2"
+  assume j2: "\<forall>x (pi::name prm). P (pi\<bullet>s1) (pi\<bullet>s2) x"
+  show ?case 
+  proof (simp, intro strip)
+    fix pi::"name prm" and x::"'a::fs_name"
+     have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>s1,pi\<bullet>s2,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>x" and f3: "c\<sharp>(pi\<bullet>s1)" and f4: "c\<sharp>(pi\<bullet>s2)"
+      by (force simp add: fresh_prod fresh_atm)
+    have x: "P (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>s1)) (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>s2)) x"
+      using a3 f2 j1 j2 by (simp, blast intro: eqvt_beta)
+    have alpha1: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>s1))) = (Lam [(pi\<bullet>a)].(pi\<bullet>s1))" using f1 f3
+      by (simp add: lam.inject alpha)
+    have alpha2: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>s2))) = (Lam [(pi\<bullet>a)].(pi\<bullet>s2))" using f1 f3
+      by (simp add: lam.inject alpha)
+    show " P (Lam [(pi\<bullet>a)].(pi\<bullet>s1)) (Lam [(pi\<bullet>a)].(pi\<bullet>s2)) x"
+      using x alpha1 alpha2 by (simp only: pt_name2)
+  qed
+next
+  case (b4 a s1 s2)
+  show ?case
+  proof (simp add: subst_eqvt, intro strip)
+    fix pi::"name prm" and x::"'a::fs_name" 
+    have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>s1,pi\<bullet>s2,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>(pi\<bullet>s2,x)" and f3: "c\<sharp>(pi\<bullet>s1)" and f4: "c\<sharp>(pi\<bullet>s2)"
+      by (force simp add: fresh_prod fresh_atm)
+    have x: "P (App (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>s1)) (pi\<bullet>s2)) ((([(c,pi\<bullet>a)]@pi)\<bullet>s1)[c::=(pi\<bullet>s2)]) x"
+      using a4 f2 by (blast intro!: eqvt_beta)
+    have alpha1: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>s1))) = (Lam [(pi\<bullet>a)].(pi\<bullet>s1))" using f1 f3
+      by (simp add: lam.inject alpha)
+    have alpha2: "(([(c,pi\<bullet>a)]@pi)\<bullet>s1)[c::=(pi\<bullet>s2)] = (pi\<bullet>s1)[(pi\<bullet>a)::=(pi\<bullet>s2)]"
+      using f3 by (simp only: subst_rename[symmetric] pt_name2)
+    show "P (App (Lam [(pi\<bullet>a)].(pi\<bullet>s1)) (pi\<bullet>s2)) ((pi\<bullet>s1)[(pi\<bullet>a)::=(pi\<bullet>s2)]) x"
+      using x alpha1 alpha2 by (simp only: pt_name2)
+  qed
+qed
+
+lemma beta_induct[case_names b1 b2 b3 b4]:
+  fixes  P :: "lam \<Rightarrow> lam \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    t :: "lam"
+  and    s :: "lam"
+  and    x :: "'a::fs_name"
+  assumes a: "t\<longrightarrow>\<^isub>\<beta>s"
+  and a1:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App s1 t) (App s2 t) x"
+  and a2:    "\<And>x t s1 s2. 
+              s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (App t s1) (App t s2) x"
+  and a3:    "\<And>x (a::name) s1 s2. 
+              a\<sharp>x \<Longrightarrow> s1\<longrightarrow>\<^isub>\<beta>s2 \<Longrightarrow> (\<forall>z. P s1 s2 z) \<Longrightarrow> P (Lam [a].s1) (Lam [a].s2) x"
+  and a4:    "\<And>x (a::name) t1 s1. 
+              a\<sharp>(s1,x) \<Longrightarrow> P (App (Lam [a].t1) s1) (t1[a::=s1]) x"
+  shows "P t s x"
+using a a1 a2 a3 a4
+by (auto intro!: beta_induct_aux[of "t" "s" "P" "[]" "x", simplified])
+
+lemma supp_beta: "t\<longrightarrow>\<^isub>\<beta> s\<Longrightarrow>(supp s)\<subseteq>((supp t)::name set)"
+apply(erule Beta.induct)
+apply(auto intro!: simp add: abs_supp lam.supp subst_supp)
+done
+lemma beta_abs: "Lam [a].t\<longrightarrow>\<^isub>\<beta> t'\<Longrightarrow>\<exists>t''. t'=Lam [a].t'' \<and> t\<longrightarrow>\<^isub>\<beta> t''"
+apply(ind_cases "Lam [a].t  \<longrightarrow>\<^isub>\<beta> t'")
+apply(auto simp add: lam.distinct lam.inject)
+apply(auto simp add: alpha)
+apply(rule_tac x="[(a,aa)]\<bullet>s2" in exI)
+apply(rule conjI)
+apply(rule sym)
+apply(rule pt_bij2[OF pt_name_inst, OF at_name_inst])
+apply(simp)
+apply(rule pt_name3)
+apply(simp add: at_ds5[OF at_name_inst])
+apply(rule conjI)
+apply(simp add: pt_fresh_left[OF pt_name_inst, OF at_name_inst] calc_atm)
+apply(force dest!: supp_beta simp add: fresh_def)
+apply(force intro!: eqvt_beta)
+done
+
+lemma beta_subst[rule_format]: 
+  assumes a: "M \<longrightarrow>\<^isub>\<beta> M'"
+  shows "M[x::=N]\<longrightarrow>\<^isub>\<beta> M'[x::=N]" 
+using a
+apply(nominal_induct M M' rule: beta_induct)
+apply(auto simp add: fresh_prod fresh_atm subs_lemma)
+done
+
+instance nat :: fs_name
+apply(intro_classes)   
+apply(simp_all add: supp_def perm_nat_def)
+done
+
+datatype ty =
+    TVar "string"
+  | TArr "ty" "ty" (infix "\<rightarrow>" 200)
+
+primrec
+ "pi\<bullet>(TVar s) = TVar s"
+ "pi\<bullet>(\<tau> \<rightarrow> \<sigma>) = (\<tau> \<rightarrow> \<sigma>)"
+
+lemma perm_ty[simp]:
+  fixes pi ::"name prm"
+  and   \<tau>  ::"ty"
+  shows "pi\<bullet>\<tau> = \<tau>"
+  by (cases \<tau>, simp_all)
+
+lemma fresh_ty:
+  fixes a ::"name"
+  and   \<tau>  ::"ty"
+  shows "a\<sharp>\<tau>"
+  by (simp add: fresh_def supp_def)
+
+instance ty :: pt_name
+apply(intro_classes)   
+apply(simp_all)
+done
+
+instance ty :: fs_name
+apply(intro_classes)
+apply(simp add: supp_def)
+done
+
+(* valid contexts *)
+
+consts
+  "dom_ty" :: "(name\<times>ty) list \<Rightarrow> (name list)"
+primrec
+  "dom_ty []    = []"
+  "dom_ty (x#\<Gamma>) = (fst x)#(dom_ty \<Gamma>)" 
+
+consts
+  ctxts :: "((name\<times>ty) list) set" 
+  valid :: "(name\<times>ty) list \<Rightarrow> bool"
+translations
+  "valid \<Gamma>" \<rightleftharpoons> "\<Gamma> \<in> ctxts"  
+inductive ctxts
+intros
+v1[intro]: "valid []"
+v2[intro]: "\<lbrakk>valid \<Gamma>;a\<sharp>\<Gamma>\<rbrakk>\<Longrightarrow> valid ((a,\<sigma>)#\<Gamma>)"
+
+lemma valid_eqvt:
+  fixes   pi:: "name prm"
+  assumes a: "valid \<Gamma>"
+  shows   "valid (pi\<bullet>\<Gamma>)"
+using a
+apply(induct)
+apply(auto simp add: pt_fresh_bij[OF pt_name_inst, OF at_name_inst])
+done
+
+(* typing judgements *)
+
+lemma fresh_context[rule_format]: 
+  fixes  \<Gamma> :: "(name\<times>ty)list"
+  and    a :: "name"
+  shows "a\<sharp>\<Gamma>\<longrightarrow>\<not>(\<exists>\<tau>::ty. (a,\<tau>)\<in>set \<Gamma>)"
+apply(induct_tac \<Gamma>)
+apply(auto simp add: fresh_prod fresh_list_cons fresh_atm)
+done
+
+lemma valid_elim: 
+  fixes  \<Gamma> :: "(name\<times>ty)list"
+  and    pi:: "name prm"
+  and    a :: "name"
+  and    \<tau> :: "ty"
+  shows "valid ((a,\<tau>)#\<Gamma>) \<Longrightarrow> valid \<Gamma> \<and> a\<sharp>\<Gamma>"
+apply(ind_cases "valid ((a,\<tau>)#\<Gamma>)", simp)
+done
+
+lemma valid_unicity[rule_format]: 
+  shows "valid \<Gamma>\<longrightarrow>(c,\<sigma>)\<in>set \<Gamma>\<longrightarrow>(c,\<tau>)\<in>set \<Gamma>\<longrightarrow>\<sigma>=\<tau>" 
+apply(induct_tac \<Gamma>)
+apply(auto dest!: valid_elim fresh_context)
+done
+
+consts
+  typing :: "(((name\<times>ty) list)\<times>lam\<times>ty) set" 
+syntax
+  "_typing_judge" :: "(name\<times>ty) list\<Rightarrow>lam\<Rightarrow>ty\<Rightarrow>bool" (" _ \<turnstile> _ : _ " [80,80,80] 80) 
+translations
+  "\<Gamma> \<turnstile> t : \<tau>" \<rightleftharpoons> "(\<Gamma>,t,\<tau>) \<in> typing"  
+
+inductive typing
+intros
+t1[intro]: "\<lbrakk>valid \<Gamma>; (a,\<tau>)\<in>set \<Gamma>\<rbrakk>\<Longrightarrow> \<Gamma> \<turnstile> Var a : \<tau>"
+t2[intro]: "\<lbrakk>\<Gamma> \<turnstile> t1 : \<tau>\<rightarrow>\<sigma>; \<Gamma> \<turnstile> t2 : \<tau>\<rbrakk>\<Longrightarrow> \<Gamma> \<turnstile> App t1 t2 : \<sigma>"
+t3[intro]: "\<lbrakk>a\<sharp>\<Gamma>;((a,\<tau>)#\<Gamma>) \<turnstile> t : \<sigma>\<rbrakk> \<Longrightarrow> \<Gamma> \<turnstile> Lam [a].t : \<tau>\<rightarrow>\<sigma>"
+
+lemma typing_eqvt: 
+  fixes  \<Gamma> :: "(name\<times>ty) list"
+  and    t :: "lam"
+  and    \<tau> :: "ty"
+  and    pi:: "name prm"
+  assumes a: "\<Gamma> \<turnstile> t : \<tau>"
+  shows "(pi\<bullet>\<Gamma>) \<turnstile> (pi\<bullet>t) : \<tau>"
+using a
+proof (induct)
+  case (t1 \<Gamma> \<tau> a)
+  have "valid (pi\<bullet>\<Gamma>)" by (rule valid_eqvt)
+  moreover
+  have "(pi\<bullet>(a,\<tau>))\<in>((pi::name prm)\<bullet>set \<Gamma>)" by (rule pt_set_bij2[OF pt_name_inst, OF at_name_inst])
+  ultimately show "(pi\<bullet>\<Gamma>) \<turnstile> (pi\<bullet>Var a) : \<tau>"
+    using typing.intros by (auto simp add: pt_list_set_pi[OF pt_name_inst])
+next 
+  case (t3 \<Gamma> \<sigma> \<tau> a t)
+  moreover have "(pi\<bullet>a)\<sharp>(pi\<bullet>\<Gamma>)" by (rule pt_fresh_bij1[OF pt_name_inst, OF at_name_inst])
+  ultimately show "(pi\<bullet>\<Gamma>) \<turnstile> (pi\<bullet>Lam [a].t) : \<tau>\<rightarrow>\<sigma>" 
+    using typing.intros by (force)
+qed (auto)
+
+lemma typing_induct_aux[rule_format]:
+  fixes  P :: "(name\<times>ty) list \<Rightarrow> lam \<Rightarrow> ty \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    \<Gamma> :: "(name\<times>ty) list"
+  and    t :: "lam"
+  and    \<tau> :: "ty"
+  assumes a: "\<Gamma> \<turnstile> t : \<tau>"
+  and a1:    "\<And>x \<Gamma> (a::name) \<tau>. valid \<Gamma> \<Longrightarrow> (a,\<tau>) \<in> set \<Gamma> \<Longrightarrow> P \<Gamma> (Var a) \<tau> x"
+  and a2:    "\<And>x \<Gamma> \<tau> \<sigma> t1 t2. 
+              \<Gamma> \<turnstile> t1 : \<tau>\<rightarrow>\<sigma> \<Longrightarrow> (\<And>z. P \<Gamma> t1 (\<tau>\<rightarrow>\<sigma>) z) \<Longrightarrow> \<Gamma> \<turnstile> t2 : \<tau> \<Longrightarrow> (\<And>z. P \<Gamma> t2 \<tau> z)
+              \<Longrightarrow> P \<Gamma> (App t1 t2) \<sigma> x"
+  and a3:    "\<And>x (a::name) \<Gamma> \<tau> \<sigma> t. 
+              a\<sharp>x \<Longrightarrow> a\<sharp>\<Gamma> \<Longrightarrow> ((a,\<tau>) # \<Gamma>) \<turnstile> t : \<sigma> \<Longrightarrow> (\<forall>z. P ((a,\<tau>)#\<Gamma>) t \<sigma> z)
+              \<Longrightarrow> P \<Gamma> (Lam [a].t) (\<tau>\<rightarrow>\<sigma>) x"
+  shows "\<forall>(pi::name prm) (x::'a::fs_name). P (pi\<bullet>\<Gamma>) (pi\<bullet>t) \<tau> x"
+using a
+proof (induct)
+  case (t1 \<Gamma> \<tau> a)
+  assume j1: "valid \<Gamma>"
+  assume j2: "(a,\<tau>)\<in>set \<Gamma>"
+  show ?case
+  proof (intro strip, simp)
+    fix pi::"name prm" and x::"'a::fs_name"
+    from j1 have j3: "valid (pi\<bullet>\<Gamma>)" by (rule valid_eqvt)
+    from j2 have "pi\<bullet>(a,\<tau>)\<in>pi\<bullet>(set \<Gamma>)" by (simp only: pt_set_bij[OF pt_name_inst, OF at_name_inst])  
+    hence j4: "(pi\<bullet>a,\<tau>)\<in>set (pi\<bullet>\<Gamma>)" by (simp add: pt_list_set_pi[OF pt_name_inst])
+    show "P (pi\<bullet>\<Gamma>) (Var (pi\<bullet>a)) \<tau> x" using a1 j3 j4 by force
+  qed
+next
+  case (t2 \<Gamma> \<sigma> \<tau> t1 t2)
+  thus ?case using a2 by (simp, blast intro: typing_eqvt)
+next
+  case (t3 \<Gamma> \<sigma> \<tau> a t)
+  have k1: "a\<sharp>\<Gamma>" by fact
+  have k2: "((a,\<tau>)#\<Gamma>)\<turnstile>t:\<sigma>" by fact
+  have k3: "\<forall>(pi::name prm) (x::'a::fs_name). P (pi \<bullet> ((a,\<tau>)#\<Gamma>)) (pi\<bullet>t) \<sigma> x" by fact
+  show ?case
+  proof (intro strip, simp)
+    fix pi::"name prm" and x::"'a::fs_name"
+    have f: "\<exists>c::name. c\<sharp>(pi\<bullet>a,pi\<bullet>t,pi\<bullet>\<Gamma>,x)"
+      by (rule at_exists_fresh[OF at_name_inst], simp add: fs_name1)
+    then obtain c::"name" 
+      where f1: "c\<noteq>(pi\<bullet>a)" and f2: "c\<sharp>x" and f3: "c\<sharp>(pi\<bullet>t)" and f4: "c\<sharp>(pi\<bullet>\<Gamma>)"
+      by (force simp add: fresh_prod fresh_atm)
+    from k1 have k1a: "(pi\<bullet>a)\<sharp>(pi\<bullet>\<Gamma>)" 
+      by (simp add: pt_fresh_left[OF pt_name_inst, OF at_name_inst] 
+                    pt_rev_pi[OF pt_name_inst, OF at_name_inst])
+    have l1: "(([(c,pi\<bullet>a)]@pi)\<bullet>\<Gamma>) = (pi\<bullet>\<Gamma>)" using f4 k1a 
+      by (simp only: pt_name2, rule pt_fresh_fresh[OF pt_name_inst, OF at_name_inst])
+    have "\<forall>x. P (([(c,pi\<bullet>a)]@pi)\<bullet>((a,\<tau>)#\<Gamma>)) (([(c,pi\<bullet>a)]@pi)\<bullet>t) \<sigma> x" using k3 by force
+    hence l2: "\<forall>x. P ((c, \<tau>)#(pi\<bullet>\<Gamma>)) (([(c,pi\<bullet>a)]@pi)\<bullet>t) \<sigma> x" using f1 l1
+      by (force simp add: pt_name2  calc_atm split: if_splits)
+    have "(([(c,pi\<bullet>a)]@pi)\<bullet>((a,\<tau>)#\<Gamma>)) \<turnstile> (([(c,pi\<bullet>a)]@pi)\<bullet>t) : \<sigma>" using k2 by (rule typing_eqvt)
+    hence l3: "((c, \<tau>)#(pi\<bullet>\<Gamma>)) \<turnstile> (([(c,pi\<bullet>a)]@pi)\<bullet>t) : \<sigma>" using l1 f1 
+      by (force simp add: pt_name2 calc_atm split: if_splits)
+    have l4: "P (pi\<bullet>\<Gamma>) (Lam [c].(([(c,pi\<bullet>a)]@pi)\<bullet>t)) (\<tau> \<rightarrow> \<sigma>) x" using f2 f4 l2 l3 a3 by auto
+    have alpha: "(Lam [c].([(c,pi\<bullet>a)]\<bullet>(pi\<bullet>t))) = (Lam [(pi\<bullet>a)].(pi\<bullet>t))" using f1 f3
+      by (simp add: lam.inject alpha)
+    show "P (pi\<bullet>\<Gamma>) (Lam [(pi\<bullet>a)].(pi\<bullet>t)) (\<tau> \<rightarrow> \<sigma>) x" using l4 alpha 
+      by (simp only: pt_name2)
+  qed
+qed
+
+lemma typing_induct[case_names t1 t2 t3]:
+  fixes  P :: "(name\<times>ty) list \<Rightarrow> lam \<Rightarrow> ty \<Rightarrow>'a::fs_name\<Rightarrow>bool"
+  and    \<Gamma> :: "(name\<times>ty) list"
+  and    t :: "lam"
+  and    \<tau> :: "ty"
+  and    x :: "'a::fs_name"
+  assumes a: "\<Gamma> \<turnstile> t : \<tau>"
+  and a1:    "\<And>x \<Gamma> (a::name) \<tau>. valid \<Gamma> \<Longrightarrow> (a,\<tau>) \<in> set \<Gamma> \<Longrightarrow> P \<Gamma> (Var a) \<tau> x"
+  and a2:    "\<And>x \<Gamma> \<tau> \<sigma> t1 t2. 
+              \<Gamma> \<turnstile> t1 : \<tau>\<rightarrow>\<sigma> \<Longrightarrow> (\<forall>z. P \<Gamma> t1 (\<tau>\<rightarrow>\<sigma>) z) \<Longrightarrow> \<Gamma> \<turnstile> t2 : \<tau> \<Longrightarrow> (\<forall>z. P \<Gamma> t2 \<tau> z)
+              \<Longrightarrow> P \<Gamma> (App t1 t2) \<sigma> x"
+  and a3:    "\<And>x (a::name) \<Gamma> \<tau> \<sigma> t. 
+              a\<sharp>x \<Longrightarrow> a\<sharp>\<Gamma> \<Longrightarrow> ((a,\<tau>) # \<Gamma>) \<turnstile> t : \<sigma> \<Longrightarrow> (\<forall>z. P ((a,\<tau>)#\<Gamma>) t \<sigma> z)
+              \<Longrightarrow> P \<Gamma> (Lam [a].t) (\<tau>\<rightarrow>\<sigma>) x"
+  shows "P \<Gamma> t \<tau> x"
+using a a1 a2 a3 typing_induct_aux[of "\<Gamma>" "t" "\<tau>" "P" "[]" "x", simplified] by force
+
+constdefs
+  "sub" :: "(name\<times>ty) list \<Rightarrow> (name\<times>ty) list \<Rightarrow> bool" (" _ \<lless> _ " [80,80] 80)
+  "\<Gamma>1 \<lless> \<Gamma>2 \<equiv> \<forall>a \<sigma>. (a,\<sigma>)\<in>set \<Gamma>1 \<longrightarrow>  (a,\<sigma>)\<in>set \<Gamma>2"
+
+lemma weakening[rule_format]: 
+  assumes a: "\<Gamma>1 \<turnstile> t : \<sigma>"
+  shows "valid \<Gamma>2 \<longrightarrow> \<Gamma>1 \<lless> \<Gamma>2 \<longrightarrow> \<Gamma>2 \<turnstile> t:\<sigma>"
+using a
+apply(nominal_induct \<Gamma>1 t \<sigma> rule: typing_induct)
+apply(auto simp add: sub_def)
+done
+
+lemma in_ctxt[rule_format]: "(a,\<tau>)\<in>set \<Gamma> \<longrightarrow> (a\<in>set(dom_ty \<Gamma>))"
+apply(induct_tac \<Gamma>)
+apply(auto)
+done
+
+lemma free_vars: 
+  assumes a: "\<Gamma> \<turnstile> t : \<tau>"
+  shows " (supp t)\<subseteq>set(dom_ty \<Gamma>)"
+using a
+apply(nominal_induct \<Gamma> t \<tau> rule: typing_induct)
+apply(auto simp add: lam.supp abs_supp supp_atm in_ctxt)
+done
+
+lemma t1_elim: "\<Gamma> \<turnstile> Var a : \<tau> \<Longrightarrow> valid \<Gamma> \<and> (a,\<tau>) \<in> set \<Gamma>"
+apply(ind_cases "\<Gamma> \<turnstile> Var a : \<tau>")
+apply(auto simp add: lam.inject lam.distinct)
+done
+
+lemma t2_elim: "\<Gamma> \<turnstile> App t1 t2 : \<sigma> \<Longrightarrow> \<exists>\<tau>. (\<Gamma> \<turnstile> t1 : \<tau>\<rightarrow>\<sigma> \<and> \<Gamma> \<turnstile> t2 : \<tau>)"
+apply(ind_cases "\<Gamma> \<turnstile> App t1 t2 : \<sigma>")
+apply(auto simp add: lam.inject lam.distinct)
+done
+
+lemma t3_elim: "\<lbrakk>\<Gamma> \<turnstile> Lam [a].t : \<sigma>;a\<sharp>\<Gamma>\<rbrakk>\<Longrightarrow> \<exists>\<tau> \<tau>'. \<sigma>=\<tau>\<rightarrow>\<tau>' \<and> ((a,\<tau>)#\<Gamma>) \<turnstile> t : \<tau>'"
+apply(ind_cases "\<Gamma> \<turnstile> Lam [a].t : \<sigma>")
+apply(auto simp add: lam.distinct lam.inject alpha) 
+apply(drule_tac pi="[(a,aa)]::name prm" in typing_eqvt)
+apply(simp)
+apply(subgoal_tac "([(a,aa)]::name prm)\<bullet>\<Gamma> = \<Gamma>")(*A*)
+apply(force simp add: calc_atm)
+(*A*)
+apply(force intro!: pt_fresh_fresh[OF pt_name_inst, OF at_name_inst])
+done
+
+lemma typing_valid: 
+  assumes a: "\<Gamma> \<turnstile> t : \<tau>" 
+  shows "valid \<Gamma>"
+using a by (induct, auto dest!: valid_elim)
+
+lemma ty_subs[rule_format]:
+  fixes \<Gamma> ::"(name\<times>ty) list"
+  and   t1 ::"lam"
+  and   t2 ::"lam"
+  and   \<tau>  ::"ty"
+  and   \<sigma>  ::"ty" 
+  and   c  ::"name"
+  shows  "((c,\<sigma>)#\<Gamma>) \<turnstile> t1:\<tau>\<longrightarrow> \<Gamma>\<turnstile> t2:\<sigma>\<longrightarrow> \<Gamma> \<turnstile> t1[c::=t2]:\<tau>"
+proof(nominal_induct t1 rule: lam_induct)
+  case (Var \<Gamma> \<sigma> \<tau> c t2 a)
+  show ?case
+  proof(intro strip)
+    assume a1: "\<Gamma> \<turnstile>t2:\<sigma>"
+    assume a2: "((c,\<sigma>)#\<Gamma>) \<turnstile> Var a:\<tau>"
+    hence a21: "(a,\<tau>)\<in>set((c,\<sigma>)#\<Gamma>)" and a22: "valid((c,\<sigma>)#\<Gamma>)" by (auto dest: t1_elim)
+    from a22 have a23: "valid \<Gamma>" and a24: "c\<sharp>\<Gamma>" by (auto dest: valid_elim) 
+    from a24 have a25: "\<not>(\<exists>\<tau>. (c,\<tau>)\<in>set \<Gamma>)" by (rule fresh_context)
+    show "\<Gamma>\<turnstile>(Var a)[c::=t2] : \<tau>"
+    proof (cases "a=c", simp_all)
+      assume case1: "a=c"
+      show "\<Gamma> \<turnstile> t2:\<tau>" using a1
+      proof (cases "\<sigma>=\<tau>")
+	assume "\<sigma>=\<tau>" thus ?thesis using a1 by simp 
+      next
+	assume a3: "\<sigma>\<noteq>\<tau>"
+	show ?thesis
+	proof (rule ccontr)
+	  from a3 a21 have "(a,\<tau>)\<in>set \<Gamma>" by force
+	  with case1 a25 show False by force 
+	qed
+      qed
+    next
+      assume case2: "a\<noteq>c"
+      with a21 have a26: "(a,\<tau>)\<in>set \<Gamma>" by force 
+      from a23 a26 show "\<Gamma> \<turnstile> Var a:\<tau>" by force
+    qed
+  qed
+next
+  case (App \<Gamma> \<sigma> \<tau> c t2 s1 s2)
+  show ?case
+  proof (intro strip, simp)
+    assume b1: "\<Gamma> \<turnstile>t2:\<sigma>" 
+    assume b2: " ((c,\<sigma>)#\<Gamma>)\<turnstile>App s1 s2 : \<tau>"
+    hence "\<exists>\<tau>'. (((c,\<sigma>)#\<Gamma>)\<turnstile>s1:\<tau>'\<rightarrow>\<tau> \<and> ((c,\<sigma>)#\<Gamma>)\<turnstile>s2:\<tau>')" by (rule t2_elim) 
+    then obtain \<tau>' where b3a: "((c,\<sigma>)#\<Gamma>)\<turnstile>s1:\<tau>'\<rightarrow>\<tau>" and b3b: "((c,\<sigma>)#\<Gamma>)\<turnstile>s2:\<tau>'" by force
+    show "\<Gamma> \<turnstile>  App (s1[c::=t2]) (s2[c::=t2]) : \<tau>" 
+      using b1 b3a b3b App by (rule_tac \<tau>="\<tau>'" in t2, auto)
+  qed
+next
+  case (Lam \<Gamma> \<sigma> \<tau> c t2 a s)
+  assume "a\<sharp>(\<Gamma>,\<sigma>,\<tau>,c,t2)" 
+  hence f1: "a\<sharp>\<Gamma>" and f2: "a\<noteq>c" and f2': "c\<sharp>a" and f3: "a\<sharp>t2" and f4: "a\<sharp>((c,\<sigma>)#\<Gamma>)"
+    by (auto simp add: fresh_atm fresh_prod fresh_list_cons)
+  show ?case using f2 f3
+  proof(intro strip, simp)
+    assume c1: "((c,\<sigma>)#\<Gamma>)\<turnstile>Lam [a].s : \<tau>"
+    hence "\<exists>\<tau>1 \<tau>2. \<tau>=\<tau>1\<rightarrow>\<tau>2 \<and> ((a,\<tau>1)#(c,\<sigma>)#\<Gamma>) \<turnstile> s : \<tau>2" using f4 by (auto dest: t3_elim) 
+    then obtain \<tau>1 \<tau>2 where c11: "\<tau>=\<tau>1\<rightarrow>\<tau>2" and c12: "((a,\<tau>1)#(c,\<sigma>)#\<Gamma>) \<turnstile> s : \<tau>2" by force
+    from c12 have "valid ((a,\<tau>1)#(c,\<sigma>)#\<Gamma>)" by (rule typing_valid)
+    hence ca: "valid \<Gamma>" and cb: "a\<sharp>\<Gamma>" and cc: "c\<sharp>\<Gamma>" 
+      by (auto dest: valid_elim simp add: fresh_list_cons) 
+    from c12 have c14: "((c,\<sigma>)#(a,\<tau>1)#\<Gamma>) \<turnstile> s : \<tau>2"
+    proof -
+      have c2: "((a,\<tau>1)#(c,\<sigma>)#\<Gamma>) \<lless> ((c,\<sigma>)#(a,\<tau>1)#\<Gamma>)" by (force simp add: sub_def)
+      have c3: "valid ((c,\<sigma>)#(a,\<tau>1)#\<Gamma>)"
+	by (rule v2, rule v2, auto simp add: fresh_list_cons fresh_prod ca cb cc f2' fresh_ty)
+      from c12 c2 c3 show ?thesis by (force intro: weakening)
+    qed
+    assume c8: "\<Gamma> \<turnstile> t2 : \<sigma>"
+    have c81: "((a,\<tau>1)#\<Gamma>)\<turnstile>t2 :\<sigma>"
+    proof -
+      have c82: "\<Gamma> \<lless> ((a,\<tau>1)#\<Gamma>)" by (force simp add: sub_def)
+      have c83: "valid ((a,\<tau>1)#\<Gamma>)" using f1 ca by force
+      with c8 c82 c83 show ?thesis by (force intro: weakening)
+    qed
+    show "\<Gamma> \<turnstile> Lam [a].(s[c::=t2]) : \<tau>"
+      using c11 Lam c14 c81 f1 by force
+  qed
+qed
+
+lemma subject[rule_format]: 
+  fixes \<Gamma>  ::"(name\<times>ty) list"
+  and   t1 ::"lam"
+  and   t2 ::"lam"
+  and   \<tau>  ::"ty"
+  assumes a: "t1\<longrightarrow>\<^isub>\<beta>t2"
+  shows "(\<Gamma> \<turnstile> t1:\<tau>) \<longrightarrow> (\<Gamma> \<turnstile> t2:\<tau>)"
+using a
+proof (nominal_induct t1 t2 rule: beta_induct, auto)
+  case (b1 \<Gamma> \<tau> t s1 s2)
+  assume i: "\<forall>\<Gamma> \<tau>. \<Gamma> \<turnstile> s1 : \<tau> \<longrightarrow> \<Gamma> \<turnstile> s2 : \<tau>" 
+  assume "\<Gamma> \<turnstile> App s1 t : \<tau>"
+  hence "\<exists>\<sigma>. (\<Gamma> \<turnstile> s1 : \<sigma>\<rightarrow>\<tau> \<and> \<Gamma> \<turnstile> t : \<sigma>)" by (rule t2_elim)
+  then obtain \<sigma> where a1: "\<Gamma> \<turnstile> s1 : \<sigma>\<rightarrow>\<tau>" and a2: "\<Gamma> \<turnstile> t : \<sigma>" by force
+  thus "\<Gamma> \<turnstile> App s2 t : \<tau>" using i by force
+next
+  case (b2 \<Gamma> \<tau> t s1 s2)
+  assume i: "\<forall>\<Gamma> \<tau>. \<Gamma> \<turnstile> s1 : \<tau> \<longrightarrow> \<Gamma> \<turnstile> s2 : \<tau>" 
+  assume "\<Gamma> \<turnstile> App t s1 : \<tau>"
+  hence "\<exists>\<sigma>. (\<Gamma> \<turnstile> t : \<sigma>\<rightarrow>\<tau> \<and> \<Gamma> \<turnstile> s1 : \<sigma>)" by (rule t2_elim)
+  then obtain \<sigma> where a1: "\<Gamma> \<turnstile> t : \<sigma>\<rightarrow>\<tau>" and a2: "\<Gamma> \<turnstile> s1 : \<sigma>" by force
+  thus "\<Gamma> \<turnstile> App t s2 : \<tau>" using i by force
+next
+  case (b3 \<Gamma> \<tau> a s1 s2)
+  assume "a\<sharp>(\<Gamma>,\<tau>)"
+  hence f: "a\<sharp>\<Gamma>" by (simp add: fresh_prod)
+  assume i: "\<forall>\<Gamma> \<tau>. \<Gamma> \<turnstile> s1 : \<tau> \<longrightarrow> \<Gamma> \<turnstile> s2 : \<tau>" 
+  assume "\<Gamma> \<turnstile> Lam [a].s1 : \<tau>"
+  with f have "\<exists>\<tau>1 \<tau>2. \<tau>=\<tau>1\<rightarrow>\<tau>2 \<and> ((a,\<tau>1)#\<Gamma>) \<turnstile> s1 : \<tau>2" by (force dest: t3_elim)
+  then obtain \<tau>1 \<tau>2 where a1: "\<tau>=\<tau>1\<rightarrow>\<tau>2" and a2: "((a,\<tau>1)#\<Gamma>) \<turnstile> s1 : \<tau>2" by force
+  thus "\<Gamma> \<turnstile> Lam [a].s2 : \<tau>" using f i by force 
+next
+  case (b4 \<Gamma> \<tau> a s1 s2)
+  have "a\<sharp>(s2,\<Gamma>,\<tau>)" by fact
+  hence f: "a\<sharp>\<Gamma>" by (simp add: fresh_prod)
+  assume "\<Gamma> \<turnstile> App (Lam [a].s1) s2 : \<tau>"
+  hence "\<exists>\<sigma>. (\<Gamma> \<turnstile> (Lam [a].s1) : \<sigma>\<rightarrow>\<tau> \<and> \<Gamma> \<turnstile> s2 : \<sigma>)" by (rule t2_elim)
+  then obtain \<sigma> where a1: "\<Gamma> \<turnstile> (Lam [(a::name)].s1) : \<sigma>\<rightarrow>\<tau>" and a2: "\<Gamma> \<turnstile> s2 : \<sigma>" by force
+  have  "((a,\<sigma>)#\<Gamma>) \<turnstile> s1 : \<tau>" using a1 f by (auto dest!: t3_elim)
+  with a2 show "\<Gamma> \<turnstile>  s1[a::=s2] : \<tau>" by (force intro: ty_subs)
+qed
+
+
+lemma subject[rule_format]: 
+  fixes \<Gamma>  ::"(name\<times>ty) list"
+  and   t1 ::"lam"
+  and   t2 ::"lam"
+  and   \<tau>  ::"ty"
+  assumes a: "t1\<longrightarrow>\<^isub>\<beta>t2"
+  shows "\<Gamma> \<turnstile> t1:\<tau> \<longrightarrow> \<Gamma> \<turnstile> t2:\<tau>"
+using a
+apply(nominal_induct t1 t2 rule: beta_induct)
+apply(auto dest!: t2_elim t3_elim intro: ty_subs simp add: fresh_prod)
+done
+
+
+
+subsection {* some facts about beta *}
+
+constdefs
+  "NORMAL" :: "lam \<Rightarrow> bool"
+  "NORMAL t \<equiv> \<not>(\<exists>t'. t\<longrightarrow>\<^isub>\<beta> t')"
+
+constdefs
+  "SN" :: "lam \<Rightarrow> bool"
+  "SN t \<equiv> t\<in>termi Beta"
+
+lemma qq1: "\<lbrakk>SN(t1);t1\<longrightarrow>\<^isub>\<beta> t2\<rbrakk>\<Longrightarrow>SN(t2)"
+apply(simp add: SN_def)
+apply(drule_tac a="t2" in acc_downward)
+apply(auto)
+done
+
+lemma qq2: "(\<forall>t2. t1\<longrightarrow>\<^isub>\<beta>t2 \<longrightarrow> SN(t2))\<Longrightarrow>SN(t1)"
+apply(simp add: SN_def)
+apply(rule accI)
+apply(auto)
+done
+
+
+section {* Candidates *}
+
+consts
+  RED :: "ty \<Rightarrow> lam set"
+primrec
+ "RED (TVar X) = {t. SN(t)}"
+ "RED (\<tau>\<rightarrow>\<sigma>) =   {t. \<forall>u. (u\<in>RED \<tau> \<longrightarrow> (App t u)\<in>RED \<sigma>)}"
+
+constdefs
+  NEUT :: "lam \<Rightarrow> bool"
+  "NEUT t \<equiv> (\<exists>a. t=Var a)\<or>(\<exists>t1 t2. t=App t1 t2)" 
+
+(* a slight hack to get the first element of applications *)
+consts
+  FST :: "(lam\<times>lam) set"
+syntax 
+  "FST_judge"   :: "lam\<Rightarrow>lam\<Rightarrow>bool" (" _ \<guillemotright> _" [80,80] 80)
+translations 
+  "t1 \<guillemotright> t2" \<rightleftharpoons> "(t1,t2) \<in> FST"
+inductive FST
+intros
+fst[intro!]:  "(App t s) \<guillemotright> t"
+
+lemma fst_elim[elim!]: "(App t s) \<guillemotright> t' \<Longrightarrow> t=t'"
+apply(ind_cases "App t s \<guillemotright> t'")
+apply(simp add: lam.inject)
+done
+
+lemma qq3: "SN(App t s)\<Longrightarrow>SN(t)"
+apply(simp add: SN_def)
+apply(subgoal_tac "\<forall>z. (App t s \<guillemotright> z) \<longrightarrow> z\<in>termi Beta")(*A*)
+apply(force)
+(*A*)
+apply(erule acc_induct)
+apply(clarify)
+apply(ind_cases "x \<guillemotright> z")
+apply(clarify)
+apply(rule accI)
+apply(auto intro: b1)
+done
+
+constdefs
+   "CR1" :: "ty \<Rightarrow> bool"
+   "CR1 \<tau> \<equiv> \<forall> t. (t\<in>RED \<tau> \<longrightarrow> SN(t))"
+
+   "CR2" :: "ty \<Rightarrow> bool"
+   "CR2 \<tau> \<equiv> \<forall>t t'. ((t\<in>RED \<tau> \<and> t \<longrightarrow>\<^isub>\<beta> t') \<longrightarrow> t'\<in>RED \<tau>)"
+
+   "CR3_RED" :: "lam \<Rightarrow> ty \<Rightarrow> bool"
+   "CR3_RED t \<tau> \<equiv> \<forall>t'. (t\<longrightarrow>\<^isub>\<beta> t' \<longrightarrow>  t'\<in>RED \<tau>)" 
+
+   "CR3" :: "ty \<Rightarrow> bool"
+   "CR3 \<tau> \<equiv> \<forall>t. (NEUT t \<and> CR3_RED t \<tau>) \<longrightarrow> t\<in>RED \<tau>"
+   
+   "CR4" :: "ty \<Rightarrow> bool"
+   "CR4 \<tau> \<equiv> \<forall>t. (NEUT t \<and> NORMAL t) \<longrightarrow>t\<in>RED \<tau>"
+
+lemma CR3_CR4: "CR3 \<tau> \<Longrightarrow> CR4 \<tau>"
+apply(simp (no_asm_use) add: CR3_def CR3_RED_def CR4_def NORMAL_def)
+apply(blast)
+done
+
+lemma sub_ind: 
+  "SN(u)\<Longrightarrow>(u\<in>RED \<tau>\<longrightarrow>(\<forall>t. (NEUT t\<and>CR2 \<tau>\<and>CR3 \<sigma>\<and>CR3_RED t (\<tau>\<rightarrow>\<sigma>))\<longrightarrow>(App t u)\<in>RED \<sigma>))"
+apply(simp add: SN_def)
+apply(erule acc_induct)
+apply(auto)
+apply(simp add: CR3_def)
+apply(rotate_tac 5)
+apply(drule_tac x="App t x" in spec)
+apply(drule mp)
+apply(rule conjI)
+apply(force simp only: NEUT_def)
+apply(simp (no_asm) add: CR3_RED_def)
+apply(clarify)
+apply(ind_cases "App t x \<longrightarrow>\<^isub>\<beta> t'")
+apply(simp_all add: lam.inject)
+apply(simp only:  CR3_RED_def)
+apply(drule_tac x="s2" in spec)
+apply(simp)
+apply(drule_tac x="s2" in spec)
+apply(simp)
+apply(drule mp)
+apply(simp (no_asm_use) add: CR2_def)
+apply(blast)
+apply(drule_tac x="ta" in spec)
+apply(force)
+apply(auto simp only: NEUT_def lam.inject lam.distinct)
+done
+
+lemma RED_props: "CR1 \<tau> \<and> CR2 \<tau> \<and> CR3 \<tau>"
+apply(induct_tac \<tau>)
+apply(auto)
+(* atom types *)
+(* C1 *)
+apply(simp add: CR1_def)
+(* C2 *)
+apply(simp add: CR2_def)
+apply(clarify)
+apply(drule_tac ?t2.0="t'" in  qq1)
+apply(assumption)+
+(* C3 *)
+apply(simp add: CR3_def CR3_RED_def)
+apply(clarify)
+apply(rule qq2)
+apply(assumption)
+(* arrow types *)
+(* C1 *)
+apply(simp (no_asm) add: CR1_def)
+apply(clarify)
+apply(subgoal_tac "NEUT (Var a)")(*A*)
+apply(subgoal_tac "(Var a)\<in>RED ty1")(*C*)
+apply(drule_tac x="Var a" in spec)
+apply(simp)
+apply(simp add: CR1_def)
+apply(rotate_tac 1)
+apply(drule_tac x="App t (Var a)" in spec)
+apply(simp)
+apply(drule qq3) 
+apply(assumption)
+(*C*)
+apply(simp (no_asm_use) add: CR3_def CR3_RED_def)
+apply(drule_tac x="Var a" in spec)
+apply(drule mp)
+apply(clarify)
+apply(ind_cases " Var a \<longrightarrow>\<^isub>\<beta> t'")
+apply(simp (no_asm_use) add: lam.distinct)+ 
+(*A*)
+apply(simp (no_asm) only: NEUT_def)
+apply(rule disjCI)
+apply(rule_tac x="a" in exI)
+apply(simp (no_asm))
+(* C2 *)
+apply(simp (no_asm) add: CR2_def)
+apply(clarify)
+apply(drule_tac x="u" in spec)
+apply(simp)
+apply(subgoal_tac "App t u \<longrightarrow>\<^isub>\<beta> App t' u")(*X*)
+apply(simp (no_asm_use) only: CR2_def)
+apply(blast)
+(*X*)
+apply(force intro!: b1)
+(* C3 *)
+apply(unfold CR3_def)
+apply(rule allI)
+apply(rule impI)
+apply(erule conjE)
+apply(simp (no_asm))
+apply(rule allI)
+apply(rule impI)
+apply(subgoal_tac "SN(u)")(*Z*)
+apply(fold CR3_def)
+apply(drule_tac \<tau>="ty1" and \<sigma>="ty2" in sub_ind)
+apply(simp)
+(*Z*)
+apply(simp add: CR1_def)
+done
+
+lemma double_acc_aux:
+  assumes a_acc: "a \<in> acc r"
+  and b_acc: "b \<in> acc r"
+  and hyp: "\<And>x z.
+    (\<And>y. (y, x) \<in> r \<Longrightarrow> y \<in> acc r) \<Longrightarrow>
+    (\<And>y. (y, x) \<in> r \<Longrightarrow> P y z) \<Longrightarrow>
+    (\<And>u. (u, z) \<in> r \<Longrightarrow> u \<in> acc r) \<Longrightarrow>
+    (\<And>u. (u, z) \<in> r \<Longrightarrow> P x u) \<Longrightarrow> P x z"
+  shows "P a b"
+proof -
+  from a_acc
+  have r: "\<And>b. b \<in> acc r \<Longrightarrow> P a b"
+  proof (induct a rule: acc.induct)
+    case (accI x)
+    note accI' = accI
+    have "b \<in> acc r" .
+    thus ?case
+    proof (induct b rule: acc.induct)
+      case (accI y)
+      show ?case
+	apply (rule hyp)
+	apply (erule accI')
+	apply (erule accI')
+	apply (rule acc.accI)
+	apply (erule accI)
+	apply (erule accI)
+	apply (erule accI)
+	done
+    qed
+  qed
+  from b_acc show ?thesis by (rule r)
+qed
+
+lemma double_acc:
+  "\<lbrakk>a \<in> acc r; b \<in> acc r; \<forall>x z. ((\<forall>y. (y, x)\<in>r\<longrightarrow>P y z)\<and>(\<forall>u. (u, z)\<in>r\<longrightarrow>P x u))\<longrightarrow>P x z\<rbrakk>\<Longrightarrow>P a b"
+apply(rule_tac r="r" in double_acc_aux)
+apply(assumption)+
+apply(blast)
+done
+
+lemma abs_RED[rule_format]: "(\<forall>s\<in>RED \<tau>. t[x::=s]\<in>RED \<sigma>)\<longrightarrow>Lam [x].t\<in>RED (\<tau>\<rightarrow>\<sigma>)"
+apply(simp)
+apply(clarify)
+apply(subgoal_tac "t\<in>termi Beta")(*1*)
+apply(erule rev_mp)
+apply(subgoal_tac "u \<in> RED \<tau>")(*A*)
+apply(erule rev_mp)
+apply(rule_tac a="t" and b="u" in double_acc)
+apply(assumption)
+apply(subgoal_tac "CR1 \<tau>")(*A*)
+apply(simp add: CR1_def SN_def)
+(*A*)
+apply(force simp add: RED_props)
+apply(simp)
+apply(clarify)
+apply(subgoal_tac "CR3 \<sigma>")(*B*)
+apply(simp add: CR3_def)
+apply(rotate_tac 6)
+apply(drule_tac x="App(Lam[x].xa ) z" in spec)
+apply(drule mp)
+apply(rule conjI)
+apply(force simp add: NEUT_def)
+apply(simp add: CR3_RED_def)
+apply(clarify)
+apply(ind_cases "App(Lam[x].xa) z \<longrightarrow>\<^isub>\<beta> t'")
+apply(auto simp add: lam.inject lam.distinct)
+apply(drule beta_abs)
+apply(auto)
+apply(drule_tac x="t''" in spec)
+apply(simp)
+apply(drule mp)
+apply(clarify)
+apply(drule_tac x="s" in bspec)
+apply(assumption)
+apply(subgoal_tac "xa [ x ::= s ] \<longrightarrow>\<^isub>\<beta>  t'' [ x ::= s ]")(*B*)
+apply(subgoal_tac "CR2 \<sigma>")(*C*)
+apply(simp (no_asm_use) add: CR2_def)
+apply(blast)
+(*C*)
+apply(force simp add: RED_props)
+(*B*)
+apply(force intro!: beta_subst)
+apply(assumption)
+apply(rotate_tac 3)
+apply(drule_tac x="s2" in spec)
+apply(subgoal_tac "s2\<in>RED \<tau>")(*D*)
+apply(simp)
+(*D*)
+apply(subgoal_tac "CR2 \<tau>")(*E*)
+apply(simp (no_asm_use) add: CR2_def)
+apply(blast)
+(*E*)
+apply(force simp add: RED_props)
+apply(simp add: alpha)
+apply(erule disjE)
+apply(force)
+apply(auto)
+apply(simp add: subst_rename)
+apply(drule_tac x="z" in bspec)
+apply(assumption)
+(*B*)
+apply(force simp add: RED_props)
+(*1*)
+apply(drule_tac x="Var x" in bspec)
+apply(subgoal_tac "CR3 \<tau>")(*2*) 
+apply(drule CR3_CR4)
+apply(simp add: CR4_def)
+apply(drule_tac x="Var x" in spec)
+apply(drule mp)
+apply(rule conjI)
+apply(force simp add: NEUT_def)
+apply(simp add: NORMAL_def)
+apply(clarify)
+apply(ind_cases "Var x \<longrightarrow>\<^isub>\<beta> t'")
+apply(auto simp add: lam.inject lam.distinct)
+apply(force simp add: RED_props)
+apply(simp add: id_subs)
+apply(subgoal_tac "CR1 \<sigma>")(*3*)
+apply(simp add: CR1_def SN_def)
+(*3*)
+apply(force simp add: RED_props)
+done
+
+lemma all_RED: 
+ "((\<forall>a \<sigma>. (a,\<sigma>)\<in>set(\<Gamma>)\<longrightarrow>(a\<in>set(dom_sss \<theta>)\<and>\<theta><a>\<in>RED \<sigma>))\<and>\<Gamma>\<turnstile>t:\<tau>) \<longrightarrow> (t[<\<theta>>]\<in>RED \<tau>)"
+apply(nominal_induct t rule: lam_induct)
+(* Variables *)
+apply(force dest: t1_elim)
+(* Applications *)
+apply(auto dest!: t2_elim)
+apply(drule_tac x="a" in spec)
+apply(drule_tac x="a" in spec)
+apply(drule_tac x="\<tau>\<rightarrow>aa" in spec)
+apply(drule_tac x="\<tau>" in spec)
+apply(drule_tac x="b" in spec)
+apply(drule_tac x="b" in spec)
+apply(force)
+(* Abstractions *)
+apply(drule t3_elim)
+apply(simp add: fresh_prod)
+apply(auto)
+apply(drule_tac x="((ab,\<tau>)#a)" in spec)
+apply(drule_tac x="\<tau>'" in spec)
+apply(drule_tac x="b" in spec)
+apply(simp)
+(* HERE *)
+
+
+done
+