-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathga.py
More file actions
119 lines (108 loc) · 5.28 KB
/
ga.py
File metadata and controls
119 lines (108 loc) · 5.28 KB
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
import random
from openAI import openAI
import numpy as np
from population import Individue, Population
class GA:
def __init__(self, mutation_rate, crossover_rate, eval):
'''Define parameters and create a population of N elements, each randomly generated'''
self.mutation_rate = mutation_rate
self.crossover_rate = crossover_rate
self.openAI = openAI(eval)
def selection(self, pop):
'''Evaluate the fitness of each element of the population and build a matting pool'''
for i in range(int(len(pop) / 2)):
parents = []
for j in range(2):
first_candidate_index = random.randint(1, len(pop) - 1)
second_candidate_index = random.randint(1, len(pop) - 1)
first_candidate_fitness = pop[first_candidate_index].fitness
second_candidate_fitness = pop[second_candidate_index].fitness
if first_candidate_fitness > second_candidate_fitness:
parents.append(pop[first_candidate_index])
else:
parents.append(pop[second_candidate_index])
return parents
def crossover_(self, parents):
'''
Create a child combining the genotype of two parents
For each weight matrix, W1, W2, W3 crossover individually
'''
# For W1:
w1_first_child = np.concatenate([parents[0].weights[0][:2, :], parents[1].weights[0][2:, 0:]])
w1_second_child = np.concatenate([parents[1].weights[0][:2, :], parents[0].weights[0][2:, 0:]])
# np.random.shuffle(w1_first_child)
# np.random.shuffle(w1_second_child)
# For W2:
w2_first_child = np.concatenate([parents[0].weights[1][:2, :], parents[1].weights[1][2:, 0:]])
w2_second_child = np.concatenate([parents[1].weights[1][:2, :], parents[0].weights[1][2:, 0:]])
# np.random.shuffle(w2_first_child)
# np.random.shuffle(w2_second_child)
# For W3:
w3_first_child = np.concatenate([[parents[0].weights[2][0]], [parents[1].weights[2][1]]])
w3_second_child = np.concatenate([[parents[1].weights[2][0]], [parents[0].weights[2][1]]])
# np.random.shuffle(w3_first_child)
# np.random.shuffle(w3_second_child)
first_child = Individue()
second_child = Individue()
first_child.weights = [w1_first_child, w2_first_child, w3_first_child]
# first_child.weights = [w1_second_child, w2_second_child, w3_second_child]
return [first_child, second_child]
def crossover(self, parents):
'''
Create a child combining the genotype of two parents
For each weight matrix, W1, W2, W3 crossover individually
'''
W = []
for w in range(3):
child = np.mean(np.array([parents[0].weights[w], parents[1].weights[w]]), axis=0)
W.append(child)
first_child = Individue()
second_child = Individue()
# first_child.weights = W
return [first_child, second_child]
def mutation_(self, individues):
if random.random() <= self.mutation_rate:
# For W1:
first_row_index, second__row_index = random.sample(range(4), 2)
first_col_index, second__col_index = random.sample(range(4), 2)
aux = individues[0].weights[0][first_row_index][first_col_index]
individues[0].weights[0][first_row_index][first_col_index] = individues[0].weights[0][second__row_index][
second__col_index]
individues[0].weights[0][second__row_index][second__col_index] = aux
# For W2:
first_col_index, second__col_index = random.sample(range(4), 2)
aux = individues[0].weights[1][first_col_index][0]
individues[0].weights[1][first_col_index][0] = individues[0].weights[1][first_col_index][1]
individues[0].weights[1][first_col_index][1] = aux
# For W3:
return individues
def mutation(self, individues):
if random.random() <= self.mutation_rate:
for child in individues:
# For W1:
np.random.shuffle(child.weights[0])
# For W2:
np.random.shuffle(child.weights[1])
# For W3:
np.random.shuffle(child.weights[2])
return individues
def calculate_fitness(self, individue):
return self.openAI.run_simulation(individue)
def generation(self, population):
'''
1. Selection: Pick two parents with probability according to relative fitness
2. Crossover: Create a child combining the genotype of these two parents
3. Mutation: Mutate the child based on a given probability
4. Add the new child to a new population
'''
new_population = Population(0)
for i in range(int(len(population) / 2)):
parents = self.selection(population)
if random.random() <= self.crossover_rate:
children = self.crossover(parents)
else:
children = parents
children = self.mutation(children)
for child in children:
new_population.add(child)
return new_population