From 0b2dc8dbe7805000c8fc506fd004e6a2bf697c6b Mon Sep 17 00:00:00 2001 From: Grufoony Date: Wed, 21 Jan 2026 10:22:13 +0100 Subject: [PATCH 1/5] Itinerary to agents as shared pointer instead of Id --- benchmark/Bench_Agent.cpp | 43 ++++++---- benchmark/Bench_Intersection.cpp | 15 ++-- benchmark/Bench_Roundabout.cpp | 12 ++- benchmark/Bench_Street.cpp | 30 ++++--- src/dsf/mobility/Agent.cpp | 10 +-- src/dsf/mobility/Agent.hpp | 18 ++-- src/dsf/mobility/RoadDynamics.hpp | 69 +++++----------- test/mobility/Test_agent.cpp | 43 ++++++---- test/mobility/Test_dynamics.cpp | 131 +++++++++++++++--------------- test/mobility/Test_street.cpp | 32 ++++---- 10 files changed, 208 insertions(+), 195 deletions(-) diff --git a/benchmark/Bench_Agent.cpp b/benchmark/Bench_Agent.cpp index 18395dde..78472f4b 100644 --- a/benchmark/Bench_Agent.cpp +++ b/benchmark/Bench_Agent.cpp @@ -6,14 +6,18 @@ static void BM_Agent_ConstructionWithItineraryId(benchmark::State& state) { std::time_t spawnTime = 0; for (auto _ : state) { - dsf::mobility::Agent agent(spawnTime++, 1, 0); + dsf::mobility::Agent agent( + spawnTime++, std::make_shared(1, 1), 0); benchmark::DoNotOptimize(agent); } } static void BM_Agent_ConstructionWithTrip(benchmark::State& state) { std::time_t spawnTime = 0; - std::vector trip = {1, 2, 3}; + std::vector> trip = { + std::make_shared(1, 1), + std::make_shared(2, 2), + std::make_shared(3, 3)}; for (auto _ : state) { dsf::mobility::Agent agent(spawnTime++, trip, 0); benchmark::DoNotOptimize(agent); @@ -29,35 +33,35 @@ static void BM_Agent_ConstructionRandom(benchmark::State& state) { } static void BM_Agent_SetSrcNodeId(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { agent.setSrcNodeId(5); } } static void BM_Agent_SetStreetId(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { agent.setStreetId(10); } } static void BM_Agent_SetNextStreetId(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { agent.setNextStreetId(15); } } static void BM_Agent_SetSpeed(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { agent.setSpeed(50.0); } } static void BM_Agent_SetFreeTime(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); std::time_t freeTime = 100; for (auto _ : state) { agent.setFreeTime(freeTime++); @@ -65,14 +69,19 @@ static void BM_Agent_SetFreeTime(benchmark::State& state) { } static void BM_Agent_IncrementDistance(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { agent.incrementDistance(10.0); } } static void BM_Agent_UpdateItinerary(benchmark::State& state) { - std::vector trip = {1, 2, 3, 4, 5}; + std::vector> trip = { + std::make_shared(1, 1), + std::make_shared(2, 2), + std::make_shared(3, 3), + std::make_shared(4, 4), + std::make_shared(5, 5)}; dsf::mobility::Agent agent(0, trip, 0); for (auto _ : state) { agent.updateItinerary(); @@ -80,7 +89,7 @@ static void BM_Agent_UpdateItinerary(benchmark::State& state) { } static void BM_Agent_Reset(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); agent.setSpeed(50.0); agent.setStreetId(10); std::time_t spawnTime = 1000; @@ -91,7 +100,7 @@ static void BM_Agent_Reset(benchmark::State& state) { // Getter benchmarks - these are inline so very fast static void BM_Agent_Getters(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); agent.setSpeed(50.0); agent.setStreetId(10); for (auto _ : state) { @@ -117,15 +126,19 @@ static void BM_Agent_Getters(benchmark::State& state) { } static void BM_Agent_ItineraryId(benchmark::State& state) { - dsf::mobility::Agent agent(0, 1, 0); + dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { - auto itineraryId = agent.itineraryId(); - benchmark::DoNotOptimize(itineraryId); + auto const& pItinerary = agent.itinerary(); + benchmark::DoNotOptimize(pItinerary); } } static void BM_Agent_Trip(benchmark::State& state) { - dsf::mobility::Agent agent(0, {1, 2, 3}, 0); + std::vector> trip = { + std::make_shared(1, 1), + std::make_shared(2, 2), + std::make_shared(3, 3)}; + dsf::mobility::Agent agent(0, trip, 0); for (auto _ : state) { auto trip = agent.trip(); benchmark::DoNotOptimize(trip); diff --git a/benchmark/Bench_Intersection.cpp b/benchmark/Bench_Intersection.cpp index 09108e1c..b97f6717 100644 --- a/benchmark/Bench_Intersection.cpp +++ b/benchmark/Bench_Intersection.cpp @@ -24,7 +24,8 @@ static void BM_Intersection_AddAgentWithAngle(benchmark::State& state) { for (auto _ : state) { dsf::mobility::Intersection intersection(0); intersection.setCapacity(100); - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique( + spawnTime++, std::make_shared(1, 1), 0); intersection.addAgent(0.0, std::move(agent)); } } @@ -34,7 +35,8 @@ static void BM_Intersection_AddAgentWithoutAngle(benchmark::State& state) { for (auto _ : state) { dsf::mobility::Intersection intersection(0); intersection.setCapacity(100); - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique( + spawnTime++, std::make_shared(1, 1), 0); intersection.addAgent(std::move(agent)); } } @@ -43,8 +45,9 @@ static void BM_Intersection_nAgents(benchmark::State& state) { dsf::mobility::Intersection intersection(0); intersection.setCapacity(1000); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 100; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); intersection.addAgent(std::move(agent)); } for (auto _ : state) { @@ -57,8 +60,9 @@ static void BM_Intersection_Density(benchmark::State& state) { dsf::mobility::Intersection intersection(0); intersection.setCapacity(1000); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 100; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); intersection.addAgent(std::move(agent)); } for (auto _ : state) { @@ -71,8 +75,9 @@ static void BM_Intersection_IsFull(benchmark::State& state) { dsf::mobility::Intersection intersection(0); intersection.setCapacity(1000); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 100; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); intersection.addAgent(std::move(agent)); } for (auto _ : state) { diff --git a/benchmark/Bench_Roundabout.cpp b/benchmark/Bench_Roundabout.cpp index 3d88f726..5d3f13be 100644 --- a/benchmark/Bench_Roundabout.cpp +++ b/benchmark/Bench_Roundabout.cpp @@ -23,8 +23,9 @@ static void BM_Roundabout_Enqueue(benchmark::State& state) { dsf::mobility::Roundabout roundabout(0); roundabout.setCapacity(1000); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (auto _ : state) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); roundabout.enqueue(std::move(agent)); } } @@ -34,7 +35,8 @@ static void BM_Roundabout_Dequeue(benchmark::State& state) { for (auto _ : state) { dsf::mobility::Roundabout roundabout(0); roundabout.setCapacity(100); - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique( + spawnTime++, std::make_shared(1, 1), 0); roundabout.enqueue(std::move(agent)); auto dequeued = roundabout.dequeue(); benchmark::DoNotOptimize(dequeued); @@ -45,8 +47,9 @@ static void BM_Roundabout_Density(benchmark::State& state) { dsf::mobility::Roundabout roundabout(0); roundabout.setCapacity(1000); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 100; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); roundabout.enqueue(std::move(agent)); } for (auto _ : state) { @@ -59,8 +62,9 @@ static void BM_Roundabout_IsFull(benchmark::State& state) { dsf::mobility::Roundabout roundabout(0); roundabout.setCapacity(1000); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 100; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); roundabout.enqueue(std::move(agent)); } for (auto _ : state) { diff --git a/benchmark/Bench_Street.cpp b/benchmark/Bench_Street.cpp index 27a41d60..5a4927dd 100644 --- a/benchmark/Bench_Street.cpp +++ b/benchmark/Bench_Street.cpp @@ -22,8 +22,9 @@ static void BM_Street_AddAgent(benchmark::State& state) { 100, // capacity 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (auto _ : state) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); } } @@ -31,8 +32,9 @@ static void BM_Street_AddAgent(benchmark::State& state) { static void BM_Street_Enqueue(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); } size_t queueId = 0; @@ -47,8 +49,9 @@ static void BM_Street_Enqueue(benchmark::State& state) { static void BM_Street_Dequeue(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); street.enqueue(0); } @@ -64,8 +67,9 @@ static void BM_Street_Dequeue(benchmark::State& state) { static void BM_Street_nAgents(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); if (i % 2 == 0) street.enqueue(0); @@ -79,8 +83,9 @@ static void BM_Street_nAgents(benchmark::State& state) { static void BM_Street_Density(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); if (i % 2 == 0) street.enqueue(0); @@ -94,8 +99,9 @@ static void BM_Street_Density(benchmark::State& state) { static void BM_Street_nMovingAgents(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); } for (auto _ : state) { @@ -107,8 +113,9 @@ static void BM_Street_nMovingAgents(benchmark::State& state) { static void BM_Street_nExitingAgents(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); street.enqueue(0); } @@ -132,8 +139,9 @@ static void BM_CoilStreet_AddAgent(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); street.enableCounter(); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (auto _ : state) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); } } @@ -142,8 +150,9 @@ static void BM_CoilStreet_MeanFlow(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); street.enableCounter(); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); street.enqueue(0); if (i % 2 == 0) { @@ -160,8 +169,9 @@ static void BM_CoilStreet_Dequeue(benchmark::State& state) { dsf::mobility::Street street(0, {0, 1}, 100.0, 13.8888888889, 2, "test", {}, 100, 1.0); street.enableCounter(); std::time_t spawnTime = 0; + auto pItinerary = std::make_shared(1, 1); for (int i = 0; i < 50; ++i) { - auto agent = std::make_unique(spawnTime++, 1, 0); + auto agent = std::make_unique(spawnTime++, pItinerary, 0); street.addAgent(std::move(agent)); street.enqueue(0); } diff --git a/src/dsf/mobility/Agent.cpp b/src/dsf/mobility/Agent.cpp index 585e8d2d..c1ff16ce 100644 --- a/src/dsf/mobility/Agent.cpp +++ b/src/dsf/mobility/Agent.cpp @@ -4,20 +4,20 @@ namespace dsf::mobility { Agent::Agent(std::time_t const& spawnTime, - std::optional itineraryId, + std::shared_ptr itinerary, std::optional srcNodeId) : m_spawnTime{spawnTime}, m_freeTime{0}, m_id{0}, - m_trip{itineraryId.has_value() ? std::vector{*itineraryId} - : std::vector{}}, + m_trip{itinerary != nullptr ? std::vector>{itinerary} + : std::vector>{}}, m_srcNodeId{srcNodeId}, m_nextStreetId{std::nullopt}, m_itineraryIdx{0}, m_speed{0.}, m_distance{0.} {} Agent::Agent(std::time_t const& spawnTime, - std::vector const& trip, + std::vector> const& trip, std::optional srcNodeId) : m_spawnTime{spawnTime}, m_freeTime{spawnTime}, @@ -77,7 +77,7 @@ namespace dsf::mobility { m_itineraryIdx = 0; } - Id Agent::itineraryId() const { + std::shared_ptr const& Agent::itinerary() const { if (isRandom()) { throw std::logic_error( std::format("Agent {} is a random agent and has no itinerary", m_id)); diff --git a/src/dsf/mobility/Agent.hpp b/src/dsf/mobility/Agent.hpp index 616120da..debc83a1 100644 --- a/src/dsf/mobility/Agent.hpp +++ b/src/dsf/mobility/Agent.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,7 @@ namespace dsf::mobility { private: std::time_t m_spawnTime, m_freeTime; Id m_id; - std::vector m_trip; + std::vector> m_trip; std::optional m_streetId; std::optional m_srcNodeId; std::optional m_nextStreetId; @@ -44,14 +45,14 @@ namespace dsf::mobility { /// @param itineraryId Optional, The agent's destination node. If not provided, the agent is a random agent /// @param srcNodeId Optional, The id of the source node of the agent Agent(std::time_t const& spawnTime, - std::optional itineraryId = std::nullopt, + std::shared_ptr itinerary = nullptr, std::optional srcNodeId = std::nullopt); /// @brief Construct a new Agent object /// @param spawnTime The agent's spawn time /// @param itineraryIds The agent's itinerary /// @param srcNodeId Optional, The id of the source node of the agent Agent(std::time_t const& spawnTime, - std::vector const& trip, + std::vector> const& trip, std::optional srcNodeId = std::nullopt); void setSrcNodeId(Id srcNodeId); @@ -105,9 +106,9 @@ namespace dsf::mobility { /// @return The agent's id inline Id id() const noexcept { return m_id; }; /// @brief Get the agent's itinerary - /// @return The agent's itinerary - /// @throw std::logic_error if the agent is a random agent - Id itineraryId() const; + /// @return std::shared_ptr const&, The agent's current itinerary + /// @throw std::out_of_range if the agent has no itinerary + std::shared_ptr const& itinerary() const; /// @brief Get the agent's maximum distance /// @return The agent's maximum distance, or throw std::logic_error if not set inline auto maxDistance() const { @@ -124,7 +125,7 @@ namespace dsf::mobility { }; /// @brief Get the agent's trip /// @return The agent's trip - inline std::vector const& trip() const noexcept { return m_trip; }; + inline auto const& trip() const noexcept { return m_trip; }; /// @brief Get the id of the street currently occupied by the agent /// @return The id of the street currently occupied by the agent inline std::optional streetId() const noexcept { return m_streetId; }; @@ -177,7 +178,8 @@ struct std::formatter { agent.srcNodeId().has_value() ? std::to_string(agent.srcNodeId().value()) : "N/A", agent.nextStreetId().has_value() ? std::to_string(agent.nextStreetId().value()) : "N/A", - agent.isRandom() ? std::string("RANDOM") : std::to_string(agent.itineraryId()), + agent.isRandom() ? std::string("RANDOM") + : std::to_string(agent.itinerary()->id()), agent.speed(), agent.distance(), agent.spawnTime(), diff --git a/src/dsf/mobility/RoadDynamics.hpp b/src/dsf/mobility/RoadDynamics.hpp index 14d1ff10..7e541fd5 100644 --- a/src/dsf/mobility/RoadDynamics.hpp +++ b/src/dsf/mobility/RoadDynamics.hpp @@ -46,7 +46,7 @@ namespace dsf::mobility { class RoadDynamics : public Dynamics { std::vector m_nodeIndices; std::vector> m_agents; - std::unordered_map> m_itineraries; + std::unordered_map> m_itineraries; std::unordered_map m_originNodes; std::unordered_map m_destinationNodes; Size m_nAgents; @@ -76,8 +76,8 @@ namespace dsf::mobility { /// @param pAgent A std::unique_ptr to the agent to kill std::unique_ptr m_killAgent(std::unique_ptr pAgent); /// @brief Update the path of a single itinerary using Dijsktra's algorithm - /// @param pItinerary An std::unique_prt to the itinerary - void m_updatePath(std::unique_ptr const& pItinerary); + /// @param pItinerary An std::shared_ptr to the itinerary + void m_updatePath(std::shared_ptr const& pItinerary); /// @brief Get the next street id /// @param pAgent A std::unique_ptr to the agent @@ -243,7 +243,7 @@ namespace dsf::mobility { /// @param itinerary std::unique_ptr to the itinerary /// @throws std::invalid_argument If the itinerary already exists /// @throws std::invalid_argument If the itinerary's destination is not a node of the graph - void addItinerary(std::unique_ptr itinerary); + void addItinerary(std::shared_ptr itinerary); /// @brief Evolve the simulation /// @details Evolve the simulation by moving the agents and updating the travel times. @@ -270,10 +270,7 @@ namespace dsf::mobility { /// @brief Get the itineraries /// @return const std::unordered_map&, The itineraries - inline const std::unordered_map>& itineraries() - const noexcept { - return m_itineraries; - } + inline auto const& itineraries() const noexcept { return m_itineraries; } /// @brief Get the origin nodes of the graph /// @return std::unordered_map const& The origin nodes of the graph inline std::unordered_map const& originNodes() const noexcept { @@ -416,7 +413,7 @@ namespace dsf::mobility { m_nodeIndices.push_back(nodeId); } for (auto const& [nodeId, weight] : this->m_destinationNodes) { - m_itineraries.emplace(nodeId, std::make_unique(nodeId, nodeId)); + m_itineraries.emplace(nodeId, std::make_shared(nodeId, nodeId)); } std::for_each( this->graph().edges().cbegin(), @@ -461,7 +458,7 @@ namespace dsf::mobility { template requires(is_numeric_v) - void RoadDynamics::m_updatePath(std::unique_ptr const& pItinerary) { + void RoadDynamics::m_updatePath(std::shared_ptr const& pItinerary) { if (m_bCacheEnabled) { auto const& file = std::format("{}{}.ity", CACHE_FOLDER, pItinerary->id()); if (std::filesystem::exists(file)) { @@ -511,20 +508,7 @@ namespace dsf::mobility { // Get path targets for non-random agents std::vector pathTargets; if (!pAgent->isRandom()) { - try { - pathTargets = m_itineraries.at(pAgent->itineraryId())->path().at(pNode->id()); - } catch (const std::out_of_range&) { - if (!m_itineraries.contains(pAgent->itineraryId())) { - throw std::runtime_error( - std::format("No itinerary found with id {}", pAgent->itineraryId())); - } - throw std::runtime_error(std::format( - "No path found for itinerary {} at node {}. To solve this error, consider " - "using ODs extracted from a fully-connected subnetwork of your whole road " - "network or, alternatively, set an error probability.", - pAgent->itineraryId(), - pNode->id())); - } + pathTargets = pAgent->itinerary()->path().at(pNode->id()); } // Calculate transition probabilities for all valid outgoing edges @@ -626,12 +610,10 @@ namespace dsf::mobility { pAgent->setSpeed(0.); bool bArrived{false}; if (!pAgent->isRandom()) { - if (this->itineraries().at(pAgent->itineraryId())->destination() == - pStreet->target()) { + if (pAgent->itinerary()->destination() == pStreet->target()) { pAgent->updateItinerary(); } - if (this->itineraries().at(pAgent->itineraryId())->destination() == - pStreet->target()) { + if (pAgent->itinerary()->destination() == pStreet->target()) { bArrived = true; } } @@ -873,8 +855,7 @@ namespace dsf::mobility { } } if (!pAgentTemp->isRandom()) { - if (destinationNode->id() == - this->itineraries().at(pAgentTemp->itineraryId())->destination()) { + if (destinationNode->id() == pAgentTemp->itinerary()->destination()) { bArrived = true; spdlog::debug("Agent {} has arrived at destination node {}", pAgentTemp->id(), @@ -1166,6 +1147,7 @@ namespace dsf::mobility { requires(is_numeric_v) void RoadDynamics::setDestinationNodes( std::unordered_map const& destinationNodes) { + m_itineraries.clear(); m_destinationNodes.clear(); m_destinationNodes.reserve(destinationNodes.size()); auto sumWeights{0.}; @@ -1173,9 +1155,6 @@ namespace dsf::mobility { destinationNodes.end(), [this, &sumWeights](auto const& pair) -> void { sumWeights += pair.second; - if (this->itineraries().contains(pair.first)) { - return; - } this->addItinerary(pair.first, pair.first); }); if (sumWeights == 1.) { @@ -1223,6 +1202,7 @@ namespace dsf::mobility { requires(is_numeric_v) void RoadDynamics::setDestinationNodes( std::initializer_list destinationNodes) { + m_itineraries.clear(); auto const numNodes{destinationNodes.size()}; m_destinationNodes.clear(); m_destinationNodes.reserve(numNodes); @@ -1230,9 +1210,6 @@ namespace dsf::mobility { destinationNodes.end(), [this, &numNodes](auto const& nodeId) -> void { this->m_destinationNodes[nodeId] = 1. / numNodes; - if (this->itineraries().contains(nodeId)) { - return; - } this->addItinerary(nodeId, nodeId); }); } @@ -1241,6 +1218,7 @@ namespace dsf::mobility { template requires(std::is_convertible_v) void RoadDynamics::setDestinationNodes(TContainer const& destinationNodes) { + m_itineraries.clear(); auto const numNodes{destinationNodes.size()}; m_destinationNodes.clear(); m_destinationNodes.reserve(numNodes); @@ -1248,9 +1226,6 @@ namespace dsf::mobility { destinationNodes.end(), [this, &numNodes](auto const& nodeId) -> void { this->m_destinationNodes[nodeId] = 1. / numNodes; - if (this->itineraries().contains(nodeId)) { - return; - } this->addItinerary(nodeId, nodeId); }); } @@ -1313,7 +1288,7 @@ namespace dsf::mobility { } bool const bRandomItinerary{!optItineraryId.has_value() && !this->itineraries().empty()}; - std::optional itineraryId{std::nullopt}; + std::shared_ptr pItinerary; std::uniform_int_distribution itineraryDist{ 0, static_cast(this->itineraries().size() - 1)}; std::uniform_int_distribution streetDist{ @@ -1330,7 +1305,7 @@ namespace dsf::mobility { if (bRandomItinerary) { auto itineraryIt{this->itineraries().cbegin()}; std::advance(itineraryIt, itineraryDist(this->m_generator)); - itineraryId = itineraryIt->first; + pItinerary = itineraryIt->second; } auto streetIt = this->graph().edges().begin(); while (true) { @@ -1343,7 +1318,7 @@ namespace dsf::mobility { } auto const& street{streetIt->second}; this->addAgent( - std::make_unique(this->time_step(), itineraryId, street->source())); + std::make_unique(this->time_step(), pItinerary, street->source())); auto& pAgent{this->m_agents.back()}; pAgent->setStreetId(street->id()); this->setAgentSpeed(pAgent); @@ -1371,14 +1346,14 @@ namespace dsf::mobility { if (bUniformSpawn) { this->addAgent(); } else if (bSingleSource) { - this->addAgent(std::nullopt, spawnWeights.begin()->first); + this->addAgent(nullptr, spawnWeights.begin()->first); } else { auto const randValue{uniformDist(this->m_generator)}; double cumulativeWeight{0.}; for (auto const& [spawnNodeId, weight] : spawnWeights) { cumulativeWeight += weight; if (randValue <= cumulativeWeight) { - this->addAgent(std::nullopt, spawnNodeId); + this->addAgent(nullptr, spawnNodeId); break; } } @@ -1522,7 +1497,7 @@ namespace dsf::mobility { continue; } - this->addAgent(itineraryIt->first, *srcId); + this->addAgent(itineraryIt->second, *srcId); --nAgents; } } @@ -1564,12 +1539,12 @@ namespace dsf::mobility { template requires(std::is_constructible_v) void RoadDynamics::addItinerary(TArgs&&... args) { - addItinerary(std::make_unique(std::forward(args)...)); + addItinerary(std::make_shared(std::forward(args)...)); } template requires(is_numeric_v) - void RoadDynamics::addItinerary(std::unique_ptr itinerary) { + void RoadDynamics::addItinerary(std::shared_ptr itinerary) { if (m_itineraries.contains(itinerary->id())) { throw std::invalid_argument( std::format("Itinerary with id {} already exists.", itinerary->id())); diff --git a/test/mobility/Test_agent.cpp b/test/mobility/Test_agent.cpp index 59ff9bfd..c94cfbc2 100644 --- a/test/mobility/Test_agent.cpp +++ b/test/mobility/Test_agent.cpp @@ -9,15 +9,16 @@ #include "doctest.h" using Agent = dsf::mobility::Agent; +using Itinerary = dsf::mobility::Itinerary; TEST_CASE("Agent") { SUBCASE("Constructors") { - GIVEN("An agent and its itinerary ids") { - uint16_t itineraryId{0}; + GIVEN("An agent and its itinerary") { + auto itinerary = std::make_shared(0, 5); WHEN("The Agent is constructed") { - Agent agent{0, itineraryId}; + Agent agent{0, itinerary}; THEN("The agent and itinerary ids are set correctly") { - CHECK_EQ(agent.itineraryId(), itineraryId); + CHECK_EQ(agent.itinerary()->id(), itinerary->id()); CHECK_FALSE(agent.streetId().has_value()); CHECK_FALSE(agent.srcNodeId().has_value()); CHECK_EQ(agent.speed(), 0); @@ -26,13 +27,13 @@ TEST_CASE("Agent") { } } } - GIVEN("An agent, its itinerary ids, and a node id") { - uint16_t itineraryId{0}; - uint16_t srcNodeId{0}; + GIVEN("An agent, its itinerary, and a node id") { + auto itinerary = std::make_shared(0, 5); + dsf::Id srcNodeId{0}; WHEN("The Agent is constructed") { - Agent agent{0, itineraryId, srcNodeId}; + Agent agent{0, itinerary, srcNodeId}; THEN("The agent and itinerary ids are set correctly") { - CHECK_EQ(agent.itineraryId(), itineraryId); + CHECK_EQ(agent.itinerary()->id(), itinerary->id()); CHECK_FALSE(agent.streetId().has_value()); CHECK(agent.srcNodeId().has_value()); CHECK_EQ(agent.srcNodeId().value(), srcNodeId); @@ -52,7 +53,8 @@ TEST_CASE("Agent") { } TEST_CASE("Agent methods") { - Agent agent{0, 42, 7}; + auto itinerary42 = std::make_shared(42, 100); + Agent agent{0, itinerary42, 7}; SUBCASE("setSrcNodeId and srcNodeId") { agent.setSrcNodeId(99); CHECK(agent.srcNodeId().has_value()); @@ -91,15 +93,18 @@ TEST_CASE("Agent methods") { CHECK_EQ(agent.distance(), d0 + 5.5); } SUBCASE("updateItinerary advances index") { - std::vector trip = {1, 2, 3}; + auto it1 = std::make_shared(1, 10); + auto it2 = std::make_shared(2, 20); + auto it3 = std::make_shared(3, 30); + std::vector> trip = {it1, it2, it3}; Agent a2{0, trip, 0}; - CHECK_EQ(a2.itineraryId(), 1); + CHECK_EQ(a2.itinerary()->id(), 1); a2.updateItinerary(); - CHECK_EQ(a2.itineraryId(), 2); + CHECK_EQ(a2.itinerary()->id(), 2); a2.updateItinerary(); - CHECK_EQ(a2.itineraryId(), 3); + CHECK_EQ(a2.itinerary()->id(), 3); a2.updateItinerary(); // Should not go out of bounds - CHECK_EQ(a2.itineraryId(), 3); + CHECK_EQ(a2.itinerary()->id(), 3); } SUBCASE("reset resets state") { agent.setSpeed(10.); @@ -112,7 +117,7 @@ TEST_CASE("Agent methods") { CHECK_EQ(agent.freeTime(), 0); CHECK_EQ(agent.speed(), 0.); CHECK_EQ(agent.distance(), 0.); - CHECK_EQ(agent.itineraryId(), 42); // itinerary index reset + CHECK_EQ(agent.itinerary()->id(), 42); // itinerary index reset CHECK_FALSE(agent.streetId().has_value()); CHECK_EQ(agent.trip().size(), 1); } @@ -120,7 +125,8 @@ TEST_CASE("Agent methods") { TEST_CASE("Agent formatting") { SUBCASE("std::format with complete agent") { - Agent agent{0, 42, 7}; + auto itinerary42 = std::make_shared(42, 100); + Agent agent{0, itinerary42, 7}; agent.setStreetId(10); agent.setNextStreetId(15); agent.setSpeed(13.5); @@ -155,7 +161,8 @@ TEST_CASE("Agent formatting") { } SUBCASE("std::format with agent with optional nullopts") { - Agent agent{10, 99}; + auto itinerary99 = std::make_shared(99, 200); + Agent agent{10, itinerary99}; std::string formatted = std::format("{}", agent); CHECK(formatted.find("id: 0") != std::string::npos); diff --git a/test/mobility/Test_dynamics.cpp b/test/mobility/Test_dynamics.cpp index b47b4731..c72dd33d 100644 --- a/test/mobility/Test_dynamics.cpp +++ b/test/mobility/Test_dynamics.cpp @@ -116,13 +116,13 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{defaultNetwork, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(2, 2); WHEN("We add the agent") { - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); THEN("The agent is added") { CHECK_EQ(dynamics.nAgents(), 1); const auto& agent = dynamics.agents().at(0); // CHECK_EQ(agent->id(), 0); CHECK_EQ(agent->srcNodeId().value(), 0); - CHECK_EQ(agent->itineraryId(), 2); + CHECK_EQ(agent->itinerary()->id(), 2); } } } @@ -155,18 +155,23 @@ TEST_CASE("FirstOrderDynamics") { CHECK_EQ(dynamics.nAgents(), 3); #ifdef __APPLE__ CHECK_EQ(dynamics.graph().edge(422)->nAgents(), 1); - CHECK_EQ(dynamics.graph().edge(422)->movingAgents().top()->itineraryId(), 2); + CHECK_EQ(dynamics.graph().edge(422)->movingAgents().top()->itinerary()->id(), + 2); CHECK_EQ(dynamics.graph().edge(199)->nAgents(), 1); - CHECK_EQ(dynamics.graph().edge(199)->movingAgents().top()->itineraryId(), 2); + CHECK_EQ(dynamics.graph().edge(199)->movingAgents().top()->itinerary()->id(), + 2); CHECK_EQ(dynamics.graph().edge(166)->nAgents(), 1); - CHECK_EQ(dynamics.graph().edge(166)->movingAgents().top()->itineraryId(), 1); + CHECK_EQ(dynamics.graph().edge(166)->movingAgents().top()->itinerary()->id(), + 1); #else CHECK_EQ(dynamics.graph().edge(13)->nAgents(), 1); - CHECK_EQ(dynamics.graph().edge(13)->movingAgents().top()->itineraryId(), 2); + CHECK_EQ(dynamics.graph().edge(13)->movingAgents().top()->itinerary()->id(), 2); CHECK_EQ(dynamics.graph().edge(370)->nAgents(), 1); - CHECK_EQ(dynamics.graph().edge(370)->movingAgents().top()->itineraryId(), 1); + CHECK_EQ(dynamics.graph().edge(370)->movingAgents().top()->itinerary()->id(), + 1); CHECK_EQ(dynamics.graph().edge(404)->nAgents(), 1); - CHECK_EQ(dynamics.graph().edge(404)->movingAgents().top()->itineraryId(), 2); + CHECK_EQ(dynamics.graph().edge(404)->movingAgents().top()->itinerary()->id(), + 2); #endif } } @@ -183,10 +188,7 @@ TEST_CASE("FirstOrderDynamics") { dynamics.addAgentsRandomly(1, src, dst); THEN("The agents are correctly set") { CHECK_EQ(dynamics.nAgents(), 1); - CHECK_EQ(dynamics.itineraries() - .at(dynamics.agents().at(0)->itineraryId()) - ->destination(), - 2); + CHECK_EQ(dynamics.agents().at(0)->itinerary()->destination(), 2); CHECK_EQ(dynamics.agents().at(0)->srcNodeId().value(), 0); } } @@ -199,20 +201,11 @@ TEST_CASE("FirstOrderDynamics") { dynamics.addAgentsRandomly(3, src, dst); THEN("The agents are correctly set") { CHECK_EQ(dynamics.nAgents(), 3); - CHECK_EQ(dynamics.itineraries() - .at(dynamics.agents().at(0)->itineraryId()) - ->destination(), - 107); + CHECK_EQ(dynamics.agents().at(0)->itinerary()->destination(), 107); CHECK_EQ(dynamics.agents().at(0)->srcNodeId().value(), 27); - CHECK_EQ(dynamics.itineraries() - .at(dynamics.agents().at(1)->itineraryId()) - ->destination(), - 14); + CHECK_EQ(dynamics.agents().at(1)->itinerary()->destination(), 14); CHECK_EQ(dynamics.agents().at(1)->srcNodeId().value(), 1); - CHECK_EQ(dynamics.itineraries() - .at(dynamics.agents().at(2)->itineraryId()) - ->destination(), - 14); + CHECK_EQ(dynamics.agents().at(2)->itinerary()->destination(), 14); CHECK_EQ(dynamics.agents().at(2)->srcNodeId().value(), 118); } } @@ -278,19 +271,16 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{defaultNetwork, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(2, 2); WHEN("We add an agent with itinerary 2") { - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); THEN( "The number of agents is 1 and the destination is the same as the " "itinerary") { CHECK_EQ(dynamics.nAgents(), 1); - CHECK_EQ(dynamics.itineraries() - .at(dynamics.agents().at(0)->itineraryId()) - ->destination(), - 2); + CHECK_EQ(dynamics.agents().at(0)->itinerary()->destination(), 2); } } - WHEN("We add 69 agents with itinerary 0") { - dynamics.addAgents(69, 0); + WHEN("We add 69 agents") { + dynamics.addAgents(69); THEN("The number of agents is 69") { CHECK_EQ(dynamics.nAgents(), 69); } } } @@ -304,7 +294,7 @@ TEST_CASE("FirstOrderDynamics") { graph2.addStreets(s1, s2, s3); FirstOrderDynamics dynamics{graph2, false, 69, 0.0, dsf::PathWeight::LENGTH}; WHEN("We add an itinerary and update the paths") { - dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 2))); + dynamics.addItinerary(std::make_shared(0, 2)); dynamics.updatePaths(); THEN( "The number of itineraries is 1 and the path is updated and " @@ -436,14 +426,14 @@ TEST_CASE("FirstOrderDynamics") { WHEN( "We add an impossible itinerary (to source node) and update paths with " "throw_on_empty=true") { - dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 0))); + dynamics.addItinerary(std::make_shared(0, 0)); THEN("It throws an exception") { CHECK_THROWS(dynamics.updatePaths(true)); } } WHEN( "We add an impossible itinerary (to source node) and update paths with " "throw_on_empty=false") { - dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 0))); + dynamics.addItinerary(std::make_shared(0, 0)); dynamics.updatePaths(false); THEN("The itinerary is removed") { CHECK(dynamics.itineraries().empty()); } } @@ -460,7 +450,7 @@ TEST_CASE("FirstOrderDynamics") { dynamics.addItinerary(2, 2); dynamics.updatePaths(); WHEN("We add an agent randomly and evolve the dynamics") { - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); auto const& network{dynamics.graph()}; dynamics.evolve(false); // Agent goes into node 0 dynamics.evolve(false); // Agent goes from node 0 to street 0->1 @@ -494,7 +484,7 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(1, 1); dynamics.updatePaths(); - dynamics.addAgent(1, 0); + dynamics.addAgent(dynamics.itineraries().at(1), 0); WHEN("We evolve the dynamics") { dynamics.evolve(false); dynamics.evolve(false); @@ -518,9 +508,9 @@ TEST_CASE("FirstOrderDynamics") { RoadNetwork graph2; graph2.addStreets(s1, s2); FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; - dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 1))); + dynamics.addItinerary(std::make_shared(0, 1)); dynamics.updatePaths(); - dynamics.addAgent(0, 0); + dynamics.addAgent(dynamics.itineraries().at(0), 0); WHEN("We evolve the dynamics") { dynamics.evolve(false); dynamics.evolve(false); @@ -551,7 +541,7 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(1, 1); dynamics.updatePaths(); - dynamics.addAgent(1, 0); + dynamics.addAgent(dynamics.itineraries().at(1), 0); WHEN("We evolve the dynamics with reinsertion") { dynamics.evolve(true); dynamics.evolve(true); @@ -583,7 +573,8 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.setDestinationNodes({1, 2}); dynamics.updatePaths(); - std::vector trip{2, 1}; + std::vector> trip{dynamics.itineraries().at(2), + dynamics.itineraries().at(1)}; dynamics.addAgent(trip, 0); WHEN("We evolve the dynamics") { dynamics.evolve(false); @@ -630,7 +621,7 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); auto const& network{dynamics.graph()}; WHEN("We evolve the dynamics") { // Logger::setLogLevel(dsf::log_level_t::DEBUG); @@ -693,8 +684,8 @@ TEST_CASE("FirstOrderDynamics") { WHEN("We add agents and make the system evolve") { // Logger::setLogLevel(dsf::log_level_t::DEBUG); - dynamics.addAgent(2, 0); - dynamics.addAgent(4, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); + dynamics.addAgent(dynamics.itineraries().at(4), 0); THEN("The agents are not yet on the streets") { CHECK_FALSE(dynamics.agents().at(0)->streetId().has_value()); CHECK_FALSE(dynamics.agents().at(1)->streetId().has_value()); @@ -756,8 +747,8 @@ TEST_CASE("FirstOrderDynamics") { dynamics.updatePaths(); WHEN("We add agents and make the system evolve") { - dynamics.addAgent(2, 0); - dynamics.addAgent(4, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); + dynamics.addAgent(dynamics.itineraries().at(4), 0); dynamics.evolve(false); // Counter 0 dynamics.evolve(false); // Counter 1 THEN("The agents are correctly placed") { @@ -809,8 +800,10 @@ TEST_CASE("FirstOrderDynamics") { dynamics.setDestinationNodes({0, 2, 3, 4}); dynamics.updatePaths(); WHEN("We evolve the dynamics and optimize traffic lights") { - dynamics.addAgents(7, 0, 2); - dynamics.addAgents(7, 2, 0); + for (int i = 0; i < 7; ++i) { + dynamics.addAgent(dynamics.itineraries().at(0), 2); + dynamics.addAgent(dynamics.itineraries().at(2), 0); + } dynamics.setDataUpdatePeriod(4); for (int i = 0; i < 9; ++i) { dynamics.evolve(false); @@ -825,10 +818,12 @@ TEST_CASE("FirstOrderDynamics") { "We evolve the dynamics and optimize traffic lights with outgoing " "streets " "full") { - dynamics.addAgents(5, 0, 1); - dynamics.addAgents(5, 2, 1); - dynamics.addAgents(5, 3, 1); - dynamics.addAgents(5, 4, 1); + for (int i = 0; i < 5; ++i) { + dynamics.addAgent(dynamics.itineraries().at(0), 1); + dynamics.addAgent(dynamics.itineraries().at(2), 1); + dynamics.addAgent(dynamics.itineraries().at(3), 1); + dynamics.addAgent(dynamics.itineraries().at(4), 1); + } dynamics.setDataUpdatePeriod(8); for (int i = 0; i < 15; ++i) { dynamics.evolve(false); @@ -860,15 +855,15 @@ TEST_CASE("FirstOrderDynamics") { dynamics.addItinerary(0, 0); dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgent(2, 0); - dynamics.addAgent(0, 2); + dynamics.addAgent(dynamics.itineraries().at(2), 0); + dynamics.addAgent(dynamics.itineraries().at(0), 2); WHEN( "We evolve the dynamics adding an agent on the path of the agent " "with " "priority") { dynamics.evolve(false); // Agents into sources // dynamics.evolve(false); // Agents from sources to streets - dynamics.addAgent(2, 1); + dynamics.addAgent(dynamics.itineraries().at(2), 1); dynamics.evolve(false); // Agents into queues, other agent into roundabout dynamics.evolve(false); // Agents from queues to roundabout auto const& network{dynamics.graph()}; @@ -903,7 +898,7 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); WHEN("We evolve the dynamics") { dynamics.evolve(false); dynamics.evolve(false); @@ -929,7 +924,7 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); WHEN("We evolve the dynamics") { // Logger::setLogLevel(dsf::log_level_t::DEBUG); CHECK_EQ(dynamics.nAgents(), 1); @@ -964,7 +959,9 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0.5}; dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgents(4, 2, 0); + for (int i = 0; i < 4; ++i) { + dynamics.addAgent(dynamics.itineraries().at(2), 0); + } auto const& pStreet{dynamics.graph().edge(0)}; dynamics.evolve(false); dynamics.evolve(false); @@ -1007,9 +1004,9 @@ TEST_CASE("FirstOrderDynamics") { dynamics.updatePaths(); WHEN("We add agents and evolve the dynamics") { // add an agent in C, D, A - dynamics.addAgent(2, 4); // Second - dynamics.addAgent(2, 3); // Third - dynamics.addAgent(2, 1); // First + dynamics.addAgent(dynamics.itineraries().at(2), 4); // Second + dynamics.addAgent(dynamics.itineraries().at(2), 3); // Third + dynamics.addAgent(dynamics.itineraries().at(2), 1); // First dynamics.evolve(false); dynamics.evolve(false); dynamics.evolve(false); @@ -1031,9 +1028,9 @@ TEST_CASE("FirstOrderDynamics") { } } WHEN("We add agents of another itinerary and update the dynamics") { - dynamics.addAgent(1, 2); - dynamics.addAgent(1, 3); - dynamics.addAgent(1, 4); + dynamics.addAgent(dynamics.itineraries().at(1), 2); + dynamics.addAgent(dynamics.itineraries().at(1), 3); + dynamics.addAgent(dynamics.itineraries().at(1), 4); dynamics.evolve(false); dynamics.evolve(false); dynamics.evolve(false); @@ -1057,8 +1054,8 @@ TEST_CASE("FirstOrderDynamics") { WHEN("We set street priorities and add agents") { nodeO.addStreetPriority(5); nodeO.addStreetPriority(15); - dynamics.addAgent(2, 1); - dynamics.addAgent(2, 4); + dynamics.addAgent(dynamics.itineraries().at(2), 1); + dynamics.addAgent(dynamics.itineraries().at(2), 4); dynamics.evolve(false); dynamics.evolve(false); dynamics.evolve(false); @@ -1079,7 +1076,7 @@ TEST_CASE("FirstOrderDynamics") { FirstOrderDynamics dynamics{graph2, false, 69, 0., dsf::PathWeight::LENGTH}; dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgent(2, 0); + dynamics.addAgent(dynamics.itineraries().at(2), 0); // Evolve a few times to generate some data for (int i = 0; i < 5; ++i) { @@ -1346,7 +1343,7 @@ TEST_CASE("Stationary Weights Impact on Random Navigation") { // Add many random agents to Street 0 for (int i = 0; i < numAgents; ++i) { - auto agent = std::make_unique(0, std::nullopt, 0); + auto agent = std::make_unique(0, nullptr, 0); agent->setStreetId(0); agent->setSpeed(10.0); agent->setFreeTime(0); diff --git a/test/mobility/Test_street.cpp b/test/mobility/Test_street.cpp index a59b1e49..6a431222 100644 --- a/test/mobility/Test_street.cpp +++ b/test/mobility/Test_street.cpp @@ -93,11 +93,11 @@ TEST_CASE("Street") { } } SUBCASE("addAgent") { - Agent a1{0, 1, 0}; + Agent a1{0, nullptr, 0}; a1.setFreeTime(5); - Agent a2{0, 1, 0}; + Agent a2{0, nullptr, 0}; a2.setFreeTime(3); - Agent a3{0, 1, 0}; + Agent a3{0, nullptr, 0}; a3.setFreeTime(7); Street street{1, std::make_pair(0, 1), 3.5}; @@ -112,10 +112,10 @@ TEST_CASE("Street") { /*This tests the insertion of an agent in a street's queue*/ // define some agents - Agent a1{0, 1, 0}; // they are all in street 1 - Agent a2{0, 1, 0}; - Agent a3{0, 1, 0}; - Agent a4{0, 1, 0}; + Agent a1{0, nullptr, 0}; // they are all in street 1 + Agent a2{0, nullptr, 0}; + Agent a3{0, nullptr, 0}; + Agent a4{0, nullptr, 0}; Street street{1, std::make_pair(0, 1), 3.5}; // fill the queue @@ -140,10 +140,10 @@ TEST_CASE("Street") { /*This tests the exit of an agent from a street's queue*/ // define some agents - Agent a1{0, 1, 0}; // they are all in street 1 - Agent a2{0, 1, 0}; - Agent a3{0, 1, 0}; - Agent a4{0, 1, 0}; + Agent a1{0, nullptr, 0}; // they are all in street 1 + Agent a2{0, nullptr, 0}; + Agent a3{0, nullptr, 0}; + Agent a4{0, nullptr, 0}; Street street{1, std::make_pair(0, 1), 3.5}; // fill the queue @@ -188,7 +188,7 @@ TEST_CASE("Street with a coil") { street.enableCounter("EntryCoil", dsf::mobility::CounterPosition::ENTRY); CHECK_EQ(street.counterName(), "EntryCoil"); WHEN("An agent is added") { - street.addAgent(std::make_unique(0, 1)); + street.addAgent(std::make_unique(0, nullptr)); THEN("The input flow is one immediately") { CHECK_EQ(street.counts(), 1); } street.enqueue(0); THEN("The input flow is still one") { CHECK_EQ(street.counts(), 1); } @@ -202,7 +202,7 @@ TEST_CASE("Street with a coil") { street.enableCounter("", dsf::mobility::CounterPosition::MIDDLE); CHECK_EQ(street.counterName(), "Coil_1"); WHEN("An agent is added") { - street.addAgent(std::make_unique(0, 1)); + street.addAgent(std::make_unique(0, nullptr)); THEN("The input flow is zero") { CHECK_EQ(street.counts(), 0); } street.enqueue(0); THEN("The input flow is one once enqueued") { CHECK_EQ(street.counts(), 1); } @@ -218,7 +218,7 @@ TEST_CASE("Street with a coil") { street.enableCounter("ExitCoil", dsf::mobility::CounterPosition::EXIT); CHECK_EQ(street.counterName(), "ExitCoil"); WHEN("An agent is added and enqueued") { - street.addAgent(std::make_unique(0, 1)); + street.addAgent(std::make_unique(0, nullptr)); street.enqueue(0); THEN("The input flow is zero") { CHECK_EQ(street.counts(), 0); } street.dequeue(0); @@ -516,8 +516,8 @@ TEST_CASE("Street formatting") { Street street{30, std::make_pair(10, 20), 50.0, 15.0, 1}; // Add some agents - auto agent1 = std::make_unique(0, 1); - auto agent2 = std::make_unique(0, 2); + auto agent1 = std::make_unique(0, nullptr); + auto agent2 = std::make_unique(0, nullptr); street.addAgent(std::move(agent1)); street.addAgent(std::move(agent2)); From 003ee21ee65aa7884aba63f440717d42c7e9f84b Mon Sep 17 00:00:00 2001 From: Grufoony Date: Wed, 21 Jan 2026 10:33:10 +0100 Subject: [PATCH 2/5] Fix examples --- examples/stalingrado.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/stalingrado.cpp b/examples/stalingrado.cpp index e5d50580..32642ddd 100644 --- a/examples/stalingrado.cpp +++ b/examples/stalingrado.cpp @@ -79,9 +79,11 @@ int main() { // Create the dynamics FirstOrderDynamics dynamics{graph, false, 69, 0.6}; dynamics.setSpeedFluctuationSTD(0.2); - dynamics.addItinerary(std::unique_ptr(new Itinerary(4, 4))); + dynamics.addItinerary(4, 4); dynamics.updatePaths(); + auto pItinerary = dynamics.itineraries().at(4); + // lauch progress bar thread_t t([MAX_TIME]() { while (progress < MAX_TIME) { @@ -103,7 +105,7 @@ int main() { ofs << progress << ';' << coil->counts() << std::endl; coil->resetCounter(); } - dynamics.addAgents(*it, 4, 0); + dynamics.addAgents(*it, pItinerary, 0); } dynamics.evolve(false); ++progress; From 69df72f059d0aa9ea603ca504c1ef48f15034b86 Mon Sep 17 00:00:00 2001 From: Gregorio Berselli Date: Wed, 21 Jan 2026 11:08:03 +0100 Subject: [PATCH 3/5] Update src/dsf/mobility/Agent.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/dsf/mobility/Agent.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsf/mobility/Agent.hpp b/src/dsf/mobility/Agent.hpp index debc83a1..af60525d 100644 --- a/src/dsf/mobility/Agent.hpp +++ b/src/dsf/mobility/Agent.hpp @@ -107,7 +107,7 @@ namespace dsf::mobility { inline Id id() const noexcept { return m_id; }; /// @brief Get the agent's itinerary /// @return std::shared_ptr const&, The agent's current itinerary - /// @throw std::out_of_range if the agent has no itinerary + /// @throw std::logic_error if the agent has no itinerary std::shared_ptr const& itinerary() const; /// @brief Get the agent's maximum distance /// @return The agent's maximum distance, or throw std::logic_error if not set From 437ecb710ff33d43b818a85def6bd3255c758853 Mon Sep 17 00:00:00 2001 From: Grufoony Date: Wed, 21 Jan 2026 11:10:27 +0100 Subject: [PATCH 4/5] Bump version --- src/dsf/dsf.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dsf/dsf.hpp b/src/dsf/dsf.hpp index 545bb385..b3172ff9 100644 --- a/src/dsf/dsf.hpp +++ b/src/dsf/dsf.hpp @@ -6,7 +6,7 @@ static constexpr uint8_t DSF_VERSION_MAJOR = 4; static constexpr uint8_t DSF_VERSION_MINOR = 7; -static constexpr uint8_t DSF_VERSION_PATCH = 0; +static constexpr uint8_t DSF_VERSION_PATCH = 1; static auto const DSF_VERSION = std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH); From eba2a5129a9f23ea2f22dffd95cdab78cc4d0d2c Mon Sep 17 00:00:00 2001 From: Grufoony Date: Wed, 21 Jan 2026 11:31:24 +0100 Subject: [PATCH 5/5] Function names [skip ci] --- benchmark/Bench_Agent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmark/Bench_Agent.cpp b/benchmark/Bench_Agent.cpp index 78472f4b..c7bdbf76 100644 --- a/benchmark/Bench_Agent.cpp +++ b/benchmark/Bench_Agent.cpp @@ -3,7 +3,7 @@ #include #include -static void BM_Agent_ConstructionWithItineraryId(benchmark::State& state) { +static void BM_Agent_ConstructionWithItinerary(benchmark::State& state) { std::time_t spawnTime = 0; for (auto _ : state) { dsf::mobility::Agent agent( @@ -125,7 +125,7 @@ static void BM_Agent_Getters(benchmark::State& state) { } } -static void BM_Agent_ItineraryId(benchmark::State& state) { +static void BM_Agent_Itinerary(benchmark::State& state) { dsf::mobility::Agent agent(0, std::make_shared(1, 1), 0); for (auto _ : state) { auto const& pItinerary = agent.itinerary(); @@ -145,7 +145,7 @@ static void BM_Agent_Trip(benchmark::State& state) { } } -BENCHMARK(BM_Agent_ConstructionWithItineraryId); +BENCHMARK(BM_Agent_ConstructionWithItinerary); BENCHMARK(BM_Agent_ConstructionWithTrip); BENCHMARK(BM_Agent_ConstructionRandom); BENCHMARK(BM_Agent_SetSrcNodeId); @@ -157,7 +157,7 @@ BENCHMARK(BM_Agent_IncrementDistance); BENCHMARK(BM_Agent_UpdateItinerary); BENCHMARK(BM_Agent_Reset); BENCHMARK(BM_Agent_Getters); -BENCHMARK(BM_Agent_ItineraryId); +BENCHMARK(BM_Agent_Itinerary); BENCHMARK(BM_Agent_Trip); BENCHMARK_MAIN(); \ No newline at end of file