SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BulkStarRouter.h
Go to the documentation of this file.
1 /****************************************************************************/
9 // A* Algorithm using shortest-path-in-fast-graph-heuristic for bulk routing
10 // This router is made for routing multiple sources (at different times) to the same destination
11 // In the reverse graph (using maximum edge speed) a lower-bound shortest path tree from the target is built.
12 // These optimistic distances are then used as admissable heuristc
13 // when routing forward in the time-dependent graph from multiple sources.
14 // @note: this heuristic does not perform well if the actual vehicles are much slower than the maximum edge speeds
15 // @note: this heuristic also does not perform well if the actual vehicles have usage restrictions
16 // @todo: add option for setting maximum speed
17 /****************************************************************************/
18 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
19 // Copyright (C) 2001-2014 DLR (http://www.dlr.de/) and contributors
20 /****************************************************************************/
21 //
22 // This file is part of SUMO.
23 // SUMO is free software: you can redistribute it and/or modify
24 // it under the terms of the GNU General Public License as published by
25 // the Free Software Foundation, either version 3 of the License, or
26 // (at your option) any later version.
27 //
28 /****************************************************************************/
29 #ifndef BulkStarRouter_h
30 #define BulkStarRouter_h
31 
32 
33 // ===========================================================================
34 // included modules
35 // ===========================================================================
36 #ifdef _MSC_VER
37 #include <windows_config.h>
38 #else
39 #include <config.h>
40 #endif
41 
42 #include <string>
43 #include <functional>
44 #include <vector>
45 #include <set>
46 #include <limits>
47 #include <algorithm>
48 #include <iterator>
50 #include <utils/common/StdDefs.h>
51 #include <utils/common/ToString.h>
53 
54 
55 // ===========================================================================
56 // class definitions
57 // ===========================================================================
73 template<class E, class V, class PF>
74 class BulkStarRouter: public SUMOAbstractRouter<E, V>, public PF {
75 
76 public:
78  typedef SUMOReal(* Operation)(const E* const, const V* const, SUMOReal);
79  typedef SUMOReal(E::* MinTTOperation)(const V* const) const;
80 
81 
83  BulkStarRouter(size_t noE, bool unbuildIsWarning, Operation operation, MinTTOperation minTTOperation) :
84  SUMOAbstractRouter<E, V>(operation, "BulkStarRouter"),
85  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
86  myMinTTOperation(minTTOperation),
88  for (size_t i = 0; i < noE; i++) {
89  myEdgeInfos.push_back(EdgeInfo(i));
90  }
91  }
92 
94  virtual ~BulkStarRouter() {}
95 
96  virtual SUMOAbstractRouter<E, V>* clone() const {
98  }
99 
105  class EdgeInfo {
106  public:
108  EdgeInfo(size_t id) :
109  edge(E::dictionary(id)),
110  traveltime(std::numeric_limits<SUMOReal>::max()),
111  heuristicTime(std::numeric_limits<SUMOReal>::max()),
112  minRemaining(0),
113  prev(0),
114  visited(false) {}
115 
117  const E* edge;
118 
121 
124 
127 
130 
132  bool visited;
133 
134  inline void reset() {
135  // heuristicTime is set before adding to the frontier, thus no reset is needed
137  visited = false;
138  }
139  };
140 
146  public:
148  bool operator()(const EdgeInfo* nod1, const EdgeInfo* nod2) const {
149  if (nod1->heuristicTime == nod2->heuristicTime) {
150  return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
151  }
152  return nod1->heuristicTime > nod2->heuristicTime;
153  }
154  };
155 
156  inline SUMOReal getMinEffort(const E* const e, const V* const v) const {
157  return (e->*myMinTTOperation)(v);
158  }
159 
160 
167  void prepare(const E* destination, const V* fastestVehicle, bool skip) {
168  if (skip) {
170  return;
171  }
172  myPreparedDestination = destination;
173  for (typename std::vector<EdgeInfo>::iterator i = myEdgeInfos.begin(); i != myEdgeInfos.end(); i++) {
174  (*i).reset();
175  (*i).minRemaining = 0;
176  }
177  myFrontier.clear();
178  myFound.clear();
179  // add begin node
180  EdgeInfo* const fromInfo = &(myEdgeInfos[destination->getNumericalID()]);
181  fromInfo->traveltime = 0;
182  fromInfo->prev = 0;
183  myFrontier.push_back(fromInfo);
184  // loop
185  int num_visited = 0;
186  while (!myFrontier.empty()) {
187  num_visited += 1;
188  // use the node with the minimal length
189  EdgeInfo* const minimumInfo = myFrontier.front();
190  const E* const minEdge = minimumInfo->edge;
191  pop_heap(myFrontier.begin(), myFrontier.end(), myComparator);
192  myFrontier.pop_back();
193  myFound.push_back(minimumInfo);
194  minimumInfo->visited = true;
195  const SUMOReal traveltime = minimumInfo->traveltime + getMinEffort(minEdge, fastestVehicle);
196  // check all ways from the node with the minimal length
197  unsigned int i = 0;
198  const unsigned int length_size = minEdge->getNumPredecessors();
199  for (i = 0; i < length_size; i++) {
200  const E* const follower = minEdge->getPredecessor(i);
201  EdgeInfo* const followerInfo = &(myEdgeInfos[follower->getNumericalID()]);
202  const SUMOReal oldEffort = followerInfo->traveltime;
203  if (!followerInfo->visited && traveltime < oldEffort) {
204  followerInfo->traveltime = traveltime;
205  followerInfo->minRemaining = traveltime;
206  followerInfo->heuristicTime = traveltime; // plain dijkstra
207  followerInfo->prev = minimumInfo;
208  if (oldEffort == std::numeric_limits<SUMOReal>::max()) {
209  myFrontier.push_back(followerInfo);
210  push_heap(myFrontier.begin(), myFrontier.end(), myComparator);
211  } else {
212  push_heap(myFrontier.begin(),
213  find(myFrontier.begin(), myFrontier.end(), followerInfo) + 1,
214  myComparator);
215  }
216  }
217  }
218  }
219  // DEBUG
220  //std::cout << "visited " + toString(num_visited) + " edges during pre-computation\n";
221 
222  // DEBUG
223  //std::vector<const E*> debugPath;
224  //for (typename std::vector<EdgeInfo>::iterator it = myEdgeInfos.begin(); it != myEdgeInfos.end(); it++) {
225  // if (it->edge->getID() == "src") {
226  // buildPathFrom(&(*it), debugPath);
227  // std::cout << "shortest path in reverse graph:\n";
228  // for (typename std::vector<const E*>::iterator it_path = debugPath.begin(); it_path != debugPath.end(); it_path++) {
229  // std::cout << (*it_path)->getID() << " ";
230  // }
231  // std::cout << "\n";
232  // }
233  //}
234  }
235 
236 
237  void init() {
238  // all EdgeInfos touched in the previous query are either in myFrontier or myFound: clean those up
239  for (typename std::vector<EdgeInfo*>::iterator i = myFrontier.begin(); i != myFrontier.end(); i++) {
240  (*i)->reset();
241  }
242  myFrontier.clear();
243  for (typename std::vector<EdgeInfo*>::iterator i = myFound.begin(); i != myFound.end(); i++) {
244  (*i)->reset();
245  }
246  myFound.clear();
247  }
248 
249 
251  void compute(const E* from, const E* to, const V* const vehicle,
252  SUMOTime msTime, std::vector<const E*>& into) {
253  assert(from != 0 && to != 0);
254  this->startQuery();
255  init();
256  const Prepared prepared = (myPreparedDestination == 0 ?
257  NO : (myPreparedDestination == to ? YES_EXACT : YES));
258  const SUMOReal time = STEPS2TIME(msTime);
259  const EdgeInfo& toInfo = myEdgeInfos[to->getNumericalID()];
260  EdgeInfo* const fromInfo = &(myEdgeInfos[from->getNumericalID()]);
261  fromInfo->traveltime = 0;
262  fromInfo->prev = 0;
263  myFrontier.push_back(fromInfo);
264  // loop
265  int num_visited = 0;
266  while (!myFrontier.empty()) {
267  num_visited += 1;
268  // use the node with the minimal length
269  EdgeInfo* const minimumInfo = myFrontier.front();
270  const E* const minEdge = minimumInfo->edge;
271  pop_heap(myFrontier.begin(), myFrontier.end(), myComparator);
272  myFrontier.pop_back();
273  myFound.push_back(minimumInfo);
274  // check whether the destination node was already reached
275  if (minEdge == to) {
276  buildPathFrom(minimumInfo, into);
277  this->endQuery(num_visited);
278  // DEBUG
279  //std::cout << "visited " + toString(num_visited) + " edges (final path length: " + toString(into.size()) + ")\n";
280  return;
281  }
282  minimumInfo->visited = true;
283  const SUMOReal traveltime = minimumInfo->traveltime + this->getEffort(minEdge, vehicle, time + minimumInfo->traveltime);
284  // check all ways from the node with the minimal length
285  unsigned int i = 0;
286  const unsigned int length_size = minEdge->getNumSuccessors();
287  for (i = 0; i < length_size; i++) {
288  const E* const follower = minEdge->getSuccessor(i);
289  EdgeInfo* const followerInfo = &(myEdgeInfos[follower->getNumericalID()]);
290  // check whether it can be used
291  if (PF::operator()(follower, vehicle)) {
292  continue;
293  }
294  const SUMOReal oldEffort = followerInfo->traveltime;
295  if (!followerInfo->visited && traveltime < oldEffort) {
296  followerInfo->traveltime = traveltime;
297  // admissible A* heuristic:
298  SUMOReal heuristic_remaining = 0;
299  switch (prepared) {
300  case NO:
301  // straight line distance at maximum speed
302  heuristic_remaining = minEdge->getDistanceTo(to) / vehicle->getMaxSpeed();
303  break;
304  case YES_EXACT:
305  // shortest path for fastest vehicle in uncongested network
306  heuristic_remaining = minimumInfo->minRemaining;
307  break;
308  case YES:
309  // triangle inequality
310  heuristic_remaining = MAX2(
311  minimumInfo->minRemaining - toInfo.minRemaining,
312  minEdge->getDistanceTo(to) / vehicle->getMaxSpeed());
313  break;
314  }
315  followerInfo->heuristicTime = traveltime + heuristic_remaining;
316  followerInfo->prev = minimumInfo;
317  if (oldEffort == std::numeric_limits<SUMOReal>::max()) {
318  myFrontier.push_back(followerInfo);
319  push_heap(myFrontier.begin(), myFrontier.end(), myComparator);
320  } else {
321  push_heap(myFrontier.begin(),
322  find(myFrontier.begin(), myFrontier.end(), followerInfo) + 1,
323  myComparator);
324  }
325  }
326  }
327  }
328  this->endQuery(num_visited);
329  myErrorMsgHandler->inform("No connection between '" + from->getID() + "' and '" + to->getID() + "' found.");
330  }
331 
332 
333  SUMOReal recomputeCosts(const std::vector<const E*>& edges, const V* const v, SUMOTime msTime) const {
334  const SUMOReal time = STEPS2TIME(msTime);
335  SUMOReal costs = 0;
336  for (typename std::vector<const E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
337  if (PF::operator()(*i, v)) {
338  return -1;
339  }
340  costs += this->getEffort(*i, v, time + costs);
341  }
342  return costs;
343  }
344 
345 public:
347  void buildPathFrom(EdgeInfo* rbegin, std::vector<const E*>& edges) {
348  std::deque<const E*> tmp;
349  while (rbegin != 0) {
350  tmp.push_front((E*) rbegin->edge); // !!!
351  rbegin = rbegin->prev;
352  }
353  std::copy(tmp.begin(), tmp.end(), std::back_inserter(edges));
354  }
355 
356 private:
357  enum Prepared {
358  NO,
360  YES_EXACT // optimistic shortest paths are computed for the current destination
361  };
362 
364  std::vector<EdgeInfo> myEdgeInfos;
365 
367  std::vector<EdgeInfo*> myFrontier;
369  std::vector<EdgeInfo*> myFound;
370 
372 
375 
377 
379 };
380 
381 
382 #endif
383 
384 /****************************************************************************/
385 
MinTTOperation myMinTTOperation
std::vector< EdgeInfo * > myFound
list of visited Edges (for resetting)
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:71
const E * edge
The current edge.
void 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.
EdgeInfo * prev
The previous edge.
void prepare(const E *destination, const V *fastestVehicle, bool skip)
Builds a complete shorteset path tree in the (static) reverse graph from destination (Dijkstra until ...
T MAX2(T a, T b)
Definition: StdDefs.h:74
SUMOReal recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime) const
MsgHandler *const myErrorMsgHandler
the handler for routing errors
SUMOReal minRemaining
minimum time to destination
const E * myPreparedDestination
#define max(a, b)
Definition: polyfonts.c:65
bool visited
The previous edge.
#define STEPS2TIME(x)
Definition: SUMOTime.h:65
bool operator()(const EdgeInfo *nod1, const EdgeInfo *nod2) const
Comparing method.
Operation myOperation
The object&#39;s operation to perform.
virtual ~BulkStarRouter()
Destructor.
void buildPathFrom(EdgeInfo *rbegin, std::vector< const E * > &edges)
Builds the path from marked edges.
SUMOReal traveltime
Effort to reach the edge.
BulkStarRouter(size_t noE, bool unbuildIsWarning, Operation operation, MinTTOperation minTTOperation)
Constructor.
SUMOReal(* Operation)(const E *const, const V *const, SUMOReal)
Type of the function that is used to retrieve the edge effort.
std::vector< EdgeInfo * > myFrontier
A container for reusage of the min edge heap.
virtual SUMOAbstractRouter< E, V > * clone() const
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:89
EdgeInfo(size_t id)
Constructor.
std::vector< EdgeInfo > myEdgeInfos
The container of edge information.
int SUMOTime
Definition: SUMOTime.h:43
SUMOReal getMinEffort(const E *const e, const V *const v) const
#define SUMOReal
Definition: config.h:218
SUMOReal heuristicTime
Estimated time to reach the edge (traveltime + lower bound on remaining time)
void endQuery(int visits)
SUMOReal(E::* MinTTOperation)(const V *const) const
SUMOReal getEffort(const E *const e, const V *const v, SUMOReal t) const
EdgeInfoComparator myComparator