LAL: Linear Arrangement Library 21.07.01
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
cycles.hpp
1/*********************************************************************
2 *
3 * Linear Arrangement Library - A library that implements a collection
4 * algorithms for linear arrangments of graphs.
5 *
6 * Copyright (C) 2019 - 2021
7 *
8 * This file is part of Linear Arrangement Library. To see the full code
9 * visit the webpage:
10 * https://github.com/lluisalemanypuig/linear-arrangement-library.git
11 *
12 * Linear Arrangement Library is free software: you can redistribute it
13 * and/or modify it under the terms of the GNU Affero General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * Linear Arrangement Library is distributed in the hope that it will be
18 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with Linear Arrangement Library. If not, see <http://www.gnu.org/licenses/>.
24 *
25 * Contact:
26 *
27 * LluĂ­s Alemany Puig (lalemany@cs.upc.edu)
28 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
29 * CQL (Complexity and Quantitative Linguistics Lab)
30 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
31 * Webpage: https://cqllab.upc.edu/people/lalemany/
32 *
33 * Ramon Ferrer i Cancho (rferrericancho@cs.upc.edu)
34 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
35 * CQL (Complexity and Quantitative Linguistics Lab)
36 * Office S124, Omega building
37 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
38 * Webpage: https://cqllab.upc.edu/people/rferrericancho/
39 *
40 ********************************************************************/
41
42#pragma once
43
44// lal includes
45#include <lal/graphs/directed_graph.hpp>
46#include <lal/internal/graphs/traversal.hpp>
47#include <lal/internal/data_array.hpp>
48
49namespace lal {
50namespace internal {
51
52namespace __lal {
53
54/*
55 * @brief Returns true if, and only if, the graph has cycles.
56 * @param g Input graph.
57 * @param u Node of the directed graph
58 * @param visited For each node, has it been visited?
59 * @param in_stack For each node, is it in the recursion stack?
60 */
61inline bool __find_cycle
62(
63 const graphs::directed_graph& g, node u,
64 char * const __restrict__ visited,
65 char * const __restrict__ in_stack
66)
67{
68 if (visited[u]) { return false; }
69 visited[u] = 1;
70
71 in_stack[u] = 1;
72 for (node v : g.get_out_neighbours(u)) {
73 if (in_stack[v]) {
74 return true;
75 }
76 if (visited[v] == 0 and __find_cycle(g,v,visited,in_stack)) {
77 return true;
78 }
79 }
80
81 in_stack[u] = 0;
82 return false;
83}
84
85/*
86 * @brief Returns true if, and only if, the graph has DIRECTED cycles.
87 * @param g Input graph.
88 * @param vis Array of size 'n', where 'n' is the number of vertices of 'g'.
89 * @param in_stack Array of size 'n', where 'n' is the number of vertices of 'g'.
90 * @returns Whether the graph has cycles or not.
91 */
92inline bool has_directed_cycles(
93 const graphs::directed_graph& g,
94 char * const __restrict__ vis,
95 char * const __restrict__ in_stack
96)
97{
98 const uint32_t n = g.get_num_nodes();
99 std::fill(&vis[0], &vis[n], 0);
100 std::fill(&in_stack[0], &in_stack[n], 0);
101 bool has_cycle = false;
102 for (node u = 0; u < n and not has_cycle; ++u) {
103 if (vis[u] == 0) {
104 has_cycle = __lal::__find_cycle(g, u, vis, in_stack);
105 }
106 }
107 return has_cycle;
108}
109
110} // -- namespace __lal
111
112/*
113 * @brief Returns true if, and only if, the graph has DIRECTED cycles.
114 * @param g Input graph.
115 * @returns Whether the graph has cycles or not.
116 */
117inline bool has_directed_cycles(const graphs::directed_graph& g) {
118 const uint32_t n = g.get_num_nodes();
119 data_array<char> all_mem(2*n);
120 char * const __restrict__ vis = &all_mem.data[0];
121 char * const __restrict__ in_stack = &all_mem.data[n];
122 const bool has_cycle = __lal::has_directed_cycles(g, vis, in_stack);
123 return has_cycle;
124}
125
126namespace __lal {
127
128/*
129 * @brief Returns true if, and only if, the graph has UNDIRECTED cycles.
130 *
131 * In case the input graph is a directed graph, reverse edges are considered.
132 * @param g Input graph.
133 * @returns Whether the graph has cycles or not.
134 */
135template<class G>
136inline bool has_undirected_cycles(const G& g, BFS<G>& bfs) {
137 const auto n = g.get_num_nodes();
138
139 // parent[s] = t <->
140 // (in the traversal) s was reached from t (NOTE THE DIFFERENT ORDER).
141 // Note that read operations "if (parent[s] != t)" always come after
142 // the first write "parent[t] = s".
143 data_array<node> parent(n, n+1);
144 // a cycle was found
145 bool cycle_found = false;
146
147 // we need to traverse "reversed edges" in directed graphs
148 bfs.set_use_rev_edges(g.is_directed());
149 // we need this to detect cycles
150 bfs.set_process_visited_neighbours(true);
151 // -- functions for the traversal
152 bfs.set_terminate(
153 [&](const auto&, const node) -> bool { return cycle_found; }
154 );
155 bfs.set_process_neighbour(
156 [&](const auto& _bfs, node s, node t, bool) -> void {
157 // Since we want to do the traversal on the directed graphs likewise on
158 // the undirected graphs, the direction is ignored. We do not want to
159 // treat the nodes 's' and 't' as in the edge "t->s" but as in the
160 // edge "s->t" so as to mimic an "undirected traversal" on directed
161 // graphs.
162
163 if (_bfs.node_was_visited(t)) {
164 // if t was visted before then
165 // "s -> t" and later "t -> s"
166 // or
167 // "s -> ..." and later "... -> s"
168 // where '...' does not contain 't'
169 if (parent[s] != t) {
170 // node 't' was reached from some node
171 // other than 's' in previous iterations
172 cycle_found = true;
173 }
174 }
175 parent[t] = s;
176 }
177 );
178
179 // find cycles
180 for (node u = 0; u < n and not cycle_found; ++u) {
181 if (not bfs.node_was_visited(u)) {
182 bfs.clear_structure();
183 bfs.start_at(u);
184 }
185 }
186 return cycle_found;
187}
188
189} // -- namespace __lal
190
191/*
192 * @brief Returns true if, and only if, the graph has UNDIRECTED cycles.
193 *
194 * In case the input graph is a directed graph, reverse edges are considered.
195 * @param g Input graph.
196 * @returns Whether the graph has cycles or not.
197 */
198template<class G>
199inline bool has_undirected_cycles(const G& g) {
200 // BFS traversal object
201 BFS<G> bfs(g);
202 return __lal::has_undirected_cycles(g, bfs);
203}
204
205} // -- namespace internal
206} // -- namespace lal
Main namespace of the library.
Definition definitions.hpp:48
uint32_t node
Node type.
Definition definitions.hpp:51