A proof that a problem is NP-complete has five parts: a verifier, its cost, a reduction from a
known NP-complete problem, the reduction's cost, and the combination. Here they are for
Clique, following Complexity/Computability/Complexity/Problems/Clique.lean.
An instance is a graph and a target size. The graph has a clique of that size when some set of
its declared vertices is pairwise adjacent and has exactly that many elements:
The certificate is a mask over the vertex list. The verifier keeps the masked vertices, checks
that there are as many as the target, and checks that each two of them are adjacent. Graph
problems that ask for a set of vertices with a pairwise property share this verifier,
Graph.verifySubset, and its correctness lemma Graph.isVerifier_verifySubset,
which leaves only the pairwise test to check:
The certificate length is Polynomial.X, one bit per bit of the encoded instance, which is at
least one bit per vertex. The verifier is executable, so you can test it on a triangle:
A set of vertices is independent in a graph exactly when it is a clique in the complement graph
on the same vertices (Graph.compl), so complementing reduces IndependentSet to
Clique. The correctness half is Graph.compl_mem_Clique_iff. The complement keeps
every pair of distinct declared vertices that no edge joins:
A new problem follows the same outline. Define it with its encoding, give a verifier and prove
IsVerifier, certify the verifier, give a reduction map from a problem in the catalogue and
prove it correct, certify the map, and combine. Put it in its own module under
Complexity/Computability/Complexity/Problems/, next to the problems it reduces from.