Theory Wrap_Defs

theory Wrap_Defs
  imports Wrap_Base "Multitape_TM_Substrate.Multitape_Origin_Float"
begin

section ‹Faithful (k-tape) encoding wrap: plant-‹le› variant (HU 12.4)›

text ‹Reaching faithful ‹k› tapes for the super-linear speed-up
  cite‹‹Theorem 12.3› in "Hopcroft1979:introduction"› by
  ∗‹rewinding› the reused input tape costs a ‹~2n› setup that the
  super-linear growth hypothesis absorbs.  Theorem 12.4's
  tight ‹(1+ε)n› bound cannot absorb it, so this variant avoids the
  rewind of the input tape entirely: it plants a fresh ‹le› at the input
  head's final position, ∗‹floating› the origin (the spent raw input to
  its left becomes unreachable, penned off by clause 1).

  Only the reset phase differs from the transpose wrap.  The storage
  tape (physical @{text 1}, carrying M's tape 0 = the encoded input) is
  still rewound to its ‹le› --- but that is only ‹⌈n/c⌉› cells (the
  encoded length), the ‹ε⋅n› term --- via the generic single-tape
  rewind @{const wrap_rewind_loop_delta_gen}.  The input tape (physical
  @{text 0}, becoming M's tape 1) is ∗‹not› rewound: the rewind-done
  step plants ‹le› on it and hands over to @{text W_Disp}.  Everything
  else --- the six transpose encoder families, the transposed run, the
  dispatch --- is reused verbatim.

  The planted ‹le› makes the wrap ∗‹not› @{const le_unique} (it writes
  ‹le› where it did not read ‹le›); it remains @{const valid_mttm}, since
  clause 1 constrains only transitions that ∗‹read› ‹le›.  The engine
  is then run from a floated-origin init config, bridged back to the
  proper @{const init_config_mttm} by the origin-float lemmas of
  @{theory Multitape_TM_Substrate.Multitape_Origin_Float}.›

subsection ‹The plant-‹le› reset done step›

text ‹Rewind-done for the plant variant: fires when the storage tape
  (index @{text "Suc 0"}) reads ‹le› (its cell 0, reached by the generic
  rewind loop), and in the same transition writes ‹le› on the input tape
  (index @{text 0}) at its current head --- the plant --- handing over to
  @{text W_Disp}.  No head moves.  This is the sole wrap-B-specific reset
  family; the loop is the generic @{const wrap_rewind_loop_delta_gen}.›

definition wrap_plant_done_delta ::
  "('q, 'b) mttm ⇒ 'a set
   ⇒ (('q, 'a, 'b) wrap_state
       × (nat ⇒ ('a, 'b) wrap_alphabet)
       × ('q, 'a, 'b) wrap_state
       × (nat ⇒ ('a, 'b) wrap_alphabet)
       × (nat ⇒ dir)) set"
where
  "wrap_plant_done_delta M Σu =
     { (W_Reset, sym, W_Disp,
        (λt. if t = 0 then Enc (le_tm M) else sym t),
        λ_. dir.N)
       | sym.
           sym (Suc 0) = Enc (le_tm M)
           ∧ (∀i≥k_tm M. sym i = Enc (bl_tm M))
           ∧ sym ∈ UNIV → Raw ` Σu ∪ Enc ` Γ_tm M }"

subsection ‹The plant-‹le› combinator›

text ‹The plant wrap's transition relation: the six transpose encoder
  families at @{term "K = k_tm M"}, the transposed run and dispatch, and
  --- for the reset --- the generic single-tape storage rewind (loop)
  plus the plant-done step.›

definition wrap_delta ::
  "('q, 'b) mttm ⇒ ('a list ⇒ 'b) ⇒ nat ⇒ 'a set
   ⇒ (('q, 'a, 'b) wrap_state
       × (nat ⇒ ('a, 'b) wrap_alphabet)
       × ('q, 'a, 'b) wrap_state
       × (nat ⇒ ('a, 'b) wrap_alphabet)
       × (nat ⇒ dir)) set"
where
  "wrap_delta M pack c Σu =
     wrap_init_delta_gen (k_tm M) M
     ∪ wrap_buf_extend_delta_gen (k_tm M) M c Σu
     ∪ wrap_buf_close_delta_gen (k_tm M) M pack c Σu
     ∪ wrap_buf_empty_end_delta_gen (k_tm M) M Σu
     ∪ wrap_buf_nonempty_end_delta_gen (k_tm M) M pack c Σu
     ∪ wrap_rewind_loop_delta_gen W_Reset (Suc 0) (k_tm M) M Σu
     ∪ wrap_plant_done_delta M Σu
     ∪ wrap_disp_delta_gen (k_tm M) M Σu
     ∪ wrap_run_delta M Σu"

text ‹The faithful ‹k›-tape plant-‹le› encoding wrap: transition relation
  @{const wrap_delta} at tape count @{term "k_tm M"}, reusing the wrap
  state set (no new state --- the plant folds into the reset-done step).
  Well-formed only when @{term "k_tm M ≥ 2"}, as for the transpose wrap.›

fun encoding_wrap ::
  "('q, 'b) mttm ⇒ ('a list ⇒ 'b) ⇒ nat ⇒ 'a set
   ⇒ (('q, 'a, 'b) wrap_state, ('a, 'b) wrap_alphabet) mttm"
where
  "encoding_wrap M pack c Σu =
     MTTM
       (wrap_state_set M c Σu)
       (Raw ` Σu)
       (Raw ` Σu ∪ Enc ` Γ_tm M)
       (Enc (bl_tm M))
       (Enc (le_tm M))
       (wrap_delta M pack c Σu)
       W_Init
       (W_Run (t_tm M))
       W_Rej
       (k_tm M)"


subsection ‹Well-formedness of the plant-‹le› wrap›

text ‹Phase-family case split for @{const wrap_delta}: a transition
  belongs to exactly one of the nine builders --- the six
  boundary-parameterised encoder families at @{term "k_tm M"}, the generic
  single-tape storage rewind loop, the plant-‹le› rewind-done step, and the
  transposed run.›

lemma wrap_delta_cases:
  assumes "(q, a, q', a', d) ∈ wrap_delta M pack c Σu"
  obtains
    (init) "(q, a, q', a', d) ∈ wrap_init_delta_gen (k_tm M) M"
  | (ext) "(q, a, q', a', d) ∈ wrap_buf_extend_delta_gen (k_tm M) M c Σu"
  | (close) "(q, a, q', a', d) ∈ wrap_buf_close_delta_gen (k_tm M) M pack c Σu"
  | (eend) "(q, a, q', a', d) ∈ wrap_buf_empty_end_delta_gen (k_tm M) M Σu"
  | (nend) "(q, a, q', a', d) ∈ wrap_buf_nonempty_end_delta_gen (k_tm M) M pack c Σu"
  | (rloop) "(q, a, q', a', d)
               ∈ wrap_rewind_loop_delta_gen W_Reset (Suc 0) (k_tm M) M Σu"
  | (rdone) "(q, a, q', a', d) ∈ wrap_plant_done_delta M Σu"
  | (disp) "(q, a, q', a', d) ∈ wrap_disp_delta_gen (k_tm M) M Σu"
  | (run) "(q, a, q', a', d) ∈ wrap_run_delta M Σu"
  using assms unfolding wrap_delta_def by blast

text ‹Obligation 1 --- well-formedness of the faithful @{text k}-tape
  plant-‹le› wrap at tape count @{term "k_tm M"}.  Hypotheses:
  @{term "2 ≤ k_tm M"}, @{term "valid_mttm M"}, and
  @{term "le_tm M ≠ bl_tm M"} (the storage rewind passes @{text bl}
  through unchanged, and the plant writes @{text le}, so the
  no-spurious-LE obligations need them distinct).  It does ∗‹not› require
  @{const le_unique} of the input, and --- crucially --- the resulting wrap
  is itself ∗‹not› @{const le_unique}: the plant-done step writes @{text le}
  on physical tape @{text 0} without reading it there.  That is legal for
  @{const valid_mttm}, whose clause 1 (obligation 14 below) constrains only
  transitions that ∗‹read› @{text le}; the dropped clause 2 was exactly the
  no-planting rule.›

lemma wrap_wf:
  assumes valM: "valid_mttm M"
      and le_ne_bl: "le_tm M ≠ bl_tm M"
      and finSu: "finite Σu"
      and c_pos: "0 < c"
      and k2: "2 ≤ k_tm M"
  shows "valid_mttm (encoding_wrap M pack c Σu)"
proof -
  have eq:
    "encoding_wrap M pack c Σu =
       MTTM (wrap_state_set M c Σu)
            (Raw ` Σu)
            (Raw ` Σu ∪ Enc ` Γ_tm M)
            (Enc (bl_tm M))
            (Enc (le_tm M))
            (wrap_delta M pack c Σu)
            W_Init
            (W_Run (t_tm M))
            W_Rej
            (k_tm M)"
    by simp
  show ?thesis
    unfolding eq valid_mttm.simps
  proof (intro conjI)
    ― ‹(1) finite Q'›
    show "finite (wrap_state_set M c Σu)"
      by (rule finite_wrap_state_set[OF valM finSu])
    ― ‹(2) finite ‹Γ›'›
    show "finite (Raw ` Σu ∪ Enc ` Γ_tm M)"
      using finSu valid_mttm_finite_Gamma[OF valM] by simp
    ― ‹(3) ‹Σ›' ‹⊆› ‹Γ›'›
    show "Raw ` Σu ⊆ Raw ` Σu ∪ Enc ` Γ_tm M"
      by blast
    ― ‹(4) start in Q'›
    show "W_Init ∈ wrap_state_set M c Σu"
      unfolding wrap_state_set_def by simp
    ― ‹(5) accept in Q'›
    show "W_Run (t_tm M) ∈ wrap_state_set M c Σu"
      using valid_mttm_t_in_Q[OF valM]
      unfolding wrap_state_set_def by simp
    ― ‹(6) reject in Q'›
    show "W_Rej ∈ wrap_state_set M c Σu"
      unfolding wrap_state_set_def by simp
    ― ‹(7a) bl in ‹Γ›'›
    show "Enc (bl_tm M) ∈ Raw ` Σu ∪ Enc ` Γ_tm M"
      using valid_mttm_blank_in_Gamma[OF valM] by blast
    ― ‹(7b) bl not in ‹Σ›'›
    show "Enc (bl_tm M) ∉ Raw ` Σu"
      by auto
    ― ‹(8a) le in ‹Γ›'›
    show "Enc (le_tm M) ∈ Raw ` Σu ∪ Enc ` Γ_tm M"
      using valid_mttm_LE_in_Gamma[OF valM] by blast
    ― ‹(8b) le not in ‹Σ›'›
    show "Enc (le_tm M) ∉ Raw ` Σu"
      by auto
    ― ‹(11) accept ‹≠› reject›
    show "W_Run (t_tm M) ≠ W_Rej"
      by simp
    ― ‹(12) ‹0 < k›: the plant wrap keeps M's tape count.›
    show "0 < k_tm M"
      using valid_mttm_k_pos[OF valM] by simp
    ― ‹(13) ‹δ›-shape: source / dest / read / write range typing.  The
       plant writes @{text "Enc le"} on tape @{text 0}, which is in range by
       @{thm valid_mttm_LE_in_Gamma}.›
    show "wrap_delta M pack c Σu
            ⊆ (wrap_state_set M c Σu - {W_Run (t_tm M), W_Rej})
              × (UNIV → Raw ` Σu ∪ Enc ` Γ_tm M)
              × wrap_state_set M c Σu
              × (UNIV → Raw ` Σu ∪ Enc ` Γ_tm M)
              × (UNIV → UNIV)"
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
                wrap_state_set_def
      using c_pos valid_mttm_t_in_Q[OF valM] valid_mttm_s_in_Q[OF valM]
            valid_mttm_LE_in_Gamma[OF valM] valid_mttm_blank_in_Gamma[OF valM]
            valid_mttm_delta_set[OF valM]
            valid_mttm_Sigma_sub_Gamma[OF valM]
      by (fastforce split: nat.split if_splits)
    ― ‹(14) ‹δ›LE-preservation: read LE ‹⟹› write LE and dir ‹∈› {N, R}.
       The plant-done step writes LE on tape @{text 0} regardless of what it
       read there --- legal, since this obligation only fires when the read
       cell already ∗‹is› LE, and then the plant writes LE anyway.  The
       rewind loop only moves the storage head (@{text "Suc 0"}), whose
       read cannot be LE (its guard), so no LE-read cell moves.›
    show "∀q a q' a' d k.
            (q, a, q', a', d) ∈ wrap_delta M pack c Σu ⟶
            a k = Enc (le_tm M) ⟶
            a' k = Enc (le_tm M) ∧ d k ∈ {dir.N, dir.R}"
    proof (intro allI impI)
      fix q a q' a' d k
      assume in_δ: "(q, a, q', a', d) ∈ wrap_delta M pack c Σu"
         and LE: "a k = Enc (le_tm M)"
      from in_δ show "a' k = Enc (le_tm M) ∧ d k ∈ {dir.N, dir.R}"
      proof (cases rule: wrap_delta_cases)
        case init
        thus ?thesis using LE unfolding wrap_init_delta_gen_def
          by (auto split: nat.splits if_splits)
      next
        case ext
        thus ?thesis using LE unfolding wrap_buf_extend_delta_gen_def
          by (auto split: nat.splits)
      next
        case close
        thus ?thesis using LE unfolding wrap_buf_close_delta_gen_def
          by (fastforce split: nat.splits if_splits)
      next
        case eend
        thus ?thesis using LE unfolding wrap_buf_empty_end_delta_gen_def
          by (auto split: nat.splits)
      next
        case nend
        thus ?thesis using LE unfolding wrap_buf_nonempty_end_delta_gen_def
          by (fastforce split: nat.splits if_splits)
      next
        case rloop
        ― ‹Storage rewind: write = read, so LE is preserved; the only moving
           head is @{text "Suc 0"}, whose guard forbids reading LE, so a
           LE-read cell (necessarily @{text "k ≠ Suc 0"}) stays stationary.›
        thus ?thesis using LE unfolding wrap_rewind_loop_delta_gen_def
          by (auto split: if_splits)
      next
        case rdone
        ― ‹Plant-done: read = write on every tape except @{text 0}, where the
           plant writes LE; either way the write at a LE-read cell is LE, and
           no head moves.›
        thus ?thesis using LE unfolding wrap_plant_done_delta_def
          by (auto split: if_splits)
      next
        case disp
        thus ?thesis using LE unfolding wrap_disp_delta_gen_def
          by (auto split: nat.splits)
      next
        case run
        then obtain qq σ q'' σ' dd sym where
            aeq: "a = sym"
            and a'eq: "a' = (λp. Enc (σ' (wrap_tau p)))"
            and deq: "d = (λp. dd (wrap_tau p))"
            and trM: "(qq, σ, q'', σ', dd) ∈ delta_tm M"
            and symc: "∀p. sym p = Enc (σ (wrap_tau p))"
          unfolding wrap_run_delta_def by auto
        have "sym k = Enc (le_tm M)" using LE aeq by simp
        moreover have "sym k = Enc (σ (wrap_tau k))" using symc by simp
        ultimately have "σ (wrap_tau k) = le_tm M" by simp
        from valid_mttm_deltaLE[OF valM trM this]
        have "σ' (wrap_tau k) = le_tm M ∧ dd (wrap_tau k) ∈ {dir.N, dir.R}" .
        with a'eq deq show ?thesis by simp
      qed
    qed
    ― ‹(15) ‹δ›-support: beyond the tape count each transition reads and
       writes blank and is stationary.  Since ‹2 ≤ k_tm M ≤ j› we have
       ‹2 ≤ j›: the storage head @{text "Suc 0"} and the plant tape @{text 0}
       are both ‹< j›, so both reset families are blank-stationary there, and
       the run inherits @{thm valid_mttm_delta_support}.›
    show "∀q a q' a' d.
            (q, a, q', a', d) ∈ wrap_delta M pack c Σu ⟶
            (∀j ≥ k_tm M.
               a j = Enc (bl_tm M) ∧ a' j = Enc (bl_tm M) ∧ d j = dir.N)"
    proof (intro allI impI)
      fix q a q' a' d j
      assume in_δ: "(q, a, q', a', d) ∈ wrap_delta M pack c Σu"
         and jge: "k_tm M ≤ j"
      from k2 jge have j2: "2 ≤ j" by simp
      from in_δ
      show "a j = Enc (bl_tm M) ∧ a' j = Enc (bl_tm M) ∧ d j = dir.N"
      proof (cases rule: wrap_delta_cases)
        case init
        thus ?thesis using jge j2 unfolding wrap_init_delta_gen_def
          by (auto split: nat.splits if_splits)
      next
        case ext
        thus ?thesis using jge j2 unfolding wrap_buf_extend_delta_gen_def
          by (auto split: nat.splits)
      next
        case close
        thus ?thesis using jge j2 unfolding wrap_buf_close_delta_gen_def
          by (auto split: nat.splits if_splits)
      next
        case eend
        thus ?thesis using jge j2 unfolding wrap_buf_empty_end_delta_gen_def
          by (auto split: nat.splits)
      next
        case nend
        thus ?thesis using jge j2 unfolding wrap_buf_nonempty_end_delta_gen_def
          by (auto split: nat.splits if_splits)
      next
        case rloop
        thus ?thesis using jge j2 unfolding wrap_rewind_loop_delta_gen_def
          by (auto split: if_splits)
      next
        case rdone
        thus ?thesis using jge j2 unfolding wrap_plant_done_delta_def
          by (auto split: if_splits)
      next
        case disp
        thus ?thesis using jge j2 unfolding wrap_disp_delta_gen_def
          by (auto split: nat.splits)
      next
        case run
        then obtain qq σ q'' σ' dd sym where
            aeq: "a = sym"
            and a'eq: "a' = (λp. Enc (σ' (wrap_tau p)))"
            and deq: "d = (λp. dd (wrap_tau p))"
            and trM: "(qq, σ, q'', σ', dd) ∈ delta_tm M"
            and symc: "∀p. sym p = Enc (σ (wrap_tau p))"
          unfolding wrap_run_delta_def by auto
        have tauj: "wrap_tau j = j" using j2 by (rule wrap_tau_ge2_id)
        from valid_mttm_delta_support[OF valM trM jge]
        have supp: "σ j = bl_tm M ∧ σ' j = bl_tm M ∧ dd j = dir.N" .
        have "a j = Enc (bl_tm M)" using aeq symc tauj supp by simp
        moreover have "a' j = Enc (bl_tm M)" using a'eq tauj supp by simp
        moreover have "d j = dir.N" using deq tauj supp by simp
        ultimately show ?thesis by simp
      qed
    qed
  qed
qed


subsection ‹Determinism of the plant-‹le› wrap›

text ‹Obligation 4 --- determinism preservation, conditional on
  @{term "det_mttm M"}.  The encoder families and
  dispatch are functional per read pattern, and the transposed run inherits
  M-determinism through @{const wrap_tau}.  Only the @{text W_Reset} case
  differs: instead of the two combined-reset families it disambiguates the
  generic storage rewind loop from the plant-done step by their
  @{text le}-guards on the storage tape (index @{text "Suc 0"}) --- the loop
  reads a non-@{text le} there, the plant-done reads @{text le} --- each
  functional in the read.›

lemma wrap_det:
  assumes valM: "valid_mttm M"
      and detM: "det_mttm M"
      and finSu: "finite Σu"
      and c_pos: "0 < c"
  shows "det_mttm (encoding_wrap M pack c Σu)"
  unfolding det_mttm_def
proof (intro allI impI)
  fix q a p1 b1 d1 p2 b2 d2
  assume t1: "(q, a, p1, b1, d1) ∈ delta_tm (encoding_wrap M pack c Σu)"
     and t2: "(q, a, p2, b2, d2) ∈ delta_tm (encoding_wrap M pack c Σu)"
  hence t1w: "(q, a, p1, b1, d1) ∈ wrap_delta M pack c Σu"
    and t2w: "(q, a, p2, b2, d2) ∈ wrap_delta M pack c Σu"
    by simp_all
  show "(p1, b1, d1) = (p2, b2, d2)"
  proof (cases q)
    case W_Init
    with t1w t2w show ?thesis
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by auto
  next
    case (W_Buf ws)
    with t1w t2w show ?thesis
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by auto
  next
    case W_Reset
    ― ‹Both storage-rewind families read @{text "sym (Suc 0)"}; the loop
       fires when it is not @{text le} (looping in @{text W_Reset}, no head
       moves but @{text "Suc 0"} left), the plant-done when it is @{text le}
       (to @{text W_Disp}, planting @{text le} on tape @{text 0}).  Their
       guards are complementary, so at most one fires per read.›
    with t1w t2w show ?thesis
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by (auto split: if_splits)
  next
    case W_Disp
    with t1w t2w show ?thesis
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by auto
  next
    case (W_Run qM)
    ― ‹Only ‹wrap_run_delta› has a ‹W_Run› source.  Extract the M-side
       ‹δ›-tuples linked to each wrap-tuple, then use M-determinism.›
    from t1w W_Run obtain sig1 q1' sig1' dd1 where
      m1: "(qM, sig1, q1', sig1', dd1) ∈ delta_tm M"
      and sym1: "∀p. a p = Enc (sig1 (wrap_tau p))"
      and p1_eq: "p1 = W_Run q1'"
      and b1_eq: "b1 = (λp. Enc (sig1' (wrap_tau p)))"
      and d1_eq: "d1 = (λp. dd1 (wrap_tau p))"
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by auto
    from t2w W_Run obtain sig2 q2' sig2' dd2 where
      m2: "(qM, sig2, q2', sig2', dd2) ∈ delta_tm M"
      and sym2: "∀p. a p = Enc (sig2 (wrap_tau p))"
      and p2_eq: "p2 = W_Run q2'"
      and b2_eq: "b2 = (λp. Enc (sig2' (wrap_tau p)))"
      and d2_eq: "d2 = (λp. dd2 (wrap_tau p))"
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by auto
    have sigma_eq: "sig1 = sig2"
    proof (rule ext)
      fix x
      have e1: "a (wrap_tau x) = Enc (sig1 (wrap_tau (wrap_tau x)))"
        using sym1 by blast
      have e2: "a (wrap_tau x) = Enc (sig2 (wrap_tau (wrap_tau x)))"
        using sym2 by blast
      from e1 e2 have "sig1 (wrap_tau (wrap_tau x)) = sig2 (wrap_tau (wrap_tau x))"
        by simp
      thus "sig1 x = sig2 x" by (simp add: wrap_tau_invol)
    qed
    have M_det: "(q1', sig1', dd1) = (q2', sig2', dd2)"
      using m1 m2 sigma_eq detM[unfolded det_mttm_def] by blast
    hence q'_eq: "q1' = q2'" and sig'_eq: "sig1' = sig2'" and dd_eq: "dd1 = dd2"
      by simp_all
    show ?thesis
      using p1_eq p2_eq b1_eq b2_eq d1_eq d2_eq q'_eq sig'_eq dd_eq
      by metis
  next
    case W_Rej
    with t1w show ?thesis
      unfolding wrap_delta_def
                wrap_init_delta_gen_def wrap_buf_extend_delta_gen_def
                wrap_buf_close_delta_gen_def wrap_buf_empty_end_delta_gen_def
                wrap_buf_nonempty_end_delta_gen_def
                wrap_rewind_loop_delta_gen_def
                wrap_plant_done_delta_def
                wrap_disp_delta_gen_def wrap_run_delta_def
      by auto
  qed
qed

end