products/Sources/formale Sprachen/PVS/ints/   (Beweissystem der NASA Version 6.0.9©)  Datei vom 28.9.2014 mit Größe 29 kB image not shown  

Quelle  Finite_Set.thy

  Sprache: Isabelle
 

(*  Title:      HOL/Finite_Set.thy
  Author: Tobias Nipkow
  Author: Lawrence C Paulson
  Author: Markus Wenzel
  Author: Jeremy Avigad
  Author: Andrei Popescu
*)

section Finite sets

theory Finite_Set
  imports Product_Type Sum_Type Fields Relation
begin

subsection Predicate for finite sets

context notes [[inductive_internals]]
begin

inductive finite :: "'a set ==> bool"
  where
    emptyI [simp, intro!]: "finite {}"
  | insertI [simp, intro!]: "finite A ==> finite (insert a A)"

end

simproc_setup finite_Collect ("finite (Collect P)") = K Set_Comprehension_Pointfree.proc

declare [[simproc del: finite_Collect]]

lemma finite_induct [case_names empty insert, induct set: finite]:
  🍋 Discharging x F entails extra work.
  assumes "finite F"
  assumes "P {}"
    and insert: "x F. finite F ==> x F ==> P F ==> P (insert x F)"
  shows "P F"
  using finite F
proof induct
  show "P {}" by fact
next
  fix x F
  assume F: "finite F" and P: "P F"
  show "P (insert x F)"
  proof cases
    assume "x F"
    then have "insert x F = F" by (rule insert_absorb)
    with P show ?thesis by (simp only:)
  next
    assume "x F"
    from F this P show ?thesis by (rule insert)
  qed
qed

lemma infinite_finite_induct [case_names infinite empty insert]:
  assumes infinite: "A. ¬ finite A ==> P A"
    and empty: "P {}"
    and insert: "x F. finite F ==> x F ==> P F ==> P (insert x F)"
  shows "P A"
proof (cases "finite A")
  case False
  with infinite show ?thesis .
next
  case True
  then show ?thesis by (induct A) (fact empty insert)+
qed


subsubsection Choice principles

lemma ex_new_if_finite: 🍋 does not depend on def of finite at all
  assumes "¬ finite (UNIV :: 'a set)" and "finite A"
  shows "a::'a. a A"
proof -
  from assms have "A UNIV" by blast
  then show ?thesis by blast
qed

text A finite choice principle. Does not need the SOME choice operator.

lemma finite_set_choice: "finite A ==> xA. y. P x y ==> f. xA. P x (f x)"
proof (induct rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert a A)
  then obtain f b where f: "xA. P x (f x)" and ab: "P a b"
    by auto
  show ?case (is "f. ?P f")
  proof
    show "?P (λx. if x = a then b else f x)"
      using f ab by auto
  qed
qed


subsubsection Finite sets are the images of initial segments of natural numbers

lemma finite_imp_nat_seg_image_inj_on:
  assumes "finite A"
  shows "(n::nat) f. A = f ` {i. i < n} inj_on f {i. i < n}"
  using assms
proof induct
  case empty
  show ?case
  proof
    show "f. {} = f ` {i::nat. i < 0} inj_on f {i. i < 0}"
      by simp
  qed
next
  case (insert a A)
  have notinA: "a A" by fact
  from insert.hyps obtain n f where "A = f ` {i::nat. i < n}" "inj_on f {i. i < n}"
    by blast
  then have "insert a A = f(n:=a) ` {i. i < Suc n}" and "inj_on (f(n:=a)) {i. i < Suc n}"
    using notinA by (auto simp add: image_def Ball_def inj_on_def less_Suc_eq)
  then show ?case by blast
qed

lemma nat_seg_image_imp_finite: "A = f ` {i::nat. i < n} ==> finite A"
proof (induct n arbitrary: A)
  case 0
  then show ?case by simp
