KrisLibrary  1.0.0
ShortestPaths.h
1 #ifndef GRAPH_SHORTEST_PATHS_H
2 #define GRAPH_SHORTEST_PATHS_H
3 
4 #include <KrisLibrary/Logger.h>
5 #include "Graph.h"
7 #include <KrisLibrary/structs/FixedSizeHeap.h>
8 #include <KrisLibrary/structs/Heap.h>
9 #include <set>
10 
11 namespace Graph {
12 
13 const static Weight inf = Math::dInf;
14 
38 template <class Node,class Edge>
40 {
41  public:
43  virtual ~ShortestPathProblem() {}
44 
45  void InitializeSource(int s);
46  void InitializeSources(const vector<int>& s);
47 
48  template <typename WeightFunc,typename Iterator>
49  void FindPath(int t,WeightFunc w,Iterator it);
50  template <typename WeightFunc,typename Iterator>
51  int FindAPath(const set<int>& t,WeightFunc w,Iterator it);
52  template <typename WeightFunc,typename Iterator>
53  inline void FindAllPaths(WeightFunc w,Iterator it) { FindPath(-1,w,it); }
54 
55  //after all paths are found, the shortest paths can be updated with the following
56  //when an edge (u,v)'s weight is increased/decreased, call these methods
57  template <typename WeightFunc,typename InIterator,typename OutIterator>
58  void IncreaseUpdate(int u,int v,WeightFunc w,InIterator in,OutIterator out);
59  template <typename WeightFunc,typename InIterator,typename OutIterator>
60  void DecreaseUpdate(int u,int v,WeightFunc w,InIterator in,OutIterator out);
61  template <typename WeightFunc,typename InIterator,typename OutIterator>
62  void DeleteUpdate(int u,int v,WeightFunc w,InIterator in,OutIterator out);
63 
64  template <typename WeightFunc,typename Iterator>
65  bool HasShortestPaths(int s,WeightFunc w,Iterator it);
66 
67  //template specializations (directed/undirected)
68 
69  template <typename WeightFunc>
70  inline void FindPath_Directed(int t,WeightFunc w) {
71  FindPath(t,w,EdgeIterator<Edge>());
72  }
73  template <typename WeightFunc>
74  inline int FindAPath_Directed(const set<int>& t,WeightFunc w) {
75  return FindAPath(t,w,EdgeIterator<Edge>());
76  }
77  template <typename WeightFunc>
78  inline void FindAllPaths_Directed(WeightFunc w) {
80  FindAllPaths(w,it);
81  }
82  template <typename WeightFunc>
83  inline void IncreaseUpdate_Directed(int u,int v,WeightFunc w) {
85  IncreaseUpdate(u,v,w,in,out);
86  }
87  template <typename WeightFunc>
88  inline void DecreaseUpdate_Directed(int u,int v,WeightFunc w) {
90  DecreaseUpdate(u,v,w,in,out);
91  }
92  template <typename WeightFunc>
93  inline void DeleteUpdate_Directed(int u,int v,WeightFunc w) {
95  DeleteUpdate(u,v,w,in,out);
96  }
97  template <typename WeightFunc>
98  inline bool HasShortestPaths_Directed(int s,WeightFunc w) {
100  return HasShortestPaths(s,w,it);
101  }
102 
103  template <typename WeightFunc>
104  inline void FindPath_Undirected(int t,WeightFunc w) {
106  FindPath(t,w,it);
107  }
108  template <typename WeightFunc>
109  inline int FindAPath_Undirected(const set<int>& t,WeightFunc w) {
110  return FindAPath(t,w,UndirectedEdgeIterator<Edge>());
111  }
112  template <typename WeightFunc>
113  inline void FindAllPaths_Undirected(WeightFunc w) {
114  FindAllPaths(w,UndirectedEdgeIterator<Edge>());
115  }
116  template <typename WeightFunc>
117  inline void IncreaseUpdate_Undirected(int u,int v,WeightFunc w) {
119  IncreaseUpdate(u,v,w,it,it);
120  IncreaseUpdate(v,u,w,it,it);
121  }
122  template <typename WeightFunc>
123  inline void DecreaseUpdate_Undirected(int u,int v,WeightFunc w) {
125  DecreaseUpdate(u,v,w,it,it);
126  DecreaseUpdate(v,u,w,it,it);
127  }
128  template <typename WeightFunc>
129  inline void DeleteUpdate_Undirected(int u,int v,WeightFunc w) {
131  DeleteUpdate(u,v,w,it,it);
132  DeleteUpdate(v,u,w,it,it);
133  }
134  template <typename WeightFunc>
135  inline bool HasShortestPaths_Undirected(int s,WeightFunc w) {
137  return HasShortestPaths(s,w,it);
138  }
139 
144  virtual void SetDistance(int n,Real dn,int pn) { d[n]=dn; p[n]=pn; }
145 
146  const Graph<Node,Edge>& g;
147 
148  std::vector<int> p;
149  std::vector<Weight> d;
150 };
151 
152 
153 //definition of ShortestPaths
154 
155 template <class Node,class Edge>
158  :g(_g)
159 {}
160 
161 template <class Node,class Edge>
163 {
164  //initialize
165  int nn = g.NumNodes();
166  p.resize(nn);
167  d.resize(nn);
168  for(int i=0;i<nn;i++) {
169  p[i] = -1;
170  d[i] = inf;
171  }
172  d[s] = 0;
173 }
174 
175 template <class Node,class Edge>
176 void ShortestPathProblem<Node,Edge>::InitializeSources(const vector<int>& s)
177 {
178  //initialize
179  int nn = g.NumNodes();
180  p.resize(nn);
181  d.resize(nn);
182  for(int i=0;i<nn;i++) {
183  p[i] = -1;
184  d[i] = inf;
185  }
186  for(size_t i=0;i<s.size();i++)
187  d[s[i]] = 0;
188 }
189 
190 template <class Node,class Edge>
191 template <typename WeightFunc,typename Iterator>
192 void ShortestPathProblem<Node,Edge>::FindPath(int t,WeightFunc w,Iterator it)
193 {
194  int nn=g.NumNodes();
195  FixedSizeHeap<Weight> H(nn); //O(n) init, worst case log n update
196  for(int i=0;i<nn;i++) H.push(i,-d[i]);
197 
198  while(!H.empty()) {
199  //pop the smallest distance element from q
200  int u = H.top(); H.pop();
201  if(u == t) return;
202 
203  for(g.Begin(u,it);!it.end();it++) {
204  int v=it.target();
205  //relax distances
206  Weight dvu = d[u] + w(*it,it.source(),it.target());
207  if(d[v] > dvu) {
208  SetDistance(v,dvu,u);
209  H.adjust(v,-d[v]);
210  }
211  }
212  }
213 }
214 
215 template <class Node,class Edge>
216 template <typename WeightFunc,typename Iterator>
217 int ShortestPathProblem<Node,Edge>::FindAPath(const set<int>& targetSet,WeightFunc w,Iterator it)
218 {
219  int nn=g.NumNodes();
220  FixedSizeHeap<Weight> H(nn); //O(n) init, worst case log n update
221  for(int i=0;i<nn;i++) H.push(i,-d[i]);
222 
223  while(!H.empty()) {
224  //pop the smallest distance element from q
225  int u = H.top(); H.pop();
226  if(targetSet.count(u)!=0) return u;
227 
228  for(g.Begin(u,it);!it.end();it++) {
229  int v=it.target();
230  //relax distances
231  Weight dvu = d[u] + w(*it,it.source(),it.target());
232  if(d[v] > dvu) {
233  SetDistance(v,dvu,u);
234  H.adjust(v,-d[v]);
235  }
236  }
237  }
238  return -1;
239 }
240 
241 
242 template <class Node,class Edge>
243 template <typename WeightFunc,typename InIterator,typename OutIterator>
244 void ShortestPathProblem<Node,Edge>::IncreaseUpdate(int u,int v,WeightFunc w,
245  InIterator in,OutIterator out)
246 {
247  //1) if not in the SP tree, return
248  if(p[v] != u) return;
249 
250  //2) look for alternative SP, if found, return
251  for(g.Begin(v,in);!in.end();in++) {
252  int t=in.target();
253  if(d[v] == d[t]+w(*in,in.source(),in.target())) {
254  p[v]=t;
255  return;
256  }
257  }
258 
259  //3) identify affected nodes
260  vector<int> Q(1,v);
261  for(size_t i=0;i<Q.size();i++) {
262  int n=Q[i];
263  SetDistance(n,inf,-1);
264  for(g.Begin(n,out);!out.end();out++) {
265  int t=out.target();
266  if(p[t]==n) {
267  //identify any alternative routes
268  for(g.Begin(t,in);!in.end();in++) {
269  int s=in.target();
270  if(d[t]==d[s]+w(*in,in.source(),in.target())) {
271  p[t]=s;
272  break;
273  }
274  }
275  if(p[t]==n) Q.push_back(t);
276  }
277  }
278  }
279  //4) update affected nodes by finding paths from outside nodes
280  Heap<int,Weight> H; //O(1) init, O(n) adjust
281  for(size_t i=0;i<Q.size();i++) {
282  int n=Q[i];
283  for(g.Begin(n,in);!in.end();in++) {
284  int s=in.target();
285  double W=w(*in,in.source(),in.target());
286  if(d[n]>d[s]+W) {
287  SetDistance(n,d[s]+W,s);
288  }
289  }
290  if(!Math::IsInf(d[n])) H.push(n,-d[n]);
291  }
292  while(!H.empty()) {
293  int n=H.top(); H.pop();
294  for(g.Begin(n,out);!out.end();out++) {
295  int t=out.target();
296  double W=w(*out,out.source(),out.target());
297  if(d[t]>d[n]+W) {
298  SetDistance(t,d[n]+W,n);
299  H.adjust(t,-d[t]);
300  }
301  }
302  }
303 }
304 
305 template <class Node,class Edge>
306 template <typename WeightFunc,typename InIterator,typename OutIterator>
307 void ShortestPathProblem<Node,Edge>::DecreaseUpdate(int u,int v,WeightFunc w,
308  InIterator in,OutIterator out)
309 {
310  //NOTE: can't use find edge because it doesn't work for undirected graphs
311  for(g.Begin(u,out);!out.end();out++)
312  if(out.target()==v) {
313  double W=w(*out,out.source(),out.target());
314  if(d[v] <= d[u]+W) {
315  return; //no change
316  }
317  SetDistance(v,d[u]+W,u);
318  break;
319  }
320  if(out.end()) {
321  FatalError("ShortestPathProblem::DecreaseUpdate(): Warning, decreasing an edge that doesn't exist in the graph!");
322  }
323  Heap<int,Weight> H; //O(1) init, O(n) adjust
324  H.push(v,-d[v]);
325  while(!H.empty()) {
326  int n=H.top(); H.pop();
327  for(g.Begin(n,out);!out.end();out++) {
328  int t=out.target();
329  double W=w(*out,out.source(),out.target());
330  if(d[t]>d[n]+W) {
331  SetDistance(t,d[n]+W,n);
332  H.adjust(t,-d[t]);
333  }
334  }
335  }
336 }
337 
338 template <class Node,class Edge>
339 template <typename WeightFunc,typename InIterator,typename OutIterator>
340 void ShortestPathProblem<Node,Edge>::DeleteUpdate(int u,int v,WeightFunc w,
341  InIterator in,OutIterator out)
342 {
343  if(p[v] == u) {
344  SetDistance(v,inf,-1);
345  //find the best alternate parent
346  for(g.Begin(v,in);!in.end();++in) {
347  int t=in.target();
348  if(p[t] == v) continue;
349  Assert(t != u);
350  double W=w(*in,in.source(),in.target());
351  if(d[v] > d[t]+W) {
352  SetDistance(v,d[t]+W,t);
353  }
354  }
355  if(p[v] != -1) {
356  d[v] = inf;
357  DecreaseUpdate(p[v],v,w,in,out);
358  d[v] = 0;
359  IncreaseUpdate(p[v],v,w,in,out);
360  }
361  else {
362  for(g.Begin(v,out);!out.end();++out) {
363  int t=out.target();
364  IncreaseUpdate(v,t,w,in,out);
365  }
366  }
367  }
368 }
369 
370 template <class Node,class Edge>
371 template <typename WeightFunc,typename Iterator>
372 bool ShortestPathProblem<Node,Edge>::HasShortestPaths(int s,WeightFunc w,Iterator it) {
373  int nn=g.NumNodes();
374  FixedSizeHeap<Weight> H(nn);
375  for(int i=0;i<nn;i++) H.push(i,-d[i]);
376  while(!H.empty()) {
377  int n=H.top(); H.pop();
378  if(n==s) {
379  if(d[n]!=0) {
380  LOG4CXX_INFO(KrisLibrary::logger(),"The start doesn't have distance 0\n");
381  return false;
382  }
383  }
384  for(g.Begin(n,it);!it.end();++it) {
385  int t=it.target();
386  double W=w(*it,it.source(),it.target());
387  if(p[n] == t) {
388  if(fabs(d[n]-d[t]-W) > 1e-10) {
389  LOG4CXX_INFO(KrisLibrary::logger(),"Inconsistency in node "<< n<<"'s weight through parent "<< t<<", "<< d[n]<<" vs "<<d[t]+W<<"="<<d[t]<<"+"<<W);
390  return false;
391  }
392  }
393  if(d[n]-d[t]-W > 1e-10) {
394  LOG4CXX_INFO(KrisLibrary::logger(),"There exists a shorter path ("<<t<<","<<n<<") not ("<<p[n]<<","<<n);
395  LOG4CXX_INFO(KrisLibrary::logger(),"Weight 1 is "<< d[t]+W<<" compared to "<< d[n]);
396  return false;
397  }
398  }
399  }
400  return true;
401 }
402 
403 
404 } //namespace Graph
405 
406 #endif
Common math typedefs, constants, functions.
Definition: Edge.h:28
Implements a heap that stores objects of type type, with priority keys of type ptype.
Definition: Heap.h:19
int IsInf(double x)
Returns +1 if x is +inf, -1 if x is -inf, and 0 otherwise.
Definition: infnan.cpp:92
A heap of fixed maximum size N. Each element is indexed by an integer 0...N-1. The priority key of ea...
Definition: FixedSizeHeap.h:13
Single-source shortest paths (Dijkstra&#39;s algorithm)
Definition: ShortestPaths.h:39
Definition: Edge.h:58
virtual void SetDistance(int n, Real dn, int pn)
Definition: ShortestPaths.h:144
The logging system used in KrisLibrary.
Namespace for all classes and functions in the Graph subdirectory.
Definition: ApproximateShortestPaths.h:7
Definition: Edge.h:88