Advertisement
sergiosvieira1978

Untitled

May 22nd, 2018
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.34 KB | None | 0 0
  1. //
  2. //  main.cpp
  3. //  tsp
  4. //
  5.  
  6. #include <iostream>
  7. #include <vector>
  8. #include <map>
  9. #include <math.h>
  10. #include <cmath>
  11. #include <set>
  12. #include <limits>
  13. #include <random>
  14. #include <fstream>
  15. #include <sstream>
  16. #include <algorithm>
  17. #include <iterator>
  18. #include <ctime>
  19.  
  20. // Genetic Algorithm
  21. static std::random_device rdev{};
  22. static std::default_random_engine eng{rdev()};
  23. static const int PopulationSize = 20;
  24. static const double MutationRate = 0.35; // 0..1
  25. static const int Generations = 10;
  26.  
  27.  
  28. using City = struct
  29. {
  30.     int id;
  31.     double x;
  32.     double y;
  33. };
  34.  
  35. using Data = std::vector<City>;
  36. using Cromossome = std::vector<int>;
  37. using Solution = struct
  38. {
  39.     Cromossome cromossome;
  40.     double cost = 0.0;
  41.     double fitness = 0.0;
  42. };
  43. using Population = std::vector<Solution>;
  44. using Distances = std::map<int, std::map<int, double>>;
  45. using CrossSolution = std::pair<Cromossome, Cromossome>;
  46.  
  47. double distance(const City& src, const City& dst)
  48. {
  49.     double d1 = src.x - dst.x;
  50.     double d2 = src.y - dst.y;
  51.     double d = sqrt(pow(d1, 2.0) + pow(d2, 2.0));
  52.     return std::round(d);
  53. }
  54.  
  55. void print(Distances& dist)
  56. {
  57.     for (auto src: dist)
  58.     {
  59.         std::cout << src.first << "\n";
  60.         for (auto dst: src.second)
  61.         {
  62.             std::cout << "\t" << dst.first << " = " << dst.second << "\n";
  63.         }
  64.     }
  65. }
  66.  
  67. std::string str(const Cromossome& r)
  68. {
  69.     std::string result = "[";
  70.     for (int i = 0; i < r.size(); ++i)
  71.     {
  72.         result += std::to_string(r[i]);
  73.         if (i < r.size() - 1) result += ",";
  74.     }
  75.     result += "]";
  76.     return result;
  77. }
  78.  
  79. bool isValidSolution(const Cromossome& cromossome, const Data& data)
  80. {
  81.     std::set<int> cityIndexes;
  82.     if (cromossome.size() != data.size())
  83.     {
  84.         return false;
  85.     }
  86.     for (int i = 0; i < cromossome.size(); ++i)
  87.     {
  88.         cityIndexes.insert(cromossome[i]);
  89.     }
  90.     if (cityIndexes.size() != cromossome.size())
  91.     {
  92.         return false;
  93.     }
  94.     return true;
  95. }
  96.  
  97. double calcCost(const Cromossome& cromossome, Distances& dist, const Data& data)
  98. {
  99.     double totalCost = 0.0;
  100.     if (!isValidSolution(cromossome, data)) return std::numeric_limits<double>::max();
  101.     for (int i = 1; i < cromossome.size(); ++i)
  102.     {
  103.         int src = cromossome[i - 1];
  104.         int dst = cromossome[i];
  105.         totalCost += dist[src][dst];
  106.     }
  107.     return totalCost;
  108. }
  109.  
  110. int rndMinMax(int min, int max)
  111. {
  112.     std::uniform_real_distribution<double> urd(min, max);
  113.     return urd(eng);
  114. }
  115.  
  116. Population initialPopulation(Distances& dist, int popSize, const Data& data)
  117. {
  118.     Population result;
  119.     for (int i = 0; i < popSize; ++i)
  120.     {
  121.         Cromossome v(dist.size());
  122.         std::iota(v.begin(), v.end(), 0);
  123.         std::shuffle(v.begin(), v.end(), eng);
  124.         Solution s;
  125.         s.cromossome = v;
  126.         s.cost = calcCost(v, dist, data);
  127.         s.fitness = 0.0;
  128.         result.push_back(s);
  129.     }
  130.     return result;
  131. }
  132.  
  133. int findBest(const Population& pop)
  134. {
  135.     double bestFitness = pop[0].fitness;
  136.     int index = 0;
  137.     for (int i = 1; i < pop.size(); ++i)
  138.     {
  139.         double fitness = pop[i].fitness;
  140.         if (fitness < bestFitness)
  141.         {
  142.             bestFitness = fitness;
  143.             index = i;
  144.         }
  145.     }
  146.     return index;
  147. }
  148.  
  149. int pickOne(const Population& pop)
  150. {
  151.     std::uniform_real_distribution<double> urd(0, 1);
  152.     double r = urd(eng);
  153.     int index = 0;
  154.     double offset = 0.0;
  155.     for (int i = 0; i < pop.size(); ++i)
  156.     {
  157.         offset += pop[i].fitness;
  158.         if (r < offset)
  159.         {
  160.             return i;
  161.         }
  162.     }
  163.     return index;
  164. }
  165.  
  166. void mutation(Cromossome& cromossome)
  167. {
  168.     int p1 = rndMinMax(0, cromossome.size() - 1);
  169.     int p2 = rndMinMax(0, cromossome.size() - 1);
  170.     int aux = cromossome[p1];
  171.     cromossome[p1] = cromossome[p2];
  172.     cromossome[p2] = aux;
  173. }
  174.  
  175. CrossSolution crossover(const Cromossome& c1, const Cromossome& c2)
  176. {
  177.     Cromossome s1(c1);
  178.     Cromossome s2(c2);
  179.     int randPos1 = rndMinMax(0, c1.size() - 1);
  180.     std::shuffle(s1.begin() + randPos1, s1.end(), eng);
  181.     int randPos2 = rndMinMax(0, c2.size() - 1);
  182.     std::shuffle(s2.begin() + randPos2, s2.end(), eng);
  183.     return std::make_pair(s1, s2);
  184. }
  185.  
  186. void printPop(Population& pop)
  187. {
  188.     for (int i = 0; i < pop.size(); ++i)
  189.     {
  190.         std::cout << str(pop[i].cromossome)
  191.             << " = " << pop[i].cost
  192.             << ", " << pop[i].fitness
  193.             << "\n";
  194.     }
  195.     std::cout << "\n";
  196. }
  197.  
  198. std::vector<std::string> split(const std::string text)
  199. {
  200.     std::stringstream ss(text);
  201.     std::istream_iterator<std::string> begin(ss);
  202.     std::istream_iterator<std::string> end;
  203.     std::vector<std::string> result(begin, end);
  204.     return result;
  205. }
  206.  
  207. void calcFitness(Solution& s, double total)
  208. {
  209.     s.fitness = s.cost / (total + 1.0);
  210. }
  211.  
  212. void calculatePopFitness(Population& pop)
  213. {
  214.     double total = 0.0;
  215.     for (int i = 0; i < pop.size(); ++i)
  216.     {
  217.         total += pop[i].cost;
  218.     }
  219.     for (int i = 0; i < pop.size(); ++i)
  220.     {
  221.         calcFitness(pop[i], total);
  222.     }
  223. }
  224.  
  225. Data readData(const char* filename)
  226. {
  227.     Data data;
  228.     std::ifstream input(filename);
  229.     if (!input.is_open()) return data;
  230.     while (input.good())
  231.     {
  232.         City c;
  233.         std::string line;
  234.         std::getline(input, line);
  235.         if (line.size() == 0) continue;
  236.         std::vector<std::string> tokens = split(line);
  237.         if (tokens.size() != 3) continue;
  238.         int id = std::atoi(tokens[0].c_str());
  239.         double x = std::atof(tokens[1].c_str());
  240.         double y = std::atof(tokens[2].c_str());
  241.         c.id = id;
  242.         c.x = x;
  243.         c.y = y;
  244.         data.push_back(c);
  245.     }
  246.     return data;
  247. }
  248.  
  249. Distances calcDistances(const Data& data)
  250. {
  251.     Distances result;
  252.     for (auto src: data)
  253.     {
  254.         for (auto dst: data)
  255.         {
  256.             double d = distance(src, dst);
  257.             if (src.id == dst.id) d = std::numeric_limits<double>::max();
  258.             result[src.id][dst.id] = d;
  259.         }
  260.     }
  261.     return result;
  262. }
  263.  
  264. int main(int argc, const char * argv[])
  265. {
  266.     if (argc < 2)
  267.     {
  268.         std::cerr << "Usage: " << argv[0] << " <input file name>\n";
  269.         return 1;
  270.     }
  271.     Data data = readData(argv[1]);
  272.     if (data.size() == 0) return 0;
  273.     Distances dist = calcDistances(data);
  274.     Population pop = initialPopulation(dist, PopulationSize, data);
  275.     //printPop(pop);
  276.     for (int i = 0; i < Generations; ++i)
  277.     {
  278.         //std::cout << "Generation #" << i << "\n";
  279.         calculatePopFitness(pop);
  280.         int best = findBest(pop);
  281.         Population newPop;
  282.         Solution s = pop[best];
  283.         newPop.push_back(s);
  284.         for (int j = 1; j < pop.size(); ++j)
  285.         {
  286.             int s1 = pickOne(pop);
  287.             int s2 = pickOne(pop);
  288.             CrossSolution cs = crossover(pop[s1].cromossome, pop[s2].cromossome);
  289.             double cost1 = calcCost(cs.first, dist, data);
  290.             double cost2 = calcCost(cs.second, dist, data);
  291.             Cromossome best = cost1 < cost2 ? cs.first : cs.second;
  292.             double bestCost = cost1 < cost2 ? cost1 : cost2;
  293.             auto it = std::find_if(pop.begin(), pop.end(), [&](const Solution& s){
  294.                 return s.cost == bestCost;
  295.             });
  296.             if (it != pop.end())
  297.             {
  298.                 std::shuffle(best.begin(), best.end(), eng);
  299.                 if (!isValidSolution(best, data))
  300.                 {
  301.                     std::cerr << "Invalid solution.\n";
  302.                 }
  303.                 bestCost = calcCost(best, dist, data);
  304.             }
  305.             if (rndMinMax(0, 100) < MutationRate * 100.)
  306.             {
  307.                 mutation(best);
  308.                 if (!isValidSolution(best, data))
  309.                 {
  310.                     std::cerr << "Invalid solution.\n";
  311.                 }
  312.                 bestCost = calcCost(best, dist, data);
  313.             }
  314.             if (bestCost > pop[j].cost)
  315.             {
  316.                 newPop.push_back(pop[j]);
  317.             }
  318.             else
  319.             {
  320.                 Solution newSolution;
  321.                 newSolution.cromossome = best;
  322.                 newSolution.cost = bestCost;
  323.                 if (!isValidSolution(best, data))
  324.                 {
  325.                     std::cerr << "Invalid solution.\n";
  326.                 }
  327.                 newPop.push_back(newSolution);
  328.             }
  329.         }
  330.         pop = newPop;
  331.     }
  332.     calculatePopFitness(pop);
  333.     int bestSolution = findBest(pop);
  334.     if (!isValidSolution(pop[bestSolution].cromossome, data))
  335.     {
  336.         std::cerr << "Invalid solution.\n";
  337.     }
  338.     int counter = 0;
  339.     std::string result = "";
  340.     std::string outputFilename = std::string(argv[1]) + ".tour";
  341.     std::ofstream output(outputFilename.c_str(),  std::ofstream::out);
  342.     //output << pop[bestSolution].cost;
  343.     result += std::to_string(pop[bestSolution].cost) + "\n";
  344.     for (auto c: pop[bestSolution].cromossome)
  345.     {
  346.         //output << c << std::endl;
  347.         result += std::to_string(c) + "\n";
  348.         ++counter;
  349.     }
  350.     output << result;
  351.     output.close();
  352.     /*
  353.     std::cout << str(pop[bestSolution].cromossome)
  354.               << " = " << pop[bestSolution].cost
  355.               << " = " << pop[bestSolution].fitness
  356.               << "\n";
  357.     printPop(pop);
  358.     */
  359.     return 0;
  360. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement