Research source · Plain text
RejectingSink.lean
formalizations/frontier-derivative/FrontierDerivative/RejectingSink.lean
282 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 86448d52e7780f8053b8ed1fe5153489866976343c5a433bd281309056516591
import FrontierDerivative.FrontierAllocator
/-!
# Pruning an absorbing rejecting sink from a total visible machine
The conventional total visible-machine presentation may send failed tagged
commands into a permanent rejecting sink. This module relates that presentation
to the successful partial frontier used by FPRD-T102.
-/
namespace FrontierDerivative
open VisibleAction
variable {Input Q Γ : Type}
/-- A designated nonaccepting control that no visible action can leave. -/
structure RejectingSink (V : VisibleMachine Input Q Γ) where
sink : Q
accept_sink : V.accept sink = false
call_sink : ∀ a, (V.call sink a).1 = sink
ret_sink : ∀ a top, V.ret sink a top = sink
local_sink : ∀ a, V.localStep sink a = sink
namespace RejectingSink
/-! ## Total tagged execution -/
/-- Execute one total visible action on a concrete visible configuration. -/
def totalApply (V : VisibleMachine Input Q Γ) (a : Input)
(action : VisibleAction) (c : PartialVisible.Config Q Γ) :
PartialVisible.Config Q Γ :=
match action with
| .call =>
let next := V.call c.ctrl a
⟨next.1, next.2 :: c.stack⟩
| .ret => ⟨V.ret c.ctrl a c.stack.head?, c.stack.drop 1⟩
| .local => ⟨V.localStep c.ctrl a, c.stack⟩
/-- Total tagged execution from an arbitrary visible configuration. -/
def totalRunFrom (V : VisibleMachine Input Q Γ)
(c : PartialVisible.Config Q Γ)
(tagged : List (Input × VisibleAction)) : PartialVisible.Config Q Γ :=
tagged.foldl (fun c t => totalApply V t.1 t.2 c) c
/-- Total tagged execution from the blank initial visible configuration. -/
def totalRun (V : VisibleMachine Input Q Γ)
(tagged : List (Input × VisibleAction)) : PartialVisible.Config Q Γ :=
totalRunFrom V ⟨V.init, []⟩ tagged
theorem totalRunFrom_append (V : VisibleMachine Input Q Γ)
(c : PartialVisible.Config Q Γ)
(u v : List (Input × VisibleAction)) :
totalRunFrom V c (u ++ v) =
totalRunFrom V (totalRunFrom V c u) v := by
simp [totalRunFrom, List.foldl_append]
theorem totalRun_append (V : VisibleMachine Input Q Γ)
(tagged : List (Input × VisibleAction)) (a : Input)
(action : VisibleAction) :
totalRun V (tagged ++ [(a, action)]) =
totalApply V a action (totalRun V tagged) := by
simp [totalRun, totalRunFrom, List.foldl_append]
/-! ## Equality with the existing one-stack evaluator -/
/-- Forget the singleton stack index in the existing strict stack evaluator. -/
def stackProjection (c : FPRD.Config Q Γ 1) : PartialVisible.Config Q Γ :=
⟨c.ctrl, c.stacks 0⟩
/-- One existing tagged stack-machine step is exactly one total visible step. -/
theorem stackProjection_step (V : VisibleMachine Input Q Γ)
(c : FPRD.Config Q Γ 1) (a : Input) (action : VisibleAction) :
stackProjection (V.stackMachine.stepConfig c (a, action)) =
totalApply V a action (stackProjection c) := by
cases action <;>
simp [stackProjection, VisibleMachine.stackMachine,
FPRD.StackMachine.stepConfig, FPRD.StackOp.apply, totalApply]
theorem stackProjection_runFrom (V : VisibleMachine Input Q Γ)
(c : FPRD.Config Q Γ 1)
(tagged : List (Input × VisibleAction)) :
stackProjection (tagged.foldl V.stackMachine.stepConfig c) =
totalRunFrom V (stackProjection c) tagged := by
induction tagged generalizing c with
| nil => rfl
| cons t tagged ih =>
simp only [List.foldl_cons]
rw [ih, stackProjection_step]
rfl
/-- The existing total tagged machine and the direct visible evaluator have
exactly the same final control and stack for every tagged word. -/
theorem stackProjection_run (V : VisibleMachine Input Q Γ)
(tagged : List (Input × VisibleAction)) :
stackProjection (V.stackMachine.run tagged) = totalRun V tagged := by
change stackProjection
(tagged.foldl V.stackMachine.stepConfig V.stackMachine.initConfig) = _
rw [stackProjection_runFrom]
rfl
/-- The existing tagged-machine Boolean readout is exactly the direct total
visible readout. -/
theorem stackMachine_decides_eq_total (V : VisibleMachine Input Q Γ)
(tagged : List (Input × VisibleAction)) :
V.stackMachine.decides tagged = V.accept (totalRun V tagged).ctrl := by
change V.accept (V.stackMachine.run tagged).ctrl = _
have h := congrArg PartialVisible.Config.ctrl (stackProjection_run V tagged)
change (V.stackMachine.run tagged).ctrl = (totalRun V tagged).ctrl at h
rw [h]
/-! ## Pruning commands that enter the rejecting sink -/
/-- Discard exactly the commands whose total target control is the sink. -/
def prune [DecidableEq Q] {V : VisibleMachine Input Q Γ}
(H : RejectingSink V) : PartialVisible.Machine Input Q Γ where
call := fun q a =>
let next := V.call q a
if next.1 = H.sink then none else some next
ret := fun q a top =>
let next := V.ret q a top
if next = H.sink then none else some next
localStep := fun q a =>
let next := V.localStep q a
if next = H.sink then none else some next
init := V.init
accept := V.accept
/-- A total step whose target is not the sink is retained exactly. -/
theorem prune_apply_of_total_nonSink [DecidableEq Q]
{V : VisibleMachine Input Q Γ} (H : RejectingSink V)
(a : Input) (action : VisibleAction) (c : PartialVisible.Config Q Γ)
(h : (totalApply V a action c).ctrl ≠ H.sink) :
H.prune.apply a action c = some (totalApply V a action c) := by
cases action <;>
simp [prune, PartialVisible.Machine.apply, totalApply] at h ⊢ <;>
exact h
/-- Every successful pruned step is exactly its underlying total step. -/
theorem totalApply_of_prune_apply [DecidableEq Q]
{V : VisibleMachine Input Q Γ} (H : RejectingSink V)
(a : Input) (action : VisibleAction) (c c' : PartialVisible.Config Q Γ)
(h : H.prune.apply a action c = some c') :
totalApply V a action c = c' := by
cases action
· simp [prune, PartialVisible.Machine.apply] at h
rcases h with ⟨q', b, ⟨_, hnext⟩, hconfig⟩
simp [totalApply, hnext]
exact hconfig
· simp [prune, PartialVisible.Machine.apply] at h
rcases h with ⟨q', ⟨_, hnext⟩, hconfig⟩
simp [totalApply, hnext]
exact hconfig
· simp [prune, PartialVisible.Machine.apply] at h
rcases h with ⟨q', ⟨_, hnext⟩, hconfig⟩
simp [totalApply, hnext]
exact hconfig
/-- Once the total run is in the sink, every next control is still the sink.
The stack may nevertheless change. -/
theorem totalApply_of_sink {V : VisibleMachine Input Q Γ}
(H : RejectingSink V) (c : PartialVisible.Config Q Γ)
(hc : c.ctrl = H.sink) (a : Input) (action : VisibleAction) :
(totalApply V a action c).ctrl = H.sink := by
rcases c with ⟨q, z⟩
change q = H.sink at hc
subst q
cases action <;>
simp [totalApply, H.call_sink, H.ret_sink, H.local_sink]
/-- A final control with true readout cannot be the rejecting sink. -/
theorem accept_true_ne_sink {V : VisibleMachine Input Q Γ}
(H : RejectingSink V) {q : Q} (h : V.accept q = true) :
q ≠ H.sink := by
intro hq
subst q
rw [H.accept_sink] at h
contradiction
/-! ## Two-directional successful-run transfer -/
/-- Every successful pruned derivation is an exact total tagged run on an
explicit same-length annotation. -/
theorem prunedTagged_to_total [DecidableEq Q]
{V : VisibleMachine Input Q Γ} (H : RejectingSink V)
{w : List Input} {c : PartialVisible.Config Q Γ}
(h : H.prune.TaggedReachable w c) :
∃ tagged : List (Input × VisibleAction),
tagged.map Prod.fst = w ∧ totalRun V tagged = c := by
induction h with
| init => exact ⟨[], rfl, rfl⟩
| step a action hprev happly ih =>
rcases ih with ⟨tagged, hinputs, hrun⟩
refine ⟨tagged ++ [(a, action)], ?_, ?_⟩
· simp [hinputs]
· rw [totalRun_append, hrun]
exact H.totalApply_of_prune_apply a action _ _ happly
/-- A total tagged run that ends outside the absorbing sink never entered the
sink and therefore has an exact successful pruned derivation. -/
theorem totalNonSink_to_prunedTagged [DecidableEq Q]
{V : VisibleMachine Input Q Γ} (H : RejectingSink V)
(tagged : List (Input × VisibleAction))
(hfinal : (totalRun V tagged).ctrl ≠ H.sink) :
H.prune.TaggedReachable (tagged.map Prod.fst) (totalRun V tagged) := by
have hall : ∀ tagged : List (Input × VisibleAction),
(totalRun V tagged).ctrl ≠ H.sink →
H.prune.TaggedReachable (tagged.map Prod.fst) (totalRun V tagged) := by
apply PartialVisible.list_snoc_induction
· intro _
exact PartialVisible.Machine.TaggedReachable.init
· intro u taggedAction ih hnext
rcases taggedAction with ⟨a, action⟩
have hprevious : (totalRun V u).ctrl ≠ H.sink := by
intro hsink
apply hnext
rw [totalRun_append]
exact H.totalApply_of_sink (totalRun V u) hsink a action
have htarget :
(totalApply V a action (totalRun V u)).ctrl ≠ H.sink := by
simpa [totalRun_append] using hnext
have hreach := ih hprevious
have happly :=
H.prune_apply_of_total_nonSink a action (totalRun V u) htarget
have hstep := PartialVisible.Machine.TaggedReachable.step
a action hreach happly
simpa [List.map_append, totalRun_append] using hstep
exact hall tagged hfinal
/-! ## Projected-language equality and allocator composition -/
/-- Removing the absorbing nonaccepting sink preserves exactly the
forgotten-action language, including at epsilon. -/
theorem projectAccepts_iff_pruned [DecidableEq Q]
{V : VisibleMachine Input Q Γ} (H : RejectingSink V)
(w : List Input) :
ResolverCover.ProjectAccepts V w ↔ H.prune.Accepts w := by
constructor
· rintro ⟨tagged, hinputs, haccept⟩
rw [stackMachine_decides_eq_total] at haccept
have hreach := H.totalNonSink_to_prunedTagged tagged
(H.accept_true_ne_sink haccept)
rw [hinputs] at hreach
apply (H.prune.accepts_iff_tagged w).2
exact ⟨totalRun V tagged, hreach, haccept⟩
· intro hpruned
have htagged := (H.prune.accepts_iff_tagged w).1 hpruned
rcases htagged with ⟨c, hreach, haccept⟩
rcases H.prunedTagged_to_total hreach with
⟨tagged, hinputs, hrun⟩
refine ⟨tagged, hinputs, ?_⟩
rw [stackMachine_decides_eq_total, hrun]
exact haccept
/-- Any stationary allocator for the pruned successful frontier decides the
original total projection after the existing T101 compilation. -/
theorem compiled_allocator_decides_total_projection [DecidableEq Q]
{V : VisibleMachine Input Q Γ} (H : RejectingSink V)
{Ctrl : Type} {s : Nat}
{E : RootSharingMachine.Machine Input Ctrl Γ s}
(K : FrontierAllocator.Allocator H.prune E) (w : List Input) :
(RootSharingMachine.compile E).decides w = true ↔
ResolverCover.ProjectAccepts V w := by
rw [K.compiled_decides_projected]
exact (H.projectAccepts_iff_pruned w).symm
#check totalRun_append
#check stackProjection_step
#check stackProjection_run
#check stackMachine_decides_eq_total
#check prune_apply_of_total_nonSink
#check totalApply_of_prune_apply
#check totalApply_of_sink
#check accept_true_ne_sink
#check prunedTagged_to_total
#check totalNonSink_to_prunedTagged
#check projectAccepts_iff_pruned
#check compiled_allocator_decides_total_projection
end RejectingSink
end FrontierDerivative