-
Notifications
You must be signed in to change notification settings - Fork 96
/
population.go
104 lines (98 loc) · 3.01 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
package gago
import (
"math"
"math/rand"
"sync"
"time"
)
// A Population contains Demes which contains Individuals.
type Population struct {
// Number of demes
NbDemes int
// Number of individuals in each deme
NbIndividuals int
// Number of genes in each individual (defined by the user)
NbGenes int
// Fitness function to evaluate individuals (defined by the user)
Ff func([]float64) float64
// Demes
Demes []Deme
// Overall best individual (dummy initialization at the begining)
Best Individual
// Initial random boundaries
Boundary float64
// Selection method
SelMethod func(Individuals, *rand.Rand) Individual
// Crossover method
CrossMethod func(Individuals, *rand.Rand) Individual
// Crossover size
CrossSize int
// Mutation method
MutMethod func(indi *Individual, rate float64, intensity float64, generator *rand.Rand)
// Mutation rate
MutRate float64
// Mutation intensity
MutIntensity float64
// Migration method
MigMethod func(demes []Deme) []Deme
}
// Initialize each deme in the population and assign an initial fitness to each
// individual in each deme.
func (pop *Population) Initialize(ff func([]float64) float64, variables int) {
// Fitness function
pop.Ff = ff
// Number of genes in each individual
pop.NbGenes = variables
// Create the demes
pop.Demes = make([]Deme, pop.NbDemes)
// Best individual (dummy instantiation)
pop.Best = Individual{make([]float64, pop.NbGenes), math.Inf(1)}
for i := range pop.Demes {
// Create a new random number generator
var source = rand.NewSource(time.Now().UnixNano())
var generator = rand.New(source)
// Create the deme
var deme = Deme{pop.NbIndividuals, make([]Individual, pop.NbIndividuals), generator}
// Initialize the deme
deme.Initialize(pop.NbGenes, pop.Boundary)
// Add it to the population
pop.Demes[i] = deme
// Initial evaluation
pop.Demes[i].Evaluate(pop.Ff)
}
}
// 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.MigMethod(pop.Demes)
}
// FindBest stores the best individual over all demes.
func (pop *Population) FindBest() {
for _, deme := range pop.Demes {
if deme.Individuals[0].Fitness < pop.Best.Fitness {
pop.Best = deme.Individuals[0]
}
}
}
// 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() {
var wg sync.WaitGroup
for i := range pop.Demes {
wg.Add(1)
go func(j int) {
defer wg.Done()
pop.Demes[j].Crossover(pop.SelMethod, pop.CrossMethod, pop.CrossSize)
pop.Demes[j].Mutate(pop.MutMethod, pop.MutRate, pop.MutIntensity)
pop.Demes[j].Evaluate(pop.Ff)
pop.Demes[j].Sort()
}(i)
}
wg.Wait()
// Check if there is a new best individual
pop.FindBest()
// Migrate the individuals between the demes
pop.Migrate()
}