L and NL
Imagine a maze so vast that writing down the full map exceeds your notebook's capacity. Yet you must decide whether an exit exists. Surprisingly, you can solve this with almost no scratch paper at all. You need just enough to remember your current position and a step counter. This is the world of logarithmic space complexity. Here, the resource under scrutiny is not time but memory. The memory budget is so tight that the machine cannot even store the entire input. The classes L and NL capture deterministic and nondeterministic computation restricted to logarithmic work space. They matter because many practical problems turn out to be solvable with astonishingly little memory. These include graph connectivity, evaluating branching programs, and checking membership in regular languages. The memory needed is far less than the size of the input itself. Understanding exactly what logarithmic space can and cannot do reveals deep structural facts about computation. It connects directly to circuit complexity, database query languages, and the design of streaming and read-only-memory algorithms in real systems. This article builds on Measuring Space Complexity and Savitch's Theorem to develop the theory of L and NL rigorously. We define these classes precisely using the standard multi-tape convention. This convention uses a read-only input tape and a separate read/write work tape. We explain why this convention is essential. We also introduce PATH (directed graph reachability) as the canonical NL-complete problem. We then prove the celebrated Immerman–Szelepcsényi theorem, which shows NL = coNL. This is a symmetry that has no known analogue at the polynomial-time level. By the end, you will be able to place problems inside L or NL with confidence. You will reduce reachability-type problems to and from PATH. You will also appreciate why the certificate-based intuition for nondeterministic space differs sharply from nondeterministic time. This sets the stage for the The Space Hierarchy Theorem. It shows that giving a machine even slightly more space provably increases its power.
- L = languages decidable by a deterministic Turing machine using O(log n) work-tape space; NL is the nondeterministic analogue.
- The read-only input tape convention is essential — otherwise no non-trivial language could be recognized in sublinear space.
- PATH (s-t reachability in a directed graph) is NL-complete under log-space reductions, and it is solvable in NL by guessing a path vertex by vertex.
- Savitch's theorem gives PATH ∈ SPACE(log² n) deterministically, showing NL ⊆ SPACE(log² n).
- The Immerman–Szelepcsényi theorem proves NL = coNL by an inductive counting technique that computes the number of reachable vertices without extra space.
- L ⊆ NL ⊆ P, and whether L = NL is a major open problem, closely tied to the broader P vs. NP landscape.
Logarithmic space is enough memory to remember "where you are" in an exponentially large space of configurations, and nondeterministic log-space reachability (NL) is exactly as powerful as its complement (coNL), a symmetry proved by cleverly counting reachable vertices without ever writing down the full set.
The idea
A Turing machine is said to run in space s(n) if, on inputs of length n, it never uses more than s(n) cells of work-tape memory. The class L (also written LOGSPACE) consists of all languages decidable by a deterministic Turing machine using O(log n) space; NL is the same but for nondeterministic machines, where acceptance means some computation path accepts within the space bound. The logarithm is not arbitrary — it is precisely the amount of space needed to write down a single pointer (an index or address) into an input of length n, since ⌈log₂ n⌉ bits suffice to name any position among n. A crucial technical convention makes these definitions meaningful: the machine has a read-only input tape and a separate read/write work tape, and only the work tape counts toward the space bound. Without this separation, a machine "using O(log n) space" could never even read its entire input, since scanning n symbols would require the head to move across n positions — but crucially, moving a read head does not require storing the input, only an index into it, and that index fits in O(log n) bits on the work tape. This convention is what allows L and NL to be non-trivial classes containing problems like graph reachability, parity, and regular language membership, rather than being trivially empty. The nondeterministic class NL is best understood through the lens of certificates, but with a twist compared to NP. In NP, a certificate is written down all at once and verified in polynomial time using polynomial space to hold it. In NL, the certificate — such as a path through a graph — is far too large to store in log space, so the machine must instead verify it incrementally, forgetting each piece as soon as it moves past it, retaining only a small log-space "state" (like the current vertex). This distinction between storing a certificate and streaming through one without remembering it is the conceptual heart of nondeterministic space complexity, and it is exactly what makes the completeness structure and the NL = coNL theorem both surprising and provable.
How it works
The canonical problem for NL is PATH (sometimes called STCONN or REACHABILITY): > Given a directed graph G and two vertices s and t, does there exist a directed path from s to t?
PATH is in NL. The algorithm guesses the path one vertex at a time, using only enough memory to remember the current vertex, the target, and a step counter bounded by n (the number of vertices) — all representable in O(log n) bits. ``` Algorithm: NL-PATH(G, s, t) // G given as adjacency list/matrix on read-only input tape // work tape holds only: current vertex v, counter i, target t v := s i := 0 while true: if v == t: ACCEPT if i >= n: REJECT // no simple path can exceed n-1 edges nondeterministically choose an edge (v, u) in G if no such edge exists: REJECT v := u i := i + 1 ``` Each of v, i, and t is an integer at most n, so each needs O(log n) bits; the total work-tape usage is O(log n), independent of how large the graph's description is. The machine accepts G, s, t if some sequence of nondeterministic choices reaches ACCEPT — exactly matching the semantics of NL.
Why bounding steps by n suffices: if t is reachable from s at all, it is reachable via a simple path (no repeated vertices), because any cycle in a walk can be excised without breaking connectivity. A simple path has at most n − 1 edges, so capping the counter at n prevents infinite loops while never causing us to miss a real path.
PATH is NL-hard, meaning every language in NL log-space-reduces to PATH. This is proved via the configuration graph of an NL machine M on input x. Each configuration (state, work-tape contents, head positions) is a vertex; since the work tape has O(log n) cells over a fixed alphabet, there are at most 2^(O(log n)) = poly(n) configurations. Draw an edge from configuration C₁ to C₂ if M can move from C₁ to C₂ in one nondeterministic step. Then M accepts x if and only if there is a path from the start configuration to some accepting configuration in this graph — which we can arrange to be a single designated accept vertex by convention. Crucially, this reduction is computable in log space itself: to output the configuration graph edge-by-edge, we only need to track a bounded amount of local information (the current configuration and a candidate successor), each of size O(log n). ``` Reduction: NL-language L via machine M ⟶ instance of PATH Input: x (length n) Build graph G_M,x: vertices = all configurations of M on x // poly(n) many, O(log n) bits each edges (C, C') whenever M transitions C -> C' on some nondeterministic choice s = start configuration t = designated unique accepting configuration Output (G_M,x, s, t) ``` Since PATH is both in NL and NL-hard under log-space reductions, PATH is NL-complete. This makes it the standard tool for proving other problems NL-complete (e.g., 2-satisfiability of certain restricted forms, some formulations of undirected reachability historically, and various graph problems), by reducing PATH to them or reducing them to PATH.
Savitch's theorem, established for the general space hierarchy, applies directly here: any nondeterministic machine using space s(n) ≥ log n can be simulated deterministically in space O(s(n)²). Applied to NL (s(n) = log n), this gives:
Savitch's algorithm for PATH is a divide-and-conquer reachability test: define REACH(u, v, k) to be true iff v is reachable from u in at most 2^k steps, and observe
The recursion depth is O(log n) (since k ranges up to log n), and each level reuses the same O(log n) bits of space for the "middle vertex" w, giving total space O(log² n) — this is the mechanism inherited directly from Savitch's theorem, and it upper-bounds NL without resolving whether NL = L.
Complexity & correctness
Space bound derivation for NL-PATH. The algorithm above stores three quantities: the current vertex v ∈ {1,...,n}, the counter i ∈ {0,...,n}, and (implicitly, fixed) the target t. Each requires ⌈log₂(n+1)⌉ bits, so total work-tape usage is Θ(log n), independent of the number of edges m, which can be as large as n² but lives on the read-only input tape and is never copied. This is why the convention of separating input and work tapes is not a technicality but the entire reason PATH belongs to a sublinear-space class at all.
Correctness of NL-PATH (soundness and completeness of the certificate).
- If t is reachable from s, there exists a simple path s = v₀, v₁, ..., v_k = t with k ≤ n − 1. The nondeterministic branch that guesses exactly this sequence of edges causes the algorithm to reach v = t within i ≤ n − 1 ≤ n steps, hitting the ACCEPT branch. Hence some computation path accepts, so the NL machine accepts (by definition of nondeterministic acceptance: there exists an accepting path).
- If t is not reachable from s, then no matter which edges are chosen, v can never equal t, since v only ever takes values reachable from s (an easy induction on the number of steps: v₀ = s is reachable from s trivially, and if v_i is reachable from s then any out-neighbor v_{i+1} is too). Hence every computation path either loops until i = n and rejects, or gets stuck with no outgoing edge and rejects. No accepting path exists, so the machine correctly rejects.
Time complexity. Although we emphasize space, it is worth noting NL ⊆ P: a machine using O(log n) space has at most 2^O(log n) = poly(n) distinct configurations, so a deterministic simulation exploring the configuration graph via BFS/DFS (which is itself a P-time reachability computation) decides the language in polynomial time. This gives the containment chain
and combined with Savitch, NL ⊆ SPACE(log² n) ⊆ PSPACE as well. Whether any of these containments is strict (except PSPACE ⊊ EXPSPACE, known from the space hierarchy theorem) remains open — in particular L = NL? is unresolved, making PATH one of the most important "boundary" problems in complexity theory, alongside its cousin undirected s-t connectivity (proven to be in L by Reingold's algorithm, a landmark result building on but distinct from the tools here).
The Immerman–Szelepcsényi theorem: NL = coNL
The complement of PATH — call it NON-PATH — asks whether t is not reachable from s. Naively, verifying non-reachability seems to require checking that no path works, which looks like it needs a universal (coNL-style) quantifier over exponentially many candidate paths, with no obvious short certificate. Immerman and Szelepcsényi independently discovered (1987) that this intuition is wrong: coNL = NL, so non-reachability also has a nondeterministic log-space verification. The key technical tool is inductive counting: an NL machine can compute, and certify, the exact number of vertices reachable from s, using only log space, even though it can never write down the set of reachable vertices (that would take Ω(n) bits in general). Let denote the number of vertices reachable from s within i steps (, counting s itself). The crucial recursive fact is:
Given (a single O(log n)-bit number) as already known and certified, the machine can verify, for each candidate vertex v in turn, whether v is reachable within i+1 steps — and simultaneously verify that it has considered every reachable-within-i vertex u (so that it does not undercount), by checking that it has found exactly distinct reachable vertices among the u's it examined. This self-checking mechanism is what lets nondeterminism certify a count rather than a single witness. ``` Algorithm: COUNT-REACHABLE(G, s) // computes R = number of vertices reachable from s, using O(log n) space R := 1 // s itself for i := 1 to n-1: R' := 0 for each vertex v in 1..n: found := FALSE count_u := 0 // counts u's certified reachable within i-1 steps for each vertex u in 1..n: guess whether u is reachable within i-1 steps if guessed "yes": // verify this guess using the (already certified) value R nondeterministically verify u reachable within i-1 steps // (recursively, using the same style of certificate, or // by re-deriving reachability-within-(i-1) certificates) count_u := count_u + 1 if u == v or edge (u, v) exists: found := TRUE if count_u != R: // did we find all reachable-within-(i-1) vertices? REJECT // (this branch is inconsistent; the overall // algorithm only accepts on a consistent branch) if found: R' := R' + 1 R := R' output R ``` Once R (the total number of reachable vertices) is known, testing whether t is reachable, or verifying that it is not reachable, becomes easy in NL: guess and verify, one at a time, R distinct vertices reachable from s (each verification is itself an NL-style guessed path, bounded by the step count), while checking along the way whether t ever appears among them. If exactly R vertices are certified reachable and t is not among them, then t is definitively not reachable — because R is the complete count, missing t cannot be an artifact of an incomplete search. ``` Algorithm: NL-VERIFY-NONREACHABLE(G, s, t) R := COUNT-REACHABLE(G, s) // total number of vertices reachable from s found_t := FALSE distinct_count := 0 for each vertex v in 1..n: guess whether v is reachable from s if guessed "yes": verify v reachable from s // nondeterministic path-guessing, as in NL-PATH distinct_count := distinct_count + 1 if v == t: found_t := TRUE if distinct_count == R and not found_t: ACCEPT // certified: exactly R vertices reachable, t is not one of them else: REJECT ```
Why this stays in log space. Every quantity manipulated — R, R', i, u, v, count_u, distinct_count — is an integer bounded by n, requiring O(log n) bits. The recursive verification of "u reachable within i-1 steps" reuses the same machinery at the previous level; because the algorithm processes levels i = 1, ..., n-1 sequentially and only needs the single number (not the whole set) to move to level i, the space does not accumulate across levels — it is reused, giving overall O(log n) space rather than O(log n) per level accumulating to more.
Correctness sketch (soundness and completeness of the counting certificate). By induction on i: assume the machine can correctly certify using accepting nondeterministic branches (existence of at least one accepting path that correctly outputs , and no accepting path that outputs a wrong value — this "no accepting path errs" property requires care in the actual construction, ensuring that failing an internal consistency check, such as `count_u != R`, always rejects that branch). Given a correct , the inductive step correctly computes because a vertex v is reachable within i+1 steps if and only if it equals s or has an in-neighbor u reachable within i steps — and the algorithm's consistency check (`count_u != R` forces rejection) guarantees that only branches which have truly enumerated all reachable vertices are allowed to contribute to R'; branches that undercount are rejected, and branches cannot overcount because reachability-within-i is itself verified via genuine paths. This gives an NL algorithm for coPATH, hence coNL ⊆ NL. Since NL is closed under complement trivially in the other direction as well (NL-completeness of PATH under log-space reductions, which are closed under complement, means PATH ∈ NL implies coPATH ∈ NL for anything reducing to it), the two containments combine to
More generally, the Immerman–Szelepcsényi technique shows NSPACE(s(n)) = coNSPACE(s(n)) for any space-constructible , a fully general closure-under-complement result for nondeterministic space classes — a symmetry with no known analogue for NTIME (it is a famous open question whether NP = coNP).
Worked example
Consider the directed graph below with vertices {1, 2, 3, 4, 5}, testing reachability from s = 1 to t = 5.
| Edge list | 1→2, 1→3, 2→4, 3→4, 4→2 |
|---|
Running NL-PATH(G, 1, 5): the machine explores nondeterministic branches guessing edges out of the current vertex.
| Step i | v (current) | Available edges from v | Guess taken (accepting branch) |
|---|---|---|---|
| 0 | 1 | 1→2, 1→3 | guess 1→2 |
| 1 | 2 | 2→4 | guess 2→4 |
| 2 | 4 | 4→2 | guess 4→2 |
| 3 | 2 | 2→4 | (cycling; other branches also cycle) |
| 4 | ... | ... | counter reaches n=5, REJECT this and all branches |
Every branch eventually reaches i = n = 5 without ever landing on v = 5, because vertex 5 has no incoming edges at all in this graph. No accepting branch exists, so NL-PATH correctly rejects: 5 is unreachable from 1.
Now let's certify this rejection using inductive counting, tracing COUNT-REACHABLE(G, 1):
| i | Reachable-within-i set (ground truth, for exposition) | |
|---|---|---|
| 0 | {1} | 1 |
| 1 | {1, 2, 3} | 3 |
| 2 | {1, 2, 3, 4} | 4 |
| 3 | {1, 2, 3, 4} (4→2 revisits 2, nothing new) | 4 |
| 4 | {1, 2, 3, 4} (stabilized) | 4 |
The algorithm computes this sequence step by step. At level i = 2, for example, to confirm it must nondeterministically re-verify, for each candidate v, whether v has an in-neighbor u known reachable within 1 step (from the certified set of size : vertices {1, 2, 3}), while tallying that it examined exactly 3 such u's before moving on. Vertex 4 gets marked reachable (in-neighbors 2 and 3 are both in the size-3 reachable set), vertex 5 does not (no in-neighbors at all), giving , matching the table. Finally, NL-VERIFY-NONREACHABLE(G, 1, 5) uses : it guesses and verifies 4 distinct reachable vertices — {1, 2, 3, 4} — never guessing 5 (any branch that tried to verify 5 as reachable would fail the path-verification subroutine and reject), and since `distinct_count == 4 == R` and `found_t == FALSE`, this branch accepts, correctly certifying that 5 is unreachable from 1 — all within O(log 5) = O(1)-scale (asymptotically O(log n)) work-tape bits per quantity tracked.
Common pitfalls & traps
| Pitfall | Why it's wrong | Fix |
|---|---|---|
| Assuming the input itself counts toward space | Would make L trivial (can't even read n-bit input in o(n) space) | Always use the two-tape convention: read-only input tape, separate work tape counted for space |
| Thinking NL certificates can be "written down and checked" like NP | A path can have length up to n−1, needing Ω(log n)·n = Ω(n log n) bits to store explicitly, violating the space bound | Verify incrementally: only remember the current vertex, discard the rest as you go |
| Believing non-reachability obviously needs coNL-only techniques (Π-certificates) | Immerman–Szelepcsényi shows NL is already closed under complement | Use inductive counting: certify total reachable count, then confirm t is absent |
| Confusing PATH (directed reachability) with the L-complete undirected version | Undirected s-t connectivity is in L (Reingold's theorem), a much harder result than PATH ∈ NL | Keep directed vs. undirected reachability as separate landmark results with different proof techniques |
| Forgetting the step counter bound of n in NL-PATH | Without it, a "no" instance could cause infinite looping instead of a clean reject | Always cap guessed-path length by the number of vertices, since a witness path can be assumed simple |
| Miscounting space for nested/recursive counting subroutines | Naively summing space "per recursion level" can look like O(log² n) or worse | Realize that levels are processed sequentially and space is reused, not accumulated, keeping it O(log n) |
Pioneers & history
The theory of L and NL grew out of foundational work connecting space complexity to structural questions in computation, culminating in a proof that many complexity theorists initially considered surprising enough to double-check carefully.
Origins · 1 minNeil Immerman and how this was discovered
Neil Immerman developed the framework of descriptive complexity, characterizing complexity classes via the expressive power of logical languages, and in 1988 independently proved (alongside Róbert Szelepcsényi) that nondeterministic space classes are closed under complementation.
Róbert Szelepcsényi's original paper, written independently of Immerman's work, gave the same inductive-counting technique proving NSPACE(s(n)) = coNSPACE(s(n)), a result that earned both researchers the Gödel Prize in 1995.
Where this matters
Logarithmic-space classes are far from a theoretical curiosity; they characterize the resources available to streaming algorithms and embedded systems that process large inputs with tiny working memory, such as network routers scanning packet streams or read-only-memory devices. NL specifically captures the complexity of many graph reachability and pathfinding subroutines that appear as primitives inside compilers (data-flow and dependency analysis), database query optimizers (evaluating transitive-closure-like queries), and model checkers (reachability analysis in finite-state system verification, closely related to questions studied under Measuring Space Complexity). The descriptive-complexity perspective pioneered by Immerman also underlies the theoretical foundations of database query languages: NL corresponds to a natural fragment of logic (transitive closure logic) which directly informs how recursive queries are expressed and optimized in systems supporting features like SQL's recursive common table expressions. The L vs. NL question, and the broader landscape of small-space complexity classes, remains central to understanding the limits of space-efficient computation, feeding directly into open problems addressed by The Space Hierarchy Theorem and into circuit-complexity characterizations of L and NL in terms of bounded-depth, bounded-width circuit families.
Ask the tutor: How exactly does the inductive counting algorithm guarantee that a branch which "undercounts" reachable vertices is always rejected, rather than accidentally accepted?
Why is logarithmic space chosen as the boundary for L and NL, rather than some other sublinear bound?
Logarithmic space is the smallest amount of space that still allows a machine to store a pointer or index into its input, since representing any position among n possible positions requires ⌈log₂ n⌉ bits. This makes O(log n) space the natural threshold for expressing meaningful positional bookkeeping — counters, vertex labels, or tape-head simulation — without being powerful enough to store the entire input structure. Classes defined with smaller bounds (like O(1) space) collapse to regular languages, which is far too restrictive to capture interesting graph and algebraic problems. Log space is thus the minimal, most natural setting where genuinely rich computation, such as reachability testing, becomes possible while remaining provably weaker than polynomial time in known containments.
Is it known whether L = NL, and why is this question hard to resolve?
No, it remains one of the major open problems in complexity theory, analogous in spirit (but not identical in difficulty or implications) to P vs. NP. The difficulty lies in the fact that nondeterministic guessing, even under an extremely tight space budget, seems to allow searching an exponentially large space of paths using only local bookkeeping — and no one has found a way either to simulate this deterministically in log space or to prove a nontrivial lower bound separating the two classes. Progress has come through partial results, such as Reingold's theorem placing undirected connectivity in L, which narrows the gap but does not resolve directed reachability, which remains the crux of the L vs. NL question.
How does NL relate to NP, and why isn't NL = coNL surprising in the same way NP = coNP would be?
NL is contained in P (hence in NP), since a log-space nondeterministic machine has only polynomially many configurations, letting a deterministic algorithm search its configuration graph in polynomial time. NL = coNL is not as surprising once you see the proof technique, because inductive counting exploits the fact that space-bounded computation only ever needs polynomially many configurations, all enumerable and countable using log-space arithmetic. NP = coNP would require an analogous counting trick over an exponentially larger, more unstructured search space (satisfying assignments), where no such log-space-style bookkeeping is available, which is precisely why the techniques do not transfer and the NP/coNP question remains open.
What role does the configuration graph play in proving PATH is NL-complete?
The configuration graph translates an arbitrary NL computation into a reachability instance: each configuration (state, head positions, work-tape contents) becomes a vertex, and a single nondeterministic transition becomes a directed edge. Because the work tape holds only O(log n) bits, there are at most polynomially many configurations, keeping the graph's size polynomial in the input size even though it may be far larger than the input itself. Since the input machine accepts if and only if some accepting configuration is reachable from the start configuration, this graph is exactly an instance of PATH, and because the graph can be constructed edge-by-edge in log space, this reduction proves PATH is NL-hard, completing the NL-completeness proof.
Why does inductive counting need to verify a count rather than just guess a path directly?
Guessing a single path only demonstrates that one vertex is reachable, which suffices to prove reachability but says nothing about non-reachability, since failing to find a path in one nondeterministic branch does not rule out success in another branch. To prove that a specific target is unreachable, the machine must effectively rule out every possible witness, which naively requires a universal (for-all) check over all branches. Inductive counting sidesteps this by certifying the total number of reachable vertices via a self-consistent process: if the machine finds exactly that many distinct reachable vertices and the target is not among them, it can conclude non-reachability with certainty, because an undercount is caught by internal consistency checks and an overcount is impossible since every counted vertex is independently path-verified.
Does the Immerman–Szelepcsényi result generalize beyond NL, and does it affect PSPACE?
Yes, the technique generalizes to show that NSPACE(s(n)) = coNSPACE(s(n)) for any space-constructible function s(n) ≥ log n, making it a broad structural theorem about nondeterministic space rather than a fact specific to logarithmic space. It does not directly simplify PSPACE, however, because PSPACE is already known to equal coPSPACE trivially (PSPACE is closed under complement by definition, since a polynomial-space machine can simulate its own complement by flipping accept/reject), so the theorem's genuine content lies in classes like NL and NSPACE(n) where closure under complement was previously unclear.
How does the space bound in NL-PATH avoid growing when the graph has many edges?
The graph's edges live entirely on the read-only input tape, described for instance as an adjacency list or matrix, and the algorithm only ever reads them, never copies them into the work tape. At each step, the machine nondeterministically selects one outgoing edge from the current vertex by scanning the relevant portion of the input tape, but it retains only the resulting destination vertex, an O(log n)-bit number, on the work tape. This is precisely why the input/work-tape separation is essential: no matter how large or dense the graph becomes (up to n² edges), the algorithm's memory footprint depends only on n, the number of vertices, not on the number of edges m.