Advertisement
Guest User

Untitled

a guest
Dec 15th, 2019
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.93 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <algo/ISolution.h>
  4. #include <lib/Timer.h>
  5. #include <lib/ThreadPool.h>
  6.  
  7. #include <vector>
  8. #include <numeric>
  9. #include <random>
  10. #include <set>
  11. #include <iostream>
  12.  
  13. namespace NAlgo {
  14.     enum class ESelectType : int {
  15.         Tournament,
  16.         RouletteMethod,
  17.         Ranking,
  18.         UniformRanking,
  19.         SigmaClipping
  20.     };
  21.  
  22.     enum class EParentSelectType : int {
  23.         Inbreeding,
  24.         Outbreeding,
  25.         Nothing
  26.     };
  27.  
  28.     struct GAHyperOpt {
  29.         int population_size = 100;
  30.         EParentSelectType parent_select_type = EParentSelectType::Nothing;
  31.         ESelectType select_type = ESelectType::Tournament;
  32.         double proportion_of_crossover = 0.3;
  33.         double proportion_of_mutation = 0.04;
  34.         struct RankingOpt {
  35.             double a = 1.5;
  36.             double b = 2 - a;
  37.         } ranking_opt;
  38.     };
  39.  
  40.     class GeneticAlgorithm : public ISolution {
  41.     public:
  42.         using Path = std::vector<int>;
  43.  
  44.         explicit GeneticAlgorithm(int version, SolutionConfig config, const GAHyperOpt& hyper_opt = {})
  45.             : ISolution(version, std::move(config))
  46.             , gen(0)
  47.             , hyper_opt(hyper_opt)
  48.         {}
  49.  
  50.         std::pair<Path, Path> genetic_epoch(const Test& test) {
  51.             auto p1 = select(hyper_opt.select_type, test, test.GetVertexNum());
  52.             auto p2 = hyper_opt.parent_select_type == EParentSelectType::Nothing
  53.                       ? select(hyper_opt.select_type, test, test.GetVertexNum())
  54.                       : choose_parent(hyper_opt.parent_select_type, p1);
  55.  
  56.             bool do_crossover = get_random_double() <= hyper_opt.proportion_of_crossover;
  57.             bool do_mutate_1 = get_random_double() <= hyper_opt.proportion_of_mutation;
  58.             bool do_mutate_2 = get_random_double() <= hyper_opt.proportion_of_mutation;
  59.  
  60.             if (do_crossover) {
  61.                 auto c1 = cross(p1, p2);
  62.                 auto c2 = cross(p2, p1);
  63.                 p1 = c1;
  64.                 p2 = c2;
  65.             }
  66.  
  67.             if (do_mutate_1) {
  68.                 mutate(p1, test.GetVertexNum());
  69.             }
  70.             if (do_mutate_2) {
  71.                 mutate(p2, test.GetVertexNum());
  72.             }
  73.  
  74.             return {p1, p2};
  75.         }
  76.  
  77.         Tour solve(const Test& test) override {
  78.             Tour tour(test);
  79.  
  80.             current_population = initialize(hyper_opt.population_size, test.GetVertexNum());
  81.  
  82.             ThreadPool pool(config.thread_count);
  83.             timer.Reset();
  84.  
  85.             int iter = 0;
  86.             std::vector<std::pair<int, int>> conv;
  87.             while (timer.Passed() < config.deadline) {
  88.                 std::vector<Path> new_population;
  89.  
  90.                 if (config.thread_count != 1) {
  91.                     size_t pool_size = current_population.size() / 2;
  92.                     std::vector<std::future<std::pair<Path, Path>>> results;
  93.  
  94.                     for(size_t i = 0; i < pool_size; i++) {
  95.                         results.emplace_back(
  96.                             pool.enqueue([this, &test](){
  97.                                 auto [p1, p2] = genetic_epoch(test);
  98.                                 return std::make_pair(p1, p2);
  99.                             })
  100.                         );
  101.                     }
  102.  
  103.                     for(auto && result: results) {
  104.                         auto [p1, p2] = result.get();
  105.                         new_population.push_back(p1);
  106.                         new_population.push_back(p2);
  107.                     }
  108.                 } else {
  109.                     while ((int) new_population.size() + 1 < (int) current_population.size()) {
  110.                         auto [p1, p2] = genetic_epoch(test);
  111.  
  112.                         new_population.push_back(std::move(p1));
  113.                         new_population.push_back(std::move(p2));
  114.                     }
  115.                 }
  116.                 current_population = std::vector<Path>(new_population.begin(), new_population.end());
  117.  
  118.                 if (iter % 1000 == 0 && config.save_method_convergence) {
  119.                     int64_t best_weight = LONG_LONG_MAX;
  120.  
  121.                     Tour candidate(test), best(test);
  122.                     for (size_t i = 0; i < current_population.size(); i++) {
  123.                         candidate.path = current_population[i];
  124.                         candidate.CalcTotalWeight();
  125.                         if (candidate.TotalWeight() < tour.TotalWeight()) {
  126.                             best = candidate;
  127.                         }
  128.                     }
  129.                     best.CalcTotalWeight();
  130.                     conv.emplace_back(iter, best.TotalWeight());
  131.                 }
  132.             }
  133.  
  134.             std::vector<int64_t> all_weights;
  135.             Tour candidate(test);
  136.             for (size_t i = 0; i < current_population.size(); i++) {
  137.                 candidate.path = current_population[i];
  138.                 candidate.CalcTotalWeight();
  139.                 all_weights.push_back(candidate.TotalWeight());
  140.                 if (candidate.TotalWeight() < tour.TotalWeight()) {
  141.                     tour = candidate;
  142.                 }
  143.             }
  144.             tour.CalcTotalWeight();
  145.             assert(tour.TotalWeight() != LONG_LONG_MAX);
  146.             return tour;
  147.         }
  148.  
  149.         std::string solution_name() const override  {
  150.             return "GeneticAlgorithm";
  151.         }
  152.  
  153.  
  154.     private:
  155.         std::vector<Path> current_population;
  156.  
  157.         GAHyperOpt hyper_opt;
  158.  
  159.         std::mt19937 gen;
  160.         Timer timer;
  161.  
  162.         std::vector<Path> initialize(int count, int vertex_num) {
  163.             std::vector<Path> population;
  164.             population.resize(count);
  165.  
  166.             Path default_path(vertex_num);
  167.             std::iota(default_path.begin(), default_path.end(), 0);
  168.  
  169.             for (int i = 0; i < count; i++) {
  170.                 population[i] = default_path;
  171.                 std::shuffle(population[i].begin() + 1, population[i].end(), gen);
  172.             }
  173.             return population;
  174.         }
  175.  
  176.         Path select(ESelectType select_type, const Test& test, int vertex_num) {
  177.             if (select_type == ESelectType::Tournament) {
  178.                 int i = gen() % (int)current_population.size();
  179.                 int j = gen() % (int)current_population.size();
  180.  
  181.                 Tour tour_i(test), tour_j(test);
  182.  
  183.                 for (int k = 0; k < vertex_num; k++) {
  184.                     tour_i.path.push_back(current_population[i][k]);
  185.                     tour_j.path.push_back(current_population[j][k]);
  186.                 }
  187.  
  188.                 tour_i.CalcTotalWeight();
  189.                 tour_j.CalcTotalWeight();
  190.  
  191.                 if (tour_i.TotalWeight() > tour_j.TotalWeight()) {
  192.                     return current_population[j];
  193.                 } else {
  194.                     return current_population[i];
  195.                 }
  196.             } else if (select_type == ESelectType::RouletteMethod || select_type == ESelectType::Ranking) {
  197.                 int64_t total_weight_for_all = 0;
  198.                 std::vector<int64_t> total_weights;
  199.                 Tour tour(test);
  200.  
  201.                 for (const auto& ind : current_population) {
  202.                     tour.path = ind;
  203.                     tour.CalcTotalWeight();
  204.                     total_weights.push_back(tour.TotalWeight());
  205.                     total_weight_for_all += total_weights.back();
  206.                 }
  207.  
  208.                 auto mn_weight = *std::min_element(total_weights.begin(), total_weights.end());
  209.                 auto mx_weight = *std::max_element(total_weights.begin(), total_weights.end());
  210.                 std::vector<long double> probs;
  211.                 for (size_t i = 0; i < current_population.size(); i++) {
  212.                     probs.emplace_back(std::log(1. * (total_weights[i] - mn_weight + 1) / (mx_weight - mn_weight + 1)));
  213.                 }
  214.  
  215.                 auto log_sum = std::accumulate(probs.begin(), probs.end(), (long double)0);
  216.                 for (size_t i = 0; i < current_population.size(); i++) {
  217.                     if (mn_weight == mx_weight) {
  218.                         probs[i] = (long double)1 / current_population.size();
  219.                     } else {
  220.                         probs[i] = probs[i] / log_sum;
  221.                     }
  222.                 }
  223.  
  224.                 if (select_type == ESelectType::Ranking) {
  225.                     std::vector<int> index;
  226.                     index.resize(current_population.size());
  227.                     std::iota(index.begin(), index.end(), 0);
  228.  
  229.                     std::sort(index.begin(), index.end(), [&probs](int i, int j) {
  230.                         return probs[i] < probs[j];
  231.                     });
  232.  
  233.                     std::vector<int> order(current_population.size());
  234.                     for (size_t i = 0; i < current_population.size(); i++) {
  235.                         order[index[i]] = i;
  236.                     }
  237.  
  238.                     for (size_t i = 0; i < current_population.size(); i++) {
  239.                         probs[i] = 1. / current_population.size() * (hyper_opt.ranking_opt.a -
  240.                                 (hyper_opt.ranking_opt.a - hyper_opt.ranking_opt.b) * order[i] / (1. * current_population.size() - 1));
  241.                     }
  242.                 }
  243.  
  244.                 auto rnd = get_random_double();
  245.                 double sum = 0;
  246.                 int to_select = -1;
  247.                 for (size_t i = 0; i < current_population.size(); i++) {
  248.                     double prob = probs[i];
  249.                     sum += prob;
  250.  
  251.                     if (rnd < sum + 1e-9) {
  252.                         to_select = i;
  253.                         break;
  254.                     }
  255.                 }
  256.  
  257.                 assert(to_select != -1);
  258.                 return current_population[to_select];
  259.             } else if (select_type == ESelectType::UniformRanking) {
  260.  
  261.             } else if (select_type == ESelectType::SigmaClipping) {
  262.  
  263.             }
  264.  
  265.             return {};
  266.         }
  267.  
  268.         Path choose_parent(EParentSelectType select_type, const Path& p1) {
  269.             if (select_type == EParentSelectType::Inbreeding || select_type == EParentSelectType::Outbreeding) {
  270.                 int par2 = 0;
  271.                 int best_count = select_type == EParentSelectType::Inbreeding ? -1 : INT_MAX;
  272.  
  273.                 for (size_t i = 0; i < current_population.size(); i++) {
  274.                     if (current_population[i] != p1) {
  275.                         int count = 0;
  276.                         for (size_t j = 0; j < current_population.size(); j++) {
  277.                             count += p1[j] == current_population[i][j];
  278.                         }
  279.                         if (
  280.                             (select_type == EParentSelectType::Inbreeding && count > best_count) ||
  281.                             (select_type == EParentSelectType::Outbreeding && count < best_count)
  282.                         ){
  283.                             best_count = count;
  284.                             par2 = i;
  285.                         }
  286.                     }
  287.                 }
  288.                 return current_population[par2];
  289.             }
  290.  
  291.             return {};
  292.         }
  293.  
  294.         Path cross(const Path& first_parent, const Path& second_parent) {
  295.             std::vector<char> used(first_parent.size(), 0);
  296.  
  297.             auto gen_bitmask = [this](int n) {
  298.                 std::vector<char> res(n);
  299.                 for (int i = 0; i < n; i++) {
  300.                     res[i] = gen() % 2;
  301.                 }
  302.                 return res;
  303.             };
  304.  
  305.             auto bitmask = gen_bitmask(first_parent.size());
  306.  
  307.             Path child(first_parent.size(), -1);
  308.             int tf1 = 0, tf2 = 0, tf3 = 0;
  309.  
  310.             for (size_t i = 0; i < first_parent.size(); i++) {
  311.                 if (bitmask[i]) {
  312.                     used[first_parent[i]] = 1;
  313.                     child[i] = first_parent[i];
  314.                 }
  315.             }
  316.  
  317.             for (size_t i = 0; i < second_parent.size(); i++) {
  318.                 if (child[i] == -1 && !used[second_parent[i]]) {
  319.                     used[second_parent[i]] = 1;
  320.                     child[i] = second_parent[i];
  321.                 }
  322.             }
  323.  
  324.             Path rest;
  325.             for (size_t i = 0; i < first_parent.size(); i++) {
  326.                 if (!used[first_parent[i]]) {
  327.                     rest.push_back(first_parent[i]);
  328.                 }
  329.             }
  330.  
  331.             for (size_t i = 0, j = 0; i < first_parent.size(); i++) {
  332.                 if (child[i] == -1) {
  333.                     child[i] = rest[j++];
  334.                 }
  335.             }
  336.  
  337.             return child;
  338.         }
  339.  
  340.         void mutate(Path& p, int vertex_num) {
  341.             int l = gen() % vertex_num;
  342.             int r = gen() % vertex_num;
  343.  
  344.             if (r < l) {
  345.                 std::swap(l, r);
  346.             }
  347.  
  348.             if (l == 0) {
  349.                 return;
  350.             }
  351.  
  352.             std::reverse(p.begin() + l, p.begin() + r + 1);
  353.         }
  354.  
  355.         double get_random_double() {
  356.             return 1. * gen() / UINT32_MAX;
  357.         }
  358.     };
  359. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement