-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathLKMatrix.cpp
273 lines (224 loc) · 7.06 KB
/
LKMatrix.cpp
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#include "LKMatrix.h"
#include <vector>
#include <cmath>
#include <set>
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <ctime>
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
using namespace std;
pair<int, int> make_sorted_pair(int x, int y) {
if (x < y) {
return make_pair(x, y);
} else {
return make_pair(y, x);
}
}
LKMatrix::LKMatrix(vector<pair<double, double> > &coords, vector<int> &ids) {
this->coords = coords;
this->ids = ids;
size = ids.size();
// initialize tour
tour = vector<int>(size, 0);
// initial 'random' tour
for (int i = 0; i < size; i++) {
tour[i] = (i + 1) % size;
}
// sets the distanceVector
edgeDistances = vector<vector<double> > (size, vector<double> (size, 0));
double edgeDistance;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
// Compute the edge distance
edgeDistance = sqrt(pow((coords[i].first - coords[j].first), 2) +
pow((coords[i].second - coords[j].second), 2));
edgeDistances[i][j] = edgeDistance;
edgeDistances[j][i] = edgeDistance;
}
}
}
double LKMatrix::getCurrentTourDistance() {
int currentIndex = 0;
double distance = 0;
for (int i = 0; i < size; i++) {
//cout << edgeDistances[i][tour[i]] << "; ";
distance += edgeDistances[i][tour[i]];
}
//cout << endl;
return distance;
}
void LKMatrix::LKMove(int tourStart) {
set<pair<int,int> > broken_set, joined_set;
vector<int> tour_opt = tour;
double g_opt = 0;
double g = 0; // := G_i
double g_local; // := g_i
int lastNextV = tourStart;
int fromV;
int nextV;
int nextFromV;
int lastPossibleNextV;
pair<int, int> broken_edge;
double y_opt_length;
double broken_edge_length;
double g_opt_local;
fromV = tour[lastNextV];
long initialTourDistance = getCurrentTourDistance();
do {
// default, no nextV is found
nextV = -1;
broken_edge = make_sorted_pair(lastNextV, fromV); // := x_i
broken_edge_length = edgeDistances[broken_edge.first][broken_edge.second];
//cout << "Breaking " << lastNextV << " " << fromV << endl;
//cout << "Testing from " << fromV << endl;;
//cout << "Breaking of length: " << broken_edge_length << endl;
// Condition 4(c)(1)
if (joined_set.count(broken_edge) > 0) break;
// y_i := (fromV, nextV)
for (int possibleNextV = tour[fromV]; nextV == -1 && possibleNextV != tourStart; possibleNextV = tour[possibleNextV]) {
//cout << "Testing " << possibleNextV << endl;
//cout << (broken_set.count(make_sorted_pair(fromV, possibleNextV)) == 0) << endl;
//cout << (possibleNextV != fromV) << endl;
//cout << (g + g_local > 0) << endl;
//cout << (joined_set.count(make_sorted_pair(possibleNextV, tour[possibleNextV])) == 0) << endl;
// calculate local gain
g_local = broken_edge_length - edgeDistances[fromV][possibleNextV];
// conditions that make this edge not a valid y_i
if (!(
// condition 4(c)(2)
broken_set.count(make_sorted_pair(fromV, possibleNextV)) == 0 &&
// condition 4(d)
g + g_local > 0 &&
// condition 4(e)
// x_{i+1} has never been joined before
joined_set.count(make_sorted_pair(lastPossibleNextV, possibleNextV)) == 0 &&
tour[possibleNextV] != 0 && // not already joined to start
possibleNextV != tour[fromV] // not the one already joined to fromV
)) {
lastPossibleNextV = possibleNextV;
continue;
}
// If we are here, then y_i := (fromV, possibleNextV)
nextV = possibleNextV;
//cout << "Moving to " << nextV << endl;
}
// a next y_i exists
if (nextV != -1) {
// add to our broken_set and joined_set
broken_set.insert(broken_edge);
joined_set.insert(make_sorted_pair(fromV, nextV));
// condition 4(f)
y_opt_length = edgeDistances[fromV][tourStart]; // y_i_opt
// The tour length if we exchanged the broken edge (x_i)
// with y_opt, (t_{2i}, t_0)
g_opt_local = g + (broken_edge_length - y_opt_length);
if (g_opt_local > g_opt) {
//vector<int> temp_tour = tour;
//temp_tour[tourStart] = fromV;
//tour = tour_opt;
//printTour();
//long old_distance = getCurrentTourDistance();
//tour = temp_tour;
//printTour();
//long new_distance = getCurrentTourDistance();
//cout << "(Temp) Joining of distance: " << y_opt_length << endl;
//cout << "Old distance: " << old_distance << endl;
//cout << "New distance: " << new_distance << endl;
//assert(new_distance <= old_distance);
g_opt = g_opt_local;
tour_opt = tour;
// join the optimal tour
tour_opt[tourStart] = fromV;
}
//cout << "Joining of distance: " << edgeDistances[fromV][nextV] << endl;
// recalculate g
g += broken_edge_length - edgeDistances[fromV][nextV];
// reverse tour direction between newNextV and fromV
// implicitly breaks x_i
reverse(fromV, lastPossibleNextV);
// remember our new t_{2i+1}
nextFromV = lastPossibleNextV;
//cout << "Joined to " << nextFromV << endl;
// build y_i
tour[fromV] = nextV;
// set new fromV to t_{2i+1}
// and out lastNextV to t_{2i}
lastNextV = nextV;
fromV = nextFromV;
}
} while (nextV != -1);
// join up
//cout << "terminated" << endl;
tour = tour_opt;
long distanceAfter = getCurrentTourDistance();
assert(distanceAfter <= initialTourDistance);
printTour();
assert(isTour());
}
void LKMatrix::optimizeTour() {
// we need to test for convergence and also the difference from last time
int diff;
int old_distance = 0;
int new_distance = 0;
for (int j = 0; j < 100; j++) {
for (int i = 0; i < size; i++) {
LKMove(i);
}
new_distance = getCurrentTourDistance();
diff = old_distance - new_distance;
if (j != 0) {
assert(diff >= 0);
if (diff == 0) {
//cout << "Converged after " << j << " iterations" << endl;
break;
}
};
old_distance = new_distance;
}
}
/*
* Reverse the tour between indices start and end
*/
void LKMatrix::reverse(int start, int end) {
int current = start;
int next = tour[start];
int nextNext;
do {
//cout << "reversing" << endl;
// look ahead to where we need to go after this iteration
nextNext = tour[next];
// reverse the direction at this point
tour[next] = current;
// move to the next pointer
current = next;
next = nextNext;
} while (current != end); // terminate once we've reversed up to end
}
// Sanity check function
bool LKMatrix::isTour() {
int count = 1;
int start = tour[0];
while (start != 0) {
start = tour[start];
count++;
}
return (count == size);
}
void LKMatrix::printTour() {
int current = 0;
do {
//cout << current << " ; ";
current = tour[current];
} while (current != 0);
//cout << endl;
}
void LKMatrix::printTourIds() {
int current = 0;
do {
cout << ids[current] << endl;
current = tour[current];
} while (current != 0);
}