Adaptagrams
shortest_paths.h
1 /*
2  * vim: ts=4 sw=4 et tw=0 wm=0
3  *
4  * libcola - A library providing force-directed network layout using the
5  * stress-majorization method subject to separation constraints.
6  *
7  * Copyright (C) 2006-2014 Monash University
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  * See the file LICENSE.LGPL distributed with the library.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * Author(s): Tim Dwyer
20 */
21 
22 #ifndef SHORTEST_PATHS_H
23 #define SHORTEST_PATHS_H
24 
25 #include <vector>
26 #include <valarray>
27 #include <cfloat>
28 #include <cassert>
29 #include <algorithm>
30 #include <iostream>
31 #include <limits>
32 
33 #include "libcola/commondefs.h"
34 #include <libvpsc/pairing_heap.h>
35 #include <libvpsc/assertions.h>
36 
37 template <class T>
38 struct PairNode;
39 
40 namespace shortest_paths {
41 
42 template <typename T>
43 struct Node {
44  unsigned id;
45  T d;
46  Node* p; // predecessor
47  std::vector<Node<T>*> neighbours;
48  std::vector<T> nweights;
49  PairNode<Node<T>*>* qnode;
50 };
51 template <typename T>
52 struct CompareNodes {
53  bool operator() (Node<T> *const &u, Node<T> *const &v) const {
54  if(u==v) return false; // with g++ 4.1.2 unless I have this explicit check
55  // it returns true for this case when using -O3 optimization
56  // CRAZY!
57  if(u->d < v->d) {
58  return true;
59  }
60  return false;
61  }
62 };
63 
64 typedef std::pair<unsigned,unsigned> Edge;
65 template <typename T>
73 void neighbours(unsigned const n, T** D, std::vector<Edge> const & es,
74  std::valarray<T> const & eweights = std::valarray<T>());
82 template <typename T>
83 void floyd_warshall(unsigned const n, T** D, std::vector<Edge> const & es,
84  std::valarray<T> const & eweights = std::valarray<T>());
85 
93 template <typename T>
94 void johnsons(unsigned const n, T** D, std::vector<Edge> const & es,
95  std::valarray<T> const & eweights = std::valarray<T>());
104 template <typename T>
105 void dijkstra(unsigned const s, unsigned const n, T* d,
106  std::vector<Edge> const & es,
107  std::valarray<T> const & eweights = std::valarray<T>());
108 
109 
110 //-----------------------------------------------------------------------------
111 // Implementation:
112 
113 // O(n^3) time dynamic programming approach. Slow, but fool proof.
114 // Use for testing.
115 template <typename T>
116 void floyd_warshall(
117  unsigned const n,
118  T** D,
119  std::vector<Edge> const & es,
120  std::valarray<T> const & eweights)
121 {
122  COLA_ASSERT((eweights.size() == 0) || (eweights.size() == es.size()));
123  for(unsigned i=0;i<n;i++) {
124  for(unsigned j=0;j<n;j++) {
125  if(i==j) D[i][j]=0;
126  else D[i][j]=std::numeric_limits<T>::max();
127  }
128  }
129  for(unsigned i=0;i<es.size();i++) {
130  unsigned u=es[i].first, v=es[i].second;
131  COLA_ASSERT(u<n&&v<n);
132  D[u][v] = D[v][u] = (eweights.size() > 0) ? eweights[i] : 1;
133  }
134  for(unsigned k=0; k<n; k++) {
135  for(unsigned i=0; i<n; i++) {
136  for(unsigned j=0; j<n; j++) {
137  D[i][j]=std::min(D[i][j],D[i][k]+D[k][j]);
138  }
139  }
140  }
141 }
142 // Simply returns the adjacency graph
143 template <typename T>
144 void neighbours(
145  unsigned const n,
146  T** D,
147  std::vector<Edge> const & es,
148  std::valarray<T> const & eweights)
149 {
150  COLA_ASSERT((eweights.size() == 0) || (eweights.size() == es.size()));
151  for(unsigned i=0;i<n;i++) {
152  for(unsigned j=0;j<n;j++) {
153  D[i][j]=0;
154  }
155  }
156  for(unsigned i=0;i<es.size();i++) {
157  unsigned u=es[i].first, v=es[i].second;
158  COLA_ASSERT(u<n&&v<n);
159  D[u][v] = D[v][u] = (eweights.size() > 0) ? eweights[i] : 1;
160  }
161 }
162 template <typename T>
163 void dijkstra_init(
164  std::vector<Node<T> > & vs,
165  std::vector<Edge> const& es,
166  std::valarray<T> const & eweights) {
167  COLA_ASSERT((eweights.size() == 0) || (eweights.size() == es.size()));
168 #ifndef NDEBUG
169  const unsigned n=vs.size();
170 #endif
171  for(unsigned i=0;i<es.size();i++) {
172  unsigned u=es[i].first, v=es[i].second;
173  COLA_ASSERT(u<n);
174  COLA_ASSERT(v<n);
175  T w = (eweights.size() > 0) ? eweights[i] : 1;
176  vs[u].neighbours.push_back(&vs[v]);
177  vs[u].nweights.push_back(w);
178  vs[v].neighbours.push_back(&vs[u]);
179  vs[v].nweights.push_back(w);
180  }
181 }
182 template <typename T>
183 void dijkstra(
184  unsigned const s,
185  std::vector<Node<T> > & vs,
186  T* d)
187 {
188  const unsigned n=vs.size();
189  COLA_ASSERT(s<n);
190  for(unsigned i=0;i<n;i++) {
191  vs[i].id=i;
192  vs[i].d=std::numeric_limits<T>::max();
193  vs[i].p=nullptr;
194  }
195  vs[s].d=0;
196  PairingHeap<Node<T>*,CompareNodes<T> > Q;
197  for(unsigned i=0;i<n;i++) {
198  vs[i].qnode = Q.insert(&vs[i]);
199  }
200  while(!Q.isEmpty()) {
201  Node<T> *u=Q.extractMin();
202  d[u->id]=u->d;
203  for(unsigned i=0;i<u->neighbours.size();i++) {
204  Node<T> *v=u->neighbours[i];
205  T w=u->nweights[i];
206  if(u->d!=std::numeric_limits<T>::max()
207  && v->d > u->d+w) {
208  v->p=u;
209  v->d=u->d+w;
210  Q.decreaseKey(v->qnode,v);
211  }
212  }
213  }
214 }
215 template <typename T>
216 void dijkstra(
217  unsigned const s,
218  unsigned const n,
219  T* d,
220  std::vector<Edge> const & es,
221  std::valarray<T> const & eweights)
222 {
223  COLA_ASSERT((eweights.size() == 0) || (eweights.size() == es.size()));
224  COLA_ASSERT(s<n);
225  std::vector<Node<T> > vs(n);
226  dijkstra_init(vs,es,eweights);
227  dijkstra(s,vs,d);
228 }
229 
230 template <typename T>
231 void johnsons(
232  unsigned const n,
233  T** D,
234  std::vector<Edge> const & es,
235  std::valarray<T> const & eweights)
236 {
237  std::vector<Node<T> > vs(n);
238  dijkstra_init(vs,es,eweights);
239  for(unsigned k=0;k<n;k++) {
240  dijkstra(k,vs,D[k]);
241  }
242 }
243 
244 } //namespace shortest_paths
245 #endif //SHORTEST_PATHS_H
Definition: shortest_paths.h:40
std::pair< unsigned, unsigned > Edge
Edges are simply a pair of indices to entries in the Node vector.
Definition: cola.h:68