SUMO - Simulation of Urban MObility
CHBuilder.h
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
17 // Contraction Hierarchy Builder for the shortest path search
18 /****************************************************************************/
19 #ifndef CHBuilder_h
20 #define CHBuilder_h
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <string>
29 #include <functional>
30 #include <vector>
31 #include <set>
32 #include <limits>
33 #include <algorithm>
34 #include <iterator>
35 #include <utils/common/SysUtils.h>
37 #include <utils/common/StdDefs.h>
39 #include "SPTree.h"
40 
41 //#define CHRouter_DEBUG_CONTRACTION
42 //#define CHRouter_DEBUG_CONTRACTION_WITNESSES
43 //#define CHRouter_DEBUG_CONTRACTION_QUEUE
44 //#define CHRouter_DEBUG_CONTRACTION_DEGREE
45 //#define CHRouter_DEBUG_WEIGHTS
46 
47 // ===========================================================================
48 // class definitions
49 // ===========================================================================
64 template<class E, class V>
65 class CHBuilder {
66 
67 public:
69  // forward connections are used only in forward search
70  // backward connections are used only in backwards search
71  class Connection {
72  public:
73  Connection(int t, double c, SVCPermissions p): target(t), cost(c), permissions(p) {}
74  int target;
75  double cost;
77  };
78 
79  typedef std::pair<const E*, const E*> ConstEdgePair;
80  typedef std::map<ConstEdgePair, const E*> ShortcutVia;
81  struct Hierarchy {
82  ShortcutVia shortcuts;
83  std::vector<std::vector<Connection> > forwardUplinks;
84  std::vector<std::vector<Connection> > backwardUplinks;
85  };
86 
92  CHBuilder(const std::vector<E*>& edges, bool unbuildIsWarning,
93  const SUMOVehicleClass svc,
94  bool validatePermissions):
95  myEdges(edges),
96  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
97  mySPTree(new SPTree<CHInfo, CHConnection>(4, validatePermissions)),
98  mySVC(svc),
99  myUpdateCount(0) {
100  for (typename std::vector<E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
101  myCHInfos.push_back(CHInfo(*i));
102  }
103  }
104 
106  virtual ~CHBuilder() {
107  delete mySPTree;
108  }
109 
110 
111  const Hierarchy* buildContractionHierarchy(SUMOTime time, const V* const vehicle, const SUMOAbstractRouter<E, V>* effortProvider) {
112  Hierarchy* result = new Hierarchy();
113  const int numEdges = (int)myCHInfos.size();
114  const std::string vClass = (mySPTree->validatePermissions() ?
115  "all vehicle classes " : "vClass='" + SumoVehicleClassStrings.getString(mySVC) + "' ");
116  PROGRESS_BEGIN_MESSAGE("Building Contraction Hierarchy for " + vClass
117  + "and time=" + time2string(time) + " (" + toString(numEdges) + " edges)\n");
118  const long startMillis = SysUtils::getCurrentMillis();
119  // init queue
120  std::vector<CHInfo*> queue; // max heap: edge to be contracted is front
121  // reset previous connections etc
122  for (int i = 0; i < numEdges; i++) {
123  myCHInfos[i].resetContractionState();
124  result->forwardUplinks.push_back(std::vector<Connection>());
125  result->backwardUplinks.push_back(std::vector<Connection>());
126  }
127  // copy connections from the original net
128  const double time_seconds = STEPS2TIME(time); // timelines store seconds!
129  for (int i = 0; i < numEdges; i++) {
130  synchronize(myCHInfos[i], time_seconds, vehicle, effortProvider);
131  }
132  // synchronization is finished. now we can compute priorities for the first time
133  for (int i = 0; i < numEdges; i++) {
134  myCHInfos[i].updatePriority(mySPTree);
135  queue.push_back(&(myCHInfos[i]));
136  }
137  make_heap(queue.begin(), queue.end(), myCmp);
138  int contractionRank = 0;
139  // contraction loop
140  while (!queue.empty()) {
141  while (tryUpdateFront(queue)) {}
142  CHInfo* max = queue.front();
143  max->rank = contractionRank;
144 #ifdef CHRouter_DEBUG_CONTRACTION
145  std::cout << "contracting '" << max->edge->getID() << "' with prio: " << max->priority << " (rank " << contractionRank << ")\n";
146 #endif
147  const E* const edge = max->edge;
148  // add outgoing connections to the forward search
149  const int edgeID = edge->getNumericalID();
150  for (typename CHConnections::const_iterator it = max->followers.begin(); it != max->followers.end(); it++) {
151  const CHConnection& con = *it;
152  result->forwardUplinks[edgeID].push_back(Connection(con.target->edge->getNumericalID(), con.cost, con.permissions));
153  disconnect(con.target->approaching, max);
154  con.target->updatePriority(0);
155  }
156  // add incoming connections to the backward search
157  for (typename CHConnections::const_iterator it = max->approaching.begin(); it != max->approaching.end(); it++) {
158  const CHConnection& con = *it;
159  result->backwardUplinks[edgeID].push_back(Connection(con.target->edge->getNumericalID(), con.cost, con.permissions));
160  disconnect(con.target->followers, max);
161  con.target->updatePriority(0);
162  }
163  // add shortcuts to the net
164  for (typename std::vector<Shortcut>::const_iterator it = max->shortcuts.begin(); it != max->shortcuts.end(); it++) {
165  const ConstEdgePair& edgePair = it->edgePair;
166  result->shortcuts[edgePair] = edge;
167  CHInfo* from = getCHInfo(edgePair.first);
168  CHInfo* to = getCHInfo(edgePair.second);
169  from->followers.push_back(CHConnection(to, it->cost, it->permissions, it->underlying));
170  to->approaching.push_back(CHConnection(from, it->cost, it->permissions, it->underlying));
171  }
172  // if you need to debug the chrouter with MSVC uncomment the following line, hierarchy building will get slower and the hierarchy may change though
173  //make_heap(queue.begin(), queue.end(), myCmp);
174  // remove from queue
175  pop_heap(queue.begin(), queue.end(), myCmp);
176  queue.pop_back();
177  /*
178  if (contractionRank % 10000 == 0) {
179  // update all and rebuild queue
180  for (typename std::vector<CHInfo*>::iterator it = queue.begin(); it != queue.end(); ++it) {
181  (*it)->updatePriority(mySPTree);
182  }
183  make_heap(queue.begin(), queue.end(), myCmp);
184  }
185  */
186  contractionRank++;
187  }
188  // reporting
189  const long duration = SysUtils::getCurrentMillis() - startMillis;
190  WRITE_MESSAGE("Created " + toString(result->shortcuts.size()) + " shortcuts.");
191  WRITE_MESSAGE("Recomputed priority " + toString(myUpdateCount) + " times.");
192  MsgHandler::getMessageInstance()->endProcessMsg("done (" + toString(duration) + "ms).");
194  myUpdateCount = 0;
195  return result;
196  }
197 
198 private:
199  struct Shortcut {
200  Shortcut(ConstEdgePair e, double c, int u, SVCPermissions p):
201  edgePair(e), cost(c), underlying(u), permissions(p) {}
202  ConstEdgePair edgePair;
203  double cost;
206  };
207 
208 
209  class CHInfo;
210 
212  class CHConnection {
213  public:
214  CHConnection(CHInfo* t, double c, SVCPermissions p, int u):
215  target(t), cost(c), permissions(p), underlying(u) {}
217  double cost;
221  };
222 
223  typedef std::vector<CHConnection> CHConnections;
224  typedef std::pair<const CHConnection*, const CHConnection*> CHConnectionPair;
225  typedef std::vector<CHConnectionPair> CHConnectionPairs;
226 
227  /* @brief container class to use when building the contraction hierarchy.
228  * instances are reused every time the hierarchy is rebuilt (new time slice)
229  * but they must be synchronized first */
230  class CHInfo {
231  public:
233  CHInfo(const E* e) :
234  edge(e),
235  contractedNeighbors(0),
236  rank(-1),
237  level(0),
238  underlyingTotal(0),
239  visited(false),
240  traveltime(std::numeric_limits<double>::max()) {
241  }
242 
245  if (spTree != 0) {
246  updateShortcuts(spTree);
247  updateLevel();
248  } else {
249  contractedNeighbors += 1; // called when a connected edge was contracted
250  }
251  const double oldPriority = priority;
252  // priority term as used by abraham []
253  const int edge_difference = (int)followers.size() + (int)approaching.size() - 2 * (int)shortcuts.size();
254  priority = (double)(2 * edge_difference - contractedNeighbors - underlyingTotal - 5 * level);
255  return priority != oldPriority;
256  }
257 
260  const bool validatePermissions = spTree->validatePermissions();
261 #ifdef CHRouter_DEBUG_CONTRACTION_DEGREE
262  const int degree = (int)approaching.size() + (int)followers.size();
263  std::cout << "computing shortcuts for '" + edge->getID() + "' with degree " + toString(degree) + "\n";
264 #endif
265  shortcuts.clear();
266  underlyingTotal = 0;
267  for (typename CHConnections::iterator it_a = approaching.begin(); it_a != approaching.end(); it_a++) {
268  CHConnection& aInfo = *it_a;
269  // build shortest path tree in a fixed neighborhood
270  spTree->rebuildFrom(aInfo.target, this);
271  for (typename CHConnections::iterator it_f = followers.begin(); it_f != followers.end(); it_f++) {
272  CHConnection& fInfo = *it_f;
273  const double viaCost = aInfo.cost + fInfo.cost;
274  const SVCPermissions viaPermissions = (aInfo.permissions & fInfo.permissions);
275  if (fInfo.target->traveltime > viaCost) {
276  // found no faster path -> we need a shortcut via edge
277 #ifdef CHRouter_DEBUG_CONTRACTION_WITNESSES
278  debugNoWitness(aInfo, fInfo);
279 #endif
280  const int underlying = aInfo.underlying + fInfo.underlying;
281  underlyingTotal += underlying;
282  shortcuts.push_back(Shortcut(ConstEdgePair(aInfo.target->edge, fInfo.target->edge),
283  viaCost, underlying, viaPermissions));
284 
285  } else if (validatePermissions) {
286  if ((fInfo.target->permissions & viaPermissions) != viaPermissions) {
287  // witness has weaker restrictions. try to find another witness
288  spTree->registerForValidation(&aInfo, &fInfo);
289  } else {
290 #ifdef CHRouter_DEBUG_CONTRACTION_WITNESSES
291  debugNoWitness(aInfo, fInfo);
292 #endif
293  }
294  } else {
295 #ifdef CHRouter_DEBUG_CONTRACTION_WITNESSES
296  debugNoWitness(aInfo, fInfo);
297 #endif
298  }
299  }
300  }
301  // insert shortcuts needed due to unmet permissions
302  if (validatePermissions) {
303  const CHConnectionPairs& pairs = spTree->getNeededShortcuts(this);
304  for (typename CHConnectionPairs::const_iterator it = pairs.begin(); it != pairs.end(); ++it) {
305  const CHConnection* aInfo = it->first;
306  const CHConnection* fInfo = it->second;
307  const double viaCost = aInfo->cost + fInfo->cost;
308  const SVCPermissions viaPermissions = (aInfo->permissions & fInfo->permissions);
309  const int underlying = aInfo->underlying + fInfo->underlying;
310  underlyingTotal += underlying;
311  shortcuts.push_back(Shortcut(ConstEdgePair(aInfo->target->edge, fInfo->target->edge),
312  viaCost, underlying, viaPermissions));
313  }
314  }
315  }
316 
317 
318  // update level as defined by Abraham
319  void updateLevel() {
320  int maxLower = std::numeric_limits<int>::min();
321  int otherRank;
322  for (typename CHConnections::iterator it = approaching.begin(); it != approaching.end(); it++) {
323  otherRank = it->target->rank;
324  if (otherRank < rank) {
325  maxLower = MAX2(rank, maxLower);
326  }
327  }
328  for (typename CHConnections::iterator it = followers.begin(); it != followers.end(); it++) {
329  otherRank = it->target->rank;
330  if (otherRank < rank) {
331  maxLower = MAX2(rank, maxLower);
332  }
333  }
334  if (maxLower == std::numeric_limits<int>::min()) {
335  level = 0;
336  } else {
337  level = maxLower + 1;
338  }
339  }
340 
341  // resets state before rebuilding the hierarchy
343  contractedNeighbors = 0;
344  rank = -1;
345  level = 0;
346  underlyingTotal = 0;
347  shortcuts.clear();
348  followers.clear();
349  approaching.clear();
350  }
351 
352 
354  const E* edge;
356  double priority;
358  std::vector<Shortcut> shortcuts;
361  int rank;
362  int level;
364 
366  CHConnections followers;
367  CHConnections approaching;
368 
369 
371  bool visited;
373  double traveltime;
375  int depth;
377  // @note: we may miss some witness paths by making traveltime the only
378  // criteria durinng search
380 
381  inline void reset() {
382  traveltime = std::numeric_limits<double>::max();
383  visited = false;
384  }
385 
386 
388  inline void debugNoWitness(const CHConnection& aInfo, const CHConnection& fInfo) {
389  std::cout << "adding shortcut between " << aInfo.target->edge->getID() << ", " << fInfo.target->edge->getID() << " via " << edge->getID() << "\n";
390  }
391 
392  inline void debugWitness(const CHConnection& aInfo, const CHConnection& fInfo) {
393  const double viaCost = aInfo.cost + fInfo.cost;
394  std::cout << "found witness with lenght " << fInfo.target->traveltime << " against via " << edge->getID() << " (length " << viaCost << ") for " << aInfo.target->edge->getID() << ", " << fInfo.target->edge->getID() << "\n";
395  }
396 
397  };
398 
399 
405  public:
407  bool operator()(const CHInfo* a, const CHInfo* b) const {
408  if (a->priority == b->priority) {
409  return a->edge->getNumericalID() > b->edge->getNumericalID();
410  } else {
411  return a->priority < b->priority;
412  };
413  }
414  };
415 
416 
417  inline CHInfo* getCHInfo(const E* const edge) {
418  return &(myCHInfos[edge->getNumericalID()]);
419  }
420 
421 
423  void synchronize(CHInfo& info, double time, const V* const vehicle, const SUMOAbstractRouter<E, V>* effortProvider) {
424  // forward and backward connections are used only in forward search,
425  // thus approaching costs are those of the approaching edge and not of the edge itself
426  const bool prune = !mySPTree->validatePermissions();
427  const E* const edge = info.edge;
428  if (prune && ((edge->getPermissions() & mySVC) != mySVC)) {
429  return;
430  }
431  const double cost = effortProvider->getEffort(edge, vehicle, time);
432 
433  const std::vector<E*>& successors = edge->getSuccessors(mySVC);
434  for (typename std::vector<E*>::const_iterator it = successors.begin(); it != successors.end(); ++it) {
435  const E* fEdge = *it;
436  if (prune && ((fEdge->getPermissions() & mySVC) != mySVC)) {
437  continue;
438  }
439  CHInfo* follower = getCHInfo(fEdge);
440  SVCPermissions permissions = (edge->getPermissions() & follower->edge->getPermissions());
441  info.followers.push_back(CHConnection(follower, cost, permissions, 1));
442  follower->approaching.push_back(CHConnection(&info, cost, permissions, 1));
443  }
444 #ifdef CHRouter_DEBUG_WEIGHTS
445  std::cout << time << ": " << edge->getID() << " cost: " << cost << "\n";
446 #endif
447  // @todo: check whether we even need to save approaching in ROEdge;
448  }
449 
450 
452  void disconnect(CHConnections& connections, CHInfo* other) {
453  for (typename CHConnections::iterator it = connections.begin(); it != connections.end(); it++) {
454  if (it->target == other) {
455  connections.erase(it);
456  return;
457  }
458  }
459  assert(false);
460  }
461 
465  bool tryUpdateFront(std::vector<CHInfo*>& queue) {
466  myUpdateCount++;
467  CHInfo* max = queue.front();
468 #ifdef CHRouter_DEBUG_CONTRACTION_QUEUE
469  std::cout << "updating '" << max->edge->getID() << "'\n";
470  debugPrintQueue(queue);
471 #endif
472  if (max->updatePriority(mySPTree)) {
473  pop_heap(queue.begin(), queue.end(), myCmp);
474  push_heap(queue.begin(), queue.end(), myCmp);
475  return true;
476  } else {
477  return false;
478  }
479  }
480 
481  // helper method for debugging
482  void debugPrintQueue(std::vector<CHInfo*>& queue) {
483  for (typename std::vector<CHInfo*>::iterator it = queue.begin(); it != queue.end(); it++) {
484  CHInfo* chInfo = *it;
485  std::cout << "(" << chInfo->edge->getID() << "," << chInfo->priority << ") ";
486  }
487  std::cout << "\n";
488  }
489 
490 private:
492  const std::vector<E*>& myEdges;
493 
496 
498  std::vector<CHInfo> myCHInfos;
499 
502 
505 
508 
511 
512 private:
514  CHBuilder& operator=(const CHBuilder& s);
515 };
516 
517 
518 #endif
519 
520 /****************************************************************************/
521 
bool operator()(const CHInfo *a, const CHInfo *b) const
Comparing method.
Definition: CHBuilder.h:407
CHInfoComparator myCmp
Comparator for contraction priority.
Definition: CHBuilder.h:501
bool tryUpdateFront(std::vector< CHInfo *> &queue)
tries to update the priority of the first edge
Definition: CHBuilder.h:465
double getEffort(const E *const e, const V *const v, double t) const
long long int SUMOTime
Definition: SUMOTime.h:36
int depth
number of edges from start
Definition: CHBuilder.h:375
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
int contractedNeighbors
priority subterms
Definition: CHBuilder.h:360
Connection(int t, double c, SVCPermissions p)
Definition: CHBuilder.h:73
CHInfo * getCHInfo(const E *const edge)
Definition: CHBuilder.h:417
void resetContractionState()
Definition: CHBuilder.h:342
std::map< ConstEdgePair, const E * > ShortcutVia
Definition: CHBuilder.h:80
SVCPermissions permissions
Definition: CHBuilder.h:76
void debugWitness(const CHConnection &aInfo, const CHConnection &fInfo)
Definition: CHBuilder.h:392
Shortcut(ConstEdgePair e, double c, int u, SVCPermissions p)
Definition: CHBuilder.h:200
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const std::vector< E * > & myEdges
all edges with numerical ids
Definition: CHBuilder.h:492
MsgHandler *const myErrorMsgHandler
the handler for routing errors
Definition: CHBuilder.h:495
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:67
void debugPrintQueue(std::vector< CHInfo *> &queue)
Definition: CHBuilder.h:482
T MAX2(T a, T b)
Definition: StdDefs.h:68
SVCPermissions permissions
Definition: CHBuilder.h:218
int underlying
the number of connections underlying this connection
Definition: CHBuilder.h:220
bool updatePriority(SPTree< CHInfo, CHConnection > *spTree)
recompute the contraction priority and report whether it changed
Definition: CHBuilder.h:244
void synchronize(CHInfo &info, double time, const V *const vehicle, const SUMOAbstractRouter< E, V > *effortProvider)
copy connections from the original net (modified destructively during contraction) ...
Definition: CHBuilder.h:423
CHConnections approaching
Definition: CHBuilder.h:367
const SUMOVehicleClass mySVC
the permissions for which the hierarchy was constructed
Definition: CHBuilder.h:507
CHConnections followers
connections (only valid after synchronization)
Definition: CHBuilder.h:366
int myUpdateCount
counters for performance logging
Definition: CHBuilder.h:510
void debugNoWitness(const CHConnection &aInfo, const CHConnection &fInfo)
debugging methods
Definition: CHBuilder.h:388
SPTree< CHInfo, CHConnection > * mySPTree
the shortest path tree to use when searching for shortcuts
Definition: CHBuilder.h:504
double traveltime
Effort to reach the edge.
Definition: CHBuilder.h:373
void registerForValidation(const C *aInfo, const C *fInfo)
save source/target pair for later validation
Definition: SPTree.h:135
std::vector< std::vector< Connection > > backwardUplinks
Definition: CHBuilder.h:84
ConstEdgePair edgePair
Definition: CHBuilder.h:202
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
SVCPermissions permissions
Definition: CHBuilder.h:205
const CHConnectionPairs & getNeededShortcuts(const E *excluded)
Definition: SPTree.h:143
#define STEPS2TIME(x)
Definition: SUMOTime.h:58
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:244
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
Definition: MsgHandler.cpp:58
std::vector< CHConnectionPair > CHConnectionPairs
Definition: CHBuilder.h:225
std::pair< const E *, const E * > ConstEdgePair
Definition: CHBuilder.h:79
StringBijection< SUMOVehicleClass > SumoVehicleClassStrings(sumoVehicleClassStringInitializer, SVC_CUSTOM2, false)
virtual ~CHBuilder()
Destructor.
Definition: CHBuilder.h:106
std::vector< std::vector< Connection > > forwardUplinks
Definition: CHBuilder.h:83
void disconnect(CHConnections &connections, CHInfo *other)
remove all connections to/from the given edge (assume it exists only once)
Definition: CHBuilder.h:452
Definition: SPTree.h:39
CHConnection(CHInfo *t, double c, SVCPermissions p, int u)
Definition: CHBuilder.h:214
double priority
The contraction priority.
Definition: CHBuilder.h:356
CHBuilder(const std::vector< E *> &edges, bool unbuildIsWarning, const SUMOVehicleClass svc, bool validatePermissions)
Constructor.
Definition: CHBuilder.h:92
bool visited
members used in SPTree
Definition: CHBuilder.h:371
const E * edge
The current edge - not const since it may receive shortcut edges.
Definition: CHBuilder.h:354
void rebuildFrom(E *start, const E *excluded)
build a shortest path tree from start to a depth of myMaxdepth. The given edge is excluded from this ...
Definition: SPTree.h:88
CHBuilder & operator=(const CHBuilder &s)
Invalidated assignment operator.
const Hierarchy * buildContractionHierarchy(SUMOTime time, const V *const vehicle, const SUMOAbstractRouter< E, V > *effortProvider)
Definition: CHBuilder.h:111
std::pair< const CHConnection *, const CHConnection * > CHConnectionPair
Definition: CHBuilder.h:224
SVCPermissions permissions
the permissions when reaching this edge on the fastest path
Definition: CHBuilder.h:379
Forward/backward connection with associated FORWARD cost.
Definition: CHBuilder.h:212
CHInfo(const E *e)
Constructor.
Definition: CHBuilder.h:233
std::vector< CHInfo > myCHInfos
static vector for lookup
Definition: CHBuilder.h:498
std::vector< CHConnection > CHConnections
Definition: CHBuilder.h:223
bool validatePermissions()
whether permissions should be validated;
Definition: SPTree.h:130
static long getCurrentMillis()
Returns the current time in milliseconds.
Definition: SysUtils.cpp:39
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:245
Forward/backward connection with associated forward/backward cost.
Definition: CHBuilder.h:71
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:243
std::vector< Shortcut > shortcuts
The needed shortcuts.
Definition: CHBuilder.h:358
void updateLevel()
Definition: CHBuilder.h:319
ShortcutVia shortcuts
Definition: CHBuilder.h:82
void updateShortcuts(SPTree< CHInfo, CHConnection > *spTree)
compute needed shortcuts when contracting this edge
Definition: CHBuilder.h:259
void endProcessMsg(std::string msg)
Ends a process information.
Definition: MsgHandler.cpp:155