Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
CCHRouter.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/****************************************************************************/
18// A SUMOAbstractRouter that answers queries via a RoutingKit Customizable
19// Contraction Hierarchy over the edge graph. The metric is re-customized
20// out-of-band (MSRoutingEngine::adaptEdgeEfforts) and published as a
21// shared_ptr snapshot; each query snapshots the current metric, so a
22// publish that lands mid-query is safe (double buffer).
23//
24// Following the AStarRouter<E, V, M> lookup-table pattern, the graph-mapping
25// class is the GRAPH template parameter (the simulation supplies its concrete
26// mapper, e.g. microsim's CCHGraph), so this header carries no simulation
27// dependencies. GRAPH must provide:
28// unsigned nodeOf(const E*) (INVALID_NODE if not a node)
29// const E* edgeOf(unsigned node)
30// const std::vector<unsigned>& tazSources(const E*) (entry-edge node sets)
31// const std::vector<unsigned>& tazSinks(const E*) (exit-edge node sets)
32// void expandNodePath(const std::vector<unsigned>&, std::vector<const E*>&)
33// static const unsigned INVALID_NODE
34//
35// Every vehicle class routes on CCH via its own published metric. Closures are
36// permission changes the per-class metric encodes as inf_weight once they have
37// been customized in; the simulation's metric provider hands out nullptr while
38// a permission flip is still pending, so those queries route exactly. The
39// embedded A* fallback is used when a class has no (fresh) metric, when the
40// vehicle routes on the ORIGINAL permissions (ignoreTransientPermissions --
41// the shared metric bakes in the live ones), or when a prohibition is NOT
42// expressible as a live permission closure (an arbitrary per-query
43// prohibition, which no shared CCH metric can represent) -- see compute() /
44// prohibitionsCoveredByMetric().
45/****************************************************************************/
46#pragma once
47#include <config.h>
48
49
50#include <memory>
51#include <vector>
52#include <cmath>
53#include <utils/common/Named.h>
58#pragma GCC diagnostic push
59#pragma GCC diagnostic ignored "-Wunused-parameter"
61#pragma GCC diagnostic pop
62
63
64// ===========================================================================
65// class definitions
66// ===========================================================================
71template<class E, class V, class GRAPH>
72class CCHRouter : public SUMOAbstractRouter<E, V> {
73public:
89 typedef void (*ResetHook)(const V*);
92
101 CCHRouter(const GRAPH* graph, MetricProvider provider,
102 Operation operation, const bool unbuildIsWarning,
103 SUMOAbstractRouter<E, V>* fallback,
104 PeriodEnd periodEnd = nullptr, ResetHook onReset = nullptr) :
105 SUMOAbstractRouter<E, V>("CCHRouter", unbuildIsWarning, operation, nullptr, false, false),
106 myGraph(graph), myMetricProvider(provider), myFallback(fallback),
107 myPeriodEnd(periodEnd), myOnReset(onReset), myProhibitionActive(false) {
108 }
109
118
119 virtual ~CCHRouter() {
120 delete myFallback;
121 }
122
124 return new CCHRouter<E, V, GRAPH>(this);
125 }
126
131 virtual void reset(const V* const vehicle) {
132 if (myOnReset != nullptr) {
133 myOnReset(vehicle);
134 }
135 myFallback->reset(vehicle);
136 }
137
138 bool compute(const E* from, const E* to, const V* const vehicle,
139 SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
140 // A CCH query can only avoid an edge the metric already encodes as inf:
141 // RoutingKit's query has no per-arc blacklist, and a query-time skip is
142 // unsound because shortcut arcs bake in shortest paths THROUGH the edge
143 // (SUMO's own CHRouter refuses prohibitions for the same reason). So we
144 // run CCH when the metric can express the request and fall back to the
145 // exact A* router otherwise: (a) no metric for this class, or (b) an
146 // active prohibition that is NOT already a live permission-closure this
147 // class's metric encodes (prohibitionsCoveredByMetric).
148 const SUMOVehicleClass vClass = vehicle == nullptr ? SVC_PASSENGER : vehicle->getVClass();
149 // A vehicle that routes on the ORIGINAL permissions (routing mode bit
150 // ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) cannot use the shared
151 // metric, which bakes in the LIVE permissions, transient closures
152 // included -- route it exactly, like Dijkstra/A* do natively.
153 if (vehicle != nullptr && vehicle->ignoreTransientPermissions()) {
154 return myFallback->compute(from, to, vehicle, msTime, into, silent);
155 }
156 MetricPtr metric = myMetricProvider(vClass, msTime, vehicle);
157 if (metric == nullptr || (myProhibitionActive && !prohibitionsCoveredByMetric(vClass))) {
158 return myFallback->compute(from, to, vehicle, msTime, into, silent);
159 }
160 // Endpoints -> node SETS: a district star connector expands to its
161 // member edges (phantom-node seeding); everything that is a graph
162 // node -- including legacy function="connector" net edges -- routes
163 // as a single node. TAZ member edges are the class-union set, so
164 // filter to edges this class may enter.
165 const bool fromTaz = from->isTazConnector() && myGraph->nodeOf(from) == GRAPH::INVALID_NODE;
166 const bool toTaz = to->isTazConnector() && myGraph->nodeOf(to) == GRAPH::INVALID_NODE;
167 // Mirror the exact routers' endpoint rejection (AStarRouter::compute):
168 // an endpoint the vehicle may not use fails loudly instead of quietly
169 // seeding a query on it. The metric masks only arcs BETWEEN nodes --
170 // the source edge's own closure never enters it (its effort is added
171 // as a plain source seed), so without this check a query from a
172 // hard-closed edge would "succeed". TAZ members are filtered below.
173 if (vehicle != nullptr) {
174 if (!fromTaz && from->prohibits(vehicle)) {
175 if (!silent && this->myErrorMsgHandler != nullptr) {
176 this->myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on source edge '" + from->getID() + "'.");
177 }
178 return false;
179 }
180 if (!toTaz && to->prohibits(vehicle)) {
181 if (!silent && this->myErrorMsgHandler != nullptr) {
182 this->myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on destination edge '" + to->getID() + "'.");
183 }
184 return false;
185 }
186 }
187 std::vector<unsigned> srcBuf, tgtBuf;
188 const std::vector<unsigned>* sources;
189 const std::vector<unsigned>* targets;
190 if (fromTaz) {
191 for (const unsigned m : myGraph->tazSources(from)) {
192 if ((myGraph->edgeOf(m)->getPermissions() & vClass) != 0) {
193 srcBuf.push_back(m);
194 }
195 }
196 sources = &srcBuf;
197 } else {
198 const unsigned s = myGraph->nodeOf(from);
199 if (s != GRAPH::INVALID_NODE) {
200 srcBuf.push_back(s);
201 }
202 sources = &srcBuf;
203 }
204 if (toTaz) {
205 for (const unsigned m : myGraph->tazSinks(to)) {
206 if ((myGraph->edgeOf(m)->getPermissions() & vClass) != 0) {
207 tgtBuf.push_back(m);
208 }
209 }
210 targets = &tgtBuf;
211 } else {
212 const unsigned t = myGraph->nodeOf(to);
213 if (t != GRAPH::INVALID_NODE) {
214 tgtBuf.push_back(t);
215 }
216 targets = &tgtBuf;
217 }
218 if (sources->empty() || targets->empty()) {
219 // unmappable endpoint (e.g. internal edge, or a TAZ with no member
220 // in this class's graph) -> exact fallback.
221 return myFallback->compute(from, to, vehicle, msTime, into, silent);
222 }
223
224 this->startQuery();
225 const double t = STEPS2TIME(msTime);
226 if (!runQuery(metric, *sources, *targets, vehicle, t)) {
227 this->endQuery(0);
228 if (!silent && this->myErrorMsgHandler != nullptr) {
229 this->myErrorMsgHandler->informf(TL("No connection between edge '%' and edge '%' found."),
230 from->getID(), to->getID());
231 }
232 return false;
233 }
234 std::vector<const E*> path;
235 buildPath(from, to, fromTaz, toTaz, path);
236 int visited = (int)path.size();
237 // Weight-period boundary: the metric of the depart period is exact as
238 // long as the trip finishes inside that period (efforts are constant
239 // within it, and no time-propagated optimum can cross the boundary if
240 // this trip does not: any path entering the next period costs at
241 // least the remaining period, which already exceeds this result).
242 // When the trip does cross, ALSO query the next period's metric and
243 // keep whichever path is cheaper under the true time-propagating
244 // walk (recomputeCosts). Exact for the common single-crossing case
245 // where the optimum follows one period's structure; trips spanning
246 // several periods keep the better of the two candidates.
247 if (myPeriodEnd != nullptr && myQuery.get_distance() > 0) {
248 const SUMOTime boundary = myPeriodEnd(msTime);
249 if (boundary != SUMOTime_MAX
250 && msTime + TIME2STEPS((double)myQuery.get_distance() / 100.) >= boundary) {
251 MetricPtr altMetric = myMetricProvider(vClass, boundary, vehicle);
252 if (altMetric != nullptr && altMetric != metric
253 && runQuery(altMetric, *sources, *targets, vehicle, t)) {
254 std::vector<const E*> altPath;
255 buildPath(from, to, fromTaz, toTaz, altPath);
256 visited += (int)altPath.size();
257 if (this->recomputeCosts(altPath, vehicle, msTime)
258 < this->recomputeCosts(path, vehicle, msTime)) {
259 path.swap(altPath);
260 }
261 }
262 }
263 }
264 into.insert(into.end(), path.begin(), path.end());
265 this->endQuery(visited);
266 return true;
267 }
268
275 void prohibit(const Prohibitions& toProhibit) {
276 myProhibited = toProhibit;
277 myProhibitionActive = !toProhibit.empty();
278 myFallback->prohibit(toProhibit);
279 }
280
281 bool supportsProhibitions() const {
282 return true; // handled by delegating to the fallback
283 }
284
285 void setBulkMode(const bool mode) {
287 myFallback->setBulkMode(mode);
288 }
289
292 void setMsgHandler(MsgHandler* const errorMsgHandler) {
294 myFallback->setMsgHandler(errorMsgHandler);
295 }
296
297private:
307 bool runQuery(MetricPtr metric, const std::vector<unsigned>& sources,
308 const std::vector<unsigned>& targets, const V* const vehicle, double t) {
309 if (metric != myBoundMetric) {
312 } else {
313 myQuery.reset();
314 }
315 const double bigEff = (double)(RoutingKit::inf_weight - 1) / 100.0;
316 for (const unsigned s : sources) {
317 const double eff = this->getEffort(myGraph->edgeOf(s), vehicle, t);
318 const unsigned d = eff < bigEff ? (unsigned)llround(eff * 100.0) : RoutingKit::inf_weight - 1;
319 myQuery.add_source(s, d);
320 }
321 for (const unsigned tt : targets) {
322 myQuery.add_target(tt, 0);
323 }
324 myQuery.run();
326 }
327
330 void buildPath(const E* from, const E* to, bool fromTaz, bool toTaz,
331 std::vector<const E*>& path) {
332 const std::vector<unsigned> nodePath = myQuery.get_node_path();
333 if (fromTaz) {
334 path.push_back(from);
335 }
336 myGraph->expandNodePath(nodePath, path);
337 if (toTaz) {
338 path.push_back(to);
339 }
340 }
341
353 for (const auto& item : myProhibited) {
354 if ((item.second.permissions & vClass) != vClass // forbids vClass here...
355 && (item.first->getPermissions() & vClass) != 0) { // ...but edge still permits it live
356 return false;
357 }
358 }
359 return true;
360 }
361
362private:
363 const GRAPH* myGraph; // shared, immutable, not owned
366 MetricPtr myBoundMetric = nullptr; // metric myQuery is currently bound to
368 PeriodEnd myPeriodEnd; // may be nullptr (static weights)
369 ResetHook myOnReset; // may be nullptr (nobody to notify)
371 Prohibitions myProhibited; // last set installed via prohibit()
372
373private:
374 CCHRouter& operator=(const CCHRouter&) = delete;
375};
376
long long int SUMOTime
Definition GUI.h:36
#define TL(string)
Definition MsgHandler.h:304
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TIME2STEPS(x)
Definition SUMOTime.h:60
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
Contraction-hierarchy router over the edge graph mapped by GRAPH.
Definition CCHRouter.h:72
bool prohibitionsCoveredByMetric(SUMOVehicleClass vClass) const
Can the per-class CCH metric already express every edge this prohibition set forbids for vClass?...
Definition CCHRouter.h:352
SUMOTime(* PeriodEnd)(SUMOTime)
the end of the weight period containing the given time (SUMOTime_MAX = weights are static)....
Definition CCHRouter.h:84
bool myProhibitionActive
Definition CCHRouter.h:370
SUMOAbstractRouter< E, V >::Prohibitions Prohibitions
Definition CCHRouter.h:91
void setMsgHandler(MsgHandler *const errorMsgHandler)
keep the fallback reporting through the same handler (duarouter swaps handlers around route repair; C...
Definition CCHRouter.h:292
SUMOAbstractRouter< E, V >::Operation Operation
Definition CCHRouter.h:90
MetricPtr myBoundMetric
Definition CCHRouter.h:366
RoutingKit::CustomizableContractionHierarchyQuery myQuery
Definition CCHRouter.h:365
CCHRouter & operator=(const CCHRouter &)=delete
void(* ResetHook)(const V *)
the host's efforts changed behind the metrics and it reset the router (SUMOAbstractRouter::reset – ma...
Definition CCHRouter.h:89
void prohibit(const Prohibitions &toProhibit)
prohibitions: a closure that is already a live permission change is served by the per-class metric (C...
Definition CCHRouter.h:275
CCHRouter(CCHRouter *other)
clone constructor: share graph + provider, clone the fallback, fresh query scratch
Definition CCHRouter.h:111
void setBulkMode(const bool mode)
Definition CCHRouter.h:285
virtual void reset(const V *const vehicle)
the host's efforts changed (see ResetHook): notify the metric store and reset the fallback's caches....
Definition CCHRouter.h:131
ResetHook myOnReset
Definition CCHRouter.h:369
const RoutingKit::CustomizableContractionHierarchyMetric * MetricPtr
Definition CCHRouter.h:74
void buildPath(const E *from, const E *to, bool fromTaz, bool toTaz, std::vector< const E * > &path)
expand the last query's node path, bracketing it with the TAZ connectors where the endpoints are zone...
Definition CCHRouter.h:330
MetricPtr(* MetricProvider)(SUMOVehicleClass, SUMOTime, const V *)
supplies the metric for a vehicle class at a query time, or nullptr => fall back. The simulation igno...
Definition CCHRouter.h:79
PeriodEnd myPeriodEnd
Definition CCHRouter.h:368
bool runQuery(MetricPtr metric, const std::vector< unsigned > &sources, const std::vector< unsigned > &targets, const V *const vehicle, double t)
Bind the query to metric (rebinding only on change), seed all sources and targets and run it; true if...
Definition CCHRouter.h:307
virtual SUMOAbstractRouter< E, V > * clone()
Definition CCHRouter.h:123
Prohibitions myProhibited
Definition CCHRouter.h:371
SUMOAbstractRouter< E, V > * myFallback
Definition CCHRouter.h:367
virtual ~CCHRouter()
Definition CCHRouter.h:119
MetricProvider myMetricProvider
Definition CCHRouter.h:364
const GRAPH * myGraph
Definition CCHRouter.h:363
bool supportsProhibitions() const
Definition CCHRouter.h:281
CCHRouter(const GRAPH *graph, MetricProvider provider, Operation operation, const bool unbuildIsWarning, SUMOAbstractRouter< E, V > *fallback, PeriodEnd periodEnd=nullptr, ResetHook onReset=nullptr)
Constructor.
Definition CCHRouter.h:101
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 effort at the given time The definition of...
Definition CCHRouter.h:138
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
void informf(const std::string &format, T value, Targs... Fargs)
adds a new formatted message
Definition MsgHandler.h:116
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:66
virtual void setBulkMode(const bool mode)
std::map< const E *, RouterProhibition > Prohibitions
double getEffort(const E *const e, const V *const v, double t) const
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
virtual void setMsgHandler(MsgHandler *const errorMsgHandler)
void endQuery(int visits)
MsgHandler * myErrorMsgHandler
the handler for routing errors
const Graph * graph
CustomizableContractionHierarchyMetric * metric
CustomizableContractionHierarchyQuery & add_source(unsigned s, unsigned dist_to_s=0)
CustomizableContractionHierarchyQuery & add_target(unsigned t, unsigned dist_to_t=0)