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-2026 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#if defined(DijkstraRouter_DEBUG_QUERY) || defined(DijkstraRouter_DEBUG_QUERY_PERF)
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
277 EdgeInfoByEffortComparator myComparator;
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:58
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:49
bool operator()(const typename SUMOAbstractRouter< E, V >::EdgeInfo *nod1, const typename SUMOAbstractRouter< E, V >::EdgeInfo *nod2) const
Comparing method.
std::tuple< const _IntermodalEdge *, const _IntermodalTrip *, SUMOTime > myLastQuery
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.
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
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
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:66
const E *const edge
The current edge.
double effort
Effort to reach the edge.
std::vector< typename SUMOAbstractRouter< _IntermodalEdge, _IntermodalTrip >::EdgeInfo > myEdgeInfos
double(* Operation)(const E *const, const V *const, double)
Type of the function that is used to retrieve the edge effort.
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
SUMOAbstractRouter(const std::string &type, bool unbuildIsWarning, Operation operation, Operation ttOperation, const bool havePermissions, const bool haveRestrictions)
Constructor.
void updateViaEdgeCost(const E *viaEdge, const V *const v, double &time, double &effort, double &length) const
void init(const int edgeID, const SUMOTime msTime)
void buildPathFrom(const typename SUMOAbstractRouter< E, V >::EdgeInfo *rbegin, std::vector< const E * > &edges)
Builds the path from marked edges.
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
void endQuery(int visits)
std::vector< typename SUMOAbstractRouter< _IntermodalEdge, _IntermodalTrip >::EdgeInfo * > myFrontierList
std::vector< typename SUMOAbstractRouter< _IntermodalEdge, _IntermodalTrip >::EdgeInfo * > myFound