-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathgenetic.py
90 lines (74 loc) · 3.15 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
from operator import attrgetter
import random
def crossover(parent, parent2, get_fitness, customCrossover):
childGenes = parent.Genes[:]
if customCrossover is not None:
customCrossover(childGenes, parent2.Genes[:])
else:
destIndex = random.randint(0, len(parent.Genes) - 1)
srcIndex = destIndex if len(parent2.Genes) > destIndex else random.randint(0, len(parent2.Genes) - 1)
childGenes[destIndex] = parent2.Genes[srcIndex]
fitness = get_fitness(childGenes)
return Individual(childGenes, fitness, "crossover")
def mutate(parent, geneSet, get_fitness, createGene, customMutate):
childGenes = parent.Genes[:]
if customMutate is not None:
customMutate(childGenes)
else:
index = random.randint(0, len(parent.Genes) - 1)
if geneSet is not None:
geneIndex = random.randint(0, len(geneSet) - 1)
childGenes[index] = geneSet[geneIndex]
else:
childGenes[index] = createGene(index, len(childGenes))
fitness = get_fitness(childGenes)
return Individual(childGenes, fitness, "mutate")
def generateParent(minLength, maxLength, geneSet, get_fitness, createGene):
childGenes = []
length = random.randint(minLength, maxLength)
if geneSet is not None:
for i in range(0, length):
geneIndex = random.randint(0, len(geneSet) - 1)
childGenes.append(geneSet[geneIndex])
else:
for i in range(0, length):
childGenes.append(createGene(i, length))
fitness = get_fitness(childGenes)
return Individual(childGenes, fitness, "random")
def getBest(get_fitness, display, minLen, optimalFitness,
geneSet=None, createGene=None, maxLen=None,
customMutate=None, customCrossover=None):
random.seed()
if geneSet is None and createGene is None:
raise ValueError('must specify geneSet or createGene')
if geneSet is not None and createGene is not None:
raise ValueError('cannot specify both geneSet and createGene')
if maxLen is None:
maxLen = minLen
bestParent = generateParent(minLen, maxLen, geneSet, get_fitness, createGene)
display(bestParent)
options = {
0: lambda p: mutate(p, geneSet, get_fitness, createGene, customMutate),
1: lambda p: crossover(p, bestParent, get_fitness, customCrossover)
}
while bestParent.Fitness < optimalFitness:
parent = generateParent(minLen, maxLen, geneSet, get_fitness, createGene)
attemptsSinceLastImprovement = 0
while attemptsSinceLastImprovement < 128:
child = options[random.randint(0, len(options) - 1)](parent)
if child.Fitness > parent.Fitness:
parent = child
attemptsSinceLastImprovement = 0
attemptsSinceLastImprovement += 1
if bestParent.Fitness < parent.Fitness:
bestParent, parent = parent, bestParent
display(bestParent)
return bestParent
class Individual:
Genes = None
Fitness = None
Strategy = None
def __init__(self, genes, fitness, strategy):
self.Genes = genes
self.Fitness = fitness
self.Strategy = strategy