Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
BellmanFord.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 <alib/list>
11#include <alib/set>
12#include <alib/map>
13#include <alib/vector>
14#include <queue>
15#include <stdexcept>
16#include <functional>
17
20
21namespace graph {
22
23namespace shortest_path {
24
26// ---------------------------------------------------------------------------------------------------------------------
27 public:
28
42 template<
43 typename TGraph,
44 typename TNode,
45 typename F = std::function<void(const TNode &,
46 const typename TGraph::edge_type::weight_type &)> >
47 static
48 void
49 run(const TGraph &graph,
50 const TNode &start,
51 F f_user = [](const TNode &,
52 const typename TGraph::edge_type::weight_type &) -> void {});
53
54// ---------------------------------------------------------------------------------------------------------------------
55
72 template<typename TGraph, typename TNode, typename F = std::function<void(const TNode &,
73 const typename TGraph::edge_type::weight_type &)>>
74 static
75 ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
76 findPath(const TGraph &graph,
77 const TNode &start,
78 const TNode &goal,
79 F f_user = [](const TNode &,
80 const typename TGraph::edge_type::weight_type &) {});
81
82 template<typename TGraph, typename TNode>
83 static
84 ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
86 const TNode &start,
87 const TNode &goal) {
88 return findPath(graph, start, goal);
89 }
90
91// =====================================================================================================================
92 private:
93
94 template<typename TNode, typename TWeight>
95 struct Data {
96 ext::map<TNode, TWeight> g; // distance (aka G score)
97 ext::map<TNode, TNode> p; // parents
98 ext::set<TNode> state1; // optimization Yen
99 ext::set<TNode> state2; // optimization Yen
100 };
101
102// ---------------------------------------------------------------------------------------------------------------------
103
104 template<typename TGraph, typename TNode, typename F>
105 static
106 Data<TNode, typename TGraph::edge_type::weight_type>
107 impl(const TGraph &graph,
108 const TNode &start,
109 F f_user);
110
111// ---------------------------------------------------------------------------------------------------------------------
112
113 template<typename TGraph, typename TNode, typename F>
114 static
115 void
116 relaxation(const TGraph &graph,
117 ext::set<TNode> &nodes,
118 BellmanFord::Data<TNode, typename TGraph::edge_type::weight_type> &data,
119 ext::set<TNode> &state1,
120 ext::set<TNode> &state2,
121 F f_user);
122
123// ---------------------------------------------------------------------------------------------------------------------
124
125 template<typename TNode, typename TWeight>
126 inline static void init(BellmanFord::Data<TNode, TWeight> &data, const TNode &start);
127
128// ---------------------------------------------------------------------------------------------------------------------
129
130};
131
132// =====================================================================================================================
133
134template<typename TGraph, typename TNode, typename F>
135void BellmanFord::run(const TGraph &graph, const TNode &start, F f_user) {
136 impl(graph, start, f_user);
137}
138
139// ---------------------------------------------------------------------------------------------------------------------
140
141template<typename TGraph, typename TNode, typename F>
142ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
144 const TNode &start,
145 const TNode &goal,
146 F f_user) {
147 using weight_type = typename TGraph::edge_type::weight_type;
148
149 Data<TNode, weight_type> data = impl(graph, start, f_user);
150
151 if (data.g.find(goal) == data.g.end()) {
153 }
154
155 return ext::make_pair(common::ReconstructPath::reconstructPath(data.p, start, goal), data.g[goal]);
156}
157
158// ---------------------------------------------------------------------------------------------------------------------
159
160template<typename TGraph, typename TNode, typename F>
161BellmanFord::Data<TNode, typename TGraph::edge_type::weight_type>
162BellmanFord::impl(const TGraph &graph, const TNode &start, F f_user) {
163
164 using weight_type = typename TGraph::edge_type::weight_type;
165
166 Data<TNode, weight_type> data;
167
168 // Init data
169 init(data, start);
170
171 // Run user's function
172 f_user(start, 0);
173
174 auto nodes = graph.getNodes();
175 size_t nodes_cnt = nodes.size();
176
177 for (size_t i = 1; i < nodes_cnt; ++i) {
178 if (i % 2 == 1) {
179 data.state2.clear();
180 relaxation(graph, nodes, data, data.state1, data.state2, f_user);
181 } else {
182 data.state1.clear();
183 relaxation(graph, nodes, data, data.state2, data.state1, f_user);
184 }
185
186 if (((i % 2 == 1) && data.state2.empty()) ||
187 ((i % 2 == 0) && data.state1.empty()))
188 break; // Optimization early stop
189 }
190
191 for (const auto &n: nodes) {
192 for (const auto &s_edge: graph.successorEdges(n)) {
193 const TNode &s = common::SupportFunction::other(s_edge, n); // successor
194
195 auto search = data.g.find(s);
196
197 if (search != data.g.end() && data.g.at(n) + s_edge.weight() < data.g.at(s)) {
198 throw std::out_of_range("BellmanFord: Detected negative weight cycle.");
199 }
200 }
201 }
202
203 return data;
204}
205
206// ---------------------------------------------------------------------------------------------------------------------
207
208template<typename TGraph, typename TNode, typename F>
209void BellmanFord::relaxation(const TGraph &graph,
210 ext::set<TNode> &nodes,
211 BellmanFord::Data<TNode, typename TGraph::edge_type::weight_type> &data,
212 ext::set<TNode> &state1,
213 ext::set<TNode> &state2,
214 F f_user) {
215 using weight_type = typename TGraph::edge_type::weight_type;
216
217 for (const auto &n: nodes) {
218
219 if (state1.find(n) == state1.end()) {
220 continue;
221 }
222
223 for (const auto &s_edge: graph.successorEdges(n)) {
224 const TNode &s = common::SupportFunction::other(s_edge, n); // successor
225
226 auto search = data.g.find(s);
227
228 // Relaxation
229 if (search == data.g.end() || data.g.at(n) + s_edge.weight() < data.g.at(s)) {
230 weight_type gscore = data.g.at(n) + s_edge.weight();
231
232 // Run user's function
233 f_user(s, gscore);
234
235 data.g[s] = gscore;
236 data.p.insert_or_assign(s, n);
237
238 state1.insert(s); // Yen optimization
239 state2.insert(s); // Yen optimization
240 }
241 }
242 }
243
244}
245
246// ---------------------------------------------------------------------------------------------------------------------
247
248template<typename TNode, typename TWeight>
249void BellmanFord::init(BellmanFord::Data<TNode, TWeight> &data, const TNode &start) {
250 data.g[start] = 0;
251 data.p.insert(std::make_pair(start, start));
252 data.state1.insert(start);
253}
254
255// ---------------------------------------------------------------------------------------------------------------------
256
257// =====================================================================================================================
258
259} // namespace shortest_path
260
261} // namespace graph
262
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
auto end() &
Inherited behavior of end for non-const instance.
Definition: set.hpp:129
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
static ext::vector< TNode > reconstructPath(const ext::map< TNode, TNode > &p, const TNode &start, const TNode &goal)
Definition: ReconstructPath.hpp:68
static TNode const & other(const TEdge &e, const TNode &n)
Definition: BellmanFord.hpp:25
static ext::pair< ext::vector< TNode >, typename TGraph::edge_type::weight_type > findPathRegistration(const TGraph &graph, const TNode &start, const TNode &goal)
Definition: BellmanFord.hpp:85
static ext::pair< ext::vector< TNode >, typename TGraph::edge_type::weight_type > findPath(const TGraph &graph, const TNode &start, const TNode &goal, F f_user=[](const TNode &, const typename TGraph::edge_type::weight_type &) {})
Definition: BellmanFord.hpp:143
static void run(const TGraph &graph, const TNode &start, F f_user=[](const TNode &, const typename TGraph::edge_type::weight_type &) -> void {})
Definition: BellmanFord.hpp:135
int i
Definition: AllEpsilonClosure.h:118
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 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