Theory Myhill_1

theory Myhill_1
imports Folds While_Combinator
(* Author: Xingyuan Zhang, Chunhan Wu, Christian Urban *)
theory Myhill_1
imports Folds
        "HOL-Library.While_Combinator" 
begin

section ‹First direction of MN: ‹finite partition ⇒ regular language››

notation 
  conc (infixr "⋅" 100) and
  star ("_⋆" [101] 102)

lemma Pair_Collect [simp]:
  shows "(x, y) ∈ {(x, y). P x y} ⟷ P x y"
by simp

text ‹Myhill-Nerode relation›

definition
  str_eq :: "'a lang ⇒ ('a list × 'a list) set" ("≈_" [100] 100)
where
  "≈A ≡ {(x, y).  (∀z. x @ z ∈ A ⟷ y @ z ∈ A)}"

abbreviation
  str_eq_applied :: "'a list ⇒ 'a lang ⇒ 'a list ⇒ bool" ("_ ≈_ _")
where
  "x ≈A y ≡ (x, y) ∈ ≈A"

lemma str_eq_conv_Derivs:
  "str_eq A = {(u,v). Derivs u A = Derivs v A}"
  by (auto simp: str_eq_def Derivs_def)  

definition 
  finals :: "'a lang ⇒ 'a lang set"
where
  "finals A ≡ {≈A `` {s} | s . s ∈ A}"

lemma lang_is_union_of_finals: 
  shows "A = ⋃(finals A)"
unfolding finals_def
unfolding Image_def
unfolding str_eq_def
by (auto) (metis append_Nil2)

lemma finals_in_partitions:
  shows "finals A ⊆ (UNIV // ≈A)"
unfolding finals_def quotient_def
by auto

subsection ‹Equational systems›

text ‹The two kinds of terms in the rhs of equations.›

datatype 'a trm = 
   Lam "'a rexp"            (* Lambda-marker *)
 | Trn "'a lang" "'a rexp"     (* Transition *)

fun 
  lang_trm::"'a trm ⇒ 'a lang"
where
  "lang_trm (Lam r) = lang r" 
| "lang_trm (Trn X r) = X ⋅ lang r"

fun 
  lang_rhs::"('a trm) set ⇒ 'a lang"
where 
  "lang_rhs rhs = ⋃ (lang_trm ` rhs)"

lemma lang_rhs_set:
  shows "lang_rhs {Trn X r | r. P r} = ⋃{lang_trm (Trn X r) | r. P r}"
by (auto)

lemma lang_rhs_union_distrib:
  shows "lang_rhs A ∪ lang_rhs B = lang_rhs (A ∪ B)"
by simp


text ‹Transitions between equivalence classes›

definition 
  transition :: "'a lang ⇒ 'a ⇒ 'a lang ⇒ bool" ("_ ⊨_⇒_" [100,100,100] 100)
where
  "Y ⊨c⇒ X ≡ Y ⋅ {[c]} ⊆ X"

text ‹Initial equational system›

definition
  "Init_rhs CS X ≡  
      if ([] ∈ X) then 
          {Lam One} ∪ {Trn Y (Atom c) | Y c. Y ∈ CS ∧ Y ⊨c⇒ X}
      else 
          {Trn Y (Atom c)| Y c. Y ∈ CS ∧ Y ⊨c⇒ X}"

definition 
  "Init CS ≡ {(X, Init_rhs CS X) | X.  X ∈ CS}"


subsection ‹Arden Operation on equations›

fun 
  Append_rexp :: "'a rexp ⇒ 'a trm ⇒ 'a trm"
where
  "Append_rexp r (Lam rexp)   = Lam (Times rexp r)"
| "Append_rexp r (Trn X rexp) = Trn X (Times rexp r)"


definition
  "Append_rexp_rhs rhs rexp ≡ (Append_rexp rexp) ` rhs"

definition 
  "Arden X rhs ≡ 
     Append_rexp_rhs (rhs - {Trn X r | r. Trn X r ∈ rhs}) (Star (⨄ {r. Trn X r ∈ rhs}))"


subsection ‹Substitution Operation on equations›

definition 
  "Subst rhs X xrhs ≡ 
        (rhs - {Trn X r | r. Trn X r ∈ rhs}) ∪ (Append_rexp_rhs xrhs (⨄ {r. Trn X r ∈ rhs}))"

definition
  Subst_all :: "('a lang × ('a trm) set) set ⇒ 'a lang ⇒ ('a trm) set ⇒ ('a lang × ('a trm) set) set"
where
  "Subst_all ES X xrhs ≡ {(Y, Subst yrhs X xrhs) | Y yrhs. (Y, yrhs) ∈ ES}"

definition
  "Remove ES X xrhs ≡ 
      Subst_all  (ES - {(X, xrhs)}) X (Arden X xrhs)"


subsection ‹While-combinator and invariants›

definition 
  "Iter X ES ≡ (let (Y, yrhs) = SOME (Y, yrhs). (Y, yrhs) ∈ ES ∧ X ≠ Y
                in Remove ES Y yrhs)"

lemma IterI2:
  assumes "(Y, yrhs) ∈ ES"
  and     "X ≠ Y"
  and     "⋀Y yrhs. ⟦(Y, yrhs) ∈ ES; X ≠ Y⟧ ⟹ Q (Remove ES Y yrhs)"
  shows "Q (Iter X ES)"
unfolding Iter_def using assms
by (rule_tac a="(Y, yrhs)" in someI2) (auto)

abbreviation
  "Cond ES ≡ card ES ≠ 1"

definition 
  "Solve X ES ≡ while Cond (Iter X) ES"


definition 
  "distinctness ES ≡ 
     ∀ X rhs rhs'. (X, rhs) ∈ ES ∧ (X, rhs') ∈ ES ⟶ rhs = rhs'"

definition 
  "soundness ES ≡ ∀(X, rhs) ∈ ES. X = lang_rhs rhs"

definition 
  "ardenable rhs ≡ (∀ Y r. Trn Y r ∈ rhs ⟶ [] ∉ lang r)"

definition 
  "ardenable_all ES ≡ ∀(X, rhs) ∈ ES. ardenable rhs"

definition
  "finite_rhs ES ≡ ∀(X, rhs) ∈ ES. finite rhs"

lemma finite_rhs_def2:
  "finite_rhs ES = (∀ X rhs. (X, rhs) ∈ ES ⟶ finite rhs)"
unfolding finite_rhs_def by auto

definition 
  "rhss rhs ≡ {X | X r. Trn X r ∈ rhs}"

definition
  "lhss ES ≡ {Y | Y yrhs. (Y, yrhs) ∈ ES}"

definition 
  "validity ES ≡ ∀(X, rhs) ∈ ES. rhss rhs ⊆ lhss ES"

lemma rhss_union_distrib:
  shows "rhss (A ∪ B) = rhss A ∪ rhss B"
by (auto simp add: rhss_def)

lemma lhss_union_distrib:
  shows "lhss (A ∪ B) = lhss A ∪ lhss B"
by (auto simp add: lhss_def)


definition 
  "invariant ES ≡ finite ES
                ∧ finite_rhs ES
                ∧ soundness ES 
                ∧ distinctness ES 
                ∧ ardenable_all ES 
                ∧ validity ES"


lemma invariantI:
  assumes "soundness ES" "finite ES" "distinctness ES" "ardenable_all ES" 
          "finite_rhs ES" "validity ES"
  shows "invariant ES"
using assms by (simp add: invariant_def)


declare [[simproc add: finite_Collect]]

lemma finite_Trn:
  assumes fin: "finite rhs"
  shows "finite {r. Trn Y r ∈ rhs}"
using assms by (auto intro!: finite_vimageI simp add: inj_on_def)

lemma finite_Lam:
  assumes fin: "finite rhs"
  shows "finite {r. Lam r ∈ rhs}"
using assms by (auto intro!: finite_vimageI simp add: inj_on_def)

lemma trm_soundness:
  assumes finite:"finite rhs"
  shows "lang_rhs ({Trn X r| r. Trn X r ∈ rhs}) = X ⋅ (lang (⨄{r. Trn X r ∈ rhs}))"
proof -
  have "finite {r. Trn X r ∈ rhs}" 
    by (rule finite_Trn[OF finite]) 
  then show "lang_rhs ({Trn X r| r. Trn X r ∈ rhs}) = X ⋅ (lang (⨄{r. Trn X r ∈ rhs}))"
    by (simp only: lang_rhs_set lang_trm.simps) (auto simp add: conc_def)
qed

lemma lang_of_append_rexp:
  "lang_trm (Append_rexp r trm) = lang_trm trm ⋅ lang r"
by (induct rule: Append_rexp.induct)
   (auto simp add: conc_assoc)

lemma lang_of_append_rexp_rhs:
  "lang_rhs (Append_rexp_rhs rhs r) = lang_rhs rhs ⋅ lang r"
unfolding Append_rexp_rhs_def
by (auto simp add: conc_def lang_of_append_rexp)


subsection ‹Intial Equational Systems›

lemma defined_by_str:
  assumes "s ∈ X" "X ∈ UNIV // ≈A" 
  shows "X = ≈A `` {s}"
using assms
unfolding quotient_def Image_def str_eq_def 
by auto

lemma every_eqclass_has_transition:
  assumes has_str: "s @ [c] ∈ X"
  and     in_CS:   "X ∈ UNIV // ≈A"
  obtains Y where "Y ∈ UNIV // ≈A" and "Y ⋅ {[c]} ⊆ X" and "s ∈ Y"
proof -
  define Y where "Y = ≈A `` {s}"
  have "Y ∈ UNIV // ≈A" 
    unfolding Y_def quotient_def by auto
  moreover
  have "X = ≈A `` {s @ [c]}" 
    using has_str in_CS defined_by_str by blast
  then have "Y ⋅ {[c]} ⊆ X" 
    unfolding Y_def Image_def conc_def
    unfolding str_eq_def
    by clarsimp
  moreover
  have "s ∈ Y" unfolding Y_def 
    unfolding Image_def str_eq_def by simp
  ultimately show thesis using that by blast
qed

lemma l_eq_r_in_eqs:
  assumes X_in_eqs: "(X, rhs) ∈ Init (UNIV // ≈A)"
  shows "X = lang_rhs rhs"
proof 
  show "X ⊆ lang_rhs rhs"
  proof
    fix x
    assume in_X: "x ∈ X"
    { assume empty: "x = []"
      then have "x ∈ lang_rhs rhs" using X_in_eqs in_X
        unfolding Init_def Init_rhs_def
        by auto
    }
    moreover
    { assume not_empty: "x ≠ []"
      then obtain s c where decom: "x = s @ [c]"
        using rev_cases by blast
      have "X ∈ UNIV // ≈A" using X_in_eqs unfolding Init_def by auto
      then obtain Y where "Y ∈ UNIV // ≈A" "Y ⋅ {[c]} ⊆ X" "s ∈ Y"
        using decom in_X every_eqclass_has_transition by metis
      then have "x ∈ lang_rhs {Trn Y (Atom c)| Y c. Y ∈ UNIV // ≈A ∧ Y ⊨c⇒ X}"
        unfolding transition_def
        using decom by (force simp add: conc_def)
      then have "x ∈ lang_rhs rhs" using X_in_eqs in_X
        unfolding Init_def Init_rhs_def by simp
    }
    ultimately show "x ∈ lang_rhs rhs" by blast
  qed
next
  show "lang_rhs rhs ⊆ X" using X_in_eqs
    unfolding Init_def Init_rhs_def transition_def
    by auto 
qed


lemma finite_Init_rhs: 
  fixes CS::"(('a::finite) lang) set"
  assumes finite: "finite CS"
  shows "finite (Init_rhs CS X)"
using assms unfolding Init_rhs_def transition_def by simp


lemma Init_ES_satisfies_invariant:
  fixes A::"(('a::finite) lang)"
  assumes finite_CS: "finite (UNIV // ≈A)"
  shows "invariant (Init (UNIV // ≈A))"
proof (rule invariantI)
  show "soundness (Init (UNIV // ≈A))"
    unfolding soundness_def 
    using l_eq_r_in_eqs by auto
  show "finite (Init (UNIV // ≈A))" using finite_CS
    unfolding Init_def by simp
  show "distinctness (Init (UNIV // ≈A))"     
    unfolding distinctness_def Init_def by simp
  show "ardenable_all (Init (UNIV // ≈A))"
    unfolding ardenable_all_def Init_def Init_rhs_def ardenable_def
   by auto 
  show "finite_rhs (Init (UNIV // ≈A))"
    using finite_Init_rhs[OF finite_CS]
    unfolding finite_rhs_def Init_def by auto
  show "validity (Init (UNIV // ≈A))"
    unfolding validity_def Init_def Init_rhs_def rhss_def lhss_def
    by auto
qed

subsection ‹Interations›

lemma Arden_preserves_soundness:
  assumes l_eq_r: "X = lang_rhs rhs"
  and not_empty: "ardenable rhs"
  and finite: "finite rhs"
  shows "X = lang_rhs (Arden X rhs)"
proof -
  define A where "A = lang (⨄{r. Trn X r ∈ rhs})"
  define b where "b = {Trn X r | r. Trn X r ∈ rhs}"
  define B where "B = lang_rhs (rhs - b)"
  have not_empty2: "[] ∉ A" 
    using finite_Trn[OF finite] not_empty
    unfolding A_def ardenable_def by simp
  have "X = lang_rhs rhs" using l_eq_r by simp
  also have "… = lang_rhs (b ∪ (rhs - b))" unfolding b_def by auto
  also have "… = lang_rhs b ∪ B" unfolding B_def by (simp only: lang_rhs_union_distrib)
  also have "… = X ⋅ A ∪ B"
    unfolding b_def
    unfolding trm_soundness[OF finite]
    unfolding A_def
    by blast
  finally have "X = X ⋅ A ∪ B" . 
  then have "X = B ⋅ A⋆"
    by (simp add: reversed_Arden[OF not_empty2])
  also have "… = lang_rhs (Arden X rhs)"
    unfolding Arden_def A_def B_def b_def
    by (simp only: lang_of_append_rexp_rhs lang.simps)
  finally show "X = lang_rhs (Arden X rhs)" by simp
qed 

lemma Append_preserves_finite:
  "finite rhs ⟹ finite (Append_rexp_rhs rhs r)"
by (auto simp: Append_rexp_rhs_def)

lemma Arden_preserves_finite:
  "finite rhs ⟹ finite (Arden X rhs)"
by (auto simp: Arden_def Append_preserves_finite)

lemma Append_preserves_ardenable:
  "ardenable rhs ⟹ ardenable (Append_rexp_rhs rhs r)"
apply (auto simp: ardenable_def Append_rexp_rhs_def)
by (case_tac x, auto simp: conc_def)

lemma ardenable_set_sub:
  "ardenable rhs ⟹ ardenable (rhs - A)"
by (auto simp:ardenable_def)

lemma ardenable_set_union:
  "⟦ardenable rhs; ardenable rhs'⟧ ⟹ ardenable (rhs ∪ rhs')"
by (auto simp:ardenable_def)

lemma Arden_preserves_ardenable:
  "ardenable rhs ⟹ ardenable (Arden X rhs)"
by (simp only:Arden_def Append_preserves_ardenable ardenable_set_sub)


lemma Subst_preserves_ardenable:
  "⟦ardenable rhs; ardenable xrhs⟧ ⟹ ardenable (Subst rhs X xrhs)"
by (simp only: Subst_def Append_preserves_ardenable ardenable_set_union ardenable_set_sub)

lemma Subst_preserves_soundness:
  assumes substor: "X = lang_rhs xrhs"
  and finite: "finite rhs"
  shows "lang_rhs (Subst rhs X xrhs) = lang_rhs rhs" (is "?Left = ?Right")
proof-
  define A where "A = lang_rhs (rhs - {Trn X r | r. Trn X r ∈ rhs})"
  have "?Left = A ∪ lang_rhs (Append_rexp_rhs xrhs (⨄{r. Trn X r ∈ rhs}))"
    unfolding Subst_def
    unfolding lang_rhs_union_distrib[symmetric]
    by (simp add: A_def)
  moreover have "?Right = A ∪ lang_rhs {Trn X r | r. Trn X r ∈ rhs}"
  proof-
    have "rhs = (rhs - {Trn X r | r. Trn X r ∈ rhs}) ∪ ({Trn X r | r. Trn X r ∈ rhs})" by auto
    thus ?thesis 
      unfolding A_def
      unfolding lang_rhs_union_distrib
      by simp
  qed
  moreover 
  have "lang_rhs (Append_rexp_rhs xrhs (⨄{r. Trn X r ∈ rhs})) = lang_rhs {Trn X r | r. Trn X r ∈ rhs}" 
    using finite substor by (simp only: lang_of_append_rexp_rhs trm_soundness)
  ultimately show ?thesis by simp
qed

lemma Subst_preserves_finite_rhs:
  "⟦finite rhs; finite yrhs⟧ ⟹ finite (Subst rhs Y yrhs)"
by (auto simp: Subst_def Append_preserves_finite)

lemma Subst_all_preserves_finite:
  assumes finite: "finite ES"
  shows "finite (Subst_all ES Y yrhs)"
using assms unfolding Subst_all_def by simp

declare [[simproc del: finite_Collect]]

lemma Subst_all_preserves_finite_rhs:
  "⟦finite_rhs ES; finite yrhs⟧ ⟹ finite_rhs (Subst_all ES Y yrhs)"
by (auto intro:Subst_preserves_finite_rhs simp add:Subst_all_def finite_rhs_def)

lemma append_rhs_preserves_cls:
  "rhss (Append_rexp_rhs rhs r) = rhss rhs"
apply (auto simp: rhss_def Append_rexp_rhs_def)
apply (case_tac xa, auto simp: image_def)
by (rule_tac x = "Times ra r" in exI, rule_tac x = "Trn x ra" in bexI, simp+)

lemma Arden_removes_cl:
  "rhss (Arden Y yrhs) = rhss yrhs - {Y}"
apply (simp add:Arden_def append_rhs_preserves_cls)
by (auto simp: rhss_def)

lemma lhss_preserves_cls:
  "lhss (Subst_all ES Y yrhs) = lhss ES"
by (auto simp: lhss_def Subst_all_def)

lemma Subst_updates_cls:
  "X ∉ rhss xrhs ⟹ 
      rhss (Subst rhs X xrhs) = rhss rhs ∪ rhss xrhs - {X}"
apply (simp only:Subst_def append_rhs_preserves_cls rhss_union_distrib)
by (auto simp: rhss_def)

lemma Subst_all_preserves_validity:
  assumes sc: "validity (ES ∪ {(Y, yrhs)})"        (is "validity ?A")
  shows "validity (Subst_all ES Y (Arden Y yrhs))"  (is "validity ?B")
proof -
  { fix X xrhs'
    assume "(X, xrhs') ∈ ?B"
    then obtain xrhs 
      where xrhs_xrhs': "xrhs' = Subst xrhs Y (Arden Y yrhs)"
      and X_in: "(X, xrhs) ∈ ES" by (simp add:Subst_all_def, blast)    
    have "rhss xrhs' ⊆ lhss ?B"
    proof-
      have "lhss ?B = lhss ES" by (auto simp add:lhss_def Subst_all_def)
      moreover have "rhss xrhs' ⊆ lhss ES"
      proof-
        have "rhss xrhs' ⊆  rhss xrhs ∪ rhss (Arden Y yrhs) - {Y}"
        proof -
          have "Y ∉ rhss (Arden Y yrhs)" 
            using Arden_removes_cl by auto
          thus ?thesis using xrhs_xrhs' by (auto simp: Subst_updates_cls)
        qed
        moreover have "rhss xrhs ⊆ lhss ES ∪ {Y}" using X_in sc
          apply (simp only:validity_def lhss_union_distrib)
          by (drule_tac x = "(X, xrhs)" in bspec, auto simp:lhss_def)
        moreover have "rhss (Arden Y yrhs) ⊆ lhss ES ∪ {Y}" 
          using sc 
          by (auto simp add: Arden_removes_cl validity_def lhss_def)
        ultimately show ?thesis by auto
      qed
      ultimately show ?thesis by simp
    qed
  } thus ?thesis by (auto simp only:Subst_all_def validity_def)
qed

lemma Subst_all_satisfies_invariant:
  assumes invariant_ES: "invariant (ES ∪ {(Y, yrhs)})"
  shows "invariant (Subst_all ES Y (Arden Y yrhs))"
