-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrossover.go
121 lines (97 loc) · 2.4 KB
/
crossover.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 main
import (
"math/rand"
)
func crossover(parent1, parent2 *individual) *individual {
n := len(parent1.tour)
neighbors := make(map[int][]int, n)
for u := 0; u < n; u++ {
neighbors[u] = make([]int, 0, 4)
}
addNeighbors := func(neighbors map[int][]int, tour []int) {
for i, u := range tour {
v := tour[(i+1)%n]
w := tour[(i+2)%n]
if !contains(neighbors[v], u) {
neighbors[v] = append(neighbors[v], u)
}
if !contains(neighbors[v], w) {
neighbors[v] = append(neighbors[v], w)
}
}
}
addNeighbors(neighbors, parent1.tour)
addNeighbors(neighbors, parent2.tour)
offspringTour := make([]int, 0, n)
u := parent1.tour[0]
remaining := make(map[int]bool, n)
for i := 0; i < n; i++ {
remaining[i] = true
}
for len(offspringTour) < n {
// add u to offspring
offspringTour = append(offspringTour, u)
delete(remaining, u)
// remove u from neighbors
for _, v := range neighbors[u] {
neighbors[v] = removeOneFrom(neighbors[v], u)
}
// if u has available neighbors
if len(neighbors[u]) > 0 {
// take the best neighbor
v := neighbors[u][0]
for _, w := range neighbors[u][1:] {
if dist(u, w) < dist(u, v) {
v = w
}
}
u = v
} else {
for v := range remaining {
u = v
break
}
}
}
return newIndividual(offspringTour)
}
// LEGACY
const (
lagacyCrossoverMinK = 0.2
lagacyCrossoverMaxK = 0.3
)
func lagacyCrossoverMultiPoint(parent1, parent2 *individual) *individual {
// copy content of parent tours so we don't alter the originals
tour1 := append([]int(nil), parent1.tour...)
tour2 := append([]int(nil), parent2.tour...)
offspringTour := make([]int, 0, len(tour1))
k := lagacyCrossoverMinK + rand.Float64()*(lagacyCrossoverMaxK-lagacyCrossoverMinK)
offset := int(k * float64(len(tour1)))
for len(tour1) > 0 {
maxOffset := offset
if len(tour1) < maxOffset {
maxOffset = len(tour1)
}
section := tour1[:maxOffset]
offspringTour = append(offspringTour, section...)
tour1 = tour1[maxOffset:]
for _, i := range section {
tour2 = removeOneFrom(tour2, i)
}
tour1, tour2 = tour2, tour1
}
return newIndividual(offspringTour)
}
var (
selectionScale = 4.0
)
func lagacyCrossoverSelection(n int) int {
r := rand.Float64() * (float64(n) * (selectionScale + 1.0)) / 2
for i := 0; i < n-1; i++ {
r -= ((1-selectionScale)/float64(n-1))*float64(i) + selectionScale
if r <= 0 {
return i
}
}
return n - 1
}