import numpy
from deap_er import Fitness, Toolbox, creator, tools
tools.rng.seed(1234) # disables randomization
SIZE = 5
MU, LAMBDA = 10, 10
MIN_BOUND = numpy.zeros(SIZE)
MAX_BOUND = numpy.ones(SIZE)
EPS_BOUND = 2.0e-5
NGEN = 500
def validity(individual):
return not (any(individual < MIN_BOUND) or any(individual > MAX_BOUND))
def feasible(individual):
feasible_ind = numpy.array(individual)
feasible_ind = numpy.maximum(MIN_BOUND, feasible_ind)
feasible_ind = numpy.minimum(MAX_BOUND, feasible_ind)
return feasible_ind
def distance(feasible_ind, original_ind):
return sum((f - o) ** 2 for f, o in zip(feasible_ind, original_ind, strict=False))
def setup():
creator.create_type("FitnessMin", Fitness, weights=(-1.0, -1.0))
creator.create_type("Individual", list, fitness=creator.FitnessMin)
toolbox = Toolbox()
toolbox.register("evaluate", tools.bm_zdt_1)
toolbox.decorate("evaluate", tools.ClosestValidPenalty(validity, feasible, 1.0e6, distance))
pop = [creator.Individual([tools.rng.uniform(0, 1) for _ in range(SIZE)]) for _ in range(MU)]
for ind in pop:
ind.fitness.values = toolbox.evaluate(ind)
strategy = tools.StrategyMultiObjective(
population=pop, sigma=1.0, offsprings=LAMBDA, survivors=MU
)
toolbox.register("generate", strategy.generate, creator.Individual)
toolbox.register("update", strategy.update)
stats = tools.Statistics(lambda x: x.fitness.values)
stats.register("min", numpy.min, axis=0)
stats.register("max", numpy.max, axis=0)
logbook = tools.Logbook()
logbook.header = ["gen", "nevals"] + (stats.fields if stats else [])
return toolbox, strategy, stats, logbook
def print_results(valid, parents):
hv = tools.hypervolume(parents, [11.0, 11.0])
if hv <= 110 and valid != len(parents):
raise RuntimeError("Evolution failed to converge.")
print(
f"\nNumber of valid individuals is {valid}/{len(parents)} with a hypervolume of {hv:.2f}."
)
print("Evolution converged correctly.")
def main():
toolbox, strategy, stats, logbook = setup()
fitness_history = []
for gen in range(NGEN):
population = toolbox.generate()
fitness = toolbox.map(toolbox.evaluate, population)
for ind, fit in zip(population, fitness, strict=False):
ind.fitness.values = fit
fitness_history.append(fit)
toolbox.update(population)
record = stats.compile(population) if stats is not None else {}
logbook.record(gen=gen, nevals=len(population), **record)
print(logbook.stream)
num_valid = 0
for ind in strategy.parents:
dist = distance(feasible(ind), ind)
if numpy.isclose(dist, 0.0, rtol=1.0e-5, atol=1.0e-5):
num_valid += 1
print_results(num_valid, strategy.parents)
if __name__ == "__main__":
main()