froleyks

dynamic_connectivity.cpp

Dec 7th, 2018
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.29 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.         continue;
  98.       }
  99.  
  100.       // avoids deadlock, alternative is to use order of locks index
  101.       std::lock(locks[root_from], locks[root_to]);
  102.       // has changed in the mean time
  103.       while (union_find[root_to] != root_to ||
  104.              union_find[root_from] != root_from) {
  105.         // std::cout << i << " error: " << root_from << " " << root_to <<
  106.         // std::endl; release all
  107.         locks[root_from].unlock();
  108.         locks[root_to].unlock();
  109.         root_from = find_representative(root_from);
  110.         root_to = find_representative(root_to);
  111.         if (root_from == root_to) {
  112.           continue;
  113.         }
  114.         std::lock(locks[root_from], locks[root_to]);
  115.       }
  116.  
  117.       // union by rank
  118.       if (component_size[root_from] > component_size[root_to]) {
  119.         union_find[root_to] = root_from;
  120.         component_size[root_from] += component_size[root_to];
  121.       } else {
  122.         union_find[root_from] = root_to;
  123.         component_size[root_to] += component_size[root_from];
  124.       }
  125.       // union_find[root_from] = root_to;
  126.  
  127.       locks[root_from].unlock();
  128.       locks[root_to].unlock();
  129.  
  130.       local_edges.push_back(edges[i]);
  131.     }
  132.     // std::cout << "critical " << omp_get_thread_num() << std::endl;
  133. #pragma omp critical
  134.     {
  135.       for (auto [from, to, length] : local_edges) {
  136.         forest_edges.push_back({from, to, length});
  137.         forest_edges.push_back({to, from, length});
  138.       }
  139.     }
  140.   }
  141.  
  142.   // used as visited in BFS
  143. #pragma omp parallel for
  144.   for (int i = 0; i < num_nodes; ++i) {
  145.     parent[i] = -2;
  146.   }
  147.   SimpleAdjacencyArray<long> forest(num_nodes, forest_edges);
  148.  
  149.   if (roots.empty()) {
  150.     for (long i = 0; i < num_nodes; ++i) {
  151.       if (union_find[i] == i) {
  152.         roots.push_back(i);
  153.       }
  154.     }
  155.   } else {
  156.     roots.erase(
  157.         std::remove_if(roots.begin(), roots.end(),
  158.                        [this](Node root) { return union_find[root] != root; }),
  159.         roots.end());
  160.   }
  161. #pragma omp parallel for
  162.   for (int i = 0; i < roots.size(); ++i) {
  163.     parent[roots[i]] = -1;
  164.     BFS(roots[i], forest);
  165.   }
  166. }
  167.  
  168. bool DynamicConnectivity::connected(Node a, Node b) const {
  169.   return find_representative(a) == find_representative(b);
  170. }
  171.  
  172. DynamicConnectivity::Node DynamicConnectivity::parentOf(Node n) const {
  173.   return parent[n];
  174. }
  175.  
  176. size_t DynamicConnectivity::sizeOf(Node n) const {
  177.   return component_size[n];
  178. }
  179.  
  180. DynamicConnectivity::Node
  181. DynamicConnectivity::find_representative(Node a) const {
  182.   Node current = a;
  183.   Node parent = union_find[current];
  184.  
  185.   while (current != parent) {
  186.     current = parent;
  187.     parent = union_find[current];
  188.   }
  189.  
  190.   // path compression
  191.   Node representative = parent;
  192.   current = a;
  193.   parent = union_find[current];
  194.   while (current != parent) {
  195.     // may fail, I don't care
  196.     union_find[current].compare_exchange_weak(current, representative);
  197.     // union_find[current] = representative;
  198.     current = parent;
  199.     parent = union_find[current];
  200.   }
  201.  
  202.   return parent;
  203. }
Add Comment
Please, Sign In to add comment