Theory Lyndon_Schutzenberger

(*  Title:      CoW_Equations/Lyndon_Schutzenberger.thy
    Author:     Štěpán Holub, Charles University
    Author:     Štěpán Starosta, CTU in Prague

Part of Combinatorics on Words Formalized. See https://gitlab.com/formalcow/combinatorics-on-words-formalized/
*)

theory Lyndon_Schutzenberger
  imports Submonoids Periodicity_Lemma

begin

chapter ‹Lyndon-Schützenberger Equation›

section ‹The original result›

text‹The Lyndon-Schützenberger equation is the following equation:
\[
x^ay^b = z^c,
\]
in this formalization denoted as @{term "x@ay@b = z@c"}.

We formalize here a complete solution of this equation.

The main result, proved by Lyndon and Schützenberger is that the equation has periodic solutions only in free groups if $2 \leq a,b,c$
In this formalization we consider the equation in words only. Then the original result can be formulated as saying that all words
$x$, $y$ and $z$ satisfying the equality ith $2 \leq a,b,c$ pairwise commute.

The result in free groups was first proved in @{cite LySch62}.
For words, there are several proofs to be found in the literature (for instance @{cite Lo83 and Dmsi2006}).
The presented proof is the authors' proof.

In addition, we give a full parametric solution of the equation for any $a$, $b$ and $c$.
›

section "The original result"

text‹If $x^a$ or $y^b$ is sufficiently long, then the claim follows from the Periodicity Lemma.›

lemma LS_per_lemma_case1:
  assumes eq: "x@ay@b = z@c" and "0 < a" and "0 < b" and "|z| + |x| - 1  |x@a|"
  shows "x  y = y  x" and "x  z = z  x"
proof
  have "x@a ≤p (z@c)  x@a" "x @ a ≤p x  x @ a"
    unfolding eq[symmetric] shifts_rev by blast+
  hence "x@a ≤p z  x@a"
    using eq pref_prod_root triv_pref by metis
  from two_pers_1[OF this x @ a ≤p x  x @ a |z| + |x| - 1  |x @ a|, symmetric]
  show "x  z = z  x".
  hence "z@cx@a = x@az@c"
    by (simp add: comm_add_exps)
  from this[folded eq, unfolded rassoc cancel, symmetric]
  have "x@a  y@b = y@b  x@a".
  from this[unfolded  comm_pow_roots[OF 0 < a 0 < b]]
  show "x  y = y  x".
qed

text ‹A weaker version will be often more convenient›
lemma LS_per_lemma_case:
  assumes eq: "x@ay@b = z@c" and "0 < a" and "0 < b" and "|z| + |x|  |x@a|"
  shows "x  y = y  x" and "x  z = z  x"
  using LS_per_lemma_case1[OF assms(1-3)] assms(4) by force+

text‹The most challenging case is when $c = 3$.›

lemma LS_core_case:
  assumes
    eq: "x@a  y@b = z@c" and
    "2  a" and "2  b" and "2  c" and
    "c = 3" and
    "b*|y|  a*|x|" and "x  ε" and "y  ε" and
    lenx: "a*|x| < |z| + |x|" and
    leny: "b*|y| < |z| + |y|"
  shows "xy = yx"
proof-
  have "0 < a" and "0 < b"
    using 2  a 2  b by auto

―‹We first show that a = 2›
  have "a*|x|+b*|y| = 3*|z|"
    using c = 3 eq lenmorph[of "x@a" "y@b"]
    by (simp add: pow_len)
  hence "3*|z|  a*|x| + a*|x|"
    using b*|y|  a*|x|  by simp
  hence "3*|z| < 2*|z| + 2*|x|"
    using lenx by linarith
  hence "|z| + |x| < 3 * |x|" by simp
  from less_trans[OF lenx this, unfolded mult_less_cancel2]
  have "a = 2" using 2  a by force

  hence "|y|  |x|" using b*|y|  a*|x| 2  b
      pow_len[of x 2]  pow_len[of y b]
      mult_le_less_imp_less[of a b "|x|" "|y|"] not_le
    by auto
  have "xxy@b = zzz" using 2  a eq c=3 a=2
    by (simp add: numeral_2_eq_2 numeral_3_eq_3)

― ‹Find words u, v, w›
  have "|z| < |xx|"
    using |z| + |x| < 3 * |x| add.commute by auto
  from ruler_le[THEN prefD, OF triv_pref[of z "zz"] _ less_imp_le[OF this]]
  obtain w  where "zw = xx"
    using prefI[of "xx" "y@b" "zzz", unfolded rassoc, OF xxy@b = zzz] by fastforce

  have "|x| < |z|"
    using a = 2 lenx by auto
  from ruler_le[THEN prefD, OF _ _ less_imp_le[OF this], of "xxy@b", OF triv_pref, unfolded xxy@b = zzz, OF triv_pref]
  obtain u :: "'a list" where "xu=z"
    by blast
  have "u  ε"
    using |x| < |z| xu = z by auto
  have "x = uw" using  zw = xx xu = z by auto

  have "|xx| < |zz|"  by (simp add: |x| < |z| add_less_mono)
  from ruler_le[OF triv_pref[of "xx" "y@b", unfolded  rassoc xxy@b = zzz, unfolded lassoc] triv_pref, OF less_imp_le[OF this]]
  have "zw ≤p zz"
    unfolding zw = xx.
  obtain v :: "'a list" where "w  v = x"
    using lq_pref[of w x]
      pref_prod_pref'[OF pref_cancel[OF zw ≤p zz, folded x  u = z, unfolded x = u  w rassoc], folded  x = u  w] by blast
  have "uwv  ε"
    by (simp add: u  ε)

― ‹Express x, y and z in terms of  u, v and w›
  hence "z = wvu"
    using w  v = x x  u = z by auto
  from x  x  y@b = z  z  z[unfolded this lassoc, folded z  w = x  x, unfolded this rassoc]
  have "wv  uw  y@b = wvuwvuwvu".
  hence "y@b = vuwvu"
    using pref_cancel by auto

― ‹Double period of uwv›
  from period_fac[OF _ uwv  ε, of v u "|y|", unfolded rassoc, folded this]
  have "period (uwv) |y|"
    using pow_per[OF y  ε 0 < b] by blast
  have "uwv = x v"
    by (simp add: x = u  w)
  have "uwv = u x"
    by (simp add: w  v = x)
  have "uwv <p u  (uwv)"
    using u  w  v = u  x[unfolded x = u  w] u  ε triv_pref[of "u  u  w" v]
    by force
  have "period (uwv) |u|"
    using uwv <p u  (uwv) by auto

― ‹Common period d›
  obtain d::nat where "d=gcd |y| |u|"
    by simp
  have "|y| + |u|  |uwv|" using |y|  |x| lenmorph uwv = u x
    by simp
  hence "period (uwv) d"
    using period (u  w  v) |u| period (u  w  v) |y| d = gcd |y| |u| two_periods
    by blast

― ‹Divisibility›
  have "vuz=y@b"
    by (simp add: y@b = v  u  w  v  u z = w  v  u)
  have "|u| = |v|"
    using x = u  w w  v = x lenmorph[of u w] lenmorph[of w v] add.commute[of "|u|" "|w|"] add_left_cancel
    by simp
  hence "d dvd |v|" using gcd_nat.cobounded1[of "|v|" "|y|"] gcd.commute[of "|y|" "|u|"]
    by (simp add: d = gcd |y| |u|)
  have "d dvd |u|"
    by (simp add: d = gcd  |y| |u|)
  have "|z| + |u| + |v| = b*|y|"
    using  lenarg[OF vuz=y@b, unfolded lenmorph pow_len] by auto
  from dvd_add_left_iff[OF d dvd |v|, of "|z|+|u|", unfolded this dvd_add_left_iff[OF d dvd |u|, of "|z|"]]
  have "d dvd |z|"
    using d = gcd  |y| |u| dvd_mult by blast
  from lenarg[OF z = w  v  u, unfolded lenmorph pow_len]
  have "d dvd |w|"
    using d dvd |z|  d dvd |u| d dvd |v|  by (simp add: dvd_add_left_iff)
  hence "d dvd |x|"
    using d dvd |v| w  v = x by force

― ‹x and y commute›
  have "x ≤p uwv"
    by (simp add: x = u  w)
  have "period x d" using per_pref'[OF xε  period (uwv) d x ≤p u wv].
  hence "x  (take d x)*"
    using d dvd |x|
    using root_divisor by blast

  hence "period u d " using x = u  w per_pref'
    using period x d u  ε by blast
  have " take d x = take d u" using uε  x = u  w pref_share_take
    by (simp add: d = gcd  |y| |u|)
  from root_divisor[OF period u d d dvd |u|, folded this]
  have "u  (take d x)*".


  hence "z  (take d x)*"
    using xu=z x  (take d x)* add_roots by blast
  from root_pref_cancel[OF _ root_pow_root[OF  x  take d x*, of a],of "y@b", unfolded eq, OF root_pow_root[OF  this, of c]]
  have "y@b  (take d x)*".
  from  comm_rootI[OF root_pow_root[OF  x  take d x*, of a] this]
  show "x  y = y  x"
    unfolding comm_pow_roots[OF 0 < a 0 < b, of x y].
qed


text‹The main proof is by induction on the length of $z$. It also uses the reverse symmetry of the equation which is
exploited by two interpretations of the locale @{term LS}. Note also that the case $|x^a| < |y^b|$ is solved by
using induction on $|z| + |y^b|$ instead of just on $|z|$.
›

lemma Lyndon_Schutzenberger':
  " x@ay@b = z@c;  2  a;  2  b; 2  c 
   xy = yx"
proof (induction "|z| + b* |y|" arbitrary: x y z a b c  rule: less_induct)
  case less

  have "0 < a" and "0 < b"
    using 2  a 2  b by auto

  have LSrev_eq: "rev y @ b  rev x @ a = rev z @ c"
    using x@ay@b = z@c
    unfolding rev_append[symmetric] rev_pow[symmetric]
    by blast

  have leneq: "a * |x| + b*|y| = c * |z|"
    using lenarg[OF x@ay@b = z@c] unfolding pow_len lenmorph.

  show "x  y = y  x"
  proof
    assume "x  ε" and "y  ε"
    show "x  y = y  x"
    proof (cases "|x @ a| < |y @ b|")

― ‹WLOG assumption›
      assume "|x@a| < |y@b|"
      have "|rev z| + a* |rev x| < |z| + b* |y|" using |x@a| < |y@b|
        by (simp add: pow_len)
      from "less.hyps"[OF this LSrev_eq 2  b 2  a 2  c, symmetric]
      show "x  y = y  x"
        unfolding rev_append[symmetric] rev_is_rev_conv by simp
    next
      assume " ¬ |x@a| < |y@b|" hence "|y@b|  |x@a|" by force
          ― ‹case solved by the Periodicity lemma›
      note minus =  Suc_minus2[OF 2  a] Suc_minus2[OF 2  b]
      consider (with_Periodicity_lemma)
        "|z| + |x|  |x @ Suc(Suc (a-2))|  |z| + |y|  |y @ Suc(Suc (b-2))|" |
        (without_Periodicity_lemma)
        "|x@Suc(Suc (a-2))| < |z| + |x|" and "|y@Suc(Suc (b-2))| < |z| + |y|"
        unfolding minus
        using not_le_imp_less by blast
      thus "x  y = y  x"
      proof (cases)
        case with_Periodicity_lemma
        have "x = ε  rev y = ε  x  y = y  x"
          by auto
        thus "x  y = y  x"
          using LS_per_lemma_case[OF x@ay@b = z@c 0 < a 0 < b]
            LS_per_lemma_case[OF LSrev_eq 0 < b 0 < a] with_Periodicity_lemma[unfolded minus]
          unfolding length_rev rev_append[symmetric] rev_is_rev_conv rev_pow[symmetric]
          by linarith
      next
        case without_Periodicity_lemma
        assume lenx: "|x@Suc (Suc (a-2))| < |z| + |x|" and leny: "|y@Suc (Suc (b-2))| < |z| + |y|"
        have "Suc (Suc (a-2)) * |x| + Suc (Suc (b-2))*|y| < 4 * |z|"
          using  lenx leny unfolding pow_len by fastforce
        hence "c < 4" using leneq unfolding minus  by auto
        consider (c_is_3) "c = 3" | (c_is_2) "c = 2"
          using c < 4 2  c by linarith
        then show "x  y = y  x"
        proof(cases)
          case c_is_3
          show "x  y = y  x"
            using
              LS_core_case[OF x@ay@b = z@c 2  a 2  b 2  c c = 3 |y@b|  |x@a|[unfolded pow_len]
                _ _ lenx[unfolded pow_len minus] leny[unfolded pow_len minus]]
              x  ε y  ε
            by blast
        next
          assume "c = 2"
          hence eq2: "x@a  y@b = z  z"
            by (simp add: x@ay@b = z@c)
          from dual_order.trans  le_cases[of "|x@a|" "|z|" "|z|  |x@a|", unfolded eq_len_iff[OF this]]
          have "|z|  |x@a|"
            using |y@b|  |x@a| by blast
          define a' where "a'  a - 1"
          have "Suc a' = a" and "1  a'"
            using 2  a unfolding a'_def by auto
          from eq2[folded Suc a' = a, unfolded pow_Suc' rassoc]  pow_Suc'[of x a', unfolded this, symmetric]
          have eq3: "x @ a'  x  y @ b = z  z" and aa':"x @ a'  x = x @ a ".
          hence "|x@a'| < |z|"
            using Suc a' = a lenx unfolding  pow_len minus by fastforce
          hence "|x| < |z|"
            using  mult_le_mono[of 1 a' "|z|" "|x|", OF 1  a', THEN leD] unfolding pow_len
            by linarith
          obtain u w where "x@a'u = z" and "w  y@b = z"
            using eqdE[OF eq3[unfolded rassoc] less_imp_le[OF |x@a'| < |z|], of thesis]
              eqdE[OF eq2[symmetric]  |z|  |x@a|, of thesis] by fast

          have "x@a'xy@b = x@a'uwy@b"
            unfolding lassoc  x @ a'  u = z w  y@b = z aa' eq2 cancel..
          hence "uw=x"
            by auto
          hence "|wu| = |x|"
            using swap_len by blast

― ‹Induction step: new equation with shorter z›
          have "w@2y@b = (wu)@a"
            unfolding pow_two using w  y @ b = z x @ a'  u = z uw=x pow_slide[of w u a', unfolded Suc a' = a] by simp
          from "less.hyps"[OF _ this _ 2  b 2  a, unfolded |wu| = |x|]
          have "yw = wy"
            using  |x| < |z|  by force

          have "y  z = z  y"
            unfolding w  y@b = z[symmetric] lassoc yw = wy
            by (simp add: pow_comm)
          hence "z@cy@b = y@bz@c"
            by (simp add: comm_add_exps)
          from this[folded x@ay@b = z@c, unfolded lassoc]
          have "x@ay@b = y@bx@a"
            using cancel_right by blast
          from this[unfolded comm_pow_roots[OF 0 < a 0 < b]]
          show "x  y = y  x".
        qed
      qed
    qed
  qed
qed

theorem Lyndon_Schutzenberger:
  assumes "x@ay@b = z@c" and  "2  a"  and "2  b" and "2  c"
  shows  "xy = yx" and "xz = zx" and "yz = zy"
proof-
  show "x  y = y  x"
    using Lyndon_Schutzenberger'[OF assms].
  have "0 < c" and  "0 < b"
    using  2  c 2  b by auto
  have "x  x@a  y@b = x@a  y@b  x" and "y  x@a  y@b = x@a  y@b  y"
    unfolding comm_add_exp[OF x  y = y  x[symmetric], of b]
    unfolding lassoc pow_comm comm_add_exp[OF x  y = y  x, symmetric, of a] by blast+
  thus "xz = zx" and "yz = zy"
    using comm_drop_exp[OF 0 < c] unfolding lassoc x@ay@b = z@c by metis+
qed
hide_fact Lyndon_Schutzenberger' LS_core_case

subsection "Some alternative formulations."

lemma Lyndon_Schutzenberger_conjug: assumes "u  v" and  "¬ primitive (u  v)" shows "u  v = v  u"
proof-
  obtain r s where "u = r  s" and "v = s  r"
    using u  v by blast
  have "u  v  r@2  s@2"
    using conjugI'[of "r  s  s" r] unfolding u = r  s v = s  r pow_two rassoc.
  hence "¬ primitive (r@2  s@2)"
    using ¬ primitive (u  v) prim_conjug by auto
  from not_prim_primroot_expE[OF this, of "r  s = s  r"]
  have "r  s = s  r"
    using Lyndon_Schutzenberger(1)[of r 2 s 2, OF _ order.refl order.refl] by metis
  thus "u  v = v  u"
    using u = r  s v = s  r by presburger
qed

lemma Lyndon_Schutzenberger_prim: assumes "¬ primitive x" and "¬ primitive y" and "¬ primitive (x  y)"
  shows "x  y = y  x"
proof
  assume "x  ε" and "y  ε"
  from not_prim_primroot_expE[OF ¬ primitive y]
  obtain m where "ρ y@m = y" and "2  m".
  from not_prim_primroot_expE[OF ¬ primitive x]
  obtain k where "ρ x@k = x" and "2  k".
  from not_prim_primroot_expE[OF ¬ primitive (x  y)]
  obtain l where "ρ(x  y)@l = x  y" and "2  l".
  from Lyndon_Schutzenberger(1)[of "ρ x" k "ρ y" m "ρ (x  y)" l,
       OF _  2  k 2  m 2  l]
  show "x  y = y  x"
    unfolding ρ y@m = y ρ x@k = x ρ(x  y)@l = x  y
    comp_primroot_conv'[of x y] by blast
qed

lemma Lyndon_Schutzenberger_rotate: assumes "x@c = r @ k  u@b  r @ k'"
  and "2  b" and "2  c" and "0 < k" and "0 < k'"
shows "u  r = r  u"
proof(rule comm_drop_exps)
  show "u@b  r@(k' + k) = r@(k' + k)  u@b"
  proof(rule Lyndon_Schutzenberger_prim)
    have "2  (k' + k)"
      using 0 < k 0 < k' by simp
    from pow_nemp_imprim[OF 2  b] pow_nemp_imprim[OF this]
    show "¬ primitive (u@b)" and "¬ primitive (r @ (k' + k))"
      unfolding Suc_minus2[OF 2  b].
    from pow_nemp_imprim[OF 2  c]
    have "¬ primitive (r @ k  u@b  r @ k')"
      unfolding assms(1)[symmetric].
    from this[unfolded conjug_prim_iff[OF conjugI'[of "r @ k" "u @ b  r @ k'"]] rassoc]
    show "¬ primitive (u @ b  r @ (k' + k))"
      unfolding add_exps[symmetric] by force
  qed
qed (use assms in force)+

section ‹Parametric solution of the equation @{term "x@jy@k = z@l"}

subsection ‹Auxiliary lemmas›

lemma xjy_imprim_len: assumes "x  y  y  x" and eq: "x@j  y = z@l" and "2  j" and "2  l"
  shows "|x@j| < |y| + 2*|x|" and "|z| < |x| + |y|" and "|x| < |z|" and "|x@j| < |z| + |x|"
proof-
  define j' where "j'  j - 2"
  have "0 < j" "j = Suc(Suc j')"
    unfolding j'_def using 2  j by force+
  from LS_per_lemma_case[of _ _ _ 1, unfolded pow_1, OF eq 0 < j]
  show "|x@j| < |z| + |x|"
    using x  y  y  x by linarith
  from lenarg[OF eq, unfolded lenmorph, unfolded pow_len]
    add_less_mono1[OF this, of "|y|",  unfolded pow_len]
  show "|z| < |x| + |y|"
    using mult_le_mono1[OF 2  l, unfolded mult_2, of "|z|"] by linarith
  with |x@j| < |z| + |x|
  show "|x@j| < |y| + 2*|x|" and "|x| < |z|"
    unfolding j = Suc (Suc j') pow_Suc lenmorph mult_2 by linarith+
qed

lemma case_j1k1: assumes
  eq: "xy = z@l" and
  non_comm: "x  y  y  x" and
  l_min: "2  l"
  obtains r q m n where
    "x = (rq)@mr" and
    "y = q (r  q)@n" and
    "z = rq" and
    "l = m + n + 1" and "rq  qr" and "|x| + |y|  4"
proof-
  have "0 < l" "y  ε"
    using l_min non_comm by force+
  from split_pow[OF eq this]
  obtain r q m n where
   x: "x = (r  q) @ m  r" and
   y: "y = (q  r)@ n  q" and
   z: "z = r  q" and
   l: "l = m + n + 1".
  from non_comm[unfolded x y]
  have "r  q  q  r"
    unfolding shifts
    unfolding lassoc add_exps[symmetric] pow_Suc[symmetric] add.commute[of m]
    by force
  hence "r  ε" and "q  ε"
    by blast+
  have "2  |r  q|"
    using nemp_pos_len[OF r  ε] nemp_pos_len[OF q  ε]
    unfolding lenmorph by linarith
  have "|x| + |y|  4"
    unfolding x y lenmorph[symmetric] shifts
    unfolding add_exps[symmetric] lassoc lenmorph[of "r  q"]
    mult_Suc[symmetric] pow_len Suc_eq_plus1 l[symmetric]
    using mult_le_mono[OF 2  l 2  |r  q|]
    by presburger
  from that[OF x y[unfolded shift_pow] z l r  q  q  r this]
  show thesis.
qed




subsection @{term x} is longer›

text‹We set up a locale representing the Lyndon-Schützenberger Equation
     with relaxed exponents and a length assumption breaking the symmetry.›

locale LS_len_le = binary_code x y for x y +
  fixes j k l z
  assumes
    y_le_x: "|y|  |x|"
    and eq: "x@j  y@k = z@l"
    and l_min: "2  l"
    and j_min: "1  j"
    and k_min: "1  k"
begin

lemma jk_small: obtains "j = 1" | "k = 1"
  using Lyndon_Schutzenberger(1)[OF eq _ _ l_min]
    le_neq_implies_less[OF j_min]
    le_neq_implies_less[OF k_min]
    non_comm
  unfolding One_less_Two_le_iff
  by blast

subsubsection ‹case @{term "2  j"}

lemma case_j2k1: assumes "2  j" "k = 1"
  obtains r q t where
    "(r  q) @ t  r = x" and
    "q  r  r  q  =  y" and
    "(r  q) @ t  r  r  q = z" and "2  t"
    "j = 2" and "l = 2" and "rq  qr" and
    "primitive x" and "primitive y"
proof-
  note eq' = eq[unfolded k = 1 pow_1]
  note xjy_imprim_len[OF non_comm eq[unfolded k = 1 pow_1] 2  j l_min]

  obtain j' where "j = Suc (Suc j')"
    using 2  j using at_least2_Suc by metis
  hence "0 < j" by blast
  from lenarg[OF eq', unfolded lenmorph, unfolded pow_len]
    add_less_mono1[OF |x@j| < |z| + |x|, of "|y|", unfolded pow_len]
  have "l*|z| < 3*|z|"
    using |x| < |z| y_le_x by linarith
  hence "l = 2"
    using l_min by simp
  from |x @ j| < |z| + |x| add_less_mono1[OF |z| < |x| + |y|, of "|x|"] y_le_x
  have "j' * |x| < |x|"
    unfolding j = Suc (Suc j') pow_Suc lenmorph pow_len by linarith
  hence "j = 2"
    using  j = Suc (Suc j') by simp

  note eq[ unfolded k = 1 pow_1 j = 2 l = 2 pow_two rassoc]
  from eqd[OF this less_imp_le[OF |x| < |z|]]
  obtain p where "x  p = z" and "p  z = x  y"
    by blast
  from eqd[OF p  z = x  y[folded x  p = z, unfolded lassoc, symmetric]]
  obtain s where "x  s = p  x" and "s  p = y"
    by auto
  have "p  ε"
    using x  p = z |x| < |z| by fastforce
  have "s  ε"
    using p  ε x  s = p  x by force
  from  conjug_eqE[OF x  s = p  x[symmetric] p  ε]
  obtain r q t where "r  q = p" and "q  r = s" and "(r  q)@tr = x" and "q  ε".
  note s  p = y[folded q  r = s r  q = p, unfolded rassoc]
  from y_le_x[folded this (r  q)@tr = x, unfolded lenmorph pow_len] nemp_len[OF q  ε]
    add_le_mono1[OF mult_le_mono1[of t 1 "|r| + |q|", unfolded mult_1], of "|r|"]
  have "2  t"
    by linarith
        from p  z = x  y[folded q  r  r  q = y (r  q)@tr = x  r  q = p, symmetric]
  have z: "(r  q) @ t  r  r  q = z"
    by comparison

― ‹y is primitive due to the Lyndon-Schutzenberger›

  from comm_drop_exp[OF 0 < j, of y x j, unfolded eq']
  have "primitive y"
    using Lyndon_Schutzenberger_prim[OF pow_nemp_imprim[OF 2 j], of y x, unfolded eq', OF _ pow_nemp_imprim[OF l_min]] non_comm by argo

  hence "q  r  r  q"
    using p  ε q  r = s r  q = p s  p = y comm_not_prim[OF s  ε p  ε] by argo

― ‹primitivity of x using @{thm per_le_prim_iff}

  thm per_le_prim_iff[of x p]
  have "x ≤p p  x"
    unfolding (r  q)@tr = x[symmetric] r  q = p[symmetric]
    by comparison
  have "2*|p|  |x|"
    unfolding (r  q)@tr = x[symmetric] r  q = p[symmetric] lenmorph pow_len
    using mult_le_mono1[OF 2  t, of "(|r| + |q|)"] by linarith
  have [symmetric]: "p  x  x  p"
    unfolding (r  q)@tr = x[symmetric] r  q = p[symmetric] lassoc pow_comm[symmetric]
    unfolding rassoc cancel by fact
  with per_le_prim_iff[OF x ≤p p  x p  ε 2 * |p|  |x|]
  have "primitive x"
    by blast

  from that[OF (r  q)@tr = x q  r  r  q = y z 2  t
      j = 2 l = 2 qr  rq[symmetric] primitive x primitive y]
  show thesis.
qed

subsubsection ‹case @{term "j = 1"}

lemma case_j1k2_primitive: assumes "j = 1" "2  k"
  shows "primitive x"
  using Lyndon_Schutzenberger_prim[OF _ pow_nemp_imprim
      pow_nemp_imprim[OF l_min, of z, folded eq], OF _ 2  k]
    comm_pow_roots[of j k x y] k_min non_comm
  unfolding j = 1 pow_1
  by linarith

lemma case_j1k2_a: assumes "j = 1" "2  k" "z ≤s y@k"
  obtains r q t where
    "x = ((q  r)  (r  (q  r) @ t) @ (k - 1)) @ (l - 2) 
      (((q  r)  (r  (q  r) @ t) @ (k - 2))  r)  q" and
    "y = r  (q  r) @ t" and
    "z = (q  r)  (r  (q  r) @ t) @ (k - 1)" and 0 < t and "rq  qr"
proof-
  have "z  ε"
    using assms(1) bin_fst_nemp eq by force
  have "0 < k" "0 < k -1"
    using 2  k by linarith+
  have "0 < l" "0 < l - 1"
    using l_min by linarith+

  from LS_per_lemma_case[reversed, OF eq 0 < k, unfolded j = 1]
  have perlem: "|y@k| < |z| + |y|"
    using non_comm
    by linarith

  obtain v where "y@k = vz"
    using z ≤s y@k suffix_def by blast
  have "|v| < |y|"
    using perlem[unfolded lenarg[OF y@k = vz] lenmorph]
    by simp
  have "v <p y"
    using prefI[OF y@k = vz[symmetric]]
    unfolding pow_pos[OF 0 < k]
    using pref_prod_less[OF _ |v| < |y|]
    by blast
  obtain u where "vu = y" "u  ε"
    using v <p y spref_exE by blast

  have "z = uy@(k-1)"
    using y@k = vz[unfolded pow_pos[OF 0 < k],
        folded v  u = y, unfolded rassoc cancel,
        unfolded v  u = y, symmetric].

  note eq[unfolded pow_pos'[OF 0 < l] y@k = vz lassoc cancel_right
      j = 1 pow_1]

  obtain u' where "u'v = y"
  proof-
    have "v ≤s z@(l-1)"
      using x  v = z @ (l - 1) by blast
    moreover have "y ≤s z@(l-1)"
      unfolding z = uy@(k-1) pow_pos'[OF 0 < k - 1]
        pow_pos'[OF 0 < l - 1] lassoc
      by blast
    ultimately have "v ≤s y"
      using order_less_imp_le[OF |v| < |y|] suffix_length_suffix by blast
    thus thesis
      using sufD that by blast
  qed
  hence "u'  ε"
    using v <p y by force

  from conjugation[OF u'v = y[folded vu = y] u'  ε]
  obtain r q t where "r  q = u'" "q  r = u" "(r  q) @ t  r = v"
    by blast

  have y: "y = r  (q  r) @ Suc t"
    using u'  v = y[symmetric, folded (r  q) @ t  r = v r  q = u']
    unfolding rassoc pow_slide[symmetric].
  have z: "z = (q  r)  (r  (q  r) @ Suc t) @ (k - 1)"
    using q  r = u z = u  y @ (k - 1) y by blast

  let ?x = "((q  r)  (r  (q  r) @ Suc t) @ (k - 1)) @ (l - 2) 
      (((q  r)  (r  (q  r) @ Suc t) @ (k - 2))  r)  q"
  have "?x  v = z @ (l - 1)"
    unfolding z (r  q) @ t  r = v[symmetric] pow_pos'[OF 0 < k - 1]
    pow_pos'[OF 0 < l - 1] diff_diff_left nat_1_add_1
    by (simp only: shifts)
  from x  v = z @ (l - 1)[folded this]
  have x: "x = ?x"
    by blast

  have "zy  yz"
    using non_comm
    using comm_add_exp[of z y l, folded eq,
        unfolded rassoc pow_comm, unfolded lassoc cancel_right
        j = 1 pow_1]
    by blast
  hence "rq  qr"
    unfolding q  r = u r  q = u' u' v  = y[symmetric]
      z = u  y @ (k - 1) pow_pos'[OF 0 < k] rassoc
      y @ k = v  z[unfolded u'  v = y[symmetric]
        z = u  y @ (k - 1), symmetric] cancel_right..
  show thesis
    using that[OF x y z _ rq  qr] by blast
qed

lemma case_j1k2_b: assumes "j = 1" "2  k" "y@k <s z"
  obtains q where
    "x = (qy@k)@(l-1)q" and
    "z = qy@k" and
    "qy  yq"
proof-
  obtain q where "z = qy@k" "q  ε"
    using ssufD[OF y@k <s z]
    unfolding suffix_def
    by blast
  have "0 < l" using l_min by linarith
  have "x = (qy@k)@(l-1)q"
    using eq[unfolded pow_pos'[OF 0 < l] j = 1 pow_1,
        unfolded z = qy@k lassoc cancel_right].
  have "qy  yq"
    using
      comm_trans[OF _ _ q  ε, of y x] conjug_pow[of y q y k, symmetric]
      conjug_pow[of "q  y @ k" q  "q  y @ k" "l-1"] non_comm
    unfolding append_same_eq[symmetric, of (q  y @ k) @ (l - 1)  q q  (q  y @ k) @ (l - 1) q]
    unfolding x = (q  y @ k) @ (l - 1)  q rassoc
    by argo
  show ?thesis
    using x = (q  y @ k) @ (l - 1)  q z = q  y @ k qy  yq that by blast
qed

subsection ‹Putting things together›

lemma solution_cases: obtains
  "j = 2" "k = 1" |
  "j = 1" "2  k" "z <s y@k" |
  "j = 1" "2  k" "y@k <s z" |
  "j = 1" "k = 1"
proof-
  have "0 < l" "0 < l-1"
    using l_min by linarith+
  have "0 < k"
    using k_min by linarith
  have "0 < j"
    using j_min by linarith
  have "z  ε"
    using eq nemp_pow_nemp[of z l] bin_fst_nemp[folded nonzero_pow_emp[OF 0 < j, of x], THEN pref_nemp]
    by force
  have "z  y@k"
  proof
    assume "z = y@k"
    with eq[unfolded pow_pos'[OF 0 < l], folded this, unfolded cancel_right]
    have "x@j  y@k = y@k  x@j"
      using pow_comm by auto
    from comm_drop_exps[OF this 0 < j 0 < k]
    show False
      using non_comm by blast
  qed
  consider
    "2  j" "k = 1" |
    "j = 1" "2  k" |
    "j = 1" "k = 1"
    using jk_small j_min k_min le_neq_implies_less
    unfolding One_less_Two_le_iff[symmetric]
    by metis
  moreover consider "z <s y@k" | "y@k <s z"
    using suffix_order.less_le
      triv_suf[of "y@k" "x@j", unfolded eq, THEN suf_prod_root,
        THEN ruler_suf'] z  y@k
    by blast
  moreover consider "j = 1" | "j = 2"
    using case_j2k1[of thesis] calculation(1) by blast
  ultimately show ?thesis
    using that
    by metis
qed

theorem parametric_solutionE: obtains
  ―‹case @{term "xy"}
  r q m n where
  "x = (rq)@mr" and
  "y = q(rq)@n" and
  "z = rq" and
  "l = m + n + 1" and "rq  qr"
|
  ―‹case @{term "xy@k"} with @{term "2  k"} and @{term "z <s y@k"}
  r q t where
  "x = ((q  r)  (r  (q  r) @ t) @ (k - 1)) @ (l - 2) 
      (((q  r)  (r  (q  r) @ t) @ (k - 2))  r)  q" and
  "y = r  (q  r) @ t" and
  "z = (q  r)  (r  (q  r) @ t) @ (k - 1)" and
  "0 < t" and "rq  qr"
|
  ―‹case @{term "xy@k"} with @{term "2  k"} and @{term "y@k <s z"}
  q where
  "x = (qy@k)@(l-1)q" and
  "z = qy@k" and
  "qy  yq"
|
  ―‹case @{term "x@jy"} with @{term "2  j"}
  r q t where
  "x = (r  q) @ t  r" and
  "y  =  q  r  r  q" and
  "z = (r  q) @ t  r  r  q" and
  "j = 2" and "l = 2" and "2  t" and "rq  qr" and
  "primitive x" and "primitive y"
proof-
  show ?thesis
    using solution_cases
  proof(cases)
    case 1
    from case_j2k1[OF _ k = 1, of thesis] j = 2
    show ?thesis
      using that(4) by blast
  next
    case 2
    from case_j1k2_a[OF this(1-2) ssufD1[OF this(3)], of thesis]
    show thesis
      using that(2)
      by blast
  next
    case 3
    from case_j1k2_b[OF this, of thesis]
    show ?thesis
      using that(3) by blast
  next
    case 4
    from case_j1k1[OF eq[unfolded k = 1 j = 1 pow_1] non_comm l_min, of thesis]
    show thesis
      using that(1).
  qed
qed

end
text ‹Using the solution from locale @{term LS_len_le},
the following theorem gives the full characterization of the equation in question:
$$ x^iy^j = z^\ell $$
›

theorem LS_parametric_solution:
  assumes y_le_x: "|y|  |x|"
    and j_min: "1  j"  and k_min: "1  k" and l_min: "2  l"
  shows
    "x@j  y@k = z@l
  
    (r m n t.
        x = r@m  y = r@n  z = r@t  m*j+n*k=t*l) ―‹Case A: {x,y} is not a code›
   (j = 1  k = 1) 
    (r q m n.
        x = (rq)@mr  y = q(rq)@n  z = rq  m + n + 1 = l  rq  qr) ― ‹Case B›
   (j = 1  2  k) 
    (r q.
        x = (qr@k)@(l-1)q  y = r  z = qr@k  rq  qr) ― ‹Case C›
   (j = 1  2  k) 
    (r q t. 0 < t 
        x = ((q  r)  (r  (q  r) @ t) @ (k - 1)) @ (l - 2)(((q  r) 
               (r  (q  r) @ t) @ (k - 2))  r)  q
         y = r  (q  r) @ t
         z = (q  r)  (r  (q  r) @ t) @ (k - 1)
         rq  qr) ― ‹Case D›
   (j = 2  k = 1  l = 2) 
    (r q t. 2  t 
        x = (r  q) @ t  r  y = q  r  r  q
         z = (r  q) @ t  r  r  q   rq  qr ) ― ‹Case E›
  "
    (is "?eq =
   (?sol_per  (?cond_j1k1  ?sol_j1k1) 
   (?cond_j1k2  ?sol_j1k2_b) 
   (?cond_j1k2  ?sol_j1k2_a) 
   (?cond_j2k1l2  ?sol_j2k1l2))")
proof(rule iffI)
  assume eq: "x @ j  y @ k = z @ l"
  show
    "(?sol_per  (?cond_j1k1  ?sol_j1k1) 
   (?cond_j1k2  ?sol_j1k2_b) 
   (?cond_j1k2  ?sol_j1k2_a) 
   (?cond_j2k1l2  ?sol_j2k1l2))"
  proof(cases)
    assume "xy = yx"
    from comm_primrootE[OF this]
    obtain r m n where "x = r @ m" "y = r @ n" "primitive r"
      using rootE by metis

    note eqs = eq[unfolded this, folded pow_mult add_exps, symmetric]
    obtain t where "z = r @ t"
      using l_min pow_comm_comm[OF eqs,
          THEN prim_comm_exp[OF primitive r]]
      by auto
    from eqs[unfolded this, folded pow_mult, symmetric]
    have "m * j + n * k = t * l"
      unfolding prim_nemp[OF primitive r, THEN eq_pow_exp].
    hence ?sol_per
      using x = r @ m y = r @ n z = r @ t by blast
    thus ?thesis
      by blast
  next
    assume "xy  yx"
    interpret LS_len_le x y j k l z
      using x @ j  y @ k = z @ l xy  yx j_min k_min l_min y_le_x
      by(unfold_locales)

    show ?thesis
      using solution_cases
    proof(cases)
      case 1
      from case_j2k1[OF less_or_eq_imp_le[of 2 j] k = 1, OF disjI2, OF j = 2[symmetric], of "?sol_j2k1l2  l = 2"]
      have "?sol_j2k1l2" and "l = 2"
        by auto
      thus ?thesis
        using k = 1 j = 2 by blast
    next
      case 2
      have "?sol_j1k2_a"
        using case_j1k2_a[OF j = 1 2  k ssufD1[OF z <s y @ k], of ?sol_j1k2_a]
        unfolding Suc_eq_plus1
        by blast
      thus ?thesis
        using j = 1 2  k by blast
    next
      case 3
      with case_j1k2_b[OF this, of "?sol_j1k2_b"]
      have "?sol_j1k2_b" by auto
      thus ?thesis
        using j = 1 2  k by blast
    next
      case 4
      with case_j1k1[OF eq[unfolded k = 1 j = 1 pow_1] non_comm l_min, of ?sol_j1k1]
      have"?sol_j1k1"
        unfolding Suc_eq_plus1 shift_pow
        by blast
      thus ?thesis
        using j = 1 k = 1 by blast
    qed
  qed
next
  have "l  0" "l - 1  0"
    using l_min by auto
  have "k  0" using k_min by auto
  have "j  0" using j_min by auto
  assume   "(?sol_per  (?cond_j1k1  ?sol_j1k1) 
   (?cond_j1k2  ?sol_j1k2_b) 
   (?cond_j1k2  ?sol_j1k2_a) 
   (?cond_j2k1l2  ?sol_j2k1l2))"
  then show ?eq
  proof(elim disjE conjE exE)
    fix r m n t
    assume sol: "x = r @ m" "y = r @ n" "z = r @ t"
      and "m * j + n * k = t * l"
    show ?thesis
      unfolding sol
      unfolding pow_mult[symmetric] add_exps[symmetric]
      unfolding m * j + n * k = t * l..
  next
    fix r q m n
    assume "j = 1" "k = 1" and sol: "x = (rq)@mr"
      "y = q(rq)@n" "z = rq"
      and "m + n + 1 = l"
    hence "Suc (m+n) = l"
      by simp
    show ?thesis
      unfolding sol
      unfolding j = 1 k = 1 Suc (m + n) = l[symmetric] pow_1
      unfolding lassoc pow_Suc add_exps
      unfolding pow_comm[of _ m, symmetric] lassoc..
  next
    fix r q
    assume "j = 1" "2  k" and sol: "x = (q  r @ k) @ (l - 1)  q" "y = r" "z = q  r @ k"
    have "0 < l"
      using 2  l by force
    show ?thesis
      unfolding sol j = 1 pow_1
      unfolding pow_pos'[OF 0 < l] rassoc..
  next
    fix r q t
    assume "j = 1" "2  k" and sol:
      "x =
        ((q  r)  (r  (q  r) @ t) @ (k - 1)) @ (l - 2) 
        (((q  r)  (r  (q  r) @ t) @ (k - 2))  r)  q"
      "y = r  (q  r) @ t"
      "z = (q  r)  (r  (q  r) @ t) @ (k - 1)"
      "0 < t"
    obtain k' where  "Suc (Suc k') = k" using  Suc_minus2[OF 2  k] by blast
    hence k1: "k - 1 = Suc k'" and k2: "k - 2 = k'" and k: "k = k'+ 2" by fastforce+
    obtain l' where "Suc (Suc l') = l" using  Suc_minus2[OF 2  l] by blast
    hence l2: "l - 2 = l'" and l: "l  = l' + 2"  by fastforce+
    show "x @ j  y @ k = z @ l"
      unfolding sol j = 1 k1 k2 l2 unfolding k l by comparison
  next
    fix r q t
    assume "j = 2" "k = 1" "l = 2" and  sol:
      "x = (r  q) @ t  r"
      "y = q  r  r  q" "z = (r  q) @ t  r  r  q"
      "2  t"
    show "x @ j  y @ k = z @ l"
      unfolding j = 2 k = 1 l = 2 sol pow_1 pow_two
      by comparison
  qed
qed

subsection ‹Uniqueness of the imprimitivity witness›

text‹In this section, we show that given a binary code @{term "{x,y}"} and
two imprimitive words @{term "x@jy@k"} and @{term "x@j'y@k'"} is possible
only if the two words are equals, that is, if @{term "j=j'"} and @{term "k=k'"}.›

lemma LS_unique_same: assumes "x  y  y  x"
  and "1  j" and "1  k" and "¬ primitive(x@jy@k)"
  and "1  k'" and "¬ primitive(x@jy@k')"
shows "k = k'"
proof(rule ccontr)
  assume "k  k'"

  define ka where "ka = (if k < k' then k else k')"
  define ka' where "ka' = (if k < k' then k' else k)"

  have "ka < ka'" and "ka  ka'"
    unfolding ka_def ka'_def using k  k' by auto
  then obtain dif where [symmetric]: "ka + dif = ka'" and "dif  0"
    using less_imp_add_positive by blast
  have "ka  0" and "ka'  0" and j  0
    unfolding ka_def ka'_def using 1  k 1  k' 1  j by force+

  have "¬ primitive(x@jy@ka)" "¬ primitive(x@jy@ka')"
    unfolding ka_def ka'_def using assms(4) assms(6) by presburger+

  have "x@jy@ka' = x@jy@kay@dif"
    unfolding add_exps[symmetric] ka' = ka + dif..

  consider "dif = 1" | "2  dif"
    using ka < ka' ka' = ka + dif by fastforce
  hence "x  y = y  x"
  proof(cases)
    assume "dif = 1"
    define u where "u = x@jy@(ka - 1)"
    have "¬ primitive (u  y)"
      unfolding u_def rassoc pow_Suc'[symmetric]  Suc_minus[OF ka  0] by fact
    have "¬ primitive (u  y  y)"
      unfolding u_def rassoc using ¬ primitive(x@jy@ka')[unfolded x@jy@ka' = x@jy@kay@dif dif = 1 pow_1]
      unfolding pow_Suc'[of y "ka - 1", unfolded Suc_minus[OF ka  0]] rassoc.
    from imprim_ext_suf_comm[OF ¬ primitive (u  y) ¬ primitive (u  y  y)]
    have "(x @ j  y @ (ka - 1))  y = y  x @ j  y @ (ka - 1)"
      unfolding u_def.
    thus "x  y = y  x"
      using j  0 by mismatch
  next
    assume "2  dif"
    hence "¬ primitive (y@dif)"..
    from Lyndon_Schutzenberger_prim[OF ¬ primitive (x @ j  y @ ka) this  ¬ primitive (x @ j  y @ ka')[unfolded x @ j  y @ ka' = x @ j  y @ ka y@dif lassoc]]
    show "x  y = y  x"
      using dif  0 j  0 by mismatch
  qed
  thus False
    using x  y  y  x by blast
qed

lemma LS_unique_distinct_le: assumes "x  y  y  x"
  and "2  j" and "¬ primitive(x@jy)"
  and "2  k" and "¬ primitive(xy@k)"
  and "|y|  |x|"
shows False
proof-
  have "0 < k"
    using 2  k by linarith
  obtain l z where [symmetric]:"z@l = x@jy" and "2  l"
    using  not_prim_primroot_expE[OF ¬ primitive(x@jy)].
  have "x@jy@1 = z@l"
    by (simp add: x @ j  y = z @ l)
  interpret eq1: LS_len_le x y j 1 l z
    using x  y  y  x |y|  |x| x@jy@1 = z@l 2  l 2  j
    by(unfold_locales) linarith+

  from eq1.case_j2k1[OF 2  j refl]
  obtain r q t where
    x[symmetric]: "(r  q) @ t  r = x" and
    y[symmetric]: "q  r  r  q  =  y" and
    z[symmetric]: "(r  q) @ t  r  r  q = z" and
    "2  t" and "j = 2" and "l = 2" and "rq  qr" and
    "primitive x" and "primitive y".

  have "qr  ε" "rq  ε"
    using eq1.bin_snd_nemp y by fastforce+

  obtain z' l' where "xy@k = z'@l'" "2  l'"
    using not_prim_primroot_expE[OF ¬ primitive (x  y @ k)] by metis
  from xy@k = z'@l'[unfolded x y, unfolded rassoc, symmetric]
  have z': "z' @ l' = (r  q) @ t  r  (q  r  r  q) @ k".
  have "0 < l'" and "0 < l' - 1"
    using 2  l' by auto
  have "r  q  r  q ≤p x"
   using pref_extD[of "rqrq" "(r  q) @ (t - 2)  r"]
    unfolding  x[folded pop_pow[OF 2  t], unfolded pow_two] rassoc by blast

  have per1: "x  q  r ≤p (r  q)  x  q  r"
    unfolding x by comparison
  have per2: "x  q  r ≤p z'  x  q  r"
    by (rule pref_prod_root[of _ _ l'],
    unfold xy@k = z'@l'[unfolded  y  pow_pos[OF 0 < k], symmetric])
    comparison
  have "(r  q)  z'  z'  (r  q)"
  proof
    assume "(r  q)  z' = z'  (r  q)"
    hence "(r  q)  z'@l' = z'@l'  r  q"
      by (simp add: comm_add_exp)
    from this[unfolded z']
    have "r  q = q  r"
      using 0 < k by mismatch
    thus False
      using r  q  q  r by presburger
  qed
  with two_pers[OF per1 per2]
  have "|x|  |z'|"
    unfolding lenmorph by linarith

  from eqdE[OF xy@k = z'@l'[unfolded pow_pos[OF 0 < l']
       pow_pos'[OF 0 < l'-1]] |x|  |z'| ]
  obtain w where "x  w = z'" "w  z' @ (l' - 1 - 1)  z' = y @ k".
  from this(1) this(2)[unfolded lassoc]
  have  "x ≤f y@k"
    by blast
  hence "rqrq ≤f (qrrq)@k"
    unfolding y
    using pref_fac[OF r  q  r  q ≤p x] by blast

  have "|r  q  r  q| = |q  r  r  q|"
    by simp
  from xyxy_conj_yxxy[OF fac_pow_len_conjug[OF this rqrq ≤f (qrrq)@k, symmetric]]
  have "r  q = q  r".
  thus False
    using r  q  q  r by blast
qed

lemma LS_unique_distinct: assumes "x  y  y  x"
  and "2  j" and "¬ primitive(x@jy)"
  and "2  k" and "¬ primitive(xy@k)"
shows False
  using LS_unique_distinct_le[OF assms] LS_unique_distinct_le[reversed, OF assms(1,4-5,2-3)] by fastforce

lemma LS_unique': assumes "x  y  y  x"
  and "1  j" and "1  k"  and "¬ primitive(x@jy@k)"
  and "1  j'" and "1  k'"  and "¬ primitive(x@j'y@k')"
shows "k = k'"
proof-
  have "j = 1  k = 1"
    using Lyndon_Schutzenberger_prim[OF pow_non_prim pow_non_prim,
        OF _ _  ¬ primitive (x @ j  y @ k), THEN comm_drop_exps]
       1  j 1  k x  y  y  x by linarith
  have "j' = 1  k' = 1"
    using Lyndon_Schutzenberger_prim[OF pow_non_prim pow_non_prim,
        OF _ _  ¬ primitive (x @ j'  y @ k'), THEN comm_drop_exps]
       1  j' 1  k' x  y  y  x by linarith
  show "k = k'"
  proof (cases "j = j'")
    assume "j = j'"
    from LS_unique_same[OF assms(1-4,6,7)[folded this]]
    show "k = k'".
  next
    assume "j  j'"
    show "k = k'"
    proof(rule ccontr, cases "j = 1")
      assume "k  k'" and  "j = 1"
      hence "2  j'" and "k' = 1" and "2  k"
        using j  j' 1  j' k  k' 1  k  j' = 1  k' = 1 by auto
      from LS_unique_distinct[OF x  y  y  x  2  j' _ 2  k]
      show False
        using ¬ primitive(x@j'y@k')[unfolded k'=1 pow_1] ¬ primitive(x@jy@k)[unfolded j=1 pow_1]
        by blast
    next
      assume "k  k'" and  "j  1"
      hence "2  j" and "k = 1" and "2  k'" and "j' = 1"
        using 1  j j = 1  k = 1 1  k' j' = 1  k' = 1 by auto
      from LS_unique_distinct[OF x  y  y  x 2  j _ 2  k']
      show False
        using ¬ primitive(x@j'y@k')[unfolded j'=1 pow_1] ¬ primitive(x@jy@k)[unfolded k=1 pow_1]
        by blast
    qed
  qed
qed

lemma LS_unique: assumes "x  y  y  x"
  and "1  j" and "1  k"  and "¬ primitive(x@jy@k)"
  and "1  j'" and "1  k'"  and "¬ primitive(x@j'y@k')"
shows "j = j'" and "k = k'"
  using  LS_unique'[OF x  y  y  x
      1  j 1  k  ¬ primitive (x @ j  y @ k)
      1  j' 1  k' ¬ primitive (x @ j' y @ k')]
    LS_unique'[reversed, OF x  y  y  x
      1  k 1  j   ¬ primitive (x @ j  y @ k)
      1  k' 1  j' ¬ primitive (x @ j' y @ k')]
  by blast+

section "The bound on the exponent in Lyndon-Schützenberger equation"

lemma (in LS_len_le) case_j1k2_exp_le:
  assumes "j = 1" "2  k"
  shows "k*|y|+ 4  |x|+2*|y|"
proof-
  have "x  y @ k = z @ l" and "|y|  0" and "0 < l"
    using eq[unfolded j = 1 cow_simps] nemp_len[OF bin_snd_nemp] l_min
    by linarith+

  consider "y @ k <s z" | "z ≤s y@k"
    using ruler_eq'[reversed,
    OF x  y@k = z@l[symmetric, unfolded pow_pos'[OF 0 < l]]] by blast
  thus ?thesis
  proof(cases)
    assume "y@k <s z"
    from case_j1k2_b[OF assms this]
    obtain q where
      x: "x = (q  y @ k) @ (l - 1)  q" and
      "z = q  y @ k" and
      "q  y  y  q".
    have "1  |q|"
      using nemp_le_len[of q] q  y  y  q by blast

    have "|y|  1"
      using bin_snd_nemp nemp_le_len by blast

    have lle: "x  (l-1)*x" for x
      using l_min
      by (simp add: quotient_smaller)

    have "|x|  k*|y| + 2"
      unfolding x lenmorph pow_len
      using le_trans[OF _ lle, of "k * |y| + 1" "|q| + k * |y|", THEN add_le_mono[OF 1  |q|]]
      unfolding add.commute[of "|q|"]
      using 1  |q| by auto
    thus ?thesis
      using |y|  1 by linarith
  next
    assume "z ≤s y @ k "
    from  case_j1k2_a[OF assms this]
    obtain q r t where
      x: "x = ((q  r)  (r  (q  r) @ t) @ (k - 1)) @ (l - 2)  (((q  r)  (r  (q  r) @ t) @ (k - 2))  r)  q" and
      "y = r  (q  r) @ t" and
      "z = (q  r)  (r  (q  r) @ t) @ (k - 1)" and
      "0 < t" and "r  q  q  r".

    have "q  ε" "r  ε"
      using r  q  q  r by blast+
    hence "|q|  1" "|r|  1"
      using nemp_le_len by blast+
    hence "|qr| + |r| + |q|  4"
      by simp

    have "|x|  |(((q  r)  (r  (q  r) @ t) @ (k - 2))  r)  q|"
      using x suf_len' by blast
    hence "|x|  |qr| + (k-2)*|y| + |r| + |q|"
      unfolding y = r  (q  r) @ t[symmetric]
      by (simp add: pow_len)
    hence "|x|  (k-2)*|y| + 4"
      using 4  |q  r| + |r| + |q| by linarith
    thus ?thesis
      unfolding add.commute[of "|x|"]
      unfolding nat_le_add_iff1[OF 2  k].
  qed
qed

lemma (in LS_len_le) case_j2k1_exp_le:
  assumes "2  j" "k = 1"
  shows "j*|x| + 4  |y| + 2*|x|"
proof-
  from case_j2k1[OF assms]
  obtain r q t where
    "(r  q) @ t  r = x" and
    "q  r  r  q = y" and
    "(r  q) @ t  r  r  q = z" and
    2  t and "j = 2" and "l = 2" and
    "r  q  q  r" and
    "primitive x" and
    "primitive y".

  have "|r|  1" "|q|  1"
    using r  q  q  r nemp_le_len by blast+
  hence "|y|  4"
    unfolding q  r  r  q = y[symmetric] lenmorph
    by linarith
  thus ?thesis
    by (simp add: j = 2)
qed

theorem LS_exp_le_one:
  assumes eq: "x  y @ k = z @ l"
      and "2  l"
      and "x  y  y  x"
      and "1  k"
      shows "k*|y| + 4  |x|+2*|y|"
proof-
  have "x  ε" "y  ε" "x  y" "|y|  0" "z  ε"
    using x  y  y  x x  y @ k = z @ l by fastforce+
  have "l  0"  1  l-1
    using 2  l by force+

  consider "k = 1" | "k  2"
    using 1  k by linarith
  then show ?thesis
  proof(cases)
    assume "k=1"
    have "4  |x| + |y|"
      using case_j1k1[OF eq[unfolded k = 1 pow_1] x  y  y  x 2  l]
      by blast
    thus ?thesis
      unfolding k = 1 by force
  next
    assume "k  2"
  show ?thesis
  proof(rule le_cases)
    assume "|y|  |x|"
    then interpret LS_len_le x y 1 k l z
      using assms by (unfold_locales, auto)
    from case_j1k2_exp_le[OF refl k  2]
    show ?thesis.
  next
    assume "|x|  |y|"
    have "y  x  x  y"
      using assms(3) by force
    define z' where "z' = rotate |x| z"
    hence "y@k  x = z' @ l"
      using arg_cong[OF assms(1), of "λt. rotate |x| t"]
      unfolding rotate_append rotate_pow_comm
      by blast
    interpret LS_len_le y x k 1 l z'
      using |x|  |y| y  x  x  y y@k  x = z' @ l 2  l 1  k
      by (unfold_locales, auto)
    from case_j2k1_exp_le[OF 2  k refl]
    show ?thesis.
     qed
  qed
qed

lemma LS_exp_le_conv_rat:
  fixes x y k::"'a::linordered_field"
  assumes "y > 0"
  shows "k * y + 4  x + 2 * y  k  (x - 4)/y+ 2"
  unfolding le_diff_eq[symmetric]
  unfolding diff_conv_add_uminus
  unfolding add.assoc add.commute[of "2*y"]
  unfolding add.assoc[symmetric]
  unfolding diff_le_eq[of _ "2*y" "x + - 4",symmetric] left_diff_distrib'[symmetric]
  unfolding pos_le_divide_eq[OF y > 0, symmetric]
  unfolding diff_le_eq..


end