# HG changeset patch # User Cezary Kaliszyk # Date 1332772097 -7200 # Node ID e05c033d69c1e0da882e5ff7a4d848a93219c692 # Parent b47301ebb3cab9aea5b5000ff112a503fee7b798 Alternate version of Nominal_Base: Executable version. diff -r b47301ebb3ca -r e05c033d69c1 Nominal/GPerm.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Nominal/GPerm.thy Mon Mar 26 16:28:17 2012 +0200 @@ -0,0 +1,495 @@ +(* General executable permutations *) + +theory GPerm +imports + "~~/src/HOL/Library/Quotient_Syntax" + "~~/src/HOL/Library/Product_ord" + "~~/src/HOL/Library/List_lexord" +begin + +definition perm_apply where + "perm_apply l e = (case [a\l . fst a = e] of [] \ e | x # xa \ snd x)" + +lemma perm_apply_simps[simp]: + "perm_apply (h # t) e = (if fst h = e then snd h else perm_apply t e)" + "perm_apply [] e = e" + by (auto simp add: perm_apply_def) + +definition valid_perm where + "valid_perm p \ distinct (map fst p) \ fst ` set p = snd ` set p" + +lemma valid_perm_zero[simp]: + "valid_perm []" + by (simp add: valid_perm_def) + +lemma length_eq_card_distinct: + "length l = card (set l) \ distinct l" + using card_distinct distinct_card by force + +lemma len_set_eq_distinct: + assumes "length l = length m" "set l = set m" + shows "distinct l = distinct m" + using assms + by (simp add: length_eq_card_distinct[symmetric]) + +lemma valid_perm_distinct_snd: "valid_perm a \ distinct (map snd a)" + by (metis valid_perm_def image_set length_map len_set_eq_distinct) + +definition + perm_eq :: "('a \ 'a) list \ ('a \ 'a) list \ bool" (infix "\" 50) +where + "x \ y \ valid_perm x \ valid_perm y \ (perm_apply x = perm_apply y)" + +lemma perm_eq_sym[sym]: + "x \ y \ y \ x" + by (auto simp add: perm_eq_def) + +lemma perm_eq_equivp: + "part_equivp perm_eq" + by (auto intro!: part_equivpI sympI transpI exI[of _ "[]"] simp add: perm_eq_def) + +quotient_type + 'a gperm = "('a \ 'a) list" / partial: "perm_eq" + by (rule perm_eq_equivp) + +definition perm_add_raw where + "perm_add_raw p q = map (map_pair id (perm_apply p)) q @ [a\p. fst a \ fst ` set q]" + +lemma perm_apply_del[simp]: + "e \ b \ perm_apply [a\l. fst a \ b] e = perm_apply l e" + "e \ b \ e \ c \ perm_apply [a\l . fst a \ b \ fst a \ c] e = perm_apply l e" + by (induct l) auto + +lemma perm_apply_appendl: + "perm_apply a e = perm_apply b e \ perm_apply (c @ a) e = perm_apply (c @ b) e" + by (induct c) auto + +lemma perm_apply_filterP: + "b \ e \ perm_apply [a\l . fst a \ b \ P a] e = perm_apply [a\l . P a] e" + by (induct l) auto + +lemma perm_add_apply: + shows "perm_apply (perm_add_raw p q) e = perm_apply p (perm_apply q e)" + by (rule sym, induct q) + (auto simp add: perm_add_raw_def perm_apply_filterP intro!: perm_apply_appendl) + +definition swap_pair where + "swap_pair a = (snd a, fst a)" + +definition uminus_perm_raw where + [simp]: "uminus_perm_raw = map swap_pair" + +lemma map_fst_minus_perm[simp]: + "map fst (uminus_perm_raw x) = map snd x" + "map snd (uminus_perm_raw x) = map fst x" + by (induct x) (auto simp add: swap_pair_def) + +lemma fst_snd_set_minus_perm[simp]: + "fst ` set (uminus_perm_raw x) = snd ` set x" + "snd ` set (uminus_perm_raw x) = fst ` set x" + by (induct x) (auto simp add: swap_pair_def) + +lemma fst_snd_swap_pair[simp]: + "fst (swap_pair x) = snd x" + "snd (swap_pair x) = fst x" + by (auto simp add: swap_pair_def) + +lemma fst_snd_swap_pair_set[simp]: + "fst ` swap_pair ` set l = snd ` set l" + "snd ` swap_pair ` set l = fst ` set l" + by (induct l) (auto simp add: swap_pair_def) + +lemma valid_perm_minus[simp]: + assumes "valid_perm x" + shows "valid_perm (map swap_pair x)" + using assms unfolding valid_perm_def + by (simp add: valid_perm_distinct_snd[OF assms] o_def) + +lemma swap_pair_id[simp]: + "swap_pair (swap_pair x) = x" + unfolding swap_pair_def by simp + +lemma perm_apply_minus_minus[simp]: + "perm_apply (uminus_perm_raw (uminus_perm_raw x)) = perm_apply x" + by (simp add: o_def) + +lemma filter_eq_nil: + "[a\a. fst a = e] = [] \ e \ fst ` set a" + "[a\a. snd a = e] = [] \ e \ snd ` set a" + by (induct a) auto + +lemma filter_rev_eq_nil: "[a\map swap_pair a. fst a = e] = [] \ e \ snd ` set a" + by (induct a) (auto simp add: swap_pair_def) + +lemma filter_fst_eq: + "[a\a . fst a = e] = (l, r) # list \ l = e" + "[a\a . snd a = e] = (l, r) # list \ r = e" + by (drule filter_eq_ConsD, auto)+ + +lemma filter_map_swap_pair: + "[a\map swap_pair a. fst a = e] = map swap_pair [a\a. snd a = e]" + by (induct a) auto + +lemma forget_tl: + "[a\l . P a] = a # b \ a \ set l" + by (metis Cons_eq_filter_iff in_set_conv_decomp) + +lemma valid_perm_lookup_fst_eq_snd: + "[a\l . fst a = f] = (f, s) # l1 \ [a\l . snd a = s] = (f2, s) # l2 \ valid_perm l \ f2 = f" + apply (drule forget_tl valid_perm_distinct_snd)+ + apply (case_tac "f2 = f") + apply (auto simp add: in_set_conv_nth swap_pair_def) + apply (case_tac "i = ia") + apply auto + by (metis length_map nth_eq_iff_index_eq nth_map snd_conv) + +lemma valid_perm_add_minus: "valid_perm a \ perm_apply (map swap_pair a) (perm_apply a e) = e" + apply (auto simp add: filter_map_swap_pair filter_eq_nil filter_rev_eq_nil perm_apply_def split: list.split) + apply (metis filter_eq_nil(2) neq_Nil_conv valid_perm_def) + apply (metis hd.simps hd_in_set image_eqI list.simps(2) member_project project_set snd_conv) + apply (frule filter_fst_eq(1)) + apply (frule filter_fst_eq(2)) + apply (auto simp add: swap_pair_def) + apply (erule valid_perm_lookup_fst_eq_snd) + apply assumption+ + done + +lemma perm_apply_minus: "valid_perm x \ perm_apply (map swap_pair x) a = b \ perm_apply x b = a" + using valid_perm_add_minus[symmetric] valid_perm_minus + by (metis uminus_perm_raw_def) + +lemma uminus_perm_raw_rsp[simp]: + "x \ y \ map swap_pair x \ map swap_pair y" + by (auto simp add: fun_eq_iff perm_apply_minus[symmetric] perm_eq_def) + +lemma [quot_respect]: + "(op \ ===> op \) uminus_perm_raw uminus_perm_raw" + by (auto intro!: fun_relI simp add: fun_eq_iff perm_apply_minus[symmetric] perm_eq_def) + +lemma fst_snd_map_pair[simp]: + "fst ` map_pair f g ` set l = f ` fst ` set l" + "snd ` map_pair f g ` set l = g ` snd ` set l" + by (induct l) auto + +lemma fst_diff[simp]: + shows "fst ` {xa \ set x. fst xa \ fst ` set y} = fst ` set x - fst ` set y" + by auto + +lemma pair_perm_apply: + "distinct (map fst x) \ (a, b) \ set x \ perm_apply x a = b" + by (induct x) (auto, metis fst_conv image_eqI) + +lemma valid_perm_apply: + "valid_perm x \ (a, b) \ set x \ perm_apply x a = b" + unfolding valid_perm_def using pair_perm_apply by auto + +lemma in_perm_apply: + "valid_perm x \ (a, b) \ set x \ a \ c \ b \ perm_apply x ` c" + by (metis imageI valid_perm_apply) + +lemma snd_set_not_in_perm_apply[simp]: + assumes "valid_perm x" + shows "snd ` {xa \ set x. fst xa \ fst ` set y} = perm_apply x ` (fst ` set x - fst ` set y)" +proof auto + fix a b + assume a: "(a, b) \ set x" " a \ fst ` set y" + then have "a \ fst ` set x - fst ` set y" + by simp (metis fst_conv image_eqI) + with a show "b \ perm_apply x ` (fst ` set x - fst ` set y)" + by (simp add: in_perm_apply assms) +next + fix a b + assume a: "a \ fst ` set y" "(a, b) \ set x" + then have "perm_apply x a = b" + by (simp add: valid_perm_apply assms) + with a show "perm_apply x a \ snd ` {xa \ set x. fst xa \ fst ` set y}" + by (metis (lifting) CollectI fst_conv image_eqI snd_conv) +qed + +lemma perm_apply_set: + "valid_perm x \ perm_apply x ` fst ` set x = fst ` set x" + by (auto simp add: valid_perm_def) + (metis (hide_lams, no_types) image_iff pair_perm_apply snd_eqD surjective_pairing)+ + +lemma perm_apply_outset: "a \ fst ` set x \ perm_apply x a = a" + by (induct x) auto + +lemma perm_apply_subset: "valid_perm x \ fst ` set x \ s \ perm_apply x ` s = s" + apply auto + apply (case_tac [!] "xa \ fst ` set x") + apply (metis imageI perm_apply_set subsetD) + apply (metis perm_apply_outset) + apply (metis image_mono perm_apply_set subsetD) + by (metis imageI perm_apply_outset) + +lemma valid_perm_add_raw[simp]: + assumes "valid_perm x" "valid_perm y" + shows "valid_perm (perm_add_raw x y)" + using assms + apply (simp (no_asm) add: valid_perm_def) + apply (intro conjI) + apply (auto simp add: perm_add_raw_def valid_perm_def fst_def[symmetric])[1] + apply (simp add: distinct_map inj_on_def) + apply (metis imageI snd_conv) + apply (simp add: perm_add_raw_def image_Un) + apply (simp add: image_Un[symmetric]) + apply (auto simp add: perm_apply_subset valid_perm_def) + done + +lemma perm_add_raw_rsp[simp]: + "x \ y \ xa \ ya \ perm_add_raw x xa \ perm_add_raw y ya" + by (simp add: fun_eq_iff perm_add_apply perm_eq_def) + +lemma [quot_respect]: + "(op \ ===> op \ ===> op \) perm_add_raw perm_add_raw" + by (auto intro!: fun_relI simp add: perm_add_raw_rsp) + +lemma [simp]: + "a \ a \ valid_perm a" + by (simp_all add: perm_eq_def) + +lemma [quot_respect]: "[] \ []" + by auto + +lemmas [simp] = in_respects + +instantiation gperm :: (type) group_add +begin + +quotient_definition "0 :: 'a gperm" is "[] :: ('a \ 'a) list" + +quotient_definition "uminus :: 'a gperm \ 'a gperm" is + "uminus_perm_raw :: ('a \ 'a) list \ ('a \ 'a) list" + +quotient_definition "(op +) :: 'a gperm \ 'a gperm \ 'a gperm" is + "perm_add_raw :: ('a \ 'a) list \ ('a \ 'a) list \ ('a \ 'a) list" + +definition + minus_perm_def: "(p1::'a gperm) - p2 = p1 + - p2" + +instance + apply default + unfolding minus_perm_def + by (partiality_descending, simp add: perm_add_apply perm_eq_def fun_eq_iff valid_perm_add_minus)+ + +end + +definition "mk_perm_raw l = (if valid_perm l then l else [])" + +quotient_definition "mk_perm :: ('a \ 'a) list \ 'a gperm" + is "mk_perm_raw" + +definition "dest_perm_raw p = sort [x\p. fst x \ snd x]" + +quotient_definition "dest_perm :: ('a :: linorder) gperm \ ('a \ 'a) list" + is "dest_perm_raw" + +lemma [quot_respect]: "(op = ===> op \) mk_perm_raw mk_perm_raw" + by (auto intro!: fun_relI simp add: mk_perm_raw_def) + +lemma distinct_fst_distinct[simp]: "distinct (map fst x) \ distinct x" + by (induct x) auto + +lemma perm_apply_in_set: + "a \ b \ perm_apply y a = b \ (a, b) \ set y" + by (induct y) (auto split: if_splits) + +lemma perm_eq_not_eq_same: + "x \ y \ {xa \ set x. fst xa \ snd xa} = {x \ set y. fst x \ snd x}" + unfolding perm_eq_def set_eq_iff + apply auto + apply (subgoal_tac "perm_apply x a = b") + apply (simp add: perm_apply_in_set) + apply (erule valid_perm_apply) + apply simp + apply (subgoal_tac "perm_apply y a = b") + apply (simp add: perm_apply_in_set) + apply (erule valid_perm_apply) + apply simp + done + +lemma [simp]: "distinct (map fst (sort x)) = distinct (map fst x)" + by (rule len_set_eq_distinct) simp_all + +lemma valid_perm_sort[simp]: + "valid_perm x \ valid_perm (sort x)" + unfolding valid_perm_def by simp + +lemma same_not_in_dpr: + "valid_perm x \ (b, b) \ set x \ b \ fst ` set (dest_perm_raw x)" + unfolding dest_perm_raw_def valid_perm_def + by auto (metis pair_perm_apply) + +lemma in_set_in_dpr: + "valid_perm x \ a \ b \ (a, b) \ set x \ (a, b) \ set (dest_perm_raw x)" + unfolding dest_perm_raw_def valid_perm_def + by simp + +lemma in_set_in_dpr2: + "a \ b \ (dest_perm_raw x = dest_perm_raw y) \ valid_perm x \ valid_perm y \ (a, b) \ set x \ (a, b) \ set y" + using in_set_in_dpr by metis + +lemma in_set_in_dpr3: + "(dest_perm_raw x = dest_perm_raw y) \ valid_perm x \ valid_perm y \ perm_apply x a = perm_apply y a" + by (metis in_set_in_dpr2 pair_perm_apply perm_apply_in_set valid_perm_def) + +lemma dest_perm_raw_eq[simp]: + "valid_perm x \ valid_perm y \ (dest_perm_raw x = dest_perm_raw y) = (x \ y)" + apply (auto simp add: perm_eq_def) + apply (metis in_set_in_dpr3 fun_eq_iff) + unfolding dest_perm_raw_def + by (rule sorted_distinct_set_unique) + (simp_all add: distinct_filter valid_perm_def perm_eq_not_eq_same[simplified perm_eq_def, simplified]) + +lemma [quot_respect]: + "(op \ ===> op =) dest_perm_raw dest_perm_raw" + by (auto intro!: fun_relI simp add: perm_eq_def) + +lemma dest_perm_mk_perm[simp]: + "dest_perm (mk_perm xs) = sort [x\mk_perm_raw xs. fst x \ snd x]" + by (partiality_descending) + (simp add: dest_perm_raw_def) + +lemma valid_perm_filter_id[simp]: + "valid_perm p \ valid_perm [x\p. fst x \ snd x]" +proof (simp (no_asm) add: valid_perm_def, intro conjI) + show "valid_perm p \ distinct (map fst [x\'a \ 'a\p . fst x \ snd x])" + by (auto simp add: distinct_map inj_on_def valid_perm_def) + assume a: "valid_perm p" + then show "fst ` {x\'a \ 'a \ set p. fst x \ snd x} = snd ` {x\'a \ 'a \ set p. fst x \ snd x}" + apply - + apply (frule valid_perm_distinct_snd) + apply (simp add: valid_perm_def) + apply auto + apply (subgoal_tac "a \ snd ` set p") + apply auto + apply (subgoal_tac "(aa, ba) \ {x \ set p. fst x \ snd x}") + apply (metis (lifting) image_eqI snd_conv) + apply (metis (lifting, mono_tags) fst_conv mem_Collect_eq snd_conv pair_perm_apply) + apply (metis fst_conv imageI) + apply (drule sym) + apply (subgoal_tac "b \ fst ` set p") + apply auto + apply (subgoal_tac "(aa, ba) \ {x \ set p. fst x \ snd x}") + apply (metis (lifting) image_eqI fst_conv) + apply simp + apply (metis valid_perm_add_minus valid_perm_apply valid_perm_def) + apply (metis snd_conv imageI) + done +qed + +lemma valid_perm_dest_pair_raw[simp]: + assumes "valid_perm x" + shows "valid_perm (dest_perm_raw x)" + using valid_perm_filter_id valid_perm_sort assms + unfolding dest_perm_raw_def + by simp + +lemma dest_perm_raw_repeat[simp]: + "dest_perm_raw (dest_perm_raw p) = dest_perm_raw p" + unfolding dest_perm_raw_def + by simp (rule sorted_sort_id[OF sorted_sort]) + +lemma valid_dest_perm_raw_eq[simp]: + "valid_perm p \ dest_perm_raw p \ p" + "valid_perm p \ p \ dest_perm_raw p" + by (simp_all add: dest_perm_raw_eq[symmetric]) + +lemma mk_perm_dest_perm[code abstype]: + "mk_perm (dest_perm p) = p" + by (partiality_descending) + (auto simp add: mk_perm_raw_def) + +instantiation gperm :: (linorder) equal begin + +definition equal_gperm_def: "equal_gperm a b \ dest_perm a = dest_perm b" + +instance + apply default + unfolding equal_gperm_def + by partiality_descending simp + +end + +lemma [code abstract]: + "dest_perm 0 = []" + by (partiality_descending) (simp add: dest_perm_raw_def) + +lemma [code abstract]: + "dest_perm (-a) = dest_perm_raw (uminus_perm_raw (dest_perm a))" + by (partiality_descending) (auto) + +lemma [code abstract]: + "dest_perm (a + b) = dest_perm_raw (perm_add_raw (dest_perm a) (dest_perm b))" + by (partiality_descending) auto + +quotient_definition "gpermute :: 'a gperm \ 'a \ 'a" +is perm_apply + +lemma [quot_respect]: "(op \ ===> op =) perm_apply perm_apply" + by (auto intro!: fun_relI simp add: perm_eq_def) + +lemma gpermute_zero[simp]: + "gpermute 0 x = x" + by descending simp + +lemma gpermute_add[simp]: + "gpermute (p + q) x = gpermute p (gpermute q x)" + by descending (simp add: perm_add_apply) + +definition [simp]:"swap_raw a b = (if a = b then [] else [(a, b), (b, a)])" + +lemma [quot_respect]: "(op = ===> op = ===> op \) swap_raw swap_raw" + by (auto intro!: fun_relI simp add: valid_perm_def) + +quotient_definition "gswap :: 'a \ 'a \ 'a gperm" +is swap_raw + +lemma [code abstract]: + "dest_perm (gswap a b) = (if (a, b) \ (b, a) then swap_raw a b else swap_raw b a)" + by (partiality_descending) (auto simp add: dest_perm_raw_def) + +lemma swap_self [simp]: + "gswap a a = 0" + by (partiality_descending, auto) + +lemma [simp]: "a \ b \ valid_perm [(a, b), (b, a)]" + unfolding valid_perm_def by auto + +lemma swap_cancel [simp]: + "gswap a b + gswap a b = 0" + "gswap a b + gswap b a = 0" + by (descending, auto simp add: perm_eq_def perm_add_apply)+ + +lemma minus_swap [simp]: + "- gswap a b = gswap a b" + by (partiality_descending, auto simp add: perm_eq_def) + +lemma swap_commute: + "gswap a b = gswap b a" + by (partiality_descending, auto simp add: perm_eq_def) + +lemma swap_triple: + assumes "a \ b" "c \ b" + shows "gswap a c + gswap b c + gswap a c = gswap a b" + using assms + by descending (auto simp add: perm_eq_def fun_eq_iff perm_add_apply) + +lemma gpermute_gswap[simp]: + "b \ a \ gpermute (gswap a b) b = a" + "a \ b \ gpermute (gswap a b) a = b" + "c \ b \ c \ a \ gpermute (gswap a b) c = c" + by (descending, auto)+ + +lemma gperm_eq: + "(p = q) = (\a. gpermute p a = gpermute q a)" + by (partiality_descending) (auto simp add: perm_eq_def) + +lemma finite_gpermute_neq: + "finite {a. gpermute p a \ a}" + apply descending + apply (rule_tac B="fst ` set p" in finite_subset) + apply auto + by (metis perm_apply_outset) + +end diff -r b47301ebb3ca -r e05c033d69c1 Nominal/Nominal2_Base_Exec.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Nominal/Nominal2_Base_Exec.thy Mon Mar 26 16:28:17 2012 +0200 @@ -0,0 +1,3165 @@ +(* Title: Nominal2_Base + Authors: Christian Urban, Brian Huffman, Cezary Kaliszyk + + Basic definitions and lemma infrastructure for + Nominal Isabelle. +*) +theory Nominal2_Base +imports Main + "~~/src/HOL/Library/Infinite_Set" + "~~/src/HOL/Quotient_Examples/FSet" + "GPerm" +keywords + "atom_decl" "equivariance" :: thy_decl +uses ("nominal_basics.ML") + ("nominal_thmdecls.ML") + ("nominal_permeq.ML") + ("nominal_library.ML") + ("nominal_atoms.ML") + ("nominal_eqvt.ML") +begin + +section {* Atoms and Sorts *} + +text {* A simple implementation for atom_sorts is strings. *} +(* types atom_sort = string *) + +text {* To deal with Church-like binding we use trees of + strings as sorts. *} + +datatype atom_sort = Sort "string" "atom_sort list" + +datatype atom = Atom atom_sort nat + + +text {* Basic projection function. *} + +primrec + sort_of :: "atom \ atom_sort" +where + "sort_of (Atom s n) = s" + +primrec + nat_of :: "atom \ nat" +where + "nat_of (Atom s n) = n" + + +text {* There are infinitely many atoms of each sort. *} +lemma INFM_sort_of_eq: + shows "INFM a. sort_of a = s" +proof - + have "INFM i. sort_of (Atom s i) = s" by simp + moreover have "inj (Atom s)" by (simp add: inj_on_def) + ultimately show "INFM a. sort_of a = s" by (rule INFM_inj) +qed + +lemma infinite_sort_of_eq: + shows "infinite {a. sort_of a = s}" + using INFM_sort_of_eq unfolding INFM_iff_infinite . + +lemma atom_infinite [simp]: + shows "infinite (UNIV :: atom set)" + using subset_UNIV infinite_sort_of_eq + by (rule infinite_super) + +lemma obtain_atom: + fixes X :: "atom set" + assumes X: "finite X" + obtains a where "a \ X" "sort_of a = s" +proof - + from X have "MOST a. a \ X" + unfolding MOST_iff_cofinite by simp + with INFM_sort_of_eq + have "INFM a. sort_of a = s \ a \ X" + by (rule INFM_conjI) + then obtain a where "a \ X" "sort_of a = s" + by (auto elim: INFM_E) + then show ?thesis .. +qed + +lemma atom_components_eq_iff: + fixes a b :: atom + shows "a = b \ sort_of a = sort_of b \ nat_of a = nat_of b" + by (induct a, induct b, simp) + + +section {* Sort-Respecting Permutations *} + +definition "sort_respecting p \ (\a. sort_of (gpermute p a) = sort_of a)" + +lemma sort_respecting_0[simp]: + "sort_respecting (0\atom gperm)" + by (simp add: sort_respecting_def) + +typedef (open) perm = "{p::atom gperm. sort_respecting p}" + by (auto intro: exI[of _ "0"]) + +lemma perm_eq_rep: + "p = q \ Rep_perm p = Rep_perm q" + by (simp add: Rep_perm_inject) + +definition mk_perm :: "atom gperm \ perm" where + "mk_perm p = Abs_perm (if sort_respecting p then p else 0)" + +lemma sort_respecting_Rep_perm [simp, intro]: + "sort_respecting (Rep_perm p)" + using Rep_perm [of p] by simp + +lemma Rep_perm_mk_perm [simp]: + "Rep_perm (mk_perm p) = (if sort_respecting p then p else 0)" + by (simp add: mk_perm_def Abs_perm_inverse) + +lemma mk_perm_Rep_perm [simp, code abstype]: + "mk_perm (Rep_perm dxs) = dxs" + by (simp add: mk_perm_def Rep_perm_inverse) + +instance perm :: size .. + +instantiation perm :: group_add +begin + +definition "(0 :: perm) = mk_perm 0" + +definition "uminus p = mk_perm (uminus (Rep_perm p))" + +definition "p + q = mk_perm ((Rep_perm p) + (Rep_perm q))" + +definition "(p :: perm) - q = p + - q" + +lemma [simp]: + "sort_respecting x \ sort_respecting y \ sort_respecting (x + y)" + unfolding sort_respecting_def + by descending (simp add: perm_add_apply) + +lemma [simp]: + "sort_respecting y \ sort_respecting (- y)" + unfolding sort_respecting_def + by partiality_descending + (auto, metis perm_apply_minus) + +lemma Rep_perm_0 [simp, code abstract]: + "Rep_perm 0 = 0" + by (simp add: zero_perm_def) + +lemma Rep_perm_uminus [simp, code abstract]: + "Rep_perm (- p) = - (Rep_perm p)" + by (simp add: uminus_perm_def) + +lemma Rep_perm_add [simp, code abstract]: + "Rep_perm (p + q) = (Rep_perm p) + (Rep_perm q)" + by (simp add: plus_perm_def) + +instance + by default (auto simp add: perm_eq_rep add_assoc minus_perm_def) + +end + +definition swap :: "atom \ atom \ perm" ("'(_ \ _')") +where "swap a b = (if sort_of a = sort_of b then mk_perm (gswap a b) else 0)" + +lemma sort_respecting_swap [simp]: + "sort_of a = sort_of b \ sort_respecting (gswap a b)" + unfolding sort_respecting_def + by descending auto + +lemma Rep_swap [simp, code abstract]: + "Rep_perm (swap a b) = (if sort_of a = sort_of b then gswap a b else 0)" + by (simp add: swap_def) + +lemma swap_different_sorts [simp]: + "sort_of a \ sort_of b \ (a \ b) = 0" + by (simp add: perm_eq_rep) + +lemma swap_cancel: + shows "(a \ b) + (a \ b) = 0" + and "(a \ b) + (b \ a) = 0" + by (simp_all add: perm_eq_rep) + +lemma swap_self [simp]: + "(a \ a) = 0" + by (simp add: perm_eq_rep) + +lemma minus_swap [simp]: + "- (a \ b) = (a \ b)" + by (simp add: perm_eq_rep) + +lemma swap_commute: + "(a \ b) = (b \ a)" + by (simp add: perm_eq_rep swap_commute) + +lemma swap_triple: + assumes "a \ b" and "c \ b" + assumes "sort_of a = sort_of b" "sort_of b = sort_of c" + shows "(a \ c) + (b \ c) + (a \ c) = (a \ b)" + using assms by (simp add: perm_eq_rep swap_triple) + +section {* Permutation Types *} + +text {* + Infix syntax for @{text permute} has higher precedence than + addition, but lower than unary minus. +*} + +class pt = + fixes permute :: "perm \ 'a \ 'a" ("_ \ _" [76, 75] 75) + assumes permute_zero [simp]: "0 \ x = x" + assumes permute_plus [simp]: "(p + q) \ x = p \ (q \ x)" +begin + +lemma permute_diff [simp]: + shows "(p - q) \ x = p \ - q \ x" + unfolding diff_minus by simp + +lemma permute_minus_cancel [simp]: + shows "p \ - p \ x = x" + and "- p \ p \ x = x" + unfolding permute_plus [symmetric] by simp_all + +lemma permute_swap_cancel [simp]: + shows "(a \ b) \ (a \ b) \ x = x" + unfolding permute_plus [symmetric] + by (simp add: swap_cancel) + +lemma permute_swap_cancel2 [simp]: + shows "(a \ b) \ (b \ a) \ x = x" + unfolding permute_plus [symmetric] + by (simp add: swap_commute) + +lemma inj_permute [simp]: + shows "inj (permute p)" + by (rule inj_on_inverseI) + (rule permute_minus_cancel) + +lemma surj_permute [simp]: + shows "surj (permute p)" + by (rule surjI, rule permute_minus_cancel) + +lemma bij_permute [simp]: + shows "bij (permute p)" + by (rule bijI [OF inj_permute surj_permute]) + +lemma inv_permute: + shows "inv (permute p) = permute (- p)" + by (rule inv_equality) (simp_all) + +lemma permute_minus: + shows "permute (- p) = inv (permute p)" + by (simp add: inv_permute) + +lemma permute_eq_iff [simp]: + shows "p \ x = p \ y \ x = y" + by (rule inj_permute [THEN inj_eq]) + +end + +subsection {* Permutations for atoms *} + +instantiation atom :: pt +begin + +definition + "p \ a = gpermute (Rep_perm p) a" + +instance + by default (simp_all add: permute_atom_def) + +end + +lemma sort_of_permute [simp]: + shows "sort_of (p \ a) = sort_of a" + by (metis sort_respecting_Rep_perm sort_respecting_def permute_atom_def) + +lemma swap_atom: + shows "(a \ b) \ c = + (if sort_of a = sort_of b + then (if c = a then b else if c = b then a else c) else c)" + by (auto simp add: permute_atom_def) + +lemma swap_atom_simps [simp]: + "sort_of a = sort_of b \ (a \ b) \ a = b" + "sort_of a = sort_of b \ (a \ b) \ b = a" + "c \ a \ c \ b \ (a \ b) \ c = c" + unfolding swap_atom by simp_all + +lemma perm_eq_iff: + fixes p q :: "perm" + shows "p = q \ (\a::atom. p \ a = q \ a)" + unfolding permute_atom_def perm_eq_rep + by (simp add: gperm_eq) + +subsection {* Permutations for permutations *} + +instantiation perm :: pt +begin + +definition + "p \ q = p + q - p" + +instance + by default + (simp_all add: permute_perm_def diff_minus minus_add add_assoc) + +end + +lemma permute_self: + shows "p \ p = p" + unfolding permute_perm_def + by (simp add: diff_minus add_assoc) + +lemma pemute_minus_self: + shows "- p \ p = p" + unfolding permute_perm_def + by (simp add: diff_minus add_assoc) + + +subsection {* Permutations for functions *} + +instantiation "fun" :: (pt, pt) pt +begin + +definition + "p \ f = (\x. p \ (f (- p \ x)))" + +instance + by default + (simp_all add: permute_fun_def minus_add) + +end + +lemma permute_fun_app_eq: + shows "p \ (f x) = (p \ f) (p \ x)" + unfolding permute_fun_def by simp + + +subsection {* Permutations for booleans *} + +instantiation bool :: pt +begin + +definition "p \ (b::bool) = b" + +instance + by (default) + (simp_all add: permute_bool_def) + +end + +lemma permute_boolE: + fixes P::"bool" + shows "p \ P \ P" + by (simp add: permute_bool_def) + +lemma permute_boolI: + fixes P::"bool" + shows "P \ p \ P" + by(simp add: permute_bool_def) + +subsection {* Permutations for sets *} + +instantiation "set" :: (pt) pt +begin + +definition + "p \ X = {p \ x | x. x \ X}" + +instance +apply default +apply (auto simp add: permute_set_def) +done + +end + +lemma permute_set_eq: + shows "p \ X = {x. - p \ x \ X}" +unfolding permute_set_def +by (auto) (metis permute_minus_cancel(1)) + +lemma permute_set_eq_image: + shows "p \ X = permute p ` X" + unfolding permute_set_def by auto + +lemma permute_set_eq_vimage: + shows "p \ X = permute (- p) -` X" + unfolding permute_set_eq vimage_def + by simp + +lemma permute_finite [simp]: + shows "finite (p \ X) = finite X" + unfolding permute_set_eq_vimage + using bij_permute by (rule finite_vimage_iff) + +lemma swap_set_not_in: + assumes a: "a \ S" "b \ S" + shows "(a \ b) \ S = S" + unfolding permute_set_def + using a by (auto simp add: swap_atom) + +lemma swap_set_in: + assumes a: "a \ S" "b \ S" "sort_of a = sort_of b" + shows "(a \ b) \ S \ S" + unfolding permute_set_def + using a by (auto simp add: swap_atom) + +lemma swap_set_in_eq: + assumes a: "a \ S" "b \ S" "sort_of a = sort_of b" + shows "(a \ b) \ S = (S - {a}) \ {b}" + unfolding permute_set_def + using a by (auto simp add: swap_atom) + +lemma swap_set_both_in: + assumes a: "a \ S" "b \ S" + shows "(a \ b) \ S = S" + unfolding permute_set_def + using a by (auto simp add: swap_atom) + +lemma mem_permute_iff: + shows "(p \ x) \ (p \ X) \ x \ X" + unfolding permute_set_def + by auto + +lemma empty_eqvt: + shows "p \ {} = {}" + unfolding permute_set_def + by (simp) + +lemma insert_eqvt: + shows "p \ (insert x A) = insert (p \ x) (p \ A)" + unfolding permute_set_eq_image image_insert .. + + +subsection {* Permutations for @{typ unit} *} + +instantiation unit :: pt +begin + +definition "p \ (u::unit) = u" + +instance +by (default) (simp_all add: permute_unit_def) + +end + + +subsection {* Permutations for products *} + +instantiation prod :: (pt, pt) pt +begin + +primrec + permute_prod +where + Pair_eqvt: "p \ (x, y) = (p \ x, p \ y)" + +instance +by default auto + +end + +subsection {* Permutations for sums *} + +instantiation sum :: (pt, pt) pt +begin + +primrec + permute_sum +where + Inl_eqvt: "p \ (Inl x) = Inl (p \ x)" +| Inr_eqvt: "p \ (Inr y) = Inr (p \ y)" + +instance +by (default) (case_tac [!] x, simp_all) + +end + +subsection {* Permutations for @{typ "'a list"} *} + +instantiation list :: (pt) pt +begin + +primrec + permute_list +where + Nil_eqvt: "p \ [] = []" +| Cons_eqvt: "p \ (x # xs) = p \ x # p \ xs" + +instance +by (default) (induct_tac [!] x, simp_all) + +end + +lemma set_eqvt: + shows "p \ (set xs) = set (p \ xs)" + by (induct xs) (simp_all add: empty_eqvt insert_eqvt) + + + +subsection {* Permutations for @{typ "'a option"} *} + +instantiation option :: (pt) pt +begin + +primrec + permute_option +where + None_eqvt: "p \ None = None" +| Some_eqvt: "p \ (Some x) = Some (p \ x)" + +instance +by (default) (induct_tac [!] x, simp_all) + +end + +subsection {* Permutations for @{typ "'a multiset"} *} + +instantiation multiset :: (pt) pt +begin + +definition + "p \ M = {# p \ x. x :# M #}" + +instance +proof + fix M :: "'a multiset" and p q :: "perm" + show "0 \ M = M" + unfolding permute_multiset_def + by (induct_tac M) (simp_all) + show "(p + q) \ M = p \ q \ M" + unfolding permute_multiset_def + by (induct_tac M) (simp_all) +qed + +end + +lemma permute_multiset [simp]: + fixes M N::"('a::pt) multiset" + shows "(p \ {#}) = ({#} ::('a::pt) multiset)" + and "(p \ {# x #}) = {# p \ x #}" + and "(p \ (M + N)) = (p \ M) + (p \ N)" + unfolding permute_multiset_def + by (simp_all) + + +subsection {* Permutations for @{typ "'a fset"} *} + +lemma permute_fset_rsp[quot_respect]: + shows "(op = ===> list_eq ===> list_eq) permute permute" + unfolding fun_rel_def + by (simp add: set_eqvt[symmetric]) + +instantiation fset :: (pt) pt +begin + +quotient_definition + "permute_fset :: perm \ 'a fset \ 'a fset" +is + "permute :: perm \ 'a list \ 'a list" + +instance +proof + fix x :: "'a fset" and p q :: "perm" + have lst: "\l :: 'a list. 0 \ l = l" by simp + show "0 \ x = x" by (lifting lst) + have lst: "\p q :: perm. \x :: 'a list. (p + q) \ x = p \ q \ x" by simp + show "(p + q) \ x = p \ q \ x" by (lifting lst) +qed + +end + +lemma permute_fset [simp]: + fixes S::"('a::pt) fset" + shows "(p \ {||}) = ({||} ::('a::pt) fset)" + and "(p \ insert_fset x S) = insert_fset (p \ x) (p \ S)" + by (lifting permute_list.simps) + +lemma fset_eqvt: + shows "p \ (fset S) = fset (p \ S)" + by (lifting set_eqvt) + + +subsection {* Permutations for @{typ char}, @{typ nat}, and @{typ int} *} + +instantiation char :: pt +begin + +definition "p \ (c::char) = c" + +instance +by (default) (simp_all add: permute_char_def) + +end + +instantiation nat :: pt +begin + +definition "p \ (n::nat) = n" + +instance +by (default) (simp_all add: permute_nat_def) + +end + +instantiation int :: pt +begin + +definition "p \ (i::int) = i" + +instance +by (default) (simp_all add: permute_int_def) + +end + + +section {* Pure types *} + +text {* Pure types will have always empty support. *} + +class pure = pt + + assumes permute_pure: "p \ x = x" + +text {* Types @{typ unit} and @{typ bool} are pure. *} + +instance unit :: pure +proof qed (rule permute_unit_def) + +instance bool :: pure +proof qed (rule permute_bool_def) + + +text {* Other type constructors preserve purity. *} + +instance "fun" :: (pure, pure) pure +by default (simp add: permute_fun_def permute_pure) + +instance set :: (pure) pure +by default (simp add: permute_set_def permute_pure) + +instance prod :: (pure, pure) pure +by default (induct_tac x, simp add: permute_pure) + +instance sum :: (pure, pure) pure +by default (induct_tac x, simp_all add: permute_pure) + +instance list :: (pure) pure +by default (induct_tac x, simp_all add: permute_pure) + +instance option :: (pure) pure +by default (induct_tac x, simp_all add: permute_pure) + + +subsection {* Types @{typ char}, @{typ nat}, and @{typ int} *} + +instance char :: pure +proof qed (rule permute_char_def) + +instance nat :: pure +proof qed (rule permute_nat_def) + +instance int :: pure +proof qed (rule permute_int_def) + + +section {* Infrastructure for Equivariance and Perm_simp *} + +subsection {* Basic functions about permutations *} + +use "nominal_basics.ML" + + +subsection {* Eqvt infrastructure *} + +text {* Setup of the theorem attributes @{text eqvt} and @{text eqvt_raw} *} + +use "nominal_thmdecls.ML" +setup "Nominal_ThmDecls.setup" + + +lemmas [eqvt] = + (* pt types *) + permute_prod.simps + permute_list.simps + permute_option.simps + permute_sum.simps + + (* sets *) + empty_eqvt insert_eqvt set_eqvt + + (* fsets *) + permute_fset fset_eqvt + + (* multisets *) + permute_multiset + +subsection {* perm_simp infrastructure *} + +definition + "unpermute p = permute (- p)" + +lemma eqvt_apply: + fixes f :: "'a::pt \ 'b::pt" + and x :: "'a::pt" + shows "p \ (f x) \ (p \ f) (p \ x)" + unfolding permute_fun_def by simp + +lemma eqvt_lambda: + fixes f :: "'a::pt \ 'b::pt" + shows "p \ f \ (\x. p \ (f (unpermute p x)))" + unfolding permute_fun_def unpermute_def by simp + +lemma eqvt_bound: + shows "p \ unpermute p x \ x" + unfolding unpermute_def by simp + +text {* provides perm_simp methods *} + +use "nominal_permeq.ML" + +method_setup perm_simp = + {* Nominal_Permeq.args_parser >> Nominal_Permeq.perm_simp_meth *} + {* pushes permutations inside. *} + +method_setup perm_strict_simp = + {* Nominal_Permeq.args_parser >> Nominal_Permeq.perm_strict_simp_meth *} + {* pushes permutations inside, raises an error if it cannot solve all permutations. *} + + +subsubsection {* Equivariance for permutations and swapping *} + +lemma permute_eqvt: + shows "p \ (q \ x) = (p \ q) \ (p \ x)" + unfolding permute_perm_def by simp + +(* the normal version of this lemma would cause loops *) +lemma permute_eqvt_raw [eqvt_raw]: + shows "p \ permute \ permute" +apply(simp add: fun_eq_iff permute_fun_def) +apply(subst permute_eqvt) +apply(simp) +done + +lemma zero_perm_eqvt [eqvt]: + shows "p \ (0::perm) = 0" + unfolding permute_perm_def by simp + +lemma add_perm_eqvt [eqvt]: + fixes p p1 p2 :: perm + shows "p \ (p1 + p2) = p \ p1 + p \ p2" + unfolding permute_perm_def + by (simp add: perm_eq_iff) + +lemma swap_eqvt [eqvt]: + shows "p \ (a \ b) = (p \ a \ p \ b)" + unfolding permute_perm_def + by (auto simp add: swap_atom perm_eq_iff) + +lemma uminus_eqvt [eqvt]: + fixes p q::"perm" + shows "p \ (- q) = - (p \ q)" + unfolding permute_perm_def + by (simp add: diff_minus minus_add add_assoc) + +subsubsection {* Equivariance of Logical Operators *} + +lemma eq_eqvt [eqvt]: + shows "p \ (x = y) \ (p \ x) = (p \ y)" + unfolding permute_eq_iff permute_bool_def .. + +lemma Not_eqvt [eqvt]: + shows "p \ (\ A) \ \ (p \ A)" + by (simp add: permute_bool_def) + +lemma conj_eqvt [eqvt]: + shows "p \ (A \ B) \ (p \ A) \ (p \ B)" + by (simp add: permute_bool_def) + +lemma imp_eqvt [eqvt]: + shows "p \ (A \ B) \ (p \ A) \ (p \ B)" + by (simp add: permute_bool_def) + +declare imp_eqvt[folded induct_implies_def, eqvt] + +lemma all_eqvt [eqvt]: + shows "p \ (\x. P x) = (\x. (p \ P) x)" + unfolding All_def + by (perm_simp) (rule refl) + +declare all_eqvt[folded induct_forall_def, eqvt] + +lemma ex_eqvt [eqvt]: + shows "p \ (\x. P x) = (\x. (p \ P) x)" + unfolding Ex_def + by (perm_simp) (rule refl) + +lemma ex1_eqvt [eqvt]: + shows "p \ (\!x. P x) = (\!x. (p \ P) x)" + unfolding Ex1_def + by (perm_simp) (rule refl) + +lemma if_eqvt [eqvt]: + shows "p \ (if b then x else y) = (if p \ b then p \ x else p \ y)" + by (simp add: permute_fun_def permute_bool_def) + +lemma True_eqvt [eqvt]: + shows "p \ True = True" + unfolding permute_bool_def .. + +lemma False_eqvt [eqvt]: + shows "p \ False = False" + unfolding permute_bool_def .. + +lemma disj_eqvt [eqvt]: + shows "p \ (A \ B) \ (p \ A) \ (p \ B)" + by (simp add: permute_bool_def) + +lemma all_eqvt2: + shows "p \ (\x. P x) = (\x. p \ P (- p \ x))" + by (perm_simp add: permute_minus_cancel) (rule refl) + +lemma ex_eqvt2: + shows "p \ (\x. P x) = (\x. p \ P (- p \ x))" + by (perm_simp add: permute_minus_cancel) (rule refl) + +lemma ex1_eqvt2: + shows "p \ (\!x. P x) = (\!x. p \ P (- p \ x))" + by (perm_simp add: permute_minus_cancel) (rule refl) + +lemma the_eqvt: + assumes unique: "\!x. P x" + shows "(p \ (THE x. P x)) = (THE x. (p \ P) x)" + apply(rule the1_equality [symmetric]) + apply(rule_tac p="-p" in permute_boolE) + apply(perm_simp add: permute_minus_cancel) + apply(rule unique) + apply(rule_tac p="-p" in permute_boolE) + apply(perm_simp add: permute_minus_cancel) + apply(rule theI'[OF unique]) + done + +lemma the_eqvt2: + assumes unique: "\!x. P x" + shows "(p \ (THE x. P x)) = (THE x. p \ P (- p \ x))" + apply(rule the1_equality [symmetric]) + apply(simp add: ex1_eqvt2[symmetric]) + apply(simp add: permute_bool_def unique) + apply(simp add: permute_bool_def) + apply(rule theI'[OF unique]) + done + +subsubsection {* Equivariance of Set operators *} + +lemma mem_eqvt [eqvt]: + shows "p \ (x \ A) \ (p \ x) \ (p \ A)" + unfolding permute_bool_def permute_set_def + by (auto) + +lemma Collect_eqvt [eqvt]: + shows "p \ {x. P x} = {x. (p \ P) x}" + unfolding permute_set_eq permute_fun_def + by (auto simp add: permute_bool_def) + +lemma inter_eqvt [eqvt]: + shows "p \ (A \ B) = (p \ A) \ (p \ B)" + unfolding Int_def + by (perm_simp) (rule refl) + +lemma Bex_eqvt [eqvt]: + shows "p \ (\x \ S. P x) = (\x \ (p \ S). (p \ P) x)" + unfolding Bex_def + by (perm_simp) (rule refl) + +lemma Ball_eqvt [eqvt]: + shows "p \ (\x \ S. P x) = (\x \ (p \ S). (p \ P) x)" + unfolding Ball_def + by (perm_simp) (rule refl) + +lemma image_eqvt [eqvt]: + shows "p \ (f ` A) = (p \ f) ` (p \ A)" + unfolding image_def + by (perm_simp) (rule refl) + +lemma Image_eqvt [eqvt]: + shows "p \ (R `` A) = (p \ R) `` (p \ A)" + unfolding Image_def + by (perm_simp) (rule refl) + +lemma UNIV_eqvt [eqvt]: + shows "p \ UNIV = UNIV" + unfolding UNIV_def + by (perm_simp) (rule refl) + +lemma union_eqvt [eqvt]: + shows "p \ (A \ B) = (p \ A) \ (p \ B)" + unfolding Un_def + by (perm_simp) (rule refl) + +lemma Diff_eqvt [eqvt]: + fixes A B :: "'a::pt set" + shows "p \ (A - B) = (p \ A) - (p \ B)" + unfolding set_diff_eq + by (perm_simp) (rule refl) + +lemma Compl_eqvt [eqvt]: + fixes A :: "'a::pt set" + shows "p \ (- A) = - (p \ A)" + unfolding Compl_eq_Diff_UNIV + by (perm_simp) (rule refl) + +lemma subset_eqvt [eqvt]: + shows "p \ (S \ T) \ (p \ S) \ (p \ T)" + unfolding subset_eq + by (perm_simp) (rule refl) + +lemma psubset_eqvt [eqvt]: + shows "p \ (S \ T) \ (p \ S) \ (p \ T)" + unfolding psubset_eq + by (perm_simp) (rule refl) + +lemma vimage_eqvt [eqvt]: + shows "p \ (f -` A) = (p \ f) -` (p \ A)" + unfolding vimage_def + by (perm_simp) (rule refl) + +lemma Union_eqvt [eqvt]: + shows "p \ (\ S) = \ (p \ S)" + unfolding Union_eq + by (perm_simp) (rule refl) + +lemma Inter_eqvt [eqvt]: + shows "p \ (\ S) = \ (p \ S)" + unfolding Inter_eq + by (perm_simp) (rule refl) + +(* FIXME: eqvt attribute *) +lemma Sigma_eqvt: + shows "(p \ (X \ Y)) = (p \ X) \ (p \ Y)" +unfolding Sigma_def +unfolding SUP_def +by (perm_simp) (rule refl) + +text {* + In order to prove that lfp is equivariant we need two + auxiliary classes which specify that (op <=) and + Inf are equivariant. Instances for bool and fun are + given. +*} + +class le_eqvt = order + + assumes le_eqvt [eqvt]: "p \ (x \ y) = ((p \ x) \ (p \ (y::('a::{pt, order}))))" + +class inf_eqvt = complete_lattice + + assumes inf_eqvt [eqvt]: "p \ (Inf X) = Inf (p \ (X::('a::{pt, Inf}) set))" + +instantiation bool :: le_eqvt +begin + +instance +apply(default) +apply perm_simp +apply(rule refl) +done + +end + +instantiation "fun" :: (pt, le_eqvt) le_eqvt +begin + +instance +apply(default) +unfolding le_fun_def +apply(perm_simp) +apply(rule refl) +done + +end + +instantiation bool :: inf_eqvt +begin + +instance +apply(default) +apply(perm_simp) +apply(rule refl) +done + +end + +instantiation "fun" :: (pt, inf_eqvt) inf_eqvt +begin + +instance +apply(default) +unfolding Inf_fun_def INF_def +apply(perm_simp) +apply(rule refl) +done + +end + +lemma lfp_eqvt [eqvt]: + fixes F::"('a \ 'b) \ ('a::pt \ 'b::{inf_eqvt, le_eqvt})" + shows "p \ (lfp F) = lfp (p \ F)" +unfolding lfp_def +by (perm_simp) (rule refl) + +lemma finite_eqvt [eqvt]: + shows "p \ finite A = finite (p \ A)" +unfolding finite_def +by (perm_simp) (rule refl) + + +subsubsection {* Equivariance for product operations *} + +lemma fst_eqvt [eqvt]: + shows "p \ (fst x) = fst (p \ x)" + by (cases x) simp + +lemma snd_eqvt [eqvt]: + shows "p \ (snd x) = snd (p \ x)" + by (cases x) simp + +lemma split_eqvt [eqvt]: + shows "p \ (split P x) = split (p \ P) (p \ x)" + unfolding split_def + by (perm_simp) (rule refl) + + +subsubsection {* Equivariance for list operations *} + +lemma append_eqvt [eqvt]: + shows "p \ (xs @ ys) = (p \ xs) @ (p \ ys)" + by (induct xs) auto + +lemma rev_eqvt [eqvt]: + shows "p \ (rev xs) = rev (p \ xs)" + by (induct xs) (simp_all add: append_eqvt) + +lemma map_eqvt [eqvt]: + shows "p \ (map f xs) = map (p \ f) (p \ xs)" + by (induct xs) (simp_all, simp only: permute_fun_app_eq) + +lemma removeAll_eqvt [eqvt]: + shows "p \ (removeAll x xs) = removeAll (p \ x) (p \ xs)" + by (induct xs) (auto) + +lemma filter_eqvt [eqvt]: + shows "p \ (filter f xs) = filter (p \ f) (p \ xs)" +apply(induct xs) +apply(simp) +apply(simp only: filter.simps permute_list.simps if_eqvt) +apply(simp only: permute_fun_app_eq) +done + +lemma distinct_eqvt [eqvt]: + shows "p \ (distinct xs) = distinct (p \ xs)" +apply(induct xs) +apply(simp add: permute_bool_def) +apply(simp add: conj_eqvt Not_eqvt mem_eqvt set_eqvt) +done + +lemma length_eqvt [eqvt]: + shows "p \ (length xs) = length (p \ xs)" +by (induct xs) (simp_all add: permute_pure) + + +subsubsection {* Equivariance for @{typ "'a option"} *} + +lemma option_map_eqvt[eqvt]: + shows "p \ (Option.map f x) = Option.map (p \ f) (p \ x)" + by (cases x) (simp_all, simp add: permute_fun_app_eq) + + +subsubsection {* Equivariance for @{typ "'a fset"} *} + +lemma in_fset_eqvt [eqvt]: + shows "(p \ (x |\| S)) = ((p \ x) |\| (p \ S))" +unfolding in_fset +by (perm_simp) (simp) + +lemma union_fset_eqvt [eqvt]: + shows "(p \ (S |\| T)) = ((p \ S) |\| (p \ T))" + by (induct S) (simp_all) + +lemma inter_list_eqvt [eqvt]: + shows "p \ (inter_list S T) = inter_list (p \ S) (p \ T)" + unfolding list_eq_def inter_list_def + by perm_simp simp + +lemma inter_fset_eqvt [eqvt]: + shows "(p \ (S |\| T)) = ((p \ S) |\| (p \ T))" + by (lifting inter_list_eqvt) + +lemma sub_list_eqvt [eqvt]: + shows "p \ (sub_list S T) = sub_list (p \ S) (p \ T)" + unfolding sub_list_def + by perm_simp simp + +lemma subset_fset_eqvt [eqvt]: + shows "(p \ (S |\| T)) = ((p \ S) |\| (p \ T))" + by (lifting sub_list_eqvt) + +lemma map_fset_eqvt [eqvt]: + shows "p \ (map_fset f S) = map_fset (p \ f) (p \ S)" + by (lifting map_eqvt) + + +section {* Supp, Freshness and Supports *} + +context pt +begin + +definition + supp :: "'a \ atom set" +where + "supp x = {a. infinite {b. (a \ b) \ x \ x}}" + +definition + fresh :: "atom \ 'a \ bool" ("_ \ _" [55, 55] 55) +where + "a \ x \ a \ supp x" + +end + +lemma supp_conv_fresh: + shows "supp x = {a. \ a \ x}" + unfolding fresh_def by simp + +lemma swap_rel_trans: + assumes "sort_of a = sort_of b" + assumes "sort_of b = sort_of c" + assumes "(a \ c) \ x = x" + assumes "(b \ c) \ x = x" + shows "(a \ b) \ x = x" +proof (cases) + assume "a = b \ c = b" + with assms show "(a \ b) \ x = x" by auto +next + assume *: "\ (a = b \ c = b)" + have "((a \ c) + (b \ c) + (a \ c)) \ x = x" + using assms by simp + also have "(a \ c) + (b \ c) + (a \ c) = (a \ b)" + using assms * by (simp add: swap_triple) + finally show "(a \ b) \ x = x" . +qed + +lemma swap_fresh_fresh: + assumes a: "a \ x" + and b: "b \ x" + shows "(a \ b) \ x = x" +proof (cases) + assume asm: "sort_of a = sort_of b" + have "finite {c. (a \ c) \ x \ x}" "finite {c. (b \ c) \ x \ x}" + using a b unfolding fresh_def supp_def by simp_all + then have "finite ({c. (a \ c) \ x \ x} \ {c. (b \ c) \ x \ x})" by simp + then obtain c + where "(a \ c) \ x = x" "(b \ c) \ x = x" "sort_of c = sort_of b" + by (rule obtain_atom) (auto) + then show "(a \ b) \ x = x" using asm by (rule_tac swap_rel_trans) (simp_all) +next + assume "sort_of a \ sort_of b" + then show "(a \ b) \ x = x" by simp +qed + + +subsection {* supp and fresh are equivariant *} + + +lemma supp_eqvt [eqvt]: + shows "p \ (supp x) = supp (p \ x)" + unfolding supp_def + by (perm_simp) + (simp only: permute_eqvt[symmetric]) + +lemma fresh_eqvt [eqvt]: + shows "p \ (a \ x) = (p \ a) \ (p \ x)" + unfolding fresh_def + by (perm_simp) (rule refl) + +lemma fresh_permute_iff: + shows "(p \ a) \ (p \ x) \ a \ x" + by (simp only: fresh_eqvt[symmetric] permute_bool_def) + +lemma fresh_permute_left: + shows "a \ p \ x \ - p \ a \ x" +proof + assume "a \ p \ x" + then have "- p \ a \ - p \ p \ x" by (simp only: fresh_permute_iff) + then show "- p \ a \ x" by simp +next + assume "- p \ a \ x" + then have "p \ - p \ a \ p \ x" by (simp only: fresh_permute_iff) + then show "a \ p \ x" by simp +qed + + +section {* supports *} + +definition + supports :: "atom set \ 'a::pt \ bool" (infixl "supports" 80) +where + "S supports x \ \a b. (a \ S \ b \ S \ (a \ b) \ x = x)" + +lemma supp_is_subset: + fixes S :: "atom set" + and x :: "'a::pt" + assumes a1: "S supports x" + and a2: "finite S" + shows "(supp x) \ S" +proof (rule ccontr) + assume "\ (supp x \ S)" + then obtain a where b1: "a \ supp x" and b2: "a \ S" by auto + from a1 b2 have "\b. b \ S \ (a \ b) \ x = x" unfolding supports_def by auto + then have "{b. (a \ b) \ x \ x} \ S" by auto + with a2 have "finite {b. (a \ b) \ x \ x}" by (simp add: finite_subset) + then have "a \ (supp x)" unfolding supp_def by simp + with b1 show False by simp +qed + +lemma supports_finite: + fixes S :: "atom set" + and x :: "'a::pt" + assumes a1: "S supports x" + and a2: "finite S" + shows "finite (supp x)" +proof - + have "(supp x) \ S" using a1 a2 by (rule supp_is_subset) + then show "finite (supp x)" using a2 by (simp add: finite_subset) +qed + +lemma supp_supports: + fixes x :: "'a::pt" + shows "(supp x) supports x" +unfolding supports_def +proof (intro strip) + fix a b + assume "a \ (supp x) \ b \ (supp x)" + then have "a \ x" and "b \ x" by (simp_all add: fresh_def) + then show "(a \ b) \ x = x" by (simp add: swap_fresh_fresh) +qed + +lemma supports_fresh: + fixes x :: "'a::pt" + assumes a1: "S supports x" + and a2: "finite S" + and a3: "a \ S" + shows "a \ x" +unfolding fresh_def +proof - + have "(supp x) \ S" using a1 a2 by (rule supp_is_subset) + then show "a \ (supp x)" using a3 by auto +qed + +lemma supp_is_least_supports: + fixes S :: "atom set" + and x :: "'a::pt" + assumes a1: "S supports x" + and a2: "finite S" + and a3: "\S'. finite S' \ (S' supports x) \ S \ S'" + shows "(supp x) = S" +proof (rule equalityI) + show "(supp x) \ S" using a1 a2 by (rule supp_is_subset) + with a2 have fin: "finite (supp x)" by (rule rev_finite_subset) + have "(supp x) supports x" by (rule supp_supports) + with fin a3 show "S \ supp x" by blast +qed + + +lemma subsetCI: + shows "(\x. x \ A \ x \ B \ False) \ A \ B" + by auto + +lemma finite_supp_unique: + assumes a1: "S supports x" + assumes a2: "finite S" + assumes a3: "\a b. \a \ S; b \ S; sort_of a = sort_of b\ \ (a \ b) \ x \ x" + shows "(supp x) = S" + using a1 a2 +proof (rule supp_is_least_supports) + fix S' + assume "finite S'" and "S' supports x" + show "S \ S'" + proof (rule subsetCI) + fix a + assume "a \ S" and "a \ S'" + have "finite (S \ S')" + using `finite S` `finite S'` by simp + then obtain b where "b \ S \ S'" and "sort_of b = sort_of a" + by (rule obtain_atom) + then have "b \ S" and "b \ S'" and "sort_of a = sort_of b" + by simp_all + then have "(a \ b) \ x = x" + using `a \ S'` `S' supports x` by (simp add: supports_def) + moreover have "(a \ b) \ x \ x" + using `a \ S` `b \ S` `sort_of a = sort_of b` + by (rule a3) + ultimately show "False" by simp + qed +qed + +section {* Support w.r.t. relations *} + +text {* + This definition is used for unquotient types, where + alpha-equivalence does not coincide with equality. +*} + +definition + "supp_rel R x = {a. infinite {b. \(R ((a \ b) \ x) x)}}" + + + +section {* Finitely-supported types *} + +class fs = pt + + assumes finite_supp: "finite (supp x)" + +lemma pure_supp: + fixes x::"'a::pure" + shows "supp x = {}" + unfolding supp_def by (simp add: permute_pure) + +lemma pure_fresh: + fixes x::"'a::pure" + shows "a \ x" + unfolding fresh_def by (simp add: pure_supp) + +instance pure < fs +by default (simp add: pure_supp) + + +subsection {* Type @{typ atom} is finitely-supported. *} + +lemma supp_atom: + shows "supp a = {a}" + by (rule finite_supp_unique) + (auto simp add: supports_def) + +lemma fresh_atom: + shows "a \ b \ a \ b" + unfolding fresh_def supp_atom by simp + +instance atom :: fs +by default (simp add: supp_atom) + + +section {* Type @{typ perm} is finitely-supported. *} + +lemma perm_swap_eq: + shows "(a \ b) \ p = p \ (p \ (a \ b)) = (a \ b)" +unfolding permute_perm_def +by (metis add_diff_cancel minus_perm_def) + +lemma supports_perm: + shows "{a. p \ a \ a} supports p" + unfolding supports_def + unfolding perm_swap_eq + by (simp add: swap_eqvt) + +lemma finite_perm_lemma: + shows "finite {a::atom. p \ a \ a}" + unfolding permute_atom_def + using finite_gpermute_neq . + +lemma supp_perm: + shows "supp p = {a. p \ a \ a}" +apply (rule finite_supp_unique) +apply (simp_all add: perm_swap_eq swap_eqvt supports_perm finite_perm_lemma) +apply (auto simp add: perm_eq_iff swap_atom perm_swap_eq swap_eqvt) +done + +lemma fresh_perm: + shows "a \ p \ p \ a = a" + unfolding fresh_def + by (simp add: supp_perm) + +lemma supp_swap: + shows "supp (a \ b) = (if a = b \ sort_of a \ sort_of b then {} else {a, b})" + by (auto simp add: supp_perm swap_atom) + +lemma fresh_zero_perm: + shows "a \ (0::perm)" + unfolding fresh_perm by simp + +lemma supp_zero_perm: + shows "supp (0::perm) = {}" + unfolding supp_perm by simp + +lemma fresh_plus_perm: + fixes p q::perm + assumes "a \ p" "a \ q" + shows "a \ (p + q)" + using assms + unfolding fresh_def + by (auto simp add: supp_perm) + +lemma supp_plus_perm: + fixes p q::perm + shows "supp (p + q) \ supp p \ supp q" + by (auto simp add: supp_perm) + +lemma fresh_minus_perm: + fixes p::perm + shows "a \ (- p) \ a \ p" + unfolding fresh_def supp_perm + by (simp) (metis permute_minus_cancel(1)) + +lemma supp_minus_perm: + fixes p::perm + shows "supp (- p) = supp p" + unfolding supp_conv_fresh + by (simp add: fresh_minus_perm) + +lemma plus_perm_eq: + fixes p q::"perm" + assumes asm: "supp p \ supp q = {}" + shows "p + q = q + p" +unfolding perm_eq_iff +proof + fix a::"atom" + show "(p + q) \ a = (q + p) \ a" + proof - + { assume "a \ supp p" "a \ supp q" + then have "(p + q) \ a = (q + p) \ a" + by (simp add: supp_perm) + } + moreover + { assume a: "a \ supp p" "a \ supp q" + then have "p \ a \ supp p" by (simp add: supp_perm) + then have "p \ a \ supp q" using asm by auto + with a have "(p + q) \ a = (q + p) \ a" + by (simp add: supp_perm) + } + moreover + { assume a: "a \ supp p" "a \ supp q" + then have "q \ a \ supp q" by (simp add: supp_perm) + then have "q \ a \ supp p" using asm by auto + with a have "(p + q) \ a = (q + p) \ a" + by (simp add: supp_perm) + } + ultimately show "(p + q) \ a = (q + p) \ a" + using asm by blast + qed +qed + +lemma supp_plus_perm_eq: + fixes p q::perm + assumes asm: "supp p \ supp q = {}" + shows "supp (p + q) = supp p \ supp q" +proof - + { fix a::"atom" + assume "a \ supp p" + then have "a \ supp q" using asm by auto + then have "a \ supp (p + q)" using `a \ supp p` + by (simp add: supp_perm) + } + moreover + { fix a::"atom" + assume "a \ supp q" + then have "a \ supp p" using asm by auto + then have "a \ supp (q + p)" using `a \ supp q` + by (simp add: supp_perm) + then have "a \ supp (p + q)" using asm plus_perm_eq + by metis + } + ultimately have "supp p \ supp q \ supp (p + q)" + by blast + then show "supp (p + q) = supp p \ supp q" using supp_plus_perm + by blast +qed + +instance perm :: fs +by default (simp add: supp_perm finite_perm_lemma) + + + +section {* Finite Support instances for other types *} + + +subsection {* Type @{typ "'a \ 'b"} is finitely-supported. *} + +lemma supp_Pair: + shows "supp (x, y) = supp x \ supp y" + by (simp add: supp_def Collect_imp_eq Collect_neg_eq) + +lemma fresh_Pair: + shows "a \ (x, y) \ a \ x \ a \ y" + by (simp add: fresh_def supp_Pair) + +lemma supp_Unit: + shows "supp () = {}" + by (simp add: supp_def) + +lemma fresh_Unit: + shows "a \ ()" + by (simp add: fresh_def supp_Unit) + +instance prod :: (fs, fs) fs + by default (auto simp add: supp_Pair finite_supp) + + +subsection {* Type @{typ "'a + 'b"} is finitely supported *} + +lemma supp_Inl: + shows "supp (Inl x) = supp x" + by (simp add: supp_def) + +lemma supp_Inr: + shows "supp (Inr x) = supp x" + by (simp add: supp_def) + +lemma fresh_Inl: + shows "a \ Inl x \ a \ x" + by (simp add: fresh_def supp_Inl) + +lemma fresh_Inr: + shows "a \ Inr y \ a \ y" + by (simp add: fresh_def supp_Inr) + +instance sum :: (fs, fs) fs +apply default +apply (case_tac x) +apply (simp_all add: supp_Inl supp_Inr finite_supp) +done + + +subsection {* Type @{typ "'a option"} is finitely supported *} + +lemma supp_None: + shows "supp None = {}" +by (simp add: supp_def) + +lemma supp_Some: + shows "supp (Some x) = supp x" + by (simp add: supp_def) + +lemma fresh_None: + shows "a \ None" + by (simp add: fresh_def supp_None) + +lemma fresh_Some: + shows "a \ Some x \ a \ x" + by (simp add: fresh_def supp_Some) + +instance option :: (fs) fs +apply default +apply (induct_tac x) +apply (simp_all add: supp_None supp_Some finite_supp) +done + + +subsubsection {* Type @{typ "'a list"} is finitely supported *} + +lemma supp_Nil: + shows "supp [] = {}" + by (simp add: supp_def) + +lemma fresh_Nil: + shows "a \ []" + by (simp add: fresh_def supp_Nil) + +lemma supp_Cons: + shows "supp (x # xs) = supp x \ supp xs" +by (simp add: supp_def Collect_imp_eq Collect_neg_eq) + +lemma fresh_Cons: + shows "a \ (x # xs) \ a \ x \ a \ xs" + by (simp add: fresh_def supp_Cons) + +lemma supp_append: + shows "supp (xs @ ys) = supp xs \ supp ys" + by (induct xs) (auto simp add: supp_Nil supp_Cons) + +lemma fresh_append: + shows "a \ (xs @ ys) \ a \ xs \ a \ ys" + by (induct xs) (simp_all add: fresh_Nil fresh_Cons) + +lemma supp_rev: + shows "supp (rev xs) = supp xs" + by (induct xs) (auto simp add: supp_append supp_Cons supp_Nil) + +lemma fresh_rev: + shows "a \ rev xs \ a \ xs" + by (induct xs) (auto simp add: fresh_append fresh_Cons fresh_Nil) + +lemma supp_removeAll: + fixes x::"atom" + shows "supp (removeAll x xs) = supp xs - {x}" + by (induct xs) + (auto simp add: supp_Nil supp_Cons supp_atom) + +lemma supp_of_atom_list: + fixes as::"atom list" + shows "supp as = set as" +by (induct as) + (simp_all add: supp_Nil supp_Cons supp_atom) + +instance list :: (fs) fs +apply default +apply (induct_tac x) +apply (simp_all add: supp_Nil supp_Cons finite_supp) +done + + +section {* Support and Freshness for Applications *} + +lemma fresh_conv_MOST: + shows "a \ x \ (MOST b. (a \ b) \ x = x)" + unfolding fresh_def supp_def + unfolding MOST_iff_cofinite by simp + +lemma fresh_fun_app: + assumes "a \ f" and "a \ x" + shows "a \ f x" + using assms + unfolding fresh_conv_MOST + unfolding permute_fun_app_eq + by (elim MOST_rev_mp) (simp) + +lemma supp_fun_app: + shows "supp (f x) \ (supp f) \ (supp x)" + using fresh_fun_app + unfolding fresh_def + by auto + + +subsection {* Equivariance Predicate @{text eqvt} and @{text eqvt_at}*} + +definition + "eqvt f \ \p. p \ f = f" + +lemma eqvt_boolI: + fixes f::"bool" + shows "eqvt f" + unfolding eqvt_def + by (simp add: permute_bool_def) + + +text {* equivariance of a function at a given argument *} + +definition + "eqvt_at f x \ \p. p \ (f x) = f (p \ x)" + +lemma eqvtI: + shows "(\p. p \ f \ f) \ eqvt f" +unfolding eqvt_def +by simp + +lemma eqvt_at_perm: + assumes "eqvt_at f x" + shows "eqvt_at f (q \ x)" +proof - + { fix p::"perm" + have "p \ (f (q \ x)) = p \ q \ (f x)" + using assms by (simp add: eqvt_at_def) + also have "\ = (p + q) \ (f x)" by simp + also have "\ = f ((p + q) \ x)" + using assms by (simp add: eqvt_at_def) + finally have "p \ (f (q \ x)) = f (p \ q \ x)" by simp } + then show "eqvt_at f (q \ x)" unfolding eqvt_at_def + by simp +qed + +lemma supp_fun_eqvt: + assumes a: "eqvt f" + shows "supp f = {}" + using a + unfolding eqvt_def + unfolding supp_def + by simp + +lemma fresh_fun_eqvt_app: + assumes a: "eqvt f" + shows "a \ x \ a \ f x" +proof - + from a have "supp f = {}" by (simp add: supp_fun_eqvt) + then show "a \ x \ a \ f x" + unfolding fresh_def + using supp_fun_app by auto +qed + +lemma supp_fun_app_eqvt: + assumes a: "eqvt f" + shows "supp (f x) \ supp x" + using fresh_fun_eqvt_app[OF a] + unfolding fresh_def + by auto + +lemma supp_eqvt_at: + assumes asm: "eqvt_at f x" + and fin: "finite (supp x)" + shows "supp (f x) \ supp x" +apply(rule supp_is_subset) +unfolding supports_def +unfolding fresh_def[symmetric] +using asm +apply(simp add: eqvt_at_def swap_fresh_fresh) +apply(rule fin) +done + +lemma finite_supp_eqvt_at: + assumes asm: "eqvt_at f x" + and fin: "finite (supp x)" + shows "finite (supp (f x))" +apply(rule finite_subset) +apply(rule supp_eqvt_at[OF asm fin]) +apply(rule fin) +done + +lemma fresh_eqvt_at: + assumes asm: "eqvt_at f x" + and fin: "finite (supp x)" + and fresh: "a \ x" + shows "a \ f x" +using fresh +unfolding fresh_def +using supp_eqvt_at[OF asm fin] +by auto + + +subsection {* helper functions for nominal_functions *} + +lemma THE_defaultI2: + assumes "\!x. P x" "\x. P x \ Q x" + shows "Q (THE_default d P)" +by (iprover intro: assms THE_defaultI') + +lemma the_default_eqvt: + assumes unique: "\!x. P x" + shows "(p \ (THE_default d P)) = (THE_default (p \ d) (p \ P))" + apply(rule THE_default1_equality [symmetric]) + apply(rule_tac p="-p" in permute_boolE) + apply(simp add: ex1_eqvt) + apply(rule unique) + apply(rule_tac p="-p" in permute_boolE) + apply(rule subst[OF permute_fun_app_eq]) + apply(simp) + apply(rule THE_defaultI'[OF unique]) + done + +lemma fundef_ex1_eqvt: + fixes x::"'a::pt" + assumes f_def: "f == (\x::'a. THE_default (d x) (G x))" + assumes eqvt: "eqvt G" + assumes ex1: "\!y. G x y" + shows "(p \ (f x)) = f (p \ x)" + apply(simp only: f_def) + apply(subst the_default_eqvt) + apply(rule ex1) + apply(rule THE_default1_equality [symmetric]) + apply(rule_tac p="-p" in permute_boolE) + apply(perm_simp add: permute_minus_cancel) + using eqvt[simplified eqvt_def] + apply(simp) + apply(rule ex1) + apply(rule THE_defaultI2) + apply(rule_tac p="-p" in permute_boolE) + apply(perm_simp add: permute_minus_cancel) + apply(rule ex1) + apply(perm_simp) + using eqvt[simplified eqvt_def] + apply(simp) + done + +lemma fundef_ex1_eqvt_at: + fixes x::"'a::pt" + assumes f_def: "f == (\x::'a. THE_default (d x) (G x))" + assumes eqvt: "eqvt G" + assumes ex1: "\!y. G x y" + shows "eqvt_at f x" + unfolding eqvt_at_def + using assms + by (auto intro: fundef_ex1_eqvt) + +lemma fundef_ex1_prop: + fixes x::"'a::pt" + assumes f_def: "f \ (\x::'a. THE_default (d x) (G x))" + assumes P_all: "\x y. G x y \ P x y" + assumes ex1: "\!y. G x y" + shows "P x (f x)" + unfolding f_def + using ex1 + apply(erule_tac ex1E) + apply(rule THE_defaultI2) + apply(blast) + apply(rule P_all) + apply(assumption) + done + + +section {* Support of Finite Sets of Finitely Supported Elements *} + +text {* support and freshness for atom sets *} + +lemma supp_finite_atom_set: + fixes S::"atom set" + assumes "finite S" + shows "supp S = S" + apply(rule finite_supp_unique) + apply(simp add: supports_def) + apply(simp add: swap_set_not_in) + apply(rule assms) + apply(simp add: swap_set_in) +done + +lemma supp_cofinite_atom_set: + fixes S::"atom set" + assumes "finite (UNIV - S)" + shows "supp S = (UNIV - S)" + apply(rule finite_supp_unique) + apply(simp add: supports_def) + apply(simp add: swap_set_both_in) + apply(rule assms) + apply(subst swap_commute) + apply(simp add: swap_set_in) +done + +lemma fresh_finite_atom_set: + fixes S::"atom set" + assumes "finite S" + shows "a \ S \ a \ S" + unfolding fresh_def + by (simp add: supp_finite_atom_set[OF assms]) + +lemma fresh_minus_atom_set: + fixes S::"atom set" + assumes "finite S" + shows "a \ S - T \ (a \ T \ a \ S)" + unfolding fresh_def + by (auto simp add: supp_finite_atom_set assms) + +lemma Union_supports_set: + shows "(\x \ S. supp x) supports S" +proof - + { fix a b + have "\x \ S. (a \ b) \ x = x \ (a \ b) \ S = S" + unfolding permute_set_def by force + } + then show "(\x \ S. supp x) supports S" + unfolding supports_def + by (simp add: fresh_def[symmetric] swap_fresh_fresh) +qed + +lemma Union_of_finite_supp_sets: + fixes S::"('a::fs set)" + assumes fin: "finite S" + shows "finite (\x\S. supp x)" + using fin by (induct) (auto simp add: finite_supp) + +lemma Union_included_in_supp: + fixes S::"('a::fs set)" + assumes fin: "finite S" + shows "(\x\S. supp x) \ supp S" +proof - + have eqvt: "eqvt (\S. \ supp ` S)" + unfolding eqvt_def + by (perm_simp) (simp) + have "(\x\S. supp x) = supp (\x\S. supp x)" + by (rule supp_finite_atom_set[symmetric]) (rule Union_of_finite_supp_sets[OF fin]) + also have "\ = supp ((\S. \ supp ` S) S)" by simp + also have "\ \ supp S" using eqvt + by (rule supp_fun_app_eqvt) + finally show "(\x\S. supp x) \ supp S" . +qed + +lemma supp_of_finite_sets: + fixes S::"('a::fs set)" + assumes fin: "finite S" + shows "(supp S) = (\x\S. supp x)" +apply(rule subset_antisym) +apply(rule supp_is_subset) +apply(rule Union_supports_set) +apply(rule Union_of_finite_supp_sets[OF fin]) +apply(rule Union_included_in_supp[OF fin]) +done + +lemma finite_sets_supp: + fixes S::"('a::fs set)" + assumes "finite S" + shows "finite (supp S)" +using assms +by (simp only: supp_of_finite_sets Union_of_finite_supp_sets) + +lemma supp_of_finite_union: + fixes S T::"('a::fs) set" + assumes fin1: "finite S" + and fin2: "finite T" + shows "supp (S \ T) = supp S \ supp T" + using fin1 fin2 + by (simp add: supp_of_finite_sets) + +lemma supp_of_finite_insert: + fixes S::"('a::fs) set" + assumes fin: "finite S" + shows "supp (insert x S) = supp x \ supp S" + using fin + by (simp add: supp_of_finite_sets) + +lemma fresh_finite_insert: + fixes S::"('a::fs) set" + assumes fin: "finite S" + shows "a \ (insert x S) \ a \ x \ a \ S" + using fin unfolding fresh_def + by (simp add: supp_of_finite_insert) + +lemma supp_set_empty: + shows "supp {} = {}" + unfolding supp_def + by (simp add: empty_eqvt) + +lemma fresh_set_empty: + shows "a \ {}" + by (simp add: fresh_def supp_set_empty) + +lemma supp_set: + fixes xs :: "('a::fs) list" + shows "supp (set xs) = supp xs" +apply(induct xs) +apply(simp add: supp_set_empty supp_Nil) +apply(simp add: supp_Cons supp_of_finite_insert) +done + +lemma fresh_set: + fixes xs :: "('a::fs) list" + shows "a \ (set xs) \ a \ xs" +unfolding fresh_def +by (simp add: supp_set) + + +subsection {* Type @{typ "'a multiset"} is finitely supported *} + +lemma set_of_eqvt[eqvt]: + shows "p \ (set_of M) = set_of (p \ M)" +by (induct M) (simp_all add: insert_eqvt empty_eqvt) + +lemma supp_set_of: + shows "supp (set_of M) \ supp M" + apply (rule supp_fun_app_eqvt) + unfolding eqvt_def + apply(perm_simp) + apply(simp) + done + +lemma Union_finite_multiset: + fixes M::"'a::fs multiset" + shows "finite (\{supp x | x. x \# M})" +proof - + have "finite (\(supp ` {x. x \# M}))" + by (induct M) (simp_all add: Collect_imp_eq Collect_neg_eq finite_supp) + then show "finite (\{supp x | x. x \# M})" + by (simp only: image_Collect) +qed + +lemma Union_supports_multiset: + shows "\{supp x | x. x :# M} supports M" +proof - + have sw: "\a b. ((\x. x :# M \ (a \ b) \ x = x) \ (a \ b) \ M = M)" + unfolding permute_multiset_def + apply(induct M) + apply(simp_all) + done + show "(\{supp x | x. x :# M}) supports M" + unfolding supports_def + apply(clarify) + apply(rule sw) + apply(rule swap_fresh_fresh) + apply(simp_all only: fresh_def) + apply(auto) + apply(metis neq0_conv)+ + done +qed + +lemma Union_included_multiset: + fixes M::"('a::fs multiset)" + shows "(\{supp x | x. x \# M}) \ supp M" +proof - + have "(\{supp x | x. x \# M}) = (\{supp x | x. x \ set_of M})" by simp + also have "... \ (\x \ set_of M. supp x)" by auto + also have "... = supp (set_of M)" by (simp add: subst supp_of_finite_sets) + also have " ... \ supp M" by (rule supp_set_of) + finally show "(\{supp x | x. x \# M}) \ supp M" . +qed + +lemma supp_of_multisets: + fixes M::"('a::fs multiset)" + shows "(supp M) = (\{supp x | x. x :# M})" +apply(rule subset_antisym) +apply(rule supp_is_subset) +apply(rule Union_supports_multiset) +apply(rule Union_finite_multiset) +apply(rule Union_included_multiset) +done + +lemma multisets_supp_finite: + fixes M::"('a::fs multiset)" + shows "finite (supp M)" +by (simp only: supp_of_multisets Union_finite_multiset) + +lemma supp_of_multiset_union: + fixes M N::"('a::fs) multiset" + shows "supp (M + N) = supp M \ supp N" + by (auto simp add: supp_of_multisets) + +lemma supp_empty_mset [simp]: + shows "supp {#} = {}" + unfolding supp_def + by simp + +instance multiset :: (fs) fs + apply (default) + apply (rule multisets_supp_finite) + done + +subsection {* Type @{typ "'a fset"} is finitely supported *} + +lemma supp_fset [simp]: + shows "supp (fset S) = supp S" + unfolding supp_def + by (simp add: fset_eqvt fset_cong) + +lemma supp_empty_fset [simp]: + shows "supp {||} = {}" + unfolding supp_def + by simp + +lemma fresh_empty_fset: + shows "a \ {||}" +unfolding fresh_def +by (simp) + +lemma supp_insert_fset [simp]: + fixes x::"'a::fs" + and S::"'a fset" + shows "supp (insert_fset x S) = supp x \ supp S" + apply(subst supp_fset[symmetric]) + apply(simp add: supp_of_finite_insert) + done + +lemma fresh_insert_fset: + fixes x::"'a::fs" + and S::"'a fset" + shows "a \ insert_fset x S \ a \ x \ a \ S" + unfolding fresh_def + by (simp) + +lemma fset_finite_supp: + fixes S::"('a::fs) fset" + shows "finite (supp S)" + by (induct S) (simp_all add: finite_supp) + +lemma supp_union_fset: + fixes S T::"'a::fs fset" + shows "supp (S |\| T) = supp S \ supp T" +by (induct S) (auto) + +lemma fresh_union_fset: + fixes S T::"'a::fs fset" + shows "a \ S |\| T \ a \ S \ a \ T" +unfolding fresh_def +by (simp add: supp_union_fset) + +instance fset :: (fs) fs + apply (default) + apply (rule fset_finite_supp) + done + + +section {* Freshness and Fresh-Star *} + +lemma fresh_Unit_elim: + shows "(a \ () \ PROP C) \ PROP C" + by (simp add: fresh_Unit) + +lemma fresh_Pair_elim: + shows "(a \ (x, y) \ PROP C) \ (a \ x \ a \ y \ PROP C)" + by rule (simp_all add: fresh_Pair) + +(* this rule needs to be added before the fresh_prodD is *) +(* added to the simplifier with mksimps *) +lemma [simp]: + shows "a \ x1 \ a \ x2 \ a \ (x1, x2)" + by (simp add: fresh_Pair) + +lemma fresh_PairD: + shows "a \ (x, y) \ a \ x" + and "a \ (x, y) \ a \ y" + by (simp_all add: fresh_Pair) + +declaration {* fn _ => +let + val mksimps_pairs = (@{const_name Nominal2_Base.fresh}, @{thms fresh_PairD}) :: mksimps_pairs +in + Simplifier.map_ss (fn ss => Simplifier.set_mksimps (mksimps mksimps_pairs) ss) +end +*} + +text {* The fresh-star generalisation of fresh is used in strong + induction principles. *} + +definition + fresh_star :: "atom set \ 'a::pt \ bool" ("_ \* _" [80,80] 80) +where + "as \* x \ \a \ as. a \ x" + +lemma fresh_star_supp_conv: + shows "supp x \* y \ supp y \* x" +by (auto simp add: fresh_star_def fresh_def) + +lemma fresh_star_perm_set_conv: + fixes p::"perm" + assumes fresh: "as \* p" + and fin: "finite as" + shows "supp p \* as" +apply(rule fresh_star_supp_conv) +apply(simp add: supp_finite_atom_set fin fresh) +done + +lemma fresh_star_atom_set_conv: + assumes fresh: "as \* bs" + and fin: "finite as" "finite bs" + shows "bs \* as" +using fresh +unfolding fresh_star_def fresh_def +by (auto simp add: supp_finite_atom_set fin) + +lemma atom_fresh_star_disjoint: + assumes fin: "finite bs" + shows "as \* bs \ (as \ bs = {})" + +unfolding fresh_star_def fresh_def +by (auto simp add: supp_finite_atom_set fin) + + +lemma fresh_star_Pair: + shows "as \* (x, y) = (as \* x \ as \* y)" + by (auto simp add: fresh_star_def fresh_Pair) + +lemma fresh_star_list: + shows "as \* (xs @ ys) \ as \* xs \ as \* ys" + and "as \* (x # xs) \ as \* x \ as \* xs" + and "as \* []" +by (auto simp add: fresh_star_def fresh_Nil fresh_Cons fresh_append) + +lemma fresh_star_set: + fixes xs::"('a::fs) list" + shows "as \* set xs \ as \* xs" +unfolding fresh_star_def +by (simp add: fresh_set) + +lemma fresh_star_singleton: + fixes a::"atom" + shows "as \* {a} \ as \* a" + by (simp add: fresh_star_def fresh_finite_insert fresh_set_empty) + +lemma fresh_star_fset: + fixes xs::"('a::fs) list" + shows "as \* fset S \ as \* S" +by (simp add: fresh_star_def fresh_def) + +lemma fresh_star_Un: + shows "(as \ bs) \* x = (as \* x \ bs \* x)" + by (auto simp add: fresh_star_def) + +lemma fresh_star_insert: + shows "(insert a as) \* x = (a \ x \ as \* x)" + by (auto simp add: fresh_star_def) + +lemma fresh_star_Un_elim: + "((as \ bs) \* x \ PROP C) \ (as \* x \ bs \* x \ PROP C)" + unfolding fresh_star_def + apply(rule) + apply(erule meta_mp) + apply(auto) + done + +lemma fresh_star_insert_elim: + "(insert a as \* x \ PROP C) \ (a \ x \ as \* x \ PROP C)" + unfolding fresh_star_def + by rule (simp_all add: fresh_star_def) + +lemma fresh_star_empty_elim: + "({} \* x \ PROP C) \ PROP C" + by (simp add: fresh_star_def) + +lemma fresh_star_Unit_elim: + shows "(a \* () \ PROP C) \ PROP C" + by (simp add: fresh_star_def fresh_Unit) + +lemma fresh_star_Pair_elim: + shows "(a \* (x, y) \ PROP C) \ (a \* x \ a \* y \ PROP C)" + by (rule, simp_all add: fresh_star_Pair) + +lemma fresh_star_zero: + shows "as \* (0::perm)" + unfolding fresh_star_def + by (simp add: fresh_zero_perm) + +lemma fresh_star_plus: + fixes p q::perm + shows "\a \* p; a \* q\ \ a \* (p + q)" + unfolding fresh_star_def + by (simp add: fresh_plus_perm) + +lemma fresh_star_permute_iff: + shows "(p \ a) \* (p \ x) \ a \* x" + unfolding fresh_star_def + by (metis mem_permute_iff permute_minus_cancel(1) fresh_permute_iff) + +lemma fresh_star_eqvt [eqvt]: + shows "p \ (as \* x) \ (p \ as) \* (p \ x)" +unfolding fresh_star_def +by (perm_simp) (rule refl) + + + +section {* Induction principle for permutations *} + +lemma smaller_supp: + assumes a: "a \ supp p" + shows "supp ((p \ a \ a) + p) \ supp p" +proof - + have "supp ((p \ a \ a) + p) \ supp p" + unfolding supp_perm by (auto simp add: swap_atom) + moreover + have "a \ supp ((p \ a \ a) + p)" by (simp add: supp_perm) + then have "supp ((p \ a \ a) + p) \ supp p" using a by auto + ultimately + show "supp ((p \ a \ a) + p) \ supp p" by auto +qed + + +lemma perm_struct_induct[consumes 1, case_names zero swap]: + assumes S: "supp p \ S" + and zero: "P 0" + and swap: "\p a b. \P p; supp p \ S; a \ S; b \ S; a \ b; sort_of a = sort_of b\ \ P ((a \ b) + p)" + shows "P p" +proof - + have "finite (supp p)" by (simp add: finite_supp) + then show "P p" using S + proof(induct A\"supp p" arbitrary: p rule: finite_psubset_induct) + case (psubset p) + then have ih: "\q. supp q \ supp p \ P q" by auto + have as: "supp p \ S" by fact + { assume "supp p = {}" + then have "p = 0" by (simp add: supp_perm perm_eq_iff) + then have "P p" using zero by simp + } + moreover + { assume "supp p \ {}" + then obtain a where a0: "a \ supp p" by blast + then have a1: "p \ a \ S" "a \ S" "sort_of (p \ a) = sort_of a" "p \ a \ a" + using as by (auto simp add: supp_atom supp_perm swap_atom) + let ?q = "(p \ a \ a) + p" + have a2: "supp ?q \ supp p" using a0 smaller_supp by simp + then have "P ?q" using ih by simp + moreover + have "supp ?q \ S" using as a2 by simp + ultimately have "P ((p \ a \ a) + ?q)" using as a1 swap by simp + moreover + have "p = (p \ a \ a) + ?q" by (simp add: perm_eq_iff) + ultimately have "P p" by simp + } + ultimately show "P p" by blast + qed +qed + +lemma perm_simple_struct_induct[case_names zero swap]: + assumes zero: "P 0" + and swap: "\p a b. \P p; a \ b; sort_of a = sort_of b\ \ P ((a \ b) + p)" + shows "P p" +by (rule_tac S="supp p" in perm_struct_induct) + (auto intro: zero swap) + +lemma perm_struct_induct2[consumes 1, case_names zero swap plus]: + assumes S: "supp p \ S" + assumes zero: "P 0" + assumes swap: "\a b. \sort_of a = sort_of b; a \ b; a \ S; b \ S\ \ P (a \ b)" + assumes plus: "\p1 p2. \P p1; P p2; supp p1 \ S; supp p2 \ S\ \ P (p1 + p2)" + shows "P p" +using S +by (induct p rule: perm_struct_induct) + (auto intro: zero plus swap simp add: supp_swap) + +lemma perm_simple_struct_induct2[case_names zero swap plus]: + assumes zero: "P 0" + assumes swap: "\a b. \sort_of a = sort_of b; a \ b\ \ P (a \ b)" + assumes plus: "\p1 p2. \P p1; P p2\ \ P (p1 + p2)" + shows "P p" +by (rule_tac S="supp p" in perm_struct_induct2) + (auto intro: zero swap plus) + +lemma supp_perm_singleton: + fixes p::"perm" + shows "supp p \ {b} \ p = 0" +proof - + { assume "supp p \ {b}" + then have "p = 0" + by (induct p rule: perm_struct_induct) (simp_all) + } + then show "supp p \ {b} \ p = 0" by (auto simp add: supp_zero_perm) +qed + +lemma supp_perm_pair: + fixes p::"perm" + shows "supp p \ {a, b} \ p = 0 \ p = (b \ a)" +proof - + { assume "supp p \ {a, b}" + then have "p = 0 \ p = (b \ a)" + apply (induct p rule: perm_struct_induct) + apply (auto simp add: swap_cancel supp_zero_perm supp_swap) + apply (simp add: swap_commute) + done + } + then show "supp p \ {a, b} \ p = 0 \ p = (b \ a)" + by (auto simp add: supp_zero_perm supp_swap split: if_splits) +qed + +lemma supp_perm_eq: + assumes "(supp x) \* p" + shows "p \ x = x" +proof - + from assms have "supp p \ {a. a \ x}" + unfolding supp_perm fresh_star_def fresh_def by auto + then show "p \ x = x" + proof (induct p rule: perm_struct_induct) + case zero + show "0 \ x = x" by simp + next + case (swap p a b) + then have "a \ x" "b \ x" "p \ x = x" by simp_all + then show "((a \ b) + p) \ x = x" by (simp add: swap_fresh_fresh) + qed +qed + +text {* same lemma as above, but proved with a different induction principle *} +lemma supp_perm_eq_test: + assumes "(supp x) \* p" + shows "p \ x = x" +proof - + from assms have "supp p \ {a. a \ x}" + unfolding supp_perm fresh_star_def fresh_def by auto + then show "p \ x = x" + proof (induct p rule: perm_struct_induct2) + case zero + show "0 \ x = x" by simp + next + case (swap a b) + then have "a \ x" "b \ x" by simp_all + then show "(a \ b) \ x = x" by (simp add: swap_fresh_fresh) + next + case (plus p1 p2) + have "p1 \ x = x" "p2 \ x = x" by fact+ + then show "(p1 + p2) \ x = x" by simp + qed +qed + +lemma perm_supp_eq: + assumes a: "(supp p) \* x" + shows "p \ x = x" +proof - + from assms have "supp p \ {a. a \ x}" + unfolding supp_perm fresh_star_def fresh_def by auto + then show "p \ x = x" + proof (induct p rule: perm_struct_induct2) + case zero + show "0 \ x = x" by simp + next + case (swap a b) + then have "a \ x" "b \ x" by simp_all + then show "(a \ b) \ x = x" by (simp add: swap_fresh_fresh) + next + case (plus p1 p2) + have "p1 \ x = x" "p2 \ x = x" by fact+ + then show "(p1 + p2) \ x = x" by simp + qed +qed + + + + +lemma supp_perm_perm_eq: + assumes a: "\a \ supp x. p \ a = q \ a" + shows "p \ x = q \ x" +proof - + from a have "\a \ supp x. (-q + p) \ a = a" by simp + then have "\a \ supp x. a \ supp (-q + p)" + unfolding supp_perm by simp + then have "supp x \* (-q + p)" + unfolding fresh_star_def fresh_def by simp + then have "(-q + p) \ x = x" by (simp only: supp_perm_eq) + then show "p \ x = q \ x" + by (metis permute_minus_cancel(1) permute_plus) +qed + +text {* disagreement set *} + +definition + dset :: "perm \ perm \ atom set" +where + "dset p q = {a::atom. p \ a \ q \ a}" + +lemma ds_fresh: + assumes "dset p q \* x" + shows "p \ x = q \ x" +using assms +unfolding dset_def fresh_star_def fresh_def +by (auto intro: supp_perm_perm_eq) + +lemma atom_set_perm_eq: + assumes a: "as \* p" + shows "p \ as = as" +proof - + from a have "supp p \ {a. a \ as}" + unfolding supp_perm fresh_star_def fresh_def by auto + then show "p \ as = as" + proof (induct p rule: perm_struct_induct) + case zero + show "0 \ as = as" by simp + next + case (swap p a b) + then have "a \ as" "b \ as" "p \ as = as" by simp_all + then show "((a \ b) + p) \ as = as" by (simp add: swap_set_not_in) + qed +qed + +section {* Avoiding of atom sets *} + +text {* + For every set of atoms, there is another set of atoms + avoiding a finitely supported c and there is a permutation + which 'translates' between both sets. +*} + +lemma at_set_avoiding_aux: + fixes Xs::"atom set" + and As::"atom set" + assumes b: "Xs \ As" + and c: "finite As" + shows "\p. (p \ Xs) \ As = {} \ (supp p) = (Xs \ (p \ Xs))" +proof - + from b c have "finite Xs" by (rule finite_subset) + then show ?thesis using b + proof (induct rule: finite_subset_induct) + case empty + have "0 \ {} \ As = {}" by simp + moreover + have "supp (0::perm) = {} \ 0 \ {}" by (simp add: supp_zero_perm) + ultimately show ?case by blast + next + case (insert x Xs) + then obtain p where + p1: "(p \ Xs) \ As = {}" and + p2: "supp p = (Xs \ (p \ Xs))" by blast + from `x \ As` p1 have "x \ p \ Xs" by fast + with `x \ Xs` p2 have "x \ supp p" by fast + hence px: "p \ x = x" unfolding supp_perm by simp + have "finite (As \ p \ Xs \ supp p)" + using `finite As` `finite Xs` + by (simp add: permute_set_eq_image finite_supp) + then obtain y where "y \ (As \ p \ Xs \ supp p)" "sort_of y = sort_of x" + by (rule obtain_atom) + hence y: "y \ As" "y \ p \ Xs" "y \ supp p" "sort_of y = sort_of x" + by simp_all + hence py: "p \ y = y" "x \ y" using `x \ As` + by (auto simp add: supp_perm) + let ?q = "(x \ y) + p" + have q: "?q \ insert x Xs = insert y (p \ Xs)" + unfolding insert_eqvt + using `p \ x = x` `sort_of y = sort_of x` + using `x \ p \ Xs` `y \ p \ Xs` + by (simp add: swap_atom swap_set_not_in) + have "?q \ insert x Xs \ As = {}" + using `y \ As` `p \ Xs \ As = {}` + unfolding q by simp + moreover + have "supp (x \ y) \ supp p = {}" using px py `sort_of y = sort_of x` + unfolding supp_swap by (simp add: supp_perm) + then have "supp ?q = (supp (x \ y) \ supp p)" + by (simp add: supp_plus_perm_eq) + then have "supp ?q = insert x Xs \ ?q \ insert x Xs" + using p2 `sort_of y = sort_of x` `x \ y` unfolding q supp_swap + by auto + ultimately show ?case by blast + qed +qed + +lemma at_set_avoiding: + assumes a: "finite Xs" + and b: "finite (supp c)" + obtains p::"perm" where "(p \ Xs)\*c" and "(supp p) = (Xs \ (p \ Xs))" + using a b at_set_avoiding_aux [where Xs="Xs" and As="Xs \ supp c"] + unfolding fresh_star_def fresh_def by blast + +lemma at_set_avoiding1: + assumes "finite xs" + and "finite (supp c)" + shows "\p. (p \ xs) \* c" +using assms +apply(erule_tac c="c" in at_set_avoiding) +apply(auto) +done + +lemma at_set_avoiding2: + assumes "finite xs" + and "finite (supp c)" "finite (supp x)" + and "xs \* x" + shows "\p. (p \ xs) \* c \ supp x \* p" +using assms +apply(erule_tac c="(c, x)" in at_set_avoiding) +apply(simp add: supp_Pair) +apply(rule_tac x="p" in exI) +apply(simp add: fresh_star_Pair) +apply(rule fresh_star_supp_conv) +apply(auto simp add: fresh_star_def) +done + +lemma at_set_avoiding3: + assumes "finite xs" + and "finite (supp c)" "finite (supp x)" + and "xs \* x" + shows "\p. (p \ xs) \* c \ supp x \* p \ supp p = xs \ (p \ xs)" +using assms +apply(erule_tac c="(c, x)" in at_set_avoiding) +apply(simp add: supp_Pair) +apply(rule_tac x="p" in exI) +apply(simp add: fresh_star_Pair) +apply(rule fresh_star_supp_conv) +apply(auto simp add: fresh_star_def) +done + +lemma at_set_avoiding2_atom: + assumes "finite (supp c)" "finite (supp x)" + and b: "a \ x" + shows "\p. (p \ a) \ c \ supp x \* p" +proof - + have a: "{a} \* x" unfolding fresh_star_def by (simp add: b) + obtain p where p1: "(p \ {a}) \* c" and p2: "supp x \* p" + using at_set_avoiding2[of "{a}" "c" "x"] assms a by blast + have c: "(p \ a) \ c" using p1 + unfolding fresh_star_def Ball_def + by(erule_tac x="p \ a" in allE) (simp add: permute_set_def) + hence "p \ a \ c \ supp x \* p" using p2 by blast + then show "\p. (p \ a) \ c \ supp x \* p" by blast +qed + + +section {* Renaming permutations *} + +lemma set_renaming_perm: + assumes b: "finite bs" + shows "\q. (\b \ bs. q \ b = p \ b) \ supp q \ bs \ (p \ bs)" +using b +proof (induct) + case empty + have "(\b \ {}. 0 \ b = p \ b) \ supp (0::perm) \ {} \ p \ {}" + by (simp add: permute_set_def supp_perm) + then show "\q. (\b \ {}. q \ b = p \ b) \ supp q \ {} \ p \ {}" by blast +next + case (insert a bs) + then have " \q. (\b \ bs. q \ b = p \ b) \ supp q \ bs \ p \ bs" by simp + then obtain q where *: "\b \ bs. q \ b = p \ b" and **: "supp q \ bs \ p \ bs" + by auto + { assume 1: "q \ a = p \ a" + have "\b \ (insert a bs). q \ b = p \ b" using 1 * by simp + moreover + have "supp q \ insert a bs \ p \ insert a bs" + using ** by (auto simp add: insert_eqvt) + ultimately + have "\q. (\b \ insert a bs. q \ b = p \ b) \ supp q \ insert a bs \ p \ insert a bs" by blast + } + moreover + { assume 2: "q \ a \ p \ a" + def q' \ "((q \ a) \ (p \ a)) + q" + have "\b \ insert a bs. q' \ b = p \ b" using 2 * `a \ bs` unfolding q'_def + by (auto simp add: swap_atom) + moreover + { have "{q \ a, p \ a} \ insert a bs \ p \ insert a bs" + using ** + apply (auto simp add: supp_perm insert_eqvt) + apply (subgoal_tac "q \ a \ bs \ p \ bs") + apply(auto)[1] + apply(subgoal_tac "q \ a \ {a. q \ a \ a}") + apply(blast) + apply(simp) + done + then have "supp (q \ a \ p \ a) \ insert a bs \ p \ insert a bs" by (simp add: supp_swap) + moreover + have "supp q \ insert a bs \ p \ insert a bs" + using ** by (auto simp add: insert_eqvt) + ultimately + have "supp q' \ insert a bs \ p \ insert a bs" + unfolding q'_def using supp_plus_perm by blast + } + ultimately + have "\q. (\b \ insert a bs. q \ b = p \ b) \ supp q \ insert a bs \ p \ insert a bs" by blast + } + ultimately show "\q. (\b \ insert a bs. q \ b = p \ b) \ supp q \ insert a bs \ p \ insert a bs" + by blast +qed + +lemma set_renaming_perm2: + shows "\q. (\b \ bs. q \ b = p \ b) \ supp q \ bs \ (p \ bs)" +proof - + have "finite (bs \ supp p)" by (simp add: finite_supp) + then obtain q + where *: "\b \ bs \ supp p. q \ b = p \ b" and **: "supp q \ (bs \ supp p) \ (p \ (bs \ supp p))" + using set_renaming_perm by blast + from ** have "supp q \ bs \ (p \ bs)" by (auto simp add: inter_eqvt) + moreover + have "\b \ bs - supp p. q \ b = p \ b" + apply(auto) + apply(subgoal_tac "b \ supp q") + apply(simp add: fresh_def[symmetric]) + apply(simp add: fresh_perm) + apply(clarify) + apply(rotate_tac 2) + apply(drule subsetD[OF **]) + apply(simp add: inter_eqvt supp_eqvt permute_self) + done + ultimately have "(\b \ bs. q \ b = p \ b) \ supp q \ bs \ (p \ bs)" using * by auto + then show "\q. (\b \ bs. q \ b = p \ b) \ supp q \ bs \ (p \ bs)" by blast +qed + +lemma list_renaming_perm: + shows "\q. (\b \ set bs. q \ b = p \ b) \ supp q \ set bs \ (p \ set bs)" +proof (induct bs) + case (Cons a bs) + then have " \q. (\b \ set bs. q \ b = p \ b) \ supp q \ set bs \ p \ (set bs)" by simp + then obtain q where *: "\b \ set bs. q \ b = p \ b" and **: "supp q \ set bs \ p \ (set bs)" + by (blast) + { assume 1: "a \ set bs" + have "q \ a = p \ a" using * 1 by (induct bs) (auto) + then have "\b \ set (a # bs). q \ b = p \ b" using * by simp + moreover + have "supp q \ set (a # bs) \ p \ (set (a # bs))" using ** by (auto simp add: insert_eqvt) + ultimately + have "\q. (\b \ set (a # bs). q \ b = p \ b) \ supp q \ set (a # bs) \ p \ (set (a # bs))" by blast + } + moreover + { assume 2: "a \ set bs" + def q' \ "((q \ a) \ (p \ a)) + q" + have "\b \ set (a # bs). q' \ b = p \ b" + unfolding q'_def using 2 * `a \ set bs` by (auto simp add: swap_atom) + moreover + { have "{q \ a, p \ a} \ set (a # bs) \ p \ (set (a # bs))" + using ** + apply (auto simp add: supp_perm insert_eqvt) + apply (subgoal_tac "q \ a \ set bs \ p \ set bs") + apply(auto)[1] + apply(subgoal_tac "q \ a \ {a. q \ a \ a}") + apply(blast) + apply(simp) + done + then have "supp (q \ a \ p \ a) \ set (a # bs) \ p \ set (a # bs)" by (simp add: supp_swap) + moreover + have "supp q \ set (a # bs) \ p \ (set (a # bs))" + using ** by (auto simp add: insert_eqvt) + ultimately + have "supp q' \ set (a # bs) \ p \ (set (a # bs))" + unfolding q'_def using supp_plus_perm by blast + } + ultimately + have "\q. (\b \ set (a # bs). q \ b = p \ b) \ supp q \ set (a # bs) \ p \ (set (a # bs))" by blast + } + ultimately show "\q. (\b \ set (a # bs). q \ b = p \ b) \ supp q \ set (a # bs) \ p \ (set (a # bs))" + by blast +next + case Nil + have "(\b \ set []. 0 \ b = p \ b) \ supp (0::perm) \ set [] \ p \ set []" + by (simp add: supp_zero_perm) + then show "\q. (\b \ set []. q \ b = p \ b) \ supp q \ set [] \ p \ (set [])" by blast +qed + + +section {* Concrete Atoms Types *} + +text {* + Class @{text at_base} allows types containing multiple sorts of atoms. + Class @{text at} only allows types with a single sort. +*} + +class at_base = pt + + fixes atom :: "'a \ atom" + assumes atom_eq_iff [simp]: "atom a = atom b \ a = b" + assumes atom_eqvt: "p \ (atom a) = atom (p \ a)" + +declare atom_eqvt[eqvt] + +class at = at_base + + assumes sort_of_atom_eq [simp]: "sort_of (atom a) = sort_of (atom b)" + +lemma sort_ineq [simp]: + assumes "sort_of (atom a) \ sort_of (atom b)" + shows "atom a \ atom b" +using assms by metis + +lemma supp_at_base: + fixes a::"'a::at_base" + shows "supp a = {atom a}" + by (simp add: supp_atom [symmetric] supp_def atom_eqvt) + +lemma fresh_at_base: + shows "sort_of a \ sort_of (atom b) \ a \ b" + and "a \ b \ a \ atom b" + unfolding fresh_def + apply(simp_all add: supp_at_base) + apply(metis) + done + +lemma fresh_atom_at_base: + fixes b::"'a::at_base" + shows "a \ atom b \ a \ b" + by (simp add: fresh_def supp_at_base supp_atom) + +lemma fresh_star_atom_at_base: + fixes b::"'a::at_base" + shows "as \* atom b \ as \* b" + by (simp add: fresh_star_def fresh_atom_at_base) + +instance at_base < fs +proof qed (simp add: supp_at_base) + +lemma at_base_infinite [simp]: + shows "infinite (UNIV :: 'a::at_base set)" (is "infinite ?U") +proof + obtain a :: 'a where "True" by auto + assume "finite ?U" + hence "finite (atom ` ?U)" + by (rule finite_imageI) + then obtain b where b: "b \ atom ` ?U" "sort_of b = sort_of (atom a)" + by (rule obtain_atom) + from b(2) have "b = atom ((atom a \ b) \ a)" + unfolding atom_eqvt [symmetric] + by (simp add: swap_atom) + hence "b \ atom ` ?U" by simp + with b(1) show "False" by simp +qed + +lemma swap_at_base_simps [simp]: + fixes x y::"'a::at_base" + shows "sort_of (atom x) = sort_of (atom y) \ (atom x \ atom y) \ x = y" + and "sort_of (atom x) = sort_of (atom y) \ (atom x \ atom y) \ y = x" + and "atom x \ a \ atom x \ b \ (a \ b) \ x = x" + unfolding atom_eq_iff [symmetric] + unfolding atom_eqvt [symmetric] + by simp_all + +lemma obtain_at_base: + assumes X: "finite X" + obtains a::"'a::at_base" where "atom a \ X" +proof - + have "inj (atom :: 'a \ atom)" + by (simp add: inj_on_def) + with X have "finite (atom -` X :: 'a set)" + by (rule finite_vimageI) + with at_base_infinite have "atom -` X \ (UNIV :: 'a set)" + by auto + then obtain a :: 'a where "atom a \ X" + by auto + thus ?thesis .. +qed + +lemma obtain_fresh': + assumes fin: "finite (supp x)" + obtains a::"'a::at_base" where "atom a \ x" +using obtain_at_base[where X="supp x"] +by (auto simp add: fresh_def fin) + +lemma obtain_fresh: + fixes x::"'b::fs" + obtains a::"'a::at_base" where "atom a \ x" + by (rule obtain_fresh') (auto simp add: finite_supp) + +lemma supp_finite_set_at_base: + assumes a: "finite S" + shows "supp S = atom ` S" +apply(simp add: supp_of_finite_sets[OF a]) +apply(simp add: supp_at_base) +apply(auto) +done + +(* FIXME +lemma supp_cofinite_set_at_base: + assumes a: "finite (UNIV - S)" + shows "supp S = atom ` (UNIV - S)" +apply(rule finite_supp_unique) +*) + +lemma fresh_finite_set_at_base: + fixes a::"'a::at_base" + assumes a: "finite S" + shows "atom a \ S \ a \ S" + unfolding fresh_def + apply(simp add: supp_finite_set_at_base[OF a]) + apply(subst inj_image_mem_iff) + apply(simp add: inj_on_def) + apply(simp) + done + +lemma fresh_at_base_permute_iff [simp]: + fixes a::"'a::at_base" + shows "atom (p \ a) \ p \ x \ atom a \ x" + unfolding atom_eqvt[symmetric] + by (simp add: fresh_permute_iff) + + +section {* Infrastructure for concrete atom types *} + +definition + flip :: "'a::at_base \ 'a \ perm" ("'(_ \ _')") +where + "(a \ b) = (atom a \ atom b)" + +lemma flip_self [simp]: "(a \ a) = 0" + unfolding flip_def by (rule swap_self) + +lemma flip_commute: "(a \ b) = (b \ a)" + unfolding flip_def by (rule swap_commute) + +lemma minus_flip [simp]: "- (a \ b) = (a \ b)" + unfolding flip_def by (rule minus_swap) + +lemma add_flip_cancel: "(a \ b) + (a \ b) = 0" + unfolding flip_def by (rule swap_cancel) + +lemma permute_flip_cancel [simp]: "(a \ b) \ (a \ b) \ x = x" + unfolding permute_plus [symmetric] add_flip_cancel by simp + +lemma permute_flip_cancel2 [simp]: "(a \ b) \ (b \ a) \ x = x" + by (simp add: flip_commute) + +lemma flip_eqvt [eqvt]: + fixes a b c::"'a::at_base" + shows "p \ (a \ b) = (p \ a \ p \ b)" + unfolding flip_def + by (simp add: swap_eqvt atom_eqvt) + +lemma flip_at_base_simps [simp]: + shows "sort_of (atom a) = sort_of (atom b) \ (a \ b) \ a = b" + and "sort_of (atom a) = sort_of (atom b) \ (a \ b) \ b = a" + and "\a \ c; b \ c\ \ (a \ b) \ c = c" + and "sort_of (atom a) \ sort_of (atom b) \ (a \ b) \ x = x" + unfolding flip_def + unfolding atom_eq_iff [symmetric] + unfolding atom_eqvt [symmetric] + by simp_all + +text {* the following two lemmas do not hold for at_base, + only for single sort atoms from at *} + +lemma permute_flip_at: + fixes a b c::"'a::at" + shows "(a \ b) \ c = (if c = a then b else if c = b then a else c)" + unfolding flip_def + apply (rule atom_eq_iff [THEN iffD1]) + apply (subst atom_eqvt [symmetric]) + apply (simp add: swap_atom) + done + +lemma flip_at_simps [simp]: + fixes a b::"'a::at" + shows "(a \ b) \ a = b" + and "(a \ b) \ b = a" + unfolding permute_flip_at by simp_all + +lemma flip_fresh_fresh: + fixes a b::"'a::at_base" + assumes "atom a \ x" "atom b \ x" + shows "(a \ b) \ x = x" +using assms +by (simp add: flip_def swap_fresh_fresh) + + + +subsection {* Syntax for coercing at-elements to the atom-type *} + +syntax + "_atom_constrain" :: "logic \ type \ logic" ("_:::_" [4, 0] 3) + +translations + "_atom_constrain a t" => "CONST atom (_constrain a t)" + + +subsection {* A lemma for proving instances of class @{text at}. *} + +setup {* Sign.add_const_constraint (@{const_name "permute"}, NONE) *} +setup {* Sign.add_const_constraint (@{const_name "atom"}, NONE) *} + +text {* + New atom types are defined as subtypes of @{typ atom}. +*} + +lemma exists_eq_simple_sort: + shows "\a. a \ {a. sort_of a = s}" + by (rule_tac x="Atom s 0" in exI, simp) + +lemma exists_eq_sort: + shows "\a. a \ {a. sort_of a \ range sort_fun}" + by (rule_tac x="Atom (sort_fun x) y" in exI, simp) + +lemma at_base_class: + fixes sort_fun :: "'b \ atom_sort" + fixes Rep :: "'a \ atom" and Abs :: "atom \ 'a" + assumes type: "type_definition Rep Abs {a. sort_of a \ range sort_fun}" + assumes atom_def: "\a. atom a = Rep a" + assumes permute_def: "\p a. p \ a = Abs (p \ Rep a)" + shows "OFCLASS('a, at_base_class)" +proof + interpret type_definition Rep Abs "{a. sort_of a \ range sort_fun}" by (rule type) + have sort_of_Rep: "\a. sort_of (Rep a) \ range sort_fun" using Rep by simp + fix a b :: 'a and p p1 p2 :: perm + show "0 \ a = a" + unfolding permute_def by (simp add: Rep_inverse) + show "(p1 + p2) \ a = p1 \ p2 \ a" + unfolding permute_def by (simp add: Abs_inverse sort_of_Rep) + show "atom a = atom b \ a = b" + unfolding atom_def by (simp add: Rep_inject) + show "p \ atom a = atom (p \ a)" + unfolding permute_def atom_def by (simp add: Abs_inverse sort_of_Rep) +qed + +(* +lemma at_class: + fixes s :: atom_sort + fixes Rep :: "'a \ atom" and Abs :: "atom \ 'a" + assumes type: "type_definition Rep Abs {a. sort_of a \ range (\x::unit. s)}" + assumes atom_def: "\a. atom a = Rep a" + assumes permute_def: "\p a. p \ a = Abs (p \ Rep a)" + shows "OFCLASS('a, at_class)" +proof + interpret type_definition Rep Abs "{a. sort_of a \ range (\x::unit. s)}" by (rule type) + have sort_of_Rep: "\a. sort_of (Rep a) = s" using Rep by (simp add: image_def) + fix a b :: 'a and p p1 p2 :: perm + show "0 \ a = a" + unfolding permute_def by (simp add: Rep_inverse) + show "(p1 + p2) \ a = p1 \ p2 \ a" + unfolding permute_def by (simp add: Abs_inverse sort_of_Rep) + show "sort_of (atom a) = sort_of (atom b)" + unfolding atom_def by (simp add: sort_of_Rep) + show "atom a = atom b \ a = b" + unfolding atom_def by (simp add: Rep_inject) + show "p \ atom a = atom (p \ a)" + unfolding permute_def atom_def by (simp add: Abs_inverse sort_of_Rep) +qed +*) + +lemma at_class: + fixes s :: atom_sort + fixes Rep :: "'a \ atom" and Abs :: "atom \ 'a" + assumes type: "type_definition Rep Abs {a. sort_of a = s}" + assumes atom_def: "\a. atom a = Rep a" + assumes permute_def: "\p a. p \ a = Abs (p \ Rep a)" + shows "OFCLASS('a, at_class)" +proof + interpret type_definition Rep Abs "{a. sort_of a = s}" by (rule type) + have sort_of_Rep: "\a. sort_of (Rep a) = s" using Rep by (simp add: image_def) + fix a b :: 'a and p p1 p2 :: perm + show "0 \ a = a" + unfolding permute_def by (simp add: Rep_inverse) + show "(p1 + p2) \ a = p1 \ p2 \ a" + unfolding permute_def by (simp add: Abs_inverse sort_of_Rep) + show "sort_of (atom a) = sort_of (atom b)" + unfolding atom_def by (simp add: sort_of_Rep) + show "atom a = atom b \ a = b" + unfolding atom_def by (simp add: Rep_inject) + show "p \ atom a = atom (p \ a)" + unfolding permute_def atom_def by (simp add: Abs_inverse sort_of_Rep) +qed + +lemma at_class_sort: + fixes s :: atom_sort + fixes Rep :: "'a \ atom" and Abs :: "atom \ 'a" + fixes a::"'a" + assumes type: "type_definition Rep Abs {a. sort_of a = s}" + assumes atom_def: "\a. atom a = Rep a" + shows "sort_of (atom a) = s" + using atom_def type + unfolding type_definition_def by simp + + +setup {* Sign.add_const_constraint + (@{const_name "permute"}, SOME @{typ "perm \ 'a::pt \ 'a"}) *} +setup {* Sign.add_const_constraint + (@{const_name "atom"}, SOME @{typ "'a::at_base \ atom"}) *} + +section {* The freshness lemma according to Andy Pitts *} + +lemma freshness_lemma: + fixes h :: "'a::at \ 'b::pt" + assumes a: "\a. atom a \ (h, h a)" + shows "\x. \a. atom a \ h \ h a = x" +proof - + from a obtain b where a1: "atom b \ h" and a2: "atom b \ h b" + by (auto simp add: fresh_Pair) + show "\x. \a. atom a \ h \ h a = x" + proof (intro exI allI impI) + fix a :: 'a + assume a3: "atom a \ h" + show "h a = h b" + proof (cases "a = b") + assume "a = b" + thus "h a = h b" by simp + next + assume "a \ b" + hence "atom a \ b" by (simp add: fresh_at_base) + with a3 have "atom a \ h b" + by (rule fresh_fun_app) + with a2 have d1: "(atom b \ atom a) \ (h b) = (h b)" + by (rule swap_fresh_fresh) + from a1 a3 have d2: "(atom b \ atom a) \ h = h" + by (rule swap_fresh_fresh) + from d1 have "h b = (atom b \ atom a) \ (h b)" by simp + also have "\ = ((atom b \ atom a) \ h) ((atom b \ atom a) \ b)" + by (rule permute_fun_app_eq) + also have "\ = h a" + using d2 by simp + finally show "h a = h b" by simp + qed + qed +qed + +lemma freshness_lemma_unique: + fixes h :: "'a::at \ 'b::pt" + assumes a: "\a. atom a \ (h, h a)" + shows "\!x. \a. atom a \ h \ h a = x" +proof (rule ex_ex1I) + from a show "\x. \a. atom a \ h \ h a = x" + by (rule freshness_lemma) +next + fix x y + assume x: "\a. atom a \ h \ h a = x" + assume y: "\a. atom a \ h \ h a = y" + from a x y show "x = y" + by (auto simp add: fresh_Pair) +qed + +text {* packaging the freshness lemma into a function *} + +definition + fresh_fun :: "('a::at \ 'b::pt) \ 'b" +where + "fresh_fun h = (THE x. \a. atom a \ h \ h a = x)" + +lemma fresh_fun_apply: + fixes h :: "'a::at \ 'b::pt" + assumes a: "\a. atom a \ (h, h a)" + assumes b: "atom a \ h" + shows "fresh_fun h = h a" +unfolding fresh_fun_def +proof (rule the_equality) + show "\a'. atom a' \ h \ h a' = h a" + proof (intro strip) + fix a':: 'a + assume c: "atom a' \ h" + from a have "\x. \a. atom a \ h \ h a = x" by (rule freshness_lemma) + with b c show "h a' = h a" by auto + qed +next + fix fr :: 'b + assume "\a. atom a \ h \ h a = fr" + with b show "fr = h a" by auto +qed + +lemma fresh_fun_apply': + fixes h :: "'a::at \ 'b::pt" + assumes a: "atom a \ h" "atom a \ h a" + shows "fresh_fun h = h a" + apply (rule fresh_fun_apply) + apply (auto simp add: fresh_Pair intro: a) + done + +lemma fresh_fun_eqvt: + fixes h :: "'a::at \ 'b::pt" + assumes a: "\a. atom a \ (h, h a)" + shows "p \ (fresh_fun h) = fresh_fun (p \ h)" + using a + apply (clarsimp simp add: fresh_Pair) + apply (subst fresh_fun_apply', assumption+) + apply (drule fresh_permute_iff [where p=p, THEN iffD2]) + apply (drule fresh_permute_iff [where p=p, THEN iffD2]) + apply (simp only: atom_eqvt permute_fun_app_eq [where f=h]) + apply (erule (1) fresh_fun_apply' [symmetric]) + done + +lemma fresh_fun_supports: + fixes h :: "'a::at \ 'b::pt" + assumes a: "\a. atom a \ (h, h a)" + shows "(supp h) supports (fresh_fun h)" + apply (simp add: supports_def fresh_def [symmetric]) + apply (simp add: fresh_fun_eqvt [OF a] swap_fresh_fresh) + done + +notation fresh_fun (binder "FRESH " 10) + +lemma FRESH_f_iff: + fixes P :: "'a::at \ 'b::pure" + fixes f :: "'b \ 'c::pure" + assumes P: "finite (supp P)" + shows "(FRESH x. f (P x)) = f (FRESH x. P x)" +proof - + obtain a::'a where "atom a \ P" using P by (rule obtain_fresh') + show "(FRESH x. f (P x)) = f (FRESH x. P x)" + apply (subst fresh_fun_apply' [where a=a, OF _ pure_fresh]) + apply (cut_tac `atom a \ P`) + apply (simp add: fresh_conv_MOST) + apply (elim MOST_rev_mp, rule MOST_I, clarify) + apply (simp add: permute_fun_def permute_pure fun_eq_iff) + apply (subst fresh_fun_apply' [where a=a, OF `atom a \ P` pure_fresh]) + apply (rule refl) + done +qed + +lemma FRESH_binop_iff: + fixes P :: "'a::at \ 'b::pure" + fixes Q :: "'a::at \ 'c::pure" + fixes binop :: "'b \ 'c \ 'd::pure" + assumes P: "finite (supp P)" + and Q: "finite (supp Q)" + shows "(FRESH x. binop (P x) (Q x)) = binop (FRESH x. P x) (FRESH x. Q x)" +proof - + from assms have "finite (supp (P, Q))" by (simp add: supp_Pair) + then obtain a::'a where "atom a \ (P, Q)" by (rule obtain_fresh') + then have "atom a \ P" and "atom a \ Q" by (simp_all add: fresh_Pair) + show ?thesis + apply (subst fresh_fun_apply' [where a=a, OF _ pure_fresh]) + apply (cut_tac `atom a \ P` `atom a \ Q`) + apply (simp add: fresh_conv_MOST) + apply (elim MOST_rev_mp, rule MOST_I, clarify) + apply (simp add: permute_fun_def permute_pure fun_eq_iff) + apply (subst fresh_fun_apply' [where a=a, OF `atom a \ P` pure_fresh]) + apply (subst fresh_fun_apply' [where a=a, OF `atom a \ Q` pure_fresh]) + apply (rule refl) + done +qed + +lemma FRESH_conj_iff: + fixes P Q :: "'a::at \ bool" + assumes P: "finite (supp P)" and Q: "finite (supp Q)" + shows "(FRESH x. P x \ Q x) \ (FRESH x. P x) \ (FRESH x. Q x)" +using P Q by (rule FRESH_binop_iff) + +lemma FRESH_disj_iff: + fixes P Q :: "'a::at \ bool" + assumes P: "finite (supp P)" and Q: "finite (supp Q)" + shows "(FRESH x. P x \ Q x) \ (FRESH x. P x) \ (FRESH x. Q x)" +using P Q by (rule FRESH_binop_iff) + + +section {* Library functions for the nominal infrastructure *} + +use "nominal_library.ML" + + +section {* Automation for creating concrete atom types *} + +text {* at the moment only single-sort concrete atoms are supported *} + +use "nominal_atoms.ML" + + +section {* automatic equivariance procedure for inductive definitions *} + +use "nominal_eqvt.ML" + + + + +end