SlideShare a Scribd company logo
1 // Obaid ur Rehman Khattak
2 // In this code, I am implementing the Simulated Annealing heuristic to solve the well
known
3 // Travelling salesman problem. The basic premise of the problem is to decide on the
sequence
4 // of cities to travel starting from an initial city and ending journey at the same
city while
5 // visiting each intermediate city exactly once.
6 // The goal is to minimize the routing distance travelled. This is a well known NP-hard
problem
7 // for which Simulated Annealing is often used.
8
9 // Please note that the code is for teaching purposes only showing the useage of STL
containers
10 // as well as the use of inheritence, polymorphism and use of smart pointers to make
the code
11 // more robust. Various Software engineering practices such as seperating the
definition and
12 // and implementation into seperate .h and .cpp files has been omitted intentionally.
13 // This code was created using Visual Studio 2015 that uses C++14 standard.
14 // Simulated_Annealing.cpp : Defines the entry point for the console application.
15 //
16
17 #include "stdafx.h"
18 #include <iostream>
19 #include <String>
20 #include <vector>
21 #include <utility>
22 #include <cmath>
23 #include <chrono>
24 #include <random>
25 #include <memory>
26
27 using namespace std;
28
29 /*
30 This is the city class which has a name with a possible, an x-coordinate and a
y-coordinate.
31 The city can have alphanumeric characters and spaces in between e.g. "Los Angeles"
32 */
33
34 class City
35 {
36 protected:
37 string name;
38 double x_coord;
39 double y_coord;
40 private:
41 /*
42 This is a private method to print out the city to an output (console, file etc.) It is
used in the
43 overloaded extraction operator.
44 */
45 virtual ostream& write(ostream& os) const
46 {
47 return os << "Name:" << name << "tX-coordinate:" << x_coord <<
"tY-coordinate:" << y_coord << endl;
48 }
49 public:
50 // Constructor
51 City(string lname = "", double lx = 0,double ly = 0):name(lname),
52 x_coord(lx),
53 y_coord(ly)
54 {}
55 // Destructor
56 virtual ~City()
57 {}
58 // Copy Constructor
59 City(const City& src)
60 {
61 name = src.name;
62 x_coord = src.x_coord;
63 y_coord = src.y_coord;
64 }
65 // Assignment operator
66 City& operator=(const City& src)
67 {
68 if (this == &src)
69 return *this;
70
71 name = src.name;
72 x_coord = src.x_coord;
73 y_coord = src.y_coord;
74
75 return *this;
76 }
77 // Move constructor. Speeds up performance when object of this kind is used in STL
containers that
78 // extensively use move semantics.
79
80 City(City&& src) noexcept
81 {
82 name = src.name;
83 x_coord = src.x_coord;
84 y_coord = src.y_coord;
85
86 src.name = "";
87 src.x_coord = 0;
88 src.y_coord = 0;
89 }
90 // Move assignment operator
91 City& operator=(City&& src) noexcept
92 {
93 if (this == &src)
94 return *this;
95 name = src.name;
96 x_coord = src.x_coord;
97 y_coord = src.y_coord;
98
99 src.name = "";
100 src.x_coord = 0;
101 src.y_coord = 0;
102 return *this;
103
104 }
105 // Getter, Setter methods
106 virtual string GetName() const
107 {
108 return name;
109 }
110 virtual double GetXCoordinate() const
111 {
112 return x_coord;
113 }
114 virtual double GetYCoordinate() const
115 {
116 return y_coord;
117 }
118
119 virtual void SetName(const string& lname)
120 {
121 name = lname;
122 }
123 virtual void SetXcoord(const double lx)
124 {
125 x_coord = lx;
126 }
127 virtual void SetYcoord(const double ly)
128 {
129 y_coord = ly;
130 }
131
132 // Overloaded extraction operator
133 friend ostream& operator<<(ostream& ostr, const City& city)
134 {
135 return city.write(ostr);
136 }
137
138 };
139
140
141 // Metro is a derived class of the Citty class that has an extra string parameter
specifying any
142 // special aspect of the city in question. It has a single extra parameter for the
aspect and
143 // corresponding getter and setter functions as well as overloaded extraction operator.
144
145 class Metro :public City
146 {
147 protected:
148 string remarks;
149 private:
150 virtual ostream& write(ostream& os) const override
151 {
152 return os << "Name:" << name << "tX-coordinate:" << x_coord <<
"tY-coordinate:" << y_coord << "tRemarks:" << remarks << endl;
153 }
154 public:
155 Metro(string name = "", double lx = 0, double ly = 0, string lremarks = "") :
156 City(name, lx, ly),
157 remarks(lremarks)
158 {}
159 virtual ~Metro()
160 {}
161
162 Metro(const Metro& src)
163 {
164 name = src.name;
165 x_coord = src.x_coord;
166 y_coord = src.y_coord;
167 remarks = src.remarks;
168 }
169 Metro& operator= (const Metro& src)
170 {
171 if (this == &src)
172 return *this;
173
174 name = src.name;
175 x_coord = src.x_coord;
176 y_coord = src.y_coord;
177 remarks = src.remarks;
178
179 return *this;
180 }
181
182 Metro(Metro&& src) noexcept
183 {
184 name = src.name;
185 x_coord = src.x_coord;
186 y_coord = src.y_coord;
187 remarks = src.remarks;
188
189 src.name = "";
190 src.x_coord = 0;
191 src.y_coord = 0;
192 src.remarks = "";
193 }
194 Metro& operator=(Metro&& src) noexcept
195 {
196 if (this == &src)
197 return *this;
198 name = src.name;
199 x_coord = src.x_coord;
200 y_coord = src.y_coord;
201 remarks = src.remarks;
202
203 src.name = "";
204 src.x_coord = 0;
205 src.y_coord = 0;
206 src.remarks = "";
207
208 return *this;
209
210 }
211
212 virtual string GetRemarks() const
213 {
214 return remarks;
215 }
216
217 virtual void SetRemarks(const string& lremarks)
218 {
219 remarks = lremarks;
220 }
221
222
223 friend ostream& operator<<(ostream& ostr, const Metro& met)
224 {
225 return met.write(ostr);
226 }
227 };
228
229
230 // We use Euclidean distance to measure the distance between two cities.
231 double GetDistance(const City& lhs, const City& rhs)
232 {
233 double x_diff_square = pow(lhs.GetXCoordinate()- rhs.GetXCoordinate(), 2);
234 double y_diff_square = pow(lhs.GetYCoordinate() - rhs.GetYCoordinate(), 2);
235
236 return sqrt(x_diff_square + y_diff_square);
237 }
238
239
240 // This function actually measures the total routing distance of visiting each of the
cities in question
241 // and returing back to the starting city such that every intermediate city is visited
exactly once.
242
243 double GetEnergy(const vector<shared_ptr<City>>& cities)
244 {
245 double energy = 0;
246 size_t n1 = cities.size() - 1;
247
248 for (size_t index = 0; index < n1;++index)
249 energy += GetDistance(*cities[index], *cities[index + 1]);
250
251 energy += GetDistance(*cities[0], *cities[n1]);
252
253 return energy;
254 }
255
256 // This function is used by the Simulated Annealing algorithm to traverse the solution
space and move between
257 // different points as a function of the routing distances with different permuations
of visting schedules.
258
259 double Acceptance_Probability(double old_energy,
260 double new_energy,
261 double temperature)
262 {
263 double delta_energy = new_energy - old_energy;
264 if (delta_energy <= 0)
265 return 1;
266 else return exp(-1 * delta_energy / temperature);
267
268 }
269
270
271 // Simulated annealing algorithm
272
273 void SimulatedAnnealing(vector<shared_ptr<City>>& cities, // Vector of cities
274 double temperature = 10000, // Starting "temperature"
with default 10000
275 double cooling_rate = 0.004) // Cooling rate.
Determines how fast the
276 // the algorithm
converges. Small rates
277 // correspong to slow
times but increased
278 // coverage of solution
space explored
279 {
280 // We define the seed, the random number generators and the distributions for
randomly
281 // picking the cities to swap in the visiting schedule at each iteration as well as
282 // generating the probability to move between points in the solution space
283 random_device rd;
284 mt19937 engine(rd());
285
286 uniform_int_distribution<size_t> distribution_int_1(0, cities.size()-1);
287 uniform_real_distribution<double> distribution_real(0.0, 1.0);
288
289 vector<shared_ptr<City>> oldState = cities;
290 double oldEnergy = GetEnergy(cities);
291
292 vector<shared_ptr<City>> bestState = oldState;
293 double bestEnergy = oldEnergy;
294
295 vector<shared_ptr<City>> newState = oldState;
296 double newEnergy = oldEnergy;
297
298 size_t index1 = 0, index2 = 0;
299 double accepted = 0;
300
301 while (temperature > 1)
302 {
303
304 vector<shared_ptr<City>> temp = oldState;
305
306 index1 = distribution_int_1(engine);
307
308 do
309 {
310 index2 = distribution_int_1(engine);
311 } while (index2 == index1);
312
313 swap(temp[index1], temp[index2]);
314
315
316 newState = temp;
317 newEnergy = GetEnergy(temp);
318
319 accepted = Acceptance_Probability(oldEnergy, newEnergy, temperature);
320
321 if (distribution_real(engine) < accepted)
322 {
323 oldState = newState;
324 oldEnergy = newEnergy;
325
326 if (oldEnergy < bestEnergy)
327 {
328 bestState = oldState;
329 bestEnergy = oldEnergy;
330 }
331 }
332
333
334 temperature = temperature*(1 - cooling_rate);
335
336 }
337
338 cities.swap(bestState);
339
340 }
341
342
343 // This function is used to input data from the user as to how many cities are to be
visited and
344 // the various properties of the cities such as the coordinates, the name of the city
and whether
345 // it is a metro or not.
346
347 // Note the use of smart pointers in the inputs. They serve two purposes. One is to be
able to move
348 // data objects that might be very "heavy" in terms of the memory they use and the
other important
349 // reason is to be able to include both base and derived classes City and Metro using
polymorphism
350 // and avoid object slicing which is loss of information incurred when an object of
type city
351 // is assigned an object of a derived class which would throw away the fields that are
not in the base
352 // class
353
354 void InputValues(vector<shared_ptr<City>>& cities, int numCities)
355 {
356 int index = 0;
357 string name,remarks,answer;
358 double lx = 0;
359 double ly = 0;
360
361 while (index < numCities)
362 {
363 cout << "Enter name of city" << (index + 1) << ":";
364 getline(cin, name);
365
366 // The following loops is used for input validation to make sure all the data
fed into the
367 // simulated annealing algorithm has valid inputs.
368
369 while (true)
370 {
371 string dummy;
372 size_t sz = 0;
373 bool done = true;
374 cout << "Enter x coordinate:";
375 try
376 {
377 getline(cin, dummy);
378 lx = stod(dummy,&sz);
379 }
380 catch (const exception& e)
381 {
382 cerr << "Error:" << e.what() << "Please try again.n";
383 }
384
385 for (auto i = sz; i < dummy.size(); ++i)
386 {
387 if (!isspace(dummy[i]))
388 {
389 cout << "Error: Not a valid number. Please try again.n";
390 done = false;
391 break;
392 }
393 }
394 if (!done)
395 {
396 continue;
397 }
398 else
399 {
400 break;
401 }
402 }
403 while (true)
404 {
405 string dummy;
406 size_t sz = 0;
407 bool done = true;
408 cout << "Enter y coordinate:";
409 try
410 {
411 getline(cin, dummy);
412 ly = stod(dummy, &sz);
413 }
414 catch (const exception& e)
415 {
416 cerr << "Error:" << e.what() << "Please try again.n";
417 }
418
419 for (auto i = sz; i < dummy.size(); ++i)
420 {
421 if (!isspace(dummy[i]))
422 {
423 cout << "Error: Not a valid number. Please try again.n";
424 done = false;
425 break;
426 }
427 }
428 if (!done)
429 {
430 continue;
431 }
432 else
433 {
434 break;
435 }
436 }
437 while (true)
438 {
439 cout << "Is this a metrpolitan?(y/n)";
440 cin >> answer;
441 cin.ignore();
442 if (answer == "y")
443 {
444 cout << "Any remarks?";
445 getline(cin, remarks);
446 cities.push_back(make_shared<Metro>(name, lx, ly, remarks));
447 break;
448 }
449 else if (answer == "n")
450 {
451 cities.push_back(make_shared<City>(name, lx, ly));
452 break;
453 }
454 else
455 {
456 cout << "The valid answers are y for yes, n for no. Please try again.n";
457 }
458 }
459
460 cout << 'n';
461 ++index;
462 }
463 }
464
465 // This method is used to output the schedule of the cities to visit as the data is
entered by
466 // the user as well as to output the result of the Simulated annealing algorithm as the
optimized
467 // visiting schedule
468 void OutputValues(const vector< shared_ptr<City>>& cities, const string& string1)
469 {
470 for (size_t index = 0; index < cities.size();++index)
471 {
472
473 cout << *cities[index] << 'n';
474 }
475 cout << string1 << GetEnergy(cities) << "nn";
476 }
477
478 // Main program
479 int main()
480 {
481 int numCities;
482
483
484 while (true)
485 {
486 cout << "Enter number of cities:";
487
488 string dummy;
489 size_t sz = 0;
490 bool done = true;
491 try
492 {
493 getline(cin, dummy);
494 numCities = stoi(dummy,&sz);
495 }
496 catch (const exception& e)
497 {
498 cerr << "Error:" << e.what() << " Please try again.n";
499 continue;
500 }
501 for (auto i = sz; i < dummy.size();++i)
502 {
503 if (!isspace(dummy[i]))
504 {
505 cout << "Error: Not a valid number. Please try again.n";
506 done = false;
507 break;
508 }
509 }
510 if (!done)
511 {
512 continue;
513 }
514 else if (numCities < 0)
515 {
516 cerr << "Error: Value must be > 0n";
517 }
518 else
519 {
520 break;
521 }
522 }
523
524
525 if (numCities == 0)
526 {
527 cout << "No route to optimize " << endl;
528 return 0;
529 }
530
531 vector<shared_ptr<City>> cities;
532
533 InputValues(cities,numCities);
534
535 cout << "Initial route as entered by user:n";
536 OutputValues(cities, "Initial routing distance:");
537
538 if (numCities == 1)
539 {
540 cout << "Thats the best you can do with one city. No optimization needs to be
runn";
541 return 0;
542 }
543
544 if (numCities == 2)
545 {
546 cout << "With two cities, you can start at any point and it will still be the
samen";
547 return 0;
548 }
549
550 chrono::system_clock::time_point t1 = chrono::system_clock::now();
551
552 SimulatedAnnealing(cities);
553
554 chrono::system_clock::time_point t2 = chrono::system_clock::now();
555
556 cout << "nnTime to run the algorithm is:" <<
chrono::duration_cast<chrono::milliseconds>(t2 - t1).count() << " ms.nn";
557
558 cout << "Optimization run and resulting route returned:n";
559 OutputValues(cities, "Optimized routing distance:");
560 return 0;
561 }
562
563

More Related Content

TXT
Advance C++notes
PDF
2 BytesC++ course_2014_c9_ pointers and dynamic arrays
PPTX
PDF
Recursion to iteration automation.
PDF
To Swift 2...and Beyond!
PDF
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
PPTX
Egor Bogatov - .NET Core intrinsics and other micro-optimizations
PPTX
How to add an optimization for C# to RyuJIT
Advance C++notes
2 BytesC++ course_2014_c9_ pointers and dynamic arrays
Recursion to iteration automation.
To Swift 2...and Beyond!
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
Egor Bogatov - .NET Core intrinsics and other micro-optimizations
How to add an optimization for C# to RyuJIT

What's hot (20)

PPT
Advance features of C++
PPTX
Operator overloading2
PDF
OpenXR 1.0 Reference Guide
PDF
Modern C++
PDF
C++11 & C++14
PPTX
C++ 11 Features
PDF
C++11
PDF
Address/Thread/Memory Sanitizer
PDF
A Decompiler for Blackhain-Based Smart Contracts Bytecode
PDF
Modern c++ (C++ 11/14)
PDF
OpenVX 1.2 Reference Guide
PDF
Let’s talk about microbenchmarking
PDF
OpenGL 4.4 Reference Card
PDF
A look into the sanitizer family (ASAN & UBSAN) by Akul Pillai
PDF
(5) cpp dynamic memory_arrays_and_c-strings
PDF
OpenGL SC 2.0 Quick Reference
PDF
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
PDF
C++11 concurrency
PDF
Конверсия управляемых языков в неуправляемые
PDF
Lambda expressions in C++
Advance features of C++
Operator overloading2
OpenXR 1.0 Reference Guide
Modern C++
C++11 & C++14
C++ 11 Features
C++11
Address/Thread/Memory Sanitizer
A Decompiler for Blackhain-Based Smart Contracts Bytecode
Modern c++ (C++ 11/14)
OpenVX 1.2 Reference Guide
Let’s talk about microbenchmarking
OpenGL 4.4 Reference Card
A look into the sanitizer family (ASAN & UBSAN) by Akul Pillai
(5) cpp dynamic memory_arrays_and_c-strings
OpenGL SC 2.0 Quick Reference
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
C++11 concurrency
Конверсия управляемых языков в неуправляемые
Lambda expressions in C++
Ad

Viewers also liked (9)

PPSX
Assessment Rubrics
PPT
trending gmp-issues_eng
DOCX
đOrđe je moja krv
PDF
International freight quote
PPT
Carlisle: Developing an effective food partnership and action plan
DOC
Vineela_HR_Visaka Industries Ltd.
PDF
IMPORTS
PPTX
Pecha kucha plan
PPT
4 trending gmp-issues_eng
Assessment Rubrics
trending gmp-issues_eng
đOrđe je moja krv
International freight quote
Carlisle: Developing an effective food partnership and action plan
Vineela_HR_Visaka Industries Ltd.
IMPORTS
Pecha kucha plan
4 trending gmp-issues_eng
Ad

Similar to cpp_sample (20)

DOCX
CSCI2312 – Object Oriented Programming Section 003 Homewo
DOCX
ECS 40 Program #3 (50 points, my time 1.5 hours) Spring 2015 .docx
DOCX
ECS 40 Program #1 (50 points, my time 2.5 hours) .docx
PDF
#include iostream #include fstream #include cstdlib #.pdf
PPTX
CPP Homework Help
PDF
Hi,you covered mostly things.there are issue to point and link poi.pdf
PDF
Object Oriented Programming (OOP) using C++ - Lecture 2
PPTX
User defined datatype in C++ with examples
PDF
Can you please debug this Thank you in advance! This program is sup.pdf
DOCX
Lab08Lab08.cppLab08Lab08.cpp.docx
PPTX
Basic C++ 11/14 for Python Programmers
PDF
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
PDF
Basic c++ 11/14 for python programmers
PDF
COMPUTER NETWORKS AND SECURITY PRACTICAL
PDF
The STL
PPT
CppTutorial.ppt
PDF
C++ practical
PDF
PDF
C++ normal assignments by maharshi_jd.pdf
PDF
Computer Vision using Ruby and libJIT - RubyConf 2009
CSCI2312 – Object Oriented Programming Section 003 Homewo
ECS 40 Program #3 (50 points, my time 1.5 hours) Spring 2015 .docx
ECS 40 Program #1 (50 points, my time 2.5 hours) .docx
#include iostream #include fstream #include cstdlib #.pdf
CPP Homework Help
Hi,you covered mostly things.there are issue to point and link poi.pdf
Object Oriented Programming (OOP) using C++ - Lecture 2
User defined datatype in C++ with examples
Can you please debug this Thank you in advance! This program is sup.pdf
Lab08Lab08.cppLab08Lab08.cpp.docx
Basic C++ 11/14 for Python Programmers
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
Basic c++ 11/14 for python programmers
COMPUTER NETWORKS AND SECURITY PRACTICAL
The STL
CppTutorial.ppt
C++ practical
C++ normal assignments by maharshi_jd.pdf
Computer Vision using Ruby and libJIT - RubyConf 2009

cpp_sample

  • 1. 1 // Obaid ur Rehman Khattak 2 // In this code, I am implementing the Simulated Annealing heuristic to solve the well known 3 // Travelling salesman problem. The basic premise of the problem is to decide on the sequence 4 // of cities to travel starting from an initial city and ending journey at the same city while 5 // visiting each intermediate city exactly once. 6 // The goal is to minimize the routing distance travelled. This is a well known NP-hard problem 7 // for which Simulated Annealing is often used. 8 9 // Please note that the code is for teaching purposes only showing the useage of STL containers 10 // as well as the use of inheritence, polymorphism and use of smart pointers to make the code 11 // more robust. Various Software engineering practices such as seperating the definition and 12 // and implementation into seperate .h and .cpp files has been omitted intentionally. 13 // This code was created using Visual Studio 2015 that uses C++14 standard. 14 // Simulated_Annealing.cpp : Defines the entry point for the console application. 15 // 16 17 #include "stdafx.h" 18 #include <iostream> 19 #include <String> 20 #include <vector> 21 #include <utility> 22 #include <cmath> 23 #include <chrono> 24 #include <random> 25 #include <memory> 26 27 using namespace std; 28 29 /* 30 This is the city class which has a name with a possible, an x-coordinate and a y-coordinate. 31 The city can have alphanumeric characters and spaces in between e.g. "Los Angeles" 32 */ 33 34 class City 35 { 36 protected: 37 string name; 38 double x_coord; 39 double y_coord; 40 private: 41 /* 42 This is a private method to print out the city to an output (console, file etc.) It is used in the 43 overloaded extraction operator. 44 */ 45 virtual ostream& write(ostream& os) const 46 { 47 return os << "Name:" << name << "tX-coordinate:" << x_coord << "tY-coordinate:" << y_coord << endl; 48 } 49 public: 50 // Constructor 51 City(string lname = "", double lx = 0,double ly = 0):name(lname), 52 x_coord(lx), 53 y_coord(ly) 54 {} 55 // Destructor 56 virtual ~City() 57 {} 58 // Copy Constructor 59 City(const City& src)
  • 2. 60 { 61 name = src.name; 62 x_coord = src.x_coord; 63 y_coord = src.y_coord; 64 } 65 // Assignment operator 66 City& operator=(const City& src) 67 { 68 if (this == &src) 69 return *this; 70 71 name = src.name; 72 x_coord = src.x_coord; 73 y_coord = src.y_coord; 74 75 return *this; 76 } 77 // Move constructor. Speeds up performance when object of this kind is used in STL containers that 78 // extensively use move semantics. 79 80 City(City&& src) noexcept 81 { 82 name = src.name; 83 x_coord = src.x_coord; 84 y_coord = src.y_coord; 85 86 src.name = ""; 87 src.x_coord = 0; 88 src.y_coord = 0; 89 } 90 // Move assignment operator 91 City& operator=(City&& src) noexcept 92 { 93 if (this == &src) 94 return *this; 95 name = src.name; 96 x_coord = src.x_coord; 97 y_coord = src.y_coord; 98 99 src.name = ""; 100 src.x_coord = 0; 101 src.y_coord = 0; 102 return *this; 103 104 } 105 // Getter, Setter methods 106 virtual string GetName() const 107 { 108 return name; 109 } 110 virtual double GetXCoordinate() const 111 { 112 return x_coord; 113 } 114 virtual double GetYCoordinate() const 115 { 116 return y_coord; 117 } 118 119 virtual void SetName(const string& lname) 120 { 121 name = lname; 122 } 123 virtual void SetXcoord(const double lx) 124 { 125 x_coord = lx; 126 } 127 virtual void SetYcoord(const double ly)
  • 3. 128 { 129 y_coord = ly; 130 } 131 132 // Overloaded extraction operator 133 friend ostream& operator<<(ostream& ostr, const City& city) 134 { 135 return city.write(ostr); 136 } 137 138 }; 139 140 141 // Metro is a derived class of the Citty class that has an extra string parameter specifying any 142 // special aspect of the city in question. It has a single extra parameter for the aspect and 143 // corresponding getter and setter functions as well as overloaded extraction operator. 144 145 class Metro :public City 146 { 147 protected: 148 string remarks; 149 private: 150 virtual ostream& write(ostream& os) const override 151 { 152 return os << "Name:" << name << "tX-coordinate:" << x_coord << "tY-coordinate:" << y_coord << "tRemarks:" << remarks << endl; 153 } 154 public: 155 Metro(string name = "", double lx = 0, double ly = 0, string lremarks = "") : 156 City(name, lx, ly), 157 remarks(lremarks) 158 {} 159 virtual ~Metro() 160 {} 161 162 Metro(const Metro& src) 163 { 164 name = src.name; 165 x_coord = src.x_coord; 166 y_coord = src.y_coord; 167 remarks = src.remarks; 168 } 169 Metro& operator= (const Metro& src) 170 { 171 if (this == &src) 172 return *this; 173 174 name = src.name; 175 x_coord = src.x_coord; 176 y_coord = src.y_coord; 177 remarks = src.remarks; 178 179 return *this; 180 } 181 182 Metro(Metro&& src) noexcept 183 { 184 name = src.name; 185 x_coord = src.x_coord; 186 y_coord = src.y_coord; 187 remarks = src.remarks; 188 189 src.name = ""; 190 src.x_coord = 0; 191 src.y_coord = 0; 192 src.remarks = ""; 193 }
  • 4. 194 Metro& operator=(Metro&& src) noexcept 195 { 196 if (this == &src) 197 return *this; 198 name = src.name; 199 x_coord = src.x_coord; 200 y_coord = src.y_coord; 201 remarks = src.remarks; 202 203 src.name = ""; 204 src.x_coord = 0; 205 src.y_coord = 0; 206 src.remarks = ""; 207 208 return *this; 209 210 } 211 212 virtual string GetRemarks() const 213 { 214 return remarks; 215 } 216 217 virtual void SetRemarks(const string& lremarks) 218 { 219 remarks = lremarks; 220 } 221 222 223 friend ostream& operator<<(ostream& ostr, const Metro& met) 224 { 225 return met.write(ostr); 226 } 227 }; 228 229 230 // We use Euclidean distance to measure the distance between two cities. 231 double GetDistance(const City& lhs, const City& rhs) 232 { 233 double x_diff_square = pow(lhs.GetXCoordinate()- rhs.GetXCoordinate(), 2); 234 double y_diff_square = pow(lhs.GetYCoordinate() - rhs.GetYCoordinate(), 2); 235 236 return sqrt(x_diff_square + y_diff_square); 237 } 238 239 240 // This function actually measures the total routing distance of visiting each of the cities in question 241 // and returing back to the starting city such that every intermediate city is visited exactly once. 242 243 double GetEnergy(const vector<shared_ptr<City>>& cities) 244 { 245 double energy = 0; 246 size_t n1 = cities.size() - 1; 247 248 for (size_t index = 0; index < n1;++index) 249 energy += GetDistance(*cities[index], *cities[index + 1]); 250 251 energy += GetDistance(*cities[0], *cities[n1]); 252 253 return energy; 254 } 255 256 // This function is used by the Simulated Annealing algorithm to traverse the solution space and move between 257 // different points as a function of the routing distances with different permuations of visting schedules. 258
  • 5. 259 double Acceptance_Probability(double old_energy, 260 double new_energy, 261 double temperature) 262 { 263 double delta_energy = new_energy - old_energy; 264 if (delta_energy <= 0) 265 return 1; 266 else return exp(-1 * delta_energy / temperature); 267 268 } 269 270 271 // Simulated annealing algorithm 272 273 void SimulatedAnnealing(vector<shared_ptr<City>>& cities, // Vector of cities 274 double temperature = 10000, // Starting "temperature" with default 10000 275 double cooling_rate = 0.004) // Cooling rate. Determines how fast the 276 // the algorithm converges. Small rates 277 // correspong to slow times but increased 278 // coverage of solution space explored 279 { 280 // We define the seed, the random number generators and the distributions for randomly 281 // picking the cities to swap in the visiting schedule at each iteration as well as 282 // generating the probability to move between points in the solution space 283 random_device rd; 284 mt19937 engine(rd()); 285 286 uniform_int_distribution<size_t> distribution_int_1(0, cities.size()-1); 287 uniform_real_distribution<double> distribution_real(0.0, 1.0); 288 289 vector<shared_ptr<City>> oldState = cities; 290 double oldEnergy = GetEnergy(cities); 291 292 vector<shared_ptr<City>> bestState = oldState; 293 double bestEnergy = oldEnergy; 294 295 vector<shared_ptr<City>> newState = oldState; 296 double newEnergy = oldEnergy; 297 298 size_t index1 = 0, index2 = 0; 299 double accepted = 0; 300 301 while (temperature > 1) 302 { 303 304 vector<shared_ptr<City>> temp = oldState; 305 306 index1 = distribution_int_1(engine); 307 308 do 309 { 310 index2 = distribution_int_1(engine); 311 } while (index2 == index1); 312 313 swap(temp[index1], temp[index2]); 314 315 316 newState = temp; 317 newEnergy = GetEnergy(temp); 318 319 accepted = Acceptance_Probability(oldEnergy, newEnergy, temperature); 320 321 if (distribution_real(engine) < accepted)
  • 6. 322 { 323 oldState = newState; 324 oldEnergy = newEnergy; 325 326 if (oldEnergy < bestEnergy) 327 { 328 bestState = oldState; 329 bestEnergy = oldEnergy; 330 } 331 } 332 333 334 temperature = temperature*(1 - cooling_rate); 335 336 } 337 338 cities.swap(bestState); 339 340 } 341 342 343 // This function is used to input data from the user as to how many cities are to be visited and 344 // the various properties of the cities such as the coordinates, the name of the city and whether 345 // it is a metro or not. 346 347 // Note the use of smart pointers in the inputs. They serve two purposes. One is to be able to move 348 // data objects that might be very "heavy" in terms of the memory they use and the other important 349 // reason is to be able to include both base and derived classes City and Metro using polymorphism 350 // and avoid object slicing which is loss of information incurred when an object of type city 351 // is assigned an object of a derived class which would throw away the fields that are not in the base 352 // class 353 354 void InputValues(vector<shared_ptr<City>>& cities, int numCities) 355 { 356 int index = 0; 357 string name,remarks,answer; 358 double lx = 0; 359 double ly = 0; 360 361 while (index < numCities) 362 { 363 cout << "Enter name of city" << (index + 1) << ":"; 364 getline(cin, name); 365 366 // The following loops is used for input validation to make sure all the data fed into the 367 // simulated annealing algorithm has valid inputs. 368 369 while (true) 370 { 371 string dummy; 372 size_t sz = 0; 373 bool done = true; 374 cout << "Enter x coordinate:"; 375 try 376 { 377 getline(cin, dummy); 378 lx = stod(dummy,&sz); 379 } 380 catch (const exception& e) 381 { 382 cerr << "Error:" << e.what() << "Please try again.n";
  • 7. 383 } 384 385 for (auto i = sz; i < dummy.size(); ++i) 386 { 387 if (!isspace(dummy[i])) 388 { 389 cout << "Error: Not a valid number. Please try again.n"; 390 done = false; 391 break; 392 } 393 } 394 if (!done) 395 { 396 continue; 397 } 398 else 399 { 400 break; 401 } 402 } 403 while (true) 404 { 405 string dummy; 406 size_t sz = 0; 407 bool done = true; 408 cout << "Enter y coordinate:"; 409 try 410 { 411 getline(cin, dummy); 412 ly = stod(dummy, &sz); 413 } 414 catch (const exception& e) 415 { 416 cerr << "Error:" << e.what() << "Please try again.n"; 417 } 418 419 for (auto i = sz; i < dummy.size(); ++i) 420 { 421 if (!isspace(dummy[i])) 422 { 423 cout << "Error: Not a valid number. Please try again.n"; 424 done = false; 425 break; 426 } 427 } 428 if (!done) 429 { 430 continue; 431 } 432 else 433 { 434 break; 435 } 436 } 437 while (true) 438 { 439 cout << "Is this a metrpolitan?(y/n)"; 440 cin >> answer; 441 cin.ignore(); 442 if (answer == "y") 443 { 444 cout << "Any remarks?"; 445 getline(cin, remarks); 446 cities.push_back(make_shared<Metro>(name, lx, ly, remarks)); 447 break; 448 } 449 else if (answer == "n") 450 { 451 cities.push_back(make_shared<City>(name, lx, ly));
  • 8. 452 break; 453 } 454 else 455 { 456 cout << "The valid answers are y for yes, n for no. Please try again.n"; 457 } 458 } 459 460 cout << 'n'; 461 ++index; 462 } 463 } 464 465 // This method is used to output the schedule of the cities to visit as the data is entered by 466 // the user as well as to output the result of the Simulated annealing algorithm as the optimized 467 // visiting schedule 468 void OutputValues(const vector< shared_ptr<City>>& cities, const string& string1) 469 { 470 for (size_t index = 0; index < cities.size();++index) 471 { 472 473 cout << *cities[index] << 'n'; 474 } 475 cout << string1 << GetEnergy(cities) << "nn"; 476 } 477 478 // Main program 479 int main() 480 { 481 int numCities; 482 483 484 while (true) 485 { 486 cout << "Enter number of cities:"; 487 488 string dummy; 489 size_t sz = 0; 490 bool done = true; 491 try 492 { 493 getline(cin, dummy); 494 numCities = stoi(dummy,&sz); 495 } 496 catch (const exception& e) 497 { 498 cerr << "Error:" << e.what() << " Please try again.n"; 499 continue; 500 } 501 for (auto i = sz; i < dummy.size();++i) 502 { 503 if (!isspace(dummy[i])) 504 { 505 cout << "Error: Not a valid number. Please try again.n"; 506 done = false; 507 break; 508 } 509 } 510 if (!done) 511 { 512 continue; 513 } 514 else if (numCities < 0) 515 { 516 cerr << "Error: Value must be > 0n"; 517 } 518 else
  • 9. 519 { 520 break; 521 } 522 } 523 524 525 if (numCities == 0) 526 { 527 cout << "No route to optimize " << endl; 528 return 0; 529 } 530 531 vector<shared_ptr<City>> cities; 532 533 InputValues(cities,numCities); 534 535 cout << "Initial route as entered by user:n"; 536 OutputValues(cities, "Initial routing distance:"); 537 538 if (numCities == 1) 539 { 540 cout << "Thats the best you can do with one city. No optimization needs to be runn"; 541 return 0; 542 } 543 544 if (numCities == 2) 545 { 546 cout << "With two cities, you can start at any point and it will still be the samen"; 547 return 0; 548 } 549 550 chrono::system_clock::time_point t1 = chrono::system_clock::now(); 551 552 SimulatedAnnealing(cities); 553 554 chrono::system_clock::time_point t2 = chrono::system_clock::now(); 555 556 cout << "nnTime to run the algorithm is:" << chrono::duration_cast<chrono::milliseconds>(t2 - t1).count() << " ms.nn"; 557 558 cout << "Optimization run and resulting route returned:n"; 559 OutputValues(cities, "Optimized routing distance:"); 560 return 0; 561 } 562 563