Skip to content

Genealogy

A short OneMax run that records a NetworkX-compatible genealogy. History.update seeds the population; history.decorator wraps mate and mutate. See Logging Statistics.

import numpy
from deap_er import Fitness, Toolbox, creator, tools

tools.rng.seed(1234)  # disables randomization

N_BITS = 20


def setup():
    creator.create_type("FitnessMax", Fitness, weights=(1.0,))
    creator.create_type("Individual", list, fitness=creator.FitnessMax)

    toolbox = Toolbox()
    toolbox.register("attr_bool", tools.rng.randint, 0, 1)
    toolbox.register("individual", tools.init_repeat, creator.Individual, toolbox.attr_bool, N_BITS)
    toolbox.register("population", tools.init_repeat, list, toolbox.individual)
    toolbox.register("mate", tools.cx_two_point)
    toolbox.register("mutate", tools.mut_flip_bit, mut_prob=0.05)
    toolbox.register("select", tools.sel_tournament, contestants=3)
    toolbox.register("evaluate", lambda ind: (sum(ind),))
    toolbox.register("clone", tools.clone_individual)

    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("max", numpy.max)
    return toolbox, stats


def print_results(history, best_ind):
    if not history.genealogy_tree:
        raise RuntimeError("Genealogy tree is empty.")
    has_parents = any(history.genealogy_tree.values())
    if not has_parents:
        raise RuntimeError("Genealogy recorded no parent links.")
    tree = history.get_genealogy(best_ind)
    if not tree:
        raise RuntimeError("get_genealogy returned an empty graph.")
    print(f"\nGenealogy nodes: {len(history.genealogy_tree)}")
    print(f"Best-individual ancestors: {len(tree)}")


def main():
    toolbox, stats = setup()
    pop = toolbox.population(size=40)
    history = tools.History()
    history.update(pop)
    toolbox.decorate("mate", history.decorator)
    toolbox.decorate("mutate", history.decorator)
    hof = tools.HallOfFame(1)
    tools.ea_simple(
        toolbox,
        pop,
        generations=12,
        cx_prob=0.5,
        mut_prob=0.2,
        hof=hof,
        stats=stats,
        verbose=True,
    )
    print_results(history, hof[0])


if __name__ == "__main__":
    main()