Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quellcode-Bibliothek Nominal2_Base.thy

  Sprache: Isabelle
 

(*  Title:      Nominal2_Base
    Authors:    Christian Urban, Brian Huffman, Cezary Kaliszyk

    Basic definitions and lemma infrastructure for
    Nominal Isabelle.
*)

theory Nominal2_Base
imports "HOL-Library.Infinite_Set"
        "HOL-Library.Multiset"
        "HOL-Library.FSet"
        FinFun.FinFun
keywords
  "atom_decl" "equivariance" :: thy_decl
begin

declare [[typedef_overloaded]]


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
  "perm {f. bij f finite {a. f a a} (a. sort_of (f a) = sort_of a)}"

typedef perm = "perm"
proof
  show "id perm" unfolding perm_def by simp
qed

lemma permI:
  assumes "bij f" and "MOST x. f x = x" and "a. sort_of (f a) = sort_of a"
  shows "f perm"
  using assms unfolding perm_def MOST_iff_cofinite by simp

lemma perm_is_bij: "f perm ==> bij f"
  unfolding perm_def by simp

lemma perm_is_finite: "f perm ==> finite {a. f a a}"
  unfolding perm_def by simp

lemma perm_is_sort_respecting: "f perm ==> sort_of (f a) = sort_of a"
  unfolding perm_def by simp

lemma perm_MOST: "f perm ==> MOST x. f x = x"
  unfolding perm_def MOST_iff_cofinite by simp

lemma perm_id: "id perm"
  unfolding perm_def by simp

lemma perm_comp:
  assumes f: "f perm" and g: "g perm"
  shows "(f g) perm"
apply (rule permI)
apply (rule bij_comp)
apply (rule perm_is_bij [OF g])
apply (rule perm_is_bij [OF f])
apply (rule MOST_rev_mp [OF perm_MOST [OF g]])
apply (rule MOST_rev_mp [OF perm_MOST [OF f]])
apply (simp)
apply (simp add: perm_is_sort_respecting [OF f])
apply (simp add: perm_is_sort_respecting [OF g])
done

lemma perm_inv:
  assumes f: "f perm"
  shows "(inv f) perm"
apply (rule permI)
apply (rule bij_imp_bij_inv)
apply (rule perm_is_bij [OF f])
apply (rule MOST_mono [OF perm_MOST [OF f]])
apply (erule subst, rule inv_f_f)
apply (rule bij_is_inj [OF perm_is_bij [OF f]])
apply (rule perm_is_sort_respecting [OF f, THEN sym, THEN trans])
apply (simp add: surj_f_inv_f [OF bij_is_surj [OF perm_is_bij [OF f]]])
done

lemma bij_Rep_perm: "bij (Rep_perm p)"
  using Rep_perm [of p] unfolding perm_def by simp

lemma finite_Rep_perm: "finite {a. Rep_perm p a a}"
  using Rep_perm [of p] unfolding perm_def by simp

lemma sort_of_Rep_perm: "sort_of (Rep_perm p a) = sort_of a"
  using Rep_perm [of p] unfolding perm_def by simp

lemma Rep_perm_ext:
  "Rep_perm p1 = Rep_perm p2 ==> p1 = p2"
  by (simp add: fun_eq_iff Rep_perm_inject [symmetric])

instance perm :: size ..


subsection Permutations form a (multiplicative) group

instantiation perm :: group_add
begin

definition
  "0 = Abs_perm id"

definition
  "- p = Abs_perm (inv (Rep_perm p))"

definition
  "p + q = Abs_perm (Rep_perm p Rep_perm q)"

definition
  "(p1::perm) - p2 = p1 + - p2"

lemma Rep_perm_0: "Rep_perm 0 = id"
  unfolding zero_perm_def
  by (simp add: Abs_perm_inverse perm_id)

lemma Rep_perm_add:
  "Rep_perm (p1 + p2) = Rep_perm p1 Rep_perm p2"
  unfolding plus_perm_def
  by (simp add: Abs_perm_inverse perm_comp Rep_perm)

lemma Rep_perm_uminus:
  "Rep_perm (- p) = inv (Rep_perm p)"
  unfolding uminus_perm_def
  by (simp add: Abs_perm_inverse perm_inv Rep_perm)

instance
apply standard
unfolding Rep_perm_inject [symmetric]
unfolding minus_perm_def
unfolding Rep_perm_add
unfolding Rep_perm_uminus
unfolding Rep_perm_0
by (simp_all add: o_assoc inv_o_cancel [OF bij_is_inj [OF bij_Rep_perm]])

end


section Implementation of swappings

definition
  swap :: "atom ==> atom ==> perm" ('(_ _'))
where
  "(a b) =
    Abs_perm (if sort_of a = sort_of b
              then (λc. if a = c then b else if b = c then a else c)
              else id)"

lemma Rep_perm_swap:
  "Rep_perm (a b) =
    (if sort_of a = sort_of b
     then (λc. if a = c then b else if b = c then a else c)
     else id)"