next
  case (Suc n)
  let ?B = "f ` {i. i < n}"
  have finB: "finite ?B" by (rule Suc.hyps[OF refl])
  show ?case
  proof (cases "k)
    case True
    then have "A = ?B"
      using Suc.prems by (auto simp:less_Suc_eq)
    then show ?thesis
      using finB by simp
  next
    case False
    then have "A = insert (f n) ?B"
      using Suc.prems by (auto simp:less_Suc_eq)
    then show ?thesis using finB by simp
  qed
qed

lemma finite_conv_nat_seg_image: "finite A (n f. A = f ` {i::nat. i < n})"
  by (blast intro: nat_seg_image_imp_finite dest: finite_imp_nat_seg_image_inj_on)

lemma finite_imp_inj_to_nat_seg:
  assumes "finite A"
  shows "f n. f ` A = {i::nat. i < n} inj_on f A"
proof -
  from finite_imp_nat_seg_image_inj_on [OF finite A]
  obtain f and n :: nat where bij: "bij_betw f {i. i
    by (auto simp: bij_betw_def)
  let ?f = "the_inv_into {i. i
  have "inj_on ?f A ?f ` A = {i. i
    by (fold bij_betw_def) (rule bij_betw_the_inv_into[OF bij])
  then show ?thesis by blast
qed

lemma finite_Collect_less_nat [iff]: "finite {n::nat. n < k}"
  by (fastforce simp: finite_conv_nat_seg_image)

lemma finite_Collect_le_nat [iff]: "finite {n::nat. n k}"
  by (simp add: le_eq_less_or_eq Collect_disj_eq)


subsection Finiteness and common set operations

lemma rev_finite_subset: "finite B ==> A B ==> finite A"
proof (induct arbitrary: A rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert x F A)
  have A: "A insert x F" and r: "A - {x} F ==> finite (A - {x})"
    by fact+
  show "finite A"
  proof cases
    assume x: "x A"
    with A have "A - {x} F" by (simp add: subset_insert_iff)
    with r have "finite (A - {x})" .
    then have "finite (insert x (A - {x}))" ..
    also have "insert x (A - {x}) = A"
      using x by (rule insert_Diff)
    finally show ?thesis .
  next
    show ?thesis when "A F"
      using that by fact
    assume "x A"
    with A show "A F"
      by (simp add: subset_insert_iff)
  qed
qed

lemma finite_subset: "A B ==> finite B ==> finite A"
  by (rule rev_finite_subset)

simproc_setup finite ("finite A") = 

 let

  val finite_subset = @{thm finite_subset}

  val Eq_TrueI = @{thm Eq_TrueI}

 
  fun is_subset A th = case Thm.prop_of th of
  (_ $ 🍋less_eq 🍋set _ for A' B)
  => if A aconv A' then SOME(B,th) else NONE
  | _ => NONE;
 
  fun is_finite th = case Thm.prop_of th of
  (_ $ 🍋finite _ for A) => SOME(A,th)
  | _ => NONE;
 
  fun comb (A,sub_th) (A',fin_th) ths = if A aconv A' then (sub_th,fin_th) :: ths else ths
 
  fun proc ctxt ct =
  (let
  val _ $ A = Thm.term_of ct
  val prems = Simplifier.prems_of ctxt
  val fins = map_filter is_finite prems
  val subsets = map_filter (is_subset A) prems
  in case fold_product comb subsets fins [] of
  (sub_th,fin_th) :: _ => SOME((fin_th RS (sub_th RS finite_subset)) RS Eq_TrueI)
  | _ => NONE
  end)
 in K proc end
 

(* Needs to be used with care *)
declare [[simproc del: finite]]

lemma finite_UnI:
  assumes "finite F" and "finite G"
  shows "finite (F G)"
  using assms by induct simp_all

lemma finite_Un [iff]: "finite (F G) finite F finite G"
  by (blast intro: finite_UnI finite_subset [of _ "F G"])

lemma finite_insert [simp]: "finite (insert a A) finite A"
proof -
  have "finite {a} finite A finite A" by simp
  then have "finite ({a} A) finite A" by (simp only: finite_Un)
  then show ?thesis by simp
qed

lemma finite_Int [simp, intro]: "finite F finite G ==> finite (F G)"
  by (blast intro: finite_subset)

lemma finite_Collect_conjI [simp, intro]:
  "finite {x. P x} finite {x. Q x} ==> finite {x. P x Q x}"
  by (simp add: Collect_conj_eq)

lemma finite_Collect_disjI [simp]:
  "finite {x. P x Q x} finite {x. P x} finite {x. Q x}"
  by (simp add: Collect_disj_eq)

lemma finite_Diff [simp, intro]: "finite A ==> finite (A - B)"
  by (rule finite_subset, rule Diff_subset)

lemma finite_Diff2 [simp]:
  assumes "finite B"
  shows "finite (A - B) finite A"
proof -
  have "finite A finite ((A - B) (A B))"
    by (simp add: Un_Diff_Int)
  also have " finite (A - B)"
    using finite B by simp
  finally show ?thesis ..
qed

lemma finite_Diff_insert [iff]: "finite (A - insert a B) finite (A - B)"
proof -
  have "finite (A - B) finite (A - B - {a})" by simp
  moreover have "A - insert a B = A - B - {a}" by auto
  ultimately show ?thesis by simp
qed

lemma finite_compl [simp]:
  "finite (A :: 'a set) ==> finite (- A) finite (UNIV :: 'a set)"
  by (simp add: Compl_eq_Diff_UNIV)

lemma finite_Collect_not [simp]:
  "finite {x :: 'a. P x} ==> finite {x. ¬ P x} finite (UNIV :: 'a set)"
  by (simp add: Collect_neg_eq)

lemma finite_Union [simp, intro]:
  "finite A ==> (M. M A ==> finite M) ==> finite (A)"
  by (induct rule: finite_induct) simp_all

lemma finite_UN_I [intro]:
  "finite A ==> (a. a A ==> finite (B a)) ==> finite (aA. B a)"
  by (induct rule: finite_induct) simp_all

lemma finite_UN [simp]: "finite A ==> finite ((B ` A)) (xA. finite (B x))"
  by (blast intro: finite_subset)

lemma finite_Inter [intro]: "AM. finite A ==> finite (M)"
  by (blast intro: Inter_lower finite_subset)

lemma finite_INT [intro]: "xI. finite (A x) ==> finite (xI. A x)"
  by (blast intro: INT_lower finite_subset)

lemma finite_imageI [simp, intro]: "finite F ==> finite (h ` F)"
  by (induct rule: finite_induct) simp_all

lemma finite_image_set [simp]: "finite {x. P x} ==> finite {f x |x. P x}"
  by (simp add: image_Collect [symmetric])

lemma finite_image_set2:
  "finite {x. P x} ==> finite {y. Q y} ==> finite {f x y |x y. P x Q y}"
  by (rule finite_subset [where B = "x {x. P x}. y {y. Q y}. {f x y}"]) auto

lemma finite_imageD:
  assumes "finite (f ` A)" and "inj_on f A"
  shows "finite A"
  using assms
proof (induct "f ` A" arbitrary: A)
  case empty
  then show ?case by simp
next
  case (insert x B)
  then have B_A: "insert x B = f ` A"
    by simp
  then obtain y where "x = f y" and "y A"
    by blast
  from B_A x B have "B = f ` A - {x}"
    by blast
  with B_A x B x = f y inj_on f A y A have "B = f ` (A - {y})"
    by (simp add: inj_on_image_set_diff)
  moreover from inj_on f A have "inj_on f (A - {y})"
    by (rule inj_on_diff)
  ultimately have "finite (A - {y})"
    by (rule insert.hyps)
  then show "finite A"
    by simp
qed

lemma finite_image_iff: "inj_on f A ==> finite (f ` A) finite A"
  using finite_imageD by blast

lemma finite_surj: "finite A ==> B f ` A ==> finite B"
  by (erule finite_subset) (rule finite_imageI)

lemma finite_range_imageI: "finite (range g) ==> finite (range (λx. f (g x)))"
  by (drule finite_imageI) (simp add: range_composition)

lemma finite_subset_image:
  assumes "finite B"
  shows "B f ` A ==> CA. finite C B = f ` C"
  using assms
proof induct
  case empty
  then show ?case by simp
next
  case insert
  then show ?case
    by (clarsimp simp del: image_insert simp add: image_insert [symmetric]) blast
qed

lemma all_subset_image: "(B. B f ` A P B) (B. B A P(f ` B))"
  by (safe elim!: subset_imageE) (use image_mono in blast+(* slow *)

lemma all_finite_subset_image:
  "(B. finite B B f ` A P B) (B. finite B B A P (f ` B))"
proof safe
  fix B :: "'a set"
  assume B: "finite B" "B f ` A" and P: "B. finite B B A P (f ` B)"
  show "P B"
    using finite_subset_image [OF B] P by blast
qed blast

lemma ex_finite_subset_image:
  "(B. finite B B f ` A P B) (B. finite B B A P (f ` B))"
proof safe
  fix B :: "'a set"
  assume B: "finite B" "B f ` A" and "P B"
  show "B. finite B B A P (f ` B)"
    using finite_subset_image [OF B] P B by blast
qed blast

lemma finite_vimage_IntI: "finite F ==> inj_on h A ==> finite (h -` F A)"
proof (induct rule: finite_induct)
  case (insert x F)
  then show ?case
    by (simp add: vimage_insert [of h x F] finite_subset [OF inj_on_vimage_singleton] Int_Un_distrib2)
qed simp

lemma finite_finite_vimage_IntI:
  assumes "finite F"
    and "y. y F ==> finite ((h -` {y}) A)"
  shows "finite (h -` F A)"
proof -
  have *: "h -` F A = ( yF. (h -` {y}) A)"
    by blast
  show ?thesis
    by (simp only: * assms finite_UN_I)
qed

lemma finite_vimageI: "finite F ==> inj h ==> finite (h -` F)"
  using finite_vimage_IntI[of F h UNIV] by auto

lemma finite_vimageD': "finite (f -` A) ==> A range f ==> finite A"
  by (auto simp add: subset_image_iff intro: finite_subset[rotated])

lemma finite_vimageD: "finite (h -` F) ==> surj h ==> finite F"
  by (auto dest: finite_vimageD')

lemma finite_vimage_iff: "bij h ==> finite (h -` F) finite F"
  unfolding bij_def by (auto elim: finite_vimageD finite_vimageI)

lemma finite_inverse_image_gen:
  assumes "finite A" "inj_on f D"
  shows "finite {jD. f j A}"
  using finite_vimage_IntI [OF assms]
  by (simp add: Collect_conj_eq inf_commute vimage_def)

lemma finite_inverse_image:
  assumes "finite A" "inj f"
  shows "finite {j. f j A}"
  using finite_inverse_image_gen [OF assms] by simp

lemma finite_Collect_bex [simp]:
  assumes "finite A"
  shows "finite {x. yA. Q x y} (yA. finite {x. Q x y})"
proof -
  have "{x. yA. Q x y} = (yA. {x. Q x y})" by auto
  with assms show ?thesis by simp
qed

lemma finite_Collect_bounded_ex [simp]:
  assumes "finite {y. P y}"
  shows "finite {x. y. P y Q x y} (y. P y finite {x. Q x y})"
proof -
  have "{x. y. P y Q x y} = (y{y. P y}. {x. Q x y})"
    by auto
  with assms show ?thesis
    by simp
qed

lemma finite_Plus: "finite A ==> finite B ==> finite (A <+> B)"
  by (simp add: Plus_def)

lemma finite_PlusD:
  fixes A :: "'a set" and B :: "'b set"
  assumes fin: "finite (A <+> B)"
  shows "finite A" "finite B"
proof -
  have "Inl ` A A <+> B"
    by auto
  then have "finite (Inl ` A :: ('a + 'b) set)"
    using fin by (rule finite_subset)
  then show "finite A"
    by (rule finite_imageD) (auto intro: inj_onI)
next
  have "Inr ` B A <+> B"
    by auto
  then have "finite (Inr ` B :: ('a + 'b) set)"
    using fin by (rule finite_subset)
  then show "finite B"
    by (rule finite_imageD) (auto intro: inj_onI)
qed

lemma finite_Plus_iff [simp]: "finite (A <+> B) finite A finite B"
  by (auto intro: finite_PlusD finite_Plus)

lemma finite_Plus_UNIV_iff [simp]:
  "finite (UNIV :: ('a + 'b) set) finite (UNIV :: 'a set) finite (UNIV :: 'b set)"
  by (subst UNIV_Plus_UNIV [symmetric]) (rule finite_Plus_iff)

lemma finite_SigmaI [simp, intro]:
  "finite A ==> (a. aA ==> finite (B a)) ==> finite (SIGMA a:A. B a)"
  unfolding Sigma_def by blast

lemma finite_SigmaI2:
  assumes "finite {xA. B x {}}"
  and "a. a A ==> finite (B a)"
  shows "finite (Sigma A B)"
proof -
  from assms have "finite (Sigma {xA. B x {}} B)"
    by auto
  also have "Sigma {x:A. B x {}} B = Sigma A B"
    by auto
  finally show ?thesis .
qed

lemma finite_cartesian_product: "finite A ==> finite B ==> finite (A × B)"
  by (rule finite_SigmaI)

lemma finite_Prod_UNIV:
  "finite (UNIV :: 'a set) ==> finite (UNIV :: 'b set) ==> finite (UNIV :: ('a × 'b) set)"
  by (simp only: UNIV_Times_UNIV [symmetric] finite_cartesian_product)

lemma finite_cartesian_productD1:
  assumes "finite (A × B)" and "B {}"
  shows "finite A"
proof -
  from assms obtain n f where "A × B = f ` {i::nat. i < n}"
    by (auto simp add: finite_conv_nat_seg_image)
  then have "fst ` (A × B) = fst ` f ` {i::nat. i < n}"
    by simp
  with B {} have "A = (fst f) ` {i::nat. i < n}"
    by (simp add: image_comp)
  then have "n f. A = f ` {i::nat. i < n}"
    by blast
  then show ?thesis
    by (auto simp add: finite_conv_nat_seg_image)
qed

lemma finite_cartesian_productD2:
  assumes "finite (A × B)" and "A {}"
  shows "finite B"
proof -
  from assms obtain n f where "A × B = f ` {i::nat. i < n}"
    by (auto simp add: finite_conv_nat_seg_image)
  then have "snd ` (A × B) = snd ` f ` {i::nat. i < n}"
    by simp
  with A {} have "B = (snd f) ` {i::nat. i < n}"
    by (simp add: image_comp)
  then have "n f. B = f ` {i::nat. i < n}"
    by blast
  then show ?thesis
    by (auto simp add: finite_conv_nat_seg_image)
qed

lemma finite_cartesian_product_iff:
  "finite (A × B) (A = {} B = {} (finite A finite B))"
  by (auto dest: finite_cartesian_productD1 finite_cartesian_productD2 finite_cartesian_product)

lemma finite_prod:
  "finite (UNIV :: ('a × 'b) set) finite (UNIV :: 'a set) finite (UNIV :: 'b set)"
  using finite_cartesian_product_iff[of UNIV UNIV] by simp

lemma finite_Pow_iff [iff]: "finite (Pow A) finite A"
proof
  assume "finite (Pow A)"
  then have "finite ((λx. {x}) ` A)"
    by (blast intro: finite_subset)  (* somewhat slow *)
  then show "finite A"
    by (rule finite_imageD [unfolded inj_on_def]) simp
next
  assume "finite A"
  then show "finite (Pow A)"
    by induct (simp_all add: Pow_insert)
qed

corollary finite_Collect_subsets [simp, intro]: "finite A ==> finite {B. B A}"
  by (simp add: Pow_def [symmetric])

lemma finite_set: "finite (UNIV :: 'a set set) finite (UNIV :: 'a set)"
  by (simp only: finite_Pow_iff Pow_UNIV[symmetric])

lemma finite_UnionD: "finite (A) ==> finite A"
  by (blast intro: finite_subset [OF subset_Pow_Union])

lemma finite_bind:
  assumes "finite S"
  assumes "x S. finite (f x)"
  shows "finite (Set.bind S f)"
using assms by (simp add: bind_UNION)

lemma finite_filter [simp]: "finite S ==> finite (Set.filter P S)"
  by (simp add:)

lemma finite_set_of_finite_funs:
  assumes "finite A" "finite B"
  shows "finite {f. x. (x A f x B) (x A f x = d)}" (is "finite ?S")
proof -
  let ?F = "λf. {(a,b). a A b = f a}"
  have "?F ` ?S Pow(A × B)"
    by auto
  from finite_subset[OF this] assms have 1: "finite (?F ` ?S)"
    by simp
  have 2: "inj_on ?F ?S"
    by (fastforce simp add: inj_on_def set_eq_iff fun_eq_iff)  (* somewhat slow *)
  show ?thesis
    by (rule finite_imageD [OF 1 2])
qed

lemma not_finite_existsD:
  assumes "¬ finite {a. P a}"
  shows "a. P a"
proof (rule classical)
  assume "¬ ?thesis"
  with assms show ?thesis by auto
qed

lemma finite_converse [iff]: "finite (r-1) finite r"
  unfolding converse_def conversep_iff
  using [[simproc add: finite_Collect]]
  by (auto elim: finite_imageD simp: inj_on_def)

lemma finite_Domain: "finite r ==> finite (Domain r)"
  by (induct set: finite) auto

lemma finite_Range: "finite r ==> finite (Range r)"
  by (induct set: finite) auto

lemma finite_Field: "finite r ==> finite (Field r)"
  by (simp add: Field_def finite_Domain finite_Range)

lemma finite_Image[simp]: "finite R ==> finite (R `` A)"
  by(rule finite_subset[OF _ finite_Range]) auto


subsection Further induction rules on finite sets

lemma finite_ne_induct [case_names singleton insert, consumes 2]:
  assumes "finite F" and "F {}"
  assumes "x. P {x}"
    and "x F. finite F ==> F {} ==> x F ==> P F ==> P (insert x F)"
  shows "P F"
  using assms
proof induct
  case empty
  then show ?case by simp
next
  case (insert x F)
  then show ?case by cases auto
qed

lemma finite_subset_induct [consumes 2, case_names empty insert]:
  assumes "finite F" and "F A"
    and empty: "P {}"
    and insert: "a F. finite F ==> a A ==> a F ==> P F ==> P (insert a F)"
  shows "P F"
  using finite F F A
proof induct
  show "P {}" by fact
next
  fix x F
  assume "finite F" and "x F" and P: "F A ==> P F" and i: "insert x F A"
  show "P (insert x F)"
  proof (rule insert)
    from i show "x A" by blast
    from i have "F A" by blast
    with P show "P F" .
    show "finite F" by fact
    show "x F" by fact
  qed
qed

lemma finite_empty_induct:
  assumes "finite A"
    and "P A"
    and remove: "a A. finite A ==> a A ==> P A ==> P (A - {a})"
  shows "P {}"
proof -
  have "P (A - B)" if "B A" for B :: "'a set"
  proof -
    from finite A that have "finite B"
      by (rule rev_finite_subset)
    from this B A show "P (A - B)"
    proof induct
      case empty
      from P A show ?case by simp
    next
      case (insert b B)
      have "P (A - B - {b})"
      proof (rule remove)
        from finite A show "finite (A - B)"
          by induct auto
        from insert show "b A - B"
          by simp
        from insert show "P (A - B)"
          by simp
      qed
      also have "A - B - {b} = A - insert b B"
        by (rule Diff_insert [symmetric])
      finally show ?case .
    qed
  qed
  then have "P (A - A)" by blast
  then show ?thesis by simp
qed

lemma finite_update_induct [consumes 1, case_names const update]:
  assumes finite: "finite {a. f a c}"
    and const: "P (λa. c)"
    and update: "a b f. finite {a. f a c} ==> f a = c ==> b c ==> P f ==> P (f(a := b))"
  shows "P f"
  using finite
proof (induct "{a. f a c}" arbitrary: f)
  case empty
  with const show ?case by simp
next
  case (insert a A)
  then have "A = {a'. (f(a := c)) a' c}" and "f a c"
    by auto
  with finite A have "finite {a'. (f(a := c)) a' c}"
    by simp
  have "(f(a := c)) a = c"
    by simp
  from insert A = {a'. (f(a := c)) a' c} have "P (f(a := c))"
    by simp
  with finite {a'. (f(a := c)) a' c} (f(a := c)) a = c f a c
  have "P ((f(a := c))(a := f a))"
    by (rule update)
  then show ?case by simp
qed

lemma finite_subset_induct' [consumes 2, case_names empty insert]:
  assumes "finite F" and "F A"
    and empty: "P {}"
    and insert: "a F. [finite F; a A; F A; a F; P F ] ==> P (insert a F)"
  shows "P F"
  using assms(1,2)
proof induct
  show "P {}" by fact
next
  fix x F
  assume "finite F" and "x F" and
    P: "F A ==> P F" and i: "insert x F A"
  show "P (insert x F)"
  proof (rule insert)
    from i show "x A" by blast
    from i have "F A" by blast
    with P show "P F" .
    show "finite F" by fact
    show "x F" by fact
    show "F A" by fact
  qed
qed


subsection Class finite\
class finite =
  assumes finite_UNIV: "finite (UNIV :: 'a set)"
begin

lemma finite [simp]: "finite (A :: 'a set)"
  by (rule subset_UNIV finite_UNIV finite_subset)+

lemma finite_code [code]: "finite (A :: 'a set) True"
  by simp

end

instance prod :: (finite, finite) finite
  by standard (simp only: UNIV_Times_UNIV [symmetric] finite_cartesian_product finite)

lemma inj_graph: "inj (λf. {(x, y). y = f x})"
  by (rule inj_onI) (auto simp add: set_eq_iff fun_eq_iff)

instance "fun" :: (finite, finite) finite
proof
  show "finite (UNIV :: ('a ==> 'b) set)"
  proof (rule finite_imageD)
    let ?graph = "λf::'a ==> 'b. {(x, y). y = f x}"
    have "range ?graph Pow UNIV"
      by simp
    moreover have "finite (Pow (UNIV :: ('a * 'b) set))"
      by (simp only: finite_Pow_iff finite)
    ultimately show "finite (range ?graph)"
      by (rule finite_subset)
    show "inj ?graph"
      by (rule inj_graph)
  qed
qed

instance bool :: finite
  by standard (simp add: UNIV_bool)

instance set :: (finite) finite
  by standard (simp only: Pow_UNIV [symmetric] finite_Pow_iff finite)

instance unit :: finite
  by standard (simp add: UNIV_unit)

instance sum :: (finite, finite) finite
  by standard (simp only: UNIV_Plus_UNIV [symmetric] finite_Plus finite)


subsection A basic fold functional for finite sets

text 
  The intended behaviour is fold f z {x🪙1, , x🪙n} = f x🪙1 ( (f x🪙n z))
  if f is ``left-commutative''.
  The commutativity requirement is relativised to the carrier set S:


locale comp_fun_commute_on =
  fixes S :: "'a set"
  fixes f :: "'a ==> 'b ==> 'b"
  assumes comp_fun_commute_on: "x S ==> y S ==> f y f x = f x f y"
begin

lemma fun_left_comm: "x S ==> y S ==> f y (f x z) = f x (f y z)"
  using comp_fun_commute_on by (simp add: fun_eq_iff)

lemma commute_left_comp: "x S ==> y S ==> f y (f x g) = f x (f y g)"
  by (simp add: o_assoc comp_fun_commute_on)

end

inductive fold_graph :: "('a ==> 'b ==> 'b) ==> 'b ==> 'a set ==> 'b ==> bool"
  for f :: "'a ==> 'b ==> 'b" and z :: 'b
  where
    emptyI [intro]: "fold_graph f z {} z"
  | insertI [intro]: "x A ==> fold_graph f z A y ==> fold_graph f z (insert x A) (f x y)"

inductive_cases empty_fold_graphE [elim!]: "fold_graph f z {} x"

lemma fold_graph_closed_lemma:
  "fold_graph f z A x x B"
  if "fold_graph g z A x"
    "a b. a A ==> b B ==> f a b = g a b"
    "a b. a A ==> b B ==> g a b B"
    "z B"
  using that(1-3)
proof (induction rule: fold_graph.induct)
  case (insertI x A y)
  have "fold_graph f z A y" "y B"
    unfolding atomize_conj
    by (rule insertI.IH) (auto intro: insertI.prems)
  then have "g x y B" and f_eq: "f x y = g x y"
    by (auto simp: insertI.prems)
  moreover have "fold_graph f z (insert x A) (f x y)"
    by (rule fold_graph.insertI; fact)
  ultimately
  show ?case
    by (simp add: f_eq)
qed (auto intro!: that)

lemma fold_graph_closed_eq:
  "fold_graph f z A = fold_graph g z A"
  if "a b. a A ==> b B ==> f a b = g a b"
     "a b. a A ==> b B ==> g a b B"
     "z B"
  using fold_graph_closed_lemma[of f z A _ B g] fold_graph_closed_lemma[of g z A _ B f] that
  by auto

definition fold :: "('a ==> 'b ==> 'b) ==> 'b ==> 'a set ==> 'b"
  where "fold f z A = (if finite A then (THE y. fold_graph f z A y) else z)"

lemma fold_closed_eq: "fold f z A = fold g z A"
  if "a b. a A ==> b B ==> f a b = g a b"
     "a b. a A ==> b B ==> g a b B"
     "z B"
  unfolding Finite_Set.fold_def
  by (subst fold_graph_closed_eq[where B=B and g=g]) (auto simp: that)

text 
  A tempting alternative for the definition is
  🍋if finite A then THE y. fold_graph f z A y else e.
  It allows the removal of finiteness assumptions from the theorems
  fold_commfold_reindex and fold_distrib.
  The proofs become ugly. It is not worth the effort. (???)


lemma finite_imp_fold_graph: "finite A ==> x. fold_graph f z A x"
  by (induct rule: finite_induct) auto


subsubsection From 🍋fold_graph to 🍋fold\<close>

context comp_fun_commute_on
begin

lemma fold_graph_finite:
  assumes "fold_graph f z A y"
  shows "finite A"
  using assms by induct simp_all

lemma fold_graph_insertE_aux:
  assumes "A S"
  assumes "fold_graph f z A y" "a A"
  shows "y'. y = f a y' fold_graph f z (A - {a}) y'"
  using assms(2-,1)
proof (induct set: fold_graph)
  case emptyI
  then show ?case by simp
next
  case (insertI x A y)
  show ?case
  proof (cases "x = a")
    case True
    with insertI show ?thesis by auto
  next
    case False
    then obtain y' where y: "y = f a y'" and y': "fold_graph f z (A - {a}) y'"
      using insertI by auto
    from insertI have "x S" "a S" by auto
    then have "f x y = f a (f x y')"
      unfolding y by (intro fun_left_comm; simp)
    moreover have "fold_graph f z (insert x A - {a}) (f x y')"
      using y' and x a and x A
      by (simp add: insert_Diff_if fold_graph.insertI)
    ultimately show ?thesis
      by fast
  qed
qed

lemma fold_graph_insertE:
  assumes "insert x A S"
  assumes "fold_graph f z (insert x A) v" and "x A"
  obtains y where "v = f x y" and "fold_graph f z A y"
  using assms by (auto dest: fold_graph_insertE_aux[OF insert x A S _ insertI1])

lemma fold_graph_determ:
  assumes "A S"
  assumes "fold_graph f z A x" "fold_graph f z A y"
  shows "y = x"
  using assms(2-,1)
proof (induct arbitrary: y set: fold_graph)
  case emptyI
  then show ?case by fast
next
  case (insertI x A y v)
  from insert x A S and fold_graph f z (insert x A) v and x A
  obtain y' where "v = f x y'" and "fold_graph f z A y'"
    by (rule fold_graph_insertE)
  from fold_graph f z A y' insertI have "y' = y"
    by simp
  with v = f x y' show "v = f x y"
    by simp
qed

lemma fold_equality: "A S ==> fold_graph f z A y ==> fold f z A = y"
  by (cases "finite A") (auto simp add: fold_def intro: fold_graph_determ dest: fold_graph_finite)

lemma fold_graph_fold:
  assumes "A S"
  assumes "finite A"
  shows "fold_graph f z A (fold f z A)"
proof -
  from finite A have "x. fold_graph f z A x"
    by (rule finite_imp_fold_graph)
  moreover note fold_graph_determ[OF A S]
  ultimately have "!x. fold_graph f z A x"
    by (rule ex_ex1I)
  then have "fold_graph f z A (The (fold_graph f z A))"
    by (rule theI')
  with assms show ?thesis
    by (simp add: fold_def)
qed

text The base case for fold:\<close>

lemma (in -) fold_infinite [simp]: "¬ finite A ==> fold f z A = z"
  by (auto simp: fold_def)

lemma (in -) fold_empty [simp]: "fold f z {} = z"
  by (auto simp: fold_def)

text The various recursion equations for 🍋fold:\<close>

lemma fold_insert [simp]:
  assumes "insert x A S"
  assumes "finite A" and "x A"
  shows "fold f z (insert x A) = f x (fold f z A)"
proof (rule fold_equality[OF insert x A S])
  fix z
  from insert x A S finite A have "fold_graph f z A (fold f z A)"
    by (blast intro: fold_graph_fold)
  with x A have "fold_graph f z (insert x A) (f x (fold f z A))"
    by (rule fold_graph.insertI)
  then show "fold_graph f z (insert x A) (f x (fold f z A))"
    by simp
qed

declare (in -) empty_fold_graphE [rule del] fold_graph.intros [rule del]
  🍋 No more proofs involve these.

lemma fold_fun_left_comm:
  assumes "insert x A S" "finite A" 
  shows "f x (fold f z A) = fold f (f x z) A"
  using assms(2,1)
proof (induct rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert y F)
  then have "fold f (f x z) (insert y F) = f y (fold f (f x z) F)"
    by simp
  also have " = f x (f y (fold f z F))"
    using insert by (simp add: fun_left_comm[where ?y=x])
  also have " = f x (fold f z (insert y F))"
  proof -
    from insert have "insert y F S" by simp
    from fold_insert[OF this] insert show ?thesis by simp
  qed
  finally show ?case ..
qed

lemma fold_insert2:
  "insert x A S ==> finite A ==> x A ==> fold f z (insert x A) = fold f (f x z) A"
  by (simp add: fold_fun_left_comm)

lemma fold_rec:
  assumes "A S"
  assumes "finite A" and "x A"
  shows "fold f z A = f x (fold f z (A - {x}))"
proof -
  have A: "A = insert x (A - {x})"
    using x A by blast
  then have "fold f z A = fold f z (insert x (A - {x}))"
    by simp
  also have " = f x (fold f z (A - {x}))"
    by (rule fold_insert) (use assms in auto)
  finally show ?thesis .
qed

lemma fold_insert_remove:
  assumes "insert x A S"
  assumes "finite A"
  shows "fold f z (insert x A) = f x (fold f z (A - {x}))"
proof -
  from finite A have "finite (insert x A)"
    by auto
  moreover have "x insert x A"
    by auto
  ultimately have "fold f z (insert x A) = f x (fold f z (insert x A - {x}))"
    using insert x A S by (blast intro: fold_rec)
  then show ?thesis
    by simp
qed

lemma fold_set_union_disj:
  assumes "A S" "B S"
  assumes "finite A" "finite B" "A B = {}"
  shows "Finite_Set.fold f z (A B) = Finite_Set.fold f (Finite_Set.fold f z A) B"
  using finite B assms(1,2,3,5)
proof induct
  case (insert x F)
  have "fold f z (A insert x F) = f x (fold f (fold f z A) F)"
    using insert by auto
  also have " = fold f (fold f z A) (insert x F)"
    using insert by (blast intro: fold_insert[symmetric])
  finally show ?case .
qed simp


end

text Other properties of 🍋fold:


lemma finite_set_fold_single [simp]: "Finite_Set.fold f z {x} = f x z"
proof -
  have "fold_graph f z {x} (f x z)"
    by (auto intro: fold_graph.intros)
  moreover
  {
    fix X y
    have "fold_graph f z X y ==> (X = {} y = z) (X = {x} y = f x z)"
      by (induct rule: fold_graph.induct) auto
  }
  ultimately have "(THE y. fold_graph f z {x} y) = f x z"
    by blast
  thus ?thesis
    by (simp add: Finite_Set.fold_def)
qed

lemma fold_graph_image:
  assumes "inj_on g A"
  shows "fold_graph f z (g ` A) = fold_graph (f g) z A"
proof
  fix w
  show "fold_graph f z (g ` A) w = fold_graph (f o g) z A w"
  proof
    assume "fold_graph f z (g ` A) w"
    then show "fold_graph (f g) z A w"
      using assms
    proof (induct "g ` A" w arbitrary: A)
      case emptyI
      then show ?case by (auto intro: fold_graph.emptyI)
    next
      case (insertI x A r B)
      from inj_on g B x A insert x A = image g B obtain x' A'
        where "x' A'" and [simp]: "B = insert x' A'" "x = g x'" "A = g ` A'"
        by (rule inj_img_insertE)
      from insertI.prems have "fold_graph (f g) z A' r"
        by (auto intro: insertI.hyps)
      with x' A' have "fold_graph (f g) z (insert x' A') ((f g) x' r)"
        by (rule fold_graph.insertI)
      then show ?case
        by simp
    qed
  next
    assume "fold_graph (f g) z A w"
    then show "fold_graph f z (g ` A) w"
      using assms
    proof induct
      case emptyI
      then show ?case
        by (auto intro: fold_graph.emptyI)
    next
      case (insertI x A r)
      from x A insertI.prems have "g x g ` A"
        by auto
      moreover from insertI have "fold_graph f z (g ` A) r"
        by simp
      ultimately have "fold_graph f z (insert (g x) (g ` A)) (f (g x) r)"
        by (rule fold_graph.insertI)
      then show ?case
        by simp
    qed
  qed
qed

lemma fold_image:
  assumes "inj_on g A"
  shows "fold f z (g ` A) = fold (f g) z A"
proof (cases "finite A")
  case False
  with assms show ?thesis
    by (auto dest: finite_imageD simp add: fold_def)
next
  case True
  then show ?thesis
    by (auto simp add: fold_def fold_graph_image[OF assms])
qed

lemma fold_cong:
  assumes "comp_fun_commute_on S f" "comp_fun_commute_on S g"
    and "A S" "finite A"
    and cong: "x. x A ==> f x = g x"
    and "s = t" and "A = B"
  shows "fold f s A = fold g t B"
proof -
  have "fold f s A = fold g s A"
    using finite A A S cong
  proof (induct A)
    case empty
    then show ?case by simp
  next
    case insert
    interpret f: comp_fun_commute_on S f by (fact comp_fun_commute_on S f)
    interpret g: comp_fun_commute_on S g by (fact comp_fun_commute_on S g)
    from insert show ?case by simp
  qed
  with assms show ?thesis by simp
qed


text A simplified version for idempotent functions:

locale comp_fun_idem_on = comp_fun_commute_on +
  assumes comp_fun_idem_on: "x S ==> f x f x = f x"
begin

lemma fun_left_idem: "x S ==> f x (f x z) = f x z"
  using comp_fun_idem_on by (simp add: fun_eq_iff)

lemma fold_insert_idem:
  assumes "insert x A S"
  assumes fin: "finite A"
  shows "fold f z (insert x A) = f x (fold f z A)"
proof cases
  assume "x A"
  then obtain B where "A = insert x B" and "x B"
    by (rule set_insert)
  then show ?thesis
    using assms by (simp add: comp_fun_idem_on fun_left_idem)
next
  assume "x A"
  then show ?thesis
    using assms by auto
qed

declare fold_insert [simp del] fold_insert_idem [simp]

lemma fold_insert_idem2: "insert x A S ==> finite A ==> fold f z (insert x A) = fold f (f x z) A"
  by (simp add: fold_fun_left_comm)

end


subsubsection Liftings to comp_fun_commute_on etc.

                   
lemma (in comp_fun_commute_on) comp_comp_fun_commute_on:
  "range g S ==> comp_fun_commute_on R (f g)"
  by standard (force intro: comp_fun_commute_on)

lemma (in comp_fun_idem_on) comp_comp_fun_idem_on:
  assumes "range g S"
  shows "comp_fun_idem_on R (f g)"
proof
  interpret f_g: comp_fun_commute_on R "f o g"
    by (fact comp_comp_fun_commute_on[OF range g S])
  show "x R ==> y R ==> (f g) y (f g) x = (f g) x (f g) y" for x y
    by (fact f_g.comp_fun_commute_on)
qed (use range g S in force intro: comp_fun_idem_on)

lemma (in comp_fun_commute_on) comp_fun_commute_on_funpow:
  "comp_fun_commute_on S (λx. f x ^^ g x)"
proof
  fix x y assume "x S" "y S"
  show "f y ^^ g y f x ^^ g x = f x ^^ g x f y ^^ g y"
  proof (cases "x = y")
    case True
    then show ?thesis by simp
  next
    case False
    show ?thesis
    proof (induct "g x" arbitrary: g)
      case 0
      then show ?case by simp
    next
      case (Suc n g)
      have hyp1: "f y ^^ g y f x = f x f y ^^ g y"
      proof (induct "g y" arbitrary: g)
        case 0
        then show ?case by simp
      next
        case (Suc n g)
        define h where "h z = g z - 1" for z
        with Suc have "n = h y"
          by simp
        with Suc have hyp: "f y ^^ h y f x = f x f y ^^ h y"
          by auto
        from Suc h_def have "g y = Suc (h y)"
          by simp
        with x S y S show ?case
          by (simp add: comp_assoc hyp) (simp add: o_assoc comp_fun_commute_on)
      qed
      define h where "h z = (if z = x then g x - 1 else g z)" for z
      with Suc have "n = h x"
        by simp
      with Suc have "f y ^^ h y f x ^^ h x = f x ^^ h x f y ^^ h y"
        by auto
      with False h_def have hyp2: "f y ^^ g y f x ^^ h x = f x ^^ h x f y ^^ g y"
        by simp
      from Suc h_def have "g x = Suc (h x)"
        by simp
      then show ?case
        by (simp del: funpow.simps add: funpow_Suc_right o_assoc hyp2) (simp add: comp_assoc hyp1)
    qed
  qed
qed


subsubsection 🍋UNIV as carrier set


locale comp_fun_commute =
  fixes f :: "'a ==> 'b ==> 'b"
  assumes comp_fun_commute: "f y f x = f x f y"
begin

lemma (in -) comp_fun_commute_def': "comp_fun_commute f = comp_fun_commute_on UNIV f"
  unfolding comp_fun_commute_def comp_fun_commute_on_def by blast

text 

  We abuse the rewrites functionality of locales to remove trivial assumptions that
  result from instantiating the carrier set to 🍋UNIV.
 
sublocale comp_fun_commute_on UNIV f
  rewrites "X. (X UNIV) True"
       and "x. x UNIV True"
       and "P. (True ==> P) Trueprop P"
       and "P Q. (True ==> PROP P ==> PROP Q) (PROP P ==> True ==> PROP Q)"
proof -
  show "comp_fun_commute_on UNIV f"
    by standard  (simp add: comp_fun_commute)
qed simp_all

end

lemma (in comp_fun_commute) comp_comp_fun_commute: "comp_fun_commute (f o g)"
  unfolding comp_fun_commute_def' by (fact comp_comp_fun_commute_on)

lemma (in comp_fun_commute) comp_fun_commute_funpow: "comp_fun_commute (λx. f x ^^ g x)"
  unfolding comp_fun_commute_def' by (fact comp_fun_commute_on_funpow)

locale comp_fun_idem = comp_fun_commute +
  assumes comp_fun_idem: "f x o f x = f x"
begin

lemma (in -) comp_fun_idem_def': "comp_fun_idem f = comp_fun_idem_on UNIV f"
  unfolding comp_fun_idem_on_def comp_fun_idem_def comp_fun_commute_def'
  unfolding comp_fun_idem_axioms_def comp_fun_idem_on_axioms_def
  by blast

text 
  Again, we abuse the rewrites functionality of locales to remove trivial assumptions that
  result from instantiating the carrier set to 🍋UNIV.
 
sublocale comp_fun_idem_on UNIV f
  rewrites "X. (X UNIV) True"
       and "x. x UNIV True"
       and "P. (True ==> P) Trueprop P"
       and "P Q. (True ==> PROP P ==> PROP Q) (PROP P ==> True ==> PROP Q)"
proof -
  show "comp_fun_idem_on UNIV f"
    by standard (simp_all add: comp_fun_idem comp_fun_commute)
qed simp_all

end

lemma (in comp_fun_idem) comp_comp_fun_idem: "comp_fun_idem (f o g)"
  unfolding comp_fun_idem_def' by (fact comp_comp_fun_idem_on)


subsubsection Expressing set operations via 🍋fold\

lemma comp_fun_commute_const: "comp_fun_commute (λ_. f)"
  by standard (rule refl)

lemma comp_fun_idem_insert: "comp_fun_idem insert"
  by standard auto

lemma comp_fun_idem_remove: "comp_fun_idem Set.remove"
  by standard auto

lemma (in semilattice_inf) comp_fun_idem_inf: "comp_fun_idem inf"
  by standard (auto simp add: inf_left_commute)

lemma (in semilattice_sup) comp_fun_idem_sup: "comp_fun_idem sup"
  by standard (auto simp add: sup_left_commute)

lemma union_fold_insert:
  assumes "finite A"
  shows "A B = fold insert B A"
proof -
  interpret comp_fun_idem insert
    by (fact comp_fun_idem_insert)
  from finite A show ?thesis
    by (induct A arbitrary: B) simp_all
qed

lemma minus_fold_remove:
  assumes "finite A"
  shows "B - A = fold Set.remove B A"
proof -
  interpret comp_fun_idem Set.remove
    by (fact comp_fun_idem_remove)
  from finite A have "fold Set.remove B A = B - A"
    by (induct A arbitrary: B) auto  (* slow *)
  then show ?thesis ..
qed

lemma comp_fun_commute_filter_fold:
  "comp_fun_commute (λx A'. if P x then Set.insert x A' else A')"
proof -
  interpret comp_fun_idem Set.insert by (fact comp_fun_idem_insert)
  show ?thesis by standard (auto simp: fun_eq_iff)
qed

lemma Set_filter_fold:
  assumes "finite A"
  shows "Set.filter P A = fold (λx A'. if P x then Set.insert x A' else A') {} A"
  using assms
proof -
  interpret commute_insert: comp_fun_commute "(λx A'. if P x then Set.insert x A' else A')"
    by (fact comp_fun_commute_filter_fold)
  from finite A show ?thesis
    by induct (auto simp add: set_eq_iff)
qed

lemma inter_Set_filter:
  assumes "finite B"
  shows "A B = Set.filter (λx. x A) B"
  using assms by (simp add: set_eq_iff ac_simps)

lemma image_fold_insert:
  assumes "finite A"
  shows "image f A = fold (λk A. Set.insert (f k) A) {} A"
proof -
  interpret comp_fun_commute "λk A. Set.insert (f k) A"
    by standard auto
  show ?thesis
    using assms by (induct A) auto
qed

lemma Ball_fold:
  assumes "finite A"
  shows "Ball A P = fold (λk s. s P k) True A"
proof -
  interpret comp_fun_commute "λk s. s P k"
    by standard auto
  show ?thesis
    using assms by (induct A) auto
qed

lemma Bex_fold:
  assumes "finite A"
  shows "Bex A P = fold (λk s. s P k) False A"
proof -
  interpret comp_fun_commute "λk s. s P k"
    by standard auto
  show ?thesis
    using assms by (induct A) auto
qed

lemma comp_fun_commute_Pow_fold: "comp_fun_commute (λx A. A Set.insert x ` A)"
  by (clarsimp simp: fun_eq_iff comp_fun_commute_def) blast

lemma Pow_fold:
  assumes "finite A"
  shows "Pow A = fold (λx A. A Set.insert x ` A) {{}} A"
proof -
  interpret comp_fun_commute "λx A. A Set.insert x ` A"
    by (rule comp_fun_commute_Pow_fold)
  show ?thesis
    using assms by (induct A) (auto simp: Pow_insert)
qed

lemma fold_union_pair:
  assumes "finite B"
  shows "(yB. {(x, y)}) A = fold (λy. Set.insert (x, y)) A B"
proof -
  interpret comp_fun_commute "λy. Set.insert (x, y)"
    by standard auto
  show ?thesis
    using assms by (induct arbitrary: A) simp_all
qed

lemma comp_fun_commute_product_fold:
  "finite B ==> comp_fun_commute (λx z. fold (λy. Set.insert (x, y)) z B)"
  by standard (auto simp: fold_union_pair [symmetric])

lemma product_fold:
  assumes "finite A" "finite B"
  shows "A × B = fold (λx z. fold (λy. Set.insert (x, y)) z B) {} A"
proof -
  interpret commute_product: comp_fun_commute "(λx z. fold (λy. Set.insert (x, y)) z B)"
    by (fact comp_fun_commute_product_fold[OF finite B])
  from assms show ?thesis unfolding Sigma_def
    by (induct A) (simp_all add: fold_union_pair)
qed

context complete_lattice
begin

lemma inf_Inf_fold_inf:
  assumes "finite A"
  shows "inf (Inf A) B = fold inf B A"
proof -
  interpret comp_fun_idem inf
    by (fact comp_fun_idem_inf)
  from finite A fold_fun_left_comm show ?thesis
    by (induct A arbitrary: B) (simp_all add: inf_commute fun_eq_iff)
qed

lemma sup_Sup_fold_sup:
  assumes "finite A"
  shows "sup (Sup A) B = fold sup B A"
proof -
  interpret comp_fun_idem sup
    by (fact comp_fun_idem_sup)
  from finite A fold_fun_left_comm show ?thesis
    by (induct A arbitrary: B) (simp_all add: sup_commute fun_eq_iff)
qed

lemma Inf_fold_inf: "finite A ==> Inf A = fold inf top A"
  using inf_Inf_fold_inf [of A top] by (simp add: inf_absorb2)

lemma Sup_fold_sup: "finite A ==> Sup A = fold sup bot A"
  using sup_Sup_fold_sup [of A bot] by (simp add: sup_absorb2)

lemma inf_INF_fold_inf:
  assumes "finite A"
  shows "inf B ((f ` A)) = fold (inf f) B A" (is "?inf = ?fold")
proof -
  interpret comp_fun_idem inf by (fact comp_fun_idem_inf)
  interpret comp_fun_idem "inf f" by (fact comp_comp_fun_idem)
  from finite A have "?fold = ?inf"
    by (induct A arbitrary: B) (simp_all add: inf_left_commute)
  then show ?thesis ..
qed

lemma sup_SUP_fold_sup:
  assumes "finite A"
  shows "sup B ((f ` A)) = fold (sup f) B A" (is "?sup = ?fold")
proof -
  interpret comp_fun_idem sup by (fact comp_fun_idem_sup)
  interpret comp_fun_idem "sup f" by (fact comp_comp_fun_idem)
  from finite A have "?fold = ?sup"
    by (induct A arbitrary: B) (simp_all add: sup_left_commute)
  then show ?thesis ..
qed

lemma INF_fold_inf: "finite A ==> (f ` A) = fold (inf f) top A"
  using inf_INF_fold_inf [of A top] by simp

lemma SUP_fold_sup: "finite A ==> (f ` A) = fold (sup f) bot A"
  using sup_SUP_fold_sup [of A bot] by simp

lemma finite_Inf_in:
  assumes "finite A" "A{}" and inf: "x y. [x A; y A] ==> inf x y A"
  shows "Inf A A"
proof -
  have "Inf B A" if "B A" "B{}" for B
    using finite_subset [OF B A finite A] that
  by (induction B) (use inf in force+)
  then show ?thesis
    by (simp add: assms)
qed

lemma finite_Sup_in:
  assumes "finite A" "A{}" and sup: "x y. [x A; y A] ==> sup x y A"
  shows "Sup A A"
proof -
  have "Sup B A" if "B A" "B{}" for B
    using finite_subset [OF B A finite A] that
  by (induction B) (use sup in force+)
  then show ?thesis
    by (simp add: assms)
qed

end

subsubsection Expressing relation operations via 🍋fold\
lemma Id_on_fold:
  assumes "finite A"
  shows "Id_on A = Finite_Set.fold (λx. Set.insert (Pair x x)) {} A"
proof -
  interpret comp_fun_commute "λx. Set.insert (Pair x x)"
    by standard auto
  from assms show ?thesis
    unfolding Id_on_def by (induct A) simp_all
qed

lemma comp_fun_commute_Image_fold:
  "comp_fun_commute (λ(x,y) A. if x S then Set.insert y A else A)"
proof -
  interpret comp_fun_idem Set.insert
    by (fact comp_fun_idem_insert)
  show ?thesis
    by standard (auto simp: fun_eq_iff comp_fun_commute split: prod.split)
qed

lemma Image_fold:
  assumes "finite R"
  shows "R `` S = Finite_Set.fold (λ(x,y) A. if x S then Set.insert y A else A) {} R"
proof -
  interpret comp_fun_commute "(λ(x,y) A. if x S then Set.insert y A else A)"
    by (rule comp_fun_commute_Image_fold)
  have *: "x F. Set.insert x F `` S = (if fst x S then Set.insert (snd x) (F `` S) else (F `` S))"
    by (force intro: rev_ImageI)
  show ?thesis
    using assms by (induct R) (auto simp: * )
qed

lemma insert_relcomp_union_fold:
  assumes "finite S"
  shows "{x} O S X = Finite_Set.fold (λ(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A') X S"
proof -
  interpret comp_fun_commute "λ(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A'"
  proof -
    interpret comp_fun_idem Set.insert
      by (fact comp_fun_idem_insert)
    show "comp_fun_commute (λ(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A')"
      by standard (auto simp add: fun_eq_iff split: prod.split)
  qed
  have *: "{x} O S = {(x', z). x' = fst x (snd x, z) S}"
    by (auto simp: relcomp_unfold intro!: exI)
  show ?thesis
    unfolding * using finite S by (induct S) (auto split: prod.split)
qed

lemma insert_relcomp_fold:
  assumes "finite S"
  shows "Set.insert x R O S =

    Finite_Set.fold (λ(w,z) A'. if snd x = w then Set.insert (fst x,z) A' else A') (R O S) S"
proof -
  have "Set.insert x R O S = ({x} O S) (R O S)"
    by auto
  then show ?thesis
    by (auto simp: insert_relcomp_union_fold [OF assms])
qed

lemma comp_fun_commute_relcomp_fold:
  assumes "finite S"
  shows "comp_fun_commute (λ(x,y) A.
    Finite_Set.fold (λ(w,z) A'. if y = w then Set.insert (x,z) A' else A') A S)"
proof -
  have *: "a b A.
    Finite_Set.fold (λ(w, z) A'. if b = w then Set.insert (a, z) A' else A') A S = {(a,b)} O S A"
    by (auto simp: insert_relcomp_union_fold[OF assms] cong: if_cong)
  show ?thesis
    by standard (auto simp: * )
qed

lemma relcomp_fold:
  assumes "finite R" "finite S"
  shows "R O S = Finite_Set.fold
    (λ(x,y) A. Finite_Set.fold (λ(w,z) A'. if y = w then Set.insert (x,z) A' else A') A S) {} R"
proof -
  interpret commute_relcomp_fold: comp_fun_commute
    "(λ(x, y) A. Finite_Set.fold (λ(w, z) A'. if y = w then insert (x, z) A' else A') A S)"
    by (fact comp_fun_commute_relcomp_fold[OF finite S])
  from assms show ?thesis
    by (induct R) (auto simp: comp_fun_commute_relcomp_fold insert_relcomp_fold cong: if_cong)
qed


subsection Locales as mini-packages for fold operations

subsubsection The natural case

locale folding_on =
  fixes S :: "'a set"
  fixes f :: "'a ==> 'b ==> 'b" and z :: "'b"
  assumes comp_fun_commute_on: "x S ==> y S ==> f y o f x = f x o f y"
begin

interpretation fold?: comp_fun_commute_on S f
  by standard (simp add: comp_fun_commute_on)

definition F :: "'a set ==> 'b"
  where eq_fold: "F A = Finite_Set.fold f z A"

lemma empty [simp]: "F {} = z"
  by (simp add: eq_fold)

lemma infinite [simp]: "¬ finite A ==> F A = z"
  by (simp add: eq_fold)

lemma insert [simp]:
  assumes "insert x A S" and "finite A" and "x A"
  shows "F (insert x A) = f x (F A)"
proof -
  from fold_insert assms
  have "Finite_Set.fold f z (insert x A)
      = f x (Finite_Set.fold f z A)"
    by simp
  with finite A show ?thesis by (simp add: eq_fold fun_eq_iff)
qed

lemma remove:
  assumes "A S" and "finite A" and "x A"
  shows "F A = f x (F (A - {x}))"
proof -
  from x A obtain B where A: "A = insert x B" and "x B"
    by (auto dest: mk_disjoint_insert)
  moreover from finite Ahave "finite B" by simp
  ultimately show ?thesis
    using A S by auto
qed

lemma insert_remove:
  assumes "insert x A S" and "finite A"
  shows "F (insert x A) = f x (F (A - {x}))"
  using assms by (cases "x A") (simp_all add: remove insert_absorb)

end


subsubsection With idempotency

locale folding_idem_on = folding_on +
  assumes comp_fun_idem_on: "x S ==> y S ==> f x f x = f x"
begin

declare insert [simp del]

interpretation fold?: comp_fun_idem_on S f
  by standard (simp_all add: comp_fun_commute_on comp_fun_idem_on)

lemma insert_idem [simp]:
  assumes "insert x A S" and "finite A"
  shows "F (insert x A) = f x (F A)"
proof -
  from fold_insert_idem assms
  have "fold f z (insert x A) = f x (fold f z A)" by simp
  with finite A show ?thesis by (simp add: eq_fold fun_eq_iff)
qed

end

subsubsection 🍋UNIV as the carrier set

locale folding =
  fixes f :: "'a ==> 'b ==> 'b" and z :: "'b"
  assumes comp_fun_commute: "f y f x = f x f y"
begin

lemma (in -) folding_def': "folding f = folding_on UNIV f"
  unfolding folding_def folding_on_def by blast

text 
  Again, we abuse the rewrites functionality of locales to remove trivial assumptions that
  result from instantiating the carrier set to 🍋UNIV.
 
sublocale folding_on UNIV f
  rewrites "X. (X UNIV) True"
       and "x. x UNIV True"
       and "P. (True ==> P) Trueprop P"
       and "P Q. (True ==> PROP P ==> PROP Q) (PROP P ==> True ==> PROP Q)"
proof -
  show "folding_on UNIV f"
    by standard (simp add: comp_fun_commute)
qed simp_all

end

locale folding_idem = folding +
  assumes comp_fun_idem: "f x f x = f x"
begin

lemma (in -) folding_idem_def': "folding_idem f = folding_idem_on UNIV f"
  unfolding folding_idem_def folding_def' folding_idem_on_def
  unfolding folding_idem_axioms_def folding_idem_on_axioms_def
  by blast

text 
  Again, we abuse the rewrites functionality of locales to remove trivial assumptions that
  result from instantiating the carrier set to 🍋UNIV.
 
sublocale folding_idem_on UNIV f
  rewrites "X. (X UNIV) True"
       and "x. x UNIV True"
       and "P. (True ==> P) Trueprop P"
       and "P Q. (True ==> PROP P ==> PROP Q) (PROP P ==> True ==> PROP Q)"
proof -
  show "folding_idem_on UNIV f"
    by standard (simp add: comp_fun_idem)
qed simp_all

end


subsection Finite cardinality

text 
  The traditional definition
  🍋card A LEAST n. f. A = {f i |i. i 🚫}
  is ugly to work with.
  But now that we have 🍋fold things are easy:
 

global_interpretation card: folding "λ_. Suc" 0
  defines card = "folding_on.F (λ_. Suc) 0"
  by standard (rule refl)

lemma card_insert_disjoint: "finite A ==> x A ==> card (insert x A) = Suc (card A)"
  by (fact card.insert)

lemma card_insert_if: "finite A ==> card (insert x A) = (if x A then card A else Suc (card A))"
  by auto (simp add: card.insert_remove card.remove)

lemma card_ge_0_finite: "card A > 0 ==> finite A"
  by (rule ccontr) simp

lemma card_0_eq [simp]: "finite A ==> card A = 0 A = {}"
  by (auto dest: mk_disjoint_insert)

lemma finite_UNIV_card_ge_0: "finite (UNIV :: 'a set) ==> card (UNIV :: 'a set) > 0"
  by (rule ccontr) simp

lemma card_eq_0_iff: "card A = 0 A = {} ¬ finite A"
  by auto

lemma card_range_greater_zero: "finite (range f) ==> card (range f) > 0"
  by (rule ccontr) (simp add: card_eq_0_iff)

lemma card_gt_0_iff: "0 < card A A {} finite A"
  by (simp add: neq0_conv [symmetric] card_eq_0_iff)

lemma card_Suc_Diff1:
  assumes "finite A" "x A" shows "Suc (card (A - {x})) = card A"
proof -
  have "Suc (card (A - {x})) = card (insert x (A - {x}))"
    using assms by (simp add: card.insert_remove)
  also have "... = card A"
    using assms by (simp add: card_insert_if)
  finally show ?thesis .
qed

lemma card_insert_le_m1:
  assumes "n > 0" "card y n - 1" shows  "card (insert x y) n"
  using assms
  by (cases "finite y") (auto simp: card_insert_if)

lemma card_Diff_singleton:
  assumes "x A" shows "card (A - {x}) = card A - 1"
proof (cases "finite A")
  case True
  with assms show ?thesis
    by (simp add: card_Suc_Diff1 [symmetric])
qed auto

lemma card_Diff_singleton_if:
  "card (A - {x}) = (if x A then card A - 1 else card A)"
  by (simp add: card_Diff_singleton)

lemma card_Diff_insert[simp]:
  assumes "a A" and "a B"
  shows "card (A - insert a B) = card (A - B) - 1"
proof -
  have "A - insert a B = (A - B) - {a}"
    using assms by blast
  then show ?thesis
    using assms by (simp add: card_Diff_singleton)
qed

lemma card_insert_le: "card A card (insert x A)"
proof (cases "finite A")
  case True
  then show ?thesis   by (simp add: card_insert_if)
qed auto

lemma card_Collect_less_nat[simp]: "card {i::nat. i < n} = n"
  by (induct n) (simp_all add:less_Suc_eq Collect_disj_eq)

lemma card_Collect_le_nat[simp]: "card {i::nat. i n} = Suc n"
  using card_Collect_less_nat[of "Suc n"by (simp add: less_Suc_eq_le)

lemma card_mono:
  assumes "finite B" and "A B"
  shows "card A card B"
proof -
  from assms have "finite A"
    by (auto intro: finite_subset)
  then show ?thesis
    using assms
  proof (induct A arbitrary: B)
    case empty
    then show ?case by simp
  next
    case (insert x A)
    then have "x B"
      by simp
    from insert have "A B - {x}" and "finite (B - {x})"
      by auto
    with insert.hyps have "card A card (B - {x})"
      by auto
    with finite A x A finite B x B show ?case
      by simp (simp only: card.remove)
  qed
qed

lemma card_seteq: 
  assumes "finite B" and A: "A B" "card B card A"
  shows "A = B"
  using assms
proof (induction arbitrary: A rule: finite_induct)
  case (insert b B)
  then have A: "finite A" "A - {b} B" 
    by force+
  then have "card B card (A - {b})"
    using insert by (auto simp add: card_Diff_singleton_if)
  then have "A - {b} = B"
    using A insert.IH by auto
  then show ?case 
    using insert.hyps insert.prems by auto
qed auto

lemma psubset_card_mono: "finite B ==> A < B ==> card A < card B"
  using card_seteq [of B A] by (auto simp add: psubset_eq)

lemma card_Un_Int:
  assumes "finite A" "finite B"
  shows "card A + card B = card (A B) + card (A B)"
  using assms
proof (induct A)
  case empty
  then show ?case by simp
next
  case insert
  then show ?case
    by (auto simp add: insert_absorb Int_insert_left)
qed

lemma card_Un_disjoint: "finite A ==> finite B ==> A B = {} ==> card (A B) = card A + card B"
  using card_Un_Int [of A B] by simp

lemma card_Un_disjnt: "[finite A; finite B; disjnt A B] ==> card (A B) = card A + card B"
  by (simp add: card_Un_disjoint disjnt_def)

lemma card_Un_le: "card (A B) card A + card B"
proof (cases "finite A finite B")
  case True
  then show ?thesis
    using le_iff_add card_Un_Int [of A B] by auto
qed auto

lemma card_Diff_subset:
  assumes "finite B"
    and "B A"
  shows "card (A - B) = card A - card B"
  using assms
proof (cases "finite A")
  case False
  with assms show ?thesis
    by simp
next
  case True
  with assms show ?thesis
    by (induct B arbitrary: A) simp_all
qed

lemma card_Diff_subset_Int:
  assumes "finite (A B)"
  shows "card (A - B) = card A - card (A B)"
proof -
  have "A - B = A - A B" by auto
  with assms show ?thesis
    by (simp add: card_Diff_subset)
qed

lemma card_Int_Diff:
  assumes "finite A"
  shows "card A = card (A B) + card (A - B)"
  by (simp add: assms card_Diff_subset_Int card_mono)

lemma diff_card_le_card_Diff:
  assumes "finite B"
  shows "card A - card B card (A - B)"
proof -
  have "card A - card B card A - card (A B)"
    using card_mono[OF assms Int_lower2, of A] by arith
  also have " = card (A - B)"
    using assms by (simp add: card_Diff_subset_Int)
  finally show ?thesis .
qed

lemma card_le_sym_Diff:
  assumes "finite A" "finite B" "card A card B"
  shows "card(A - B) card(B - A)"
proof -
  have "card(A - B) = card A - card (A B)" using assms(1,2) by(simp add: card_Diff_subset_Int)
  also have " card B - card (A B)" using assms(3) by linarith
  also have " = card(B - A)" using assms(1,2) by(simp add: card_Diff_subset_Int Int_commute)
  finally show ?thesis .
qed

lemma card_less_sym_Diff:
  assumes "finite A" "finite B" "card A < card B"
  shows "card(A - B) < card(B - A)"
proof -
  have "card(A - B) = card A - card (A B)" using assms(1,2) by(simp add: card_Diff_subset_Int)
  also have " < card B - card (A B)" using assms(1,3) by (simp add: card_mono diff_less_mono)
  also have " = card(B - A)" using assms(1,2) by(simp add: card_Diff_subset_Int Int_commute)
  finally show ?thesis .
qed

lemma card_Diff1_less_iff: "card (A - {x}) < card A finite A x A"
proof (cases "finite A x A")
  case True
  then show ?thesis
    by (auto simp: card_gt_0_iff intro: diff_less)
qed auto

lemma card_Diff1_less: "finite A ==> x A ==> card (A - {x}) < card A"
  unfolding card_Diff1_less_iff by auto

lemma card_Diff2_less:
  assumes "finite A" "x A" "y A" shows "card (A - {x} - {y}) < card A"
proof (cases "x = y")
  case True
  with assms show ?thesis
    by (simp add: card_Diff1_less del: card_Diff_insert)
next
  case False
  then have "card (A - {x} - {y}) < card (A - {x})" "card (A - {x}) < card A"
    using assms by (intro card_Diff1_less; simp)+
  then show ?thesis
    by (blast intro: less_trans)
qed

lemma card_Diff1_le: "card (A - {x}) card A"
proof (cases "finite A")
  case True
  then show ?thesis  
    by (cases "x A") (simp_all add: card_Diff1_less less_imp_le)
qed auto

lemma card_psubset: "finite B ==> A B ==> card A < card B ==> A < B"
  by (erule psubsetI) blast

lemma card_le_inj:
  assumes fA: "finite A"
    and fB: "finite B"
    and c: "card A card B"
  shows "f. f ` A B inj_on f A"
  using fA fB c
proof (induct arbitrary: B rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert x s t)
  then show ?case
  proof (induct rule: finite_induct [OF insert.prems(1)])
    case 1
    then show ?case by simp
  next
    case (2 y t)
    from "2.prems"(1,2,5) "2.hyps"(1,2) have cst: "card s card t"
      by simp
    from "2.prems"(3) [OF "2.hyps"(1) cst]
    obtain f where *: "f ` s t" "inj_on f s"
      by blast
    let ?g = "(λa. if a = x then y else f a)"
    have "?g ` insert x s insert y t inj_on ?g (insert x s)"
      using * "2.prems"(2) "2.hyps"(2) unfolding inj_on_def by auto
    then show ?case by (rule exI[where ?x="?g"])
  qed
qed

lemma card_subset_eq:
  assumes fB: "finite B"
    and AB: "A B"
    and c: "card A = card B"
  shows "A = B"
proof -
  from fB AB have fA: "finite A"
    by (auto intro: finite_subset)
  from fA fB have fBA: "finite (B - A)"
    by auto
  have e: "A (B - A) = {}"
    by blast
  have eq: "A (B - A) = B"
    using AB by blast
  from card_Un_disjoint[OF fA fBA e, unfolded eq c] have "card (B - A) = 0"
    by arith
  then have "B - A = {}"
    unfolding card_eq_0_iff using fA fB by simp
  with AB show "A = B"
    by blast
qed

lemma insert_partition:
  "x F ==> c1 insert x F. c2 insert x F. c1 c2 c1 c2 = {} ==> x F = {}"
  by auto

lemma finite_psubset_induct [consumes 1, case_names psubset]:
  assumes finite: "finite A"
    and major: "A. finite A ==> (B. B A ==> P B) ==> P A"
  shows "P A"
  using finite
proof (induct A taking: card rule: measure_induct_rule)
  case (less A)
  have fin: "finite A" by fact
  have ih: "card B < card A ==> finite B ==> P B" for B by fact
  have "P B" if "B A" for B
  proof -
    from that have "card B < card A"
      using psubset_card_mono fin by blast
    moreover
    from that have "B A"
      by auto
    then have "finite B"
      using fin finite_subset by blast
    ultimately show ?thesis using ih by simp
  qed
  with fin show "P A" using major by blast
qed

lemma finite_induct_select [consumes 1, case_names empty select]:
  assumes "finite S"
    and "P {}"
    and select: "T. T S ==> P T ==> sS - T. P (insert s T)"
  shows "P S"
proof -
  have "0 card S" by simp
  then have "T S. card T = card S P T"
  proof (induct rule: dec_induct)
    case base with P {}
    show ?case
      by (intro exI[of _ "{}"]) auto
  next
    case (step n)
    then obtain T where T: "T S" "card T = n" "P T"
      by auto
    with n 🚫 S have "T S" "P T"
      by auto
    with select[of T] obtain s where "s S" "s T" "P (insert s T)"
      by auto
    with step(2) T finite S show ?case
      by (intro exI[of _ "insert s T"]) (auto dest: finite_subset)
  qed
  with finite S show "P S"
    by (auto dest: card_subset_eq)
qed

lemma remove_induct [case_names empty infinite remove]:
  assumes empty: "P ({} :: 'a set)"
    and infinite: "¬ finite B ==> P B"
    and remove: "A. finite A ==> A {} ==> A B ==> (x. x A ==> P (A - {x})) ==> P A"
  shows "P B"
proof (cases "finite B")
  case False
  then show ?thesis by (rule infinite)
next
  case True
  define A where "A = B"
  with True have "finite A" "A B"
    by simp_all
  then show "P A"
  proof (induct "card A" arbitrary: A)
    case 0
    then have "A = {}" by auto
    with empty show ?case by simp
  next
    case (Suc n A)
    from A B and finite B have "finite A"
      by (rule finite_subset)
    moreover from Suc.hyps have "A {}" by auto
    moreover note A B
    moreover have "P (A - {x})" if x: "x A" for x
      using x Suc.prems Suc n = card A by (intro Suc) auto
    ultimately show ?case by (rule remove)
  qed
qed

lemma finite_remove_induct [consumes 1, case_names empty remove]:
  fixes P :: "'a set ==> bool"
  assumes "finite B"
    and "P {}"
    and "A. finite A ==> A {} ==> A B ==> (x. x A ==> P (A - {x})) ==> P A"
  defines "B' B"
  shows "P B'"
  by (induct B' rule: remove_induct) (simp_all add: assms)


text Main cardinality theorem.
lemma card_partition [rule_format]:
  "finite C ==> finite (C) ==> (cC. card c = k) ==>
    (c1 C. c2 C. c1 c2 c1 c2 = {}) ==>
    k * card C = card (C)"
proof (induct rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert x F)
  then show ?case
    by (simp add: card_Un_disjoint insert_partition finite_subset [of _ "(insert _ _)"])
qed

lemma card_eq_UNIV_imp_eq_UNIV:
  assumes fin: "finite (UNIV :: 'a set)"
    and card: "card A = card (UNIV :: 'a set)"
  shows "A = (UNIV :: 'a set)"
proof
  show "A UNIV" by simp
  show "UNIV A"
  proof
    show "x A" for x
    proof (rule ccontr)
      assume "x A"
      then have "A UNIV" by auto
      with fin have "card A < card (UNIV :: 'a set)"
        by (fact psubset_card_mono)
      with card show False by simp
    qed
  qed
qed

text The form of a finite set of given cardinality

lemma card_eq_SucD:
  assumes "card A = Suc k"
  shows "b B. A = insert b B b B card B = k (k = 0 B = {})"
proof -
  have fin: "finite A"
    using assms by (auto intro: ccontr)
  moreover have "card A 0"
    using assms by auto
  ultimately obtain b where b: "b A"
    by auto
  show ?thesis
  proof (intro exI conjI)
    show "A = insert b (A - {b})"
      using b by blast
    show "b A - {b}"
      by blast
    show "card (A - {b}) = k" and "k = 0 A - {b} = {}"
      using assms b fin by (fastforce dest: mk_disjoint_insert)+
  qed
qed

lemma card_Suc_eq:
  "card A = Suc k
    (b B. A = insert b B b B card B = k (k = 0 B = {}))"
  by (auto simp: card_insert_if card_gt_0_iff elim!: card_eq_SucD)

lemma card_Suc_eq_finite:
  "card A = Suc k (b B. A = insert b B b B card B = k finite B)"
  unfolding card_Suc_eq using card_gt_0_iff by fastforce

lemma card_1_singletonE:
  assumes "card A = 1"
  obtains x where "A = {x}"
  using assms by (auto simp: card_Suc_eq)

lemma is_singleton_iff_card_eq_Suc_0 [code]:
  is_singleton A card A = Suc 0
  by (simp add: is_singleton_def card_Suc_eq)

lemma is_singleton_altdef:
  is_singleton A card A = 1
  by (simp add: is_singleton_iff_card_eq_Suc_0)

lemma card_eq_Suc_0_iff_is_singleton:
  card A = Suc 0 is_singleton A
  by (simp add: is_singleton_altdef)

lemma card_1_singleton_iff:
  card A = Suc 0 (x. A = {x})
  by (simp add: card_eq_Suc_0_iff_is_singleton is_singleton_def)

lemma card_le_Suc0_iff_eq:
  assumes "finite A"
  shows "card A Suc 0 (a1 A. a2 A. a1 = a2)" (is "?C = ?A")
proof
  assume ?C thus ?A using assms by (auto simp: le_Suc_eq dest: card_eq_SucD)
next
  assume ?A
  show ?C
  proof cases
    assume "A = {}" thus ?C using ?A by simp
  next
    assume "A {}"
    then obtain a where "A = {a}" using ?A by blast
    thus ?C by simp
  qed
qed

lemma card_le_Suc_iff:
  "Suc n card A = (a B. A = insert a B a B n card B finite B)"
proof (cases "finite A")
  case True
  then show ?thesis
    by (fastforce simp: card_Suc_eq less_eq_nat.simps split: nat.splits)
qed auto

lemma finite_fun_UNIVD2:
  assumes fin: "finite (UNIV :: ('a ==> 'b) set)"
  shows "finite (UNIV :: 'b set)"
proof -
  from fin have "finite (range (λf :: 'a ==> 'b. f arbitrary))" for arbitrary
    by (rule finite_imageI)
  moreover have "UNIV = range (λf :: 'a ==> 'b. f arbitrary)" for arbitrary
    by (rule UNIV_eq_I) auto
  ultimately show "finite (UNIV :: 'b set)"
    by simp
qed

lemma card_UNIV_unit [simp]: "card (UNIV :: unit set) = 1"
  unfolding UNIV_unit by simp

lemma infinite_arbitrarily_large:
  assumes "¬ finite A"
  shows "B. finite B card B = n B A"
proof (induction n)
  case 0
  show ?case by (intro exI[of _ "{}"]) auto
next
  case (Suc n)
  then obtain B where B: "finite B card B = n B A" ..
  with ¬ finite A have "A B" by auto
  with B have "B A" by auto
  then have "x. x A - B"
    by (elim psubset_imp_ex_mem)
  then obtain x where x: "x A - B" ..
  with B have "finite (insert x B) card (insert x B) = Suc n insert x B A"
    by auto
  then show "B. finite B card B = Suc n B A" ..
qed

corollary finite_arbitrarily_large_disj:
  "[ ¬ finite(UNIV::'a set); finite (A::'a set) ] ==> B. finite B card B = n A B = {}"
using infinite_arbitrarily_large[of "UNIV - A"]
by fastforce

text Sometimes, to prove that a set is finite, it is convenient to work with finite subsets
 and to show that their cardinalities are uniformly bounded. This possibility is formalized in
 the next criterion.

lemma finite_if_finite_subsets_card_bdd:
  assumes "G. G F ==> finite G ==> card G C"
  shows "finite F card F C"
proof (cases "finite F")
  case False
  obtain n::nat where n: "n > max C 0" by auto
  obtain G where G: "G F" "card G = n" using infinite_arbitrarily_large[OF False] by auto
  hence "finite G" using n > max C 0 using card.infinite gr_implies_not0 by blast
  hence False using assms G n not_less by auto
  thus ?thesis ..
next
  case True thus ?thesis using assms[of F] by auto
qed

lemma obtain_subset_with_card_n:
  assumes "n card S"
  obtains T where "T S" "card T = n" "finite T"
proof -
  obtain n' where "card S = n + n'"
    using le_Suc_ex[OF assms] by blast
  with that show thesis
  proof (induct n' arbitrary: S)
    case 0 
    thus ?case by (cases "finite S") auto
  next
    case Suc 
    thus ?case by (auto simp add: card_Suc_eq)
  qed
qed

lemma exists_subset_between: 
  assumes 
    "card A n" 
    "n card C"
    "A C"
    "finite C"
  shows "B. A B B C card B = n" 
  using assms 
proof (induct n arbitrary: A C)
  case 0
  thus ?case using finite_subset[of A C] by (intro exI[of _ "{}"], auto)
next
  case (Suc n A C)
  show ?case
  proof (cases "A = {}")
    case True
    from obtain_subset_with_card_n[OF Suc(3)]
    obtain B where "B C" "card B = Suc n" by blast
    thus ?thesis unfolding True by blast
  next
    case False
    then obtain a where a: "a A" by auto
    let ?A = "A - {a}" 
    let ?C = "C - {a}" 
    have 1: "card ?A n" using Suc(2-) a 
      using finite_subset by fastforce 
    have 2: "card ?C n" using Suc(2-) a by auto
    from Suc(1)[OF 1 2 _ finite_subset[OF _ Suc(5)]] Suc(2-)
    obtain B where "?A B" "B ?C" "card B = n" by blast
    thus ?thesis using a Suc(2-) 
      by (intro exI[of _ "insert a B"], auto intro!: card_insert_disjoint finite_subset[of B C])
  qed
qed


subsubsection Cardinality of image

lemma card_image_le: "finite A ==> card (f ` A) card A"
  by (induct rule: finite_induct) (simp_all add: le_SucI card_insert_if)

lemma card_image: "inj_on f A ==> card (f ` A) = card A"
proof (induct A rule: infinite_finite_induct)
  case (infinite A)
  then have "¬ finite (f ` A)" by (auto dest: finite_imageD)
  with infinite show ?case by simp
qed simp_all

lemma bij_betw_same_card: "bij_betw f A B ==> card A = card B"
  by (auto simp: card_image bij_betw_def)

lemma endo_inj_surj: "finite A ==> f ` A A ==> inj_on f A ==> f ` A = A"
  by (simp add: card_seteq card_image)

lemma eq_card_imp_inj_on:
  assumes "finite A" "card(f ` A) = card A"
  shows "inj_on f A"
  using assms
proof (induct rule:finite_induct)
  case empty
  show ?case by simp
next
  case (insert x A)
  then show ?case
    using card_image_le [of A f] by (simp add: card_insert_if split: if_splits)
qed

lemma inj_on_iff_eq_card: "finite A ==> inj_on f A card (f ` A) = card A"
  by (blast intro: card_image eq_card_imp_inj_on)

lemma card_inj_on_le:
  assumes "inj_on f A" "f ` A B" "finite B"
  shows "card A card B"
proof -
  have "finite A"
    using assms by (blast intro: finite_imageD dest: finite_subset)
  then show ?thesis
    using assms by (force intro: card_mono simp: card_image [symmetric])
qed

lemma inj_on_iff_card_le:
  "[ finite A; finite B ] ==> (f. inj_on f A f ` A B) = (card A card B)"
using card_inj_on_le[of _ A B] card_le_inj[of A B] by blast

lemma surj_card_le: "finite A ==> B f ` A ==> card B card A"
  by (blast intro: card_image_le card_mono le_trans)

lemma card_bij_eq:
  "inj_on f A ==> f ` A B ==> inj_on g B ==> g ` B A ==> finite A ==> finite B
    ==> card A = card B"
  by (auto intro: le_antisym card_inj_on_le)

lemma bij_betw_finite: "bij_betw f A B ==> finite A finite B"
  unfolding bij_betw_def using finite_imageD [of f A] by auto

lemma inj_on_finite: "inj_on f A ==> f ` A B ==> finite B ==> finite A"
  using finite_imageD finite_subset by blast

lemma card_vimage_inj_on_le:
  assumes "inj_on f D" "finite A"
  shows "card (f-`A D) card A"
proof (rule card_inj_on_le)
  show "inj_on f (f -` A D)"
    by (blast intro: assms inj_on_subset)
qed (use assms in auto)

lemma card_vimage_inj: "inj f ==> A range f ==> card (f -` A) = card A"
  by (auto 4 3 simp: subset_image_iff inj_vimage_image_eq
      intro: card_image[symmetric, OF inj_on_subset])

lemma card_inverse[simp]: "card (R-1) = card R"
proof -
  have *: "R. prod.swap ` R = R-1" by auto
  {
    assume "¬finite R"
    hence ?thesis
      by auto
  } moreover {
    assume "finite R"
    with card_image_le[of R prod.swap] card_image_le[of "R-1" prod.swap]
    have ?thesis by (auto simp: * )
  } ultimately show ?thesis by blast
qed

subsubsection Pigeonhole Principles

lemma pigeonhole: "card A > card (f ` A) ==> ¬ inj_on f A "
  by (auto dest: card_image less_irrefl_nat)

lemma pigeonhole_infinite:
  assumes "¬ finite A" and "finite (f`A)"
  shows "a0A. ¬ finite {aA. f a = f a0}"
  using assms(2,1)
proof (induct "f`A" arbitrary: A rule: finite_induct)
  case empty
  then show ?case by simp
next
  case (insert b F)
  show ?case
  proof (cases "finite {aA. f a = b}")
    case True
    with ¬ finite A have "¬ finite (A - {aA. f a = b})"
      by simp
    also have "A - {aA. f a = b} = {aA. f a b}"
      by blast
    finally have "¬ finite {aA. f a b}" .
    from insert(3)[OF _ this] insert(2,4) show ?thesis
      by simp (blast intro: rev_finite_subset)
  next
    case False
    then have "{a A. f a = b} {}" by force
    with False show ?thesis by blast
  qed
qed

lemma pigeonhole_infinite_rel:
  assumes "¬ finite A"
    and "finite B"
    and "aA. bB. R a b"
  shows "bB. ¬ finite {a:A. R a b}"
proof -
  let ?F = "λa. {bB. R a b}"
  from finite_Pow_iff[THEN iffD2, OF finite Bhave "finite (?F ` A)"
    by (blast intro: rev_finite_subset)
  from pigeonhole_infinite [where f = ?F, OF assms(1) this]
  obtain a0 where "a0 A" and infinite: "¬ finite {aA. ?F a = ?F a0}" ..
  obtain b0 where "b0 B" and "R a0 b0"
    using a0 A assms(3) by blast
  have "finite {aA. ?F a = ?F a0}" if "finite {aA. R a b0}"
    using b0 B R a0 b0 that by (blast intro: rev_finite_subset)
  with infinite b0 B show ?thesis
    by blast
qed


subsubsection Cardinality of sums

lemma card_Plus:
  assumes "finite A" "finite B"
  shows "card (A <+> B) = card A + card B"
proof -
  have "Inl`A Inr`B = {}" by fast
  with assms show ?thesis
    by (simp add: Plus_def card_Un_disjoint card_image)
qed

lemma card_Plus_conv_if:
  "card (A <+> B) = (if finite A finite B then card A + card B else 0)"
  by (auto simp add: card_Plus)

text Relates to equivalence classes. Based on a theorem of F. Kammüller.

lemma dvd_partition:
  assumes f: "finite (C)"
    and "cC. k dvd card c" "c1C. c2C. c1 c2 c1 c2 = {}"
  shows "k dvd card (C)"
proof -
  have "finite C"
    by (rule finite_UnionD [OF f])
  then show ?thesis
    using assms
  proof (induct rule: finite_induct)
    case empty
    show ?case by simp
  next
    case (insert c C)
    then have "c C = {}"
      by auto
    with insert show ?case
      by (simp add: card_Un_disjoint)
  qed
qed


subsection Minimal and maximal elements of finite sets

context begin

qualified lemma
  assumes "finite A" and "asymp_on A R" and "transp_on A R" and "x A. P x"
  shows
    bex_min_element_with_property: "x A. P x (y A. R y x ¬ P y)" and
    bex_max_element_with_property: "x A. P x (y A. R x y ¬ P y)"
  unfolding atomize_conj
  using assms
proof (induction A rule: finite_induct)
  case empty
  hence False
    by simp_all
  thus ?case ..
next
  case (insert x F)

  from insert.prems have "asymp_on F R"
    using asymp_on_subset by blast

  from insert.prems have "transp_on F R"
    using transp_on_subset by blast

  show ?case
  proof (cases "P x")
    case True
    show ?thesis
    proof (cases "aF. P a")
      case True
      with insert.IH obtain min max where
        "min F" and "P min" and "z F. R z min ¬ P z"
        "max F" and "P max" and "z F. R max z ¬ P z"
        using asymp_on F R transp_on F R by auto

      show ?thesis
      proof (rule conjI)
        show "y insert x F. P y (z insert x F. R y z ¬ P z)"
        proof (cases "R max x")
          case True
          show ?thesis
          proof (intro bexI conjI ballI impI)
            show "x insert x F"
              by simp
          next
            show "P x"
              using P x by simp
          next
            fix z assume "z insert x F" and "R x z"
            hence "z = x z F"
              by simp
            thus "¬ P z"
            proof (rule disjE)
              assume "z = x"
              hence "R x x"
                using R x z by simp
              moreover have "¬ R x x"
                using asymp_on (insert x F) R[THEN irreflp_on_if_asymp_on, THEN irreflp_onD]
                by simp
              ultimately have False
                by simp
              thus ?thesis ..
            next
              assume "z F"
              moreover have "R max z"
                using R max x R x z
                using transp_on (insert x F) R[THEN transp_onD, of max x z]
                using max F z F by simp
              ultimately show ?thesis
                using z F. R max z ¬ P z by simp
            qed
          qed
        next
          case False
          show ?thesis
          proof (intro bexI conjI ballI impI)
            show "max insert x F"
              using max F by simp
          next
            show "P max"
              using P max by simp
          next
            fix z assume "z insert x F" and "R max z"
            hence "z = x z F"
              by simp
            thus "¬ P z"
            proof (rule disjE)
              assume "z = x"
              hence False
                using ¬ R max x R max z by simp
              thus ?thesis ..
            next
              assume "z F"
              thus ?thesis
                using R max z zF. R max z ¬ P z by simp
            qed
          qed
        qed
      next
        show "y insert x F. P y (z insert x F. R z y ¬ P z)"
        proof (cases "R x min")
          case True
          show ?thesis
          proof (intro bexI conjI ballI impI)
            show "x insert x F"
              by simp
          next
            show "P x"
              using P x by simp
          next
            fix z assume "z insert x F" and "R z x"
            hence "z = x z F"
              by simp
            thus "¬ P z"
            proof (rule disjE)
              assume "z = x"
              hence "R x x"
                using R z x by simp
              moreover have "¬ R x x"
                using asymp_on (insert x F) R[THEN irreflp_on_if_asymp_on, THEN irreflp_onD]
                by simp
              ultimately have False
                by simp
              thus ?thesis ..
            next
              assume "z F"
              moreover have "R z min"
                using R z x R x min
                using transp_on (insert x F) R[THEN transp_onD, of z x min]
                using min F z F by simp
              ultimately show ?thesis
                using z F. R z min ¬ P z by simp
            qed
          qed
        next
          case False
          show ?thesis
          proof (intro bexI conjI ballI impI)
            show "min insert x F"
              using min F by simp
          next
            show "P min"
              using P min by simp
          next
            fix z assume "z insert x F" and "R z min"
            hence "z = x z F"
              by simp
            thus "¬ P z"
            proof (rule disjE)
              assume "z = x"
              hence False
                using ¬ R x min R z min by simp
              thus ?thesis ..
            next
              assume "z F"
              thus ?thesis
                using R z min zF. R z min ¬ P z by simp
            qed
          qed
        qed
      qed
    next
      case False
      then show ?thesis
        using ainsert x F. P a
        using asymp_on (insert x F) R[THEN asymp_onD, of x] insert_iff[of _ x F]
        by blast
    qed
  next
    case False
    with insert.prems have "x F. P x"
      by simp
    with insert.IH have
      "y F. P y (zF. R z y ¬ P z)"
      "y F. P y (zF. R y z ¬ P z)"
      using asymp_on F R transp_on F R by auto
    thus ?thesis
      using False by auto
  qed
qed

qualified lemma
  assumes "finite A" and "asymp_on A R" and "transp_on A R" and "A {}"
  shows
    bex_min_element: "m A. x A. x m ¬ R x m" and
    bex_max_element: "m A. x A. x m ¬ R m x"
  using A {}
    bex_min_element_with_property[OF assms(1,2,3), of "λ_. True", simplified]
    bex_max_element_with_property[OF assms(1,2,3), of "λ_. True", simplified]
  by blast+

end

text The following alternative form might sometimes be easier to work with.

lemma is_min_element_in_set_iff:
  "asymp_on A R ==> (y A. y x ¬ R y x) (y. R y x y A)"
  by (auto dest: asymp_onD)

lemma is_max_element_in_set_iff:
  "asymp_on A R ==> (y A. y x ¬ R x y) (y. R x y y A)"
  by (auto dest: asymp_onD)

context begin

qualified lemma
  assumes "finite A" and "A {}" and "transp_on A R" and "totalp_on A R"
  shows
    bex_least_element: "l A. x A. x l R l x" and
    bex_greatest_element: "g A. x A. x g R x g"
  unfolding atomize_conj
  using assms
proof (induction A rule: finite_induct)
  case empty
  hence False by simp
  thus ?case ..
next
  case (insert a A')

  from insert.prems(2) have transp_on_A': "transp_on A' R"
    by (auto intro: transp_onI dest: transp_onD)

  from insert.prems(3) have
    totalp_on_a_A'_raw: "y A'. a y R a y R y a" and
    totalp_on_A': "totalp_on A' R"
    by (simp_all add: totalp_on_def)

  show ?case
  proof (cases "A' = {}")
    case True
    thus ?thesis by simp
  next
    case False
    then obtain least greatest where
      "least A'" and least_of_A': "xA'. x least R least x" and
      "greatest A'" and greatest_of_A': "xA'. x greatest R x greatest"
      using insert.IH[OF _ transp_on_A' totalp_on_A'] by auto

    show ?thesis
    proof (rule conjI)
      show "linsert a A'. xinsert a A'. x l R l x"
      proof (cases "R a least")
        case True
        show ?thesis
        proof (intro bexI ballI impI)
          show "a insert a A'"
            by simp
        next
          fix x
          show "x. x insert a A' ==> x a ==> R a x"
            using True least A' least_of_A'
            using insert.prems(2)[THEN transp_onD, of a least]
            by auto
        qed
      next
        case False
        show ?thesis
        proof (intro bexI ballI impI)
          show "least insert a A'"
            using least A' by simp
        next
          fix x
          show "x insert a A' ==> x least ==> R least x"
            using False least A' least_of_A' totalp_on_a_A'_raw
            by (cases "x = a") auto
        qed
      qed
    next
      show "g insert a A'. x insert a A'. x g R x g"
      proof (cases "R greatest a")
        case True
        show ?thesis
        proof (intro bexI ballI impI)
          show "a insert a A'"
            by simp
        next
          fix x
          show "x. x insert a A' ==> x a ==> R x a"
            using True greatest A' greatest_of_A'
            using insert.prems(2)[THEN transp_onD, of _ greatest a]
            by auto
        qed
      next
        case False
        show ?thesis
        proof (intro bexI ballI impI)
          show "greatest insert a A'"
            using greatest A' by simp
        next
          fix x
          show "x insert a A' ==> x greatest ==> R x greatest"
            using False greatest A' greatest_of_A' totalp_on_a_A'_raw
            by (cases "x = a") auto
        qed
      qed
    qed
  qed
qed

end

subsubsection Finite orders

context order
begin

lemma finite_has_maximal:
  assumes "finite A" and "A {}"
  shows " m A. b A. m b m = b"
proof -
  obtain m where "m A" and m_is_max: "xA. x m ¬ m < x"
    using Finite_Set.bex_max_element[OF finite A _ _ A {}, of "(<)"by auto
  moreover have "b A. m b m = b"
    using m_is_max by (auto simp: le_less)
  ultimately show ?thesis
    by auto
qed

lemma finite_has_maximal2:
  "[ finite A; a A ] ==> m A. a m ( b A. m b m = b)"
using finite_has_maximal[of "{b A. a b}"by fastforce

lemma finite_has_minimal:
  assumes "finite A" and "A {}"
  shows " m A. b A. b m m = b"
proof -
  obtain m where "m A" and m_is_min: "xA. x m ¬ x < m"
    using Finite_Set.bex_min_element[OF finite A _ _ A {}, of "(<)"by auto
  moreover have "b A. b m m = b"
    using m_is_min by (auto simp: le_less)
  ultimately show ?thesis
    by auto
qed

lemma finite_has_minimal2:
  "[ finite A; a A ] ==> m A. m a ( b A. b m m = b)"
using finite_has_minimal[of "{b A. b a}"by fastforce

end

subsubsection Relating injectivity and surjectivity

lemma finite_surj_inj:
  assumes "finite A" "A f ` A"
  shows "inj_on f A"
proof -
  have "f ` A = A"
    by (rule card_seteq [THEN sym]) (auto simp add: assms card_image_le)
  then show ?thesis using assms
    by (simp add: eq_card_imp_inj_on)
qed

lemma finite_UNIV_surj_inj: "finite(UNIV:: 'a set) ==> surj f ==> inj f"
  for f :: "'a ==> 'a"
  by (blast intro: finite_surj_inj subset_UNIV)

lemma finite_UNIV_inj_surj: "finite(UNIV:: 'a set) ==> inj f ==> surj f"
  for f :: "'a ==> 'a"
  by (fastforce simp:surj_def dest!: endo_inj_surj)

lemma surjective_iff_injective_gen:
  assumes fS: "finite S"
    and fT: "finite T"
    and c: "card S = card T"
    and ST: "f ` S T"
  shows "(y T. x S. f x = y) inj_on f S"
  (is "?lhs ?rhs")
proof
  assume h: "?lhs"
  {
    fix x y
    assume x: "x S"
    assume y: "y S"
    assume f: "f x = f y"
    from x fS have S0: "card S 0"
      by auto
    have "x = y"
    proof (rule ccontr)
      assume xy: "¬ ?thesis"
      have th: "card S card (f ` (S - {y}))"
        unfolding c
      proof (rule card_mono)
        show "finite (f ` (S - {y}))"
          by (simp add: fS)
        have "[x y; x S; z S; f x = f y]
         ==> x S. x y f z = f x" for z
          by (cases "z = y z = x") auto
        then show "T f ` (S - {y})"
          using h xy x y f by fastforce
      qed
      also have " card (S - {y})"
        by (simp add: card_image_le fS)
      also have " card S - 1" using y fS by simp
      finally show False using S0 by arith
    qed
  }
  then show ?rhs
    unfolding inj_on_def by blast
next
  assume h: ?rhs
  have "f ` S = T"
    by (simp add: ST c card_image card_subset_eq fT h)
  then show ?lhs by blast
qed

hide_const (open) Finite_Set.fold


subsection Infinite Sets

text 
  Some elementary facts about infinite sets, mostly by Stephan Merz.
  Beware! Because "infinite" merely abbreviates a negation, these
  lemmas may not work well with blast.
 

abbreviation infinite :: "'a set ==> bool"
  where "infinite S ¬ finite S"

text 
  Infinite sets are non-empty, and if we remove some elements from an
  infinite set, the result is still infinite.
 

lemma infinite_UNIV_nat [iff]: "infinite (UNIV :: nat set)"
proof
  assume "finite (UNIV :: nat set)"
  with finite_UNIV_inj_surj [of Suc] show False
    by simp (blast dest: Suc_neq_Zero surjD)
qed

lemma infinite_UNIV_char_0: "infinite (UNIV :: 'a::semiring_char_0 set)"
proof
  assume "finite (UNIV :: 'a set)"
  with subset_UNIV have "finite (range of_nat :: 'a set)"
    by (rule finite_subset)
  moreover have "inj (of_nat :: nat ==> 'a)"
    by (simp add: inj_on_def)
  ultimately have "finite (UNIV :: nat set)"
    by (rule finite_imageD)
  then show False
    by simp
qed

lemma infinite_imp_nonempty: "infinite S ==> S {}"
  by auto

lemma infinite_remove: "infinite S ==> infinite (S - {a})"
  by simp

lemma Diff_infinite_finite:
  assumes "finite T" "infinite S"
  shows "infinite (S - T)"
  using finite T
proof induct
  from infinite S show "infinite (S - {})"
    by auto
next
  fix T x
  assume ih: "infinite (S - T)"
  have "S - (insert x T) = (S - T) - {x}"
    by (rule Diff_insert)
  with ih show "infinite (S - (insert x T))"
    by (simp add: infinite_remove)
qed

lemma Un_infinite: "infinite S ==> infinite (S T)"
  by simp

lemma infinite_Un: "infinite (S T) infinite S infinite T"
  by simp

lemma infinite_super:
  assumes "S T"
    and "infinite S"
  shows "infinite T"
proof
  assume "finite T"
  with S T have "finite S" by (simp add: finite_subset)
  with infinite S show False by simp
qed

proposition infinite_coinduct [consumes 1, case_names infinite]:
  assumes "X A"
    and step: "A. X A ==> xA. X (A - {x}) infinite (A - {x})"
  shows "infinite A"
proof
  assume "finite A"
  then show False
    using X A
  proof (induction rule: finite_psubset_induct)
    case (psubset A)
    then obtain x where "x A" "X (A - {x}) infinite (A - {x})"
      using local.step psubset.prems by blast
    then have "X (A - {x})"
      using psubset.hyps by blast
    show False
    proof (rule psubset.IH [where B = "A - {x}"])
      show "A - {x} A"
        using x A by blast
    qed fact
  qed
qed

text 
  For any function with infinite domain and finite range there is some
  element that is the image of infinitely many domain elements. In
  particular, any infinite sequence of elements from a finite set
  contains some element that occurs infinitely often.
 

lemma inf_img_fin_dom':
  assumes img: "finite (f ` A)"
    and dom: "infinite A"
  shows "y f ` A. infinite (f -` {y} A)"
proof (rule ccontr)
  have "A (yf ` A. f -` {y} A)" by auto
  moreover assume "¬ ?thesis"
  with img have "finite (yf ` A. f -` {y} A)" by blast
  ultimately have "finite A" by (rule finite_subset)
  with dom show False by contradiction
qed

lemma inf_img_fin_domE':
  assumes "finite (f ` A)" and "infinite A"
  obtains y where "y f`A" and "infinite (f -` {y} A)"
  using assms by (blast dest: inf_img_fin_dom')

lemma inf_img_fin_dom:
  assumes img: "finite (f`A)" and dom: "infinite A"
  shows "y f`A. infinite (f -` {y})"
  using inf_img_fin_dom'[OF assms] by auto

lemma inf_img_fin_domE:
  assumes "finite (f`A)" and "infinite A"
  obtains y where "y f`A" and "infinite (f -` {y})"
  using assms by (blast dest: inf_img_fin_dom)

proposition finite_image_absD: "finite (abs ` S) ==> finite S"
  for S :: "'a::linordered_ring set"
  by (rule ccontr) (auto simp: abs_eq_iff vimage_def dest: inf_img_fin_dom)


subsection The finite powerset operator

definition Fpow :: "'a set ==> 'a set set"
where "Fpow A {X. X A finite X}"

lemma Fpow_mono: "A B ==> Fpow A Fpow B"
unfolding Fpow_def by auto

lemma empty_in_Fpow: "{} Fpow A"
unfolding Fpow_def by auto

lemma Fpow_not_empty: "Fpow A {}"
using empty_in_Fpow by blast

lemma Fpow_subset_Pow: "Fpow A Pow A"
unfolding Fpow_def by auto

lemma Fpow_Pow_finite: "Fpow A = Pow A Int {A. finite A}"
unfolding Fpow_def Pow_def by blast

lemma inj_on_image_Fpow:
  assumes "inj_on f A"
  shows "inj_on (image f) (Fpow A)"
  using assms Fpow_subset_Pow[of A] inj_on_subset[of "image f" "Pow A"]
    inj_on_image_Pow by blast

lemma image_Fpow_mono:
  assumes "f ` A B"
  shows "(image f) ` (Fpow A) Fpow B"
  using assms by(unfold Fpow_def, auto)

end

Messung V0.5 in Prozent
C=90 H=98 G=94

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.116Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-26) ¤

*Eine klare Vorstellung vom Zielzustand






Versionsinformation zu Columbo

Bemerkung:

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders