← Emergence Series

Genetic Algorithms

Natural selection, applied to code, finds solutions no programmer would design.

A scheduling problem or circuit layout has too many configurations to enumerate and no closed-form solution. A genetic algorithm starts with a population of random guesses, scores each one, lets the better guesses reproduce, introduces small random changes, and repeats. Over many generations the population drifts toward good solutions without anyone programming the answer.

The recipe needs three pieces: a way to encode a candidate, a fitness function that scores it, and operators (selection, crossover, mutation) to produce the next generation.

1. A Population of Guesses

The classic demonstration: evolve a string of characters to match a target phrase. Each individual in the population is a random string of the same length. Fitness is the number of characters that match the target. Each generation, the best individuals are selected, paired up, and their "genes" (characters) are crossed over and mutated.

1.0×
Generation 0
Best fitness 0

Figure 1. Evolving a string to match a target. Blue characters are correct matches. The chart tracks the best fitness (matching characters) per generation. Slow the speed down, or pause mid-run, to watch the top eight candidates jostle for position: green characters are correct, red are wrong. The runner-up is almost always one mutation away from the leader.

A 28-character phrase drawn from 27 characters has $27^{28}$ possibilities, but with selection pressure the algorithm converges in a few hundred generations. Each generation keeps what works and explores nearby — directed search, not random search.

2. Evolving Shapes

Each candidate here is a stack of translucent triangles. Fitness is pixel-level similarity to the target image. Mutation nudges a vertex, changes a color, or adjusts transparency; crossover swaps triangles between parents. Early generations look like colored blobs, but the triangles eventually settle into positions that approximate the target's edges and shading.

Target
Best candidate
Generation 0
Fitness 0%
0.08

Figure 2. Translucent triangles evolving to approximate a target shape. Fitness is the percentage of pixel-level similarity. The chart tracks fitness over time. Try raising the mutation rate to explore faster, at the cost of less stability.

The mutation slider trades off refinement against exploration. The sweet spot shifts as the population converges: big mutations help early, small ones help late. Real evolutionary systems regulate their own mutation rates.

3. The Fitness Landscape

Plot every solution on a plane with height as fitness, and you get a landscape of hills and valleys. A population of climbers gets pulled uphill by selection and nudged sideways by mutation. A solo hill-climber gets stuck on the nearest peak; a population can spread across several.

Low mutation clusters everyone on the nearest hill. High mutation scatters them far enough to find distant peaks. This is the exploration-exploitation tradeoff that shows up in every optimization method.

Generation 0
Peaks 3
Best fitness 0.00
0.030

Click to place a new fitness peak. Watch the population split.

Low-fitness individual High-fitness individual Peak center

Figure 3. A 2D fitness landscape with the population shown as colored dots (red = low fitness, yellow = high). Brighter terrain is higher fitness; white rings mark peak centers. Selection pushes individuals uphill, while mutation provides the randomness needed to escape local peaks and discover global ones.

Place a tall peak far from the current population. With low mutation, nobody finds it. Crank the rate up and a few scouts wander far enough; once they do, selection amplifies the discovery and the population flows toward it. A uniform population is efficient but fragile; a diverse one is slower but adaptive.

Genetic algorithms have designed NASA antennas that outperform hand-engineered ones, optimized neural network architectures, and evolved Prisoner's Dilemma strategies. The results often look alien because the algorithm only cares whether the solution works.