Advertisement
mamamaria

BoltzmannTravellingSalesman

Nov 4th, 2021
940
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.45 KB | None | 0 0
  1. // TravellingSalesmanBoltzman.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
  2. //
  3.  
  4. #include <iostream>
  5. #include <vector>
  6. #include <ctime>
  7. #include <random>
  8. #include <cmath>
  9.  
  10. const int N = 20;
  11. using namespace std;
  12. default_random_engine eng;
  13.  
  14. using Graph = vector<vector<double>>;
  15. using NN = vector<double>;//сеть с нейронами, где нейрон - это double
  16. using Weights = vector<vector<double>>;
  17. using Ways = vector<int>;
  18.  
  19. void GraphPrinter(Graph graph) {
  20.     for (int i = 0; i < graph.size(); i++) {
  21.         for (int j = 0; j < graph.size(); j++)
  22.             cout << graph[i][j] << " ";
  23.         cout << endl;
  24.     }
  25. }
  26. void WaysPrinter(Ways ways) {
  27.     for (int i = 0; i < ways.size(); i++)
  28.         cout << ways[i] << " ";
  29.     cout << endl;
  30. }
  31.  
  32. void NNPrinter(NN nn) {
  33.     for (int i = 0; i < N; i++) {
  34.         for (int j = 0; j < N; j++)
  35.             cout << round(nn[i * N + j]) << " ";
  36.         cout << endl;
  37.     }
  38. }
  39. Graph GraphGenerator() {
  40.     Graph graph(N);
  41.     for (int i = 0; i < graph.size(); i++) {
  42.         graph[i].resize(N);
  43.     }
  44.     uniform_real_distribution<double> distr(1, 10);
  45.     for (int i = 0; i < graph.size(); i++) {
  46.         for (int j = 0; j < i; j++) {
  47.             if (i == j) {
  48.                 graph[i][j] = 0;
  49.                 graph[j][i] = 0;
  50.                 continue;
  51.             }
  52.             double dist = distr(eng);
  53.             graph[i][j] = dist;
  54.             graph[j][i] = graph[i][j];
  55.         }
  56.     }
  57.     return graph;
  58. }
  59.  
  60. /*Weights WeightsCalculator(Graph graph, double A = 20, double B = 20, double C = 10, double D = 0.14) {*/
  61. Weights WeightsCalculator(Graph graph, double A, double B, double C, double D) {
  62.     Weights weights(N * N);
  63.     for (int i = 0; i < weights.size(); i++) {
  64.         weights[i].resize(N * N);
  65.     }
  66.     for (int index = 0; index < N * N; index++) {
  67.         int x = index / N;
  68.         int i = index % N;
  69.         for (int endex = 0; endex < N * N; endex++) {
  70.             int y = endex / N;
  71.             int j = endex % N;
  72.             double w = 0;
  73.             if (x == y && i != j)
  74.                 w -= A;
  75.             if (x != y && i == j)
  76.                 w -= B;
  77.             w -= C;
  78.             if (j == i + 1 || j == i - 1)
  79.                 w -= (D * graph[x][y]);
  80.             if ((j == 0 && i == N - 1) || (j == N - 1 && i == 0))
  81.                 w -= (D * graph[x][y]);
  82.             if (index == endex) w = 0;
  83.             weights[index][endex] = w;
  84.         }
  85.     }
  86.     return weights;
  87. }
  88.  
  89. void NeuronUpdater(NN& nn, Weights weights, double C, int j, double t) {
  90.     double NET = 0;
  91.     for (int i = 0; i < nn.size(); i++)
  92.         NET += weights[i][j] * nn[i];
  93.     double w_0_j = C * (N - 0.5);
  94.     NET += w_0_j;
  95.     double u_0 = 1;
  96.     /*if (NET > 0)
  97.         nn[j] = 1;
  98.     if (NET < 0)
  99.         nn[j] = 0;*/
  100.  
  101.         /*nn[j] = 0.5 * (1 + tanh(NET / u_0));*/
  102.     double p = 1 / (1 + exp(-NET / t));
  103.     if (rand() < p * RAND_MAX)
  104.         nn[j] = 1;
  105.     else
  106.         nn[j] = 0;
  107. }
  108.  
  109. double EnegryChecker(NN nn, Weights weights, double C) {
  110.     double E = 0;
  111.     double w_0_j = C * (N - 0.5);
  112.     for (int i = 0; i < nn.size(); i++)
  113.         for (int j = 0; j < nn.size(); j++)
  114.             E += weights[i][j] * nn[i] * nn[j];
  115.     E *= -0.5;
  116.  
  117.     for (int j = 0; j < nn.size(); j++)
  118.         E -= (w_0_j * nn[j]);
  119.     return E;
  120. }
  121.  
  122. bool OkayNNChecker(NN nn, Ways& ways) {
  123.     ways.resize(N);
  124.     int counter1 = 0, counter2 = 0;
  125.     for (int i = 0; i < N; i++) {
  126.         int counter1 = 0;
  127.         for (int j = 0; j < N; j++) {
  128.             int index = i * N + j;
  129.             if (nn[index] >= 0.5) {
  130.                 counter1++;
  131.                 ways[j] = i;
  132.             }
  133.         }
  134.         counter2 = 0;
  135.         for (int k = 0; k < N; k++) {
  136.             if (nn[i + k * N] >= 0.5)
  137.                 counter2++;
  138.         }
  139.         if (counter1 != 1 || counter2 != 1) return false;
  140.     }
  141.     return true;
  142. }
  143. double LengthCounter(Ways ways, Graph graph) {
  144.     double length = 0;
  145.     for (int i = 0; i < N - 1; i++)
  146.         length += graph[ways[i]][ways[i + 1]];
  147.     length += graph[ways[0]][ways[N - 1]];
  148.     return length;
  149.  
  150. }
  151. void NNFilling(NN& nn) {
  152.     for (int i = 0; i < N; i++)
  153.         nn[i] = rand() % 2;
  154. }
  155. //нужно сделать чтобы в каждом городе ровно 1 единица матрицы nn и в кадждый момент времени был только один город
  156. // найти длину пути
  157. bool NarayanaPermutation(Ways& ways) {
  158.  
  159.     int index = -1;
  160.     for (int i = (N - 2); i >= 0; i--) {
  161.         if (ways[i] < ways[i + 1]) {
  162.             index = i;
  163.             break;
  164.         }
  165.     }
  166.     if (index == -1)
  167.         return false;
  168.     for (int j = (N - 1); j > index; j--) {
  169.         if (ways[index] < ways[j]) {
  170.             swap(ways[index], ways[j]);
  171.             break;
  172.         }
  173.     }
  174.     reverse(ways.begin() + (index + 1), ways.end());
  175.     return true;
  176. }
  177.  
  178. Ways OrdinaryTravelingSalesman(Graph graph) {
  179.     Ways ways(N); Ways minimalWays(N);
  180.     for (int i = 0; i < N; i++)
  181.         ways[i] = i;
  182.     double min = INFINITY;
  183.     while (true) {
  184.         double newMinimum = LengthCounter(ways, graph);
  185.         if (newMinimum < min) {
  186.             min = newMinimum;
  187.             minimalWays = ways;
  188.         }
  189.         if (!NarayanaPermutation(ways)) break;
  190.     }
  191.     return minimalWays;
  192. }
  193. Ways WorstOrdinaryTravelingSalesman(Graph graph) {
  194.     Ways ways(N); Ways maximumWays(N);
  195.     for (int i = 0; i < N; i++)
  196.         ways[i] = i;
  197.     double max = -INFINITY;
  198.     while (true) {
  199.         double newMinimum = LengthCounter(ways, graph);
  200.         if (newMinimum > max) {
  201.             max = newMinimum;
  202.             maximumWays = ways;
  203.         }
  204.         if (!NarayanaPermutation(ways)) break;
  205.     }
  206.     return maximumWays;
  207. }
  208. int main()
  209. {
  210.  
  211.     Graph graph = GraphGenerator();
  212.     srand(time(0));
  213.     GraphPrinter(graph);
  214.     cout << endl;
  215.     Weights weights1 = WeightsCalculator(graph, 20, 20, 10, 0.14);
  216.     Weights weights2 = WeightsCalculator(graph, 5, 5, 5, 0.5);
  217.     Ways ways(N, 0);
  218.     //Ways ordindaryWays = OrdinaryTravelingSalesman(graph);
  219.     //WaysPrinter(ordindaryWays);
  220.     //cout << LengthCounter(ordindaryWays, graph) << endl;
  221.     //Ways WorstordindaryWays = WorstOrdinaryTravelingSalesman(graph);
  222.     //WaysPrinter(WorstordindaryWays);
  223.     //cout << LengthCounter(WorstordindaryWays, graph) << endl;
  224.  
  225.     double sum = 0;
  226.     double best = INFINITY;
  227.     int TESTS = 20;
  228.     for (int test = 0; test < TESTS; test++) {
  229.         cout << "test: " << test << endl;
  230.         NN nn(N * N);
  231.         NNFilling(nn);
  232.         double t = 10*N;
  233.         double difference = t / (40.0 * N * N);
  234.         for (int i = 0; i < 40; i++) {
  235.             t = 0.85 * t + 0.003;
  236.             /*for (int j = 0; j < N * N; j++) {
  237.                 NeuronUpdater(nn, weights2, 5, rand() % (N * N),t);
  238.                 t *= 0.9999;
  239.             }*/
  240.             /*for (int j = 0; j < N * N; j++) {
  241.                 NeuronUpdater(nn, weights2, 5, j, t);
  242.                 t *= 0.9999;
  243.             }*/
  244.  
  245.             for (int j = 0; j < N * N; j++) {
  246.                 NeuronUpdater(nn, weights1, 10, rand() % (N * N), t);
  247.                
  248.             }
  249.             for (int j = 0; j < N * N; j++) {
  250.                 NeuronUpdater(nn, weights1, 10, j, t);
  251.                
  252.             }
  253.             double E = EnegryChecker(nn, weights1, 10);
  254.  
  255.             //if (i % 200 == 0) {
  256.             ways.clear();
  257.             bool NNCheck = OkayNNChecker(nn, ways);
  258.             if (NNCheck) {
  259.                 cout << "Count 1 in NN: " << NNCheck << endl;
  260.                 WaysPrinter(ways);
  261.                 cout << LengthCounter(ways, graph) << endl;
  262.                 cout << endl;
  263.  
  264.             }
  265.             else
  266.                 cout << "Fail\n";
  267.             //NNPrinter(nn);
  268.             cout << endl;
  269.             cout << "Temperature: " << t << endl;
  270.             cout << "E: " << E << endl;
  271.             //}
  272.  
  273.             if (i == 39 && NNCheck) {
  274.                 double l = LengthCounter(ways, graph);
  275.                 sum += l;
  276.                 if (l < best) best = l;
  277.             }
  278.         }
  279.     }
  280.    
  281.     cout << "Best: " << best << " -- Average: " << sum / TESTS << endl;
  282. }
  283.  
  284. //написать обычного полного переборного коммивояжера
  285. // энергия при гиперболическом тангенсе не монотонно уменьшается, испытывает скачки, при этом результат, который некронйка считает верным, не имеет минимальную энергию
  286. //Хопфилд через диффуры
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement