-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSolution.java
354 lines (314 loc) · 7.44 KB
/
Solution.java
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
import java.util.Random;
/**
* This object is used to encapsulate the solution
* to a vehicle routing problem determined by the
* Artificial Bee Colony algorithm.
*
* Contains utility methods that compute various
* parameters associated with the ABC algorithm
* (like the fitness value).
*
* @author Ajinkya Dhaigude
* @author Sameer Raghuram
*/
class Solution implements Cloneable, Comparable<Solution>{
// shared variables
private Node route[]; // Solution path eg {0->1->2->3->0->4->5->6->0->7->8}
private int totalNodes; // Total nodes
private double fitness = 0.0;
private int TRIAL_LIMIT = 20;
private int trial = 0;
public int id;
/**
* Empty constructor
*/
public Solution(){}
/**
* Constructor to initialize shared variables.
*
* @param allNodes
* @param totVehicles
* @param id
*/
public Solution(Node allNodes[], int totVehicles, int id){
this.id = id;
totalNodes = allNodes.length;
route = new Node[totalNodes + totVehicles];
// Initialize nodes in the route
for(int i=0; i<route.length; i++){
if(i < totalNodes)
route[i] = allNodes[i];
else
route[i] = allNodes[0]; // depot
}
}
/**
* Compute the fitness value of the route.
*
* @return double route fitness
*/
public double computeFitness(){
double distance = computeDistance();
return 1/distance;
}
/**
* Computes the total distance covered by all the
* vehicles for the current route.
*
* @return double route distance
*/
public double altComputeDistance(){
double distance = 0;
for(int i=0; i<route.length-1; i++){
distance += getDistance(route[i], route[i+1]);
}
return distance;
}
/**
* Computes the total distance covered by all the
* vehicles for the current route.
*
* @return double route distance
*/
public double computeDistance(){
double distance = 0;
for(int i=0; i<route.length-1; i++){
double nextDistance = getDistance(route[i], route[i+1]);
if(nextDistance == 0){
distance = Double.POSITIVE_INFINITY;
break;
}
distance += nextDistance;
}
return distance;
}
/**
* Computes the euclidean distance between two nodes.
* @param n1 Node First Node
* @param n2 Node Second Node
* @return double distance between nodes
*/
public double getDistance(Node n1, Node n2){
int yDiff = (n2.y - n1.y);
int xDiff = (n2.x - n1.x);
return Math.sqrt((yDiff * yDiff) + (xDiff * xDiff));
}
/**
* Setter for fitness value
*
* @param fitness fitness to set
*/
public void setFitness(double fitness){
this.fitness = fitness;
}
/**
* Getter for fitness
*
* @return double fitness value of solution
*/
public double getFitness(){
return fitness;
}
/**
* Getter for route array
* @return Node[] Route computed in solution
*/
public Node[] getRoute(){
return this.route;
}
/**
* Set the route to a given route
*
* @param route
*/
public void setRoute(Node[] route){
if(route[0] == null){
System.out.println("route is null during copy or deep copy");
}
this.route = route;
}
/**
* Setter for the trial value of the solution
* @param trial
*/
public void setTrial(int trial){
this.trial = trial;
}
/**
* Increment the trial by a given amount
* @param num
*/
public void incTrial(int num){
this.trial += num;
}
/**
* Getter for the trial value of the solution
* @return int Number of times the solution has been explored
*/
public int getTrial(){
return this.trial;
}
/**
* Checks if the trial number exceeds the maximum number of
* trials allowed for a solution.
* @return boolean true if the solution is exhausted
*/
public boolean isExhausted(){
return this.trial>this.TRIAL_LIMIT;
}
/**
* Swaps the location of two nodes in a route.
*
* @param idx1
* @param idx2
*/
public void swap(int idx1, int idx2){
Node temp = route[idx1];
route[idx1] = route[idx2];
route[idx2] = temp;
}
/**
* Randomizes the order of the nodes in the
* route to obtain a random solution.
*
* @param rand Random pseudorandom-generator
*/
void genRandomSolution(Random rand){
for(int i=1; i< route.length - 1; i++){
int idx2 = rand.nextInt(route.length - 2) + 1;
swap(i, idx2);
}
//this.fitness = computeFitness();
}
/**
* Performs a local search on the current solution
* Computes the fitness as a result.
*
* @param rand Random Pseeudorandom generator.
* @returns double Fitness value of solution
*/
public double exploitSolution(Random rand){
double oldFitness = computeFitness();
int idx1 = rand.nextInt(route.length - 2) + 1;
int idx2 = rand.nextInt(route.length - 2) + 1;
swap(idx1, idx2);
double newFitness = computeFitness();
if(oldFitness > newFitness) {
// Increment the number of trials to indicate exhaustion of
// a food source
incTrial(1);
swap(idx1, idx2); //revert
newFitness = oldFitness; //revert to old fitness
}
// reset the number of trials of solution to indicate improvement
if(!(oldFitness == newFitness)){
setTrial(0);
}
setFitness(newFitness);
return this.fitness;
}
/**
* Utility to compare different Solution instances
* in our program. Solutions are ordered according to
* their fitness value
*
* @param other Solution Solution being compared to
* @return int Natural ordering
*/
@Override
public int compareTo(Solution other) {
// This soltion is better
if(this.fitness > other.fitness){
return -1;
}
// The other solution is better
else if(this.fitness < other.fitness){
return 1;
}
// The solutions are identical
else{
return 0;
}
}
/**
* Returns a string representation of the routes
* of all the vehicles as described by the solution.
*
* @return String Solution String repr
*/
public String toString(){
double distance = computeDistance();
if(distance != Double.POSITIVE_INFINITY){
String toReturn1 = "Fitness: "+distance+"\nRoute:";
String toReturn2="";
int route_no = 0;
int vehicle_no = 1;
for(Node n:route){
if(n.isDepot()) {
if(route_no != 0)
toReturn2 += n.toString() + "\n";
if(route_no != route.length - 1) {
toReturn2 += "\n Vehicle " + vehicle_no + ": " + n.toString();
vehicle_no++;
}
route_no++;
}
else {
toReturn2 += n.toString();
route_no++;
}
}
return toReturn1 + toReturn2;
}
else{
distance = altComputeDistance();
String toReturn1 = "Fitness: "+distance+"\nRoute:";
String toReturn2="";
int route_no = 0;
int vehicle_no = 1;
for(Node n:route){
if(n.isDepot()) {
if(route_no != 0)
toReturn2 += n.toString() + "\n";
if(route_no != route.length - 1) {
toReturn2 += "\n Vehicle " + vehicle_no + ": " + n.toString();
vehicle_no++;
}
route_no++;
}
else {
toReturn2 += n.toString();
route_no++;
}
}
return toReturn1 + toReturn2;
}
}
/**
* Implement method to clone object
*/
public Object clone()
{
try{
Solution soln = (Solution) super.clone();
soln.copy(this);
return soln;
}
catch(CloneNotSupportedException e){
throw new RuntimeException("Bad code");
}
}
/**
* Method to deep copy shared variables.
*
* @param soln Solution instance
*/
public Solution copy(Solution soln){
this.setFitness(soln.getFitness());
this.setRoute(soln.getRoute());
this.setTrial(soln.getTrial());
this.id = soln.id;
this.totalNodes = soln.totalNodes;
return this;
}
}