1 /* Copyright (c) 1997-2021
2 Ewgenij Gawrilow, Michael Joswig, and the polymake team
3 Technische Universität Berlin, Germany
4 https://polymake.org
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version: http://www.gnu.org/licenses/gpl.txt.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 --------------------------------------------------------------------------------
16 */
17
18 #pragma once
19
20 #include "polymake/GenericGraph.h"
21 #include "polymake/Bitset.h"
22 #include "polymake/ContainerChain.h"
23 #include "polymake/vector"
24 #include "polymake/meta_list.h"
25 #include <deque>
26 #include <cassert>
27
28 namespace polymake { namespace graph {
29
30 template <bool TInversed=false>
31 class NodeVisitor {
32 protected:
33 Bitset visited;
34 public:
35 static const bool visit_all_edges=false;
36
37 NodeVisitor() = default;
38
39 template <typename TGraph>
NodeVisitor(const GenericGraph<TGraph> & G)40 NodeVisitor(const GenericGraph<TGraph>& G)
41 : visited(G.top().dim())
42 {
43 clear(G);
44 }
45
46 template <typename TGraph>
clear(const GenericGraph<TGraph> & G)47 void clear(const GenericGraph<TGraph>& G)
48 {
49 if (TInversed) {
50 if (G.top().has_gaps())
51 visited=nodes(G);
52 else
53 visited=sequence(0, G.top().dim());
54 } else {
55 visited.clear();
56 }
57 }
58
operator()59 bool operator()(Int n)
60 {
61 return operator()(n, n);
62 }
63
operator()64 bool operator()(Int n_from, Int n_to)
65 {
66 if (TInversed == visited.contains(n_to)) {
67 if (TInversed)
68 visited-=n_to;
69 else
70 visited+=n_to;
71 return true;
72 }
73 return false;
74 }
75
get_visited_nodes()76 const Bitset& get_visited_nodes() const { return visited; }
77 };
78
79
80 /// storage for and actions on visited nodes
81 template <typename> class VisitorTag;
82
83 /// how to traverse a directed graph:
84 /// 1 = follow the edges as is
85 /// -1 = follow reversed edges
86 /// 0 = follow all incident adges regardless of their direction
87 template <typename> class TraversalDirectionTag;
88
89 /// DFS only: whether to expose the parent (root) node before its children (leaves)
90 template <typename> class VisitParentFirstTag;
91
92 template <typename TGraph, typename... TParams>
93 class graph_iterator_base {
94 public:
95 typedef typename mlist_wrap<TParams...>::type params;
96 typedef TGraph graph_t;
97 typedef typename mtagged_list_extract<params, VisitorTag, NodeVisitor<> >::type visitor_t;
98 typedef typename std::conditional<TGraph::is_directed,
99 typename mtagged_list_extract<params, TraversalDirectionTag, int_constant<1>>::type,
100 int_constant<1>>::type traverse_edges;
101
102 typedef std::forward_iterator_tag iterator_category;
103 typedef Int value_type;
104 typedef const Int& reference;
105 typedef const Int* pointer;
106 typedef ptrdiff_t difference_type;
107
node_visitor()108 const visitor_t& node_visitor() const { return visitor; }
node_visitor_mutable()109 visitor_t& node_visitor_mutable() { return visitor; }
110
111 protected:
graph_iterator_base()112 graph_iterator_base()
113 : graph(nullptr) {}
114
graph_iterator_base(const graph_t & graph_arg)115 explicit graph_iterator_base(const graph_t& graph_arg)
116 : graph(&graph_arg)
117 , visitor(graph_arg)
118 , undiscovered(graph->nodes()) {}
119
graph_iterator_base(const graph_t & graph_arg,visitor_t && visitor_arg)120 graph_iterator_base(const graph_t& graph_arg, visitor_t&& visitor_arg)
121 : graph(&graph_arg)
122 , visitor(std::move(visitor_arg))
123 , undiscovered(graph->nodes()) {}
124
edges(Int n,int_constant<1>)125 decltype(auto) edges(Int n, int_constant<1>) const
126 {
127 return graph->out_edges(n);
128 }
129
edges(Int n,int_constant<-1>)130 decltype(auto) edges(Int n, int_constant<-1>) const
131 {
132 return graph->in_edges(n);
133 }
134
edges(Int n,int_constant<0>)135 decltype(auto) edges(Int n, int_constant<0>) const
136 {
137 return concatenate(graph->out_edges(n), graph->in_edges(n));
138 }
139
140 public:
decltype(auto)141 decltype(auto) edges(Int n) const
142 {
143 return entire(edges(n, traverse_edges()));
144 }
145
146 /// get the number of nodes which haven't been touched so far
undiscovered_nodes()147 Int undiscovered_nodes() const { return undiscovered; }
148
149 protected:
reset()150 void reset()
151 {
152 visitor.clear(*graph);
153 undiscovered=graph->nodes();
154 }
155
156 template <typename TEdgeIterator>
157 static
from_node(const TEdgeIterator & e,int_constant<1>)158 Int from_node(const TEdgeIterator& e, int_constant<1>)
159 {
160 return e.from_node();
161 }
162
163 template <typename TEdgeIterator>
164 static
from_node(const TEdgeIterator & e,int_constant<-1>)165 Int from_node(const TEdgeIterator& e, int_constant<-1>)
166 {
167 return e.to_node();
168 }
169
170 template <typename TEdgeIterator>
171 static
to_node(const TEdgeIterator & e,int_constant<1>)172 Int to_node(const TEdgeIterator& e, int_constant<1>)
173 {
174 return e.to_node();
175 }
176
177 template <typename TEdgeIterator>
178 static
to_node(const TEdgeIterator & e,int_constant<-1>)179 Int to_node(const TEdgeIterator& e, int_constant<-1>)
180 {
181 return e.from_node();
182 }
183
184 template <typename TEdgeIterator>
185 static
from_node(const TEdgeIterator & e,int_constant<0>)186 Int from_node(const TEdgeIterator& e, int_constant<0>)
187 {
188 return e.get_leg()==0
189 ? std::get<0>(e.get_it_tuple()).from_node()
190 : std::get<1>(e.get_it_tuple()).to_node();
191 }
192
193 template <typename TEdgeIterator>
194 static
to_node(const TEdgeIterator & e,int_constant<0>)195 Int to_node(const TEdgeIterator& e, int_constant<0>)
196 {
197 return e.get_leg()==0
198 ? std::get<0>(e.get_it_tuple()).to_node()
199 : std::get<1>(e.get_it_tuple()).from_node();
200 }
201
202 template <typename TEdgeIterator>
203 static
from_node(const TEdgeIterator & e)204 Int from_node(const TEdgeIterator& e)
205 {
206 return from_node(e, traverse_edges());
207 }
208
209 template <typename TEdgeIterator>
210 static
to_node(const TEdgeIterator & e)211 Int to_node(const TEdgeIterator& e)
212 {
213 return to_node(e, traverse_edges());
214 }
215
216 template <typename TEdgeIterator>
217 static
218 std::false_type probe_visitor(const TEdgeIterator& e, decltype(std::declval<visitor_t&>()(e.from_node(), e.to_node())));
219
220 template <typename TEdgeIterator>
221 static
222 std::true_type probe_visitor(const TEdgeIterator& e, decltype(std::declval<visitor_t&>()(e.from_node(), e.to_node(), *e)));
223
224 typedef decltype(probe_visitor(entire(std::declval<graph_t>().out_edges(0)), true)) visitor_needs_edge;
225
226 template <typename TEdgeIterator>
227 typename std::enable_if<visitor_needs_edge::value, typename mproject2nd<TEdgeIterator, bool>::type>::type
visit_edge(Int n_from,Int n_to,const TEdgeIterator & e)228 visit_edge(Int n_from, Int n_to, const TEdgeIterator& e)
229 {
230 return visitor(n_from, n_to, *e);
231 }
232
233 template <typename TEdgeIterator>
234 typename std::enable_if<!visitor_needs_edge::value, typename mproject2nd<TEdgeIterator, bool>::type>::type
visit_edge(Int n_from,Int n_to,const TEdgeIterator & e)235 visit_edge(Int n_from, Int n_to, const TEdgeIterator& e)
236 {
237 return visitor(n_from, n_to);
238 }
239
240 const graph_t *graph;
241 visitor_t visitor;
242 Int undiscovered;
243 };
244
245
246 template <typename TGraph, typename... TParams>
247 class BFSiterator
248 : public graph_iterator_base<TGraph, TParams...> {
249 using base_t = graph_iterator_base<TGraph, TParams...>;
250 public:
251 using typename base_t::visitor_t;
252 using typename base_t::reference;
253 using queue_t = std::deque<Int>;
254
255 using iterator = BFSiterator;
256 using const_iterator = BFSiterator;
257
258 BFSiterator() = default;
259
BFSiterator(const GenericGraph<TGraph> & graph_arg)260 explicit BFSiterator(const GenericGraph<TGraph>& graph_arg)
261 : base_t(graph_arg.top()) {}
262
BFSiterator(const GenericGraph<TGraph> & graph_arg,visitor_t && visitor_arg)263 BFSiterator(const GenericGraph<TGraph>& graph_arg, visitor_t&& visitor_arg)
264 : base_t(graph_arg.top(), std::move(visitor_arg)) {}
265
BFSiterator(const GenericGraph<TGraph> & graph_arg,Int start_node)266 BFSiterator(const GenericGraph<TGraph>& graph_arg, Int start_node)
267 : base_t(graph_arg.top())
268 {
269 process(start_node);
270 }
271
BFSiterator(const GenericGraph<TGraph> & graph_arg,visitor_t && visitor_arg,Int start_node)272 BFSiterator(const GenericGraph<TGraph>& graph_arg, visitor_t&& visitor_arg, Int start_node)
273 : base_t(graph_arg.top(), std::move(visitor_arg))
274 {
275 process(start_node);
276 }
277
278 /// get the current node
279 reference operator* () const { return queue.front(); }
280
281 /// add the neighbors of the current node to the search front, then switch to the next node
282 iterator& operator++ ()
283 {
284 const Int n = queue.front(); queue.pop_front();
285 if (visitor_t::visit_all_edges || this->undiscovered != 0)
286 propagate(n, this->edges(n));
287 return *this;
288 }
289 const iterator operator++ (int) { iterator copy(*this); operator++(); return copy; }
290
291 /// switch to the next node without visiting neighbors of the current one
skip_node()292 void skip_node() { queue.pop_front(); }
293
get_queue()294 const queue_t& get_queue() const { return queue; }
295
at_end()296 bool at_end() const { return queue.empty(); }
297
298 bool operator== (const iterator& it) const
299 {
300 return at_end() ? it.at_end() : !it.at_end() && queue.front()==it.queue.front();
301 }
302 bool operator!= (const iterator& it) const { return !operator==(it); }
303
304 /// restore the initial state of the iterator, make all nodes undiscovered
reset(Int start_node)305 void reset(Int start_node)
306 {
307 base_t::reset();
308 restart(start_node);
309 }
310
311 /// empty the queue, make the given node the current one
restart(Int n)312 void restart(Int n)
313 {
314 queue.clear();
315 process(n);
316 }
317
318 /// make the given node the current one without clearing the visited state of any nodes
319 /// and preserving the queue.
process(Int n)320 void process(Int n)
321 {
322 if (const Int dim = this->graph->dim()) {
323 if (POLYMAKE_DEBUG) {
324 if (n < 0 || n >= dim)
325 throw std::runtime_error("BFSiterator - start node out of range");
326 }
327 if (this->visitor(n)) {
328 queue.push_back(n);
329 --this->undiscovered;
330 }
331 }
332 }
333
334 protected:
335 template <typename TEdgeIterator>
propagate(Int n,TEdgeIterator && e)336 void propagate(Int n, TEdgeIterator&& e)
337 {
338 for (; !e.at_end(); ++e) {
339 const Int to_n = this->to_node(e);
340 if (this->visit_edge(n, to_n, e)) {
341 queue.push_back(to_n);
342 --this->undiscovered;
343 }
344 }
345 }
346
347 queue_t queue;
348 };
349
350
351 template <typename TGraph, typename... TParams>
352 class DFSiterator
353 : public graph_iterator_base<TGraph, TParams...> {
354 using base_t = graph_iterator_base<TGraph, TParams...>;
355 public:
356 using typename base_t::visitor_t;
357 using typename base_t::reference;
358 using typename base_t::params;
359
360 static const bool visit_parent_first=tagged_list_extract_integral<params, VisitParentFirstTag>(false);
361
362 using iterator = DFSiterator;
363 using const_iterator = DFSiterator;
364
DFSiterator()365 DFSiterator()
366 : cur(-1) {}
367
DFSiterator(const GenericGraph<TGraph> & graph_arg)368 explicit DFSiterator(const GenericGraph<TGraph>& graph_arg)
369 : base_t(graph_arg.top())
370 , cur(-1) {}
371
DFSiterator(const GenericGraph<TGraph> & graph_arg,visitor_t && visitor_arg)372 DFSiterator(const GenericGraph<TGraph>& graph_arg, visitor_t&& visitor_arg)
373 : base_t(graph_arg.top(), std::move(visitor_arg))
374 , cur(-1) {}
375
DFSiterator(const GenericGraph<TGraph> & graph_arg,Int start_node)376 DFSiterator(const GenericGraph<TGraph>& graph_arg, Int start_node)
377 : base_t(graph_arg.top())
378 , cur(-1)
379 {
380 process(start_node);
381 }
382
DFSiterator(const GenericGraph<TGraph> & graph_arg,visitor_t && visitor_arg,Int start_node)383 DFSiterator(const GenericGraph<TGraph>& graph_arg, visitor_t&& visitor_arg, Int start_node)
384 : base_t(graph_arg.top(), std::move(visitor_arg))
385 , cur(-1)
386 {
387 process(start_node);
388 }
389
390 reference operator* () const { return cur; }
391
392 iterator& operator++ ()
393 {
394 if (visit_parent_first) {
395 it_stack.push_back(this->edges(cur));
396 propagate();
397 } else {
398 cur=predecessor();
399 if (cur >= 0) {
400 ++it_stack.back();
401 descend();
402 }
403 }
404 return *this;
405 }
406
407 const iterator operator++ (int) { iterator copy(*this); operator++(); return copy; }
408
skip_node()409 void skip_node()
410 {
411 assert(visit_parent_first && !it_stack.empty());
412 ++it_stack.back();
413 propagate();
414 }
415
at_end()416 bool at_end() const { return cur<0; }
417
418 bool operator== (const iterator& it) const { return cur==it.cur; }
419 bool operator!= (const iterator& it) const { return !operator==(it); }
420
421 /// restore the initial state of the iterator, make all nodes undiscovered
reset(Int start_node)422 void reset(Int start_node)
423 {
424 base_t::reset();
425 restart(start_node);
426 }
427
428 /// empty the stack, start from the given node
restart(Int n)429 void restart(Int n)
430 {
431 it_stack.clear();
432 process(n);
433 }
434
process(Int n)435 void process(Int n)
436 {
437 if (const Int dim = this->graph->dim()) {
438 if (POLYMAKE_DEBUG) {
439 if (n < 0 || n >= dim)
440 throw std::runtime_error("DFSiterator - start node out of range");
441 }
442 if (this->visitor(n)) {
443 cur = n;
444 --this->undiscovered;
445 if (!visit_parent_first) {
446 it_stack.push_back(this->edges(n));
447 descend();
448 }
449 }
450 }
451 }
452
453 using edge_iterator = decltype(std::declval<base_t>().edges(0));
454 using it_stack_t = std::deque<edge_iterator>;
455
get_stack()456 const it_stack_t& get_stack() const { return it_stack; }
457
predecessor()458 Int predecessor() const { return it_stack.empty() ? -1 : base_t::from_node(it_stack.back()); }
459
460 protected:
descend()461 void descend()
462 {
463 while (!it_stack.back().at_end()) {
464 edge_iterator& e = it_stack.back();
465 const Int to_n = this->to_node(e);
466 if (!is_back_edge(to_n) && this->visit_edge(cur, to_n, e)) {
467 cur = to_n;
468 --this->undiscovered;
469 it_stack.push_back(this->edges(to_n));
470 } else {
471 ++e;
472 }
473 }
474 it_stack.pop_back();
475 }
476
propagate()477 void propagate()
478 {
479 for (;; ++it_stack.back()) {
480 edge_iterator& e = it_stack.back();
481 if (!e.at_end()) {
482 const Int to_n = this->to_node(e);
483 if (!is_back_edge(to_n) && this->visit_edge(cur, to_n, e)) {
484 cur = to_n;
485 --this->undiscovered;
486 break;
487 }
488 } else {
489 it_stack.pop_back();
490 if (it_stack.empty()) {
491 cur = -1;
492 break;
493 }
494 }
495 }
496 }
497
is_back_edge(Int n)498 bool is_back_edge(Int n) const
499 {
500 if (!visitor_t::visit_all_edges || TGraph::is_directed) return false;
501 const Int s = it_stack.size();
502 return s >= 2 && base_t::from_node(it_stack[s-2]) == n;
503 }
504
505 it_stack_t it_stack;
506 Int cur;
507 };
508
509
510 class TopologicalSortVisitor
511 {
512 public:
513 static const bool visit_all_edges=true;
514
TopologicalSortVisitor()515 TopologicalSortVisitor()
516 : max_rank(0) {}
517
518 template <typename TGraph>
TopologicalSortVisitor(const GenericGraph<TGraph> & G)519 TopologicalSortVisitor(const GenericGraph<TGraph>& G)
520 : rank(G.top().dim(), 0)
521 , max_rank(G.top().nodes()) {}
522
523 template <typename TGraph>
clear(const GenericGraph<TGraph> & G)524 void clear(const GenericGraph<TGraph>& G)
525 {
526 std::fill(rank.begin(), rank.end(), 0);
527 }
528
operator()529 bool operator()(Int n)
530 {
531 if (rank[n] == 0) {
532 rank[n] = max_rank;
533 return true;
534 }
535 return false;
536 }
537
operator()538 bool operator()(Int n_from, Int n_to)
539 {
540 if (rank[n_to] == 0) {
541 rank[n_to] = max_rank;
542 return true;
543 }
544 propagate_back(n_from, n_to);
545 return false;
546 }
547
propagate_back(Int n_from,Int n_to)548 void propagate_back(Int n_from, Int n_to)
549 {
550 assign_min(rank[n_from], rank[n_to]-1);
551 }
552
get_ranks()553 const std::vector<Int>& get_ranks() const { return rank; }
get_ranks()554 std::vector<Int>& get_ranks() { return rank; }
555
556 private:
557 std::vector<Int> rank;
558 Int max_rank;
559 };
560
561
562 template <typename TGraph, typename = std::enable_if_t<TGraph::is_directed>>
topological_sort(const GenericGraph<TGraph> & G)563 std::pair<std::vector<Int>, Int> topological_sort(const GenericGraph<TGraph>& G)
564 {
565 Int min_rank = G.top().nodes();
566 if (min_rank <= 1) return { std::vector<Int>(min_rank, 1), min_rank };
567
568 DFSiterator<TGraph, VisitorTag<TopologicalSortVisitor>> search_it(G.top());
569 std::vector<Int>& ranks = search_it.node_visitor_mutable().get_ranks();
570
571 for (auto nodes_it=entire(nodes(G)); !nodes_it.at_end(); ) {
572 for (search_it.restart(*nodes_it); !search_it.at_end(); ++search_it) {
573 const Int n_pred = search_it.predecessor();
574 if (n_pred >= 0)
575 search_it.node_visitor_mutable().propagate_back(n_pred, *search_it);
576 else
577 assign_min(min_rank, ranks[*search_it]);
578 }
579 if (search_it.undiscovered_nodes()) {
580 do {
581 ++nodes_it;
582 assert(!nodes_it.at_end());
583 } while (ranks[*nodes_it] != 0);
584 } else {
585 break;
586 }
587 }
588
589 return { std::move(ranks), min_rank };
590 }
591
592 template <typename TGraph, typename=typename std::enable_if<TGraph::is_directed>::type>
is_totally_ordered(const GenericGraph<TGraph> & G)593 bool is_totally_ordered(const GenericGraph<TGraph>& G)
594 {
595 return topological_sort(G).second <= 1;
596 }
597
598 } }
599
600 namespace pm {
601 template <typename TGraph, typename... TParams>
602 struct check_iterator_feature<polymake::graph::BFSiterator<TGraph, TParams...>, end_sensitive> : std::true_type {};
603
604 template <typename TGraph, typename... TParams>
605 struct check_iterator_feature<polymake::graph::DFSiterator<TGraph, TParams...>, end_sensitive> : std::true_type {};
606 }
607
608
609 // Local Variables:
610 // mode:C++
611 // c-basic-offset:3
612 // indent-tabs-mode:nil
613 // End:
614