Multi-Objective CMA

  1from deap_er import creator
  2from deap_er import tools
  3from deap_er import base
  4import numpy
  5
  6
  7numpy.random.seed(1234)  # disables randomization
  8
  9
 10SIZE = 5
 11MU, LAMBDA = 10, 10
 12MIN_BOUND = numpy.zeros(SIZE)
 13MAX_BOUND = numpy.ones(SIZE)
 14EPS_BOUND = 2.e-5
 15NGEN = 500
 16
 17
 18def validity(individual):
 19    if any(individual < MIN_BOUND) or any(individual > MAX_BOUND):
 20        return False
 21    return True
 22
 23
 24def feasible(individual):
 25    feasible_ind = numpy.array(individual)
 26    feasible_ind = numpy.maximum(MIN_BOUND, feasible_ind)
 27    feasible_ind = numpy.minimum(MAX_BOUND, feasible_ind)
 28    return feasible_ind
 29
 30
 31def distance(feasible_ind, original_ind):
 32    return sum((f - o)**2 for f, o in zip(feasible_ind, original_ind))
 33
 34
 35def setup():
 36    creator.create("FitnessMin", base.Fitness, weights=(-1.0, -1.0))
 37    creator.create("Individual", list, fitness=creator.FitnessMin)
 38
 39    toolbox = base.Toolbox()
 40    toolbox.register("evaluate", tools.bm_zdt_1)
 41    toolbox.decorate("evaluate", tools.ClosestValidPenalty(validity, feasible, 1.0e+6, distance))
 42
 43    pop = [creator.Individual(x) for x in (numpy.random.uniform(0, 1, (MU, SIZE)))]
 44    for ind in pop:
 45        ind.fitness.values = toolbox.evaluate(ind)
 46    strategy = tools.StrategyMultiObjective(
 47        population=pop,
 48        sigma=1.0,
 49        offsprings=LAMBDA,
 50        survivors=MU
 51    )
 52    toolbox.register("generate", strategy.generate, creator.Individual)
 53    toolbox.register("update", strategy.update)
 54
 55    stats = tools.Statistics(lambda x: x.fitness.values)
 56    stats.register("min", numpy.min, axis=0)
 57    stats.register("max", numpy.max, axis=0)
 58
 59    logbook = tools.Logbook()
 60    logbook.header = ["gen", "nevals"] + (stats.fields if stats else [])
 61
 62    return toolbox, strategy, stats, logbook
 63
 64
 65def print_results(valid, parents):
 66    hv = tools.hypervolume(parents, [11.0, 11.0])
 67    if not hv > 110 and valid != len(parents):
 68        raise RuntimeError('Evolution failed to converge.')
 69    print(f"\nNumber of valid individuals is {valid}/{len(parents)}"
 70          f" with a hypervolume of {hv:.2f}.")
 71    print(f'Evolution converged correctly.')
 72
 73
 74def main():
 75    toolbox, strategy, stats, logbook = setup()
 76
 77    fitness_history = []
 78    for gen in range(NGEN):
 79        population = toolbox.generate()
 80        fitness = toolbox.map(toolbox.evaluate, population)
 81
 82        for ind, fit in zip(population, fitness):
 83            ind.fitness.values = fit
 84            fitness_history.append(fit)
 85
 86        toolbox.update(population)
 87        record = stats.compile(population) if stats is not None else {}
 88        logbook.record(gen=gen, nevals=len(population), **record)
 89        print(logbook.stream)
 90
 91    num_valid = 0
 92    for ind in strategy.parents:
 93        dist = distance(feasible(ind), ind)
 94        if numpy.isclose(dist, 0.0, rtol=1.e-5, atol=1.e-5):
 95            num_valid += 1
 96
 97    print_results(num_valid, strategy.parents)
 98
 99
100if __name__ == "__main__":
101    main()