LCOV - code coverage report
Current view: top level - modules/disct - graphs.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 4 411 1.0 %
Date: 2024-05-13 05:06:06 Functions: 1 34 2.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*************************************************************************
       2             :  *
       3             :  *  Project
       4             :  *                         _____ _____  __  __ _____
       5             :  *                        / ____|  __ \|  \/  |  __ \
       6             :  *  ___  _ __   ___ _ __ | |  __| |__) | \  / | |__) |
       7             :  * / _ \| '_ \ / _ \ '_ \| | |_ |  ___/| |\/| |  ___/
       8             :  *| (_) | |_) |  __/ | | | |__| | |    | |  | | |
       9             :  * \___/| .__/ \___|_| |_|\_____|_|    |_|  |_|_|
      10             :  *      | |
      11             :  *      |_|
      12             :  *
      13             :  * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al.
      14             :  *
      15             :  * This software is licensed as described in the file LICENSE, which
      16             :  * you should have received as part of this distribution. The terms
      17             :  * among other details are referenced in the official documentation
      18             :  * seen here : https://akielaries.github.io/openGPMP/ along with
      19             :  * important files seen in this project.
      20             :  *
      21             :  * You may opt to use, copy, modify, merge, publish, distribute
      22             :  * and/or sell copies of the Software, and permit persons to whom
      23             :  * the Software is furnished to do so, under the terms of the
      24             :  * LICENSE file.
      25             :  *
      26             :  *
      27             :  *
      28             :  * This software is distributed on an AS IS basis, WITHOUT
      29             :  * WARRANTY OF ANY KIND, either express or implied.
      30             :  *
      31             :  ************************************************************************/
      32             : #include <algorithm>
      33             : #include <bitset>
      34             : #include <cmath>
      35             : #include <cstdint>
      36             : #include <iostream>
      37             : #include <limits>
      38             : #include <openGPMP/disct/graphs.hpp>
      39             : #include <queue>
      40             : #include <set>
      41             : #include <stack>
      42             : #include <vector>
      43             : 
      44           3 : void gpmp::Graph::add_edge(int v, int w, int weight) {
      45           3 :     adj_list[v].emplace_back(w, weight);
      46           3 :     adj_list[w].emplace_back(v, weight); // uncomment for undirected graph
      47           3 : }
      48             : 
      49           0 : void gpmp::Graph::dfs(int start) {
      50           0 :     std::vector<bool> visited(vertices, false);
      51           0 :     dfs_rec(start, visited);
      52           0 : }
      53             : 
      54           0 : void gpmp::Graph::dfs_rec(int v, std::vector<bool> &visited) {
      55           0 :     visited[v] = true;
      56           0 :     std::cout << v << " ";
      57             : 
      58           0 :     for (const auto &neighbor : adj_list[v]) {
      59           0 :         if (!visited[neighbor.first]) {
      60           0 :             dfs_rec(neighbor.first, visited);
      61             :         }
      62             :     }
      63           0 : }
      64             : 
      65           0 : void gpmp::Graph::bfs(int start) {
      66           0 :     std::vector<bool> visited(vertices, false);
      67           0 :     std::queue<int> bfs_queue;
      68             : 
      69           0 :     visited[start] = true;
      70           0 :     bfs_queue.push(start);
      71             : 
      72           0 :     while (!bfs_queue.empty()) {
      73           0 :         int v = bfs_queue.front();
      74           0 :         bfs_queue.pop();
      75           0 :         std::cout << v << " ";
      76             : 
      77           0 :         for (const auto &neighbor : adj_list[v]) {
      78           0 :             if (!visited[neighbor.first]) {
      79           0 :                 visited[neighbor.first] = true;
      80           0 :                 bfs_queue.push(neighbor.first);
      81             :             }
      82             :         }
      83             :     }
      84           0 : }
      85             : 
      86           0 : void gpmp::Graph::dijkstra(int start) {
      87             :     std::priority_queue<std::pair<int, int>,
      88             :                         std::vector<std::pair<int, int>>,
      89             :                         std::greater<std::pair<int, int>>>
      90           0 :         pq;
      91           0 :     std::vector<int> dist(vertices, std::numeric_limits<int>::max());
      92             : 
      93           0 :     dist[start] = 0;
      94           0 :     pq.push({0, start});
      95             : 
      96           0 :     while (!pq.empty()) {
      97           0 :         int u = pq.top().second;
      98           0 :         pq.pop();
      99             : 
     100           0 :         for (const auto &neighbor : adj_list[u]) {
     101           0 :             int v = neighbor.first;
     102           0 :             int weight = neighbor.second;
     103             : 
     104           0 :             if (dist[u] + weight < dist[v]) {
     105           0 :                 dist[v] = dist[u] + weight;
     106           0 :                 pq.push({dist[v], v});
     107             :             }
     108             :         }
     109             :     }
     110             : 
     111           0 :     std::cout << "Dijkstra's Shortest Paths from vertex " << start << ":\n";
     112           0 :     for (int i = 0; i < vertices; ++i)
     113           0 :         std::cout << "Vertex " << i << ": " << dist[i] << "\n";
     114           0 : }
     115             : 
     116           0 : void gpmp::Graph::bellman_ford(int start) {
     117           0 :     std::vector<int> dist(vertices, std::numeric_limits<int>::max());
     118           0 :     dist[start] = 0;
     119             : 
     120           0 :     for (int i = 0; i < vertices - 1; ++i) {
     121           0 :         for (int u = 0; u < vertices; ++u) {
     122           0 :             for (const auto &neighbor : adj_list[u]) {
     123           0 :                 int v = neighbor.first;
     124           0 :                 int weight = neighbor.second;
     125             : 
     126           0 :                 if (dist[u] != std::numeric_limits<int>::max() &&
     127           0 :                     dist[u] + weight < dist[v]) {
     128           0 :                     dist[v] = dist[u] + weight;
     129             :                 }
     130             :             }
     131             :         }
     132             :     }
     133             : 
     134           0 :     std::cout << "Bellman-Ford Shortest Paths from vertex " << start << ":\n";
     135           0 :     for (int i = 0; i < vertices; ++i)
     136           0 :         std::cout << "Vertex " << i << ": " << dist[i] << "\n";
     137           0 : }
     138             : 
     139           0 : std::vector<std::pair<int, std::pair<int, int>>> gpmp::Graph::kruskal() {
     140           0 :     std::vector<std::pair<int, std::pair<int, int>>> edges;
     141           0 :     for (int u = 0; u < vertices; ++u) {
     142           0 :         for (const auto &neighbor : adj_list[u]) {
     143           0 :             int v = neighbor.first;
     144           0 :             int weight = neighbor.second;
     145           0 :             edges.emplace_back(weight, std::make_pair(u, v));
     146             :         }
     147             :     }
     148             : 
     149           0 :     std::sort(edges.begin(), edges.end());
     150             : 
     151           0 :     std::vector<std::pair<int, std::pair<int, int>>> min_span_tree;
     152           0 :     std::vector<int> parent(vertices, -1);
     153             : 
     154           0 :     for (const auto &edge : edges) {
     155           0 :         int u = edge.second.first;
     156           0 :         int v = edge.second.second;
     157             : 
     158           0 :         int setU = find(parent, u);
     159           0 :         int setV = find(parent, v);
     160             : 
     161           0 :         if (setU != setV) {
     162           0 :             min_span_tree.push_back(edge);
     163           0 :             union_sets(parent, setU, setV);
     164             :         }
     165             :     }
     166             : 
     167           0 :     return min_span_tree;
     168           0 : }
     169             : 
     170           0 : void gpmp::Graph::floyd_warshall() {
     171             :     std::vector<std::vector<int>> dist(
     172           0 :         vertices,
     173           0 :         std::vector<int>(vertices, std::numeric_limits<int>::max()));
     174             : 
     175           0 :     for (int i = 0; i < vertices; ++i) {
     176           0 :         dist[i][i] = 0;
     177           0 :         for (const auto &neighbor : adj_list[i]) {
     178           0 :             int v = neighbor.first;
     179           0 :             int weight = neighbor.second;
     180           0 :             dist[i][v] = weight;
     181             :         }
     182             :     }
     183             : 
     184           0 :     for (int k = 0; k < vertices; ++k) {
     185           0 :         for (int i = 0; i < vertices; ++i) {
     186           0 :             for (int j = 0; j < vertices; ++j) {
     187           0 :                 if (dist[i][k] != std::numeric_limits<int>::max() &&
     188           0 :                     dist[k][j] != std::numeric_limits<int>::max() &&
     189           0 :                     dist[i][k] + dist[k][j] < dist[i][j]) {
     190           0 :                     dist[i][j] = dist[i][k] + dist[k][j];
     191             :                 }
     192             :             }
     193             :         }
     194             :     }
     195             : 
     196           0 :     std::cout << "Floyd-Warshall Shortest Paths:\n";
     197           0 :     for (int i = 0; i < vertices; ++i) {
     198           0 :         for (int j = 0; j < vertices; ++j) {
     199           0 :             std::cout << "From " << i << " to " << j << ": ";
     200           0 :             if (dist[i][j] == std::numeric_limits<int>::max())
     201           0 :                 std::cout << "INF";
     202             :             else
     203           0 :                 std::cout << dist[i][j];
     204           0 :             std::cout << "\n";
     205             :         }
     206             :     }
     207           0 : }
     208             : 
     209           0 : void gpmp::Graph::topo_sort() {
     210           0 :     std::stack<int> topo_stack;
     211           0 :     std::vector<bool> visited(vertices, false);
     212             : 
     213           0 :     for (int i = 0; i < vertices; ++i) {
     214           0 :         if (!visited[i]) {
     215           0 :             topo_sort_util(i, visited, topo_stack);
     216             :         }
     217             :     }
     218             : 
     219           0 :     std::cout << "Topological Sorting: ";
     220           0 :     while (!topo_stack.empty()) {
     221           0 :         std::cout << topo_stack.top() << " ";
     222           0 :         topo_stack.pop();
     223             :     }
     224           0 :     std::cout << std::endl;
     225           0 : }
     226             : 
     227           0 : void gpmp::Graph::topo_sort_util(int v,
     228             :                                  std::vector<bool> &visited,
     229             :                                  std::stack<int> &topo_stack) {
     230           0 :     visited[v] = true;
     231             : 
     232           0 :     for (const auto &neighbor : adj_list[v]) {
     233           0 :         int u = neighbor.first;
     234           0 :         if (!visited[u]) {
     235           0 :             topo_sort_util(u, visited, topo_stack);
     236             :         }
     237             :     }
     238             : 
     239           0 :     topo_stack.push(v);
     240           0 : }
     241             : 
     242           0 : int gpmp::Graph::find(std::vector<int> &parent, int i) {
     243           0 :     if (parent[i] == -1)
     244           0 :         return i;
     245           0 :     return find(parent, parent[i]);
     246             : }
     247             : 
     248           0 : void gpmp::Graph::union_sets(std::vector<int> &parent, int x, int y) {
     249           0 :     int setX = find(parent, x);
     250           0 :     int setY = find(parent, y);
     251           0 :     parent[setX] = setY;
     252           0 : }
     253             : 
     254           0 : std::vector<std::vector<int>> gpmp::Graph::connected_components() {
     255           0 :     std::vector<std::vector<int>> components;
     256           0 :     std::vector<bool> visited(vertices, false);
     257             : 
     258           0 :     for (int v = 0; v < vertices; ++v) {
     259           0 :         if (!visited[v]) {
     260           0 :             std::vector<int> component;
     261           0 :             dfs_connected_components(v, visited, component);
     262           0 :             components.push_back(component);
     263           0 :         }
     264             :     }
     265             : 
     266           0 :     return components;
     267           0 : }
     268             : 
     269           0 : bool gpmp::Graph::is_bipartite() {
     270           0 :     std::vector<int> color(vertices, -1);
     271           0 :     std::queue<int> bfs_queue;
     272             : 
     273           0 :     for (int start = 0; start < vertices; ++start) {
     274           0 :         if (color[start] == -1) {
     275           0 :             color[start] = 0;
     276           0 :             bfs_queue.push(start);
     277             : 
     278           0 :             while (!bfs_queue.empty()) {
     279           0 :                 int v = bfs_queue.front();
     280           0 :                 bfs_queue.pop();
     281             : 
     282           0 :                 for (const auto &neighbor : adj_list[v]) {
     283           0 :                     int u = neighbor.first;
     284           0 :                     if (color[u] == -1) {
     285           0 :                         color[u] = 1 - color[v];
     286           0 :                         bfs_queue.push(u);
     287           0 :                     } else if (color[u] == color[v]) {
     288           0 :                         return false; // Not bipartite
     289             :                     }
     290             :                 }
     291             :             }
     292             :         }
     293             :     }
     294             : 
     295           0 :     return true; // Bipartite
     296           0 : }
     297             : 
     298           0 : std::vector<double> gpmp::Graph::betweenness_centrality() {
     299           0 :     std::vector<double> centrality(vertices, 0.0);
     300             : 
     301           0 :     for (int s = 0; s < vertices; ++s) {
     302           0 :         std::vector<int> predecessors(vertices, -1);
     303           0 :         std::vector<int> distance(vertices, -1);
     304           0 :         std::vector<int> num_shortest_paths(vertices, 0);
     305           0 :         std::stack<int> stack;
     306           0 :         std::queue<int> bfs_queue;
     307             : 
     308           0 :         distance[s] = 0;
     309           0 :         num_shortest_paths[s] = 1;
     310           0 :         bfs_queue.push(s);
     311             : 
     312           0 :         while (!bfs_queue.empty()) {
     313           0 :             int v = bfs_queue.front();
     314           0 :             bfs_queue.pop();
     315           0 :             stack.push(v);
     316             : 
     317           0 :             for (const auto &neighbor : adj_list[v]) {
     318           0 :                 int w = neighbor.first;
     319           0 :                 if (distance[w] == -1) {
     320           0 :                     distance[w] = distance[v] + 1;
     321           0 :                     bfs_queue.push(w);
     322             :                 }
     323             : 
     324           0 :                 if (distance[w] == distance[v] + 1) {
     325           0 :                     num_shortest_paths[w] += num_shortest_paths[v];
     326           0 :                     predecessors[w] = v;
     327             :                 }
     328             :             }
     329             :         }
     330             : 
     331           0 :         std::vector<double> dependency(vertices, 0.0);
     332             : 
     333           0 :         while (!stack.empty()) {
     334           0 :             int w = stack.top();
     335           0 :             stack.pop();
     336             : 
     337           0 :             for (const auto &predecessor : adj_list[w]) {
     338           0 :                 int v = predecessor.first;
     339           0 :                 dependency[v] += (static_cast<double>(num_shortest_paths[v]) /
     340           0 :                                   num_shortest_paths[w]) *
     341           0 :                                  (1 + dependency[w]);
     342             :             }
     343             : 
     344           0 :             if (w != s) {
     345           0 :                 centrality[w] += dependency[w];
     346             :             }
     347             :         }
     348           0 :     }
     349             : 
     350           0 :     return centrality;
     351           0 : }
     352             : 
     353           0 : void gpmp::Graph::dfs_connected_components(int v,
     354             :                                            std::vector<bool> &visited,
     355             :                                            std::vector<int> &component) {
     356           0 :     visited[v] = true;
     357           0 :     component.push_back(v);
     358             : 
     359           0 :     for (const auto &neighbor : adj_list[v]) {
     360           0 :         int u = neighbor.first;
     361           0 :         if (!visited[u]) {
     362           0 :             dfs_connected_components(u, visited, component);
     363             :         }
     364             :     }
     365           0 : }
     366             : 
     367           0 : bool gpmp::Graph::has_hamiltonian_circuit() {
     368           0 :     std::vector<int> path;
     369           0 :     std::vector<bool> visited(vertices, false);
     370             : 
     371           0 :     for (int v = 0; v < vertices; ++v) {
     372           0 :         path.clear();
     373           0 :         if (hamiltonian_circuit_util(v, visited, path, 1)) {
     374           0 :             return true;
     375             :         }
     376             :     }
     377             : 
     378           0 :     return false;
     379           0 : }
     380             : 
     381           0 : bool gpmp::Graph::has_eulerian_path() {
     382             :     // A connected graph has an Eulerian path if and only if it has exactly 0 or
     383             :     // 2 vertices with an odd degree.
     384           0 :     int odd_degrees = 0;
     385             : 
     386           0 :     for (int v = 0; v < vertices; ++v) {
     387           0 :         if (adj_list[v].size() % 2 != 0) {
     388           0 :             ++odd_degrees;
     389             :         }
     390             :     }
     391             : 
     392           0 :     return odd_degrees == 0 || odd_degrees == 2;
     393             : }
     394             : 
     395           0 : bool gpmp::Graph::hamiltonian_circuit_util(int v,
     396             :                                            std::vector<bool> &visited,
     397             :                                            std::vector<int> &path,
     398             :                                            int count) {
     399           0 :     visited[v] = true;
     400           0 :     path.push_back(v);
     401             : 
     402           0 :     if (count == vertices) {
     403             :         // all vertices are visited; check if there is an edge from the last
     404             :         // added vertex to the starting vertex
     405           0 :         for (const auto &neighbor : adj_list[v]) {
     406           0 :             if (neighbor.first == path[0]) {
     407           0 :                 return true; // Hamiltonian circuit found
     408             :             }
     409             :         }
     410             :     } else {
     411             :         // recursive step to try all vertices as the next one in the Hamiltonian
     412             :         // circuit
     413           0 :         for (const auto &neighbor : adj_list[v]) {
     414           0 :             if (!visited[neighbor.first]) {
     415           0 :                 if (hamiltonian_circuit_util(neighbor.first,
     416             :                                              visited,
     417             :                                              path,
     418             :                                              count + 1)) {
     419           0 :                     return true;
     420             :                 }
     421             :             }
     422             :         }
     423             :     }
     424             : 
     425             :     // backtrack
     426           0 :     visited[v] = false;
     427           0 :     path.pop_back();
     428           0 :     return false;
     429             : }
     430             : 
     431           0 : int gpmp::Graph::eccentricity(int vertex) {
     432           0 :     std::vector<int> distance(vertices, std::numeric_limits<int>::max());
     433           0 :     distance[vertex] = 0;
     434             : 
     435           0 :     std::queue<int> bfs_queue;
     436           0 :     bfs_queue.push(vertex);
     437             : 
     438           0 :     while (!bfs_queue.empty()) {
     439           0 :         int v = bfs_queue.front();
     440           0 :         bfs_queue.pop();
     441             : 
     442           0 :         for (const auto &neighbor : adj_list[v]) {
     443           0 :             int u = neighbor.first;
     444           0 :             if (distance[u] == std::numeric_limits<int>::max()) {
     445           0 :                 distance[u] = distance[v] + 1;
     446           0 :                 bfs_queue.push(u);
     447             :             }
     448             :         }
     449             :     }
     450             : 
     451             :     // the eccentricity is the maximum distance from the given vertex
     452           0 :     return *std::max_element(distance.begin(), distance.end());
     453           0 : }
     454             : 
     455             : // method to calculate the radius of the graph
     456           0 : int gpmp::Graph::radius() {
     457           0 :     int min_ecntrc = std::numeric_limits<int>::max();
     458             : 
     459           0 :     for (int v = 0; v < vertices; ++v) {
     460           0 :         int vEccentricity = eccentricity(v);
     461           0 :         min_ecntrc = std::min(min_ecntrc, vEccentricity);
     462             :     }
     463             : 
     464           0 :     return min_ecntrc;
     465             : }
     466             : 
     467           0 : int gpmp::Graph::chromatic_number() {
     468           0 :     std::vector<int> result(vertices, -1);
     469             : 
     470             :     // assign the first color to the first vertex
     471           0 :     result[0] = 0;
     472             : 
     473             :     // initialize available colors. For each vertex, remove colors used by its
     474             :     // neighbors.
     475           0 :     std::vector<bool> available(vertices, false);
     476           0 :     for (const auto &neighbor : adj_list[0]) {
     477           0 :         int v = neighbor.first;
     478           0 :         if (result[v] != -1) {
     479           0 :             available[result[v]] = true;
     480             :         }
     481             :     }
     482             : 
     483             :     // assign colors to the remaining vertices
     484           0 :     for (int v = 1; v < vertices; ++v) {
     485           0 :         for (int c = 0; c < vertices; ++c) {
     486           0 :             if (!available[c]) {
     487           0 :                 result[v] = c;
     488           0 :                 break;
     489             :             }
     490             :         }
     491             : 
     492             :         // reset available colors for the next vertex
     493           0 :         std::fill(available.begin(), available.end(), false);
     494             : 
     495             :         // update available colors for neighbors
     496           0 :         for (const auto &neighbor : adj_list[v]) {
     497           0 :             int u = neighbor.first;
     498           0 :             if (result[u] != -1) {
     499           0 :                 available[result[u]] = true;
     500             :             }
     501             :         }
     502             :     }
     503             : 
     504             :     // find the maximum color assigned, which represents the chromatic number
     505           0 :     int chrom_num = *std::max_element(result.begin(), result.end()) + 1;
     506             : 
     507           0 :     return chrom_num;
     508           0 : }
     509             : 
     510             : // method to perform graph coloring using the greedy algorithm
     511           0 : std::vector<int> gpmp::Graph::greedy_coloring() {
     512           0 :     std::vector<int> result(vertices, -1);
     513             : 
     514             :     // assign colors to vertices
     515           0 :     for (int v = 0; v < vertices; ++v) {
     516           0 :         std::vector<bool> available(vertices, false);
     517           0 :         for (const auto &neighbor : adj_list[v]) {
     518           0 :             int u = neighbor.first;
     519           0 :             if (result[u] != -1) {
     520           0 :                 available[result[u]] = true;
     521             :             }
     522             :         }
     523             : 
     524           0 :         for (int c = 0; c < vertices; ++c) {
     525           0 :             if (!available[c]) {
     526           0 :                 result[v] = c;
     527           0 :                 break;
     528             :             }
     529             :         }
     530           0 :     }
     531             : 
     532           0 :     return result;
     533           0 : }
     534             : 
     535           0 : std::vector<std::pair<int, int>> gpmp::Graph::match_cardinality() {
     536           0 :     std::vector<std::pair<int, int>> matching;
     537             : 
     538             :     // iterate through each vertex and find unmatched neighbors
     539           0 :     for (int v = 0; v < vertices; ++v) {
     540           0 :         if (!is_matched[v]) {
     541           0 :             for (const auto &neighbor : adj_list[v]) {
     542           0 :                 int u = neighbor.first;
     543           0 :                 if (!is_matched[u]) {
     544           0 :                     matching.push_back({v, u});
     545           0 :                     is_matched[v] = true;
     546           0 :                     is_matched[u] = true;
     547           0 :                     break;
     548             :                 }
     549             :             }
     550             :         }
     551             :     }
     552             : 
     553           0 :     return matching;
     554           0 : }
     555             : 
     556             : // method to find a maximum weight matching in the graph using greedy algorithm
     557           0 : std::vector<std::pair<int, int>> gpmp::Graph::match_wt() {
     558           0 :     std::vector<std::pair<int, int>> matching;
     559             : 
     560             :     // sort edges in descending order based on weights
     561           0 :     std::vector<std::pair<std::pair<int, int>, int>> wt_edges;
     562           0 :     for (int v = 0; v < vertices; ++v) {
     563           0 :         for (const auto &neighbor : adj_list[v]) {
     564           0 :             int u = neighbor.first;
     565           0 :             int weight = neighbor.second;
     566           0 :             wt_edges.push_back({{v, u}, weight});
     567             :         }
     568             :     }
     569             : 
     570           0 :     std::sort(wt_edges.rbegin(),
     571           0 :               wt_edges.rend(),
     572           0 :               [](const auto &a, const auto &b) { return a.second < b.second; });
     573             : 
     574             :     // iterate through sorted edges and add to matching if both vertices are
     575             :     // unmatched
     576           0 :     for (const auto &edge : wt_edges) {
     577           0 :         int v = edge.first.first;
     578           0 :         int u = edge.first.second;
     579           0 :         if (!is_matched[v] && !is_matched[u]) {
     580           0 :             matching.push_back({v, u});
     581           0 :             is_matched[v] = true;
     582           0 :             is_matched[u] = true;
     583             :         }
     584             :     }
     585             : 
     586           0 :     return matching;
     587           0 : }
     588             : 
     589           0 : bool gpmp::Graph::is_planar() {
     590             :     // planar graphs satisfy Kuratowski's theorem: they do not contain a
     591             :     // subgraph that is a subdivision of K5 or K3,3.
     592           0 :     return !has_k5() && !has_k33();
     593             : }
     594             : 
     595             : // method to generate a random planar graph using the random geometric graph
     596             : // model
     597           0 : void gpmp::Graph::planar_gen(int num_vertices, double radius) {
     598           0 :     vertices = num_vertices;
     599           0 :     adj_list.resize(vertices);
     600             : 
     601             :     // generate random points in a 2D plane
     602           0 :     std::vector<std::pair<double, double>> points;
     603           0 :     for (int v = 0; v < vertices; ++v) {
     604           0 :         double x = static_cast<double>(rand()) / RAND_MAX;
     605           0 :         double y = static_cast<double>(rand()) / RAND_MAX;
     606           0 :         points.push_back({x, y});
     607             :     }
     608             : 
     609             :     // connect vertices if their Euclidean distance is less than the specified
     610             :     // radius
     611           0 :     for (int v = 0; v < vertices; ++v) {
     612           0 :         for (int u = v + 1; u < vertices; ++u) {
     613           0 :             double distance = euclid_dist(points[v], points[u]);
     614           0 :             if (distance < radius) {
     615             :                 // TODO the weight of the generated edges should probably be
     616             :                 // determined algorithmically
     617           0 :                 add_edge(v, u, 0);
     618             :             }
     619             :         }
     620             :     }
     621           0 : }
     622             : 
     623             : // method to check if the graph contains a subgraph that is a subdivision of K5
     624           0 : bool gpmp::Graph::has_k5() {
     625           0 :     for (int v = 0; v < vertices; ++v) {
     626           0 :         if (adj_list[v].size() >= 5) {
     627           0 :             std::set<int> neighbors;
     628           0 :             for (const auto &neighbor : adj_list[v]) {
     629           0 :                 neighbors.insert(neighbor.first);
     630             :             }
     631             : 
     632           0 :             for (const auto &u : neighbors) {
     633           0 :                 std::set<int> common_neighbors;
     634           0 :                 for (const auto &neighbor : adj_list[u]) {
     635           0 :                     if (neighbors.find(neighbor.first) != neighbors.end()) {
     636           0 :                         common_neighbors.insert(neighbor.first);
     637             :                     }
     638             :                 }
     639             : 
     640           0 :                 for (const auto &w : common_neighbors) {
     641           0 :                     if (neighbors.find(w) != neighbors.end()) {
     642           0 :                         return true;
     643             :                     }
     644             :                 }
     645           0 :             }
     646           0 :         }
     647             :     }
     648             : 
     649           0 :     return false;
     650             : }
     651             : 
     652             : // method to check if the graph contains a subgraph that is a subdivision of
     653             : // K3,3
     654           0 : bool gpmp::Graph::has_k33() {
     655           0 :     for (int v = 0; v < vertices; ++v) {
     656           0 :         if (adj_list[v].size() >= 3) {
     657           0 :             std::set<int> neighbors;
     658           0 :             for (const auto &neighbor : adj_list[v]) {
     659           0 :                 neighbors.insert(neighbor.first);
     660             :             }
     661             : 
     662           0 :             if (is_k33(neighbors)) {
     663           0 :                 return true;
     664             :             }
     665           0 :         }
     666             :     }
     667             : 
     668           0 :     return false;
     669             : }
     670             : 
     671             : // helper method to check if a set of vertices forms a K3,3 subgraph
     672           0 : bool gpmp::Graph::is_k33(const std::set<int> &k_vertices) {
     673           0 :     if (k_vertices.size() == 6) {
     674           0 :         int degree_sum = 0;
     675           0 :         for (int v : k_vertices) {
     676           0 :             degree_sum += adj_list[v].size();
     677             :         }
     678             : 
     679             :         // Cast vertices.size() to int to avoid the comparison warning
     680           0 :         return degree_sum == 2 * static_cast<int>(k_vertices.size());
     681             :     }
     682           0 :     return false;
     683             : }
     684             : 
     685             : // helper method to calculate the Euclidean distance between two points
     686           0 : double gpmp::Graph::euclid_dist(const std::pair<double, double> &point1,
     687             :                                 const std::pair<double, double> &point2) {
     688           0 :     double dx = point1.first - point2.first;
     689           0 :     double dy = point1.second - point2.second;
     690           0 :     return std::sqrt(dx * dx + dy * dy);
     691             : }
     692             : 
     693           0 : std::vector<uint64_t> gpmp::Graph::compress() {
     694           0 :     std::vector<uint64_t> compressed;
     695           0 :     compressed.push_back(vertices);
     696             : 
     697           0 :     for (int v = 0; v < vertices; ++v) {
     698             :         // encode the number of neighbors using Elias Gamma encoding
     699           0 :         std::bitset<64> binary_representation(adj_list[v].size() + 1);
     700           0 :         int length = log2(adj_list[v].size() + 1) + 1;
     701             : 
     702             :         // store the length of the encoded number
     703           0 :         compressed.push_back(length);
     704             : 
     705             :         // store the encoded number
     706           0 :         compressed.push_back(
     707           0 :             std::stoull(binary_representation.to_string(), 0, 2));
     708             : 
     709             :         // store the neighbors
     710           0 :         for (const auto &neighbor : adj_list[v]) {
     711           0 :             compressed.push_back(neighbor.first);
     712             :         }
     713             :     }
     714             : 
     715           0 :     return compressed;
     716           0 : }
     717             : 
     718             : // method to decompress a compressed graph using the Elias Gamma encoding
     719           0 : void gpmp::Graph::decompress(const std::vector<uint64_t> &compressed) {
     720           0 :     int index = 0;
     721           0 :     vertices = compressed[index++];
     722             : 
     723           0 :     adj_list.resize(vertices);
     724             : 
     725           0 :     for (int v = 0; v < vertices; ++v) {
     726           0 :         int length = compressed[index++];
     727           0 :         uint64_t encoded_neighbors = compressed[index++];
     728           0 :         std::bitset<64> binary_representation(encoded_neighbors);
     729             : 
     730             :         // decode the number of neighbors
     731             :         int num_neighbors =
     732           0 :             std::stoi(binary_representation.to_string().substr(64 - length),
     733             :                       nullptr,
     734             :                       2) -
     735           0 :             1;
     736             : 
     737             :         // decode and add neighbors
     738           0 :         for (int i = 0; i < num_neighbors; ++i) {
     739           0 :             adj_list[v].emplace_back(compressed[index++],
     740           0 :                                      0); // TODO assuming unweighted graph
     741             :         }
     742             :     }
     743           0 : }

Generated by: LCOV version 1.14