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 double bestCost = myRouter.recomputeCostsPos(edges, myVehicle, sourcePos, 0, myT);
40 std::vector<int> skipped;
41
42 // each upcoming stop is part of a graph where we can start to search for a
43 // better solution. We evaluate followers lazily and prune based on the best
44 // solution already found
45 std::priority_queue<std::shared_ptr<StopPathNode>, std::vector<std::shared_ptr<StopPathNode> >, spnCompare> queue;
46
47 auto prev = std::make_shared<StopPathNode>(*this, StopEdgeInfo(source, -1, SIMSTEP, sourcePos));
48 std::shared_ptr<StopPathNode> bestNode = prev;
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 if (bestNode->stopIndex < 0) {
178 // all stops were skipped. End route on current edge
179 bestEdges.push_back(source);
180 }
181 while (bestNode != nullptr && bestNode->stopIndex >= 0) {
182#ifdef DEBUG_OPTIMIZE_SKIPPED
183 std::cout << " revBestNode index=" << bestNode->stopIndex << " edge=" << bestNode->edge->getID() << " name=" << bestNode->nameTag.first << " tc=" << bestNode->trackChanges << " c=" << bestNode->cost << "\n";
184#endif
185 stops[bestNode->stopIndex].skipped = false;
186 stops[bestNode->stopIndex].backtracked = false;
187 stops[bestNode->stopIndex].origEdge = bestNode->origEdge;
188 if (!bestEdges.empty() && !bestNode->edges.empty()) {
189 bestNode->edges.pop_back();
190 }
191 bestEdges.insert(bestEdges.begin(), bestNode->edges.begin(), bestNode->edges.end());
192 bestNode = bestNode->prev;
193 }
194#ifdef DEBUG_OPTIMIZE_SKIPPED
195 std::cout << "oldEdges=" << toString(edges) << "\nnewEdges=" << toString(bestEdges) << "\n";
196#endif
197 return bestEdges;
198}
199
200
201std::shared_ptr<MSStopOptimizer::StopPathNode>
202MSStopOptimizer::StopPathNode::getSuccessor(const std::vector<StopEdgeInfo>& stops, double minSkipped) {
203 if (!checked) {
204 checked = true;
205 // @todo caching, bulk-routing
206 double newCost = 0;
207 if (!so.reachableInTime(prev->edge, prev->pos, edge, pos, arrival, edges, newCost)) {
208#ifdef DEBUG_OPTIMIZE_SKIPPED
209 std::cout << " prevIndex=" << prev->stopIndex << " prevEdge=" << prev->edge->getID() << " i=" << stopIndex << " edge=" << edge->getID() << " unreachable\n";
210#endif
211 // indicate failure
212 reachedMandatory = -1;
213 return nullptr;
214 } else {
215#ifdef DEBUG_OPTIMIZE_SKIPPED
216 std::cout << " prevIndex=" << prev->stopIndex << " prevEdge=" << prev->edge->getID() << " i=" << stopIndex << " edge=" << edge->getID() << " reached with edges=" << toString(edges) << " cost=" << cost << " newCost=" << newCost << "\n";
217#endif
218 }
219 reachedPrio += MAX2(0.0, priority);
220 cost += newCost;
221 if (priority < 0) {
223 }
224 }
225 int nextIndex = stopIndex + numSkipped + 1;
226 while (nextIndex < (int)stops.size()) {
227 const StopEdgeInfo& next = stops[nextIndex];
228#ifdef DEBUG_OPTIMIZE_SKIPPED
229 std::cout << " i=" << stopIndex << " next=" << nextIndex << " numSkipped=" << numSkipped << " altIndex=" << altIndex << "\n";
230#endif
231 // always try the default track first
232 if (altIndex == -1) {
233 altIndex++;
234 auto succ = std::make_shared<StopPathNode>(so, next);
235 succ->skippedPrio = skippedPrio;
236 succ->reachedPrio = reachedPrio;
237 succ->reachedMandatory = reachedMandatory;
238 succ->trackChanges = trackChanges;
239 succ->cost = cost;
240 succ->prev = shared_from_this();
241 succ->stopIndex = nextIndex;
242 return succ;
243 }
244 const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(next.nameTag.first, next.nameTag.second);
245 if (next.priority < 0) {
246 // next stop can neither be skipped nor changed
247#ifdef DEBUG_OPTIMIZE_SKIPPED
248 std::cout << " i=" << stopIndex << " next=" << nextIndex << " isMandatory\n";
249#endif
250 return nullptr;
251 }
252 while (altIndex < (int)alternatives.size()) {
253 MSStoppingPlace* alt = alternatives[altIndex];
254 const MSEdge* altEdge = &alt->getLane().getEdge();
255 altIndex++;
256 if (altEdge == next.edge || !alt->getLane().allowsVehicleClass(so.myVehicle->getVClass())) {
257 continue;
258 }
259 auto succ = std::make_shared<StopPathNode>(so, next);
260 succ->trackChanges = trackChanges;
261 succ->pos = alt->getEndLanePosition();
262 succ->skippedPrio = skippedPrio;
263 succ->reachedPrio = reachedPrio;
264 succ->reachedMandatory = reachedMandatory;
265 succ->cost = cost;
266 succ->prev = shared_from_this();
267 succ->stopIndex = nextIndex;
268 succ->origEdge = succ->edge;
269 succ->edge = altEdge;
270 succ->trackChanges += 1;
271 return succ;
272 }
273 skippedPrio += next.priority;
274 if (skippedPrio >= minSkipped) {
275 // cannot improve on current best solution
276#ifdef DEBUG_OPTIMIZE_SKIPPED
277 std::cout << " i=" << stopIndex << " next=" << nextIndex << " skippedPrio=" << skippedPrio << " minSkipped=" << minSkipped << " pruned\n";
278#endif
279 return nullptr;
280 }
281 nextIndex++;
282 altIndex = -1;
283 numSkipped++;
284 }
285#ifdef DEBUG_OPTIMIZE_SKIPPED
286 std::cout << " i=" << stopIndex << " noSuccessors\n";
287#endif
288 return nullptr;
289}
290
291
292bool
293MSStopOptimizer::reachableInTime(const MSEdge* from, double fromPos,
294 const MSEdge* to, double toPos,
295 SUMOTime arrival,
296 ConstMSEdgeVector& into, double &cost) const {
297 myRouter.compute(from, fromPos, to, toPos, myVehicle, myT, into, true);
298 if (into.size() > 0) {
299 cost = myRouter.recomputeCostsPos(into, myVehicle, fromPos, toPos, myT);
300 //std::cout << " from=" << from->getID() << " fromPos=" << fromPos << " to=" << to->getID() << " toPos=" << toPos << " t=" << myT << " cost=" << cost << " arrival=" << arrival << " maxDelay=" << myMaxDelay << "\n";
301 if (myT + TIME2STEPS(cost) <= arrival + myMaxDelay) {
302 return true;
303 }
304 }
305 return false;
306}
307
308
309/****************************************************************************/
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:935
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)