Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
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