LAL: Linear Arrangement Library 23.01.00
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 - 2023
7 *
8 * This file is part of Linear Arrangement Library. The full code is available
9 * at:
10 * https://github.com/LAL-project/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 <limits>
50#include <tuple>
51
52// lal includes
53#include <lal/graphs/directed_graph.hpp>
54#include <lal/graphs/undirected_graph.hpp>
55
56namespace lal {
57namespace iterators {
58
98template <
99 typename GRAPH,
100 bool is_directed = std::is_base_of_v<graphs::directed_graph, GRAPH>,
101 std::enable_if_t<
102 std::is_base_of_v<graphs::directed_graph, GRAPH> ||
103 std::is_base_of_v<graphs::undirected_graph, GRAPH>
104 , bool
105 > = true
106>
108public:
109 /* CONSTRUCTORS */
110
115 Q_iterator(const GRAPH& g) noexcept : m_G(g), m_n(m_G.get_num_nodes()) {
116 reset();
117 }
118
120 ~Q_iterator() = default;
121
122 /* GETTERS */
123
125 bool end() const noexcept { return m_reached_end; }
126
128 const edge_pair& get_edge_pair() const noexcept { return m_cur_pair; }
129
131 edge_pair_t get_edge_pair_t() const noexcept { return m_cur_pair; }
132
135 const auto e = get_edge_pair();
136 next();
137 return e;
138 }
139
140 /* MODIFIERS */
141
143 void next() noexcept {
144 if (not m_exists_next) {
145 m_reached_end = true;
146 return;
147 }
148
150#if defined DEBUG
151 assert(not share_nodes(
152 m_cur_pair.first.first, m_cur_pair.first.second,
153 m_cur_pair.second.first, m_cur_pair.second.second));
154#endif
155
156 // find the next edge
157 auto [found, new_cur1, new_cur2] =
159 m_cur1.first, m_cur1.second,
160 m_cur2.first, m_cur2.second + 1
161 );
162 m_exists_next = found;
163 m_cur1 = new_cur1;
164 m_cur2 = new_cur2;
165 }
166
168 void reset() noexcept {
169 __reset();
170 next();
171 }
172
173private:
174 typedef std::pair<node,std::size_t> E_pointer;
175
176private:
177
179 const GRAPH& m_G;
181 const uint64_t m_n;
182
184 E_pointer m_cur1 = E_pointer(0,0);
186 E_pointer m_cur2 = E_pointer(0,0);
187
189 bool m_exists_next = true;
191 bool m_reached_end = false;
193 edge_pair m_cur_pair = { {0,0}, {0,0} };
194
195private:
197 void __reset() noexcept {
198 // there are not enough edges to have |Q| > 0
199 if (m_G.get_num_edges() <= 1) {
200 m_exists_next = false;
201 m_reached_end = true;
202 return;
203 }
204
205 m_cur1.first = m_cur1.second = 0;
206 m_cur2.first = 1;
207 m_cur2.second = std::numeric_limits<std::size_t>::max();
208
209 const auto [found, new_cur1, new_cur2] =
211 m_cur1.first, m_cur1.second,
212 m_cur2.first, m_cur2.second + 1
213 );
214
215 if (not found) {
216 // if we can't find the next pair, then there is no next...
217 m_exists_next = false;
218 m_reached_end = true;
219 return;
220 }
221
222#if defined DEBUG
223 assert(not share_nodes_pointer(
224 new_cur1.first, new_cur1.second,
225 new_cur2.first, new_cur2.second));
226#endif
227
228 // since a pair was found, store it in current
229 m_cur1 = new_cur1;
230 m_cur2 = new_cur2;
232
233 // how do we know there is a next edge?
234 // well, find it!
235 const auto [f2, _, __] =
237 m_cur1.first, m_cur1.second,
238 m_cur2.first, m_cur2.second + 1
239 );
240
241 m_exists_next = f2;
242
243 // this is the case of the graph
244 // having only one independent pair of edges
245 if (not m_exists_next) {
246 m_exists_next = true;
247 m_reached_end = false;
248 }
249 }
250
257 edge_pair make_current_pair() const noexcept {
258 node s,t,u,v;
259 s = m_cur1.first;
260 u = m_cur2.first;
261 if constexpr (is_directed) {
262 t = m_G.get_out_neighbours(s)[m_cur1.second];
263 v = m_G.get_out_neighbours(u)[m_cur2.second];
264 }
265 else {
266 t = m_G.get_neighbours(s)[m_cur1.second];
267 v = m_G.get_neighbours(u)[m_cur2.second];
268 }
269 return {{s,t}, {u,v}};
270 }
271
285 const node s, const std::size_t pt,
286 const node u, const std::size_t pv
287 )
288 const noexcept
289 {
290 node t, v;
291 if constexpr (is_directed) {
292 t = m_G.get_out_neighbours(s)[pt];
293 v = m_G.get_out_neighbours(u)[pv];
294 }
295 else {
296 t = m_G.get_neighbours(s)[pt];
297 v = m_G.get_neighbours(u)[pv];
298 }
299 return share_nodes(s,t, u,v);
300 }
301
310 bool share_nodes(const node s, const node t, const node u, const node v)
311 const noexcept
312 { return s == u or s == v or t == u or t == v; }
313
315 template <bool isdir = is_directed, std::enable_if_t<isdir, bool> = true>
316 std::tuple<bool, E_pointer, E_pointer>
317 find_next_pair(node s, std::size_t pt, node u, std::size_t pv)
318 noexcept
319 {
320 // base case 1: consumed all pairs
321 if (s == m_n) {
322 return {false, {s,pt}, {u,pv}};
323 }
324 // base case 2: consumed neighbours of 's'
325 if (pt >= m_G.get_out_degree(s)) {
326 return find_next_pair(s+1, 0, s+2, 0);
327 }
328 // base case 3: consumed second pointer
329 if (u == m_n) {
330 // advance the first^ pointer
331 return find_next_pair(s, pt + 1, s + 1, 0);
332 }
333 // base case 4: consumed neighbours of 'u'
334 if (pv >= m_G.get_out_degree(u)) {
335 // advance second pointer
336 return find_next_pair(s, pt, u + 1, 0);
337 }
338
339 if (share_nodes_pointer(s,pt, u,pv)) {
340 return find_next_pair(s, pt, u, pv + 1);
341 }
342
343 return {true, {s,pt}, {u,pv}};
344 }
345
347 template <bool isdir = is_directed, std::enable_if_t<not isdir, bool> = true>
348 std::tuple<bool, E_pointer, E_pointer>
349 find_next_pair(node s, std::size_t pt, node u, std::size_t pv)
350 noexcept
351 {
352 // base case 1: consumed all pairs
353 if (s == m_n) {
354 return {false, {s,pt}, {u,pv}};
355 }
356 // base case 2: consumed neighbours of 's'
357 if (pt >= m_G.get_degree(s)) {
358 return find_next_pair(s+1, 0, s+2, 0);
359 }
360 // base case 3: consumed second pointer
361 if (u == m_n) {
362 // advance the first pointer
363 return find_next_pair(s, pt + 1, s + 1, 0);
364 }
365 // base case 4: consumed neighbours of 'u'
366 if (pv >= m_G.get_degree(u)) {
367 // advance second pointer
368 return find_next_pair(s, pt, u + 1, 0);
369 }
370
371 const auto& Ns = m_G.get_neighbours(s);
372 if (s > Ns[pt]) {
373 return find_next_pair(s, pt+1, u, 0);
374 }
375
376 const auto& Nu = m_G.get_neighbours(u);
377 if (u > Nu[pv] or share_nodes_pointer(s,pt, u,pv)) {
378 return find_next_pair(s, pt, u, pv + 1);
379 }
380
381 return {true, {s,pt}, {u,pv}};
382 }
383
384};
385
386} // -- namespace iterators
387} // -- namespace lal
Iterator over the set of pairs of independent edges of a graph.
Definition: Q_iterator.hpp:107
E_pointer m_cur2
Current pointers to the second edge.
Definition: Q_iterator.hpp:186
bool end() const noexcept
Returns true if the end of the iteration was reached.
Definition: Q_iterator.hpp:125
void __reset() noexcept
Sets the iterator at the beginning of the set of edges.
Definition: Q_iterator.hpp:197
void next() noexcept
Moves the iterator to the next pair, if there is any.
Definition: Q_iterator.hpp:143
bool share_nodes_pointer(const node s, const std::size_t pt, const node u, const std::size_t pv) const noexcept
Returns whether two edges share vertices or not.
Definition: Q_iterator.hpp:284
bool share_nodes(const node s, const node t, const node u, const node v) const noexcept
Returns whether two edges share vertices or not.
Definition: Q_iterator.hpp:310
E_pointer m_cur1
Current pointers to the first edge.
Definition: Q_iterator.hpp:184
const edge_pair & get_edge_pair() const noexcept
Returns the current edge pair.
Definition: Q_iterator.hpp:128
~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:317
const uint64_t m_n
Number of vertices.
Definition: Q_iterator.hpp:181
const GRAPH & m_G
Graph we are iterating on.
Definition: Q_iterator.hpp:179
bool m_reached_end
Has the end of the iteration been reached?
Definition: Q_iterator.hpp:191
bool m_exists_next
Is there a next pair of independent edges?
Definition: Q_iterator.hpp:189
Q_iterator(const GRAPH &g) noexcept
Constructor.
Definition: Q_iterator.hpp:115
edge_pair m_cur_pair
Current pair of independent edges.
Definition: Q_iterator.hpp:193
edge_pair make_current_pair() const noexcept
Returns the current pair of independent edges.
Definition: Q_iterator.hpp:257
edge_pair yield_edge_pair() noexcept
Returns the current edge pair and advances the iterator.
Definition: Q_iterator.hpp:134
edge_pair_t get_edge_pair_t() const noexcept
Returns the current edge pair.
Definition: Q_iterator.hpp:131
void reset() noexcept
Sets the iterator at the beginning of the set of edges.
Definition: Q_iterator.hpp:168
Main namespace of the library.
Definition: basic_types.hpp:50
std::pair< edge, edge > edge_pair
Edge pair type.
Definition: basic_types.hpp:60
std::pair< edge_t, edge_t > edge_pair_t
Similar to edge_pair.
Definition: basic_types.hpp:165
uint64_t node
Node type. See Node / Vertex page for further details.
Definition: basic_types.hpp:53