-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtsp-ga.cc
178 lines (138 loc) · 4.49 KB
/
tsp-ga.cc
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include "tsp-ga.hh"
#include <algorithm>
// I don't know what the compile time problem wass because it compiled fine
// on my computer, even without <algorithm>.
// I'm using g++ -Wall -std=c++14 Point.cc tsp-ga.cc tsp-main.cc -o tspga
using namespace std;
// Constructor for given number of points
TSPGenome::TSPGenome(int numPoints) {
pointOrder.reserve(numPoints);
for (int i = 0; i < numPoints; i++){
pointOrder.push_back(i); // initialize order to [0, 1...numPoints-1]
}
random_shuffle(pointOrder.begin(), pointOrder.end()); // randomize the order
circuitLength = 1e9; // initialize circuitLength to dummy value
}
// Constructor for given ordering of points
TSPGenome::TSPGenome(vector<int> order) {
pointOrder = order;
circuitLength = 1e9;
}
// Destructor
TSPGenome::~TSPGenome() {
}
// Get current order
vector<int> TSPGenome::getOrder() const {
return pointOrder;
}
// Prints contents of pointOrder
void TSPGenome::print() const {
for (int n = 0; n < pointOrder.size(); n++) {
cout << pointOrder[n] << " ";
}
cout << endl;
}
// Compute circuit length for given points visited in pointOrder
void TSPGenome::computeCircuitLength(const vector<Point> &points){
int a;
int b;
double length = 0;
for (int i = 0; i < pointOrder.size(); i++) {
a = pointOrder[i];
if ((i + 1) == pointOrder.size()) {
b = pointOrder[0];
}
else {
b = pointOrder[i+1];
}
length += points[a].distanceTo(points[b]);
}
circuitLength = length;
}
// Get current circuit length
double TSPGenome::getCircuitLength() const {
return circuitLength;
}
// Swaps two randomly-selected values in the order vector
void TSPGenome::mutate() {
vector<int> order = getOrder();
int numPoints = order.size();
int randA = rand() % numPoints;
int randB = randA;
while (randB == randA) { // Make sure the swap indices are different
randB = rand() % numPoints;
}
int temp = order[randA];
order[randA] = order[randB];
order[randB] = temp;
pointOrder = order;
}
// Make a new genome from parent genomes g1 and g2
TSPGenome crosslink(const TSPGenome &g1, const TSPGenome &g2) {
int numPoints = g1.getOrder().size();
int i = rand() % numPoints;
vector<int> offspring;
offspring.reserve(numPoints);
for (int j = 0; j < i; j++) {
offspring.push_back(g1.getOrder()[j]);
}
// Fill in the rest of the offspring genome from g2
for (int k = 0; k < numPoints; k++){
// Only insert values that aren't already used
if (find(offspring.begin(), offspring.end(), g2.getOrder()[k])
== offspring.end()) {
offspring.push_back(g2.getOrder()[k]);
}
}
TSPGenome offspring_Genome = TSPGenome(offspring);
return offspring_Genome;
}
// Return whether g1 is shorter than g2
bool isShorterPath(const TSPGenome &g1, const TSPGenome &g2) {
return (g1.getCircuitLength() < g2.getCircuitLength());
}
// Find a short path between points, using a given population size,
// number of generations, number to keep, and mutations per generation
TSPGenome findAShortPath(const vector<Point> &points,
int populationSize, int numGenerations,
int keepPopulation, int numMutations) {
int generation = 0;
// Generate the initial population
vector<TSPGenome> population;
population.reserve(populationSize);
for (int i = 0; i < populationSize; i++) {
population.push_back(TSPGenome(points.size()));
}
// Repeat for the given number of generations
while (generation < numGenerations){
// Update circuitLength for each genome
for (int i = 0; i < populationSize; i++) {
population[i].computeCircuitLength(points);
}
// Sort the genomes in this generation
sort(population.begin(), population.end(), isShorterPath);
// Every 10th generation, print the shortest path found
if (generation % 10 == 0) {
cout << "Generation " << generation << ": shortest path is "
<< population[0].getCircuitLength() << endl;
}
// Replace the least-fit genomes
for (int j = keepPopulation; j < populationSize; j++) {
int g1 = rand() % keepPopulation;
int g2 = g1;
while (g1 == g2) { // Make sure the indices are different
g2 = rand() % keepPopulation;
}
// Generate new genomes from the fittest ones
population[j] = crosslink(population[g1], population[g2]);
}
// Mutate the population
for (int k =0; k < numMutations; k++){
int mIndex = 1 + rand() % (populationSize - 1); // pick a random index other than 0
population[mIndex].mutate(); // mutate the chosen genome
}
generation++;
}
// Once all generations have completed, return the best solution found
return population[0];
}