Advertisement
froleyks

dynamic_connectivity.cpp

Dec 8th, 2018
185
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.36 KB | None | 0 0
  1. #include "dynamic_connectivity.hpp"
  2. #include <algorithm>
  3. #include <iomanip>
  4. #include <iostream>
  5. #include <omp.h>
  6.  
  7. DynamicConnectivity::DynamicConnectivity() {
  8. }
  9.  
  10. DynamicConnectivity::DynamicConnectivity(long num_nodes)
  11.     : num_nodes(num_nodes) {
  12.   union_find = new std::atomic<Node>[num_nodes];
  13.   for (int i = 0; i < num_nodes; ++i) {
  14.     union_find[i] = i;
  15.   }
  16.  
  17.   component_size = new std::atomic<uint>[num_nodes];
  18.   for (int i = 0; i < num_nodes; ++i) {
  19.     component_size[i] = 1;
  20.   }
  21.  
  22.   // both directions
  23.   forest_edges.reserve(2 * num_nodes);
  24.   parent = new Node[num_nodes];
  25.   for (int i = 0; i < num_nodes; ++i) {
  26.     parent[i] = -2;
  27.   }
  28.  
  29.   // locks.resize(num_nodes);
  30.   locks = new std::mutex[num_nodes];
  31. }
  32.  
  33. DynamicConnectivity::~DynamicConnectivity() {
  34.   delete[] union_find;
  35.   delete[] parent;
  36.   delete[] component_size;
  37.   delete[] locks;
  38. }
  39.  
  40. void DynamicConnectivity::printUF() {
  41.   for (int i = 0; i < 9; ++i) {
  42.     std::cout << i << ": " << union_find[i] << std::endl;
  43.   }
  44.   std::cout << std::endl;
  45. }
  46.  
  47. #define NOT_EMPTY head != queue.size()
  48.  
  49. #define PUSH(N, DIST) queue.push_back({N, DIST});
  50.  
  51. #define POP queue[head++]
  52.  
  53. struct QueueNode {
  54.   long id;
  55.   size_t distance;
  56. };
  57.  
  58. void DynamicConnectivity::BFS(const Node s,
  59.                               const SimpleAdjacencyArray<long> &graph) {
  60.   // std::vector<char> visited(num_nodes, false);
  61.   std::vector<QueueNode> queue;
  62.   size_t head = 0;
  63.   queue.reserve(num_nodes);
  64.   PUSH(s, 0)
  65.   while (NOT_EMPTY) {
  66.     QueueNode queueNode = POP;
  67.     SimpleAdjacencyArray<long>::NodeHandle currentHandle =
  68.         graph.node(queueNode.id);
  69.     for (auto nIt = graph.beginEdges(currentHandle);
  70.          nIt != graph.endEdges(currentHandle); ++nIt) {
  71.       long nID = graph.nodeId(graph.edgeHead(nIt));
  72.       if (parent[nID] == -1) {
  73.         parent[nID] = currentHandle;
  74.         PUSH(nID, queueNode.distance + 1);
  75.       }
  76.     }
  77.   }
  78. }
  79.  
  80. void DynamicConnectivity::addEdges(const EdgeList &edges) {
  81. #pragma omp parallel
  82.   {
  83.     EdgeList local_edges;
  84.     local_edges.reserve(edges.size() / omp_get_num_threads() + 1);
  85. #pragma omp for nowait
  86.     for (uint i = 0; i < edges.size(); ++i) {
  87.       // std::cout << std::setw(2) << edges[i].from << " | " << std::setw(2) <<
  88.       // edges[i].to
  89.       //           << std::endl;
  90.  
  91.       // find bigger component
  92.       Node root_from = find_representative(edges[i].from);
  93.       Node root_to = find_representative(edges[i].to);
  94.  
  95.       // same component
  96.       if (root_from == root_to) {
  97.       i_cant_belive_i_am_using_goto:
  98.         continue;
  99.       }
  100.  
  101.       // avoids deadlock, alternative is to use order of locks index
  102.       std::lock(locks[root_from], locks[root_to]);
  103.       // has changed in the mean time
  104.       while (union_find[root_to] != root_to ||
  105.              union_find[root_from] != root_from) {
  106.         // std::cout << i << " error: " << root_from << " " << root_to <<
  107.         // std::endl; release all
  108.         locks[root_from].unlock();
  109.         locks[root_to].unlock();
  110.         root_from = find_representative(root_from);
  111.         root_to = find_representative(root_to);
  112.         if (root_from == root_to) {
  113.           goto i_cant_belive_i_am_using_goto;
  114.         }
  115.         std::lock(locks[root_from], locks[root_to]);
  116.       }
  117.  
  118.       // union by rank
  119.       if (component_size[root_from] > component_size[root_to]) {
  120.         union_find[root_to] = root_from;
  121.         component_size[root_from] += component_size[root_to];
  122.       } else {
  123.         union_find[root_from] = root_to;
  124.         component_size[root_to] += component_size[root_from];
  125.       }
  126.       // union_find[root_from] = root_to;
  127.  
  128.       locks[root_from].unlock();
  129.       locks[root_to].unlock();
  130.  
  131.       local_edges.push_back(edges[i]);
  132.     }
  133.     // std::cout << "critical " << omp_get_thread_num() << std::endl;
  134. #pragma omp critical
  135.     {
  136.       for (auto [from, to, length] : local_edges) {
  137.         forest_edges.push_back({from, to, length});
  138.         forest_edges.push_back({to, from, length});
  139.       }
  140.     }
  141.   }
  142.  
  143.   // used as visited in BFS
  144. #pragma omp parallel for
  145.   for (int i = 0; i < num_nodes; ++i) {
  146.     parent[i] = -2;
  147.   }
  148.   SimpleAdjacencyArray<long> forest(num_nodes, forest_edges);
  149.  
  150.   if (roots.empty()) {
  151.     for (long i = 0; i < num_nodes; ++i) {
  152.       if (union_find[i] == i) {
  153.         roots.push_back(i);
  154.       }
  155.     }
  156.   } else {
  157.     roots.erase(
  158.         std::remove_if(roots.begin(), roots.end(),
  159.                        [this](Node root) { return union_find[root] != root; }),
  160.         roots.end());
  161.   }
  162. #pragma omp parallel for
  163.   for (int i = 0; i < roots.size(); ++i) {
  164.     parent[roots[i]] = -1;
  165.     BFS(roots[i], forest);
  166.   }
  167. }
  168.  
  169. bool DynamicConnectivity::connected(Node a, Node b) const {
  170.   return find_representative(a) == find_representative(b);
  171. }
  172.  
  173. DynamicConnectivity::Node DynamicConnectivity::parentOf(Node n) const {
  174.   return parent[n];
  175. }
  176.  
  177. size_t DynamicConnectivity::sizeOf(Node n) const {
  178.   return component_size[n];
  179. }
  180.  
  181. DynamicConnectivity::Node
  182. DynamicConnectivity::find_representative(Node a) const {
  183.   Node current = a;
  184.   Node parent = union_find[current];
  185.  
  186.   while (current != parent) {
  187.     current = parent;
  188.     parent = union_find[current];
  189.   }
  190.  
  191.   // path compression
  192.   Node representative = parent;
  193.   current = a;
  194.   parent = union_find[current];
  195.   while (current != parent) {
  196.     // may fail, I don't care
  197.     union_find[current].compare_exchange_weak(current, representative);
  198.     // union_find[current] = representative;
  199.     current = parent;
  200.     parent = union_find[current];
  201.   }
  202.  
  203.   return parent;
  204. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement