SUMO - Simulation of Urban MObility
DijkstraRouter.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 // Dijkstra shortest path algorithm using travel time or other values
18 /****************************************************************************/
19 #ifndef DijkstraRouter_h
20 #define DijkstraRouter_h
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <cassert>
29 #include <string>
30 #include <functional>
31 #include <vector>
32 #include <set>
33 #include <limits>
34 #include <algorithm>
35 #include <iterator>
36 #include <utils/common/ToString.h>
38 #include <utils/common/StdDefs.h>
39 #include "EffortCalculator.h"
40 #include "SUMOAbstractRouter.h"
41 
42 //#define DijkstraRouter_DEBUG_QUERY
43 //#define DijkstraRouter_DEBUG_QUERY_PERF
44 
45 // ===========================================================================
46 // class definitions
47 // ===========================================================================
62 template<class E, class V, class BASE>
63 class DijkstraRouter : public BASE {
64 public:
70  class EdgeInfo {
71  public:
73  EdgeInfo(const E* const e)
74  : edge(e), effort(std::numeric_limits<double>::max()), leaveTime(0.), prev(nullptr), via(nullptr), visited(false) {}
75 
77  const E* const edge;
78 
80  double effort;
81 
83  double leaveTime;
84 
86  const EdgeInfo* prev;
87 
89  const E* via;
90 
92  bool visited;
93 
94  inline void reset() {
95  effort = std::numeric_limits<double>::max();
96  via = nullptr;
97  visited = false;
98  }
99 
100  private:
102  EdgeInfo& operator=(const EdgeInfo& s) = delete;
103 
104  };
105 
111  public:
113  bool operator()(const EdgeInfo* nod1, const EdgeInfo* nod2) const {
114  if (nod1->effort == nod2->effort) {
115  return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
116  }
117  return nod1->effort > nod2->effort;
118  }
119  };
120 
121 
123  DijkstraRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename BASE::Operation effortOperation,
124  typename BASE::Operation ttOperation = nullptr, bool silent = false, EffortCalculator* calc = nullptr) :
125  BASE("DijkstraRouter", effortOperation, ttOperation),
126  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
127  mySilent(silent), myExternalEffort(calc) {
128  for (typename std::vector<E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
129  myEdgeInfos.push_back(EdgeInfo(*i));
130  }
131  }
132 
134  virtual ~DijkstraRouter() { }
135 
137  return new DijkstraRouter<E, V, BASE>(myEdgeInfos, myErrorMsgHandler == MsgHandler::getWarningInstance(), this->myOperation, this->myTTOperation, mySilent, myExternalEffort);
138  }
139 
140  void init() {
141  // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
142  for (typename std::vector<EdgeInfo*>::iterator i = myFrontierList.begin(); i != myFrontierList.end(); i++) {
143  (*i)->reset();
144  }
145  myFrontierList.clear();
146  for (typename std::vector<EdgeInfo*>::iterator i = myFound.begin(); i != myFound.end(); i++) {
147  (*i)->reset();
148  }
149  myFound.clear();
150  }
151 
152 
155  virtual bool compute(const E* from, const E* to, const V* const vehicle,
156  SUMOTime msTime, std::vector<const E*>& into) {
157  assert(from != 0 && (vehicle == 0 || to != 0));
158  // check whether from and to can be used
159  if (this->isProhibited(from, vehicle)) {
160  myErrorMsgHandler->inform("Vehicle '" + vehicle->getID() + "' is not allowed on source edge '" + from->getID() + "'.");
161  return false;
162  }
163  if (this->isProhibited(to, vehicle)) {
164  myErrorMsgHandler->inform("Vehicle '" + vehicle->getID() + "' is not allowed on destination edge '" + to->getID() + "'.");
165  return false;
166  }
167  this->startQuery();
168 #ifdef DijkstraRouter_DEBUG_QUERY
169  std::cout << "DEBUG: starting search for '" << vehicle->getID() << "' time: " << STEPS2TIME(msTime) << "\n";
170 #endif
171  const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
172  if (this->myBulkMode) {
173  const EdgeInfo& toInfo = myEdgeInfos[to->getNumericalID()];
174  if (toInfo.visited) {
175  buildPathFrom(&toInfo, into);
176  this->endQuery(1);
177  return true;
178  }
179  } else {
180  init();
181  // add begin node
182  EdgeInfo* const fromInfo = &(myEdgeInfos[from->getNumericalID()]);
183  fromInfo->effort = 0;
184  fromInfo->prev = 0;
185  fromInfo->leaveTime = STEPS2TIME(msTime);
186  myFrontierList.push_back(fromInfo);
187  }
188  // loop
189  int num_visited = 0;
190  while (!myFrontierList.empty()) {
191  num_visited += 1;
192  // use the node with the minimal length
193  EdgeInfo* const minimumInfo = myFrontierList.front();
194  const E* const minEdge = minimumInfo->edge;
195 #ifdef DijkstraRouter_DEBUG_QUERY
196  std::cout << "DEBUG: hit '" << minEdge->getID() << "' Eff: " << minimumInfo->effort << ", Leave: " << minimumInfo->leaveTime << " Q: ";
197  for (typename std::vector<EdgeInfo*>::iterator it = myFrontierList.begin(); it != myFrontierList.end(); it++) {
198  std::cout << (*it)->effort << "," << (*it)->edge->getID() << " ";
199  }
200  std::cout << "\n";
201 #endif
202  // check whether the destination node was already reached
203  if (minEdge == to) {
204  buildPathFrom(minimumInfo, into);
205  this->endQuery(num_visited);
206 #ifdef DijkstraRouter_DEBUG_QUERY_PERF
207  std::cout << "visited " + toString(num_visited) + " edges (final path length=" + toString(into.size()) + " edges=" + toString(into) + ")\n";
208 #endif
209  return true;
210  }
211  pop_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
212  myFrontierList.pop_back();
213  myFound.push_back(minimumInfo);
214  minimumInfo->visited = true;
215  const E* viaEdge = minimumInfo->via;
216  double effort = minimumInfo->effort;
217  double leaveTime = minimumInfo->leaveTime;
218  while (viaEdge != nullptr && viaEdge != minEdge) {
219  const double viaEffortDelta = this->getEffort(viaEdge, vehicle, leaveTime);
220  leaveTime += this->getTravelTime(viaEdge, vehicle, leaveTime, viaEffortDelta);
221  effort += viaEffortDelta;
222  viaEdge = viaEdge->getViaSuccessors().front().first;
223  }
224  const double effortDelta = this->getEffort(minEdge, vehicle, leaveTime);
225  leaveTime += this->getTravelTime(minEdge, vehicle, minimumInfo->leaveTime, effortDelta);
226  effort += effortDelta;
227  if (myExternalEffort != nullptr) {
228  myExternalEffort->update(minEdge->getNumericalID(), minimumInfo->prev->edge->getNumericalID(), minEdge->getLength());
229  }
230  assert(effort >= minimumInfo->effort);
231  assert(leaveTime >= minimumInfo->leaveTime);
232  // check all ways from the node with the minimal length
233  for (const std::pair<const E*, const E*>& follower : minEdge->getViaSuccessors(vClass)) {
234  EdgeInfo* const followerInfo = &(myEdgeInfos[follower.first->getNumericalID()]);
235  // check whether it can be used
236  if (this->isProhibited(follower.first, vehicle)) {
237  continue;
238  }
239  const double oldEffort = followerInfo->effort;
240  if (!followerInfo->visited && effort < oldEffort) {
241  followerInfo->effort = effort;
242  followerInfo->leaveTime = leaveTime;
243  followerInfo->prev = minimumInfo;
244  followerInfo->via = follower.second;
245  if (oldEffort == std::numeric_limits<double>::max()) {
246  myFrontierList.push_back(followerInfo);
247  push_heap(myFrontierList.begin(), myFrontierList.end(), myComparator);
248  } else {
249  push_heap(myFrontierList.begin(),
250  find(myFrontierList.begin(), myFrontierList.end(), followerInfo) + 1,
251  myComparator);
252  }
253  }
254  }
255  }
256  this->endQuery(num_visited);
257 #ifdef DijkstraRouter_DEBUG_QUERY_PERF
258  std::cout << "visited " + toString(num_visited) + " edges (unsuccessful path length: " + toString(into.size()) + ")\n";
259 #endif
260  if (to != 0 && !mySilent) {
261  myErrorMsgHandler->inform("No connection between edge '" + from->getID() + "' and edge '" + to->getID() + "' found.");
262  }
263  return false;
264  }
265 
266 
268  void buildPathFrom(const EdgeInfo* rbegin, std::vector<const E*>& edges) {
269  std::vector<const E*> tmp;
270  while (rbegin != 0) {
271  tmp.push_back(rbegin->edge);
272  rbegin = rbegin->prev;
273  }
274  std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(edges));
275  }
276 
277  const EdgeInfo& getEdgeInfo(int index) const {
278  return myEdgeInfos[index];
279  }
280 
281 private:
282  DijkstraRouter(const std::vector<EdgeInfo>& edgeInfos, bool unbuildIsWarning,
283  typename BASE::Operation effortOperation, typename BASE::Operation ttOperation, bool silent, EffortCalculator* calc) :
284  BASE("DijkstraRouter", effortOperation, ttOperation),
285  myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
286  mySilent(silent),
287  myExternalEffort(calc) {
288  for (const EdgeInfo& ei : edgeInfos) {
289  myEdgeInfos.push_back(EdgeInfo(ei.edge));
290  }
291  }
292 
293 private:
296 
298  bool mySilent;
299 
301 
303  std::vector<EdgeInfo> myEdgeInfos;
304 
306  std::vector<EdgeInfo*> myFrontierList;
308  std::vector<EdgeInfo*> myFound;
309 
311 };
312 
313 
314 #endif
315 
316 /****************************************************************************/
317 
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:67
long long int SUMOTime
Definition: SUMOTime.h:36
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.
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 effort at the given time The definition of...
double leaveTime
The time the vehicle leaves the edge.
MsgHandler *const myErrorMsgHandler
the handler for routing errors
std::vector< EdgeInfo * > myFound
list of visited Edges (for resetting)
std::vector< EdgeInfo > myEdgeInfos
The container of edge information.
EdgeInfo & operator=(const EdgeInfo &s)=delete
Invalidated assignment operator.
double effort
Effort to reach the edge.
virtual SUMOAbstractRouter< E, V > * clone()
const EdgeInfo * prev
The previous edge.
the effort calculator interface
EffortCalculator *const myExternalEffort
const EdgeInfo & getEdgeInfo(int index) const
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
virtual void update(const int edge, const int prev, const double length)=0
Computes the shortest path through a network using the Dijkstra algorithm.
#define STEPS2TIME(x)
Definition: SUMOTime.h:58
double getTravelTime(const ROEdge *const edge, const ROVehicle *const, double)
bool visited
The previous edge.
const E *const edge
The current edge.
EdgeInfoByEffortComparator myComparator
DijkstraRouter(const std::vector< E *> &edges, bool unbuildIsWarning, typename BASE::Operation effortOperation, typename BASE::Operation ttOperation=nullptr, bool silent=false, EffortCalculator *calc=nullptr)
Constructor.
std::vector< EdgeInfo * > myFrontierList
A container for reusage of the min edge heap.
virtual ~DijkstraRouter()
Destructor.
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:113
EdgeInfo(const E *const e)
Constructor.
const E * via
The optional internal edge corresponding to prev.
bool mySilent
whether to supress warning/error if no route was found
DijkstraRouter(const std::vector< EdgeInfo > &edgeInfos, bool unbuildIsWarning, typename BASE::Operation effortOperation, typename BASE::Operation ttOperation, bool silent, EffortCalculator *calc)
vehicles ignoring classes
bool operator()(const EdgeInfo *nod1, const EdgeInfo *nod2) const
Comparing method.