Last active
August 29, 2015 13:57
-
-
Save soravux/9657679 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import operator | |
import math | |
import random | |
import ctypes | |
from functools import reduce | |
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 div(left, right): | |
try: | |
return int(left / right) | |
except ZeroDivisionError: | |
return 0 | |
def mod(left, right): | |
try: | |
return int(left % right) | |
except ZeroDivisionError: | |
return 0 | |
def lshift(val): | |
return operator.lshift(val, 1) | |
def rshift(val): | |
return operator.rshift(val, 1) | |
def arity3(left, middle, right): | |
return left + middle + right | |
defaultSymbolMap = { | |
'add': '({0} + {1})', | |
'sub': '({0} - {1})', | |
'xor': '({0} ^ {1})', | |
'mod': '({0} % {1})', | |
'mul': '({0} * {1})', | |
'div': '({0} / {1})', | |
'neg': '~{0}', | |
'lshift': '({0} << 1)', | |
'rshift': '({0} >> 1)', | |
} | |
def getInfix(individual, symbolMap=defaultSymbolMap, index=0): | |
x = individual[index] | |
if x.arity >= 3: | |
data = [] | |
last_index = index | |
for _ in range(x.arity): | |
out, last_index = getInfix(individual, index=last_index+1) | |
data.append(out) | |
retVal = x.seq.format(*data) | |
elif x.arity == 2: | |
out_left, next_idx = getInfix(individual, index=index+1) | |
out_right, last_index = getInfix(individual, index=next_idx+1) | |
retVal = symbolMap.get(x.name, x.name).format(out_left, out_right) | |
elif x.arity == 1: | |
val, last_index = getInfix(individual, index=index+1) | |
retVal = symbolMap.get(x.name, x.name).format(val) | |
else: | |
retVal, last_index = x.value, index | |
if index == 0: | |
return retVal | |
return retVal, last_index | |
pset = gp.PrimitiveSet("MAIN", 1) | |
pset.addPrimitive(arity3, 3) | |
pset.addPrimitive(operator.add, 2) | |
pset.addPrimitive(operator.sub, 2) | |
pset.addPrimitive(operator.mul, 2) | |
pset.addPrimitive(mod, 2) | |
pset.addPrimitive(operator.xor, 2) | |
pset.addPrimitive(div, 2) | |
pset.addPrimitive(operator.neg, 1) | |
pset.addPrimitive(lshift, 1) | |
pset.addPrimitive(rshift, 1) | |
pset.addEphemeralConstant("rand101", lambda: random.randint(-1, 1)) | |
pset.renameArguments(ARG0='x') | |
creator.create("FitnessMulti", base.Fitness, weights=(-1.0,)) | |
creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMulti) | |
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 evaluation(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 | |
sqerrors = ((func(x) - (x ^ 0b101001101))**2 for x in points) | |
return math.fsum(sqerrors) / len(points), | |
points = [int(x) for x in range(0, 42)] | |
toolbox.register("evaluate", evaluation, points=points) | |
toolbox.register("select", tools.selTournament, tournsize=3) | |
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) | |
def main(): | |
#random.seed(315) | |
pop = toolbox.population(n=300) | |
hof = tools.HallOfFame(10) | |
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) | |
try: | |
pop, log = algorithms.eaSimple(pop, toolbox, 0.5, 0.1, 40, stats=mstats, | |
halloffame=hof, verbose=True) | |
except KeyboardInterrupt: | |
pass | |
print() | |
for idx, y in enumerate(hof): | |
err, = evaluation(y, points) | |
print("#{idx:01d}: ({err:.2f}) {eq}".format( | |
eq=getInfix(y), | |
**locals() | |
)) | |
return pop, log, hof | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment