Archive & Restarting from a Database¶
Two closely related features make it easy to reuse data across EA runs: the Archive class for querying historical individuals from a past experiment’s database, and the restart parameter on EA for resuming an evolution from any saved generation.
The Archive Class¶
Archive opens a SQLite database written by any previous EA run and exposes query methods for retrieving individuals from it.
It is read-only — it never modifies the source database.
from pathlib import Path
from ariel.ec import Archive
archive = Archive("__data__/run_1/database.db")
print(archive)
# Archive(path=..., size=3200) ← total evaluated individuals across all generations
print(archive.generation_range)
# (0, 99) ← earliest birth, latest death recorded
print(archive.fitness_stats())
# {"min": 0.12, "max": 9.87, "mean": 4.3, "std": 1.2, "median": 4.1}
Retrieving individuals¶
All query methods return Individual objects (or lists of them) with their genotype and fitness already populated.
# Single best individual ever recorded
best = archive.best_individual(fitness_mode="min")
print(best.fitness)
# A random individual (uniform sample)
random_ind = archive.random_individual()
# Only individuals that died before generation 30
early = archive.random_individual(death_range=(0, 30))
Retrieving populations¶
# Hall of fame — the 10 best individuals of all time
hof = archive.hall_of_fame(n=10, fitness_mode="min")
# Random sample of 20 individuals
pool = archive.random_population(n=20)
# Everyone alive at generation 50
gen50 = archive.by_generation(generation=50)
# Individuals in the 40th–60th fitness percentile (mediocre-but-diverse sample)
mid_tier = archive.fitness_percentile_population(lo_pct=40, hi_pct=60, n=15)
Tournament selection from the archive¶
tournament_population is the primary method of injecting historically successful individuals back into a stagnating population.
# Fetch 10 individuals via tournament selection from the full history
resurrected = archive.tournament_population(
n=10,
tournament_size=4,
fitness_mode="min",
pool_multiplier=3, # sample 30 candidates, run 10 tournaments
)
These can be passed directly into a running EA as injection candidates via a custom EAOperation.
Restarting an EA from a Database¶
The EA class accepts a restart parameter that loads a previous run’s final population (or any past generation) and continues evolution from there. No separate Archive interaction is needed.
Resume from the latest generation¶
from ariel.ec import EA
ea = EA(
population=None, # ignored when restart is set
operations=my_operations,
restart="__data__/run_1/database.db",
num_steps=100,
)
ea.run()
The engine automatically picks the last recorded generation, copies those individuals into a fresh population with requires_eval=False (their fitness is already known), and continues from generation last + 1.
Resume from a specific generation¶
Pass a (path, generation) tuple to restart from any historical snapshot:
ea = EA(
population=None,
operations=my_operations,
restart=("__data__/run_1/database.db", 50), # resume from generation 50
num_steps=50,
)
ea.run()
This is useful for branching experiments — run once, then fork from an intermediate checkpoint with different operators or parameters.
Combining Both: Archive Injection + Restart¶
A common pattern is to restart a stagnated run and seed it with historically fit individuals pulled from the same (or a different) archive:
from ariel.ec import EA, Archive, EAOperation
archive = Archive("__data__/run_1/database.db")
def inject_hall_of_fame(population):
"""Replace the bottom 10% of the population with all-time best individuals."""
hof = archive.hall_of_fame(n=len(population) // 10, fitness_mode="min")
worst = population.sort(key=lambda ind: ind.fitness, reverse=True)
for slot, hero in zip(worst, hof):
slot.genotype = hero.genotype
slot.requires_eval = True
ea = EA(
population=None,
operations=[
EAOperation(inject_hall_of_fame),
EAOperation(my_evaluator),
EAOperation(my_survivor_selection),
],
restart="__data__/run_1/database.db",
num_steps=100,
)
ea.run()
Summary¶
Feature |
What it does |
When to use |
|---|---|---|
|
Read-only query interface to a past run’s SQLite DB |
Post-hoc analysis, JESUS-style injection, cross-run comparison |
|
Best |
Seeding new runs with proven solutions |
|
Tournament selection from full history |
JESUS resurrection injection |
|
Resume from latest generation in a DB |
Continuing an interrupted run |
|
Resume from a specific past generation |
Branching experiments from a checkpoint |