Skip to content

Commit 7c31781

Browse files
committed
Added DisplacementMutator
1 parent 3e0c72b commit 7c31781

File tree

4 files changed

+223
-119
lines changed

4 files changed

+223
-119
lines changed

Diff for: mutator_displacement.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package genetic_algorithm
2+
3+
import (
4+
"math/rand"
5+
)
6+
7+
// Mutator selects some part of the chromosome and places it in random position
8+
type DisplacementMutator struct {
9+
*MutatorIntervalBase
10+
}
11+
12+
// Probability is applied to each chromosome
13+
func NewDisplacementMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor) *DisplacementMutator {
14+
mutator := new(DisplacementMutator)
15+
16+
mutator.MutatorIntervalBase = NewMutatorIntervalBase(mutator, probability, chromosomeConstructor)
17+
18+
return mutator
19+
}
20+
21+
// Mutator selects random element from chromosome and places it in random position
22+
// Probability is applied to each chromosome
23+
func NewInsertionMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor) *MutatorIntervalBase {
24+
return NewDisplacementMutator(probability, chromosomeConstructor).ExactInterval(1, 1)
25+
}
26+
27+
func (mutator *DisplacementMutator) MutateGenes(genes GenesInterface, from, to int) {
28+
insertPoint := mutator.chooseInsertPoint(genes.Len(), from, to)
29+
mutator.insert(genes, from, to, insertPoint)
30+
}
31+
func (mutator *DisplacementMutator) chooseInsertPoint(genesLen, from, to int) int {
32+
possiblePoints := genesLen - (to - from)
33+
point := rand.Intn(possiblePoints)
34+
if point >= from {
35+
point += to - from + 1
36+
}
37+
return point
38+
}
39+
func (mutator *DisplacementMutator) insert(genes GenesInterface, from, to, insertPoint int) {
40+
temp := mutator.getIntervalCopy(genes, from, to)
41+
42+
if insertPoint < from {
43+
copyLen := from - insertPoint
44+
genes.Copy(genes, to-copyLen, insertPoint, from)
45+
genes.Copy(temp, insertPoint, from, to)
46+
} else {
47+
copyLen := insertPoint - to
48+
genes.Copy(genes, from, to, insertPoint)
49+
genes.Copy(temp, from+copyLen, from, to)
50+
}
51+
}

