Skip to content

Commit 1b2a765

Browse files
author
Daniel Kroening
authored
Merge pull request #1089 from mgudemann/feature/graph_topological_sort
Add Kahn's algorithm to graph.h
2 parents 10b48f5 + de657ed commit 1b2a765

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/util/graph.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Author: Daniel Kroening, [email protected]
1919
#include <ostream>
2020
#include <cassert>
2121
#include <algorithm>
22+
#include <queue>
23+
24+
#include "invariant.h"
2225

2326
class empty_edget
2427
{
@@ -226,6 +229,13 @@ class grapht
226229
// return value: number of SCCs
227230
std::size_t SCCs(std::vector<node_indext> &subgraph_nr);
228231

232+
bool is_dag() const
233+
{
234+
return empty() || !topsort().empty();
235+
}
236+
237+
std::list<node_indext> topsort() const;
238+
229239
void output_dot(std::ostream &out) const;
230240
void output_dot_node(std::ostream &out, node_indext n) const;
231241

@@ -570,6 +580,52 @@ void grapht<N>::make_chordal()
570580
}
571581
}
572582

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+
573629
template<class N>
574630
void grapht<N>::output_dot(std::ostream &out) const
575631
{

0 commit comments

Comments
 (0)