Skip to content

feat(Computability/MultiTapeTM): input/output tape predicates#162

Open
SamuelSchlesinger wants to merge 2 commits into
crei:multi-tape-tmfrom
SamuelSchlesinger:multi-tape-tm
Open

feat(Computability/MultiTapeTM): input/output tape predicates#162
SamuelSchlesinger wants to merge 2 commits into
crei:multi-tape-tmfrom
SamuelSchlesinger:multi-tape-tm

Conversation

@SamuelSchlesinger
Copy link
Copy Markdown

The stuff we talked about in Discord.

Comment thread Cslib/Foundations/Data/StackTape.lean Outdated
Comment thread Cslib/Computability/Machines/MultiTapeTuring/Basic.lean Outdated
Comment thread Cslib/Foundations/Data/BiTape/Canonical.lean Outdated
-/
def canonicalInputTape (s : List Symbol) (p : ℤ) : BiTape Symbol :=
if 0 ≤ p then canonicalInputTapeNat s p.toNat
else ⟨none, ∅, StackTape.map_some s⟩
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit surprising to me that this cuts off for negative numbers but not for positive numbers beyond the input length. is that intended, or should this be the equivalent of move_int (mk₁ s) p?

Comment thread Cslib/Foundations/Data/BiTape/Canonical.lean Outdated
further in direction `d` without returning first. The condition is finitary — both the
reachability relation and the existential in `MovesOffBlankInDir` range over finite types.
-/
def IsBoundedInDirectionOnTape
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all assumes that we do not write on the first tape. Do you think this could be more self-contained by adding this to MoveThenStays?

in `t` steps has its tape-`0` content in canonical shape `canonicalInputTape s p` for some
integer position `p ∈ [-1, s.length]`. In particular, the head on tape `0` stays within
one cell of the input region throughout the trace. -/
theorem HasInputTape.head_position_bounded
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't read through the full file, but I think I understood that this machinery starts with the initial configuration. I try to avoid tm.initCfg because it makes a lot of assumptions that makes the theorems that use it unusable for composition (all tapes except the first are empty, for example). If instead, we just assume "we start with a configuration where the head is inside the input", the theorem could be directly applied in a proof for tm composition.

…position bound

Adds read-only input and write-only output tape abstractions for
multi-tape Turing machines, plus a proof that the input-tape head
position stays within [-1, |input|] across reachable configurations.

- StackTape/BiTape: migrated `*_nil` lemmas into BiTape, extended
  StackTape API used by the new invariants.
- MultiTapeTM.HasInputTape / HasOutputTape: predicates characterising
  read-only input and write-only output tapes.
- HeadBoundInvariantAt: Prop-valued structure carrying the
  position bound, canonical-tape equality, and left/right reachability
  chains; .initCfg and .step lemmas prove inductivity.
- HasInputTape.step_tape0_decompose: factors a step through its
  predecessor state, eliminating `change`-tactic gymnastics in
  invariant-preservation proofs.
- head_position_bounded: quantitative head-position bound derived from
  the invariant via iter_step.
For machines with designated input and output tapes:

* `MultiTapeTM.HasInputTape`: tape `0` is write-preserving, with a syntactic head-bound
condition that rules out two consecutive same-direction off-end moves
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add: In other words, the machine will not modify the input tape contents and the head will move at most one cell outside the written area. (not 100% happy with the wording)

* `MultiTapeTM.HasInputTape`: tape `0` is write-preserving, with a syntactic head-bound
condition that rules out two consecutive same-direction off-end moves
* `MultiTapeTM.HasOutputTape`: in a machine with at least two tapes, the last tape is write-only
(`Stmt.IsWriteOnly` on every transition)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add: , i.e. after each write, the head moves one cell to the right and does not move otherwise.


end MultiTapeTM

/-!
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should all move to a different file?

t.move_int 0 = t := by
simp [move_int]

@[simp]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I would make this a simp. I think it's more useful to have simp lemmas that combine compositions:
((t.move_int -1).move_int x).move_int 1 = t.move_int (-1 + x + 1)

On the other hand, maybe transforming everything into the function-view first would be best, then move_right etc is not useful anyway.

rw [← Equiv.Perm.mul_apply, ← zpow_add, add_comm]

@[simp]
lemma move_int_nil (delta : ℤ) : (nil : BiTape Symbol).move_int delta = nil := by
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be more easily proven by turning nil into its function view. Although I realize we don't have that here yet....

/--
A predicate preserved by every step of `r` is preserved along any chain of `r`-steps.
-/
lemma RelatesInSteps.invariant {a b : α} {n : ℕ} {P : α → Prop}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming: Maybe mention the word "transitivity"?

For `n < s.length`, the head reads `some s[n]`; for `n ≥ s.length`, the head reads
`none`.
-/
def canonicalInputTapeNat (s : List Symbol) (n : ℕ) : BiTape Symbol :=
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with move_int, all of the definitions here are redundant. I think it would be better to directly work with (BiTape.mk₁ s).move_int n instead.

dictated by `tm.tr q`. The intermediate `tm.step ⟨some q, cfg.tapes⟩ = some cfg'` form is
handy for feeding `MoveThenStaysOnBlank.move`, whose constructor destructures `cfg`.
-/
lemma HasInputTape.step_tape0_decompose
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this lemma and probably some others in this file are overly complicated.

remains empty. Use `HasOutputTape.relatesInSteps_outputTapeContents` when the stronger
canonical output shape is needed.
-/
lemma HasOutputTape.relatesInSteps_right_empty
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found it easier to work with tm.configs instead of RelatesInSteps - on the other hand, tm.configs only works for deterministic machines...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants