1
- /*
2
- * @author Antoine "Anthony" Sébert
3
- * @description Implementation of Dijkstra's algorithm in C++17 as a single header library using a fibonacci heap and named tuples
4
- * @note in this implementation, the weights are positives
5
- * @date 01/04/2018
6
- * @todo Spécialisation de l'algorithme : arrêter la recherche lorsque l'égalité s(1) = s(fin) est vérifiée, dans le cas où on ne cherche que la distance minimale entre s(deb) et s(fin)
7
- * 1 S ← empty sequence
8
- * 2 u ← target
9
- * 3 while prev[u] is defined: // Construct the shortest path with a stack S
10
- * 4 insert u at the beginning of S // Push the vertex onto the stack
11
- * 5 u ← prev[u] // Traverse from target to source
12
- * 6 insert u at the beginning of S // Push the source onto the stack
13
- * https://www.cl.cam.ac.uk/teaching/1112/AlgorithII/1987-FredmanTar-fibonacci.pdf
14
- */
15
-
16
- #if 201703L <= __cplusplus
17
- #error This library needs at least a C++17 compliant compiler
18
- #endif
19
-
20
1
#ifndef DIJKSTRA_HPP
21
2
#define DIJKSTRA_HPP
22
3
23
- #include < any >
4
+ #include < algorithm >
24
5
#include < cassert>
25
- #include < chrono >
26
- #include < iostream >
6
+ #include < filesystem >
7
+ #include < functional >
27
8
#include < limits>
28
9
#include < map>
10
+ #include < memory>
29
11
#include < optional>
30
12
#include < set>
31
- #include < unordered_set>
13
+ #include < string>
14
+ #include < type_traits>
32
15
#include < utility>
16
+ #include < vector>
17
+
18
+ #include " boost/heap/fibonacci_heap.hpp"
33
19
34
- #include " ../../fiboheap/fiboheap.hpp"
35
-
36
- namespace std {
37
- template <typename T>
38
- using graph = set<map<unsigned int , T>>;
39
-
40
- template <typename T>
41
- using graph_iterator = typename graph<T>::iterator;
42
-
43
- template <typename T>
44
- using graph_const_iterator = typename graph<T>::const_iterator;
45
- }
46
-
47
- namespace std {
48
- template <class T , class = void >
49
- struct is_iterator : false_type {};
50
- template <class T >
51
- struct is_iterator <T, void_t <typename iterator_traits<T>::iterator_category>> : true_type { };
52
-
53
- template <typename Iter>
54
- bool check_range (const Iter first, const Iter second) {
55
- static_cast <void >(first == second); // ill-formed compilation if iterators are not comparable, making it fail
56
- return is_iterator<Iter>();
57
- }
58
-
59
- template <typename T = unsigned int >
60
- pair<optional<any>, chrono::duration<double >> dijkstra (const graph<typename T>& data, graph_iterator<typename T> Source, graph_iterator<typename T> Arr) {
61
- /*
62
- if(data.empty() == false)
63
- return pair<optional<any>, chrono::duration<double>>();
64
- */
65
- // Initialization
66
- check_range (Source, Arr);
67
-
68
- auto start = chrono::high_resolution_clock::now ();
69
-
70
- fibonacci_heap::fibonacci_heap<unsigned int > queue = fibonacci_heap::fibonacci_heap<unsigned int >();
71
- vector<T> distances (data.size (), numeric_limits<unsigned int >::max ());
72
- // distances.at(distance(Source, data.begin())) = 0;
73
- unordered_set<optional<unsigned int >> path;
74
-
75
- assert (data.size () == distances.size ());
76
-
77
- unsigned int i = 0 ;
78
- for (const auto & element : data) {
79
- // typeid(element).name();
80
- // queue.push(element, distances.at(i));
81
- ++i;
82
- }
83
-
84
-
85
- while (!queue.empty ()) { // The main loop
86
- auto u = queue.extract_min (); // Remove and return best vertex
87
- // for(const auto& vertex : (data.begin() + u->payload)) { // only v that is still in Q
88
- /*
89
- if(unsigned int alt = dist[u] + length(u, vertex); alt < dist[vertex]) {
90
- dist[vertex] = alt;
91
- prev[vertex] = u;
92
- queue.decrease_priority(vertex, alt);
20
+ /*
21
+ * @author Antoine Sébert
22
+ * @description Implementation of Dijkstra's algorithm in C++17 as a single
23
+ * header library using a fibonacci heap
24
+ */
25
+ namespace dijkstra {
26
+ using namespace std ;
27
+ using namespace boost ::heap;
28
+ namespace fs = std::filesystem;
29
+
30
+ enum class Direction : uint8_t {
31
+ DIRECTED,
32
+ UNDIRECTED,
33
+ };
34
+
35
+ template <typename W, class = enable_if_t <is_integral_v<W>>>
36
+ class Graph {
37
+ public:
38
+ struct Node {
39
+ map<string, W> neighbors = {};
40
+ };
41
+ struct comparator {
42
+ bool operator () (const pair<string, W>& lhs, const pair<string, W>& rhs) const {
43
+ return get<1 >(lhs) > get<1 >(rhs);
93
44
}
94
- */
95
- // }
96
- }
97
-
98
- auto end = chrono::high_resolution_clock::now ();
99
- chrono::duration<double > elapsed_time = end - start;
100
- cout << " elapsed time: " << elapsed_time.count () << " s" << endl;
101
-
102
- // return dist, prev
103
- return pair<optional<any>, chrono::duration<double >>();
104
- }
105
- }
45
+ };
46
+ private:
47
+ map<string, Node> nodes;
48
+ Direction dir;
49
+
50
+ public:
51
+ Graph (Direction _dir = Direction::UNDIRECTED) noexcept : nodes({}), dir(_dir) {}
52
+
53
+ Direction get_direction () const noexcept {
54
+ return dir;
55
+ }
56
+
57
+ const map<string, Node>& get_nodes () const noexcept {
58
+ return nodes;
59
+ }
60
+
61
+ void add_node (string label) {
62
+ if (!contains (label))
63
+ nodes[label] = {};
64
+ }
65
+
66
+ Graph add_node (string label, const map<string, W>& neighbors) {
67
+ add_node (label);
68
+
69
+ for (const auto & [neighbor, weight] : neighbors)
70
+ add_edge (label, neighbor, weight);
71
+
72
+ if (dir == Direction::UNDIRECTED)
73
+ for (const auto & [neighbor, weight] : neighbors)
74
+ add_edge (neighbor, label, weight);
75
+ }
76
+
77
+ void remove_node (string label) {
78
+ nodes.erase (label);
79
+
80
+ for (auto & [_, node] : nodes)
81
+ node.neighbors .erase (label);
82
+ }
83
+
84
+ void add_edge (string label0, string label1, W weight = W(0 )) {
85
+ add_node (label0);
86
+ add_node (label1);
87
+
88
+ nodes.at (label0).neighbors [label1] = weight;
89
+
90
+ if (dir == Direction::UNDIRECTED)
91
+ nodes.at (label1).neighbors [label0] = weight;
92
+ }
93
+
94
+ bool remove_edge (string label0, string label1) {
95
+ if (has_neighbor (label0, label1)) {
96
+ nodes.at (label0).neighbors .erase (label1);
97
+
98
+ if (dir == Direction::UNDIRECTED && has_neighbor (label1, label0))
99
+ nodes.at (label1).neighbors .erase (label0);
100
+
101
+ return true ;
102
+ }
103
+
104
+ return false ;
105
+ }
106
+
107
+ inline bool contains (string label) const {
108
+ return nodes.find (label) != nodes.end ();
109
+ }
110
+
111
+ bool empty () const {
112
+ return nodes.empty ();
113
+ }
114
+
115
+ bool has_neighbor (string label0, string label1) const {
116
+ return contains (label0) && contains (label1)
117
+ && nodes.at (label0).neighbors .find (label1) != nodes.at (label0).neighbors .end ();
118
+ }
119
+
120
+ fs::path find (string src, string dst) const {
121
+ assertions (src, dst);
122
+
123
+ auto preds = map<string, string>();
124
+ auto heap = fibonacci_heap<pair<string, W>, compare<comparator>>();
125
+ auto handles = map<string, decltype (heap)::handle_type>();
126
+
127
+ for (auto & [label, _] : nodes)
128
+ handles[label] = heap.push (make_pair (label, label == src ? 0 : numeric_limits<W>::max ()));
129
+
130
+ while (!heap.empty ()) {
131
+ auto & [nearest, distance] = heap.top ();
132
+
133
+ if (nearest == dst)
134
+ break ;
135
+
136
+ for (auto & [neighbor, weight] : nodes.at (nearest).neighbors )
137
+ if (handles.find (neighbor) != handles.end ())
138
+ if (W alt = distance + weight; alt < get_distance (heap, neighbor)) {
139
+ preds[neighbor] = nearest;
140
+ heap.update (handles.at (neighbor), make_pair (neighbor, alt));
141
+ }
142
+
143
+ handles.erase (nearest);
144
+ heap.pop ();
145
+ }
146
+
147
+ return preds_to_path (preds, src, dst);
148
+ }
149
+
150
+ private:
151
+ W get_distance (fibonacci_heap<pair<string, W>, compare<comparator>>& heap, string label) const {
152
+ return find_if (heap.begin (), heap.end (), [&](const auto & e) { return get<0 >(e) == label; })->second ;
153
+ }
154
+ void assertions (string src, string dst) const {
155
+ assert ((" The graph is empty" , !empty ()));
156
+ assert ((" The source node is not in the graph" , contains (src)));
157
+ assert ((" The destination node is not in the graph" , contains (dst)));
158
+ assert ((" The source and destinatino are the same" , dst != src));
159
+ }
160
+
161
+ fs::path preds_to_path (const map<string, string>& preds, string src, string dst) const {
162
+ vector<string> reverse_path = { dst };
163
+ while (reverse_path.back () != src)
164
+ reverse_path.push_back (preds.at (reverse_path.back ()));
165
+
166
+ auto _path = fs::path ();
167
+ for (auto it = reverse_path.rbegin (); it != reverse_path.rend (); it++)
168
+ _path /= *it;
169
+
170
+ return _path;
171
+ }
172
+ };
173
+ };
106
174
107
175
#endif
0 commit comments