Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/router/SPTree.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-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 SPTree.h
15
/// @author Laura Bieker
16
/// @author Michael Behrisch
17
/// @date February 2012
18
///
19
// Shortest Path tree of limited depth using Dijkstras algorithm
20
/****************************************************************************/
21
#pragma once
22
#include <config.h>
23
24
#include <string>
25
#include <functional>
26
#include <vector>
27
#include <set>
28
#include <limits>
29
#include <algorithm>
30
#include <iterator>
31
#include <utils/common/MsgHandler.h>
32
#include <utils/common/StdDefs.h>
33
34
35
template<class E, class C>
36
class SPTree {
37
38
public:
39
typedef std::vector<C> CHConnections;
40
typedef std::pair<const C*, const C*> CHConnectionPair;
41
typedef std::vector<CHConnectionPair> CHConnectionPairs;
42
43
/**
44
* @class EdgeInfoByEffortComparator
45
* Class to compare (and so sort) nodes by their effort
46
*/
47
class EdgeByTTComparator {
48
public:
49
/// Comparing method
50
bool operator()(const E* a, const E* b) const {
51
if (a->traveltime == b->traveltime) {
52
return a->edge->getNumericalID() > b->edge->getNumericalID();
53
}
54
return a->traveltime > b->traveltime;
55
}
56
};
57
58
59
/**
60
* @brief Constructor
61
*/
62
SPTree(int maxDepth, bool validatePermissions) :
63
myMaxDepth(maxDepth),
64
myValidatePermissions(validatePermissions) {
65
}
66
67
68
void init() {
69
// all EdgeInfos touched in the previous query are either in myFrontier or myFound: clean those up
70
for (typename std::vector<E*>::iterator i = myFrontier.begin(); i != myFrontier.end(); i++) {
71
(*i)->reset();
72
}
73
myFrontier.clear();
74
for (typename std::vector<E*>::iterator i = myFound.begin(); i != myFound.end(); i++) {
75
(*i)->reset();
76
}
77
myFound.clear();
78
}
79
80
81
/**
82
* @brief build a shortest path tree from start to a depth of myMaxdepth. The given
83
* edge is excluded from this tree
84
*/
85
void rebuildFrom(E* start, const E* excluded) {
86
init();
87
start->traveltime = 0;
88
start->depth = 0;
89
start->permissions = start->edge->getPermissions();
90
myFrontier.push_back(start);
91
// build SPT
92
while (!myFrontier.empty()) {
93
E* min = myFrontier.front();
94
std::pop_heap(myFrontier.begin(), myFrontier.end(), myCmp);
95
myFrontier.pop_back();
96
myFound.push_back(min);
97
min->visited = true;
98
if (min->depth < myMaxDepth) {
99
for (typename CHConnections::iterator it = min->followers.begin(); it != min->followers.end(); it++) {
100
C& con = *it;
101
E* follower = con.target;
102
if (follower == excluded) {
103
continue;
104
}
105
const double traveltime = min->traveltime + con.cost;
106
const double oldTraveltime = follower->traveltime;
107
if (!follower->visited && traveltime < oldTraveltime) {
108
follower->traveltime = traveltime;
109
follower->depth = min->depth + 1;
110
follower->permissions = (min->permissions & con.permissions);
111
if (oldTraveltime == std::numeric_limits<double>::max()) {
112
myFrontier.push_back(follower);
113
std::push_heap(myFrontier.begin(), myFrontier.end(), myCmp);
114
} else {
115
std::push_heap(myFrontier.begin(),
116
std::find(myFrontier.begin(), myFrontier.end(), follower) + 1,
117
myCmp);
118
}
119
}
120
}
121
}
122
}
123
}
124
125
126
/// @brief whether permissions should be validated;
127
inline bool validatePermissions() {
128
return myValidatePermissions;
129
}
130
131
/// @brief save source/target pair for later validation
132
void registerForValidation(const C* aInfo, const C* fInfo) {
133
assert(myValidatePermissions);
134
myShortcutsToValidate.push_back(CHConnectionPair(aInfo, fInfo));
135
}
136
137
138
/* @brief for each path source->excluded->target try to find a witness with a witness
139
* with equal permissions */
140
const CHConnectionPairs& getNeededShortcuts(const E* excluded) {
141
assert(myValidatePermissions);
142
myNeededShortcuts.clear();
143
for (typename CHConnectionPairs::iterator it = myShortcutsToValidate.begin(); it != myShortcutsToValidate.end(); ++it) {
144
const C* const aInfo = it->first;
145
const C* const fInfo = it->second;
146
const double bestWitness = dijkstraTT(
147
aInfo->target, fInfo->target, excluded, (aInfo->permissions & fInfo->permissions));
148
const double viaCost = aInfo->cost + fInfo->cost;
149
if (viaCost < bestWitness) {
150
myNeededShortcuts.push_back(*it);
151
}
152
}
153
myShortcutsToValidate.clear();
154
return myNeededShortcuts;
155
}
156
157
158
private:
159
// perform dijkstra search under permission constraints
160
double dijkstraTT(E* start, E* dest, const E* excluded, SVCPermissions permissions) {
161
init();
162
start->traveltime = 0;
163
start->depth = 0;
164
myFrontier.push_back(start);
165
// build SPT
166
while (!myFrontier.empty()) {
167
E* min = myFrontier.front();
168
if (min == dest) {
169
return dest->traveltime;
170
}
171
std::pop_heap(myFrontier.begin(), myFrontier.end(), myCmp);
172
myFrontier.pop_back();
173
myFound.push_back(min);
174
min->visited = true;
175
if (min->depth < myMaxDepth) {
176
for (typename CHConnections::iterator it = min->followers.begin(); it != min->followers.end(); it++) {
177
C& con = *it;
178
E* follower = con.target;
179
if (follower == excluded) {
180
continue;
181
}
182
if ((con.permissions & permissions) != permissions) {
183
continue;
184
}
185
const double traveltime = min->traveltime + con.cost;
186
const double oldTraveltime = follower->traveltime;
187
if (!follower->visited && traveltime < oldTraveltime) {
188
follower->traveltime = traveltime;
189
follower->depth = min->depth + 1;
190
follower->permissions = (min->permissions & con.permissions);
191
if (oldTraveltime == std::numeric_limits<double>::max()) {
192
myFrontier.push_back(follower);
193
std::push_heap(myFrontier.begin(), myFrontier.end(), myCmp);
194
} else {
195
std::push_heap(myFrontier.begin(),
196
std::find(myFrontier.begin(), myFrontier.end(), follower) + 1,
197
myCmp);
198
}
199
}
200
}
201
}
202
}
203
return dest->traveltime;
204
}
205
206
207
// helper method for debugging
208
void debugPrintVector(std::vector<E*>& vec, E* start, const E* excluded) {
209
std::cout << "computed SPT from '" << start->edge->getID() << "' (excluding " << excluded->edge->getID() << ") with " << myFound.size() << " edges\n";
210
for (typename std::vector<E*>::iterator it = vec.begin(); it != vec.end(); it++) {
211
E* e = *it;
212
std::cout << "(" << e->edge->getID() << "," << e->traveltime << ") ";
213
}
214
std::cout << "\n";
215
}
216
217
/// @brief the min edge heap
218
std::vector<E*> myFrontier;
219
/// @brief the list of visited edges (used when resetting)
220
std::vector<E*> myFound;
221
222
/// @brief comparator for search queue
223
EdgeByTTComparator myCmp;
224
225
/// @brief maximum search depth
226
int myMaxDepth;
227
228
/// @brief whether permissions should be validated
229
bool myValidatePermissions;
230
231
/// @brief vector of needed shortcuts after validation
232
CHConnectionPairs myShortcutsToValidate;
233
/// @brief vector of needed shortcuts after validation
234
CHConnectionPairs myNeededShortcuts;
235
};
236
237