https://gitlab.com/formalcow/combinatorics-on-words-formalized
Raw File
Tip revision: a4ae71365568015f2f8958c96856fd8b8e9a180a authored by Štěpán Starosta on 14 May 2021, 15:37:50 UTC
v1.4.0: renamed directories to match session names, several small additions (incl. some code equations), many optimizations; moved CoW/Borders into CoW/CoWBasic
Tip revision: a4ae713
Graph_Lemma.thy
(*  Title:      CoW_Graph_Lemma.Graph_Lemma
    Author:     Štěpán Holub, Charles University
    Author:     Štěpán Starosta, CTU in Prague
*)

theory Graph_Lemma
  imports CoW.Submonoids

begin

chapter \<open>Graph Lemma\<close>

text\<open>The Graph Lemma is an important tool for gaining information about systems of word equations. 
It yields an upper bound on the rank of the solution, that is, on the number of factors into all images of unknowns can be factorized.
The most straightforward application is showing that a system of equations admits periodic solutions only, which
in particular holds for any nontrivial equation over two words.

The name refers to a graph whose vertices are the unknowns of the system, and edges connect front letters of the left- and right-
hand sides of equations. The bound mentioned above is then the number of connected components of the graph.

We formalize the algebraic proof from @{cite Berstel1979} \<close>

text\<open>Let @{term C} be a set of generators, and $b$ its distinguished element. We define the set of all 
 products that do not start with $b$.\<close>

inductive_set no_head :: "'a list set \<Rightarrow> 'a list \<Rightarrow> 'a list set"
  for C b where
  emp_in_no_head[simp]:  "\<epsilon> \<in> no_head C b"
  | "u \<in> C \<Longrightarrow> u \<noteq> b \<Longrightarrow> u \<in> no_head C b" 
  | "u \<noteq> \<epsilon> \<Longrightarrow> u \<in> no_head C b \<Longrightarrow> v \<in> \<langle>C\<rangle> \<Longrightarrow>  u \<cdot> v \<in> no_head C b"

text\<open>The set is a submonoid of @{term "\<langle>C\<rangle>"}\<close>

lemma no_head_sub: "b \<in> C \<Longrightarrow> no_head C b \<subseteq> \<langle>C\<rangle>"
proof
  fix u assume "b \<in> C" "u \<in> no_head C b"
  show "u \<in> \<langle>C\<rangle>"
  proof (induction rule: no_head.induct[OF \<open>u \<in> no_head C b\<close>], auto)
    case (3 u v)
    then show "u \<cdot> v \<in> \<langle>C\<rangle>"
      using hull_closed by blast 
  qed
qed

lemma no_head_closed:  "b \<in> C \<Longrightarrow> \<langle>no_head C b\<rangle> = no_head C b"
proof(intro equalityI subsetI)
  fix x assume  "x \<in> \<langle>no_head C b\<rangle>"
  thus "b \<in> C \<Longrightarrow> x \<in> no_head C b" 
  proof (induction rule: hull.induct, simp)
    case (prod_cl w1 w2)
    then show "w1 \<cdot> w2 \<in> no_head C b"
      using  no_head.intros(3)[OF _ \<open>w1 \<in> no_head C b\<close>]
      in_mono[OF no_head_sub[OF \<open>b \<in> C\<close>], of w2] by fastforce
  qed
next
  fix x assume "b \<in> C" "x \<in> no_head C b"
  show "x \<in> \<langle>no_head C b\<rangle>"
    by (simp add: \<open>x \<in> no_head C b\<close> gen_in)
qed

text\<open>We are interested mainly in the situation when @{term C} is a code.\<close>

context code
begin

text\<open>We characterize the set @{term no_head} in terms of the decomposition of its (nonempty) elements: the first factor is not b\<close>

lemma no_head_hd: assumes "b \<in> \<C>" and "u \<in> no_head \<C> b" and "u \<noteq> \<epsilon>" shows "hd (Dec \<C> u) \<noteq> b"
  using \<open>u \<noteq> \<epsilon>\<close> 
proof(induct rule: no_head.induct[OF \<open>u \<in> no_head \<C> b\<close>], simp)
  case (2 u)
  then show ?case
    using code_el_dec by auto
next
  case (3 u v)
  have "Dec \<C> u \<noteq> \<epsilon>" and "u \<in> \<langle>\<C>\<rangle>" and "v \<in> \<langle>\<C>\<rangle>" 
    using dec_nemp no_head_sub[OF \<open>b \<in> \<C>\<close>] "3.hyps" by blast+
  show "hd (Dec \<C> u \<cdot> v) \<noteq> b" 
    using "3.hyps"(3)[OF \<open>u \<noteq> \<epsilon>\<close>] hd_append2[OF \<open>Dec \<C> u \<noteq> \<epsilon>\<close>, of "Dec \<C> v"] 
    unfolding code_dec_morph[OF \<open> u \<in> \<langle>\<C>\<rangle>\<close> \<open>v \<in> \<langle>\<C>\<rangle>\<close>] by simp
qed 

lemma b_not_in_no_head: assumes "b \<in> \<C>" shows "b \<notin> no_head \<C> b"
  using \<open>b \<in> \<C>\<close> code_el_dec emp_not_in_code no_head_hd by fastforce

lemma hd_no_head: assumes "b \<in> \<C>" "u \<in> \<langle>\<C>\<rangle>" "hd (Dec \<C> u) \<noteq> b" shows "u \<in> no_head \<C> b"
proof(cases "u \<noteq> \<epsilon>", auto)
  assume "u \<noteq> \<epsilon>"
  have "Dec \<C> u \<noteq> \<epsilon>"
    using  dec_nemp'[OF \<open>u \<noteq> \<epsilon>\<close> \<open>u \<in> \<langle>\<C>\<rangle>\<close>].  
  have "u = hd (Dec \<C> u) \<cdot> concat (tl (Dec \<C> u))"
    using  concat.simps(2)[of "hd (Dec \<C> u)" "tl(Dec \<C> u)"] 
    unfolding hd_Cons_tl[OF \<open>Dec \<C> u \<noteq> \<epsilon>\<close>] decI[OF \<open>u \<in> \<langle>\<C>\<rangle>\<close>].
  have "hd (Dec \<C> u) # tl (Dec \<C> u) \<in> lists \<C>" and "hd (Dec \<C> u) \<in> \<C>"
    using \<open>Dec \<C> u \<noteq> \<epsilon>\<close> \<open>u \<in> \<langle>\<C>\<rangle>\<close> dec_dom' lists_hd by auto blast
  have "concat (tl (decompose \<C> u)) \<in> \<langle>\<C>\<rangle>"
    using concat_tl[of "hd (Dec \<C> u)" "tl(Dec \<C> u)" \<C>, OF \<open>hd (Dec \<C> u) # tl (Dec \<C> u) \<in> lists \<C>\<close>].
  have "hd (Dec \<C> u) \<noteq> \<epsilon>" and "hd (Dec \<C> u) \<in> no_head \<C> b"
    using no_head.intros(2)[OF \<open>hd (Dec \<C> u) \<in> \<C>\<close> \<open>hd (Dec \<C> u) \<noteq> b\<close>] \<open>hd (Dec \<C> u) \<in> \<C>\<close> emp_not_in_code by auto
  from no_head.intros(3)[OF this \<open>concat (tl (decompose \<C> u)) \<in> \<langle>\<C>\<rangle>\<close> ] 
  show "u \<in> no_head \<C> b"
    unfolding sym[OF \<open>u = hd (Dec \<C> u) \<cdot> concat (tl (Dec \<C> u))\<close>].
qed

corollary "b \<in> \<C> \<Longrightarrow> no_head \<C> b = {u \<in> \<langle>\<C>\<rangle>. u = \<epsilon> \<or> hd (Dec \<C> u) \<noteq> b}"
proof(intro equalityI subsetI, standard)
  fix x  assume "b \<in> \<C>" "x \<in> no_head \<C> b"
  thus "x \<in> \<langle>\<C>\<rangle> \<and> (x = \<epsilon> \<or> hd (Dec \<C> x) \<noteq> b)"
    using no_head_hd no_head_sub by blast
next
  fix x  assume "b \<in> \<C>" "x \<in> {u \<in> \<langle>\<C>\<rangle>. u = \<epsilon> \<or> hd (Dec \<C> u) \<noteq> b}"
  thus "x \<in> no_head \<C> b"
    using hd_no_head no_head.simps by blast 
qed

end

text\<open>The set @{term no_head} is generated by the following set.\<close>

inductive_set no_head_gen :: "'a list set \<Rightarrow> 'a list \<Rightarrow> 'a list set"
  for C b where
    "u \<in> C \<Longrightarrow> u \<noteq> b \<Longrightarrow> u \<in> no_head_gen C b" 
  | "u \<in> no_head_gen C b \<Longrightarrow>  u \<cdot> b \<in> no_head_gen C b"

lemma no_head_gen_set: "no_head_gen C b = {z \<cdot> b\<^sup>@k |z k. z \<in> C \<and> z \<noteq> b}"
proof(intro equalityI subsetI)
  fix x assume "x \<in> no_head_gen C b"
  hence "\<exists> z k. z \<in> C \<and> z \<noteq> b \<and> x = z \<cdot> b\<^sup>@k" 
  proof (rule no_head_gen.induct[of _ C b])
    fix u assume "u \<in> C" and "u \<noteq> b"
    show "\<exists>z k. z \<in> C \<and> z \<noteq> b \<and> u = z \<cdot> b\<^sup>@k"
      using \<open>u \<in> C\<close> \<open>u \<noteq> b\<close> pow_zero by blast
  next
    fix u assume "u \<in> no_head_gen C b" and "\<exists>z k. z \<in> C \<and> z \<noteq> b \<and> u = z \<cdot> b\<^sup>@k"
    thus "\<exists>z k. z \<in> C \<and> z \<noteq> b \<and> u \<cdot> b = z \<cdot> b\<^sup>@k"
      using pow_Suc2_list[of b] append.assoc by metis         
  qed
  thus "x \<in> {z \<cdot> b\<^sup>@k |z k. z \<in> C \<and> z \<noteq> b}"
    by auto
next
  fix x assume "x \<in> {z \<cdot> b \<^sup>@ k |z k. z \<in> C \<and> z \<noteq> b}"
  then obtain z k where "z \<in> C" and "z \<noteq> b" and "x = z\<cdot>b\<^sup>@k" by blast   
  then show "x \<in> no_head_gen C b"
  proof(induct k arbitrary: x)
    case 0
    then show ?case
      by (simp add: \<open>z \<in> C\<close> \<open>z \<noteq> b\<close> no_head_gen.intros(1)) 
  next
    case (Suc k)
    then show ?case 
      using no_head_gen.intros(2)
      by (metis pow_Suc2_list append.assoc)
  qed
qed

lemma no_head_genE: assumes  "u \<in> no_head_gen C b"
  obtains z k where "z \<in> C" and  "z \<noteq> b" and  "u = z \<cdot> b\<^sup>@k"
proof(induct rule: no_head_gen.induct[OF assms])
  case (1 u)
  show ?case
    using "1.prems"[OF "1.hyps", of 0] by simp  
next
  case (2 u)
  have "(z \<cdot> b\<^sup>@k) \<cdot> b = z \<cdot> b\<^sup>@(Suc k)" for z k
    by (simp add: power_commutes)  
  then show ?case   
    using "2.prems" "2.hyps"(2) by blast
qed

context code
begin

text\<open>We show that this indeed is a set of generators\<close>

lemma emp_not_in_Cb: "\<epsilon> \<notin> no_head_gen \<C> b"
proof-
  have "\<epsilon> \<notin> {z \<cdot> b\<^sup>@k |z k. z \<in> \<C> \<and> z \<noteq> b}"
    by (simp add: emp_not_in_code)
  thus ?thesis
    by (simp add: no_head_gen_set)
qed

thm  no_head_gen.induct

lemma no_head_sub': "b \<in> \<C> \<Longrightarrow> no_head_gen \<C> b \<subseteq> no_head \<C> b"
proof
  fix u assume "b \<in> \<C>" "u \<in> no_head_gen \<C> b"
  show "u \<in> no_head \<C> b"
  proof (induction rule: no_head_gen.induct[OF \<open>u \<in> no_head_gen \<C> b\<close>], simp add: no_head.intros(2))
    case (2 u)
    show "u \<cdot> b \<in> no_head \<C> b"
      using no_head.intros(3)[OF _ \<open>u \<in> no_head \<C> b\<close> gen_in[OF \<open>b \<in> \<C>\<close>]]
       "2.hyps" emp_not_in_Cb by blast 
  qed
qed

lemma no_head_generates0: assumes "v \<in> \<langle>\<C>\<rangle>" shows 
  "u \<noteq> \<epsilon> \<longrightarrow> u \<in> \<langle>no_head_gen \<C> b\<rangle> \<longrightarrow> u \<cdot> v \<in>  \<langle>no_head_gen \<C> b\<rangle>"
proof (induct arbitrary: u rule: hull.induct[OF \<open>v \<in> \<langle>\<C>\<rangle>\<close>], simp)
  case (2 w1 w2)
  then show ?case
  proof(cases "w1 = b")
    assume "w1 \<noteq> b" 
    show ?thesis
      using "2.hyps"(1) emp_not_in_code  no_head_gen.intros(1)[OF \<open>w1 \<in> \<C>\<close> \<open>w1 \<noteq> b\<close>,THEN gen_in]
            "2.hyps"(3)[of w1] hull_closed[of u "no_head_gen \<C> b" "w1\<cdot> w2"] by blast
  next 
    assume "w1 = b"
    show ?thesis
    proof (standard, standard)
      assume "u \<noteq> \<epsilon>" and "u \<in> \<langle>no_head_gen \<C> b\<rangle>"
      hence dec_nemp: "Dec (no_head_gen \<C> b) u \<noteq> \<epsilon>"
        using dec_nemp' by blast
      from concat_butlast_last[OF this]
      have u_w1: "u \<cdot> w1 = concat (butlast (Dec (no_head_gen \<C> b) u)) \<cdot> (last (Dec (no_head_gen \<C> b) u) \<cdot> w1)"
        unfolding decI[OF \<open>u \<in> \<langle>no_head_gen \<C> b\<rangle>\<close>] by simp
      from dec_dom'[OF \<open>u \<in> \<langle>no_head_gen \<C> b\<rangle>\<close>] append_butlast_last_id[OF dec_nemp]
      have con_but: "concat (butlast (Dec (no_head_gen \<C> b) u)) \<in> \<langle>no_head_gen \<C> b\<rangle>" and last_in: "last (Dec (no_head_gen \<C> b) u) \<in> no_head_gen \<C> b"
        using append_in_lists_conv[of "butlast (Dec (no_head_gen \<C> b) u)" "[last (Dec (no_head_gen \<C> b) u)]" "no_head_gen \<C> b"] 
          concat_in_hull'[of "butlast (Dec (no_head_gen \<C> b) u)" "no_head_gen \<C> b"] by auto 
      hence "last (Dec (no_head_gen \<C> b) u) \<cdot> w1 \<in> no_head_gen \<C> b"
        unfolding \<open>w1 = b\<close> using  no_head_gen.intros(2)[of "last (Dec (no_head_gen \<C> b) u)" \<C> b] by blast
      from this[THEN  gen_in,THEN[2] hull_closed, OF con_but]
      have "u \<cdot> w1 \<in> \<langle>no_head_gen \<C> b\<rangle>"
        unfolding u_w1.
      from "2.hyps"(3)[rule_format, OF _ this, unfolded rassoc]
      show "u \<cdot> w1 \<cdot> w2 \<in> \<langle>no_head_gen \<C> b\<rangle>"
        using  pref_nemp[OF \<open>u\<noteq>\<epsilon>\<close>] by blast
    qed
  qed
qed


theorem no_head_generates: assumes "b \<in> \<C>" shows "\<langle>no_head_gen \<C> b\<rangle> =  no_head \<C> b"
proof (intro equalityI)  
  show "\<langle>no_head_gen \<C> b\<rangle> \<subseteq> no_head \<C> b"
    using hull_mon[OF no_head_sub'[OF \<open>b \<in> \<C>\<close>]]  unfolding no_head_closed[OF \<open>b \<in> \<C>\<close>].  
  show "no_head \<C> b \<subseteq> \<langle>no_head_gen \<C> b\<rangle>"
  proof (intro subsetI)
    fix x assume "x \<in> no_head \<C> b" 
    show "x \<in> \<langle>no_head_gen \<C> b\<rangle>"
      by (induct rule: no_head.induct[OF \<open>x \<in> no_head \<C> b\<close>],auto, simp add: gen_in no_head_gen.intros(1),simp add: no_head_generates0)
  qed
qed

text\<open>Moreover, the generating set @{term no_head_gen} is a code\<close>

lemma lists_no_head_sub: "b \<in> \<C> \<Longrightarrow> us \<in> lists (no_head_gen \<C> b) \<Longrightarrow> us \<in> lists \<langle>\<C>\<rangle>"
  using no_head_sub' no_head_sub by blast   

lemma ref_hd: assumes "z \<in> \<C>" and  "b \<in> \<C>" and "z \<noteq> b" and "vs \<in> lists (no_head_gen \<C> b)" 
  shows "refine \<C> ((z\<cdot>b\<^sup>@k) # vs) = [z]\<cdot>[b]\<^sup>@k \<cdot> refine \<C> vs" 
proof-
  have "refine \<C> ((z\<cdot>b\<^sup>@k) # vs) = (Dec \<C> (z\<cdot>b\<^sup>@k)) \<cdot> refine \<C> vs" 
    using ref_pop_hd lists_no_head_sub[OF \<open>b \<in> \<C>\<close>]  by simp 
  have "[z]\<cdot>[b]\<^sup>@k \<in> lists \<C>"
    by (induct k, simp add: \<open>z \<in> \<C>\<close>, simp add: \<open>b \<in> \<C>\<close>)
  have "concat ([z]\<cdot>[b]\<^sup>@k) = z \<cdot> b\<^sup>@k"
    using concat_sing_pow by auto
  hence "Dec \<C> (z\<cdot>b\<^sup>@k) = [z]\<cdot>[b]\<^sup>@k"
    using  code.code_unique_dec[OF code_axioms \<open>[z]\<cdot>[b]\<^sup>@k \<in> lists \<C>\<close>] by auto
  thus ?thesis
    by simp
qed


lemma no_head_gen_code_ind_step:
  assumes "vs \<in> lists (no_head_gen \<C> b)" "us \<in> lists (no_head_gen \<C> b)" "b \<in> \<C>"
    and eq: "[b]\<^sup>@ku \<cdot> (refine \<C> us) = [b]\<^sup>@kv \<cdot> (refine \<C> vs)"
  shows  "ku = kv"
proof-
  {fix ku :: nat and kv and us and vs and b 
    assume "kv \<le> ku" "[b]\<^sup>@ku \<cdot> (refine \<C> us) = [b]\<^sup>@kv \<cdot> (refine \<C> vs)"
      "vs \<in> lists (no_head_gen \<C> b)" "us \<in> lists (no_head_gen \<C> b)" "b \<in> \<C>"
    have  "concat vs \<in> no_head \<C> b"
      using  \<open>vs \<in> lists (no_head_gen \<C> b)\<close> no_head_generates[OF \<open>b \<in> \<C>\<close>] by fastforce
    have  "Ref \<C> vs = Dec \<C> (concat vs)"
      using \<open>vs \<in> lists (no_head_gen \<C> b)\<close> \<open>b \<in> \<C>\<close> code_unique_ref lists_no_head_sub by auto
    have "vs \<noteq> \<epsilon> \<Longrightarrow> concat vs \<noteq> \<epsilon>"
      using  emp_not_in_Cb[of b] concat.simps(2) \<open>vs \<in> lists (no_head_gen \<C> b)\<close>[unfolded lists.simps[of vs]]
        pref_nemp by auto 
    have "[b]\<^sup>@(ku - kv) \<cdot> (refine \<C> us) = refine \<C> vs"
      using \<open>kv \<le> ku\<close> eq pop_pow_cancel \<open>[b]\<^sup>@ku \<cdot> (refine \<C> us) = [b]\<^sup>@kv \<cdot> (refine \<C> vs) \<close>by blast
    hence "ku - kv \<noteq> 0 \<Longrightarrow> hd (refine \<C> vs) = b \<and> vs \<noteq> \<epsilon>"
      using hd_append2[of "[b]\<^sup>@(ku - kv)" "refine \<C> us"]  \<open>[b]\<^sup>@(ku - kv) \<cdot> (refine \<C> us) = refine \<C> vs\<close>
        hd_sing_power[of "ku - kv" b] 
        append_is_Nil_conv[of "[b]\<^sup>@(ku - kv)" "refine \<C> us"]  sing_pow_empty[of b "ku - kv"]
        dec_emp[of \<C>] by auto 
    hence "ku = kv"
      using \<open>kv \<le> ku\<close> no_head_hd[OF \<open>b \<in> \<C>\<close> \<open>concat vs \<in> no_head \<C> b\<close>] \<open>vs \<noteq> \<epsilon> \<Longrightarrow> concat vs \<noteq> \<epsilon>\<close> 
      unfolding \<open>Ref \<C> vs = Dec \<C> (concat vs)\<close> by auto} 
  thus ?thesis  using assms nat_le_linear[of ku kv] by metis
qed 

lemma no_head_gen_code':
  "b \<in> \<C> \<Longrightarrow> xs \<in> lists (no_head_gen \<C> b) 
   \<Longrightarrow> ys \<in>  lists (no_head_gen \<C> b) \<Longrightarrow> concat xs = concat ys \<Longrightarrow> xs = ys"
proof (induct xs ys rule: list_induct2', simp, simp add: emp_not_in_Cb, simp add: emp_not_in_Cb)
  case (4 hx xs hy ys)
  then show ?case 
  proof-
    have "hx # xs \<in> lists \<langle>\<C>\<rangle>" and "hy # ys \<in> lists \<langle>\<C>\<rangle>"
      using \<open>b \<in> \<C>\<close>  \<open>hx # xs \<in> lists (no_head_gen \<C> b)\<close> \<open>hy # ys \<in> lists (no_head_gen \<C> b)\<close> lists_no_head_sub by blast+
    have eq: "refine \<C> (hx#xs) = refine \<C>  (hy#ys)"
      using \<open>concat (hx # xs) = concat (hy # ys)\<close> \<open>hx # xs \<in> lists \<langle>\<C>\<rangle>\<close> \<open>hy # ys \<in> lists \<langle>\<C>\<rangle>\<close>
      using code_unique_ref by presburger 
    have "hx \<in> (no_head_gen \<C> b)" and "hy \<in> (no_head_gen \<C> b)"
      using \<open>hx # xs \<in> lists (no_head_gen \<C> b)\<close> \<open>hy # ys \<in> lists (no_head_gen \<C> b)\<close> by auto+
    then obtain zx zy kx ky where "hx = zx \<cdot> b\<^sup>@kx" and "hy = zy \<cdot> b\<^sup>@ky" "zx \<noteq> b" "zy \<noteq> b" "zx \<in> \<C>" "zy \<in> \<C>"
      using no_head_genE by metis
    have r1: "refine \<C> (hx#xs) = [zx] \<cdot> [b]\<^sup>@kx \<cdot> refine \<C> xs"
      using \<open>hx = zx \<cdot> b\<^sup>@kx\<close> \<open>zx \<in> \<C>\<close> \<open>zx \<noteq> b\<close> ref_hd \<open>b \<in> \<C>\<close> by auto
    have r2: "refine \<C> (hy#ys) = [zy] \<cdot> [b]\<^sup>@ky \<cdot> refine \<C> ys"
      using \<open>hy = zy \<cdot> b\<^sup>@ky\<close> \<open>zy \<in> \<C>\<close> \<open>zy \<noteq> b\<close> ref_hd \<open>b \<in> \<C>\<close> by auto
    hence "zx = zy"
      using r1 r2 eq by auto
    hence "[b]\<^sup>@kx \<cdot> refine \<C> xs = [b]\<^sup>@ky \<cdot> refine \<C> ys"
      using eq r1 r2 by auto 
    hence "kx = ky" 
      using no_head_gen_code_ind_step \<open>b \<in> \<C>\<close> \<open>hx # xs \<in> lists (no_head_gen \<C> b)\<close> \<open>hy # ys \<in> lists (no_head_gen \<C> b)\<close> 
        listsE  by metis 
    hence "hx = hy"
      by (simp add: \<open>hx = zx \<cdot> b\<^sup>@kx\<close> \<open>hy = zy \<cdot> b\<^sup>@ky\<close> \<open>zx = zy\<close>)
    hence "xs = ys" using "4.hyps" 
      using \<open>hx # xs \<in> lists (no_head_gen \<C> b)\<close> \<open>hy # ys \<in> lists (no_head_gen \<C> b)\<close> 
        \<open>concat (hx # xs) = concat (hy # ys)\<close> \<open>b \<in> \<C>\<close> by auto
    thus ?thesis
      by (simp add: \<open>hx = hy\<close>) 
  qed
qed  

end

theorem no_head_gen_code:
  assumes "code C" and "b \<in> C"
  shows "code {z \<cdot> b\<^sup>@k | z k. z \<in> C \<and> z \<noteq> b}"
  using code.no_head_gen_code'[OF \<open>code C\<close> \<open>b \<in> C\<close>] code.intro
  unfolding no_head_gen_set  by blast

text\<open>We are now ready to prove the Graph Lemma \<close>

theorem graph_lemma: "\<BB>\<^sub>F X = {hd (Dec (\<BB>\<^sub>F X) x) | x. x \<in> X \<and> x \<noteq> \<epsilon>}"
proof 
  \<comment> \<open>the core is to show that each element of the free basis must be a head\<close>
  show "\<BB>\<^sub>F X \<subseteq> {hd (Dec (\<BB>\<^sub>F X) x) | x. x \<in> X \<and> x \<noteq> \<epsilon>}"
  proof (rule ccontr)
    \<comment> \<open>Assume the contrary.\<close>
     assume "\<not> \<BB>\<^sub>F X \<subseteq> {hd (Dec \<BB>\<^sub>F X x) |x. x \<in> X \<and> x \<noteq> \<epsilon>}"  
    \<comment> \<open>And let b be the not-head\<close>
    then obtain b where "b \<in> \<BB>\<^sub>F X" and nohd: "\<And> x.   x \<in> X \<and> x \<noteq> \<epsilon> \<Longrightarrow> hd (Dec (\<BB>\<^sub>F X) x) \<noteq> b"
      by blast
    interpret code "\<BB>\<^sub>F X"
        using free_basis_code by auto
          \<comment> \<open>For contradiction: We have a free hull which does not contain b but contains X.\<close>
      let ?Cb = "no_head_gen (\<BB>\<^sub>F X) b"
      have "code ?Cb"
        using \<open>b \<in> \<BB>\<^sub>F X\<close> code_def no_head_gen_code' by blast 
      have "b \<notin> \<langle>?Cb\<rangle>"
        using \<open>b \<in> \<BB>\<^sub>F X\<close> b_not_in_no_head no_head_generates by blast
      have "X \<subseteq> \<langle>?Cb\<rangle>"
      proof
        fix x assume "x \<in> X" 
        hence "x \<in> \<langle>\<BB>\<^sub>F X\<rangle>"
          using basis_gen_hull free_hull.free_gen_in 
          unfolding free_basis_def by blast
        have " x \<in> X \<and> x \<noteq> \<epsilon> \<Longrightarrow> x \<in> \<langle>?Cb\<rangle>"
          using hd_no_head[OF \<open>b \<in> \<BB>\<^sub>F X\<close> \<open>x \<in> \<langle>\<BB>\<^sub>F X\<rangle>\<close> nohd]
            \<open>b \<in> \<BB>\<^sub>F X\<close> no_head_generates by blast
        thus "x \<in> \<langle>?Cb\<rangle>"
          using \<open>x \<in> X\<close> by blast 
      qed
      have "\<langle>X\<rangle>\<^sub>F \<subseteq> \<langle>?Cb\<rangle>" 
        using free_hull_min[OF \<open>code ?Cb\<close> \<open>X \<subseteq> \<langle>?Cb\<rangle>\<close>].
      from this[unfolded subset_eq, rule_format, of b]
      show False
        using \<open>b \<in> \<BB>\<^sub>F X\<close> \<open>b \<notin> \<langle>?Cb\<rangle>\<close> basisD simp_el_el unfolding free_basis_def by blast
  qed
next
  \<comment> \<open>The opposite inclusion is easy\<close>
  show "{hd (Dec (\<BB>\<^sub>F X) x) | x.  x \<in> X \<and> x \<noteq> \<epsilon>} \<subseteq> \<BB>\<^sub>F X"
    using basis_gen_hull_free dec_hd genset_sub_free by blast
qed

section \<open>Binary code\<close>

text\<open>We illustrate the use of the Graph Lemma in an alternative proof of the fact that two non-commuting words form a code.
See also @{thm no_comm_bin_code [no_vars]} in @{theory CoW.CoWBasic}.

First, we prove a lemma which is the core of the alternative proof.
\<close>

lemma non_comm_hds_neq: assumes "u \<cdot> v \<noteq> v \<cdot> u" shows "hd (Dec \<BB>\<^sub>F {u,v} u) \<noteq> hd (Dec \<BB>\<^sub>F {u,v} v)"
proof
  have "u \<noteq> \<epsilon>" and "v \<noteq> \<epsilon>" using assms by auto
  hence basis: "\<BB>\<^sub>F {u,v} = {hd (Dec \<BB>\<^sub>F {u,v} u),hd (Dec \<BB>\<^sub>F {u,v} v)}"
    using graph_lemma[of "{u,v}"] by blast
  assume eq: "hd (Dec \<BB>\<^sub>F {u,v} u) = hd (Dec \<BB>\<^sub>F {u,v} v)"
  hence "u \<in> (hd (Dec \<BB>\<^sub>F {u,v} u))*" 
    using basis unfolding free_basis_def
    by (metis basis_gen_hull free_hull.simps free_hull_hull insertI1 insert_absorb2 sing_gen)
  moreover have  "v \<in> (hd (Dec \<BB>\<^sub>F {u,v} u))*"
    using basis eq unfolding free_basis_def
    by (metis basis_gen_hull free_hull_hull genset_sub_free insert_absorb2 insert_subset sing_gen) 
  ultimately show False
    using comm_root assms by blast
qed

theorem assumes "u \<cdot> v \<noteq> v \<cdot> u" 
  shows "xs \<in> lists {u, v} \<Longrightarrow> ys \<in> lists {u, v} \<Longrightarrow> concat xs = concat ys \<Longrightarrow> xs = ys"
proof (induct xs ys rule: list_induct2', simp)
  case (2 x xs)
  then show ?case
    using Nil_is_append_conv append_Nil assms by auto 
next
  case (3 y ys)
  then show ?case
    using Nil_is_append_conv append_Nil assms by auto 
next
  case (4 x xs y ys)
  then show ?case
  proof-
    have "u \<noteq> \<epsilon>" and "v \<noteq> \<epsilon>" using assms by force+
    hence "x \<noteq> \<epsilon>" and "y \<noteq> \<epsilon>" using \<open>x # xs \<in> lists {u, v}\<close> \<open>y # ys \<in> lists {u, v}\<close> by auto
    have or_x: "x = u \<or> x = v" and or_y: "y = u \<or> y = v" using \<open>x # xs \<in> lists {u, v}\<close> \<open>y # ys \<in> lists {u, v}\<close> by auto

    have hd_z: "z \<noteq> \<epsilon> \<Longrightarrow> z # zs \<in> lists {u, v} \<Longrightarrow> hd (Dec \<BB>\<^sub>F {u,v} (concat (z#zs))) = hd (Dec \<BB>\<^sub>F {u,v} z)" for z zs
    proof-
      assume "z \<noteq> \<epsilon>" "z # zs \<in> lists {u, v}"
      have "z \<in> \<langle>{u,v}\<rangle>\<^sub>F"
        using \<open>z # zs \<in> lists {u, v}\<close> by auto
      moreover have "concat zs \<in> \<langle>{u,v}\<rangle>\<^sub>F"
        using concat_tl[OF \<open>z # zs \<in> lists {u, v}\<close>] hull_in_free_hull[of "{u,v}"] by blast 
      ultimately have "Dec \<BB>\<^sub>F {u,v} (concat (z#zs)) = (Dec \<BB>\<^sub>F {u,v} z) \<cdot> (Dec \<BB>\<^sub>F {u,v} (concat zs))"
        using free_basis_dec_morph[of z "{u,v}" "concat zs"] by fastforce
      moreover have "Dec \<BB>\<^sub>F {u,v} z \<noteq> \<epsilon>"
        using \<open>z \<in> \<langle>{u, v}\<rangle>\<^sub>F\<close> basis_gen_hull_free dec_nemp'[OF  \<open>z \<noteq> \<epsilon>\<close>] by blast
      ultimately show "hd (Dec \<BB>\<^sub>F {u,v} (concat (z#zs))) = hd (Dec \<BB>\<^sub>F {u,v} z)"
        using hd_append  by simp
    qed
    
    have "hd (Dec \<BB>\<^sub>F {u,v} u) \<noteq> hd (Dec \<BB>\<^sub>F {u,v} v)" 
      using non_comm_hds_neq[OF assms].
    hence "x  = y"
      using hd_z[OF \<open>x \<noteq> \<epsilon>\<close> \<open>x # xs \<in> lists {u, v}\<close> , unfolded \<open>concat (x # xs) = concat (y # ys)\<close> hd_z[OF \<open>y \<noteq> \<epsilon>\<close> \<open>y # ys \<in> lists {u, v}\<close>]] or_x or_y 
      by fastforce
    thus ?thesis
      using "4.hyps" "4.prems" by auto 
  qed
qed

end
back to top