Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
SPFA.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#include <algorithm>
18
21
22namespace graph {
23
24namespace shortest_path {
25
26class SPFA {
27// ---------------------------------------------------------------------------------------------------------------------
28 public:
29
43 template<
44 typename TGraph,
45 typename TNode,
46 typename F = std::function<void(const TNode &,
47 const typename TGraph::edge_type::weight_type &)> >
48 static
49 void
50 run(const TGraph &graph,
51 const TNode &start,
52 F f_user = [](const TNode &,
53 const typename TGraph::edge_type::weight_type &) -> void {});
54
55// ---------------------------------------------------------------------------------------------------------------------
56
73 template<typename TGraph, typename TNode, typename F = std::function<void(const TNode &,
74 const typename TGraph::edge_type::weight_type &)>>
75 static
76 ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
77 findPath(const TGraph &graph,
78 const TNode &start,
79 const TNode &goal,
80 F f_user = [](const TNode &,
81 const typename TGraph::edge_type::weight_type &) {});
82
83 template<typename TGraph, typename TNode>
84 static
85 ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type>
87 const TNode &start,
88 const TNode &goal) {
89 return findPath(graph, start, goal);
90 }
91
92// =====================================================================================================================
93 private:
94
95 template<typename TNode, typename TWeight>
96 struct Data {
97 std::deque<TNode> q; // queue
98 ext::map<TNode, TWeight> g; // distance (aka G score)
99 ext::map<TNode, TNode> p; // parents
100 ext::map<TNode, size_t> v; // visits
101 };
102
103// ---------------------------------------------------------------------------------------------------------------------
104
105 template<typename TGraph, typename TNode, typename F>
106 static
107 Data<TNode, typename TGraph::edge_type::weight_type>
108 impl(const TGraph &graph,
109 const TNode &start,
110 F f_user);
111
112// ---------------------------------------------------------------------------------------------------------------------
113
114 template<typename TNode, typename TWeight>
115 inline static void init(SPFA::Data<TNode, TWeight> &data, const TNode &start);
116
117// ---------------------------------------------------------------------------------------------------------------------
118
119};
120
121// =====================================================================================================================
122
123template<typename TGraph, typename TNode, typename F>
124void SPFA::run(const TGraph &graph, const TNode &start, F f_user) {
125 impl(graph, start, f_user);
126}
127
128// ---------------------------------------------------------------------------------------------------------------------
129
130template<typename TGraph, typename TNode, typename F>
131ext::pair<ext::vector<TNode>, typename TGraph::edge_type::weight_type> SPFA::findPath(const TGraph &graph,
132 const TNode &start,
133 const TNode &goal,
134 F f_user) {
135 using weight_type = typename TGraph::edge_type::weight_type;
136
137 Data<TNode, weight_type> data = impl(graph, start, f_user);
138 return common::ReconstructPath::reconstructWeightedPath(data.p, data.g, start, goal);
139}
140
141// ---------------------------------------------------------------------------------------------------------------------
142
143template<typename TGraph, typename TNode, typename F>
144SPFA::Data<TNode, typename TGraph::edge_type::weight_type>
145SPFA::impl(const TGraph &graph, const TNode &start, F f_user) {
146 using weight_type = typename TGraph::edge_type::weight_type;
147
148 Data<TNode, weight_type> data;
149
150 auto nodes = graph.getNodes();
151 size_t nodes_cnt = nodes.size();
152
153 // Init data
154 init(data, start);
155
156 while (!data.q.empty()) {
157 TNode n = data.q.front();
158 data.q.pop_front();
159
160 ++data.v[n];
161
162 // Run user's function
163 f_user(n, data.g[n]);
164
165 if (data.v[n] >= nodes_cnt) {
166 throw std::out_of_range("SPFA: Detect negative cycle in graph.");
167 }
168
169 for (const auto &s_edge: graph.successorEdges(n)) {
170 const TNode &s = common::SupportFunction::other(s_edge, n); // successor
171
172 // Calculate new G score
173 weight_type gscore = data.g.at(n) + s_edge.weight();
174
175 // Search if the node s was already visited
176 auto search_d = data.g.find(s);
177
178 // If not or the distance can be improve do relaxation
179 if (search_d == data.g.end() || search_d->second > gscore) {
180
181 data.g[s] = gscore;
182 data.p.insert_or_assign(s, n);
183
184 // More effective than code below
185 data.q.push_back(s);
186 // Not effective at all
187// auto search_q = std::find(data.q.begin(), data.q.end(), s);
188// if (search_q == data.q.end()) {
189// data.q.push_back(s);
190// }
191 }
192 }
193 }
194
195 return data;
196}
197
198// ---------------------------------------------------------------------------------------------------------------------
199
200template<typename TNode, typename TWeight>
201void SPFA::init(SPFA::Data<TNode, TWeight> &data, const TNode &start) {
202 data.q.push_back(start);
203 data.v[start] = 1;
204 data.g[start] = 0;
205 data.p.insert_or_assign(start, start);
206}
207
208// ---------------------------------------------------------------------------------------------------------------------
209
210} // namespace shortest_path
211
212} // namespace graph
213
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
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 TNode const & other(const TEdge &e, const TNode &n)
Definition: SPFA.hpp:26
static ext::pair< ext::vector< TNode >, typename TGraph::edge_type::weight_type > findPathRegistration(const TGraph &graph, const TNode &start, const TNode &goal)
Definition: SPFA.hpp:86
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: SPFA.hpp:131
static void run(const TGraph &graph, const TNode &start, F f_user=[](const TNode &, const typename TGraph::edge_type::weight_type &) -> void {})
Definition: SPFA.hpp:124
q
Definition: SingleInitialStateEpsilonTransition.h:85
Definition: ReconstructPath.hpp:14
void start(measurements::stealth_string name, measurements::Type type)
Definition: measurements.cpp:14