Skip to content

Commit 439ab0b

Browse files
feat(Computability): add complexity classes P, NP, coNP, PSPACE and reductions
Define the fundamental complexity classes using single-tape Turing machines, namespaced under Cslib.Complexity. Classes/Core.lean: shared language-level definitions Decides and Verifies. Classes/Time.lean: P, NP, CoNP, PNeNP, and foundational results P_subset_NP and NP_subset_CoNP_iff. Classes/Space.lean: OutputsWithinSpace, SpaceBoundedComputable, PSPACE, and P_subset_PSPACE (a TM running in time t uses at most t work cells). Reductions.lean: polynomial-time many-one reductions (PolyTimeReduces), NPHard, NPComplete, with reflexivity, transitivity, downward closure under P, and NPHard.p_eq_np.
1 parent 20f3f0c commit 439ab0b

6 files changed

Lines changed: 424 additions & 0 deletions

File tree

Cslib.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public import Cslib.Computability.Languages.OmegaLanguage
3030
public import Cslib.Computability.Languages.OmegaRegularLanguage
3131
public import Cslib.Computability.Languages.RegularLanguage
3232
public import Cslib.Computability.Machines.SingleTapeTuring.Basic
33+
public import Cslib.Computability.Complexity.Classes
34+
public import Cslib.Computability.Complexity.Reductions
3335
public import Cslib.Computability.URM.Basic
3436
public import Cslib.Computability.URM.Computable
3537
public import Cslib.Computability.URM.Defs
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/-
2+
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Samuel Schlesinger
5+
-/
6+
7+
module
8+
9+
public import Cslib.Computability.Complexity.Classes.Core
10+
public import Cslib.Computability.Complexity.Classes.Time
11+
public import Cslib.Computability.Complexity.Classes.Space
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/-
2+
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Samuel Schlesinger
5+
-/
6+
7+
module
8+
9+
public import Cslib.Computability.Machines.SingleTapeTuring.Basic
10+
11+
@[expose] public section
12+
13+
/-!
14+
# Complexity Class Core Definitions
15+
16+
This file contains shared language-level definitions used by both
17+
time and space complexity classes.
18+
19+
## Main Definitions
20+
21+
* `Decides f L` — `f` decides language `L` (non-empty output means accept)
22+
* `Verifies verify L p` — `verify` verifies language `L` with polynomial witness bound `p`
23+
-/
24+
25+
variable {Symbol : Type}
26+
27+
namespace Cslib.Complexity
28+
29+
/--
30+
A function `f : List Symbol → List Symbol` **decides** a language `L` when
31+
membership in `L` corresponds to `f` producing non-empty output.
32+
-/
33+
def Decides (f : List Symbol → List Symbol) (L : Set (List Symbol)) : Prop :=
34+
∀ x, x ∈ L ↔ f x ≠ []
35+
36+
/--
37+
A verifier `verify` **verifies** a language `L` with polynomial witness bound `p` when
38+
membership in `L` is equivalent to the existence of a short witness `w` such that
39+
`verify (x ++ w)` produces non-empty output.
40+
-/
41+
-- TODO: The verifier receives `x ++ w` as a bare concatenation, so it cannot
42+
-- distinguish the input/witness boundary. A more robust formulation would use
43+
-- a two-tape machine with a separate read-only witness tape.
44+
def Verifies (verify : List Symbol → List Symbol) (L : Set (List Symbol))
45+
(p : Polynomial ℕ) : Prop :=
46+
∀ x, x ∈ L ↔ ∃ w : List Symbol, w.length ≤ p.eval x.length ∧ verify (x ++ w) ≠ []
47+
48+
end Cslib.Complexity
49+
50+
end
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/-
2+
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Samuel Schlesinger
5+
-/
6+
7+
module
8+
9+
public import Cslib.Computability.Complexity.Classes.Time
10+
11+
@[expose] public section
12+
13+
/-!
14+
# Space Complexity Classes
15+
16+
This file defines space-bounded computation and the complexity class **PSPACE**.
17+
18+
## Main Definitions
19+
20+
* `OutputsWithinSpace` — TM outputs on input using at most `s` additional work cells
21+
* `SpaceBoundedComputable f s` — `f` is computable within space `s`
22+
* `PSPACE` — languages decidable in polynomial space
23+
24+
## Main Results
25+
26+
* `P_subset_PSPACE` — P ⊆ PSPACE
27+
28+
## References
29+
30+
* [S. Arora, B. Barak, *Computational Complexity: A Modern Approach*][AroraB2009]
31+
-/
32+
33+
open Turing SingleTapeTM Polynomial Relation
34+
35+
variable {Symbol : Type}
36+
37+
namespace Cslib.Complexity
38+
39+
/-- The work space used by a configuration on input `l`: total tape space
40+
minus the initial input footprint `max 1 l.length`. -/
41+
def Cfg.work_space_used (tm : SingleTapeTM Symbol) (l : List Symbol) (cfg : tm.Cfg) : ℕ :=
42+
SingleTapeTM.Cfg.space_used tm cfg - max 1 l.length
43+
44+
/-- A TM `tm` **outputs** `l'` on input `l` using at most `s` additional work cells
45+
throughout the computation. This combines the time-based reachability
46+
with a space bound: every configuration along the computation path
47+
uses at most `s` work space beyond the initial input footprint. -/
48+
def OutputsWithinSpace (tm : SingleTapeTM Symbol)
49+
(l l' : List Symbol) (s : ℕ) : Prop :=
50+
∃ t : ℕ, tm.OutputsWithinTime l l' t ∧
51+
∀ cfg : tm.Cfg,
52+
ReflTransGen tm.TransitionRelation (tm.initCfg l) cfg →
53+
Cfg.work_space_used tm l cfg ≤ s
54+
55+
/-- A function `f` is **space-bounded computable** with space bound `s`
56+
if there exists a TM computing `f` that uses at most `s(|x|)` additional
57+
work cells on input `x`. -/
58+
structure SpaceBoundedComputable
59+
(f : List Symbol → List Symbol) (s : ℕ → ℕ) where
60+
/-- The underlying Turing machine -/
61+
tm : SingleTapeTM Symbol
62+
/-- Proof that the machine computes `f` within space `s` -/
63+
outputsInSpace : ∀ a,
64+
OutputsWithinSpace tm a (f a) (s a.length)
65+
66+
/-- **PSPACE** is the class of languages decidable by a Turing machine
67+
using polynomial work space. -/
68+
def PSPACE : Set (Set (List Symbol)) :=
69+
{ L | ∃ f : List Symbol → List Symbol,
70+
∃ p : Polynomial ℕ,
71+
Nonempty (SpaceBoundedComputable f (fun n => p.eval n)) ∧
72+
Decides f L }
73+
74+
-- TODO: Define L (LOGSPACE) using multi-tape Turing machines with a
75+
-- read-only input tape. The single-tape model allows overwriting input
76+
-- cells, giving O(n) writable space instead of O(log n).
77+
78+
/-- Any configuration reachable during a halting computation has its space
79+
bounded by the initial space plus the halting time. -/
80+
private lemma space_bounded_of_time_bounded (tm : SingleTapeTM Symbol)
81+
(l l' : List Symbol) (t : ℕ)
82+
(htime : tm.OutputsWithinTime l l' t)
83+
(cfg : tm.Cfg)
84+
(hreach : ReflTransGen tm.TransitionRelation (tm.initCfg l) cfg) :
85+
Cfg.space_used tm cfg ≤ max 1 l.length + t := by
86+
-- Convert ReflTransGen to RelatesInSteps.
87+
obtain ⟨m, hm⟩ := ReflTransGen.relatesInSteps hreach
88+
-- Extract the halting computation.
89+
obtain ⟨t', ht'_le, ht'⟩ := htime
90+
-- `haltCfg` has no successors.
91+
have hhalt : ∀ cfg', ¬tm.TransitionRelation (tm.haltCfg l') cfg' :=
92+
fun cfg' => no_step_from_halt tm _ cfg' rfl
93+
-- By determinism, m ≤ t' ≤ t.
94+
have hm_le := reachable_steps_le_halting_steps tm ht' hhalt hm
95+
-- Space grows by at most 1 per step.
96+
have hspace := RelatesInSteps.apply_le_apply_add hm (Cfg.space_used tm)
97+
fun a b hstep => Cfg.space_used_step a b (Option.mem_def.mp hstep)
98+
rw [Cfg.space_used_initCfg] at hspace
99+
omega
100+
101+
/-- Any configuration reachable during a halting computation uses at most `t`
102+
work cells beyond the initial input footprint. -/
103+
private lemma work_space_bounded_of_time_bounded (tm : SingleTapeTM Symbol)
104+
(l l' : List Symbol) (t : ℕ)
105+
(htime : tm.OutputsWithinTime l l' t)
106+
(cfg : tm.Cfg)
107+
(hreach : ReflTransGen tm.TransitionRelation (tm.initCfg l) cfg) :
108+
Cfg.work_space_used tm l cfg ≤ t := by
109+
have htotal := space_bounded_of_time_bounded tm l l' t htime cfg hreach
110+
apply (Nat.sub_le_iff_le_add).2
111+
simpa [Cfg.work_space_used, Nat.add_comm, Nat.add_left_comm,
112+
Nat.add_assoc] using htotal
113+
114+
/-- **P ⊆ PSPACE**: every language decidable in polynomial time is also
115+
decidable in polynomial space.
116+
117+
A TM running in time `t` can use at most `t` additional work cells
118+
beyond the initial input footprint (at most one new cell per step).
119+
So a polynomial time bound gives a polynomial work-space bound. -/
120+
public theorem P_subset_PSPACE :
121+
P (Symbol := Symbol) ⊆ PSPACE := by
122+
intro L ⟨f, ⟨hf⟩, hDecides⟩
123+
refine ⟨f, hf.poly, ⟨{
124+
tm := hf.tm
125+
outputsInSpace := fun a =>
126+
⟨hf.time_bound a.length, hf.outputsFunInTime a, fun cfg hreach =>
127+
le_trans
128+
(work_space_bounded_of_time_bounded hf.tm a (f a) (hf.time_bound a.length)
129+
(hf.outputsFunInTime a) cfg hreach)
130+
(hf.bounds a.length)⟩
131+
}⟩, hDecides⟩
132+
133+
end Cslib.Complexity
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/-
2+
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Samuel Schlesinger
5+
-/
6+
7+
module
8+
9+
public import Cslib.Computability.Complexity.Classes.Core
10+
11+
@[expose] public section
12+
13+
/-!
14+
# Time Complexity Classes
15+
16+
This file defines the fundamental time complexity classes **P**, **NP**, and **coNP**
17+
using single-tape Turing machines, and states the **P ≠ NP** conjecture.
18+
19+
## Main Definitions
20+
21+
* `P` — the class **P** of languages decidable in polynomial time
22+
* `NP` — the class **NP** of languages verifiable in polynomial time
23+
* `CoNP` — the class **coNP**, complements of **NP** languages
24+
* `PNeNP` — the proposition **P ≠ NP**
25+
26+
## Main Results
27+
28+
* `P_subset_NP` — **P ⊆ NP**
29+
-/
30+
31+
open Turing SingleTapeTM
32+
33+
variable {Symbol : Type}
34+
35+
namespace Cslib.Complexity
36+
37+
/--
38+
**P** is the class of languages decidable by a polynomial-time Turing machine.
39+
40+
We use `Nonempty (PolyTimeComputable f)` because `PolyTimeComputable` is a structure
41+
(carrying computational data), while set membership requires a `Prop`.
42+
-/
43+
def P : Set (Set (List Symbol)) :=
44+
{ L | ∃ f, Nonempty (PolyTimeComputable f) ∧ Decides f L }
45+
46+
/--
47+
**NP** is the class of languages for which membership can be verified
48+
in polynomial time given a polynomial-length witness (certificate).
49+
-/
50+
def NP : Set (Set (List Symbol)) :=
51+
{ L | ∃ verify p, Nonempty (PolyTimeComputable verify) ∧ Verifies verify L p }
52+
53+
/--
54+
**coNP** is the class of languages whose complements are in **NP**.
55+
-/
56+
def CoNP : Set (Set (List Symbol)) :=
57+
{ L | Lᶜ ∈ NP }
58+
59+
/--
60+
The **P ≠ NP** conjecture states that the complexity classes P and NP are distinct.
61+
This is stated as a `Prop` definition rather than an axiom.
62+
-/
63+
def PNeNP : Prop := P (Symbol := Symbol) ≠ NP
64+
65+
end Cslib.Complexity
66+
67+
end
68+
69+
open Cslib.Complexity
70+
71+
namespace Cslib.Complexity
72+
73+
/--
74+
**P ⊆ NP**: Every language decidable in polynomial time is also verifiable
75+
in polynomial time.
76+
77+
*Proof sketch*: Given a polytime decider `f` for `L`, use `f` as a verifier
78+
that ignores the witness. The witness is taken to be empty (`[]`),
79+
and the polynomial witness bound is `0`.
80+
-/
81+
public theorem P_subset_NP
82+
{Symbol : Type} :
83+
P (Symbol := Symbol) ⊆ NP := by
84+
intro L ⟨f, hf, hDecides⟩
85+
refine ⟨f, 0, hf, fun x => ?_⟩
86+
simp only [Polynomial.eval_zero]
87+
constructor
88+
· intro hx
89+
exact ⟨[], Nat.le_refl 0, by rwa [List.append_nil, ← hDecides]⟩
90+
· rintro ⟨w, hw, hverify⟩
91+
rw [hDecides]
92+
have : w = [] := List.eq_nil_of_length_eq_zero (Nat.le_zero.mp hw)
93+
rwa [this, List.append_nil] at hverify
94+
95+
/-- **NP ⊆ coNP ↔ ∀ L ∈ NP, Lᶜ ∈ NP**. This is just the unfolding of
96+
the definitions: coNP is defined as `{L | Lᶜ ∈ NP}`, so `NP ⊆ coNP`
97+
means every NP language has its complement in NP. -/
98+
public theorem NP_subset_CoNP_iff
99+
{Symbol : Type} :
100+
NP (Symbol := Symbol) ⊆ CoNP ↔
101+
∀ L ∈ NP (Symbol := Symbol), Lᶜ ∈ NP := by rfl
102+
103+
end Cslib.Complexity

0 commit comments

Comments
 (0)