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 vector<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 vector<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 vector<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 vector<int>& t,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  set<int> targetSet;
224  for(size_t i=0;i<t.size();i++) targetSet.insert(t[i]);
225 
226  while(!H.empty()) {
227  //pop the smallest distance element from q
228  int u = H.top(); H.pop();
229  if(targetSet.count(u)!=0) return u;
230 
231  for(g.Begin(u,it);!it.end();it++) {
232  int v=it.target();
233  //relax distances
234  Weight dvu = d[u] + w(*it,it.source(),it.target());
235  if(d[v] > dvu) {
236  SetDistance(v,dvu,u);
237  H.adjust(v,-d[v]);
238  }
239  }
240  }
241  return -1;
242 }
243 
244 
245 template <class Node,class Edge>
246 template <typename WeightFunc,typename InIterator,typename OutIterator>
247 void ShortestPathProblem<Node,Edge>::IncreaseUpdate(int u,int v,WeightFunc w,
248  InIterator in,OutIterator out)
249 {
250  //1) if not in the SP tree, return
251  if(p[v] != u) return;
252 
253  //2) look for alternative SP, if found, return
254  for(g.Begin(v,in);!in.end();in++) {
255  int t=in.target();
256  if(d[v] == d[t]+w(*in,in.source(),in.target())) {
257  p[v]=t;
258  return;
259  }
260  }
261 
262  //3) identify affected nodes
263  vector<int> Q(1,v);
264  for(size_t i=0;i<Q.size();i++) {
265  int n=Q[i];
266  SetDistance(n,inf,-1);
267  for(g.Begin(n,out);!out.end();out++) {
268  int t=out.target();
269  if(p[t]==n) {
270  //identify any alternative routes
271  for(g.Begin(t,in);!in.end();in++) {
272  int s=in.target();
273  if(d[t]==d[s]+w(*in,in.source(),in.target())) {
274  p[t]=s;
275  break;
276  }
277  }
278  if(p[t]==n) Q.push_back(t);
279  }
280  }
281  }
282  //4) update affected nodes by finding paths from outside nodes
283  Heap<int,Weight> H; //O(1) init, O(n) adjust
284  for(size_t i=0;i<Q.size();i++) {
285  int n=Q[i];
286  for(g.Begin(n,in);!in.end();in++) {
287  int s=in.target();
288  double W=w(*in,in.source(),in.target());
289  if(d[n]>d[s]+W) {
290  SetDistance(n,d[s]+W,s);
291  }
292  }
293  if(!Math::IsInf(d[n])) H.push(n,-d[n]);
294  }
295  while(!H.empty()) {
296  int n=H.top(); H.pop();
297  for(g.Begin(n,out);!out.end();out++) {
298  int t=out.target();
299  double W=w(*out,out.source(),out.target());
300  if(d[t]>d[n]+W) {
301  SetDistance(t,d[n]+W,n);
302  H.adjust(t,-d[t]);
303  }
304  }
305  }
306 }
307 
308 template <class Node,class Edge>
309 template <typename WeightFunc,typename InIterator,typename OutIterator>
310 void ShortestPathProblem<Node,Edge>::DecreaseUpdate(int u,int v,WeightFunc w,
311  InIterator in,OutIterator out)
312 {
313  //NOTE: can't use find edge because it doesn't work for undirected graphs
314  for(g.Begin(u,out);!out.end();out++)
315  if(out.target()==v) {
316  double W=w(*out,out.source(),out.target());
317  if(d[v] <= d[u]+W) {
318  return; //no change
319  }
320  SetDistance(v,d[u]+W,u);
321  break;
322  }
323  if(out.end()) {
324  FatalError("ShortestPathProblem::DecreaseUpdate(): Warning, decreasing an edge that doesn't exist in the graph!");
325  }
326  Heap<int,Weight> H; //O(1) init, O(n) adjust
327  H.push(v,-d[v]);
328  while(!H.empty()) {
329  int n=H.top(); H.pop();
330  for(g.Begin(n,out);!out.end();out++) {
331  int t=out.target();
332  double W=w(*out,out.source(),out.target());
333  if(d[t]>d[n]+W) {
334  SetDistance(t,d[n]+W,n);
335  H.adjust(t,-d[t]);
336  }
337  }
338  }
339 }
340 
341 template <class Node,class Edge>
342 template <typename WeightFunc,typename InIterator,typename OutIterator>
343 void ShortestPathProblem<Node,Edge>::DeleteUpdate(int u,int v,WeightFunc w,
344  InIterator in,OutIterator out)
345 {
346  if(p[v] == u) {
347  SetDistance(v,inf,-1);
348  //find the best alternate parent
349  for(g.Begin(v,in);!in.end();++in) {
350  int t=in.target();
351  if(p[t] == v) continue;
352  Assert(t != u);
353  double W=w(*in,in.source(),in.target());
354  if(d[v] > d[t]+W) {
355  SetDistance(v,d[t]+W,t);
356  }
357  }
358  if(p[v] != -1) {
359  d[v] = inf;
360  DecreaseUpdate(p[v],v,w,in,out);
361  d[v] = 0;
362  IncreaseUpdate(p[v],v,w,in,out);
363  }
364  else {
365  for(g.Begin(v,out);!out.end();++out) {
366  int t=out.target();
367  IncreaseUpdate(v,t,w,in,out);
368  }
369  }
370  }
371 }
372 
373 template <class Node,class Edge>
374 template <typename WeightFunc,typename Iterator>
375 bool ShortestPathProblem<Node,Edge>::HasShortestPaths(int s,WeightFunc w,Iterator it) {
376  int nn=g.NumNodes();
377  FixedSizeHeap<Weight> H(nn);
378  for(int i=0;i<nn;i++) H.push(i,-d[i]);
379  while(!H.empty()) {
380  int n=H.top(); H.pop();
381  if(n==s) {
382  if(d[n]!=0) {
383  LOG4CXX_INFO(KrisLibrary::logger(),"The start doesn't have distance 0\n");
384  return false;
385  }
386  }
387  for(g.Begin(n,it);!it.end();++it) {
388  int t=it.target();
389  double W=w(*it,it.source(),it.target());
390  if(p[n] == t) {
391  if(fabs(d[n]-d[t]-W) > 1e-10) {
392  LOG4CXX_INFO(KrisLibrary::logger(),"Inconsistency in node "<< n<<"'s weight through parent "<< t<<", "<< d[n]<<" vs "<<d[t]+W<<"="<<d[t]<<"+"<<W);
393  return false;
394  }
395  }
396  if(d[n]-d[t]-W > 1e-10) {
397  LOG4CXX_INFO(KrisLibrary::logger(),"There exists a shorter path ("<<t<<","<<n<<") not ("<<p[n]<<","<<n);
398  LOG4CXX_INFO(KrisLibrary::logger(),"Weight 1 is "<< d[t]+W<<" compared to "<< d[n]);
399  return false;
400  }
401  }
402  }
403  return true;
404 }
405 
406 
407 } //namespace Graph
408 
409 #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:40
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