Cook's classes , , , p-reducibility, -completeness, and the languages SAT and 3-SAT over
DefinitionPvsNPThis bundle fixes, in the namespace PvsNP, the objects of Stephen Cook's official description of the Clay Millennium Prize Problem The P versus NP problem: the classes and (p. 2), polynomial-time reducibility and -completeness (Definitions 3 and 4, p. 4), the exponential-time class (p. 9), and the languages Satisfiability and 3-SAT (p. 5).
Strings and languages. The alphabet is . Str is the set of binary strings, is the length of , and a language is a subset (Language Bool). Cook (p. 2) notes that the problem is independent of the size of the alphabet as long as it has at least two symbols.
Machines and running time. A machine is Mathlib's bundled multi-stack machine Turing.FinTM2: finitely many stacks, among them an input stack and an output stack, a finite set of program labels, a finite internal memory, and a finite input alphabet. The program assigns to each label a statement, which is a finite tree of push/pop/peek/load/branch operations ending in a jump to a label or in a halt. The machine is started with the input string on its input stack, all other stacks empty, the initial memory value and the main label; one step executes one statement. It outputs within steps if after exactly steps it is in the halting configuration with on the output stack, every other stack empty and the memory reset to its initial value. Mathlib's Turing.TM2ComputableInPolyTime ea eb f bundles such a machine, identifications of its input and output alphabets with those of the encodings ea, eb, and a polynomial with natural coefficients such that for every , on input ea a the machine outputs eb (f a) within steps; Turing.TM2ComputableInTime is the same with an arbitrary time function in place of . Cook's bound is equivalent to a bound by a polynomial with natural coefficients.
PolyTimeDecider χ(Cook, p. 1–2: " runs in polynomial time", with iff accepts ): there is a polynomial-time machine computing , the input encoding being the identity on and the output encoding .P(Cook, p. 2): .encodePair (w, y)is Cook's string : the symbols of tagged as "left", followed by the symbols of tagged as "right", over the four-symbol alphabet ; its length is .PolyTimeChecker R(Cook, p. 2: " is polynomial-time iff "): the indicator of a checking relation is computed by a polynomial-time machine on the input , so within steps.NP(Cook, p. 2): iff there are and a polynomial-time checking relation such that for all , .PolyTimeComputable f(Cook, Definition 3): is computed by a polynomial-time machine with identity encodings on both sides.PReducible L₁ L₂(Cook, Definition 3): iff there is a polynomial-time computable with for all .NPComplete L(Cook, Definition 4): and for every .E(Cook, p. 9: " for some Turing machine with for some "): iff there are and a machine computing whose time function satisfies for all , for some , with .
Satisfiability. A literal is a pair , read as the variable if and as if ; a clause is a list of literals; a CNF formula is a list of clauses. Under a truth assignment the literal has value if and if (evalLiteral); a clause is true iff at least one of its literals is (evalClause; the empty clause is false); a formula is true iff all its clauses are (evalCNF; the empty formula is true). Satisfiable F means that some makes true. The binary coding writes every symbol as a two-bit block: encodeLiteral (s,i) is the block , then one block for each binary digit of (least significant first, no digits for ), then the end-of-literal block ; encodeClause is the concatenation of the codes of its literals followed by the end-of-clause block ; encodeCNF is the concatenation of the codes of the clauses. SAT is the set of strings that are the code of some satisfiable formula, and ThreeSAT the set of codes of satisfiable formulas all of whose clauses have exactly three literals.
Formalization Note The alphabet is fixed to throughout (certificates included), following Cook's remark that the problem does not depend on the alphabet. The machine model is Mathlib's multi-stack machine rather than Cook's one-tape Turing machine of the appendix; the two simulate each other with polynomial overhead, and each statement performs a bounded number of stack operations, so all the classes defined here coincide with the standard ones. A machine "outputs" only in the cleaned-up halting configuration (output alone on the output stack, other stacks empty, memory reset); any machine can be made to do this with polynomially many extra steps. In the certificate bound Lean's convention applies. Satisfiability is satisfiability of CNF formulas with the specific coding encodeCNF; strings that are not the code of a formula belong neither to SAT nor to ThreeSAT. Assignments are total functions on all variable indices; in 3-SAT clauses have exactly three literals and may repeat variables.
import Mathlib
/-!
S. Cook, *The P versus NP problem*, Clay Mathematics Institute Millennium Prize Problem
description (2000), pp. 1–5 and p. 9.
The objects of Cook's Section 1: the classes `P` (p. 2) and `NP` (p. 2, via polynomial-time
checking relations), polynomial-time (Karp) reducibility `≤ₚ` (Definition 3), `NP`-completeness
(Definition 4), the exponential-time class `E` (p. 9), and the languages Satisfiability and 3-SAT
(p. 5) as sets of binary strings coding CNF formulas.
Conventions. The alphabet is `Σ = {0,1} = Bool` throughout (Cook, p. 2: the problem is
independent of the alphabet size, provided `|Σ| ≥ 2`); a string is a `List Bool` and a language
is a `Language Bool = Set (List Bool)`. The machine model is Mathlib's bundled multi-stack
machine `Turing.FinTM2` (finitely many stacks, finitely many program labels, finite internal
memory, finite input alphabet), and "computable in polynomial time" is Mathlib's
`Turing.TM2ComputableInPolyTime`: the machine, started with the input on its input stack, halts
within `p(|input|)` steps (`p` a polynomial with natural coefficients) with the required output
on its output stack, every other stack empty and the internal memory reset. Each step executes
one program statement, which is a fixed finite tree of stack pushes/pops/peeks, so this step
count is within a constant factor of the number of elementary operations. Multi-stack machines
and Turing machines simulate each other with polynomial overhead, so `P`, `NP`, `≤ₚ` and
`NP`-completeness below are the standard classes (Cook, p. 1: "`P` is a robust class and has
equivalent definitions over a large class of computer models").
-/
namespace PvsNP
open Computability Turing
/-- A binary string `w ∈ Σ*` with `Σ = {0,1}`. -/
abbrev Str := List Bool
/-! ### Polynomial-time computation -/
/-- Cook, p. 1–2: a decision procedure `χ : Σ* → {0,1}` runs in polynomial time. There is a
bundled multi-stack machine and a polynomial `p` (natural coefficients) such that, for every
string `w`, the machine started with `w` on its input stack halts within `p(|w|)` steps with the
single symbol `χ w` on its output stack. `χ w = true` means "accept". -/
def PolyTimeDecider (χ : Str → Bool) : Prop :=
Nonempty (TM2ComputableInPolyTime (id : Str → Str) encodeBool χ)
/-- Cook, p. 2: the class `P` of languages `L ⊆ Σ*` accepted by some Turing machine that runs in
polynomial time, i.e. `L = {w | χ w = true}` for some polynomial-time decision procedure `χ`. -/
def P : Set (Language Bool) :=
{L | ∃ χ : Str → Bool, PolyTimeDecider χ ∧ ∀ w, w ∈ L ↔ χ w = true}
/-- Cook, p. 2: the string `w#y` coding a pair `(w, y)` of strings. The symbols of `w` are tagged
with `Sum.inl` and those of `y` with `Sum.inr`, so the input alphabet is `Bool ⊕ Bool` (four
symbols) and the boundary between `w` and `y` is visible to the machine, exactly as with Cook's
separator symbol `#`. Its length is `|w| + |y|`. -/
def encodePair (x : Str × Str) : List (Bool ⊕ Bool) :=
x.1.map Sum.inl ++ x.2.map Sum.inr
/-- Cook, p. 2: a checking relation `R ⊆ Σ* × Σ*`, given as its indicator `R : Σ* × Σ* → {0,1}`,
is polynomial-time: the language `L_R = {w#y | R(w,y)}` is decided by a multi-stack machine
within `p(|w| + |y|)` steps for some polynomial `p`. -/
def PolyTimeChecker (R : Str × Str → Bool) : Prop :=
Nonempty (TM2ComputableInPolyTime encodePair encodeBool R)
/-- Cook, p. 2: the class `NP`. A language `L` is in `NP` iff there are `k ∈ ℕ` and a
polynomial-time checking relation `R` such that for all `w ∈ Σ*`,
`w ∈ L ⟺ ∃ y (|y| ≤ |w|^k and R(w,y))`. -/
def NP : Set (Language Bool) :=
{L | ∃ (R : Str × Str → Bool) (k : ℕ), PolyTimeChecker R ∧
∀ w, w ∈ L ↔ ∃ y : Str, y.length ≤ w.length ^ k ∧ R (w, y) = true}
/-- Cook, Definition 3: a function `f : Σ* → Σ*` is polynomial-time computable: a multi-stack
machine started with `w` on its input stack halts within `p(|w|)` steps with `f w` on its output
stack, for some polynomial `p`. -/
def PolyTimeComputable (f : Str → Str) : Prop :=
Nonempty (TM2ComputableInPolyTime (id : Str → Str) (id : Str → Str) f)
/-- Cook, Definition 3: `L₁ ≤ₚ L₂` (`L₁` is p-reducible to `L₂`) iff there is a polynomial-time
computable `f : Σ* → Σ*` with `x ∈ L₁ ⟺ f(x) ∈ L₂` for all `x ∈ Σ*`. -/
def PReducible (L₁ L₂ : Language Bool) : Prop :=
∃ f : Str → Str, PolyTimeComputable f ∧ ∀ x, x ∈ L₁ ↔ f x ∈ L₂
/-- Cook, Definition 4: `L` is `NP`-complete iff `L ∈ NP` and `L' ≤ₚ L` for every `L' ∈ NP`. -/
def NPComplete (L : Language Bool) : Prop :=
L ∈ NP ∧ ∀ L' ∈ NP, PReducible L' L
/-- Cook, p. 9: the class `E` of languages recognizable in exponential time, `L = L(M)` for a
Turing machine `M` with worst-case running time `T_M(n) = O(2^{cn})` for some `c`. Here the
machine is a multi-stack machine with a time function `t : ℕ → ℕ` (a bound on the number of steps
on inputs of length `n`) satisfying `t n ≤ C · 2^{c·n}` for all `n`, for some constants `c, C`. -/
def E : Set (Language Bool) :=
{L | ∃ χ : Str → Bool,
(∃ M : TM2ComputableInTime (id : Str → Str) encodeBool χ,
∃ c C : ℕ, ∀ n, M.time n ≤ C * 2 ^ (c * n)) ∧
∀ w, w ∈ L ↔ χ w = true}
/-! ### Satisfiability -/
/-- A propositional literal `(s, i)`: the variable `xᵢ` if `s = true`, its negation `¬xᵢ` if
`s = false`. -/
abbrev Literal := Bool × ℕ
/-- A clause: a disjunction of literals, given as a list. -/
abbrev Clause := List Literal
/-- A formula in conjunctive normal form (CNF): a conjunction of clauses, given as a list. -/
abbrev CNF := List Clause
/-- The truth value of a literal under a truth assignment `τ : ℕ → Bool` to the variables. -/
def evalLiteral (τ : ℕ → Bool) (l : Literal) : Bool :=
if l.1 then τ l.2 else !τ l.2
/-- A clause is true under `τ` iff at least one of its literals is (the empty clause is false). -/
def evalClause (τ : ℕ → Bool) (c : Clause) : Bool :=
c.any (evalLiteral τ)
/-- A CNF formula is true under `τ` iff all of its clauses are (the empty formula is true). -/
def evalCNF (τ : ℕ → Bool) (F : CNF) : Bool :=
F.all (evalClause τ)
/-- Cook, p. 5: a formula `F` is satisfiable iff some truth assignment makes it true. -/
def Satisfiable (F : CNF) : Prop :=
∃ τ : ℕ → Bool, evalCNF τ F = true
/-- Binary coding of a literal `(s, i)`: the sign bit followed by the binary digits of `i`
(least significant first, no leading zeros), each written as the two-bit block `0b`, followed by
the end-of-literal marker `10`. Its length is `2 · (⌈log₂(i+1)⌉ + 2)`. -/
def encodeLiteral (l : Literal) : Str :=
((l.1 :: Nat.bits l.2).flatMap fun b => [false, b]) ++ [true, false]
/-- Binary coding of a clause: the codes of its literals in order, followed by the end-of-clause
marker `11`. -/
def encodeClause (c : Clause) : Str :=
c.flatMap encodeLiteral ++ [true, true]
/-- Cook, p. 5, "standard coding methods": the binary code of a CNF formula is the concatenation
of the codes of its clauses. Every symbol is a two-bit block (`0b` = data bit `b`, `10` = end of
literal, `11` = end of clause), so the code can be parsed unambiguously from left to right, and
its length is linear in the number of literals times the number of bits of the variable indices.
The empty formula is coded by the empty string. -/
def encodeCNF (F : CNF) : Str :=
F.flatMap encodeClause
/-- Cook, p. 5: Satisfiability, as a language over `{0,1}`: the set of strings coding a
satisfiable CNF formula. Strings that code no formula are not in `SAT`. -/
def SAT : Language Bool :=
{w | ∃ F : CNF, encodeCNF F = w ∧ Satisfiable F}
/-- Cook, p. 5: 3-SAT, the set of strings coding a satisfiable CNF formula in which every clause
has exactly three literals. -/
def ThreeSAT : Language Bool :=
{w | ∃ F : CNF, encodeCNF F = w ∧ (∀ c ∈ F, c.length = 3) ∧ Satisfiable F}
end PvsNP
Read-back
What the Lean code literally says, in plain math · claude-fable-5-1
Str
is an abbreviation for the type of finite lists of Booleans, i.e. finite bit strings with each , including the empty string of length . Its length is written . (Everywhere below, a "language over " means an arbitrary subset ; membership is plain set membership, and no decidability or definability of is assumed.)
PolyTimeDecider
For a total function , is the proposition that there exists at least one "polynomial-time machine computing " in the following exact sense (Mathlib's TM2ComputableInPolyTime with input encoding the identity on bit strings and output encoding ). A machine is a bundled multi-stack machine (Mathlib's TM2 model, FinTM2) consisting of: a finite index set of stacks (with decidable equality); two distinguished indices (input stack) and (output stack), which are allowed to coincide; for each a type of stack symbols, where only is required to be finite; a finite set of program labels with a distinguished label ; a finite set of internal states with a distinguished initial state ; and a program assigning to every label a statement . A statement is a finite tree built from the constructors: push onto stack the symbol , where is an arbitrary function of the current internal state , then continue with a sub-statement; peek at the top symbol of stack (or "empty") and replace the internal state by for an arbitrary function , then continue; pop, which is peek followed by removal of the top symbol of stack (popping an empty stack leaves it empty), then continue; load, replacing the internal state by for an arbitrary , then continue; branch between two sub-statements according to an arbitrary predicate of the internal state; goto, which sets the current label to for an arbitrary and ends the statement; and halt, which sets the current label to "none" and ends the statement. A configuration is a triple (current label, which is either some or "none"; current internal state ; the contents of every stack as a finite list over whose first entry is the top of the stack). One step of the machine from a configuration with label executes the whole statement down to its terminating goto or halt (however many pushes, pops, peeks, loads and branches that statement contains) and returns the resulting configuration; a configuration with label "none" has no successor. Time is the number of steps in this sense. The initial configuration on an input list over has label , internal state , stack equal to (first symbol of on top), and every other stack empty. The halting configuration for an output list over has label "none", internal state equal to the initial state , stack equal to (first symbol on top), and every other stack empty (in particular, if the input stack must have been emptied). Now asserts the existence of: such a machine ; a bijection (so the input alphabet has exactly two symbols); a bijection ; a polynomial with natural-number coefficients; and, for every bit string , a natural number with
such that iterating the step function exactly times from the initial configuration on input (the string transported symbolwise into ) yields exactly the halting configuration whose output stack is the one-symbol list ; here iteration is understood so that once a configuration has no successor all later iterates are "no configuration", so the requirement says that the machine is not yet halted before step and at step is in precisely that halting configuration (label none, state , stack , all other stacks empty). Since the initial configuration has a label and the halting one has none, necessarily . No computability restriction is placed on the functions inside statements beyond the finiteness of , and ; stacks other than may have infinite symbol types.
P
is the set of languages over for which there exists a total function such that (i) holds, i.e. there exists a bundled multi-stack machine in Mathlib's TM2 model (finitely many stacks; finite input-stack alphabet in bijection with ; output-stack alphabet in bijection with ; finitely many labels and internal states; one step = full execution of one labelled statement, made of arbitrarily many push/pop/peek/load/branch operations ending in a goto or halt) together with a polynomial such that for every , started with on the input stack (first symbol on top), initial internal state, all other stacks empty, and label , the machine reaches after exactly some steps the configuration with label "none", internal state equal to the initial state, output stack exactly the one-symbol list (transported through the alphabet bijection), and all other stacks empty; and (ii) for every ,
So is exactly the set of strings on which outputs ; nothing is asserted about beyond the existence of such a and such a machine.
encodePair
For a pair of bit strings, is the list over the four-element alphabet (disjoint union, with left and right copies) obtained by tagging every symbol of as a left-copy symbol, every symbol of as a right-copy symbol, and concatenating:
Its length is ; either component may be empty.
PolyTimeChecker
For a total function , is the proposition that there exists at least one machine computing in polynomial time in the following exact sense (Mathlib's TM2ComputableInPolyTime with input encoding and output encoding ). The machine model is Mathlib's bundled TM2 multi-stack machine: a finite index set of stacks (decidable equality), distinguished input index and output index (possibly equal), a symbol type for each stack with only required finite, a finite label set with distinguished label , a finite internal-state set with initial state , and a program , where a statement is a finite tree of push (push onto a chosen stack, arbitrary), peek (update the state by an arbitrary function of the state and the top symbol-or-empty), pop (peek and then remove the top; popping an empty stack is a no-op on the stack), load (arbitrary state update), branch (on an arbitrary predicate of the state), ending in goto (set label to an arbitrary function of the state) or halt (set label to "none"). A configuration is (label or none, internal state, contents of all stacks as lists with head = top); one step executes the entire statement of the current label; a configuration with label none has no successor; time is the number of steps. asserts the existence of such a machine, a bijection (so the input alphabet has exactly four symbols), a bijection , a polynomial with natural-number coefficients, and for every pair a natural number with
such that, starting from the configuration with label , internal state , stack holding (the left-tagged symbols of followed by the right-tagged symbols of , first symbol on top) and all other stacks empty, exactly iterations of the step function lead to precisely the configuration with label "none", internal state (the initial state again), stack equal to the one-symbol list , and every other stack empty (iterates past a halted configuration count as "no configuration", so the machine must halt exactly at step in exactly that configuration). Note that the time bound is a polynomial in the combined length , not in alone.
NP
is the set of languages over for which there exist a total function and a natural number (with allowed) such that (i) holds, i.e. there is a bundled TM2 multi-stack machine (finitely many stacks, finite input alphabet in bijection with the four-element set , output alphabet in bijection with , finitely many labels and internal states, one step = complete execution of one labelled statement) and a polynomial such that for every , started with the tagged concatenation on the input stack, initial state, other stacks empty, label , the machine halts after exactly some steps in the configuration with label none, internal state equal to the initial state, output stack exactly (through the alphabet bijection) and all other stacks empty; and (ii) for every ,
Here is natural-number exponentiation with the convention for all (including ); thus for the certificate must have length at most , and for and the only admissible certificate is . The bound on is , and ranges over all bit strings of that length or shorter.
PolyTimeComputable
For a total function , is the proposition that there exists at least one machine computing in polynomial time in the following exact sense (Mathlib's TM2ComputableInPolyTime with both input and output encodings the identity on bit strings). The machine is a bundled TM2 multi-stack machine: a finite index set of stacks (decidable equality), input index and output index (possibly equal), symbol types with only required finite, a finite label set with distinguished , a finite state set with initial state , and a program assigning to each label a statement, i.e. a finite tree of push/peek/pop/load/branch operations (each driven by arbitrary functions of the finite internal state and, for peek/pop, of the top symbol-or-empty of the chosen stack; popping an empty stack leaves it empty) terminated by goto (label becomes an arbitrary function of the state) or halt (label becomes "none"). A configuration is (label or none, state, all stack contents as lists with head = top); one step executes the whole statement of the current label; halted configurations (label none) have no successor; time is the number of steps. asserts the existence of such a machine, bijections and , a polynomial with natural-number coefficients, and for every a natural number with
such that from the initial configuration (label , state , stack with the first symbol of on top, all other stacks empty) exactly steps lead to precisely the configuration with label "none", state , stack (the whole output string, first symbol on top) and all other stacks empty. The time bound depends only on ; the length of is not separately constrained (it is implicitly bounded by what can be pushed in steps, but no explicit bound appears).
PReducible
For two languages over , is the proposition that there exists a total function such that (i) holds, i.e. there is a bundled TM2 multi-stack machine (finitely many stacks; input and output stack alphabets each in bijection with ; finitely many labels and internal states; one step = complete execution of one labelled statement) and a polynomial such that for every , started with on the input stack, initial state, other stacks empty and label , the machine halts after exactly some steps in the configuration with label none, internal state equal to the initial state, output stack exactly and all other stacks empty; and (ii) for every ,
This is a many-one reduction by a single total function; the equivalence is required for all , including .
NPComplete
For a language over , is the conjunction of two statements: (i) , i.e. there exist and with (a bundled TM2 multi-stack machine over the four-symbol tagged input alphabet, with a polynomial , halting on input after at most full-statement steps in the configuration with label none, initial internal state, output stack and all other stacks empty) and for all ; and (ii) for every language (in the same sense), holds, i.e. there is a total computed by some bundled TM2 machine with two-symbol input and output alphabets within a polynomial number of steps in (halting in the configuration with label none, initial state, output stack , other stacks empty) such that for all .
E
is the set of languages over for which there exists a total function such that (i) there exist a machine-with-time-bound of Mathlib's type TM2ComputableInTime (input encoding the identity on bit strings, output encoding ) computing , together with natural numbers such that for every ,
and (ii) for every , . Here consists of: a bundled TM2 multi-stack machine (finite index set of stacks with decidable equality; input index and output index , possibly equal; symbol types with only required finite; finite label set with distinguished ; finite state set with initial state ; program assigning to each label a statement, i.e. a finite tree of push/peek/pop/load/branch operations driven by arbitrary functions of the state and top-of-stack, ending in goto or halt); bijections and ; an arbitrary time function (not required to be a polynomial); and, for every , a number of steps such that from the initial configuration (label , state , stack with first symbol on top, all other stacks empty) exactly applications of the step function (one step = complete execution of the current label's statement; halted configurations have no successor) yield precisely the configuration with label "none", state , stack and all other stacks empty. The exponent may be , in which case the bound is the constant ; if the bound forces , which cannot be met since at least one step is needed to pass from a labelled to an unlabelled configuration, so any witness has . The bound must hold for all , including .
Literal
is an abbreviation for the type : a literal is a pair of a sign bit and a variable index (variables are indexed by all natural numbers, starting at ). No further structure is imposed here; the meaning of the sign is fixed only by below.
Clause
is an abbreviation for finite lists of literals, i.e. finite sequences with ; the empty clause is allowed, repeated literals are allowed, and a clause may contain both and for the same . Order is part of the data (a clause is a list, not a set).
CNF
is an abbreviation for finite lists of clauses, i.e. finite sequences of clauses with ; the empty formula is allowed, repeated clauses are allowed, and order is part of the data.
evalLiteral
For an assignment (a total function on all variable indices) and a literal , is the Boolean
So sign denotes the positive literal and sign the negated literal .
evalClause
For an assignment and a clause , is if and only if there exists some with (the disjunction of the literal values); in particular the empty clause evaluates to under every .
evalCNF
For an assignment and a formula , is if and only if for every (the conjunction of the clause values); in particular the empty formula evaluates to under every , and any formula containing an empty clause evaluates to under every .
Satisfiable
For a formula , is the proposition that there exists a total assignment (defined on all natural-number indices, not only those occurring in ) with , i.e. every clause of contains at least one literal with . The empty formula is satisfiable; a formula containing an empty clause is not.
encodeLiteral
For a literal , is the bit string built as follows. Let denote the binary digits of listed least-significant first with no leading zeros, so , , , , and for the list has length and ends in (writing for and for ). Form the list (the sign bit followed by the digits of , so ), replace each entry by the two-symbol block , concatenate, and append the terminator :
Its length is . For example and .
encodeClause
For a clause , is the concatenation followed by the two-symbol terminator (writing for ). The empty clause encodes as .
encodeCNF
For a formula , is the concatenation with no additional delimiter; the empty formula encodes as the empty string .
SAT
is the language over consisting of all bit strings for which there exists a formula (a finite list of finite lists of sign/index pairs) with
where is the concatenation over clauses of (concatenation over literals of the blocks with the least-significant-first binary digits of without leading zeros, followed by ), and means some total assignment makes every clause of contain a literal with . Strings that are not the encoding of any formula are not in ; the empty string is in (it encodes the empty formula, which is satisfiable). Membership only requires some formula with encoding to be satisfiable; no injectivity of the encoding is asserted in the definition.
ThreeSAT
is the language over consisting of all bit strings for which there exists a formula such that
with and as in (encoding: per literal the blocks with the least-significant-first binary digits of , per clause a trailing , clauses concatenated; satisfiability: some total makes each clause contain a literal with ). "Length exactly " counts list entries, so a clause such as or one containing both and qualifies; the condition is vacuous for the empty formula, so the empty string is in . Strings not encoding any formula all of whose clauses have length are excluded.