Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
AFCentralizedSPTree.h
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2012-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// Class for a label-correcting algorithm calculating multiple shortest path
19// trees at once (centralized shortest path tree, cf. Hilger et al.)
20// Used for setting the arc flags for the arc flag router
21// @note Intended use is on a backward graph with flipped edges
22/****************************************************************************/
23#pragma once
24#include <config.h>
25
26#include <cassert>
27#include <string>
28#include <functional>
29#include <vector>
30#include <set>
31#include <limits>
32#include <algorithm>
33#include <iterator>
34#include <map>
35#include <iostream>
36#include <memory>
37#include <stdexcept>
38#include <cstddef>
46#include "SUMOAbstractRouter.h"
47#include "KDTreePartition.h"
48#include "AFInfo.h"
49
50//#define CSPT_WRITE_QGIS_FILTERS
51//#define CSPT_DEBUG_LEVEL_0
52
53template<class E, class N, class V>
55public:
57 typedef typename AFInfo<E>::ArcInfo ArcInfo;
58
60 public:
64 EdgeInfoComparator(std::vector<ArcInfo*>& arcInfos) : myArcInfos(arcInfos) {
65 }
66
73 bool operator()(const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo1,
74 const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo2) const {
75 int index1 = edgeInfo1->edge->getNumericalID();
76 int index2 = edgeInfo2->edge->getNumericalID();
77 ArcInfo* arcInfo1 = myArcInfos[index1];
78 ArcInfo* arcInfo2 = myArcInfos[index2];
79 double key1 = arcInfo1->key;
80 double key2 = arcInfo2->key;
81
82 if (key1 == key2) { // tie
83 return index1 > index2;
84 }
85 return key1 > key2;
86 }
87 private:
88 std::vector<ArcInfo*>& myArcInfos;
89 };
90
99 AFCentralizedSPTree(const std::vector<E*>& edges, std::vector<ArcInfo*>& arcInfos, bool unbuildIsWarning,
100 SUMOAbstractRouter<E, V>* effortProvider,
101 const bool havePermissions = false, const bool haveRestrictions = false) :
102 myArcInfos(arcInfos),
103 myHavePermissions(havePermissions),
104 myHaveRestrictions(haveRestrictions),
105 myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
106 myEffortProvider(effortProvider),
107 myMaxSpeed(NUMERICAL_EPS) {
108 for (const E* const edge : edges) {
109 myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(edge));
110 myMaxSpeed = MAX2(myMaxSpeed, edge->getSpeedLimit() * MAX2(1.0, edge->getLengthGeometryFactor()));
111 }
113 }
114
117 delete myComparator;
118 }
119
125 bool isProhibited(const E* const edge, const V* const vehicle) const {
126 return (myHavePermissions && edge->prohibits(vehicle)) || (myHaveRestrictions && edge->restricts(vehicle));
127 }
128
138 bool computeCentralizedSPTree(SUMOTime msTime, const Cell* cell, const V* const vehicle,
139 const std::map<const E*, std::vector<const E*>>& incomingEdgesOfOutgoingBoundaryEdges,
140 bool silent = false) {
141 assert(cell != nullptr);
142 const std::unordered_set<const E*>& fromEdges = cell->getOutgoingBoundaryEdges();
143 if (fromEdges.empty()) { // nothing to do here
144 return false;
145 }
146 double length = 0.; // dummy for the via edge cost update
147 const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
148 std::vector<const E*> fromEdgesAsVector(fromEdges.begin(), fromEdges.end());
149 init(fromEdgesAsVector, vehicle, msTime);
150 size_t numberOfVisitedFromEdges = 0;
151 bool minIsFromEdge = false;
152#ifdef CSPT_DEBUG_LEVEL_0
153 size_t numberOfTouchedSupercellEdges = 0;
154 int num_visited = 0;
155#endif
156#ifdef _DEBUG
157 const Cell* supercell = cell->getSupercell();
158#endif
159 const bool mayRevisit = true;
160
161 while (!myFrontierList.empty()) {
162#ifdef CSPT_DEBUG_LEVEL_0
163 num_visited += 1;
164#endif
165 // use the edge with the minimal length
166 typename SUMOAbstractRouter<E, V>::EdgeInfo* minimumInfo = myFrontierList.front();
167 const E* const minEdge = minimumInfo->edge;
168 assert(!minEdge->isInternal());
169 ArcInfo* minimumArcInfo = myArcInfos[minEdge->getNumericalID()];
170 if (minimumInfo->visited || numberOfVisitedFromEdges < fromEdges.size()) {
171 minIsFromEdge = incomingEdgesOfOutgoingBoundaryEdges.find(minEdge) != incomingEdgesOfOutgoingBoundaryEdges.end();
172 } else {
173 minIsFromEdge = false;
174 }
175 if (minIsFromEdge) {
176 if (numberOfVisitedFromEdges < fromEdges.size()) {
177 numberOfVisitedFromEdges++;
178 }
179 }
180 assert(incomingEdgesOfOutgoingBoundaryEdges.size() == fromEdges.size());
181 assert(minimumArcInfo->key != std::numeric_limits<double>::max() && minimumArcInfo->key != UNREACHABLE);
182 size_t index;
183#ifdef CSPT_DEBUG_LEVEL_0
184 if (supercell->contains(minEdge->getToJunction())) {
185 // minEdge is a supercell edge (we check for the to-node since we work on a backward graph)
186 if (!minimumArcInfo->touched) {
187 numberOfTouchedSupercellEdges++;
188 minimumArcInfo->touched = true;
189 }
190 }
191#endif
192#ifdef CSPT_DEBUG_LEVEL_0
193 if (num_visited % 500 == 0) {
194 std::cout << "num_visited: " << num_visited << ", numberOfTouchedSupercellEdges: " << numberOfTouchedSupercellEdges
195 << ", minimumArcInfo->key: " << minimumArcInfo->key << std::endl;
196 }
197#endif
198 std::pop_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
199 myFrontierList.pop_back();
200 myFound.push_back(minimumInfo);
201 minimumInfo->visited = true;
202 const double effortDelta = myEffortProvider->getEffort(minEdge, vehicle, minimumInfo->leaveTime);
203 const double leaveTime = minimumInfo->leaveTime + myEffortProvider->getTravelTime(minEdge, vehicle, minimumInfo->leaveTime, effortDelta);
204
205 // check all ways from the edge with the minimal length
206 for (const std::pair<const E*, const E*>& follower : minEdge->getViaSuccessors(vClass)) {
207 assert(!follower.first->isInternal());
208 bool wasPushedToHeap = false;
209 auto& followerInfo = myEdgeInfos[follower.first->getNumericalID()];
210 ArcInfo* followerArcInfo = myArcInfos[follower.first->getNumericalID()];
211 // check whether it can be used
212 if (followerInfo.prohibited || isProhibited(follower.first, vehicle)) {
213 if (!silent) {
214 myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on source edge '" + followerInfo.edge->getID() + "'.");
215 }
216 continue;
217 }
218
219 if (followerArcInfo->effortsToBoundaryNodes.empty()) { // non-initialized non-supercell edge
220#ifdef _DEBUG
221 assert(!supercell->contains(follower.first->getToJunction()));
222#endif
223 std::fill_n(std::back_inserter(followerArcInfo->effortsToBoundaryNodes),
224 minimumArcInfo->effortsToBoundaryNodes.size(), std::numeric_limits<double>::max());
225 }
226
227 double key = std::numeric_limits<double>::max();
228 assert(followerArcInfo->effortsToBoundaryNodes.size() == minimumArcInfo->effortsToBoundaryNodes.size());
229 bool hasImproved = false;
230 // loop over all boundary nodes
231 for (index = 0; index < followerArcInfo->effortsToBoundaryNodes.size(); index++) {
232 // is minEdge a from-edge (i.e., an outgoing boundary edge of the passed cell),
233 // and 'index' not the index of its from-node (i.e., not of the 'own' boundary node)?
234 if (minIsFromEdge && (incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index]) {
235 // if yes, assign the successor edges of the incoming edge of minEdge on the shortest route from
236 // the boundary node with the index 'index' to followersOfIncomingEdge
237 assert((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge)).size()
238 == followerArcInfo->effortsToBoundaryNodes.size());
239 const std::vector<std::pair<const E*, const E*>>& followersOfIncomingEdge
240 = ((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index])->getViaSuccessors(vClass);
241 // is the current follower among said successor edges?
242 bool turningAllowed = false;
243 for (std::pair<const E*, const E*> followerOfIncomingEdge : followersOfIncomingEdge) {
244 if (follower.first == followerOfIncomingEdge.first) {
245 turningAllowed = true;
246 break;
247 }
248 }
249 // if not, then turning from said incoming edge to the current follower is not allowed
250 // and we mustn't propagate the distance to said boundary node
251 // instead simply skip this follower
252 if (!turningAllowed) {
253 continue;
254 }
255 }
256 // propagate distances to other boundary nodes
257 double effortToFollower = minimumArcInfo->effortsToBoundaryNodes[index] == UNREACHABLE ?
258 UNREACHABLE : minimumArcInfo->effortsToBoundaryNodes[index] + effortDelta;
259 if (effortToFollower == UNREACHABLE) {
260 continue; // no need to consider this follower
261 }
262 double time = leaveTime;
263 myEffortProvider->updateViaEdgeCost(follower.second, vehicle, time, effortToFollower, length);
264 if (effortToFollower < key) {
265 key = effortToFollower;
266 }
267 const double oldEffort = followerArcInfo->effortsToBoundaryNodes[index];
268 if (oldEffort != std::numeric_limits<double>::max()) {
269 wasPushedToHeap = true; // must have been pushed to heap during an earlier visit
270 }
271
272 if ((!followerInfo.visited || mayRevisit)
273 && effortToFollower < oldEffort) {
274 hasImproved = true;
275 followerArcInfo->effortsToBoundaryNodes[index] = effortToFollower;
276 }
277 } // end index loop
278
279 if (!hasImproved) {
280 continue; // no need to re-enque this follower, continue w/ next one
281 }
282 followerArcInfo->key = key;
283 if (!wasPushedToHeap) {
284 myFrontierList.push_back(&followerInfo);
285 std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
286 } else {
287 auto fi = std::find(myFrontierList.begin(), myFrontierList.end(), &followerInfo);
288 if (fi == myFrontierList.end()) { // has already been expanded, reinsert into frontier
289 assert(mayRevisit);
290 myFrontierList.push_back(&followerInfo);
291 std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
292 } else {
293 std::push_heap(myFrontierList.begin(), fi + 1, *myComparator);
294 }
295 }
296 } // end follower loop
297 } // end while (!myFrontierList.empty())
298
299#ifdef CSPT_DEBUG_LEVEL_0
300 std::cout << "centralizedSPTree finished (queue empty)." << std::endl;
301#endif
302 return true;
303 }
304
305protected:
311 void init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime);
314 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontierList;
316 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFound;
318 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
321 std::vector<ArcInfo*>& myArcInfos;
334};
335
336// ===========================================================================
337// method definitions
338// ===========================================================================
339
340template<class E, class N, class V>
341void AFCentralizedSPTree<E, N, V>::init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime) {
342 // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
343 for (auto& edgeInfo : myFrontierList) {
344 edgeInfo->reset();
345 }
346 myFrontierList.clear();
347 for (auto& edgeInfo : myFound) {
348 edgeInfo->reset();
349 }
350 for (auto& arcInfo : myArcInfos) {
351 arcInfo->reset(); // does not reset effortsToBoundaryNodes
352 }
353 myFound.clear();
354 for (const E* from : fromEdges) {
355 if (from->isInternal()) {
356 continue;
357 }
358 int edgeID = from->getNumericalID();
359 auto& fromInfo = myEdgeInfos[edgeID];
360 if (fromInfo.prohibited || isProhibited(from, vehicle)) {
361 continue;
362 }
363 fromInfo.heuristicEffort = 0.;
364 fromInfo.prev = nullptr;
365 fromInfo.leaveTime = STEPS2TIME(msTime);
366 myFrontierList.push_back(&fromInfo);
367 ArcInfo* fromArcInfo = myArcInfos[edgeID];
368 fromArcInfo->key = 0;
369 }
370}
#define UNREACHABLE
Definition AFRouter.h:50
long long int SUMOTime
Definition GUI.h:36
#define STEPS2TIME(x)
Definition SUMOTime.h:55
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_IGNORING
vehicles ignoring classes
T MAX2(T a, T b)
Definition StdDefs.h:86
EdgeInfoComparator(std::vector< ArcInfo * > &arcInfos)
Constructor.
bool operator()(const typename SUMOAbstractRouter< E, V >::EdgeInfo *edgeInfo1, const typename SUMOAbstractRouter< E, V >::EdgeInfo *edgeInfo2) const
Comparing method.
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo > myEdgeInfos
The container of edge information.
const bool myHaveRestrictions
The boolean flag indicating whether edge restrictions need to be considered or not.
~AFCentralizedSPTree()
Destructor.
double myMaxSpeed
The maximum speed in the network.
MsgHandler *const myErrorMsgHandler
The handler for routing errors.
std::vector< ArcInfo * > & myArcInfos
The edge informations specific to arc flag routing.
bool isProhibited(const E *const edge, const V *const vehicle) const
Returns true iff driving the given vehicle on the given edge is prohibited.
AFInfo< E >::ArcInfo ArcInfo
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo * > myFound
The list of visited edges (for resetting).
void init(std::vector< const E * > fromEdges, const V *const vehicle, SUMOTime msTime)
Initialize the arc flag router.
SUMOAbstractRouter< E, V > * myEffortProvider
The object's operation to perform.
EdgeInfoComparator * myComparator
The comparator.
bool computeCentralizedSPTree(SUMOTime msTime, const Cell *cell, const V *const vehicle, const std::map< const E *, std::vector< const E * > > &incomingEdgesOfOutgoingBoundaryEdges, bool silent=false)
Computes a shortest path tree for each boundary edge of the given cell, returns true iff this was suc...
KDTreePartition< E, N, V >::Cell Cell
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo * > myFrontierList
The min edge heap.
AFCentralizedSPTree(const std::vector< E * > &edges, std::vector< ArcInfo * > &arcInfos, bool unbuildIsWarning, SUMOAbstractRouter< E, V > *effortProvider, const bool havePermissions=false, const bool haveRestrictions=false)
Constructor.
const bool myHavePermissions
The boolean flag indicating whether edge permissions need to be considered or not.
double key
The key for sorting the heap.
Definition AFInfo.h:109
bool touched
The flag indicating whether the edge has already been touched or not.
Definition AFInfo.h:111
std::vector< double > effortsToBoundaryNodes
The efforts to boundary nodes.
Definition AFInfo.h:151
Represents an element of the node partition (i.e. a node set).
bool contains(const N *node) const
Tests whether the given node belongs to the cell.
const std::unordered_set< const E * > & getOutgoingBoundaryEdges() const
Returns the set of outgoing boundary edges.
const Cell * getSupercell() const
Returns the supercell.
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:67
bool visited
whether the edge was already evaluated
const E *const edge
The current edge.
double leaveTime
The time the vehicle leaves the edge.