-
Notifications
You must be signed in to change notification settings - Fork 0
/
genetic.py
135 lines (105 loc) · 4.45 KB
/
genetic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# coding: utf8
#############################################################################
#
# This file is part of evolveRobot.
#
# Contributors:
# - created by Valentin Owczarek
#############################################################################
from config import Config
from indi import *
import dump
class Population(object):
def __init__(self):
self.numberOfIndi = 0
self.populationMax = Config.PopulationPopMax
self.members =[]
def __len__(self):
return len(self.members)
def addIndi(self, i):
self.numberOfIndi += 1
self.members.append(i)
def reducePopulation(self):
"""Reduce the population to keep it below self.populationMax. The Candidates that are
removed are the one with the highest fitness function """
self.members = sorted(self.members, key = lambda x : x.fitness)
self.members = self.members[:self.populationMax]
def cleanPop(self):
self.members = []
self.numberOfIndi = 0
def tournament(self, nbCandidate=4):
s = random.choice(self.members)
for _ in range(nbCandidate):
sCandidate = random.choice(self.members)
if s.fitness > sCandidate.fitness:
s = sCandidate
return s
class GeneticAlgo(object):
def __init__(self, fitnessFun, population):
self.population = population
self.fitnessFun = fitnessFun
self.nbCycle = 0
self.best = Config.geneticBest
self.nbAugmentation = Config.genticNbAugmentation
self.addRate = Config.genticAddRate
self.crossRate = Config.genticCrossRate
self.cleanRate = Config.genticCleanRate
self.nbAdd = int(self.nbAugmentation * self.addRate)
self.nbCross = int(self.nbAugmentation * self.crossRate)
self.nbClean = int(self.nbAugmentation * self.cleanRate)
# self.nbSplit = 30
def evolve(self, historyLog=False):
# print("========================= generation {0} ================================".format(self.nbCycle))
self.population.reducePopulation()
newCandidates = []
newBest = []
events = {}
for i in range(self.best):
newBest.append(self.population.members[i])
for _ in range(self.nbAdd):
best = self.population.tournament()
child = best.copy()
child.addRandomShape()
newCandidates.append(child)
if historyLog:
events[child] = [child, ["A", best, None], self.nbCycle, -1]
for _ in range(self.nbClean):
best = self.population.tournament()
child = best.copy()
res = child.removeShapeAtRandom()
if res == 1:
newCandidates.append(child)
if historyLog:
events[child] = [child, ["D", best, None], self.nbCycle, -1]
for _ in range(self.nbCross):
best1 = self.population.tournament()
best2 = self.population.tournament()
child1, child2 = best1.crossOver(best2)
newCandidates.append(child1)
newCandidates.append(child2)
if historyLog:
events[child1] = [child1, ["X", best1, best2], self.nbCycle, -1]
events[child2] = [child2, ["X", best1, best2], self.nbCycle, -1]
# for _ in range(self.nbSplit):
# best = self.population.tournament()
# child = best.copy()
# res = child.splitSquare()
# if res == 1:
# newCandidates.append(child)
# if historyLog:
# historyLog.addEvent(child, ["S", best, None], self.nbCycle)
self.population.cleanPop()
# Evaluates all the candidates.
self.fitnessFun.computeValues(newCandidates)
if historyLog:
for c in newCandidates:
evt = events[c]
evt[3] = c.fitness
historyLog.addEvent(evt[0], evt[1], evt[2], 1.0/evt[3])
for i in newCandidates:
self.population.addIndi(i)
for i in newBest:
self.population.addIndi(i)
if dump.activated():
dump.addGeneration(newCandidates, self.fitnessFun)
self.nbCycle += 1