Skip to content

Island Models

Three OneMax demes. Each toolbox registers vary (var_and), select, and evaluate. step_islands steps every deme, then mig_ring moves emigrants. See the island models tutorial.

from deap_er import Fitness, Toolbox, creator, tools

tools.rng.seed(1234)  # disables randomization

N_BITS = 30
N_DEMES = 3
DEME_SIZE = 40
GENERATIONS = 25
MIG_INTERVAL = 5


def evaluate(individual):
    return (sum(individual),)


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", evaluate)
    toolbox.register("clone", tools.clone_individual)

    def vary(population):
        return tools.var_and(toolbox, population, 0.5, 0.2)

    toolbox.register("vary", vary)
    return toolbox


def migrate(populations):
    tools.mig_ring(populations, mig_count=4, selection=tools.sel_best)


def print_results(best_ind):
    if not all(gene == 1 for gene in best_ind):
        raise RuntimeError("Island OneMax failed to reach all-ones.")
    print("\nEvolution converged correctly.")


def main():
    toolbox = setup()
    demes = [(toolbox, toolbox.population(size=DEME_SIZE)) for _ in range(N_DEMES)]
    for _ in range(GENERATIONS):
        tools.step_islands(demes, migrate=migrate if _ % MIG_INTERVAL == 0 else None)
    best = max((ind for _, pop in demes for ind in pop), key=lambda ind: ind.fitness.values)
    print_results(best)


if __name__ == "__main__":
    main()

Island topologies

The same deme contract with mig_fully_connected and mig_random next to mig_ring. See the island models tutorial and roadmap item 35.

from deap_er import Fitness, Toolbox, creator, tools

tools.rng.seed(1234)  # disables randomization

N_BITS = 24
N_DEMES = 3
DEME_SIZE = 30
GENERATIONS = 20
MIG_INTERVAL = 4


def evaluate(individual):
    return (sum(individual),)


def setup(label):
    fit_name = f"Island{label}Fit"
    ind_name = f"Island{label}Ind"
    creator.create_type(fit_name, Fitness, weights=(1.0,))
    creator.create_type(ind_name, list, fitness=getattr(creator, fit_name))
    ind_cls = getattr(creator, ind_name)

    toolbox = Toolbox()
    toolbox.register("attr_bool", tools.rng.randint, 0, 1)
    toolbox.register("individual", tools.init_repeat, ind_cls, 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", evaluate)
    toolbox.register("clone", tools.clone_individual)

    def vary(population):
        return tools.var_and(toolbox, population, 0.5, 0.2)

    toolbox.register("vary", vary)
    return toolbox


def migrate_ring(populations):
    tools.mig_ring(populations, mig_count=3, selection=tools.sel_best)


def migrate_mesh(populations):
    tools.mig_fully_connected(populations, mig_count=2, selection=tools.sel_best)


def migrate_random(populations):
    tools.mig_random(populations, mig_count=2, selection=tools.sel_best)


def run_topology(label, migrate):
    toolbox = setup(label.replace(" ", ""))
    demes = [(toolbox, toolbox.population(size=DEME_SIZE)) for _ in range(N_DEMES)]
    for gen in range(GENERATIONS):
        step = migrate if gen % MIG_INTERVAL == 0 else None
        tools.step_islands(demes, migrate=step)
    best = max((ind for _, pop in demes for ind in pop), key=lambda ind: ind.fitness.values)
    score = best.fitness.values[0]
    print(f"{label}: best ones {score} / {N_BITS}")
    return score


def main():
    ring_score = run_topology("Ring", migrate_ring)
    mesh_score = run_topology("Fully connected", migrate_mesh)
    random_score = run_topology("Random destinations", migrate_random)
    if max(ring_score, mesh_score, random_score) < N_BITS - 2:
        raise RuntimeError("Island topologies failed to reach the seed-fixed floor.")


if __name__ == "__main__":
    main()