SUMO - Simulation of Urban MObility
AStarRouter.h
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2012-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 // A* Algorithm using euclidean distance heuristic.
18 // Based on DijkstraRouter. For routing by effort a novel heuristic would be needed.
19 /****************************************************************************/
20 #ifndef AStarRouter_h
21 #define AStarRouter_h
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #include <config.h>
28 
29 #include <cassert>
30 #include <string>
31 #include <functional>
32 #include <vector>
33 #include <set>
34 #include <limits>
35 #include <algorithm>
36 #include <iterator>
37 #include <map>
38 #include <iostream>
42 #include <utils/common/StdDefs.h>
43 #include <utils/common/ToString.h>
46 #include "AStarLookupTable.h"
47 #include "SUMOAbstractRouter.h"
48 
49 #define UNREACHABLE (std::numeric_limits<double>::max() / 1000.0)
50 
51 //#define ASTAR_DEBUG_QUERY
52 //#define ASTAR_DEBUG_QUERY_FOLLOWERS
53 //#define ASTAR_DEBUG_QUERY_PERF
54 //#define ASTAR_DEBUG_VISITED
55 //#define ASTAR_DEBUG_LOOKUPTABLE
56 //#define ASTAR_DEBUG_LOOKUPTABLE_FROM "disabled"
57 //#define ASTAR_DEBUG_UNREACHABLE
58 
59 // ===========================================================================
60 // class definitions
61 // ===========================================================================
76 template<class E, class V, class BASE>
77 class AStarRouter : public BASE {
78 public:
82 
88  class EdgeInfo {
89  public:
91  EdgeInfo(const E* e) :
92  edge(e),
93  traveltime(std::numeric_limits<double>::max()),
94  heuristicTime(std::numeric_limits<double>::max()),
95  prev(0),
96  visited(false) {
97  }
98 
100  const E* edge;
101 
103  double traveltime;
104 
107 
110 
112  bool visited;
113 
114  inline void reset() {
115  // heuristicTime is set before adding to the frontier, thus no reset is needed
116  traveltime = std::numeric_limits<double>::max();
117  visited = false;
118  }
119 
120  };
121 
127  public:
129  bool operator()(const EdgeInfo* nod1, const EdgeInfo* nod2) const {
130  if (nod1->heuristicTime == nod2->heuristicTime) {
131  return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
132  }
133  return nod1->heuristicTime > nod2->heuristicTime;
134  }
135  };
136 
138  AStarRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename BASE::Operation operation, const LookupTable* const lookup = 0) :
139  BASE("AStarRouter", operation),
140  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
141  myLookupTable(lookup),
143  for (typename std::vector<E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
144  myEdgeInfos.push_back(EdgeInfo(*i));
145  myMaxSpeed = MAX2(myMaxSpeed, (*i)->getSpeedLimit() * MAX2(1.0, (*i)->getLengthGeometryFactor()));
146  }
147  }
148 
149  AStarRouter(const std::vector<EdgeInfo>& edgeInfos, bool unbuildIsWarning, typename BASE::Operation operation, const LookupTable* const lookup = 0) :
150  BASE("AStarRouter", operation),
151  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
152  myLookupTable(lookup),
154  for (typename std::vector<EdgeInfo>::const_iterator i = edgeInfos.begin(); i != edgeInfos.end(); ++i) {
155  myEdgeInfos.push_back(EdgeInfo(i->edge));
156  myMaxSpeed = MAX2(myMaxSpeed, i->edge->getSpeedLimit() * i->edge->getLengthGeometryFactor());
157  }
158  }
159 
161  virtual ~AStarRouter() {}
162 
165  }
166 
167  void init() {
168  // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
169  for (typename std::vector<EdgeInfo*>::iterator i = myFrontierList.begin(); i != myFrontierList.end(); i++) {
170  (*i)->reset();
171  }
172  myFrontierList.clear();
173  for (typename std::vector<EdgeInfo*>::iterator i = myFound.begin(); i != myFound.end(); i++) {
174  (*i)->reset();
175  }
176  myFound.clear();
177  }
178 
179 
181  virtual bool compute(const E* from, const E* to, const V* const vehicle,
182  SUMOTime msTime, std::vector<const E*>& into) {
183  assert(from != 0 && to != 0);
184  // check whether from and to can be used
185  if (this->isProhibited(from, vehicle)) {
186  myErrorMsgHandler->inform("Vehicle '" + vehicle->getID() + "' is not allowed on source edge '" + from->getID() + "'.");
187  return false;
188  }
189  if (this->isProhibited(to, vehicle)) {
190  myErrorMsgHandler->inform("Vehicle '" + vehicle->getID() + "' is not allowed on destination edge '" + to->getID() + "'.");
191  return false;
192  }
193  this->startQuery();
194 #ifdef ASTAR_DEBUG_QUERY
195  std::cout << "DEBUG: starting search for '" << vehicle->getID() << "' speed: " << MIN2(vehicle->getMaxSpeed(), myMaxSpeed * vehicle->getChosenSpeedFactor()) << " time: " << STEPS2TIME(msTime) << "\n";
196 #endif
197  const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
198  const double time = STEPS2TIME(msTime);
199  if (this->myBulkMode) {
200  const EdgeInfo& toInfo = myEdgeInfos[to->getNumericalID()];
201  if (toInfo.visited) {
202  buildPathFrom(&toInfo, into);
203  this->endQuery(1);
204  return true;
205  }
206  } else {
207  init();
208  // add begin node
209  EdgeInfo* const fromInfo = &(myEdgeInfos[from->getNumericalID()]);
210  fromInfo->traveltime = 0;
211  fromInfo->prev = 0;
212  myFrontierList.push_back(fromInfo);
213  }
214  // loop
215  int num_visited = 0;
216  const bool mayRevisit = myLookupTable != 0 && !myLookupTable->consistent();
217  const double speed = vehicle == nullptr ? myMaxSpeed : MIN2(vehicle->getMaxSpeed(), myMaxSpeed * vehicle->getChosenSpeedFactor());
218  while (!myFrontierList.empty()) {
219  num_visited += 1;
220  // use the node with the minimal length
221  EdgeInfo* const minimumInfo = myFrontierList.front();
222  const E* const minEdge = minimumInfo->edge;
223  // check whether the destination node was already reached
224  if (minEdge == to) {
225  buildPathFrom(minimumInfo, into);
226  this->endQuery(num_visited);
227 #ifdef ASTAR_DEBUG_QUERY_PERF
228  std::cout << "visited " + toString(num_visited) + " edges (final path length=" + toString(into.size())
229  + " time=" + toString(recomputeCosts(into, vehicle, msTime))
230  + " edges=" + toString(into) + ")\n";
231 #endif
232 #ifdef ASTAR_DEBUG_VISITED
233  OutputDevice& dev = OutputDevice::getDevice(vehicle->getID() + "_" + time2string(msTime) + "_" + from->getID() + "_" + to->getID());
234  for (typename std::vector<EdgeInfo>::const_iterator i = myEdgeInfos.begin(); i != myEdgeInfos.end(); ++i) {
235  if (i->visited) {
236  dev << "edge:" << i->edge->getID() << "\n";
237  }
238  }
239  dev.close();
240 #endif
241  return true;
242  }
243  pop_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
244  myFrontierList.pop_back();
245  myFound.push_back(minimumInfo);
246  minimumInfo->visited = true;
247 #ifdef ASTAR_DEBUG_QUERY
248  std::cout << "DEBUG: hit=" << minEdge->getID()
249  << " TT=" << minimumInfo->traveltime
250  << " EF=" << this->getEffort(minEdge, vehicle, time + minimumInfo->traveltime)
251  << " HT=" << minimumInfo->heuristicTime
252  << " Q(TT,HT,Edge)=";
253  for (typename std::vector<EdgeInfo*>::iterator it = myFrontierList.begin(); it != myFrontierList.end(); it++) {
254  std::cout << (*it)->traveltime << "," << (*it)->heuristicTime << "," << (*it)->edge->getID() << " ";
255  }
256  std::cout << "\n";
257 #endif
258  const double traveltime = minimumInfo->traveltime + this->getEffort(minEdge, vehicle, time + minimumInfo->traveltime);
259  // admissible A* heuristic: straight line distance at maximum speed
260  const double heuristic_remaining = (myLookupTable == 0 ? minEdge->getDistanceTo(to) / speed :
261  myLookupTable->lowerBound(minEdge, to, speed, vehicle->getChosenSpeedFactor(), minEdge->getMinimumTravelTime(0), to->getMinimumTravelTime(0)));
262  if (heuristic_remaining == UNREACHABLE) {
263  continue;
264  }
265  // check all ways from the node with the minimal length
266  const std::vector<E*>& successors = minEdge->getSuccessors(vClass);
267  for (typename std::vector<E*>::const_iterator it = successors.begin(); it != successors.end(); ++it) {
268  const E* const follower = *it;
269  EdgeInfo* const followerInfo = &(myEdgeInfos[follower->getNumericalID()]);
270  // check whether it can be used
271  if (this->isProhibited(follower, vehicle)) {
272  continue;
273  }
274  const double oldEffort = followerInfo->traveltime;
275  if ((!followerInfo->visited || mayRevisit) && traveltime < oldEffort) {
276  followerInfo->traveltime = traveltime;
277  followerInfo->heuristicTime = traveltime + heuristic_remaining;
278  /* the code below results in fewer edges being looked up but is more costly due to the effort
279  calculations. Overall it resulted in a slowdown in the Berlin tests but could be made configurable someday.
280  followerInfo->heuristicTime = traveltime;
281  if (follower != to) {
282  if (myLookupTable == 0) {
283  // admissible A* heuristic: straight line distance at maximum speed
284  followerInfo->heuristicTime += this->getEffort(follower, vehicle, time + traveltime) + follower->getDistanceTo(to) / speed;
285  } else {
286  followerInfo->heuristicTime += this->getEffort(follower, vehicle, time + traveltime) + (*myLookupTable)[follower->getNumericalID()][to->getNumericalID()] / vehicle->getChosenSpeedFactor();
287  }
288  }*/
289 #ifdef ASTAR_DEBUG_QUERY_FOLLOWERS
290  std::cout << " follower=" << followerInfo->edge->getID() << " OEF=" << oldEffort << " TT=" << traveltime << " HR=" << heuristic_remaining << " HT=" << followerInfo->heuristicTime << "\n";
291 #endif
292  followerInfo->prev = minimumInfo;
293  if (oldEffort == std::numeric_limits<double>::max()) {
294  myFrontierList.push_back(followerInfo);
295  push_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
296  } else {
297  typename std::vector<EdgeInfo*>::iterator fi = find(myFrontierList.begin(), myFrontierList.end(), followerInfo);
298  if (fi == myFrontierList.end()) {
299  assert(mayRevisit);
300  myFrontierList.push_back(followerInfo);
301  push_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
302  } else {
303  push_heap(myFrontierList.begin(), fi + 1, myComparator);
304  }
305  }
306  }
307  }
308  }
309  this->endQuery(num_visited);
310 #ifdef ASTAR_DEBUG_QUERY_PERF
311  std::cout << "visited " + toString(num_visited) + " edges (unsuccesful path length: " + toString(into.size()) + ")\n";
312 #endif
313  myErrorMsgHandler->inform("No connection between edge '" + from->getID() + "' and edge '" + to->getID() + "' found.");
314  return false;
315  }
316 
317 public:
319  void buildPathFrom(const EdgeInfo* rbegin, std::vector<const E*>& edges) {
320  std::vector<const E*> tmp;
321  while (rbegin != 0) {
322  tmp.push_back(rbegin->edge);
323  rbegin = rbegin->prev;
324  }
325  std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(edges));
326  }
327 
328 protected:
330  std::vector<EdgeInfo> myEdgeInfos;
331 
333  std::vector<EdgeInfo*> myFrontierList;
335  std::vector<EdgeInfo*> myFound;
336 
337  EdgeInfoComparator myComparator;
338 
341 
343  const LookupTable* const myLookupTable;
344 
346  double myMaxSpeed;
347 };
348 
349 
350 #endif
351 
352 /****************************************************************************/
353 
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< E *> &edges, bool unbuildIsWarning, typename BASE::Operation operation, const LookupTable *const lookup=0)
Constructor.
Definition: AStarRouter.h:138
const E * edge
The current edge.
Definition: AStarRouter.h:100
long long int SUMOTime
Definition: SUMOTime.h:36
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
FullLookupTable< E, V > FLT
Definition: AStarRouter.h:80
std::vector< EdgeInfo > myEdgeInfos
The container of edge information.
Definition: AStarRouter.h:330
#define UNREACHABLE
Definition: AStarRouter.h:49
double traveltime
Effort to reach the edge.
Definition: AStarRouter.h:103
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:67
Computes the shortest path through a network using the A* algorithm.
Definition: AStarRouter.h:77
std::vector< EdgeInfo * > myFrontierList
A container for reusage of the min edge heap.
Definition: AStarRouter.h:333
T MAX2(T a, T b)
Definition: StdDefs.h:68
const LookupTable *const myLookupTable
the lookup table for travel time heuristics
Definition: AStarRouter.h:343
void buildPathFrom(const EdgeInfo *rbegin, std::vector< const E *> &edges)
Builds the path from marked edges.
Definition: AStarRouter.h:319
bool operator()(const EdgeInfo *nod1, const EdgeInfo *nod2) const
Comparing method.
Definition: AStarRouter.h:129
virtual ~AStarRouter()
Destructor.
Definition: AStarRouter.h:161
MsgHandler *const myErrorMsgHandler
the handler for routing errors
Definition: AStarRouter.h:340
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
#define STEPS2TIME(x)
Definition: SUMOTime.h:58
T MIN2(T a, T b)
Definition: StdDefs.h:62
double myMaxSpeed
maximum speed in the network
Definition: AStarRouter.h:346
EdgeInfo * prev
The previous edge.
Definition: AStarRouter.h:109
virtual bool consistent() const =0
whether the heuristic ist consistent (found nodes are always visited on the shortest path the first t...
virtual SUMOAbstractRouter< E, V > * clone()
Definition: AStarRouter.h:163
double heuristicTime
Estimated time to reach the edge (traveltime + lower bound on remaining time)
Definition: AStarRouter.h:106
AStarRouter(const std::vector< EdgeInfo > &edgeInfos, bool unbuildIsWarning, typename BASE::Operation operation, const LookupTable *const lookup=0)
Definition: AStarRouter.h:149
EdgeInfo(const E *e)
Constructor.
Definition: AStarRouter.h:91
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:181
AbstractLookupTable< E, V > LookupTable
Definition: AStarRouter.h:79
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) ...
std::vector< EdgeInfo * > myFound
list of visited Edges (for resetting)
Definition: AStarRouter.h:335
EdgeInfoComparator myComparator
Definition: AStarRouter.h:337
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:113
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
#define NUMERICAL_EPS
Definition: config.h:148
Computes the shortest path through a network using the A* algorithm.
LandmarkLookupTable< E, V > LMLT
Definition: AStarRouter.h:81
vehicles ignoring classes
void init()
Definition: AStarRouter.h:167
bool visited
The previous edge.
Definition: AStarRouter.h:112