-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmutator_gene_base.go
121 lines (99 loc) · 2.92 KB
/
mutator_gene_base.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
package genetic_algorithm
import (
"fmt"
log "github.com/cihub/seelog"
"math"
"math/rand"
)
const (
// Will roll for every element in chromosome, mutate it if success
MutatorOneByOneType = 0
// Will mutete exactly (Npop * Nel * P) elements
MutatorExactCountType = 1
)
// Base class for mutators that mutate separate genes
type MutatorGeneBase struct {
MutatorGeneBaseVirtualMInterface
probability float64
elitism int
kind int
}
// MutatorGeneBase's virtual methods
type MutatorGeneBaseVirtualMInterface interface {
MutateCromosome(chrom ChromosomeInterface, ind int)
}
func NewGeneBaseMutator(virtual MutatorGeneBaseVirtualMInterface, probability float64) *MutatorGeneBase {
if probability > 1 || probability < 0 {
panic(fmt.Sprintf("Incorrect probability %v", probability))
}
mutator := new(MutatorGeneBase)
mutator.MutatorGeneBaseVirtualMInterface = virtual
mutator.probability = probability
mutator.elitism = 1
mutator.kind = MutatorOneByOneType
return mutator
}
// Will roll for every element in chromosome, mutate it if success
func (mutator *MutatorGeneBase) OneByOne() *MutatorGeneBase {
mutator.kind = MutatorOneByOneType
return mutator
}
// Will mutete exactly (Npop * Nel * P) elements
func (mutator *MutatorGeneBase) ExactCount() *MutatorGeneBase {
mutator.kind = MutatorExactCountType
return mutator
}
// The best chromosome[s] can't be mutated
func (mutator *MutatorGeneBase) WithElitism(count int) *MutatorGeneBase {
if count < 0 {
panic("Elitism can't be negative")
}
mutator.elitism = count
return mutator
}
// All chromosomes can be mutated
func (mutator *MutatorGeneBase) WithoutElitism() *MutatorGeneBase {
mutator.elitism = 0
return mutator
}
func (mutator *MutatorGeneBase) Mutate(population Chromosomes) {
switch mutator.kind {
case MutatorOneByOneType:
mutator.mutateOneByOne(population)
case MutatorExactCountType:
mutator.mutateExactCount(population)
}
}
func (mutator *MutatorGeneBase) mutateOneByOne(population Chromosomes) {
m := 0
for ind, chrom := range population {
if mutator.elitism > ind {
continue
}
for i := 0; i < chrom.Genes().Len(); i++ {
if rand.Float64() > mutator.probability {
continue
}
log.Tracef("Mutate: %v, at %d\n", chrom, i)
mutator.MutateCromosome(chrom, i)
m++
}
}
log.Debugf("Elems mutated: %d", m)
}
func (mutator *MutatorGeneBase) mutateExactCount(population Chromosomes) {
popLen := len(population)
if popLen == 0 {
return
}
genesLen := population[0].Genes().Len()
chromsToMutate := popLen - mutator.elitism
elementsToMutate := int(math.Floor(mutator.probability * float64(chromsToMutate*genesLen)))
log.Debugf("ElemsToMutate: %d", elementsToMutate)
for i := 0; i < elementsToMutate; i++ {
chromInd := rand.Intn(popLen-mutator.elitism) + mutator.elitism
elemInd := rand.Intn(genesLen)
log.Tracef("Mutate: %v, at %d\n", population[chromInd], elemInd)
mutator.MutateCromosome(population[chromInd], elemInd)
}
}