Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Concepts
MM.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
12#include <ext/algorithm>
13
14#include <alib/vector>
15#include <alib/map>
16#include <alib/set>
17#include <alib/tuple>
18
21
22namespace graph {
23
24namespace shortest_path {
25
26class MM {
27// ---------------------------------------------------------------------------------------------------------------------
28
29 public:
30
52 template<
53 typename TGraph,
54 typename TNode,
55 typename F1 = std::function<typename TGraph::edge_type::weight_type(const TNode &)>,
56 typename F2 = std::function<typename TGraph::edge_type::weight_type(const TNode &)>,
57 typename F3 = std::function<void(const TNode &, const typename TGraph::edge_type::weight_type &)>>
58 static
59 ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
60 findPathBidirectional(const TGraph &graph,
61 const TNode &start,
62 const TNode &goal,
63 F1 f_heuristic_forward,
64 F2 f_heuristic_backward,
65 F3 f_user = [](const TNode &,
66 const typename TGraph::edge_type::weight_type &) {});
67
68 template<
69 typename TGraph,
70 typename TNode,
71 typename F1 = std::function<typename TGraph::edge_type::weight_type(const TNode &, const TNode &)>
72 >
73 static
74 ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
76 const TNode &start,
77 const TNode &goal,
78 F1 f_heuristic) {
79 return findPathBidirectional(graph, start, goal,
80 [&](const TNode &n) { return f_heuristic(goal, n); },
81 [&](const TNode &n) { return f_heuristic(start, n); });
82
83 }
84
85
86// =====================================================================================================================
87
88 private:
89
90 template<typename TNode, typename TWeight>
91 struct Data {
92 ext::set<ext::tuple<TWeight, TWeight, TNode>> queue; // priority queue
93
94 ext::set<ext::pair<TWeight, TNode>> f_set; // F score of currently OPEN nodes
95 ext::map<TNode, TWeight> f_map; // F score
96
97 ext::set<ext::pair<TWeight, TNode>> g_set; // G score of currently OPEN nodes
98 ext::map<TNode, TWeight> g_map; // G score
99
100 ext::map<TNode, TNode> p; // parents
101 };
102
103// ---------------------------------------------------------------------------------------------------------------------
104
105 template<typename FSuccEdge, typename TNode, typename TWeight, typename F1, typename F2, typename F3>
106 static void relaxation(FSuccEdge successor_edges,
107 Data<TNode, TWeight> &data,
108 F1 f_heuristic,
109 F2 f_user,
110 F3 f_update);
111
112// ---------------------------------------------------------------------------------------------------------------------
113
114 template<typename TNode, typename TWeight, typename F>
115 inline static void init(MM::Data<TNode, TWeight> &data, const TNode &start, F f_heuristic);
116
117
118
119// ---------------------------------------------------------------------------------------------------------------------
120};
121
122// =====================================================================================================================
123
124template<typename TGraph, typename TNode, typename F1, typename F2, typename F3>
125ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
127 const TNode &start,
128 const TNode &goal,
129 F1 f_heuristic_forward,
130 F2 f_heuristic_backward,
131 F3 f_user) {
132
133 using weight_type = typename TGraph::edge_type::weight_type;
134
135 weight_type eps = common::SupportFunction::getMinEdgeValue(graph); // Smallest value of the weight in graph
136
137 weight_type p = std::numeric_limits<weight_type>::max(); // Currently best path weight
138 ext::vector<TNode> intersection_nodes; // Last one is currently best intersection node
139 Data<TNode, weight_type> forward_data;
140 Data<TNode, weight_type> backward_data;
141
142 // Init forward search
143 init(forward_data, start, f_heuristic_forward);
144 auto f_forward_update = [&](const auto &s) -> void {
145 if (backward_data.g_map.find(s) != backward_data.g_map.end()) {
146 if (forward_data.g_map.at(s) + backward_data.g_map.at(s) < p) {
147 p = forward_data.g_map.at(s) + backward_data.g_map.at(s);
148 intersection_nodes.push_back(s);
149 }
150 }
151 };
152
153 // Init backward search
154 init(backward_data, goal, f_heuristic_backward);
155 auto f_backward_update = [&](const auto &s) -> void {
156 if (forward_data.g_map.find(s) != forward_data.g_map.end()) {
157 if (backward_data.g_map.at(s) + forward_data.g_map.at(s) < p) {
158 p = backward_data.g_map.at(s) + forward_data.g_map.at(s);
159 intersection_nodes.push_back(s);
160 }
161 }
162 };
163
164 while (!forward_data.queue.empty() && !backward_data.queue.empty()) {
165 // Check whether can stop searching
166 if (ext::max(std::min(std::get<0>(*forward_data.queue.begin()),
167 std::get<0>(*backward_data.queue.begin())),
168 forward_data.f_set.begin()->first,
169 backward_data.f_set.begin()->first,
170 forward_data.g_set.begin()->first + backward_data.g_set.begin()->first + eps)
171 >= p) {
173 backward_data.p,
174 forward_data.g_map,
175 backward_data.g_map,
176 start,
177 goal,
178 intersection_nodes.back());
179 }
180
181 // Expand the lower value
182 if (std::get<0>(*forward_data.queue.begin()) < std::get<0>(*backward_data.queue.begin())) {
183 // Forward search
184 relaxation([&](const auto &node) -> auto { return graph.successorEdges(node); },
185 forward_data,
186 f_heuristic_forward,
187 f_user,
188 f_forward_update);
189 } else {
190 // Backward search
191 relaxation([&](const auto &node) -> auto { return graph.predecessorEdges(node); },
192 backward_data,
193 f_heuristic_backward,
194 f_user,
195 f_backward_update);
196 }
197 }
198
200}
201
202// ---------------------------------------------------------------------------------------------------------------------
203
204template<typename FSuccEdge, typename TNode, typename TWeight, typename F1, typename F2, typename F3>
205void MM::relaxation(FSuccEdge successor_edges,
206 MM::Data<TNode, TWeight> &data,
207 F1 f_heuristic,
208 F2 f_user,
209 F3 f_update) {
210 TNode n = std::get<2>(*data.queue.begin());
211 data.queue.erase(data.queue.begin()); // erase from priority queue
212 data.f_set.erase(data.f_set.find(ext::make_pair(data.f_map[n], n))); // erase from f score ordered array
213 data.g_set.erase(data.g_set.find(ext::make_pair(data.g_map[n], n))); // erase from g score ordered array
214
215 // Run user's function
216 f_user(n, data.g_map[n]);
217
218 for (const auto &s_edge: successor_edges(n)) {
219 const TNode &s = common::SupportFunction::other(s_edge, n); // successor
220
221 // Check for negative edge
222 if (s_edge.weight() < 0) {
223 throw std::out_of_range("MM: Detect negative weight on edge in graph.");
224 }
225
226 // Calculate new G score and F score
227 TWeight gscore = data.g_map.at(n) + s_edge.weight();
228
229 // Search if the node s was already visited
230 auto search_g = data.g_map.find(s);
231
232 // If not or the G score can be improve do relaxation
233 if (search_g == data.g_map.end() || data.g_map.at(s) > gscore) {
234 // Search if the node s is in OPEN
235 auto search_q = data.queue.find(ext::make_tuple(std::max(data.f_map[s], 2 * data.g_map[s]), data.g_map[s], s));
236
237 if (search_q != data.queue.end()) {
238 // Erase node from priority queue
239 data.queue.erase(search_q);
240 data.g_set.erase(data.g_set.find(ext::make_pair(data.g_map[s], s)));
241 data.f_set.erase(data.f_set.find(ext::make_pair(data.f_map[s], s)));
242 }
243
244 data.g_map[s] = gscore;
245 data.g_set.insert(ext::make_pair(data.g_map[s], s));
246 data.f_map[s] = gscore + f_heuristic(s);
247 data.f_set.insert(ext::make_pair(data.f_map[s], s));
248 data.p.insert_or_assign(s, n);
249 data.queue.insert(ext::make_tuple(std::max(data.f_map[s], 2 * data.g_map[s]), data.g_map[s], s));
250
251 f_update(s); // Update currently best path
252 }
253 }
254}
255
256// ---------------------------------------------------------------------------------------------------------------------
257
258template<typename TNode, typename TWeight, typename F>
259void MM::init(MM::Data<TNode, TWeight> &data, const TNode &start, F f_heuristic) {
260 data.g_map[start] = 0;
261 data.g_set.insert(ext::make_pair(data.g_map[start], start));
262 data.f_map[start] = data.g_map[start] + f_heuristic(start);
263 data.f_set.insert(ext::make_pair(data.f_map[start], start));
264 data.p.insert_or_assign(start, start);
265 data.queue.insert(ext::make_tuple(std::max(data.f_map[start], 2 * data.g_map[start]),
266 data.g_map[start],
267 start));
268}
269
270// ---------------------------------------------------------------------------------------------------------------------
271
272} // namespace shortest_path
273
274} // namespace graph
275
Class extending the map class from the standard library. Original reason is to allow printing of the ...
Definition: map.hpp:48
Class extending the pair class from the standard library. Original reason is to allow printing of the...
Definition: pair.hpp:43
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
static ext::pair< ext::vector< TNode >, TWeight > reconstructWeightedPath(const ext::map< TNode, TNode > &p, const ext::map< TNode, TWeight > &g, const TNode &start, const TNode &goal)
Definition: ReconstructPath.hpp:132
static TGraph::edge_type::weight_type getMinEdgeValue(const TGraph &graph)
Definition: SupportFunction.hpp:71
static TNode const & other(const TEdge &e, const TNode &n)
Definition: MM.hpp:26
static ext::pair< ext::vector< TNode >, typename TGraph::edge_type::weight_type > findPathBidirectional(const TGraph &graph, const TNode &start, const TNode &goal, F1 f_heuristic_forward, F2 f_heuristic_backward, F3 f_user=[](const TNode &, const typename TGraph::edge_type::weight_type &) {})
Definition: MM.hpp:126
static ext::pair< ext::vector< TNode >, typename TGraph::edge_type::weight_type > findPathBidirectionalRegistration(const TGraph &graph, const TNode &start, const TNode &goal, F1 f_heuristic)
Definition: MM.hpp:75
constexpr const T & max(const T &a)
Root case of maximum computation. The maximum from one value is the value itself.
Definition: algorithm.hpp:278
constexpr const T & min(const T &a)
Definition: algorithm.hpp:310
constexpr auto make_tuple(Elements &&... args)
Helper of extended tuple construction. The tuple is constructed from values pack, types are deduced.
Definition: tuple.hpp:203
constexpr auto make_pair(T1 &&x, T2 &&y)
Definition: pair.hpp:79
Definition: ReconstructPath.hpp:14
void start(measurements::stealth_string name, measurements::Type type)
Definition: measurements.cpp:14
Definition: Node.cpp:11