# Não remover - config do notebook
%load_ext autoreload
%autoreload 2
!pip install deap
!pip install networkx
Collecting deap
Downloading deap-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (160 kB)
|████████████████████████████████| 160 kB 16.6 MB/s
Requirement already satisfied: numpy in /shared-libs/python3.7/py/lib/python3.7/site-packages (from deap) (1.19.5)
Installing collected packages: deap
Successfully installed deap-1.3.1
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
Collecting networkx
Downloading networkx-2.5.1-py3-none-any.whl (1.6 MB)
|████████████████████████████████| 1.6 MB 50.3 MB/s
Collecting decorator<5,>=4.3
Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Installing collected packages: decorator, networkx
Attempting uninstall: decorator
Found existing installation: decorator 5.0.9
Not uninstalling decorator at /shared-libs/python3.7/py-core/lib/python3.7/site-packages, outside environment /root/venv
Can't uninstall 'decorator'. No files were found to uninstall.
Successfully installed decorator-4.4.2 networkx-2.5.1
WARNING: You are using pip version 21.1.2; however, version 21.1.3 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
import random
import operator
import os
import subprocess
import copy
import matplotlib.pyplot as plt
import numpy as np
from deap import base, creator, tools, gp, algorithms
from pacman import runGames
import layout
from searchAgents import GpAgent, Agent
from ghostAgents import GhostAgent, RandomGhost
from pacman import loadAgent
import textDisplay
import networkx as nx
def safe_division(numerator, denominator):
try:
return numerator / denominator
except ZeroDivisionError:
return 1
def mean(n1, n2):
return (float)((n1+n2)/2)
pset = gp.PrimitiveSet("main", 10)
# Operadores
pset.addPrimitive(max, 2)
pset.addPrimitive(min, 2)
pset.addPrimitive(mean, 2)
pset.addPrimitive(operator.add, 2)
pset.addPrimitive(operator.sub, 2)
pset.addPrimitive(operator.mul, 2)
pset.addPrimitive(safe_division, 2)
# Constantes
pset.addTerminal(-1.0)
pset.addTerminal(0.0)
pset.addTerminal(0.1)
pset.addTerminal(0.5)
pset.addTerminal(2.0)
pset.addTerminal(5.0)
pset.addTerminal(10.0)
# Demais terminais
pset.renameArguments(ARG0="DistToNextPill")
pset.renameArguments(ARG1="DistToNextPowerPill")
pset.renameArguments(ARG2="DistToEdibleGhost")
pset.renameArguments(ARG3="DistToNonEdibleGhost")
pset.renameArguments(ARG4="DistToNextJunction")
pset.renameArguments(ARG5="GdPillCount")
pset.renameArguments(ARG6="GdPowerPillCount")
pset.renameArguments(ARG7="GdEdibleGhostCount")
pset.renameArguments(ARG8="GdNonEdibleGhostCount")
pset.renameArguments(ARG9="GdJunctionCount")
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMax, pset=pset)
toolbox = base.Toolbox()
toolbox.register("select", tools.selTournament, tournsize=10)
toolbox.register("mate", gp.cxOnePoint)
toolbox.register("expr_mut", gp.genFull, min_=1, max_=2)
toolbox.register("mutate", gp.mutUniform, expr=toolbox.expr_mut, pset=pset)
# Then, we decorate the mate and mutate method to limit the height of generated individuals.
# This is done to avoid an important draw back of genetic programming : bloat.
# Koza in his book on genetic programming suggest to use a max depth of 17.
toolbox.decorate("mate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17))
toolbox.decorate("mutate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17))
#Fitness function
def evaluate(expr):
tree = gp.PrimitiveTree(expr)
function = gp.compile(tree, pset)
# Choose a layout
mediumClassicLayout = layout.getLayout('mediumClassic')
# Choose a Pacman agent
pacmanType = loadAgent('GpAgent', True)
pacman = pacmanType(function)
# Choose a ghost agent
numGhosts = 2
ghostType = loadAgent('RandomGhost', True)
ghosts = [ghostType( i+1 ) for i in range( numGhosts )]
#pacman = GpAgent(function)
#ghosts = [RandomGhost(GhostAgent(Agent(i))) for i in [1,2]]
display = textDisplay.NullGraphics()
# jogar, e retornar o score médio
score = runGames(mediumClassicLayout, pacman, ghosts, display, numGames=5, record=False)
return (score,) # retorno precisa ser uma tupla
toolbox.register("evaluate", evaluate)
#Fitness function
def generalize(expr):
tree = gp.PrimitiveTree(expr)
function = gp.compile(tree, pset)
# Choose a layout
mediumClassicLayout = layout.getLayout('originalClassic')
# Choose a Pacman agent
pacmanType = loadAgent('GpAgent', True)
pacman = pacmanType(function)
# Choose a ghost agent
numGhosts = 2
ghostType = loadAgent('RandomGhost', True)
ghosts = [ghostType( i+1 ) for i in range( numGhosts )]
display = textDisplay.NullGraphics()
# jogar, e retornar o score médio
score = runGames(mediumClassicLayout, pacman, ghosts, display, numGames=20, record=False)
return (score,) # retorno precisa ser uma tupla
toolbox.register("generalize", generalize)
toolbox.register("expr", gp.genFull, pset=pset, min_=2, max_=5)
toolbox.register("compile", gp.compile, pset=pset)
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.expr)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
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", np.mean)
mstats.register("std", np.std)
mstats.register("min", np.min)
mstats.register("max", np.max)
def graphEvolution(records, lastGen):
maxFitness = [records[i]['fitness']['max'] for i in range(0, lastGen)]
minFitness = [records[i]['fitness']['min'] for i in range(0, lastGen)]
avgFitness = [records[i]['fitness']['avg'] for i in range(0, lastGen)]
generations = np.arange(0, lastGen)
plt.plot(generations, maxFitness, label = "maxFitness")
plt.plot(generations, minFitness, label = "minFitness")
plt.plot(generations, avgFitness, label = "avgFitness")
plt.xlabel('Geração')
# Set the y axis label of the current axis.
plt.ylabel('Pontuação média em 5 jogos')
# Set a title of the current axes.
plt.title('Evolução dos cromossomos no mapa mediumClassic')
# show a legend on the plot
plt.legend(loc='upper left')
# Display a figure.
plt.show()
def graphGeneralization(generalization, lastGen):
generalizationFitness = [generalization[i][0] for i in range(0, lastGen)]
generations = np.arange(0, lastGen)
plt.plot(generations, generalizationFitness)
plt.xlabel('Geração')
# Set the y axis label of the current axis.
plt.ylabel('Pontuação média em 5 jogos')
# Set a title of the current axes.
plt.title('Aptidão dos melhores cromossomos no mapa originalClassic')
# show a legend on the plot
plt.legend()
# Display a figure.
plt.show()
def eaCustom(population, toolbox, cxpb, mutpb, ngen, failSafe, stats=None, halloffame=None, verbose=__debug__):
logbook = tools.Logbook()
logbook.header = ['gen', 'nevals'] + (stats.fields if stats else [])
# Evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in population if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
if halloffame is not None:
halloffame.update(population)
record = stats.compile(population) if stats else {}
logbook.record(gen=0, nevals=len(invalid_ind), **record)
if verbose:
print(logbook.stream)
n=1
gen=0
generalization = []
records = []
# Begin the generational process
while n <= ngen:
gen+=1
oldHallOfFame = copy.deepcopy(halloffame)
# Select the next generation individuals
offspring = toolbox.select(population, len(population))
# Vary the pool of individuals
offspring = algorithms.varAnd(offspring, toolbox, cxpb, mutpb)
# Evaluate the individuals with an invalid fitness
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
# Update the hall of fame with the generated individuals
if halloffame is not None:
halloffame.update(offspring)
# Replace the current population by the offspring
population[:] = offspring
# Append the current generation statistics to the logbook
record = stats.compile(population) if stats else {}
# Critério de parada
newMax = record['fitness']['max']
if(oldHallOfFame[0].fitness.values[0] > newMax):
print(halloffame[0].fitness.values[0], newMax)
print("INOVOU\n")
n=1
else:
print(halloffame[0].fitness.values[0], newMax)
print("REPETIU", n, 'VEZES\n')
n+=1
# Generalização
bestOfAllTimesTree = gp.PrimitiveTree(halloffame[0])
generalization.append(toolbox.generalize(bestOfAllTimesTree))
records.append(record)
logbook.record(gen=gen, nevals=len(invalid_ind), **record)
if verbose:
print(logbook.stream)
#FailSafe - Verificar a necessidade de deepcopy
failSafe.population = population
failSafe.logbook = copy.deepcopy(logbook)
failSafe.records = copy.deepcopy(records)
failSafe.generalization = copy.deepcopy(generalization)
failSafe.lastGen = gen
return population, logbook, records, generalization, gen
class FailSafe:
def __init__(self):
self.population = None
self.logbook = None
self.records = None
self.generalization = None
self.lastGen = None
pop = toolbox.population(n=100)
hof = tools.HallOfFame(1)
failSafe = FailSafe()
pop, log, records, generalization, lastGen = eaCustom(pop, toolbox, 0.8, 0.1, ngen=50, failSafe=failSafe, stats=mstats, halloffame=hof, verbose=False)
print(failSafe.logbook)
fitness size
------------------------------------------------------- -----------------------------------------------
gen nevals avg gen max min nevals std avg gen max min nevals std
0 100 -501.078 0 -130.4 -624.6 100 81.8535 28.92 0 63 7 100 21.6922
1 72 -387.446 1 44.2 -824.2 72 141.879 33.76 1 77 5 72 20.5169
2 67 -255.984 2 44.2 -1152.2 67 206.796 53.42 2 97 7 67 17.0559
3 81 -208.166 3 486.4 -764.4 81 211.074 59.98 3 81 29 81 10.1528
4 81 -137.854 4 921.6 -630.4 81 309.535 58.2 4 91 3 81 15.2026
5 91 188.344 5 1179 -595.2 91 517.679 56.78 5 121 23 91 15.4581
6 78 512.33 6 1383.8 -595 78 436.36 53.12 6 73 29 78 9.66569
7 85 495.162 7 1383.8 -582.6 85 499.305 53.76 7 73 31 85 7.76546
8 77 415.44 8 1625 -1732.2 77 655.211 53.88 8 87 17 77 11.0935
print(failSafe.records)
[{'fitness': {'avg': -387.4460000000001, 'std': 141.878761920169, 'min': -824.2, 'max': 44.2}, 'size': {'avg': 33.76, 'std': 20.516880854554866, 'min': 5, 'max': 77}}, {'fitness': {'avg': -255.98399999999998, 'std': 206.79600514516716, 'min': -1152.2, 'max': 44.2}, 'size': {'avg': 53.42, 'std': 17.05589634114842, 'min': 7, 'max': 97}}, {'fitness': {'avg': -208.16600000000003, 'std': 211.07378435987732, 'min': -764.4, 'max': 486.4}, 'size': {'avg': 59.98, 'std': 10.152812418241558, 'min': 29, 'max': 81}}, {'fitness': {'avg': -137.85399999999998, 'std': 309.5353328523256, 'min': -630.4, 'max': 921.6}, 'size': {'avg': 58.2, 'std': 15.202631351183912, 'min': 3, 'max': 91}}, {'fitness': {'avg': 188.34400000000002, 'std': 517.679293060868, 'min': -595.2, 'max': 1179.0}, 'size': {'avg': 56.78, 'std': 15.458059386611243, 'min': 23, 'max': 121}}, {'fitness': {'avg': 512.33, 'std': 436.35984359241854, 'min': -595.0, 'max': 1383.8}, 'size': {'avg': 53.12, 'std': 9.665691904876752, 'min': 29, 'max': 73}}, {'fitness': {'avg': 495.162, 'std': 499.30513451796185, 'min': -582.6, 'max': 1383.8}, 'size': {'avg': 53.76, 'std': 7.765461995271112, 'min': 31, 'max': 73}}, {'fitness': {'avg': 415.43999999999994, 'std': 655.2108503375078, 'min': -1732.2, 'max': 1625.0}, 'size': {'avg': 53.88, 'std': 11.093493588586059, 'min': 17, 'max': 87}}]
graphEvolution(failSafe.records, failSafe.lastGen)
graphGeneralization(failSafe.generalization, failSafe.lastGen)
No handles with labels found to put in legend.
print(hof[0])
mean(add(max(add(sub(GdPowerPillCount, -1.0), add(10.0, GdNonEdibleGhostCount)), add(sub(10.0, DistToNextPowerPill), min(DistToNextPill, 5.0))), mul(max(min(-1.0, 5.0), add(DistToNextPill, 5.0)), sub(safe_division(GdPowerPillCount, DistToNextPill), DistToNextPowerPill))), mean(max(safe_division(10.0, add(GdNonEdibleGhostCount, GdPillCount)), sub(safe_division(10.0, sub(2.0, DistToNextPowerPill)), GdPowerPillCount)), add(max(mul(10.0, 10.0), add(GdPowerPillCount, GdJunctionCount)), max(sub(0.5, DistToNextPill), DistToNextJunction))))
print(toolbox.evaluate(hof[0])[0])
Pacman emerges victorious! Score: 1546
525.2