SUMO - Simulation of Urban MObility
AStarRouter.h
Go to the documentation of this file.
1 /****************************************************************************/
9 // A* Algorithm using euclidean distance heuristic.
10 // Based on DijkstraRouterTT. For routing by effort a novel heuristic would be needed.
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
13 // Copyright (C) 2012-2017 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 #ifndef AStarRouter_h
24 #define AStarRouter_h
25 
26 
27 // ===========================================================================
28 // included modules
29 // ===========================================================================
30 #ifdef _MSC_VER
31 #include <windows_config.h>
32 #else
33 #include <config.h>
34 #endif
35 
36 #include <cassert>
37 #include <string>
38 #include <functional>
39 #include <vector>
40 #include <set>
41 #include <limits>
42 #include <algorithm>
43 #include <iterator>
44 #include <map>
45 #include <iostream>
49 #include <utils/common/StdDefs.h>
50 #include <utils/common/ToString.h>
53 #include "AStarLookupTable.h"
54 #include "SUMOAbstractRouter.h"
55 
56 #define UNREACHABLE (std::numeric_limits<double>::max() / 1000.0)
57 
58 //#define ASTAR_DEBUG_QUERY
59 //#define ASTAR_DEBUG_QUERY_FOLLOWERS
60 //#define ASTAR_DEBUG_QUERY_PERF
61 //#define ASTAR_DEBUG_VISITED
62 //#define ASTAR_DEBUG_LOOKUPTABLE
63 //#define ASTAR_DEBUG_LOOKUPTABLE_FROM "disabled"
64 //#define ASTAR_DEBUG_UNREACHABLE
65 
66 // ===========================================================================
67 // class definitions
68 // ===========================================================================
84 template<class E, class V, class PF>
85 class AStarRouter : public SUMOAbstractRouter<E, V>, public PF {
86 
87 public:
91  typedef double(* Operation)(const E* const, const V* const, double);
92 
93 
94 
100  class EdgeInfo {
101  public:
103  EdgeInfo(const E* e) :
104  edge(e),
105  traveltime(std::numeric_limits<double>::max()),
106  heuristicTime(std::numeric_limits<double>::max()),
107  prev(0),
108  visited(false) {
109  }
110 
112  const E* edge;
113 
115  double traveltime;
116 
119 
122 
124  bool visited;
125 
126  inline void reset() {
127  // heuristicTime is set before adding to the frontier, thus no reset is needed
128  traveltime = std::numeric_limits<double>::max();
129  visited = false;
130  }
131 
132  };
133 
139  public:
141  bool operator()(const EdgeInfo* nod1, const EdgeInfo* nod2) const {
142  if (nod1->heuristicTime == nod2->heuristicTime) {
143  return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
144  }
145  return nod1->heuristicTime > nod2->heuristicTime;
146  }
147  };
148 
150  AStarRouter(const std::vector<E*>& edges, bool unbuildIsWarning, Operation operation, const LookupTable* const lookup = 0):
151  SUMOAbstractRouter<E, V>(operation, "AStarRouter"),
152  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
153  myLookupTable(lookup),
155  for (typename std::vector<E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
156  myEdgeInfos.push_back(EdgeInfo(*i));
157  myMaxSpeed = MAX2(myMaxSpeed, (*i)->getSpeedLimit() * MAX2(1.0, (*i)->getLengthGeometryFactor()));
158  }
159  }
160 
161  AStarRouter(const std::vector<EdgeInfo>& edgeInfos, bool unbuildIsWarning, Operation operation, const LookupTable* const lookup = 0):
162  SUMOAbstractRouter<E, V>(operation, "AStarRouter"),
163  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
164  myLookupTable(lookup),
166  for (typename std::vector<EdgeInfo>::const_iterator i = edgeInfos.begin(); i != edgeInfos.end(); ++i) {
167  myEdgeInfos.push_back(EdgeInfo(i->edge));
168  myMaxSpeed = MAX2(myMaxSpeed, i->edge->getSpeedLimit() * i->edge->getLengthGeometryFactor());
169  }
170  }
171 
173  virtual ~AStarRouter() {}
174 
177  }
178 
179  void init() {
180  // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
181  for (typename std::vector<EdgeInfo*>::iterator i = myFrontierList.begin(); i != myFrontierList.end(); i++) {
182  (*i)->reset();
183  }
184  myFrontierList.clear();
185  for (typename std::vector<EdgeInfo*>::iterator i = myFound.begin(); i != myFound.end(); i++) {
186  (*i)->reset();
187  }
188  myFound.clear();
189  }
190 
191 
193  virtual bool compute(const E* from, const E* to, const V* const vehicle,
194  SUMOTime msTime, std::vector<const E*>& into) {
195  assert(from != 0 && to != 0);
196  // check whether from and to can be used
197  if (PF::operator()(from, vehicle)) {
198  myErrorMsgHandler->inform("Vehicle '" + vehicle->getID() + "' is not allowed on source edge '" + from->getID() + "'.");
199  return false;
200  }
201  if (PF::operator()(to, vehicle)) {
202  myErrorMsgHandler->inform("Vehicle '" + vehicle->getID() + "' is not allowed on destination edge '" + to->getID() + "'.");
203  return false;
204  }
205  this->startQuery();
206 #ifdef ASTAR_DEBUG_QUERY
207  std::cout << "DEBUG: starting search for '" << vehicle->getID() << "' speed: " << MIN2(vehicle->getMaxSpeed(), myMaxSpeed * vehicle->getChosenSpeedFactor()) << " time: " << STEPS2TIME(msTime) << "\n";
208 #endif
209  const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
210  const double time = STEPS2TIME(msTime);
211  if (this->myBulkMode) {
212  const EdgeInfo& toInfo = myEdgeInfos[to->getNumericalID()];
213  if (toInfo.visited) {
214  buildPathFrom(&toInfo, into);
215  this->endQuery(1);
216  return true;
217  }
218  } else {
219  init();
220  // add begin node
221  EdgeInfo* const fromInfo = &(myEdgeInfos[from->getNumericalID()]);
222  fromInfo->traveltime = 0;
223  fromInfo->prev = 0;
224  myFrontierList.push_back(fromInfo);
225  }
226  // loop
227  int num_visited = 0;
228  const bool mayRevisit = myLookupTable != 0 && !myLookupTable->consistent();
229  const double speed = MIN2(vehicle->getMaxSpeed(), myMaxSpeed * vehicle->getChosenSpeedFactor());
230  while (!myFrontierList.empty()) {
231  num_visited += 1;
232  // use the node with the minimal length
233  EdgeInfo* const minimumInfo = myFrontierList.front();
234  const E* const minEdge = minimumInfo->edge;
235  // check whether the destination node was already reached
236  if (minEdge == to) {
237  buildPathFrom(minimumInfo, into);
238  this->endQuery(num_visited);
239 #ifdef ASTAR_DEBUG_QUERY_PERF
240  std::cout << "visited " + toString(num_visited) + " edges (final path length=" + toString(into.size())
241  + " time=" + toString(recomputeCosts(into, vehicle, msTime))
242  + " edges=" + toString(into) + ")\n";
243 #endif
244 #ifdef ASTAR_DEBUG_VISITED
245  OutputDevice& dev = OutputDevice::getDevice(vehicle->getID() + "_" + time2string(msTime) + "_" + from->getID() + "_" + to->getID());
246  for (typename std::vector<EdgeInfo>::const_iterator i = myEdgeInfos.begin(); i != myEdgeInfos.end(); ++i) {
247  if (i->visited) {
248  dev << "edge:" << i->edge->getID() << "\n";
249  }
250  }
251  dev.close();
252 #endif
253  return true;
254  }
255  pop_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
256  myFrontierList.pop_back();
257  myFound.push_back(minimumInfo);
258  minimumInfo->visited = true;
259 #ifdef ASTAR_DEBUG_QUERY
260  std::cout << "DEBUG: hit=" << minEdge->getID()
261  << " TT=" << minimumInfo->traveltime
262  << " EF=" << this->getEffort(minEdge, vehicle, time + minimumInfo->traveltime)
263  << " HT=" << minimumInfo->heuristicTime
264  << " Q(TT,HT,Edge)=";
265  for (typename std::vector<EdgeInfo*>::iterator it = myFrontierList.begin(); it != myFrontierList.end(); it++) {
266  std::cout << (*it)->traveltime << "," << (*it)->heuristicTime << "," << (*it)->edge->getID() << " ";
267  }
268  std::cout << "\n";
269 #endif
270  const double traveltime = minimumInfo->traveltime + this->getEffort(minEdge, vehicle, time + minimumInfo->traveltime);
271  // admissible A* heuristic: straight line distance at maximum speed
272  const double heuristic_remaining = (myLookupTable == 0 ? minEdge->getDistanceTo(to) / speed :
273  myLookupTable->lowerBound(minEdge, to, speed, vehicle->getChosenSpeedFactor(), minEdge->getMinimumTravelTime(0), to->getMinimumTravelTime(0)));
274  if (heuristic_remaining == UNREACHABLE) {
275  continue;
276  }
277  // check all ways from the node with the minimal length
278  const std::vector<E*>& successors = minEdge->getSuccessors(vClass);
279  for (typename std::vector<E*>::const_iterator it = successors.begin(); it != successors.end(); ++it) {
280  const E* const follower = *it;
281  EdgeInfo* const followerInfo = &(myEdgeInfos[follower->getNumericalID()]);
282  // check whether it can be used
283  if (PF::operator()(follower, vehicle)) {
284  continue;
285  }
286  const double oldEffort = followerInfo->traveltime;
287  if ((!followerInfo->visited || mayRevisit) && traveltime < oldEffort) {
288  followerInfo->traveltime = traveltime;
289  followerInfo->heuristicTime = traveltime + heuristic_remaining;
290  /* the code below results in fewer edges being looked up but is more costly due to the effort
291  calculations. Overall it resulted in a slowdown in the Berlin tests but could be made configurable someday.
292  followerInfo->heuristicTime = traveltime;
293  if (follower != to) {
294  if (myLookupTable == 0) {
295  // admissible A* heuristic: straight line distance at maximum speed
296  followerInfo->heuristicTime += this->getEffort(follower, vehicle, time + traveltime) + follower->getDistanceTo(to) / speed;
297  } else {
298  followerInfo->heuristicTime += this->getEffort(follower, vehicle, time + traveltime) + (*myLookupTable)[follower->getNumericalID()][to->getNumericalID()] / vehicle->getChosenSpeedFactor();
299  }
300  }*/
301 #ifdef ASTAR_DEBUG_QUERY_FOLLOWERS
302  std::cout << " follower=" << followerInfo->edge->getID() << " OEF=" << oldEffort << " TT=" << traveltime << " HR=" << heuristic_remaining << " HT=" << followerInfo->heuristicTime << "\n";
303 #endif
304  followerInfo->prev = minimumInfo;
305  if (oldEffort == std::numeric_limits<double>::max()) {
306  myFrontierList.push_back(followerInfo);
307  push_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
308  } else {
309  typename std::vector<EdgeInfo*>::iterator fi = find(myFrontierList.begin(), myFrontierList.end(), followerInfo);
310  if (fi == myFrontierList.end()) {
311  assert(mayRevisit);
312  myFrontierList.push_back(followerInfo);
313  push_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
314  } else {
315  push_heap(myFrontierList.begin(), fi + 1, myComparator);
316  }
317  }
318  }
319  }
320  }
321  this->endQuery(num_visited);
322 #ifdef ASTAR_DEBUG_QUERY_PERF
323  std::cout << "visited " + toString(num_visited) + " edges (unsuccesful path length: " + toString(into.size()) + ")\n";
324 #endif
325  myErrorMsgHandler->inform("No connection between edge '" + from->getID() + "' and edge '" + to->getID() + "' found.");
326  return false;
327  }
328 
329 
330  double recomputeCosts(const std::vector<const E*>& edges, const V* const v, SUMOTime msTime) const {
331  const double time = STEPS2TIME(msTime);
332  double costs = 0;
333  for (typename std::vector<const E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
334  if (PF::operator()(*i, v)) {
335  return -1;
336  }
337  costs += this->getEffort(*i, v, time + costs);
338  }
339  return costs;
340  }
341 
342 public:
344  void buildPathFrom(const EdgeInfo* rbegin, std::vector<const E*>& edges) {
345  std::vector<const E*> tmp;
346  while (rbegin != 0) {
347  tmp.push_back(rbegin->edge);
348  rbegin = rbegin->prev;
349  }
350  std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(edges));
351  }
352 
353 protected:
355  std::vector<EdgeInfo> myEdgeInfos;
356 
358  std::vector<EdgeInfo*> myFrontierList;
360  std::vector<EdgeInfo*> myFound;
361 
362  EdgeInfoComparator myComparator;
363 
366 
368  const LookupTable* const myLookupTable;
369 
371  double myMaxSpeed;
372 };
373 
374 
375 #endif
376 
377 /****************************************************************************/
378 
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:67
void close()
Closes the device and removes it from the dictionary.
AStarRouter(const std::vector< EdgeInfo > &edgeInfos, bool unbuildIsWarning, Operation operation, const LookupTable *const lookup=0)
Definition: AStarRouter.h:161
bool visited
The previous edge.
Definition: AStarRouter.h:124
std::vector< EdgeInfo > myEdgeInfos
The container of edge information.
Definition: AStarRouter.h:355
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
void buildPathFrom(const EdgeInfo *rbegin, std::vector< const E * > &edges)
Builds the path from marked edges.
Definition: AStarRouter.h:344
std::vector< EdgeInfo * > myFrontierList
A container for reusage of the min edge heap.
Definition: AStarRouter.h:358
EdgeInfoComparator myComparator
Definition: AStarRouter.h:362
#define UNREACHABLE
Definition: AStarRouter.h:56
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:60
MsgHandler *const myErrorMsgHandler
the handler for routing errors
Definition: AStarRouter.h:365
Computes the shortest path through a network using the A* algorithm.
Definition: AStarRouter.h:85
AStarRouter(const std::vector< E * > &edges, bool unbuildIsWarning, Operation operation, const LookupTable *const lookup=0)
Constructor.
Definition: AStarRouter.h:150
T MAX2(T a, T b)
Definition: StdDefs.h:74
double myMaxSpeed
maximum speed in the network
Definition: AStarRouter.h:371
double heuristicTime
Estimated time to reach the edge (traveltime + lower bound on remaining time)
Definition: AStarRouter.h:118
void init()
Definition: AStarRouter.h:179
double(* Operation)(const E *const, const V *const, double)
Definition: AStarRouter.h:91
double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime) const
Definition: AStarRouter.h:330
double getEffort(const E *const e, const V *const v, double t) const
virtual double lowerBound(const E *from, const E *to, double speed, double speedFactor, double fromEffort, double toEffort) const =0
provide a lower bound on the distance between from and to (excluding traveltime of both edges) ...
EdgeInfo * prev
The previous edge.
Definition: AStarRouter.h:121
bool operator()(const EdgeInfo *nod1, const EdgeInfo *nod2) const
Comparing method.
Definition: AStarRouter.h:141
#define max(a, b)
Definition: polyfonts.c:65
virtual SUMOAbstractRouter< E, V > * clone()
Definition: AStarRouter.h:175
FullLookupTable< E, V > FLT
Definition: AStarRouter.h:89
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
EdgeInfo(const E *e)
Constructor.
Definition: AStarRouter.h:103
virtual ~AStarRouter()
Destructor.
Definition: AStarRouter.h:173
bool myBulkMode
whether we are currently operating several route queries in a bulk
#define STEPS2TIME(x)
Definition: SUMOTime.h:65
T MIN2(T a, T b)
Definition: StdDefs.h:68
Operation myOperation
The object&#39;s operation to perform.
virtual bool consistent() const =0
whether the heuristic ist consistent (found nodes are always visited on the shortest path the first t...
LandmarkLookupTable< E, V > LMLT
Definition: AStarRouter.h:90
double traveltime
Effort to reach the edge.
Definition: AStarRouter.h:115
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 travel time.
Definition: AStarRouter.h:193
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:85
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:71
void endQuery(int visits)
long long int SUMOTime
Definition: TraCIDefs.h:52
#define NUMERICAL_EPS
Definition: config.h:152
const LookupTable *const myLookupTable
the lookup table for travel time heuristics
Definition: AStarRouter.h:368
Computes the shortest path through a network using the A* algorithm.
std::vector< EdgeInfo * > myFound
list of visited Edges (for resetting)
Definition: AStarRouter.h:360
AbstractLookupTable< E, V > LookupTable
Definition: AStarRouter.h:88
vehicles ignoring classes
const E * edge
The current edge.
Definition: AStarRouter.h:112