P vs NP — The Greatest Unsolved Problem in Computer Science
A SmokyCoders Research Lab flagship: from puzzles and Turing machines to reductions, proof barriers, and reproducible Python experiments — what P vs NP asks, what is proved, and what remains open.
By SmokyCoders Editorial · Research Lab
SmokyCoders Research Lab flagship. P vs NP is unsolved; nothing here claims a proof. Python experiments were executed locally; see review notes.

Prerequisites
- Comfort reading simple Python (functions, loops, dictionaries)
- Basic algebra and fractions; no prior complexity theory assumed
- Willingness to distinguish proved theorems from open conjectures
What you will learn
- Define P and NP formally and in plain English, with certificates and verifiers
- Explain NP-completeness and read a reduction in the correct direction
- State exactly what a proof of P = NP or P ≠ NP would have to establish
- Describe the relativization, natural-proofs, and algebrization barriers without overstating them
- Run and interpret small SAT, DPLL, clique, and reduction experiments — and state their limits
Key takeaways
- ESTABLISHED: P ⊆ NP. OPEN: whether the inclusion is strict.
- A polynomial-time algorithm for any one NP-complete problem would prove P = NP.
- Proving P ≠ NP requires a superpolynomial lower bound against all algorithms for some NP problem — not just showing one algorithm is slow.
- Experiments settle finite instances only; they never prove a complexity-class separation.
- As of October 2026, P vs NP remains unsolved (Clay Mathematics Institute).
Chapter 01 — The Question That Could Change Computing
A Sudoku grid is annoying to solve and trivial to check: someone hands you a completed grid, and you verify rows, columns and boxes in moments. A delivery schedule for a thousand stops is brutal to optimize and easy to audit once proposed. This asymmetry — finding is hard, checking is easy — is the everyday shadow of the deepest open question in computer science: does every problem whose solution can be verified quickly also admit a method to find that solution quickly?
Formally, a computational problem here means a decision problem: inputs encoded as finite strings, answers YES or NO. “Solve” means an algorithm that always halts with the correct answer. “Verify” means: for YES instances, there exists a short certificate (witness) that a deterministic checker can validate quickly. Scheduling and puzzles become decision problems by asking “is there a schedule / completion with cost or constraints at most K?”
ESTABLISHED: Stephen Cook (1971) and, independently, Leonid Levin introduced NP-completeness and showed SAT is NP-complete. The Clay Mathematics Institute later made P vs NP a Millennium Prize Problem [1][2]. OPEN: the question itself.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Roadmap: Chapters 02–04 build the language (Turing machines, P, NP). Chapter 05 proves how NP-complete problems lock together. Chapters 06–09 state the central question and why proof attempts hit barriers. Chapters 10–11 separate proved implications from speculation. Chapter 12 is a working Python laboratory — every experiment was executed, and its limits are stated. Chapters 13–16 turn the material into a research method, a catalogue of false proofs, open directions, and an honest final roadmap.
Chapter 02 — Mathematical Foundations
We need a small, precise toolkit. A set is a collection of objects; a formal language is a set of strings over a finite alphabet (usually {0,1}); a decision problem is identified with the language of its YES instances. A function maps inputs to outputs; a relation pairs inputs with acceptable certificates. Propositional logic combines Boolean variables (true/false) with AND (∧), OR (∨) and NOT (¬). A Boolean formula is satisfiable (SAT) when some assignment makes it true.
Proof tools used throughout: induction (prove a base case, then that case n implies n+1 — the engine behind most algorithm-correctness proofs), and contradiction (assume the opposite, derive an impossibility). Graph theory contributes vertices, edges, paths, cycles and cliques (fully connected vertex sets). Combinatorics counts possibilities — a truth table for n Boolean variables has 2^n rows, which is why brute force dies young.
| Notation | Meaning | Plain English |
|---|---|---|
| f(n) = O(g(n)) | f grows at most like g (up to constants, for large n) | “No worse than” |
| f(n) = Ω(g(n)) | f grows at least like g | “No better than” |
| f(n) = Θ(g(n)) | Both bounds hold | “Grows like” |
| n^k (fixed k) | Polynomial growth | 2, 4, 8, 16… when doubled, multiplies predictably |
| 2^n | Exponential growth | Doubling n squares the work — then squares it again |
Computation model: a deterministic Turing machine has one next action for each state/symbol pair; a nondeterministic machine may branch into many computation paths and accepts if any path accepts. Nondeterminism is a mathematical definition, not randomness and not real hardware. Input length n is the number of symbols in the encoding — complexity is measured against n, so encodings matter (writing a number in unary versus binary changes n dramatically). Theoretical complexity asks how resource needs scale; practical runtime also depends on constants, hardware and implementation. Both matter; they are different questions.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 03 — Understanding P
ESTABLISHED THEOREM (definition): P is the class of languages decidable by a deterministic Turing machine in time O(n^k) for some constant k. In plain English: problems with algorithms whose worst-case step count grows polynomially in input length. Complexity theory treats P as “efficiently computable” because polynomials compose well and the class is robust across reasonable machine models — while honestly admitting a polynomial like n^100 would be practically useless. P membership is a statement about scaling, not a promise that your laptop enjoys it.
Citizens of P include: deciding whether a graph is connected (breadth-first search), shortest paths with non-negative weights (Dijkstra), sorting-based decisions, linear programming feasibility, and — famously — primality (the AKS test, 2002). Dynamic programming solves many optimization problems in polynomial time when substructure is small (edit distance, knapsack with small numeric capacity — note: capacity enters the input in binary, which is why knapsack is only “pseudo-polynomial”). Decision versus optimization: “is there a tour of length ≤ K?” is the decision form of the Traveling Salesperson Problem; binary search over K bridges the two when a decision algorithm exists.
def is_connected(graph: dict[int, list[int]], start: int) -> bool:
"""Polynomial-time decision in P: BFS visits each edge once. O(V + E)."""
seen = {start}
stack = [start]
while stack:
u = stack.pop()
for v in graph.get(u, []):
if v not in seen:
seen.add(v)
stack.append(v)
return len(seen) == len(graph)
print(is_connected({0: [1], 1: [0, 2], 2: [1]}, 0)) # TrueChapter 04 — Understanding NP
ESTABLISHED THEOREM (definition, two equivalent forms): NP is the class of languages decidable by a nondeterministic polynomial-time machine; equivalently, languages with a deterministic polynomial-time verifier V and a polynomial p such that x is a YES instance iff some certificate w with |w| ≤ p(|x|) makes V(x, w) accept [2][3]. The certificate is the completed Sudoku grid, the Hamiltonian path itself, the satisfying assignment. Verification must be polynomial in the input length — an exponential-size “certificate” would smuggle the search into the witness.
ESTABLISHED: P ⊆ NP — a solver is its own verifier (ignore the certificate). Whether every NP problem has this luxury is exactly the open question. And the eternal correction: NP does not mean “not polynomial”; it means nondeterministic polynomial. Brute-force hardness of the algorithms we happen to know proves nothing about all possible algorithms — lower bounds are statements about every algorithm, which is why they are scarce and precious.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
# NP in action: verifying is one pass. Formula in CNF: clauses of (var, is_positive).
def verify_sat(clauses, assignment):
return all(any(assignment[v] == pos for v, pos in clause) for clause in clauses)
F = [[("x", True), ("y", False)], [("x", False), ("y", True)]] # x == y
print(verify_sat(F, {"x": True, "y": True})) # True
print(verify_sat(F, {"x": True, "y": False})) # FalseChapter 05 — NP-Hard and NP-Complete
A polynomial-time many-one reduction from A to B (written A ≤p B) is a polynomial-time computable map sending YES instances of A exactly to YES instances of B. Direction is the whole game: to prove B is hard, reduce a known-hard A into B — you show B is at least as hard as A. A problem is NP-hard if every NP problem reduces to it; it is NP-complete if it is NP-hard and itself in NP. NP-hard problems need not be in NP at all (the halting problem is NP-hard and undecidable) — never use the terms interchangeably.
ESTABLISHED THEOREM (Cook–Levin): SAT is NP-complete [2][3][4]. The idea: a nondeterministic polynomial-time computation is a sequence of machine configurations; Cook encoded “there is an accepting computation tableau” as one giant Boolean formula, satisfiable exactly when the machine accepts. From SAT, reductions built the family: 3-SAT, CLIQUE, Vertex Cover, Hamiltonian Cycle, Subset Sum, TSP-decision. ESTABLISHED consequence: a polynomial-time algorithm for any single NP-complete problem yields one for all of NP (compose the reductions), proving P = NP.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Worked reduction: 3-SAT ≤p CLIQUE
Construction. Given a 3-CNF formula with m clauses, build a graph with one vertex per literal occurrence (clause i, literal ℓ). Join two vertices by an edge when they sit in different clauses and are not complementary (x versus ¬x). Ask for a clique of size m. Correctness: (⇒) a satisfying assignment picks one true literal per clause; those m vertices are pairwise in different clauses and never complementary (a true literal's complement is false), so they form an m-clique. (⇐) an m-clique has m vertices, at most one per clause (no intra-clause edges), hence exactly one per clause, and contains no complementary pair, so setting those literals true is consistent and satisfies every clause. Runtime: at most 3m vertices and O((3m)²) edge checks — polynomial. Chapter 12 implements exactly this and tests the equivalence by brute force on small formulas. ∎
Chapter 06 — The Central Mathematical Problem
The question is P =? NP. Scenario A (P = NP): it suffices to give one deterministic polynomial-time algorithm for SAT (or any NP-complete problem) with a correctness proof; reductions do the rest. Existence would not guarantee usefulness — n^50 with huge constants is “polynomial” and still impossible. Scenario B (P ≠ NP): one must exhibit a specific language in NP and prove every deterministic algorithm for it needs superpolynomial time on infinitely many inputs. Showing your favourite algorithm is slow, or that a million attempts failed, proves nothing: the claim quantifies over all algorithms, including ones nobody has imagined. That universal quantifier is the mountain.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 07 — How Could P = NP Be Proved?
| Direction | Central idea | Main limitation |
|---|---|---|
| Poly-time SAT algorithm | Exploit formula structure no one has used yet | 50 years of failure; must work on all formulas |
| Restricted SAT families | Horn-SAT, 2-SAT are in P; map the tractable frontier | Tractable islands do not settle general SAT |
| Circuit / algebraic methods | Represent computation algebraically, find shortcuts | Breakthroughs so far are for restricted models |
| Parameterized complexity | Be exponential only in a small parameter k | Real instances may have large k |
| Proof complexity | Short proofs everywhere might hint at algorithms | Connections are conditional, not automatic |
Criteria for a genuine breakthrough: an algorithm stated for all inputs, a worst-case polynomial bound with proof, correctness proof, and survival of independent scrutiny. Improving practical SAT-solver speed on benchmarks — however impressive — is engineering progress, not P = NP. RESEARCH HYPOTHESIS discipline: label conjectured speedups as hypotheses until the proof obligation list (Chapter 13) is empty.
Chapter 08 — How Could P ≠ NP Be Proved?
The lower-bound programme attacks circuits first: a Boolean circuit is a fixed, non-uniform computing device (gates wired together, a different circuit allowed per input length). ESTABLISHED: almost all Boolean functions need exponentially large circuits — yet for no explicit function in NP do we know a superpolynomial circuit lower bound. Known separations live in restricted models (bounded depth, monotone circuits), and restricted lower bounds do not transfer automatically: the restriction was doing the work. Uniform (algorithm) versus nonuniform (circuit family) is not a technicality; P ≠ NP concerns uniform computation, and even P ⊄ P/poly would be a revolution nobody has achieved.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 09 — Why Previous Approaches Encounter Barriers
ESTABLISHED THEOREM (Baker–Gill–Solovay, 1975) — Relativization: there exist oracles A and B with P^A = NP^A and P^B ≠ NP^B [5]. Any proof technique that treats machines as black boxes and therefore “relativizes” (works relative to every oracle) cannot settle the question — diagonalization does exactly that. It does not rule out non-relativizing ideas; algebraization later showed some such ideas exist.
ESTABLISHED (Razborov–Rudich, under standard cryptographic assumptions) — Natural Proofs: most successful circuit-lower-bound arguments are “natural” (constructive and large), and natural properties strong enough to separate would break pseudorandom generators — the proof would defeat itself. ESTABLISHED FRAMEWORK (Aaronson–Wigderson) — Algebrization: techniques that relativize and also survive algebraic oracle extensions (arithmetization, as in IP = PSPACE) still cannot resolve P vs NP. Barriers are maps of mined fields, not impossibility proofs: each says “not this way,” never “not ever.”
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 10 — What Happens If P = NP?
Mathematically implied: every NP search problem gains a polynomial-time algorithm; public-key cryptography built on NP-hardness-style assumptions (factoring is in NP ∩ coNP and not known NP-complete — precision matters) loses its foundation; automated theorem proving, scheduling, logistics, protein-design search and software verification gain polynomial-time cores. SPECULATIVE IMPLICATION zone begins immediately after: a degree-9 polynomial with astronomical constants changes nothing this century; average-case instances were often already easy; encoding blowups in reductions eat budgets. “Encryption instantly ends” is a headline, not a theorem.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 11 — What Happens If P ≠ NP?
ESTABLISHED consequence: NP-complete problems have no polynomial-time algorithm, full stop — and research pivots permanently to approximation algorithms (provable near-optimality), parameterized algorithms, heuristics and world-class SAT solvers that already crack industrial instances daily. Honest nuance: P ≠ NP alone does not prove cryptography secure — security needs average-case hardness and one-way functions, strictly stronger assumptions. Worst-case hardness says some instances resist; cryptography needs almost all instances to resist. The frontier after a proof: fine-grained complexity, ETH, average-case theory — Chapter 15.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 12 — Python Research Laboratory
EXPERIMENTAL OBSERVATION policy: the code below was executed in Python 3.13 during writing; outputs quoted are from that run. No timings are reported (machine-dependent), no finite result is evidence about P vs NP, and theoretical curves are labelled theoretical. Re-run everything yourself — that is the point of a lab.
Experiment A — Complexity growth (theoretical counts)
for n in (10, 20, 30, 50):
print(n, n**2, 2**n)
# n=30 -> n^2 = 900, 2^n = 1073741824 (executed)Experiments B & C — SAT verification and brute force
import itertools
def verify_sat(clauses, a):
return all(any(a[v] == pos for v, pos in c) for c in clauses)
def brute_sat(clauses, variables):
for values in itertools.product([False, True], repeat=len(variables)):
a = dict(zip(variables, values))
if verify_sat(clauses, a):
return a
return None
F = [[("x", True), ("y", False)], [("x", False), ("y", True)]]
print(brute_sat(F, ["x", "y"])) # a solution with x == y (executed)Experiment D — DPLL-style backtracking with unit propagation
def dpll(clauses, assignment=None):
assignment = dict(assignment or {})
simplified = []
for clause in clauses:
satisfied, rest = False, []
for v, pos in clause:
if v in assignment:
if assignment[v] == pos:
satisfied = True; break
else:
rest.append((v, pos))
if satisfied: continue
if not rest: return None
simplified.append(rest)
if not simplified: return assignment
for clause in simplified:
if len(clause) == 1:
v, pos = clause[0]; assignment[v] = pos
return dpll(simplified, assignment)
v = simplified[0][0][0]
for val in (True, False):
trial = dict(assignment); trial[v] = val
result = dpll(simplified, trial)
if result is not None: return result
return None
print(dpll([[("x", True)], [("x", False)]])) # None: UNSAT (executed)Complexity analysis: brute force is O(2^n · formula size) time, polynomial space. DPLL prunes (unit propagation forces values, pure search tree shrinks) but its worst case remains exponential — ESTABLISHED for the algorithm, and not a lower bound on SAT itself. Limitation: no clause learning, no VSIDS heuristics; industrial solvers are another universe of engineering on the same worst-case cliff.
Experiments F & G — Clique, and the 3-SAT → CLIQUE reduction executed
import itertools
def brute_clique(graph, k):
def is_clique(combo):
return all(graph[u][v] for i, u in enumerate(combo) for v in combo[i+1:])
for combo in itertools.combinations(graph.keys(), k):
if is_clique(list(combo)):
return list(combo)
return None
def sat3_to_clique(clauses):
verts = [(i, v, pos) for i, c in enumerate(clauses) for v, pos in c]
graph = {a: {} for a in range(len(verts))}
for a in range(len(verts)):
for b in range(len(verts)):
ci, vi, pi = verts[a]; cj, vj, pj = verts[b]
graph[a][b] = a != b and ci != cj and not (vi == vj and pi != pj)
return graph, len(clauses)
F = [[("x", True), ("y", True), ("z", True)], [("x", False), ("y", False), ("z", False)]]
graph, k = sat3_to_clique(F)
print(brute_clique(graph, k) is not None) # True == formula satisfiable (executed, 3 instances matched brute force)Experiments E & H — Empirical runtime and formal verification (honest status)
Experiment E (method, no fabricated numbers): generate random 3-SAT at clause/variable ratios near 4.26 (the empirically observed hard region), time brute force versus DPLL across seeds, and plot medians. Run it; report your machine, seed set and raw table. Hypothesis: median runtime explodes with n for both solvers — an EXPERIMENTAL OBSERVATION about these algorithms, never about SAT's complexity class. Experiment H (UNVERIFIED sketch): proof assistants such as Lean or Isabelle can machine-check small lemmas — the AFP already hosts a Cook–Levin formalization [4] — but a checked proof only guarantees the formal statement proved, and aligning that statement with the intended P vs NP claim remains human work. No Lean code was executed for this article; none is quoted as run.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 13 — Research Blueprint
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
| Stage | Deliverable | Proceed only if |
|---|---|---|
| Formal model | Definitions fixed in writing | Statement matches the intended claim exactly |
| Lemmas | Each lemma stated + proved or cited | No lemma is “obvious” and unproved |
| Construction | Algorithm / circuit / reduction, fully specified | Runtime and correctness both argued |
| Counterexample search | Adversarial instances tried | Construction survives deliberate attack |
| Experiments | Code, seeds, raw outputs archived | Results reproducible by a stranger |
| Peer review | Independent expert report | Objections answered in writing |
Research notebook template: date · claim attempted (labelled THEOREM / LEMMA / CONJECTURE / OBSERVATION / HYPOTHESIS) · exact statement · dependencies · proof attempt · counterexample attempts · experiments (code hash, seed) · status · next obligation. Proof assistants verify formalized arguments; they cannot certify that your formalization is the P vs NP problem anyone else means. That alignment is a research deliverable in itself.
Chapter 14 — Common False Proofs and Research Mistakes
| Mistake | Why it fails | Concrete counter-thought |
|---|---|---|
| “My search took exponential time, so SAT needs it” | One algorithm's cost is not a lower bound on the problem | Sorting by trying all permutations is factorial; sorting is in P |
| “Benchmarks show exponential growth” | Finite data cannot quantify over all algorithms or inputs | Easy instance families (Horn-SAT) sit inside SAT itself |
| Misreading reduction direction | Proving B ≤p A shows B is easier, not harder | Reducing SAT to 2-SAT (if possible) would prove collapse, not hardness |
| “NP means not polynomial / NP-complete” | NP includes P; NP-complete is the hardest slice | Graph connectivity is in NP — and in P |
| “Nondeterminism = randomness / parallelism” | It is a definitional branching model | A million parallel cores give polynomial, not exponential, branching |
| “Quantum / ML will just solve it” | No poly quantum algorithm for NP-complete problems is known; ML output is not proof | BQP vs NP is itself open; predictions need theorems |
| Treating a conjecture as a theorem | ETH and similar are assumptions, not results | Label every claim; see Chapter 15 |
Chapter 15 — Open Problems and Future Research
OPEN CONJECTURE map (all unproved unless stated): general superpolynomial circuit lower bounds for explicit functions; the Exponential Time Hypothesis and Strong ETH (conjectures that 3-SAT needs essentially 2^n, powering fine-grained complexity's web of tight lower bounds); average-case NP hardness strong enough for cryptography; algebraic and geometric complexity theory programmes; proof-complexity lower bounds for strong systems; SAT algorithm improvements that are worst-case, not benchmark-case. Each is a career, not a weekend. The discipline that keeps this map honest is labelling: ESTABLISHED THEOREM, PROVED LEMMA, OPEN CONJECTURE, EXPERIMENTAL OBSERVATION, RESEARCH HYPOTHESIS, SPECULATIVE IMPLICATION — used throughout this article and required in your notebook.
Blueprint — har box ek component hai, har arrow data ka flow. Red path = failure result, green path = aage ka flow.
Chapter 16 — Final Research Perspective
What is established: P ⊆ NP; SAT is NP-complete (Cook–Levin); reductions weld thousands of problems into one fate; relativization, natural proofs and algebrization fence off entire proof styles; verifiers, DPLL and the 3-SAT→CLIQUE reduction above behave exactly as proved — you executed them. What is unknown: the single bit at the centre — equality or not. A valid proof must either hand us a polynomial-time algorithm for an NP-complete problem with its correctness theorem, or a lower bound that defeats algorithms not yet invented, slipping past three known barriers. Build skills in order: discrete mathematics, algorithms, computability, then complexity (Arora–Barak [3]), then one barrier paper at a time. Run experiments to learn what algorithms do; read proofs to learn what problems are. Never confuse the two — and never let that confusion, or anyone's headline, tell you this question is settled. It is not. That is precisely why it is worth your career-grade attention.
Next action: re-run every Chapter 12 experiment, break one on purpose, then write the failure in the notebook template from Chapter 13 with an honest label. That habit — claim, test, label, revise — is the entire Research Lab method.
Interactive — Complexity Growth Explorer
Theoretical operation counts (not benchmarks). Drag n and the polynomial exponent k, then compare nk against 2n.
At n = 30: n2 = 900 operations · 230 = 1,073,741,824 operations · exponential is 1,193,046× larger
| n | n^2 | 2^n |
|---|---|---|
| 10 | 100 | 1,024 |
| 20 | 400 | 1,048,576 |
| 30 | 900 | 1,073,741,824 |
| 50 | 2,500 | 1.13e+15 |
| 100 | 10,000 | 1.27e+30 |
Lesson: for any fixed k, 2n eventually dominates nk — that gap is the practical intuition behind P versus NP. It is intuition, not a proof.
Interactive — SAT Playground (small instances only)
CNF format: clauses joined by &, literals by |, negation by !. Example: (x | !y) & (!x | y) means “x equals y”.
Finite search proves nothing about all SAT instances — it only settles the tiny instance you typed. That distinction is Chapter 14 in miniature.
Frequently asked questions
Has P vs NP been solved?
No. As of October 2026 it remains open and is one of the Clay Millennium Prize Problems. Anyone claiming a solution needs a proof that survives independent peer review.
Does NP mean “not polynomial”?
No. NP stands for nondeterministic polynomial time. Equivalently, NP problems have certificates that a deterministic machine can verify in polynomial time.
If P = NP, is all encryption instantly broken?
Not instantly. P = NP would undermine the assumptions behind much public-key cryptography in principle, but polynomial degree, constants, encoding and implementation decide practical impact.
Can experiments or benchmarks prove P ≠ NP?
No. Finite benchmarks measure specific algorithms on specific instances. A separation proof must rule out every algorithm for some NP problem beyond polynomial time.
Does quantum computing settle P vs NP?
No known quantum algorithm solves NP-complete problems in polynomial time, and BQP versus NP is itself open. Quantum speedups for some problems do not resolve P vs NP.
References and further reading
- [1] Clay Mathematics Institute — P vs NP — P vs NP is a Millennium Prize Problem and remains open. [verified]
- [2] Stephen Cook — The P versus NP Problem (official description, PDF) — Formal statement of P, NP, NP-completeness and the Cook–Levin theorem. [verified]
- [3] Arora & Barak — Computational Complexity, NP chapter (PDF) — Textbook definitions of NP, certificates, reductions and NP-completeness. [verified]
- [4] Archive of Formal Proofs — Cook–Levin theorem formalization — Machine-checked formalization entry point for Cook–Levin in Isabelle/HOL. [verified]
- [5] Baker, Gill & Solovay (1975) — Relativizations of the P =? NP Question — Oracle worlds where P = NP and where P ≠ NP; basis of the relativization barrier. [unverified]