forked from fullmetalfelix/ML-CSC-tutorial
-
Notifications
You must be signed in to change notification settings - Fork 1
/
GA.py
102 lines (62 loc) · 3.02 KB
/
GA.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
import numpy, random
def Evaluation_dummy(element):
return random.random()
class GAEngine:
def __init__(self, popSize, dnaSize, scale=1.0):
self.populationSize = popSize
self.dnaSize = dnaSize
self.scale = scale
self.population = scale*(2*numpy.random.rand(popSize, dnaSize)-1);
self.generation = 0
self.best = None
self.bestFit = None
self.mutationRate = 0.01
self.mutationScale = 0.1
self.Evaluate = Evaluation_dummy
self.tau = 0.1
def Evolve(self):
# evaluate all elements
fitness = numpy.zeros(self.populationSize)
ps = numpy.arange(self.populationSize) / (self.populationSize-1)
ps = (self.tau) * numpy.exp(-ps*self.tau)
ps /= numpy.sum(ps)
for i in range(self.populationSize):
element = self.population[i]
fitness[i] = self.Evaluate(element)
# sort population by fitness - inverse order
idx = numpy.argsort(-fitness)
fitness = fitness[idx]
self.population = self.population[idx]
print('generation[{}] fitness: best {}, avg {}, worse {}'.format(self.generation, fitness[0], numpy.mean(fitness), fitness[self.populationSize-1]))
if self.bestFit == None:
self.best = self.population[0]
self.bestFit = fitness[0]
else:
if self.bestFit < fitness[0]:
self.best = self.population[0]
self.bestFit = fitness[0]
# pick pairs for reproduction
idx = numpy.arange(self.populationSize, dtype=numpy.int32)
mfactor = self.mutationRate/self.dnaSize
newpop = numpy.zeros((self.populationSize, self.dnaSize))
for i in range(self.populationSize):
parentsIdx = numpy.random.choice(idx, size=2, p=ps)
parents = self.population[parentsIdx]
# do the mixing
mixer = numpy.random.choice([0,1], size=self.dnaSize)
son = parents[0] * mixer + parents[1] * (1-mixer)
# mutate
mutator = numpy.random.choice([0,1], size=self.dnaSize, p=[1-mfactor, mfactor])
mutator = (2*numpy.random.rand(self.dnaSize)-1) * self.mutationScale * mutator
son += mutator
newpop[i] = son
self.population = newpop
self.generation += 1
return [fitness[0], numpy.mean(fitness), fitness[self.populationSize-1]]
def TrySelection(self, n):
ps = numpy.arange(self.populationSize) / (self.populationSize-1)
ps = (self.tau) * numpy.exp(-ps*self.tau)
ps /= numpy.sum(ps)
idx = numpy.arange(self.populationSize, dtype=numpy.int32)
selected = numpy.random.choice(idx, size=n, p=ps)
return selected