Skip to content

Commit 1813730

Browse files
committed
remake + finish + test
1 parent 235fba3 commit 1813730

File tree

1 file changed

+162
-94
lines changed

1 file changed

+162
-94
lines changed

src/dijkstra.hpp

Lines changed: 162 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,175 @@
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

Comments
 (0)