SUMO - Simulation of Urban MObility
AStarLookupTable.h
Go to the documentation of this file.
1 /****************************************************************************/
7 // Precomputed landmark distances to speed up the A* routing algorithm
8 /****************************************************************************/
9 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
10 // Copyright (C) 2012-2017 DLR (http://www.dlr.de/) and contributors
11 /****************************************************************************/
12 //
13 // This file is part of SUMO.
14 // SUMO is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 /****************************************************************************/
20 #ifndef AStarLookupTable_h
21 #define AStarLookupTable_h
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <iostream>
34 #include <fstream>
35 
36 #ifdef HAVE_FOX
38 #endif
39 
40 #define UNREACHABLE (std::numeric_limits<double>::max() / 1000.0)
41 
42 //#define ASTAR_DEBUG_LOOKUPTABLE
43 //#define ASTAR_DEBUG_LOOKUPTABLE_FROM "disabled"
44 //#define ASTAR_DEBUG_UNREACHABLE
45 
46 // ===========================================================================
47 // class definitions
48 // ===========================================================================
65 template<class E, class V>
67 public:
69  virtual double lowerBound(const E* from, const E* to, double speed, double speedFactor, double fromEffort, double toEffort) const = 0;
70 
72  virtual bool consistent() const = 0;
73 };
74 
75 
76 template<class E, class V>
77 class FullLookupTable : public AbstractLookupTable<E, V> {
78 public:
79  FullLookupTable(const std::string& filename, const int size) :
80  myTable(size) {
81  BinaryInputDevice dev(filename);
82  for (int i = 0; i < size; i++) {
83  for (int j = 0; j < size; j++) {
84  double val;
85  dev >> val;
86  myTable[i].push_back(val);
87  }
88  }
89  }
90 
91  double lowerBound(const E* from, const E* to, double /*speed*/, double speedFactor, double /*fromEffort*/, double /*toEffort*/) const {
92  return myTable[from->getNumericalID()][to->getNumericalID()] / speedFactor;
93  }
94 
95  bool consistent() const {
96  return true;
97  }
98 
99 private:
100  std::vector<std::vector<double> > myTable;
101 };
102 
103 
104 template<class E, class V>
106 public:
107  LandmarkLookupTable(const std::string& filename, const std::vector<E*>& edges, SUMOAbstractRouter<E, V>* router, const V* defaultVehicle, const std::string& outfile, const int maxNumThreads) {
108  myFirstNonInternal = -1;
109  std::map<std::string, int> numericID;
110  for (E* e : edges) {
111  if (!e->isInternal()) {
112  if (myFirstNonInternal == -1) {
113  myFirstNonInternal = e->getNumericalID();
114  }
115  numericID[e->getID()] = e->getNumericalID() - myFirstNonInternal;
116  }
117  }
118  std::ifstream strm(filename.c_str());
119  if (!strm.good()) {
120  throw ProcessError("Could not load landmark-lookup-table from '" + filename + "'.");
121  }
122  std::ofstream* ostrm = 0;
123  if (!outfile.empty()) {
124  ostrm = new std::ofstream(outfile.c_str());
125  if (!ostrm->good()) {
126  throw ProcessError("Could not open file '" + outfile + "' for writing.");
127  }
128  }
129  std::string line;
130  int numLandMarks = 0;
131  while (std::getline(strm, line)) {
132  if (line == "") {
133  break;
134  }
135  //std::cout << "'" << line << "'" << "\n";
136  StringTokenizer st(line);
137  if (st.size() == 1) {
138  const std::string lm = st.get(0);
139  myLandmarks[lm] = numLandMarks++;
140  myFromLandmarkDists.push_back(std::vector<double>(0));
141  myToLandmarkDists.push_back(std::vector<double>(0));
142  if (ostrm != 0) {
143  (*ostrm) << lm << "\n";
144  }
145  } else {
146  assert(st.size() == 4);
147  const std::string lm = st.get(0);
148  const std::string edge = st.get(1);
149  if (numericID[edge] != (int)myFromLandmarkDists[myLandmarks[lm]].size()) {
150  WRITE_WARNING("Unknown or unordered edge '" + edge + "' in landmark file.");
151  }
152  const double distFrom = TplConvert::_2double(st.get(2).c_str());
153  const double distTo = TplConvert::_2double(st.get(3).c_str());
154  myFromLandmarkDists[myLandmarks[lm]].push_back(distFrom);
155  myToLandmarkDists[myLandmarks[lm]].push_back(distTo);
156  }
157  }
158  if (myLandmarks.empty()) {
159  WRITE_WARNING("No landmarks in '" + filename + "', falling back to standard A*.");
160  return;
161  }
162 #ifdef HAVE_FOX
163  FXWorkerThread::Pool threadPool;
164 #endif
165  for (int i = 0; i < (int)myLandmarks.size(); ++i) {
166  if ((int)myFromLandmarkDists[i].size() != (int)edges.size() - myFirstNonInternal) {
167  const std::string landmarkID = getLandmark(i);
168  const E* landmark = 0;
169  // retrieve landmark edge
170  for (typename std::vector<E*>::const_iterator it_e = edges.begin(); it_e != edges.end(); ++it_e) {
171  if ((*it_e)->getID() == landmarkID) {
172  landmark = *it_e;
173  }
174  }
175  if (landmark == 0) {
176  WRITE_WARNING("Landmark '" + landmarkID + "' does not exist in the network.");
177  continue;
178  }
179  if (router != 0) {
180  const std::string missing = filename + ".missing";
181  WRITE_WARNING("Not all network edges were found in the lookup table '" + filename + "' for landmark '" + landmarkID + "'. Saving missing values to '" + missing + "'.");
182  if (ostrm == 0) {
183  ostrm = new std::ofstream(missing.c_str());
184  if (!ostrm->good()) {
185  throw ProcessError("Could not open file '" + missing + "' for writing.");
186  }
187  }
188  } else {
189  throw ProcessError("Not all network edges were found in the lookup table '" + filename + "' for landmark '" + landmarkID + "'.");
190  }
191  std::vector<const E*> routeLM(1, landmark);
192  const double lmCost = router->recomputeCosts(routeLM, defaultVehicle, 0);
193  std::vector<const E*> route;
194 #ifdef HAVE_FOX
195  if (maxNumThreads > 0) {
196  if (threadPool.size() == 0) {
197  // The CHRouter needs initialization
198  // before it gets cloned, so we do a dummy routing which is not in parallel
199  router->compute(landmark, landmark, defaultVehicle, 0, route);
200  route.clear();
201  while ((int)threadPool.size() < maxNumThreads) {
202  new WorkerThread(threadPool, router->clone(), defaultVehicle);
203  }
204  }
205  std::vector<RoutingTask*> currentTasks;
206  for (int j = (int)myFromLandmarkDists[i].size() + myFirstNonInternal; j < (int)edges.size(); ++j) {
207  const E* edge = edges[j];
208  if (landmark != edge) {
209  std::vector<const E*> routeE(1, edge);
210  const double sourceDestCost = lmCost + router->recomputeCosts(routeE, defaultVehicle, 0);
211  // compute from-distance (skip taz-sources and other unreachable edges)
212  if (edge->getPredecessors().size() > 0 && landmark->getSuccessors().size() > 0) {
213  currentTasks.push_back(new RoutingTask(landmark, edge, sourceDestCost));
214  threadPool.add(currentTasks.back());
215  }
216  // compute to-distance (skip unreachable landmarks)
217  if (landmark->getPredecessors().size() > 0 && edge->getSuccessors().size() > 0) {
218  currentTasks.push_back(new RoutingTask(edge, landmark, sourceDestCost));
219  threadPool.add(currentTasks.back());
220  }
221  }
222  }
223  threadPool.waitAll(false);
224  int taskIndex = 0;
225  for (int j = (int)myFromLandmarkDists[i].size() + myFirstNonInternal; j < (int)edges.size(); ++j) {
226  const E* edge = edges[j];
227  double distFrom = -1;
228  double distTo = -1;
229  if (landmark == edge) {
230  distFrom = 0;
231  distTo = 0;
232  } else {
233  if (edge->getPredecessors().size() > 0 && landmark->getSuccessors().size() > 0) {
234  distFrom = currentTasks[taskIndex]->getCost();
235  delete currentTasks[taskIndex++];
236  }
237  if (landmark->getPredecessors().size() > 0 && edge->getSuccessors().size() > 0) {
238  distTo = currentTasks[taskIndex]->getCost();
239  delete currentTasks[taskIndex++];
240  }
241  }
242  myFromLandmarkDists[i].push_back(distFrom);
243  myToLandmarkDists[i].push_back(distTo);
244  (*ostrm) << landmarkID << " " << edge->getID() << " " << distFrom << " " << distTo << "\n";
245  }
246  currentTasks.clear();
247  continue;
248  }
249 #endif
250  for (int j = (int)myFromLandmarkDists[i].size() + myFirstNonInternal; j < (int)edges.size(); ++j) {
251  const E* edge = edges[j];
252  double distFrom = -1;
253  double distTo = -1;
254  if (landmark == edge) {
255  distFrom = 0;
256  distTo = 0;
257  } else {
258  std::vector<const E*> routeE(1, edge);
259  const double sourceDestCost = lmCost + router->recomputeCosts(routeE, defaultVehicle, 0);
260  // compute from-distance (skip taz-sources and other unreachable edges)
261  if (edge->getPredecessors().size() > 0 && landmark->getSuccessors().size() > 0) {
262  if (router->compute(landmark, edge, defaultVehicle, 0, route)) {
263  distFrom = MAX2(0.0, router->recomputeCosts(route, defaultVehicle, 0) - sourceDestCost);
264  route.clear();
265  }
266  }
267  // compute to-distance (skip unreachable landmarks)
268  if (landmark->getPredecessors().size() > 0 && edge->getSuccessors().size() > 0) {
269  if (router->compute(edge, landmark, defaultVehicle, 0, route)) {
270  distTo = MAX2(0.0, router->recomputeCosts(route, defaultVehicle, 0) - sourceDestCost);
271  route.clear();
272  }
273  }
274  }
275  myFromLandmarkDists[i].push_back(distFrom);
276  myToLandmarkDists[i].push_back(distTo);
277  (*ostrm) << landmarkID << " " << edge->getID() << " " << distFrom << " " << distTo << "\n";
278  }
279  }
280  }
281  delete ostrm;
282  }
283 
284  double lowerBound(const E* from, const E* to, double speed, double speedFactor, double fromEffort, double toEffort) const {
285  double result = from->getDistanceTo(to) / speed;
286 #ifdef ASTAR_DEBUG_LOOKUPTABLE
287  if (from->getID() == ASTAR_DEBUG_LOOKUPTABLE_FROM) {
288  std::cout << " lowerBound to=" << to->getID() << " result1=" << result << "\n";
289  }
290 #endif
291  for (int i = 0; i < (int)myLandmarks.size(); ++i) {
292  // a cost of -1 is used to encode unreachability.
293  const double fl = myToLandmarkDists[i][from->getNumericalID() - myFirstNonInternal];
294  const double tl = myToLandmarkDists[i][to->getNumericalID() - myFirstNonInternal];
295  if (fl >= 0 && tl >= 0) {
296  const double bound = (fl - tl - toEffort) / speedFactor;
297 #ifdef ASTAR_DEBUG_LOOKUPTABLE
298  if (from->getID() == ASTAR_DEBUG_LOOKUPTABLE_FROM && result < bound) {
299  std::cout << " landmarkTo=" << getLandmark(i) << " result2=" << bound
300  << " fl=" << fl << " tl=" << tl << "\n";
301  }
302 #endif
303  result = MAX2(result, bound);
304  }
305  const double lt = myFromLandmarkDists[i][to->getNumericalID() - myFirstNonInternal];
306  const double lf = myFromLandmarkDists[i][from->getNumericalID() - myFirstNonInternal];
307  if (lt >= 0 && lf >= 0) {
308  const double bound = (lt - lf - fromEffort) / speedFactor;
309 #ifdef ASTAR_DEBUG_LOOKUPTABLE
310  if (from->getID() == ASTAR_DEBUG_LOOKUPTABLE_FROM && result < bound) {
311  std::cout << " landmarkFrom=" << getLandmark(i) << " result3=" << bound
312  << " lt=" << lt << " lf=" << lf << "\n";
313  }
314 #endif
315  result = MAX2(result, bound);
316  }
317  if ((tl >= 0 && fl < 0)
318  || (lf >= 0 && lt < 0)) {
319  // target unreachable.
320 #ifdef ASTAR_DEBUG_UNREACHABLE
321  std::cout << " unreachable: from=" << from->getID() << " to=" << to->getID() << " landmark=" << getLandmark(i) << " "
322  << ((tl >= 0 && fl < 0) ? " (toLandmark)" : " (fromLandmark)")
323  << " fl=" << fl << " tl=" << tl << " lt=" << lt << " lf=" << lf
324  << "\n";
325 #endif
326  return UNREACHABLE;
327  }
328  }
329  return result;
330  }
331 
332  bool consistent() const {
333  return false;
334  }
335 
336 private:
337  std::map<std::string, int> myLandmarks;
338  std::vector<std::vector<double> > myFromLandmarkDists;
339  std::vector<std::vector<double> > myToLandmarkDists;
341 
342 #ifdef HAVE_FOX
343 private:
344  class WorkerThread : public FXWorkerThread {
345  public:
346  WorkerThread(FXWorkerThread::Pool& pool,
347  SUMOAbstractRouter<E, V>* router, const V* vehicle)
348  : FXWorkerThread(pool), myRouter(router), myVehicle(vehicle) {}
349  virtual ~WorkerThread() {
350  delete myRouter;
351  }
352  double compute(const E* src, const E* dest, const double costOff) {
353  double result = -1.;
354  if (myRouter->compute(src, dest, myVehicle, 0, myRoute)) {
355  result = MAX2(0.0, myRouter->recomputeCosts(myRoute, myVehicle, 0) + costOff);
356  myRoute.clear();
357  }
358  return result;
359  }
360  private:
361  SUMOAbstractRouter<E, V>* myRouter;
362  const V* myVehicle;
363  std::vector<const E*> myRoute;
364  };
365 
366  class RoutingTask : public FXWorkerThread::Task {
367  public:
368  RoutingTask(const E* src, const E* dest, const double costOff)
369  : mySrc(src), myDest(dest), myCost(-costOff) {}
370  void run(FXWorkerThread* context) {
371  myCost = ((WorkerThread*)context)->compute(mySrc, myDest, myCost);
372  }
373  double getCost() {
374  return myCost;
375  }
376  private:
377  const E* const mySrc;
378  const E* const myDest;
379  double myCost;
380  private:
382  RoutingTask& operator=(const RoutingTask&);
383  };
384 
385 
386 private:
388 #endif
389 
390  std::string getLandmark(int i) const {
391  for (std::map<std::string, int>::const_iterator it = myLandmarks.begin(); it != myLandmarks.end(); ++it) {
392  if (it->second == i) {
393  return it->first;
394  }
395  }
396  return "";
397  }
398 };
399 
400 
401 
402 
403 #endif
404 
405 /****************************************************************************/
406 
void waitAll(const bool deleteFinished=true)
waits for all tasks to be finished
bool consistent() const
whether the heuristic ist consistent (found nodes are always visited on the shortest path the first t...
bool consistent() const
whether the heuristic ist consistent (found nodes are always visited on the shortest path the first t...
T MAX2(T a, T b)
Definition: StdDefs.h:74
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
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) ...
LandmarkLookupTable(const std::string &filename, const std::vector< E * > &edges, SUMOAbstractRouter< E, V > *router, const V *defaultVehicle, const std::string &outfile, const int maxNumThreads)
#define UNREACHABLE
std::vector< std::vector< double > > myToLandmarkDists
FullLookupTable(const std::string &filename, const int size)
std::map< std::string, int > myLandmarks
virtual bool consistent() const =0
whether the heuristic ist consistent (found nodes are always visited on the shortest path the first t...
void add(Task *const t, int index=-1)
Gives a number to the given task and assigns it to the worker with the given index. If the index is negative, assign to the next (round robin) one.
std::string getLandmark(int i) const
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime) const =0
int size() const
Returns the number of threads in the pool.
double lowerBound(const E *from, const E *to, double, double speedFactor, double, double) const
provide a lower bound on the distance between from and to (excluding traveltime of both edges) ...
A pool of worker threads which distributes the tasks and collects the results.
std::vector< std::vector< double > > myTable
std::string get(int pos) const
static double _2double(const E *const data)
converts a char-type array into the double value described by it
Definition: TplConvert.h:312
double lowerBound(const E *from, const E *to, double speed, double speedFactor, double fromEffort, double toEffort) const
provide a lower bound on the distance between from and to (excluding traveltime of both edges) ...
Abstract superclass of a task to be run with an index to keep track of pending tasks.
A thread repeatingly calculating incoming tasks.
Computes the shortest path through a network using the A* algorithm.
virtual SUMOAbstractRouter * clone()=0
Encapsulates binary reading operations on a file.
std::vector< std::vector< double > > myFromLandmarkDists