-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcrossover_edge_recombination.go
129 lines (101 loc) · 2.94 KB
/
crossover_edge_recombination.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
122
123
124
125
126
127
128
129
package genetic_algorithm
import (
log "github.com/cihub/seelog"
"math/rand"
)
// The edge recombination operator (ERO) is an operator that creates a path that is similar to a set of existing paths (parents) by looking at the edges rather than the vertices.
//
// http://en.wikipedia.org/wiki/Edge_recombination_operator
type EdgeRecombinationCrossover struct {
}
func NewEdgeRecombinationCrossover() *EdgeRecombinationCrossover {
crossover := new(EdgeRecombinationCrossover)
return crossover
}
func (crossover *EdgeRecombinationCrossover) ParentsCount() int {
return 2
}
func (crossover *EdgeRecombinationCrossover) Crossover(parents Chromosomes) Chromosomes {
if len(parents) != crossover.ParentsCount() {
panic("Incorrect parents count")
}
p1, ok := parents[0].(*OrderedChromosome)
if !ok {
panic("Expects OrderedChromosome")
}
p2, ok := parents[1].(*OrderedChromosome)
if !ok {
panic("Expects OrderedChromosome")
}
genesLen := p1.Genes().Len()
if genesLen != p2.Genes().Len() {
panic("Crossover do not support different chromosome size")
}
matrix := crossover.generateMatrix(p1, p2)
log.Tracef("Cross with %v", matrix)
c1 := crossover.crossover(p1, p2, matrix)
return Chromosomes{c1}
}
func (crossover *EdgeRecombinationCrossover) generateMatrix(p1, p2 *OrderedChromosome) map[int]map[int]bool {
p1genes := p1.OrderedGenes()
p2genes := p2.OrderedGenes()
genesLen := p1genes.Len()
matrix := make(map[int]map[int]bool, genesLen)
for i := 0; i < genesLen; i++ {
matrix[p1genes[i]] = make(map[int]bool, 4)
}
for i := 0; i < genesLen; i++ {
ind1 := (i - 1 + genesLen) % genesLen
ind2 := (i + 1) % genesLen
matrix[p1genes[i]][p1genes[ind1]] = true
matrix[p1genes[i]][p1genes[ind2]] = true
matrix[p2genes[i]][p2genes[ind1]] = true
matrix[p2genes[i]][p2genes[ind2]] = true
}
return matrix
}
func (crossover *EdgeRecombinationCrossover) crossover(p1, p2 *OrderedChromosome, matrix map[int]map[int]bool) (c1 ChromosomeInterface) {
p1genes := p1.OrderedGenes()
p2genes := p2.OrderedGenes()
genesLen := p1genes.Len()
c1 = NewEmptyOrderedChromosome(genesLen)
c1genes := c1.Genes().(OrderedGenes)
crossover.fillChild(c1genes, p1genes, p2genes, matrix)
return
}
func (crossover *EdgeRecombinationCrossover) fillChild(c, p1, p2 OrderedGenes, matrix map[int]map[int]bool) {
nextNs := make([]int, 0, 4)
var n int
if rand.Intn(2) == 0 {
n = p1[0]
} else {
n = p2[0]
}
for i := 0; i < len(c); i++ {
c[i] = n
nextNs = nextNs[0:0]
minLen := 0
for k, _ := range matrix[n] {
delete(matrix[k], n)
if len(nextNs) == 0 || len(matrix[k]) == minLen {
nextNs = append(nextNs, k)
minLen = len(matrix[k])
} else if len(matrix[k]) < minLen {
nextNs = nextNs[0:0]
nextNs = append(nextNs, k)
minLen = len(matrix[k])
}
}
delete(matrix, n)
if len(nextNs) == 0 {
if len(matrix) == 0 {
break
}
for k, _ := range matrix {
n = k
}
} else {
n = nextNs[rand.Intn(len(nextNs))]
}
}
}