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-2024 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 int num_visited = 0;
151 size_t numberOfVisitedFromEdges = 0;
152 bool minIsFromEdge = false;
153#ifdef CSPT_DEBUG_LEVEL_0
154 size_t numberOfTouchedSupercellEdges = 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 num_visited += 1;
163 // use the edge with the minimal length
164 typename SUMOAbstractRouter<E, V>::EdgeInfo* minimumInfo = myFrontierList.front();
165 const E* const minEdge = minimumInfo->edge;
166 assert(!minEdge->isInternal());
167 ArcInfo* minimumArcInfo = myArcInfos[minEdge->getNumericalID()];
168 if (minimumInfo->visited || numberOfVisitedFromEdges < fromEdges.size()) {
169 minIsFromEdge = incomingEdgesOfOutgoingBoundaryEdges.find(minEdge) != incomingEdgesOfOutgoingBoundaryEdges.end();
170 } else {
171 minIsFromEdge = false;
172 }
173 if (minIsFromEdge) {
174 if (numberOfVisitedFromEdges < fromEdges.size()) {
175 numberOfVisitedFromEdges++;
176 }
177 }
178 assert(incomingEdgesOfOutgoingBoundaryEdges.size() == fromEdges.size());
179 assert(minimumArcInfo->key != std::numeric_limits<double>::max() && minimumArcInfo->key != UNREACHABLE);
180 size_t index;
181#ifdef CSPT_DEBUG_LEVEL_0
182 if (supercell->contains(minEdge->getToJunction())) {
183 // minEdge is a supercell edge (we check for the to-node since we work on a backward graph)
184 if (!minimumArcInfo->touched) {
185 numberOfTouchedSupercellEdges++;
186 minimumArcInfo->touched = true;
187 }
188 }
189#endif
190#ifdef CSPT_DEBUG_LEVEL_0
191 if (num_visited % 500 == 0) {
192 std::cout << "num_visited: " << num_visited << ", numberOfTouchedSupercellEdges: " << numberOfTouchedSupercellEdges
193 << ", minimumArcInfo->key: " << minimumArcInfo->key << std::endl;
194 }
195#endif
196 std::pop_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
197 myFrontierList.pop_back();
198 myFound.push_back(minimumInfo);
199 minimumInfo->visited = true;
200 const double effortDelta = myEffortProvider->getEffort(minEdge, vehicle, minimumInfo->leaveTime);
201 const double leaveTime = minimumInfo->leaveTime + myEffortProvider->getTravelTime(minEdge, vehicle, minimumInfo->leaveTime, effortDelta);
202
203 // check all ways from the edge with the minimal length
204 for (const std::pair<const E*, const E*>& follower : minEdge->getViaSuccessors(vClass)) {
205 assert(!follower.first->isInternal());
206 bool wasPushedToHeap = false;
207 auto& followerInfo = myEdgeInfos[follower.first->getNumericalID()];
208 ArcInfo* followerArcInfo = myArcInfos[follower.first->getNumericalID()];
209 // check whether it can be used
210 if (followerInfo.prohibited || isProhibited(follower.first, vehicle)) {
211 if (!silent) {
212 myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on source edge '" + followerInfo.edge->getID() + "'.");
213 }
214 continue;
215 }
216
217 if (followerArcInfo->effortsToBoundaryNodes.empty()) { // non-initialized non-supercell edge
218 assert(!supercell->contains(follower.first->getToJunction()));
219 std::fill_n(std::back_inserter(followerArcInfo->effortsToBoundaryNodes),
220 minimumArcInfo->effortsToBoundaryNodes.size(), std::numeric_limits<double>::max());
221 }
222
223 double key = std::numeric_limits<double>::max();
224 assert(followerArcInfo->effortsToBoundaryNodes.size() == minimumArcInfo->effortsToBoundaryNodes.size());
225 bool hasImproved = false;
226 // loop over all boundary nodes
227 for (index = 0; index < followerArcInfo->effortsToBoundaryNodes.size(); index++) {
228 // is minEdge a from-edge (i.e., an outgoing boundary edge of the passed cell),
229 // and 'index' not the index of its from-node (i.e., not of the 'own' boundary node)?
230 if (minIsFromEdge && (incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index]) {
231 // if yes, assign the successor edges of the incoming edge of minEdge on the shortest route from
232 // the boundary node with the index 'index' to followersOfIncomingEdge
233 assert((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge)).size()
234 == followerArcInfo->effortsToBoundaryNodes.size());
235 const std::vector<std::pair<const E*, const E*>>& followersOfIncomingEdge
236 = ((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index])->getViaSuccessors(vClass);
237 // is the current follower among said successor edges?
238 bool turningAllowed = false;
239 for (std::pair<const E*, const E*> followerOfIncomingEdge : followersOfIncomingEdge) {
240 if (follower.first == followerOfIncomingEdge.first) {
241 turningAllowed = true;
242 break;
243 }
244 }
245 // if not, then turning from said incoming edge to the current follower is not allowed
246 // and we mustn't propagate the distance to said boundary node
247 // instead simply skip this follower
248 if (!turningAllowed) {
249 continue;
250 }
251 }
252 // propagate distances to other boundary nodes
253 double effortToFollower = minimumArcInfo->effortsToBoundaryNodes[index] == UNREACHABLE ?
254 UNREACHABLE : minimumArcInfo->effortsToBoundaryNodes[index] + effortDelta;
255 if (effortToFollower == UNREACHABLE) {
256 continue; // no need to consider this follower
257 }
258 double time = leaveTime;
259 myEffortProvider->updateViaEdgeCost(follower.second, vehicle, time, effortToFollower, length);
260 if (effortToFollower < key) {
261 key = effortToFollower;
262 }
263 const double oldEffort = followerArcInfo->effortsToBoundaryNodes[index];
264 if (oldEffort != std::numeric_limits<double>::max()) {
265 wasPushedToHeap = true; // must have been pushed to heap during an earlier visit
266 }
267
268 if ((!followerInfo.visited || mayRevisit)
269 && effortToFollower < oldEffort) {
270 hasImproved = true;
271 followerArcInfo->effortsToBoundaryNodes[index] = effortToFollower;
272 }
273 } // end index loop
274
275 if (!hasImproved) {
276 continue; // no need to re-enque this follower, continue w/ next one
277 }
278 followerArcInfo->key = key;
279 if (!wasPushedToHeap) {
280 myFrontierList.push_back(&followerInfo);
281 std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
282 } else {
283 auto fi = std::find(myFrontierList.begin(), myFrontierList.end(), &followerInfo);
284 if (fi == myFrontierList.end()) { // has already been expanded, reinsert into frontier
285 assert(mayRevisit);
286 myFrontierList.push_back(&followerInfo);
287 std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
288 } else {
289 std::push_heap(myFrontierList.begin(), fi + 1, *myComparator);
290 }
291 }
292 } // end follower loop
293 } // end while (!myFrontierList.empty())
294
295#ifdef CSPT_DEBUG_LEVEL_0
296 std::cout << "centralizedSPTree finished (queue empty)." << std::endl;
297#endif
298 return true;
299 }
300
301protected:
307 void init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime);
310 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontierList;
312 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFound;
314 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
317 std::vector<ArcInfo*>& myArcInfos;
330};
331
332// ===========================================================================
333// method definitions
334// ===========================================================================
335
336template<class E, class N, class V>
337void AFCentralizedSPTree<E, N, V>::init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime) {
338 // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
339 for (auto& edgeInfo : myFrontierList) {
340 edgeInfo->reset();
341 }
342 myFrontierList.clear();
343 for (auto& edgeInfo : myFound) {
344 edgeInfo->reset();
345 }
346 for (auto& arcInfo : myArcInfos) {
347 arcInfo->reset(); // does not reset effortsToBoundaryNodes
348 }
349 myFound.clear();
350 for (const E* from : fromEdges) {
351 if (from->isInternal()) {
352 continue;
353 }
354 int edgeID = from->getNumericalID();
355 auto& fromInfo = myEdgeInfos[edgeID];
356 if (fromInfo.prohibited || isProhibited(from, vehicle)) {
357 continue;
358 }
359 fromInfo.heuristicEffort = 0.;
360 fromInfo.prev = nullptr;
361 fromInfo.leaveTime = STEPS2TIME(msTime);
362 myFrontierList.push_back(&fromInfo);
363 ArcInfo* fromArcInfo = myArcInfos[edgeID];
364 fromArcInfo->key = 0;
365 }
366}
#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:82
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.
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
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.