liveBook · Manning

Chapter 4: Memoizing immutable quadtrees to make a better Life

What you will learn in chapter 4 of Fabulous Adventures in Data Structures and Algorithms

This chapter introduces Conway’s Game of Life as a vehicle for comparing incremental optimization with a frame-changing HashLife approach built from immutable quadtrees and memoization.

After this chapter you will be able to

What it builds on

Section by section

Introduction

This chapter introduces Conway’s Game of Life as a vehicle for comparing incremental optimization with a frame-changing HashLife approach built from immutable quadtrees and memoization.

Key terms: hot spots, frame of reference, incremental improvements, Game of Life, cellular automaton, immutable quadtrees, memoization, HashLife algorithm, quadtrees, octrees

4.1 The rules of Life

This section defines Conway’s Game of Life, illustrates characteristic pattern behaviors, and frames Life as the subject for later algorithmic optimization.

Key terms: infinite grid, alive, dead, ticks, steps, eight neighboring cells, still lifes, blinker, oscillator, glider

4.2 A typical first attempt

This section defines a mutable Life-engine interface and introduces a simple two-array, bounded-grid implementation with practical performance trade-offs.

Key terms: Life computation engine, ADT, Clear, indexer, Step(speed), infinite grid, rectangular array, permanently dead, active portion of the grid, cells array

4.2.1 Performance of the naïve implementation

This subsection evaluates the naïve Life implementation's deliberate memory-for-speed trade-off and its linear scaling costs.

Key terms: bit-twiddling arithmetic, memory for less time, trade-off, O(n) memory, O(n) work per tick, tick, n cells

4.2.2 Same algorithm, better constant factor

This section shows how profiling and parallel hardware can greatly reduce the constant factor of the naïve Life simulation without changing its O(n)-per-tick complexity.

Key terms: profiler, hot spots, range checks, innermost loop, two-cell dead zone, constant factor, single instruction, multiple data, SIMD, bit vectors, GPU

4.2.3 Improving the algorithm with change tracking

This section shows how change tracking can avoid recalculating unchanged parts of a Life grid, making work depend on active regions rather than the entire grid.

Key terms: still lifes, bordering rectangle, dead, tick, change tracking, active region, still, O(n), naïve algorithm, tracking whether the new state differs from the old state

4.3 An immutable quadtree

This section defines an immutable quadtree as a recursive representation of an arbitrarily large square grid of alive or dead cells.

Key terms: immutable quadtree, quad, alive, dead, 0-quad, n-quad, NE, NW, SE, SW

4.3.1 The IQuad interface

Introduces IQuad as a deliberately minimal interface for the quadtree abstract data type, with other operations supplied as extension methods.

Key terms: IQuad, ADT, quad, extension methods

4.3.2 Implementing the 0-quad leaf cells

This subsection represents the two possible single-cell quadtree leaves as shared instances while highlighting the apparent memory cost of using reference objects.

Key terms: 0-quad, leaf cells, doubleton instances, singleton instance, reference type, .NET, 16 bits, single bit, 64 bits

4.3.3 A strategy for compressing space

This section motivates deduplicating immutable Life quadtrees by reusing identical quads and introduces memoization as the mechanism for doing so.

Key terms: 0-quad, 1-quad, 2-quad, reuse, equivalent graph, deduplicate, still lifes, Life grid, memoizer, previous result

4.3.4 A general-purpose memoizer

This section introduces a reusable one-argument memoizer for pure functions and explains why its cache must be observable and resettable.

Key terms: pure function, memoized function, memo, dictionary, memoizer, constructor, MemoizedFunc, one-argument function, cache, memory leak

4.3.5 A memoized quadtree implementation

This section implements memoized quadtree construction to deduplicate identical grids, make empty grids cheap to recognize, and show why sparse enormous Life grids can use little memory.

Key terms: memoizer, memoized factories, general-purpose quadtrees, empty ones, deduplicate quads, empty quad, reference comparison, memoization strategy, irregularity, living and dead cells

4.3.6 Indexing an immutable quadtree like an array

This section defines stable coordinates for immutable quadtrees and shows recursive read and write access that preserves sharing.

Key terms: n-quad, 0-quad, indices, southwestern corner, getter, point, inside, recursion, northeast 1-quad, setter

4.3.7 A few more helpful extension methods

This section adds immutable-quadtree helper methods that embiggen a quad, detect an empty surrounding ring, and extract centered or directional subquads for HashLife.

Key terms: embiggening, n-quad, (n+1)-quad, empty 1-quad, immutable, reuse, IsEmpty, ring of emptiness, center (n−1)-quad, north (n−1)-quad

4.4 The HashLife algorithm

This introduction presents HashLife as a recursive, memoized quadtree approach for advancing Conway’s Life by many generations while treating space beyond the stored tree as dead.

Key terms: HashLife, n-quad, (n−1)-quad, ticks, memoize, mutable Life-grid ADT, 9-quad, quadtree, dead, embiggen

4.4.1 The base case: Stepping a 2-quad produces a 1-quad

This subsection establishes the HashLife base case: a 2-quad contains enough neighborhood information to compute its center 1-quad one Life tick later.

Key terms: 2-quad, 1-quad, base case, tick, center 1-quad, 0-quad, future state, living neighbors, a through p, f

4.4.2 A first attempt at a recursive algorithm

This section derives a first recursive HashLife step that computes the future center of an n-quad from overlapping smaller quads, while identifying its apparent shrinking and efficiency concerns.

Key terms: n-quad, 3-quad, 2-quad, 1-quad, base case, North, empty quad, empty space, optimization, rules of Life

4.4.3 The grid always shrinks

This section fixes HashLife's shrinking-grid problem by maintaining ample empty border space and enlarging the quadtree when needed.

Key terms: n-quad, (n−1)-quad, Step(IQuad), spaceship, invariant, embiggening, dead space, live cells

4.4.4 Is this algorithm inefficient?

This section explains why the recursive HashLife Step algorithm appears exponentially expensive, how memoizing its pure repeated subproblems changes that cost in practice, and why cache usage still creates a memory-performance trade-off.

Key terms: Step, n-quad, empty quad, recursion, pure method, memoization, Make, cache, power law, hot entries

4.4.5 Take bigger steps forward

This section extends HashLife’s recursive step so that larger quadtrees advance their centers by exponentially larger numbers of Life ticks.

Key terms: n-quad, (n−1)-quad, center, recursive case, 13 recursions, Step, speed, 2^speed ticks, 2^(n−2) ticks, embiggen

4.4.6 Putting it all together

This section combines memoized fast HashLife stepping with cache eviction and explains the algorithm’s practical memory tradeoff and eventual performance on settled Life patterns.

Key terms: HashLife, Step, memoization, fast stepping, self-tuning cache-eviction policy, cache expiration, Make, private Step, memoizer, least-recently-used cache

4.5 Summary

This summary extracts general design lessons from HashLife: use memoization to trade memory for speed, manage caches carefully, and seek problem-specific algorithmic reframings.

Where this is used later

Concepts explained in this chapter

← Chapter 3: An immutable deque Chapter 5: What’s up with you, Directed Acyclic Word Graph? →

These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.