GraphLibrary  0.0.1
A simple library that implements various graph algorithms.
 All Classes Namespaces Files Functions Variables Typedefs Macros
FloydWarshall.hpp
Go to the documentation of this file.
1 #ifndef GL_FLOYD_WARSHALL_HPP
2 #define GL_FLOYD_WARSHALL_HPP
3 
4 #include "../gl_base.hpp"
5 
6 namespace gl {
7 namespace algorithm {
8 
10 // Class declaration
12 
17 template <class Graph>
19  using idx_t = typename Graph::idx_t;
20  using val_t = typename Graph::val_t;
21  using distance_matrix_t = std::vector<Distance<val_t>>;
22  using idx_list_t = typename Graph::idx_list_t;
23 
24 public:
25 
26  FloydWarshall();
27  explicit FloydWarshall(const Graph& graph);
28 
29  FloydWarshall(const FloydWarshall &) = default;
30  FloydWarshall(FloydWarshall &&) noexcept = default;
31  FloydWarshall &operator=(const FloydWarshall &) = default;
32  FloydWarshall &operator=(FloydWarshall &&) noexcept = default;
33  ~FloydWarshall() = default;
34 
39  void compute(const Graph& graph);
44  bool hasNegativePath () const;
51  Distance<val_t> pathLength(const idx_t src, const idx_t dest) const;
58  std::pair<bool,idx_list_t> getPath(const idx_t src, const idx_t dest) const;
64  Graph getSPT (const idx_t src) const;
71  double closenessCentrality (const idx_t id) const;
77  double harmonicCentrality (const idx_t id) const;
78 
79 
80 private:
81  bool isInitialized_ = false;
82  std::pair<bool,idx_t> negativePath_;
86 };
87 
89 // Member function implementations
91 
92 template <class Graph>
93 FloydWarshall<Graph>::FloydWarshall() : isInitialized_(false), negativePath_(std::make_pair<bool,idx_t>(false,0)) {}
94 
95 template <class Graph>
96 FloydWarshall<Graph>::FloydWarshall(const Graph& graph) : isInitialized_(false), negativePath_(std::make_pair<bool,idx_t>(false,0))
97 {
98  compute(graph);
99 }
100 
101 template <class Graph>
103 {
104  idx_t i, j, k;
105  idx_t numNodes = graph.numNodes();
106  val_t weight;
107  distance_matrix_t dist (numNodes*numNodes);
108  idx_list_t next (numNodes*numNodes,GL_INF(idx_t));
109  // fill initial known edges
110  for (int i = 0; i < graph.numNodes(); ++i)
111  {
112  for (int j = 0; j < graph.numNodes(); ++j)
113  {
114  if (!graph.hasEdge(i,j)) continue;
115  weight = graph.getEdgeWeight(i,j);
116  // check for negative weights in undirected graphs
117  if (!graph.isDirected())
118  {
119  GL_ASSERT(weight >= 0,"FloydWarshall::compute | Graph is undirected and contains negative weights")
120  }
121  dist[i*numNodes+j].setDistance(weight);
122  next[i*numNodes+j] = j;
123  }
124  }
125  // set diagonals
126  for (idx_t i = 0; i < numNodes; ++i)
127  {
128  dist[i*numNodes+i].setDistance(0);
129  next[i*numNodes+i] = i;
130  }
131  // Actual Floyd-Warshall Algorithm
132  for (k = 0; k < numNodes; ++k) {
133  for (j = 0; j < numNodes; ++j) {
134  for (i = 0; i < numNodes; ++i) {
135  if (k == i || k == j)
136  continue;
137  if (dist[i*numNodes+k] + dist[k*numNodes+j] < dist[i*numNodes+j])
138  {
139  dist[i*numNodes+j] = dist[i*numNodes+k] + dist[k*numNodes+j];
140  next[i*numNodes+j] = next[i*numNodes+k];
141  }
142  }
143  }
144  }
145  // Check for negative cycles
146  for (idx_t i = 0; i < numNodes; ++i)
147  {
148  if (!dist[i*numNodes+i].isZero())
149  {
150  negativePath_ = {true,i};
151  }
152  }
153  dist_ = dist;
154  graph_ = graph;
155  next_ = next;
156  isInitialized_ = true;
157 }
158 
159 template <class Graph>
161  GL_ASSERT(isInitialized_,"FloydWarshall::hasNegativePath | FloydWarshall has not been initialized with a graph.")
162 
163  return negativePath_.first;
164 }
165 
166 template <class Graph>
168  GL_ASSERT(isInitialized_,"FloydWarshall::pathLength | FloydWarshall has not been initialized with a graph.")
169  graph_.checkRange(src,dest);
170  GL_ASSERT(!negativePath_.first,std::string("FloydWarshall::pathLength | The input graph has a negative cycle at node ")+std::to_string(negativePath_.second))
171 
172  return dist_[src*graph_.numNodes()+dest];
173 }
174 
175 template <class Graph>
176 std::pair<bool,typename Graph::idx_list_t> FloydWarshall<Graph>::getPath (const idx_t src, const idx_t dest) const {
177  GL_ASSERT(isInitialized_,"FloydWarshall::getPath | FloydWarshall has not been initialized with a graph.")
178  graph_.checkRange(src,dest);
179  GL_ASSERT(!negativePath_.first,std::string("FloydWarshall::getPath | The input graph has a negative cycle at node ")+std::to_string(negativePath_.second))
180 
181  // Check for path existance
182  if (dist_[src*graph_.numNodes()+dest].isInfinite())
183  return {false,{}};
184 
185  // backtracking
186  typename Graph::idx_list_t out;
187  out.push_back(src);
188  idx_t u = src;
189  while (u != dest) {
190  u = next_[u*graph_.numNodes()+dest];
191  out.push_back(u);
192  }
193  return {true,out};
194 }
195 
196 template <class Graph>
198 {
199  GL_ASSERT(isInitialized_,"FloydWarshall::getSPT | FloydWarshall has not been initialized with a graph.")
200  graph_.checkRange(src);
201  GL_ASSERT(!negativePath_.first,std::string("FloydWarshall::getSPT | The input graph has a negative cycle at node ")+std::to_string(negativePath_.second))
202 
203  Graph result(graph_.numNodes(),std::string(std::string("SPT of node ")+std::to_string(src)+std::string(" in ")+graph_.getGraphLabel()));
204  for (idx_t i = 0; i < graph_.numNodes(); ++i)
205  {
206  auto path = getPath(src,i);
207  if (path.first) {
208  idx_t i = 0;
209  for (idx_t j = i+1; j < path.second.size(); ++i, ++j)
210  {
211  if (!result.hasEdge(path.second[i],path.second[j]))
212  {
213  result.setEdge(path.second[i],path.second[j],graph_.getEdgeWeight(path.second[i],path.second[j]));
214  }
215  }
216  }
217  }
218  return result;
219 }
220 
221 template <class Graph>
223 {
224  GL_ASSERT(isInitialized_,"FloydWarshall::closenessCentrality | FloydWarshall has not been initialized with a graph.")
225  graph_.checkRange(id);
226  GL_ASSERT(!negativePath_.first,std::string("FloydWarshall::closenessCentrality | The input graph has a negative cycle at node ")+std::to_string(negativePath_.second))
227 
228  double result = 0;
230 
231  for (idx_t i = 0; i < graph_.numNodes(); ++i)
232  {
233  if (id == i) continue;
234  distance = pathLength(i,id);
235  if (distance.isInfinite())
236  return 0;
237  else
238  result += distance.scalarDistance();
239  }
240  return static_cast<double>((graph_.numNodes()-1)/result);
241 }
242 
243 template <class Graph>
245 {
246  GL_ASSERT(isInitialized_,"FloydWarshall::closenessCentrality | FloydWarshall has not been initialized with a graph.")
247  graph_.checkRange(id);
248  GL_ASSERT(!negativePath_.first,std::string("FloydWarshall::closenessCentrality | The input graph has a negative cycle at node ")+std::to_string(negativePath_.second))
249 
250  double result = 0;
252 
253  for (idx_t i = 0; i < graph_.numNodes(); ++i)
254  {
255  if (id == i) continue;
256  distance = pathLength(i,id);
257  if (distance.isInfinite())
258  continue;
259  else
260  result += 1./distance.scalarDistance();
261  }
262  return static_cast<double>(result/(graph_.numNodes()-1));
263 }
264 
265 } // namespace algorithm
266 } // namespace gl
267 
268 #endif // GL_FLOYD_WARSHALL_HPP
SCALAR val_t
Value type.
Definition: Graph.hpp:43
Graph getSPT(const idx_t src) const
Returns a graph that only contains the edges of the SPT (Shortest Path Tree) starting at 'src'...
Definition: FloydWarshall.hpp:197
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
std::vector< Distance< val_t >> distance_matrix_t
Definition: FloydWarshall.hpp:21
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
Stores and implements a Graph.
Definition: Graph.hpp:39
typename Graph::idx_t idx_t
Definition: FloydWarshall.hpp:19
bool isInfinite() const
Checks whether the distance is infinite.
Definition: Distance.hpp:108
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 graph_
Reference to graph.
Definition: FloydWarshall.hpp:83
distance_matrix_t dist_
Shortest Path lengths.
Definition: FloydWarshall.hpp:84
double closenessCentrality(const idx_t id) const
Computes the closeness centrality of node 'id'.
Definition: FloydWarshall.hpp:222
bool isDirected() const
Returns true if the graph is directed, false if not.
Definition: Graph.hpp:426
#define GL_ASSERT(EXPR, ERROR_MSG)
Custom assert that supports attaching a message.
Definition: gl_assert.hpp:14
FloydWarshall()
Default constructor.
Definition: FloydWarshall.hpp:93
idx_t numNodes() const
Returns the number of nodes currently in the graph.
Definition: Graph.hpp:406
bool hasNegativePath() const
Checks whether the input graph has negative cycles.
Definition: FloydWarshall.hpp:160
void compute(const Graph &graph)
Computation. This is where the shortest distances and the successors of each node pair gets computed...
Definition: FloydWarshall.hpp:102
std::pair< bool, idx_list_t > getPath(const idx_t src, const idx_t dest) const
Computes the node sequence that represents the shortest path from 'src' to 'dest'.
Definition: FloydWarshall.hpp:176
idx_list_t next_
Shortest Path successors.
Definition: FloydWarshall.hpp:85
Implements a numerical distance that supports "infinite distance".
Definition: Distance.hpp:13
#define GL_INF(ValueType)
Definition: gl_base.hpp:7
std::pair< bool, idx_t > negativePath_
Boolean storing info on negative path in graph.
Definition: FloydWarshall.hpp:82
bool isInitialized_
Boolean storing initialization status.
Definition: FloydWarshall.hpp:81
Distance< val_t > pathLength(const idx_t src, const idx_t dest) const
Computes the shortest path length from 'src' to 'dest'.
Definition: FloydWarshall.hpp:167
Class computes that Shortest Paths for all pairs of nodes in the graph using the Floyd-Warshall algor...
Definition: FloydWarshall.hpp:18
typename Graph::idx_list_t idx_list_t
Definition: FloydWarshall.hpp:22
SCALAR scalarDistance() const
Gets the numerical value of the distance. If the distance is infinite, returns the maximum value of t...
Definition: Distance.hpp:90
val_t getEdgeWeight(const idx_t &start, const idx_t &end) const
Finds the weight of the edge going from start to end.
Definition: Graph.hpp:858
typename Graph::val_t val_t
Definition: FloydWarshall.hpp:20
double harmonicCentrality(const idx_t id) const
Computes the harmonic centrality of node 'id'.
Definition: FloydWarshall.hpp:244