proof (rule invariantI)
  have Y_eq_yrhs: "Y = lang_rhs yrhs" 
    using invariant_ES by (simp only:invariant_def soundness_def, blast)
   have finite_yrhs: "finite yrhs" 
    using invariant_ES by (auto simp:invariant_def finite_rhs_def)
  have ardenable_yrhs: "ardenable yrhs" 
    using invariant_ES by (auto simp:invariant_def ardenable_all_def)
  show "soundness (Subst_all ES Y (Arden Y yrhs))"
  proof -
    have "Y = lang_rhs (Arden Y yrhs)" 
      using Y_eq_yrhs invariant_ES finite_yrhs
      using finite_Trn[OF finite_yrhs]
      apply(rule_tac Arden_preserves_soundness)
      apply(simp_all)
      unfolding invariant_def ardenable_all_def ardenable_def
      apply(auto)
      done
    thus ?thesis using invariant_ES
      unfolding invariant_def finite_rhs_def2 soundness_def Subst_all_def
      by (auto simp add: Subst_preserves_soundness simp del: lang_rhs.simps)
  qed
  show "finite (Subst_all ES Y (Arden Y yrhs))" 
    using invariant_ES by (simp add:invariant_def Subst_all_preserves_finite)
  show "distinctness (Subst_all ES Y (Arden Y yrhs))" 
    using invariant_ES 
    unfolding distinctness_def Subst_all_def invariant_def by auto
  show "ardenable_all (Subst_all ES Y (Arden Y yrhs))"
  proof - 
    { fix X rhs
      assume "(X, rhs) ∈ ES"
      hence "ardenable rhs"  using invariant_ES  
        by (auto simp add:invariant_def ardenable_all_def)
      with ardenable_yrhs 
      have "ardenable (Subst rhs Y (Arden Y yrhs))"
        by (simp add:ardenable_yrhs 
               Subst_preserves_ardenable Arden_preserves_ardenable)
    } thus ?thesis by (auto simp add:ardenable_all_def Subst_all_def)
  qed
  show "finite_rhs (Subst_all ES Y (Arden Y yrhs))"
  proof-
    have "finite_rhs ES" using invariant_ES 
      by (simp add:invariant_def finite_rhs_def)
    moreover have "finite (Arden Y yrhs)"
    proof -
      have "finite yrhs" using invariant_ES 
        by (auto simp:invariant_def finite_rhs_def)
      thus ?thesis using Arden_preserves_finite by auto
    qed
    ultimately show ?thesis 
      by (simp add:Subst_all_preserves_finite_rhs)
  qed
  show "validity (Subst_all ES Y (Arden Y yrhs))"
    using invariant_ES Subst_all_preserves_validity by (auto simp add: invariant_def)
qed

lemma Remove_in_card_measure:
  assumes finite: "finite ES"
  and     in_ES: "(X, rhs) ∈ ES"
  shows "(Remove ES X rhs, ES) ∈ measure card"
proof -
  define f where "f x = ((fst x)::'a lang, Subst (snd x) X (Arden X rhs))" for x
  define ES' where "ES' = ES - {(X, rhs)}"
  have "Subst_all ES' X (Arden X rhs) = f ` ES'" 
    apply (auto simp: Subst_all_def f_def image_def)
    by (rule_tac x = "(Y, yrhs)" in bexI, simp+)
  then have "card (Subst_all ES' X (Arden X rhs)) ≤ card ES'"
    unfolding ES'_def using finite by (auto intro: card_image_le)
  also have "… < card ES" unfolding ES'_def 
    using in_ES finite by (rule_tac card_Diff1_less)
  finally show "(Remove ES X rhs, ES) ∈ measure card" 
    unfolding Remove_def ES'_def by simp
qed
    

lemma Subst_all_cls_remains: 
  "(X, xrhs) ∈ ES ⟹ ∃ xrhs'. (X, xrhs') ∈ (Subst_all ES Y yrhs)"
by (auto simp: Subst_all_def)

lemma card_noteq_1_has_more:
  assumes card:"Cond ES"
  and e_in: "(X, xrhs) ∈ ES"
  and finite: "finite ES"
  shows "∃(Y, yrhs) ∈ ES. (X, xrhs) ≠ (Y, yrhs)"
proof-
  have "card ES > 1" using card e_in finite 
    by (cases "card ES") (auto) 
  then have "card (ES - {(X, xrhs)}) > 0"
    using finite e_in by auto
  then have "(ES - {(X, xrhs)}) ≠ {}" using finite by (rule_tac notI, simp)
  then show "∃(Y, yrhs) ∈ ES. (X, xrhs) ≠ (Y, yrhs)"
    by auto
qed

lemma iteration_step_measure:
  assumes Inv_ES: "invariant ES"
  and    X_in_ES: "(X, xrhs) ∈ ES"
  and    Cnd:     "Cond ES "
  shows "(Iter X ES, ES) ∈ measure card"
proof -
  have fin: "finite ES" using Inv_ES unfolding invariant_def by simp
  then obtain Y yrhs 
    where Y_in_ES: "(Y, yrhs) ∈ ES" and not_eq: "(X, xrhs) ≠ (Y, yrhs)" 
    using Cnd X_in_ES by (drule_tac card_noteq_1_has_more) (auto)
  then have "(Y, yrhs) ∈ ES " "X ≠ Y"  
    using X_in_ES Inv_ES unfolding invariant_def distinctness_def
    by auto
  then show "(Iter X ES, ES) ∈ measure card" 
  apply(rule IterI2)
  apply(rule Remove_in_card_measure)
  apply(simp_all add: fin)
  done
qed

lemma iteration_step_invariant:
  assumes Inv_ES: "invariant ES"
  and    X_in_ES: "(X, xrhs) ∈ ES"
  and    Cnd: "Cond ES"
  shows "invariant (Iter X ES)"
proof -
  have finite_ES: "finite ES" using Inv_ES by (simp add: invariant_def)
  then obtain Y yrhs 
    where Y_in_ES: "(Y, yrhs) ∈ ES" and not_eq: "(X, xrhs) ≠ (Y, yrhs)" 
    using Cnd X_in_ES by (drule_tac card_noteq_1_has_more) (auto)
  then have "(Y, yrhs) ∈ ES" "X ≠ Y" 
    using X_in_ES Inv_ES unfolding invariant_def distinctness_def
    by auto
  then show "invariant (Iter X ES)" 
  proof(rule IterI2)
    fix Y yrhs
    assume h: "(Y, yrhs) ∈ ES" "X ≠ Y"
    then have "ES - {(Y, yrhs)} ∪ {(Y, yrhs)} = ES" by auto
    then show "invariant (Remove ES Y yrhs)" unfolding Remove_def
      using Inv_ES
      by (rule_tac Subst_all_satisfies_invariant) (simp) 
  qed
qed

lemma iteration_step_ex:
  assumes Inv_ES: "invariant ES"
  and    X_in_ES: "(X, xrhs) ∈ ES"
  and    Cnd: "Cond ES"
  shows "∃xrhs'. (X, xrhs') ∈ (Iter X ES)"
proof -
  have finite_ES: "finite ES" using Inv_ES by (simp add: invariant_def)
  then obtain Y yrhs 
    where "(Y, yrhs) ∈ ES" "(X, xrhs) ≠ (Y, yrhs)" 
    using Cnd X_in_ES by (drule_tac card_noteq_1_has_more) (auto)
  then have "(Y, yrhs) ∈ ES " "X ≠ Y"  
    using X_in_ES Inv_ES unfolding invariant_def distinctness_def
    by auto
  then show "∃xrhs'. (X, xrhs') ∈ (Iter X ES)" 
  apply(rule IterI2)
  unfolding Remove_def
  apply(rule Subst_all_cls_remains)
  using X_in_ES
  apply(auto)
  done
qed


subsection ‹The conclusion of the first direction›

lemma Solve:
  fixes A::"('a::finite) lang"
  assumes fin: "finite (UNIV // ≈A)"
  and     X_in: "X ∈ (UNIV // ≈A)"
  shows "∃rhs. Solve X (Init (UNIV // ≈A)) = {(X, rhs)} ∧ invariant {(X, rhs)}"
