77 lines
3.0 KiB
Python
77 lines
3.0 KiB
Python
import random
|
|
from deap import creator, base, tools, algorithms
|
|
import numpy as np
|
|
|
|
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
|
|
creator.create("Individual", np.ndarray, fitness=creator.FitnessMax)
|
|
|
|
toolbox = base.Toolbox()
|
|
|
|
#toolbox.register("attr_bool", random.randint, 0, 1) # non-numpy non-float version
|
|
toolbox.register("attr_float", random.random)
|
|
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_float, n=100)
|
|
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
|
|
|
|
def linearFitness(individual):
|
|
'''selection pressure for genome values to be numpy.arange(start=0.0, stop=1.0, step=1/len(genome))'''
|
|
import numpy as np
|
|
a = np.arange(0, 1, 1.0/len(individual))
|
|
b = np.array(individual)
|
|
return 1.0-np.sum(np.abs(a-b))/(len(individual)*0.5),
|
|
|
|
def cxTwoPointCopy(ind1, ind2):
|
|
"""Execute a two points crossover with copy on the input individuals. The
|
|
copy is required because the slicing in numpy returns a view of the data,
|
|
which leads to a self overwriting in the swap operation. It prevents
|
|
::
|
|
>>> import numpy as np
|
|
>>> a = np.array((1,2,3,4))
|
|
>>> b = np.array((5,6,7,8))
|
|
>>> a[1:3], b[1:3] = b[1:3], a[1:3]
|
|
>>> print(a)
|
|
[1 6 7 4]
|
|
>>> print(b)
|
|
[5 6 7 8]
|
|
"""
|
|
size = len(ind1)
|
|
cxpoint1 = random.randint(1, size)
|
|
cxpoint2 = random.randint(1, size - 1)
|
|
if cxpoint2 >= cxpoint1:
|
|
cxpoint2 += 1
|
|
else: # Swap the two cx points
|
|
cxpoint1, cxpoint2 = cxpoint2, cxpoint1
|
|
ind1[cxpoint1:cxpoint2], ind2[cxpoint1:cxpoint2] = ind2[cxpoint1:cxpoint2].copy(), ind1[cxpoint1:cxpoint2].copy()
|
|
return ind1, ind2
|
|
|
|
toolbox.register("evaluate", linearFitness)
|
|
#toolbox.register("mate", tools.cxTwoPoint) # non-numpy non-float version
|
|
toolbox.register("mate", cxTwoPointCopy)
|
|
#toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) # non-numpy non-float version
|
|
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=0.2, indpb=0.05)
|
|
toolbox.register("select", tools.selTournament, tournsize=3)
|
|
|
|
# evolution loop
|
|
population = toolbox.population(n=100)
|
|
NGEN=500
|
|
for gen in range(NGEN):
|
|
offspring = algorithms.varAnd(population, toolbox, cxpb=0.5, mutpb=0.1)
|
|
# constrain genome values to [0,1]
|
|
for offspring_i,individual in enumerate(offspring):
|
|
np.clip(np.array(offspring[offspring_i]), 0.0, 1.0)
|
|
# Evaluate the individuals with an invalid fitness (not yet evaluated)
|
|
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
|
|
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
|
|
for ind, fit in zip(invalid_ind, fitnesses):
|
|
ind.fitness.values = fit
|
|
population = toolbox.select(offspring, k=len(population))
|
|
|
|
# post-evolution analysis
|
|
fitnesses = toolbox.map(toolbox.evaluate, population)
|
|
sortedFitnesses = sorted(fitnesses)
|
|
|
|
bestFitness, worstFitness = sortedFitnesses[0], sortedFitnesses[-1]
|
|
print(bestFitness, worstFitness)
|
|
|
|
bestGenome = tools.selBest(population, k=1)
|
|
print(bestGenome)
|