JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

What a DFA Can Never Do

You can now design clever finite automata for substrings, parity, and counting modulo k. So here is the unsettling question that ends this rung: is there a pattern so simple a child could check it, that no DFA on earth can ever recognize? Yes — and the reason reveals the deepest truth about finite memory.

A machine with exactly as much memory as it has states

By now you have built real DFAs: one that accepts strings with an even number of a's, one that fires whenever it sees the substring 'abb', one that counts the input length modulo 3, and you have stitched conditions together with the product construction. Each was clever, but each shared one humble feature — a fixed, finite set of states drawn once and never changed. This guide takes that humility seriously and asks what it costs. The answer is the punchline of the whole rung: a DFA's entire memory IS which of its finitely many states it is currently in, and nothing else.

Think of a turnstile in a subway. It does not remember how many people passed through this morning, nor your face, nor the time. It remembers exactly one thing: am I locked or unlocked? That is two states. A DFA is the same kind of creature with more states — maybe five, maybe five hundred — but always a number fixed in advance, written down before it ever reads a single symbol. As it scans the input left to right, all the information it could possibly carry forward about everything it has seen so far is compressed into 'which state am I in now.' If it has k states, it has at most k genuinely different memories of the past. This is the finite-memory limit, and it is not a flaw to fix — it is the definition.

The pattern that breaks every DFA

Here is the famous troublemaker, the language a^n b^n: some number of a's, then exactly the same number of b's. So 'ab', 'aabb', 'aaabbb' are all in it; but 'aab', 'abb', and 'aaabb' are all out. A six-year-old can check membership: count the a's, count the b's, see if they match. The rule is trivial. And yet no DFA — not one with ten states, not one with a trillion states — can recognize a^n b^n. Sit with how strange that is. The machine that can spot 'abb' anywhere in a billion-character string is helpless against 'equal numbers of two letters.'

Why? Because recognizing a^n b^n requires remembering n — and n can be any whole number, with no upper bound. To know that 'aaaaa' should be matched by exactly five b's, you must have somehow recorded the count five. But a DFA has only k states, a number nailed down before it ever runs. To distinguish among all the prefixes a, aa, aaa, ... and respond correctly to each, it would need a separate memory for arbitrarily large counts. A fixed finite bag of states simply cannot hold an unbounded number. The slogan is exact and worth memorizing: a DFA cannot count without bound. It can count modulo a fixed k forever (that only needs k states, cycling), but it cannot keep a running tally that may grow past any limit.

The pigeonhole principle, which forces the collision

Hand-waving 'it can't remember enough' is unsatisfying; let us make it airtight with the pigeonhole principle — the homely fact that if you put more pigeons than pigeonholes, some hole gets two pigeons. Suppose, for contradiction, that some DFA M with exactly k states does recognize a^n b^n. Feed it the k+1 inputs that are pure runs of a's: the empty string, 'a', 'aa', up to 'a' repeated k times. After reading each of these prefixes, M sits in some state. There are k+1 prefixes but only k states, so two different prefixes — say a^i and a^j with i not equal to j — must land M in the very same state. M now genuinely cannot tell those two prefixes apart; from this state onward, its future behaviour is identical regardless of which one it read.

Now spring the trap. Append exactly i b's to both. The string a^i b^i is in the language and must be accepted; but a^j b^i is NOT in the language (its counts differ) and must be rejected. Yet M is in the same state after a^i and after a^j, so it does the identical thing on the trailing 'b^i' in both cases — it either accepts both or rejects both. One of those two verdicts is wrong. The contradiction is forced, so our assumption was false: no k-state DFA recognizes a^n b^n, and since k was arbitrary, no DFA does. Notice the shape of this argument — it is a proof by contradiction whose engine is pure pigeonhole.

M has k states.  Feed k+1 prefixes of a's:

  prefix:   (empty)  a    aa   aaa  ...  a^k       <- k+1 prefixes
  state:    s0       s1   s2   s3   ...  sk        <- only k states exist
                            \          /
                   PIGEONHOLE: two prefixes share a state
                   say  a^i  and  a^j   (i != j)  land in the SAME state q

Now append b^i to each, starting from that shared state q:

  a^i b^i  -> (same state q) ->[reads b^i]-> verdict V    must ACCEPT (in language)
  a^j b^i  -> (same state q) ->[reads b^i]-> verdict V    must REJECT (not in language)

Same start state q, same suffix b^i  =>  same verdict V for both.
But one must be accepted and the other rejected.  CONTRADICTION.
Pigeonhole forces two a-prefixes into one state; appending the same b-suffix then demands one wrong answer.

Naming the trick: the pumping lemma

That two-prefixes-collide argument is so useful that it gets a name and a reusable form: the pumping lemma for regular languages. It says that for any regular language there is a length p (the pumping length, essentially the number of states) such that every string at least that long contains a non-empty middle chunk you can repeat — 'pump' — any number of times and stay in the language. The intuition is exactly the pigeonhole collision dressed up: a long enough string must revisit some state, and the loop between the two visits can be traversed zero times, once, twice, forever, all yielding accepted strings. To prove a language like a^n b^n is not regular, you show that no such pumpable middle can exist, and the language is convicted.

Where the limit is real, and where it is not

It is easy to draw the wrong moral, so let us be precise about what this limit does and does not say. The limit is about UNBOUNDED memory, not about difficulty in any everyday sense. A^n b^n is computationally trivial; the obstacle is purely that matching the counts needs storage that grows with the input. By contrast, a real subtlety from earlier guides survives untouched: nondeterminism does NOT rescue you. An NFA — the version that can 'clone itself' to explore many paths at once — is no more powerful than a DFA; the subset construction converts any NFA back into a DFA. Nondeterminism only buys conciseness, sometimes a smaller diagram, never a single extra language. So you cannot escape the a^n b^n wall by going nondeterministic; it is the same wall.

So what would break through? Exactly one more scrap of the right memory. Give the machine a stack — a stack of plates where you may only push onto or pop off the top — and you get a pushdown automaton. Now a^n b^n becomes easy: push one plate for each a, then pop one plate for each b, and accept only if the stack empties exactly as the input ends. The stack is unbounded, so it can hold any count; restricting you to its top is what keeps it weaker than a full computer's memory. That single upgrade is the bridge from regular languages to the next ring of the hierarchy, and it is precisely where the next rung of this ladder begins. The DFA's wall is not the end of the story — it is the doorway to grammars and pushdown automata.