This section introduces the basics of computability and complexity theory. These topics are not very important in OI (though they are still somewhat useful: if you encounter an NP-hard problem, you may assume that no polynomial-time solution exists), so you can read them out of interest or as preparation for later study.
Many conclusions in this article are stated without proof; if you are interested, you can look up the relevant proofs yourself.
Prerequisite knowledge: time complexity.
Problems
Languages
An alphabet is a nonempty finite set whose elements are called symbols/characters.
Let denote the strings formed by concatenating a nonnegative number of characters from . A language over the alphabet is a subset of .
Note that “language” here is an abstract concept. Ordinary strings form a language, and the set of all directed acyclic graphs can also be a language (a bijection can be established between binary strings and directed graphs; the details are not needed here).
Since every language can be converted into binary-string form, below we take unless stated otherwise.
Decision Problems
A decision problem is a problem whose answer can only be YES or NO. Essentially, it asks whether a string belongs to a language: defines a decision problem over alphabet and language . For example, “deciding whether a graph is a directed acyclic graph” is a decision problem.
Decision problems are often studied in computability theory because of their simplicity. Unless stated otherwise, “problem” in this article means “decision problem”; some statements can of course be extended to other kinds of problems.
A language may also refer to the decision problem of determining whether a string belongs to it. Thus, “language” and “problem” can be treated as synonyms.
Functional Problems
A functional problem can have answers other than YES or NO, such as a number. For example, “find the sum of two numbers” is a functional problem.
Every functional problem can be converted into a decision problem. For example, “find the sum of two numbers” can become “decide whether the sum of two numbers equals a third number”.
A decision problem can also be converted into a functional problem: compute its indicator function, namely the in the definition above.
Turing Machines
Deterministic Turing Machines
Unless stated otherwise, “Turing machine” usually means “deterministic Turing machine”, and that is the convention here.
There are many definitions of a Turing machine. We use one of them here; Turing machines under other definitions generally have equivalent computational power.
A Turing machine is a machine operating on a tape that extends infinitely in both directions and is divided into cells. It has internal states and a head that can modify the tape and move along it.
Formally, a Turing machine is a 7-tuple , where:
- is a finite nonempty set of states;
- is a finite nonempty tape alphabet;
- is the blank symbol, the only symbol that may appear on the tape infinitely often during computation;
- is the input alphabet, whose symbols may appear on the initial tape (the input);
- is the initial state;
- is the set of accepting states. If a Turing machine halts in an accepting state, the contents of its initial tape are said to be accepted by the machine.
- is a partial function called the transition function (a function defined only on a subset of its domain). If is undefined for the current state, the Turing machine halts.
Starting from the initial state and the beginning of the tape, the Turing machine acts at each step according to its current internal state and the symbol in the cell currently under the head: if is undefined, it halts; otherwise, if , it changes the internal state to , changes the symbol in the cell to , and moves one cell left if is or one cell right if is $R.
In fact, knowing the operational details of a Turing machine is unnecessary; an intuitive understanding is enough.
The output of Turing machine on input is denoted by ( if and only if accepts ; if and only if halts after finitely many steps on input without accepting ). Multiple parameters may also be placed in the parentheses and separated by commas; in an implementation, a symbol representing a comma can be added to the alphabet.
The time complexities of Turing machines and von Neumann computers for solving problems differ only polynomially, so Turing machines can be used as a computational model when studying complexity classes.
Nondeterministic Turing Machines
A nondeterministic Turing machine is a type of Turing machine. Unlike a deterministic Turing machine, which can transition to only one state at each step, it can “simultaneously” transition to multiple states and compute along multiple “branches” in parallel. If any branch halts in an accepting state, the nondeterministic Turing machine accepts the input.
In fact, any deterministic Turing machine can simulate the polynomial-time behavior of a nondeterministic Turing machine in exponential time using a method similar to iterative deepening search.
In real life, a deterministic Turing machine is analogous to a single-core processor supporting only serial processing, while a nondeterministic Turing machine is analogous to an ideal multicore processor supporting parallel processing of unlimited size.
Multitape Turing Machines
A standard Turing machine operates on only one tape, but for convenience this article studies multitape Turing machines. For a -tape machine, one tape is a read-only input tape, while the remaining tapes are readable and writable, and one of these tapes is used as the output tape.
A multitape Turing machine must have finitely many tapes.
For a multitape Turing machine, its space usage is the number of cells visited by the heads on tapes other than the input tape.
Encoding Turing Machines
Turing machines can be encoded by natural numbers: there is a surjective function such that every natural number corresponds to a Turing machine, while every Turing machine has infinitely many encodings. Therefore, a set consisting of Turing machines can be a language.
Let denote the Turing machine encoded by the natural number .
Universal Turing Machine
There exists a Turing machine such that:
- If halts in finite time on input , then ; otherwise, does not halt in finite time;
- If, for every , halts in time on input , then, for every , halts in time.
In other words, there is a universal Turing machine that can simulate any Turing machine, with only a logarithmic slowdown relative to the simulated machine's running time.
Computability
Uncomputable Problems
For a decision problem, if there is a Turing machine that always halts in finitely many steps and decides it correctly, the problem is Turing-computable; otherwise, it is Turing-uncomputable.
Because Turing machines can be encoded by natural numbers, there are countably infinitely many Turing machines, whereas there are uncountably many languages (sets of binary strings). Since each Turing machine decides at most one language, uncomputable problems must exist.
Halting Problem
The halting problem is a classic Turing-uncomputable problem: given and , decide whether halts in finitely many steps on input .
Proof that the Halting Problem Is Turing-Uncomputable
Define by:
We first prove that is Turing-uncomputable:
Suppose a Turing machine computes . By the definition of , we get , while by the assumption that computes , we get , a contradiction. Thus the assumption is false, and no Turing machine computes .
Let be a Turing machine that solves the halting problem, so that decides whether halts in finitely many steps on input . We can then construct a Turing machine that computes :
first calls . If it outputs , then ; otherwise, uses a universal Turing machine to simulate the computation and obtain the answer.
Since is Turing-uncomputable, does not exist; in other words, the halting problem is Turing-uncomputable.
Church–Turing Thesis
The Church–Turing thesis states that if a class of problems has an effective method of solution, then the class can be solved by some Turing machine.
Here, an “effective method” must satisfy:
- contain finitely many clear instructions;
- when used to solve one problem in the class, terminate in finitely many steps and produce the correct answer.
This thesis has not been proved, but it is a basic axiom of computability theory.
Complexity Classes
There are many complexity classes; this article introduces only a small selection of the more common ones.
R and RE
For a language and Turing machine , if halts in finitely many steps on every input and , then is said to decide .
For a language and Turing machine , if halts in finitely many steps for every input in and , then is said to recognize .
The complexity class is the set of languages decidable by some Turing machine, namely all Turing-computable languages.
The complexity class is the set of languages recognizable by some Turing machine. is also called the class of recursively enumerable languages.
By definition, .
DTIME
If a deterministic Turing machine decides a language and halts in time for every input , then the language belongs to .
P
The complexity class consists of decision problems solvable by a deterministic Turing machine in polynomial time, namely:
Linear programming, computing the greatest common divisor, and the decision version of finding a maximum matching in a graph are all problems in .
EXPTIME
The complexity class consists of decision problems solvable by a deterministic Turing machine in exponential time, namely:
A weakened version of the halting problem—given an encoding of a Turing machine and a positive integer , decide whether the machine halts within steps—is in . Its solution takes time, while can be encoded as a binary string of length .
NTIME
If a nondeterministic Turing machine decides a language and halts in time for every input , then the language belongs to .
NP
The complexity class consists of decision problems solvable by a nondeterministic Turing machine in polynomial time, namely:
Every problem in is in . For more problems in , see the NPC and NP-intermediate problems below.
NP-hard
If every problem in can be reduced to problem in polynomial time, then is NP-hard.
In other words, if NP-hard problem could be solved in one unit of time, then every problem in could be solved in polynomial time.
NP-complete
If a problem is both in and NP-hard, it is NP-complete, or an NPC problem.
Classic NPC problems include the decision versions of the traveling salesperson, maximum independent set, minimum vertex cover, longest path, and 0–1 integer programming problems, as well as set cover, graph coloring, knapsack, three-dimensional matching, and the decision version of maximum cut.
The functional version of an NPC problem is often NP-hard. For example, “decide whether a graph contains a clique of size ” is both in and NP-hard, so it is an NPC problem; its functional version, “find the maximum clique of a graph”, is not an NPC problem but is still NP-hard.
Similarly, other complexity classes have “XX-complete” problems; for example, every problem in can be reduced in polynomial time to an EXPTIME-complete problem.
co-NP
A problem is in if and only if its complement is in . If “problem” is understood as “language”, and a language is a subset of , the meaning of “complement” is clear.
For example, “given subsets, decide whether of them can cover the entire set” is an NPC problem, while its complement, “given subsets, decide whether no choice of subsets can cover the entire set”, is in . If the answer to the first problem is YES, we have found a counterexample to the second, whose answer is therefore NO.
NP-intermediate
A problem in that is neither in nor NPC is called an NP-intermediate problem.
As far as currently known, graph isomorphism, discrete logarithm, and integer factorization may be NP-intermediate.
Ladner's theorem states that if , then an NP-intermediate problem must exist.
NEXPTIME
The complexity class consists of decision problems solvable by a nondeterministic Turing machine in exponential time, namely:
#P
Problems in are not decision problems, but counting problems about problems: counting the number of solutions to an problem is a problem. Equivalently, counting the number of branches of a nondeterministic Turing machine that always halts in polynomial time on which a string is accepted is a problem.
Counting matchings or perfect matchings in an ordinary graph or a bipartite graph is #P-complete; the corresponding decision problem is “decide whether a graph has a (perfect) matching”.
DSPACE
If a deterministic Turing machine can decide a language using space on input , then the language belongs to .
-
,that is, the regular languages, namely the languages decidable by automata.
-
,Note that the space used by a Turing machine does not include the space occupied by the input.
-
-
NSPACE
If a nondeterministic Turing machine can decide a language using space on input , then the language belongs to .
-
-
-
,that is, the context-sensitive languages.
-
-
Polynomial Time
Simply put, if there is a positive number such that an algorithm has time complexity (not ), where is the problem size (the input length), then the algorithm runs in polynomial time. If a problem has a polynomial-time algorithm on a deterministic Turing machine, it belongs to .
Polynomial time can be divided into strongly and weakly polynomial time; there is also pseudo-polynomial time.
Strongly Polynomial Time
First define a computational model called the arithmetic model. In it, arithmetic operations on numbers (addition, subtraction, multiplication, division, and comparison) take unit time (that is, time regardless of the numbers' sizes).
If an algorithm uses a polynomial number of operations in the number of input numbers in the arithmetic model, and its space complexity is polynomial in the input size (rather than the number of numbers), then it runs in strongly polynomial time. Since arithmetic operations can be performed in polynomial time in the input size (the logarithm of the numbers' sizes) in the usual model, every strongly polynomial-time algorithm is polynomial-time.
In general, the time complexity of a strongly polynomial-time algorithm is independent of the value range.
Weakly Polynomial Time
If an algorithm is polynomial-time but not strongly polynomial-time, it is weakly polynomial-time.
For example, Euclid's algorithm for computing the greatest common divisor has time complexity , where and are the input numbers, and is weakly polynomial-time.
Pseudo-Polynomial Time
If an algorithm's running time is polynomial in the value range, it is pseudo-polynomial-time. A pseudo-polynomial-time algorithm may or may not be polynomial-time. It may fail to be polynomial-time because a positive integer of size generally needs only bits, so a value-polynomial algorithm is often exponential in the input length. Although it can technically be polynomial-time, calling an algorithm pseudo-polynomial-time generally means that it is not polynomial-time.
For example, knapsack is NP-hard but has a dynamic-programming pseudo-polynomial-time solution.
If an NPC/NP-hard problem has a pseudo-polynomial-time solution, it is called a weakly NPC/weakly NP-hard problem. If an NPC/NP-hard problem has no pseudo-polynomial-time solution assuming , it is called a strongly NPC/strongly NP-hard problem.
Constructible Functions
Time-Constructible Functions
Sometimes we want a Turing machine to know how much time it has used, for example to force it to halt after steps. This is impossible if computing itself takes longer than . Time-constructible functions are defined to avoid this issue.
If there is a Turing machine that, on input ( ones), halts in time and outputs the binary representation of (the output here is a string, not acceptance or rejection, and can be written on the tape), then is time-constructible.
Since reading the input takes time, no nonconstant function in is time-constructible.
Space-Constructible Functions
Space-constructible functions can be defined similarly.
If there is a Turing machine that, on input ( ones), halts using space and outputs the binary representation of , then is space-constructible.
Relations Between Complexity Classes
Time Hierarchy Theorems
Deterministic Time Hierarchy Theorem
If is time-constructible, then:
The deterministic time hierarchy theorem gives .
Proof of the Deterministic Time Hierarchy Theorem
Define the language . Since is time-constructible, can be decided from this definition in time, so .
Now suppose , and let be the Turing machine that decides in time.
Let the running time of the universal Turing machine as a function of be . From the discussion of universal Turing machines above, , so for sufficiently large , .
Let be a sufficiently large . Then must halt within time, giving , a contradiction. Thus the assumption is false, proving the deterministic time hierarchy theorem.
Nondeterministic Time Hierarchy Theorem
If is time-constructible and , then .
The nondeterministic time hierarchy theorem gives .
Space Hierarchy Theorem
If is space-constructible and , then .
Here may denote either or .
The space hierarchy theorem gives .
Savitch's Theorem
A deterministic Turing machine can simulate a nondeterministic Turing machine using the square of its space consumption (although it may use much more time), namely:
If , then:
Corollary: and .
P?=NP
Whether the complexity classes and are equal is a famous open problem in computational complexity theory.
If , then , but the converse does not follow (there is currently no way to prove from ).
Why Isn't NP?=co-NP Obvious?
Because an problem and its corresponding problem have opposite answers, it is tempting to think that, for a problem, we can simply reverse the output of the nondeterministic Turing machine that solves its complement, and thus obtain .
In fact, this method does solve the problem, but it does not produce a nondeterministic Turing machine that solves it. If a machine reverses the output of a nondeterministic Turing machine, it is not itself a nondeterministic Turing machine: a nondeterministic Turing machine accepts when some branch accepts and rejects when all branches reject. Reversing the output would make it accept when all branches accept and reject when one branch rejects, which does not match the definition of a nondeterministic Turing machine. Thus, solving this problem with that machine for this problem does not make the problem an problem.
If , then .
If , then NP-intermediate is nonempty.
References
-
Computational Complexity (1): Automata and Regular Languages;
-
Computational Complexity (2): Turing Machines and Computability;
-
Wikipedia relevant entries and their references.