|
19 | 19 | #include <ostream>
|
20 | 20 | #include <cassert>
|
21 | 21 | #include <algorithm>
|
| 22 | +#include <queue> |
| 23 | + |
| 24 | +#include "invariant.h" |
22 | 25 |
|
23 | 26 | class empty_edget
|
24 | 27 | {
|
@@ -226,6 +229,13 @@ class grapht
|
226 | 229 | // return value: number of SCCs
|
227 | 230 | std::size_t SCCs(std::vector<node_indext> &subgraph_nr);
|
228 | 231 |
|
| 232 | + bool is_dag() const |
| 233 | + { |
| 234 | + return empty() || !topsort().empty(); |
| 235 | + } |
| 236 | + |
| 237 | + std::list<node_indext> topsort() const; |
| 238 | + |
229 | 239 | void output_dot(std::ostream &out) const;
|
230 | 240 | void output_dot_node(std::ostream &out, node_indext n) const;
|
231 | 241 |
|
@@ -570,6 +580,52 @@ void grapht<N>::make_chordal()
|
570 | 580 | }
|
571 | 581 | }
|
572 | 582 |
|
| 583 | +/// Find a topological order of the nodes if graph is DAG, return empty list for |
| 584 | +/// non-DAG or empty graph. Uses Kahn's algorithm running in O(#edges+#nodes). |
| 585 | +template<class N> |
| 586 | +std::list<typename grapht<N>::node_indext> grapht<N>::topsort() const |
| 587 | +{ |
| 588 | + // list of topologically sorted nodes |
| 589 | + std::list<node_indext> nodelist; |
| 590 | + // queue of working set nodes with in-degree zero |
| 591 | + std::queue<node_indext> indeg0_nodes; |
| 592 | + // in-degree for each node |
| 593 | + std::vector<size_t> in_deg(nodes.size(), 0); |
| 594 | + |
| 595 | + // abstract graph as in-degree of each node |
| 596 | + for(node_indext idx=0; idx<nodes.size(); idx++) |
| 597 | + { |
| 598 | + in_deg[idx]=in(idx).size(); |
| 599 | + if(in_deg[idx]==0) |
| 600 | + indeg0_nodes.push(idx); |
| 601 | + } |
| 602 | + |
| 603 | + while(!indeg0_nodes.empty()) |
| 604 | + { |
| 605 | + node_indext source=indeg0_nodes.front(); |
| 606 | + indeg0_nodes.pop(); |
| 607 | + nodelist.push_back(source); |
| 608 | + |
| 609 | + for(const auto &edge : out(source)) |
| 610 | + { |
| 611 | + const node_indext target=edge.first; |
| 612 | + INVARIANT(in_deg[target]!=0, "in-degree of node cannot be zero here"); |
| 613 | + |
| 614 | + // remove edge from graph, by decrementing the in-degree of target |
| 615 | + // outgoing edges from source will not be traversed again |
| 616 | + in_deg[target]--; |
| 617 | + if(in_deg[target]==0) |
| 618 | + indeg0_nodes.push(target); |
| 619 | + } |
| 620 | + } |
| 621 | + |
| 622 | + // if all nodes are sorted, the graph is acyclic |
| 623 | + // return empty list in case of cyclic graph |
| 624 | + if(nodelist.size()!=nodes.size()) |
| 625 | + nodelist.clear(); |
| 626 | + return nodelist; |
| 627 | +} |
| 628 | + |
573 | 629 | template<class N>
|
574 | 630 | void grapht<N>::output_dot(std::ostream &out) const
|
575 | 631 | {
|
|
0 commit comments