Theory Heyting

(*<*)
theory Heyting
imports
  Closures
begin

(*>*)
section‹ Heyting algebras \label{sec:heyting_algebras} ›

text‹

Our (complete) lattices are Heyting algebras. The following development is oriented towards
using the derived Heyting implication in a logical fashion. As there are no standard classes for
semi-(complete-)lattices we simply work with complete lattices.

References:
  citet"Esakia:2019" -- fundamental theory
  citet‹Lemma 5.2.1› in "vanDalen:2004" -- some equivalences
  🌐‹https://en.wikipedia.org/wiki/Pseudocomplement› -- properties

›

class heyting_algebra = complete_lattice +
  assumes inf_Sup_distrib1: "Y::'a set. x::'a. x  (Y) = (yY. x  y)"
begin

definition heyting :: "'a  'a  'a" (infixr H 53) where
  "x H y = {z. x  z  y}"

lemma heyting: ―‹ The Galois property for (⊓)› and H
  shows "z  x H y  z  x  y" (is "?lhs  ?rhs")
proof(rule iffI)
  from inf_Sup_distrib1 have "{a. x  a  y}  x  y" by (simp add: SUP_le_iff inf_commute)
  then show "?lhs  ?rhs" unfolding heyting_def by (meson inf_mono order.trans order_refl)
  show "?rhs  ?lhs" by (simp add: heyting_def Sup_upper inf.commute)
qed

end

setup Sign.mandatory_path "heyting"

context heyting_algebra
begin

lemma commute:
  shows "x  z  y  z  (x H y)"
by (simp add: heyting inf.commute)

lemmas uncurry = iffD1[OF heyting]
lemmas curry = iffD2[OF heyting]

lemma curry_conv:
  shows "(x  y H z) = (x H y H z)"
by (simp add: order_eq_iff) (metis heyting eq_refl inf.assoc)

lemma swap:
  shows "P H Q H R = Q H P H R"
by (metis curry_conv inf.commute)

lemma absorb:
  shows "y  (x H y) = y"
    and "(x H y)  y = y"
by (simp_all add: curry inf_absorb1 ac_simps)

lemma detachment:
  shows "x  (x H y) = x  y" (is ?thesis1)
    and "(x H y)  x = x  y" (is ?thesis2)
proof -
  show ?thesis1 by (metis absorb(1) uncurry inf.assoc inf.commute inf.idem inf_iff_le(2))
  then show ?thesis2 by (simp add: ac_simps)
qed

lemma discharge:
  assumes "x'  x"
  shows "x'  (x H y) = x'  y" (is ?thesis1)
    and "(x H y)  x' = y  x'" (is ?thesis2)
proof -
  from assms show ?thesis1 by (metis curry_conv detachment(2) inf.absorb1)
  then show ?thesis2 by (simp add: ac_simps)
qed

lemma trans:
  shows "(x H y)  (y H z)  x H z"
by (metis curry detachment(2) swap uncurry inf_le2)

lemma rev_trans:
  shows "(y H z)  (x H y)  x H z"
by (simp add: inf.commute trans)

lemma discard:
  shows "Q  P H Q"
by (simp add: curry)

lemma infR:
  shows "x H y  z = (x H y)  (x H z)"
by (simp add: order_eq_iff curry uncurry detachment le_infI2)

lemma mono:
  assumes "x'  x"
  assumes "y  y'"
  shows "x H y  x' H y'"
using assms by (metis curry detachment(1) uncurry inf_commute inf_absorb2 le_infI1)

lemma strengthen[strg]:
  assumes "st_ord (¬ F) X X'"
  assumes "st_ord F Y Y'"
  shows "st_ord F (X H Y) (X' H Y')"
using assms by (cases F; simp add: heyting.mono)

lemma mono2mono[cont_intro, partial_function_mono]:
  assumes "monotone orda (≥) F"
  assumes "monotone orda (≤) G"
  shows "monotone orda (≤) (λx. F x H G x)"
by (simp add: monotoneI curry discharge le_infI1 monotoneD[OF assms(1)] monotoneD[OF assms(2)])

lemma mp:
  assumes "x  y H z"
  assumes "x  y"
  shows "x  z"
by (meson assms uncurry inf_greatest order.refl order_trans)

lemma botL:
  shows " H x = "
by (simp add: heyting top_le)

lemma top_conv:
  shows "x H y =   x  y"
by (metis curry detachment(2) inf_iff_le(1) inf_top.left_neutral)

lemma refl[simp]:
  shows "x H x = "
by (simp add: top_conv)

lemma topL[simp]:
  shows " H x = x"
by (metis detachment(1) inf_top_left)

lemma topR[simp]:
  shows "x H  = "
by (simp add: top_conv)

lemma K[simp]:
  shows "x H (y H x) = "
by (simp add: discard top_conv)

subclass distrib_lattice
proof ―‹ citet‹Proposition~1.5.3› in "Esakia:2019"
  have "x  (y  z)  x  y  x  z" for x y z :: 'a
    using commute by fastforce
  then have "x  (y  z) = (x  y)  (x  z)" for x y z :: 'a
    by (simp add: order.eq_iff le_infI2)
  then show "x  (y  z) = (x  y)  (x  z)" for x y z :: 'a
    by (rule distrib_imp1)
qed

lemma supL:
  shows "(x  y) H z = (x H z)  (y H z)"
by (simp add: order_eq_iff mono curry uncurry inf_sup_distrib1)

subclass (in complete_distrib_lattice) heyting_algebra by standard (rule inf_Sup)

lemma inf_Sup_distrib:
  shows "x  Y = (yY. x  y)"
    and "Y  x = (yY. x  y)"
by (simp_all add: inf_Sup_distrib1 inf_commute)

lemma inf_SUP_distrib:
  shows "x  (iI. Y i) = (iI. x  Y i)"
    and "(iI. Y i)  x = (iI. Y i  x)"
by (simp_all add: inf_Sup_distrib image_image ac_simps)

end

lemma eq_boolean_implication: ―‹ the implications coincide in classboolean_algebras  ›
  fixes x :: "_::boolean_algebra"
  shows "x H y = x B y"
by (simp add: order.eq_iff boolean_implication_def heyting.detachment heyting.curry flip: shunt1)

lemmas simp_thms =
  heyting.botL
  heyting.topL
  heyting.topR
  heyting.refl

lemma Sup_prime_Sup_irreducible_iff:
  fixes x :: "_::heyting_algebra"
  shows "Sup_prime x  Sup_irreducible x"
by (fastforce simp: Sup_prime_on_def Sup_irreducible_on_def inf.order_iff heyting.inf_Sup_distrib
             intro: Sup_prime_on_imp_Sup_irreducible_on)

paragraph‹ Logical rules ala HOL ›

lemma bspec:
  fixes P :: "_  (_::heyting_algebra)"
  shows "x  X  (xX. P x H Q x)  P x  Q x" (is "?X  ?thesis1")
    and "x  X  P x  (xX. P x H Q x)  Q x" (is "_  ?thesis2")
    and "(x. P x H Q x)  P x  Q x" (is ?thesis3)
    and "P x  (x. P x H Q x)  Q x" (is ?thesis4)
proof -
  show "?X  ?thesis1" by (meson INF_lower heyting.uncurry)
  then show "?X  ?thesis2" by (simp add: inf_commute)
  show ?thesis3 by (simp add: Inf_lower heyting.commute inf_commute)
  then show ?thesis4 by (simp add: inf_commute)
qed

lemma INFL:
  fixes Q :: "_::heyting_algebra"
  shows "(xX. P x H Q) = (xX. P x) H Q" (is "?lhs = ?rhs")
proof(rule antisym)
  show "?lhs  ?rhs" by (meson INFE SUPE order.refl heyting.commute heyting.uncurry)
  show "?rhs  ?lhs" by (simp add: INFI SupI heyting.mono)
qed

lemmas SUPL = heyting.INFL[symmetric]

lemma INFR:
  fixes P :: "_::heyting_algebra"
  shows "(xX. P H Q x) = (P H (xX. Q x))" (is "?lhs = ?rhs")
by (simp add: order_eq_iff INFI INF_lower heyting.mono)
   (meson INFI INF_lower heyting.curry heyting.uncurry)

lemmas Inf_simps = ―‹ "Miniscoping: pushing in universal quantifiers." ›
  Inf_inf
  inf_Inf
  INF_inf_const1
  INF_inf_const2
  heyting.INFL
  heyting.INFR

lemma SUPL_le:
  fixes Q :: "_::heyting_algebra"
  shows "(xX. P x H Q)  (xX. P x) H Q"
by (simp add: INF_lower SUPE heyting.mono)

lemma SUPR_le:
  fixes P :: "_::heyting_algebra"
  shows "(xX. P H Q x)  P H (xX. Q x)"
by (simp add: SUPE SUP_upper heyting.mono)

lemma SUP_inf:
  fixes Q :: "_::heyting_algebra"
  shows "(xX. P x  Q) = (xX. P x)  Q"
by (simp add: heyting.inf_SUP_distrib(2))

lemma inf_SUP:
  fixes P :: "_::heyting_algebra"
  shows "(xX. P  Q x) =  P  (xX. Q x)"
by (simp add: heyting.inf_SUP_distrib(1))

lemmas Sup_simps = ―‹ "Miniscoping: pushing in universal quantifiers." ›
  sup_SUP
  SUP_sup
  heyting.inf_SUP
  heyting.SUP_inf

lemma mcont2mcont_inf[cont_intro]:
  fixes F :: "_  'a::heyting_algebra"
  fixes G :: "_  'a::heyting_algebra"
  assumes "mcont luba orda Sup (≤) F"
  assumes "mcont luba orda Sup (≤) G"
  shows "mcont luba orda Sup (≤) (λx. F x  G x)"
proof -
  have mcont_inf1: "mcont Sup (≤) Sup (≤) (λy. x  y)" for x :: "'a::heyting_algebra"
    by (auto intro!: contI mcontI monotoneI intro: le_infI2 simp flip: heyting.inf_SUP_distrib)
  then have mcont_inf2: "mcont Sup (≤) Sup (≤) (λx. x  y)" for y :: "'a::heyting_algebra"
    by (subst inf.commute) (rule mcont_inf1)
  from assms mcont_inf1 mcont_inf2 show ?thesis
    by (best intro: ccpo.mcont2mcont'[OF complete_lattice_ccpo] ccpo.mcont_const[OF complete_lattice_ccpo])
qed

lemma closure_imp_distrib_le: ―‹ citet‹Lemma~3.3› in "AbadiPlotkin:1993", generalized ›
  fixes P Q :: "_ :: heyting_algebra"
  assumes cl: "closure_axioms (≤) cl"
  assumes cl_inf: "x y. cl x  cl y  cl (x  y)"
  shows "P H Q  cl P H cl Q"
proof -
  from cl have "(P H Q)  cl P  cl (P H Q)  cl P"
    by (metis (mono_tags) closure_axioms_def inf_mono order.refl)
  also have "  cl ((P H Q)  P)"
    by (simp add: cl_inf)
  also from cl have "  cl Q"
    by (metis (mono_tags) closure_axioms_def order.refl heyting.mono heyting.uncurry)
  finally show ?thesis
    by (simp add: heyting)
qed

setup Sign.parent_path


paragraph‹ Pseudocomplements ›

definition pseudocomplement :: "'a::heyting_algebra  'a" (¬H _› [75] 75) where
  "¬Hx = x H "

lemma pseudocomplementI:
  shows "x  ¬Hy  x  y  "
by (simp add: pseudocomplement_def heyting)

setup Sign.mandatory_path "pseudocomplement"

lemma monotone:
  shows "antimono pseudocomplement"
by (simp add: antimonoI heyting.mono pseudocomplement_def)

lemmas strengthen[strg] = st_monotone[OF pseudocomplement.monotone]
lemmas mono = monotoneD[OF pseudocomplement.monotone]
lemmas mono2mono[cont_intro, partial_function_mono]
   = monotone2monotone[OF pseudocomplement.monotone, simplified, of orda P for orda P]

lemma eq_boolean_negation: ―‹ the negations coincide in classboolean_algebras  ›
  fixes x :: "_::{boolean_algebra,heyting_algebra}"
  shows "¬Hx = -x"
by (simp add: pseudocomplement_def heyting.eq_boolean_implication)

lemma heyting:
  shows "x H ¬Hx = ¬Hx"
by (simp add: pseudocomplement_def order_eq_iff heyting heyting.detachment)

lemma Inf:
  shows "x  ¬Hx = "
    and "¬Hx  x = "
by (simp_all add: pseudocomplement_def heyting.detachment)

lemma double_le:
  shows "x  ¬H¬Hx"
by (simp add: pseudocomplement_def heyting.detachment heyting.curry)

interpretation double: closure_complete_lattice_class "pseudocomplement  pseudocomplement"
by standard (simp; meson order.trans pseudocomplement.double_le pseudocomplement.mono)

lemma triple:
  shows "¬H¬H¬Hx = ¬Hx"
by (simp add: order_eq_iff pseudocomplement.double_le pseudocomplement.mono)

lemma contrapos_le:
  shows "x H y  ¬Hy H ¬Hx"
by (simp add: heyting.curry heyting.trans pseudocomplement_def)

lemma sup_inf: ―‹ half of de Morgan ›
  shows "¬H(x  y) = ¬Hx  ¬Hy"
by (simp add: pseudocomplement_def heyting.supL)

lemma inf_sup_weak: ―‹ the weakened other half of de Morgan ›
  shows "¬H(x  y) = ¬H¬H(¬Hx  ¬Hy)"
by (metis (no_types, opaque_lifting) pseudocomplement_def heyting.curry_conv heyting.supL inf_commute pseudocomplement.triple)                   

lemma fix_triv:
  assumes "x = ¬Hx"
  shows "x = y"
using assms by (metis antisym bot.extremum inf.idem inf_le2 pseudocomplementI)

lemma double_top:
  shows "¬H¬H(x  ¬Hx) = "
by (metis pseudocomplement_def heyting.refl pseudocomplement.Inf(1) pseudocomplement.sup_inf)

lemma Inf_inf:
  fixes P :: "_  (_::heyting_algebra)"
  shows "(x. P x)  ¬HP x = "
by (simp add: pseudocomplement_def Inf_lower heyting.discharge(1))

lemma SUP_le: ―‹ half of de Morgan ›
  fixes P :: "_  (_::heyting_algebra)"
  shows "(xX. P x)  ¬H(xX. ¬HP x)"
by (rule SUP_least) (meson INF_lower order.trans pseudocomplement.double_le pseudocomplement.mono)

lemma SUP_INF_le:
  fixes P :: "_  (_::heyting_algebra)"
  shows "(xX. ¬HP x)  ¬H(xX. P x)"
by (simp add: INF_lower SUPE pseudocomplement.mono)

lemma SUP:
  fixes P :: "_  (_::heyting_algebra)"
  shows "¬H(xX. P x) = (xX. ¬HP x)"
by (simp add: order.eq_iff SUP_upper le_INF_iff pseudocomplement.mono)
   (metis inf_commute pseudocomplement.SUP_le pseudocomplementI)

setup Sign.parent_path


subsection‹ Downwards closure of preorders (downsets) \label{sec:closures-downwards} ›

text‹

A ‹downset› (also ‹lower set› and ‹order ideal›) is a subset of a preorder that is closed under
the order relation. (An ‹ideal› is a downset that is constdirected.) Some results require
antisymmetry (a partial order).

References:
  citet"Vickers:1989", early chapters.
  🌐‹https://en.wikipedia.org/wiki/Alexandrov_topology›
  citet‹\S3› in "AbadiPlotkin:1991"

setup Sign.mandatory_path "downwards"

definition cl :: "'a::preorder set  'a set" where
  "cl P = {x |x y. y  P  x  y}"

setup Sign.parent_path

interpretation downwards: closure_powerset_distributive downwards.cl ―‹ On preorders ›
proof standard
  show "(P  downwards.cl Q)  (downwards.cl P  downwards.cl Q)" for P Q :: "'a set"
    unfolding downwards.cl_def by (auto dest: order_trans)
  show "downwards.cl (X)   (downwards.cl ` X)  downwards.cl {}" for X :: "'a set set"
    unfolding downwards.cl_def by auto
qed

interpretation downwards: closure_powerset_distributive_anti_exchange "(downwards.cl::_::order set  _)"
  ―‹ On partial orders; see citet"PfaltzSlapal:2013"
by standard (unfold downwards.cl_def; blast intro: anti_exchangeI antisym)

setup Sign.mandatory_path "downwards"

lemma cl_empty:
  shows "downwards.cl {} = {}"
unfolding downwards.cl_def by simp

lemma closed_empty[iff]:
  shows "{}  downwards.closed"
using downwards.cl_def by fastforce

lemma clI[intro]:
  assumes "y  P"
  assumes "x  y"
  shows "x  downwards.cl P"
unfolding closure.closed_def downwards.cl_def using assms by blast

lemma clE:
  assumes "x  downwards.cl P"
  obtains y where "y  P" and "x  y"
using assms unfolding downwards.cl_def by fast

lemma closed_in:
  assumes "x  P"
  assumes "y  x"
  assumes "P  downwards.closed"
  shows "y  P"
using assms unfolding downwards.cl_def downwards.closed_def by blast

lemma order_embedding: ―‹ On preorders; see citet‹\S1.35› in "DaveyPriestley:2002"
  fixes x :: "_::preorder"
  shows "downwards.cl {x}  downwards.cl {y}  x  y"
using downwards.cl by (blast elim: downwards.clE)

text‹

The lattice of downsets of a set X› is always a classheyting_algebra.

References:
  citet‹\S7.5› in "Ono:2019"; uses upsets, points to citet"Stone:1938" as the origin
  citet‹\S2.2› in "Esakia:2019"
  🌐‹https://en.wikipedia.org/wiki/Intuitionistic_logic#Heyting_algebra_semantics›

definition imp :: "'a::preorder set  'a set  'a set" where
  "imp P Q = {σ. σ'σ. σ'  P  σ'  Q}"

lemma imp_refl:
  shows "downwards.imp P P = UNIV"
by (simp add: downwards.imp_def)

lemma imp_contained:
  assumes "P  Q"
  shows "downwards.imp P Q = UNIV"
unfolding downwards.imp_def using assms by fast

lemma heyting_imp:
  assumes "P  downwards.closed"
  shows "P  downwards.imp Q R  P  Q  R"
using assms unfolding downwards.imp_def downwards.closed_def by blast

lemma imp_mp':
  assumes "σ  downwards.imp P Q"
  assumes "σ  P"
  shows "σ  Q"
using assms by (simp add: downwards.imp_def)

lemma imp_mp:
  shows "P  downwards.imp P Q  Q"
    and "downwards.imp P Q  P  Q"
by (meson IntD1 IntD2 downwards.imp_mp' subsetI)+

lemma imp_contains:
  assumes "X  Q"
  assumes "X  downwards.closed"
  shows "X  downwards.imp P Q"
using assms by (auto simp: downwards.imp_def elim: downwards.closed_in)

lemma imp_downwards:
  assumes "y  downwards.imp P Q"
  assumes "x  y"
  shows "x  downwards.imp P Q"
using assms order_trans by (force simp: downwards.imp_def)

lemma closed_imp:
  shows "downwards.imp P Q  downwards.closed"
by (meson downwards.clE downwards.closedI downwards.imp_downwards)

text‹

The set downwards.imp P Q› is the greatest downset contained in the Boolean implication
P B Q›, i.e., downwards.imp› is the ‹kernel› of (B)› citep"Zwiers:1989".
Note that ``kernel'' is a choice or interior function.

›

lemma imp_boolean_implication_subseteq:
  shows "downwards.imp P Q  P B Q"
unfolding downwards.imp_def boolean_implication.set_alt_def by blast

lemma downwards_closed_imp_greatest:
  assumes "R  P B Q"
  assumes "R  downwards.closed"
  shows "R  downwards.imp P Q"
using assms unfolding boolean_implication.set_alt_def downwards.imp_def downwards.closed_def by blast

definition kernel :: "'a::order set  'a set" where
  "kernel X = {Q  downwards.closed. Q  X}"

lemma kernel_def2:
  shows "downwards.kernel X = {σ. σ'σ. σ'  X}" (is "?lhs = ?rhs")
proof(rule antisym)
  show "?lhs  ?rhs"
    unfolding downwards.kernel_def using downwards.closed_conv by blast
next
  have "x  ?lhs" if "x  ?rhs" for x
    unfolding downwards.kernel_def using that
    by (auto elim: downwards.clE intro: exI[where x="downwards.cl {x}"])
  then show "?rhs  ?lhs" by blast
qed

lemma kernel_contractive:
  shows "downwards.kernel X  X"
unfolding downwards.kernel_def by blast

lemma kernel_idempotent:
  shows "downwards.kernel (downwards.kernel X) = downwards.kernel X"
unfolding downwards.kernel_def by blast

lemma kernel_monotone:
  shows "mono downwards.kernel"
unfolding downwards.kernel_def by (rule monotoneI) blast

lemma closed_kernel_conv:
  shows "X  downwards.closed  downwards.kernel X = X"
unfolding downwards.kernel_def2 downwards.closed_def by (blast elim: downwards.clE)

lemma closed_kernel:
  shows "downwards.kernel X  downwards.closed"
by (simp add: downwards.closed_kernel_conv downwards.kernel_idempotent)

lemma kernel_cl:
  shows "downwards.kernel (downwards.cl X) = downwards.cl X"
using downwards.closed_kernel_conv by blast

lemma cl_kernel:
  shows "downwards.cl (downwards.kernel X) = downwards.kernel X"
by (simp flip: downwards.closed_conv add: downwards.closed_kernel)

lemma kernel_boolean_implication:
  fixes P :: "_::order"
  shows "downwards.kernel (P B Q) = downwards.imp P Q"
unfolding downwards.kernel_def2 boolean_implication.set_alt_def downwards.imp_def by blast

setup Sign.parent_path
(*<*)

end
(*>*)