From c7f99fa201f4aac01db65bfe1469801f48ea0f9a Mon Sep 17 00:00:00 2001 From: Eddie Pantridge Date: Fri, 2 Sep 2016 23:10:02 -0400 Subject: [PATCH] Fixed bug in automatic epsilon lexicase, and added example. --- deap/tools/selection.py | 4 +- examples/gp/symbreg_epsilon_lexicase.py | 92 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 examples/gp/symbreg_epsilon_lexicase.py diff --git a/deap/tools/selection.py b/deap/tools/selection.py index a83525b6a..d69e168ed 100644 --- a/deap/tools/selection.py +++ b/deap/tools/selection.py @@ -295,9 +295,9 @@ def selAutomaticEpsilonLexicase(individuals, k): random.shuffle(cases) while len(cases) > 0 and len(candidates) > 1: - errors_for_this_case = [x.fitness.values[cases[0] for x in candidates] + errors_for_this_case = [x.fitness.values[cases[0]] for x in candidates] median_val = np.median(errors_for_this_case) - median_absolute_deviation = np.median([abs(x - median_val) for x in candidates]) + median_absolute_deviation = np.median([abs(x - median_val) for x in errors_for_this_case]) if fit_weights[cases[0]] > 0: best_val_for_case = max(errors_for_this_case) min_val_to_survive = best_val_for_case - median_absolute_deviation diff --git a/examples/gp/symbreg_epsilon_lexicase.py b/examples/gp/symbreg_epsilon_lexicase.py new file mode 100644 index 000000000..86a993faa --- /dev/null +++ b/examples/gp/symbreg_epsilon_lexicase.py @@ -0,0 +1,92 @@ +# This file is part of EAP. +# +# EAP is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# EAP is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with EAP. If not, see . + +import operator +import math +import random + +import numpy + +from deap import algorithms +from deap import base +from deap import creator +from deap import tools +from deap import gp + +# Define new functions +def protectedDiv(left, right): + try: + return left / right + except ZeroDivisionError: + return 1 + +pset = gp.PrimitiveSet("MAIN", 1) +pset.addPrimitive(operator.add, 2) +pset.addPrimitive(operator.sub, 2) +pset.addPrimitive(operator.mul, 2) +pset.addPrimitive(protectedDiv, 2) +pset.addPrimitive(operator.neg, 1) +pset.addPrimitive(math.cos, 1) +pset.addPrimitive(math.sin, 1) +pset.addEphemeralConstant("rand101", lambda: random.randint(-1,1)) +pset.renameArguments(ARG0='x') + +creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) +creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMin) + +toolbox = base.Toolbox() +toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2) +toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.expr) +toolbox.register("population", tools.initRepeat, list, toolbox.individual) +toolbox.register("compile", gp.compile, pset=pset) + +def evalSymbReg(individual, points): + # Transform the tree expression in a callable function + func = toolbox.compile(expr=individual) + # Evaluate the mean squared error between the expression + # and the real function : x**4 + x**3 + x**2 + x + sqerrors = ((func(x) - x**4 - x**3 - x**2 - x)**2 for x in points) + return math.fsum(sqerrors) / len(points), + +toolbox.register("evaluate", evalSymbReg, points=[x/10. for x in range(-10,10)]) +toolbox.register("select", tools.selAutomaticEpsilonLexicase) +toolbox.register("mate", gp.cxOnePoint) +toolbox.register("expr_mut", gp.genFull, min_=0, max_=2) +toolbox.register("mutate", gp.mutUniform, expr=toolbox.expr_mut, pset=pset) + +toolbox.decorate("mate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17)) +toolbox.decorate("mutate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17)) + +def main(): + #random.seed(318) + + pop = toolbox.population(n=300) + hof = tools.HallOfFame(1) + + stats_fit = tools.Statistics(lambda ind: ind.fitness.values) + stats_size = tools.Statistics(len) + mstats = tools.MultiStatistics(fitness=stats_fit, size=stats_size) + mstats.register("avg", numpy.mean) + mstats.register("std", numpy.std) + mstats.register("min", numpy.min) + mstats.register("max", numpy.max) + + pop, log = algorithms.eaSimple(pop, toolbox, 0.5, 0.1, 40, stats=mstats, + halloffame=hof, verbose=True) + # print log + return pop, log, hof + +if __name__ == "__main__": + main()