unfolding swap_def
apply (rule Abs_perm_inverse)
apply (rule permI)
apply (auto simp: bij_def inj_on_def surj_def)[1]
apply (rule MOST_rev_mp [OF MOST_neq(1) [of a]])
apply (rule MOST_rev_mp [OF MOST_neq(1) [of b]])
apply (simp)
apply (simp)
done

lemmas Rep_perm_simps =
  Rep_perm_0
  Rep_perm_add
  Rep_perm_uminus
  Rep_perm_swap

lemma swap_different_sorts [simp]:
  "sort_of a sort_of b ==> (a b) = 0"
  by (rule Rep_perm_ext) (simp add: Rep_perm_simps)

lemma swap_cancel:
  shows "(a b) + (a b) = 0"
  and   "(a b) + (b a) = 0"
  by (rule_tac [!] Rep_perm_ext)
     (simp_all add: Rep_perm_simps fun_eq_iff)

lemma swap_self [simp]:
  "(a a) = 0"
  by (rule Rep_perm_ext, simp add: Rep_perm_simps fun_eq_iff)

lemma minus_swap [simp]:
  "- (a b) = (a b)"
  by (rule minus_unique [OF swap_cancel(1)])

lemma swap_commute:
  "(a b) = (b a)"
  by (rule Rep_perm_ext)
     (simp add: Rep_perm_swap fun_eq_iff)

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 (rule_tac Rep_perm_ext)
     (auto simp: Rep_perm_simps fun_eq_iff)


section Permutation Types

text 
 Infix syntax for permute has higher precedence than
 addition, but lower than unary minus.
 


class pt =
  fixes permute :: "perm ==> 'a ==> 'a" (_ _ [767575)
  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"
  using permute_plus [of p "- q" x] 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 = (Rep_perm p) a"

instance
apply standard
apply(simp_all add: permute_atom_def Rep_perm_simps)
done

end

lemma sort_of_permute [simp]:
  shows "sort_of (p a) = sort_of a"
  unfolding permute_atom_def by (rule sort_of_Rep_perm)

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)"
  unfolding permute_atom_def
  by (simp add: Rep_perm_swap)

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
  by (metis Rep_perm_ext ext)

subsection Permutations for permutations

instantiation perm :: pt
begin

definition
  "p q = p + q - p"

instance
apply standard
apply (simp add: permute_perm_def)
apply (simp add: permute_perm_def algebra_simps)
done

end

lemma permute_self:
  shows "p p = p"
  unfolding permute_perm_def
  by (simp add: add.assoc)

lemma pemute_minus_self:
  shows "- p p = p"
  unfolding permute_perm_def
  by (simp add: add.assoc)


subsection Permutations for functions

instantiation "fun" :: (pt, pt) pt
begin

definition
  "p f = (λx. p (f (- p x)))"

instance
apply standard
apply (simp add: permute_fun_def)
apply (simp add: permute_fun_def minus_add)
done

end

lemma permute_fun_app_eq:
  shows "p (f x) = (p f) (p x)"
  unfolding permute_fun_def by simp

lemma permute_fun_comp:
  shows "p f = (permute p) o f o (permute (-p))"
by (simp add: comp_def permute_fun_def)

subsection Permutations for booleans

instantiation bool :: pt
begin

definition "p (b::bool) = b"

instance
apply standard
apply(simp_all add: permute_bool_def)
done

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 standard
apply (auto simp: 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: 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: 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: 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: 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 standard (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 standard 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 standard (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 standard (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 standard (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 add_mset x M) = add_mset (p x) (p M)"
  and   "(p (M + N)) = (p M) + (p N)"
  unfolding permute_multiset_def
  by (simp_all)


subsection Permutations for @{typ "'a fset"}

instantiation fset :: (pt) pt
begin

context includes fset.lifting begin
lift_definition
  "permute_fset" :: "perm ==> 'a fset ==> 'a fset"
is "permute :: perm ==> 'a set ==> 'a set" by simp
end

context includes fset.lifting begin
instance
proof
  fix x :: "'a fset" and p q :: "perm"
  show "0 x = x" by transfer simp
  show "(p + q) x = p q x"  by transfer simp
qed
end

end

context includes fset.lifting
begin
lemma permute_fset [simp]:
  fixes S::"('a::pt) fset"
  shows "(p {||}) = ({||} ::('a::pt) fset)"
  and   "(p finsert x S) = finsert (p x) (p S)"
  apply (transfer, simp add: empty_eqvt)
  apply (transfer, simp add: insert_eqvt)
  done

lemma fset_eqvt:
  shows "p (fset S) = fset (p S)"
  by transfer simp
end


subsection Permutations for @{typ "('a, 'b) finfun"}

instantiation finfun :: (pt, pt) pt
begin

lift_definition
  permute_finfun :: "perm ==> ('a, 'b) finfun ==> ('a, 'b) finfun"
is
  "permute :: perm ==> ('a ==> 'b) ==> ('a ==> 'b)"
  apply(simp add: permute_fun_comp)
  apply(rule finfun_right_compose)
  apply(rule finfun_left_compose)
  apply(assumption)
  apply(simp)
  done

instance
apply standard
apply(transfer)
apply(simp)
apply(transfer)
apply(simp)
done

end


subsection Permutations for @{typ char}, @{typ nat}, and @{typ int}

instantiation char :: pt
begin

definition "p (c::char) = c"

instance
  by standard (simp_all add: permute_char_def)

end

instantiation nat :: pt
begin

definition "p (n::nat) = n"

instance
  by standard (simp_all add: permute_nat_def)

end

instantiation int :: pt
begin

definition "p (i::int) = i"

instance
  by standard (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 standard (simp add: permute_fun_def permute_pure)

instance set :: (pure) pure
  by standard (simp add: permute_set_def permute_pure)

instance prod :: (pure, pure) pure
  by standard (induct_tac x, simp add: permute_pure)

instance sum :: (pure, pure) pure
  by standard (induct_tac x, simp_all add: permute_pure)

instance list :: (pure) pure
  by standard (induct_tac x, simp_all add: permute_pure)

instance option :: (pure) pure
  by standard (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

ML_file nominal_basics.ML


subsection Eqvt infrastructure

text Setup of the theorem attributes eqvt and eqvt_raw.

ML_file nominal_thmdecls.ML


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

ML_file 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.

simproc_setup perm_simproc ("p t") = fn _ => fn ctxt => fn ctrm =>
 case Thm.term_of (Thm.dest_arg ctrm) of
 Free _ => NONE
 | Var _ => NONE
 | 🍋permute _ for _ _ => NONE
 | _ =>
 let
 val thm = Nominal_Permeq.eqvt_conv ctxt Nominal_Permeq.eqvt_strict_config ctrm
 handle ERROR _ => Thm.reflexive ctrm
 in
 if Thm.is_reflexive thm then NONE else SOME(thm)
 end
 



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: 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_add_eq_diff_diff_swap)


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 HOL.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 HOL.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 only: 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: permute_bool_def)

lemma Bex_eqvt [eqvt]:
  shows "p (x S. P x) = (x (p S). (p P) x)"
  unfolding Bex_def by simp

lemma Ball_eqvt [eqvt]:
  shows "p (x S. P x) = (x (p S). (p P) x)"
  unfolding Ball_def by simp

lemma image_eqvt [eqvt]:
  shows "p (f ` A) = (p f) ` (p A)"
  unfolding image_def by simp

lemma Image_eqvt [eqvt]:
  shows "p (R `` A) = (p R) `` (p A)"
  unfolding Image_def by simp

lemma UNIV_eqvt [eqvt]:
  shows "p UNIV = UNIV"
  unfolding UNIV_def
  by (perm_simp) (rule refl)

lemma inter_eqvt [eqvt]:
  shows "p (A B) = (p A) (p B)"
  unfolding Int_def by simp

lemma Inter_eqvt [eqvt]:
  shows "p S = (p S)"
  unfolding Inter_eq by simp

lemma union_eqvt [eqvt]:
  shows "p (A B) = (p A) (p B)"
  unfolding Un_def by simp

lemma Union_eqvt [eqvt]:
  shows "p A = (p A)"
  unfolding Union_eq
  by perm_simp rule

lemma Diff_eqvt [eqvt]:
  fixes A B :: "'a::pt set"
  shows "p (A - B) = (p A) - (p B)"
  unfolding set_diff_eq by simp

lemma Compl_eqvt [eqvt]:
  fixes A :: "'a::pt set"
  shows "p (- A) = - (p A)"
  unfolding Compl_eq_Diff_UNIV by simp

lemma subset_eqvt [eqvt]:
  shows "p (S T) (p S) (p T)"
  unfolding subset_eq by simp

lemma psubset_eqvt [eqvt]:
  shows "p (S T) (p S) (p T)"
  unfolding psubset_eq by simp

lemma vimage_eqvt [eqvt]:
  shows "p (f -` A) = (p f) -` (p A)"
  unfolding vimage_def by simp

lemma foldr_eqvt[eqvt]:
  "p foldr f xs = foldr (p f) (p xs)"
  apply(induct xs)
  apply(simp_all)
  apply(perm_simp exclude: foldr)
  apply(simp)
  done

(* FIXME: eqvt attribute *)
lemma Sigma_eqvt:
  shows "(p (X × Y)) = (p X) × (p Y)"
unfolding Sigma_def
by (perm_simp) (rule refl)

text 
 In order to prove that lfp is equivariant we need two
 auxiliary classes which specify that (<=) and
 Inf are equivariant. Instances for bool and fun are
 given.
 


class le_eqvt = pt +
  assumes le_eqvt [eqvt]: "p (x y) = ((p x) (p (y :: 'a :: {order, pt})))"

class inf_eqvt = pt +
  assumes inf_eqvt [eqvt]: "p (Inf X) = Inf (p (X :: 'a :: {complete_lattice, pt} set))"

instantiation bool :: le_eqvt
begin

instance
apply standard
unfolding le_bool_def
apply(perm_simp)
apply(rule refl)
done

end

instantiation "fun" :: (pt, le_eqvt) le_eqvt
begin

instance
apply standard
unfolding le_fun_def
apply(perm_simp)
apply(rule refl)
done

end

instantiation bool :: inf_eqvt
begin

instance
apply standard
unfolding Inf_bool_def
apply(perm_simp)
apply(rule refl)
done

end

instantiation "fun" :: (pt, inf_eqvt) inf_eqvt
begin

instance
apply standard
unfolding Inf_fun_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 simp

lemma finite_eqvt [eqvt]:
  shows "p finite A = finite (p A)"
unfolding finite_def
by simp

lemma fun_upd_eqvt[eqvt]:
  shows "p (f(x := y)) = (p f)((p x) := (p y))"
unfolding fun_upd_def
by simp

lemma comp_eqvt [eqvt]:
  shows "p (f g) = (p f) (p g)"
unfolding comp_def
by simp

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 (case_prod P x) = case_prod (p P) (p x)"
  unfolding split_def
  by simp


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)

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 map_option_eqvt[eqvt]:
  shows "p (map_option f x) = map_option (p f) (p x)"
  by (cases x) (simp_all)


subsubsection Equivariance for @{typ "'a fset"}

context includes fset.lifting begin
lemma in_fset_eqvt:
  shows "(p (x || S)) = ((p x) || (p S))"
  by transfer simp

lemma union_fset_eqvt [eqvt]:
  shows "(p (S || T)) = ((p S) || (p T))"
  by (induct S) (simp_all)

lemma inter_fset_eqvt [eqvt]:
  shows "(p (S || T)) = ((p S) || (p T))"
  by transfer simp

lemma subset_fset_eqvt [eqvt]:
  shows "(p (S || T)) = ((p S) || (p T))"
  by transfer simp

lemma map_fset_eqvt [eqvt]:
  shows "p (f |`| S) = (p f) |`| (p S)"
  by transfer simp
end

subsubsection Equivariance for @{typ "('a, 'b) finfun"}

lemma finfun_update_eqvt [eqvt]:
  shows "(p (finfun_update f a b)) = finfun_update (p f) (p a) (p b)"
by (transfer) (simp)

lemma finfun_const_eqvt [eqvt]:
  shows "(p (finfun_const b)) = finfun_const (p b)"
by (transfer) (simp)

lemma finfun_apply_eqvt [eqvt]:
  shows "(p (finfun_apply f b)) = finfun_apply (p f) (p b)"
by (transfer) (simp)


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" (_ _ [555555)
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 simp

lemma fresh_eqvt [eqvt]:
  shows "p (a x) = (p a) (p x)"
  unfolding fresh_def by simp

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 standard (simp add: pure_supp)


subsection  Type 🍋atom is finitely-supported.

lemma supp_atom:
  shows "supp a = {a}"
apply (rule finite_supp_unique)
apply (clarsimp simp add: supports_def)
apply simp
apply simp
done

lemma fresh_atom:
  shows "a b a b"
  unfolding fresh_def supp_atom by simp

instance atom :: fs
  by standard (simp add: supp_atom)


section Type 🍋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}"
  using finite_Rep_perm [of p]
  unfolding permute_atom_def .

lemma supp_perm:
  shows "supp p = {a. p a a}"
apply (rule finite_supp_unique)
apply (rule supports_perm)
apply (rule finite_perm_lemma)
apply (simp add: perm_swap_eq swap_eqvt)
apply (auto simp: perm_eq_iff swap_atom)
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: supp_perm swap_atom)

lemma fresh_swap:
  shows "a (b c) (sort_of b sort_of c) b = c (a b a c)"
  by (simp add: fresh_def supp_swap supp_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: supp_perm)

lemma supp_plus_perm:
  fixes p q::perm
  shows "supp (p + q) supp p supp q"
  by (auto simp: supp_perm)

lemma fresh_minus_perm:
  fixes p::perm
  shows "a (- p) a p"
  unfolding fresh_def
  unfolding supp_perm
  apply(simp)
  apply(metis permute_minus_cancel)
  done

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

lemma perm_eq_iff2:
  fixes p q :: "perm"
  shows "p = q (a::atom supp p supp q. p a = q a)"
  unfolding perm_eq_iff
  apply(auto)
  apply(case_tac "a p a q")
  apply(simp add: fresh_perm)
  apply(simp add: fresh_def)
  done


instance perm :: fs
  by standard (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
apply standard
apply (case_tac x)
apply (simp add: supp_Pair finite_supp)
done


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 standard
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 standard
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: 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: supp_append supp_Cons supp_Nil)

lemma fresh_rev:
  shows "a rev xs a xs"
  by (induct xs) (auto simp: 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: 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 standard
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 eqvt and 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 only: 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:
  assumes a: "eqvt f"
  shows "a f"
  using a
  unfolding fresh_def
  by (simp add: supp_fun_eqvt)

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)
apply(simp add: 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

text for handling of freshness of functions

simproc_setup fresh_fun_simproc ("a (f::'a::pt ==>'b::pt)") = fn _ => fn ctxt => fn ctrm =>
 let
 val _ $ _ $ f = Thm.term_of ctrm
 in
 case (Term.add_frees f [], Term.add_vars f []) of
 ([], []) => SOME(@{thm fresh_fun_eqvt[simplified eqvt_def, THEN Eq_TrueI]})
 | (x::_, []) =>
 let
 val argx = Free x
 val absf = absfree x f
 val cty_inst =
 [SOME (Thm.ctyp_of ctxt (fastype_of argx)), SOME (Thm.ctyp_of ctxt (fastype_of f))]
 val ctrm_inst = [NONE, SOME (Thm.cterm_of ctxt absf), SOME (Thm.cterm_of ctxt argx)]
 val thm = Thm.instantiate' cty_inst ctrm_inst @{thm fresh_fun_app}
 in
 SOME(thm RS @{thm Eq_TrueI})
 end
 | (_, _) => NONE
 end
 


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: 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 (xS. supp x)"
  using fin by (induct) (auto simp: finite_supp)

lemma Union_included_in_supp:
  fixes S::"('a::fs set)"
  assumes fin: "finite S"
  shows "(xS. supp x) supp S"
proof -
  have eqvt: "eqvt (λS. x S. supp x)"
    unfolding eqvt_def by simp
  have "(xS. supp x) = supp (xS. supp x)"
    by (rule supp_finite_atom_set[symmetric]) (rule Union_of_finite_supp_sets[OF fin])
  also have " supp S" using eqvt
    by (rule supp_fun_app_eqvt)
  finally show "(xS. supp x) supp S" .
qed

lemma supp_of_finite_sets:
  fixes S::"('a::fs set)"
  assumes fin: "finite S"
  shows "(supp S) = (xS. 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 fresh_finite_union:
  fixes S T::"('a::fs) set"
  assumes fin1: "finite S"
  and     fin2: "finite T"
  shows "a (S T) a S a T"
  unfolding fresh_def
  by (simp add: supp_of_finite_union[OF fin1 fin2])

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_mset_eqvt [eqvt]:
  shows "p (set_mset M) = set_mset (p M)"
by (induct M) (simp_all add: insert_eqvt empty_eqvt)

lemma supp_set_mset:
  shows "supp (set_mset 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 by (induct M) simp_all
  have "(xset_mset M. supp x) supports M"
    by (auto intro!: sw swap_fresh_fresh simp add: fresh_def supports_def)
  also have "(xset_mset M. supp x) = ({supp x | x. x # M})"
    by auto
  finally show "({supp x | x. x # M}) supports M" .
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}) = (x set_mset M. supp x)" by auto
  also have "... = supp (set_mset M)"
    by (simp add: supp_of_finite_sets)
  also have " ... supp M" by (rule supp_set_mset)
  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: supp_of_multisets)

