Skip to content

feat(MultitapeTM): Prove an exponential upper bound in the number of configurations reachable in bounded space - #772

Open
crei wants to merge 7 commits into
leanprover:mainfrom
crei:configs_reachable_in_bounded_space
Open

feat(MultitapeTM): Prove an exponential upper bound in the number of configurations reachable in bounded space#772
crei wants to merge 7 commits into
leanprover:mainfrom
crei:configs_reachable_in_bounded_space

Conversation

@crei

@crei crei commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Proves an upper bound on the number of configurations reachable in bounded space on a multi-tape TM.

The proof introduces the concept of Storage, the projection of Cfg that only contain the state and the work tapes. It shows that if the TM uses at most s space, there is an injection to a structure that only uses [-s, s] to index the tape.

@crei

crei commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

#819 should be merged first, I'll update this one in a minute.

@crei
crei marked this pull request as draft August 27, 2026 10:28
@crei
crei marked this pull request as ready for review August 29, 2026 09:56
@crei

crei commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator Author

This is now updated to the new definition of Cfg. I kept most of it so that it also applies to nondeterministic machines, so once that is merged, it should be easy to adapt.

Comment on lines +148 to +154
lemma Storage.FitsIn_mono {x : UnboundedStorage Symbol State k} : Monotone x.FitsIn := by
intro w₁ w₂ h_le h_fits
refine ⟨?_, ?_⟩
· intro j
grind [h_fits.pos_le j, h_le j]
· intro j z h_ne
grind [h_fits.cell_le j z h_ne, h_le j]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
lemma Storage.FitsIn_mono {x : UnboundedStorage Symbol State k} : Monotone x.FitsIn := by
intro w₁ w₂ h_le h_fits
refine ⟨?_, ?_⟩
· intro j
grind [h_fits.pos_le j, h_le j]
· intro j z h_ne
grind [h_fits.cell_le j z h_ne, h_le j]
lemma Storage.FitsIn_mono {x : UnboundedStorage Symbol State k} : Monotone x.FitsIn :=
fun _ _ hle h => ⟨fun j => (h.pos_le j).trans (hle j),
fun j z hz => (h.cell_le j z hz).trans (hle j)⟩

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I mean this is shorter, but not sure it is better. I replaced grind by your explicit proofs, though, so one sees that nothing "fancy" is going on.

Comment on lines +169 to +176
rintro x ⟨hxp, hxc⟩ y ⟨hyp, hyc⟩ hxy
simp only [Storage.toBounded, Storage.mk.injEq] at hxy
obtain ⟨hstate, htapes, hpos⟩ := hxy
refine Storage.ext hstate (funext₂ fun j z => ?_) (funext fun j => ?_)
· by_cases hz : z ∈ window (w j)
· exact congrFun (congrFun htapes j) ⟨z, hz⟩
· grind
· grind [congrFun hpos j]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
rintro x ⟨hxp, hxc⟩ y ⟨hyp, hyc⟩ hxy
simp only [Storage.toBounded, Storage.mk.injEq] at hxy
obtain ⟨hstate, htapes, hpos⟩ := hxy
refine Storage.ext hstate (funext₂ fun j z => ?_) (funext fun j => ?_)
· by_cases hz : z ∈ window (w j)
· exact congrFun (congrFun htapes j) ⟨z, hz⟩
· grind
· grind [congrFun hpos j]
rintro x hx y hy hxy
simp only [Storage.toBounded, Storage.mk.injEq, funext_iff, Subtype.forall,
Storage.mem_window] at hxy
ext j z j' <;> grind [hx.pos_le, hx.cell_le, hy.pos_le, hy.cell_le]

Comment on lines +227 to +235
calc {x : UnboundedStorage Symbol State k | x.FitsIn w}.encard
= ((Storage.toBounded · w) '' {x | x.FitsIn w}).encard :=
((Storage.toBounded_injOn w).encard_image).symm
_ ≤ (Set.univ : Set (BoundedStorage Symbol State w)).encard :=
Set.encard_le_encard (Set.subset_univ _)
_ = Fintype.card (BoundedStorage Symbol State w) := by
simp [Set.encard_univ, ENat.card_eq_coe_fintype_card]
_ ≤ storageBound Symbol State k s := by
exact_mod_cast card_boundedStorage_le hsum

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
calc {x : UnboundedStorage Symbol State k | x.FitsIn w}.encard
= ((Storage.toBounded · w) '' {x | x.FitsIn w}).encard :=
((Storage.toBounded_injOn w).encard_image).symm
_ ≤ (Set.univ : Set (BoundedStorage Symbol State w)).encard :=
Set.encard_le_encard (Set.subset_univ _)
_ = Fintype.card (BoundedStorage Symbol State w) := by
simp [Set.encard_univ, ENat.card_eq_coe_fintype_card]
_ ≤ storageBound Symbol State k s := by
exact_mod_cast card_boundedStorage_le hsum
rw [← (Storage.toBounded_injOn w).encard_image]
refine Set.encard_le_card.trans ?_
rw [ENat.card_eq_coe_fintype_card]
exact_mod_cast card_boundedStorage_le hsum

Comment on lines +316 to +321
refine ⟨?_, ?_⟩
· intro j
simpa [Cfg.storage] using tm.natAbs_le_spaceUsedByTape_of_mem_visited
(tm.mem_visitedByTapeHead_self (tm.initCfg input) t j)
· intro j
exact content_natAbs_le_spaceUsedByTape t

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
refine ⟨?_, ?_⟩
· intro j
simpa [Cfg.storage] using tm.natAbs_le_spaceUsedByTape_of_mem_visited
(tm.mem_visitedByTapeHead_self (tm.initCfg input) t j)
· intro j
exact content_natAbs_le_spaceUsedByTape t
refine ⟨fun j => ?_, fun j => content_natAbs_le_spaceUsedByTape t⟩
simpa [Cfg.storage] using tm.natAbs_le_spaceUsedByTape_of_mem_visited
(tm.mem_visitedByTapeHead_self (tm.initCfg input) t j)

Comment on lines +344 to +346
refine Set.encard_le_encard ?_
rintro _ ⟨t, rfl⟩
exact ⟨Set.mem_univ _, t, rfl⟩

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
refine Set.encard_le_encard ?_
rintro _ ⟨t, rfl⟩
exact ⟨Set.mem_univ _, t, rfl⟩
exact Set.encard_le_encard (Set.range_subset_iff.2 fun t => ⟨Set.mem_univ _, t, rfl⟩)

Comment on lines +373 to +380
have : Fintype Symbol := Fintype.ofFinite Symbol
have : Fintype State := Fintype.ofFinite State
obtain ⟨a, c, hpow⟩ := storageBound_le_pow (Symbol := Symbol) (State := State) (k := k)
refine ⟨a, c, fun input s hs => (tm.encard_cores_le hs).trans ?_⟩
calc ((input.length + 2) * storageBound Symbol State k s : ℕ∞)
≤ ((input.length + 2) * (a * 2 ^ (c * s)) : ℕ) := by
exact_mod_cast Nat.mul_le_mul_left _ (hpow s)
_ = (input.length + 2) * a * 2 ^ (c * s) := by push_cast; ring

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
have : Fintype Symbol := Fintype.ofFinite Symbol
have : Fintype State := Fintype.ofFinite State
obtain ⟨a, c, hpow⟩ := storageBound_le_pow (Symbol := Symbol) (State := State) (k := k)
refine ⟨a, c, fun input s hs => (tm.encard_cores_le hs).trans ?_⟩
calc ((input.length + 2) * storageBound Symbol State k s : ℕ∞)
≤ ((input.length + 2) * (a * 2 ^ (c * s)) : ℕ) := by
exact_mod_cast Nat.mul_le_mul_left _ (hpow s)
_ = (input.length + 2) * a * 2 ^ (c * s) := by push_cast; ring
cases nonempty_fintype Symbol
cases nonempty_fintype State
obtain ⟨a, c, hpow⟩ := storageBound_le_pow (Symbol := Symbol) (State := State) (k := k)
refine ⟨a, c, fun input s hs => (tm.encard_cores_le hs).trans ?_⟩
rw [mul_assoc]
gcongr
exact_mod_cast hpow s

Comment on lines +167 to +174
have hmono : ∀ j, tm.spaceUsedByTape cfg T j ≤ tm.spaceUsedByTape cfg (max t T) j :=
fun j => tm.spaceUsedByTape_mono cfg j (le_max_right t T)
have hsup : tm.spaceUsed cfg (max t T) ≤ tm.spaceUsed cfg T :=
(le_csSup hbdd ⟨max t T, rfl⟩).trans hT.ge
have hsum : ∑ j, tm.spaceUsedByTape cfg T j = ∑ j, tm.spaceUsedByTape cfg (max t T) j :=
le_antisymm (Finset.sum_le_sum fun j _ => hmono j) hsup
have heq := (Finset.sum_eq_sum_iff_of_le fun j _ => hmono j).mp hsum i (Finset.mem_univ i)
exact heq ▸ tm.spaceUsedByTape_mono cfg i (le_max_left t T)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
have hmono : ∀ j, tm.spaceUsedByTape cfg T j ≤ tm.spaceUsedByTape cfg (max t T) j :=
fun j => tm.spaceUsedByTape_mono cfg j (le_max_right t T)
have hsup : tm.spaceUsed cfg (max t T) ≤ tm.spaceUsed cfg T :=
(le_csSup hbdd ⟨max t T, rfl⟩).trans hT.ge
have hsum : ∑ j, tm.spaceUsedByTape cfg T j = ∑ j, tm.spaceUsedByTape cfg (max t T) j :=
le_antisymm (Finset.sum_le_sum fun j _ => hmono j) hsup
have heq := (Finset.sum_eq_sum_iff_of_le fun j _ => hmono j).mp hsum i (Finset.mem_univ i)
exact heq ▸ tm.spaceUsedByTape_mono cfg i (le_max_left t T)
have hmono : ∀ j ∈ Finset.univ,
tm.spaceUsedByTape cfg T j ≤ tm.spaceUsedByTape cfg (max t T) j :=
fun j _ => tm.spaceUsedByTape_mono cfg j (le_max_right t T)
have heq := (Finset.sum_eq_sum_iff_of_le hmono).mp
(le_antisymm (Finset.sum_le_sum hmono) ((le_csSup hbdd ⟨max t T, rfl⟩).trans hT.ge))
exact heq i (Finset.mem_univ i) ▸ tm.spaceUsedByTape_mono cfg i (le_max_left t T)

def window (s : ℕ) : Finset ℤ := Finset.Icc (-(s : ℤ)) s

@[scoped grind =]
lemma Storage.mem_window {s : ℕ} {z : ℤ} : z ∈ window s ↔ z.natAbs ≤ s := by

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are lemmas about window in "Storage" namespace?

Comment thread Cslib.lean Outdated
public import Cslib.Computability.Languages.OmegaLanguage
public import Cslib.Computability.Languages.OmegaRegularLanguage
public import Cslib.Computability.Languages.RegularLanguage
public import Cslib.Computability.Machines.Turing.MultiTape.ConfigBound

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Insert in alphabetical order of imports

/-- The state and work-tape data of a machine, with the cells and head position of tape `i` indexed
by an arbitrary type `ι i`. -/
@[ext]
structure Storage (Symbol State : Type*) {k : ℕ} (ι : Fin k → Type*) where

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think that (ι : Fin k → Type*) is an overkill for what you want to achieve here.
It is instanciated twice, once at and once at the subtype ↥(window (w i)).
Consider defining Storage over directly, and replacing Storage.toBounded with a Storage.restrict that lands straight in the product type:

structure Storage (Symbol State : Type*) (k : ℕ) where
  /-- the state of the TM (cf. `Cfg.state`) -/
  state : Option State
  /-- the contents of work tape `i` (cf. `Cfg.workTapes`) -/
  workTapes : Fin k → ℤ → Option Symbol
  /-- the position of the head on work tape `i` (cf. `Cfg.workTapePos`) -/
  workTapePos : Fin k → ℤ

/-- Restriction of a storage to the finite windows `w` (with heads outside their window
clamped to `0`). -/
def Storage.restrict (x : Storage Symbol State k) (w : Fin k → ℕ) :
    Option State × ((i : Fin k) → window (w i) → Option Symbol) × ((i : Fin k) → window (w i)) :=
  (x.state, fun j z => x.workTapes j z.1,
    fun j => if h : x.workTapePos j ∈ window (w j) then ⟨_, h⟩
      else ⟨0, Storage.mem_window.mpr (Nat.zero_le _)⟩)

It saves a lot of code


/-- The part of a configuration that the machine can still read: the input head position together
with the `Storage`, i.e. the configuration without the write-only output tape. -/
def Cfg.core (c : Cfg k Symbol State input) :

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't how good the terms "Storage" and "Core". I don't see any standard name for specifically these stuff, so maybe just call them ore explicitely instead of assigning new terms?

Comment on lines +72 to +73
open Cslib

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
open Cslib

/-- The restriction is injective on storages that fit in the windows. -/
lemma Storage.toBounded_injOn (w : Fin k → ℕ) :
Set.InjOn (Storage.toBounded (Symbol := Symbol) (State := State) · w) {x | x.FitsIn w} := by
rintro x ⟨hxp, hxc⟩ y ⟨hyp, hyc⟩ hxy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
rintro x ⟨hxp, hxc⟩ y ⟨hyp, hyc⟩ hxy
rintro x ⟨_, _⟩ y ⟨_, _⟩ hxy


/-! ## The storage and the core of a configuration

Now we relate `Cfg` and `Storage` by givin the projection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
Now we relate `Cfg` and `Storage` by givin the projection.
Now we relate `Cfg` and `Storage` by giving the projection.

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.

4 participants