Theory AlphabetEnlargement_Uniqueness

theory AlphabetEnlargement_Uniqueness
  imports AlphabetEnlargement_Simulation
begin

subsection ‹Block-predicate identities (VFwd exclusion support)›

text ‹Identities relating ‹is_pure_block›,
  ‹is_padded_block›, ‹LE_block›, and ‹bl_block›.
  Used by the VFwd 6-fold pairwise exclusion lemmas below
  (and downstream by the reverse-arm trace decoder).  Located here
  because the proofs need ‹c_idx_enum_nth› to construct
  index witnesses inside the existential in
  ‹is_padded_block›.›

lemma is_pure_not_padded:
  fixes f :: "'c :: enum ⇒ 'a"
  shows "is_pure_block bl f ⟹ ¬ is_padded_block bl f"
  unfolding is_pure_block_def is_padded_block_def
proof clarify
  fix k :: nat
  assume pure: "∀x :: 'c. f x ≠ bl"
     and k_lb: "1 ≤ k"
     and k_ub: "k < length (enum_class.enum :: 'c list)"
     and suffix: "∀x :: 'c. k ≤ c_idx x ⟶ f x = bl"
  let ?x = "(enum_class.enum :: 'c list) ! k"
  have "c_idx ?x = k" using c_idx_enum_nth[OF k_ub] .
  hence "k ≤ c_idx ?x" by simp
  hence "f ?x = bl" using suffix by blast
  thus False using pure by blast
qed

lemma not_is_pure_bl_block:
  "¬ is_pure_block (bl :: 'a) (bl_block bl :: 'c :: enum ⇒ 'a)"
  unfolding is_pure_block_def bl_block_def by simp

lemma not_is_padded_bl_block:
  "¬ is_padded_block (bl :: 'a) (bl_block bl :: 'c :: enum ⇒ 'a)"
  unfolding is_padded_block_def bl_block_def
proof clarify
  fix k :: nat
  assume k_lb: "1 ≤ k"
     and k_ub: "k < length (enum_class.enum :: 'c list)"
     and prefix: "∀x :: 'c. c_idx x < k ⟶ (λ_. bl) x ≠ bl"
  have len_pos: "0 < length (enum_class.enum :: 'c list)" using k_lb k_ub by linarith
  let ?x = "(enum_class.enum :: 'c list) ! 0"
  have "c_idx ?x = 0" using c_idx_enum_nth[OF len_pos] .
  hence "c_idx ?x < k" using k_lb by linarith
  hence "(λ_ :: 'c. bl) ?x ≠ bl" using prefix by blast
  thus False by simp
qed

lemma is_pure_LE_block:
  "(le :: 'a) ≠ bl ⟹
     is_pure_block bl (LE_block le :: 'c :: enum ⇒ 'a)"
  unfolding is_pure_block_def LE_block_def by simp

lemma not_is_padded_LE_block:
  "(le :: 'a) ≠ bl ⟹
     ¬ is_padded_block bl (LE_block le :: 'c :: enum ⇒ 'a)"
  using is_pure_LE_block is_pure_not_padded by metis

lemma LE_block_eq_bl_block_imp_eq:
  fixes le bl :: 'a
  assumes "(LE_block le :: 'c :: enum ⇒ 'a) = bl_block bl"
  shows "le = bl"
proof -
  have len_pos: "0 < length (enum_class.enum :: 'c list)"
    using c_idx_in_range(1)[of "c_first :: 'c"] by linarith
  let ?x = "(enum_class.enum :: 'c list) ! 0"
  from assms have "(LE_block le :: 'c ⇒ 'a) ?x = bl_block bl ?x" by simp
  thus ?thesis unfolding LE_block_def bl_block_def by simp
qed

subsection ‹VFwd 6-fold within-phase exclusion›

text ‹The four VFwd-source relations (advance, ‹to_padded›,
  ‹to_ret›, reject) are pairwise disjoint under
  ‹le_neq_bl›.›

lemma ae_delta_val_fwd_advance_to_padded_disjoint:
  fixes M :: "('q, 'a) mttm"
    and a :: "nat ⇒ 'c :: enum ⇒ 'a"
  assumes "le_tm M ≠ bl_tm M"
      and "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_advance M"
      and "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_padded M"
  shows "False"
