Zen C++ Libraries
Zero-dependency re-usable components for C++
Loading...
Searching...
No Matches
graph.hpp
1#ifndef ZEN_GRAPH_HPP
2#define ZEN_GRAPH_HPP
3
4#include <unordered_set>
5#include <unordered_map>
6#include <vector>
7#include <stack>
8#include <optional>
9
10#include "zen/config.hpp"
12
13ZEN_NAMESPACE_START
14
15struct no_label_t {};
16
17template<typename V, typename L = no_label_t>
19private:
20
21 struct in_edge_t {
22 V vertex;
23 L label;
24 };
25
26 struct out_edge_t {
27 L label;
28 V vertex;
29 };
30
31 std::unordered_set<V> vertices;
32
33 std::unordered_multimap<V, out_edge_t> out_edges;
34
35public:
36
37 using vertex_type = V;
38 using label_type = L;
39
40 void add_vertex(V vertex) {
41 vertices.emplace(vertex);
42 }
43
44 void add_edge(V from, V to, L label) {
45 ZEN_ASSERT(vertices.count(from));
46 ZEN_ASSERT(vertices.count(to));
47 out_edges.emplace(from, out_edge_t { label, to });
48 }
49
50 void add_edge(V from, V to) requires (std::is_same_v<L, no_label_t>) {
51 ZEN_ASSERT(vertices.count(from));
52 ZEN_ASSERT(vertices.count(to));
53 out_edges.emplace(from, out_edge_t { {}, to });
54 }
55
56 std::vector<V> get_target_vertices(const V& from) const {
57 std::vector<V> out;
58 for (auto [_, edge]: make_iterator_range(out_edges.equal_range(from))) {
59 out.push_back(edge.vertex);
60 }
61 return out;
62 }
63
64 std::size_t count_vertices() {
65 return vertices.size();
66 }
67
68 auto get_vertices() {
69 return make_iterator_range(vertices.begin(), vertices.end());
70 }
71
72 auto get_vertices() const {
73 return make_iterator_range(vertices.cbegin(), vertices.cend());
74 }
75
76};
77
78// template<typename V>
79// class hash_graph<V, no_label_t> {
80// public:
81
82// using in_edge_t = V;
83// using out_edge_t = V;
84
85// using vertex_type = V;
86// using label_type = no_label_t;
87
88// private:
89
90// std::unordered_set<V> vertices;
91
92// std::unordered_multimap<V, out_edge_t> out_edges;
93
94// public:
95
96// void add_vertex(V vertex) {
97// vertices.emplace(vertex);
98// }
99
100// void add_edge(V from, V to) {
101// out_edges.emplace(from, to);
102// }
103
104// std::vector<out_edge_t> get_out_edges(const V& from) {
105// std::vector<out_edge_t> out;
106// for (auto& x: out_edges.equal_range(from)) {
107// out.push_back(x);
108// }
109// return out;
110// }
111
112// };
113
114template<typename G>
115std::vector<typename G::vertex_type> dijkstra(const G& graph) {
116 // TODO
117}
118
119template<typename Graph>
120std::vector<std::vector<typename Graph::vertex_type>> toposort(const Graph& graph) {
121
122 using V = typename Graph::vertex_type;
123
124 struct TarjanVertexData {
125 std::optional<std::size_t> index;
126 std::size_t low_link;
127 bool on_stack = false;
128 };
129
130 class TarjanSolver {
131 public:
132
133 std::vector<std::vector<V>> components;
134
135 private:
136
137 const Graph& graph;
138 std::unordered_map<V, TarjanVertexData> mapping;
139 std::size_t index = 0;
140 std::stack<V> stack;
141
142 TarjanVertexData& get_data(V from) {
143 return mapping.emplace(from, TarjanVertexData {}).first->second;
144 }
145
146 void visit_cycle(const V& from) {
147
148 auto& data_from = get_data(from);
149 data_from.index = index;
150 data_from.low_link = index;
151 index++;
152 stack.push(from);
153 data_from.on_stack = true;
154
155 for (const auto& to: graph.get_target_vertices(from)) {
156 auto& data_to = get_data(to);
157 if (!data_to.index) {
158 visit_cycle(to);
159 data_from.low_link = std::min(data_from.low_link, data_to.low_link);
160 } else if (data_to.on_stack) {
161 data_from.low_link = std::min(data_from.low_link, *data_to.index);
162 }
163 }
164
165 if (data_from.low_link == data_from.index) {
166 std::vector<V> component;
167 for (;;) {
168 auto& X = stack.top();
169 stack.pop();
170 auto& data_x = get_data(X);
171 data_x.on_stack = false;
172 component.push_back(X);
173 if (X == from) {
174 break;
175 }
176 }
177 components.push_back(component);
178 }
179
180 }
181
182 public:
183
184 TarjanSolver(const Graph& graph):
185 graph(graph) {}
186
187 void solve() {
188 for (auto from: graph.get_vertices()) {
189 if (!mapping.count(from)) {
190 visit_cycle(from);
191 }
192 }
193 }
194
195 };
196
197 TarjanSolver S { graph };
198 S.solve();
199 return S.components;
200
201}
202
203ZEN_NAMESPACE_END
204
205#endif // of #ifndef ZEN_GRAPH_HPP
Definition graph.hpp:18
Support for creating ranges over iterators.
auto make_iterator_range(IterT &&a, IterT &&b)
Definition iterator_range.hpp:92
Definition graph.hpp:15