Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
CHRouter.h
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
20// Shortest Path search using a Contraction Hierarchy
21/****************************************************************************/
22#pragma once
23#include <config.h>
24
25#include <string>
26#include <functional>
27#include <vector>
28#include <set>
29#include <limits>
30#include <algorithm>
31#include <iterator>
32#include <deque>
37#include "CHBuilder.h"
38
39//#define CHRouter_DEBUG_QUERY
40//#define CHRouter_DEBUG_QUERY_PERF
41
42// ===========================================================================
43// class definitions
44// ===========================================================================
58template<class E, class V>
59class CHRouter: public SUMOAbstractRouter<E, V> {
60
61public:
63 typedef std::pair<const typename SUMOAbstractRouter<E, V>::EdgeInfo*, const typename SUMOAbstractRouter<E, V>::EdgeInfo*> Meeting;
64
70 public:
72 Unidirectional(const std::vector<E*>& edges, bool forward):
73 myAmForward(forward),
74 myVehicle(0) {
75 for (const E* const e : edges) {
77 }
78 }
79
80 inline bool found(const E* const edge) const {
81 return myFound.count(edge) > 0;
82 }
83
84 inline typename SUMOAbstractRouter<E, V>::EdgeInfo* getEdgeInfo(const E* const edge) {
85 return &(myEdgeInfos[edge->getNumericalID()]);
86 }
87
88 inline const typename SUMOAbstractRouter<E, V>::EdgeInfo* getEdgeInfo(const E* const edge) const {
89 return &(myEdgeInfos[edge->getNumericalID()]);
90 }
91
97 public:
99 bool operator()(const typename SUMOAbstractRouter<E, V>::EdgeInfo* nod1, const typename SUMOAbstractRouter<E, V>::EdgeInfo* nod2) const {
100 if (nod1->effort == nod2->effort) {
101 return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
102 }
103 return nod1->effort > nod2->effort;
104 }
105 };
106
107
108 void init(const E* const start, const V* const vehicle) {
109 assert(vehicle != 0);
110 // all EdgeInfos touched in the previous query are either in myFrontier or myFound: clean those up
111 for (auto ei : myFrontier) {
112 ei->reset();
113 }
114 myFrontier.clear();
115 for (auto edge : myFound) {
116 getEdgeInfo(edge)->reset();
117 }
118 myFound.clear();
119 myVehicle = vehicle;
120 auto startInfo = getEdgeInfo(start);
121 startInfo->effort = 0.;
122 startInfo->prev = nullptr;
123 myFrontier.push_back(startInfo);
124 }
125
126
127 typedef std::vector<typename CHBuilder<E, V>::Connection> ConnectionVector;
132 bool step(const std::vector<ConnectionVector>& uplinks, const Unidirectional& otherSearch, double& minTTSeen, Meeting& meeting) {
133 // pop the node with the minimal length
134 auto* const minimumInfo = myFrontier.front();
135 std::pop_heap(myFrontier.begin(), myFrontier.end(), myComparator);
136 myFrontier.pop_back();
137 // check for a meeting with the other search
138 const E* const minEdge = minimumInfo->edge;
139#ifdef CHRouter_DEBUG_QUERY
140 std::cout << "DEBUG: " << (myAmForward ? "Forward" : "Backward") << " hit '" << minEdge->getID() << "' Q: ";
141 for (typename std::vector<EdgeInfo*>::iterator it = myFrontier.begin(); it != myFrontier.end(); it++) {
142 std::cout << (*it)->traveltime << "," << (*it)->edge->getID() << " ";
143 }
144 std::cout << "\n";
145#endif
146 if (otherSearch.found(minEdge)) {
147 const auto* const otherInfo = otherSearch.getEdgeInfo(minEdge);
148 const double ttSeen = minimumInfo->effort + otherInfo->effort;
149#ifdef CHRouter_DEBUG_QUERY
150 std::cout << "DEBUG: " << (myAmForward ? "Forward" : "Backward") << "-Search hit other search at '" << minEdge->getID() << "', tt: " << ttSeen << " \n";
151#endif
152 if (ttSeen < minTTSeen) {
153 minTTSeen = ttSeen;
154 if (myAmForward) {
155 meeting.first = minimumInfo;
156 meeting.second = otherInfo;
157 } else {
158 meeting.first = otherInfo;
159 meeting.second = minimumInfo;
160 }
161 }
162 }
163 // prepare next steps
164 minimumInfo->visited = true;
165 // XXX we only need to keep found elements if they have a higher rank than the lowest rank in the other search queue
166 myFound.insert(minimumInfo->edge);
167 for (const auto& uplink : uplinks[minEdge->getNumericalID()]) {
168 const auto upwardInfo = &myEdgeInfos[uplink.target];
169 const double effort = minimumInfo->effort + uplink.cost;
170 const SUMOVehicleClass svc = myVehicle->getVClass();
171 // check whether it can be used
172 if ((uplink.permissions & svc) != svc) {
173 continue;
174 }
175 const double oldEffort = upwardInfo->effort;
176 if (!upwardInfo->visited && effort < oldEffort) {
177 upwardInfo->effort = effort;
178 upwardInfo->prev = minimumInfo;
179 if (oldEffort == std::numeric_limits<double>::max()) {
180 myFrontier.push_back(upwardInfo);
181 std::push_heap(myFrontier.begin(), myFrontier.end(), myComparator);
182 } else {
183 std::push_heap(myFrontier.begin(),
184 std::find(myFrontier.begin(), myFrontier.end(), upwardInfo) + 1,
186 }
187 }
188 }
189 // @note: this effectively does a full dijkstra search.
190 // the effort compared to the naive stopping criterion is thus
191 // quadrupled. We could implement a better stopping criterion (Holte)
192 // However since the search shall take place in a contracted graph
193 // it probably does not matter
194 return !myFrontier.empty() && myFrontier.front()->effort < minTTSeen;
195 }
196
197 private:
201 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontier;
203 std::set<const E*> myFound;
205 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
206
208
209 const V* myVehicle;
210
211 };
212
218 CHRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename SUMOAbstractRouter<E, V>::Operation operation,
219 const SUMOVehicleClass svc,
220 SUMOTime weightPeriod,
221 const bool havePermissions, const bool haveRestrictions):
222 SUMOAbstractRouter<E, V>("CHRouter", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions),
223 myEdges(edges),
224 myForwardSearch(edges, true),
225 myBackwardSearch(edges, false),
226 myHierarchyBuilder(new CHBuilder<E, V>(edges, unbuildIsWarning, svc, havePermissions)),
227 myHierarchy(nullptr),
228 myWeightPeriod(weightPeriod),
229 myValidUntil(0),
230 mySVC(svc) {
231 }
232
235 CHRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename SUMOAbstractRouter<E, V>::Operation operation,
236 const SUMOVehicleClass svc,
237 typename CHBuilder<E, V>::Hierarchy* hierarchy,
238 const bool havePermissions, const bool haveRestrictions) :
239 SUMOAbstractRouter<E, V>("CHRouterClone", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions),
240 myEdges(edges),
241 myForwardSearch(edges, true),
242 myBackwardSearch(edges, false),
243 myHierarchyBuilder(nullptr),
244 myHierarchy(hierarchy),
247 mySVC(svc) {
248 }
249
251 virtual ~CHRouter() {
252 if (myHierarchyBuilder != nullptr) {
253 delete myHierarchy;
254 delete myHierarchyBuilder;
255 }
256 }
257
258
260 if (myWeightPeriod == SUMOTime_MAX && myHierarchy != nullptr) {
261 // we only need one hierarchy
264 }
267 }
268
269
270 virtual void prohibit(const std::map<const E*, RouterProhibition>& toProhibit) {
271 if (toProhibit.size() > 0) {
272 WRITE_WARNINGF(TL("Routing algorithm CH does not support dynamic closing of edges%"), "");
273 }
274 }
275
276 virtual bool supportsProhibitions() const {
277 WRITE_WARNINGF(TL("Routing algorithm CH does not support dynamic closing of edges and lanes%"), "");
278 return false;
279 }
280
282 virtual void reset(const V* const vehicle) {
283 if (myValidUntil == 0) {
285 }
286 typename CHBuilder<E, V>::Hierarchy* newHierarchy = myHierarchyBuilder->buildContractionHierarchy(myValidUntil - myWeightPeriod, vehicle, this);
287 if (myHierarchy == nullptr) {
288 myHierarchy = newHierarchy;
289 } else {
290 *myHierarchy = *newHierarchy;
291 delete newHierarchy;
292 }
293 }
294
299 virtual bool compute(const E* from, const E* to, const V* const vehicle,
300 SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
301 assert(from != nullptr && to != nullptr);
302 // assert(myHierarchyBuilder.mySPTree->validatePermissions() || vehicle->getVClass() == mySVC || mySVC == SVC_IGNORING);
303 // do we need to rebuild the hierarchy?
304 if (msTime >= myValidUntil) {
305 assert(myHierarchyBuilder != nullptr); // only time independent clones do not have a builder
306 while (msTime >= myValidUntil) {
308 }
309 this->reset(vehicle);
310 }
311 // ready for routing
312 this->startQuery();
313 myForwardSearch.init(from, vehicle);
314 myBackwardSearch.init(to, vehicle);
315 double minTTSeen = std::numeric_limits<double>::max();
316 Meeting meeting(nullptr, nullptr);
317 bool continueForward = true;
318 bool continueBackward = true;
319 int num_visited_fw = 0;
320 int num_visited_bw = 0;
321 bool result = true;
322 while (continueForward || continueBackward) {
323 if (continueForward) {
324 continueForward = myForwardSearch.step(myHierarchy->forwardUplinks, myBackwardSearch, minTTSeen, meeting);
325 num_visited_fw += 1;
326 }
327 if (continueBackward) {
328 continueBackward = myBackwardSearch.step(myHierarchy->backwardUplinks, myForwardSearch, minTTSeen, meeting);
329 num_visited_bw += 1;
330 }
331 }
332 if (minTTSeen < std::numeric_limits<double>::max()) {
333 buildPathFromMeeting(meeting, into);
334 } else {
335 if (!silent) {
336 this->myErrorMsgHandler->informf(TL("No connection between edge '%' and edge '%' found."), from->getID(), to->getID());
337 }
338 result = false;
339 }
340#ifdef CHRouter_DEBUG_QUERY_PERF
341 std::cout << "visited " << num_visited_fw + num_visited_bw << " edges (" << num_visited_fw << "," << num_visited_bw << ") ,final path length: " + toString(into.size()) + ")\n";
342#endif
343 this->endQuery(num_visited_bw + num_visited_fw);
344 return result;
345 }
346
348
350 void buildPathFromMeeting(Meeting meeting, std::vector<const E*>& into) const {
351 std::deque<const E*> tmp;
352 const auto* backtrack = meeting.first;
353 while (backtrack != 0) {
354 tmp.push_front((E*) backtrack->edge); // !!!
355 backtrack = backtrack->prev;
356 }
357 backtrack = meeting.second->prev; // don't use central edge twice
358 while (backtrack != 0) {
359 tmp.push_back((E*) backtrack->edge); // !!!
360 backtrack = backtrack->prev;
361 }
362 // expand shortcuts
363 const E* prev = 0;
364 while (!tmp.empty()) {
365 const E* cur = tmp.front();
366 tmp.pop_front();
367 if (prev == 0) {
368 into.push_back(cur);
369 prev = cur;
370 } else {
371 const E* via = getVia(prev, cur);
372 if (via == 0) {
373 into.push_back(cur);
374 prev = cur;
375 } else {
376 tmp.push_front(cur);
377 tmp.push_front(via);
378 }
379 }
380 }
381 }
382
383private:
384 // retrieve the via edge for a shortcut
385 const E* getVia(const E* forwardFrom, const E* forwardTo) const {
386 typename CHBuilder<E, V>::ConstEdgePair forward(forwardFrom, forwardTo);
387 typename CHBuilder<E, V>::ShortcutVia::const_iterator it = myHierarchy->shortcuts.find(forward);
388 if (it != myHierarchy->shortcuts.end()) {
389 return it->second;
390 } else {
391 return 0;
392 }
393 }
394
395
396private:
398 const std::vector<E*>& myEdges;
399
403
406
409
412
415};
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define TL(string)
Definition MsgHandler.h:304
#define SUMOTime_MAX
Definition SUMOTime.h:34
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
std::pair< const E *, const E * > ConstEdgePair
Definition CHBuilder.h:76
bool operator()(const typename SUMOAbstractRouter< E, V >::EdgeInfo *nod1, const typename SUMOAbstractRouter< E, V >::EdgeInfo *nod2) const
Comparing method.
Definition CHRouter.h:99
SUMOAbstractRouter< E, V >::EdgeInfo * getEdgeInfo(const E *const edge)
Definition CHRouter.h:84
EdgeInfoByTTComparator myComparator
Definition CHRouter.h:207
bool step(const std::vector< ConnectionVector > &uplinks, const Unidirectional &otherSearch, double &minTTSeen, Meeting &meeting)
explore on element from the frontier,update minTTSeen and meeting if an EdgeInfo found by the otherSe...
Definition CHRouter.h:132
Unidirectional(const std::vector< E * > &edges, bool forward)
Constructor.
Definition CHRouter.h:72
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo > myEdgeInfos
The container of edge information.
Definition CHRouter.h:205
const SUMOAbstractRouter< E, V >::EdgeInfo * getEdgeInfo(const E *const edge) const
Definition CHRouter.h:88
std::vector< typename CHBuilder< E, V >::Connection > ConnectionVector
Definition CHRouter.h:127
bool myAmForward
the role of this search
Definition CHRouter.h:199
void init(const E *const start, const V *const vehicle)
Definition CHRouter.h:108
bool found(const E *const edge) const
Definition CHRouter.h:80
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo * > myFrontier
the min edge heap
Definition CHRouter.h:201
std::set< const E * > myFound
the set of visited (settled) Edges
Definition CHRouter.h:203
Computes the shortest path through a contracted network.
Definition CHRouter.h:59
virtual SUMOAbstractRouter< E, V > * clone()
Definition CHRouter.h:259
virtual void prohibit(const std::map< const E *, RouterProhibition > &toProhibit)
Definition CHRouter.h:270
virtual ~CHRouter()
Destructor.
Definition CHRouter.h:251
const SUMOTime myWeightPeriod
the validity duration of one weight interval
Definition CHRouter.h:408
const E * getVia(const E *forwardFrom, const E *forwardTo) const
Definition CHRouter.h:385
SUMOTime myValidUntil
the validity duration of the current hierarchy (exclusive)
Definition CHRouter.h:411
Unidirectional myBackwardSearch
Definition CHRouter.h:402
CHRouter(const std::vector< E * > &edges, bool unbuildIsWarning, typename SUMOAbstractRouter< E, V >::Operation operation, const SUMOVehicleClass svc, SUMOTime weightPeriod, const bool havePermissions, const bool haveRestrictions)
Constructor.
Definition CHRouter.h:218
CHBuilder< E, V >::Hierarchy * myHierarchy
Definition CHRouter.h:405
Unidirectional myForwardSearch
the unidirectional search queues
Definition CHRouter.h:401
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)
Builds the route between the given edges using the minimum traveltime in the contracted graph.
Definition CHRouter.h:299
virtual bool supportsProhibitions() const
Definition CHRouter.h:276
std::pair< const typename SUMOAbstractRouter< E, V >::EdgeInfo *, const typename SUMOAbstractRouter< E, V >::EdgeInfo * > Meeting
A meeting point of the two search scopes.
Definition CHRouter.h:63
void buildPathFromMeeting(Meeting meeting, std::vector< const E * > &into) const
normal routing methods
Definition CHRouter.h:350
CHRouter(const std::vector< E * > &edges, bool unbuildIsWarning, typename SUMOAbstractRouter< E, V >::Operation operation, const SUMOVehicleClass svc, typename CHBuilder< E, V >::Hierarchy *hierarchy, const bool havePermissions, const bool haveRestrictions)
Cloning constructor, should be used only for time independent instances which build a hierarchy only ...
Definition CHRouter.h:235
CHBuilder< E, V > * myHierarchyBuilder
Definition CHRouter.h:404
virtual void reset(const V *const vehicle)
trigger hierarchy rebuild
Definition CHRouter.h:282
const std::vector< E * > & myEdges
all edges with numerical ids
Definition CHRouter.h:398
const SUMOVehicleClass mySVC
the permissions for which the hierarchy was constructed
Definition CHRouter.h:414
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
void informf(const std::string &format, T value, Targs... Fargs)
adds a new formatted message
Definition MsgHandler.h:116
const E *const edge
The current edge.
double effort
Effort to reach the edge.
const bool myHavePermissions
whether edge permissions need to be considered
Operation myOperation
The object's operation to perform.
const bool myHaveRestrictions
whether edge restrictions need to be considered
void endQuery(int visits)
MsgHandler * myErrorMsgHandler
the handler for routing errors