Skip to content

Commit 3e0c72b

Browse files
committed
Added mutator invert
1 parent 6f75f17 commit 3e0c72b

14 files changed

+268
-67
lines changed

chromosome.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ func (c Chromosomes) String() string {
5252

5353
type GenesInterface interface {
5454
Len() int
55-
}
56-
type CopyableGenesInterface interface {
5755
Copy(genes GenesInterface, from1, from2, to2 int) int
56+
Swap(int, int)
57+
Get(int) interface{}
58+
Set(int, interface{})
5859
}

chromosome_binary.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import (
77

88
type BinaryGenes []bool
99

10-
func (g BinaryGenes) Len() int { return len(g) }
10+
func (g BinaryGenes) Len() int { return len(g) }
11+
func (g BinaryGenes) Swap(i, j int) { g[i], g[j] = g[j], g[i] }
12+
func (g BinaryGenes) Get(i int) interface{} { return g[i] }
13+
func (g BinaryGenes) Set(i int, val interface{}) { g[i] = val.(bool) }
1114
func (g BinaryGenes) Copy(genes GenesInterface, from1, from2, to2 int) int {
1215
bgenes, ok := genes.(BinaryGenes)
1316
if !ok {

chromosome_ordered.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ import (
88

99
type OrderedGenes []int
1010

11-
func (g OrderedGenes) Len() int { return len(g) }
12-
13-
/*func (g OrderedGenes) Copy(genes GenesInterface, from1, from2, to2 int) int {
11+
func (g OrderedGenes) Len() int { return len(g) }
12+
func (g OrderedGenes) Swap(i, j int) { g[i], g[j] = g[j], g[i] }
13+
func (g OrderedGenes) Get(i int) interface{} { return g[i] }
14+
func (g OrderedGenes) Set(i int, val interface{}) { g[i] = val.(int) }
15+
func (g OrderedGenes) Copy(genes GenesInterface, from1, from2, to2 int) int {
1416
bgenes, ok := genes.(OrderedGenes)
1517
if !ok {
1618
panic("Unexpected genes. Expected OrderedGenes")
1719
}
1820

1921
return copy(g[from1:], bgenes[from2:to2])
20-
}*/
22+
}
2123
func (g OrderedGenes) Ind(val int) int {
2224
for i := 0; i < len(g); i++ {
2325
if g[i] == val {

crossover_multi_point.go

+2-8
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,10 @@ func (crossover *MultiPointCrossover) crossover(p1, p2 ChromosomeInterface, cros
9797
genesLen := p1.Genes().Len()
9898

9999
c1 = crossover.chromConstr(genesLen)
100-
c1genes, ok := c1.Genes().(CopyableGenesInterface)
101-
if !ok {
102-
panic("Chromosome's genes does not implement CopyableGenesInterface")
103-
}
100+
c1genes := c1.Genes()
104101

105102
c2 = crossover.chromConstr(genesLen)
106-
c2genes, ok := c2.Genes().(CopyableGenesInterface)
107-
if !ok {
108-
panic("Chromosome's genes does not implement CopyableGenesInterface")
109-
}
103+
c2genes := c2.Genes()
110104

111105
crossPoint := 0
112106
for i := 0; i < len(crossPoints); i++ {

examples/tsp/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func createOptimizer() OptimizerInterface {
6464
Initializer(NewOrderedRandomInitializer()).
6565
Selector(NewRouletteWheelRankWeightingSelector()).
6666
Crossover(NewOrderCrossoverVer1()).
67-
Mutator(NewOrderedSwapMutator(mutationProb)).
67+
Mutator(NewSwapMutator(mutationProb)).
6868
CostFunction(Cost).
6969
StopCriterion(NewStopCriterionDefault().
7070
Max_Generations(generations).

examples/tsp_with_plot_comparison/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func createOptimizer(ver int) OptimizerInterface {
9797
Weeder(NewSimpleWeeder(weedRate)).
9898
Initializer(NewOrderedRandomInitializer()).
9999
Selector(NewRouletteWheelRankWeightingSelector()).
100-
Mutator(NewOrderedSwapMutator(mutationProb)).
100+
Mutator(NewSwapMutator(mutationProb)).
101101
CostFunction(tsp.Cost).
102102
StopCriterion(NewStopCriterionDefault().
103103
Max_Generations(generations).

helper.go

+19
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,22 @@ func chooseDifferentRandomNumbers(count, upperBound int) []int {
154154

155155
return numbersList
156156
}
157+
158+
func round(val float64) int {
159+
return int(roundEx(val, .5, 0))
160+
}
161+
func roundEx(val float64, roundOn float64, places int) (newVal float64) {
162+
var round float64
163+
pow := math.Pow(10, float64(places))
164+
digit := pow * val
165+
_, div := math.Modf(digit)
166+
_div := math.Copysign(div, val)
167+
_roundOn := math.Copysign(roundOn, val)
168+
if _div >= _roundOn {
169+
round = math.Ceil(digit)
170+
} else {
171+
round = math.Floor(digit)
172+
}
173+
newVal = round / pow
174+
return
175+
}

mutator_binary.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ package genetic_algorithm
55
type BinaryMutator struct {
66
}
77

8-
func NewBinaryMutator(probability float64) *MutatorBase {
9-
mutator := NewMutator(new(BinaryMutator), probability)
8+
// Probability is applied to each element separately.
9+
func NewBinaryMutator(probability float64) *MutatorGeneBase {
10+
mutator := NewGeneBaseMutator(new(BinaryMutator), probability)
1011

1112
return mutator
1213
}

mutator_base.go renamed to mutator_gene_base.go

+20-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package genetic_algorithm
22

33
import (
4+
"fmt"
45
log "github.com/cihub/seelog"
56
"math"
67
"math/rand"
@@ -13,24 +14,28 @@ const (
1314
MutatorExactCountType = 1
1415
)
1516

16-
// Base class for mutators
17-
type MutatorBase struct {
18-
MutatorBaseVirtualMInterface
17+
// Base class for mutators that mutate separate genes
18+
type MutatorGeneBase struct {
19+
MutatorGeneBaseVirtualMInterface
1920

2021
probability float64
2122
elitism int
2223
kind int
2324
}
2425

25-
// MutatorBase's virtual methods
26-
type MutatorBaseVirtualMInterface interface {
26+
// MutatorGeneBase's virtual methods
27+
type MutatorGeneBaseVirtualMInterface interface {
2728
MutateCromosome(chrom ChromosomeInterface, ind int)
2829
}
2930

30-
func NewMutator(virtual MutatorBaseVirtualMInterface, probability float64) *MutatorBase {
31-
mutator := new(MutatorBase)
31+
func NewGeneBaseMutator(virtual MutatorGeneBaseVirtualMInterface, probability float64) *MutatorGeneBase {
32+
if probability > 1 || probability < 0 {
33+
panic(fmt.Sprintf("Incorrect probability %v", probability))
34+
}
35+
36+
mutator := new(MutatorGeneBase)
3237

33-
mutator.MutatorBaseVirtualMInterface = virtual
38+
mutator.MutatorGeneBaseVirtualMInterface = virtual
3439
mutator.probability = probability
3540
mutator.elitism = 1
3641
mutator.kind = MutatorOneByOneType
@@ -39,19 +44,19 @@ func NewMutator(virtual MutatorBaseVirtualMInterface, probability float64) *Muta
3944
}
4045

4146
// Will roll for every element in chromosome, mutate it if success
42-
func (mutator *MutatorBase) OneByOne() *MutatorBase {
47+
func (mutator *MutatorGeneBase) OneByOne() *MutatorGeneBase {
4348
mutator.kind = MutatorOneByOneType
4449
return mutator
4550
}
4651

4752
// Will mutete exactly (Npop * Nel * P) elements
48-
func (mutator *MutatorBase) ExactCount() *MutatorBase {
53+
func (mutator *MutatorGeneBase) ExactCount() *MutatorGeneBase {
4954
mutator.kind = MutatorExactCountType
5055
return mutator
5156
}
5257

5358
// The best chromosome[s] can't be mutated
54-
func (mutator *MutatorBase) WithElitism(count int) *MutatorBase {
59+
func (mutator *MutatorGeneBase) WithElitism(count int) *MutatorGeneBase {
5560
if count < 0 {
5661
panic("Elitism can't be negative")
5762
}
@@ -61,20 +66,20 @@ func (mutator *MutatorBase) WithElitism(count int) *MutatorBase {
6166
}
6267

6368
// All chromosomes can be mutated
64-
func (mutator *MutatorBase) WithoutElitism() *MutatorBase {
69+
func (mutator *MutatorGeneBase) WithoutElitism() *MutatorGeneBase {
6570
mutator.elitism = 0
6671
return mutator
6772
}
6873

69-
func (mutator *MutatorBase) Mutate(population Chromosomes) {
74+
func (mutator *MutatorGeneBase) Mutate(population Chromosomes) {
7075
switch mutator.kind {
7176
case MutatorOneByOneType:
7277
mutator.mutateOneByOne(population)
7378
case MutatorExactCountType:
7479
mutator.mutateExactCount(population)
7580
}
7681
}
77-
func (mutator *MutatorBase) mutateOneByOne(population Chromosomes) {
82+
func (mutator *MutatorGeneBase) mutateOneByOne(population Chromosomes) {
7883
m := 0
7984
for ind, chrom := range population {
8085
if mutator.elitism > ind {
@@ -94,7 +99,7 @@ func (mutator *MutatorBase) mutateOneByOne(population Chromosomes) {
9499

95100
log.Debugf("Elems mutated: %d", m)
96101
}
97-
func (mutator *MutatorBase) mutateExactCount(population Chromosomes) {
102+
func (mutator *MutatorGeneBase) mutateExactCount(population Chromosomes) {
98103
popLen := len(population)
99104
if popLen == 0 {
100105
return

mutator_invert.go

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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+
// Mutator selects some part of the chromosome and inverts it
14+
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
24+
}
25+
26+
func newInvertMutator(probability float64, chromosomeConstructor EmptyChromosomeConstructor) *InvertMutator {
27+
if probability > 1 || probability < 0 {
28+
panic(fmt.Sprintf("Incorrect probability %v", probability))
29+
}
30+
31+
mutator := new(InvertMutator)
32+
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
73+
74+
return mutator
75+
}
76+
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)
120+
121+
for i := from; i < to; i++ {
122+
ind := to + from - i - 1
123+
genes.Set(i, mutator.temp.Get(ind))
124+
}
125+
}

mutator_ordered_swap.go

-32
This file was deleted.

0 commit comments

Comments
 (0)