proof -
  have alt: "a 0 = LE_block (le_tm M)
              ∨ is_pure_block (bl_tm M) (a 0)"
    using assms(2) unfolding ae_delta_val_fwd_advance_def by auto
  have padded: "is_padded_block (bl_tm M) (a 0)"
    using assms(3) unfolding ae_delta_val_fwd_to_padded_def by auto
  from alt show False
  proof
    assume "a 0 = LE_block (le_tm M)"
    thus False using padded assms(1) not_is_padded_LE_block by metis
  next
    assume "is_pure_block (bl_tm M) (a 0)"
    thus False using padded is_pure_not_padded by metis
  qed
qed

lemma ae_delta_val_fwd_advance_to_ret_disjoint:
  fixes M :: "('q, 'a) mttm"
    and a :: "nat ⇒ 'c :: enum ⇒ 'a"
  assumes "le_tm M ≠ bl_tm M"
      and "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_advance M"
      and "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
  shows "False"
proof -
  have alt: "a 0 = LE_block (le_tm M)
              ∨ is_pure_block (bl_tm M) (a 0)"
    using assms(2) unfolding ae_delta_val_fwd_advance_def by auto
  have to_ret: "a 0 = bl_block (bl_tm M)"
    using assms(3) unfolding ae_delta_val_fwd_to_ret_def by auto
  from alt show False
  proof
    assume "a 0 = LE_block (le_tm M)"
    with to_ret have eq: "(LE_block (le_tm M) :: 'c ⇒ 'a) = bl_block (bl_tm M)" by simp
    hence "le_tm M = bl_tm M" by (rule LE_block_eq_bl_block_imp_eq)
    thus False using assms(1) by simp
  next
    assume "is_pure_block (bl_tm M) (a 0)"
    with to_ret have "is_pure_block (bl_tm M) (bl_block (bl_tm M) :: 'c ⇒ 'a)" by simp
    thus False using not_is_pure_bl_block[where 'c='c and bl="bl_tm M"] by simp
  qed
qed

lemma ae_delta_val_fwd_advance_reject_disjoint:
  assumes "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_advance M"
      and "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
  shows "False"
  using assms
  unfolding ae_delta_val_fwd_advance_def ae_delta_val_fwd_reject_def
            is_canonical_block_def
  by auto

lemma ae_delta_val_fwd_to_padded_to_ret_disjoint:
  fixes M :: "('q, 'a) mttm"
    and a :: "nat ⇒ 'c :: enum ⇒ 'a"
  assumes "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_padded M"
      and "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
  shows "False"
proof -
  have padded: "is_padded_block (bl_tm M) (a 0)"
    using assms(1) unfolding ae_delta_val_fwd_to_padded_def by auto
  have to_ret: "a 0 = bl_block (bl_tm M)"
    using assms(2) unfolding ae_delta_val_fwd_to_ret_def by auto
  from padded to_ret
    have "is_padded_block (bl_tm M) (bl_block (bl_tm M) :: 'c ⇒ 'a)" by simp
  thus False using not_is_padded_bl_block[where 'c='c and bl="bl_tm M"] by simp
qed

lemma ae_delta_val_fwd_to_padded_reject_disjoint:
  assumes "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_padded M"
      and "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
  shows "False"
  using assms
  unfolding ae_delta_val_fwd_to_padded_def ae_delta_val_fwd_reject_def
            is_canonical_block_def
  by auto

lemma ae_delta_val_fwd_to_ret_reject_disjoint:
  assumes "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_ret M"
      and "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
  shows "False"
  using assms
  unfolding ae_delta_val_fwd_to_ret_def ae_delta_val_fwd_reject_def
  by auto

text ‹V-marker dispatch helpers: package the within-cluster
  multi-relation disjunction + pairwise disjointness + per-relation
  functionality into a single ‹_functional› lemma per V marker.
  Used by ‹alphabet_enlarge_delta_functional›'s V cases.›

lemma ae_delta_VFwd_functional:
  fixes M :: "('q, 'a) mttm"
  assumes le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(s, a, s1, a1, d1) ∈ alphabet_enlarge_delta M"
      and h2: "(s, a, s2, a2, d2) ∈ alphabet_enlarge_delta M"
      and idx: "snd (snd (snd (snd s))) = VFwd"
  shows "s1 = s2 ∧ a1 = a2 ∧ d1 = d2"
proof -
  have alt1: "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_advance M
                ∨ (s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_padded M
                ∨ (s, a, s1, a1, d1) ∈ ae_delta_val_fwd_reject M
                ∨ (s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_ret M"
    using h1 idx
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  have alt2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_advance M
                ∨ (s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_padded M
                ∨ (s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M
                ∨ (s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
    using h2 idx
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  from alt1 show ?thesis
  proof (elim disjE)
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_advance M"
    from alt2 show ?thesis
    proof (elim disjE)
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_advance M"
      show ?thesis using ae_delta_val_fwd_advance_functional[OF A1 A2] by simp
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_padded M"
      have False using ae_delta_val_fwd_advance_to_padded_disjoint[OF le_neq_bl A1 A2] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
      have False using ae_delta_val_fwd_advance_reject_disjoint[OF A1 A2] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
      have False using ae_delta_val_fwd_advance_to_ret_disjoint[OF le_neq_bl A1 A2] .
      thus ?thesis ..
    qed
  next
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_padded M"
    from alt2 show ?thesis
    proof (elim disjE)
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_advance M"
      have False using ae_delta_val_fwd_advance_to_padded_disjoint[OF le_neq_bl A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_padded M"
      show ?thesis using ae_delta_val_fwd_to_padded_functional[OF A1 A2] by simp
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
      have False using ae_delta_val_fwd_to_padded_reject_disjoint[OF A1 A2] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
      have False using ae_delta_val_fwd_to_padded_to_ret_disjoint[OF A1 A2] .
      thus ?thesis ..
    qed
  next
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_reject M"
    from alt2 show ?thesis
    proof (elim disjE)
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_advance M"
      have False using ae_delta_val_fwd_advance_reject_disjoint[OF A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_padded M"
      have False using ae_delta_val_fwd_to_padded_reject_disjoint[OF A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
      show ?thesis using ae_delta_val_fwd_reject_functional[OF A1 A2] by simp
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
      have False using ae_delta_val_fwd_to_ret_reject_disjoint[OF A2 A1] .
      thus ?thesis ..
    qed
  next
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_fwd_to_ret M"
    from alt2 show ?thesis
    proof (elim disjE)
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_advance M"
      have False using ae_delta_val_fwd_advance_to_ret_disjoint[OF le_neq_bl A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_padded M"
      have False using ae_delta_val_fwd_to_padded_to_ret_disjoint[OF A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_reject M"
      have False using ae_delta_val_fwd_to_ret_reject_disjoint[OF A1 A2] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_fwd_to_ret M"
      show ?thesis using ae_delta_val_fwd_to_ret_functional[OF A1 A2] by simp
    qed
  qed
qed

lemma ae_delta_VRet_functional:
  fixes M :: "('q, 'a) mttm"
  assumes h1: "(s, a, s1, a1, d1) ∈ alphabet_enlarge_delta M"
      and h2: "(s, a, s2, a2, d2) ∈ alphabet_enlarge_delta M"
      and idx: "snd (snd (snd (snd s))) = VRet"
  shows "s1 = s2 ∧ a1 = a2 ∧ d1 = d2"
proof -
  have alt1: "(s, a, s1, a1, d1) ∈ ae_delta_val_ret_step M
                ∨ (s, a, s1, a1, d1) ∈ ae_delta_val_ret_to_sim M"
    using h1 idx
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  have alt2: "(s, a, s2, a2, d2) ∈ ae_delta_val_ret_step M
                ∨ (s, a, s2, a2, d2) ∈ ae_delta_val_ret_to_sim M"
    using h2 idx
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_pad_to_ret_def
              ae_delta_val_pad_reject_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  from alt1 show ?thesis
  proof
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_ret_step M"
    from alt2 show ?thesis
    proof
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_ret_step M"
      show ?thesis using ae_delta_val_ret_step_functional[OF A1 A2] by simp
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_ret_to_sim M"
      have False using ae_delta_val_ret_step_ret_to_sim_disjoint[OF A1 A2] .
      thus ?thesis ..
    qed
  next
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_ret_to_sim M"
    from alt2 show ?thesis
    proof
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_ret_step M"
      have False using ae_delta_val_ret_step_ret_to_sim_disjoint[OF A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_ret_to_sim M"
      show ?thesis using ae_delta_val_ret_to_sim_functional[OF A1 A2] by simp
    qed
  qed
qed

lemma ae_delta_VFwdPad_functional:
  fixes M :: "('q, 'a) mttm"
  assumes h1: "(s, a, s1, a1, d1) ∈ alphabet_enlarge_delta M"
      and h2: "(s, a, s2, a2, d2) ∈ alphabet_enlarge_delta M"
      and idx: "snd (snd (snd (snd s))) = VFwdPad"
  shows "s1 = s2 ∧ a1 = a2 ∧ d1 = d2"
proof -
  have alt1: "(s, a, s1, a1, d1) ∈ ae_delta_val_pad_to_ret M
                ∨ (s, a, s1, a1, d1) ∈ ae_delta_val_pad_reject M"
    using h1 idx
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  have alt2: "(s, a, s2, a2, d2) ∈ ae_delta_val_pad_to_ret M
                ∨ (s, a, s2, a2, d2) ∈ ae_delta_val_pad_reject M"
    using h2 idx
    unfolding alphabet_enlarge_delta_def
              ae_delta_val_fwd_advance_def
              ae_delta_val_fwd_to_padded_def
              ae_delta_val_fwd_reject_def
              ae_delta_val_fwd_to_ret_def
              ae_delta_val_ret_step_def
              ae_delta_val_ret_to_sim_def
              ae_delta_ss1_ss2_def
              ae_delta_ss2_ss3_def
              ae_delta_ss3_ss4_def
              ae_delta_ss4_ss5_def
              ae_delta_ss5_ss6_def
              ae_delta_ss6_ss7_def
              ae_delta_ss7_ss8_def
              ae_delta_ss8_ss1_def
    by auto
  from alt1 show ?thesis
  proof
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_pad_to_ret M"
    from alt2 show ?thesis
    proof
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_pad_to_ret M"
      show ?thesis using ae_delta_val_pad_to_ret_functional[OF A1 A2] by simp
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_pad_reject M"
      have False using ae_delta_val_pad_to_ret_pad_reject_disjoint[OF A1 A2] .
      thus ?thesis ..
    qed
  next
    assume A1: "(s, a, s1, a1, d1) ∈ ae_delta_val_pad_reject M"
    from alt2 show ?thesis
    proof
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_pad_to_ret M"
      have False using ae_delta_val_pad_to_ret_pad_reject_disjoint[OF A2 A1] .
      thus ?thesis ..
    next
      assume A2: "(s, a, s2, a2, d2) ∈ ae_delta_val_pad_reject M"
      show ?thesis using ae_delta_val_pad_reject_functional[OF A1 A2] by simp
    qed
  qed
qed


subsection ‹Chain uniqueness --- single-step functionality›

text ‹Under ‹valid_mttm M›, ‹det_mttm M›, and
  ‹le_tm M ≠ bl_tm M›, the alphabet-enlargement
  transition relation is functional in its source pair.  Proof
  case-splits on the source substep index: ‹SSN› cases dispatch
  via the matching ‹ae_delta_ssN_only› + ‹*_functional›
  pair; V-marker cases (‹VFwd›, ‹VFwdPad›, ‹VRet›) use
  within-cluster disjointness to collapse the multi-relation
  alternative, then apply the surviving sub-relation's functionality
  lemma.›

lemma alphabet_enlarge_delta_functional:
  fixes M :: "('q, 'a) mttm"
  assumes vM:  "valid_mttm M"
      and det: "det_mttm M"
      and le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(s, a, s1, a1, d1) ∈ alphabet_enlarge_delta M"
      and h2: "(s, a, s2, a2, d2) ∈ alphabet_enlarge_delta M"
  shows "s1 = s2 ∧ a1 = a2 ∧ d1 = d2"
proof (cases "snd (snd (snd (snd s)))")
  case VFwd
  show ?thesis by (rule ae_delta_VFwd_functional[OF le_neq_bl h1 h2 VFwd])
next
  case VFwdPad
  show ?thesis by (rule ae_delta_VFwdPad_functional[OF h1 h2 VFwdPad])
next
  case VRet
  show ?thesis by (rule ae_delta_VRet_functional[OF h1 h2 VRet])
next
  case SS1
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss1_ss2 M"
    by (rule ae_delta_ss1_only[OF h1 SS1])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss1_ss2 M"
    by (rule ae_delta_ss1_only[OF h2 SS1])
  show ?thesis using ae_delta_ss1_ss2_functional[OF e1 e2] by simp
next
  case SS2
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss2_ss3 M"
    by (rule ae_delta_ss2_only[OF h1 SS2])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss2_ss3 M"
    by (rule ae_delta_ss2_only[OF h2 SS2])
  show ?thesis using ae_delta_ss2_ss3_functional[OF e1 e2] by simp
next
  case SS3
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss3_ss4 M"
    by (rule ae_delta_ss3_only[OF h1 SS3])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss3_ss4 M"
    by (rule ae_delta_ss3_only[OF h2 SS3])
  show ?thesis using ae_delta_ss3_ss4_functional[OF e1 e2] by simp
next
  case SS4
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss4_ss5 M"
    by (rule ae_delta_ss4_only[OF h1 SS4])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss4_ss5 M"
    by (rule ae_delta_ss4_only[OF h2 SS4])
  show ?thesis using ae_delta_ss4_ss5_functional[OF vM det e1 e2] by simp
next
  case SS5
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss5_ss6 M"
    by (rule ae_delta_ss5_only[OF h1 SS5])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss5_ss6 M"
    by (rule ae_delta_ss5_only[OF h2 SS5])
  show ?thesis using ae_delta_ss5_ss6_functional[OF e1 e2] by simp
next
  case SS6
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss6_ss7 M"
    by (rule ae_delta_ss6_only[OF h1 SS6])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss6_ss7 M"
    by (rule ae_delta_ss6_only[OF h2 SS6])
  show ?thesis using ae_delta_ss6_ss7_functional[OF e1 e2] by simp
next
  case SS7
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss7_ss8 M"
    by (rule ae_delta_ss7_only[OF h1 SS7])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss7_ss8 M"
    by (rule ae_delta_ss7_only[OF h2 SS7])
  show ?thesis using ae_delta_ss7_ss8_functional[OF e1 e2] by simp
next
  case SS8
  have e1: "(s, a, s1, a1, d1) ∈ ae_delta_ss8_ss1 M"
    by (rule ae_delta_ss8_only[OF h1 SS8])
  have e2: "(s, a, s2, a2, d2) ∈ ae_delta_ss8_ss1 M"
    by (rule ae_delta_ss8_only[OF h2 SS8])
  show ?thesis using ae_delta_ss8_ss1_functional[OF e1 e2] by simp
qed

text ‹Lifting chain uniqueness from ‹alphabet_enlarge_delta›
  to ‹mttm_step (alphabet_enlarge_delta M)›: single-step then
  ‹n›-fold via standard induction.  Consumed in stage 6 to identify
  the forward arm's produced ‹c'''› with the backward arm's
  given ‹c''›.›

lemma mttm_step_alphabet_enlarge_functional:
  fixes M :: "('q, 'a) mttm"
  assumes vM:  "valid_mttm M"
      and det: "det_mttm M"
      and le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(c, c1) ∈ mttm_step (alphabet_enlarge_delta M)"
      and h2: "(c, c2) ∈ mttm_step (alphabet_enlarge_delta M)"
  shows "c1 = c2"
proof -
  from h1 obtain q ts n q1 a1 dir1 where
      c_eq1:  "c  = ConfigM q ts n"
    and c1_eq: "c1 = ConfigM q1 (λk. (ts k)(n k := a1 k))
                                  (λk. go_dir (dir1 k) (n k))"
    and tr1: "(q, λk. ts k (n k), q1, a1, dir1)
                ∈ alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  from h2 obtain q' ts' n' q2 a2 dir2 where
      c_eq2:  "c  = ConfigM q' ts' n'"
    and c2_eq: "c2 = ConfigM q2 (λk. (ts' k)(n' k := a2 k))
                                  (λk. go_dir (dir2 k) (n' k))"
    and tr2: "(q', λk. ts' k (n' k), q2, a2, dir2)
                ∈ alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  from c_eq1 c_eq2
  have qq: "q = q'" and tsts: "ts = ts'" and nn: "n = n'"
    by auto
  from tr1 qq tsts nn
  have tr1': "(q, λk. ts k (n k), q1, a1, dir1)
                ∈ alphabet_enlarge_delta M" by simp
  from tr2 qq tsts nn
  have tr2': "(q, λk. ts k (n k), q2, a2, dir2)
                ∈ alphabet_enlarge_delta M" by simp
  have "q1 = q2 ∧ a1 = a2 ∧ dir1 = dir2"
    using alphabet_enlarge_delta_functional[OF vM det le_neq_bl tr1' tr2'] .
  thus ?thesis using c1_eq c2_eq tsts nn by simp
qed

lemma mttm_step_alphabet_enlarge_relpow_functional:
  fixes M :: "('q, 'a) mttm"
  assumes vM:  "valid_mttm M"
      and det: "det_mttm M"
      and le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(c, c1) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
      and h2: "(c, c2) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
  shows "c1 = c2"
  using h1 h2
proof (induction n arbitrary: c c1 c2)
  case 0
  thus ?case by simp
next
  case (Suc n)
  from Suc.prems(1) obtain c1' where
      step1: "(c, c1') ∈ mttm_step (alphabet_enlarge_delta M)"
    and rest1: "(c1', c1) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
    by (meson relpow_Suc_D2)
  from Suc.prems(2) obtain c2' where
      step2: "(c, c2') ∈ mttm_step (alphabet_enlarge_delta M)"
    and rest2: "(c2', c2) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
    by (meson relpow_Suc_D2)
  have c'_eq: "c1' = c2'"
    by (rule mttm_step_alphabet_enlarge_functional
              [OF vM det le_neq_bl step1 step2])
  show ?case using Suc.IH[OF rest1] rest2 c'_eq by simp
qed


text ‹‹det›-free chain uniqueness for the ∗‹validation›
  prefix.  ‹alphabet_enlarge_delta›'s only nondeterministic source is
  the SS4‹→›SS5 macro-step; every other stage marker dispatches to a
  functional substep builder.  In particular, from a validation marker
  (‹VFwd› / ‹VFwdPad› / ‹VRet›) the transition is single-valued
  with no appeal to ‹det_mttm M› --- the det-free analogue of
  ‹alphabet_enlarge_delta_functional› restricted to validation
  sources.  Consumed by ‹alphabet_enlarge_language›'s reverse arm to
  identify the unique validation prefix from ‹ae_init_config› without
  the ‹det› hypothesis of Hopcroft--Ullman's speed-up theorems
  cite‹‹Theorems 12.3, 12.4› in "Hopcroft1979:introduction"›.›

lemma alphabet_enlarge_delta_val_functional:
  fixes M :: "('q, 'a) mttm"
  assumes le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(s, a, s1, a1, d1) ∈ alphabet_enlarge_delta M"
      and h2: "(s, a, s2, a2, d2) ∈ alphabet_enlarge_delta M"
      and idx: "snd (snd (snd (snd s))) ∈ {VFwd, VFwdPad, VRet}"
  shows "s1 = s2 ∧ a1 = a2 ∧ d1 = d2"
proof -
  consider (VFwd) "snd (snd (snd (snd s))) = VFwd"
         | (VFwdPad) "snd (snd (snd (snd s))) = VFwdPad"
         | (VRet) "snd (snd (snd (snd s))) = VRet"
    using idx by blast
  thus ?thesis
  proof cases
    case VFwd
    show ?thesis by (rule ae_delta_VFwd_functional[OF le_neq_bl h1 h2 VFwd])
  next
    case VFwdPad
    show ?thesis by (rule ae_delta_VFwdPad_functional[OF h1 h2 VFwdPad])
  next
    case VRet
    show ?thesis by (rule ae_delta_VRet_functional[OF h1 h2 VRet])
  qed
qed

lemma mttm_step_alphabet_enlarge_val_functional:
  fixes M :: "('q, 'a) mttm"
  assumes le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(c, c1) ∈ mttm_step (alphabet_enlarge_delta M)"
      and h2: "(c, c2) ∈ mttm_step (alphabet_enlarge_delta M)"
      and idx: "snd (snd (snd (snd (mt_state c)))) ∈ {VFwd, VFwdPad, VRet}"
  shows "c1 = c2"
proof -
  from h1 obtain q ts n q1 a1 dir1 where
      c_eq1:  "c  = ConfigM q ts n"
    and c1_eq: "c1 = ConfigM q1 (λk. (ts k)(n k := a1 k))
                                  (λk. go_dir (dir1 k) (n k))"
    and tr1: "(q, λk. ts k (n k), q1, a1, dir1) ∈ alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  from h2 obtain q' ts' n' q2 a2 dir2 where
      c_eq2:  "c  = ConfigM q' ts' n'"
    and c2_eq: "c2 = ConfigM q2 (λk. (ts' k)(n' k := a2 k))
                                  (λk. go_dir (dir2 k) (n' k))"
    and tr2: "(q', λk. ts' k (n' k), q2, a2, dir2) ∈ alphabet_enlarge_delta M"
    by (auto elim: mttm_step.cases)
  from c_eq1 c_eq2 have qq: "q = q'" and tsts: "ts = ts'" and nn: "n = n'"
    by auto
  from tr2 qq tsts nn
  have tr2': "(q, λk. ts k (n k), q2, a2, dir2) ∈ alphabet_enlarge_delta M"
    by simp
  have idx': "snd (snd (snd (snd q))) ∈ {VFwd, VFwdPad, VRet}"
    using idx c_eq1 by simp
  have "q1 = q2 ∧ a1 = a2 ∧ dir1 = dir2"
    by (rule alphabet_enlarge_delta_val_functional[OF le_neq_bl tr1 tr2' idx'])
  thus ?thesis using c1_eq c2_eq tsts nn by simp
qed

text ‹The relpow lift: an ‹R›-chain whose every source config (every
  config strictly before the end) sits at a validation marker is unique.
  The discharge supplies the invariant for an ‹ae_init_config› prefix
  that stays within the validation sweep.›

lemma mttm_step_alphabet_enlarge_val_relpow_functional:
  fixes M :: "('q, 'a) mttm"
  assumes le_neq_bl: "le_tm M ≠ bl_tm M"
      and h1: "(c, c1) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
      and h2: "(c, c2) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
      and inv: "∀i<n. ∀d. (c, d) ∈ mttm_step (alphabet_enlarge_delta M) ^^ i
                    ⟶ snd (snd (snd (snd (mt_state d))))
                          ∈ {VFwd, VFwdPad, VRet}"
  shows "c1 = c2"
  using h1 h2 inv
proof (induction n arbitrary: c c1 c2)
  case 0
  thus ?case by simp
next
  case (Suc n)
  from Suc.prems(1) obtain c1' where
      step1: "(c, c1') ∈ mttm_step (alphabet_enlarge_delta M)"
    and rest1: "(c1', c1) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
    by (meson relpow_Suc_D2)
  from Suc.prems(2) obtain c2' where
      step2: "(c, c2') ∈ mttm_step (alphabet_enlarge_delta M)"
    and rest2: "(c2', c2) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
    by (meson relpow_Suc_D2)
  have c_val: "snd (snd (snd (snd (mt_state c)))) ∈ {VFwd, VFwdPad, VRet}"
  proof -
    have a: "(c, c) ∈ mttm_step (alphabet_enlarge_delta M) ^^ 0" by simp
    have b: "(0::nat) < Suc n" by simp
    show ?thesis using Suc.prems(3) a b by blast
  qed
  have c'_eq: "c1' = c2'"
    by (rule mttm_step_alphabet_enlarge_val_functional
                [OF le_neq_bl step1 step2 c_val])
  have rest2': "(c1', c2) ∈ mttm_step (alphabet_enlarge_delta M) ^^ n"
    using rest2 c'_eq by simp
  have inv':
      "∀i<n. ∀d. (c1', d) ∈ mttm_step (alphabet_enlarge_delta M) ^^ i
                    ⟶ snd (snd (snd (snd (mt_state d))))
                          ∈ {VFwd, VFwdPad, VRet}"
  proof (intro allI impI)
    fix i d
    assume i_lt: "i < n"
      and reach: "(c1', d) ∈ mttm_step (alphabet_enlarge_delta M) ^^ i"
    have "(c, d) ∈ mttm_step (alphabet_enlarge_delta M) ^^ Suc i"
      by (rule relpow_Suc_I2[OF step1 reach])
    moreover have "Suc i < Suc n" using i_lt by simp
    ultimately show "snd (snd (snd (snd (mt_state d))))
                        ∈ {VFwd, VFwdPad, VRet}"
      using Suc.prems(3) by blast
  qed
  show ?case by (rule Suc.IH[OF rest1 rest2' inv'])
qed


end