SUMO - Simulation of Urban MObility
CHRouter.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 // Shortest Path search using a Contraction Hierarchy
18 /****************************************************************************/
19 #ifndef CHRouter_h
20 #define CHRouter_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 <deque>
36 #include <utils/common/SysUtils.h>
38 #include <utils/common/StdDefs.h>
40 #include "CHBuilder.h"
41 
42 //#define CHRouter_DEBUG_QUERY
43 //#define CHRouter_DEBUG_QUERY_PERF
44 
45 // ===========================================================================
46 // class definitions
47 // ===========================================================================
62 template<class E, class V, class BASE>
63 class CHRouter: public BASE {
64 
65 public:
67  typedef double(* Operation)(const E* const, const V* const, double);
68 
74  class EdgeInfo {
75  public:
77  EdgeInfo(const E* e) :
78  edge(e),
79  traveltime(std::numeric_limits<double>::max()),
80  prev(0),
81  visited(false) {
82  }
83 
85  const E* edge;
86 
88  double traveltime;
89 
92 
94  bool visited;
95 
96  inline void reset() {
97  traveltime = std::numeric_limits<double>::max();
98  visited = false;
99  }
100  };
101 
102 
104  typedef std::pair<const EdgeInfo*, const EdgeInfo*> Meeting;
105 
111  public:
113  Unidirectional(const std::vector<E*>& edges, bool forward):
114  myAmForward(forward),
115  myVehicle(0) {
116  for (typename std::vector<E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
117  myEdgeInfos.push_back(EdgeInfo(*i));
118  }
119  }
120 
121  inline bool found(const E* edge) const {
122  return myFound.count(edge) > 0;
123  }
124 
125  inline EdgeInfo* getEdgeInfo(const E* const edge) {
126  return &(myEdgeInfos[edge->getNumericalID()]);
127  }
128 
129  inline const EdgeInfo* getEdgeInfo(const E* const edge) const {
130  return &(myEdgeInfos[edge->getNumericalID()]);
131  }
132 
138  public:
140  bool operator()(const EdgeInfo* nod1, const EdgeInfo* nod2) const {
141  if (nod1->traveltime == nod2->traveltime) {
142  return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
143  }
144  return nod1->traveltime > nod2->traveltime;
145  }
146  };
147 
148 
149  void init(const E* const start, const V* const vehicle) {
150  assert(vehicle != 0);
151  // all EdgeInfos touched in the previous query are either in myFrontier or myFound: clean those up
152  for (typename std::vector<EdgeInfo*>::iterator i = myFrontier.begin(); i != myFrontier.end(); i++) {
153  (*i)->reset();
154  }
155  myFrontier.clear();
156  for (typename std::set<const E*>::const_iterator i = myFound.begin(); i != myFound.end(); i++) {
157  getEdgeInfo(*i)->reset();
158  }
159  myFound.clear();
160  myVehicle = vehicle;
161  EdgeInfo* startInfo = getEdgeInfo(start);
162  startInfo->traveltime = 0;
163  startInfo->prev = 0;
164  myFrontier.push_back(startInfo);
165  }
166 
167 
168  typedef std::vector<typename CHBuilder<E, V>::Connection> ConnectionVector;
173  bool step(const std::vector<ConnectionVector>& uplinks, const Unidirectional& otherSearch, double& minTTSeen, Meeting& meeting) {
174  // pop the node with the minimal length
175  EdgeInfo* const minimumInfo = myFrontier.front();
176  pop_heap(myFrontier.begin(), myFrontier.end(), myComparator);
177  myFrontier.pop_back();
178  // check for a meeting with the other search
179  const E* const minEdge = minimumInfo->edge;
180 #ifdef CHRouter_DEBUG_QUERY
181  std::cout << "DEBUG: " << (myAmForward ? "Forward" : "Backward") << " hit '" << minEdge->getID() << "' Q: ";
182  for (typename std::vector<EdgeInfo*>::iterator it = myFrontier.begin(); it != myFrontier.end(); it++) {
183  std::cout << (*it)->traveltime << "," << (*it)->edge->getID() << " ";
184  }
185  std::cout << "\n";
186 #endif
187  if (otherSearch.found(minEdge)) {
188  const EdgeInfo* const otherInfo = otherSearch.getEdgeInfo(minEdge);
189  const double ttSeen = minimumInfo->traveltime + otherInfo->traveltime;
190 #ifdef CHRouter_DEBUG_QUERY
191  std::cout << "DEBUG: " << (myAmForward ? "Forward" : "Backward") << "-Search hit other search at '" << minEdge->getID() << "', tt: " << ttSeen << " \n";
192 #endif
193  if (ttSeen < minTTSeen) {
194  minTTSeen = ttSeen;
195  if (myAmForward) {
196  meeting.first = minimumInfo;
197  meeting.second = otherInfo;
198  } else {
199  meeting.first = otherInfo;
200  meeting.second = minimumInfo;
201  }
202  }
203  }
204  // prepare next steps
205  minimumInfo->visited = true;
206  // XXX we only need to keep found elements if they have a higher rank than the lowest rank in the other search queue
207  myFound.insert(minimumInfo->edge);
208  const ConnectionVector& upward = uplinks[minEdge->getNumericalID()];
209  for (typename ConnectionVector::const_iterator it = upward.begin(); it != upward.end(); it++) {
210  EdgeInfo* upwardInfo = &myEdgeInfos[it->target];
211  const double traveltime = minimumInfo->traveltime + it->cost;
212  const SUMOVehicleClass svc = myVehicle->getVClass();
213  // check whether it can be used
214  if ((it->permissions & svc) != svc) {
215  continue;
216  }
217  const double oldTraveltime = upwardInfo->traveltime;
218  if (!upwardInfo->visited && traveltime < oldTraveltime) {
219  upwardInfo->traveltime = traveltime;
220  upwardInfo->prev = minimumInfo;
221  if (oldTraveltime == std::numeric_limits<double>::max()) {
222  myFrontier.push_back(upwardInfo);
223  push_heap(myFrontier.begin(), myFrontier.end(), myComparator);
224  } else {
225  push_heap(myFrontier.begin(),
226  find(myFrontier.begin(), myFrontier.end(), upwardInfo) + 1,
227  myComparator);
228  }
229  }
230  }
231  // @note: this effectively does a full dijkstra search.
232  // the effort compared to the naive stopping criterion is thus
233  // quadrupled. We could implement a better stopping criterion (Holte)
234  // However since the search shall take place in a contracted graph
235  // it probably does not matter
236  return !myFrontier.empty() && myFrontier.front()->traveltime < minTTSeen;
237  }
238 
239  private:
243  std::vector<EdgeInfo*> myFrontier;
245  std::set<const E*> myFound;
247  std::vector<EdgeInfo> myEdgeInfos;
248 
250 
251  const V* myVehicle;
252 
253  };
254 
260  CHRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename BASE::Operation operation,
261  const SUMOVehicleClass svc,
262  SUMOTime weightPeriod,
263  bool validatePermissions):
264  BASE("CHRouter", operation),
265  myEdges(edges),
266  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
267  myForwardSearch(edges, true),
268  myBackwardSearch(edges, false),
269  myHierarchyBuilder(new CHBuilder<E, V>(edges, unbuildIsWarning, svc, validatePermissions)),
270  myHierarchy(0),
271  myWeightPeriod(weightPeriod),
272  myValidUntil(0),
273  mySVC(svc) {
274  }
275 
278  CHRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename BASE::Operation operation,
279  const SUMOVehicleClass svc,
280  SUMOTime weightPeriod,
281  const typename CHBuilder<E, V>::Hierarchy* hierarchy) :
282  BASE("CHRouterClone", operation),
283  myEdges(edges),
284  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
285  myForwardSearch(edges, true),
286  myBackwardSearch(edges, false),
288  myHierarchy(hierarchy),
289  myWeightPeriod(weightPeriod),
290  myValidUntil(0),
291  mySVC(svc) {
292  }
293 
295  virtual ~CHRouter() {
296  if (myHierarchyBuilder != 0) {
297  delete myHierarchy;
298  delete myHierarchyBuilder;
299  }
300  }
301 
302 
304  WRITE_MESSAGE("Cloning Contraction Hierarchy for " + SumoVehicleClassStrings.getString(mySVC) + " and time " + time2string(myValidUntil) + ".");
307  clone->myValidUntil = myValidUntil;
308  return clone;
309  }
310 
315  virtual bool compute(const E* from, const E* to, const V* const vehicle,
316  SUMOTime msTime, std::vector<const E*>& into) {
317  assert(from != 0 && to != 0);
318  // assert(myHierarchyBuilder.mySPTree->validatePermissions() || vehicle->getVClass() == mySVC || mySVC == SVC_IGNORING);
319  // do we need to rebuild the hierarchy?
320  if (msTime >= myValidUntil) {
321  while (msTime >= myValidUntil) {
323  }
325  }
326  // ready for routing
327  this->startQuery();
328  myForwardSearch.init(from, vehicle);
329  myBackwardSearch.init(to, vehicle);
330  double minTTSeen = std::numeric_limits<double>::max();
331  Meeting meeting(static_cast<EdgeInfo*>(0), static_cast<EdgeInfo*>(0));
332  bool continueForward = true;
333  bool continueBackward = true;
334  int num_visited_fw = 0;
335  int num_visited_bw = 0;
336  bool result = true;
337  while (continueForward || continueBackward) {
338  if (continueForward) {
339  continueForward = myForwardSearch.step(myHierarchy->forwardUplinks, myBackwardSearch, minTTSeen, meeting);
340  num_visited_fw += 1;
341  }
342  if (continueBackward) {
343  continueBackward = myBackwardSearch.step(myHierarchy->backwardUplinks, myForwardSearch, minTTSeen, meeting);
344  num_visited_bw += 1;
345  }
346  }
347  if (minTTSeen < std::numeric_limits<double>::max()) {
348  buildPathFromMeeting(meeting, into);
349  } else {
350  myErrorMsgHandler->inform("No connection between edge '" + from->getID() + "' and edge '" + to->getID() + "' found.");
351  result = false;
352  }
353 #ifdef CHRouter_DEBUG_QUERY_PERF
354  std::cout << "visited " << num_visited_fw + num_visited_bw << " edges (" << num_visited_fw << "," << num_visited_bw << ") ,final path length: " + toString(into.size()) + ")\n";
355 #endif
356  this->endQuery(num_visited_bw + num_visited_fw);
357  return result;
358  }
359 
361 
363  void buildPathFromMeeting(Meeting meeting, std::vector<const E*>& into) const {
364  std::deque<const E*> tmp;
365  const EdgeInfo* backtrack = meeting.first;
366  while (backtrack != 0) {
367  tmp.push_front((E*) backtrack->edge); // !!!
368  backtrack = backtrack->prev;
369  }
370  backtrack = meeting.second->prev; // don't use central edge twice
371  while (backtrack != 0) {
372  tmp.push_back((E*) backtrack->edge); // !!!
373  backtrack = backtrack->prev;
374  }
375  // expand shortcuts
376  const E* prev = 0;
377  while (!tmp.empty()) {
378  const E* cur = tmp.front();
379  tmp.pop_front();
380  if (prev == 0) {
381  into.push_back(cur);
382  prev = cur;
383  } else {
384  const E* via = getVia(prev, cur);
385  if (via == 0) {
386  into.push_back(cur);
387  prev = cur;
388  } else {
389  tmp.push_front(cur);
390  tmp.push_front(via);
391  }
392  }
393  }
394  }
395 
396  void buildContractionHierarchy(SUMOTime time, const V* const vehicle) {
397  if (myHierarchyBuilder != 0) {
398  delete myHierarchy;
399  myHierarchy = myHierarchyBuilder->buildContractionHierarchy(time, vehicle, this);
400  }
401  // declare new validUntil (prevent overflow)
402  if (myWeightPeriod < std::numeric_limits<int>::max()) {
403  myValidUntil = time + myWeightPeriod;
404  } else {
406  }
407  }
408 
409 private:
410  // retrieve the via edge for a shortcut
411  const E* getVia(const E* forwardFrom, const E* forwardTo) const {
412  typename CHBuilder<E, V>::ConstEdgePair forward(forwardFrom, forwardTo);
413  typename CHBuilder<E, V>::ShortcutVia::const_iterator it = myHierarchy->shortcuts.find(forward);
414  if (it != myHierarchy->shortcuts.end()) {
415  return it->second;
416  } else {
417  return 0;
418  }
419  }
420 
421 
422 private:
424  const std::vector<E*>& myEdges;
425 
428 
432 
435 
438 
441 
444 };
445 
446 
447 #endif
448 
449 /****************************************************************************/
450 
Computes the shortest path through a contracted network.
Definition: CHRouter.h:63
const SUMOVehicleClass mySVC
the permissions for which the hierarchy was constructed
Definition: CHRouter.h:443
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:67
long long int SUMOTime
Definition: SUMOTime.h:36
SUMOTime myValidUntil
the validity duration of the current hierarchy (exclusive)
Definition: CHRouter.h:440
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
bool operator()(const EdgeInfo *nod1, const EdgeInfo *nod2) const
Comparing method.
Definition: CHRouter.h:140
std::vector< typename CHBuilder< E, V >::Connection > ConnectionVector
Definition: CHRouter.h:168
void buildContractionHierarchy(SUMOTime time, const V *const vehicle)
Definition: CHRouter.h:396
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:67
void init(const E *const start, const V *const vehicle)
Definition: CHRouter.h:149
EdgeInfo * prev
The previous edge.
Definition: CHRouter.h:91
void buildPathFromMeeting(Meeting meeting, std::vector< const E *> &into) const
normal routing methods
Definition: CHRouter.h:363
virtual ~CHRouter()
Destructor.
Definition: CHRouter.h:295
std::vector< EdgeInfo * > myFrontier
the min edge heap
Definition: CHRouter.h:243
CHRouter(const std::vector< E *> &edges, bool unbuildIsWarning, typename BASE::Operation operation, const SUMOVehicleClass svc, SUMOTime weightPeriod, bool validatePermissions)
Constructor.
Definition: CHRouter.h:260
Unidirectional myBackwardSearch
Definition: CHRouter.h:431
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
const CHBuilder< E, V >::Hierarchy * myHierarchy
Definition: CHRouter.h:434
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E *> &into)
Builds the route between the given edges using the minimum traveltime in the contracted graph...
Definition: CHRouter.h:315
std::vector< EdgeInfo > myEdgeInfos
The container of edge information.
Definition: CHRouter.h:247
double traveltime
Effort to reach the edge.
Definition: CHRouter.h:88
const E * getVia(const E *forwardFrom, const E *forwardTo) const
Definition: CHRouter.h:411
bool visited
Whether the shortest path to this edge is already found.
Definition: CHRouter.h:94
const std::vector< E * > & myEdges
all edges with numerical ids
Definition: CHRouter.h:424
MsgHandler *const myErrorMsgHandler
the handler for routing errors
Definition: CHRouter.h:427
std::pair< const E *, const E * > ConstEdgePair
Definition: CHBuilder.h:79
StringBijection< SUMOVehicleClass > SumoVehicleClassStrings(sumoVehicleClassStringInitializer, SVC_CUSTOM2, false)
EdgeInfo(const E *e)
Constructor.
Definition: CHRouter.h:77
std::set< const E * > myFound
the set of visited (settled) Edges
Definition: CHRouter.h:245
const SUMOTime myWeightPeriod
the validity duration of one weight interval
Definition: CHRouter.h:437
const E * edge
The current edge.
Definition: CHRouter.h:85
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:113
double(* Operation)(const E *const, const V *const, double)
Type of the function that is used to retrieve the edge effort.
Definition: CHRouter.h:67
std::pair< const EdgeInfo *, const EdgeInfo * > Meeting
A meeting point of the two search scopes.
Definition: CHRouter.h:104
EdgeInfo * getEdgeInfo(const E *const edge)
Definition: CHRouter.h:125
Unidirectional(const std::vector< E *> &edges, bool forward)
Constructor.
Definition: CHRouter.h:113
Unidirectional myForwardSearch
the unidirectional search queues
Definition: CHRouter.h:430
virtual SUMOAbstractRouter< E, V > * clone()
Definition: CHRouter.h:303
bool myAmForward
the role of this search
Definition: CHRouter.h:241
bool found(const E *edge) const
Definition: CHRouter.h:121
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:243
const EdgeInfo * getEdgeInfo(const E *const edge) const
Definition: CHRouter.h:129
EdgeInfoByTTComparator myComparator
Definition: CHRouter.h:249
bool step(const std::vector< ConnectionVector > &uplinks, const Unidirectional &otherSearch, double &minTTSeen, Meeting &meeting)
explore on element from the frontier,update minTTSeen and meeting if an EdgeInfo found by the otherSe...
Definition: CHRouter.h:173
CHBuilder< E, V > * myHierarchyBuilder
Definition: CHRouter.h:433
CHRouter(const std::vector< E *> &edges, bool unbuildIsWarning, typename BASE::Operation operation, const SUMOVehicleClass svc, SUMOTime weightPeriod, const typename CHBuilder< E, V >::Hierarchy *hierarchy)
Cloning constructor.
Definition: CHRouter.h:278