Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/router/SUMOAbstractRouter.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2006-2025 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
/****************************************************************************/
14
/// @file SUMOAbstractRouter.h
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Jakob Erdmann
18
/// @date 25.Jan 2006
19
///
20
// An abstract router base class
21
/****************************************************************************/
22
#pragma once
23
#include <config.h>
24
25
#include <string>
26
#include <vector>
27
#include <algorithm>
28
#include <iterator>
29
#include <assert.h>
30
#include <utils/common/SysUtils.h>
31
#include <utils/common/MsgHandler.h>
32
#include <utils/common/SUMOTime.h>
33
#include <utils/common/ToString.h>
34
//#define ROUTER_DEBUG_HINT
35
//#define ROUTER_DEBUG_COND (true)
36
37
38
// ===========================================================================
39
// class definitions
40
// ===========================================================================
41
/**
42
* @class SUMOAbstractRouter
43
* The interface for routing the vehicles over the network.
44
*/
45
template<class E, class V>
46
class SUMOAbstractRouter {
47
public:
48
/**
49
* @class EdgeInfo
50
* A definition about a route's edge with the effort needed to reach it and
51
* the information about the previous edge.
52
*/
53
class EdgeInfo {
54
public:
55
/// Constructor
56
EdgeInfo(const E* const e)
57
: edge(e), effort(std::numeric_limits<double>::max()),
58
heuristicEffort(std::numeric_limits<double>::max()),
59
leaveTime(0.), prev(nullptr), visited(false), prohibited(false), prohibitionEnd(0) {}
60
61
/// The current edge
62
const E* const edge;
63
64
/// Effort to reach the edge
65
double effort;
66
67
/// Estimated effort to reach the edge (effort + lower bound on remaining effort)
68
// only used by A*
69
double heuristicEffort;
70
71
/// The time the vehicle leaves the edge
72
double leaveTime;
73
74
/// The previous edge
75
const EdgeInfo* prev;
76
77
/// whether the edge was already evaluated
78
bool visited;
79
80
/// whether the edge is currently not allowed
81
bool prohibited;
82
83
/// the time at which a temporary prohibitione ends
84
double prohibitionEnd;
85
86
inline void reset() {
87
effort = std::numeric_limits<double>::max();
88
heuristicEffort = std::numeric_limits<double>::max();
89
visited = false;
90
}
91
92
};
93
94
/// Type of the function that is used to retrieve the edge effort.
95
typedef double(* Operation)(const E* const, const V* const, double);
96
97
/// Prohibitions and their estimated end time
98
typedef std::map<const E*, double> Prohibitions;
99
100
/// Constructor
101
SUMOAbstractRouter(const std::string& type, bool unbuildIsWarning, Operation operation, Operation ttOperation,
102
const bool havePermissions, const bool haveRestrictions) :
103
myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
104
myOperation(operation), myTTOperation(ttOperation),
105
myBulkMode(false),
106
myAutoBulkMode(false),
107
myHavePermissions(havePermissions),
108
myHaveRestrictions(haveRestrictions),
109
myType(type),
110
myQueryVisits(0),
111
myNumQueries(0),
112
myQueryStartTime(0),
113
myQueryTimeSum(0) {
114
}
115
116
/// Copy Constructor
117
SUMOAbstractRouter(SUMOAbstractRouter* other) :
118
myErrorMsgHandler(other->myErrorMsgHandler),
119
myOperation(other->myOperation), myTTOperation(other->myTTOperation),
120
myBulkMode(false),
121
myAutoBulkMode(false),
122
myHavePermissions(other->myHavePermissions),
123
myHaveRestrictions(other->myHaveRestrictions),
124
myType(other->myType),
125
myQueryVisits(0),
126
myNumQueries(0),
127
myQueryStartTime(0),
128
myQueryTimeSum(0) { }
129
130
131
132
/// Destructor
133
virtual ~SUMOAbstractRouter() {
134
if (myNumQueries > 0) {
135
WRITE_MESSAGE(myType + " answered " + toString(myNumQueries) + " queries and explored " + toString((double)myQueryVisits / (double)myNumQueries) + " edges on average.");
136
WRITE_MESSAGE(myType + " spent " + elapsedMs2string(myQueryTimeSum) + " answering queries (" + toString((double)myQueryTimeSum / (double)myNumQueries) + "ms on average).");
137
}
138
}
139
140
virtual SUMOAbstractRouter* clone() = 0;
141
142
inline void init(const int edgeID, const SUMOTime msTime) {
143
// if (!myAmClean) {
144
// all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
145
for (auto& edgeInfo : myFrontierList) {
146
edgeInfo->reset();
147
}
148
myFrontierList.clear();
149
for (auto& edgeInfo : myFound) {
150
edgeInfo->reset();
151
}
152
myFound.clear();
153
if (edgeID > -1) {
154
// add begin node
155
auto& fromInfo = myEdgeInfos[edgeID];
156
fromInfo.effort = 0.;
157
fromInfo.heuristicEffort = 0.;
158
fromInfo.prev = nullptr;
159
fromInfo.leaveTime = STEPS2TIME(msTime);
160
myFrontierList.push_back(&fromInfo);
161
}
162
myAmClean = true;
163
// }
164
}
165
166
/// reset internal caches, used by CHRouter
167
virtual void reset(const V* const vehicle) {
168
UNUSED_PARAMETER(vehicle);
169
}
170
171
const std::string& getType() const {
172
return myType;
173
}
174
175
inline const typename SUMOAbstractRouter<E, V>::EdgeInfo& getEdgeInfo(int index) const {
176
return myEdgeInfos[index];
177
}
178
179
/** @brief Builds the route between the given edges using the minimum effort at the given time
180
The definition of the effort depends on the wished routing scheme */
181
virtual bool compute(const E* from, const E* to, const V* const vehicle,
182
SUMOTime msTime, std::vector<const E*>& into, bool silent = false) = 0;
183
184
185
/** @brief Builds the route between the given edges using the minimum effort at the given time,
186
* also taking into account position along the edges to ensure currect
187
* handling of looped routes
188
* The definition of the effort depends on the wished routing scheme */
189
inline bool compute(
190
const E* from, double fromPos,
191
const E* to, double toPos,
192
const V* const vehicle,
193
SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
194
if (from != to || fromPos <= toPos) {
195
return compute(from, to, vehicle, msTime, into, silent);
196
} else {
197
return computeLooped(from, to, vehicle, msTime, into, silent);
198
}
199
}
200
201
202
/** @brief Builds the route between the given edges using the minimum effort at the given time
203
* if from == to, return the shortest looped route */
204
inline bool computeLooped(const E* from, const E* to, const V* const vehicle,
205
SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
206
if (from != to) {
207
return compute(from, to, vehicle, msTime, into, silent);
208
}
209
double minEffort = std::numeric_limits<double>::max();
210
std::vector<const E*> best;
211
const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
212
for (const std::pair<const E*, const E*>& follower : from->getViaSuccessors(vClass)) {
213
std::vector<const E*> tmp;
214
compute(follower.first, to, vehicle, msTime, tmp, true);
215
if (tmp.size() > 0) {
216
double effort = recomputeCosts(tmp, vehicle, msTime);
217
if (effort < minEffort) {
218
minEffort = effort;
219
best = tmp;
220
}
221
}
222
}
223
if (minEffort != std::numeric_limits<double>::max()) {
224
into.push_back(from);
225
std::copy(best.begin(), best.end(), std::back_inserter(into));
226
return true;
227
} else if (!silent && myErrorMsgHandler != nullptr) {
228
myErrorMsgHandler->informf(TL("No connection between edge '%' and edge '%' found."), from->getID(), to->getID());
229
}
230
return false;
231
}
232
233
inline bool isProhibited(const E* const edge, const V* const vehicle) const {
234
return (myHavePermissions && edge->prohibits(vehicle)) || (myHaveRestrictions && edge->restricts(vehicle));
235
}
236
237
inline double getTravelTime(const E* const e, const V* const v, const double t, const double effort) const {
238
return myTTOperation == nullptr ? effort : (*myTTOperation)(e, v, t);
239
}
240
241
inline void updateViaEdgeCost(const E* viaEdge, const V* const v, double& time, double& effort, double& length) const {
242
while (viaEdge != nullptr && viaEdge->isInternal()) {
243
const double viaEffortDelta = this->getEffort(viaEdge, v, time);
244
time += getTravelTime(viaEdge, v, time, viaEffortDelta);
245
effort += viaEffortDelta;
246
length += viaEdge->getLength();
247
viaEdge = viaEdge->getViaSuccessors().front().second;
248
}
249
}
250
251
inline void updateViaCost(const E* const prev, const E* const e, const V* const v, double& time, double& effort, double& length) const {
252
if (prev != nullptr) {
253
for (const std::pair<const E*, const E*>& follower : prev->getViaSuccessors()) {
254
if (follower.first == e) {
255
updateViaEdgeCost(follower.second, v, time, effort, length);
256
break;
257
}
258
}
259
}
260
const double effortDelta = this->getEffort(e, v, time);
261
effort += effortDelta;
262
time += getTravelTime(e, v, time, effortDelta);
263
length += e->getLength();
264
}
265
266
bool isValid(const std::vector<const E*>& edges, const V* const v) const {
267
for (const E* const e : edges) {
268
if (isProhibited(e, v)) {
269
return false;
270
}
271
}
272
return true;
273
}
274
275
virtual double recomputeCosts(const std::vector<const E*>& edges, const V* const v, SUMOTime msTime, double* lengthp = nullptr) const {
276
double time = STEPS2TIME(msTime);
277
double effort = 0.;
278
double length = 0.;
279
if (lengthp == nullptr) {
280
lengthp = &length;
281
} else {
282
*lengthp = 0.;
283
}
284
const E* prev = nullptr;
285
for (const E* const e : edges) {
286
updateViaCost(prev, e, v, time, effort, *lengthp);
287
prev = e;
288
}
289
return effort;
290
}
291
292
293
inline double recomputeCostsPos(const std::vector<const E*>& edges, const V* const v, double fromPos, double toPos, SUMOTime msTime, double* lengthp = nullptr) const {
294
double effort = recomputeCosts(edges, v, msTime, lengthp);
295
if (!edges.empty()) {
296
double firstEffort = this->getEffort(edges.front(), v, STEPS2TIME(msTime));
297
double lastEffort = this->getEffort(edges.back(), v, STEPS2TIME(msTime));
298
effort -= firstEffort * fromPos / edges.front()->getLength();
299
effort -= lastEffort * (edges.back()->getLength() - toPos) / edges.back()->getLength();
300
}
301
return effort;
302
}
303
304
305
inline double setHint(const typename std::vector<const E*>::const_iterator routeBegin, const typename std::vector<const E*>::const_iterator routeEnd, const V* const v, SUMOTime msTime) {
306
double time = STEPS2TIME(msTime);
307
double effort = 0.;
308
double length = 0.;
309
const EdgeInfo* prev = &myEdgeInfos[(*routeBegin)->getNumericalID()];
310
init((*routeBegin)->getNumericalID(), msTime);
311
for (auto e = routeBegin + 1; e != routeEnd; ++e) {
312
if (isProhibited(*e, v)) {
313
return -1;
314
}
315
auto& edgeInfo = myEdgeInfos[(*e)->getNumericalID()];
316
edgeInfo.heuristicEffort = effort;
317
edgeInfo.prev = prev;
318
updateViaCost(prev->edge, *e, v, time, effort, length);
319
edgeInfo.effort = effort;
320
edgeInfo.leaveTime = time;
321
myFound.push_back(&edgeInfo);
322
prev = &edgeInfo;
323
#ifdef ROUTER_DEBUG_HINT
324
if (ROUTER_DEBUG_COND) {
325
std::cout << "DEBUG: hit=" << (*e)->getID()
326
<< " TT=" << edgeInfo.effort
327
<< " EF=" << this->getEffort(*e, v, edgeInfo.leaveTime)
328
<< " HT=" << edgeInfo.heuristicEffort << "\n";
329
}
330
#endif
331
}
332
return effort;
333
}
334
335
336
inline double getEffort(const E* const e, const V* const v, double t) const {
337
if (this->myProhibited.size() > 0 && myEdgeInfos.size() > 0 && myEdgeInfos[e->getNumericalID()].prohibitionEnd > 0) {
338
// pass edge after prohibition ends
339
return (myEdgeInfos[e->getNumericalID()].prohibitionEnd - t) + (*myOperation)(e, v, myEdgeInfos[e->getNumericalID()].prohibitionEnd);
340
} else {
341
return (*myOperation)(e, v, t);
342
}
343
}
344
345
inline void startQuery() {
346
myNumQueries++;
347
myQueryStartTime = SysUtils::getCurrentMillis();
348
}
349
350
inline void endQuery(int visits) {
351
myQueryVisits += visits;
352
myQueryTimeSum += (SysUtils::getCurrentMillis() - myQueryStartTime);
353
}
354
355
virtual void setBulkMode(const bool mode) {
356
myBulkMode = mode;
357
}
358
359
inline void setAutoBulkMode(const bool mode) {
360
myAutoBulkMode = mode;
361
}
362
363
virtual void prohibit(const Prohibitions& toProhibit) {
364
for (auto item : this->myProhibited) {
365
myEdgeInfos[item.first->getNumericalID()].prohibited = false;
366
myEdgeInfos[item.first->getNumericalID()].prohibitionEnd = 0;
367
}
368
for (auto item : toProhibit) {
369
if (item.second >= 0 && item.second != std::numeric_limits<double>::max()) {
370
myEdgeInfos[item.first->getNumericalID()].prohibitionEnd = item.second;
371
} else {
372
myEdgeInfos[item.first->getNumericalID()].prohibited = true;
373
}
374
}
375
this->myProhibited = toProhibit;
376
}
377
378
379
/// Builds the path from marked edges
380
void buildPathFrom(const typename SUMOAbstractRouter<E, V>::EdgeInfo* rbegin, std::vector<const E*>& edges) {
381
std::vector<const E*> tmp;
382
while (rbegin != nullptr) {
383
tmp.push_back(rbegin->edge);
384
rbegin = rbegin->prev;
385
}
386
std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(edges));
387
}
388
389
protected:
390
/// @brief the handler for routing errors
391
MsgHandler* const myErrorMsgHandler;
392
393
/// @brief The object's operation to perform.
394
Operation myOperation;
395
396
/// @brief The object's operation to perform for travel times
397
Operation myTTOperation;
398
399
/// @brief whether we are currently operating several route queries in a bulk
400
bool myBulkMode;
401
402
/// @brief whether we are currently trying to detect bulk mode automatically
403
bool myAutoBulkMode;
404
405
/// @brief whether we are already initialized
406
bool myAmClean;
407
408
/// @brief whether edge permissions need to be considered
409
const bool myHavePermissions;
410
411
/// @brief whether edge restrictions need to be considered
412
const bool myHaveRestrictions;
413
414
/// The list of explicitly prohibited edges and estimated end time of prohibition
415
Prohibitions myProhibited;
416
417
/// The container of edge information
418
std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
419
420
/// A container for reusage of the min edge heap
421
std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontierList;
422
/// @brief list of visited Edges (for resetting)
423
std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFound;
424
425
private:
426
/// @brief the type of this router
427
const std::string myType;
428
429
/// @brief counters for performance logging
430
long long int myQueryVisits;
431
long long int myNumQueries;
432
/// @brief the time spent querying in milliseconds
433
long long int myQueryStartTime;
434
long long int myQueryTimeSum;
435
436
private:
437
/// @brief Invalidated assignment operator
438
SUMOAbstractRouter& operator=(const SUMOAbstractRouter& s) = delete;
439
};
440
441