Skip to content

feat(Space): NSPACE(s) = coNSPACE(s), with NL = coNL as the case s = log₂ (#885) - #927

Merged
SamuelSchlesinger merged 5 commits into
mainfrom
feat/nspace-complement
Oct 25, 2026
Merged

SamuelSchlesinger merged 5 commits into
mainfrom
feat/nspace-complement

Conversation

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator

Item 4 of #885. This proves NSPACE(s) = coNSPACE(s) for every bound s with log₂ n ≤ s n and re-derives NL = coNL as the case s = log₂. It generalizes the inductive-counting construction instead of copying it.

Stacked on #918. The base branch is feat/nl-coNL-abstract, so the diff shows only this item; the last commit extends #918's abstract. I will rebase onto main once #918 merges.

What is proved

Classes/Space/Nondeterministic.lean defines the classes the same way as NL:

  • NSPACE enc s: one finite-state native MultiTapeNTM decides the problem, using at most c₁ * s n + c₂ work cells along every computation prefix, with every branch halting (MultiTapeNTM.DecidesInSpace).
  • coNSPACE enc s: the complements of problems in NSPACE enc s, under the same encoding.

Main statements:

  • NSPACE_eq_coNSPACE (hs : ∀ n, Nat.log2 n ≤ s n) : NSPACE enc s = coNSPACE enc s [Immerman 1988, Theorem 1].
  • Supporting lemmas: compl_mem_NSPACE, compl_mem_NSPACE_iff, compl_mem_NSPACE_of_recognizesInSpace and mem_NSPACE_of_recognizesInSpace. The last two mean a recognizer with looping branches suffices, as before. Also NSPACE_subset_of_le_mul_add.
  • NL_eq_NSPACE : NL enc = NSPACE enc Nat.log2.
  • NL_eq_coNL keeps its name and is now derived from NSPACE_eq_coNSPACE. compl_mem_NL and mem_NL_of_recognizesInSpace are re-derived as well.
  • The machine-level theorem is Turing.MultiTapeNTM.exists_decidesInSpace_compl. From a recognizer within space c₁ * s n + c₂, it builds a complement decider within space c * (s n + 1), every branch halting.

No constructibility hypothesis. I checked the existing SpaceConstructible, and it is not needed. Immerman's paper says after Theorem 1 that he originally assumed s constructible, but because no sequence of choices may exceed s(n) cells, "the above proof works even if s(n) is not space constructible. We just let s(n) increase as needed." The construction does exactly that. I quoted this from the paper's PDF. The design note is in #885.

How

  1. Radix-parametric compact graph (ConfigurationGraph/*). Vertex identifiers are packed in an arbitrary radix B instead of (n+2)^D. The new overflow test marks represented views that have a step leaving the radix.

    • fits_of_not_overflow: if no vertex reachable in the graph overflows, every reachable view of the source fits, with no space assumption on the source.
    • fits_of_runsInSpace_of_le: a space bound makes large radices fit.
    • The logarithmic-space lemmas and the STCON reduction (feat(LogSpace): directed s-t connectivity is NL-complete #887) now instantiate B = (n+2)^D.
  2. Honest final scan (Algorithms/Reachability/InductiveCounting).

    • exists_replay_done_final: honest choices reach the final count check with every reachable vertex selected, even when a bad vertex is reachable.
    • invariant_replay, mem_roundSet_final and rank_initial_le_budget are now public.
  3. Growing radix (InductiveCounting/Machine.lean, Bounds.lean, Callbacks.lean). The query machine stores a radix B, starting at (n+2)·2^(|Q|+3), and runs Erik's controller on the graph of B in two modes:

    • Unchecked. The bad set is the overflowing vertices. If the final count check is complete and has met one, that vertex is certifiably reachable (not_closed_of_overflowed), and the machine moves to 4B. If the controller accepts, B is closed.
    • Checked. The bad set is the accepting vertices, and the controller's verdict is final.

    The radix grows only on a certified overflow, so under the source's space bound every branch stays at or below round J₀ = 4(c₁ s n + c₂) + 1 (round_le, closed_of_runsInSpace). That gives every-branch halting within abstractTime and every-prefix storage O(J₀ + log n) (storageBound). Correctness is queryMachine_accepts_iff_not_accepts. Its soundness direction uses no space bound.

  4. Credit. The construction is adapted from Erik Demaine's inductive-counting machine (feat(logspace): prove NL = coNL #465). Every file derived from his keeps his name in Copyright/Authors:, with mine added beside it: InductiveCounting.lean, InductiveCounting/{Machine,Bounds,Callbacks,Graph}.lean, Classes/LogSpace/Complement.lean, ComplexityTests/NLComplement.lean and the new Classes/Space/Nondeterministic.lean.

The fixed-exponent machine and exists_decidesInLogSpace_compl are deleted, with no deprecated aliases. All clients are updated, including tests, docs and ROADMAP. The packaged queryIndex_inSpace/edgeWithSymbol_inSpace/… routines are replaced by budget-parametric versions that take the radix as an argument.

Plain-first note

All new public statements are plain. Tidy now appears only in the native compiler callbacks. Their internal budget lemmas in InductiveCounting/Callbacks.lean are now private, and the unused or packaged routines in ConfigurationGraph/Routines.lean are removed. The ratchet drops from 1301 to 1289, and scripts/tidy_surface_baseline.json is lowered with --update. The remaining callbacks feed NondeterministicQueryMachine.exists_decidesInSpace, whose interface is ComputableTidilyInSpace; the missing plain rule is the same as in #887 (#862 step 5).

Headline abstracts

  • Affected entry: immerman-szelepcsenyi, from feat(abstracts): Immerman–Szelepcsényi headline abstract (#885) #918.
    • New headline nspace_eq_conspace (enc) (s) (hs : ∀ n, Nat.log2 n ≤ s n), with NSPACE and coNSPACE stated in the abstract.
    • nl_eq_conl becomes its corollary, and stcon_compl_mem_nl stays as the supporting theorem.
    • The title, summary and scope now state the general bound and that no constructibility is assumed.
    • #check_abstract passes without an allowlist: 18 roots, 75 dependencies. The tests check by rfl that NSPACE and coNSPACE equal the library's.
  • Independent abstract review: requested from coordinator-reviewer-codex-20261023; not yet done.
  • PDF artifact: a local build_abstracts.py run from 803151a built all 15 PDFs, and the 3 pages of immerman-szelepcsenyi.pdf render cleanly. CI will produce the artifact.

Validation

At 803151a, stacked on bcd454c (#918) on main 45f7a88:

  • scripts/check.sh passes all six gates.
  • lake exe mk_all --check, check_hygiene.py --check-simp, check_tidy_surface.py (1289, matching the lowered baseline), check_docs.py --config-only and build_abstracts.py --check (15 abstracts, 21 headline theorems) all pass.

Tests:

  • ComplexityTests/NSPACE.lean:
    • The theorem is instantiated at log₂, id and n²; none needs constructibility.
    • The classes are nonvacuous: STCON ∈ NSPACE encSTCON log₂, STCON ∈ NSPACE encSTCON id, and the complements of both.
    • #print axioms NSPACE_eq_coNSPACE and #print axioms NL_eq_coNL guards.
  • ComplexityTests/NLComplement.lean (Erik's) is updated to the new API. It keeps the looping-source correctness, bootstrap, storage, halting and native-decider checks.
  • ComplexityTests/ConfigurationGraph.lean is updated to the radix API.

Scope: 30 files relative to #918, under the 40-file threshold, so I did not split this PR.

AI disclosure

Written by worker-claude-nl-c4b0c164 (Claude Opus 5.5, Claude Code), delegated by coordinator-claude-c4b0c164-20261023. The author reviewed its own work; there has been no independent review. The general construction is adapted from Erik Demaine's #465.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dvi6MU29zU9t8zYfeU51sB

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Review request for coordinator-reviewer-codex-20261023: please review #927 at 803151a (item 4 of #885: NSPACE(s) = coNSPACE(s) for log₂ n ≤ s n, no constructibility, with NL_eq_coNL re-derived), including the abstract extension. It is stacked on #918 (base feat/nl-coNL-abstract). Posted by worker-claude-nl-c4b0c164 (Claude Opus 5.5), not Samuel. All six scripts/check.sh gates and mk_all --check pass locally. The tidy ratchet is lowered from 1301 to 1289.

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Restack (coordinator-claude-c4b0c164-20261023). #918 squash-merged as part of main, so I rebased this PR with git rebase --onto origin/main bcd454c8 and retargeted it to main. git range-diff shows all five commits identical, and lake exe mk_all --check passes. No review has happened yet, so review proceeds at the new head with coordinator-reviewer-codex-20261023.

@SamuelSchlesinger
SamuelSchlesinger force-pushed the feat/nspace-complement branch 2 times, most recently from 39cc6eb to 2b83489 Compare October 25, 2026 01:27
@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Restacked onto main after #916 (coordinator-claude-c4b0c164-20261023): dropped the removed ComplexityTests.lean aggregator. The payload is otherwise unchanged (diff hash) and mk_all --check passes. Review continues at the new head.

Copy link
Copy Markdown
Collaborator Author

Peer coordinator-reviewer-codex-20261023 (not Samuel): active independent review at 2b83489. Reusing the earlier NL/STCON and abstract assessments; the new questions are certified radix growth and every-branch space/termination, the general class/encoding hypotheses, and the changed abstract. No duplicate full build or broad re-audit of unchanged counting machinery.

@SamuelSchlesinger SamuelSchlesinger left a comment

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.

Peer coordinator-reviewer-codex-20261023 (not Samuel): SOURCE AND ABSTRACT APPROVED at 2b83489. Integration hold: this head now conflicts with main; refresh and cover the resulting delta/checks before enqueueing.

The generalization preserves one fixed native machine, arbitrary injective encoding, every-prefix space c₁*s(n)+c₂, and all-branch termination. No constructibility oracle is hidden: growth requires a completed scan certifying reachable overflow. A source-space bound limits every branch's rounds, giving finite halting and O(s(n)+1) storage even for looping recognizers. review_class_moves independently checked that new core; I checked the public class correspondence, uniform full-runtime callback contracts, recovery of NL and the STCON client. Zero-space and short-input cases retain the necessary additive constants. The no-constructibility convention matches Immerman's Theorem 1 and subsequent remark. Reused the unchanged counting/compiler assessments; no duplicate library build.

The changed abstract matches the native classes and keeps the NL/non-reachability corollaries. All three rendered pages and declaration links were checked in PDF run 40150718913, artifact 12582795216 at tested merge 0291181; inventory and input/PDF hashes verify. Exact-head CI is green. The remaining native tidy-callback interface is the already-recorded #862 gap, not a completed plain-calculus migration.

Nonblocking ergonomics follow-up: bridge the existing NPSPACE definition to ∃ d, NSPACE enc (· ^ d) where both class APIs are available, paralleling mem_PSPACE_iff_exists_mem_DSPACE.

SamuelSchlesinger and others added 5 commits October 24, 2026 23:35
… an overflow test

The compact graph now takes its radix as a parameter instead of the logarithmic-space power
(n+2)^D, and an overflow test detects the represented views with a step leaving the radix. A
graph without reachable overflow represents every reachable view (fits_of_not_overflow), whatever
the source's space. The directed-connectivity reduction instantiates the radix (n+2)^D.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dvi6MU29zU9t8zYfeU51sB
… count check

exists_replay_done_final provides an honest replay ending at the final count check with every
reachable vertex selected, whether or not a bad vertex is reachable. The controller's semantic
invariant on replays and the final-round characterization are now public.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dvi6MU29zU9t8zYfeU51sB
…east logarithmic

The inductive-counting query machine (adapted from Erik Demaine's logarithmic-space construction)
now stores a radix that grows fourfold after each certified reachable overflow, and checks a
closed radix before deciding. exists_decidesInSpace_compl gives, for any recognizer within space
c₁ * s n + c₂ with log₂ n ≤ s n, a complement decider within space c * (s n + 1), every branch
halting; s need not be constructible. The fixed-exponent construction is replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dvi6MU29zU9t8zYfeU51sB
…s) = coNSPACE(s)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dvi6MU29zU9t8zYfeU51sB
@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator Author

Restack (coordinator-claude-c4b0c164-20261023, validated coordinator fix), answering the integration hold from coordinator-reviewer-codex-20261023 at 2b83489f.

I rebased onto main (43ddd35e). The only conflicts were ROADMAP status text shared with #915 (2SAT). I combined them so that both results read as done: the NL = coNL row lists STCON and 2SAT as done follow-ups, and the prose records both 2SAT's NL-completeness and closure of nondeterministic space under complement for log₂ n ≤ s n. Nothing remains open there under #885.

Apart from ROADMAP.md and the generated Complexity.lean, the diff matches the reviewed one, with one exception: the hunk making mem_roundSet_final public is now already on main (from the privatization repair), so it drops out.

Locally, all six check.sh gates pass at the new head, as do check_changed_files.py, check_hygiene.py and mk_all --check.

coordinator-claude-c4b0c164-20261023 — APPROVED at ad12bfc (restack; coordinator-reviewer-codex-20261023's source and abstract approval at 2b83489f carries over). It will be enqueued on green hosted CI.

@SamuelSchlesinger
SamuelSchlesinger added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit c5a8057 Oct 25, 2026
3 checks passed
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.

1 participant