-
Notifications
You must be signed in to change notification settings - Fork 96
/
population.go
executable file
·126 lines (120 loc) · 3.4 KB
/
population.go
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
package gago
import (
"math"
"math/rand"
"sync"
"time"
)
// A Population contains deme which themselves contain individuals.
type Population struct {
// Number of demes
NbDemes int
// Number of individuals in each deme
NbIndividuals int
// Number of genes in each individual (imposed by the problem)
NbGenes int
// Demes
Demes []Deme
// Overall best individual (dummy initialization at the begining)
Best Individual
// Fitness function to evaluate individuals (imposed by the problem)
Ff FitnessFunction
// Initial random boundaries
Initializer Initializer
// Selection method
Selector Selector
// Crossover method
Crossover Crossover
// Mutation method
Mutators []Mutator
// Migration method
Migrator Migrator
}
// Initialize each deme in the population and assign an initial fitness to each
// individual in each deme.
func (pop *Population) Initialize(variables int) {
// Number of genes in each individual
pop.NbGenes = variables
// Create the demes
pop.Demes = make([]Deme, pop.NbDemes)
var wg sync.WaitGroup
for i := range pop.Demes {
wg.Add(1)
go func(j int) {
defer wg.Done()
// Create a new random number generator
var source = rand.NewSource(time.Now().UnixNano())
var generator = rand.New(source)
// Create the deme
var deme = Deme{make([]Individual, pop.NbIndividuals), generator}
// Initialize the deme
deme.initialize(pop.NbGenes, pop.Initializer)
// Add it to the population
pop.Demes[j] = deme
// Initial evaluation
pop.Demes[j].evaluate(pop.Ff)
// Sort the deme
pop.Demes[j].sort()
}(i)
}
wg.Wait()
// Best individual (dummy initialization)
pop.Best = Individual{make([]interface{}, pop.NbGenes), math.Inf(1)}
// Find the best individual
pop.findBest()
}
// Find the best individual in each deme and then compare the best overall
// individual to the current best individual.
func (pop *Population) findBest() {
// Get each deme's best individual
var best = make(Individuals, pop.NbDemes)
for i, deme := range pop.Demes {
best[i] = deme.Individuals[0]
}
// Sort the best individuals
best.Sort()
// Get the overall best individual
var overallBest = best[0]
// Compare it to the current best individual
if overallBest.Fitness < pop.Best.Fitness {
pop.Best = overallBest
}
}
// Migrate allows demes to exchange individuals through the migration protocol
// defined in pop.MigMethod. This is a convenience method for calling purposes.
func (pop *Population) migrate() {
// Use the pointer to the demes to perform migration
pop.Demes = pop.Migrator.apply(pop.Demes)
}
// Enhance each deme in the population. The deme level operations are done in
// parallel with a wait group. After all the deme operations have been run, the
// population level operations are run.
func (pop *Population) Enhance() {
// Migrate the individuals between the demes
if pop.Migrator != nil {
pop.migrate()
}
// Use a wait group to run the genetic operators in each deme in parallel
var wg sync.WaitGroup
for i := range pop.Demes {
wg.Add(1)
go func(j int) {
defer wg.Done()
// 1. Crossover
if pop.Crossover != nil {
pop.Demes[j].crossover(pop.Selector, pop.Crossover)
}
// 2. Mutate
if pop.Mutators != nil {
pop.Demes[j].mutate(pop.Mutators)
}
// 3. Evaluate
pop.Demes[j].evaluate(pop.Ff)
// 4. Sort
pop.Demes[j].sort()
}(i)
}
wg.Wait()
// Check if there is an individual that is better than the current one
pop.findBest()
}