proof -
  define Inv where "Inv ES ⟷ invariant ES ∧ (∃rhs. (X, rhs) ∈ ES)" for ES
  have "Inv (Init (UNIV // ≈A))" unfolding Inv_def
      using fin X_in by (simp add: Init_ES_satisfies_invariant, simp add: Init_def)
  moreover
  { fix ES
    assume inv: "Inv ES" and crd: "Cond ES"
    then have "Inv (Iter X ES)"
      unfolding Inv_def
      by (auto simp add: iteration_step_invariant iteration_step_ex) }
  moreover
  { fix ES
    assume inv: "Inv ES" and not_crd: "¬Cond ES"
    from inv obtain rhs where "(X, rhs) ∈ ES" unfolding Inv_def by auto
    moreover
    from not_crd have "card ES = 1" by simp
    ultimately 
    have "ES = {(X, rhs)}" by (auto simp add: card_Suc_eq) 
    then have "∃rhs'. ES = {(X, rhs')} ∧ invariant {(X, rhs')}" using inv
      unfolding Inv_def by auto }
  moreover
    have "wf (measure card)" by simp
  moreover
  { fix ES
    assume inv: "Inv ES" and crd: "Cond ES"
    then have "(Iter X ES, ES) ∈ measure card"
      unfolding Inv_def
      apply(clarify)
      apply(rule_tac iteration_step_measure)
      apply(auto)
      done }
  ultimately 
  show "∃rhs. Solve X (Init (UNIV // ≈A)) = {(X, rhs)} ∧ invariant {(X, rhs)}" 
    unfolding Solve_def by (rule while_rule)
qed

lemma every_eqcl_has_reg:
  fixes A::"('a::finite) lang"
  assumes finite_CS: "finite (UNIV // ≈A)"
  and X_in_CS: "X ∈ (UNIV // ≈A)"
  shows "∃r. X = lang r" 
proof -
  from finite_CS X_in_CS 
  obtain xrhs where Inv_ES: "invariant {(X, xrhs)}"
    using Solve by metis

  define A where "A = Arden X xrhs"
  have "rhss xrhs ⊆ {X}" using Inv_ES 
    unfolding validity_def invariant_def rhss_def lhss_def
    by auto
  then have "rhss A = {}" unfolding A_def 
    by (simp add: Arden_removes_cl)
  then have eq: "{Lam r | r. Lam r ∈ A} = A" unfolding rhss_def
    by (auto, case_tac x, auto)
  
  have "finite A" using Inv_ES unfolding A_def invariant_def finite_rhs_def
    using Arden_preserves_finite by auto
  then have fin: "finite {r. Lam r ∈ A}" by (rule finite_Lam)

  have "X = lang_rhs xrhs" using Inv_ES unfolding invariant_def soundness_def
    by simp
  then have "X = lang_rhs A" using Inv_ES 
    unfolding A_def invariant_def ardenable_all_def finite_rhs_def 
    by (rule_tac Arden_preserves_soundness) (simp_all add: finite_Trn)
  then have "X = lang_rhs {Lam r | r. Lam r ∈ A}" using eq by simp
  then have "X = lang (⨄{r. Lam r ∈ A})" using fin by auto
  then show "∃r. X = lang r" by blast
qed

lemma bchoice_finite_set:
  assumes a: "∀x ∈ S. ∃y. x = f y" 
  and     b: "finite S"
  shows "∃ys. (⋃ S) = ⋃(f ` ys) ∧ finite ys"
using bchoice[OF a] b
apply(erule_tac exE)
apply(rule_tac x="fa ` S" in exI)
apply(auto)
done

theorem Myhill_Nerode1:
  fixes A::"('a::finite) lang"
  assumes finite_CS: "finite (UNIV // ≈A)"
  shows   "∃r. A = lang r"
proof -
  have fin: "finite (finals A)" 
    using finals_in_partitions finite_CS by (rule finite_subset)
  have "∀X ∈ (UNIV // ≈A). ∃r. X = lang r" 
    using finite_CS every_eqcl_has_reg by blast
  then have a: "∀X ∈ finals A. ∃r. X = lang r"
    using finals_in_partitions by auto
  then obtain rs::"('a rexp) set" where "⋃ (finals A) = ⋃(lang ` rs)" "finite rs"
    using fin by (auto dest: bchoice_finite_set)
  then have "A = lang (⨄rs)" 
    unfolding lang_is_union_of_finals[symmetric] by simp
  then show "∃r. A = lang r" by blast
qed 


end