Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
BFS.hpp
Go to the documentation of this file.
1
6// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
7
8#pragma once
9
10#include <functional>
11#include <queue>
12#include <alib/map>
13#include <alib/set>
14#include <iostream>
15
17
18namespace graph {
19
20namespace traverse {
21
22class BFS {
23// ---------------------------------------------------------------------------------------------------------------------
24
25 public:
26
36 template<
37 typename TGraph,
38 typename TNode,
39 typename F = std::function<void(const TNode &, const size_t &)>>
40 static
41 void
42 run(const TGraph &graph,
43 const TNode &start,
44 F f_user = [](const TNode &, const size_t &) -> bool { return false; });
45
46// ---------------------------------------------------------------------------------------------------------------------
47
59 template<
60 typename TGraph,
61 typename TNode,
62 typename F = std::function<void(const TNode &, const size_t &)>>
63 static
65 findPath(const TGraph &graph,
66 const TNode &start,
67 const TNode &goal,
68 F f_user = [](const TNode &, const size_t &) {});
69
70 template<typename TGraph, typename TNode>
71 static
74 const TNode &start,
75 const TNode &goal) {
76 return findPath(graph, start, goal);
77
78 }
79
80// ---------------------------------------------------------------------------------------------------------------------
81
94 template<
95 typename TGraph,
96 typename TNode,
97 typename F = std::function<void(const TNode &, const size_t &)>>
98 static
100 findPathBidirectional(const TGraph &graph,
101 const TNode &start,
102 const TNode &goal,
103 F f_user = [](const TNode &, const size_t &) {});
104
105 template<typename TGraph, typename TNode>
106 static
109 const TNode &start,
110 const TNode &goal) {
111 return findPath(graph, start, goal);
112 }
113
114// =====================================================================================================================
115
116 private:
117
118// ---------------------------------------------------------------------------------------------------------------------
119
120 template<typename TNode>
121 struct Data {
122 std::queue<TNode> queue;
126 };
127
128// ---------------------------------------------------------------------------------------------------------------------
129
130 template<typename TGraph, typename TNode, typename F1, typename F2>
131 static
133 implNormal(const TGraph &graph,
134 const TNode &start,
135 const TNode &goal,
136 F1 f_user,
137 F2 f_stop);
138
139// ---------------------------------------------------------------------------------------------------------------------
140
141 template<typename FSucc, typename TNode, typename F1, typename F2>
142 static bool expansion(FSucc successors,
143 Data<TNode> &data,
144 F1 f_user,
145 F2 f_stop);
146
147// ---------------------------------------------------------------------------------------------------------------------
148
149 template<typename TGraph, typename TNode, typename F1>
150 static
152 implBidirectional(const TGraph &graph,
153 const TNode &start,
154 const TNode &goal,
155 F1 f_user);
156
157// ---------------------------------------------------------------------------------------------------------------------
158
159 template<typename TNode>
160 inline static void init(BFS::Data<TNode> &data, const TNode &start);
161
162// ---------------------------------------------------------------------------------------------------------------------
163};
164
165// =====================================================================================================================
166
167template<typename TGraph, typename TNode, typename F>
168void BFS::run(const TGraph &graph, const TNode &start, F f_user) {
169 // goal -> start: in order to avoid call constructor
170 implNormal(graph, start, start, f_user, [](const TNode &) -> bool { return false; });
171}
172
173// ---------------------------------------------------------------------------------------------------------------------
174
175template<typename TGraph, typename TNode, typename F>
177BFS::findPath(const TGraph &graph,
178 const TNode &start,
179 const TNode &goal,
180 F f_user) {
181 return implNormal(graph, start, goal,
182 [&](const TNode &n, const size_t &d) -> bool {
183 f_user(n, d);
184 return false;
185 },
186 [&goal](const TNode &n) -> bool { return goal == n; });
187}
188
189// ---------------------------------------------------------------------------------------------------------------------
190
191template<typename TGraph, typename TNode, typename F>
194 const TNode &start,
195 const TNode &goal,
196 F f_user) {
197 return implBidirectional(graph, start, goal,
198 [&](const TNode &n, const size_t &d) -> bool {
199 f_user(n, d);
200 return false;
201 });
202}
203
204// =====================================================================================================================
205
206// ---------------------------------------------------------------------------------------------------------------------
207
208template<typename TGraph, typename TNode, typename F1, typename F2>
210BFS::implNormal(const TGraph &graph,
211 const TNode &start,
212 const TNode &goal,
213 F1 f_user,
214 F2 f_stop) {
215 Data<TNode> data;
216
217 // Init search
218 init(data, start);
219
220 while (!data.queue.empty()) {
221 bool stop = expansion([&](const TNode &node) { return graph.successors(node); }, data, f_user, f_stop);
222
223 if (stop) {
224 break;
225 }
226
227 }
228
230}
231
232// ---------------------------------------------------------------------------------------------------------------------
233
234template<typename FSucc, typename TNode, typename F1, typename F2>
235bool BFS::expansion(FSucc successors,
236 Data<TNode> &data,
237 F1 f_user,
238 F2 f_stop) {
239 TNode n = data.queue.front();
240 data.queue.pop();
241
242 // Run user's function
243 if (f_user(n, data.d[n])) {
244 return true;
245 }
246
247 // Stop if reach the goal
248 if (f_stop(n)) {
249 return true;
250 }
251
252 for (const auto &s : successors(n)) {
253 if (data.v.count(s) == 0) {
254 data.v.insert(s);
255 data.p.insert_or_assign(s, n);
256 data.queue.push(s);
257 }
258 }
259
260 return false;
261}
262
263// ---------------------------------------------------------------------------------------------------------------------
264
265template<typename TGraph, typename TNode, typename F1>
267BFS::implBidirectional(const TGraph &graph,
268 const TNode &start,
269 const TNode &goal,
270 F1 f_user) {
271 Data<TNode> forward_data;
272 Data<TNode> backward_data;
273 ext::vector<TNode> intersection;
274
275 // Init forward search
276 init(forward_data, start);
277
278 // Init backward search
279 init(backward_data, goal);
280
281 while (!forward_data.queue.empty() && !backward_data.queue.empty()) {
282 // Forward search relaxation
283 bool stop = expansion([&](const TNode &node) { return graph.successors(node); }, forward_data, f_user,
284 [&](const TNode &n) {
285 if (backward_data.v.find(n) != backward_data.v.end()) {
286 intersection.push_back(n);
287 return true;
288 }
289 return false;
290 });
291
292
293 // If there is a intersection, then we can reconstruct path
294 if (stop) {
295 return common::ReconstructPath::reconstructPath(forward_data.p,
296 backward_data.p,
297 start,
298 goal,
299 *intersection.begin());
300 }
301
302 // Backward search relaxation
303 stop = expansion([&](const TNode &node) { return graph.predecessors(node); }, backward_data, f_user,
304 [&](const TNode &n) {
305 if (forward_data.v.find(n) != forward_data.v.end()) {
306 intersection.push_back(n);
307 return true;
308 }
309 return false;
310 });
311
312 // If there is a intersection, then we can reconstruct path
313 if (stop) {
314 return common::ReconstructPath::reconstructPath(forward_data.p,
315 backward_data.p,
316 start,
317 goal,
318 *intersection.begin());
319 }
320 }
321
322 // Path not found -> return empty vector
323 return ext::vector<TNode>();
324}
325
326// ---------------------------------------------------------------------------------------------------------------------
327
328template<typename TNode>
329void BFS::init(BFS::Data<TNode> &data, const TNode &start) {
330 data.queue.push(start);
331 data.v.insert(start);
332 data.p.insert_or_assign(start, start);
333 data.d[start] = 0;
334}
335
336// ---------------------------------------------------------------------------------------------------------------------
337
338} // namespace traverse
339
340} // namespace graph
341
Class extending the map class from the standard library. Original reason is to allow printing of the ...
Definition: map.hpp:48
Definition: set.hpp:44
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
auto begin() &
Inherited behavior of begin for non-const instance.
Definition: vector.hpp:125
static ext::vector< TNode > reconstructPath(const ext::map< TNode, TNode > &p, const TNode &start, const TNode &goal)
Definition: ReconstructPath.hpp:68
Definition: BFS.hpp:22
static ext::vector< TNode > findPath(const TGraph &graph, const TNode &start, const TNode &goal, F f_user=[](const TNode &, const size_t &) {})
Definition: BFS.hpp:177
static void run(const TGraph &graph, const TNode &start, F f_user=[](const TNode &, const size_t &) -> bool { return false;})
Definition: BFS.hpp:168
static ext::vector< TNode > findPathBidirectional(const TGraph &graph, const TNode &start, const TNode &goal, F f_user=[](const TNode &, const size_t &) {})
Definition: BFS.hpp:193
static ext::vector< TNode > findPathBidirectionalRegistration(const TGraph &graph, const TNode &start, const TNode &goal)
Definition: BFS.hpp:108
static ext::vector< TNode > findPathRegistration(const TGraph &graph, const TNode &start, const TNode &goal)
Definition: BFS.hpp:73
Definition: ReconstructPath.hpp:14
void start(measurements::stealth_string name, measurements::Type type)
Definition: measurements.cpp:14
Definition: Node.cpp:11