LAL: Linear Arrangement Library 21.07.01
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
Q_iterator.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// C++ includes
45#if defined DEBUG
46#include <cassert>
47#endif
48#include <type_traits>
49#include <tuple>
50
51// lal includes
52#include <lal/graphs/directed_graph.hpp>
53#include <lal/graphs/undirected_graph.hpp>
54
55namespace lal {
56namespace iterators {
57
89template<
90 typename GRAPH,
91 bool is_directed = std::is_base_of_v<graphs::directed_graph, GRAPH>,
92 std::enable_if_t<
93 std::is_base_of_v<graphs::directed_graph, GRAPH> ||
94 std::is_base_of_v<graphs::undirected_graph, GRAPH>
95 , bool
96 > = true
97>
99public:
100 /* CONSTRUCTORS */
101
106 Q_iterator(const GRAPH& g) noexcept : m_G(g) {
107 reset();
108 }
109
111 ~Q_iterator() = default;
112
113 /* GETTERS */
114
116 inline bool end() const noexcept { return m_reached_end; }
117
119 inline edge_pair get_edge_pair() const noexcept { return m_cur_pair; }
120
121 /* MODIFIERS */
122
124 inline void next() noexcept {
125 if (not m_exists_next) {
126 m_reached_end = true;
127 return;
128 }
129
131#if defined DEBUG
132 assert(not share_nodes(m_cur_pair));
133#endif
134
135 // find the next edge
136 auto [found, new_cur1, new_cur2] =
138 m_cur1.first, m_cur1.second,
139 m_cur2.first, m_cur2.second + 1
140 );
141 m_exists_next = found;
142 m_cur1 = new_cur1;
143 m_cur2 = new_cur2;
144 }
145
147 inline void reset() noexcept {
148 __reset();
149 next();
150 }
151
152private:
153 typedef std::pair<node,std::size_t> E_pointer;
154
155private:
156
158 const GRAPH& m_G;
159
161 E_pointer m_cur1 = E_pointer(0,0);
163 E_pointer m_cur2 = E_pointer(0,0);
164
166 bool m_exists_next = true;
168 bool m_reached_end = false;
170 edge_pair m_cur_pair = { {0,0}, {0,0} };
171
172private:
174 inline void __reset() noexcept {
175 // there are not enough edges to have |Q| > 0
176 if (m_G.get_num_edges() <= 1) {
177 m_exists_next = false;
178 m_reached_end = true;
179 return;
180 }
181
182 m_cur1 = E_pointer(0, 0);
183 m_cur2 = E_pointer(1, static_cast<size_t>(-1));
184
185 const auto [found, new_cur1, new_cur2] =
187 m_cur1.first, m_cur1.second,
188 m_cur2.first, m_cur2.second + 1
189 );
190 if (not found) {
191 // if we can't find the next pair, then there is no next...
192 m_exists_next = false;
193 m_reached_end = true;
194 return;
195 }
196
197#if defined DEBUG
198 assert(not share_nodes(new_cur1, new_cur2));
199#endif
200
201 // since a pair was found, store it in current
202 m_cur1 = new_cur1;
203 m_cur2 = new_cur2;
205
206 // how do we know there is a next edge?
207 // well, find it!
208 const auto [f2, _, __] =
210 m_cur1.first, m_cur1.second,
211 m_cur2.first, m_cur2.second + 1
212 );
213
214 m_exists_next = f2;
215
216 // this is the case of the graph
217 // having only one independent pair of edges
218 if (not m_exists_next) {
219 m_exists_next = true;
220 m_reached_end = false;
221 }
222 }
223
230 inline edge_pair make_current_pair() const noexcept {
231 node s,t,u,v;
232 if constexpr (is_directed) {
233 s = m_cur1.first;
234 t = m_G.get_out_neighbours(s)[m_cur1.second];
235 u = m_cur2.first;
236 v = m_G.get_out_neighbours(u)[m_cur2.second];
237 }
238 else {
239 s = m_cur1.first;
240 t = m_G.get_neighbours(s)[m_cur1.second];
241 u = m_cur2.first;
242 v = m_G.get_neighbours(u)[m_cur2.second];
243 }
244 return edge_pair(edge(s,t), edge(u,v));
245 }
246
248 static inline bool share_nodes(const edge_pair& st_uv) noexcept {
249 const auto [s,t] = st_uv.first;
250 const auto [u,v] = st_uv.second;
251 return s == u or s == v or t == u or t == v;
252 }
253
255 inline
256 bool share_nodes(const E_pointer& p1, const E_pointer& p2)
257 const noexcept
258 {
259 node s, t, u, v;
260 if constexpr (is_directed) {
261 s = p1.first;
262 t = m_G.get_out_neighbours(s)[p1.second];
263 u = p2.first;
264 v = m_G.get_out_neighbours(u)[p2.second];
265 }
266 else {
267 s = p1.first;
268 t = m_G.get_neighbours(s)[p1.second];
269 u = p2.first;
270 v = m_G.get_neighbours(u)[p2.second];
271 }
272 return share_nodes(edge_pair(edge(s,t),edge(u,v)));
273 }
274
276 template<bool isdir = is_directed, std::enable_if_t<isdir, bool> = true>
277 inline std::tuple<bool, E_pointer, E_pointer>
278 find_next_pair(node s, std::size_t pt, node u, std::size_t pv)
279 noexcept
280 {
281 const uint32_t n = m_G.get_num_nodes();
282
283 // base case 1: consumed all pairs
284 if (s == n) {
285 return make_tuple(false, E_pointer(s,pt), E_pointer(u,pv));
286 }
287 // base case 2: consumed neighbours of 's'
288 if (pt >= m_G.get_out_degree(s)) {
289 return find_next_pair(s+1, 0, s+2, 0);
290 }
291 // base case 3: consumed second pointer
292 if (u == n) {
293 // advance the first pointer
294 return find_next_pair(s, pt + 1, s + 1, 0);
295 }
296 // base case 4: consumed neighbours of 'u'
297 if (pv >= m_G.get_out_degree(u)) {
298 // advance second pointer
299 return find_next_pair(s, pt, u + 1, 0);
300 }
301
302 if (share_nodes(E_pointer(s,pt), E_pointer(u,pv))) {
303 return find_next_pair(s, pt, u, pv + 1);
304 }
305
306 return make_tuple(true, E_pointer(s,pt), E_pointer(u,pv));
307 }
308
310 template<bool isdir = is_directed, std::enable_if_t<not isdir, bool> = true>
311 inline std::tuple<bool, E_pointer, E_pointer>
312 find_next_pair(node s, std::size_t pt, node u, std::size_t pv)
313 noexcept
314 {
315 // FOR GOD'S SAKE! DO NOT USE 'STATIC'!!!
316 const uint32_t n = m_G.get_num_nodes();
317
318 // base case 1: consumed all pairs
319 if (s == n) {
320 return std::make_tuple(false, E_pointer(s,pt), E_pointer(u,pv));
321 }
322 // base case 2: consumed neighbours of 's'
323 if (pt >= m_G.get_degree(s)) {
324 return find_next_pair(s+1, 0, s+2, 0);
325 }
326 // base case 3: consumed second pointer
327 if (u == n) {
328 // advance the first pointer
329 return find_next_pair(s, pt + 1, s + 1, 0);
330 }
331 // base case 4: consumed neighbours of 'u'
332 if (pv >= m_G.get_degree(u)) {
333 // advance second pointer
334 return find_next_pair(s, pt, u + 1, 0);
335 }
336
337 auto Ns = m_G.get_neighbours(s);
338 if (s > Ns[pt]) {
339 return find_next_pair(s, pt+1, u, 0);
340 }
341
342 auto Nu = m_G.get_neighbours(u);
343 if (u > Nu[pv] or share_nodes(E_pointer(s,pt), E_pointer(u,pv))) {
344 return find_next_pair(s, pt, u, pv + 1);
345 }
346
347 return make_tuple(true, E_pointer(s,pt), E_pointer(u,pv));
348 }
349
350};
351
352} // -- namespace iterators
353} // -- namespace lal
Iterator over the set of pairs of independent edges of a graph.
Definition Q_iterator.hpp:98
E_pointer m_cur2
Current pointers to the second edge.
Definition Q_iterator.hpp:163
bool end() const noexcept
Returns true if the end of the iteration was reached.
Definition Q_iterator.hpp:116
void __reset() noexcept
Sets the iterator at the beginning of the set of edges.
Definition Q_iterator.hpp:174
void next() noexcept
Moves the iterator to the next pair, if there is any.
Definition Q_iterator.hpp:124
E_pointer m_cur1
Current pointers to the first edge.
Definition Q_iterator.hpp:161
~Q_iterator()=default
Default destructor.
std::tuple< bool, E_pointer, E_pointer > find_next_pair(node s, std::size_t pt, node u, std::size_t pv) noexcept
Find the next pair in a directed graph.
Definition Q_iterator.hpp:278
edge_pair get_edge_pair() const noexcept
Returns the current edge pair.
Definition Q_iterator.hpp:119
const GRAPH & m_G
Graph we are iterating on.
Definition Q_iterator.hpp:158
bool m_reached_end
Has the end of the iteration been reached?
Definition Q_iterator.hpp:168
static bool share_nodes(const edge_pair &st_uv) noexcept
Returns whether the edges share vertices or not.
Definition Q_iterator.hpp:248
bool m_exists_next
Is there a next pair of independent edges?
Definition Q_iterator.hpp:166
Q_iterator(const GRAPH &g) noexcept
Constructor.
Definition Q_iterator.hpp:106
bool share_nodes(const E_pointer &p1, const E_pointer &p2) const noexcept
Returns whether the edges share vertices or not.
Definition Q_iterator.hpp:256
edge_pair m_cur_pair
Current pair of independent edges.
Definition Q_iterator.hpp:170
edge_pair make_current_pair() const noexcept
Returns the current pair of independent edges.
Definition Q_iterator.hpp:230
void reset() noexcept
Sets the iterator at the beginning of the set of edges.
Definition Q_iterator.hpp:147
Main namespace of the library.
Definition definitions.hpp:48
std::pair< edge, edge > edge_pair
Edge pair type.
Definition definitions.hpp:77
std::pair< node, node > edge
Edge type.
Definition definitions.hpp:75
uint32_t node
Node type.
Definition definitions.hpp:51