From 9d0b45e887b0acf63bb592885f9fe12934305669 Mon Sep 17 00:00:00 2001 From: Ruediger Ebendt Date: Mon, 17 Feb 2025 20:14:54 +0100 Subject: [PATCH] Removed parameter 'partition' from ctor of AFRouter - now handled inside of AFRouter - for a time-dependent instance: now, like for the backward k-d tree partition, also the forward k-d tree partition is initialized when compute() is called for the first time - thereby, it is initialized with vehicle as parameter Signed-off-by: Ruediger Ebendt --- src/afrotest/AFROTest.cpp | 22 +++---- src/duarouter/duarouter_main.cpp | 8 +-- src/utils/router/AFBuild.h | 25 +++++--- src/utils/router/AFBuilder.h | 40 ++++++++----- src/utils/router/AFRouter.h | 49 +++++++++------- src/utils/router/KDTreePartition.h | 94 ++++++++++++++++++++---------- 6 files changed, 149 insertions(+), 89 deletions(-) mode change 100644 => 100755 src/afrotest/AFROTest.cpp mode change 100644 => 100755 src/duarouter/duarouter_main.cpp mode change 100644 => 100755 src/utils/router/AFBuild.h mode change 100644 => 100755 src/utils/router/AFBuilder.h mode change 100644 => 100755 src/utils/router/AFRouter.h mode change 100644 => 100755 src/utils/router/KDTreePartition.h diff --git a/src/afrotest/AFROTest.cpp b/src/afrotest/AFROTest.cpp old mode 100644 new mode 100755 index c319244545fb..fb84dfa66e01 --- a/src/afrotest/AFROTest.cpp +++ b/src/afrotest/AFROTest.cpp @@ -1,6 +1,6 @@ /****************************************************************************/ -// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo -// Copyright (C) 2001-2023 German Aerospace Center (DLR) and others. +// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo +// Copyright (C) 2001-2024 German Aerospace Center (DLR) and others. // This program and the accompanying materials are made available under the // terms of the Eclipse Public License 2.0 which is available at // https://www.eclipse.org/legal/epl-2.0/ @@ -20,12 +20,12 @@ #include #include "AFROTest.h" -/// @brief The number of levels in the k-d tree partition -constexpr auto NUMBER_OF_LEVELS = 5; //or 4 or 8 +/// @brief The maximum number of levels in the k-d tree partition +constexpr auto MAX_NUMBER_OF_LEVELS = 5; //or 4 or 8 /// @brief The number of start edges of the route queries -constexpr auto NUMBER_OF_START_EDGES = 32; // 32 -> 32^2 = 1024 test routes +constexpr auto MAX_NUMBER_OF_START_EDGES = 32; // 32 -> 32^2 = maximal 1024 test routes /// @brief The number of end edges of the route queries -constexpr auto NUMBER_OF_END_EDGES = NUMBER_OF_START_EDGES; +constexpr auto MAX_NUMBER_OF_END_EDGES = MAX_NUMBER_OF_START_EDGES; //#define ATST_DEBUG_LEVEL_0 @@ -49,14 +49,15 @@ AFROTest::test(const ROVehicle* const vehicle, bool unbuildIsWarning, typename S long long int kDPartitionBuildStart = 0; long long int kDPartitionBuildTime = 0; kDPartitionBuildStart = SysUtils::getCurrentMillis(); - KDTreePartition* partition = new KDTreePartition(NUMBER_OF_LEVELS, edges, havePermissions, haveRestrictions); + KDTreePartition* partition = new KDTreePartition(MAX_NUMBER_OF_LEVELS, edges, havePermissions, haveRestrictions); partition->init(vehicle); kDPartitionBuildTime = (SysUtils::getCurrentMillis() - kDPartitionBuildStart); std::cout << "Time spent for k-d partition build: " << elapsedMs2string(kDPartitionBuildTime) << std::endl; std::cout << "Forward k-d tree partition ready." << std::endl; AFRouter* arcFlagRouter = new AFRouter(edges, - partition, unbuildIsWarning, operation, flippedOperation, weightPeriod, lookup, flippedLookup, havePermissions, + unbuildIsWarning, operation, flippedOperation, weightPeriod, lookup, flippedLookup, havePermissions, haveRestrictions); + std::cout << "AFRouter instantiated." << std::endl; CHRouter* cHRouter = new CHRouter( edges, unbuildIsWarning, operation, /*SVC_IGNORING*/vehicle->getVClass(), weightPeriod, havePermissions, haveRestrictions); AStarRouter* aStar = new AStarRouter(edges, unbuildIsWarning, operation, lookup, @@ -190,7 +191,7 @@ AFROTest::testRoutes(const Cell* cell1, const Cell* cell2, const ROVehicle* cons } std::unordered_set someCell1InsideEdges; auto iter = cell1InsideEdges->begin(); - std::advance(iter, MIN2(cell1InsideEdges->size(), static_cast(NUMBER_OF_START_EDGES))); + std::advance(iter, MIN2(cell1InsideEdges->size(), static_cast(MAX_NUMBER_OF_START_EDGES))); someCell1InsideEdges.insert(cell1InsideEdges->begin(), iter); delete cell1InsideEdges; std::unordered_set* cell2InsideEdges = cell2->edgeSet(vehicle); @@ -204,7 +205,7 @@ AFROTest::testRoutes(const Cell* cell1, const Cell* cell2, const ROVehicle* cons } std::unordered_set someCell2InsideEdges; auto iter2 = cell2InsideEdges->begin(); - std::advance(iter2, MIN2(cell2InsideEdges->size(), static_cast(NUMBER_OF_END_EDGES))); + std::advance(iter2, MIN2(cell2InsideEdges->size(), static_cast(MAX_NUMBER_OF_END_EDGES))); someCell2InsideEdges.insert(cell2InsideEdges->begin(), iter2); delete cell2InsideEdges; @@ -409,4 +410,5 @@ AFROTest::testQuery(const ROEdge* edge1, const ROEdge* edge2, const ROVehicle* c } } + /****************************************************************************/ diff --git a/src/duarouter/duarouter_main.cpp b/src/duarouter/duarouter_main.cpp old mode 100644 new mode 100755 index 69b6cf745f16..b3c513d044db --- a/src/duarouter/duarouter_main.cpp +++ b/src/duarouter/duarouter_main.cpp @@ -15,6 +15,7 @@ /// @author Daniel Krajzewicz /// @author Jakob Erdmann /// @author Michael Behrisch +/// @author Ruediger Ebendt /// @date Thu, 06 Jun 2002 /// // Main for DUAROUTER @@ -150,15 +151,10 @@ computeRoutes(RONet& net, ROLoader& loader, OptionsCont& oc) { ROEdge::getAllEdges(), oc.getBool("ignore-errors"), ttFunction, begin, end, weightPeriod, net.hasPermissions(), oc.getInt("routing-threads")); } else if (routingAlgorithm == "arcflag") { - /// @brief The number of levels in the k-d tree partition - constexpr auto NUMBER_OF_LEVELS = 5; //or 4 or 8 - ROVehicle defaultVehicle(SUMOVehicleParameter(), nullptr, net.getVehicleTypeSecure(DEFAULT_VTYPE_ID), &net); - KDTreePartition* partition = new KDTreePartition(NUMBER_OF_LEVELS, ROEdge::getAllEdges(), net.hasPermissions(), oc.isSet("restriction-params")); - partition->init(&defaultVehicle); auto ttFunction = gWeightsRandomFactor > 1 ? &ROEdge::getTravelTimeStaticRandomized : &ROEdge::getTravelTimeStatic; auto reversedTtFunction = gWeightsRandomFactor > 1 ? &FlippedEdge::getTravelTimeStaticRandomized : &FlippedEdge::getTravelTimeStatic; router = new AFRouter(ROEdge::getAllEdges(), - partition, oc.getBool("ignore-errors"), ttFunction, reversedTtFunction, (oc.isSet("weight-files") ? string2time(oc.getString("weight-period")) : SUMOTime_MAX), + oc.getBool("ignore-errors"), ttFunction, reversedTtFunction, (oc.isSet("weight-files") ? string2time(oc.getString("weight-period")) : SUMOTime_MAX), nullptr, nullptr, net.hasPermissions(), oc.isSet("restriction-params")); } else { throw ProcessError(TLF("Unknown routing Algorithm '%'!", routingAlgorithm)); diff --git a/src/utils/router/AFBuild.h b/src/utils/router/AFBuild.h old mode 100644 new mode 100755 index 6ce996b3db32..9707f7f47dbc --- a/src/utils/router/AFBuild.h +++ b/src/utils/router/AFBuild.h @@ -91,7 +91,6 @@ class AFBuild { /** @brief Constructor * @param[in] flippedEdges The flipped (aka reversed / backward) edges * @param[in] flippedPartition The k-d tree partition of the backward graph with flipped edges - * @param[in] numberOfLevels The number of levels * @param[in] unbuildIsWarning The flag indicating whether network unbuilds should issue warnings or errors * @param[in] flippedOperation The operation for a backward graph with flipped edges * @param[in] flippedLookup The lookup table for a backward graph with flipped edges @@ -102,14 +101,14 @@ class AFBuild { AFBuild( const std::vector*>& flippedEdges, const KDTreePartition, FlippedNode, V>* const flippedPartition, - int numberOfLevels, bool unbuildIsWarning, + bool unbuildIsWarning, typename SUMOAbstractRouter, V>::Operation flippedOperation, const std::shared_ptr flippedLookup = nullptr, const bool havePermissions = false, const bool haveRestrictions = false, const std::vector*>* toProhibit = nullptr) : myFlippedEdges(flippedEdges), myFlippedPartition(flippedPartition), - myNumberOfLevels(numberOfLevels), + myNumberOfLevels(-1), myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()), myFlippedOperation(flippedOperation), myFlippedLookupTable(flippedLookup), @@ -144,7 +143,7 @@ class AFBuild { * @param[in] vehicle The vehicle * @param[in] flagInfos The arc flag informations */ - void init(SUMOTime time, const V* const vehicle, std::vector& flagInfos); + void init(SUMOTime msTime, const V* const vehicle, std::vector& flagInfos); /** @brief Set the flipped partition * param[in] flippedPartition The flipped partition */ @@ -156,6 +155,9 @@ class AFBuild { * @return The SHARC level number corresponding to the given partition level number */ int partitionLevel2SHARCLevel(int partitionLevel) { + if (myNumberOfLevels < 0) { + throw std::runtime_error("The (actual) number of levels is uninitialized, call AFBuild::init() before."); + } return AFRouter::partitionLevel2SHARCLevel(partitionLevel, myNumberOfLevels); } /** @brief Converts a SHARC level number to a partition level number @@ -163,6 +165,9 @@ class AFBuild { * @return The partition level number corresponding to the given SHARC level number */ int sHARCLevel2PartitionLevel(int sHARCLevel) { + if (myNumberOfLevels < 0) { + throw std::runtime_error("The (actual) number of levels is uninitialized, call AFBuild::init() before."); + } return AFRouter::sHARCLevel2PartitionLevel(sHARCLevel, myNumberOfLevels); } @@ -199,7 +204,7 @@ class AFBuild { /// @brief The partition for the backward graph with flipped edges const KDTreePartition, FlippedNode, V>* myFlippedPartition; /// @brief The number of levels - const int myNumberOfLevels; + int myNumberOfLevels; /// @brief The handler for routing errors MsgHandler* const myErrorMsgHandler; /// @brief The object's operation to perform on a backward graph with flipped edges @@ -255,6 +260,11 @@ void AFBuild::init(SUMOTime msTime, const V* const vehicle, std::vector } } int sHARCLevel; + assert(myFlippedPartition != nullptr); + myNumberOfLevels = myFlippedPartition->getNumberOfLevels(); + if (myNumberOfLevels < 0) { + throw std::runtime_error("The (actual) number of levels is uninitialized, call myFlippedPartition->init() before."); + } for (sHARCLevel = 0; sHARCLevel < myNumberOfLevels - 1; sHARCLevel++) { #ifdef AFBU_DEBUG_LEVEL_0 std::cout << "Starting computation of flags of level " << sHARCLevel << " (levels run from 0 to " @@ -401,7 +411,7 @@ void AFBuild::computeArcFlags(SUMOTime msTime, const int sHARCLevel, co #endif // initialization of arc flag vectors initBoundaryEdges(boundaryEdges); -#ifdef AFBU_DEBUG_LEVEL_1 +#ifdef AFBU_DEBUG_LEVEL_0 long long int startTime = SysUtils::getCurrentMillis(); #endif std::map*, std::vector*>> incomingEdgesOfOutgoingBoundaryEdges; @@ -412,7 +422,8 @@ void AFBuild::computeArcFlags(SUMOTime msTime, const int sHARCLevel, co int index = 0; // boundary node index for (const FlippedNode* boundaryNode : boundaryNodes) { myNode2EdgeRouter->reset(vehicle); - if (myNode2EdgeRouter->computeNode2Edges(boundaryNode, boundaryEdges, vehicle, msTime)) { + // last param = true -> mute output of node2edge router + if (myNode2EdgeRouter->computeNode2Edges(boundaryNode, boundaryEdges, vehicle, msTime, true)) { #ifdef AFBU_DEBUG_LEVEL_2 std::cout << "Node-to-edge router succeeded." << std::endl; #endif diff --git a/src/utils/router/AFBuilder.h b/src/utils/router/AFBuilder.h old mode 100644 new mode 100755 index 7005f41890dd..c0ea8d23e111 --- a/src/utils/router/AFBuilder.h +++ b/src/utils/router/AFBuilder.h @@ -54,7 +54,7 @@ class AFBuilder { typedef AbstractLookupTable, V> FlippedLookupTable; /** @brief Constructor - * @param[in] numberOfLevels The number of levels + * @param[in] maxNumberOfLevels The number of levels * @param[in] edges The container with all edges of the network * @param[in] unbuildIsWarning The flag indicating whether network unbuilds should issue warnings or errors * @param[in] flippedOperation The operation for a backward graph with flipped edges @@ -63,15 +63,17 @@ class AFBuilder { * @param[in] haveRestrictions The flag indicating whether edges have restrictions which must be respected * @param[in] toProhibit The list of explicitly prohibited edges */ - AFBuilder(int numberOfLevels, const std::vector& edges, bool unbuildIsWarning, + AFBuilder(int maxNumberOfLevels, const std::vector& edges, bool unbuildIsWarning, typename SUMOAbstractRouter, V>::Operation flippedOperation, const std::shared_ptr flippedLookup = nullptr, const bool havePermissions = false, const bool haveRestrictions = false, const std::vector*>* toProhibit = nullptr) : myEdges(edges), - myNumberOfLevels(numberOfLevels), - myNumberOfArcFlags(2 * (myNumberOfLevels - 1)), -#ifdef AFBL_DEBUG_LEVEL_0 + myMaxNumberOfLevels(maxNumberOfLevels), +#ifdef AFBL_DEBUG_LEVEL_2 + myNumberOfArcFlags(-1), +#endif +#ifdef AFBL_DEBUG_LEVEL_2 myArcFlagsFileName("arcflags.csv"), #endif myAmClean(true) { @@ -91,12 +93,12 @@ class AFBuilder { #ifdef AFBL_DEBUG_LEVEL_0 std::cout << "Flipped edges / nodes are ready." << std::endl; #endif - myFlippedPartition = new KDTreePartition, FlippedNode, V>(myNumberOfLevels, + myFlippedPartition = new KDTreePartition, FlippedNode, V>(myMaxNumberOfLevels, myFlippedEdges, havePermissions, haveRestrictions); #ifdef AFBL_DEBUG_LEVEL_0 std::cout << "Instantiating arc flag build..." << std::endl; #endif - myArcFlagBuild = new AFBuild(myFlippedEdges, myFlippedPartition, numberOfLevels, unbuildIsWarning, + myArcFlagBuild = new AFBuild(myFlippedEdges, myFlippedPartition, unbuildIsWarning, flippedOperation, flippedLookup, havePermissions, haveRestrictions, toProhibit); #ifdef AFBL_DEBUG_LEVEL_0 @@ -128,11 +130,14 @@ class AFBuilder { * @return The partition level number */ int sHARCLevel2PartitionLevel(int sHARCLevel) { + if (myNumberOfLevels < 0) { + throw std::runtime_error("The (actual) number of levels is uninitialized, call AFBuilder::build() before."); + } return AFRouter::sHARCLevel2PartitionLevel(sHARCLevel, myNumberOfLevels); } protected: -#ifdef AFBL_DEBUG_LEVEL_0 +#ifdef AFBL_DEBUG_LEVEL_2 /** @brief Loads already precomputed arc flags from a CSV file (for testing purposes) * @param[in] fileName The name of the CSV file */ @@ -160,11 +165,13 @@ class AFBuilder { std::vector myFlagInfos; /// @brief The arc flag build AFBuild* myArcFlagBuild; - /// @brief The number of levels of the k-d tree partition of the network + /// @brief The maximum number of levels of the k-d tree partition of the network + int myMaxNumberOfLevels; + /// @brief The (actual) number of levels of the initialized k-d tree partition of the network int myNumberOfLevels; +#ifdef AFBL_DEBUG_LEVEL_2 /// @brief The number of arc flags per each edge int myNumberOfArcFlags; -#ifdef AFBL_DEBUG_LEVEL_0 /// @brief The name of the arc flags file. // @note This is a CSV file for convenience/testing purposes const std::string myArcFlagsFileName; @@ -201,12 +208,16 @@ std::vector::FlagInfo*>& AFBuilder::build(SUMOTime m assert(myFlippedPartition); if (myFlippedPartition->isClean()) { myFlippedPartition->init(vehicle); + myNumberOfLevels = myFlippedPartition->getNumberOfLevels(); +#ifdef AFBL_DEBUG_LEVEL_2 + myNumberOfArcFlags = 2 * (myNumberOfLevels - 1); +#endif myArcFlagBuild->setFlippedPartition(myFlippedPartition); } else { myFlippedPartition->reset(vehicle); } assert(myArcFlagBuild); -#ifdef AFBL_DEBUG_LEVEL_0 +#ifdef AFBL_DEBUG_LEVEL_2 bool fileExists = this->fileExists(myArcFlagsFileName); if (fileExists && myAmClean) { std::cout << "Loading arc flags from file " << myArcFlagsFileName << std::endl; @@ -215,13 +226,13 @@ std::vector::FlagInfo*>& AFBuilder::build(SUMOTime m } else { #endif myArcFlagBuild->init(msTime, vehicle, myFlagInfos); -#ifdef AFBL_DEBUG_LEVEL_0 +#ifdef AFBL_DEBUG_LEVEL_2 } #endif delete myFlippedPartition; myFlippedPartition = nullptr; -#ifdef AFBL_DEBUG_LEVEL_0 +#ifdef AFBL_DEBUG_LEVEL_2 if (!fileExists) { std::cout << "Saving arc flags..." << std::endl; // save flag vectors in a CSV file (one column, flag vectors in the order of edges) @@ -233,9 +244,10 @@ std::vector::FlagInfo*>& AFBuilder::build(SUMOTime m return myFlagInfos; } -#ifdef AFBL_DEBUG_LEVEL_0 +#ifdef AFBL_DEBUG_LEVEL_2 template void AFBuilder::saveFlagsToCsv(const std::string fileName) { + assert(myNumberOfArcFlags > 0); std::ofstream csvFile(fileName); for (FlagInfo* flagInfo : myFlagInfos) { if ((flagInfo->arcFlags).empty()) { diff --git a/src/utils/router/AFRouter.h b/src/utils/router/AFRouter.h old mode 100644 new mode 100755 index 1d7e0fd6790f..5bdc391533e9 --- a/src/utils/router/AFRouter.h +++ b/src/utils/router/AFRouter.h @@ -67,6 +67,9 @@ #define AFRO_DEBUG_LEVEL_0 #endif +/// @brief The maximum number of levels in the k-d tree partition +constexpr auto AFRO_MAX_NUMBER_OF_PARTITION_LEVELS = 5; //or 4 or 8 + // =========================================================================== // class definitions // =========================================================================== @@ -137,7 +140,6 @@ class AFRouter : public SUMOAbstractRouter { /** @brief Constructor * @param[in] edges The edges - * @param[in] partition A partition of the router's network wrt a k-d tree subdivision scheme * @param[in] unbuildIsWarning The flag indicating whether network unbuilds should issue warnings or errors * @param[in] operation The operation for a forward graph * @param[in] flippedOperation The operation for a backward graph with flipped edges @@ -148,7 +150,6 @@ class AFRouter : public SUMOAbstractRouter { * @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered or not */ AFRouter(const std::vector& edges, - const KDTreePartition* partition, bool unbuildIsWarning, typename SUMOAbstractRouter::Operation operation, typename SUMOAbstractRouter, V>::Operation flippedOperation, SUMOTime weightPeriod, const std::shared_ptr lookup = nullptr, @@ -156,13 +157,12 @@ class AFRouter : public SUMOAbstractRouter { const bool havePermissions = false, const bool haveRestrictions = false) : SUMOAbstractRouter("arcFlagRouter", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions), myFlagInfos(nullptr), - myPartition(partition), + myPartition(nullptr), myLookupTable(lookup), myMaxSpeed(NUMERICAL_EPS), myWeightPeriod(weightPeriod), myValidUntil(0), - myBuilder(new AFBuilder(myPartition->getNumberOfLevels(), edges, unbuildIsWarning, - flippedOperation, flippedLookup, havePermissions, haveRestrictions)), + myBuilder(nullptr), myType("arcFlagRouter"), myQueryVisits(0), myNumQueries(0), @@ -174,6 +174,10 @@ class AFRouter : public SUMOAbstractRouter { #endif myLastSettledEdgeCell(nullptr), myTargetEdgeCellLevel0(nullptr) { + myPartition = new KDTreePartition(AFRO_MAX_NUMBER_OF_PARTITION_LEVELS, edges, this->myHavePermissions, + this->myHaveRestrictions); + myBuilder = new AFBuilder(AFRO_MAX_NUMBER_OF_PARTITION_LEVELS, edges, unbuildIsWarning, + flippedOperation, flippedLookup, this->myHavePermissions, this->myHaveRestrictions); for (const E* const edge : edges) { this->myEdgeInfos.push_back(typename SUMOAbstractRouter::EdgeInfo(edge)); myMaxSpeed = MAX2(myMaxSpeed, edge->getSpeedLimit() * MAX2(1.0, edge->getLengthGeometryFactor())); @@ -181,8 +185,8 @@ class AFRouter : public SUMOAbstractRouter { } /** @brief "Normal" cloning constructor for uninitialized or time-dependent instances + * @param[in] edgeInfos The vector of edge information * @param[in] edges The edges - * @param[in] partition A partition of the router's network wrt a k-d tree subdivision scheme * @param[in] unbuildIsWarning The flag indicating whether network unbuilds should issue warnings or errors * @param[in] operation The operation for a forward graph * @param[in] flippedOperation The operation for a backward graph with flipped edges @@ -194,7 +198,6 @@ class AFRouter : public SUMOAbstractRouter { */ AFRouter(const std::vector::EdgeInfo>& edgeInfos, const std::vector& edges, - const KDTreePartition* partition, bool unbuildIsWarning, typename SUMOAbstractRouter::Operation operation, typename SUMOAbstractRouter, V>::Operation flippedOperation, @@ -203,13 +206,12 @@ class AFRouter : public SUMOAbstractRouter { const bool havePermissions = false, const bool haveRestrictions = false) : SUMOAbstractRouter("arcFlagRouter", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions), myFlagInfos(nullptr), - myPartition(partition), + myPartition(nullptr), myLookupTable(lookup), myMaxSpeed(NUMERICAL_EPS), myWeightPeriod(weightPeriod), myValidUntil(0), - myBuilder(new AFBuilder(myPartition->getNumberOfLevels(), edges, unbuildIsWarning, - flippedOperation, flippedLookup, havePermissions, haveRestrictions)), + myBuilder(nullptr), myType("arcFlagRouter"), myQueryVisits(0), myNumQueries(0), @@ -221,6 +223,10 @@ class AFRouter : public SUMOAbstractRouter { #endif myLastSettledEdgeCell(nullptr), myTargetEdgeCellLevel0(nullptr) { + myPartition = new KDTreePartition(AFRO_MAX_NUMBER_OF_PARTITION_LEVELS, edges, this->myHavePermissions, + this->myHaveRestrictions); + myBuilder = new AFBuilder(AFRO_MAX_NUMBER_OF_PARTITION_LEVELS, edges, unbuildIsWarning, + flippedOperation, flippedLookup, this->myHavePermissions, this->myHaveRestrictions); for (const auto& edgeInfo : edgeInfos) { this->myEdgeInfos.push_back(typename SUMOAbstractRouter::EdgeInfo(edgeInfo.edge)); myMaxSpeed = MAX2(myMaxSpeed, edgeInfo.edge->getSpeedLimit() * edgeInfo.edge->getLengthGeometryFactor()); @@ -229,7 +235,6 @@ class AFRouter : public SUMOAbstractRouter { /** @brief Special cloning constructor, only for time-independent instances which never rebuild arc infos * @param[in] edgeInfos The vector of edge information - * @param[in] partition A partition of the router's network wrt a k-d tree subdivision scheme * @param[in] unbuildIsWarning The flag indicating whether network unbuilds should issue warnings or errors * @param[in] operation The operation for a forward graph * @param[in] flagInfos The vector of arc flag information @@ -238,14 +243,13 @@ class AFRouter : public SUMOAbstractRouter { * @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered */ AFRouter(const std::vector::EdgeInfo>& edgeInfos, - const KDTreePartition* partition, bool unbuildIsWarning, typename SUMOAbstractRouter::Operation operation, std::vector* flagInfos, const std::shared_ptr lookup = nullptr, const bool havePermissions = false, const bool haveRestrictions = false) : SUMOAbstractRouter("arcFlagRouterClone", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions), myFlagInfos(flagInfos), - myPartition(partition), + myPartition(nullptr), myLookupTable(lookup), myMaxSpeed(NUMERICAL_EPS), myWeightPeriod(SUMOTime_MAX), @@ -271,6 +275,7 @@ class AFRouter : public SUMOAbstractRouter { /// @brief Destructor virtual ~AFRouter() { delete myBuilder; + delete myPartition; } /// @brief Cloning method @@ -279,12 +284,13 @@ class AFRouter : public SUMOAbstractRouter { // (i.e., I have been created with a maximum weight period) if (myWeightPeriod == SUMOTime_MAX && myFlagInfos != nullptr) { // we only need the arc infos once: - return new AFRouter(this->myEdgeInfos, myPartition, this->myErrorMsgHandler == MsgHandler::getWarningInstance(), + return new AFRouter(this->myEdgeInfos, this->myErrorMsgHandler == MsgHandler::getWarningInstance(), this->myOperation, myFlagInfos, myLookupTable, this->myHavePermissions, this->myHaveRestrictions); } // I am not a clone: I am either uninitialized, or initialized but time-dependent: // create another such guy (also flagged as a non-clone) - return new AFRouter(this->myEdgeInfos, myBuilder->getEdges(), myPartition, + assert(myBuilder != nullptr); + return new AFRouter(this->myEdgeInfos, myBuilder->getEdges(), this->myErrorMsgHandler == MsgHandler::getWarningInstance(), this->myOperation, myBuilder->getArcFlagBuild()->getFlippedOperation(), myWeightPeriod, myLookupTable, myBuilder->getArcFlagBuild()->getFlippedLookup(), @@ -353,13 +359,18 @@ class AFRouter : public SUMOAbstractRouter { if (myValidUntil == 0) { myValidUntil = myWeightPeriod; } - assert(myBuilder); + assert(myBuilder != nullptr); #ifdef AFRO_DEBUG_LEVEL_0 long long int firstCallStart = 0; long long int firstCallTime = 0; firstCallStart = SysUtils::getCurrentMillis(); std::cout << "Calling arc flag router for the first time during current weight period (arc flags build). This might take a while... " << std::endl; #endif + // reset forward partition wrt vehicle + delete myPartition; + myPartition = new KDTreePartition(AFRO_MAX_NUMBER_OF_PARTITION_LEVELS, myBuilder->getEdges(), this->myHavePermissions, + this->myHaveRestrictions); + myPartition->init(vehicle); myFlagInfos = &(myBuilder->build(myValidUntil - myWeightPeriod, vehicle)); #ifdef AFRO_DEBUG_LEVEL_0 firstCallTime = (SysUtils::getCurrentMillis() - firstCallStart); @@ -404,7 +415,6 @@ class AFRouter : public SUMOAbstractRouter { } return false; } - if (msTime >= myValidUntil) { assert(myBuilder != nullptr); // only time independent clones do not have a builder while (msTime >= myValidUntil) { @@ -412,8 +422,6 @@ class AFRouter : public SUMOAbstractRouter { } reset(vehicle); } - // rewind routing start time to building time (this can only be a gross approximation - // of time-dependent routing) msTime = myValidUntil - myWeightPeriod; double length = 0.; // dummy for the via edge cost update @@ -477,6 +485,7 @@ class AFRouter : public SUMOAbstractRouter { myFlagContextStartTime = SysUtils::getCurrentMillis(); #endif std::tuple flagContext = this->flagContext(follower.first, to); + // kept to make comparisons possible //std::tuple flagContext = this->flagContextNaive(follower.first, to); #ifdef AFRO_DEBUG_LEVEL_2 myFlagContextTimeSum += (SysUtils::getCurrentMillis() - myFlagContextStartTime); @@ -561,7 +570,7 @@ class AFRouter : public SUMOAbstractRouter { /// @brief Edge infos containing the associated edge and its arc flags std::vector* myFlagInfos; /// @brief The partition - const KDTreePartition* myPartition; + KDTreePartition* myPartition; /// @brief The comparator for edge information EdgeInfoComparator myComparator; /// @brief The lookup table for travel time heuristics diff --git a/src/utils/router/KDTreePartition.h b/src/utils/router/KDTreePartition.h old mode 100644 new mode 100755 index 6e22a297d8dd..d9175ab5997e --- a/src/utils/router/KDTreePartition.h +++ b/src/utils/router/KDTreePartition.h @@ -150,7 +150,7 @@ class KDTreePartition { * @param[in] cells The vector of all cells * @param[in] sortedNodes The vector of nodes * @note Initially unsorted, gets sorted wrt to the divisional scheme of the k-dtree after instantiation of the k-d tree - * @param[in] numberOfLevels The number of levels + * @param[in] maxNumberOfLevels The maximum number of levels * @param[in] level The level * @param[in] levelCells The vector of all level cell vectors * @param[in] axis The axis (X or X) @@ -170,7 +170,7 @@ class KDTreePartition { * @param[in] havePermissions The boolean flag indicating whether edge permissions need to be considered. * @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered. */ - Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, int numberOfLevels, + Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, const int maxNumberOfLevels, int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY, std::unordered_set* northernConflictNodes, std::unordered_set* easternConflictNodes, std::unordered_set* southernConflictNodes, std::unordered_set* westernConflictNodes, @@ -182,7 +182,7 @@ class KDTreePartition { * @param[in] levelCells The vector of all level cell vectors * @param[in] sortedNodes The vector of nodes * @note Initially unsorted, after instantiation gets sorted wrt to the k-d tree subdivision scheme - * @param[in] numberOfLevels The number of levels + * @param[in] maxNumberOfLevels The maximum number of levels * @param[in] level The level * @param[in] axis The axis (X or X) * @param[in] fromInclusive The from-index (inclusive) @@ -198,7 +198,7 @@ class KDTreePartition { * @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered or not */ Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, - int numberOfLevels, int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, + const int maxNumberOfLevels, int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY, bool isLeftOrLowerCell, const V* const vehicle, const bool havePermissions, const bool haveRestrictions); #endif @@ -222,7 +222,7 @@ class KDTreePartition { }; /** * @brief Returns all edges situated inside the cell - * @param[in] vehicle The vehicle + * @param[in] vehicle The optional vehicle parameter */ std::unordered_set* edgeSet(const V* const vehicle = nullptr) const { std::unordered_set* edgeSet = new std::unordered_set(); @@ -479,8 +479,8 @@ class KDTreePartition { std::vector>* myLevelCells; /// @brief The container with all nodes, sorted wrt to the k-d tree subdivisional scheme std::vector* mySortedNodes; - /// @brief The total number of levels of the k-d tree - int myNumberOfLevels; + /// @brief The maximum number of levels of the k-d tree + const int myMaxNumberOfLevels; /// @brief The level const int myLevel; /// @brief The number @@ -556,12 +556,12 @@ class KDTreePartition { }; // end of class Cell declaration /** @brief Constructor - * @param[in] numberOfLevels The number of levels + * @param[in] maxNumberOfLevels The maximum number of levels * @param[in] edges The container with all edges of the network * @param[in] havePermissions The boolean flag indicating whether edge permissions need to be considered or not * @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered or not */ - KDTreePartition(int numberOfLevels, const std::vector& edges, + KDTreePartition(const int maxNumberOfLevels, const std::vector& edges, const bool havePermissions, const bool haveRestrictions); /// @brief Destructor @@ -615,19 +615,19 @@ class KDTreePartition { mySortedNodes.resize(nodeCounter); mySortedNodes.shrink_to_fit(); myCells.resize(numberOfCells()); - myLevelCells.resize(myNumberOfLevels); + myLevelCells.resize(myMaxNumberOfLevels); // call the recursive cell constructor at the root (instantiates the whole k-d tree of cells) #ifdef KDTP_DEBUG_LEVEL_1 std::cout << "Calling root cell constructor..." << std::endl; #endif #ifdef KDTP_FOR_SYNTHETIC_NETWORKS - myRoot = new Cell(&myCells, &myLevelCells, &mySortedNodes, myNumberOfLevels, 0, Axis::Y, 0, mySortedNodes.size(), nullptr, -1, -1, -1, -1, + myRoot = new Cell(&myCells, &myLevelCells, &mySortedNodes, myMaxNumberOfLevels, 0, Axis::Y, 0, mySortedNodes.size(), nullptr, -1, -1, -1, -1, nullptr, nullptr, nullptr, nullptr, false, vehicle, havePermissions, haveRestrictions); #else - myRoot = new Cell(&myCells, &myLevelCells, &mySortedNodes, myNumberOfLevels, 0, Axis::Y, 0, mySortedNodes.size(), nullptr, -1, -1, -1, -1, + myRoot = new Cell(&myCells, &myLevelCells, &mySortedNodes, myMaxNumberOfLevels, 0, Axis::Y, 0, mySortedNodes.size(), nullptr, -1, -1, -1, -1, false, vehicle, myHavePermissions, myHaveRestrictions); #endif - assert(myRoot->smallestLeafLevel() + 1 <= myNumberOfLevels); + assert(myRoot->smallestLeafLevel() + 1 <= myMaxNumberOfLevels); myNumberOfLevels = myRoot->smallestLeafLevel() + 1; myCells.resize(numberOfCells()); myCells.shrink_to_fit(); @@ -706,6 +706,9 @@ class KDTreePartition { * @return The number of arc flags required in a multi-level approach */ int numberOfArcFlags() const { + if (myNumberOfLevels < 0) { + throw std::runtime_error("The (actual) number of levels is uninitialized, call KDTreePartition::init() before."); + } return 2 * (myNumberOfLevels - 1); } /// @brief Returns the number of levels L incl. the zeroth level @@ -714,15 +717,22 @@ class KDTreePartition { return myNumberOfLevels; } /** @brief Returns the number of cells at all levels + * @note In case the (number of) levels are not initialized yet, the number of cells at the maximum number of levels is returned * @return The number of cells at all levels */ size_t numberOfCells() const { + if (myNumberOfLevels < 0) { + return static_cast(std::lround(std::pow(2, myMaxNumberOfLevels)) - 1); + } return static_cast(std::lround(std::pow(2, myNumberOfLevels)) - 1); } /** @brief Returns the number of regions, i.e. the number of cells at the shallowest (bottom/leaf) level * @return The number of regions, i.e. the number of cells at the shallowest (bottom/leaf) level */ size_t numberOfRegions() const { + if (myNumberOfLevels < 0) { + throw std::runtime_error("The (actual) number of levels is uninitialized, call KDTreePartition::init() before."); + } return static_cast(std::lround(std::pow(2, myNumberOfLevels - 1))); } /// @brief Returns true iff the k-d tree is uninitialized @@ -747,7 +757,9 @@ class KDTreePartition { void cellNumbersAux(const N* node, const Cell* cell, int level, std::vector* nodeCellNumbers) const; /// @brief The root of the k-d tree const Cell* myRoot; - /// @brief The number of levels + /// @brief The maximum number of levels + const int myMaxNumberOfLevels; + /// @brief The (actual) number of levels int myNumberOfLevels; /// @brief The reference to a constant container with pointers to edges const std::vector& myEdges; @@ -770,15 +782,16 @@ class KDTreePartition { // =========================================================================== template -KDTreePartition::KDTreePartition(int numberOfLevels, const std::vector& edges, +KDTreePartition::KDTreePartition(const int maxNumberOfLevels, const std::vector& edges, const bool havePermissions, const bool haveRestrictions) : myRoot(nullptr), - myNumberOfLevels(numberOfLevels), + myMaxNumberOfLevels(maxNumberOfLevels), + myNumberOfLevels(-1), myEdges(edges), myHavePermissions(havePermissions), myHaveRestrictions(haveRestrictions), myAmClean(true) { /* still uninitialized */ - if (numberOfLevels <= 0) { + if (maxNumberOfLevels <= 0) { throw std::invalid_argument("KDTreePartition::KDTreePartition: zero or negative number of levels has been passed!"); } } @@ -851,14 +864,14 @@ void KDTreePartition::cellNumbersAux(const N* node, const Cell* cell, i template #ifdef KDTP_FOR_SYNTHETIC_NETWORKS -KDTreePartition::Cell::Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, int numberOfLevels, int level, +KDTreePartition::Cell::Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, const int maxNumberOfLevels, int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY, std::unordered_set* northernConflictNodes, std::unordered_set* easternConflictNodes, std::unordered_set* southernConflictNodes, std::unordered_set* westernConflictNodes, const V* const vehicle, const bool havePermissions, const bool haveRestrictions) : myCells(cells), myLevelCells(levelCells), mySortedNodes(sortedNodes), - myNumberOfLevels(numberOfLevels), + myMaxNumberOfLevels(maxNumberOfLevels), myLevel(level), myNumber(cellCounter()++), myAxis(axis), myFromInclusive(fromInclusive), @@ -877,15 +890,15 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto myHaveRestrictions(haveRestrictions), myMedianCoordinate(-1.) { #else -KDTreePartition::Cell::Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, int numberOfLevels, int level, +KDTreePartition::Cell::Cell(std::vector* cells, std::vector>* levelCells, std::vector* sortedNodes, const int maxNumberOfLevels, int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY, bool isLeftOrLowerCell, const V* const vehicle, const bool havePermissions, const bool haveRestrictions) : myCells(cells), myLevelCells(levelCells), mySortedNodes(sortedNodes), - myNumberOfLevels(numberOfLevels), + myMaxNumberOfLevels(maxNumberOfLevels), myLevel(level), - myNumber(cellCounter()++), + myNumber(myLevel == 0 ? 0 : cellCounter()++), myAxis(axis), myFromInclusive(fromInclusive), myToExclusive(toExclusive), @@ -898,6 +911,10 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto myHavePermissions(havePermissions), myHaveRestrictions(haveRestrictions), myMedianCoordinate(-1.) { + if (myLevel == 0) { + cellCounter() = 1; + smallestLeafLevel() = std::numeric_limits::max(); + } #endif // throw invalid argument exception if fromInclusive is greater than or equal to toExclusive if (myFromInclusive >= myToExclusive) { @@ -952,11 +969,17 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto std::cout << "Done. Now collecting boundary edges..." << std::endl; int i = 0; #endif - /// go through the nodes of the cell in order to identify and collect boundary nodes / edges - for (iter = first; iter != last; iter++) { #if defined(KDTP_KEEP_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS) - std::unordered_set nodeEdgeSet; + std::unordered_set nodeEdgeSet; +#endif +#if defined(KDTP_KEEP_INCOMING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_TO_NODES) + std::unordered_set boundaryToNodesSet; #endif +#if defined(KDTP_KEEP_OUTGOING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_FROM_NODES) + std::unordered_set boundaryFromNodesSet; +#endif + /// go through the nodes of the cell in order to identify and collect boundary nodes / edges + for (iter = first; iter != last; iter++) { #ifdef KDTP_DEBUG_LEVEL_1 if ((i++ % 10000) == 0) { std::cout << i << " cell nodes processed..." << std::endl; @@ -1006,7 +1029,6 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto #endif #if defined(KDTP_KEEP_INCOMING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_TO_NODES) const std::vector& incoming = (*iter)->getIncoming(); - std::unordered_set boundaryToNodesSet; for (const E* nodeEdge : incoming) { if (vehicle != nullptr && isProhibited(nodeEdge, vehicle)) { continue; @@ -1033,7 +1055,6 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto #endif #if defined(KDTP_KEEP_OUTGOING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_FROM_NODES) const std::vector& outgoing = (*iter)->getOutgoing(); - std::unordered_set boundaryFromNodesSet; for (const E* nodeEdge : outgoing) { if (vehicle != nullptr && isProhibited(nodeEdge, vehicle)) { continue; @@ -1057,6 +1078,15 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto std::copy(boundaryFromNodesSet.begin(), boundaryFromNodesSet.end(), std::back_inserter(myBoundaryFromNodes)); #endif +#endif +#if defined(KDTP_KEEP_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS) + nodeEdgeSet.clear(); +#endif +#if defined(KDTP_KEEP_INCOMING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_TO_NODES) + boundaryToNodesSet.clear(); +#endif +#if defined(KDTP_KEEP_OUTGOING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_FROM_NODES) + boundaryFromNodesSet.clear(); #endif } delete edgeSet; @@ -1137,7 +1167,7 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto completeSpatialInfo(); } // create subcells - if (myLevel < myNumberOfLevels - 1) { + if (myLevel < myMaxNumberOfLevels - 1) { // determine min/max X/Y-values to pass on to left or lower subcell double passMinX = -1, passMaxX = -1, passMinY = -1, passMaxY = -1; if (myAxis == Axis::X) { // left subcell @@ -1176,11 +1206,11 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto passSouthernConflictNodes = mySouthernConflictNodes; passWesternConflictNodes = myWesternConflictNodes; } - myLeftOrLowerSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), myFromInclusive, medianIndex + 1, this, + myLeftOrLowerSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myMaxNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), myFromInclusive, medianIndex + 1, this, passMinX, passMaxX, passMinY, passMaxY, passNorthernConflictNodes, passEasternConflictNodes, passSouthernConflictNodes, passWesternConflictNodes, true, vehicle, myHavePermissions, myHaveRestrictions); #else - myLeftOrLowerSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), myFromInclusive, medianIndex + 1, this, + myLeftOrLowerSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myMaxNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), myFromInclusive, medianIndex + 1, this, passMinX, passMaxX, passMinY, passMaxY, true, vehicle, myHavePermissions, myHaveRestrictions); #endif #ifdef KDTP_DEBUG_LEVEL_1 @@ -1212,11 +1242,11 @@ KDTreePartition::Cell::Cell(std::vector* cells, std::vecto passSouthernConflictNodes = conflictNodes.second; passWesternConflictNodes = myWesternConflictNodes; } - myRightOrUpperSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), medianIndex + 1, myToExclusive, this, + myRightOrUpperSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myMaxNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), medianIndex + 1, myToExclusive, this, passMinX, passMaxX, passMinY, passMaxY, passNorthernConflictNodes, passEasternConflictNodes, passSouthernConflictNodes, passWesternConflictNodes, false, vehicle, myHavePermissions, myHaveRestrictions); #else - myRightOrUpperSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), medianIndex + 1, myToExclusive, this, + myRightOrUpperSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myMaxNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), medianIndex + 1, myToExclusive, this, passMinX, passMaxX, passMinY, passMaxY, false, vehicle, myHavePermissions, myHaveRestrictions); #endif #ifdef KDTP_DEBUG_LEVEL_1