-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathselector.go
74 lines (61 loc) · 1.89 KB
/
selector.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
package goga
import (
"math/rand"
)
// Selector - a selector interface used to pick 2 genomes to mate
type Selector interface {
Go([]Genome, int) Genome
}
// NullSelector - a null implementation of the Selector interface
type NullSelector struct {
}
// Go - a null implementation of Selector's 'go'
func (ns *NullSelector) Go(genomes []Genome, totalFitness int) Genome {
return genomes[0]
}
// SelectorFunctionProbability -
// Contains a selector function and a probability
// where selector function 'F' is called with probability 'P'
// where 'P' is a value between 0 and 1
// 0 = never called, 1 = called every time we need a new genome to mate
type SelectorFunctionProbability struct {
P float32
F func([]Genome, int) Genome
}
type selector struct {
selectorConfig []SelectorFunctionProbability
}
// NewSelector returns an instance of an ISelector with several SelectorFunctionProbabiities
func NewSelector(selectorConfig []SelectorFunctionProbability) Selector {
return &selector{
selectorConfig: selectorConfig,
}
}
// Go - cycles through the selector function probabilities until one returns a genome
func (s *selector) Go(genomeArray []Genome, totalFitness int) Genome {
for {
for _, config := range s.selectorConfig {
if rand.Float32() < config.P {
return config.F(genomeArray, totalFitness)
}
}
}
}
// Roulette is a selection function that selects a genome where genomes that have a higher fitness are more likely to be picked
func Roulette(genomeArray []Genome, totalFitness int) Genome {
if len(genomeArray) == 0 {
panic("genome array contains no elements")
}
if totalFitness == 0 {
randomIndex := rand.Intn(len(genomeArray))
return genomeArray[randomIndex]
}
randomFitness := rand.Intn(totalFitness)
for i := range genomeArray {
randomFitness -= genomeArray[i].GetFitness()
if randomFitness <= 0 {
return genomeArray[i]
}
}
panic("total fitness is too large")
}