Você está na página 1de 5

import numpy as np, random, operator, pandas as pd, matplotlib.

pyplot as plt

class City:
def __init__(self, x, y):
self.x = x
self.y = y

# Calcula a distância euclidiana


def distance(self, city):
return ((self.x - city.x) ** 2 + (self.y - city.y) ** 2) ** 0.5

# Imprime as coordenadas como (x,y)


def __repr__(self):
return "(" + str(self.x) + "," + str(self.y) + ")"

def createRoute(cityList):
route = random.sample(cityList, len(cityList))
return route

def initialPopulation(popSize, cityList):


population = []

for i in range(0, popSize):


population.append(createRoute(cityList))
return population

class Fitness:
def __init__(self, route):
self.route = route
self.distance = 0
self.fitness = 0.0

def routeDistance(self):
if self.distance == 0:
pathDistance = 0
for i in range(0, len(self.route)):
fromCity = self.route[i]
toCity = None

# precisa terminar na cidade onde começou, então faz essa


verificação
# se não for o último nó, adiciona a próxima "cidade" a ser
visitada
if i + 1 < len(self.route):
toCity = self.route[i + 1]
# caso contrário, é o último nó e atribui o primeiro nó visitado
else:
toCity = self.route[0]

# calcula a distância entre a cidade inicial e a próxima


pathDistance += fromCity.distance(toCity)

self.distance = pathDistance
return self.distance

def routeFitness(self):
if self.fitness == 0:
self.fitness = 1 / float(self.routeDistance())
return self.fitness

def rankRoutes(population):
fitnessResults = {}
for i in range(0, len(population)):
fitnessResults[i] = Fitness(population[i]).routeFitness()
return sorted(fitnessResults.items(), key=operator.itemgetter(1),
reverse=True)

# A função de seleção recebe como primeiro parâmetro a saída da função


rankRoutes
# para determinar qual rota utilizar
def selection(popRanked, eliteSize):
selectionResults = []
# Aqui é feito o cálculo de peso relativo de aptidão para cada indivíduo
df = pd.DataFrame(np.array(popRanked), columns=["Index", "Fitness"])
df['cum_sum'] = df.Fitness.cumsum()
df['cum_perc'] = 100 * df.cum_sum / df.Fitness.sum()

# Adição do elitismo
for i in range(0, eliteSize):
selectionResults.append(popRanked[i][0])
# Aqui é feita a comparação de um número aleatório com esses pesos
relativos
# de aptidão para selecionar os indivíduos para a etapa de "Procriação"
for i in range(0, len(popRanked) - eliteSize):
pick = 100 * random.random()
for i in range(0, len(popRanked)):
if pick <= df.iat[i, 3]:
selectionResults.append(popRanked[i][0])
break
return selectionResults

# Essa função pega o resultado da nossa seleção anterior e busca estes


indivíduos
# da nossa população
def matingPool(population, selectionResults):
matingpool = []
for i in range(0, len(selectionResults)):
index = selectionResults[i]
matingpool.append(population[index])
return matingpool

def breed(parent1, parent2):


child = []
childP1 = []
childP2 = []

geneA = int(random.random() * len(parent1))


geneB = int(random.random() * len(parent1))

startGene = min(geneA, geneB)


endGene = max(geneA, geneB)

# Aqui é feita a escolha do subconjunto aleatório do primeiro pai


for i in range(startGene, endGene):
childP1.append(parent1[i])
# Se o gene não existe no primeiro pai, então pega do segundo pai
childP2 = [item for item in parent2 if item not in childP1]

child = childP1 + childP2


return child

def breedPopulation(matingpool, eliteSize):


children = []
length = len(matingpool) - eliteSize
pool = random.sample(matingpool, len(matingpool))

# Aqui novamente usamos o elitismo para manter as melhores rotas/indivíduos


for i in range(0, eliteSize):
children.append(matingpool[i])
# Aqui utilizamos a função de breed mencionada acima para preencher o resto
# dos indivíduos
for i in range(0, length):
child = matingpool.breed(pool[i], pool[len(matingpool) - i - 1])
children.append(child)
return children

def mutate(individual, mutationRate):


for swapped in range(len(individual)):
if (random.random() < mutationRate):
swapWith = int(random.random() * len(individual))

city1 = individual[swapped]
city2 = individual[swapWith]

individual[swapped] = city2
individual[swapWith] = city1
return individual

# Aqui a mutação é aplicada na população


def mutatePopulation(population, mutationRate):
mutatedPop = []

for ind in range(0, len(population)):


mutatedInd = population.mutate(population[ind], mutationRate)
mutatedPop.append(mutatedInd)
return mutatedPop

def nextGeneration(currentGen, eliteSize, mutationRate):


popRanked = currentGen.rankRoutes(currentGen)
selectionResults = currentGen.selection(popRanked, eliteSize)
matingpool = currentGen.matingPool(currentGen, selectionResults)
children = currentGen.breedPopulation(matingpool, eliteSize)
nextGeneration = currentGen.mutatePopulation(children, mutationRate)
return nextGeneration

def geneticAlgorithm(population, popSize, eliteSize, mutationRate,


generations):
pop = initialPopulation(popSize, population)
print("Initial distance: " + str(1 / population.rankRoutes(pop)[0][1]))

for i in range(0, generations):


pop = population.nextGeneration(pop, eliteSize, mutationRate)
print("Final distance: " + str(1 / population.rankRoutes(pop)[0][1]))
bestRouteIndex = population.rankRoutes(pop)[0][0]
bestRoute = pop[bestRouteIndex]
return bestRoute

def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate,


generations):
pop = initialPopulation(popSize, population)
print("Distância Inicial: " + str(1 / population.rankRoutes(pop)[0][1]))
progress = []
progress.append(1 / population.rankRoutes(pop)[0][1])

for i in range(0, generations):


pop = population.nextGeneration(pop, eliteSize, mutationRate)
progress.append(1 / population.rankRoutes(pop)[0][1])

print("Distância Final: " + str(1 / population.rankRoutes(pop)[0][1]))


bestRouteIndex = population.rankRoutes(pop)[0][0]
bestRoute = pop[bestRouteIndex]
print("Melhor rota:", bestRoute)
plt.plot(progress)
plt.ylabel('Distância')
plt.xlabel('Geração')
plt.show()

def main ():


berlin = [City(565, 575),
City(25, 185),
City(345, 750),
City(945, 685),
City(845, 655),
City(880, 660),
City(25, 230),
City(525, 1000),
City(580, 1175),
City(650, 1130),
City(1605, 620),
City(1220, 580),
City(1465, 200),
City(1530, 5),
City(845, 680),
City(725, 370),
City(145, 665),
City(415, 635),
City(510, 875),
City(560, 365),
City(300, 465),
City(520, 585),
City(480, 415),
City(835, 625),
City(975, 580),
City(1215, 245),
City(1320, 315),
City(1250, 400),
City(660, 180),
City(410, 250),
City(420, 555),
City(575, 665),
City(1150, 1160),
City(700, 580),
City(685, 595),
City(685, 610),
City(770, 610),
City(795, 645),
City(720, 635),
City(760, 650),
City(475, 960),
City(95, 260),
City(875, 920),
City(700, 500),
City(555, 815),
City(830, 485),
City(1170, 65),
City(830, 610),
City(605, 625),
City(595, 360),
City(1340, 725),
City(1740, 245)]
Fitness.geneticAlgorithmPlot(population=berlin, popSize=200, eliteSize=55,
mutationRate=0.001, generations=800)

if __name__ == '__main__':
main()

Você também pode gostar