Diff for: mutator_interval_base.go

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package genetic_algorithm
2+
3+
import (
4+
"fmt"
5+
"math/rand"
6+
)
7+
8+
const (
9+
mutatorInvertExactLen = 0
10+
mutatorInvertPercentageLen = 1
11+
)
12+
13+
// Base class for mutators that mutate some interval of genes
14+
type MutatorIntervalBase struct {
15+
MutatorIntervalBaseVirtualMInterface
16+
17+
probability float64
18+
chromosomeConstructor EmptyChromosomeConstructor
19+
kind int
20+
fromExact int
21+
toExact int
22+
fromPercent float64
23+
toPercent float64
24+
25+
temp GenesInterface
26+
}
27+
28+
// MutatorIntervalBase's virtual methods
29+
type MutatorIntervalBaseVirtualMInterface interface {
30+
MutateGenes(genes GenesInterface, from, to int)
31+
}
32+
33+
// Probability is applied to each chromosome
34+
// By default interval will be equal one third of the chromosome
35+
func NewMutatorIntervalBase(virtual MutatorIntervalBaseVirtualMInterface, probability float64, chromosomeConstructor EmptyChromosomeConstructor) *MutatorIntervalBase {
36+
if probability > 1 || probability < 0 {
37+
panic(fmt.Sprintf("Incorrect probability %v", probability))
38+
}
39+
40+
mutator := new(MutatorIntervalBase)
41+
42+
mutator.MutatorIntervalBaseVirtualMInterface = virtual
43+
mutator.probability = probability
44+
mutator.chromosomeConstructor = chromosomeConstructor
45+
mutator.kind = mutatorInvertPercentageLen
46+
mutator.fromPercent = 0.33
47+
mutator.toPercent = 0.33
48+
49+
return mutator
50+
}
51+
52+
// Sets interval len to be randomly choosen from [from:to]
53+
func (mutator *MutatorIntervalBase) ExactInterval(from, to int) *MutatorIntervalBase {
54+
if from > to || from < 0 || to < 1 {
55+
panic(fmt.Sprintf("Incorrect interval [%d:%d]", from, to))
56+
}
57+
58+
mutator.kind = mutatorInvertExactLen
59+
mutator.fromExact = from
60+
mutator.toExact = to
61+
62+
return mutator
63+
}
64+
65+
// Sets interval len to be randomly choosen from [from*chromLen : to*chromLen]
66+
func (mutator *MutatorIntervalBase) PercentageInterval(from, to float64) *MutatorIntervalBase {
67+
if from > to || from < 0 || to < 0 || from > 1 || to > 1 {
68+
panic(fmt.Sprintf("Incorrect percentage interval [%v:%v]", from, to))
69+
}
70+
71+
mutator.kind = mutatorInvertPercentageLen
72+
mutator.fromPercent = from
73+
mutator.toPercent = to
74+
75+
return mutator
76+
}
77+
78+
func (mutator *MutatorIntervalBase) Mutate(population Chromosomes) {
79+
for _, chrom := range population {
80+
if mutator.probability < rand.Float64() {
81+
continue
82+
}
83+
84+
genesLen := chrom.Genes().Len()
85+
intervalLen := mutator.getIntervalLen(genesLen)
86+
if intervalLen == 0 || intervalLen == genesLen {
87+
continue
88+
}
89+
90+
from, to := mutator.getInterval(genesLen, intervalLen)
91+
92+
mutator.MutateGenes(chrom.Genes(), from, to)
93+
}
94+
}
95+
func (mutator *MutatorIntervalBase) getIntervalLen(genesLen int) int {
96+
if mutator.kind == mutatorInvertExactLen {
97+
return rand.Intn(mutator.toExact-mutator.fromExact+1) + mutator.fromExact
98+
}
99+
100+
percent := rand.Float64()*(mutator.toPercent-mutator.fromPercent) + mutator.fromPercent
101+
return round(percent * float64(genesLen))
102+
}
103+
func (mutator *MutatorIntervalBase) getInterval(genesLen, intervalLen int) (int, int) {
104+
if intervalLen > genesLen {
105+
panic(fmt.Sprintf("Interval bigger than chromosome. %d > %d", intervalLen, genesLen))
106+
}
107+
108+
firstPoint := rand.Intn(genesLen - intervalLen + 1)
109+
return firstPoint, firstPoint + intervalLen
110+
}
111+
func (mutator *MutatorIntervalBase) getIntervalCopy(genes GenesInterface, from, to int) GenesInterface {
112+
genesLen := genes.Len()
113+
114+
if mutator.temp == nil || mutator.temp.Len() != genesLen {
115+
mutator.temp = mutator.chromosomeConstructor(genesLen).Genes()
116+
}
117+
118+
mutator.temp.Copy(genes, from, from, to)
119+
120+
return mutator.temp
121+
}

Diff for: mutator_invert.go

+7-108
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,24 @@
11
package genetic_algorithm
22

3-
import (
4-
"fmt"
5-
"math/rand"
6-
)
7-
8-
const (
9-
mutatorInvertExactLen = 0
10-
mutatorInvertPercentageLen = 1
11-
)
12-
133
// Mutator selects some part of the chromosome and inverts it
144
type InvertMutator struct {
15-
probability float64
16-
chromosomeConstructor EmptyChromosomeConstructor
17-
kind int
18-
fromExact int
19-
toExact int
20-
fromPercent float64
21-
toPercent float64
22-
23-
temp GenesInterface
5+
*MutatorIntervalBase
246
}
257

26-
func newInvertMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor) *InvertMutator {
27-
if probability > 1 || probability < 0 {
28-
panic(fmt.Sprintf("Incorrect probability %v", probability))
29-
}
30-
8+
// Probability is applied to each chromosome
9+
func NewInvertMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor) *InvertMutator {
3110
mutator := new(InvertMutator)
3211

33-
mutator.probability = probability
34-
mutator.chromosomeConstructor = chromosomeConstructor
35-
36-
return mutator
37-
}
38-
39-
// Creates mutator that will invert part of chromosome that lays on interval [from:to]
40-
// Probability is applied to each chromosome.
41-
func NewInvertExactIntervalMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, from, to int) *InvertMutator {
42-
if from > to || from < 0 || to < 1 {
43-
panic(fmt.Sprintf("Incorrect interval [%d:%d]", from, to))
44-
}
45-
46-
mutator := newInvertMutator(probability, chromosomeConstructor)
47-
48-
mutator.kind = mutatorInvertExactLen
49-
mutator.fromExact = from
50-
mutator.toExact = to
51-
52-
return mutator
53-
}
54-
55-
// Creates mutator that will invert part of chromosome.Part's len defined by genesToInvert.
56-
// Probability is applied to each chromosome.
57-
func NewInvertExactMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, genesToInvert int) *InvertMutator {
58-
return NewInvertExactIntervalMutator(probability, chromosomeConstructor, genesToInvert, genesToInvert)
59-
}
60-
61-
// Creates mutator that will invert part of chromosome that lays on interval [from*chromLen : to*chromLen]
62-
// Probability is applied to each chromosome.
63-
func NewInvertPercentageIntervalMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, from, to float64) *InvertMutator {
64-
if from > to || from < 0 || to < 0 || from > 1 || to > 1 {
65-
panic(fmt.Sprintf("Incorrect percentage interval [%v:%v]", from, to))
66-
}
67-
68-
mutator := newInvertMutator(probability, chromosomeConstructor)
69-
70-
mutator.kind = mutatorInvertPercentageLen
71-
mutator.fromPercent = from
72-
mutator.toPercent = to
12+
mutator.MutatorIntervalBase = NewMutatorIntervalBase(mutator, probability, chromosomeConstructor)
7313

7414
return mutator
7515
}
7616

77-
// Creates mutator that will invert part of chromosome. Part's len calcs as percentage * chromLen
78-
// Probability is applied to each chromosome.
79-
func NewInvertPercentageMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor, percentage float64) *InvertMutator {
80-
return NewInvertPercentageIntervalMutator(probability, chromosomeConstructor, percentage, percentage)
81-
}
82-
83-
func (mutator *InvertMutator) Mutate(population Chromosomes) {
84-
for _, chrom := range population {
85-
if mutator.probability < rand.Float64() {
86-
continue
87-
}
88-
89-
genesLen := chrom.Genes().Len()
90-
intervalLen := mutator.getIntervalLen(genesLen)
91-
from, to := mutator.getInterval(genesLen, intervalLen)
92-
93-
mutator.mutate(chrom.Genes(), from, to)
94-
}
95-
}
96-
func (mutator *InvertMutator) getIntervalLen(genesLen int) int {
97-
if mutator.kind == mutatorInvertExactLen {
98-
return rand.Intn(mutator.toExact-mutator.fromExact+1) + mutator.fromExact
99-
}
100-
101-
percent := rand.Float64()*(mutator.toPercent-mutator.fromPercent) + mutator.fromPercent
102-
return round(percent * float64(genesLen))
103-
}
104-
func (mutator *InvertMutator) getInterval(genesLen, intervalLen int) (int, int) {
105-
if intervalLen > genesLen {
106-
panic(fmt.Sprintf("Interval bigger than chromosome. %d > %d", intervalLen, genesLen))
107-
}
108-
109-
firstPoint := rand.Intn(genesLen - intervalLen + 1)
110-
return firstPoint, firstPoint + intervalLen
111-
}
112-
func (mutator *InvertMutator) mutate(genes GenesInterface, from, to int) {
113-
genesLen := genes.Len()
114-
115-
if mutator.temp == nil || mutator.temp.Len() != genesLen {
116-
mutator.temp = mutator.chromosomeConstructor(genesLen).Genes()
117-
}
118-
119-
mutator.temp.Copy(genes, from, from, to)
17+
func (mutator *InvertMutator) MutateGenes(genes GenesInterface, from, to int) {
18+
temp := mutator.getIntervalCopy(genes, from, to)
12019

12120
for i := from; i < to; i++ {
12221
ind := to + from - i - 1
123-
genes.Set(i, mutator.temp.Get(ind))
22+
genes.Set(i, temp.Get(ind))
12423
}
12524
}

Diff for: ~mutator_test.go

+44-11
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,34 @@ func (s *MutatorSuite) TestMutatorGenesBase_Elitism(c *C) {
3838
c.Assert(pop[2].Genes(), DeepEquals, falseGenes)
3939
}
4040

41-
func (s *MutatorSuite) TestMutatorInvert_getIntervalLen(c *C) {
42-
var mutator *InvertMutator
41+
func (s *MutatorSuite) TestMutatorIntervalBase_getIntervalLen(c *C) {
42+
var mutator *MutatorIntervalBase
4343

44-
mutator = NewInvertExactMutator(1, nil, 5)
44+
mutator = NewMutatorIntervalBase(nil, 1, nil).ExactInterval(5, 5)
4545
c.Assert(mutator.getIntervalLen(10), Equals, 5)
4646

4747
fromExact := 5
4848
toExact := 7
49-
mutator = NewInvertExactIntervalMutator(1, nil, fromExact, toExact)
49+
mutator = NewMutatorIntervalBase(nil, 1, nil).ExactInterval(fromExact, toExact)
5050
res := mutator.getIntervalLen(10)
5151
if res < fromExact || res > toExact {
5252
c.Fatalf("Unexpected interval len. Exp: [%d:%d]. Got: [%d]", fromExact, toExact, res)
5353
}
5454

55-
mutator = NewInvertPercentageMutator(1, nil, .5)
55+
mutator = NewMutatorIntervalBase(nil, 1, nil).PercentageInterval(.5, .5)
5656
c.Assert(mutator.getIntervalLen(10), Equals, 5)
5757

5858
fromPercentage := .5
5959
toPercentage := .7
6060
genesLen := 10
61-
mutator = NewInvertPercentageIntervalMutator(1, nil, fromPercentage, toPercentage)
61+
mutator = NewMutatorIntervalBase(nil, 1, nil).PercentageInterval(fromPercentage, toPercentage)
6262
resf := float64(mutator.getIntervalLen(genesLen))
6363
if resf < fromPercentage*float64(genesLen) || resf > toPercentage*float64(genesLen) {
6464
c.Fatalf("Unexpected interval len. Exp: [%f:%f]. Got: [%f]", fromPercentage*float64(genesLen), toPercentage*float64(genesLen), resf)
6565
}
6666
}
67-
func (s *MutatorSuite) TestMutatorInvert_getInterval(c *C) {
68-
mutator := &InvertMutator{}
67+
func (s *MutatorSuite) TestMutatorIntervalBase_getInterval(c *C) {
68+
mutator := &MutatorIntervalBase{}
6969

7070
from, to := mutator.getInterval(1, 1)
7171
c.Assert(from, Equals, 0)
@@ -79,12 +79,45 @@ func (s *MutatorSuite) TestMutatorInvert_getInterval(c *C) {
7979
from, to = mutator.getInterval(10, intervalLen)
8080
c.Assert(to-from, Equals, intervalLen)
8181
}
82-
func (s *MutatorSuite) TestMutatorInvert_mutate(c *C) {
82+
83+
func (s *MutatorSuite) TestInvertMutator_mutate(c *C) {
8384
beforeGenes := OrderedGenes{1, 2, 3, 4, 5, 6}
8485
afterGenes := OrderedGenes{1, 2, 5, 4, 3, 6}
8586

86-
mutator := newInvertMutator(1, NewEmptyOrderedChromosome)
87-
mutator.mutate(beforeGenes, 2, 5)
87+
mutator := NewInvertMutator(1, NewEmptyOrderedChromosome)
88+
mutator.MutateGenes(beforeGenes, 2, 5)
8889

8990
c.Assert(beforeGenes, DeepEquals, afterGenes)
9091
}
92+
93+
func (s *MutatorSuite) TestDisplacementMutator_insert(c *C) {
94+
beforeGenes := OrderedGenes{1, 2, 3, 4, 5, 6}
95+
genes := make(OrderedGenes, len(beforeGenes))
96+
mutator := NewDisplacementMutator(1, NewEmptyOrderedChromosome)
97+
98+
genes.Copy(beforeGenes, 0, 0, len(beforeGenes))
99+
mutator.insert(genes, 2, 5, 0)
100+
c.Assert(genes, DeepEquals, OrderedGenes{3, 4, 5, 1, 2, 6})
101+
102+
genes.Copy(beforeGenes, 0, 0, len(beforeGenes))
103+
mutator.insert(genes, 2, 5, 1)
104+
c.Assert(genes, DeepEquals, OrderedGenes{1, 3, 4, 5, 2, 6})
105+
106+
genes.Copy(beforeGenes, 0, 0, len(beforeGenes))
107+
mutator.insert(genes, 2, 5, 6)
108+
c.Assert(genes, DeepEquals, OrderedGenes{1, 2, 6, 3, 4, 5})
109+
}
110+
func (s *MutatorSuite) TestDisplacementMutator_chooseInsertPoint(c *C) {
111+
mutator := NewDisplacementMutator(1, NewEmptyOrderedChromosome)
112+
113+
point := mutator.chooseInsertPoint(2, 0, 1)
114+
c.Assert(point, Equals, 2)
115+
116+
point = mutator.chooseInsertPoint(2, 1, 2)
117+
c.Assert(point, Equals, 0)
118+
119+
point = mutator.chooseInsertPoint(6, 2, 5)
120+
if point != 0 && point != 1 && point != 6 {
121+
c.Fatalf("Unexpected insert point. Exp: [0|1|6]. Got: [%d]", point)
122+
}
123+
}

0 commit comments

Comments
 (0)