Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSStopOptimizer.cpp
Go to the documentation of this file.
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/****************************************************************************/
18// Optimizes prioritized stops
19/****************************************************************************/
20#include <config.h>
21#include <queue>
22#include "MSLane.h"
23#include "MSEdge.h"
24#include "MSStoppingPlace.h"
25#include "MSStopOptimizer.h"
26
27//#define DEBUG_OPTIMIZE_SKIPPED
28
29// ===========================================================================
30// method definitions
31// ===========================================================================
32
34MSStopOptimizer::optimizeSkipped(const MSEdge* source, double sourcePos, std::vector<StopEdgeInfo>& stops, ConstMSEdgeVector edges) const {
35 // intial solution is an upper bound on the acceptle total skipped priority
36 double minSkipped = 0;
37 double totalPrio = 0;
38 std::vector<StopEdgeInfo> bestStops = stops;
39 std::shared_ptr<StopPathNode> bestNode = nullptr;
40 double bestCost = myRouter.recomputeCostsPos(edges, myVehicle, sourcePos, 0, myT);
41 std::vector<int> skipped;
42
43 // each upcoming stop is part of a graph where we can start to search for a
44 // better solution. We evaluate followers lazily and prune based on the best
45 // solution already found
46 std::priority_queue<std::shared_ptr<StopPathNode>, std::vector<std::shared_ptr<StopPathNode> >, spnCompare> queue;
47
48 auto prev = std::make_shared<StopPathNode>(*this, StopEdgeInfo(source, -1, SIMSTEP, sourcePos));
49 prev->stopIndex = -1;
50 prev->routeIndex = 0;
51 prev->cost = bestCost;
52 prev->checked = true;
53 //std::cout << " i=-1 e=" << prev->edge->getID() << " sp=" << prev->skippedPrio << " rp=" << prev->reachedPrio << "\n";
54 queue.push(prev);
55
56 for (int i = 0; i < (int)stops.size(); i++) {
57 const StopEdgeInfo& stop = stops[i];
58 if (stop.skipped) {
59 skipped.push_back(i);
60 minSkipped += stops[i].priority;
61 } else {
62 auto ptr = std::make_shared<StopPathNode>(*this, stop);
63 ptr->skippedPrio = minSkipped;
64 ptr->reachedPrio = prev->reachedPrio;
65 ptr->reachedMandatory = prev->reachedMandatory;
66 if (stop.priority >= 0) {
67 ptr->reachedPrio += stop.priority;
68 } else {
69 ptr->reachedMandatory += 1;
70 }
71 ptr->checked = true;
72 ptr->prev = prev;
73 ptr->stopIndex = i;
74 ConstMSEdgeVector subEdges(edges.begin(), edges.begin() + stop.routeIndex);
75 ptr->cost = myRouter.recomputeCostsPos(subEdges, myVehicle, sourcePos, 0, myT);
76 ptr->edges.insert(ptr->edges.begin(), edges.begin() + prev->routeIndex, edges.begin() + stop.routeIndex + 1);
77 prev = ptr;
78 bestNode = ptr;
79 queue.push(ptr);
80 }
81 totalPrio += MAX2(0.0, stop.priority);
82 //std::cout << " i=" << i << " e=" << ptr->edge->getID() << " sp=" << ptr->skippedPrio << " rp=" << ptr->reachedPrio << "\n";
83 }
84#ifdef DEBUG_OPTIMIZE_SKIPPED
85 std::cout << SIMTIME << " optimizeSkipped veh=" << myVehicle->getID()
86 << " source=" << source->getID() << " sourcePos=" << sourcePos
87 << " nStops=" << stops.size() << " skipped=" << toString(skipped) << " qSize=" << queue.size()
88 << " minSkipped=" << minSkipped << " totalPrio=" << totalPrio << "\n";
89 for (const StopEdgeInfo& stop : stops) {
90 std::cout << " edge=" << stop.edge->getID() << " name=" << stop.nameTag.first << " wasSkipped=" << stop.skipped << " prio=" << stop.priority << "\n";
91 }
92 std::cout << " bestNode edge=" << bestNode->edge->getID() << " rPrio=" << bestNode->reachedPrio << " cost=" << bestNode->cost << "\n";
93#endif
94
95 std::map<const MSEdge*, std::shared_ptr<StopPathNode> > bestIntermediate;
96 while (!queue.empty()) {
97 auto ptr = queue.top();
98 queue.pop();
99#ifdef DEBUG_OPTIMIZE_SKIPPED
100 std::cout << " qSize=" << queue.size() << " topNode edge=" << ptr->edge->getID()
101 << " name='" << ptr->nameTag.first << "' skippedPrio=" << ptr->skippedPrio
102 << " trackChanges=" << ptr->trackChanges
103 << " cost=" << ptr->cost
104 << " reachedPrio=" << ptr->reachedPrio
105 << " mandatory=" << ptr->reachedMandatory
106 << " stopIndex=" << ptr->stopIndex << "\n";
107#endif
108 auto succ = ptr->getSuccessor(stops, minSkipped);
109#ifdef DEBUG_OPTIMIZE_SKIPPED
110 std::cout << " cost2=" << ptr->cost << " reachedPrio2=" << ptr->reachedPrio << " mandatory2=" << ptr->reachedMandatory << " succ=" << (succ == nullptr ? "NULL" : succ->edge->getID()) << "\n";
111#endif
112 if (*bestNode < *ptr) {
113 minSkipped = MIN2(minSkipped, totalPrio - ptr->reachedPrio);
114#ifdef DEBUG_OPTIMIZE_SKIPPED
115 std::cout << " newBestNode edge=" << bestNode->edge->getID() << " minSkipped=" << minSkipped
116 << " orm=" << bestNode->reachedMandatory << " rm=" << ptr->reachedMandatory
117 << " orp=" << bestNode->reachedPrio << " rp=" << ptr->reachedPrio
118 << " otc=" << bestNode->trackChanges << " tc=" << ptr->trackChanges
119 << " oc=" << bestNode->cost << " c=" << ptr->cost
120 << "\n";
121#endif
122 bestNode = ptr;
123 }
124 if (succ != nullptr) {
125 if (minSkipped == 0 && ptr->trackChanges > bestNode->trackChanges) {
126#ifdef DEBUG_OPTIMIZE_SKIPPED
127 std::cout << "pruned by minTC=" << bestNode->trackChanges << "\n";
128#endif
129 continue;
130 }
131 auto it = bestIntermediate.find(ptr->edge);
132 if (it == bestIntermediate.end()) {
133 bestIntermediate[ptr->edge] = ptr;
134#ifdef DEBUG_OPTIMIZE_SKIPPED
135 std::cout << "firstBest " << ptr->edge->getID() << "\n";
136#endif
137 } else {
138 auto best = it->second;
139 assert(best->checked);
140 assert(ptr->checked);
141 if (best == ptr) {
142#ifdef DEBUG_OPTIMIZE_SKIPPED
143 std::cout << "alreadyBest " << ptr->edge->getID() << " rp=" << ptr->reachedPrio << " tc=" << ptr->trackChanges << " c=" << ptr->cost << "\n";
144#endif
145 } else if (!(*best < *ptr)) {
146#ifdef DEBUG_OPTIMIZE_SKIPPED
147 std::cout << "skip " << ptr->edge->getID()
148 << " orp=" << best->reachedPrio << " rp=" << ptr->reachedPrio
149 << " otc=" << best->trackChanges << " tc=" << ptr->trackChanges
150 << " oc=" << best->cost << " c=" << ptr->cost
151 << "\n";
152#endif
153 continue;
154 } else {
155 bestIntermediate[ptr->edge] = ptr;
156#ifdef DEBUG_OPTIMIZE_SKIPPED
157 std::cout << "newBest " << ptr->edge->getID()
158 << " orp=" << best->reachedPrio << " rp=" << ptr->reachedPrio
159 << " otc=" << best->trackChanges << " tc=" << ptr->trackChanges
160 << " oc=" << best->cost << " c=" << ptr->cost
161 << "\n";
162#endif
163 }
164 }
165 queue.push(ptr);
166 queue.push(succ);
167 }
168 }
169 for (auto& stop : stops) {
170 // init true and later set false for all used stops
171 if (!stop.skipped) {
172 stop.backtracked = true;
173 stop.skipped = true;
174 }
175 }
176 ConstMSEdgeVector bestEdges;
177 while (bestNode != nullptr && bestNode->stopIndex >= 0) {
178#ifdef DEBUG_OPTIMIZE_SKIPPED
179 std::cout << " revBestNode index=" << bestNode->stopIndex << " edge=" << bestNode->edge->getID() << " name=" << bestNode->nameTag.first << " tc=" << bestNode->trackChanges << " c=" << bestNode->cost << "\n";
180#endif
181 stops[bestNode->stopIndex].skipped = false;
182 stops[bestNode->stopIndex].backtracked = false;
183 stops[bestNode->stopIndex].origEdge = bestNode->origEdge;
184 if (!bestEdges.empty() && !bestNode->edges.empty()) {
185 bestNode->edges.pop_back();
186 }
187 bestEdges.insert(bestEdges.begin(), bestNode->edges.begin(), bestNode->edges.end());
188 bestNode = bestNode->prev;
189 }
190#ifdef DEBUG_OPTIMIZE_SKIPPED
191 std::cout << "oldEdges=" << toString(edges) << "\nnewEdges=" << toString(bestEdges) << "\n";
192#endif
193 return bestEdges;
194}
195
196
197std::shared_ptr<MSStopOptimizer::StopPathNode>
198MSStopOptimizer::StopPathNode::getSuccessor(const std::vector<StopEdgeInfo>& stops, double minSkipped) {
199 if (!checked) {
200 checked = true;
201 // @todo caching, bulk-routing
202 double newCost = 0;
203 if (!so.reachableInTime(prev->edge, prev->pos, edge, pos, arrival, edges, newCost)) {
204#ifdef DEBUG_OPTIMIZE_SKIPPED
205 std::cout << " prevIndex=" << prev->stopIndex << " prevEdge=" << prev->edge->getID() << " i=" << stopIndex << " edge=" << edge->getID() << " unreachable\n";
206#endif
207 // indicate failure
208 reachedMandatory = -1;
209 return nullptr;
210 } else {
211#ifdef DEBUG_OPTIMIZE_SKIPPED
212 std::cout << " prevIndex=" << prev->stopIndex << " prevEdge=" << prev->edge->getID() << " i=" << stopIndex << " edge=" << edge->getID() << " reached with edges=" << toString(edges) << " cost=" << cost << " newCost=" << newCost << "\n";
213#endif
214 }
215 reachedPrio += MAX2(0.0, priority);
216 cost += newCost;
217 if (priority < 0) {
219 }
220 }
221 int nextIndex = stopIndex + numSkipped + 1;
222 while (nextIndex < (int)stops.size()) {
223 const StopEdgeInfo& next = stops[nextIndex];
224#ifdef DEBUG_OPTIMIZE_SKIPPED
225 std::cout << " i=" << stopIndex << " next=" << nextIndex << " numSkipped=" << numSkipped << " altIndex=" << altIndex << "\n";
226#endif
227 // always try the default track first
228 if (altIndex == -1) {
229 altIndex++;
230 auto succ = std::make_shared<StopPathNode>(so, next);
231 succ->skippedPrio = skippedPrio;
232 succ->reachedPrio = reachedPrio;
233 succ->reachedMandatory = reachedMandatory;
234 succ->trackChanges = trackChanges;
235 succ->cost = cost;
236 succ->prev = shared_from_this();
237 succ->stopIndex = nextIndex;
238 return succ;
239 }
240 const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(next.nameTag.first, next.nameTag.second);
241 if (next.priority < 0) {
242 // next stop can neither be skipped nor changed
243#ifdef DEBUG_OPTIMIZE_SKIPPED
244 std::cout << " i=" << stopIndex << " next=" << nextIndex << " isMandatory\n";
245#endif
246 return nullptr;
247 }
248 while (altIndex < (int)alternatives.size()) {
249 MSStoppingPlace* alt = alternatives[altIndex];
250 const MSEdge* altEdge = &alt->getLane().getEdge();
251 altIndex++;
252 if (altEdge == next.edge || !alt->getLane().allowsVehicleClass(so.myVehicle->getVClass())) {
253 continue;
254 }
255 auto succ = std::make_shared<StopPathNode>(so, next);
256 succ->trackChanges = trackChanges;
257 succ->pos = alt->getEndLanePosition();
258 succ->skippedPrio = skippedPrio;
259 succ->reachedPrio = reachedPrio;
260 succ->reachedMandatory = reachedMandatory;
261 succ->cost = cost;
262 succ->prev = shared_from_this();
263 succ->stopIndex = nextIndex;
264 succ->origEdge = succ->edge;
265 succ->edge = altEdge;
266 succ->trackChanges += 1;
267 return succ;
268 }
269 skippedPrio += next.priority;
270 if (skippedPrio >= minSkipped) {
271 // cannot improve on current best solution
272#ifdef DEBUG_OPTIMIZE_SKIPPED
273 std::cout << " i=" << stopIndex << " next=" << nextIndex << " skippedPrio=" << skippedPrio << " minSkipped=" << minSkipped << " pruned\n";
274#endif
275 return nullptr;
276 }
277 nextIndex++;
278 altIndex = -1;
279 numSkipped++;
280 }
281#ifdef DEBUG_OPTIMIZE_SKIPPED
282 std::cout << " i=" << stopIndex << " noSuccessors\n";
283#endif
284 return nullptr;
285}
286
287
288bool
289MSStopOptimizer::reachableInTime(const MSEdge* from, double fromPos,
290 const MSEdge* to, double toPos,
291 SUMOTime arrival,
292 ConstMSEdgeVector& into, double &cost) const {
293 myRouter.compute(from, fromPos, to, toPos, myVehicle, myT, into, true);
294 if (into.size() > 0) {
295 cost = myRouter.recomputeCostsPos(into, myVehicle, fromPos, toPos, myT);
296 //std::cout << " from=" << from->getID() << " fromPos=" << fromPos << " to=" << to->getID() << " toPos=" << toPos << " t=" << myT << " cost=" << cost << " arrival=" << arrival << " maxDelay=" << myMaxDelay << "\n";
297 if (myT + TIME2STEPS(cost) <= arrival + myMaxDelay) {
298 return true;
299 }
300 }
301 return false;
302}
303
304
305/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
MSBaseVehicle::StopEdgeInfo StopEdgeInfo
#define SIMSTEP
Definition SUMOTime.h:61
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
A road/street connecting two junctions.
Definition MSEdge.h:77
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition MSLane.h:932
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:769
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:187
const std::vector< MSStoppingPlace * > & getStoppingPlaceAlternatives(const std::string &name, SumoXMLTag category) const
Definition MSNet.cpp:1502
SUMOAbstractRouter< MSEdge, SUMOVehicle > & myRouter
ConstMSEdgeVector optimizeSkipped(const MSEdge *source, double sourcePos, std::vector< StopEdgeInfo > &stops, ConstMSEdgeVector edges) const
bool reachableInTime(const MSEdge *from, double fromPos, const MSEdge *to, double toPos, SUMOTime arrival, ConstMSEdgeVector &into, double &cost) const
MSBaseVehicle * myVehicle
A lane area vehicles can halt at.
double getEndLanePosition() const
Returns the end position of this stop.
const MSLane & getLane() const
Returns the lane this stop is located at.
const std::string & getID() const
Returns the id.
Definition Named.h:74
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
double recomputeCostsPos(const std::vector< const E * > &edges, const V *const v, double fromPos, double toPos, SUMOTime msTime, double *lengthp=nullptr) const
std::pair< std::string, SumoXMLTag > nameTag
optional info about stopping place
int routeIndex
values set during routing and used during optimization
const MSStopOptimizer & so
std::shared_ptr< StopPathNode > prev
std::shared_ptr< StopPathNode > getSuccessor(const std::vector< StopEdgeInfo > &stops, double minSkipped)