LCOV - code coverage report
Current view: top level - src/utils/router - SUMOAbstractRouter.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.2 % 165 162
Test Date: 2026-10-12 15:53:19 Functions: 51.9 % 183 95

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2006-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              : /****************************************************************************/
      14              : /// @file    SUMOAbstractRouter.h
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Michael Behrisch
      17              : /// @author  Jakob Erdmann
      18              : /// @date    25.Jan 2006
      19              : ///
      20              : // An abstract router base class
      21              : /****************************************************************************/
      22              : #pragma once
      23              : #include <config.h>
      24              : 
      25              : #include <iostream>
      26              : #include <string>
      27              : #include <vector>
      28              : #include <algorithm>
      29              : #include <iterator>
      30              : #include <assert.h>
      31              : #include <utils/common/SysUtils.h>
      32              : #include <utils/common/MsgHandler.h>
      33              : #include <utils/common/SUMOTime.h>
      34              : #include <utils/common/ToString.h>
      35              : 
      36              : //#define ROUTER_DEBUG_HINT
      37              : //#define ROUTER_DEBUG_COND (true)
      38              : 
      39              : 
      40              : // ===========================================================================
      41              : // class definitions
      42              : // ===========================================================================
      43              : 
      44              : /// Prohibitions and their estimated end time
      45      2443439 : struct RouterProhibition {
      46              :     double begin = 0;
      47              :     double end = std::numeric_limits<double>::max();
      48              :     SVCPermissions permissions = SVC_IGNORING;
      49              : };
      50              : 
      51              : /**
      52              :  * @class SUMOAbstractRouter
      53              :  * The interface for routing the vehicles over the network.
      54              :  */
      55              : template<class E, class V>
      56              : class SUMOAbstractRouter {
      57              : public:
      58              :     /**
      59              :     * @class EdgeInfo
      60              :     * A definition about a route's edge with the effort needed to reach it and
      61              :     *  the information about the previous edge.
      62              :     */
      63              :     class EdgeInfo {
      64              :     public:
      65              :         /// Constructor
      66     21946327 :         EdgeInfo(const E* const e)
      67     21946327 :             : edge(e), effort(std::numeric_limits<double>::max()),
      68     21946327 :               heuristicEffort(std::numeric_limits<double>::max()),
      69     21946327 :               leaveTime(0.), prev(nullptr), visited(false), prohibitedPermissions(SVCAll), prohibitionBegin(-1), prohibitionEnd(-1) {}
      70              : 
      71              :         /// The current edge
      72              :         const E* const edge;
      73              : 
      74              :         /// Effort to reach the edge
      75              :         double effort;
      76              : 
      77              :         /// Estimated effort to reach the edge (effort + lower bound on remaining effort)
      78              :         // only used by A*
      79              :         double heuristicEffort;
      80              : 
      81              :         /// The time the vehicle leaves the edge
      82              :         double leaveTime;
      83              : 
      84              :         /// The previous edge
      85              :         const EdgeInfo* prev;
      86              : 
      87              :         /// whether the edge was already evaluated
      88              :         bool visited;
      89              : 
      90              :         /// temporary permission change
      91              :         SVCPermissions prohibitedPermissions;
      92              : 
      93              :         /// the time at which a temporary prohibition begins
      94              :         double prohibitionBegin;
      95              : 
      96              :         /// the time at which a temporary prohibition ends
      97              :         double prohibitionEnd;
      98              : 
      99              :         inline void reset() {
     100     87900224 :             effort = std::numeric_limits<double>::max();
     101     87900224 :             heuristicEffort = std::numeric_limits<double>::max();
     102      2991030 :             visited = false;
     103              :         }
     104              : 
     105              :     };
     106              : 
     107              :     /// Type of the function that is used to retrieve the edge effort.
     108              :     typedef double(* Operation)(const E* const, const V* const, double);
     109              : 
     110              :     typedef std::map<const E*, RouterProhibition> Prohibitions;
     111              : 
     112              :     /// Constructor
     113        67561 :     SUMOAbstractRouter(const std::string& type, bool unbuildIsWarning, Operation operation, Operation ttOperation,
     114              :                        const bool havePermissions, const bool haveRestrictions) :
     115        67561 :         myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
     116        67561 :         myOperation(operation), myTTOperation(ttOperation),
     117        67561 :         myBulkMode(false),
     118        67561 :         myAutoBulkMode(false),
     119        67561 :         myAmClean(true),
     120        67561 :         myHavePermissions(havePermissions),
     121        67561 :         myHaveRestrictions(haveRestrictions),
     122        67561 :         myType(type),
     123        67561 :         myQueryVisits(0),
     124        67561 :         myNumQueries(0),
     125        67561 :         myQueryStartTime(0),
     126        67561 :         myQueryTimeSum(0) {
     127        67561 :     }
     128              : 
     129              :     /// Copy Constructor
     130          516 :     SUMOAbstractRouter(SUMOAbstractRouter* other) :
     131          516 :         myErrorMsgHandler(other->myErrorMsgHandler),
     132          516 :         myOperation(other->myOperation), myTTOperation(other->myTTOperation),
     133          516 :         myBulkMode(false),
     134          516 :         myAutoBulkMode(false),
     135          516 :         myAmClean(true),
     136          516 :         myHavePermissions(other->myHavePermissions),
     137          516 :         myHaveRestrictions(other->myHaveRestrictions),
     138          516 :         myType(other->myType),
     139          516 :         myQueryVisits(0),
     140          516 :         myNumQueries(0),
     141          516 :         myQueryStartTime(0),
     142         1032 :         myQueryTimeSum(0) { }
     143              : 
     144              : 
     145              : 
     146              :     /// Destructor
     147        68072 :     virtual ~SUMOAbstractRouter() {
     148        68072 :         if (myNumQueries > 0) {
     149        84684 :             WRITE_MESSAGE(myType + " answered " + toString(myNumQueries) + " queries and explored " + toString((double)myQueryVisits / (double)myNumQueries) +  " edges on average.");
     150        84684 :             WRITE_MESSAGE(myType + " spent " + elapsedMs2string(myQueryTimeSum) + " answering queries (" + toString((double)myQueryTimeSum / (double)myNumQueries) +  "ms on average).");
     151              :         }
     152        89243 :     }
     153              : 
     154              :     virtual SUMOAbstractRouter* clone() = 0;
     155              : 
     156      4178341 :     inline void init(const int edgeID, const SUMOTime msTime) {
     157              : //        if (!myAmClean) {
     158              :         // all EdgeInfos touched in the previous query are either in myFrontierList or myFound: clean those up
     159     18317115 :         for (auto& edgeInfo : myFrontierList) {
     160     14138774 :             edgeInfo->reset();
     161              :         }
     162              :         myFrontierList.clear();
     163     74958851 :         for (auto& edgeInfo : myFound) {
     164     70780510 :             edgeInfo->reset();
     165              :         }
     166              :         myFound.clear();
     167      4178341 :         if (edgeID > -1) {
     168              :             // add begin node
     169      4178341 :             auto& fromInfo = myEdgeInfos[edgeID];
     170      4178341 :             fromInfo.effort = 0.;
     171      4178341 :             fromInfo.heuristicEffort = 0.;
     172      4178341 :             fromInfo.prev = nullptr;
     173      4178341 :             fromInfo.leaveTime = STEPS2TIME(msTime);
     174      4178341 :             myFrontierList.push_back(&fromInfo);
     175              :         }
     176      4178341 :         myAmClean = true;
     177              : //        }
     178      4178341 :     }
     179              : 
     180              :     /// reset internal caches, used by CHRouter
     181         4312 :     virtual void reset(const V* const vehicle) {
     182              :         UNUSED_PARAMETER(vehicle);
     183         4312 :     }
     184              : 
     185       269390 :     virtual void setMsgHandler(MsgHandler* const errorMsgHandler) {
     186       274117 :         myErrorMsgHandler = errorMsgHandler;
     187       269390 :     }
     188              : 
     189              :     const std::string& getType() const {
     190              :         return myType;
     191              :     }
     192              : 
     193              :     inline const typename SUMOAbstractRouter<E, V>::EdgeInfo& getEdgeInfo(int index) const {
     194           56 :         return myEdgeInfos[index];
     195              :     }
     196              : 
     197              :     /** @brief Builds the route between the given edges using the minimum effort at the given time
     198              :         The definition of the effort depends on the wished routing scheme */
     199              :     virtual bool compute(const E* from, const E* to, const V* const vehicle,
     200              :                          SUMOTime msTime, std::vector<const E*>& into, bool silent = false) = 0;
     201              : 
     202              : 
     203              :     /** @brief Builds the route between the given edges using the minimum effort at the given time,
     204              :      * also taking into account position along the edges to ensure currect
     205              :      * handling of looped routes
     206              :      * The definition of the effort depends on the wished routing scheme */
     207      2989979 :     inline bool compute(
     208              :         const E* from, double fromPos,
     209              :         const E* to, double toPos,
     210              :         const V* const vehicle,
     211              :         SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
     212      2989979 :         if (from != to || fromPos <= toPos) {
     213      2981819 :             return compute(from, to, vehicle, msTime, into, silent);
     214              :         } else {
     215         8160 :             return computeLooped(from, to, vehicle, msTime, into, silent);
     216              :         }
     217              :     }
     218              : 
     219              : 
     220              :     /** @brief Builds the route between the given edges using the minimum effort at the given time
     221              :      * if from == to, return the shortest looped route */
     222         8650 :     inline bool computeLooped(const E* from, const E* to, const V* const vehicle,
     223              :                               SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
     224         8650 :         if (from != to) {
     225            0 :             return compute(from, to, vehicle, msTime, into, silent);
     226              :         }
     227              :         double minEffort = std::numeric_limits<double>::max();
     228            0 :         std::vector<const E*> best;
     229         8650 :         const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
     230        29440 :         for (const std::pair<const E*, const E*>& follower : from->getViaSuccessors(vClass)) {
     231            0 :             std::vector<const E*> tmp;
     232        10395 :             compute(follower.first, to, vehicle, msTime, tmp, true);
     233        10395 :             if (tmp.size() > 0) {
     234         9802 :                 double effort = recomputeCosts(tmp, vehicle, msTime);
     235         9802 :                 if (effort < minEffort) {
     236              :                     minEffort = effort;
     237         9378 :                     best = tmp;
     238              :                 }
     239              :             }
     240              :         }
     241         8650 :         if (minEffort != std::numeric_limits<double>::max()) {
     242         8103 :             into.push_back(from);
     243              :             std::copy(best.begin(), best.end(), std::back_inserter(into));
     244              :             return true;
     245          547 :         } else if (!silent && myErrorMsgHandler != nullptr) {
     246          144 :             myErrorMsgHandler->informf(TL("No connection between edge '%' and edge '%' found."), from->getID(), to->getID());
     247              :         }
     248              :         return false;
     249         8650 :     }
     250              : 
     251    180425799 :     inline bool isProhibited(const E* const edge, const V* const vehicle, double t) const {
     252              :         return (myProhibited.size() > 0
     253     20897312 :                 && (myEdgeInfos[edge->getNumericalID()].prohibitedPermissions & vehicle->getVClass()) != vehicle->getVClass()
     254       837579 :                 && myEdgeInfos[edge->getNumericalID()].prohibitionBegin <= t
     255       837574 :                 && myEdgeInfos[edge->getNumericalID()].prohibitionEnd == std::numeric_limits<double>::max())
     256    200497735 :                || (myHavePermissions && edge->prohibits(vehicle)) || (myHaveRestrictions && edge->restricts(vehicle));
     257              :     }
     258              : 
     259              :     inline double getTravelTime(const E* const e, const V* const v, const double t, const double effort) const {
     260     71685511 :         return myTTOperation == nullptr ? effort : (*myTTOperation)(e, v, t);
     261              :     }
     262              : 
     263    188005582 :     inline void updateViaEdgeCost(const E* viaEdge, const V* const v, double& time, double& effort, double& length) const {
     264    315346847 :         while (viaEdge != nullptr && viaEdge->isInternal()) {
     265    127341265 :             const double viaEffortDelta = this->getEffort(viaEdge, v, time);
     266    127341265 :             time += getTravelTime(viaEdge, v, time, viaEffortDelta);
     267    127341265 :             effort += viaEffortDelta;
     268    127341265 :             length += viaEdge->getLength();
     269    127341265 :             viaEdge = viaEdge->getViaSuccessors().front().second;
     270              :         }
     271    188005582 :     }
     272              : 
     273     29253869 :     inline void updateViaCost(const E* const prev, const E* const e, const V* const v, double& time, double& effort, double& length) const {
     274     29253869 :         if (prev != nullptr) {
     275     35971063 :             for (const std::pair<const E*, const E*>& follower : prev->getViaSuccessors()) {
     276     35966228 :                 if (follower.first == e) {
     277     22426637 :                     updateViaEdgeCost(follower.second, v, time, effort, length);
     278              :                     break;
     279              :                 }
     280              :             }
     281              :         }
     282     29253869 :         const double effortDelta = this->getEffort(e, v, time);
     283     29253869 :         effort += effortDelta;
     284     29253869 :         time += getTravelTime(e, v, time, effortDelta);
     285     29253869 :         length += e->getLength();
     286     29253869 :     }
     287              : 
     288              :     bool isValid(const std::vector<const E*>& edges, const V* const v, double t) const {
     289      2889525 :         for (const E* const e : edges) {
     290      2447410 :             if (isProhibited(e, v, t)) {
     291              :                 return false;
     292              :             }
     293              :         }
     294              :         return true;
     295              :     }
     296              : 
     297      6649158 :     virtual double recomputeCosts(const std::vector<const E*>& edges, const V* const v, SUMOTime msTime, double* lengthp = nullptr) const {
     298      6649158 :         double time = STEPS2TIME(msTime);
     299      6649158 :         double effort = 0.;
     300      6649158 :         double length = 0.;
     301      6649158 :         if (lengthp == nullptr) {
     302              :             lengthp = &length;
     303              :         } else {
     304         6047 :             *lengthp = 0.;
     305              :         }
     306              :         const E* prev = nullptr;
     307     34220080 :         for (const E* const e : edges) {
     308     27570922 :             updateViaCost(prev, e, v, time, effort, *lengthp);
     309              :             prev = e;
     310              :         }
     311      6649158 :         return effort;
     312              :     }
     313              : 
     314              : 
     315      2881428 :     inline double recomputeCostsPos(const std::vector<const E*>& edges, const V* const v, double fromPos, double toPos, SUMOTime msTime, double* lengthp = nullptr) const {
     316      2881428 :         double effort = recomputeCosts(edges, v, msTime, lengthp);
     317      2881428 :         if (!edges.empty()) {
     318      2881428 :             const E* first = edges.front();
     319      2881428 :             if (first->getLength() == 0) {
     320       465926 :                 if (edges.size() > 1 && edges[1]->getLength() > 0) {
     321              :                     first = edges[1];
     322              :                 } else {
     323              :                     return effort;
     324              :                 }
     325              :             }
     326      2881428 :             const E* last = edges.back();
     327      2881428 :             if (last->getLength() == 0) {
     328       465968 :                 if (edges.size() > 1 && edges[edges.size() - 2]->getLength() > 0) {
     329              :                     last = edges[edges.size() - 2];
     330              :                 } else {
     331              :                     return effort;
     332              :                 }
     333              :             }
     334              :             assert(first->getLength() > 0);
     335              :             assert(last->getLength() > 0);
     336      2881428 :             double firstEffort = this->getEffort(first, v, STEPS2TIME(msTime));
     337      2881428 :             double lastEffort = this->getEffort(last, v, STEPS2TIME(msTime));
     338      2881428 :             effort -= firstEffort * fromPos / first->getLength();
     339      2881428 :             effort -= lastEffort * (last->getLength() - toPos) / last->getLength();
     340      2881428 :             if (lengthp != nullptr) {
     341         6047 :                 (*lengthp) -= fromPos + last->getLength() - toPos;
     342              :             }
     343              :         }
     344              :         return effort;
     345              :     }
     346              : 
     347              : 
     348              :     inline double setHint(const typename std::vector<const E*>::const_iterator routeBegin, const typename std::vector<const E*>::const_iterator routeEnd, const V* const v, SUMOTime msTime) {
     349              :         double time = STEPS2TIME(msTime);
     350              :         double effort = 0.;
     351              :         double length = 0.;
     352              :         const EdgeInfo* prev = &myEdgeInfos[(*routeBegin)->getNumericalID()];
     353              :         init((*routeBegin)->getNumericalID(), msTime);
     354              :         for (auto e = routeBegin + 1; e != routeEnd; ++e) {
     355              :             if (isProhibited(*e, v)) {
     356              :                 return -1;
     357              :             }
     358              :             auto& edgeInfo = myEdgeInfos[(*e)->getNumericalID()];
     359              :             edgeInfo.heuristicEffort = effort;
     360              :             edgeInfo.prev = prev;
     361              :             updateViaCost(prev->edge, *e, v, time, effort, length);
     362              :             edgeInfo.effort = effort;
     363              :             edgeInfo.leaveTime = time;
     364              :             myFound.push_back(&edgeInfo);
     365              :             prev = &edgeInfo;
     366              : #ifdef ROUTER_DEBUG_HINT
     367              :             if (ROUTER_DEBUG_COND) {
     368              :                 std::cout << "DEBUG: hit=" << (*e)->getID()
     369              :                           << " TT=" << edgeInfo.effort
     370              :                           << " EF=" << this->getEffort(*e, v, edgeInfo.leaveTime)
     371              :                           << " HT=" << edgeInfo.heuristicEffort << "\n";
     372              :             }
     373              : #endif
     374              :         }
     375              :         return effort;
     376              :     }
     377              : 
     378              : 
     379    237770718 :     inline double getEffort(const E* const e, const V* const v, double t) const {
     380     13901547 :         if (this->myProhibited.size() > 0 && myEdgeInfos.size() > 0
     381     13901232 :                 && myEdgeInfos[e->getNumericalID()].prohibitionEnd > t
     382         1965 :                 && myEdgeInfos[e->getNumericalID()].prohibitionBegin <= t
     383    237772684 :                 && (myEdgeInfos[e->getNumericalID()].prohibitedPermissions & v->getVClass()) != v->getVClass()) {
     384              :             // pass edge after prohibition ends
     385         1911 :             return (myEdgeInfos[e->getNumericalID()].prohibitionEnd - t) + (*myOperation)(e, v, myEdgeInfos[e->getNumericalID()].prohibitionEnd);
     386              :         } else {
     387    237768807 :             return (*myOperation)(e, v, t);
     388              :         }
     389              :     }
     390              : 
     391              :     inline void startQuery() {
     392      4321019 :         myNumQueries++;
     393      4321019 :         myQueryStartTime = SysUtils::getCurrentMillis();
     394              :     }
     395              : 
     396              :     inline void endQuery(int visits) {
     397      4320853 :         myQueryVisits += visits;
     398      4321019 :         myQueryTimeSum += (SysUtils::getCurrentMillis() - myQueryStartTime);
     399              :     }
     400              : 
     401        83127 :     virtual void setBulkMode(const bool mode) {
     402        84039 :         myBulkMode = mode;
     403        83127 :     }
     404              : 
     405              :     inline void setAutoBulkMode(const bool mode) {
     406         4722 :         myAutoBulkMode = mode;
     407            4 :     }
     408              : 
     409      1773832 :     virtual void prohibit(const Prohibitions& toProhibit) {
     410      3397554 :         for (auto item : this->myProhibited) {
     411      1623722 :             myEdgeInfos[item.first->getNumericalID()].prohibitedPermissions = SVCAll;
     412      1623722 :             myEdgeInfos[item.first->getNumericalID()].prohibitionBegin = -1;
     413      1623722 :             myEdgeInfos[item.first->getNumericalID()].prohibitionEnd = -1;
     414              :         }
     415      3403129 :         for (auto item : toProhibit) {
     416      1629297 :             myEdgeInfos[item.first->getNumericalID()].prohibitionBegin = item.second.begin;
     417      1629297 :             myEdgeInfos[item.first->getNumericalID()].prohibitionEnd = item.second.end;
     418      1629297 :             myEdgeInfos[item.first->getNumericalID()].prohibitedPermissions = item.second.permissions;
     419              :             //std::cout << item.first->getID() << " " << item.second.begin << " " << item.second.end << " (" << getVehicleClassNames(item.second.permissions) << ")\n";
     420              :         }
     421              :         this->myProhibited = toProhibit;
     422      1773832 :     }
     423              : 
     424              :     bool hasProhibitions() const {
     425              :         return this->myProhibited.size() > 0;
     426              :     }
     427              : 
     428           20 :     virtual bool supportsProhibitions() const {
     429           20 :         return true;
     430              :     }
     431              : 
     432              :     /// Builds the path from marked edges
     433      4191666 :     void buildPathFrom(const typename SUMOAbstractRouter<E, V>::EdgeInfo* rbegin, std::vector<const E*>& edges) {
     434       289852 :         std::vector<const E*> tmp;
     435     22629557 :         while (rbegin != nullptr) {
     436     18437891 :             tmp.push_back(rbegin->edge);
     437     18437891 :             rbegin = rbegin->prev;
     438              :         }
     439              :         std::copy(tmp.rbegin(), tmp.rend(), std::back_inserter(edges));
     440      4191666 :     }
     441              : 
     442              : protected:
     443              :     /// @brief the handler for routing errors
     444              :     MsgHandler* myErrorMsgHandler;
     445              : 
     446              :     /// @brief The object's operation to perform.
     447              :     Operation myOperation;
     448              : 
     449              :     /// @brief The object's operation to perform for travel times
     450              :     Operation myTTOperation;
     451              : 
     452              :     /// @brief whether we are currently operating several route queries in a bulk
     453              :     bool myBulkMode;
     454              : 
     455              :     /// @brief whether we are currently trying to detect bulk mode automatically
     456              :     bool myAutoBulkMode;
     457              : 
     458              :     /// @brief whether we are already initialized
     459              :     bool myAmClean;
     460              : 
     461              :     /// @brief whether edge permissions need to be considered
     462              :     const bool myHavePermissions;
     463              : 
     464              :     /// @brief whether edge restrictions need to be considered
     465              :     const bool myHaveRestrictions;
     466              : 
     467              :     /// The list of explicitly prohibited edges and estimated end time of prohibition
     468              :     Prohibitions myProhibited;
     469              : 
     470              :     /// The container of edge information
     471              :     std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
     472              : 
     473              :     /// A container for reusage of the min edge heap
     474              :     std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontierList;
     475              :     /// @brief list of visited Edges (for resetting)
     476              :     std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFound;
     477              : 
     478              : private:
     479              :     /// @brief the type of this router
     480              :     const std::string myType;
     481              : 
     482              :     /// @brief counters for performance logging
     483              :     long long int myQueryVisits;
     484              :     long long int myNumQueries;
     485              :     /// @brief the time spent querying in milliseconds
     486              :     long long int myQueryStartTime;
     487              :     long long int myQueryTimeSum;
     488              : 
     489              : private:
     490              :     /// @brief Invalidated assignment operator
     491              :     SUMOAbstractRouter& operator=(const SUMOAbstractRouter& s) = delete;
     492              : };
        

Generated by: LCOV version 2.0-1