Clingo
Loading...
Searching...
No Matches
graph.hh
1#pragma once
2
3#include <cstddef>
4#include <vector>
5
6namespace CppClingo::Util {
7
10
12class Graph {
13 public:
15 using IdVec = std::vector<size_t>;
17 using SCCVec = std::vector<IdVec>;
18
22 template <class Callback> void tarjan(Callback cb);
24 void ensure_size(size_t n);
28 void add_edge(size_t u, size_t v);
33 [[nodiscard]] auto has_loop(size_t u) const -> bool;
35 void clear() {
36 phase_ = 0;
37 nodes_.clear();
38 }
39
40 private:
42 struct Node {
43 Node(size_t visited) : visited_(visited) {}
45 IdVec out;
47 IdVec::iterator finished_;
49 size_t visited_;
50 };
51
53 [[nodiscard]] auto prev_phase_() const -> size_t;
54
56 std::vector<Node> nodes_;
58 size_t phase_ = 0;
59};
60
61inline auto Graph::prev_phase_() const -> size_t {
62 return phase_ == 0 ? 1 : 0;
63}
64
65inline void Graph::ensure_size(size_t n) {
66 if (nodes_.size() < n) {
67 while (nodes_.size() < n) {
68 nodes_.emplace_back(prev_phase_());
69 }
70 }
71}
72
73inline void Graph::add_edge(size_t u, size_t v) {
74 ensure_size(std::max(u, v) + 1);
75 nodes_[u].out.emplace_back(v);
76}
77
78inline auto Graph::has_loop(size_t u) const -> bool {
79 return std::ranges::find(nodes_[u].out, u) != nodes_[u].out.end();
80}
81
82template <class Callback> inline void Graph::tarjan(Callback cb) {
83 IdVec scc;
84 IdVec stack;
85 IdVec trail;
86 for (size_t id_x = 0, n = nodes_.size(); id_x != n; ++id_x) {
87 auto &x = nodes_[id_x];
88 if (x.visited_ == prev_phase_()) {
89 unsigned index = 1;
90 auto push = [&stack, &trail, &index, this](size_t id_x) {
91 auto &x = nodes_[id_x];
92 x.visited_ = ++index;
93 x.finished_ = x.out.begin();
94 stack.emplace_back(id_x);
95 trail.emplace_back(id_x);
96 };
97 push(id_x);
98 while (!stack.empty()) {
99 auto id_y = stack.back();
100 auto &y = nodes_[id_y];
101 auto end = y.out.end();
102 for (; y.finished_ != end && nodes_[*y.finished_].visited_ != prev_phase_(); ++y.finished_) {
103 }
104 if (y.finished_ != end) {
105 push(*y.finished_++);
106 } else {
107 stack.pop_back();
108 bool root = true;
109 for (auto id_z : y.out) {
110 auto &z = nodes_[id_z];
111 if (z.visited_ != phase_ && z.visited_ < y.visited_) {
112 root = false;
113 y.visited_ = z.visited_;
114 }
115 }
116 if (root) {
117 do {
118 scc.emplace_back(trail.back());
119 nodes_[trail.back()].visited_ = phase_;
120 trail.pop_back();
121 } while (scc.back() != id_y);
122 cb(scc);
123 scc.clear();
124 }
125 }
126 }
127 }
128 }
129 phase_ = prev_phase_();
130}
131
133
134} // namespace CppClingo::Util
Graph class to compute strongly connected components.
Definition graph.hh:12
std::vector< size_t > IdVec
A vector of node ids.
Definition graph.hh:15
std::vector< IdVec > SCCVec
A vector of vector of nodes forming a strongly connected component.
Definition graph.hh:17
void clear()
Clear the graph.
Definition graph.hh:35
auto has_loop(size_t u) const -> bool
Check if the given vertex has a loop.
Definition graph.hh:78
void tarjan(Callback cb)
Compute the strongly connected components of the graph.
Definition graph.hh:82
void ensure_size(size_t n)
Ensure that the graph holds at least n nodes.
Definition graph.hh:65
void add_edge(size_t u, size_t v)
Add an edge to the graph.
Definition graph.hh:73