Rule 110 and Computation in a Grid
Cellular Automata From First Principles 04: Rule 110 and Computation in a Grid
Rule 110 looks like another one-byte transition table.
111 110 101 100 011 010 001 000
0 1 1 0 1 1 1 0
But its behavior gives us a much deeper idea: a cellular automaton can become a computational medium.
The important shift is this:
pattern generator
->
signal system
->
computation
Rule 110 is computationally universal. Matthew Cook published the universality proof in Complex Systems in 2004, showing that this elementary one-dimensional automaton can emulate universal computation.
The proof is much more elaborate than anything we need in this chapter. We are not going to pretend that a visually interesting Rule 110 run somehow proves universality.
Instead, we will study the mechanism that makes the result plausible: structured backgrounds, localized disturbances, propagation and interaction.
Primary reference: Matthew Cook, “Universality in Elementary Cellular Automata”.
Run Rule 110
A single-cell seed is useful for comparing elementary rules, but Rule 110’s characteristic mixture of domains and disturbances is easier to see from a richer initial state.
rng = np.random.default_rng(110)
initial = rng.integers(0, 2, size=241, dtype=np.uint8)
history = run_from_state(
initial_state=initial,
rule_number=110,
generations=160,
)
Visualize it:
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 8))
plt.imshow(history, cmap="binary", interpolation="nearest")
plt.title("Rule 110")
plt.xlabel("cell")
plt.ylabel("generation")
plt.show()
The canonical book figure is generated with:
python scripts/figures/cellular-automata/part01_foundations.py 04

The important observation is not simply that the image is complicated.
Look for the coexistence of:
repeating domains
localized defects
moving boundaries
interactions between structures
That mixture is much more interesting computationally than visual irregularity alone.
Patterns can act like signals
Imagine a repeating background with a localized defect moving through it.
Conceptually:
background background [defect] background background
--->
If the defect persists, its position and type can carry information.
If two defects collide and the collision produces another persistent pattern, the interaction can transform information.
flowchart LR
A[Persistent local structure] --> B[Propagation]
B --> C[Collision with another structure]
C --> D[Changed outgoing structures]
D --> E[Information transformation]
That gives us the ingredients from which computation can be constructed:
persistent structures
+
controlled movement
+
interactions
=
computational substrate
This idea appears again in Conway’s Game of Life, where gliders make the signal interpretation especially visual.
Detect local activity
We can start analyzing Rule 110 without knowing the names of every structure.
One simple tool is a temporal activity map:
activity = history[1:] != history[:-1]
plt.figure(figsize=(12, 8))
plt.imshow(activity, cmap="binary", interpolation="nearest")
plt.title("Cells that changed")
plt.show()
Another is neighborhood frequency:
from collections import Counter
def neighborhood_counts(row):
counts = Counter()
for i in range(len(row)):
n = (
int(row[(i - 1) % len(row)]),
int(row[i]),
int(row[(i + 1) % len(row)]),
)
counts[n] += 1
return counts
These tools do not identify Cook’s computational construction for us.
They do something more basic and reusable: they turn the automaton into a system we can interrogate rather than merely watch.
Computation does not need a CPU-shaped machine
Programmers are used to computation looking like this:
instruction
register
memory
branch
instruction
Cellular automata show another possibility:
local state
local interaction
propagating pattern
collision
new pattern
The computation is embodied in the dynamics.
There is no separate processor walking over passive memory. The state of the world and the process transforming that state are intertwined.
That is one reason cellular automata connect naturally to distributed and unconventional computing.
Build a perturbation experiment
Start from the same random world twice, then flip one bit.
rng = np.random.default_rng(4)
base = rng.integers(0, 2, size=201, dtype=np.uint8)
changed = base.copy()
changed[100] ^= 1
ha = run_from_state(base, 110, 120)
hb = run_from_state(changed, 110, 120)
diff = ha != hb
Visualize the difference:
plt.imshow(diff, cmap="binary", interpolation="nearest")
plt.title("Propagation of one-bit perturbation")
plt.show()
This experiment gives us a visual map of causal influence.
The broader lesson is useful:
A computation can be studied as the propagation and transformation of distinctions in state.
That statement alone does not prove that a system is universal. It gives us a practical lens for looking for information-bearing dynamics.
Rule 30 versus Rule 110
It is useful to place the two famous rules side by side.
Rule 30
- strong visual irregularity
- excellent example of simple rule -> complex history
Rule 110
- regular domains plus interacting local structures
- proven capable of universal computation
Neither label tells the whole story.
The point is to learn to inspect a dynamical system in terms of:
- persistent structures,
- information propagation,
- perturbation growth,
- collisions,
- attractors,
- and measurable state change.
From one dimension to two
One-dimensional automata are wonderful because time gives us the second visual axis.
But two-dimensional grids let structures move inside the world itself.
That is where one cellular automaton became iconic.
In the next chapter we move to Conway’s Game of Life and build its complete rule from first principles.