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-
201#ifndef DIJKSTRA_HPP
212#define DIJKSTRA_HPP
223
23- #include < any >
4+ #include < algorithm >
245#include < cassert>
25- #include < chrono >
26- #include < iostream >
6+ #include < filesystem >
7+ #include < functional >
278#include < limits>
289#include < map>
10+ #include < memory>
2911#include < optional>
3012#include < set>
31- #include < unordered_set>
13+ #include < string>
14+ #include < type_traits>
3215#include < utility>
16+ #include < vector>
17+
18+ #include " boost/heap/fibonacci_heap.hpp"
3319
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);
9344 }
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+ };
106174
107175#endif
0 commit comments