GraphLibrary  0.0.1
A simple library that implements various graph algorithms.
 All Classes Namespaces Files Functions Variables Typedefs Macros
Dijkstra.hpp
Go to the documentation of this file.
1 #ifndef GL_DIJKSTRA_HPP
2 #define GL_DIJKSTRA_HPP
3 
4 #include "../gl_base.hpp"
5 
6 #include <queue>
7 
8 namespace gl::algorithm {
9 
11 // Class declaration
13 
19 template <class Graph>
20 class Dijkstra {
21  using idx_t = typename Graph::idx_t;
22  using val_t = typename Graph::val_t;
23  using pair_t = std::pair<Distance<val_t>,idx_t>;
24  using result_t = std::vector<pair_t>;
25 
26 public:
32  explicit Dijkstra(const Graph graph);
33 
34  Dijkstra();
35  Dijkstra(const Dijkstra &) = default;
36  Dijkstra(Dijkstra &&) noexcept = default;
37  Dijkstra &operator=(const Dijkstra &) = default;
38  Dijkstra &operator=(Dijkstra &&) noexcept = default;
39  ~Dijkstra() = default;
40 
41  Distance<val_t> pathLength(const idx_t src, const idx_t dest);
48  std::pair<bool,typename Graph::idx_list_t> getPath(const idx_t src, const idx_t dest);
54  Graph getSPT(const idx_t src);
59  void initialize(const Graph graph);
60 
61 private:
62 
67  void compute(const idx_t src);
68 
69 
71  std::vector<bool> isInitializedWithSource_;
73  // TODO: make pointer to prevent copies
74 
75  std::vector<Graph> result_;
76  std::vector<result_t> final_;
77 };
78 
80 // Member function implementations
82 
83 template <class Graph>
84 Dijkstra<Graph>::Dijkstra() : isInitializedWithGraph_(false),
85  isInitializedWithSource_(1,false) {}
86 
87 template <class Graph>
89  graph_(graph),
90  result_(graph.numNodes()),
91  final_(graph.numNodes()) {}
92 
93 template <class Graph>
95 {
96  // range has been checked in calling functions
97 
98  // verify that all non-self-loop edge weights are positive
99  for (auto it = graph_.edge_cbegin(); it != graph_.edge_cend(); ++it) {
100  if (it->source() != it->dest()) {
101  GL_ASSERT(it->weight() > 0, "Dijkstra::compute | Found non-positive edge weights in the graph.");
102  }
103  }
104 
105  // priority queue sorting (possibly non-trivial due to usage of Distance)
106  class prio {
107  public:
108  bool operator() (pair_t& lhs, pair_t& rhs) {
109  return lhs.first > rhs.first;
110  }
111  };
112 
113  std::priority_queue<pair_t,std::vector<pair_t>,prio> pq;
114  typename Graph::visit_list_t visited (graph_.numNodes());
115  std::vector<pair_t> out (graph_.numNodes());
116 
117  pq.push(std::make_pair(0,src));
118  out[src] = std::make_pair(idx_t(0),src);
119 
120  while (!pq.empty()) {
121  idx_t u = pq.top().second;
122  pq.pop();
123  if(visited[u]) continue;
124  visited[u] = true;
125  auto neighbours = graph_.getUnvisitedNeighbourWeights(u,visited);
126  for (const auto& x : neighbours) {
127  idx_t v = x.first;
128  Distance<val_t> temp_weight (x.second);
129  if(out[v].first > out[u].first + temp_weight) {
130  out[v] = std::make_pair(out[u].first + temp_weight,u);
131  pq.push(std::make_pair(out[v].first, v));
132  }
133  }
134  }
135  final_[src] = out;
136  isInitializedWithSource_[src] = true;
137 
138  Graph result(graph_.numNodes(),std::string(std::string("SPT of node ")+std::to_string(src)+std::string(" in ")+graph_.getGraphLabel()));
139  for (idx_t i = 0; i < graph_.numNodes(); ++i)
140  {
141  auto path = getPath(src, i);
142  if (path.first) {
143  idx_t i = 0;
144  for (idx_t j = i+1; j < path.second.size(); ++i, ++j)
145  {
146  if (!result.hasEdge(path.second[i],path.second[j]))
147  {
148  result.setEdge(path.second[i],path.second[j],graph_.getEdgeWeight(path.second[i],path.second[j]),graph_.getEdgeColor(path.second[i],path.second[j]));
149  }
150  }
151  }
152  }
153  result_[src] = result;
154 }
155 
156 template <class Graph>
158  GL_ASSERT(isInitializedWithGraph_,"Dijkstra::pathLength | Dijkstra has not been initialized with a graph.")
159  graph_.checkRange(src,dest);
160 
161  if (!isInitializedWithSource_[src])
162  compute(src);
163 
164  return final_[src][dest].first;
165 }
166 
167 template <class Graph>
168 std::pair<bool,typename Graph::idx_list_t> Dijkstra<Graph>::getPath (const idx_t src, const idx_t dest) {
169  GL_ASSERT(isInitializedWithGraph_,"Dijkstra::getPath | Dijkstra has not been initialized with a graph.")
170  graph_.checkRange(src,dest);
171 
172  if (!isInitializedWithSource_[src])
173  compute(src);
174 
175  typename Graph::idx_list_t out;
176  if (pathLength(src,dest).isInfinite())
177  {
178  return {false,{}};
179  }
180  idx_t node = dest;
181  while (node != src) {
182  out.push_back(node);
183  node = final_[src][node].second;
184  }
185  out.push_back(src);
186  std::reverse(out.begin(),out.end());
187  return {true,out};
188 }
189 
190 template <class Graph>
192 {
193  GL_ASSERT(isInitializedWithGraph_,"Dijkstra::getSPT | Dijkstra has not been initialized with a graph.")
194  graph_.checkRange(src);
195  if (!isInitializedWithSource_[src])
196  compute(src);
197 
198  return result_[src];
199 }
200 
201 template <class Graph>
203 {
204  std::vector<bool> isInitializedWithSource (graph.numNodes(),false);
205  isInitializedWithSource = isInitializedWithSource_;
206  graph_ = graph;
207 
208  std::vector<Graph> result (graph.numNodes());
209  result_ = result;
210  std::vector<result_t> final (graph.numNodes());
211  final_ = final;
212  isInitializedWithGraph_ = true;
213 }
214 
215 } // namespace gl::algorithm
216 
217 #endif // GL_DIJKSTRA_HPP
SCALAR val_t
Value type.
Definition: Graph.hpp:43
typename Graph::idx_t idx_t
Definition: Dijkstra.hpp:21
std::vector< idx_t > idx_list_t
Index List type.
Definition: Graph.hpp:48
gl::index_type idx_t
Index type.
Definition: Graph.hpp:44
Distance< val_t > pathLength(const idx_t src, const idx_t dest)
Definition: Dijkstra.hpp:157
void setEdge(const idx_t &start, const idx_t &end, const val_t &weight=1, const Color &color=Color())
Sets an edge including start/end points and weight.
Definition: Graph.hpp:510
std::vector< bool > isInitializedWithSource_
Boolean vector indicating whether the node whose ID corresponds to an element in the vector had its s...
Definition: Dijkstra.hpp:71
void initialize(const Graph graph)
Initializes the algorithm with a new Graph.
Definition: Dijkstra.hpp:202
Stores and implements a Graph.
Definition: Graph.hpp:39
bool hasEdge(const idx_t &start, const idx_t &end) const
Checks whether an edge exists from start to end.
Definition: Graph.hpp:818
Graph getSPT(const idx_t src)
Returns a graph that only contains the edges of the SPT (Shortest Path Tree)
Definition: Dijkstra.hpp:191
std::pair< Distance< val_t >, idx_t > pair_t
Definition: Dijkstra.hpp:23
std::vector< pair_t > result_t
Definition: Dijkstra.hpp:24
Dijkstra()
Default constructor.
Definition: Dijkstra.hpp:84
Graph graph_
Source Graph.
Definition: Dijkstra.hpp:72
std::pair< bool, typename Graph::idx_list_t > getPath(const idx_t src, const idx_t dest)
Computes the node sequence that represents the shortest path from src to dest.
Definition: Dijkstra.hpp:168
std::vector< Graph > result_
SPT graph.
Definition: Dijkstra.hpp:75
#define GL_ASSERT(EXPR, ERROR_MSG)
Custom assert that supports attaching a message.
Definition: gl_assert.hpp:14
idx_t numNodes() const
Returns the number of nodes currently in the graph.
Definition: Graph.hpp:406
void compute(const idx_t src)
Computation. This is where the shortest distances and the predecessors of each node on the shortest p...
Definition: Dijkstra.hpp:94
typename Graph::val_t val_t
Definition: Dijkstra.hpp:22
bool isInitializedWithGraph_
Boolean indicating whether the class has been initialized with a Graph.
Definition: Dijkstra.hpp:70
Implements a numerical distance that supports "infinite distance".
Definition: Distance.hpp:13
std::vector< bool > visit_list_t
Visited-List type.
Definition: Graph.hpp:50
Class that computes Dijkstra's Shortest Paths algorithm.
Definition: Dijkstra.hpp:20
std::vector< result_t > final_
Shortest Path lengths & predecessors.
Definition: Dijkstra.hpp:76