Research source · Plain text

ActionWindowEscapeExamples.lean

formalizations/frontier-derivative/FrontierDerivative/ActionWindowEscapeExamples.lean

175 lines. Source is displayed for inspection; it is not executed by this page.

File fingerprint

SHA-256: c44bd0862904f7cc421c0b9e9fc3b0364e10baeda66ba7555119ae059433b7d9

import FrontierDerivative.BoundedActionWindow

/-!
# Every fixed action window can fail on a regular projection

One one-state partial visible machine accepts every unary input through its
local action.  For each fixed window depth `k`, the same observed word also
has two successful traces: an initial call followed by `k` local actions, and
`k + 1` local actions.  The traces finish in the same control with different
stacks, while their newest-first depth-`k` action windows agree.

This separates the bounded-action-window coordinate doctrine from language
recognition.  It is not a PEG or scaffold lower bound.
-/

namespace FrontierDerivative.ActionWindowEscapeExamples

open BoundedActionWindow

/-- A unary, one-control visible source. Calls push `7`, locals preserve the
stack, returns fail, and the only control is accepting. -/
def universalProjection : PartialVisible.Machine Unit Unit Nat where
  call := fun _ _ => some ((), 7)
  ret := fun _ _ _ => none
  localStep := fun _ _ => some ()
  init := ()
  accept := fun _ => true

/-- A chronological suffix of `k` local actions. -/
def localActions : Nat → List VisibleAction
  | 0 => []
  | k + 1 => localActions k ++ [.local]

@[simp] theorem localActions_length (k : Nat) : (localActions k).length = k := by
  induction k with
  | zero => rfl
  | succ k ih => simp [localActions, ih]

/-- A unary suffix of `k` observed letters. -/
def unitLetters : Nat → List Unit
  | 0 => []
  | k + 1 => unitLetters k ++ [()]

/-- The shared observed word used by the depth-`k` collision. -/
def collisionWord (k : Nat) : List Unit := [()] ++ unitLetters k

/-- A traced run is also an ordinary successful tagged run when its explicit
action list is forgotten. -/
theorem traced_to_tagged {Input Q Γ : Type}
    {V : PartialVisible.Machine Input Q Γ}
    {w : List Input} {actions : List VisibleAction}
    {c : PartialVisible.Config Q Γ}
    (h : TracedReachable V w actions c) :
    V.TaggedReachable w c := by
  induction h with
  | init => exact PartialVisible.Machine.TaggedReachable.init
  | step a action _ happly ih =>
      exact PartialVisible.Machine.TaggedReachable.step a action ih happly

/-- Appending `k` local rounds preserves the current stack exactly. -/
theorem append_local_trace {w : List Unit} {actions : List VisibleAction}
    {stack : List Nat}
    (h : TracedReachable universalProjection w actions ⟨(), stack⟩) :
    ∀ k,
      TracedReachable universalProjection
        (w ++ unitLetters k) (actions ++ localActions k) ⟨(), stack⟩ := by
  intro k
  induction k with
  | zero => simpa [unitLetters, localActions] using h
  | succ k ih =>
      have hstep := TracedReachable.step () .local ih (by rfl)
      simpa [unitLetters, localActions, List.append_assoc] using hstep

theorem first_call_trace :
    TracedReachable universalProjection [()] [.call] ⟨(), [7]⟩ :=
  TracedReachable.step () .call TracedReachable.init (by rfl)

theorem first_local_trace :
    TracedReachable universalProjection [()] [.local] ⟨(), []⟩ :=
  TracedReachable.step () .local TracedReachable.init (by rfl)

/-- The first collision trace calls once, then remains local for `k` rounds. -/
theorem call_then_locals_trace (k : Nat) :
    TracedReachable universalProjection (collisionWord k)
      ([.call] ++ localActions k) ⟨(), [7]⟩ := by
  exact append_local_trace first_call_trace k

/-- The second collision trace remains local in all `k + 1` rounds. -/
theorem all_locals_trace (k : Nat) :
    TracedReachable universalProjection (collisionWord k)
      ([.local] ++ localActions k) ⟨(), []⟩ := by
  exact append_local_trace first_local_trace k

/-- `windowOf` is the reversed chronological suffix of length at most `k`. -/
theorem windowOf_value (k : Nat) (actions : List VisibleAction) :
    (windowOf k actions).1 = actions.reverse.take k := by
  exact PartialVisible.list_snoc_induction
    (motive := fun xs =>
      (windowOf k xs).1 = xs.reverse.take k)
    (by simp [windowOf, emptyWindow])
    (by
      intro xs action ih
      rw [windowOf_append]
      change (action :: (windowOf k xs).1).take k =
        (xs ++ [action]).reverse.take k
      rw [ih]
      simp only [List.reverse_append, List.reverse_singleton,
        List.singleton_append]
      cases k with
      | zero => rfl
      | succ k =>
          simp only [List.take_succ_cons, List.take_take,
            Nat.min_eq_left (Nat.le_succ k)])
    actions

/-- The differing first action lies exactly beyond the retained depth. -/
theorem collision_windows_equal (k : Nat) :
    windowOf k ([.call] ++ localActions k) =
      windowOf k ([.local] ++ localActions k) := by
  apply Subtype.ext
  rw [windowOf_value, windowOf_value]
  simp only [List.singleton_append, List.reverse_cons]
  have hlength : k ≤ (localActions k).reverse.length := by
    simp
  rw [List.take_append_of_le_length hlength,
    List.take_append_of_le_length hlength]

theorem call_stack_in_windowFrontier (k : Nat) :
    WindowFrontier universalProjection k (collisionWord k)
      (windowOf k ([.call] ++ localActions k)) () [7] :=
  ⟨[.call] ++ localActions k, call_then_locals_trace k, rfl⟩

theorem empty_stack_in_windowFrontier (k : Nat) :
    WindowFrontier universalProjection k (collisionWord k)
      (windowOf k ([.call] ++ localActions k)) () [] :=
  ⟨[.local] ++ localActions k, all_locals_trace k,
    (collision_windows_equal k).symm⟩

/-- No fixed suffix of hidden actions separates the concrete frontier. -/
theorem universal_not_windowSeparated (k : Nat) :
    ¬WindowSeparated universalProjection k := by
  intro hsep
  have hstack : ([7] : List Nat) = [] :=
    hsep (collisionWord k) (windowOf k ([.call] ++ localActions k)) ()
      [7] [] (call_stack_in_windowFrontier k)
      (empty_stack_in_windowFrontier k)
  simp at hstack

/-- Every observed word is accepted through its all-local trace, including
the empty word. -/
theorem universal_accepts (w : List Unit) : universalProjection.Accepts w := by
  have htrace : ∃ actions,
      TracedReachable universalProjection w actions ⟨(), []⟩ := by
    exact PartialVisible.list_snoc_induction
      (motive := fun xs => ∃ actions,
        TracedReachable universalProjection xs actions ⟨(), []⟩)
      ⟨[], TracedReachable.init⟩
      (by
        intro xs letter h
        rcases letter with ⟨⟩
        rcases h with ⟨actions, htrace⟩
        exact ⟨actions ++ [.local],
          TracedReachable.step () .local htrace (by rfl)⟩)
      w
  rcases htrace with ⟨actions, htrace⟩
  exact ⟨(), [], PartialVisible.Machine.tagged_to_frontier
    universalProjection (traced_to_tagged htrace), rfl⟩

#check universal_accepts
#check call_then_locals_trace
#check all_locals_trace
#check collision_windows_equal
#check universal_not_windowSeparated

end FrontierDerivative.ActionWindowEscapeExamples