LAL: Linear Arrangement Library 24.10.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 - 2024
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 (lluis.alemany.puig@upc.edu)
28 * LQMC (Quantitative, Mathematical, and Computational Linguisitcs)
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 * LQMC (Quantitative, Mathematical, and Computational Linguisitcs)
35 * CQL (Complexity and Quantitative Linguistics Lab)
36 * Office 220, 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 :
116 m_G(g),
117 m_n(m_G.get_num_nodes())
118 {
119 reset();
120 }
121
123 ~Q_iterator() = default;
124
125 /* GETTERS */
126
128 [[nodiscard]] bool end() const noexcept { return m_reached_end; }
129
131 [[nodiscard]] const edge_pair& get_edge_pair() const noexcept { return m_cur_pair; }
132
134 [[nodiscard]] edge_pair_t get_edge_pair_t() const noexcept { return m_cur_pair; }
135
137 [[nodiscard]] edge_pair yield_edge_pair() noexcept {
138 const auto e = get_edge_pair();
139 next();
140 return e;
141 }
142
143 /* MODIFIERS */
144
146 void next() noexcept {
147 if (not m_exists_next) {
148 m_reached_end = true;
149 return;
150 }
151
153#if defined DEBUG
154 assert(not share_nodes(
155 m_cur_pair.first.first, m_cur_pair.first.second,
156 m_cur_pair.second.first, m_cur_pair.second.second));
157#endif
158
159 // find the next edge
160 auto [found, new_cur1, new_cur2] =
162 m_cur1.first, m_cur1.second,
163 m_cur2.first, m_cur2.second + 1
164 );
165 m_exists_next = found;
166 m_cur1 = new_cur1;
167 m_cur2 = new_cur2;
168 }
169
171 void reset() noexcept {
172 __reset();
173 next();
174 }
175
176private:
177 typedef std::pair<node,std::size_t> E_pointer;
178
179private:
180
182 const GRAPH& m_G;
184 const uint64_t m_n;
185
187 E_pointer m_cur1;
189 E_pointer m_cur2;
190
197
198private:
200 void __reset() noexcept {
201 m_exists_next = true;
202 m_reached_end = false;
203
204 // there are not enough edges to have |Q| > 0
205 if (m_G.get_num_edges() <= 1) {
206 m_exists_next = false;
207 m_reached_end = true;
208 return;
209 }
210
211 m_cur1.first = m_cur1.second = 0;
212 m_cur2.first = 1;
213 m_cur2.second = std::numeric_limits<std::size_t>::max();
214
215 const auto [found, new_cur1, new_cur2] =
217 m_cur1.first, m_cur1.second,
218 m_cur2.first, m_cur2.second + 1
219 );
220
221 if (not found) {
222 // if we can't find the next pair, then there is no next...
223 m_exists_next = false;
224 m_reached_end = true;
225 return;
226 }
227
228#if defined DEBUG
229 assert(not share_nodes_pointer(
230 new_cur1.first, new_cur1.second,
231 new_cur2.first, new_cur2.second));
232#endif
233
234 // since a pair was found, store it in current
235 m_cur1 = new_cur1;
236 m_cur2 = new_cur2;
238
239 // how do we know there is a next edge?
240 // well, look for it!
241 const auto [f2, _, __] =
243 m_cur1.first, m_cur1.second,
244 m_cur2.first, m_cur2.second + 1
245 );
246
247 m_exists_next = f2;
248
249 // this is the case of the graph
250 // having only one independent pair of edges
251 if (not m_exists_next) {
252 m_exists_next = true;
253 m_reached_end = false;
254 }
255 }
256
263 [[nodiscard]] edge_pair make_current_pair() const noexcept {
264 node s,t,u,v;
265 s = m_cur1.first;
266 u = m_cur2.first;
267 if constexpr (is_directed) {
268 t = m_G.get_out_neighbors(s)[m_cur1.second];
269 v = m_G.get_out_neighbors(u)[m_cur2.second];
270 }
271 else {
272 t = m_G.get_neighbors(s)[m_cur1.second];
273 v = m_G.get_neighbors(u)[m_cur2.second];
274 }
275 return {{s,t}, {u,v}};
276 }
277
290 [[nodiscard]] bool share_nodes_pointer
291 (
292 const node s, const std::size_t pt,
293 const node u, const std::size_t pv
294 )
295 const noexcept
296 {
297 node t, v;
298 if constexpr (is_directed) {
299 t = m_G.get_out_neighbors(s)[pt];
300 v = m_G.get_out_neighbors(u)[pv];
301 }
302 else {
303 t = m_G.get_neighbors(s)[pt];
304 v = m_G.get_neighbors(u)[pv];
305 }
306 return share_nodes(s,t, u,v);
307 }
308
317 [[nodiscard]] bool share_nodes(
318 const node s, const node t,
319 const node u, const node v
320 )
321 const noexcept
322 {
323 return s == u or s == v or t == u or t == v;
324 }
325
327 template <bool isdir = is_directed, std::enable_if_t<isdir, bool> = true>
328 [[nodiscard]] std::tuple<bool, E_pointer, E_pointer>
330 const node s, const std::size_t pt,
331 const node u, const std::size_t pv
332 )
333 noexcept
334 {
335 // base case 1: consumed all pairs
336 if (s == m_n) {
337 return {false, {s,pt}, {u,pv}};
338 }
339 // base case 2: consumed neighbors of 's'
340 if (pt >= m_G.get_out_degree(s)) {
341 return find_next_pair(s+1, 0, s+2, 0);
342 }
343 // base case 3: consumed second pointer
344 if (u == m_n) {
345 // advance the first^ pointer
346 return find_next_pair(s, pt + 1, s + 1, 0);
347 }
348 // base case 4: consumed neighbors of 'u'
349 if (pv >= m_G.get_out_degree(u)) {
350 // advance second pointer
351 return find_next_pair(s, pt, u + 1, 0);
352 }
353
354 if (share_nodes_pointer(s,pt, u,pv)) {
355 return find_next_pair(s, pt, u, pv + 1);
356 }
357
358 return {true, {s,pt}, {u,pv}};
359 }
360
362 template <bool isdir = is_directed, std::enable_if_t<not isdir, bool> = true>
363 [[nodiscard]] std::tuple<bool, E_pointer, E_pointer>
365 const node s, const std::size_t pt,
366 const node u, const std::size_t pv
367 )
368 noexcept
369 {
370 // base case 1: consumed all pairs
371 if (s == m_n) {
372 return {false, {s,pt}, {u,pv}};
373 }
374 // base case 2: consumed neighbors of 's'
375 if (pt >= m_G.get_degree(s)) {
376 return find_next_pair(s+1, 0, s+2, 0);
377 }
378 // base case 3: consumed second pointer
379 if (u == m_n) {
380 // advance the first pointer
381 return find_next_pair(s, pt + 1, s + 1, 0);
382 }
383 // base case 4: consumed neighbors of 'u'
384 if (pv >= m_G.get_degree(u)) {
385 // advance second pointer
386 return find_next_pair(s, pt, u + 1, 0);
387 }
388
389 const auto& Ns = m_G.get_neighbors(s);
390 if (s > Ns[pt]) {
391 return find_next_pair(s, pt+1, u, 0);
392 }
393
394 const auto& Nu = m_G.get_neighbors(u);
395 if (u > Nu[pv] or share_nodes_pointer(s,pt, u,pv)) {
396 return find_next_pair(s, pt, u, pv + 1);
397 }
398
399 return {true, {s,pt}, {u,pv}};
400 }
401
402};
403
404} // -- namespace iterators
405} // -- namespace lal
Iterator over the set of pairs of independent edges of a graph.
Definition Q_iterator.hpp:107
std::tuple< bool, E_pointer, E_pointer > find_next_pair(const node s, const std::size_t pt, const node u, const std::size_t pv) noexcept
Find the next pair in a directed graph.
Definition Q_iterator.hpp:329
E_pointer m_cur2
Current pointers to the second edge.
Definition Q_iterator.hpp:189
bool end() const noexcept
Returns true if the end of the iteration was reached.
Definition Q_iterator.hpp:128
void __reset() noexcept
Sets the iterator at the beginning of the set of edges.
Definition Q_iterator.hpp:200
void next() noexcept
Moves the iterator to the next pair, if there is any.
Definition Q_iterator.hpp:146
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:291
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:317
E_pointer m_cur1
Current pointers to the first edge.
Definition Q_iterator.hpp:187
const edge_pair & get_edge_pair() const noexcept
Returns the current edge pair.
Definition Q_iterator.hpp:131
~Q_iterator()=default
Default destructor.
const uint64_t m_n
Number of vertices.
Definition Q_iterator.hpp:184
const GRAPH & m_G
Graph we are iterating on.
Definition Q_iterator.hpp:182
bool m_reached_end
Has the end of the iteration been reached?
Definition Q_iterator.hpp:194
bool m_exists_next
Is there a next pair of independent edges?
Definition Q_iterator.hpp:192
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:196
edge_pair make_current_pair() const noexcept
Returns the current pair of independent edges.
Definition Q_iterator.hpp:263
edge_pair yield_edge_pair() noexcept
Returns the current edge pair and advances the iterator.
Definition Q_iterator.hpp:137
edge_pair_t get_edge_pair_t() const noexcept
Returns the current edge pair.
Definition Q_iterator.hpp:134
void reset() noexcept
Sets the iterator at the beginning of the set of edges.
Definition Q_iterator.hpp:171
Main namespace of the library.
Definition basic_types.hpp:48
std::pair< edge, edge > edge_pair
Edge pair type.
Definition basic_types.hpp:62
std::pair< edge_t, edge_t > edge_pair_t
Similar to edge_pair.
Definition basic_types.hpp:241
uint64_t node
Node type. See Node / Vertex page for further details.
Definition basic_types.hpp:51