Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
DijkstraRouter.h
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/****************************************************************************/
20// Dijkstra shortest path algorithm using travel time or other values
21/****************************************************************************/
22#pragma once
23#include <config.h>
24
25#include <cassert>
26#include <string>
27#include <functional>
28#include <vector>
29#include <set>
30#include <limits>
31#include <algorithm>
32#include <iterator>
36#include "EffortCalculator.h"
37#include "SUMOAbstractRouter.h"
38
39//#define DijkstraRouter_DEBUG_QUERY
40//#define DijkstraRouter_DEBUG_QUERY_FRONTIER
41//#define DijkstraRouter_DEBUG_QUERY_VISITED
42//#define DijkstraRouter_DEBUG_QUERY_PERF
43//#define DijkstraRouter_DEBUG_BULKMODE
44
45#define DijkstraRouter_DEBUG_QUERY_VISITED_OUT std::cerr
46
47// ===========================================================================
48// class definitions
49// ===========================================================================
63template<class E, class V>
64class DijkstraRouter : public SUMOAbstractRouter<E, V> {
65public:
71 public:
73 bool operator()(const typename SUMOAbstractRouter<E, V>::EdgeInfo* nod1, const typename SUMOAbstractRouter<E, V>::EdgeInfo* nod2) const {
74 if (nod1->effort == nod2->effort) {
75 return nod1->edge->getNumericalID() > nod2->edge->getNumericalID();
76 }
77 return nod1->effort > nod2->effort;
78 }
79 };
80
81
83 DijkstraRouter(const std::vector<E*>& edges, bool unbuildIsWarning, typename SUMOAbstractRouter<E, V>::Operation effortOperation,
84 typename SUMOAbstractRouter<E, V>::Operation ttOperation = nullptr, bool silent = false, EffortCalculator* calc = nullptr,
85 const bool havePermissions = false, const bool haveRestrictions = false) :
86 SUMOAbstractRouter<E, V>("DijkstraRouter", unbuildIsWarning, effortOperation, ttOperation, havePermissions, haveRestrictions),
87 mySilent(silent), myExternalEffort(calc) {
88 for (typename std::vector<E*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
89 this->myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(*i));
90 }
91 }
92
94 virtual ~DijkstraRouter() { }
95
103
106 bool compute(const E* from, const E* to, const V* const vehicle,
107 SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
108 assert(from != nullptr && (vehicle == nullptr || to != nullptr));
109 // check whether from and to can be used
110 if (this->isProhibited(from, vehicle, STEPS2TIME(msTime))) {
111 if (!silent) {
112 this->myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on source edge '" + from->getID() + "'.");
113 }
114 return false;
115 }
116 // technically, a temporary permission might be lifted by the time of arrival
117 if (to != nullptr && this->isProhibited(to, vehicle, STEPS2TIME(msTime))) {
118 if (!silent) {
119 this->myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on destination edge '" + to->getID() + "'.");
120 }
121 return false;
122 }
123 double length = 0.; // dummy for the via edge cost update
124 this->startQuery();
125#ifdef DijkstraRouter_DEBUG_QUERY
126 std::cout << "DEBUG: starting search for '" << Named::getIDSecure(vehicle) << "' from '" << Named::getIDSecure(from) << "' to '" << Named::getIDSecure(to) << "' time: " << STEPS2TIME(msTime) << "\n";
127#endif
128 const SUMOVehicleClass vClass = vehicle == nullptr ? SVC_IGNORING : vehicle->getVClass();
129 const bool ignoreTransient = vehicle == nullptr ? false : vehicle->ignoreTransientPermissions();
130 std::tuple<const E*, const V*, SUMOTime> query = std::make_tuple(from, vehicle, msTime);
131 if ((this->myBulkMode || (this->myAutoBulkMode && query == myLastQuery)) && !this->myAmClean) {
132#ifdef DijkstraRouter_DEBUG_BULKMODE
133 if (query != myLastQuery) {
134 std::cout << " invalid bulk mode. myLastQuery="
135 << std::get<0>(myLastQuery)->getID() << ","
136 << std::get<1>(myLastQuery)->getID() << ","
137 << time2string(std::get<2>(myLastQuery))
138 << " query="
139 << std::get<0>(query)->getID() << ","
140 << std::get<1>(query)->getID() << ","
141 << time2string(std::get<2>(query))
142 << "\n";
143 } else {
144 std::cout << " using bulk mode\n";
145 }
146#endif
147 const auto& toInfo = this->myEdgeInfos[to->getNumericalID()];
148 if (toInfo.visited) {
149 this->buildPathFrom(&toInfo, into);
150 this->endQuery(1);
151#ifdef DijkstraRouter_DEBUG_QUERY_PERF
152 std::cout << " instant bulk success for vehicle " << vehicle->getID() << "\n";
153#endif
154 return true;
155 }
156 } else {
157 this->init(from->getNumericalID(), msTime);
158 if (myExternalEffort != nullptr) {
159 myExternalEffort->setInitialState(from->getNumericalID());
160 }
161 this->myAmClean = false;
162 }
163 myLastQuery = query;
164 // loop
165 int num_visited = 0;
166#ifdef DijkstraRouter_DEBUG_QUERY_VISITED
167 DijkstraRouter_DEBUG_QUERY_VISITED_OUT << "<edgeData>\n <interval begin=\"" << time2string(msTime) << "\" end=\"" << toString(msTime + 1000) << "\" id=\"" << Named::getIDSecure(vehicle) << "\">\n";
168#endif
169 while (!this->myFrontierList.empty()) {
170 num_visited += 1;
171 // use the node with the minimal length
172 auto* const minimumInfo = this->myFrontierList.front();
173 const E* const minEdge = minimumInfo->edge;
174#ifdef DijkstraRouter_DEBUG_QUERY
175 std::cout << "DEBUG: hit=" << minEdge->getID()
176 << " TT=" << minimumInfo->effort
177 << " EF=" << this->getEffort(minEdge, vehicle, minimumInfo->leaveTime)
178 << " Leave: " << minimumInfo->leaveTime << " Q: ";
179#ifdef DijkstraRouter_DEBUG_QUERY_FRONTIER
180 for (const auto& edgeInfo : this->myFrontierList) {
181 std::cout << "\n " << edgeInfo->effort << ", " << edgeInfo->edge->getID();
182 }
183#endif
184 std::cout << "\n";
185#endif
186#ifdef DijkstraRouter_DEBUG_QUERY_VISITED
187 DijkstraRouter_DEBUG_QUERY_VISITED_OUT << " <edge id=\"" << minEdge->getID() << "\" index=\"" << num_visited << "\" cost=\"" << minimumInfo->effort << "\" time=\"" << minimumInfo->leaveTime << "\"/>\n";
188#endif
189 minimumInfo->visited = true;
190 // check whether the destination node was already reached
191 if (minEdge == to) {
192 //propagate last external effort state to destination edge
193 if (myExternalEffort != nullptr) {
194 myExternalEffort->update(minEdge->getNumericalID(), minimumInfo->prev->edge->getNumericalID(), minEdge->getLength());
195 }
196 this->buildPathFrom(minimumInfo, into);
197 this->endQuery(num_visited);
198#ifdef DijkstraRouter_DEBUG_QUERY_PERF
199 const double cost = this->recomputeCosts(into, vehicle, msTime);
200 std::cout << "visited " + toString(num_visited) + " edges (final path length=" + toString(into.size()) + " cost=" << cost << " edges=" + toString(into) + ")\n";
201#endif
202#ifdef DijkstraRouter_DEBUG_QUERY_VISITED
203 DijkstraRouter_DEBUG_QUERY_VISITED_OUT << " </interval>\n</edgeData>\n";
204#endif
205 return true;
206 }
207 std::pop_heap(this->myFrontierList.begin(), this->myFrontierList.end(), myComparator);
208 this->myFrontierList.pop_back();
209 this->myFound.push_back(minimumInfo);
210 const double effortDelta = this->getEffort(minEdge, vehicle, minimumInfo->leaveTime);
211 const double leaveTime = minimumInfo->leaveTime + this->getTravelTime(minEdge, vehicle, minimumInfo->leaveTime, effortDelta);
212 if (myExternalEffort != nullptr) {
213 myExternalEffort->update(minEdge->getNumericalID(), minimumInfo->prev->edge->getNumericalID(), minEdge->getLength());
214 }
215 // check all ways from the node with the minimal length
216 for (const std::pair<const E*, const E*>& follower : minEdge->getViaSuccessors(vClass, ignoreTransient)) {
217 auto& followerInfo = this->myEdgeInfos[follower.first->getNumericalID()];
218 // check whether it can be used
219 if (this->isProhibited(follower.first, vehicle, leaveTime)) {
220 continue;
221 }
222 double effort = minimumInfo->effort + effortDelta;
223 double time = leaveTime;
224 this->updateViaEdgeCost(follower.second, vehicle, time, effort, length);
225 assert(effort >= minimumInfo->effort);
226 assert(time >= minimumInfo->leaveTime);
227 const double oldEffort = followerInfo.effort;
228 if (!followerInfo.visited && effort < oldEffort) {
229 followerInfo.effort = effort;
230 followerInfo.leaveTime = time;
231 followerInfo.prev = minimumInfo;
232 if (oldEffort == std::numeric_limits<double>::max()) {
233 this->myFrontierList.push_back(&followerInfo);
234 std::push_heap(this->myFrontierList.begin(), this->myFrontierList.end(), myComparator);
235 } else {
236 std::push_heap(this->myFrontierList.begin(),
237 std::find(this->myFrontierList.begin(), this->myFrontierList.end(), &followerInfo) + 1,
239 }
240 }
241 }
242 }
243 this->endQuery(num_visited);
244#ifdef DijkstraRouter_DEBUG_QUERY_PERF
245 std::cout << "visited " + toString(num_visited) + " edges (unsuccessful path length: " + toString(into.size()) + ")\n";
246#endif
247 if (to != nullptr && !mySilent && !silent) {
248 this->myErrorMsgHandler->informf(TL("No connection between edge '%' and edge '%' found."), from->getID(), to->getID());
249 }
250#ifdef DijkstraRouter_DEBUG_QUERY_VISITED
251 DijkstraRouter_DEBUG_QUERY_VISITED_OUT << " </interval>\n</edgeData>\n";
252#endif
253 return false;
254 }
255
256private:
257 DijkstraRouter(const std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo>& edgeInfos, bool unbuildIsWarning,
258 typename SUMOAbstractRouter<E, V>::Operation effortOperation, typename SUMOAbstractRouter<E, V>::Operation ttOperation, bool silent, EffortCalculator* calc,
259 const bool havePermissions, const bool haveRestrictions) :
260 SUMOAbstractRouter<E, V>("DijkstraRouter", unbuildIsWarning, effortOperation, ttOperation, havePermissions, haveRestrictions),
261 mySilent(silent),
262 myExternalEffort(calc) {
263 for (const auto& edgeInfo : edgeInfos) {
264 this->myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(edgeInfo.edge));
265 }
266 }
267
268private:
271
273 std::tuple<const E*, const V*, SUMOTime> myLastQuery;
274
276
278};
#define DijkstraRouter_DEBUG_QUERY_VISITED_OUT
long long int SUMOTime
Definition GUI.h:36
#define TL(string)
Definition MsgHandler.h:304
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#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
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
bool operator()(const typename SUMOAbstractRouter< E, V >::EdgeInfo *nod1, const typename SUMOAbstractRouter< E, V >::EdgeInfo *nod2) const
Comparing method.
Computes the shortest path through a network using the Dijkstra algorithm.
bool mySilent
whether to suppress warning/error if no route was found
std::tuple< const E *, const V *, SUMOTime > myLastQuery
cache of the last query to enable automated bulk routing
EffortCalculator *const myExternalEffort
bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)
Builds the route between the given edges using the minimum effort at the given time The definition of...
virtual SUMOAbstractRouter< E, V > * clone()
DijkstraRouter(const std::vector< E * > &edges, bool unbuildIsWarning, typename SUMOAbstractRouter< E, V >::Operation effortOperation, typename SUMOAbstractRouter< E, V >::Operation ttOperation=nullptr, bool silent=false, EffortCalculator *calc=nullptr, const bool havePermissions=false, const bool haveRestrictions=false)
Constructor.
EdgeInfoByEffortComparator myComparator
virtual ~DijkstraRouter()
Destructor.
DijkstraRouter(const std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo > &edgeInfos, bool unbuildIsWarning, typename SUMOAbstractRouter< E, V >::Operation effortOperation, typename SUMOAbstractRouter< E, V >::Operation ttOperation, bool silent, EffortCalculator *calc, const bool havePermissions, const bool haveRestrictions)
the effort calculator interface
virtual void setInitialState(const int edge)=0
virtual void update(const int edge, const int prev, const double length)=0
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
void informf(const std::string &format, T value, Targs... Fargs)
adds a new formatted message
Definition MsgHandler.h:116
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
const E *const edge
The current edge.
double effort
Effort to reach the edge.
Operation myTTOperation
The object's operation to perform for travel times.
const bool myHavePermissions
whether edge permissions need to be considered
bool myBulkMode
whether we are currently operating several route queries in a bulk
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo > myEdgeInfos
The container of edge information.
Operation myOperation
The object's operation to perform.
double getTravelTime(const E *const e, const V *const v, const double t, const double effort) const
double getEffort(const E *const e, const V *const v, double t) const
bool isProhibited(const E *const edge, const V *const vehicle, double t) const
void updateViaEdgeCost(const E *viaEdge, const V *const v, double &time, double &effort, double &length) const
void init(const int edgeID, const SUMOTime msTime)
bool myAmClean
whether we are already initialized
const bool myHaveRestrictions
whether edge restrictions need to be considered
void buildPathFrom(const typename SUMOAbstractRouter< E, V >::EdgeInfo *rbegin, std::vector< const E * > &edges)
Builds the path from marked edges.
bool myAutoBulkMode
whether we are currently trying to detect bulk mode automatically
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
void endQuery(int visits)
MsgHandler * myErrorMsgHandler
the handler for routing errors
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo * > myFrontierList
A container for reusage of the min edge heap.
std::vector< typename SUMOAbstractRouter< E, V >::EdgeInfo * > myFound
list of visited Edges (for resetting)