Theory MonoBoolTranAlgebra.Mono_Bool_Tran_Algebra

section ‹Algebra of Monotonic Boolean Transformers›

theory  Mono_Bool_Tran_Algebra
imports Mono_Bool_Tran
begin

text‹
In this section we introduce the {\em algebra of monotonic boolean transformers}.
This is a bounded distributive lattice with a monoid operation, a
dual operator and an iteration operator. The standard model for this
algebra is the set of monotonic boolean transformers introduced
in the previous section. 
›

class dual = 
  fixes dual::"'a ⇒ 'a" (‹_ ^ o› [81] 80)

class omega = 
  fixes omega::"'a ⇒ 'a" (‹_ ^ ω› [81] 80)

class star = 
  fixes star::"'a ⇒ 'a" (‹(_ ^ *)› [81] 80)

class dual_star = 
  fixes dual_star::"'a ⇒ 'a" (‹(_ ^ ⊗)› [81] 80)

class mbt_algebra = monoid_mult + dual + omega + distrib_lattice + order_top + order_bot + star + dual_star +
  assumes
      dual_le: "(x ≤ y) = (y ^ o ≤ x ^ o)"
  and dual_dual [simp]: "(x ^ o) ^ o = x"
  and dual_comp: "(x * y) ^ o = x ^ o * y ^ o"
  and dual_one [simp]: "1 ^ o = 1"
  and top_comp [simp]: "⊤ * x = ⊤"
  and inf_comp: "(x ⊓ y) * z = (x * z) ⊓ (y * z)"
  and le_comp: "x ≤ y ⟹ z * x ≤ z * y"
  and dual_neg: "(x * ⊤) ⊓ (x ^ o * ⊥) = ⊥"
  and omega_fix: "x ^ ω = (x * (x ^ ω)) ⊓ 1"
  and omega_least: "(x * z) ⊓ y ≤ z ⟹ (x ^ ω) * y ≤ z"
  and star_fix: "x ^ * = (x * (x ^ *)) ⊓ 1"
  and star_greatest: "z ≤ (x * z) ⊓ y ⟹ z ≤ (x ^ *) * y"
  and dual_star_def: "(x ^ ⊗) = (((x ^ o) ^ *) ^ o)"
begin

lemma le_comp_right: "x ≤ y ⟹ x * z ≤ y * z"
  apply (cut_tac x = x and y = y and z = z in inf_comp)
  apply (simp add: inf_absorb1)
  apply (subgoal_tac "x * z ⊓ (y * z) ≤ y * z")
  apply simp
  by (rule inf_le2)

subclass bounded_lattice
  proof qed

end

instantiation MonoTran :: (complete_boolean_algebra) mbt_algebra
begin

lift_definition dual_MonoTran :: "'a MonoTran ⇒ 'a MonoTran"
  is dual_fun
  by (fact mono_dual_fun)

lift_definition omega_MonoTran :: "'a MonoTran ⇒ 'a MonoTran"
  is omega_fun
  by (fact mono_omega_fun)

lift_definition star_MonoTran :: "'a MonoTran ⇒ 'a MonoTran"
  is star_fun
  by (fact mono_star_fun)

definition dual_star_MonoTran :: "'a MonoTran ⇒ 'a MonoTran"
where
  "(x::('a MonoTran)) ^ ⊗ = ((x ^ o) ^ *) ^ o"
  
instance proof
  fix x y :: "'a MonoTran" show "(x ≤ y) = (y ^ o ≤ x ^ o)"
    apply transfer
    apply (auto simp add: fun_eq_iff le_fun_def)
    apply (drule_tac x = "-xa" in spec)
    apply simp
    done
next
  fix x :: "'a MonoTran" show "(x ^ o) ^ o = x"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
next
  fix x y :: "'a MonoTran" show "(x * y) ^ o = x ^ o * y ^ o"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
next
  show "(1::'a MonoTran) ^ o = 1"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
next
  fix x :: "'a MonoTran" show "⊤ * x = ⊤"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
next
  fix x y z :: "'a MonoTran" show "(x ⊓ y) * z = (x * z) ⊓ (y * z)"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
next
  fix x y z :: "'a MonoTran" assume A: "x ≤ y" from A show " z * x ≤ z * y"
    apply transfer
    apply (auto simp add: le_fun_def elim: monoE)
    done
next
  fix x :: "'a MonoTran" show "x * ⊤ ⊓ (x ^ o * ⊥) = ⊥"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
next
  fix x :: "'a MonoTran" show "x ^ ω = x * x ^ ω ⊓ 1"
    apply transfer
    apply (simp add: fun_eq_iff)
    apply (simp add: omega_fun_def Omega_fun_def)
    apply (subst lfp_unfold, simp_all add: ac_simps)
    apply (auto intro!: mono_comp mono_comp_fun)
    done
next
  fix x y z :: "'a MonoTran" assume A: "x * z ⊓ y ≤ z" from A show "x ^ ω * y ≤ z"
    apply transfer
    apply (auto simp add: lfp_omega lfp_def)
    apply (rule Inf_lower)
    apply (auto simp add: Omega_fun_def ac_simps)
    done
next
  fix x :: "'a MonoTran" show "x ^ * = x * x ^ * ⊓ 1"
    apply transfer
    apply (auto simp add: star_fun_def Omega_fun_def)
    apply (subst gfp_unfold, simp_all add: ac_simps)
    apply (auto intro!: mono_comp mono_comp_fun)
    done
next
  fix x y z :: "'a MonoTran" assume A: "z ≤ x * z ⊓ y" from A show "z ≤ x ^ * * y"
    apply transfer
    apply (auto simp add: gfp_star gfp_def)
    apply (rule Sup_upper)
    apply (auto simp add: Omega_fun_def)
    done
next
  fix x :: "'a MonoTran" show "x ^ ⊗ = ((x ^ o) ^ *) ^ o"
    by (simp add: dual_star_MonoTran_def) 
qed

end

context mbt_algebra begin

lemma dual_top [simp]: "⊤ ^ o = ⊥"
  apply (rule order.antisym, simp_all)
  by (subst dual_le, simp)

lemma dual_bot [simp]: "⊥ ^ o = ⊤"
  apply (rule order.antisym, simp_all)
  by (subst dual_le, simp)

lemma dual_inf: "(x ⊓ y) ^ o = (x ^ o) ⊔ (y ^ o)"
  apply (rule order.antisym, simp_all, safe)
  apply (subst dual_le, simp, safe)
  apply (subst dual_le, simp)
  apply (subst dual_le, simp)
  apply (subst dual_le, simp)
  by (subst dual_le, simp)

lemma dual_sup: "(x ⊔ y) ^ o = (x ^ o) ⊓ (y ^ o)"
  apply (rule order.antisym, simp_all, safe)
  apply (subst dual_le, simp)
  apply (subst dual_le, simp)
  apply (subst dual_le, simp, safe)
  apply (subst dual_le, simp)
  by (subst dual_le, simp)

lemma sup_comp: "(x ⊔ y) * z = (x * z) ⊔ (y * z)"
  apply (subgoal_tac "((x ^ o ⊓ y ^ o) * z ^ o) ^ o = ((x ^ o * z ^ o) ⊓ (y ^ o * z ^ o)) ^ o")
  apply (simp add: dual_inf dual_comp)
  by (simp add: inf_comp)


lemma dual_eq: "x ^ o = y ^ o ⟹ x = y"
  apply (subgoal_tac "(x ^ o) ^ o = (y ^ o) ^ o")
  apply (subst (asm) dual_dual)
  apply (subst (asm) dual_dual)
  by simp_all

lemma dual_neg_top [simp]: "(x ^ o * ⊥) ⊔ (x * ⊤) = ⊤"
  apply (rule dual_eq)
  by(simp add: dual_sup dual_comp dual_neg)

 lemma bot_comp [simp]: "⊥ * x = ⊥"
   by (rule dual_eq, simp add: dual_comp)

lemma [simp]: "(x * ⊤) * y = x * ⊤" 
  by (simp add: mult.assoc)

lemma [simp]: "(x * ⊥) * y = x * ⊥" 
  by (simp add: mult.assoc)


lemma gt_one_comp: "1 ≤ x ⟹ y ≤ x * y"
  by (cut_tac x = 1 and y = x and z = y in le_comp_right, simp_all)


  theorem omega_comp_fix: "x ^ ω * y = (x * (x ^ ω) * y) ⊓ y"
  apply (subst omega_fix)
  by (simp add: inf_comp)

  theorem dual_star_fix: "x^⊗ = (x * (x^⊗)) ⊔ 1"
    by (metis dual_comp dual_dual dual_inf dual_one dual_star_def star_fix)

  theorem star_comp_fix: "x ^ * * y = (x * (x ^ *) * y) ⊓ y"
  apply (subst star_fix)
  by (simp add: inf_comp)

  theorem dual_star_comp_fix: "x^⊗ * y = (x * (x^⊗) * y) ⊔ y"
  apply (subst dual_star_fix)
  by (simp add: sup_comp)

  theorem dual_star_least: "(x * z) ⊔ y ≤ z ⟹ (x^⊗) * y ≤ z"
    apply (subst dual_le)
    apply (simp add: dual_star_def dual_comp)
    apply (rule star_greatest)
    apply (subst dual_le)
    by (simp add: dual_inf dual_comp)

  lemma omega_one [simp]: "1 ^ ω = ⊥"
    apply (rule order.antisym, simp_all)
    by (cut_tac x = "1::'a" and y = 1 and z = ⊥ in omega_least, simp_all)

  lemma omega_mono: "x ≤ y ⟹ x ^ ω ≤ y ^ ω"
    apply (cut_tac x = x and y = 1 and z = "y ^ ω" in omega_least, simp_all)
    apply (subst (2) omega_fix, simp_all)
    apply (rule_tac y = "x * y ^ ω" in order_trans, simp)
    by (rule le_comp_right, simp)
end

sublocale mbt_algebra < conjunctive "inf" "inf" "times"
done
sublocale mbt_algebra < disjunctive "sup" "sup" "times"
done

context mbt_algebra begin
lemma dual_conjunctive: "x ∈ conjunctive ⟹ x ^ o ∈ disjunctive"
  apply (simp add: conjunctive_def disjunctive_def)
  apply safe
  apply (rule dual_eq)
  by (simp add: dual_comp dual_sup)

lemma dual_disjunctive: "x ∈ disjunctive ⟹ x ^ o ∈ conjunctive"
  apply (simp add: conjunctive_def disjunctive_def)
  apply safe
  apply (rule dual_eq)
  by (simp add: dual_comp dual_inf)

lemma comp_pres_conj: "x ∈ conjunctive ⟹ y ∈ conjunctive ⟹ x * y ∈ conjunctive"
  apply (subst conjunctive_def, safe)
  by (simp add: mult.assoc conjunctiveD)

lemma comp_pres_disj: "x ∈ disjunctive ⟹ y ∈ disjunctive ⟹ x * y ∈ disjunctive"
  apply (subst disjunctive_def, safe)
  by (simp add: mult.assoc disjunctiveD)

lemma start_pres_conj: "x ∈ conjunctive ⟹ (x ^ *) ∈ conjunctive"
  apply (subst conjunctive_def, safe)
  apply (rule order.antisym, simp_all)
  apply (metis inf_le1 inf_le2 le_comp)
  apply (rule star_greatest)
  apply (subst conjunctiveD, simp)
  apply (subst star_comp_fix)
  apply (subst star_comp_fix)
  by (metis inf.assoc inf_left_commute mult.assoc order_refl)

lemma dual_star_pres_disj: "x ∈ disjunctive ⟹ x^⊗ ∈ disjunctive"
  apply (simp add: dual_star_def)
  apply (rule dual_conjunctive)
  apply (rule start_pres_conj)
  by (rule dual_disjunctive, simp)

subsection‹Assertions›

text‹
Usually, in Kleene algebra with tests or in other progrm algebras, tests or assertions
or assumptions are defined using an existential quantifier. An element of the algebra
is a test if it has a complement with respect to $\bot$ and $1$. In this formalization
assertions can be defined much simpler using the dual operator.
›

definition
   "assertion = {x . x ≤ 1 ∧ (x * ⊤) ⊓ (x ^ o) = x}"

lemma assertion_prop: "x ∈ assertion ⟹ (x * ⊤) ⊓ 1 = x"
  apply (simp add: assertion_def)
  apply safe
  apply (rule order.antisym)
  apply simp_all
  proof -
    assume [simp]: "x ≤ 1"
    assume A: "x * ⊤ ⊓ x ^ o = x"
    have "x * ⊤ ⊓ 1 ≤ x * ⊤ ⊓ x ^ o"
      apply simp
      apply (rule_tac y = 1 in order_trans)
      apply simp
      apply (subst dual_le)
      by simp
    also have "… = x" by (cut_tac A, simp)
    finally show "x * ⊤ ⊓ 1 ≤ x" .
  next
    assume A: "x * ⊤ ⊓ x ^ o = x"
    have "x = x * ⊤ ⊓ x ^ o" by (simp add: A)
    also have "… ≤ x * ⊤" by simp
    finally show "x ≤ x * ⊤" .
  qed

lemma dual_assertion_prop: "x ∈ assertion ⟹ ((x ^ o) * ⊥) ⊔ 1 = x ^ o"
  apply (rule dual_eq)
  by (simp add: dual_sup dual_comp assertion_prop)

lemma assertion_disjunctive: "x ∈ assertion ⟹ x ∈ disjunctive"
  apply (simp add: disjunctive_def, safe)
  apply (drule assertion_prop)
  proof -
    assume A: "x * ⊤ ⊓ 1 = x"
    fix y z::"'a"
    have "x * (y ⊔ z) = (x * ⊤ ⊓ 1) * (y ⊔ z)" by (cut_tac  A, simp)
    also have "… = (x * ⊤) ⊓ (y ⊔ z)" by (simp add: inf_comp)
    also have "… = ((x * ⊤) ⊓ y) ⊔ ((x * ⊤) ⊓ z)" by (simp add: inf_sup_distrib)
    also have "… = (((x * ⊤) ⊓ 1) * y) ⊔ (((x * ⊤) ⊓ 1) * z)" by (simp add: inf_comp)
    also have "… = x * y ⊔ x * z" by (cut_tac  A, simp)
    finally show "x * (y ⊔ z) = x * y ⊔ x * z" .
  qed

lemma Abs_MonoTran_injective: "mono x ⟹ mono y ⟹ Abs_MonoTran x = Abs_MonoTran y ⟹ x = y"
  apply (subgoal_tac "Rep_MonoTran (Abs_MonoTran x) = Rep_MonoTran (Abs_MonoTran y)")
  apply (subst (asm) Abs_MonoTran_inverse, simp)
  by (subst (asm) Abs_MonoTran_inverse, simp_all)
end

lemma mbta_MonoTran_disjunctive: "Rep_MonoTran ` disjunctive = Apply.disjunctive"
  apply (simp add: disjunctive_def Apply.disjunctive_def)
  apply transfer
  apply auto
  proof -
    fix f :: "'a ⇒ 'a" and a b
    assume prem: "∀y. mono y ⟶ (∀z. mono z ⟶ f ∘ y ⊔ z = (f ∘ y) ⊔ (f ∘ z))"
    { fix g h :: "'b ⇒ 'a"
      assume "mono g" and "mono h"
      then have "f ∘ g ⊔ h = (f ∘ g) ⊔ (f ∘ h)"
        using prem by blast
    } note * = this
    assume "mono f"
    show "f (a ⊔ b) = f a ⊔ f b" (is "?P = ?Q")
    proof (rule order_antisym)
      show "?P ≤ ?Q"
        using * [of "λ_. a" "λ_. b"] by (simp add: comp_def fun_eq_iff)
    next
      from ‹mono f› show "?Q ≤ ?P"
        using Fun.semilattice_sup_class.mono_sup by blast
    qed
  next
    fix f :: "'a ⇒ 'a"
    assume "∀y z. f (y ⊔ z) = f y ⊔ f z"
    then have *: "⋀y z. f (y ⊔ z) = f y ⊔ f z" by blast
    show "mono f"
    proof
      fix a b :: 'a
      assume "a ≤ b"
      then show "f a ≤ f b"
        unfolding sup.order_iff * [symmetric] by simp
    qed
  qed

lemma assertion_MonoTran: "assertion = Abs_MonoTran ` assertion_fun"
    apply (safe)
    apply (subst assertion_fun_disj_less_one)
    apply (simp add: image_def)
    apply (rule_tac x = "Rep_MonoTran x" in bexI)
    apply (simp add: Rep_MonoTran_inverse)
    apply safe
    apply (drule assertion_disjunctive)
    apply (unfold mbta_MonoTran_disjunctive [THEN sym], simp)
    apply (simp add: assertion_def less_eq_MonoTran_def one_MonoTran_def Abs_MonoTran_inverse)
    apply (simp add: assertion_def)
    by (simp_all add: inf_MonoTran_def less_eq_MonoTran_def 
      times_MonoTran_def dual_MonoTran_def top_MonoTran_def Abs_MonoTran_inverse one_MonoTran_def assertion_fun_dual)

context mbt_algebra begin
lemma assertion_conjunctive: "x ∈ assertion ⟹ x ∈ conjunctive"
  apply (simp add: conjunctive_def, safe)
  apply (drule assertion_prop)
  proof -
    assume A: "x * ⊤ ⊓ 1 = x"
    fix y z::"'a"
    have "x * (y ⊓ z) = (x * ⊤ ⊓ 1) * (y ⊓ z)" by (cut_tac  A, simp)
    also have "… = (x * ⊤) ⊓ (y ⊓ z)" by (simp add: inf_comp)
    also have "… = ((x * ⊤) ⊓ y) ⊓ ((x * ⊤) ⊓ z)"
      apply (rule order.antisym, simp_all, safe)
      apply (rule_tac y = "y ⊓ z" in order_trans)
      apply (rule inf_le2)
      apply simp
      apply (rule_tac y = "y ⊓ z" in order_trans)
      apply (rule inf_le2)
      apply simp_all
      apply (simp add: inf_assoc)
      apply (rule_tac y = " x * ⊤ ⊓ y" in order_trans)
      apply (rule inf_le1)
      apply simp
      apply (rule_tac y = " x * ⊤ ⊓ z" in order_trans)
      apply (rule inf_le2)
      by simp
    also have "… = (((x * ⊤) ⊓ 1) * y) ⊓ (((x * ⊤) ⊓ 1) * z)" by (simp add: inf_comp)
    also have "… = (x * y) ⊓ (x * z)" by (cut_tac  A, simp)
    finally show "x * (y ⊓ z) = (x * y) ⊓ (x * z)" .
  qed

lemma dual_assertion_conjunctive: "x ∈ assertion ⟹ x ^ o ∈ conjunctive"
  apply (drule assertion_disjunctive)
  by (rule dual_disjunctive, simp)

lemma dual_assertion_disjunct: "x ∈ assertion ⟹ x ^ o ∈ disjunctive"
  apply (drule assertion_conjunctive)
  by (rule dual_conjunctive, simp)


lemma [simp]: "x ∈ assertion ⟹ y ∈ assertion ⟹ x ⊓ y ≤ x * y"
  apply (simp add: assertion_def, safe)
  proof -
  assume A: "x ≤ 1"
  assume B: "x * ⊤ ⊓ x ^ o = x"
  assume C: "y ≤ 1"
  assume D: "y * ⊤ ⊓ y ^ o = y"
  have "x ⊓ y = (x * ⊤ ⊓ x ^ o) ⊓ (y * ⊤ ⊓ y ^ o)" by (cut_tac B D, simp)
  also have "… ≤ (x * ⊤) ⊓ (((x^o) * (y * ⊤)) ⊓ ((x^o) * (y^o)))"
    apply (simp, safe)
      apply (rule_tac y = "x * ⊤ ⊓ x ^ o" in order_trans)
      apply (rule inf_le1)
      apply simp
      apply (rule_tac y = "y * ⊤" in order_trans)
      apply (rule_tac y = "y * ⊤ ⊓ y ^ o" in order_trans)
      apply (rule inf_le2)
      apply simp
      apply (rule gt_one_comp)
      apply (subst dual_le, simp add: A)
      apply (rule_tac y = "y ^ o" in order_trans)
      apply (rule_tac y = "y * ⊤ ⊓ y ^ o" in order_trans)
      apply (rule inf_le2)
      apply simp
      apply (rule gt_one_comp)
      by (subst dual_le, simp add: A)
    also have "... = ((x * ⊤) ⊓ (x ^ o)) * ((y * ⊤) ⊓ (y ^ o))"
      apply (cut_tac x = x in dual_assertion_conjunctive)
      apply (cut_tac A, cut_tac B, simp add: assertion_def)
      by (simp add: inf_comp conjunctiveD)
    also have "... = x * y"
      by (cut_tac B, cut_tac D, simp)
    finally show "x ⊓ y ≤ x * y" .
  qed
    
lemma [simp]: "x ∈ assertion ⟹ x * y ≤ y"
  by (unfold assertion_def, cut_tac x = x and y = 1 and z = y in le_comp_right, simp_all)


lemma [simp]: "x ∈ assertion ⟹ y ∈ assertion ⟹ x * y ≤ x"
  apply (subgoal_tac "x * y ≤ (x * ⊤) ⊓ (x ^ o)")
  apply (simp add: assertion_def) 
  apply (simp, safe)
  apply (rule le_comp, simp)
  apply (rule_tac y = 1 in order_trans)
  apply (rule_tac y = y in order_trans)
  apply simp
  apply (simp add: assertion_def)
  by (subst dual_le, simp add: assertion_def)

lemma assertion_inf_comp_eq: "x ∈ assertion ⟹ y ∈ assertion ⟹ x ⊓ y = x * y"
  by (rule order.antisym, simp_all)

lemma one_right_assertion [simp]: "x ∈ assertion ⟹ x * 1 = x"
  apply (drule assertion_prop)
  proof -
    assume A: "x * ⊤ ⊓ 1 = x"
    have "x * 1 = (x * ⊤ ⊓ 1) * 1" by (simp add: A)
    also have "… = x * ⊤ ⊓ 1" by (simp add: inf_comp)
    also have "… = x" by (simp add: A)
    finally show ?thesis .
  qed

lemma [simp]: "x ∈ assertion ⟹ x ⊔ 1 = 1"
  by (rule order.antisym, simp_all add: assertion_def)
  
lemma [simp]: "x ∈ assertion ⟹ 1 ⊔ x = 1"
  by (rule order.antisym, simp_all add: assertion_def)
  
lemma [simp]: "x ∈ assertion ⟹ x ⊓ 1 = x"
  by (rule order.antisym, simp_all add: assertion_def)
  
lemma [simp]: "x ∈ assertion ⟹ 1 ⊓ x = x"
  by (rule order.antisym, simp_all add: assertion_def)

lemma [simp]:  "x ∈ assertion ⟹ x ≤ x * ⊤"
  by (cut_tac x = 1 and y = ⊤ and z = x in le_comp, simp_all)

lemma [simp]: "x ∈ assertion ⟹ x ≤ 1"
  by (simp add: assertion_def)

definition
  "neg_assert (x::'a) = (x ^ o * ⊥) ⊓ 1"
  

lemma sup_uminus[simp]: "x ∈ assertion ⟹ x ⊔ neg_assert x = 1"
  apply (simp add: neg_assert_def)
  apply (simp add: sup_inf_distrib)
  apply (rule order.antisym, simp_all)
  apply (unfold assertion_def)
  apply safe
  apply (subst dual_le)
  apply (simp add: dual_sup dual_comp)
  apply (subst inf_commute)
  by simp

lemma inf_uminus[simp]: "x ∈ assertion ⟹ x ⊓ neg_assert x = ⊥"
  apply (simp add: neg_assert_def)
  apply (rule order.antisym, simp_all)
  apply (rule_tac y = "x ⊓ (x ^ o * ⊥)" in order_trans)
  apply simp
  apply (rule_tac y = "x ^ o * ⊥ ⊓ 1" in order_trans)
  apply (rule inf_le2)
  apply simp
  apply (rule_tac y = "(x * ⊤)  ⊓ (x ^ o * ⊥)" in order_trans)
  apply simp
  apply (rule_tac y = x in order_trans)
  apply simp_all
  by (simp add: dual_neg)


lemma uminus_assertion[simp]: "x ∈ assertion ⟹ neg_assert x ∈ assertion"
  apply (subst assertion_def)
  apply (simp add: neg_assert_def)
  apply (simp add: inf_comp dual_inf dual_comp inf_sup_distrib)
  apply (subst inf_commute)
  by (simp add: dual_neg)

lemma uminus_uminus [simp]: "x ∈ assertion ⟹ neg_assert (neg_assert x) = x"
  apply (simp add: neg_assert_def)
  by (simp add: dual_inf dual_comp sup_comp assertion_prop)

lemma dual_comp_neg [simp]: "x ^ o * y ⊔ (neg_assert x) * ⊤ = x ^ o * y"
  apply (simp add: neg_assert_def inf_comp)
  apply (rule order.antisym, simp_all)
  by (rule le_comp, simp)


lemma [simp]: "(neg_assert x) ^ o * y ⊔ x * ⊤ = (neg_assert x) ^ o * y"
  apply (simp add: neg_assert_def inf_comp dual_inf dual_comp sup_comp)
  by (rule order.antisym, simp_all)

lemma [simp]: " x * ⊤ ⊔ (neg_assert x) ^ o * y= (neg_assert x) ^ o * y"
  by (simp add: neg_assert_def inf_comp dual_inf dual_comp sup_comp)

lemma inf_assertion [simp]: "x ∈ assertion ⟹ y ∈ assertion ⟹ x ⊓ y ∈ assertion"
  apply (subst assertion_def)
  apply safe
  apply (rule_tac y = x in order_trans)
  apply simp_all
  apply (simp add: assertion_inf_comp_eq)
  proof -
    assume A: "x ∈ assertion"
    assume B: "y ∈ assertion"
    have C: "(x * ⊤) ⊓ (x ^ o) = x"
      by (cut_tac A, unfold assertion_def, simp) 
    have D: "(y * ⊤) ⊓ (y ^ o) = y"
      by (cut_tac B, unfold assertion_def, simp)
    have "x * y = ((x * ⊤) ⊓ (x ^ o)) * ((y * ⊤) ⊓ (y ^ o))" by (simp add: C D)
    also have "… = x * ⊤ ⊓ ((x ^ o) * ((y * ⊤) ⊓ (y ^ o)))" by (simp add: inf_comp)
    also have "… =  x * ⊤ ⊓ ((x ^ o) * (y * ⊤)) ⊓ ((x ^ o) *(y ^ o))" 
      by (cut_tac A, cut_tac x = x in dual_assertion_conjunctive, simp_all add: conjunctiveD inf_assoc)
    also have "… = (((x * ⊤) ⊓ (x ^ o)) * (y * ⊤)) ⊓ ((x ^ o) *(y ^ o))"
      by (simp add: inf_comp)
    also have "… = (x * y * ⊤)  ⊓ ((x * y) ^ o)" by (simp add: C mult.assoc dual_comp)
    finally show "(x * y * ⊤)  ⊓ ((x * y) ^ o) = x * y" by simp
  qed

lemma comp_assertion [simp]: "x ∈ assertion ⟹ y ∈ assertion ⟹ x * y ∈ assertion"
  by (subst assertion_inf_comp_eq [THEN sym], simp_all)


lemma sup_assertion [simp]: "x ∈ assertion ⟹ y ∈ assertion ⟹ x ⊔ y ∈ assertion"
  apply (subst assertion_def)
  apply safe
  apply (unfold assertion_def)
  apply simp
  apply safe
  proof -
    assume [simp]: "x ≤ 1"
    assume [simp]: "y ≤ 1"
    assume A: "x * ⊤ ⊓ x ^ o = x"
    assume B: "y * ⊤ ⊓ y ^ o = y"
    have "(y * ⊤) ⊓ (x ^ o) ⊓ (y ^ o) = (x ^ o) ⊓ (y * ⊤) ⊓ (y ^ o)" by (simp add: inf_commute)
    also have "… = (x ^ o) ⊓ ((y * ⊤) ⊓ (y ^ o))" by (simp add: inf_assoc)
    also have "… = (x ^ o) ⊓ y" by (simp add: B)
    also have "… = y"
      apply (rule order.antisym, simp_all)
      apply (rule_tac y = 1 in order_trans)
      apply simp
      by (subst dual_le, simp)
    finally have [simp]: "(y * ⊤) ⊓ (x ^ o) ⊓ (y ^ o) = y" .
    have "x * ⊤ ⊓ (x ^ o) ⊓ (y ^ o) = x ⊓ (y ^ o)"  by (simp add: A)
    also have "… = x"
      apply (rule order.antisym, simp_all)
      apply (rule_tac y = 1 in order_trans)
      apply simp
      by (subst dual_le, simp)
    finally have [simp]: "x * ⊤ ⊓ (x ^ o) ⊓ (y ^ o) = x" .
    have "(x ⊔ y) * ⊤ ⊓ (x ⊔ y) ^ o = (x * ⊤ ⊔ y * ⊤) ⊓ ((x ^ o) ⊓ (y ^ o))" by (simp add: sup_comp dual_sup)
    also have "… = x ⊔ y" by (simp add: inf_sup_distrib inf_assoc [THEN sym])
    finally show "(x ⊔ y) * ⊤ ⊓ (x ⊔ y) ^ o = x ⊔ y" .
  qed

lemma [simp]: "x ∈ assertion ⟹ x * x = x"
  by (simp add: assertion_inf_comp_eq [THEN sym])

lemma [simp]: "x ∈ assertion ⟹ (x ^ o) * (x ^ o) = x ^ o"
  apply (rule dual_eq)
  by (simp add: dual_comp assertion_inf_comp_eq [THEN sym])

lemma [simp]: "x ∈ assertion ⟹ x * (x ^ o) = x"
  proof -
    assume A: "x ∈ assertion"
    have B: "x * ⊤ ⊓ (x ^ o) = x" by (cut_tac A, unfold assertion_def, simp)
    have "x * x ^ o = (x * ⊤ ⊓ (x ^ o)) * x ^ o" by (simp add: B)
    also have "… = x * ⊤ ⊓ (x ^ o)" by (cut_tac A, simp add: inf_comp)
    also have "… = x" by (simp add: B)
    finally show ?thesis .
  qed

lemma [simp]: "x ∈ assertion ⟹ (x ^ o) * x = x ^ o"
  apply (rule dual_eq)
  by (simp add: dual_comp)


lemma [simp]: "⊥ ∈ assertion"
  by (unfold assertion_def, simp)

lemma [simp]: "1 ∈ assertion"
  by (unfold assertion_def, simp)


subsection ‹Weakest precondition of true›

definition
  "wpt x = (x * ⊤) ⊓ 1"

lemma wpt_is_assertion [simp]: "wpt x ∈ assertion"
  apply (unfold wpt_def assertion_def, safe)
  apply simp
  apply (simp add: inf_comp dual_inf dual_comp inf_sup_distrib)
  apply (rule order.antisym)
  by (simp_all add: dual_neg)

lemma wpt_comp: "(wpt x) * x = x"
  apply (simp add: wpt_def inf_comp)
  apply (rule order.antisym, simp_all)
  by (cut_tac x = 1 and y = ⊤ and z = x in le_comp, simp_all)

lemma wpt_comp_2: "wpt (x * y) = wpt (x * (wpt y))"
  by (simp add: wpt_def inf_comp mult.assoc)

lemma wpt_assertion [simp]: "x ∈ assertion ⟹ wpt x = x"
  by (simp add: wpt_def assertion_prop)

lemma wpt_le_assertion: "x ∈ assertion ⟹ x * y = y ⟹ wpt y ≤ x"
  apply (simp add: wpt_def)
  proof -
    assume A: "x ∈ assertion"
    assume B: "x * y = y"
    have "y * ⊤ ⊓ 1 = x * (y * ⊤) ⊓ 1" by (simp add: B mult.assoc [THEN sym])
    also have "… ≤ x * ⊤ ⊓ 1" 
      apply simp
      apply (rule_tac y = "x * (y * ⊤)" in order_trans)
      apply simp_all
      by (rule le_comp, simp)
    also have "… = x" by (cut_tac A, simp add: assertion_prop)
    finally show "y * ⊤ ⊓ 1 ≤ x" .
  qed

lemma wpt_choice: "wpt (x ⊓ y) = wpt x ⊓ wpt y"
  apply (simp add: wpt_def inf_comp)
  proof -
    have "x * ⊤ ⊓ 1 ⊓ (y * ⊤ ⊓ 1) = x * ⊤ ⊓ ((y * ⊤ ⊓ 1) ⊓ 1)" apply (subst inf_assoc) by (simp add: inf_commute)
    also have "... = x * ⊤ ⊓ (y * ⊤ ⊓ 1)" by (subst inf_assoc, simp)
    also have "... = (x * ⊤) ⊓ (y * ⊤) ⊓ 1" by (subst inf_assoc, simp)
    finally show "x * ⊤ ⊓ (y * ⊤) ⊓ 1 = x * ⊤ ⊓ 1 ⊓ (y * ⊤ ⊓ 1)" by simp
  qed
end 

context lattice begin
lemma [simp]: "x ≤ y ⟹ x ⊓ y = x"
  by (simp add: inf_absorb1)
end


context mbt_algebra begin

lemma wpt_dual_assertion_comp: "x ∈ assertion ⟹ y ∈ assertion ⟹ wpt ((x ^ o) * y) = (neg_assert x) ⊔ y"
  apply (simp add: wpt_def neg_assert_def)
  proof -
    assume A: "x ∈ assertion"
    assume B: "y ∈ assertion"
    have C: "((x ^ o) * ⊥) ⊔ 1 = x ^ o"
      by (rule dual_assertion_prop, rule A)
    have "x ^ o * y * ⊤ ⊓ 1 = (((x ^ o) * ⊥) ⊔ 1) * y * ⊤ ⊓ 1" by (simp add: C)
    also have "… = ((x ^ o) * ⊥ ⊔ (y * ⊤)) ⊓ 1" by (simp add: sup_comp)
    also have "… = (((x ^ o) * ⊥) ⊓ 1) ⊔ ((y * ⊤) ⊓ 1)" by (simp add: inf_sup_distrib2)
    also have "… = (((x ^ o) * ⊥) ⊓ 1) ⊔ y" by (cut_tac B, drule assertion_prop, simp)
    finally show "x ^ o * y * ⊤ ⊓ 1 = (((x ^ o) * ⊥) ⊓ 1) ⊔ y" .
  qed

lemma le_comp_left_right: "x ≤ y ⟹ u ≤ v ⟹ x * u ≤ y * v"
  apply (rule_tac y = "x * v" in order_trans)
  apply (rule le_comp, simp)
  by (rule le_comp_right, simp)

lemma wpt_dual_assertion: "x ∈ assertion ⟹ wpt (x ^ o) = 1"
  apply (simp add: wpt_def)
  apply (rule order.antisym)
  apply simp_all
  apply (cut_tac x = 1 and y = "x ^ o" and u = 1 and v = ⊤ in le_comp_left_right)
  apply simp_all
  apply (subst dual_le)
  by simp

lemma assertion_commute: "x ∈ assertion ⟹ y ∈ conjunctive ⟹ y * x = wpt(y * x) * y"
  apply (simp add: wpt_def)
  apply (simp add: inf_comp)
  apply (drule_tac x = y and y = "x * ⊤" and z = 1 in conjunctiveD)
  by (simp add: mult.assoc [THEN sym] assertion_prop)


lemma wpt_mono: "x ≤ y ⟹ wpt x ≤ wpt y"
  apply (simp add: wpt_def)
  apply (rule_tac y = "x * ⊤" in order_trans, simp_all)
  by (rule le_comp_right, simp)

lemma "a ∈ conjunctive ⟹ x * a ≤ a * y ⟹ (x ^ ω) * a ≤ a * (y ^ ω)"
  apply (rule omega_least)
  apply (simp add: mult.assoc [THEN sym])
  apply (rule_tac y = "a * y * y ^ ω ⊓ a" in order_trans)
  apply (simp)
  apply (rule_tac y = "x * a * y ^ ω" in order_trans, simp_all)
  apply (rule le_comp_right, simp)
  apply (simp add: mult.assoc)
  apply (subst (2) omega_fix)
  by (simp add: conjunctiveD)

lemma [simp]: "x ≤ 1 ⟹ y * x ≤ y"
  by (cut_tac x = x and y = 1 and z = y in le_comp, simp_all)

lemma [simp]: "x ≤ x * ⊤"
  by (cut_tac x = 1 and y = ⊤ and z = x in le_comp, simp_all)

lemma [simp]: "x * ⊥ ≤ x"
  by (cut_tac x = ⊥ and y = 1 and z = x in le_comp, simp_all)

end

subsection‹Monotonic Boolean trasformers algebra with post condition statement›

definition
  "post_fun (p::'a::order) q = (if p ≤ q then (⊤::'b::{order_bot,order_top}) else ⊥)"

lemma mono_post_fun [simp]: "mono (post_fun (p::_::{order_bot,order_top}))"
  apply (simp add: post_fun_def mono_def, safe)
  apply (subgoal_tac "p ≤ y", simp)
  apply (rule_tac y = x in order_trans)
  apply simp_all
  done

lemma post_top [simp]: "post_fun p p = ⊤"
  by (simp add: post_fun_def)

lemma post_refin [simp]: "mono S ⟹ ((S p)::'a::bounded_lattice) ⊓ (post_fun p) x ≤ S x"
  apply (simp add: le_fun_def assert_fun_def post_fun_def, safe)
  by (rule_tac f = S in monoD, simp_all)

class post_mbt_algebra = mbt_algebra +
  fixes post :: "'a ⇒ 'a"
  assumes post_1: "(post x) * x * ⊤ = ⊤"
  and post_2: "y * x * ⊤ ⊓ (post x) ≤ y"

instantiation MonoTran :: (complete_boolean_algebra) post_mbt_algebra
begin

lift_definition post_MonoTran :: "'a::complete_boolean_algebra MonoTran ⇒ 'a::complete_boolean_algebra MonoTran"
  is "λx. post_fun (x ⊤)"
  by (rule mono_post_fun)

instance proof
  fix x :: "'a MonoTran" show "post x * x * ⊤ = ⊤"
    apply transfer
    apply (simp add: fun_eq_iff)
    done
  fix x y :: "'a MonoTran" show "y * x * ⊤ ⊓ post x ≤ y"
    apply transfer
    apply (simp add: le_fun_def)
    done
qed
   
end

subsection‹Complete monotonic Boolean transformers algebra›

class complete_mbt_algebra = post_mbt_algebra + complete_distrib_lattice +
  assumes Inf_comp: "(Inf X) * z = (INF x ∈ X . (x * z))"

instance MonoTran :: (complete_boolean_algebra) complete_mbt_algebra
  apply intro_classes
  apply transfer
  apply (simp add: Inf_comp_fun)
  done

context complete_mbt_algebra begin
lemma dual_Inf: "(Inf X) ^ o = (SUP x∈ X . x ^ o)"
  apply (rule order.antisym)
  apply (subst dual_le, simp)
  apply (rule Inf_greatest)
  apply (subst dual_le, simp)
  apply (rule SUP_upper, simp)
  apply (rule SUP_least)
  apply (subst dual_le, simp)
  by (rule Inf_lower, simp)

lemma dual_Sup: "(Sup X) ^ o = (INF x∈ X . x ^ o)"
  apply (rule order.antisym)
  apply (rule INF_greatest)
  apply (subst dual_le, simp)
  apply (rule Sup_upper, simp)
  apply (subst dual_le, simp)
  apply (rule Sup_least)
  apply (subst dual_le, simp)
  by (rule INF_lower, simp)

lemma INF_comp: "(⨅(f ` A)) * z = (INF a ∈ A . (f a) * z)"
  unfolding Inf_comp
  apply (subgoal_tac "((λx::'a. x * z) ` f ` A) = ((λa::'b. f a * z) ` A)")
  by auto

lemma dual_INF: "(⨅(f ` A)) ^ o = (SUP a ∈ A . (f a) ^ o)"
  unfolding Inf_comp dual_Inf
  apply (subgoal_tac "(dual ` f ` A) = ((λa::'b. f a ^ o) ` A)")
  by auto

lemma dual_SUP: "(⨆(f ` A)) ^ o = (INF a ∈ A . (f a) ^ o)"
  unfolding dual_Sup
  apply (subgoal_tac "(dual ` f ` A) = ((λa::'b. f a ^ o) ` A)")
  by auto

lemma Sup_comp: "(Sup X) * z = (SUP x ∈ X . (x * z))"
  apply (rule dual_eq)
  by (simp add: dual_comp dual_Sup dual_SUP INF_comp image_comp)

lemma SUP_comp: "(⨆(f ` A)) * z = (SUP a ∈ A . (f a) * z)"
  unfolding Sup_comp
  apply (subgoal_tac "((λx::'a. x * z) ` f ` A) = ((λa::'b. f a * z) ` A)")
  by auto


lemma Sup_assertion [simp]: "X ⊆ assertion ⟹ Sup X ∈ assertion"
  apply (unfold assertion_def)
  apply safe
  apply (rule Sup_least)
  apply blast
  apply (simp add: Sup_comp dual_Sup Sup_inf)
  apply (subgoal_tac "((λy . y ⊓ ⨅(dual ` X)) ` (λx . x * ⊤) ` X) = X")
  apply simp
  proof -
    assume A: "X ⊆ {x. x ≤ 1 ∧ x * ⊤ ⊓ x ^ o = x}"
    have B [simp]: "!! x . x ∈ X ⟹  x * ⊤ ⊓ (⨅(dual ` X)) = x"
    proof -
      fix x
      assume C: "x ∈ X"
      have "x * ⊤ ⊓ ⨅(dual ` X) = x * ⊤ ⊓ (x ^ o ⊓ ⨅(dual ` X))"
        apply (subgoal_tac "⨅(dual ` X) = (x ^ o ⊓ ⨅(dual ` X))", simp)
        apply (rule order.antisym, simp_all)
        apply (rule Inf_lower, cut_tac C, simp)
        done
      also have "… = x ⊓ ⨅(dual ` X)" by (unfold  inf_assoc [THEN sym], cut_tac A, cut_tac C, auto)
      also have "… = x"
        apply (rule order.antisym, simp_all)
        apply (rule INF_greatest)
        apply (cut_tac A C)
        apply (rule_tac y = 1 in order_trans)
        apply auto[1]
        apply (subst dual_le, auto)
        done
      finally show "x * ⊤ ⊓ ⨅(dual ` X) = x" .
      qed
      show "(λy. y ⊓ ⨅(dual ` X)) ` (λx . x * ⊤) ` X = X"
        by (simp add: image_comp)
    qed

lemma Sup_range_assertion [simp]: "(!!w . p w ∈ assertion) ⟹ Sup (range p) ∈ assertion"
  by (rule Sup_assertion, auto)

lemma Sup_less_assertion [simp]: "(!!w . p w ∈ assertion) ⟹ Sup_less p w ∈ assertion"
  by (unfold Sup_less_def, rule Sup_assertion, auto)

theorem omega_lfp: 
  "x ^ ω * y = lfp (λ z . (x * z) ⊓ y)"
  apply (rule order.antisym)
  apply (rule lfp_greatest)
  apply (drule omega_least, simp)
  apply (rule lfp_lowerbound)
  apply (subst (2) omega_fix)
  by (simp add: inf_comp mult.assoc)
end

lemma [simp]: "mono (λ (t::'a::mbt_algebra) . x * t ⊓ y)"
  apply (simp add: mono_def, safe)
  apply (rule_tac y = "x * xa" in order_trans, simp)
  by (rule le_comp, simp)


class mbt_algebra_fusion = mbt_algebra +
  assumes fusion: "(∀ t . x * t ⊓ y ⊓ z ≤ u * (t ⊓ z) ⊓ v)
          ⟹ (x ^ ω) * y ⊓ z ≤ (u ^ ω) * v "

lemma 
    "class.mbt_algebra_fusion (1::'a::complete_mbt_algebra) ((*)) (⊓) (≤) (<) (⊔) dual dual_star omega star ⊥ ⊤"
    apply unfold_locales
    apply (cut_tac h = "λ t . t ⊓ z" and f = "λ t . x * t ⊓ y" and g = "λ t . u * t ⊓ v" in weak_fusion)
    apply (rule inf_Disj)
    apply simp_all
    apply (simp add: le_fun_def)
    by  (simp add: omega_lfp)

context mbt_algebra_fusion
begin

lemma omega_star: "x ∈ conjunctive ⟹ x ^ ω = wpt (x ^ ω) * (x ^ *)"
  apply (simp add: wpt_def inf_comp)
  apply (rule order.antisym)
  apply (cut_tac x = x and y = 1 and z = "x ^ ω * ⊤ ⊓ x ^ *" in omega_least)
  apply (simp_all add: conjunctiveD,safe)
  apply  (subst (2) omega_fix)
  apply (simp add: inf_comp inf_assoc mult.assoc)
  apply (metis inf.commute inf_assoc inf_le1 star_fix)
  apply (cut_tac x = x and y = ⊤ and z = "x ^ *" and u = x and v = 1 in fusion)
  apply (simp add: conjunctiveD)
  apply (metis inf_commute inf_le1 le_infE star_fix)
  by (metis mult.right_neutral)

lemma omega_pres_conj: "x ∈ conjunctive ⟹ x ^ ω ∈ conjunctive"
  apply (subst omega_star, simp)
  apply (rule comp_pres_conj)
  apply (rule assertion_conjunctive, simp)
  by (rule start_pres_conj, simp)
end

end