C++ Library Extensions 2022.12.09
To help learn modern C++ programming
060-graph02.hpp
Go to the documentation of this file.
1#include <tpf_set.hpp>
2
3namespace tpf
4{
5 template<typename ElementType, typename NodeIndexType,
6 template<typename, typename...> class NodeContainerType,
7 template<typename, typename...> class IndexContainerType>
8 class graph
9 {
10 public:
11 using element_t = ElementType;
12 using index_t = NodeIndexType;
13 using index_container_t = IndexContainerType<index_t>; // container type for node indices
14 using node_container_t = NodeContainerType<index_container_t>; // container type for nodes
15 using element_container_t = NodeContainerType<element_t>; // container type for node values
16
17 using ref_element_container_t = NodeContainerType<std::reference_wrapper<element_t>>;
18 using const_ref_element_container_t = NodeContainerType<std::reference_wrapper<const element_t>>;
19
20 using node_ref_t = std::tuple<ElementType&, index_container_t&>;
21 using const_node_ref_t = std::tuple<const ElementType&, const index_container_t&>;
22
23 using node_info_t = std::tuple<const ElementType&, const_ref_element_container_t>;
24
25 enum class visit_mode: int { graph, visit_bfs, visit_dfs };
26
27 private:
28
29 node_container_t m_nodes; // container for node list
30 element_container_t m_values; // container for each node's value
31
32 public:
33
34 auto begin() { return this->m_nodes.begin(); }
35 auto end() { return this->m_nodes.end(); }
36
37 auto cbegin() { return this->m_nodes.cbegin(); }
38 auto cend() { return this->m_nodes.cend(); }
39
40 bool empty() const { return this->m_nodes.empty(); }
41
42 decltype(auto) adjacency_node_list(size_t node_index)
43 {
44 return tpf::element<node_container_t&>(m_nodes, node_index);
45 }
46
47 decltype(auto) adjacency_node_list(size_t node_index) const
48 {
49 return tpf::element<const node_container_t&>(m_nodes, node_index);
50 }
51
52 const node_container_t& node_lists() const { return this->m_nodes; }
53 const element_container_t& values() const { return this->m_values; }
54
55 auto adjacent_node_values(size_t node_index)
56 {
58 auto indices = tpf::element<node_container_t&>(m_nodes, node_index);
59
60 for(auto& idx: indices)
61 {
62 auto& value = tpf::element<element_container_t&>(m_values, idx);
63 elements.emplace_back(std::ref(value));
64 }
65
66 return elements;
67 }
68
69 auto adjacent_node_values(size_t node_index) const
70 {
72 auto indices = tpf::element<const node_container_t&>(m_nodes, node_index);
73
74 for(auto& idx: indices)
75 {
76 auto& value = tpf::element<const element_container_t&>(m_values, idx);
77 elements.emplace_back(std::cref(value));
78 }
79
80 return elements;
81 }
82
83 decltype(auto) node_value(size_t node_index)
84 {
85 return tpf::element<element_container_t&>(m_values, node_index);
86 }
87
88 decltype(auto) node_value(size_t node_index) const
89 {
90 return tpf::element<const element_container_t&>(m_values, node_index);
91 }
92
93 node_info_t node_info(size_t node_index) const
94 {
96 auto indices = tpf::element<const node_container_t&>(m_nodes, node_index);
97
98 for(auto& idx: indices)
99 {
100 auto& value = tpf::element<const element_container_t&>(m_values, idx);
101 elements.emplace_back(std::cref(value));
102 }
103
104 return { node_value(node_index), std::move(elements) };
105 }
106
108 {
109 os << "node_"<<index; return os;
110 }
111
113 {
114 auto& value = this->node_value(index);
115
116 get_node_name(os, index) << " [ label =\""
117 << value << "\"];";
118
119 return os;
120 }
121
122 tpf::sstream& build_graph_edges(tpf::sstream& os, visit_mode vmode = visit_mode::graph)
123 {
124 size_t size = this->m_nodes.size();
125
126 for(size_t i=0; i <size; ++i)
127 {
128 get_node_definition(os, i) << "\n";
129 }
130
131 os << "\n";
132
133 using set_t = std::vector<index_t>;
134 using sets_t = std::vector<set_t>;
135
136 sets_t sets;
137
138 for(size_t i = 0; i < size; ++i)
139 {
140 auto nodes = this->adjacency_node_list(i);
141 for(const auto& v: nodes)
142 {
143 set_t s{(index_t)i}; s.emplace_back(v);
144 sets.push_back(s);
145 }
146 }
147
149
150 for(auto& s: sets)
151 {
152 get_node_name(os, s[0]);
153
154 if(vmode == visit_mode::graph)
155 os << " -- ";
156 else
157 os << " -> ";
158
159 get_node_name(os, s[1]);
160
161 if(vmode != visit_mode::graph)
162 os << " [dir=none, color=red, style=dashed] ; \n";
163 else
164 os << " ; \n";
165 }
166
167 if(vmode != visit_mode::graph)
168 {
169
170 std::vector<index_t> visit_order;
171
172 if(vmode == visit_mode::visit_bfs)
173 visit_order = traverse_bfs();
174 else
175 visit_order = traverse_dfs();
176
177 if(visit_order.size() > 1)
178 {
179 os << "\n";
180
181 for(size_t i = 1; i < visit_order.size(); ++i )
182 {
183 get_node_name(os, (size_t)visit_order[i-1]);
184 os << " -> ";
185 get_node_name(os, (size_t)visit_order[i]);
186
187 os << " [ color = blue ] ; \n";
188 }
189 }
190 }
191 return os;
192 }
193
194 std::string build_graph(visit_mode vmode = visit_mode::graph)
195 {
196 if(vmode == visit_mode::graph)
197 {
198 tpf::sstream os;
199
200 os << "graph G {\n";
201 os << "label=\"Plain Graph\"\n";
202
204
205 os << "}";
206
207 return os.str();
208 }
209 else
210 {
211 tpf::sstream os;
212
213 os << "digraph G {\n";
214
215 if(vmode == visit_mode::visit_bfs)
216 os << "label=\"Breadth First Search\"\n";
217 else
218 os << "label=\"Depth First Search\"\n";
219
220 build_graph_edges(os, vmode);
221
222 os << "}";
223
224 return os.str();
225 }
226 }
227
228 graph() = default;
229
230 size_t size() { return this->m_nodes.size(); }
231
232 template<typename EleType, typename Type, typename... Types>
233 void emplace_back(EleType&& value, Type&& index0, Types&&... indices)
234 {
235 auto v = tpf::make_random_access_container<IndexContainerType>((NodeIndexType)std::forward<Type>(index0),
236 (NodeIndexType)std::forward<Types>(indices)...);
238
239 this->m_nodes.emplace_back(std::move(v));
240 this->m_values.emplace_back(std::forward<EleType>(value));
241 }
242
243 auto operator[](size_t node_index)
244 {
245 return node_ref_t{ tpf::element<element_container_t&>(this->m_values, node_index),
246 tpf::element<node_container_t&>(this->m_nodes, node_index) };
247 }
248
249 auto operator[](size_t node_index) const
250 {
251 return const_node_ref_t{ tpf::element<const element_container_t&>(this->m_values, node_index),
252 tpf::element<const node_container_t&>(this->m_nodes, node_index) };
253 }
254
255 std::vector<index_t> traverse_bfs(index_t start = 0)
256 {
258 auto endl = tpf::endl;
259
260 std::deque<index_t> queue;
261 std::vector<char> visited(m_nodes.size());
262 std::vector<index_t> traversal;
263
264 for(auto& v: visited) v = 0;
265 queue.push_back(start);
266
267 visited[(size_t)start] = 1;
268
269 while(!queue.empty())
270 {
271 auto p = queue.front();
272 queue.pop_front();
273
274 traversal.push_back(p);
275
276 auto node_list = this->adjacency_node_list((size_t)p);
277 for(auto& node: node_list)
278 {
279 if(visited[(size_t)node] == 0)
280 {
281 queue.push_back(node);
282 visited[(size_t)node] = 1;
283
284 }
285 }
286 }
287
288 return traversal;
289 }
290
291 void push_stack(std::deque<index_t>& stack,
292 std::vector<char>& visited,
293 size_t node_index)
294 {
295 index_container_t& node_list
296 = this->adjacency_node_list(node_index);
297
298 for(const auto& node: node_list)
299 {
300 if(visited[(size_t)node] != 1)
301 {
302 stack.push_front(node);
303 visited[(size_t)node] = 1;
304 }
305 }
306 }
307
308 std::vector<index_t> traverse_dfs(index_t start=0)
309 {
311 auto endl = tpf::endl;
312
313 std::deque<index_t> stack;
314 std::vector<char> visited(this->m_nodes.size());
315 std::vector<index_t> traversal;
316
317 for(auto& v: visited) v = 0;
318
319 push_stack(stack, visited, (size_t)start);
320
321 while(!stack.empty())
322 {
323 traversal.push_back(stack.front());
324 stack.pop_front();
325 push_stack(stack, visited, (size_t)traversal.back());
326 }
327
328 return traversal;
329 }
330
332 {
333 if(g.m_nodes.empty())
334 {
335 os << "--------\n";
336 os << " empty \n";
337 os << "--------\n";
338
339 return os;
340 }
341
342 auto last_itr = g.m_nodes.cend();
343
344 os << "--------\n";
345
347
348 size_t index = 0;
349
350 for(auto itr = g.m_nodes.cbegin(); itr != g.m_nodes.cend(); ++itr)
351 os << std::setw(3) << index << " - ("
352 << tpf::element<const element_container_t&>(g.m_values, index++)<<") " << *itr << "\n";
353
354 os << "--------";
355
356 return os;
357 }
358 };
359
360 template<typename ElementType = int, typename NodeIndexType = int,
361 template<typename, typename...> class NodeContainerType = std::list,
362 template<typename, typename...> class IndexContainerType = std::vector>
363 using graph_t = graph<ElementType, NodeIndexType, NodeContainerType, IndexContainerType>;
364
365} // end of namespace tpf
reference_wrapper< Type > ref(Type &val) noexcept
tpf::sstream stream
std::tuple< const ElementType &, const_ref_element_container_t > node_info_t
Definition: 059-graph01.hpp:23
const element_container_t & values() const
Definition: 060-graph02.hpp:53
bool empty() const
Definition: 060-graph02.hpp:40
size_t size()
NodeContainerType< std::reference_wrapper< element_t > > ref_element_container_t
Definition: 059-graph01.hpp:17
tpf::sstream & build_graph_edges(tpf::sstream &os, visit_mode vmode=visit_mode::graph)
std::vector< index_t > traverse_dfs(index_t start=0)
std::string build_graph(visit_mode vmode=visit_mode::graph)
graph()=default
std::vector< index_t > traverse_bfs(index_t start=0)
decltype(auto) node_value(size_t node_index) const
Definition: 060-graph02.hpp:88
auto adjacent_node_values(size_t node_index) const
Definition: 060-graph02.hpp:69
std::tuple< const ElementType &, const index_container_t & > const_node_ref_t
Definition: 059-graph01.hpp:21
decltype(auto) adjacency_node_list(size_t node_index)
Definition: 060-graph02.hpp:42
tpf::sstream & get_node_name(tpf::sstream &os, size_t index)
NodeIndexType index_t
Definition: 059-graph01.hpp:12
tpf::sstream & get_node_definition(tpf::sstream &os, size_t index)
decltype(auto) adjacency_node_list(size_t node_index) const
Definition: 060-graph02.hpp:47
auto operator[](size_t node_index)
void emplace_back(EleType &&value, Type &&index0, Types &&... indices)
NodeContainerType< std::reference_wrapper< const element_t > > const_ref_element_container_t
Definition: 059-graph01.hpp:18
NodeContainerType< index_container_t > node_container_t
Definition: 059-graph01.hpp:14
auto operator[](size_t node_index) const
std::tuple< ElementType &, index_container_t & > node_ref_t
Definition: 059-graph01.hpp:20
auto begin()
Definition: 060-graph02.hpp:34
decltype(auto) node_value(size_t node_index)
Definition: 060-graph02.hpp:83
friend tpf::sstream & operator<<(tpf::sstream &os, const graph &g)
auto end()
Definition: 060-graph02.hpp:35
auto cbegin()
Definition: 060-graph02.hpp:37
void push_stack(std::deque< index_t > &stack, std::vector< char > &visited, size_t node_index)
auto adjacent_node_values(size_t node_index)
Definition: 060-graph02.hpp:55
auto cend()
Definition: 060-graph02.hpp:38
NodeContainerType< element_t > element_container_t
Definition: 059-graph01.hpp:15
const node_container_t & node_lists() const
Definition: 060-graph02.hpp:52
node_info_t node_info(size_t node_index) const
Definition: 060-graph02.hpp:93
IndexContainerType< index_t > index_container_t
Definition: 059-graph01.hpp:13
std::string str() const
Definition: tpf_output.hpp:951
types::enable_if_container_type_t< ContainerType< EleType, Types... >, bool > sort_in_place(ContainerType< EleType, Types... > &container, sort_order order=sort_order::ascending, sort_method method=sort_method::size)
Definition: tpf_set.hpp:376
Includes subnamespace conversion.
Definition: 31-visit.cpp:7
typename SetTagType::set_t set_t
Definition: tpf_types.hpp:1966
constexpr auto endl
Definition: tpf_output.hpp:973
typename SetTagType::sets_t sets_t
Definition: tpf_types.hpp:1969
Implements set operations.