1#ifndef GRAPHLIB_ALGORITHMS_DIJKSTRA_H
2#define GRAPHLIB_ALGORITHMS_DIJKSTRA_H
9#include <unordered_map>
24template <val
id_weighted_graph_type G>
41 assert(graph.node_count() > 0);
42 assert(graph.node_exists(start));
44 frontier.push(priority_pair_type(edge_weight_type {}, start));
45 node_lookup[start] = {start, edge_weight_type {}};
72 return {best, node_lookup.at(best).first};
87 if (!(other.graph == graph && other.start == start && other.done == done))
92 return other.iterations == iterations;
97 return !(*
this == other);
107 return node_lookup.at(node).first;
115 return node_lookup.at(node).second;
123 return node_lookup.contains(node);
129 using edge_weight_type =
typename G::edge_type::weight_type;
131 using priority_queue_type =
132 std::priority_queue<priority_pair_type, std::vector<priority_pair_type>, std::greater<priority_pair_type>>;
137 unsigned long iterations {0};
140 std::unordered_map<value_type, std::pair<value_type, edge_weight_type>> node_lookup {};
143 std::set<value_type> closed_nodes {};
149 priority_queue_type frontier {};
160 const auto [best_cost, best_node] = frontier.top();
162 const auto best_neighbors = graph.get_neighbors(best_node);
165 for (
auto const node : best_neighbors) {
166 if (closed_nodes.contains(node))
169 if (graph.get_edge(best_node, node).weight < 0)
170 throw std::out_of_range(
"Graph with negative edge weight not permitted");
172 const auto new_cost = best_cost + graph.get_edge_weight(best_node, node);
173 if (!(node_lookup.contains(node) && new_cost >= node_lookup[node].second)) {
174 node_lookup[node] = {best_node, new_cost};
175 frontier.push(priority_pair_type(new_cost, node));
179 closed_nodes.insert(best_node);
182 while (!frontier.empty() && closed_nodes.contains(frontier.top().value)) {
186 if (frontier.empty())
208template <Internal::val
id_weighted_graph_type G>
209G
dijkstra(
const G& graph,
const typename G::id_type start)
211 if (!graph.node_exists(start))
212 throw std::invalid_argument(
"Start node not in the passed graph");
214 auto spanning_tree = G {};
217 for (
const auto [best, best_pred] : explorer) {
218 spanning_tree.add_node_with_id(best, graph.get_node_data(best));
220 const auto edge = graph.get_edge(best_pred, best);
221 spanning_tree.add_edge(best_pred, best, edge.weight);
225 return spanning_tree;
237template <Internal::val
id_weighted_graph_type G>
238std::optional<std::list<typename G::id_type>>
uniform_cost_search(
const G& graph,
const typename G::id_type start,
239 const typename G::id_type target)
241 if (!(graph.node_exists(start) && graph.node_exists(start)))
242 throw std::invalid_argument(
"Start and/or target node not in the passed graph");
246 for (; explorer != explorer.end(); ++explorer)
247 if ((*explorer).first == target)
250 if (!explorer.has_seen(target))
253 auto path = std::list<typename G::id_type> {};
254 path.push_front(target);
256 typename G::id_type current = target;
257 while (current != start) {
258 current = explorer.get_current_pred(current);
259 path.push_front(current);
Iterator that incrementally explores the shortest paths from a start node using Dijkstra's algorithm.
std::ptrdiff_t difference_type
const DijkstraIterator end() const
Returns an iterator that marks the end of the traversal.
const DijkstraIterator begin() const
Returns an iterator at the beginning of the Dijkstra traversal.
std::pair< value_type, value_type > operator*() const
Returns the current node and its predecessor on the shortest path.
value_type get_current_cost(const value_type node) const
Returns the current cost to reach a node from the start.
bool has_seen(const value_type node) const
Checks whether a node has been encountered during traversal.
value_type get_current_pred(const value_type node) const
Returns the current predecessor of a node in the shortest path tree.
void perform_update()
Performs one iteration of the Dijkstra algorithm, expanding the best node.
G::id_type value_type
Type used to represent node identifiers, as defined by the graph type.
DijkstraIterator & operator++()
Advances the iterator to the next node in the shortest path tree.
DijkstraIterator(const G &graph, const value_type start)
Constructs a Dijkstra iterator starting at a given node.
Defines C++20 concepts used for type constraints in the GraphLib library.
std::optional< std::list< typename G::id_type > > uniform_cost_search(const G &graph, const typename G::id_type start, const typename G::id_type target)
Finds the lowest-cost path from start to target using Dijkstra's algorithm.
G dijkstra(const G &graph, const typename G::id_type start)
Computes the shortest-path spanning tree from a start node using Dijkstra's algorithm.
A pair combining a priority and a value, supporting comparison by priority.
Utility structures used internally by GraphLib.