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 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 assert(!supercell->contains(follower.first->getToJunction()));
221 std::fill_n(std::back_inserter(followerArcInfo->effortsToBoundaryNodes),
222 minimumArcInfo->effortsToBoundaryNodes.size(), std::numeric_limits<double>::max());
223 }
224
225 double key = std::numeric_limits<double>::max();
226 assert(followerArcInfo->effortsToBoundaryNodes.size() == minimumArcInfo->effortsToBoundaryNodes.size());
227 bool hasImproved = false;
228 // loop over all boundary nodes
229 for (index = 0; index < followerArcInfo->effortsToBoundaryNodes.size(); index++) {
230 // is minEdge a from-edge (i.e., an outgoing boundary edge of the passed cell),
231 // and 'index' not the index of its from-node (i.e., not of the 'own' boundary node)?
232 if (minIsFromEdge && (incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index]) {
233 // if yes, assign the successor edges of the incoming edge of minEdge on the shortest route from
234 // the boundary node with the index 'index' to followersOfIncomingEdge
235 assert((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge)).size()
236 == followerArcInfo->effortsToBoundaryNodes.size());
237 const std::vector<std::pair<const E*, const E*>>& followersOfIncomingEdge
238 = ((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index])->getViaSuccessors(vClass);
239 // is the current follower among said successor edges?
240 bool turningAllowed = false;
241 for (std::pair<const E*, const E*> followerOfIncomingEdge : followersOfIncomingEdge) {
242 if (follower.first == followerOfIncomingEdge.first) {
243 turningAllowed = true;
244 break;
245 }
246 }
247 // if not, then turning from said incoming edge to the current follower is not allowed
248 // and we mustn't propagate the distance to said boundary node
249 // instead simply skip this follower
250 if (!turningAllowed) {
251 continue;
252 }
253 }
254 // propagate distances to other boundary nodes
255 double effortToFollower = minimumArcInfo->effortsToBoundaryNodes[index] == UNREACHABLE ?
256 UNREACHABLE : minimumArcInfo->effortsToBoundaryNodes[index] + effortDelta;
257 if (effortToFollower == UNREACHABLE) {
258 continue; // no need to consider this follower
259 }
260 double time = leaveTime;
261 myEffortProvider->updateViaEdgeCost(follower.second, vehicle, time, effortToFollower, length);
262 if (effortToFollower < key) {
263 key = effortToFollower;
264 }
265 const double oldEffort = followerArcInfo->effortsToBoundaryNodes[index];
266 if (oldEffort != std::numeric_limits<double>::max()) {
267 wasPushedToHeap = true; // must have been pushed to heap during an earlier visit
268 }
269
270 if ((!followerInfo.visited || mayRevisit)
271 && effortToFollower < oldEffort) {
272 hasImproved = true;
273 followerArcInfo->effortsToBoundaryNodes[index] = effortToFollower;
274 }
275 } // end index loop
276
277 if (!hasImproved) {
278 continue; // no need to re-enque this follower, continue w/ next one
279 }
280 followerArcInfo->key = key;
281 if (!wasPushedToHeap) {
282 myFrontierList.push_back(&followerInfo);
283 std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
284 } else {
285 auto fi = std::find(myFrontierList.begin(), myFrontierList.end(), &followerInfo);
286 if (fi == myFrontierList.end()) { // has already been expanded, reinsert into frontier
287 assert(mayRevisit);
288 myFrontierList.push_back(&followerInfo);
289 std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
290 } else {
291 std::push_heap(myFrontierList.begin(), fi + 1, *myComparator);
292 }
293 }
294 } // end follower loop
295 } // end while (!myFrontierList.empty())
296
297#ifdef CSPT_DEBUG_LEVEL_0
298 std::cout << "centralizedSPTree finished (queue empty)." << std::endl;
299#endif
300 return true;
301 }
302
303protected:
309 void init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime);
312 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontierList;
314 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFound;
316 std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
319 std::vector<ArcInfo*>& myArcInfos;
332};
333
334// ===========================================================================
335// method definitions
336// ===========================================================================
337
338template<class E, class N, class V>
339void AFCentralizedSPTree<E, N, V>::init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime) {
340 // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
341 for (auto& edgeInfo : myFrontierList) {
342 edgeInfo->reset();
343 }
344 myFrontierList.clear();
345 for (auto& edgeInfo : myFound) {
346 edgeInfo->reset();
347 }
348 for (auto& arcInfo : myArcInfos) {
349 arcInfo->reset(); // does not reset effortsToBoundaryNodes
350 }
351 myFound.clear();
352 for (const E* from : fromEdges) {
353 if (from->isInternal()) {
354 continue;
355 }
356 int edgeID = from->getNumericalID();
357 auto& fromInfo = myEdgeInfos[edgeID];
358 if (fromInfo.prohibited || isProhibited(from, vehicle)) {
359 continue;
360 }
361 fromInfo.heuristicEffort = 0.;
362 fromInfo.prev = nullptr;
363 fromInfo.leaveTime = STEPS2TIME(msTime);
364 myFrontierList.push_back(&fromInfo);
365 ArcInfo* fromArcInfo = myArcInfos[edgeID];
366 fromArcInfo->key = 0;
367 }
368}
#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.