Theory Complete_Lattices

theory Complete_Lattices
imports Fun
```(*  Title:      HOL/Complete_Lattices.thy
Author:     Tobias Nipkow
Author:     Lawrence C Paulson
Author:     Markus Wenzel
Author:     Florian Haftmann
*)

section ‹Complete lattices›

theory Complete_Lattices
imports Fun
begin

subsection ‹Syntactic infimum and supremum operations›

class Inf =
fixes Inf :: "'a set ⇒ 'a"  ("⨅_" [900] 900)
begin

abbreviation INFIMUM :: "'b set ⇒ ('b ⇒ 'a) ⇒ 'a"
where "INFIMUM A f ≡ ⨅(f ` A)"

lemma INF_image [simp]: "INFIMUM (f ` A) g = INFIMUM A (g ∘ f)"

lemma INF_identity_eq [simp]: "INFIMUM A (λx. x) = ⨅A"
by simp

lemma INF_id_eq [simp]: "INFIMUM A id = ⨅A"
by simp

lemma INF_cong: "A = B ⟹ (⋀x. x ∈ B ⟹ C x = D x) ⟹ INFIMUM A C = INFIMUM B D"

lemma strong_INF_cong [cong]:
"A = B ⟹ (⋀x. x ∈ B =simp=> C x = D x) ⟹ INFIMUM A C = INFIMUM B D"
unfolding simp_implies_def by (fact INF_cong)

end

class Sup =
fixes Sup :: "'a set ⇒ 'a"  ("⨆_" [900] 900)
begin

abbreviation SUPREMUM :: "'b set ⇒ ('b ⇒ 'a) ⇒ 'a"
where "SUPREMUM A f ≡ ⨆(f ` A)"

lemma SUP_image [simp]: "SUPREMUM (f ` A) g = SUPREMUM A (g ∘ f)"

lemma SUP_identity_eq [simp]: "SUPREMUM A (λx. x) = ⨆A"
by simp

lemma SUP_id_eq [simp]: "SUPREMUM A id = ⨆A"

lemma SUP_cong: "A = B ⟹ (⋀x. x ∈ B ⟹ C x = D x) ⟹ SUPREMUM A C = SUPREMUM B D"

lemma strong_SUP_cong [cong]:
"A = B ⟹ (⋀x. x ∈ B =simp=> C x = D x) ⟹ SUPREMUM A C = SUPREMUM B D"
unfolding simp_implies_def by (fact SUP_cong)

end

text ‹
Note: must use names @{const INFIMUM} and @{const SUPREMUM} here instead of
‹INF› and ‹SUP› to allow the following syntax coexist
with the plain constant names.
›

syntax (ASCII)
"_INF1"     :: "pttrns ⇒ 'b ⇒ 'b"           ("(3INF _./ _)" [0, 10] 10)
"_INF"      :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b"  ("(3INF _:_./ _)" [0, 0, 10] 10)
"_SUP1"     :: "pttrns ⇒ 'b ⇒ 'b"           ("(3SUP _./ _)" [0, 10] 10)
"_SUP"      :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b"  ("(3SUP _:_./ _)" [0, 0, 10] 10)

syntax (output)
"_INF1"     :: "pttrns ⇒ 'b ⇒ 'b"           ("(3INF _./ _)" [0, 10] 10)
"_INF"      :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b"  ("(3INF _:_./ _)" [0, 0, 10] 10)
"_SUP1"     :: "pttrns ⇒ 'b ⇒ 'b"           ("(3SUP _./ _)" [0, 10] 10)
"_SUP"      :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b"  ("(3SUP _:_./ _)" [0, 0, 10] 10)

syntax
"_INF1"     :: "pttrns ⇒ 'b ⇒ 'b"           ("(3⨅_./ _)" [0, 10] 10)
"_INF"      :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b"  ("(3⨅_∈_./ _)" [0, 0, 10] 10)
"_SUP1"     :: "pttrns ⇒ 'b ⇒ 'b"           ("(3⨆_./ _)" [0, 10] 10)
"_SUP"      :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b"  ("(3⨆_∈_./ _)" [0, 0, 10] 10)

translations
"⨅x y. B"   ⇌ "⨅x. ⨅y. B"
"⨅x. B"     ⇌ "CONST INFIMUM CONST UNIV (λx. B)"
"⨅x. B"     ⇌ "⨅x ∈ CONST UNIV. B"
"⨅x∈A. B"   ⇌ "CONST INFIMUM A (λx. B)"
"⨆x y. B"   ⇌ "⨆x. ⨆y. B"
"⨆x. B"     ⇌ "CONST SUPREMUM CONST UNIV (λx. B)"
"⨆x. B"     ⇌ "⨆x ∈ CONST UNIV. B"
"⨆x∈A. B"   ⇌ "CONST SUPREMUM A (λx. B)"

print_translation ‹
[Syntax_Trans.preserve_binder_abs2_tr' @{const_syntax INFIMUM} @{syntax_const "_INF"},
Syntax_Trans.preserve_binder_abs2_tr' @{const_syntax SUPREMUM} @{syntax_const "_SUP"}]
› ― ‹to avoid eta-contraction of body›

subsection ‹Abstract complete lattices›

text ‹A complete lattice always has a bottom and a top,
so we include them into the following type class,
along with assumptions that define bottom and top
in terms of infimum and supremum.›

class complete_lattice = lattice + Inf + Sup + bot + top +
assumes Inf_lower: "x ∈ A ⟹ ⨅A ≤ x"
and Inf_greatest: "(⋀x. x ∈ A ⟹ z ≤ x) ⟹ z ≤ ⨅A"
and Sup_upper: "x ∈ A ⟹ x ≤ ⨆A"
and Sup_least: "(⋀x. x ∈ A ⟹ x ≤ z) ⟹ ⨆A ≤ z"
and Inf_empty [simp]: "⨅{} = ⊤"
and Sup_empty [simp]: "⨆{} = ⊥"
begin

subclass bounded_lattice
proof
fix a
show "⊥ ≤ a"
by (auto intro: Sup_least simp only: Sup_empty [symmetric])
show "a ≤ ⊤"
by (auto intro: Inf_greatest simp only: Inf_empty [symmetric])
qed

lemma dual_complete_lattice: "class.complete_lattice Sup Inf sup (op ≥) (op >) inf ⊤ ⊥"
by (auto intro!: class.complete_lattice.intro dual_lattice)
(unfold_locales, (fact Inf_empty Sup_empty Sup_upper Sup_least Inf_lower Inf_greatest)+)

end

context complete_lattice
begin

lemma Sup_eqI:
"(⋀y. y ∈ A ⟹ y ≤ x) ⟹ (⋀y. (⋀z. z ∈ A ⟹ z ≤ y) ⟹ x ≤ y) ⟹ ⨆A = x"
by (blast intro: antisym Sup_least Sup_upper)

lemma Inf_eqI:
"(⋀i. i ∈ A ⟹ x ≤ i) ⟹ (⋀y. (⋀i. i ∈ A ⟹ y ≤ i) ⟹ y ≤ x) ⟹ ⨅A = x"
by (blast intro: antisym Inf_greatest Inf_lower)

lemma SUP_eqI:
"(⋀i. i ∈ A ⟹ f i ≤ x) ⟹ (⋀y. (⋀i. i ∈ A ⟹ f i ≤ y) ⟹ x ≤ y) ⟹ (⨆i∈A. f i) = x"
using Sup_eqI [of "f ` A" x] by auto

lemma INF_eqI:
"(⋀i. i ∈ A ⟹ x ≤ f i) ⟹ (⋀y. (⋀i. i ∈ A ⟹ f i ≥ y) ⟹ x ≥ y) ⟹ (⨅i∈A. f i) = x"
using Inf_eqI [of "f ` A" x] by auto

lemma INF_lower: "i ∈ A ⟹ (⨅i∈A. f i) ≤ f i"
using Inf_lower [of _ "f ` A"] by simp

lemma INF_greatest: "(⋀i. i ∈ A ⟹ u ≤ f i) ⟹ u ≤ (⨅i∈A. f i)"
using Inf_greatest [of "f ` A"] by auto

lemma SUP_upper: "i ∈ A ⟹ f i ≤ (⨆i∈A. f i)"
using Sup_upper [of _ "f ` A"] by simp

lemma SUP_least: "(⋀i. i ∈ A ⟹ f i ≤ u) ⟹ (⨆i∈A. f i) ≤ u"
using Sup_least [of "f ` A"] by auto

lemma Inf_lower2: "u ∈ A ⟹ u ≤ v ⟹ ⨅A ≤ v"
using Inf_lower [of u A] by auto

lemma INF_lower2: "i ∈ A ⟹ f i ≤ u ⟹ (⨅i∈A. f i) ≤ u"
using INF_lower [of i A f] by auto

lemma Sup_upper2: "u ∈ A ⟹ v ≤ u ⟹ v ≤ ⨆A"
using Sup_upper [of u A] by auto

lemma SUP_upper2: "i ∈ A ⟹ u ≤ f i ⟹ u ≤ (⨆i∈A. f i)"
using SUP_upper [of i A f] by auto

lemma le_Inf_iff: "b ≤ ⨅A ⟷ (∀a∈A. b ≤ a)"
by (auto intro: Inf_greatest dest: Inf_lower)

lemma le_INF_iff: "u ≤ (⨅i∈A. f i) ⟷ (∀i∈A. u ≤ f i)"
using le_Inf_iff [of _ "f ` A"] by simp

lemma Sup_le_iff: "⨆A ≤ b ⟷ (∀a∈A. a ≤ b)"
by (auto intro: Sup_least dest: Sup_upper)

lemma SUP_le_iff: "(⨆i∈A. f i) ≤ u ⟷ (∀i∈A. f i ≤ u)"
using Sup_le_iff [of "f ` A"] by simp

lemma Inf_insert [simp]: "⨅insert a A = a ⊓ ⨅A"
by (auto intro: le_infI le_infI1 le_infI2 antisym Inf_greatest Inf_lower)

lemma INF_insert [simp]: "(⨅x∈insert a A. f x) = f a ⊓ INFIMUM A f"
by (simp cong del: strong_INF_cong)

lemma Sup_insert [simp]: "⨆insert a A = a ⊔ ⨆A"
by (auto intro: le_supI le_supI1 le_supI2 antisym Sup_least Sup_upper)

lemma SUP_insert [simp]: "(⨆x∈insert a A. f x) = f a ⊔ SUPREMUM A f"
by (simp cong del: strong_SUP_cong)

lemma INF_empty [simp]: "(⨅x∈{}. f x) = ⊤"
by (simp cong del: strong_INF_cong)

lemma SUP_empty [simp]: "(⨆x∈{}. f x) = ⊥"
by (simp cong del: strong_SUP_cong)

lemma Inf_UNIV [simp]: "⨅UNIV = ⊥"
by (auto intro!: antisym Inf_lower)

lemma Sup_UNIV [simp]: "⨆UNIV = ⊤"
by (auto intro!: antisym Sup_upper)

lemma Inf_Sup: "⨅A = ⨆{b. ∀a ∈ A. b ≤ a}"
by (auto intro: antisym Inf_lower Inf_greatest Sup_upper Sup_least)

lemma Sup_Inf:  "⨆A = ⨅{b. ∀a ∈ A. a ≤ b}"
by (auto intro: antisym Inf_lower Inf_greatest Sup_upper Sup_least)

lemma Inf_superset_mono: "B ⊆ A ⟹ ⨅A ≤ ⨅B"
by (auto intro: Inf_greatest Inf_lower)

lemma Sup_subset_mono: "A ⊆ B ⟹ ⨆A ≤ ⨆B"
by (auto intro: Sup_least Sup_upper)

lemma Inf_mono:
assumes "⋀b. b ∈ B ⟹ ∃a∈A. a ≤ b"
shows "⨅A ≤ ⨅B"
proof (rule Inf_greatest)
fix b assume "b ∈ B"
with assms obtain a where "a ∈ A" and "a ≤ b" by blast
from ‹a ∈ A› have "⨅A ≤ a" by (rule Inf_lower)
with ‹a ≤ b› show "⨅A ≤ b" by auto
qed

lemma INF_mono: "(⋀m. m ∈ B ⟹ ∃n∈A. f n ≤ g m) ⟹ (⨅n∈A. f n) ≤ (⨅n∈B. g n)"
using Inf_mono [of "g ` B" "f ` A"] by auto

lemma Sup_mono:
assumes "⋀a. a ∈ A ⟹ ∃b∈B. a ≤ b"
shows "⨆A ≤ ⨆B"
proof (rule Sup_least)
fix a assume "a ∈ A"
with assms obtain b where "b ∈ B" and "a ≤ b" by blast
from ‹b ∈ B› have "b ≤ ⨆B" by (rule Sup_upper)
with ‹a ≤ b› show "a ≤ ⨆B" by auto
qed

lemma SUP_mono: "(⋀n. n ∈ A ⟹ ∃m∈B. f n ≤ g m) ⟹ (⨆n∈A. f n) ≤ (⨆n∈B. g n)"
using Sup_mono [of "f ` A" "g ` B"] by auto

lemma INF_superset_mono: "B ⊆ A ⟹ (⋀x. x ∈ B ⟹ f x ≤ g x) ⟹ (⨅x∈A. f x) ≤ (⨅x∈B. g x)"
― ‹The last inclusion is POSITIVE!›
by (blast intro: INF_mono dest: subsetD)

lemma SUP_subset_mono: "A ⊆ B ⟹ (⋀x. x ∈ A ⟹ f x ≤ g x) ⟹ (⨆x∈A. f x) ≤ (⨆x∈B. g x)"
by (blast intro: SUP_mono dest: subsetD)

lemma Inf_less_eq:
assumes "⋀v. v ∈ A ⟹ v ≤ u"
and "A ≠ {}"
shows "⨅A ≤ u"
proof -
from ‹A ≠ {}› obtain v where "v ∈ A" by blast
moreover from ‹v ∈ A› assms(1) have "v ≤ u" by blast
ultimately show ?thesis by (rule Inf_lower2)
qed

lemma less_eq_Sup:
assumes "⋀v. v ∈ A ⟹ u ≤ v"
and "A ≠ {}"
shows "u ≤ ⨆A"
proof -
from ‹A ≠ {}› obtain v where "v ∈ A" by blast
moreover from ‹v ∈ A› assms(1) have "u ≤ v" by blast
ultimately show ?thesis by (rule Sup_upper2)
qed

lemma INF_eq:
assumes "⋀i. i ∈ A ⟹ ∃j∈B. f i ≥ g j"
and "⋀j. j ∈ B ⟹ ∃i∈A. g j ≥ f i"
shows "INFIMUM A f = INFIMUM B g"
by (intro antisym INF_greatest) (blast intro: INF_lower2 dest: assms)+

lemma SUP_eq:
assumes "⋀i. i ∈ A ⟹ ∃j∈B. f i ≤ g j"
and "⋀j. j ∈ B ⟹ ∃i∈A. g j ≤ f i"
shows "SUPREMUM A f = SUPREMUM B g"
by (intro antisym SUP_least) (blast intro: SUP_upper2 dest: assms)+

lemma less_eq_Inf_inter: "⨅A ⊔ ⨅B ≤ ⨅(A ∩ B)"
by (auto intro: Inf_greatest Inf_lower)

lemma Sup_inter_less_eq: "⨆(A ∩ B) ≤ ⨆A ⊓ ⨆B "
by (auto intro: Sup_least Sup_upper)

lemma Inf_union_distrib: "⨅(A ∪ B) = ⨅A ⊓ ⨅B"
by (rule antisym) (auto intro: Inf_greatest Inf_lower le_infI1 le_infI2)

lemma INF_union: "(⨅i ∈ A ∪ B. M i) = (⨅i ∈ A. M i) ⊓ (⨅i∈B. M i)"
by (auto intro!: antisym INF_mono intro: le_infI1 le_infI2 INF_greatest INF_lower)

lemma Sup_union_distrib: "⨆(A ∪ B) = ⨆A ⊔ ⨆B"
by (rule antisym) (auto intro: Sup_least Sup_upper le_supI1 le_supI2)

lemma SUP_union: "(⨆i ∈ A ∪ B. M i) = (⨆i ∈ A. M i) ⊔ (⨆i∈B. M i)"
by (auto intro!: antisym SUP_mono intro: le_supI1 le_supI2 SUP_least SUP_upper)

lemma INF_inf_distrib: "(⨅a∈A. f a) ⊓ (⨅a∈A. g a) = (⨅a∈A. f a ⊓ g a)"
by (rule antisym) (rule INF_greatest, auto intro: le_infI1 le_infI2 INF_lower INF_mono)

lemma SUP_sup_distrib: "(⨆a∈A. f a) ⊔ (⨆a∈A. g a) = (⨆a∈A. f a ⊔ g a)"
(is "?L = ?R")
proof (rule antisym)
show "?L ≤ ?R"
by (auto intro: le_supI1 le_supI2 SUP_upper SUP_mono)
show "?R ≤ ?L"
by (rule SUP_least) (auto intro: le_supI1 le_supI2 SUP_upper)
qed

lemma Inf_top_conv [simp]:
"⨅A = ⊤ ⟷ (∀x∈A. x = ⊤)"
"⊤ = ⨅A ⟷ (∀x∈A. x = ⊤)"
proof -
show "⨅A = ⊤ ⟷ (∀x∈A. x = ⊤)"
proof
assume "∀x∈A. x = ⊤"
then have "A = {} ∨ A = {⊤}" by auto
then show "⨅A = ⊤" by auto
next
assume "⨅A = ⊤"
show "∀x∈A. x = ⊤"
proof (rule ccontr)
assume "¬ (∀x∈A. x = ⊤)"
then obtain x where "x ∈ A" and "x ≠ ⊤" by blast
then obtain B where "A = insert x B" by blast
with ‹⨅A = ⊤› ‹x ≠ ⊤› show False by simp
qed
qed
then show "⊤ = ⨅A ⟷ (∀x∈A. x = ⊤)" by auto
qed

lemma INF_top_conv [simp]:
"(⨅x∈A. B x) = ⊤ ⟷ (∀x∈A. B x = ⊤)"
"⊤ = (⨅x∈A. B x) ⟷ (∀x∈A. B x = ⊤)"
using Inf_top_conv [of "B ` A"] by simp_all

lemma Sup_bot_conv [simp]:
"⨆A = ⊥ ⟷ (∀x∈A. x = ⊥)"
"⊥ = ⨆A ⟷ (∀x∈A. x = ⊥)"
using dual_complete_lattice
by (rule complete_lattice.Inf_top_conv)+

lemma SUP_bot_conv [simp]:
"(⨆x∈A. B x) = ⊥ ⟷ (∀x∈A. B x = ⊥)"
"⊥ = (⨆x∈A. B x) ⟷ (∀x∈A. B x = ⊥)"
using Sup_bot_conv [of "B ` A"] by simp_all

lemma INF_const [simp]: "A ≠ {} ⟹ (⨅i∈A. f) = f"
by (auto intro: antisym INF_lower INF_greatest)

lemma SUP_const [simp]: "A ≠ {} ⟹ (⨆i∈A. f) = f"
by (auto intro: antisym SUP_upper SUP_least)

lemma INF_top [simp]: "(⨅x∈A. ⊤) = ⊤"
by (cases "A = {}") simp_all

lemma SUP_bot [simp]: "(⨆x∈A. ⊥) = ⊥"
by (cases "A = {}") simp_all

lemma INF_commute: "(⨅i∈A. ⨅j∈B. f i j) = (⨅j∈B. ⨅i∈A. f i j)"
by (iprover intro: INF_lower INF_greatest order_trans antisym)

lemma SUP_commute: "(⨆i∈A. ⨆j∈B. f i j) = (⨆j∈B. ⨆i∈A. f i j)"
by (iprover intro: SUP_upper SUP_least order_trans antisym)

lemma INF_absorb:
assumes "k ∈ I"
shows "A k ⊓ (⨅i∈I. A i) = (⨅i∈I. A i)"
proof -
from assms obtain J where "I = insert k J" by blast
then show ?thesis by simp
qed

lemma SUP_absorb:
assumes "k ∈ I"
shows "A k ⊔ (⨆i∈I. A i) = (⨆i∈I. A i)"
proof -
from assms obtain J where "I = insert k J" by blast
then show ?thesis by simp
qed

lemma INF_inf_const1: "I ≠ {} ⟹ (INF i:I. inf x (f i)) = inf x (INF i:I. f i)"
by (intro antisym INF_greatest inf_mono order_refl INF_lower)
(auto intro: INF_lower2 le_infI2 intro!: INF_mono)

lemma INF_inf_const2: "I ≠ {} ⟹ (INF i:I. inf (f i) x) = inf (INF i:I. f i) x"
using INF_inf_const1[of I x f] by (simp add: inf_commute)

lemma INF_constant: "(⨅y∈A. c) = (if A = {} then ⊤ else c)"
by simp

lemma SUP_constant: "(⨆y∈A. c) = (if A = {} then ⊥ else c)"
by simp

lemma less_INF_D:
assumes "y < (⨅i∈A. f i)" "i ∈ A"
shows "y < f i"
proof -
note ‹y < (⨅i∈A. f i)›
also have "(⨅i∈A. f i) ≤ f i" using ‹i ∈ A›
by (rule INF_lower)
finally show "y < f i" .
qed

lemma SUP_lessD:
assumes "(⨆i∈A. f i) < y" "i ∈ A"
shows "f i < y"
proof -
have "f i ≤ (⨆i∈A. f i)"
using ‹i ∈ A› by (rule SUP_upper)
also note ‹(⨆i∈A. f i) < y›
finally show "f i < y" .
qed

lemma INF_UNIV_bool_expand: "(⨅b. A b) = A True ⊓ A False"

lemma SUP_UNIV_bool_expand: "(⨆b. A b) = A True ⊔ A False"

lemma Inf_le_Sup: "A ≠ {} ⟹ Inf A ≤ Sup A"
by (blast intro: Sup_upper2 Inf_lower ex_in_conv)

lemma INF_le_SUP: "A ≠ {} ⟹ INFIMUM A f ≤ SUPREMUM A f"
using Inf_le_Sup [of "f ` A"] by simp

lemma INF_eq_const: "I ≠ {} ⟹ (⋀i. i ∈ I ⟹ f i = x) ⟹ INFIMUM I f = x"
by (auto intro: INF_eqI)

lemma SUP_eq_const: "I ≠ {} ⟹ (⋀i. i ∈ I ⟹ f i = x) ⟹ SUPREMUM I f = x"
by (auto intro: SUP_eqI)

lemma INF_eq_iff: "I ≠ {} ⟹ (⋀i. i ∈ I ⟹ f i ≤ c) ⟹ INFIMUM I f = c ⟷ (∀i∈I. f i = c)"
using INF_eq_const [of I f c] INF_lower [of _ I f]
by (auto intro: antisym cong del: strong_INF_cong)

lemma SUP_eq_iff: "I ≠ {} ⟹ (⋀i. i ∈ I ⟹ c ≤ f i) ⟹ SUPREMUM I f = c ⟷ (∀i∈I. f i = c)"
using SUP_eq_const [of I f c] SUP_upper [of _ I f]
by (auto intro: antisym cong del: strong_SUP_cong)

end

class complete_distrib_lattice = complete_lattice +
assumes sup_Inf: "a ⊔ ⨅B = (⨅b∈B. a ⊔ b)"
and inf_Sup: "a ⊓ ⨆B = (⨆b∈B. a ⊓ b)"
begin

lemma sup_INF: "a ⊔ (⨅b∈B. f b) = (⨅b∈B. a ⊔ f b)"

lemma inf_SUP: "a ⊓ (⨆b∈B. f b) = (⨆b∈B. a ⊓ f b)"

lemma dual_complete_distrib_lattice:
"class.complete_distrib_lattice Sup Inf sup (op ≥) (op >) inf ⊤ ⊥"
apply (rule class.complete_distrib_lattice.intro)
apply (fact dual_complete_lattice)
apply (rule class.complete_distrib_lattice_axioms.intro)
done

subclass distrib_lattice
proof
fix a b c
have "a ⊔ ⨅{b, c} = (⨅d∈{b, c}. a ⊔ d)" by (rule sup_Inf)
then show "a ⊔ b ⊓ c = (a ⊔ b) ⊓ (a ⊔ c)" by simp
qed

lemma Inf_sup: "⨅B ⊔ a = (⨅b∈B. b ⊔ a)"

lemma Sup_inf: "⨆B ⊓ a = (⨆b∈B. b ⊓ a)"

lemma INF_sup: "(⨅b∈B. f b) ⊔ a = (⨅b∈B. f b ⊔ a)"

lemma SUP_inf: "(⨆b∈B. f b) ⊓ a = (⨆b∈B. f b ⊓ a)"

lemma Inf_sup_eq_top_iff: "(⨅B ⊔ a = ⊤) ⟷ (∀b∈B. b ⊔ a = ⊤)"
by (simp only: Inf_sup INF_top_conv)

lemma Sup_inf_eq_bot_iff: "(⨆B ⊓ a = ⊥) ⟷ (∀b∈B. b ⊓ a = ⊥)"
by (simp only: Sup_inf SUP_bot_conv)

lemma INF_sup_distrib2: "(⨅a∈A. f a) ⊔ (⨅b∈B. g b) = (⨅a∈A. ⨅b∈B. f a ⊔ g b)"
by (subst INF_commute) (simp add: sup_INF INF_sup)

lemma SUP_inf_distrib2: "(⨆a∈A. f a) ⊓ (⨆b∈B. g b) = (⨆a∈A. ⨆b∈B. f a ⊓ g b)"
by (subst SUP_commute) (simp add: inf_SUP SUP_inf)

context
fixes f :: "'a ⇒ 'b::complete_lattice"
assumes "mono f"
begin

lemma mono_Inf: "f (⨅A) ≤ (⨅x∈A. f x)"
using ‹mono f› by (auto intro: complete_lattice_class.INF_greatest Inf_lower dest: monoD)

lemma mono_Sup: "(⨆x∈A. f x) ≤ f (⨆A)"
using ‹mono f› by (auto intro: complete_lattice_class.SUP_least Sup_upper dest: monoD)

lemma mono_INF: "f (INF i : I. A i) ≤ (INF x : I. f (A x))"
by (intro complete_lattice_class.INF_greatest monoD[OF ‹mono f›] INF_lower)

lemma mono_SUP: "(SUP x : I. f (A x)) ≤ f (SUP i : I. A i)"
by (intro complete_lattice_class.SUP_least monoD[OF ‹mono f›] SUP_upper)

end

end

class complete_boolean_algebra = boolean_algebra + complete_distrib_lattice
begin

lemma dual_complete_boolean_algebra:
"class.complete_boolean_algebra Sup Inf sup (op ≥) (op >) inf ⊤ ⊥ (λx y. x ⊔ - y) uminus"
by (rule class.complete_boolean_algebra.intro,
rule dual_complete_distrib_lattice,
rule dual_boolean_algebra)

lemma uminus_Inf: "- (⨅A) = ⨆(uminus ` A)"
proof (rule antisym)
show "- ⨅A ≤ ⨆(uminus ` A)"
by (rule compl_le_swap2, rule Inf_greatest, rule compl_le_swap2, rule Sup_upper) simp
show "⨆(uminus ` A) ≤ - ⨅A"
by (rule Sup_least, rule compl_le_swap1, rule Inf_lower) auto
qed

lemma uminus_INF: "- (⨅x∈A. B x) = (⨆x∈A. - B x)"

lemma uminus_Sup: "- (⨆A) = ⨅(uminus ` A)"
proof -
have "⨆A = - ⨅(uminus ` A)"
then show ?thesis by simp
qed

lemma uminus_SUP: "- (⨆x∈A. B x) = (⨅x∈A. - B x)"

end

class complete_linorder = linorder + complete_lattice
begin

lemma dual_complete_linorder:
"class.complete_linorder Sup Inf sup (op ≥) (op >) inf ⊤ ⊥"
by (rule class.complete_linorder.intro, rule dual_complete_lattice, rule dual_linorder)

lemma complete_linorder_inf_min: "inf = min"
by (auto intro: antisym simp add: min_def fun_eq_iff)

lemma complete_linorder_sup_max: "sup = max"
by (auto intro: antisym simp add: max_def fun_eq_iff)

lemma Inf_less_iff: "⨅S < a ⟷ (∃x∈S. x < a)"
by (simp add: not_le [symmetric] le_Inf_iff)

lemma INF_less_iff: "(⨅i∈A. f i) < a ⟷ (∃x∈A. f x < a)"
by (simp add: Inf_less_iff [of "f ` A"])

lemma less_Sup_iff: "a < ⨆S ⟷ (∃x∈S. a < x)"
by (simp add: not_le [symmetric] Sup_le_iff)

lemma less_SUP_iff: "a < (⨆i∈A. f i) ⟷ (∃x∈A. a < f x)"
by (simp add: less_Sup_iff [of _ "f ` A"])

lemma Sup_eq_top_iff [simp]: "⨆A = ⊤ ⟷ (∀x<⊤. ∃i∈A. x < i)"
proof
assume *: "⨆A = ⊤"
show "(∀x<⊤. ∃i∈A. x < i)"
unfolding * [symmetric]
proof (intro allI impI)
fix x
assume "x < ⨆A"
then show "∃i∈A. x < i"
qed
next
assume *: "∀x<⊤. ∃i∈A. x < i"
show "⨆A = ⊤"
proof (rule ccontr)
assume "⨆A ≠ ⊤"
with top_greatest [of "⨆A"] have "⨆A < ⊤"
unfolding le_less by auto
with * have "⨆A < ⨆A"
unfolding less_Sup_iff by auto
then show False by auto
qed
qed

lemma SUP_eq_top_iff [simp]: "(⨆i∈A. f i) = ⊤ ⟷ (∀x<⊤. ∃i∈A. x < f i)"
using Sup_eq_top_iff [of "f ` A"] by simp

lemma Inf_eq_bot_iff [simp]: "⨅A = ⊥ ⟷ (∀x>⊥. ∃i∈A. i < x)"
using dual_complete_linorder
by (rule complete_linorder.Sup_eq_top_iff)

lemma INF_eq_bot_iff [simp]: "(⨅i∈A. f i) = ⊥ ⟷ (∀x>⊥. ∃i∈A. f i < x)"
using Inf_eq_bot_iff [of "f ` A"] by simp

lemma Inf_le_iff: "⨅A ≤ x ⟷ (∀y>x. ∃a∈A. y > a)"
proof safe
fix y
assume "x ≥ ⨅A" "y > x"
then have "y > ⨅A" by auto
then show "∃a∈A. y > a"
unfolding Inf_less_iff .
qed (auto elim!: allE[of _ "⨅A"] simp add: not_le[symmetric] Inf_lower)

lemma INF_le_iff: "INFIMUM A f ≤ x ⟷ (∀y>x. ∃i∈A. y > f i)"
using Inf_le_iff [of "f ` A"] by simp

lemma le_Sup_iff: "x ≤ ⨆A ⟷ (∀y<x. ∃a∈A. y < a)"
proof safe
fix y
assume "x ≤ ⨆A" "y < x"
then have "y < ⨆A" by auto
then show "∃a∈A. y < a"
unfolding less_Sup_iff .
qed (auto elim!: allE[of _ "⨆A"] simp add: not_le[symmetric] Sup_upper)

lemma le_SUP_iff: "x ≤ SUPREMUM A f ⟷ (∀y<x. ∃i∈A. y < f i)"
using le_Sup_iff [of _ "f ` A"] by simp

subclass complete_distrib_lattice
proof
fix a and B
show "a ⊔ ⨅B = (⨅b∈B. a ⊔ b)" and "a ⊓ ⨆B = (⨆b∈B. a ⊓ b)"
by (safe intro!: INF_eqI [symmetric] sup_mono Inf_lower SUP_eqI [symmetric] inf_mono Sup_upper)
(auto simp: not_less [symmetric] Inf_less_iff less_Sup_iff
le_max_iff_disj complete_linorder_sup_max min_le_iff_disj complete_linorder_inf_min)
qed

end

subsection ‹Complete lattice on @{typ bool}›

instantiation bool :: complete_lattice
begin

definition [simp, code]: "⨅A ⟷ False ∉ A"

definition [simp, code]: "⨆A ⟷ True ∈ A"

instance
by standard (auto intro: bool_induct)

end

lemma not_False_in_image_Ball [simp]: "False ∉ P ` A ⟷ Ball A P"
by auto

lemma True_in_image_Bex [simp]: "True ∈ P ` A ⟷ Bex A P"
by auto

lemma INF_bool_eq [simp]: "INFIMUM = Ball"

lemma SUP_bool_eq [simp]: "SUPREMUM = Bex"

instance bool :: complete_boolean_algebra
by standard (auto intro: bool_induct)

subsection ‹Complete lattice on @{typ "_ ⇒ _"}›

instantiation "fun" :: (type, Inf) Inf
begin

definition "⨅A = (λx. ⨅f∈A. f x)"

lemma Inf_apply [simp, code]: "(⨅A) x = (⨅f∈A. f x)"

instance ..

end

instantiation "fun" :: (type, Sup) Sup
begin

definition "⨆A = (λx. ⨆f∈A. f x)"

lemma Sup_apply [simp, code]: "(⨆A) x = (⨆f∈A. f x)"

instance ..

end

instantiation "fun" :: (type, complete_lattice) complete_lattice
begin

instance
by standard (auto simp add: le_fun_def intro: INF_lower INF_greatest SUP_upper SUP_least)

end

lemma INF_apply [simp]: "(⨅y∈A. f y) x = (⨅y∈A. f y x)"
using Inf_apply [of "f ` A"] by (simp add: comp_def)

lemma SUP_apply [simp]: "(⨆y∈A. f y) x = (⨆y∈A. f y x)"
using Sup_apply [of "f ` A"] by (simp add: comp_def)

instance "fun" :: (type, complete_distrib_lattice) complete_distrib_lattice
by standard (auto simp add: inf_Sup sup_Inf fun_eq_iff image_image)

instance "fun" :: (type, complete_boolean_algebra) complete_boolean_algebra ..

subsection ‹Complete lattice on unary and binary predicates›

lemma Inf1_I: "(⋀P. P ∈ A ⟹ P a) ⟹ (⨅A) a"
by auto

lemma INF1_I: "(⋀x. x ∈ A ⟹ B x b) ⟹ (⨅x∈A. B x) b"
by simp

lemma INF2_I: "(⋀x. x ∈ A ⟹ B x b c) ⟹ (⨅x∈A. B x) b c"
by simp

lemma Inf2_I: "(⋀r. r ∈ A ⟹ r a b) ⟹ (⨅A) a b"
by auto

lemma Inf1_D: "(⨅A) a ⟹ P ∈ A ⟹ P a"
by auto

lemma INF1_D: "(⨅x∈A. B x) b ⟹ a ∈ A ⟹ B a b"
by simp

lemma Inf2_D: "(⨅A) a b ⟹ r ∈ A ⟹ r a b"
by auto

lemma INF2_D: "(⨅x∈A. B x) b c ⟹ a ∈ A ⟹ B a b c"
by simp

lemma Inf1_E:
assumes "(⨅A) a"
obtains "P a" | "P ∉ A"
using assms by auto

lemma INF1_E:
assumes "(⨅x∈A. B x) b"
obtains "B a b" | "a ∉ A"
using assms by auto

lemma Inf2_E:
assumes "(⨅A) a b"
obtains "r a b" | "r ∉ A"
using assms by auto

lemma INF2_E:
assumes "(⨅x∈A. B x) b c"
obtains "B a b c" | "a ∉ A"
using assms by auto

lemma Sup1_I: "P ∈ A ⟹ P a ⟹ (⨆A) a"
by auto

lemma SUP1_I: "a ∈ A ⟹ B a b ⟹ (⨆x∈A. B x) b"
by auto

lemma Sup2_I: "r ∈ A ⟹ r a b ⟹ (⨆A) a b"
by auto

lemma SUP2_I: "a ∈ A ⟹ B a b c ⟹ (⨆x∈A. B x) b c"
by auto

lemma Sup1_E:
assumes "(⨆A) a"
obtains P where "P ∈ A" and "P a"
using assms by auto

lemma SUP1_E:
assumes "(⨆x∈A. B x) b"
obtains x where "x ∈ A" and "B x b"
using assms by auto

lemma Sup2_E:
assumes "(⨆A) a b"
obtains r where "r ∈ A" "r a b"
using assms by auto

lemma SUP2_E:
assumes "(⨆x∈A. B x) b c"
obtains x where "x ∈ A" "B x b c"
using assms by auto

subsection ‹Complete lattice on @{typ "_ set"}›

instantiation "set" :: (type) complete_lattice
begin

definition "⨅A = {x. ⨅((λB. x ∈ B) ` A)}"

definition "⨆A = {x. ⨆((λB. x ∈ B) ` A)}"

instance
by standard (auto simp add: less_eq_set_def Inf_set_def Sup_set_def le_fun_def)

end

instance "set" :: (type) complete_boolean_algebra
by standard (auto simp add: Inf_set_def Sup_set_def image_def)

subsubsection ‹Inter›

abbreviation Inter :: "'a set set ⇒ 'a set"  ("⋂_" [900] 900)
where "⋂S ≡ ⨅S"

lemma Inter_eq: "⋂A = {x. ∀B ∈ A. x ∈ B}"
proof (rule set_eqI)
fix x
have "(∀Q∈{P. ∃B∈A. P ⟷ x ∈ B}. Q) ⟷ (∀B∈A. x ∈ B)"
by auto
then show "x ∈ ⋂A ⟷ x ∈ {x. ∀B ∈ A. x ∈ B}"
qed

lemma Inter_iff [simp]: "A ∈ ⋂C ⟷ (∀X∈C. A ∈ X)"
by (unfold Inter_eq) blast

lemma InterI [intro!]: "(⋀X. X ∈ C ⟹ A ∈ X) ⟹ A ∈ ⋂C"

text ‹
┉ A ``destruct'' rule -- every @{term X} in @{term C}
contains @{term A} as an element, but @{prop "A ∈ X"} can hold when
@{prop "X ∈ C"} does not!  This rule is analogous to ‹spec›.
›

lemma InterD [elim, Pure.elim]: "A ∈ ⋂C ⟹ X ∈ C ⟹ A ∈ X"
by auto

lemma InterE [elim]: "A ∈ ⋂C ⟹ (X ∉ C ⟹ R) ⟹ (A ∈ X ⟹ R) ⟹ R"
― ‹``Classical'' elimination rule -- does not require proving
@{prop "X ∈ C"}.›
unfolding Inter_eq by blast

lemma Inter_lower: "B ∈ A ⟹ ⋂A ⊆ B"
by (fact Inf_lower)

lemma Inter_subset: "(⋀X. X ∈ A ⟹ X ⊆ B) ⟹ A ≠ {} ⟹ ⋂A ⊆ B"
by (fact Inf_less_eq)

lemma Inter_greatest: "(⋀X. X ∈ A ⟹ C ⊆ X) ⟹ C ⊆ ⋂A"
by (fact Inf_greatest)

lemma Inter_empty: "⋂{} = UNIV"
by (fact Inf_empty) (* already simp *)

lemma Inter_UNIV: "⋂UNIV = {}"
by (fact Inf_UNIV) (* already simp *)

lemma Inter_insert: "⋂(insert a B) = a ∩ ⋂B"
by (fact Inf_insert) (* already simp *)

lemma Inter_Un_subset: "⋂A ∪ ⋂B ⊆ ⋂(A ∩ B)"
by (fact less_eq_Inf_inter)

lemma Inter_Un_distrib: "⋂(A ∪ B) = ⋂A ∩ ⋂B"
by (fact Inf_union_distrib)

lemma Inter_UNIV_conv [simp]:
"⋂A = UNIV ⟷ (∀x∈A. x = UNIV)"
"UNIV = ⋂A ⟷ (∀x∈A. x = UNIV)"
by (fact Inf_top_conv)+

lemma Inter_anti_mono: "B ⊆ A ⟹ ⋂A ⊆ ⋂B"
by (fact Inf_superset_mono)

subsubsection ‹Intersections of families›

abbreviation INTER :: "'a set ⇒ ('a ⇒ 'b set) ⇒ 'b set"
where "INTER ≡ INFIMUM"

text ‹
Note: must use name @{const INTER} here instead of ‹INT›
to allow the following syntax coexist with the plain constant name.
›

syntax (ASCII)
"_INTER1"     :: "pttrns ⇒ 'b set ⇒ 'b set"           ("(3INT _./ _)" [0, 10] 10)
"_INTER"      :: "pttrn ⇒ 'a set ⇒ 'b set ⇒ 'b set"  ("(3INT _:_./ _)" [0, 0, 10] 10)

syntax (latex output)
"_INTER1"     :: "pttrns ⇒ 'b set ⇒ 'b set"           ("(3⋂(‹unbreakable›⇘_⇙)/ _)" [0, 10] 10)
"_INTER"      :: "pttrn ⇒ 'a set ⇒ 'b set ⇒ 'b set"  ("(3⋂(‹unbreakable›⇘_∈_⇙)/ _)" [0, 0, 10] 10)

syntax
"_INTER1"     :: "pttrns ⇒ 'b set ⇒ 'b set"           ("(3⋂_./ _)" [0, 10] 10)
"_INTER"      :: "pttrn ⇒ 'a set ⇒ 'b set ⇒ 'b set"  ("(3⋂_∈_./ _)" [0, 0, 10] 10)

translations
"⋂x y. B"  ⇌ "⋂x. ⋂y. B"
"⋂x. B"    ⇌ "CONST INTER CONST UNIV (λx. B)"
"⋂x. B"    ⇌ "⋂x ∈ CONST UNIV. B"
"⋂x∈A. B"  ⇌ "CONST INTER A (λx. B)"

print_translation ‹
[Syntax_Trans.preserve_binder_abs2_tr' @{const_syntax INTER} @{syntax_const "_INTER"}]
› ― ‹to avoid eta-contraction of body›

lemma INTER_eq: "(⋂x∈A. B x) = {y. ∀x∈A. y ∈ B x}"
by (auto intro!: INF_eqI)

lemma INT_iff [simp]: "b ∈ (⋂x∈A. B x) ⟷ (∀x∈A. b ∈ B x)"
using Inter_iff [of _ "B ` A"] by simp

lemma INT_I [intro!]: "(⋀x. x ∈ A ⟹ b ∈ B x) ⟹ b ∈ (⋂x∈A. B x)"
by auto

lemma INT_D [elim, Pure.elim]: "b ∈ (⋂x∈A. B x) ⟹ a ∈ A ⟹ b ∈ B a"
by auto

lemma INT_E [elim]: "b ∈ (⋂x∈A. B x) ⟹ (b ∈ B a ⟹ R) ⟹ (a ∉ A ⟹ R) ⟹ R"
― ‹"Classical" elimination -- by the Excluded Middle on @{prop "a∈A"}.›
by auto

lemma Collect_ball_eq: "{x. ∀y∈A. P x y} = (⋂y∈A. {x. P x y})"
by blast

lemma Collect_all_eq: "{x. ∀y. P x y} = (⋂y. {x. P x y})"
by blast

lemma INT_lower: "a ∈ A ⟹ (⋂x∈A. B x) ⊆ B a"
by (fact INF_lower)

lemma INT_greatest: "(⋀x. x ∈ A ⟹ C ⊆ B x) ⟹ C ⊆ (⋂x∈A. B x)"
by (fact INF_greatest)

lemma INT_empty: "(⋂x∈{}. B x) = UNIV"
by (fact INF_empty)

lemma INT_absorb: "k ∈ I ⟹ A k ∩ (⋂i∈I. A i) = (⋂i∈I. A i)"
by (fact INF_absorb)

lemma INT_subset_iff: "B ⊆ (⋂i∈I. A i) ⟷ (∀i∈I. B ⊆ A i)"
by (fact le_INF_iff)

lemma INT_insert [simp]: "(⋂x ∈ insert a A. B x) = B a ∩ INTER A B"
by (fact INF_insert)

lemma INT_Un: "(⋂i ∈ A ∪ B. M i) = (⋂i ∈ A. M i) ∩ (⋂i∈B. M i)"
by (fact INF_union)

lemma INT_insert_distrib: "u ∈ A ⟹ (⋂x∈A. insert a (B x)) = insert a (⋂x∈A. B x)"
by blast

lemma INT_constant [simp]: "(⋂y∈A. c) = (if A = {} then UNIV else c)"
by (fact INF_constant)

lemma INTER_UNIV_conv:
"(UNIV = (⋂x∈A. B x)) = (∀x∈A. B x = UNIV)"
"((⋂x∈A. B x) = UNIV) = (∀x∈A. B x = UNIV)"
by (fact INF_top_conv)+ (* already simp *)

lemma INT_bool_eq: "(⋂b. A b) = A True ∩ A False"
by (fact INF_UNIV_bool_expand)

lemma INT_anti_mono: "A ⊆ B ⟹ (⋀x. x ∈ A ⟹ f x ⊆ g x) ⟹ (⋂x∈B. f x) ⊆ (⋂x∈A. g x)"
― ‹The last inclusion is POSITIVE!›
by (fact INF_superset_mono)

lemma Pow_INT_eq: "Pow (⋂x∈A. B x) = (⋂x∈A. Pow (B x))"
by blast

lemma vimage_INT: "f -` (⋂x∈A. B x) = (⋂x∈A. f -` B x)"
by blast

subsubsection ‹Union›

abbreviation Union :: "'a set set ⇒ 'a set"  ("⋃_" [900] 900)
where "⋃S ≡ ⨆S"

lemma Union_eq: "⋃A = {x. ∃B ∈ A. x ∈ B}"
proof (rule set_eqI)
fix x
have "(∃Q∈{P. ∃B∈A. P ⟷ x ∈ B}. Q) ⟷ (∃B∈A. x ∈ B)"
by auto
then show "x ∈ ⋃A ⟷ x ∈ {x. ∃B∈A. x ∈ B}"
qed

lemma Union_iff [simp]: "A ∈ ⋃C ⟷ (∃X∈C. A∈X)"
by (unfold Union_eq) blast

lemma UnionI [intro]: "X ∈ C ⟹ A ∈ X ⟹ A ∈ ⋃C"
― ‹The order of the premises presupposes that @{term C} is rigid;
@{term A} may be flexible.›
by auto

lemma UnionE [elim!]: "A ∈ ⋃C ⟹ (⋀X. A ∈ X ⟹ X ∈ C ⟹ R) ⟹ R"
by auto

lemma Union_upper: "B ∈ A ⟹ B ⊆ ⋃A"
by (fact Sup_upper)

lemma Union_least: "(⋀X. X ∈ A ⟹ X ⊆ C) ⟹ ⋃A ⊆ C"
by (fact Sup_least)

lemma Union_empty: "⋃{} = {}"
by (fact Sup_empty) (* already simp *)

lemma Union_UNIV: "⋃UNIV = UNIV"
by (fact Sup_UNIV) (* already simp *)

lemma Union_insert: "⋃insert a B = a ∪ ⋃B"
by (fact Sup_insert) (* already simp *)

lemma Union_Un_distrib [simp]: "⋃(A ∪ B) = ⋃A ∪ ⋃B"
by (fact Sup_union_distrib)

lemma Union_Int_subset: "⋃(A ∩ B) ⊆ ⋃A ∩ ⋃B"
by (fact Sup_inter_less_eq)

lemma Union_empty_conv: "(⋃A = {}) ⟷ (∀x∈A. x = {})"
by (fact Sup_bot_conv) (* already simp *)

lemma empty_Union_conv: "({} = ⋃A) ⟷ (∀x∈A. x = {})"
by (fact Sup_bot_conv) (* already simp *)

lemma subset_Pow_Union: "A ⊆ Pow (⋃A)"
by blast

lemma Union_Pow_eq [simp]: "⋃(Pow A) = A"
by blast

lemma Union_mono: "A ⊆ B ⟹ ⋃A ⊆ ⋃B"
by (fact Sup_subset_mono)

lemma Union_subsetI: "(⋀x. x ∈ A ⟹ ∃y. y ∈ B ∧ x ⊆ y) ⟹ ⋃A ⊆ ⋃B"
by blast

lemma disjnt_inj_on_iff:
"⟦inj_on f (⋃𝒜); X ∈ 𝒜; Y ∈ 𝒜⟧ ⟹ disjnt (f ` X) (f ` Y) ⟷ disjnt X Y"
apply (auto simp: disjnt_def)
using inj_on_eq_iff by fastforce

subsubsection ‹Unions of families›

abbreviation UNION :: "'a set ⇒ ('a ⇒ 'b set) ⇒ 'b set"
where "UNION ≡ SUPREMUM"

text ‹
Note: must use name @{const UNION} here instead of ‹UN›
to allow the following syntax coexist with the plain constant name.
›

syntax (ASCII)
"_UNION1"     :: "pttrns => 'b set => 'b set"           ("(3UN _./ _)" [0, 10] 10)
"_UNION"      :: "pttrn => 'a set => 'b set => 'b set"  ("(3UN _:_./ _)" [0, 0, 10] 10)

syntax (latex output)
"_UNION1"     :: "pttrns => 'b set => 'b set"           ("(3⋃(‹unbreakable›⇘_⇙)/ _)" [0, 10] 10)
"_UNION"      :: "pttrn => 'a set => 'b set => 'b set"  ("(3⋃(‹unbreakable›⇘_∈_⇙)/ _)" [0, 0, 10] 10)

syntax
"_UNION1"     :: "pttrns => 'b set => 'b set"           ("(3⋃_./ _)" [0, 10] 10)
"_UNION"      :: "pttrn => 'a set => 'b set => 'b set"  ("(3⋃_∈_./ _)" [0, 0, 10] 10)

translations
"⋃x y. B"   ⇌ "⋃x. ⋃y. B"
"⋃x. B"     ⇌ "CONST UNION CONST UNIV (λx. B)"
"⋃x. B"     ⇌ "⋃x ∈ CONST UNIV. B"
"⋃x∈A. B"   ⇌ "CONST UNION A (λx. B)"

text ‹
Note the difference between ordinary syntax of indexed
unions and intersections (e.g.\ ‹⋃a⇩1∈A⇩1. B›)
and their \LaTeX\ rendition: @{term"⋃a⇩1∈A⇩1. B"}.
›

print_translation ‹
[Syntax_Trans.preserve_binder_abs2_tr' @{const_syntax UNION} @{syntax_const "_UNION"}]
› ― ‹to avoid eta-contraction of body›

lemma UNION_eq: "(⋃x∈A. B x) = {y. ∃x∈A. y ∈ B x}"
by (auto intro!: SUP_eqI)

lemma bind_UNION [code]: "Set.bind A f = UNION A f"

lemma member_bind [simp]: "x ∈ Set.bind P f ⟷ x ∈ UNION P f "

lemma Union_SetCompr_eq: "⋃{f x| x. P x} = {a. ∃x. P x ∧ a ∈ f x}"
by blast

lemma UN_iff [simp]: "b ∈ (⋃x∈A. B x) ⟷ (∃x∈A. b ∈ B x)"
using Union_iff [of _ "B ` A"] by simp

lemma UN_I [intro]: "a ∈ A ⟹ b ∈ B a ⟹ b ∈ (⋃x∈A. B x)"
― ‹The order of the premises presupposes that @{term A} is rigid;
@{term b} may be flexible.›
by auto

lemma UN_E [elim!]: "b ∈ (⋃x∈A. B x) ⟹ (⋀x. x∈A ⟹ b ∈ B x ⟹ R) ⟹ R"
by auto

lemma UN_upper: "a ∈ A ⟹ B a ⊆ (⋃x∈A. B x)"
by (fact SUP_upper)

lemma UN_least: "(⋀x. x ∈ A ⟹ B x ⊆ C) ⟹ (⋃x∈A. B x) ⊆ C"
by (fact SUP_least)

lemma Collect_bex_eq: "{x. ∃y∈A. P x y} = (⋃y∈A. {x. P x y})"
by blast

lemma UN_insert_distrib: "u ∈ A ⟹ (⋃x∈A. insert a (B x)) = insert a (⋃x∈A. B x)"
by blast

lemma UN_empty: "(⋃x∈{}. B x) = {}"
by (fact SUP_empty)

lemma UN_empty2: "(⋃x∈A. {}) = {}"
by (fact SUP_bot) (* already simp *)

lemma UN_absorb: "k ∈ I ⟹ A k ∪ (⋃i∈I. A i) = (⋃i∈I. A i)"
by (fact SUP_absorb)

lemma UN_insert [simp]: "(⋃x∈insert a A. B x) = B a ∪ UNION A B"
by (fact SUP_insert)

lemma UN_Un [simp]: "(⋃i ∈ A ∪ B. M i) = (⋃i∈A. M i) ∪ (⋃i∈B. M i)"
by (fact SUP_union)

lemma UN_UN_flatten: "(⋃x ∈ (⋃y∈A. B y). C x) = (⋃y∈A. ⋃x∈B y. C x)"
by blast

lemma UN_subset_iff: "((⋃i∈I. A i) ⊆ B) = (∀i∈I. A i ⊆ B)"
by (fact SUP_le_iff)

lemma UN_constant [simp]: "(⋃y∈A. c) = (if A = {} then {} else c)"
by (fact SUP_constant)

lemma image_Union: "f ` ⋃S = (⋃x∈S. f ` x)"
by blast

lemma UNION_empty_conv:
"{} = (⋃x∈A. B x) ⟷ (∀x∈A. B x = {})"
"(⋃x∈A. B x) = {} ⟷ (∀x∈A. B x = {})"
by (fact SUP_bot_conv)+ (* already simp *)

lemma Collect_ex_eq: "{x. ∃y. P x y} = (⋃y. {x. P x y})"
by blast

lemma ball_UN: "(∀z ∈ UNION A B. P z) ⟷ (∀x∈A. ∀z ∈ B x. P z)"
by blast

lemma bex_UN: "(∃z ∈ UNION A B. P z) ⟷ (∃x∈A. ∃z∈B x. P z)"
by blast

lemma Un_eq_UN: "A ∪ B = (⋃b. if b then A else B)"
by safe (auto simp add: if_split_mem2)

lemma UN_bool_eq: "(⋃b. A b) = (A True ∪ A False)"
by (fact SUP_UNIV_bool_expand)

lemma UN_Pow_subset: "(⋃x∈A. Pow (B x)) ⊆ Pow (⋃x∈A. B x)"
by blast

lemma UN_mono:
"A ⊆ B ⟹ (⋀x. x ∈ A ⟹ f x ⊆ g x) ⟹
(⋃x∈A. f x) ⊆ (⋃x∈B. g x)"
by (fact SUP_subset_mono)

lemma vimage_Union: "f -` (⋃A) = (⋃X∈A. f -` X)"
by blast

lemma vimage_UN: "f -` (⋃x∈A. B x) = (⋃x∈A. f -` B x)"
by blast

lemma vimage_eq_UN: "f -` B = (⋃y∈B. f -` {y})"
― ‹NOT suitable for rewriting›
by blast

lemma image_UN: "f ` UNION A B = (⋃x∈A. f ` B x)"
by blast

lemma UN_singleton [simp]: "(⋃x∈A. {x}) = A"
by blast

lemma inj_on_image: "inj_on f (⋃A) ⟹ inj_on (op ` f) A"
unfolding inj_on_def by blast

subsubsection ‹Distributive laws›

lemma Int_Union: "A ∩ ⋃B = (⋃C∈B. A ∩ C)"
by (fact inf_Sup)

lemma Un_Inter: "A ∪ ⋂B = (⋂C∈B. A ∪ C)"
by (fact sup_Inf)

lemma Int_Union2: "⋃B ∩ A = (⋃C∈B. C ∩ A)"
by (fact Sup_inf)

lemma INT_Int_distrib: "(⋂i∈I. A i ∩ B i) = (⋂i∈I. A i) ∩ (⋂i∈I. B i)"
by (rule sym) (rule INF_inf_distrib)

lemma UN_Un_distrib: "(⋃i∈I. A i ∪ B i) = (⋃i∈I. A i) ∪ (⋃i∈I. B i)"
by (rule sym) (rule SUP_sup_distrib)

lemma Int_Inter_image: "(⋂x∈C. A x ∩ B x) = ⋂(A ` C) ∩ ⋂(B ` C)"  (* FIXME drop *)

lemma Un_Union_image: "(⋃x∈C. A x ∪ B x) = ⋃(A ` C) ∪ ⋃(B ` C)"  (* FIXME drop *)
― ‹Devlin, Fundamentals of Contemporary Set Theory, page 12, exercise 5:›
― ‹Union of a family of unions›

lemma Un_INT_distrib: "B ∪ (⋂i∈I. A i) = (⋂i∈I. B ∪ A i)"
by (fact sup_INF)

lemma Int_UN_distrib: "B ∩ (⋃i∈I. A i) = (⋃i∈I. B ∩ A i)"
― ‹Halmos, Naive Set Theory, page 35.›
by (fact inf_SUP)

lemma Int_UN_distrib2: "(⋃i∈I. A i) ∩ (⋃j∈J. B j) = (⋃i∈I. ⋃j∈J. A i ∩ B j)"
by (fact SUP_inf_distrib2)

lemma Un_INT_distrib2: "(⋂i∈I. A i) ∪ (⋂j∈J. B j) = (⋂i∈I. ⋂j∈J. A i ∪ B j)"
by (fact INF_sup_distrib2)

lemma Union_disjoint: "(⋃C ∩ A = {}) ⟷ (∀B∈C. B ∩ A = {})"
by (fact Sup_inf_eq_bot_iff)

lemma SUP_UNION: "(SUP x:(UN y:A. g y). f x) = (SUP y:A. SUP x:g y. f x :: _ :: complete_lattice)"
by (rule order_antisym) (blast intro: SUP_least SUP_upper2)+

subsection ‹Injections and bijections›

lemma inj_on_Inter: "S ≠ {} ⟹ (⋀A. A ∈ S ⟹ inj_on f A) ⟹ inj_on f (⋂S)"
unfolding inj_on_def by blast

lemma inj_on_INTER: "I ≠ {} ⟹ (⋀i. i ∈ I ⟹ inj_on f (A i)) ⟹ inj_on f (⋂i ∈ I. A i)"
unfolding inj_on_def by safe simp

lemma inj_on_UNION_chain:
assumes chain: "⋀i j. i ∈ I ⟹ j ∈ I ⟹ A i ≤ A j ∨ A j ≤ A i"
and inj: "⋀i. i ∈ I ⟹ inj_on f (A i)"
shows "inj_on f (⋃i ∈ I. A i)"
proof -
have "x = y"
if *: "i ∈ I" "j ∈ I"
and **: "x ∈ A i" "y ∈ A j"
and ***: "f x = f y"
for i j x y
using chain [OF *]
proof
assume "A i ≤ A j"
with ** have "x ∈ A j" by auto
with inj * ** *** show ?thesis
next
assume "A j ≤ A i"
with ** have "y ∈ A i" by auto
with inj * ** *** show ?thesis
qed
then show ?thesis
by (unfold inj_on_def UNION_eq) auto
qed

lemma bij_betw_UNION_chain:
assumes chain: "⋀i j. i ∈ I ⟹ j ∈ I ⟹ A i ≤ A j ∨ A j ≤ A i"
and bij: "⋀i. i ∈ I ⟹ bij_betw f (A i) (A' i)"
shows "bij_betw f (⋃i ∈ I. A i) (⋃i ∈ I. A' i)"
unfolding bij_betw_def
proof safe
have "⋀i. i ∈ I ⟹ inj_on f (A i)"
using bij bij_betw_def[of f] by auto
then show "inj_on f (UNION I A)"
using chain inj_on_UNION_chain[of I A f] by auto
next
fix i x
assume *: "i ∈ I" "x ∈ A i"
with bij have "f x ∈ A' i"
by (auto simp: bij_betw_def)
with * show "f x ∈ UNION I A'" by blast
next
fix i x'
assume *: "i ∈ I" "x' ∈ A' i"
with bij have "∃x ∈ A i. x' = f x"
unfolding bij_betw_def by blast
with * have "∃j ∈ I. ∃x ∈ A j. x' = f x"
by blast
then show "x' ∈ f ` UNION I A"
by blast
qed

(*injectivity's required.  Left-to-right inclusion holds even if A is empty*)
lemma image_INT: "inj_on f C ⟹ ∀x∈A. B x ⊆ C ⟹ j ∈ A ⟹ f ` (INTER A B) = (INT x:A. f ` B x)"
by (auto simp add: inj_on_def) blast

lemma bij_image_INT: "bij f ⟹ f ` (INTER A B) = (INT x:A. f ` B x)"
by (auto simp: bij_def inj_def surj_def) blast

lemma UNION_fun_upd: "UNION J (A(i := B)) = UNION (J - {i}) A ∪ (if i ∈ J then B else {})"

lemma bij_betw_Pow:
assumes "bij_betw f A B"
shows "bij_betw (image f) (Pow A) (Pow B)"
proof -
from assms have "inj_on f A"
by (rule bij_betw_imp_inj_on)
then have "inj_on f (⋃Pow A)"
by simp
then have "inj_on (image f) (Pow A)"
by (rule inj_on_image)
then have "bij_betw (image f) (Pow A) (image f ` Pow A)"
by (rule inj_on_imp_bij_betw)
moreover from assms have "f ` A = B"
by (rule bij_betw_imp_surj_on)
then have "image f ` Pow A = Pow B"
by (rule image_Pow_surj)
ultimately show ?thesis by simp
qed

subsubsection ‹Complement›

lemma Compl_INT [simp]: "- (⋂x∈A. B x) = (⋃x∈A. -B x)"
by (fact uminus_INF)

lemma Compl_UN [simp]: "- (⋃x∈A. B x) = (⋂x∈A. -B x)"
by (fact uminus_SUP)

subsubsection ‹Miniscoping and maxiscoping›

text ‹┉ Miniscoping: pushing in quantifiers and big Unions and Intersections.›

lemma UN_simps [simp]:
"⋀a B C. (⋃x∈C. insert a (B x)) = (if C={} then {} else insert a (⋃x∈C. B x))"
"⋀A B C. (⋃x∈C. A x ∪ B) = ((if C={} then {} else (⋃x∈C. A x) ∪ B))"
"⋀A B C. (⋃x∈C. A ∪ B x) = ((if C={} then {} else A ∪ (⋃x∈C. B x)))"
"⋀A B C. (⋃x∈C. A x ∩ B) = ((⋃x∈C. A x) ∩ B)"
"⋀A B C. (⋃x∈C. A ∩ B x) = (A ∩(⋃x∈C. B x))"
"⋀A B C. (⋃x∈C. A x - B) = ((⋃x∈C. A x) - B)"
"⋀A B C. (⋃x∈C. A - B x) = (A - (⋂x∈C. B x))"
"⋀A B. (⋃x∈⋃A. B x) = (⋃y∈A. ⋃x∈y. B x)"
"⋀A B C. (⋃z∈UNION A B. C z) = (⋃x∈A. ⋃z∈B x. C z)"
"⋀A B f. (⋃x∈f`A. B x) = (⋃a∈A. B (f a))"
by auto

lemma INT_simps [simp]:
"⋀A B C. (⋂x∈C. A x ∩ B) = (if C={} then UNIV else (⋂x∈C. A x) ∩ B)"
"⋀A B C. (⋂x∈C. A ∩ B x) = (if C={} then UNIV else A ∩(⋂x∈C. B x))"
"⋀A B C. (⋂x∈C. A x - B) = (if C={} then UNIV else (⋂x∈C. A x) - B)"
"⋀A B C. (⋂x∈C. A - B x) = (if C={} then UNIV else A - (⋃x∈C. B x))"
"⋀a B C. (⋂x∈C. insert a (B x)) = insert a (⋂x∈C. B x)"
"⋀A B C. (⋂x∈C. A x ∪ B) = ((⋂x∈C. A x) ∪ B)"
"⋀A B C. (⋂x∈C. A ∪ B x) = (A ∪ (⋂x∈C. B x))"
"⋀A B. (⋂x∈⋃A. B x) = (⋂y∈A. ⋂x∈y. B x)"
"⋀A B C. (⋂z∈UNION A B. C z) = (⋂x∈A. ⋂z∈B x. C z)"
"⋀A B f. (⋂x∈f`A. B x) = (⋂a∈A. B (f a))"
by auto

lemma UN_ball_bex_simps [simp]:
"⋀A P. (∀x∈⋃A. P x) ⟷ (∀y∈A. ∀x∈y. P x)"
"⋀A B P. (∀x∈UNION A B. P x) = (∀a∈A. ∀x∈ B a. P x)"
"⋀A P. (∃x∈⋃A. P x) ⟷ (∃y∈A. ∃x∈y. P x)"
"⋀A B P. (∃x∈UNION A B. P x) ⟷ (∃a∈A. ∃x∈B a. P x)"
by auto

text ‹┉ Maxiscoping: pulling out big Unions and Intersections.›

lemma UN_extend_simps:
"⋀a B C. insert a (⋃x∈C. B x) = (if C={} then {a} else (⋃x∈C. insert a (B x)))"
"⋀A B C. (⋃x∈C. A x) ∪ B = (if C={} then B else (⋃x∈C. A x ∪ B))"
"⋀A B C. A ∪ (⋃x∈C. B x) = (if C={} then A else (⋃x∈C. A ∪ B x))"
"⋀A B C. ((⋃x∈C. A x) ∩ B) = (⋃x∈C. A x ∩ B)"
"⋀A B C. (A ∩ (⋃x∈C. B x)) = (⋃x∈C. A ∩ B x)"
"⋀A B C. ((⋃x∈C. A x) - B) = (⋃x∈C. A x - B)"
"⋀A B C. (A - (⋂x∈C. B x)) = (⋃x∈C. A - B x)"
"⋀A B. (⋃y∈A. ⋃x∈y. B x) = (⋃x∈⋃A. B x)"
"⋀A B C. (⋃x∈A. ⋃z∈B x. C z) = (⋃z∈UNION A B. C z)"
"⋀A B f. (⋃a∈A. B (f a)) = (⋃x∈f`A. B x)"
by auto

lemma INT_extend_simps:
"⋀A B C. (⋂x∈C. A x) ∩ B = (if C={} then B else (⋂x∈C. A x ∩ B))"
"⋀A B C. A ∩ (⋂x∈C. B x) = (if C={} then A else (⋂x∈C. A ∩ B x))"
"⋀A B C. (⋂x∈C. A x) - B = (if C={} then UNIV - B else (⋂x∈C. A x - B))"
"⋀A B C. A - (⋃x∈C. B x) = (if C={} then A else (⋂x∈C. A - B x))"
"⋀a B C. insert a (⋂x∈C. B x) = (⋂x∈C. insert a (B x))"
"⋀A B C. ((⋂x∈C. A x) ∪ B) = (⋂x∈C. A x ∪ B)"
"⋀A B C. A ∪ (⋂x∈C. B x) = (⋂x∈C. A ∪ B x)"
"⋀A B. (⋂y∈A. ⋂x∈y. B x) = (⋂x∈⋃A. B x)"
"⋀A B C. (⋂x∈A. ⋂z∈B x. C z) = (⋂z∈UNION A B. C z)"
"⋀A B f. (⋂a∈A. B (f a)) = (⋂x∈f`A. B x)"
by auto

text ‹Finally›

lemmas mem_simps =
insert_iff empty_iff Un_iff Int_iff Compl_iff Diff_iff
mem_Collect_eq UN_iff Union_iff INT_iff Inter_iff