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