Theory Transformer_Semantics.Kleisli_Transformers

(* 
  Title: State Transformers and Predicate Transformers Based on the Powerset Monad
  Author: Georg Struth 
  Maintainer: Georg Struth <g.struth@sheffield.ac.uk> 
*)

section ‹State Transformers and Predicate Transformers Based on the Powerset Monad›

theory Kleisli_Transformers

imports Powerset_Monad 
        Sup_Inf_Preserving_Transformers
begin          


subsection ‹Backward Diamonds from Kleisli Arrows›

text ‹First I verify the embedding of the Kleisli category of the powerset functor into its Eilenberg-Moore category. 
This functor maps sets to their mus and functions to their Kleisli liftings. But this is just functoriality of dagger!. 
I model it as a backward diamond operator in the sense of dynamic logic. It corresponds to a strongest postcondition 
operator. In the parlance of program semantics, this is an embedding of state into prediate transformers.›

notation klift (bd)

text ‹bd stands for backward diamond, the index indicates the setting of Kleisli arrows or nondeterministic 
functions. ifbd is its inverse.›

abbreviation ifbd :: "('a set  'b set)  'a  'b set" (bd-) where 
  "bd-  (λφ. φ  η)"

lemma fbd_set: "bd f X = {y. x. y  f x  x  X}"
  by (force simp: klift_prop) 
 
lemma ifbd_set: "bd- φ x = {y. y  φ {x}}"
  by simp

text ‹The two functors form a bijective pair.›

lemma fbd_ifbd_inv2: "Sup_pres φ  (bd  bd-) φ = φ" 
proof -
  assume h: "Sup_pres φ"
  have "(bd  bd-) φ = Sup  𝒫 (φ  η)"
    unfolding klift_def by simp
  also have "... = Sup  𝒫 φ  𝒫 η"
    by (simp add: comp_assoc P_func1)
  also have "... = φ  Sup  𝒫 η"
    by (simp add: h)
  also have "... = φ  id"
    by force
  finally show ?thesis
    by simp
qed

lemma fbd_ifbd_inv2_inv: "(bd  bd-) φ = φ  Sup_pres φ" 
  unfolding fun_eq_iff comp_def by (metis (no_types, lifting) Inf.INF_cong UN_extend_simps(8) klift_prop)

lemma fbd_ifbd_inv2_iff: "((bd  bd-) φ = φ) = (Sup_pres φ)"
  using fbd_ifbd_inv2 fbd_ifbd_inv2_inv by force

lemma fbd_inj: "inj bd"
  by (meson inj_on_inverseI klift_eta_inv1)

lemma fbd_inj_iff: "(bd f = bd g) = (f = g)"
  by (meson injD fbd_inj)

lemma ifbd_inj: "Sup_pres φ  Sup_pres ψ  bd- φ = bd- ψ  φ = ψ"
proof-
  assume h1: "Sup_pres φ"
  and h2: "Sup_pres ψ" 
  and "bd- φ = bd- ψ"
  hence "(bd  bd-) φ = (bd  bd-) ψ"
    by simp
  thus ?thesis
    by (metis h1 h2 fbd_ifbd_inv2)
qed

lemma ifbd_inj_iff: "Sup_pres φ  Sup_pres ψ  (bd- φ = bd- ψ) = (φ = ψ)"
  using ifbd_inj by force

lemma fbd_ifbd_galois: "Sup_pres φ  (bd- φ = f) = (bd f = φ)"
  using fbd_ifbd_inv2 by force

lemma fbd_surj: "Sup_pres φ  (f. bd f = φ)"
  using fbd_ifbd_inv2 by auto 

lemma ifbd_surj: "surj bd-"
  unfolding surj_def by (metis klift_eta_inv1)

text ‹In addition they preserve the Sup-quantale structure of the powerset algebra. This means that
morphisms preserve compositions, units and Sups, but not Infs, hence also bottom but not top.›

lemma fbd_comp_pres: "bd (f K g) = bd g  bd f"
  unfolding kcomp_klift klift_prop1 by simp

lemma fbd_Sup_pres: "Sup_pres bd"
  by (force simp: fun_eq_iff klift_def)

lemma fbd_sup_pres: "sup_pres bd"
  using Sup_sup_pres fbd_Sup_pres by blast

lemma fbd_Disj: "Sup_pres (bd f)"
  by (simp add: fbd_ifbd_inv2_inv)

lemma fbd_disj: "sup_pres (bd f)"
  by (simp add: klift_prop)

lemma fbd_bot_pres: "bot_pres bd"
  unfolding klift_def by fastforce

lemma fbd_zero_pres2 [simp]: "bd f {} = {}"
  by (simp add: klift_prop)

lemma fbd_iso: "X  Y  bd f X  bd f Y"
  by (metis fbd_disj le_iff_sup)

text ‹The following counterexamples show that Infs are not preserved.›

lemma "top_pres bd" (*nitpick*)
  oops

lemma "inf_pres bd" (*nitpick*)
  oops

text ‹Dual preservation statements hold for ifbd ... and even Inf-preservation.›

lemma ifbd_comp_pres: "Sup_pres φ  bd- (φ  ψ) = bd- ψ K bd- φ"
  by (smt fbd_ifbd_galois fun.map_comp kcomp_def klift_def)

lemma ifbd_Sup_pres: "Sup_pres bd-"   
  by (simp add: fun_eq_iff)

lemma ifbd_sup_pres: "sup_pres bd-"
  by force

lemma ifbd_Inf_pres: "Inf_pres bd-"
  by (simp add: fun_eq_iff)

lemma ifbd_inf_pres: "inf_pres bd-"
  by force

lemma ifbd_bot_pres: "bot_pres bd-"
  by auto

lemma ifbd_top_pres: "top_pres bd-"
  by auto

text ‹Preservation of units by the Kleisli lifting has been proved in klift-prop3.›

text ‹These results estabilish the isomorphism between state and predicate transformers given by backward diamonds.
The isomorphism preserves the Sup-quantale structure, but not Infs.›
 


subsection ‹Backward Diamonds from Relations›

text ‹Using the isomorphism between binary relations and Kleisli arrows (or state transformers), it is straightforward
to define backward diamonds from relations, by composing isomorphisms. It follows that Sup-quantales of binary relations 
(under relational composition, the identity relation and Sups) are isomorphic to the Sup-quantales of predicate transformers.
Once again, Infs are not preserved.›

definition rbd :: "('a × 'b) set  'a set  'b set"  (bd) where
  "bd = bd  "

definition irbd :: "('a set  'b set)  ('a × 'b) set"  (bd-) where
  "bd- =   bd-"

lemma rbd_Im: "bd = (``)"
  unfolding rbd_def klift_def r2f_def fun_eq_iff by force

lemma rbd_set: "bd R X = {y. x  X. (x,y)  R}"
  by (force simp: rbd_Im Image_def)
  
lemma irbd_set: "bd- φ = {(x,y). y  (φ  η) x}"
  by (simp add: irbd_def f2r_def o_def)

lemma irbd_set_var: "bd- φ = {(x,y). y  φ {x}}"
  by (simp add: irbd_def f2r_def o_def)

lemma rbd_irbd_inv1 [simp]: "bd-  bd = id"
  by (metis (no_types, lifting) comp_eq_dest_lhs eq_id_iff fbd_Disj fbd_ifbd_galois irbd_def r2f_f2r_galois rbd_def)

lemma irbd_rbd_inv2: "Sup_pres φ  (bd  bd-) φ = φ"
  by (metis comp_apply fbd_ifbd_galois irbd_def r2f_f2r_galois rbd_def)

lemma irbd_rbd_inv2_inv: "(bd  bd-) φ = φ  Sup_pres φ"
  by (simp add: rbd_def irbd_def, metis fbd_Disj)

lemma irbd_rbd_inv2_iff: "((bd  bd-) φ = φ) = (Sup_pres φ)"
  using irbd_rbd_inv2 irbd_rbd_inv2_inv by blast

lemma rbd_inj: "inj bd"
  by (simp add: fbd_inj inj_compose r2f_inj rbd_def)

lemma rbd_translate: "(bd R = bd S) = (R = S)"
  by (simp add: rbd_inj inj_eq)

lemma irbd_inj: "Sup_pres φ  Sup_pres ψ  bd- φ = bd- ψ  φ = ψ"
  by (metis rbd_Im comp_eq_dest_lhs irbd_rbd_inv2)

lemma irbd_inj_iff: "Sup_pres φ  Sup_pres ψ  (bd- φ = bd- ψ) = (φ = ψ)"
  using irbd_inj by force

lemma rbd_surj: "Sup_pres φ  (R. bd R = φ)"
  using irbd_rbd_inv2 by force

lemma irbd_surj: "surj bd-"
  by (metis UNIV_I fun.set_map imageE rbd_irbd_inv1 surj_def surj_id)

lemma rbd_irbd_galois: "Sup_pres φ  (φ = bd R) = (R = bd- φ)"
  by (smt comp_apply fbd_ifbd_galois irbd_def r2f_f2r_galois rbd_def)

lemma rbd_comp_pres: "bd (R ; S) = bd S  bd R"
  by (simp add: rbd_def r2f_comp_pres fbd_comp_pres)

lemma rbd_Id_pres: "bd Id = id"
  unfolding rbd_def by simp

lemma rbd_Un_pres: "Sup_pres bd"
  by (simp add: rbd_def Sup_pres_comp fbd_Sup_pres r2f_Sup_pres)

lemma rbd_un_pres: "sup_pres bd"
  by (simp add: rbd_def fbd_sup_pres r2f_sup_pres)

lemma "inf_pres bd" (*nitpick*)
  oops

lemma rbd_disj: "Sup_pres (bd R)"
  by (simp add: rbd_def fbd_Disj)

lemma rbd_disj2: "sup_pres (bd R)"
  by (simp add: Image_Un rbd_Im)

lemma rbd_bot_pres: "bot_pres bd"
  by (simp add: fbd_bot_pres r2f_bot_pres rbd_def)

lemma rbd_zero_pres2 [simp]: "bd R {} = {}"
  by (simp add: rbd_Im)

lemma rbd_univ: "bd R UNIV = Range R"
  unfolding rbd_def fun_eq_iff klift_def r2f_def by force

lemma rbd_iso: "X  Y  bd R X  bd R Y"
  by (metis le_iff_sup rbd_disj2)

lemma irbd_comp_pres: "Sup_pres φ  bd- (φ  ψ) = bd- ψ ; bd- φ"
  by (simp add: ifbd_comp_pres f2r_kcomp_pres irbd_def)

lemma irbd_id_pres [simp]: "bd- id = Id"
  unfolding irbd_def by simp

lemma irbd_Sup_pres: "Sup_pres bd-"
  by (simp add: irbd_def Sup_pres_comp ifbd_Sup_pres f2r_Sup_pres)

lemma irbd_sup_pres: "sup_pres bd-"
  by (simp add: irbd_def ifbd_sup_pres f2r_sup_pres)  

lemma irbd_Inf_pres: "Inf_pres bd-"
  by (auto simp: fun_eq_iff irbd_def f2r_def)

lemma irbd_inf_pres: "inf_pres bd-"
  by (auto simp: fun_eq_iff irbd_def f2r_def)

lemma irbd_bot_pres: "bot_pres bd-"
  by (metis comp_def ifbd_bot_pres f2r_bot_pres irbd_def)

text ‹This shows that relations are isomorphic to disjunctive forward predicate transformers. In many cases Isabelle picks up
the composition of morphisms in proofs.›


subsection ‹Forward Boxes on Kleisli Arrows›

text ‹Forward box operators correspond to weakest liberal preconditions in program semantics. Here, 
Kleisli arrows are mapped to the opposite of the Eilenberg-Moore category, that is, Inf-lattices. 
It follows that the Inf-quantale structure is preserved. Modelling opposition is based on the fact 
that Kleisli arrows can be swapped by going through relations.›

definition ffb :: "('a  'b set)  'b set  'a set" (fb) where
  "fb = F  bd  opK" 

text ‹Here, $\partial_F$ is map-dual, which amounts to De Morgan duality. Hence the forward box operator is
obtained from the backward diamond by taking the opposite Kleisli arrow, applying the backward diamond, and then De Morgan
duality.›

lemma ffb_prop: "fb f =   bd (opK f)  "
  by (simp add: ffb_def map_dual_def)

lemma ffb_prop_var: "fb f = uminus  bd (opK f)  uminus"
  by (simp add: dual_set_def ffb_prop)
 
lemma ffb_fbd_dual: "  fb f = bd (opK f)  "
  by (simp add: ffb_prop o_assoc)

text ‹I give a set-theoretic definition of iffb, because the algebraic one below depends on Inf-preservation.›

definition iffb :: "('b set  'a set)  'a  'b set" (fb-) where
  "fb- φ = (λx. {X. x  φ X})"

lemma ffb_set: "fb f = (λY. {x. f x  Y})" 
  by (force simp: fun_eq_iff ffb_prop_var kop_def klift_def f2r_def r2f_def)

text ‹Forward boxes and backward diamonds are adjoints.›

lemma ffb_fbd_galois: "(bd f)  (fb f)"
  unfolding adj_def ffb_set klift_prop by blast

lemma iffb_inv1: "fb-  fb = id"
  unfolding fun_eq_iff ffb_set iffb_def by force

lemma iffb_inv2_aux: "Inf_pres φ  {X. x  φ X}  Y  x  φ Y"
proof-
  assume "Inf_pres φ"
    and h1: "{X. x  φ X}  Y"
  hence h2: "X. φ (X) = (x  X. φ x)"
    by (metis comp_eq_dest)
  hence "φ ({X. x  φ X})  φ Y"
    by (metis h1 INF_lower2 cInf_eq_minimum mem_Collect_eq order_refl)
  hence "({φ X |X. x  φ X})  φ Y" 
    by (metis h2 setcompr_eq_image)
  thus ?thesis
    by (force simp add: subset_iff)
qed

lemma iffb_inv2: "Inf_pres φ  (fb  fb-) φ = φ"
proof-
  assume h: "Inf_pres φ"
  {fix Y
  have "(fb  fb-) φ Y = {x. {X. x  φ X}  Y}"
    by (simp add: ffb_set iffb_def)
  hence "x. x  (fb  fb-) φ Y  {X. x  φ X}  Y"
    by auto
  hence "x. x  (fb  fb-) φ Y  x  φ Y" 
    by (auto simp: h iffb_inv2_aux)
  hence  "(fb  fb-) φ Y = φ Y"
    by (simp add: fun_eq_iff set_eq_iff)}
  thus ?thesis
    unfolding fun_eq_iff by simp
qed

lemma iffb_inv2_inv: "(fb  fb-) φ = φ  Inf_pres φ"
  by (auto simp: fun_eq_iff ffb_set iffb_def)

lemma iffb_inv2_iff: "((fb  fb-) φ = φ) = (Inf_pres φ)"
  using iffb_inv2 iffb_inv2_inv by blast

lemma ffb_inj: "inj fb"
  unfolding inj_def by (metis iffb_inv1 pointfree_idE)

lemma ffb_inj_iff: "(fb f = fb g) = (f = g)"
  by (simp add: ffb_inj inj_eq)

lemma ffb_iffb_galois: "Inf_pres φ  (fb- φ = f) = (fb f = φ)"
  using ffb_inj_iff iffb_inv2 by force

lemma iffb_inj: "Inf_pres φ  Inf_pres ψ  fb- φ = fb- ψ   φ = ψ"
  by (metis ffb_iffb_galois)

lemma iffb_inj_iff: "Inf_pres φ  Inf_pres ψ  (fb- φ = fb- ψ) = (φ = ψ)"
  using iffb_inj by blast

lemma ffb_surj: "Inf_pres φ   (f. fb f = φ)"
  using iffb_inv2 by auto

lemma iffb_surj: "surj fb-" 
  using surj_def by (metis comp_apply iffb_inv1 surj_id) 

text ‹This is now the explicit "definition" of iffb, for Inf-preserving transformers.›

lemma iffb_ifbd_dual: "Inf_pres φ  fb- φ = (opK  bd-  F) φ" 
proof-
  assume h: "Inf_pres φ"
  {fix f
    have "(fb- φ = f) = ((F  bd  opK) f = φ)"
      by (simp add: ffb_def ffb_iffb_galois h)
    also have "... = (opK f = (bd-  F) φ)"
      by (metis (mono_tags, lifting) comp_apply map_dual_dual ffb_def ffb_surj h klift_eta_inv1 map_dual_dual)
    finally have "(fb- φ = f) = (f = (opK  bd-  F) φ)"
      using kop_galois by auto}
  thus ?thesis
    by blast
qed

lemma fbd_ffb_dual: "F  fb  opK = bd"
proof-
  have "F  fb  opK = F  F  bd  (opK  opK)"
    by (simp add: comp_def ffb_def)
  thus ?thesis
    by simp
qed

lemma ffbd_ffb_dual_var: "  bd f = fb (opK f)  "
  by (metis ffb_prop fun_dual1 kop_galois)

lemma ifbd_iffb_dual: "Sup_pres φ  bd- φ = (opK  fb-  F) φ" 
proof-
  assume h: "Sup_pres φ"
  hence "Inf_pres (F φ)"
    using Sup_pres_Inf_pres by blast
  hence "(opK  fb-  F) φ = (opK  (opK  bd-  F)  F) φ"
    by (simp add: iffb_ifbd_dual)
  thus ?thesis
    by (metis comp_def kop_galois map_dual_dual)
qed

lemma ffb_kcomp_pres: "fb (f K g) = fb f  fb g"
proof-
  have "fb (f K g) = F (bd (opK (f K g)))"
    by (simp add: ffb_def)
  also have "... = F (bd (opK g K opK f))"
    by (simp add: kop_contrav)
  also have "... = F (bd (opK f)  bd (opK g))"
    by (simp add: fbd_comp_pres)
  also have "... = F (bd (opK f))  F (bd (opK g))"
    by (simp add: map_dual_func1)
  finally show ?thesis
    by (simp add: ffb_def)
qed

lemma ffb_eta_pres: "fb η = id"
  unfolding ffb_def by simp

lemma ffb_Sup_dual: "Sup_dual fb"
  unfolding ffb_prop_var comp_def fun_eq_iff klift_prop kop_def f2r_def r2f_def converse_def by fastforce

lemma ffb_Sup_dual_var: "fb (F) = (f  F. fb f)"
  unfolding ffb_prop_var comp_def fun_eq_iff klift_prop kop_def f2r_def r2f_def converse_def by fastforce

lemma ffb_sup_dual: "sup_dual fb"
  using ffb_Sup_dual Sup_sup_dual by force

lemma ffb_zero_dual: "fb ζ = (λX. UNIV)" 
  unfolding ffb_prop_var kop_def klift_prop fun_eq_iff f2r_def r2f_def by simp

lemma "inf_dual ffb" (*nitpick*)
  oops

text ‹Once again, only the Sup-quantale structure is preserved.›

lemma iffb_comp_pres:
  assumes "Inf_pres φ"
  assumes "Inf_pres ψ"
  shows "fb- (φ  ψ) = fb- φ K fb- ψ"
    by (metis assms Inf_pres_comp ffb_iffb_galois ffb_kcomp_pres)

lemma iffb_id_pres: "fb- id = η"
  unfolding iffb_def by force

lemma iffb_Inf_dual: 
  assumes "φ  Φ. Inf_pres φ"
  shows "(fb-  Inf) Φ = (Sup  𝒫 fb-) Φ" 
proof-
  have "Inf_pres (Φ)"
    using Inf_pres_Inf assms by blast
  hence "(fb  fb-) (Φ) = (𝒫 (fb  fb-) Φ)"
    by (metis (mono_tags, lifting) INF_cong INF_identity_eq assms iffb_inv2)
  hence "(fb  fb-) (Φ) = fb ((𝒫 fb- Φ))"
    by (simp add: Setcompr_eq_image ffb_Sup_dual_var image_comp)
  thus ?thesis
    by (simp add: ffb_inj_iff)
qed  

lemma iffb_Sup_dual: "Sup_dual fb-"
  by (auto simp: iffb_def fun_eq_iff)
 
lemma iffb_inf_dual: 
  assumes "Inf_pres φ" 
  and "Inf_pres ψ"
shows "fb- (φ  ψ) = fb- φ  fb- ψ"
proof -
  have f1: "φ  ψ = fb (fb- φ)  fb (fb- ψ)"
    using assms iffb_inv2 by fastforce
  have "φ  ψ  Inter = Inter  𝒫 (φ  ψ)"
    using assms Inf_pres_inf by blast
  thus ?thesis
    by (simp add: f1 ffb_iffb_galois ffb_sup_dual)
qed 

lemma  iffb_sup_dual: "fb- (φ  ψ) = fb- φ  fb- ψ"
  unfolding iffb_def by fastforce

lemma iffb_top_pres [simp]: "fb-  = ζ"
  unfolding iffb_def by simp

text ‹This establishes the duality between state transformers and weakest liberal preconditions.›


subsection ‹Forward Box Operators from Relations›

text ‹Once again one can compose isomorphisms, linking weakest liberal preconditions with relational semantics.
The isomorphism obtained should by now be obvious.›

definition rfb :: "('a × 'b) set  'b set  'a set"  (fb) where
  "fb = fb  "

definition irfb :: "('b set  'a set)  ('a × 'b) set" (fb-) where
  "fb- =   fb-"

lemma rfb_rbd_dual: "fb R = F (bd (R¯))" 
  by (simp add: rfb_def rbd_def kop_def ffb_def, metis r2f_f2r_galois)

lemma rbd_rfb_dual: "bd R = F (fb (R¯))"
  by (simp add: rfb_def rbd_def kop_def ffb_def, metis converse_converse map_dual_dual r2f_f2r_galois)
  
lemma irfb_irbd_dual: "Inf_pres φ  fb- φ = (()  bd-   F) φ"
  by (simp add: irfb_def irbd_def iffb_ifbd_dual kop_def r2f_f2r_galois)

lemma irbd_irfb_dual: "Sup_pres φ  bd- φ = (()  fb-  F) φ"
  by (simp add: irfb_def irbd_def ifbd_iffb_dual kop_def r2f_f2r_galois)

lemma rfb_set: "fb R Y = {x. y. (x,y)  R  y  Y}"
  unfolding rfb_def ffb_prop_var comp_def klift_def f2r_def r2f_def kop_def by force

lemma rfb_rbd_galois: "(bd R)  (fb R)"
  by (simp add: ffb_fbd_galois rbd_def rfb_def)

lemma irfb_set: "fb- φ = {(x, y). Y. x  φ Y  y  Y}"
  by (simp add: irfb_def iffb_def f2r_def)

lemma irfb_inv1 [simp]: "fb-  fb = id"
  by (simp add: fun_eq_iff rfb_def irfb_def iffb_inv1 pointfree_idE)

lemma irfb_inv2: "Inf_pres φ  (fb  fb-) φ = φ"
  by (simp add: rfb_def irfb_def, metis ffb_iffb_galois r2f_f2r_galois)

lemma rfb_inj: "inj fb"
  by (simp add: rfb_def ffb_inj inj_compose r2f_inj)

lemma rfb_inj_iff: "(fb R = fb S) = (R = S)"
  by (simp add: rfb_inj inj_eq)

lemma irfb_inj: "Inf_pres φ  Inf_pres ψ  fb- φ = fb- ψ  φ = ψ"
  unfolding irfb_def using iffb_inj r2f_inj_iff by fastforce

lemma irfb_inf_iff: "Inf_pres φ  Inf_pres ψ  (fb- φ = fb- ψ) = (φ = ψ)"
  using irfb_inj by auto

lemma rfb_surj: "Inf_pres φ  (R. fb R = φ)"
  using irfb_inv2 by fastforce

lemma irfb_surj: "surj fb-" 
  by (simp add: irfb_def comp_surj f2r_surj iffb_surj cong del: image_cong_simp)

lemma rfb_irfb_galois: "Inf_pres φ  (fb- φ = R) = (fb R = φ)"
  by (simp add: irfb_def rfb_def, metis ffb_iffb_galois r2f_f2r_galois)

lemma rfb_comp_pres: "fb (R ; S) = fb R  fb S"
  by (simp add: ffb_kcomp_pres r2f_comp_pres rfb_def)

lemma rfb_Id_pres [simp]: "fb Id = id"
  unfolding rfb_def ffb_prop by force

lemma rfb_Sup_dual: "Sup_dual fb"
proof- 
  have "fb  μ = fb    Sup"
    by (simp add: rfb_def)
  also have "... = fb  Sup  𝒫 "
    by (metis fun.map_comp r2f_Sup_pres)
  also have "... = Inf  𝒫 fb  𝒫 "
    by (simp add: ffb_Sup_dual)
  also have "... = Inf  𝒫 (fb  )"
    by (simp add: P_func1 comp_assoc)
  finally show ?thesis
    by (simp add: rfb_def)
qed

lemma rfb_Sup_dual_var: "fb (φ) = (𝒫 fb) φ"
  by (meson comp_eq_dest rfb_Sup_dual)

lemma rfb_sup_dual: "sup_dual fb"
  by (simp add: rfb_def ffb_sup_dual r2f_sup_pres)

lemma "inf_dual fb" (*nitpick*)
  oops

lemma rfb_Inf_pres: "Inf_pres (fb R)"
  unfolding rfb_def ffb_prop_var comp_def fun_eq_iff klift_def kop_def f2r_def r2f_def converse_def by auto

lemma rfb_inf_pres: "inf_pres (fb R)"
  unfolding rfb_def ffb_prop_var comp_def fun_eq_iff klift_def kop_def f2r_def r2f_def converse_def by auto

lemma rfb_zero_pres [simp]: "fb {} X = UNIV"
 unfolding rfb_def ffb_prop_var comp_def fun_eq_iff klift_def kop_def f2r_def r2f_def converse_def by auto

lemma rfb_zero_pres2 [simp]: "fb R {} = - Domain R"
 unfolding rfb_def ffb_prop_var comp_def fun_eq_iff klift_def kop_def f2r_def r2f_def converse_def by auto

lemma rfb_univ [simp]: "fb R UNIV = UNIV"
  unfolding rfb_def ffb_prop_var comp_def fun_eq_iff klift_def kop_def f2r_def r2f_def converse_def by auto

lemma rfb_iso: "X  Y  fb R X  fb R Y"
  unfolding rfb_def ffb_prop_var comp_def fun_eq_iff klift_def kop_def f2r_def r2f_def converse_def by auto

lemma irfb_comp_pres: 
  assumes "Inf_pres φ"
  assumes "Inf_pres ψ"
  shows "fb- (φ  ψ) = fb- φ ; fb- ψ"
  by (metis assms rfb_Inf_pres rfb_comp_pres rfb_irfb_galois)

lemma irfb_id_pres [simp]: "fb- id = Id"
  by (simp add: rfb_irfb_galois)

lemma irfb_Sup_dual: "Sup_dual fb-"
  by (auto simp: fun_eq_iff irfb_def iffb_def f2r_def)

lemma irfb_Inf_dual: 
  assumes "φ  Φ. Inf_pres φ"
  shows "(fb-  Inf) Φ = (Sup  𝒫 fb-) Φ" 
proof-
  have "Inf_pres (Φ)"
    using Inf_pres_Inf assms by blast
  hence  "(fb  fb-) (Φ) = (𝒫 (fb  fb-) Φ)"
    by (smt INF_identity_eq Sup.SUP_cong assms irfb_inv2)
  also have "... = (𝒫 fb (𝒫 fb- Φ))"
    by (simp add: image_comp)
  also have "... = fb ((𝒫 fb- Φ))"
    by (simp add: rfb_Sup_dual_var)
  finally have "(fb  fb-) (Φ) = fb ((𝒫 fb- Φ))".
  thus ?thesis
    by (simp add: rfb_inj_iff)
qed  

lemma irfb_sup_dual: "sup_dual fb-"
  by (force simp: fun_eq_iff irfb_def iffb_def f2r_def)

lemma irfb_inf_dual: 
  assumes "Inf_pres φ" 
  and "Inf_pres ψ"
  shows "fb- (φ  ψ) = fb- φ  fb- ψ"
  by (metis assms rfb_Inf_pres rfb_irfb_galois rfb_sup_dual)

lemma irfb_top_pres [simp]: "bd-  = UNIV"
  unfolding irbd_def f2r_def by auto

text ‹Finally, the adjunctions between the predicate transformers considered so far are revisited.›

lemma ffb_fbd_galois_var: "(bd f X  Y) = (X  fb f Y)"
  by (meson adj_def ffb_fbd_galois)

lemma rfb_rbd_galois_var: "(bd R X  Y) = (X  fb R Y)"
  by (meson adj_def rfb_rbd_galois)

lemma ffb_fbd: "fb f Y = {X. bd f X  Y}"
  using ffb_fbd_galois_var by fastforce

lemma rfb_rbd: "fb R Y = {X. bd R X  Y}"
  using rfb_rbd_galois_var by fastforce 

lemma fbd_ffb: "bd f X = {Y. X  fb f Y}"
  using ffb_fbd_galois_var by fastforce 

lemma rbd_rfb: "bd R X = {Y. X  fb R Y}"
  using rfb_rbd_galois_var by fastforce 


subsection ‹The Remaining Modalities›

text ‹Finally I set up the remaining dual transformers: forward diamonds and backward boxes. 
Most properties are not repeated, only some symmetries and dualities are spelled out.›

text ‹First, forward diamond operators are introduced, from state transformers and relations; together
with their inverses.›

definition ffd :: "('a  'b set)  'b set  'a set" (fd) where 
  "fd = bd  opK"

definition iffd :: "('b set  'a set)  'a  'b set" (fd-) where 
  "fd- = opK  bd-"

definition rfd :: "('a × 'b) set  'b set  'a set" (fd) where 
  "fd = fd  "

definition irfd :: "('b set  'a set)  ('a × 'b) set" (fd-) where 
  "fd- =   fd-"

text ‹Second, I introduce forward boxes and their inverses.›

definition fbb :: "('a  'b set)  'a set  'b set" (bb) where 
  "bb = fb  opK"

definition ifbb :: "('a  set  'b set)  'a  'b set" (bb-) where 
 "bb- = opK  fb-"

definition rbb :: "('a × 'b) set  'a set  'b set" (bb) where 
  "bb = bb  "

definition irbb :: "('a  set  'b set)  ('a × 'b) set" (bb-) where 
  "bb- =   bb-"

text ‹Forward and backward operators of the same type (box or diamond) are related by opposition.›

lemma rfd_rbd: "fd = bd  ()"
  by (simp add: rfd_def rbd_def ffd_def kop_def comp_assoc)

lemma irfd_irbd: "fd- = ()  bd-"
  by (simp add: irfd_def iffd_def kop_def irbd_def comp_assoc[symmetric])

lemma fbd_ffd: "bd = fd  opK"
  by (simp add: ffd_def kop_def converse_def f2r_def r2f_def klift_def fun_eq_iff)

lemma rbb_rfb: "bb = fb  ()"
  by (simp add: rfb_def rbb_def, metis fbb_def kop_def r2f_f2r_galois_var2 rewriteR_comp_comp2)

lemma irbb_irfb: "bb- = ()  fb-"
proof-
  have "bb- =   opK  fb-"
    by (simp add: irbb_def ifbb_def o_assoc)
  also have "... =     ()    fb-"
    by (simp add: kop_def o_assoc)
  also have "... = ()  fb-"
    by (simp add: comp_assoc irfb_def)
  finally show ?thesis.
qed

text ‹Complementation is a natural isomorphism between forwards and backward operators of different type.›

lemma ffd_ffb_demorgan: "  fd f = fb f  "
  by (simp add: comp_assoc ffb_prop ffd_def)

lemma iffd_iffb_demorgan: "Sup_pres φ  fd- φ = (fb-  F) φ"
  by (smt Sup_pres_Inf_pres comp_apply iffb_ifbd_dual iffd_def map_dual_dual)

lemma ffb_ffd_demorgan: "  fb f = fd f  "
  by (simp add: ffb_prop ffd_def rewriteL_comp_comp)

lemma iffb_iffd_demorgan: "Inf_pres φ  fb- φ = (fd-  F) φ"
  by (simp add: iffb_ifbd_dual iffd_def)

lemma rfd_rfb_demorgan: "  fd R = fb R  "
  by (simp add: rfb_def rfd_def ffd_ffb_demorgan)

lemma irfd_irfb_demorgan: "Sup_pres φ  fd- φ = (fb-  F) φ"
  by (simp add: irfb_def irfd_def iffd_iffb_demorgan)

lemma rfb_rfd_demorgan: "  fb R = fd R  "
  by (simp add: ffb_ffd_demorgan rfb_def rfd_def)

lemma irfb_irfd_demorgan: "Inf_pres φ  fb- φ  = (fd-  F) φ"
  by (simp add: irfb_irbd_dual irfd_irbd)

lemma fbd_fbb_demorgan: "  bd f = bb f  "   
  by (simp add: fbb_def fbd_ffd ffd_ffb_demorgan)

lemma ifbd_ifbb_demorgan: "Sup_pres φ  bd- φ = (bb-  F) φ"
  by (simp add: ifbd_iffb_dual ifbb_def)  

lemma fbb_fbd_demorgan: "  bb R = bd R  "
  by (simp add: fbb_def fbd_ffd ffb_ffd_demorgan)

lemma ifbb_ifbd_demorgan: "Inf_pres φ  bb- φ = (bd-  F) φ"
proof-
  assume h: "Inf_pres φ"
  have "bb- φ = (opK  fb-) φ"
    by (simp add: ifbb_def)
  also have "... = (opK  opK  bd-) (F φ)"
    by (metis comp_apply h iffb_ifbd_dual) 
  also have "... = (bd-  F) φ"
    by auto
  finally show ?thesis.
qed

lemma rbd_rbb_demorgan: "  bd R = bb R  "
  by (simp add: rbb_def rbd_def fbd_fbb_demorgan)

lemma irbd_irbb_demorgan: "Sup_pres φ  bd- φ = (bb-  F) φ"
  by (simp add: irbb_irfb irbd_irfb_dual)

lemma rbb_rbd_demorgan: "  bb R = bd R  "
  by (simp add: rbb_def rbd_def fbb_fbd_demorgan)

lemma irbb_irbd_demorgan: "Inf_pres φ  bb- φ = (bd-  F) φ"
  by (simp add: irbb_def irbd_def ifbb_ifbd_demorgan)

text ‹Further symmetries arise by combination.›

lemma ffd_fbb_dual: "  fd f = bb (opK f)  "
  by (simp add: fbd_fbb_demorgan ffd_def)

lemma iffd_ifbb_dual: "Sup_pres φ  fd- φ = (opK  bb-  F) φ"
  by (simp add: ifbd_ifbb_demorgan iffd_def)  

lemma fbb_ffd_dual: "  bb f = fd (opK f)  "
  by (simp add: fbd_ffd fbb_fbd_demorgan) 

lemma ifbb_iffd_dual: "Inf_pres φ  bb- φ = (opK  fd-  F) φ"
  by (simp add: ifbb_def iffb_iffd_demorgan)

lemma rfd_rbb_dual: "  fd R = bb (R¯)  "
  by (metis fun_dual1 map_dual_def rbd_rbb_demorgan rfb_rbd_dual rfd_rfb_demorgan)

lemma ifd_ibb_dual: "Sup_pres φ  fd- φ = (()  bb-  F) φ"
  by (simp add: irbb_irfb irbd_irfb_dual irfd_irbd)
 
lemma rbb_rfd_dual: "  bb R = fd (R¯)  "
  by (simp add: rbb_rfb rfb_rfd_demorgan)

lemma irbb_irfd_dual: "Inf_pres φ  bb- φ = (()  fd-  F) φ"
  by (simp add: irbb_irfb irfb_irbd_dual irfd_irbd)

lemma ffd_iffd_galois: "Sup_pres φ  (φ = fd f) = (f = fd- φ)"
  unfolding ffd_def iffd_def by (metis comp_apply fbd_surj klift_eta_inv1 kop_galois)

lemma rfd_irfd_galois: "Sup_pres φ  (φ = fd R) = (R = fd- φ)"
  unfolding irfd_def rfd_def by (metis comp_apply ffd_iffd_galois r2f_f2r_galois)

lemma fbb_ifbb_galois: "Inf_pres φ  (φ = bb f) = (f = bb- φ)"
  unfolding fbb_def iffb_def by (metis (no_types, lifting) comp_apply ffb_iffb_galois ifbb_ifbd_demorgan iffb_ifbd_dual kop_galois)

lemma rbb_irbb_galois: "Inf_pres φ  (φ = bb R) = (R = bb- φ)"
  apply (simp add: rbb_def irbb_def) using fbb_ifbb_galois r2f_f2r_galois by blast

text ‹Next I spell out the missing adjunctions.›

lemma ffd_ffb_adj: "fd f  bb f"
  by (simp add: fbb_def ffb_fbd_galois ffd_def)

lemma ffd_fbb_galois: "(fd f X  Y) = (X  bb f Y)"
  by (simp add: fbb_def ffb_fbd_galois_var ffd_def)

lemma rfd_rfb_adj: "fd f  bb f"
  by (simp add: ffd_ffb_adj rbb_def rfd_def)

lemma rfd_rbb_galois: "(fd R X  Y) = (X  bb R Y)"
  by (simp add: ffd_fbb_galois rbb_def rfd_def)

text ‹Finally, forward and backward operators of the same type are linked by conjugation.›

lemma ffd_fbd_conjugation: "(fd f X  Y = {}) = (X  bd f Y = {})"
proof-
  have "(fd f X  Y = {}) = (fd f X  -Y)"
    by (simp add: disjoint_eq_subset_Compl)
  also have "... = (X  bb f (-Y))"
    by (simp add: ffd_fbb_galois)
  also have "... = (X  - bb f (-Y) = {})"
    by (simp add: disjoint_eq_subset_Compl)
  also have "... = (X   (bb f ( Y)) = {})"
    by (simp add: dual_set_def)
  finally show ?thesis
    by (metis (no_types, opaque_lifting) comp_apply fbb_fbd_demorgan invol_dual_var)
qed

lemma rfd_rbd_conjugation: "((fd R X)  Y = {}) = (X  (bd R Y) = {})"
  by (simp add: rbd_def rfd_def ffd_fbd_conjugation) 

lemma ffb_fbb_conjugation: "((fb f X)  Y = UNIV) = (X  (bb f Y) = UNIV)" 
proof-
  have "((fb f X)  Y = UNIV) = (-Y  fb f X)"
    by blast
  also have "... = (bd f ( Y)  X)"
    by (simp add: ffb_fbd_galois_var dual_set_def)
  also have "... = ( (bb f Y)  X)"
    by (metis comp_def fbb_fbd_demorgan)
  also have "... = (X  (bb f Y) = UNIV)"
    by (metis compl_le_swap2 dual_set_def sup_shunt)
    finally show ?thesis.
qed

lemma rfb_rbb_conjugation: "((fb R X)  Y = UNIV) = (X  (bb R Y) = UNIV)" 
  by (simp add: rfb_def rbb_def ffb_fbb_conjugation) 

end