-
Notifications
You must be signed in to change notification settings - Fork 176
feat(MultiTapeTM): Some lemmas about Turing machine tapes #768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+234
−32
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
Cslib/Computability/Machines/Turing/MultiTape/TapeLemmas.lean
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| /- | ||
| Copyright (c) 2026 Christian Reitwiessner. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Christian Reitwiessner | ||
| -/ | ||
|
|
||
| module | ||
|
|
||
| public import Cslib.Computability.Machines.Turing.MultiTape.Deterministic | ||
|
|
||
| /-! | ||
| # Tape head visitation and space-usage lemmas | ||
|
|
||
| This file collects lemmas about the set of positions visited by a work-tape head | ||
| (`MultiTapeTM.visitedByTapeHead`) and the resulting space-usage measures | ||
| (`MultiTapeTM.spaceUsedByTape`, `MultiTapeTM.spaceUsed`) and how the tape head positions | ||
| influence the cells that are modified on a tape. | ||
|
|
||
| -/ | ||
|
|
||
| @[expose] public section | ||
|
|
||
| namespace Turing.MultiTapeTM | ||
|
|
||
| variable {k : ℕ} | ||
| variable {State Symbol : Type*} | ||
| variable {input : List Symbol} | ||
| variable {tm : MultiTapeTM k Symbol State} | ||
| variable {cfg : Cfg k Symbol State input} | ||
|
|
||
| /-- If the work tape head is not at position `z`, then the tape does not change there. -/ | ||
| lemma step_workTapes_eq_of_ne | ||
| (cfg : Cfg k Symbol State input) | ||
| (j : Fin k) | ||
| (z : ℤ) | ||
| (hz : z ≠ cfg.workTapePos j) : | ||
| (tm.step cfg).workTapes j z = cfg.workTapes j z := by | ||
| unfold step | ||
| cases hst : cfg.state with | ||
| | none => simp_all | ||
| | some q => | ||
| rcases hw : ((tm.tr q cfg.inputSymbol cfg.workTapeSymbols).workActions j).1 <;> simp_all | ||
|
|
||
| lemma mem_visitedByTapeHead {t : ℕ} {i : Fin k} {z : ℤ} : | ||
| z ∈ tm.visitedByTapeHead cfg t i ↔ ∃ t' < t + 1, (tm.configs cfg t').workTapePos i = z := by | ||
| simp [visitedByTapeHead] | ||
|
|
||
| lemma mem_visitedByTapeHead_self (cfg : Cfg k Symbol State input) (t : ℕ) (i : Fin k) : | ||
| (tm.configs cfg t).workTapePos i ∈ tm.visitedByTapeHead cfg t i := | ||
| tm.mem_visitedByTapeHead.mpr ⟨t, by omega, rfl⟩ | ||
|
|
||
| /-- The set of positions visited by a tape head is monotone in the number of steps. -/ | ||
| lemma visitedByTapeHead_mono (cfg : Cfg k Symbol State input) (i : Fin k) {t t' : ℕ} (h : t ≤ t') : | ||
| tm.visitedByTapeHead cfg t i ⊆ tm.visitedByTapeHead cfg t' i := by | ||
| apply Finset.image_subset_image | ||
| grind | ||
|
|
||
| /-- Starting from configuration `cfg`, every position between the initial head position of tape | ||
| `i` and the one after `t` steps is part of the "visited set" at step `t`. -/ | ||
| lemma uIcc_workTapePos_subset_visitedByTapeHead | ||
| (cfg : Cfg k Symbol State input) (i : Fin k) (t : ℕ) : | ||
| Finset.uIcc (cfg.workTapePos i) ((tm.configs cfg t).workTapePos i) | ||
| ⊆ tm.visitedByTapeHead cfg t i := by | ||
| induction t with | ||
| | zero => simpa [configs] using tm.mem_visitedByTapeHead_self cfg 0 i | ||
| | succ t ih => | ||
| intro z hz | ||
| have hstep : |(tm.configs cfg (t + 1)).workTapePos i - (tm.configs cfg t).workTapePos i| ≤ 1 := | ||
| configs_succ_eq_step' (tm := tm) ▸ tm.workTapePos_step_le _ i | ||
| have hmono := tm.visitedByTapeHead_mono cfg i (Nat.le_succ t) | ||
| have hself := tm.mem_visitedByTapeHead_self cfg (t + 1) i | ||
| grind [Finset.mem_uIcc] | ||
|
|
||
| /-- If a work tape cell is changed after `t` steps, it must have been visited by the tape head. -/ | ||
| lemma mem_visitedByTapeHead_of_workTapes_ne | ||
| (j : Fin k) | ||
| (t : ℕ) | ||
| (z : ℤ) | ||
| (h : (tm.configs cfg t).workTapes j z ≠ cfg.workTapes j z) : | ||
| z ∈ tm.visitedByTapeHead cfg t j := by | ||
| induction t with | ||
| | zero => exact absurd (by simp [configs]) h | ||
| | succ t ih => | ||
| rw [configs_succ_eq_step'] at h | ||
| by_cases hz : z = (tm.configs cfg t).workTapePos j | ||
| · exact hz ▸ tm.visitedByTapeHead_mono cfg j (Nat.le_succ t) | ||
| (tm.mem_visitedByTapeHead_self cfg t j) | ||
| · rw [tm.step_workTapes_eq_of_ne _ j z hz] at h | ||
| exact tm.visitedByTapeHead_mono cfg j (Nat.le_succ t) (ih h) | ||
|
|
||
| /-- Every position visited by the head of tape `i` lies within `spaceUsedByTape … i` of the | ||
| head's starting position. -/ | ||
| lemma natAbs_le_spaceUsedByTape_of_mem_visited | ||
| {i : Fin k} | ||
| {z : ℤ} | ||
| {t : ℕ} | ||
| (hz : z ∈ tm.visitedByTapeHead cfg t i) : | ||
| (z - cfg.workTapePos i).natAbs ≤ tm.spaceUsedByTape cfg t i := by | ||
| obtain ⟨t', ht', rfl⟩ := tm.mem_visitedByTapeHead.mp hz | ||
| have h1 := Finset.card_le_card | ||
| ((tm.uIcc_workTapePos_subset_visitedByTapeHead cfg i t').trans | ||
| (tm.visitedByTapeHead_mono cfg i (show t' ≤ t by omega))) | ||
| rw [Int.card_uIcc] at h1 | ||
| unfold spaceUsedByTape | ||
| omega | ||
|
|
||
| /-- Every non-blank cell on work tape `i` lies within `spaceUsedByTape … i t` of the origin. -/ | ||
| lemma content_natAbs_le_spaceUsedByTape | ||
| {i : Fin k} | ||
| (t : ℕ) | ||
| (z : ℤ) | ||
| (h : (tm.configs (tm.initCfg input) t).workTapes i z ≠ none) : | ||
| z.natAbs ≤ tm.spaceUsedByTape (tm.initCfg input) t i := by | ||
| -- The work tapes start out blank, so any non-blank cell has been visited by the head; the | ||
| -- initial head position is `0`, so the displacement bound is a bound on the position itself. | ||
| simpa using tm.natAbs_le_spaceUsedByTape_of_mem_visited | ||
| (tm.mem_visitedByTapeHead_of_workTapes_ne i t z h) | ||
|
|
||
| /-- The number of cells touched by a single work tape grows by at most one each step. -/ | ||
| lemma spaceUsedByTape_le (cfg : Cfg k Symbol State input) (t : ℕ) (i : Fin k) : | ||
| tm.spaceUsedByTape cfg t i ≤ t + 1 := by | ||
| calc | ||
| tm.spaceUsedByTape cfg t i | ||
| _ ≤ (Finset.range (t + 1)).card := Finset.card_image_le | ||
| _ = t + 1 := Finset.card_range _ | ||
|
|
||
| /-- The space used by a computation is bounded linearly by the number of steps. -/ | ||
| lemma spaceUsed_linear (cfg : Cfg k Symbol State input) (t : ℕ) : | ||
| tm.spaceUsed cfg t ≤ k * t + k := by | ||
| calc tm.spaceUsed cfg t | ||
| = ∑ i, (tm.spaceUsedByTape cfg t i) := by rfl | ||
| _ ≤ ∑ i, (t + 1) := Finset.sum_le_sum (fun i _ => tm.spaceUsedByTape_le cfg t i) | ||
| _ = k * t + k := by simp [Nat.mul_succ] | ||
|
|
||
| /-- The space used by a single tape is monotone in the number of steps. -/ | ||
| lemma spaceUsedByTape_mono | ||
| (tm : MultiTapeTM k Symbol State) | ||
| (cfg : Cfg k Symbol State input) | ||
| (i : Fin k) : | ||
| Monotone (tm.spaceUsedByTape cfg · i) := by | ||
| intro t t' h | ||
| exact Finset.card_le_card (tm.visitedByTapeHead_mono cfg i h) | ||
|
|
||
| /-- The total space used is monotone in the number of steps. -/ | ||
| lemma spaceUsed_mono (tm : MultiTapeTM k Symbol State) (cfg : Cfg k Symbol State input) : | ||
| Monotone (tm.spaceUsed cfg ·) := by | ||
| intro t t' h | ||
| exact Finset.sum_le_sum (fun i _ => spaceUsedByTape_mono tm cfg i h) | ||
|
|
||
| end Turing.MultiTapeTM |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially, I thought proofs should always first turn
configsintostep^[n]and then use theFunction.iterate_*lemmas, but I think it's better to not unfoldconfigsand add these lemmas here instead.