lemma supp_empty_mset [simp]:
  shows "supp {#} = {}"
  unfolding supp_def
  by simp

instance multiset :: (fs) fs
  by standard (rule multisets_supp_finite)

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_finsert [simp]:
  fixes x::"'a::fs"
  and   S::"'a fset"
  shows "supp (finsert x S) = supp x supp S"
  apply(subst supp_fset[symmetric])
  apply(simp add: supp_of_finite_insert)
  done

lemma fresh_finsert:
  fixes x::"'a::fs"
  and   S::"'a fset"
  shows "a finsert 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
  by standard (rule fset_finite_supp)


subsection Type @{typ "('a, 'b) finfun"} is finitely supported

lemma fresh_finfun_const:
  shows "a (finfun_const b) a b"
  by (simp add: fresh_def supp_def)

lemma fresh_finfun_update:
  shows "[a f; a x; a y] ==> a finfun_update f x y"
  unfolding fresh_conv_MOST
  unfolding finfun_update_eqvt
  by (elim MOST_rev_mp) (simp)

lemma supp_finfun_const:
  shows "supp (finfun_const b) = supp(b)"
  by (simp add: supp_def)

lemma supp_finfun_update:
  shows "supp (finfun_update f x y) supp(f, x, y)"
using fresh_finfun_update
by (auto simp: fresh_def supp_Pair)

instance finfun :: (fs, fs) fs
  apply standard
  apply(induct_tac x rule: finfun_weak_induct)
  apply(simp add: supp_finfun_const finite_supp)
  apply(rule finite_subset)
  apply(rule supp_finfun_update)
  apply(simp add: supp_Pair 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 _ =>
 
 val mksimps_pairs = (@{const_name Nominal2_Base.fresh}, @{thms fresh_PairD}) :: mksimps_pairs
 
 Simplifier.map_ss (fn ss => Simplifier.set_mksimps (mksimps mksimps_pairs) ss)
 
 



text The fresh-star generalisation of fresh is used in strong
 induction principles.


definition
  fresh_star :: "atom set ==> 'a::pt ==> bool" (_ * _ [80,8080)
where
  "as * x a as. a x"

lemma fresh_star_supp_conv:
  shows "supp x * y ==> supp y * x"
by (auto simp: 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: 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: supp_finite_atom_set fin)


lemma fresh_star_Pair:
  shows "as * (x, y) = (as * x as * y)"
  by (auto simp: 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: 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: fresh_star_def)

lemma fresh_star_insert:
  shows "(insert a as) * x = (a x as * x)"
  by (auto simp: 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 simp


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: 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: 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)
(uto intro: zero swap)

perm_struct_induct2
  assumes
  assumes zero: "P 0"
  assumes swapAnd b. [sort_of a = sort_of b; a <noteq  S] <Longrightarrow 
Tangle_Moves
  sp
using Sjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
 _lencen(domain_blockhave.s
   (autoproof

lemmaperm_simple_struct_induct2 zero
  assumes zero " "
>f<oteq b] <Longrightarrow     by auto
     0
  shows
by ule_tac p"inp)
   (auto intro: zero swap plus)

lemma supp_perm_singleton:
  fixes p::"
  shows "supp \ubseteq {b}
proof -
  { assume "supp[ sic
     "p = 0"
      bytruleinduct
  }
           e_diagram_defjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
qeded

lemma:
java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 17
  shows(cup#[])))(vert#vert#[])))"
proof
  { assume "using
    then[>c##)
       (usingl_right_tensor
      apply (auto simp: swap_cancel supp_zero_perm supp_swap
      apply (simp add: swap_commute)
      done
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 3
  then show "supp \subseteq {a, b} 🚫(enhn mcm s
 auto sip:spp_ero_prm sppwppi: fpts
qed

lemma_e:
  assumes "(ake_vert_block_def
  shows
proof -
  assms" p x}"
    unfolding supp_perm fresh_star_def fresh_def by auto
  then show "p (?w)) = (b~ (basic [cu)
  = c?m)
    case zero
     "0x = x" by simp
  next
    moreovereaeiga(?z"
    then have "a
    then show "((a  b)            Longrightarrow ?thesis"
qed
qed

text codomain_walli#p#]) <> ?ep)=oial(a u, u <>basic [vert, over, vert])
emmatest
  assumes "(circ (basic (cap[)
bullet
proof -
  fromassms x}"
    unfolding supp_perm fresh_st = make_ve(nat (domain_w(ba (ca#[]))))"
   pbullet x = x"
  proof (induct p rule: perm_struct_induct2)
    case zero
    show "0 java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "brackoff" is null
  next
    case (swap a b)
    then have "a x" "b
    then shac(b (cap[)))~ ?cc
  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 " x = x"
proof -
  from assms have "supp p  {a. a  x}"
    unfolding supp_perm fresh_star_def fresh_def by auto
  then show " x = x"
  proof (induct p rule: perm_struct_induct2)
    case zero
    show "0  x = x" by simp
  next
    case (swap a b)
    then have " x" " 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: " supp x. p  a = q  a"
  shows " x = q  x"
proof -
  from a have " supp x. (-q + p)  a = a" by simp
  then have " 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 " x = q  x"
    by (metis permute_minus_cancel 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 " 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 " as = as"
proof -
  from a have "supp p  {a. a  as}"
    unfolding supp_perm fresh_star_def fresh_def by auto
  then show " 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 " as" " as" " 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.
\<close>

lemma at_set_avoiding_aux:
  fixes Xs::"  set"
 and As::"atom set"
 assumes b: "Xs As"
 and c: "finite As"
 shows "p. (p Xs) As = {} (supp p) = (Xs (p Xs))"
  -
 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: 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
 

  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

  at_set_avoiding1:
 assumes "finite xs"
 and "finite (supp c)"
 shows "p. (p xs) * c"
  assms
 (erule_tac c="c" in at_set_avoiding)
 (auto)
 

  at_set_avoiding2:
 assumes "finite xs"
 and "finite (supp c)" "finite (supp x)"
 and "xs * x"
 shows "p. (p xs) * c supp x * p"
  assms
 (erule_tac c="(c, x)" in at_set_avoiding)
 (simp add: supp_Pair)
 (rule_tac x="p" in exI)
 (simp add: fresh_star_Pair)
 (rule fresh_star_supp_conv)
 (auto simp: fresh_star_def)
 

  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)"
  assms
 (erule_tac c="(c, x)" in at_set_avoiding)
 (simp add: supp_Pair)
 (rule_tac x="p" in exI)
 (simp add: fresh_star_Pair)
 (rule fresh_star_supp_conv)
 (auto simp: fresh_star_def)
 

  at_set_avoiding2_atom:
 assumes "finite (supp c)" "finite (supp x)"
 and b: "a x"
 shows "p. (p a) c supp x * p"
  -
 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
 


  Renaming permutations

  set_renaming_perm:
 assumes b: "finite bs"
 shows "q. (b bs. q b = p b) supp q bs (p bs)"
  b
  (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
 
 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 (metis empty_subsetI insert(3) supp_swap)
 { 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: 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"
 define q' where "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: swap_atom)
 moreover
 { have "{q a, p a} insert a bs p insert a bs"
 using **
 apply (auto simp: 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"
 unfolding supp_swap by auto
 moreover
 have "supp q insert a bs p insert a bs"
 using ** by (auto simp: 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
 

  set_renaming_perm2:
 shows "q. (b bs. q b = p b) supp q bs (p bs)"
  -
 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: 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
 

  list_renaming_perm:
 shows "q. (b set bs. q b = p b) supp q set bs (p set bs)"
  (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: 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"
 define q' where "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: swap_atom)
 moreover
 { have "{q a, p a} set (a # bs) p (set (a # bs))"
 using **
 apply (auto simp: 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)"
 unfolding supp_swap by auto
 moreover
 have "supp q set (a # bs) p (set (a # bs))"
 using ** by (auto simp: 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
 
 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
 


  Concrete Atoms Types

 
 Class at_base allows types containing multiple sorts of atoms.
 Class at only allows types with a single sort.
 


  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)"

  atom_eqvt [eqvt]

  at = at_base +
 assumes sort_of_atom_eq [simp]: "sort_of (atom a) = sort_of (atom b)"

  sort_ineq [simp]:
 assumes "sort_of (atom a) sort_of (atom b)"
 shows "atom a atom b"
  assms by metis

  supp_at_base:
 fixes a::"'a::at_base"
 shows "supp a = {atom a}"
 by (simp add: supp_atom [symmetric] supp_def atom_eqvt)

  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

 
   simproc below *)
lemma fresh_ineq_at_base [simp]:
  shows "a atom b ==> a b"
  by (simp add: fresh_at_base)


lemma fresh_atom_at_base [simp]:
  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)

lemma if_fresh_at_base [simp]:
  shows "atom a x ==> P (if a = x then t else s) = P s"
  and   "atom a x ==> P (if x = a then t else s) = P s"
by (simp_all add: fresh_at_base)


simproc_setup fresh_ineq ("x (y::'a::at_base)") = fn _ => fn ctxt => fn ctrm =>
 case Thm.term_of ctrm of 🍋Not for 🍋HOL.eq _ for lhs rhs =>
 let
 fun first_is_neg lhs rhs [] = NONE
 | first_is_neg lhs rhs (thm::thms) =
 (case Thm.prop_of thm of
 _ $ 🍋Not for 🍋HOL.eq _ for l r =>
 (if l = lhs andalso r = rhs then SOME(thm)
 else if r = lhs andalso l = rhs then SOME(thm RS @{thm not_sym})
 else first_is_neg lhs rhs thms)
 | _ => first_is_neg lhs rhs thms)

 val simp_thms = @{thms fresh_Pair fresh_at_base atom_eq_iff}
 val prems = Simplifier.prems_of ctxt
 |> filter (fn thm => case Thm.prop_of thm of
 _ $ 🍋fresh _ for _ $ a b =>
 (let
 val atms = a :: HOLogic.strip_tuple b
 in
 member (op =) atms lhs andalso member (op =) atms rhs
 end)
 | _ => false)
 |> map (simplify (put_simpset HOL_basic_ss ctxt addsimps simp_thms))
 |> map HOLogic.conj_elims
 |> flat
 in
 case first_is_neg lhs rhs prems of
 SOME(thm) => SOME(thm RS @{thm Eq_TrueI})
 | NONE => NONE
 end
 | _ => NONE
 



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(2have "b = atom ((atom a b) a)"
    unfolding atom_eqvt [symmetric]
    by (simp add: swap_atom)
  hence "b atom ` ?U" by simp
  with b(1show "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: 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: 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 only: fresh_permute_iff)

lemma fresh_at_base_permI:
  shows "atom a p ==> p a = a"
by (simp add: fresh_def supp_perm)


section Infrastructure for concrete atom types

definition
  flip :: "'a::at_base ==> 'a ==> perm" ('(_ _'))
where
  "(a b) = (atom a atom b)"

lemma flip_fresh_fresh:
  assumes "atom a x" "atom b x"
  shows "(a b) x = x"
using assms
by (simp add: flip_def swap_fresh_fresh)

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]:
  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 flip_triple:
  fixes a b c::"'a::at"
  assumes "a b" and "c b"
  shows "(a c) + (b c) + (a c) = (a b)"
  unfolding flip_def
  by (rule swap_triple) (simp_all add: assms)

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


subsection Syntax for coercing at-elements to the atom-type

syntax
  "_atom_constrain" :: "logic ==> type ==> logic" (_:::_ [403)

syntax_consts
  "_atom_constrain" == atom

translations
  "_atom_constrain a t" => "CONST atom (_constrain a t)"


subsection A lemma for proving instances of class 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 🍋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 \<Rightarrow> atom" and Abs :: "atom \<Rightarrow> 'a"
  assumes type: "type_definition Rep Abs {a. sort_of a \<in> range (\<lambda>x::unit. s)}"
  assumes atom_def: "\<And>a. atom a = Rep a"
  assumes permute_def: "\<And>p a. p \<bullet> a = Abs (p \<bullet> Rep a)"
  shows "OFCLASS('a, at_class)"
proof
  interpret type_definition Rep Abs "{a. sort_of a \<in> range (\<lambda>x::unit. s)}" by (rule type)
  have sort_of_Rep: "\<And>a. sort_of (Rep a) = s" using Rep by (simp add: image_def)
  fix a b :: 'a and p p1 p2 :: perm
  show "0 \<bullet> a = a"
    unfolding permute_def by (simp add: Rep_inverse)
  show "(p1 + p2) \<bullet> a = p1 \<bullet> p2 \<bullet> 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 \<longleftrightarrow> a = b"
    unfolding atom_def by (simp add: Rep_inject)
  show "p \<bullet> atom a = atom (p \<bullet> 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 Library functions for the nominal infrastructure

ML_file nominal_library.ML


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: 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: fresh_Pair)
qed

text packaging the freshness lemma into a function

definition
  Fresh :: "('a::at ==> 'b::pt) ==> 'b"
where
  "Fresh h = (THE x. a. atom a h h a = x)"

lemma Fresh_apply:
  fixes h :: "'a::at ==> 'b::pt"
  assumes a: "a. atom a (h, h a)"
  assumes b: "atom a h"
  shows "Fresh h = h a"
unfolding Fresh_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_apply':
  fixes h :: "'a::at ==> 'b::pt"
  assumes a: "atom a h" "atom a h a"
  shows "Fresh h = h a"
  apply (rule Fresh_apply)
  apply (auto simp: fresh_Pair intro: a)
  done

simproc_setup Fresh_simproc ("Fresh (h::'a::at ==> 'b::pt)") = fn _ => fn ctxt => fn ctrm =>
 let
 val _ $ h = Thm.term_of ctrm

 val atoms = Simplifier.prems_of ctxt
 |> map_filter (fn thm => case Thm.prop_of thm of
 _ $ 🍋fresh _ for 🍋atom _ for atm _ => SOME atm | _ => NONE)
 |> distinct (op =)

 fun get_thm atm =
 let
 val goal1 = HOLogic.mk_Trueprop (mk_fresh (mk_atom atm) h)
 val goal2 = HOLogic.mk_Trueprop (mk_fresh (mk_atom atm) (h $ atm))

 val thm1 = Goal.prove ctxt [] [] goal1 (fn {context = ctxt', ...} => asm_simp_tac ctxt' 1)
 val thm2 = Goal.prove ctxt [] [] goal2 (fn {context = ctxt', ...} => asm_simp_tac ctxt' 1)
 in
 SOME (@{thm Fresh_apply'} OF [thm1, thm2] RS eq_reflection)
 end handle ERROR _ => NONE
 in
 get_first get_thm atoms
 end
 



lemma Fresh_eqvt:
  fixes h :: "'a::at ==> 'b::pt"
  assumes a: "a. atom a (h, h a)"
  shows "p (Fresh h) = Fresh (p h)"
proof -
  from a obtain a::"'a::at" where fr: "atom a h" "atom a h a"
    by (metis fresh_Pair)
  then have fr_p: "atom (p a) (p h)" "atom (p a) (p h) (p a)"
    by (metis atom_eqvt fresh_permute_iff eqvt_apply)+
  have "p (Fresh h) = p (h a)" using fr by simp
  also have "... = (p h) (p a)" by simp
  also have "... = Fresh (p h)" using fr_p by simp
  finally show "p (Fresh h) = Fresh (p h)" .
qed

lemma Fresh_supports:
  fixes h :: "'a::at ==> 'b::pt"
  assumes a: "a. atom a (h, h a)"
  shows "(supp h) supports (Fresh h)"
  apply (simp add: supports_def fresh_def [symmetric])
  apply (simp add: Fresh_eqvt [OF a] swap_fresh_fresh)
  done

notation Fresh (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')
  then show "(FRESH x. f (P x)) = f (FRESH x. P x)"
    by (simp add: pure_fresh)
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 show ?thesis
    by (simp add: pure_fresh)
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 Automation for creating concrete atom types

text At the moment only single-sort concrete atoms are supported.

ML_file nominal_atoms.ML


section Automatic equivariance procedure for inductive definitions

ML_file nominal_eqvt.ML

end

Messung V0.5 in Prozent
C=84 H=96 G=90

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.99Bemerkung:  (vorverarbeitet am  2026-06-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge