Theory Omega_Algebra

(* Title:      Omega Algebra
   Author:     Alasdair Armstrong, Georg Struth, Tjark Weber
   Maintainer: Georg Struth <g.struth at sheffield.ac.uk>
               Tjark Weber <tjark.weber at it.uu.se>
*)

section ‹Omega Algebras›

theory Omega_Algebra
imports Kleene_Algebra
begin

text ‹
\emph{Omega algebras}~cite‹"cohen00omega"› extend Kleene algebras by an
$\omega$-operation that axiomatizes infinite iteration (just like the
Kleene star axiomatizes finite iteration).
›


subsection ‹Left Omega Algebras›

text ‹
In this section we consider \emph{left omega algebras}, i.e., omega
algebras based on left Kleene algebras. Surprisingly, we are still
looking for statements mentioning~$\omega$ that are true in omega
algebras, but do not already hold in left omega algebras.
›

class left_omega_algebra = left_kleene_algebra_zero + omega_op +
  assumes omega_unfold: "xω ≤ x ⋅ xω"
  and omega_coinduct: "y ≤ z + x ⋅ y ⟹ y ≤ xω + x⋆ ⋅ z"
begin

text ‹First we prove some variants of the coinduction axiom.›

lemma omega_coinduct_var1: "y ≤ 1 + x ⋅ y ⟹ y ≤ xω + x⋆"
  using local.omega_coinduct by fastforce

lemma  omega_coinduct_var2: "y ≤ x ⋅ y ⟹ y ≤ xω"
  by (metis add.commute add_zero_l annir omega_coinduct)

lemma omega_coinduct_eq: "y = z + x ⋅ y ⟹ y ≤ xω + x⋆ ⋅ z"
  by (simp add: local.omega_coinduct)

lemma omega_coinduct_eq_var1: "y = 1 + x ⋅ y ⟹ y ≤ xω + x⋆"
  by (simp add: omega_coinduct_var1)

lemma  omega_coinduct_eq_var2: "y = x ⋅ y ⟹ y ≤ xω"
  by (simp add: omega_coinduct_var2)

lemma "y = x ⋅ y + z ⟹ y = x⋆ ⋅ z + xω"
  (* nitpick [expect=genuine] -- "2-element counterexample" *)
oops

lemma "y = 1 + x ⋅ y ⟹ y = xω + x⋆"
  (* nitpick [expect=genuine] -- "3-element counterexample" *)
oops

lemma "y = x ⋅ y ⟹ y = xω"
  (* nitpick [expect=genuine] -- "2-element counterexample" *)
oops

text ‹Next we strengthen the unfold law to an equation.›

lemma omega_unfold_eq [simp]: "x ⋅ xω = xω"
proof (rule order.antisym)
  have "x ⋅ xω ≤ x ⋅ x ⋅ xω"
    by (simp add: local.mult_isol local.omega_unfold mult_assoc)
  thus "x ⋅ xω ≤ xω"
    by (simp add: mult_assoc omega_coinduct_var2)
  show  "xω ≤ x ⋅ xω"
    by (fact omega_unfold)
qed

lemma omega_unfold_var: "z + x ⋅ xω ≤ xω + x⋆ ⋅ z"
  by (simp add: local.omega_coinduct)

lemma "z + x ⋅ xω = xω + x⋆ ⋅ z"
  (* nitpick [expect=genuine] -- "4-element counterexample" *)
oops

text ‹We now prove subdistributivity and isotonicity of omega.›

lemma omega_subdist: "xω ≤ (x + y)ω"
proof -
  have "xω ≤ (x + y) ⋅ xω"
    by simp
  thus ?thesis
    by (rule omega_coinduct_var2)
qed

lemma omega_iso: "x ≤ y ⟹ xω ≤ yω"
  by (metis less_eq_def omega_subdist)

lemma omega_subdist_var: "xω + yω ≤ (x + y)ω"
  by (simp add: omega_iso)

lemma zero_omega [simp]: "0ω = 0"
  by (metis annil omega_unfold_eq)

text ‹The next lemma is another variant of omega unfold›

lemma star_omega_1 [simp]: "x⋆ ⋅ xω = xω"
proof (rule order.antisym)
  have "x ⋅ xω ≤ xω"
    by simp
  thus "x⋆ ⋅ xω ≤ xω"
    by simp
  show "xω ≤ x⋆ ⋅ xω"
    using local.star_inductl_var_eq2 by auto
qed

text ‹The next lemma says that~@{term "1ω"} is the maximal element
of omega algebra. We therefore baptise it~$\top$.›

lemma max_element: "x ≤ 1ω"
  by (simp add: omega_coinduct_eq_var2)

definition top (‹⊤›)
  where "⊤ = 1ω"

lemma star_omega_3 [simp]: "(x⋆)ω = ⊤"
proof -
  have "1 ≤ x⋆"
    by (fact star_ref)
  hence "⊤ ≤ (x⋆)ω"
    by (simp add: omega_iso top_def)
  thus ?thesis
    by (simp add: local.order.antisym max_element top_def)
qed

text ‹The following lemma is strange since it is counterintuitive
that one should be able to append something after an infinite
iteration.›

lemma omega_1: "xω ⋅ y ≤ xω"
proof -
  have "xω ⋅ y ≤ x ⋅ xω ⋅ y"
    by simp
  thus ?thesis
    by (metis mult.assoc omega_coinduct_var2)
qed

lemma "xω ⋅ y = xω"
  (*nitpick [expect=genuine] -- "2-element counterexample"*)
oops

lemma omega_sup_id: "1 ≤ y ⟹ xω ⋅ y = xω"
  using order.eq_iff local.mult_isol omega_1 by fastforce

lemma omega_top [simp]: "xω ⋅ ⊤ = xω"
  by (simp add: max_element omega_sup_id top_def)

lemma supid_omega: "1 ≤ x ⟹ xω = ⊤"
  by (simp add: local.order.antisym max_element omega_iso top_def)

lemma "xω = ⊤ ⟹ 1 ≤ x"
  (* nitpick [expect=genuine] -- "4-element counterexample" *)
oops

text ‹Next we prove a simulation law for the omega operation›

lemma omega_simulation: "z ⋅ x ≤ y ⋅ z ⟹ z ⋅ xω ≤ yω"
proof -
  assume hyp: "z ⋅ x ≤ y ⋅ z"
  have "z ⋅ xω = z ⋅ x ⋅ xω"
    by (simp add: mult_assoc)
  also have "... ≤ y ⋅ z ⋅ xω"
    by (simp add: hyp local.mult_isor)
  finally show "z ⋅ xω ≤ yω"
    by (simp add: mult_assoc omega_coinduct_var2)
qed

lemma "z ⋅ x ≤ y ⋅ z ⟹ z ⋅ xω ≤ yω ⋅ z"
  (* nitpick [expect=genuine] -- "4-element counterexample" *)
oops

lemma "y ⋅ z  ≤ z ⋅ x ⟹ yω ≤ z ⋅ xω"
  (* nitpick [expect=genuine] -- "2-element counterexample" *)
oops

lemma "y ⋅ z  ≤ z ⋅ x ⟹ yω ⋅ z ≤ xω"
  (* nitpick [expect=genuine] -- "4-element counterexample" *)
oops

text ‹Next we prove transitivity of omega elements.›

lemma omega_omega: "(xω)ω ≤ xω"
  by (metis omega_1 omega_unfold_eq)

(*
lemma "xω ⋅ xω = xω"
nitpick -- "no proof, no counterexample"

lemma "(xω)ω = xω"
nitpick -- "no proof, no counterexample"
*)

text ‹The next lemmas are axioms of Wagner's complete axiomatisation
for omega-regular languages~cite‹"wagner77omega"›, but in a slightly
different setting.›

lemma wagner_1 [simp]: "(x ⋅ x⋆)ω = xω"
proof (rule order.antisym)
  have "(x ⋅ x⋆)ω = x ⋅ x⋆ ⋅ x ⋅ x⋆ ⋅ (x ⋅ x⋆)ω"
    by (metis mult.assoc omega_unfold_eq)
  also have "... = x ⋅ x ⋅ x⋆ ⋅ x⋆ ⋅ (x ⋅ x⋆)ω"
    by (simp add: local.star_slide_var mult_assoc)
  also have "... = x ⋅ x ⋅ x⋆ ⋅ (x ⋅ x⋆)ω"
    by (simp add: mult_assoc)
  also have "... = x ⋅ (x ⋅ x⋆)ω"
    by (simp add: mult_assoc)
  thus "(x ⋅ x⋆)ω ≤ xω"
    using calculation omega_coinduct_eq_var2 by auto
   show "xω ≤ (x ⋅ x⋆)ω"
    by (simp add: mult_assoc omega_coinduct_eq_var2)
qed

lemma wagner_2_var: "x ⋅ (y ⋅ x)ω ≤ (x ⋅ y)ω"
proof -
  have "x ⋅ y ⋅ x ≤ x ⋅ y ⋅ x"
    by auto
  thus "x ⋅ (y ⋅ x)ω ≤ (x ⋅ y)ω"
    by (simp add: mult_assoc omega_simulation)
qed

lemma wagner_2 [simp]: "x ⋅ (y ⋅ x)ω = (x ⋅ y)ω"
proof (rule order.antisym)
  show "x ⋅ (y ⋅ x)ω ≤ (x ⋅ y)ω"
    by (rule wagner_2_var)
  have "(x ⋅ y)ω = x ⋅ y ⋅ (x ⋅ y)ω"
    by simp
  thus "(x ⋅ y)ω ≤ x ⋅ (y ⋅ x)ω"
    by (metis mult.assoc mult_isol wagner_2_var)
qed

text ‹
This identity is called~(A8) in Wagner's paper.
›

lemma wagner_3:
assumes "x ⋅ (x + y)ω + z = (x + y)ω"
shows "(x + y)ω = xω + x⋆ ⋅ z"
proof (rule order.antisym)
  show  "(x + y)ω ≤ xω + x⋆ ⋅ z"
    using assms local.join.sup_commute omega_coinduct_eq by auto
  have "x⋆ ⋅ z ≤ (x + y)ω"
    using assms local.join.sup_commute local.star_inductl_eq by auto
  thus "xω + x⋆ ⋅ z ≤ (x + y)ω"
    by (simp add: omega_subdist)
qed

text ‹
This identity is called~(R4) in Wagner's paper.
›

lemma wagner_1_var [simp]: "(x⋆ ⋅ x)ω = xω"
  by (simp add: local.star_slide_var)

lemma star_omega_4 [simp]: "(xω)⋆ = 1 + xω"
proof (rule order.antisym)
  have "(xω)⋆ = 1 + xω ⋅ (xω)⋆"
    by simp
  also have "... ≤ 1 + xω ⋅ ⊤"
    by (simp add: omega_sup_id)
  finally show "(xω)⋆ ≤ 1 + xω"
    by simp
  show "1 + xω ≤ (xω)⋆"
    by simp
qed

lemma star_omega_5 [simp]: "xω ⋅ (xω)⋆ = xω"
proof (rule order.antisym)
  show "xω ⋅ (xω)⋆ ≤ xω"
    by (rule omega_1)
  show "xω ≤ xω ⋅ (xω)⋆"
    by (simp add: omega_sup_id)
qed

text ‹The next law shows how omegas below a sum can be unfolded.›

lemma omega_sum_unfold: "xω + x⋆ ⋅ y ⋅ (x + y)ω = (x + y)ω"
proof -
  have "(x + y)ω = x ⋅ (x + y)ω + y ⋅ (x+y)ω"
    by (metis distrib_right omega_unfold_eq)
  thus ?thesis
    by (metis mult.assoc wagner_3)
qed

text ‹
The next two lemmas apply induction and coinduction to this law.
›

lemma omega_sum_unfold_coind: "(x + y)ω ≤ (x⋆ ⋅ y)ω + (x⋆ ⋅ y)⋆ ⋅ xω"
  by (simp add: omega_coinduct_eq omega_sum_unfold)

lemma omega_sum_unfold_ind: "(x⋆ ⋅ y)⋆ ⋅ xω ≤ (x + y)ω"
  by (simp add: local.star_inductl_eq omega_sum_unfold)

lemma wagner_1_gen: "(x ⋅ y⋆)ω ≤ (x + y)ω"
proof -
  have "(x ⋅ y⋆)ω ≤ ((x + y) ⋅ (x + y)⋆)ω"
    using local.join.le_sup_iff local.join.sup.cobounded1 local.mult_isol_var local.star_subdist_var omega_iso by presburger
  thus ?thesis
    by (metis wagner_1)
qed

lemma wagner_1_var_gen: "(x⋆ ⋅ y)ω ≤ (x + y)ω"
proof -
  have "(x⋆ ⋅ y)ω = x⋆ ⋅ (y ⋅ x⋆)ω"
    by simp
  also have "... ≤ x⋆ ⋅ (x + y)ω"
    by (metis add.commute mult_isol wagner_1_gen)
  also have "... ≤ (x + y)⋆ ⋅ (x + y)ω"
    using local.mult_isor local.star_subdist by auto
  thus ?thesis
    by (metis calculation order_trans star_omega_1)
qed

text ‹The next lemma is a variant of the denest law for the star at
the level of omega.›

lemma omega_denest [simp]: "(x + y)ω = (x⋆ ⋅ y)ω + (x⋆ ⋅ y)⋆ ⋅ xω"
proof (rule order.antisym)
  show "(x + y)ω ≤ (x⋆ ⋅ y)ω + (x⋆ ⋅ y)⋆ ⋅ xω"
    by (rule omega_sum_unfold_coind)
  have "(x⋆ ⋅ y)ω ≤  (x + y)ω"
    by (rule wagner_1_var_gen)
  hence "(x⋆ ⋅ y)⋆ ⋅ xω ≤ (x + y)ω"
    by (simp add: omega_sum_unfold_ind)
  thus "(x⋆ ⋅ y)ω + (x⋆ ⋅ y)⋆ ⋅ xω ≤ (x + y)ω"
    by (simp add: wagner_1_var_gen)
qed

text ‹The next lemma yields a separation theorem for infinite
iteration in the presence of a quasicommutation property. A
nondeterministic loop over~@{term x} and~@{term y} can be refined into
separate infinite loops over~@{term x} and~@{term y}.›

lemma omega_sum_refine:
  assumes "y ⋅ x ≤ x ⋅ (x + y)⋆"
  shows "(x + y)ω = xω + x⋆ ⋅ yω"
proof (rule order.antisym)
  have a: "y⋆ ⋅ x ≤ x ⋅ (x + y)⋆"
    using assms local.quasicomm_var by blast
  have "(x + y)ω = yω + y⋆ ⋅ x ⋅ (x + y)ω"
    by (metis add.commute omega_sum_unfold)
  also have "... ≤ yω + x ⋅ (x + y)⋆ ⋅ (x + y)ω"
    using a local.join.sup_mono local.mult_isol_var by blast
  also have "... ≤ x ⋅ (x + y)ω + yω"
    using local.eq_refl local.join.sup_commute mult_assoc star_omega_1 by presburger
  finally show "(x + y)ω ≤ xω + x⋆ ⋅ yω"
    by (metis add_commute local.omega_coinduct)
  have "xω + x⋆ ⋅ yω ≤ (x + y)ω + (x + y)⋆ ⋅ (x + y)ω"
    using local.join.sup.cobounded2 local.join.sup.mono local.mult_isol_var local.star_subdist omega_iso omega_subdist by presburger
  thus "xω + x⋆ ⋅ yω ≤ (x + y)ω"
    by (metis local.join.sup_idem star_omega_1)
qed

text ‹The following theorem by Bachmair and
Dershowitz~cite‹"bachmair86commutation"› is a corollary.›

lemma bachmair_dershowitz:
  assumes "y ⋅ x ≤ x ⋅ (x + y)⋆"
  shows "(x + y)ω = 0 ⟷ xω + yω = 0"
  by (metis add_commute assms local.annir local.join.le_bot local.no_trivial_inverse omega_subdist omega_sum_refine)

text ‹
The next lemmas consider an abstract variant of the empty word
property from language theory and match it with the absence of
infinite iteration~cite‹"struth12regeq"›.
›

definition (in dioid_one_zero) ewp
where "ewp x ≡ ¬(∀y. y ≤ x ⋅ y ⟶ y = 0)"

lemma ewp_super_id1: "0 ≠ 1 ⟹ 1 ≤ x ⟹ ewp x"
  by (metis ewp_def mult_oner)

lemma "0 ≠ 1 ⟹ 1 ≤ x ⟷ ewp x"
  (* nitpick [expect=genuine] -- "3-element counterexample" *)
oops

text ‹The next facts relate the absence of the empty word property
with the absence of infinite iteration.›

lemma ewp_neg_and_omega: "¬ ewp x ⟷ xω = 0"
proof
  assume "¬ ewp x"
  hence "∀ y. y ≤ x ⋅ y ⟶ y = 0"
    by (meson ewp_def)
  thus "xω = 0"
    by simp
next
  assume "xω = 0"
  hence "∀ y. y ≤ x ⋅ y ⟶ y = 0"
    using local.join.le_bot local.omega_coinduct_var2 by blast
  thus "¬ ewp x"
    by (meson ewp_def)
qed

lemma ewp_alt1: "(∀z. xω ≤ x⋆ ⋅ z) ⟷ (∀y z. y ≤ x ⋅ y + z ⟶ y ≤ x⋆ ⋅ z)"
  by (metis add_comm less_eq_def omega_coinduct omega_unfold_eq order_prop)

lemma ewp_alt: "xω = 0 ⟷ (∀y z. y ≤ x ⋅ y + z ⟶ y ≤ x⋆ ⋅ z)"
  by (metis annir order.antisym ewp_alt1 join.bot_least)

text ‹So we have obtained a condition for Arden's lemma in omega
algebra.›

lemma omega_super_id1: "0 ≠ 1 ⟹ 1 ≤ x ⟹ xω ≠ 0"
  using ewp_neg_and_omega ewp_super_id1 by blast

lemma omega_super_id2: "0 ≠ 1 ⟹ xω = 0 ⟹ ¬(1 ≤ x)"
  using omega_super_id1 by blast

text ‹The next lemmas are abstract versions of Arden's lemma from
language theory.›

lemma ardens_lemma_var:
  assumes "xω = 0" 
  and "z + x ⋅ y = y"
  shows "x⋆ ⋅ z = y"
proof -
  have "y ≤ xω + x⋆ ⋅ z"
    by (simp add: assms(2) local.omega_coinduct_eq)
  hence "y ≤ x⋆ ⋅ z"
    by (simp add: assms(1))
  thus "x⋆ ⋅ z = y"
    by (simp add: assms(2) order.eq_iff local.star_inductl_eq)
qed

lemma ardens_lemma: "¬ ewp x ⟹ z + x ⋅ y = y ⟹ x⋆ ⋅ z = y"
  by (simp add: ardens_lemma_var ewp_neg_and_omega)

lemma ardens_lemma_equiv:
  assumes "¬ ewp x"
  shows "z + x ⋅ y = y ⟷ x⋆ ⋅ z = y"
  by (metis ardens_lemma_var assms ewp_neg_and_omega local.conway.dagger_unfoldl_distr mult_assoc)

lemma ardens_lemma_var_equiv: "xω = 0 ⟹ (z + x ⋅ y = y ⟷ x⋆ ⋅ z = y)"
  by (simp add: ardens_lemma_equiv ewp_neg_and_omega)

lemma arden_conv1: "(∀y z. z + x ⋅ y = y ⟶ x⋆ ⋅ z = y) ⟹ ¬ ewp x"
  by (metis add_zero_l annir ewp_neg_and_omega omega_unfold_eq)

lemma arden_conv2: "(∀y z. z + x ⋅ y = y ⟶ x⋆ ⋅ z = y) ⟹ xω = 0"
  using arden_conv1 ewp_neg_and_omega by blast

lemma arden_var3: "(∀y z. z + x ⋅ y = y ⟶ x⋆ ⋅ z = y) ⟷ xω = 0"
  using arden_conv2 ardens_lemma_var by blast

end

subsection ‹Omega Algebras›

class omega_algebra = kleene_algebra + left_omega_algebra

end