diff --git a/benchmark/Adj/BenchAdj.cpp b/benchmark/Adj/BenchAdj.cpp index 6b05d5754..3d0ab9314 100644 --- a/benchmark/Adj/BenchAdj.cpp +++ b/benchmark/Adj/BenchAdj.cpp @@ -1,6 +1,6 @@ #include -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "Itinerary.hpp" #include "FirstOrderDynamics.hpp" #include "SparseMatrix.hpp" @@ -11,11 +11,11 @@ using namespace dsm; using Bench = sb::Bench; int main() { - Graph graph{}; + RoadNetwork graph{}; graph.importOSMNodes("../test/data/forlì_nodes.csv"); graph.importOSMEdges("../test/data/forlì_edges.csv"); graph.buildAdj(); - auto const& adj{graph.adjMatrix()}; + auto const& adj{graph.adjacencyMatrix()}; auto const N{adj.n()}; SparseMatrix sm(N, N); for (const auto& [srcId, dstId] : adj.elements()) { diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 6ef9d1252..f4c303e57 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -10,7 +10,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) include_directories(../extern/benchmark/) # add subdirectories -# add_subdirectory(Graph) +# add_subdirectory(RoadNetwork) # add_subdirectory(Street) add_subdirectory(Dynamics) add_subdirectory(Adj) diff --git a/benchmark/Dynamics/BenchDynamics.cpp b/benchmark/Dynamics/BenchDynamics.cpp index 8ba7dc5d3..7ce0a2e0b 100644 --- a/benchmark/Dynamics/BenchDynamics.cpp +++ b/benchmark/Dynamics/BenchDynamics.cpp @@ -1,18 +1,18 @@ #include -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "Itinerary.hpp" #include "FirstOrderDynamics.hpp" #include "Bench.hpp" -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using Itinerary = dsm::Itinerary; using Dynamics = dsm::FirstOrderDynamics; using Bench = sb::Bench; int main() { - Graph graph{}; + RoadNetwork graph{}; graph.importOSMNodes("../test/data/forlì_nodes.csv"); graph.importOSMEdges("../test/data/forlì_edges.csv"); graph.buildAdj(); diff --git a/benchmark/Graph/BenchGraph.cpp b/benchmark/Graph/BenchGraph.cpp index dc5a0e9f4..6f50756d6 100644 --- a/benchmark/Graph/BenchGraph.cpp +++ b/benchmark/Graph/BenchGraph.cpp @@ -5,9 +5,9 @@ #include #include "Bench.hpp" -#include "Graph.hpp" +#include "RoadNetwork.hpp" -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using Intersection = dsm::Intersection; using Street = dsm::Street; using SparseMatrix = dsm::SparseMatrix; @@ -15,7 +15,7 @@ using SparseMatrix = dsm::SparseMatrix; using Bench = sb::Bench; int main() { - Graph g1; + RoadNetwork g1; const int n_rep{1000}; Bench b1(n_rep); @@ -48,18 +48,18 @@ int main() { } Bench b2; std::cout << "Benchmarking construction with adjacency matrix\n"; - b2.benchmark([&sm]() -> void { Graph g(sm); }); + b2.benchmark([&sm]() -> void { RoadNetwork g(sm); }); b2.print(); // Bench b3(1); - // Graph g2(sm); + // RoadNetwork g2(sm); // std::cout << "Benchmarking building the adjacency matrix\n"; // b3.benchmark([&g2]() -> void { g2.buildAdj(); }); // b3.print(); // Bench b4(3); - // Graph g3; - // g3.importMatrix("./Graph/data/matrix.dat"); + // RoadNetwork g3; + // g3.importMatrix("./RoadNetwork/data/matrix.dat"); // std::cout << "Benchmarking the algorithm for the shortest path\n"; // b4.benchmark([&g3]() -> void { g3.shortestPath(0, 1); }); // b4.print(); diff --git a/benchmark/Street/BenchStreet.cpp b/benchmark/Street/BenchStreet.cpp index beb9001c4..47f1345cd 100644 --- a/benchmark/Street/BenchStreet.cpp +++ b/benchmark/Street/BenchStreet.cpp @@ -4,7 +4,7 @@ #include #include "Bench.hpp" -#include "Graph.hpp" +#include "RoadNetwork.hpp" using Agent = dsm::Agent; using Street = dsm::Street; diff --git a/examples/slow_charge_rb.cpp b/examples/slow_charge_rb.cpp index d7584de39..81e57cc49 100644 --- a/examples/slow_charge_rb.cpp +++ b/examples/slow_charge_rb.cpp @@ -33,7 +33,7 @@ std::atomic bExitFlag{false}; using Unit = unsigned int; using Delay = uint8_t; -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using Dynamics = dsm::FirstOrderDynamics; using Street = dsm::Street; using SpireStreet = dsm::SpireStreet; @@ -83,7 +83,7 @@ int main(int argc, char** argv) { fs::create_directory(OUT_FOLDER); // Starting std::cout << "Using dsm version: " << dsm::version() << '\n'; - Graph graph{}; + RoadNetwork graph{}; std::cout << "Importing matrix.dat...\n"; graph.importMatrix(IN_MATRIX, false); graph.importCoordinates(IN_COORDS); @@ -98,20 +98,20 @@ int main(int argc, char** argv) { graph.makeRoundabout(i); } std::cout << "Making every street a spire...\n"; - for (const auto& [id, street] : graph.streetSet()) { + for (const auto& [id, street] : graph.edges()) { graph.makeSpireStreet(id); } // check isSpire for each street - for (const auto& [id, street] : graph.streetSet()) { + for (const auto& [id, street] : graph.edges()) { if (!street->isSpire()) { std::cerr << "Street " << id << " is not a spire.\n"; } } - const auto& adj = graph.adjMatrix(); + const auto& adj = graph.adjacencyMatrix(); auto const degreeVector = adj.getOutDegreeVector(); std::cout << "Setting roundabouts parameters..." << '\n'; - for (const auto& [nodeId, node] : graph.nodeSet()) { + for (const auto& [nodeId, node] : graph.nodes()) { auto& rb = dynamic_cast(*node); rb.setCapacity(degreeVector[nodeId]); rb.setTransportCapacity(degreeVector[nodeId]); @@ -149,7 +149,7 @@ int main(int argc, char** argv) { #ifdef PRINT_DENSITIES std::ofstream streetDensity(OUT_FOLDER + "densities.csv"); streetDensity << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetDensity << ';' << id; } streetDensity << '\n'; @@ -157,7 +157,7 @@ int main(int argc, char** argv) { #ifdef PRINT_FLOWS std::ofstream streetFlow(OUT_FOLDER + "flows.csv"); streetFlow << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetFlow << ';' << id; } streetFlow << '\n'; @@ -165,7 +165,7 @@ int main(int argc, char** argv) { #ifdef PRINT_SPEEDS std::ofstream streetSpeed(OUT_FOLDER + "speeds.csv"); streetSpeed << "time;"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetSpeed << ';' << id; } streetSpeed << '\n'; @@ -175,7 +175,7 @@ int main(int argc, char** argv) { std::ofstream inSpires(OUT_FOLDER + "in_spires.csv"); outSpires << "time"; inSpires << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { outSpires << ';' << id; inSpires << ';' << id; } @@ -223,7 +223,7 @@ int main(int argc, char** argv) { #ifdef PRINT_OUT_SPIRES outSpires << dynamics.time(); inSpires << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { auto& spire = dynamic_cast(*street); outSpires << ';' << spire.outputCounts(false); inSpires << ';' << spire.inputCounts(false); @@ -247,14 +247,14 @@ int main(int argc, char** argv) { if (dynamics.time() % 10 == 0) { #ifdef PRINT_DENSITIES streetDensity << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetDensity << ';' << street->density(); } streetDensity << std::endl; #endif #ifdef PRINT_FLOWS streetFlow << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { const auto& meanSpeed = dynamics.streetMeanSpeed(id); if (meanSpeed.has_value()) { streetFlow << ';' << meanSpeed.value() * street->density(); @@ -266,7 +266,7 @@ int main(int argc, char** argv) { #endif #ifdef PRINT_SPEEDS streetSpeed << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { const auto& meanSpeed = dynamics.streetMeanSpeed(id); if (meanSpeed.has_value()) { streetSpeed << ';' << meanSpeed.value(); diff --git a/examples/slow_charge_tl.cpp b/examples/slow_charge_tl.cpp index 1d1468bc8..313084a7a 100644 --- a/examples/slow_charge_tl.cpp +++ b/examples/slow_charge_tl.cpp @@ -34,7 +34,7 @@ std::atomic bExitFlag{false}; using Unit = unsigned int; using Delay = uint8_t; -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using Dynamics = dsm::FirstOrderDynamics; using Street = dsm::Street; using SpireStreet = dsm::SpireStreet; @@ -90,7 +90,7 @@ int main(int argc, char** argv) { fs::create_directory(OUT_FOLDER); // Starting std::cout << "Using dsm version: " << dsm::version() << '\n'; - Graph graph{}; + RoadNetwork graph{}; std::cout << "Importing matrix.dat...\n"; graph.importMatrix(IN_MATRIX, false); graph.importCoordinates(IN_COORDS); @@ -152,16 +152,16 @@ int main(int argc, char** argv) { graph.makeTrafficLight(i, 120); } std::cout << "Making every street a spire...\n"; - for (const auto& [id, street] : graph.streetSet()) { + for (const auto& [id, street] : graph.edges()) { graph.makeSpireStreet(id); } // check isSpire for each street - for (const auto& [id, street] : graph.streetSet()) { + for (const auto& [id, street] : graph.edges()) { if (!street->isSpire()) { std::cerr << "Street " << id << " is not a spire.\n"; } } - auto const degreeVector = graph.adjMatrix().getOutDegreeVector(); + auto const degreeVector = graph.adjacencyMatrix().getOutDegreeVector(); // create gaussian random number generator std::random_device rd; std::mt19937 gen(rd()); @@ -170,7 +170,7 @@ int main(int argc, char** argv) { std::array sda{0, 0}; auto random = [&d, &gen]() { return std::round(d(gen)); }; std::cout << "Setting traffic light parameters..." << '\n'; - for (const auto& [nodeId, node] : graph.nodeSet()) { + for (const auto& [nodeId, node] : graph.nodes()) { auto& tl = dynamic_cast(*node); tl.setCapacity(degreeVector[nodeId]); tl.setTransportCapacity(degreeVector[nodeId]); @@ -178,7 +178,7 @@ int main(int argc, char** argv) { while (value < 0.) { value = random(); } - const auto& col = graph.adjMatrix().getCol(nodeId); + const auto& col = graph.adjacencyMatrix().getCol(nodeId); std::set streets; const auto& refLat = node->coords().value().first; for (const auto& id : col) { @@ -208,7 +208,7 @@ int main(int argc, char** argv) { std::cout << "Creating dynamics...\n"; Dynamics dynamics{graph, true, SEED, 0.6}; - auto const& adj{dynamics.graph().adjMatrix()}; + auto const& adj{dynamics.graph().adjacencyMatrix()}; Unit n{0}; { std::vector destinationNodes; @@ -241,7 +241,7 @@ int main(int argc, char** argv) { #ifdef PRINT_DENSITIES std::ofstream streetDensity(OUT_FOLDER + "densities.csv"); streetDensity << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetDensity << ';' << id; } streetDensity << '\n'; @@ -249,7 +249,7 @@ int main(int argc, char** argv) { #ifdef PRINT_FLOWS std::ofstream streetFlow(OUT_FOLDER + "flows.csv"); streetFlow << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetFlow << ';' << id; } streetFlow << '\n'; @@ -257,7 +257,7 @@ int main(int argc, char** argv) { #ifdef PRINT_SPEEDS std::ofstream streetSpeed(OUT_FOLDER + "speeds.csv"); streetSpeed << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetSpeed << ';' << id; } streetSpeed << '\n'; @@ -267,7 +267,7 @@ int main(int argc, char** argv) { std::ofstream inSpires(OUT_FOLDER + "in_spires.csv"); outSpires << "time"; inSpires << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { outSpires << ';' << id; inSpires << ';' << id; } @@ -277,7 +277,7 @@ int main(int argc, char** argv) { #ifdef PRINT_TP std::ofstream outTP(OUT_FOLDER + "turn_probabilities.csv"); outTP << "time"; - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { outTP << ';' << id; } outTP << '\n'; @@ -335,7 +335,7 @@ int main(int argc, char** argv) { #ifdef PRINT_OUT_SPIRES outSpires << dynamics.time(); inSpires << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { auto& spire = dynamic_cast(*street); outSpires << ';' << spire.outputCounts(false); inSpires << ';' << spire.inputCounts(false); @@ -359,7 +359,7 @@ int main(int argc, char** argv) { #ifdef PRINT_TP const auto& tc{dynamics.turnCounts()}; outTP << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { const auto& probs{tc.at(id)}; outTP << ";["; const auto& nextStreets = TM.at(id); @@ -391,14 +391,14 @@ int main(int argc, char** argv) { if (dynamics.time() % 10 == 0) { #ifdef PRINT_DENSITIES streetDensity << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { streetDensity << ';' << street->density(); } streetDensity << std::endl; #endif #ifdef PRINT_FLOWS streetFlow << ';' << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { const auto& meanSpeed = dynamics.streetMeanSpeed(id); if (meanSpeed.has_value()) { streetFlow << ';' << meanSpeed.value() * street->density(); @@ -410,7 +410,7 @@ int main(int argc, char** argv) { #endif #ifdef PRINT_SPEEDS streetSpeed << dynamics.time(); - for (const auto& [id, street] : dynamics.graph().streetSet()) { + for (const auto& [id, street] : dynamics.graph().edges()) { const auto& meanSpeed = dynamics.streetMeanSpeed(id); if (meanSpeed.has_value()) { streetSpeed << ';' << meanSpeed.value(); diff --git a/examples/stalingrado.cpp b/examples/stalingrado.cpp index 5404593b4..775b451c5 100644 --- a/examples/stalingrado.cpp +++ b/examples/stalingrado.cpp @@ -24,7 +24,7 @@ std::atomic progress{0}; using Unit = unsigned int; using Delay = uint8_t; -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using Itinerary = dsm::Itinerary; using Dynamics = dsm::FirstOrderDynamics; using Street = dsm::Street; @@ -51,7 +51,7 @@ int main() { const auto MAX_TIME{static_cast(timeUnit * vehiclesToInsert.size())}; // Create the graph - Graph graph; + RoadNetwork graph; // Street(StreetId, Capacity, Length, vMax, (from, to)) dsm::Road::setMeanVehicleLength(8.); @@ -60,23 +60,27 @@ int main() { Street s23{13, std::make_pair(2, 3), 222., 13.9, 2}; Street s34{19, std::make_pair(3, 4), 651., 13.9, 2}; // Viale Aldo Moro - auto& tl1 = graph.addNode(1, 132); + graph.addNode(1, 132); + auto& tl1 = graph.node(1); tl1.setCycle(s01.id(), dsm::Direction::ANY, {62, 0}); // Via Donato Creti - auto& tl2 = graph.addNode(2, 141); + graph.addNode(2, 141); + auto& tl2 = graph.node(2); tl2.setCycle(s12.id(), dsm::Direction::ANY, {72, 0}); // Via del Lavoro - auto& tl3 = graph.addNode(3, 138); + graph.addNode(3, 138); + auto& tl3 = graph.node(3); tl3.setCycle(s23.id(), dsm::Direction::ANY, {88, 0}); // Viali - auto& tl4 = graph.addNode(4, 131); + graph.addNode(4, 131); + auto& tl4 = graph.node(4); tl4.setCycle(s34.id(), dsm::Direction::ANY, {81, 0}); graph.addStreets(s01, s12, s23, s34); graph.buildAdj(); graph.adjustNodeCapacities(); graph.makeSpireStreet(19); - auto& spire = dynamic_cast(*graph.street(19)); + auto& spire = graph.edge(19); dsm::Logger::info(std::format("Intersections: {}", graph.nNodes())); dsm::Logger::info(std::format("Streets: {}", graph.nEdges())); diff --git a/profiling/main.cpp b/profiling/main.cpp index acb7ffcd7..6cdab2ad0 100644 --- a/profiling/main.cpp +++ b/profiling/main.cpp @@ -8,22 +8,22 @@ using unit = uint32_t; -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using Itinerary = dsm::Itinerary; using Dynamics = dsm::FirstOrderDynamics; int main() { - Graph graph{}; + RoadNetwork graph{}; std::cout << "Importing matrix.dat...\n"; graph.importMatrix("../test/data/rawMatrix.dat", false); - std::cout << "Number of nodes: " << graph.nodeSet().size() << '\n' - << "Number of streets: " << graph.streetSet().size() << '\n'; - for (auto& streetPair : graph.streetSet()) { + std::cout << "Number of nodes: " << graph.nodes().size() << '\n' + << "Number of streets: " << graph.edges().size() << '\n'; + for (auto& streetPair : graph.edges()) { auto& street = streetPair.second; street->setCapacity(100); street->setMaxSpeed(10.); } - for (auto& nodePair : graph.nodeSet()) { + for (auto& nodePair : graph.nodes()) { auto& node = nodePair.second; node->setCapacity(10); } diff --git a/src/dsm/dsm.hpp b/src/dsm/dsm.hpp index c2f1ad909..cf001db4f 100644 --- a/src/dsm/dsm.hpp +++ b/src/dsm/dsm.hpp @@ -5,8 +5,8 @@ #include static constexpr uint8_t DSM_VERSION_MAJOR = 2; -static constexpr uint8_t DSM_VERSION_MINOR = 4; -static constexpr uint8_t DSM_VERSION_PATCH = 2; +static constexpr uint8_t DSM_VERSION_MINOR = 5; +static constexpr uint8_t DSM_VERSION_PATCH = 0; static auto const DSM_VERSION = std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH); @@ -19,7 +19,7 @@ namespace dsm { #include "headers/AdjacencyMatrix.hpp" #include "headers/Agent.hpp" -#include "headers/Graph.hpp" +#include "headers/RoadNetwork.hpp" #include "headers/Itinerary.hpp" #include "headers/Intersection.hpp" #include "headers/TrafficLight.hpp" diff --git a/src/dsm/headers/DijkstraWeights.hpp b/src/dsm/headers/DijkstraWeights.hpp index 1184e5f86..e3b0132d4 100644 --- a/src/dsm/headers/DijkstraWeights.hpp +++ b/src/dsm/headers/DijkstraWeights.hpp @@ -4,7 +4,7 @@ namespace dsm { - class Graph; + class RoadNetwork; namespace weight_functions { /// @brief Returns the length of a street given its source and destination nodes @@ -12,14 +12,14 @@ namespace dsm { /// @param node1 The source node id /// @param node2 The destination node id /// @return The length of the street - double streetLength(const Graph* graph, Id node1, Id node2); + double streetLength(const RoadNetwork* graph, Id node1, Id node2); /// @brief Returns the time to cross a street given its source and destination nodes /// @param graph A pointer to the graph /// @param node1 The source node id /// @param node2 The destination node id /// @return The time to cross the street /// @details This time also takes into account the number of agents on the street - double streetTime(const Graph* graph, Id node1, Id node2); + double streetTime(const RoadNetwork* graph, Id node1, Id node2); } // namespace weight_functions }; // namespace dsm diff --git a/src/dsm/headers/Dynamics.hpp b/src/dsm/headers/Dynamics.hpp index 64e1467d6..4ac18a5cc 100644 --- a/src/dsm/headers/Dynamics.hpp +++ b/src/dsm/headers/Dynamics.hpp @@ -28,7 +28,7 @@ #include "DijkstraWeights.hpp" #include "Itinerary.hpp" -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "SparseMatrix.hpp" #include "../utility/TypeTraits/is_agent.hpp" #include "../utility/TypeTraits/is_itinerary.hpp" @@ -73,12 +73,12 @@ namespace dsm { private: std::map> m_agents; std::unordered_map> m_itineraries; - std::function m_weightFunction; + std::function m_weightFunction; double m_weightTreshold; bool m_bCacheEnabled; protected: - Graph m_graph; + RoadNetwork m_graph; Time m_time, m_previousSpireTime; std::mt19937_64 m_generator; @@ -103,8 +103,8 @@ namespace dsm { auto const destinationID = pItinerary->destination(); std::vector shortestDistances(m_graph.nNodes()); tbb::parallel_for_each( - m_graph.nodeSet().cbegin(), - m_graph.nodeSet().cend(), + m_graph.nodes().cbegin(), + m_graph.nodes().cend(), [this, &shortestDistances, &destinationID](auto const& it) -> void { auto const nodeId{it.first}; if (nodeId == destinationID) { @@ -122,7 +122,7 @@ namespace dsm { }); AdjacencyMatrix path; // cycle over the nodes - for (const auto& [nodeId, node] : m_graph.nodeSet()) { + for (const auto& [nodeId, node] : m_graph.nodes()) { if (nodeId == destinationID) { continue; } @@ -131,7 +131,7 @@ namespace dsm { if (minDistance < 0.) { continue; } - auto const& row{m_graph.adjMatrix().getRow(nodeId)}; + auto const& row{m_graph.adjacencyMatrix().getRow(nodeId)}; for (const auto nextNodeId : row) { if (nextNodeId == destinationID) { if (std::abs(m_weightFunction(&m_graph, nodeId, nextNodeId) - minDistance) < @@ -191,7 +191,7 @@ namespace dsm { /// @param graph The graph representing the network /// @param useCache If true, the paths are cached (default is false) /// @param seed The seed for the random number generator (default is std::nullopt) - Dynamics(Graph& graph, + Dynamics(RoadNetwork& graph, bool useCache = false, std::optional seed = std::nullopt); @@ -207,7 +207,8 @@ namespace dsm { /// @details The weight function must return the weight of the edge between the source and the /// target node. One can use the predefined weight functions in the DijkstraWeights.hpp file, /// like weight_functions::streetLength or weight_functions::streetTime. - void setWeightFunction(std::function weightFunction); + void setWeightFunction( + std::function weightFunction); /// @brief Set the weight treshold for updating the paths /// @param weightTreshold The weight treshold /// @details If two paths differs only for a weight smaller than the treshold, the two paths are @@ -280,8 +281,8 @@ namespace dsm { void resetTime(); /// @brief Get the graph - /// @return const Graph&, The graph - const Graph& graph() const { return m_graph; }; + /// @return const RoadNetwork&, The graph + const RoadNetwork& graph() const { return m_graph; }; /// @brief Get the itineraries /// @return const std::unordered_map&, The itineraries const std::unordered_map>& itineraries() const { @@ -355,7 +356,7 @@ namespace dsm { }; template - Dynamics::Dynamics(Graph& graph, + Dynamics::Dynamics(RoadNetwork& graph, bool useCache, std::optional seed) : m_weightFunction{weight_functions::streetLength}, @@ -390,7 +391,7 @@ namespace dsm { template void Dynamics::setWeightFunction( - std::function weightFunction) { + std::function weightFunction) { m_weightFunction = weightFunction; } @@ -422,16 +423,16 @@ namespace dsm { template void Dynamics::addAgent(std::unique_ptr agent) { if (m_agents.size() + 1 > m_graph.maxCapacity()) { - throw std::overflow_error(Logger::buildExceptionMessage( - std::format("Graph is already holding the max possible number of agents ({})", - m_graph.maxCapacity()))); + throw std::overflow_error(Logger::buildExceptionMessage(std::format( + "RoadNetwork is already holding the max possible number of agents ({})", + m_graph.maxCapacity()))); } if (m_agents.contains(agent->id())) { throw std::invalid_argument(Logger::buildExceptionMessage( std::format("Agent with id {} already exists.", agent->id()))); } m_agents.emplace(agent->id(), std::move(agent)); - // Logger::debug(std::format("Added agent with id {} from node {} to node {}", + // Logger::info(std::format("Added agent with id {} from node {} to node {}", // m_agents.rbegin()->first, // m_agents.rbegin()->second->srcNodeId().value_or(-1), // m_agents.rbegin()->second->itineraryId())); @@ -504,7 +505,7 @@ namespace dsm { throw std::invalid_argument(Logger::buildExceptionMessage( std::format("Itinerary with id {} already exists.", itinerary->id()))); } - if (!m_graph.nodeSet().contains(itinerary->destination())) { + if (!m_graph.nodes().contains(itinerary->destination())) { throw std::invalid_argument(Logger::buildExceptionMessage(std::format( "Destination node with id {} not found", itinerary->destination()))); } @@ -530,7 +531,7 @@ namespace dsm { template double Dynamics::streetMeanSpeed(Id streetId) const { - auto const& pStreet{m_graph.street(streetId)}; + auto const& pStreet{m_graph.edge(streetId)}; auto const nAgents{pStreet->nAgents()}; if (nAgents == 0) { return 0.; @@ -545,8 +546,8 @@ namespace dsm { template Measurement Dynamics::streetMeanSpeed() const { std::vector speeds; - speeds.reserve(m_graph.streetSet().size()); - for (const auto& [streetId, street] : m_graph.streetSet()) { + speeds.reserve(m_graph.edges().size()); + for (const auto& [streetId, street] : m_graph.edges()) { speeds.push_back(streetMeanSpeed(streetId)); } return Measurement(speeds); @@ -556,8 +557,8 @@ namespace dsm { Measurement Dynamics::streetMeanSpeed(double threshold, bool above) const { std::vector speeds; - speeds.reserve(m_graph.streetSet().size()); - for (const auto& [streetId, street] : m_graph.streetSet()) { + speeds.reserve(m_graph.nEdges()); + for (const auto& [streetId, street] : m_graph.edges()) { if (above && (street->density(true) > threshold)) { speeds.push_back(streetMeanSpeed(streetId)); } else if (!above && (street->density(true) < threshold)) { @@ -569,18 +570,18 @@ namespace dsm { template Measurement Dynamics::streetMeanDensity(bool normalized) const { - if (m_graph.streetSet().empty()) { + if (m_graph.edges().empty()) { return Measurement(0., 0.); } std::vector densities; - densities.reserve(m_graph.streetSet().size()); + densities.reserve(m_graph.edges().size()); if (normalized) { - for (const auto& [streetId, street] : m_graph.streetSet()) { + for (const auto& [streetId, street] : m_graph.edges()) { densities.push_back(street->density(true)); } } else { double sum{0.}; - for (const auto& [streetId, street] : m_graph.streetSet()) { + for (const auto& [streetId, street] : m_graph.edges()) { densities.push_back(street->density(false) * street->length()); sum += street->length(); } @@ -596,8 +597,8 @@ namespace dsm { template Measurement Dynamics::streetMeanFlow() const { std::vector flows; - flows.reserve(m_graph.streetSet().size()); - for (const auto& [streetId, street] : m_graph.streetSet()) { + flows.reserve(m_graph.edges().size()); + for (const auto& [streetId, street] : m_graph.edges()) { flows.push_back(street->density() * this->streetMeanSpeed(streetId)); } return Measurement(flows); @@ -607,8 +608,8 @@ namespace dsm { Measurement Dynamics::streetMeanFlow(double threshold, bool above) const { std::vector flows; - flows.reserve(m_graph.streetSet().size()); - for (const auto& [streetId, street] : m_graph.streetSet()) { + flows.reserve(m_graph.edges().size()); + for (const auto& [streetId, street] : m_graph.edges()) { if (above && (street->density(true) > threshold)) { flows.push_back(street->density() * this->streetMeanSpeed(streetId)); } else if (!above && (street->density(true) < threshold)) { @@ -626,8 +627,8 @@ namespace dsm { } m_previousSpireTime = m_time; std::vector flows; - flows.reserve(m_graph.streetSet().size()); - for (const auto& [streetId, street] : m_graph.streetSet()) { + flows.reserve(m_graph.nEdges()); + for (const auto& [streetId, street] : m_graph.edges()) { if (street->isSpire()) { auto& spire = dynamic_cast(*street); flows.push_back(static_cast(spire.inputCounts(resetValue)) / deltaTime); @@ -644,8 +645,8 @@ namespace dsm { } m_previousSpireTime = m_time; std::vector flows; - flows.reserve(m_graph.streetSet().size()); - for (auto const& [streetId, street] : m_graph.streetSet()) { + flows.reserve(m_graph.edges().size()); + for (auto const& [streetId, street] : m_graph.edges()) { if (street->isSpire()) { auto& spire = dynamic_cast(*street); flows.push_back(static_cast(spire.outputCounts(resetValue)) / deltaTime); @@ -669,13 +670,13 @@ namespace dsm { } if (bEmptyFile) { file << "time"; - for (auto const& [streetId, _] : this->m_graph.streetSet()) { + for (auto const& [streetId, _] : this->m_graph.edges()) { file << separator << streetId; } file << std::endl; } file << this->time(); - for (auto const& [_, pStreet] : this->m_graph.streetSet()) { + for (auto const& [_, pStreet] : this->m_graph.edges()) { // keep 2 decimal digits; file << separator << std::fixed << std::setprecision(2) << pStreet->density(normalized); @@ -698,13 +699,13 @@ namespace dsm { } if (bEmptyFile) { file << "time"; - for (auto const& [streetId, _] : this->m_graph.streetSet()) { + for (auto const& [streetId, _] : this->m_graph.edges()) { file << separator << streetId; } file << std::endl; } file << this->time(); - for (auto const& [_, pStreet] : this->m_graph.streetSet()) { + for (auto const& [_, pStreet] : this->m_graph.edges()) { int value{0}; if (pStreet->isSpire()) { if (pStreet->isStochastic()) { @@ -733,13 +734,13 @@ namespace dsm { } if (bEmptyFile) { file << "time"; - for (auto const& [streetId, _] : this->m_graph.streetSet()) { + for (auto const& [streetId, _] : this->m_graph.edges()) { file << separator << streetId; } file << std::endl; } file << this->time(); - for (auto const& [_, pStreet] : this->m_graph.streetSet()) { + for (auto const& [_, pStreet] : this->m_graph.edges()) { int value{0}; if (pStreet->isSpire()) { if (pStreet->isStochastic()) { diff --git a/src/dsm/headers/FirstOrderDynamics.hpp b/src/dsm/headers/FirstOrderDynamics.hpp index 3c00e968c..9db060d8b 100644 --- a/src/dsm/headers/FirstOrderDynamics.hpp +++ b/src/dsm/headers/FirstOrderDynamics.hpp @@ -13,7 +13,7 @@ namespace dsm { /// @param useCache If true, the cache is used (default is false) /// @param seed The seed for the random number generator (default is std::nullopt) /// @param alpha The minimum speed rate (default is 0) - explicit FirstOrderDynamics(Graph& graph, + explicit FirstOrderDynamics(RoadNetwork& graph, bool useCache = false, std::optional seed = std::nullopt, double alpha = 0.); diff --git a/src/dsm/headers/Network.hpp b/src/dsm/headers/Network.hpp new file mode 100644 index 000000000..bbeee0aff --- /dev/null +++ b/src/dsm/headers/Network.hpp @@ -0,0 +1,200 @@ +#pragma once + +#include +#include + +#include "AdjacencyMatrix.hpp" +#include "Edge.hpp" +#include "Node.hpp" + +namespace dsm { + template + requires(std::is_base_of_v && std::is_base_of_v) + class Network { + protected: + AdjacencyMatrix m_adjacencyMatrix; + std::unordered_map> m_nodes; + std::unordered_map> m_edges; + + virtual void m_addMissingNodes(Id const edgeId); + + public: + /// @brief Construct a new Network object + /// @param adj The adjacency matrix representing the network + explicit Network(AdjacencyMatrix const& adj); + + /// @brief Get the adjacency matrix + /// @return AdjacencyMatrix The adjacency matrix + AdjacencyMatrix const& adjacencyMatrix() const; + /// @brief Get the nodes as an unordered map + /// @return std::unordered_map> The nodes + std::unordered_map> const& nodes() const; + /// @brief Get the edges as an unordered map + /// @return std::unordered_map> The edges + std::unordered_map> const& edges() const; + /// @brief Get the number of nodes + /// @return size_t The number of nodes + size_t nNodes() const; + /// @brief Get the number of edges + /// @return size_t The number of edges + size_t nEdges() const; + + /// @brief Add a node to the network + /// @tparam TNode The type of the node (default is node_t) + /// @tparam TArgs The types of the arguments + /// @param nodeId The node's id + /// @param args The arguments to pass to the node's constructor + template + requires(std::is_base_of_v && + std::constructible_from) + void addNode(Id nodeId, TArgs&&... args); + /// @brief Add an edge to the network + /// @tparam TEdge The type of the edge (default is edge_t) + /// @tparam TArgs The types of the arguments + /// @param edgeId The edge's id + /// @param args The arguments to pass to the edge's constructor + template + requires(std::is_base_of_v && + std::constructible_from) + void addEdge(Id edgeId, TArgs&&... args); + + /// @brief Get a node by id + /// @param nodeId The node's id + /// @return std::unique_ptr const& A const reference to the node + std::unique_ptr const& node(Id nodeId) const; + /// @brief Get an edge by id + /// @param edgeId The edge's id + /// @return std::unique_ptr const& A const reference to the edge + std::unique_ptr const& edge(Id edgeId) const; + /// @brief Get a node by id + /// @tparam TNode The type of the node + /// @param nodeId The node's id + /// @return TNode& A reference to the node + template + requires(std::is_base_of_v) + TNode& node(Id nodeId); + /// @brief Get an edge by id + /// @tparam TEdge The type of the edge + /// @param edgeId The edge's id + /// @return TEdge& A reference to the edge + template + requires(std::is_base_of_v) + TEdge& edge(Id edgeId); + }; + + template + requires(std::is_base_of_v && std::is_base_of_v) + void Network::m_addMissingNodes(Id const edgeId) { + auto const srcNodeId{m_edges.at(edgeId)->source()}; + auto const dstNodeId{m_edges.at(edgeId)->target()}; + if (srcNodeId < m_adjacencyMatrix.n() && dstNodeId < m_adjacencyMatrix.n()) { + if (!m_adjacencyMatrix.contains(srcNodeId, dstNodeId)) { + m_adjacencyMatrix.insert(srcNodeId, dstNodeId); + } + } else { + m_adjacencyMatrix.insert(srcNodeId, dstNodeId); + } + if (!m_nodes.contains(srcNodeId)) { + m_nodes.emplace(srcNodeId, std::make_unique(srcNodeId)); + } + if (!m_nodes.contains(dstNodeId)) { + m_nodes.emplace(dstNodeId, std::make_unique(dstNodeId)); + } + } + + template + requires(std::is_base_of_v && std::is_base_of_v) + Network::Network(AdjacencyMatrix const& adj) : m_adjacencyMatrix{adj} { + auto const& elements{m_adjacencyMatrix.elements()}; + auto const N{static_cast(elements.size())}; + std::for_each(elements.cbegin(), elements.cend(), [&](auto const& pair) { + auto const srcNodeId{pair.first}; + auto const dstNodeId{pair.second}; + auto const edgeId{srcNodeId * N + dstNodeId}; + if (!m_nodes.contains(srcNodeId)) { + m_nodes.emplace(srcNodeId, std::make_unique(srcNodeId)); + } + if (!m_nodes.contains(dstNodeId)) { + m_nodes.emplace(dstNodeId, std::make_unique(dstNodeId)); + } + addEdge(edgeId, std::make_pair(srcNodeId, dstNodeId)); + }); + } + + template + requires(std::is_base_of_v && std::is_base_of_v) + AdjacencyMatrix const& Network::adjacencyMatrix() const { + return m_adjacencyMatrix; + } + template + requires(std::is_base_of_v && std::is_base_of_v) + std::unordered_map> const& Network::nodes() + const { + return m_nodes; + } + template + requires(std::is_base_of_v && std::is_base_of_v) + std::unordered_map> const& Network::edges() + const { + return m_edges; + } + + template + requires(std::is_base_of_v && std::is_base_of_v) + size_t Network::nNodes() const { + return m_nodes.size(); + } + template + requires(std::is_base_of_v && std::is_base_of_v) + size_t Network::nEdges() const { + return m_edges.size(); + } + + template + requires(std::is_base_of_v && std::is_base_of_v) + template + requires(std::is_base_of_v && + std::constructible_from) + void Network::addNode(Id nodeId, TArgs&&... args) { + assert(!m_nodes.contains(nodeId)); + m_nodes.emplace(std::make_pair( + nodeId, std::make_unique(nodeId, std::forward(args)...))); + } + template + requires(std::is_base_of_v && std::is_base_of_v) + template + requires(std::is_base_of_v && + std::constructible_from) + void Network::addEdge(Id edgeId, TArgs&&... args) { + assert(!m_edges.contains(edgeId)); + m_edges.emplace(std::make_pair( + edgeId, std::make_unique(edgeId, std::forward(args)...))); + m_addMissingNodes(edgeId); + } + + template + requires(std::is_base_of_v && std::is_base_of_v) + std::unique_ptr const& Network::node(Id nodeId) const { + return m_nodes.at(nodeId); + } + template + requires(std::is_base_of_v && std::is_base_of_v) + std::unique_ptr const& Network::edge(Id edgeId) const { + return m_edges.at(edgeId); + } + + template + requires(std::is_base_of_v && std::is_base_of_v) + template + requires(std::is_base_of_v) + TNode& Network::node(Id nodeId) { + return dynamic_cast(*m_nodes.at(nodeId)); + } + template + requires(std::is_base_of_v && std::is_base_of_v) + template + requires(std::is_base_of_v) + TEdge& Network::edge(Id edgeId) { + return dynamic_cast(*m_edges.at(edgeId)); + } +} // namespace dsm \ No newline at end of file diff --git a/src/dsm/headers/Node.hpp b/src/dsm/headers/Node.hpp index c68782a1c..ca452db78 100644 --- a/src/dsm/headers/Node.hpp +++ b/src/dsm/headers/Node.hpp @@ -102,8 +102,8 @@ namespace dsm { /// @return Size The node's transport capacity int transportCapacity() const { return m_transportCapacity; } - virtual double density() const = 0; - virtual bool isFull() const = 0; + virtual double density() const { return 0.; }; + virtual bool isFull() const { return true; }; virtual bool isIntersection() const noexcept { return false; } virtual bool isTrafficLight() const noexcept { return false; } diff --git a/src/dsm/headers/RoadDynamics.hpp b/src/dsm/headers/RoadDynamics.hpp index 9604ba3e7..cff3e1373 100644 --- a/src/dsm/headers/RoadDynamics.hpp +++ b/src/dsm/headers/RoadDynamics.hpp @@ -28,7 +28,7 @@ #include "Agent.hpp" #include "DijkstraWeights.hpp" #include "Itinerary.hpp" -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "SparseMatrix.hpp" #include "../utility/TypeTraits/is_agent.hpp" #include "../utility/TypeTraits/is_itinerary.hpp" @@ -89,7 +89,7 @@ namespace dsm { /// @param graph The graph representing the network /// @param useCache If true, the cache is used (default is false) /// @param seed The seed for the random number generator (default is std::nullopt) - RoadDynamics(Graph& graph, + RoadDynamics(RoadNetwork& graph, bool useCache = false, std::optional seed = std::nullopt); @@ -184,7 +184,7 @@ namespace dsm { template requires(is_numeric_v) - RoadDynamics::RoadDynamics(Graph& graph, + RoadDynamics::RoadDynamics(RoadNetwork& graph, bool useCache, std::optional seed) : Dynamics>(graph, useCache, seed), @@ -192,16 +192,16 @@ namespace dsm { m_errorProbability{std::nullopt}, m_passageProbability{std::nullopt}, m_forcePriorities{false} { - for (const auto& [streetId, street] : this->m_graph.streetSet()) { + for (const auto& [streetId, street] : this->m_graph.edges()) { m_streetTails.emplace(streetId, 0); m_turnCounts.emplace(streetId, std::array{0, 0, 0, 0}); // fill turn mapping as [streetId, [left street Id, straight street Id, right street Id, U self street Id]] m_turnMapping.emplace(streetId, std::array{-1, -1, -1, -1}); // Turn mappings const auto& srcNodeId = street->target(); - for (const auto& targetId : this->m_graph.adjMatrix().getRow(srcNodeId)) { + for (const auto& targetId : this->m_graph.adjacencyMatrix().getRow(srcNodeId)) { auto const ss = srcNodeId * this->m_graph.nNodes() + targetId; - const auto& delta = street->angle() - this->m_graph.streetSet()[ss]->angle(); + const auto& delta = street->angle() - this->m_graph.edge(ss)->angle(); if (std::abs(delta) < std::numbers::pi) { if (delta < 0.) { m_turnMapping[streetId][dsm::Direction::RIGHT] = ss; @@ -224,7 +224,7 @@ namespace dsm { Id nodeId, std::optional streetId) { auto const& pAgent{this->agents().at(agentId)}; - auto possibleMoves = this->m_graph.adjMatrix().getRow(nodeId); + auto possibleMoves = this->m_graph.adjacencyMatrix().getRow(nodeId); if (!pAgent->isRandom()) { std::uniform_real_distribution uniformDist{0., 1.}; if (!(this->itineraries().empty())) { @@ -249,8 +249,8 @@ namespace dsm { nextStreetId = nodeId * this->m_graph.nNodes() + possibleMoves[moveDist(this->m_generator)]; } while (!this->m_graph.node(nodeId)->isRoundabout() && streetId.has_value() && - (this->m_graph.street(nextStreetId)->target() == - this->m_graph.street(streetId.value())->source()) && + (this->m_graph.edge(nextStreetId)->target() == + this->m_graph.edge(streetId.value())->source()) && (possibleMoves.size() > 1)); return nextStreetId; } @@ -333,7 +333,7 @@ namespace dsm { continue; } auto const& nextStreet{ - this->m_graph.street(this->agents().at(agentId)->nextStreetId().value())}; + this->m_graph.edge(this->agents().at(agentId)->nextStreetId().value())}; if (nextStreet->isFull()) { continue; } @@ -364,7 +364,7 @@ namespace dsm { } for (auto const [angle, agentId] : intersection.agents()) { auto const& nextStreet{ - this->m_graph.street(this->agents().at(agentId)->nextStreetId().value())}; + this->m_graph.edge(this->agents().at(agentId)->nextStreetId().value())}; if (nextStreet->isFull()) { if (m_forcePriorities) { return false; @@ -387,11 +387,11 @@ namespace dsm { } auto const agentId{roundabout.agents().front()}; auto const& nextStreet{ - this->m_graph.street(this->agents().at(agentId)->nextStreetId().value())}; + this->m_graph.edge(this->agents().at(agentId)->nextStreetId().value())}; if (!(nextStreet->isFull())) { if (this->agents().at(agentId)->streetId().has_value()) { const auto streetId = this->agents().at(agentId)->streetId().value(); - auto delta = nextStreet->angle() - this->m_graph.streetSet()[streetId]->angle(); + auto delta = nextStreet->angle() - this->m_graph.edge(streetId)->angle(); if (delta > std::numbers::pi) { delta -= 2 * std::numbers::pi; } else if (delta < -std::numbers::pi) { @@ -419,7 +419,7 @@ namespace dsm { 0, static_cast(this->m_graph.nNodes() - 1)}; for (const auto& [agentId, agent] : this->agents()) { if (agent->delay() > 0) { - const auto& street{this->m_graph.street(agent->streetId().value())}; + const auto& street{this->m_graph.edge(agent->streetId().value())}; if (agent->delay() > 1) { agent->incrementDistance(); } else { @@ -451,7 +451,7 @@ namespace dsm { } else { auto const nextStreetId = this->m_nextStreetId(agentId, street->target(), street->id()); - auto const& pNextStreet{this->m_graph.street(nextStreetId)}; + auto const& pNextStreet{this->m_graph.edge(nextStreetId)}; agent->setNextStreetId(nextStreetId); if (nLanes == 1) { street->enqueue(agentId, 0); @@ -501,7 +501,7 @@ namespace dsm { continue; } const auto& nextStreet{ - this->m_graph.streetSet()[this->m_nextStreetId(agentId, srcNode->id())]}; + this->m_graph.edge(this->m_nextStreetId(agentId, srcNode->id()))}; if (nextStreet->isFull()) { continue; } @@ -571,13 +571,13 @@ namespace dsm { } Id streetId{0}; do { - auto streetIt = this->m_graph.streetSet().begin(); + auto streetIt = this->m_graph.edges().begin(); Size step = streetDist(this->m_generator); std::advance(streetIt, step); streetId = streetIt->first; - } while (this->m_graph.streetSet()[streetId]->isFull() && + } while (this->m_graph.edge(streetId)->isFull() && this->nAgents() < this->m_graph.maxCapacity()); - const auto& street{this->m_graph.streetSet()[streetId]}; + const auto& street{this->m_graph.edge(streetId)}; this->addAgent(agentId, itineraryId, street->nodePair().first); auto const& pAgent{this->agents().at(agentId)}; pAgent->setStreetId(streetId); @@ -721,28 +721,28 @@ namespace dsm { bool const bUpdateData = m_dataUpdatePeriod.has_value() && this->m_time % m_dataUpdatePeriod.value() == 0; auto const N{this->m_graph.nNodes()}; - std::for_each( - this->m_graph.nodeSet().cbegin(), - this->m_graph.nodeSet().cend(), - [&](const auto& pair) { - for (auto const& sourceId : this->m_graph.adjMatrix().getCol(pair.first)) { - auto const streetId = sourceId * N + pair.first; - auto const& pStreet{this->m_graph.street(streetId)}; - if (bUpdateData) { - m_streetTails[streetId] += pStreet->nExitingAgents(); - } - for (auto i = 0; i < pStreet->transportCapacity(); ++i) { - this->m_evolveStreet(pStreet, reinsert_agents); - } - } - }); + std::for_each(this->m_graph.nodes().cbegin(), + this->m_graph.nodes().cend(), + [&](const auto& pair) { + for (auto const& sourceId : + this->m_graph.adjacencyMatrix().getCol(pair.first)) { + auto const streetId = sourceId * N + pair.first; + auto const& pStreet{this->m_graph.edge(streetId)}; + if (bUpdateData) { + m_streetTails[streetId] += pStreet->nExitingAgents(); + } + for (auto i = 0; i < pStreet->transportCapacity(); ++i) { + this->m_evolveStreet(pStreet, reinsert_agents); + } + } + }); std::for_each(this->m_agentsToRemove.cbegin(), this->m_agentsToRemove.cend(), [this](const auto& agentId) { this->removeAgent(agentId); }); m_agentsToRemove.clear(); // Move transport capacity agents from each node - std::for_each(this->m_graph.nodeSet().cbegin(), - this->m_graph.nodeSet().cend(), + std::for_each(this->m_graph.nodes().cbegin(), + this->m_graph.nodes().cend(), [&](const auto& pair) { for (auto i = 0; i < pair.second->transportCapacity(); ++i) { this->m_evolveNode(pair.second); @@ -768,7 +768,7 @@ namespace dsm { } auto const nCycles{static_cast(this->m_time - m_previousOptimizationTime) / m_dataUpdatePeriod.value()}; - for (const auto& [nodeId, pNode] : this->m_graph.nodeSet()) { + for (const auto& [nodeId, pNode] : this->m_graph.nodes()) { if (!pNode->isTrafficLight()) { continue; } @@ -779,10 +779,10 @@ namespace dsm { double inputGreenSum{0.}, inputRedSum{0.}; auto const N{this->m_graph.nNodes()}; - auto column = this->m_graph.adjMatrix().getCol(nodeId); + auto column = this->m_graph.adjacencyMatrix().getCol(nodeId); for (const auto& sourceId : column) { auto const streetId = sourceId * N + nodeId; - auto const& pStreet{this->m_graph.street(streetId)}; + auto const& pStreet{this->m_graph.edge(streetId)}; if (streetPriorities.contains(streetId)) { inputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes(); } else { @@ -824,9 +824,9 @@ namespace dsm { // - Check that the incoming streets have a density less than the mean one (eventually + tolerance): I want to avoid being into the cluster, better to be out or on the border // - If the previous check fails, do nothing double outputGreenSum{0.}, outputRedSum{0.}; - for (auto const& targetId : this->m_graph.adjMatrix().getRow(nodeId)) { + for (auto const& targetId : this->m_graph.adjacencyMatrix().getRow(nodeId)) { auto const streetId = nodeId * N + targetId; - auto const& pStreet{this->m_graph.street(streetId)}; + auto const& pStreet{this->m_graph.edge(streetId)}; if (streetPriorities.contains(streetId)) { outputGreenSum += m_streetTails.at(streetId) / pStreet->nLanes(); } else { diff --git a/src/dsm/headers/Graph.hpp b/src/dsm/headers/RoadNetwork.hpp similarity index 68% rename from src/dsm/headers/Graph.hpp rename to src/dsm/headers/RoadNetwork.hpp index cfd8b88c4..533a0e37f 100644 --- a/src/dsm/headers/Graph.hpp +++ b/src/dsm/headers/RoadNetwork.hpp @@ -1,9 +1,9 @@ -/// @file /src/dsm/headers/Graph.hpp -/// @file /src/dsm/headers/Graph.hpp -/// @brief Defines the Graph class. +/// @file /src/dsm/headers/RoadNetwork.hpp +/// @file /src/dsm/headers/RoadNetwork.hpp +/// @brief Defines the RoadNetwork class. /// -/// @details This file contains the definition of the Graph class. -/// The Graph class represents a graph in the network. It is templated by the type +/// @details This file contains the definition of the RoadNetwork class. +/// The RoadNetwork class represents a graph in the network. It is templated by the type /// of the graph's id and the type of the graph's capacity. /// The graph's id and capacity must be unsigned integral types. @@ -28,7 +28,7 @@ #include "AdjacencyMatrix.hpp" #include "DijkstraWeights.hpp" -#include "Node.hpp" +#include "Network.hpp" #include "Intersection.hpp" #include "TrafficLight.hpp" #include "Roundabout.hpp" @@ -42,14 +42,11 @@ namespace dsm { - /// @brief The Graph class represents a graph in the network. + /// @brief The RoadNetwork class represents a graph in the network. /// @tparam Id, The type of the graph's id. It must be an unsigned integral type. /// @tparam Size, The type of the graph's capacity. It must be an unsigned integral type. - class Graph { + class RoadNetwork : public Network { private: - std::unordered_map> m_nodes; - std::unordered_map> m_streets; - AdjacencyMatrix m_adjacencyMatrix; std::unordered_map m_nodeMapping; std::vector m_inputNodes; std::vector m_outputNodes; @@ -63,39 +60,39 @@ namespace dsm { /// @details The street angles are set using the node's coordinates. void m_setStreetAngles(); + void m_addMissingNodes(Id const nodeId) final; + public: - Graph(); - /// @brief Construct a new Graph object + RoadNetwork(); + /// @brief Construct a new RoadNetwork object /// @param adj An adjacency matrix made by a SparseMatrix representing the graph's adjacency matrix - Graph(AdjacencyMatrix const& adj); - /// @brief Construct a new Graph object + RoadNetwork(AdjacencyMatrix const& adj); + /// @brief Construct a new RoadNetwork object /// @param streetSet A map of streets representing the graph's streets - Graph(const std::unordered_map>& streetSet); + RoadNetwork(const std::unordered_map>& streetSet); - Graph(const Graph& other) { + RoadNetwork(const RoadNetwork& other) : Network{AdjacencyMatrix()} { std::for_each(other.m_nodes.begin(), other.m_nodes.end(), [this](const auto& pair) { this->m_nodes.emplace(pair.first, pair.second.get()); }); - std::for_each( - other.m_streets.begin(), other.m_streets.end(), [this](const auto& pair) { - this->m_streets.emplace(pair.first, pair.second.get()); - }); + std::for_each(other.m_edges.begin(), other.m_edges.end(), [this](const auto& pair) { + this->m_edges.emplace(pair.first, pair.second.get()); + }); m_nodeMapping = other.m_nodeMapping; m_adjacencyMatrix = other.m_adjacencyMatrix; m_inputNodes = other.m_inputNodes; m_outputNodes = other.m_outputNodes; } - Graph& operator=(const Graph& other) { + RoadNetwork& operator=(const RoadNetwork& other) { std::for_each(other.m_nodes.begin(), other.m_nodes.end(), [this](const auto& pair) { this->m_nodes.insert_or_assign(pair.first, std::unique_ptr(pair.second.get())); }); - std::for_each( - other.m_streets.begin(), other.m_streets.end(), [this](const auto& pair) { - this->m_streets.insert_or_assign(pair.first, - std::make_unique(*pair.second)); - }); + std::for_each(other.m_edges.begin(), other.m_edges.end(), [this](const auto& pair) { + this->m_edges.insert_or_assign(pair.first, + std::make_unique(*pair.second)); + }); m_nodeMapping = other.m_nodeMapping; m_adjacencyMatrix = other.m_adjacencyMatrix; m_inputNodes = other.m_inputNodes; @@ -104,8 +101,8 @@ namespace dsm { return *this; } - Graph(Graph&&) = default; - Graph& operator=(Graph&&) = default; + RoadNetwork(RoadNetwork&&) = default; + RoadNetwork& operator=(RoadNetwork&&) = default; /// @brief Build the graph's adjacency matrix and computes max capacity /// @details The adjacency matrix is built using the graph's streets and nodes. N.B.: The street ids @@ -157,18 +154,6 @@ namespace dsm { /// @throws std::invalid_argument if the file is not found or invalid void exportMatrix(std::string path = "./matrix.dsm", bool isAdj = true); - /// @brief Add a node to the graph - /// @param node A std::unique_ptr to the node to add - void addNode(std::unique_ptr node); - /// @brief Add a node of type node_t to the graph - /// @param id The node's id - /// @param args The node's arguments to forward to the constructor - /// @return A reference to the added node - template - requires(std::is_base_of_v, - std::constructible_from) - node_t& addNode(Id id, TArgs&&... args); - template requires is_node_v> && (is_node_v> && ...) @@ -201,17 +186,6 @@ namespace dsm { /// @throws std::invalid_argument if the node does not exist Station& makeStation(Id nodeId, const unsigned int managementTime); - /// @brief Add an edge of type edge_t to the graph - /// @param edge A std::unique_ptr to the edge to add - /// @param args The edge's arguments to forward to the constructor - /// @return A reference to the added edge - template - requires(std::is_base_of_v, - std::constructible_from) - edge_t& addEdge(Id id, TArgs&&... args); - /// @brief Add a street to the graph - /// @param street A std::unique_ptr to the street to add - void addStreet(std::unique_ptr street); /// @brief Add a street to the graph /// @param street A reference to the street to add void addStreet(const Street& street); @@ -225,37 +199,6 @@ namespace dsm { (is_street_v> && ...) void addStreets(T1&& street, Tn&&... streets); - /// @brief Get the graph's adjacency matrix - /// @return A const reference to the graph's adjacency matrix - AdjacencyMatrix const& adjMatrix() const { return m_adjacencyMatrix; } - /// @brief Get the graph's number of nodes - /// @return size_t The number of nodes in the graph - size_t nNodes() const { return m_nodes.size(); } - /// @brief Get the graph's node map - /// @return A std::unordered_map containing the graph's nodes - const std::unordered_map>& nodeSet() const { - return m_nodes; - } - /// @brief Get the graph's node map - /// @return A std::unordered_map containing the graph's nodes - std::unordered_map>& nodeSet() { return m_nodes; } - /// @brief Get a node from the graph - /// @param id The node's id - const std::unique_ptr& node(Id id) const { return m_nodes.at(id); } - /// @brief Get the Graph's number of streets - /// @return size_t The number of streets in the graph - size_t nEdges() const { return m_streets.size(); } - /// @brief Get the graph's street map - /// @return A std::unordered_map containing the graph's streets - const std::unordered_map>& streetSet() const { - return m_streets; - } - /// @brief Get the graph's street map - /// @return A std::unordered_map containing the graph's streets - std::unordered_map>& streetSet() { return m_streets; } - /// @brief Get a street from the graph - /// @param id The street's id - const std::unique_ptr& street(Id id) const { return m_streets.at(id); } /// @brief Get a street from the graph /// @param source The source node /// @param destination The destination node @@ -278,8 +221,9 @@ namespace dsm { /// @param source The source node /// @param destination The destination node /// @return A DijkstraResult object containing the path and the distance - template > - requires(std::is_same_v, double>) + template > + requires( + std::is_same_v, double>) std::optional shortestPath( const Node& source, const Node& destination, @@ -289,77 +233,54 @@ namespace dsm { /// @param source The source node id /// @param destination The destination node id /// @return A DijkstraResult object containing the path and the distance - template > - requires(std::is_same_v, double>) + template > + requires( + std::is_same_v, double>) std::optional shortestPath( Id source, Id destination, Func f = weight_functions::streetLength) const; }; - template - requires(std::is_base_of_v, - std::constructible_from) - node_t& Graph::addNode(Id id, TArgs&&... args) { - addNode(std::make_unique(id, std::forward(args)...)); - return dynamic_cast(*m_nodes.at(id)); - } template requires is_node_v> && (is_node_v> && ...) - void Graph::addNodes(T1&& node, Tn&&... nodes) { + void RoadNetwork::addNodes(T1&& node, Tn&&... nodes) { addNode(std::forward(node)); addNodes(std::forward(nodes)...); } - template - requires(std::is_base_of_v, - std::constructible_from) - edge_t& Graph::addEdge(Id id, TArgs&&... args) { - addStreet(std::make_unique(id, std::forward(args)...)); - return dynamic_cast(*m_streets.at(id)); - } - template requires is_street_v> - void Graph::addStreets(T1&& street) { - if (m_streets.contains(street.id())) { + void RoadNetwork::addStreets(T1&& street) { + if (m_edges.contains(street.id())) { throw std::invalid_argument(Logger::buildExceptionMessage( std::format("Street with id {} already exists.", street.id()))); } - // emplace nodes - auto const srcId{street.source()}; - auto const dstId{street.target()}; - if (!m_nodes.contains(srcId)) { - m_nodes.emplace(srcId, std::make_unique(srcId)); - } - if (!m_nodes.contains(dstId)) { - m_nodes.emplace(dstId, std::make_unique(dstId)); - } - // emplace street - m_streets.emplace(std::make_pair(street.id(), std::make_unique(street))); - m_adjacencyMatrix.insert(srcId, dstId); + addEdge(street.id(), street); } template requires is_street_v> && (is_street_v> && ...) - void Graph::addStreets(T1&& street, Tn&&... streets) { + void RoadNetwork::addStreets(T1&& street, Tn&&... streets) { addStreet(std::forward(street)); addStreets(std::forward(streets)...); } template - requires(std::is_same_v, double>) - std::optional Graph::shortestPath(const Node& source, - const Node& destination, - Func f) const { + requires( + std::is_same_v, double>) + std::optional RoadNetwork::shortestPath(const Node& source, + const Node& destination, + Func f) const { return this->shortestPath(source.id(), destination.id()); } template - requires(std::is_same_v, double>) - std::optional Graph::shortestPath(Id source, - Id destination, - Func getStreetWeight) const { + requires( + std::is_same_v, double>) + std::optional RoadNetwork::shortestPath(Id source, + Id destination, + Func getStreetWeight) const { const Id sourceId{source}; std::unordered_set unvisitedNodes; diff --git a/src/dsm/sources/DijkstraWeights.cpp b/src/dsm/sources/DijkstraWeights.cpp index 71bb54d40..a5e543529 100644 --- a/src/dsm/sources/DijkstraWeights.cpp +++ b/src/dsm/sources/DijkstraWeights.cpp @@ -1,16 +1,16 @@ #include "../headers/DijkstraWeights.hpp" -#include "../headers/Graph.hpp" +#include "../headers/RoadNetwork.hpp" namespace dsm { namespace weight_functions { - double streetLength(const Graph* graph, Id node1, Id node2) { + double streetLength(const RoadNetwork* graph, Id node1, Id node2) { const auto street{graph->street(node1, node2)}; return (*street)->length(); } - double streetTime(const Graph* graph, Id node1, Id node2) { + double streetTime(const RoadNetwork* graph, Id node1, Id node2) { const auto street{graph->street(node1, node2)}; const auto length{(*street)->length()}; const auto speed{(*street)->maxSpeed() * diff --git a/src/dsm/sources/FirstOrderDynamics.cpp b/src/dsm/sources/FirstOrderDynamics.cpp index 20590050c..1f93ff121 100644 --- a/src/dsm/sources/FirstOrderDynamics.cpp +++ b/src/dsm/sources/FirstOrderDynamics.cpp @@ -1,7 +1,7 @@ #include "../headers/FirstOrderDynamics.hpp" namespace dsm { - FirstOrderDynamics::FirstOrderDynamics(Graph& graph, + FirstOrderDynamics::FirstOrderDynamics(RoadNetwork& graph, bool useCache, std::optional seed, double alpha) @@ -12,7 +12,7 @@ namespace dsm { Logger::error(std::format("The minimum speed rateo ({}) must be in [0, 1[", alpha)); } double globMaxTimePenalty{0.}; - for (const auto& [streetId, street] : this->m_graph.streetSet()) { + for (const auto& [streetId, street] : this->m_graph.edges()) { globMaxTimePenalty = std::max(globMaxTimePenalty, std::ceil(street->length() / ((1. - m_alpha) * street->maxSpeed()))); @@ -28,7 +28,7 @@ namespace dsm { void FirstOrderDynamics::setAgentSpeed(Size agentId) { const auto& agent{this->agents().at(agentId)}; - const auto& street{this->m_graph.street(agent->streetId().value())}; + const auto& street{this->m_graph.edge(agent->streetId().value())}; double speed{street->maxSpeed() * (1. - m_alpha * street->density(true))}; if (m_speedFluctuationSTD > 0.) { std::normal_distribution speedDist{speed, speed * m_speedFluctuationSTD}; @@ -48,7 +48,7 @@ namespace dsm { } double FirstOrderDynamics::streetMeanSpeed(Id streetId) const { - const auto& street{this->m_graph.street(streetId)}; + const auto& street{this->m_graph.edge(streetId)}; if (street->nAgents() == 0) { return street->maxSpeed(); } @@ -98,8 +98,8 @@ namespace dsm { return Measurement(0., 0.); } std::vector speeds; - speeds.reserve(this->m_graph.streetSet().size()); - for (const auto& [streetId, street] : this->m_graph.streetSet()) { + speeds.reserve(this->m_graph.edges().size()); + for (const auto& [streetId, street] : this->m_graph.edges()) { speeds.push_back(this->streetMeanSpeed(streetId)); } return Measurement(speeds); @@ -110,8 +110,8 @@ namespace dsm { return Measurement(0., 0.); } std::vector speeds; - speeds.reserve(this->m_graph.streetSet().size()); - for (const auto& [streetId, street] : this->m_graph.streetSet()) { + speeds.reserve(this->m_graph.edges().size()); + for (const auto& [streetId, street] : this->m_graph.edges()) { if (above) { if (street->density(true) > threshold) { speeds.push_back(this->streetMeanSpeed(streetId)); diff --git a/src/dsm/sources/Graph.cpp b/src/dsm/sources/RoadNetwork.cpp similarity index 77% rename from src/dsm/sources/Graph.cpp rename to src/dsm/sources/RoadNetwork.cpp index 2268213d5..9a4964581 100644 --- a/src/dsm/sources/Graph.cpp +++ b/src/dsm/sources/RoadNetwork.cpp @@ -1,53 +1,59 @@ -#include "../headers/Graph.hpp" +#include "../headers/RoadNetwork.hpp" #include namespace dsm { - Graph::Graph() - : m_adjacencyMatrix{AdjacencyMatrix()}, - m_maxAgentCapacity{std::numeric_limits::max()} {} - - Graph::Graph(AdjacencyMatrix const& adj) - : m_adjacencyMatrix{adj}, - m_maxAgentCapacity{std::numeric_limits::max()} { - auto n{static_cast(adj.n())}; - for (const auto& [srcId, dstId] : adj.elements()) { - auto const id{srcId * n + dstId}; - if (!m_nodes.contains(srcId)) { - m_nodes.emplace(srcId, std::make_unique(srcId)); + void RoadNetwork::m_addMissingNodes(Id const nodeId) { + auto const srcNodeId{m_edges.at(nodeId)->source()}; + auto const dstNodeId{m_edges.at(nodeId)->target()}; + if (srcNodeId < m_adjacencyMatrix.n() && dstNodeId < m_adjacencyMatrix.n()) { + if (!m_adjacencyMatrix.contains(srcNodeId, dstNodeId)) { + m_adjacencyMatrix.insert(srcNodeId, dstNodeId); } - if (!m_nodes.contains(dstId)) { - m_nodes.emplace(dstId, std::make_unique(dstId)); - } - m_streets.emplace(id, std::make_unique(id, std::make_pair(srcId, dstId))); + } else { + m_adjacencyMatrix.insert(srcNodeId, dstNodeId); + } + if (!m_nodes.contains(srcNodeId)) { + m_nodes.emplace(srcNodeId, std::make_unique(srcNodeId)); + } + if (!m_nodes.contains(dstNodeId)) { + m_nodes.emplace(dstNodeId, std::make_unique(dstNodeId)); } } + RoadNetwork::RoadNetwork() + : Network{AdjacencyMatrix()}, + m_maxAgentCapacity{std::numeric_limits::max()} {} - Graph::Graph(const std::unordered_map>& streetSet) - : m_adjacencyMatrix{AdjacencyMatrix(streetSet)} { - for (auto& street : streetSet) { - m_streets.emplace(street.second->id(), street.second.get()); + RoadNetwork::RoadNetwork(AdjacencyMatrix const& adj) + : Network{adj}, + m_maxAgentCapacity{std::numeric_limits::max()} {} - Id node1 = street.second->nodePair().first; - Id node2 = street.second->nodePair().second; - m_nodes.emplace(node1, std::make_unique(node1)); - m_nodes.emplace(node2, std::make_unique(node2)); - } + RoadNetwork::RoadNetwork( + const std::unordered_map>& streetSet) + : Network{AdjacencyMatrix(streetSet)} { + // for (auto& street : streetSet) { + // m_edges.emplace(street.second->id(), street.second.get()); + + // Id node1 = street.second->nodePair().first; + // Id node2 = street.second->nodePair().second; + // m_nodes.emplace(node1, std::make_unique(node1)); + // m_nodes.emplace(node2, std::make_unique(node2)); + // } - buildAdj(); + // buildAdj(); } - void Graph::m_reassignIds() { + void RoadNetwork::m_reassignIds() { // not sure about this, might need a bit more work - auto const oldStreetSet{std::move(m_streets)}; + auto const oldStreetSet{std::move(m_edges)}; auto const N{nNodes()}; std::unordered_map newStreetIds; for (const auto& [streetId, street] : oldStreetSet) { const auto srcId{street->source()}; const auto dstId{street->target()}; const auto newStreetId{static_cast(srcId * N + dstId)}; - if (m_streets.contains(newStreetId)) { + if (m_edges.contains(newStreetId)) { throw std::invalid_argument(Logger::buildExceptionMessage( std::format("Street with same id ({}) from {} to {} already exists.", newStreetId, @@ -55,22 +61,17 @@ namespace dsm { dstId))); } if (street->isSpire() && street->isStochastic()) { - m_streets.emplace(newStreetId, - std::make_unique( - newStreetId, - *street, - dynamic_cast(*street).flowRate())); + addEdge( + newStreetId, + *street, + dynamic_cast(*street).flowRate()); } else if (street->isStochastic()) { - m_streets.emplace(newStreetId, - std::make_unique( - newStreetId, - *street, - dynamic_cast(*street).flowRate())); + addEdge( + newStreetId, *street, dynamic_cast(*street).flowRate()); } else if (street->isSpire()) { - m_streets.emplace(newStreetId, - std::make_unique(newStreetId, *street)); + addEdge(newStreetId, *street); } else { - m_streets.emplace(newStreetId, std::make_unique(newStreetId, *street)); + addEdge(newStreetId, *street); } newStreetIds.emplace(streetId, newStreetId); } @@ -96,10 +97,10 @@ namespace dsm { } } - void Graph::buildAdj() { + void RoadNetwork::buildAdj() { // find max values in streets node pairs m_maxAgentCapacity = 0; - for (const auto& [streetId, pStreet] : m_streets) { + for (const auto& [streetId, pStreet] : m_edges) { m_maxAgentCapacity += pStreet->capacity(); if (pStreet->geometry().empty()) { std::vector> coords; @@ -117,14 +118,14 @@ namespace dsm { this->m_reassignIds(); } - void Graph::adjustNodeCapacities() { + void RoadNetwork::adjustNodeCapacities() { int16_t value; for (Id nodeId = 0; nodeId < m_nodes.size(); ++nodeId) { value = 0; auto const N{nNodes()}; for (const auto& sourceId : m_adjacencyMatrix.getCol(nodeId)) { auto const streetId{sourceId * N + nodeId}; - auto const& pStreet{m_streets.at(streetId)}; + auto const& pStreet{m_edges.at(streetId)}; value += pStreet->nLanes() * pStreet->transportCapacity(); } auto const& pNode{m_nodes.at(nodeId)}; @@ -132,7 +133,7 @@ namespace dsm { value = 0; for (const auto& targetId : m_adjacencyMatrix.getRow(nodeId)) { auto const streetId{nodeId * N + targetId}; - auto const& pStreet{m_streets.at(streetId)}; + auto const& pStreet{m_edges.at(streetId)}; value += pStreet->nLanes() * pStreet->transportCapacity(); } pNode->setTransportCapacity(value == 0 ? 1 : value); @@ -142,7 +143,9 @@ namespace dsm { } } - void Graph::importMatrix(const std::string& fileName, bool isAdj, double defaultSpeed) { + void RoadNetwork::importMatrix(const std::string& fileName, + bool isAdj, + double defaultSpeed) { // check the file extension std::string fileExt = fileName.substr(fileName.find_last_of(".") + 1); if (fileExt == "dsm") { @@ -173,11 +176,11 @@ namespace dsm { } assert(index == srcId * n + dstId); if (isAdj) { - addEdge(index, std::make_pair(srcId, dstId)); + addEdge(index, std::make_pair(srcId, dstId)); } else { - addEdge(index, std::make_pair(srcId, dstId), val); + addEdge(index, std::make_pair(srcId, dstId), val); } - m_streets.at(index)->setMaxSpeed(defaultSpeed); + m_edges.at(index)->setMaxSpeed(defaultSpeed); } } else { // default case: read the file as a matrix with the first two elements being the number of rows and columns and @@ -218,18 +221,18 @@ namespace dsm { } assert(index == srcId * n + dstId); if (isAdj) { - addEdge(index, std::make_pair(srcId, dstId)); + addEdge(index, std::make_pair(srcId, dstId)); } else { - addEdge(index, std::make_pair(srcId, dstId), value); + addEdge(index, std::make_pair(srcId, dstId), value); } - m_streets.at(index)->setMaxSpeed(defaultSpeed); + m_edges.at(index)->setMaxSpeed(defaultSpeed); } ++index; } } } - void Graph::importCoordinates(const std::string& fileName) { + void RoadNetwork::importCoordinates(const std::string& fileName) { std::string fileExt = fileName.substr(fileName.find_last_of(".") + 1); if (fileExt == "dsm") { // first input number is the number of nodes @@ -294,7 +297,7 @@ namespace dsm { } } - void Graph::importOSMNodes(const std::string& fileName) { + void RoadNetwork::importOSMNodes(const std::string& fileName) { std::string fileExt = fileName.substr(fileName.find_last_of(".") + 1); if (fileExt == "csv") { std::ifstream file{fileName}; @@ -345,7 +348,7 @@ namespace dsm { Logger::info(std::format("Successfully imported {} nodes", nNodes())); } - void Graph::importOSMEdges(const std::string& fileName) { + void RoadNetwork::importOSMEdges(const std::string& fileName) { std::string fileExt = fileName.substr(fileName.find_last_of(".") + 1); auto const nNodes{m_nodes.size()}; if (fileExt == "csv") { @@ -465,7 +468,7 @@ namespace dsm { Logger::info(std::format("Successfully imported {} edges", nEdges())); } - void Graph::exportNodes(std::string const& path) { + void RoadNetwork::exportNodes(std::string const& path) { // assert that path ends with ".csv" assert((void("Only csv export is supported."), path.substr(path.find_last_of(".")) == ".csv")); @@ -483,14 +486,14 @@ namespace dsm { } file.close(); } - void Graph::exportEdges(std::string const& path) { + void RoadNetwork::exportEdges(std::string const& path) { // assert that path ends with ".csv" assert((void("Only csv export is supported."), path.substr(path.find_last_of(".")) == ".csv")); std::ofstream file{path}; // Column names file << "id;source_id;target_id;name;geometry\n"; - for (auto const& [streetId, pStreet] : m_streets) { + for (auto const& [streetId, pStreet] : m_edges) { file << streetId << ';' << pStreet->source() << ';' << pStreet->target() << ';' << pStreet->name() << ';'; if (!pStreet->geometry().empty()) { @@ -509,7 +512,7 @@ namespace dsm { } file.close(); } - void Graph::exportMatrix(std::string path, bool isAdj) { + void RoadNetwork::exportMatrix(std::string path, bool isAdj) { std::ofstream file{path}; if (!file.is_open()) { throw std::invalid_argument( @@ -522,74 +525,49 @@ namespace dsm { file << '\n' << source * N + target << '\t' << 1; } } else { - for (const auto& [id, street] : m_streets) { + for (const auto& [id, street] : m_edges) { file << '\n' << id << '\t' << street->length(); } } } - void Graph::addNode(std::unique_ptr node) { - m_nodes.emplace(std::make_pair(node->id(), std::move(node))); - } - - TrafficLight& Graph::makeTrafficLight(Id const nodeId, - Delay const cycleTime, - Delay const counter) { + TrafficLight& RoadNetwork::makeTrafficLight(Id const nodeId, + Delay const cycleTime, + Delay const counter) { auto& pNode = m_nodes.at(nodeId); pNode = std::make_unique(*pNode, cycleTime, counter); - return dynamic_cast(*pNode); + return node(nodeId); } - Roundabout& Graph::makeRoundabout(Id nodeId) { + Roundabout& RoadNetwork::makeRoundabout(Id nodeId) { auto& pNode = m_nodes.at(nodeId); pNode = std::make_unique(*pNode); - return dynamic_cast(*pNode); + return node(nodeId); } - Station& Graph::makeStation(Id nodeId, const unsigned int managementTime) { + Station& RoadNetwork::makeStation(Id nodeId, const unsigned int managementTime) { auto& pNode = m_nodes.at(nodeId); pNode = std::make_unique(*pNode, managementTime); - return dynamic_cast(*pNode); + return node(nodeId); } - StochasticStreet& Graph::makeStochasticStreet(Id streetId, double const flowRate) { - auto& pStreet = m_streets.at(streetId); + StochasticStreet& RoadNetwork::makeStochasticStreet(Id streetId, + double const flowRate) { + auto& pStreet = m_edges.at(streetId); pStreet = std::make_unique(pStreet->id(), *pStreet, flowRate); - return dynamic_cast(*pStreet); + return edge(streetId); } - void Graph::makeSpireStreet(Id streetId) { - auto& pStreet = m_streets.at(streetId); + void RoadNetwork::makeSpireStreet(Id streetId) { + auto& pStreet = m_edges.at(streetId); if (pStreet->isStochastic()) { pStreet = std::make_unique( - pStreet->id(), *pStreet, dynamic_cast(*pStreet).flowRate()); + pStreet->id(), *pStreet, edge(streetId).flowRate()); return; } pStreet = std::make_unique(pStreet->id(), *pStreet); } - void Graph::addStreet(std::unique_ptr street) { - if (m_streets.contains(street->id())) { - throw std::invalid_argument(Logger::buildExceptionMessage( - std::format("Street with id {} from {} to {} already exists.", - street->id(), - street->source(), - street->target()))); - } - // emplace nodes - const auto srcId{street->source()}; - const auto dstId{street->target()}; - if (!m_nodes.contains(srcId)) { - m_nodes.emplace(srcId, std::make_unique(srcId)); - } - if (!m_nodes.contains(dstId)) { - m_nodes.emplace(dstId, std::make_unique(dstId)); - } - // emplace street - m_streets.emplace(std::make_pair(street->id(), std::move(street))); - m_adjacencyMatrix.insert(srcId, dstId); - } - - void Graph::addStreet(const Street& street) { - if (m_streets.contains(street.id())) { + void RoadNetwork::addStreet(const Street& street) { + if (m_edges.contains(street.id())) { throw std::invalid_argument(Logger::buildExceptionMessage( std::format("Street with id {} from {} to {} already exists.", street.id(), @@ -606,18 +584,18 @@ namespace dsm { m_nodes.emplace(dstId, std::make_unique(dstId)); } // emplace street - m_streets.emplace(std::make_pair(street.id(), std::make_unique(street))); + m_edges.emplace(std::make_pair(street.id(), std::make_unique(street))); m_adjacencyMatrix.insert(srcId, dstId); } - const std::unique_ptr* Graph::street(Id source, Id destination) const { - auto streetIt = std::find_if(m_streets.begin(), - m_streets.end(), + const std::unique_ptr* RoadNetwork::street(Id source, Id destination) const { + auto streetIt = std::find_if(m_edges.begin(), + m_edges.end(), [source, destination](const auto& street) -> bool { return street.second->nodePair().first == source && street.second->nodePair().second == destination; }); - if (streetIt == m_streets.end()) { + if (streetIt == m_edges.end()) { return nullptr; } Size n = m_nodes.size(); @@ -632,14 +610,14 @@ namespace dsm { return &(streetIt->second); } - const std::unique_ptr* Graph::oppositeStreet(Id streetId) const { - if (!m_streets.contains(streetId)) { + const std::unique_ptr* RoadNetwork::oppositeStreet(Id streetId) const { + if (!m_edges.contains(streetId)) { throw std::invalid_argument(Logger::buildExceptionMessage( std::format("Street with id {} does not exist: maybe it has changed " "id once called buildAdj.", streetId))); } - const auto& nodePair = m_streets.at(streetId)->nodePair(); + const auto& nodePair = m_edges.at(streetId)->nodePair(); return this->street(nodePair.second, nodePair.first); } }; // namespace dsm diff --git a/src/dsm/sources/Street.cpp b/src/dsm/sources/Street.cpp index 995ef23ea..7ebb61c90 100644 --- a/src/dsm/sources/Street.cpp +++ b/src/dsm/sources/Street.cpp @@ -174,6 +174,7 @@ namespace dsm { } void StochasticSpireStreet::addAgent(Id agentId) { Street::addAgent(agentId); + Logger::info(std::format("Adding agent {} to spire street {}", agentId, this->id())); increaseInputCounter(); } diff --git a/test/Test_AdjacencyMatrix.cpp b/test/Test_AdjacencyMatrix.cpp index 791d00147..93d50b941 100644 --- a/test/Test_AdjacencyMatrix.cpp +++ b/test/Test_AdjacencyMatrix.cpp @@ -1,5 +1,5 @@ #include "AdjacencyMatrix.hpp" -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "doctest.h" @@ -120,13 +120,13 @@ TEST_CASE("Test default construction and insertion") { } } TEST_CASE("Test construction from edge map") { - Graph g; + RoadNetwork g; g.addEdge(0, std::make_pair(0, 1)); g.addEdge(1, std::make_pair(1, 2)); g.addEdge(2, std::make_pair(1, 3)); g.addEdge(3, std::make_pair(2, 3)); g.addEdge(4, std::make_pair(3, 4)); - AdjacencyMatrix adj(g.streetSet()); + AdjacencyMatrix adj(g.edges()); auto offsets = test::offsets(adj); auto indices = test::indices(adj); diff --git a/test/Test_dynamics.cpp b/test/Test_dynamics.cpp index 0b8188e4c..204abdcd6 100644 --- a/test/Test_dynamics.cpp +++ b/test/Test_dynamics.cpp @@ -1,14 +1,14 @@ #include #include "FirstOrderDynamics.hpp" -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "SparseMatrix.hpp" #include "Street.hpp" #include "doctest.h" using Dynamics = dsm::FirstOrderDynamics; -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using SparseMatrix = dsm::SparseMatrix; using Road = dsm::Road; using Street = dsm::Street; @@ -51,7 +51,7 @@ TEST_CASE("Measurement") { TEST_CASE("Dynamics") { SUBCASE("Constructor") { GIVEN("A graph object") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dsm"); graph.buildAdj(); WHEN("A dynamics object is created") { @@ -89,13 +89,13 @@ TEST_CASE("Dynamics") { WHEN("We transorm a street into a spire and create the dynamcis") { graph.makeSpireStreet(8); Dynamics dynamics{graph, false, 69}; - THEN("The street is a spire") { CHECK(dynamics.graph().street(8)->isSpire()); } + THEN("The street is a spire") { CHECK(dynamics.graph().edge(8)->isSpire()); } } } } SUBCASE("setDestinationNodes") { GIVEN("A dynamics object and a destination node") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dat"); Dynamics dynamics{graph, false, 69}; WHEN("We add a span of destination nodes") { @@ -113,7 +113,7 @@ TEST_CASE("Dynamics") { } SUBCASE("addAgent") { GIVEN("A dynamics object, a source node and a destination node") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dsm"); Dynamics dynamics{graph, false, 69}; dynamics.addItinerary(std::unique_ptr(new Itinerary(2, 2))); @@ -131,7 +131,7 @@ TEST_CASE("Dynamics") { } SUBCASE("addAgentsUniformly") { GIVEN("A dynamics object and an itinerary") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dsm"); Dynamics dynamics{graph, false, 69}; WHEN("We add a random agent") { @@ -149,7 +149,7 @@ TEST_CASE("Dynamics") { } } GIVEN("A dynamics object and many itineraries") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dsm"); Dynamics dynamics{graph, false, 69}; dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 2))); @@ -203,7 +203,7 @@ TEST_CASE("Dynamics") { } SUBCASE("addAgentsRandomly") { GIVEN("A graph object") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dat"); Dynamics dynamics{graph, false, 69}; WHEN("We add one agent for existing itinerary") { @@ -251,7 +251,7 @@ TEST_CASE("Dynamics") { GIVEN("A dynamics object") { auto const p{0.1}; auto const n{100}; - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dat", false); graph.buildAdj(); Dynamics dynamics{graph, false, 69}; @@ -270,7 +270,7 @@ TEST_CASE("Dynamics") { } SUBCASE("addAgents") { GIVEN("A dynamics object and one itinerary") { - auto graph = Graph{}; + auto graph = RoadNetwork{}; graph.importMatrix("./data/matrix.dsm"); Dynamics dynamics{graph, false, 69}; dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 2))); @@ -295,7 +295,7 @@ TEST_CASE("Dynamics") { SUBCASE("Add too many agents") { GIVEN("A simple graph with two nodes and only one street") { Street s{0, std::make_pair(0, 1), 2.}; // Capacity of 1 agent - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; @@ -317,7 +317,7 @@ TEST_CASE("Dynamics") { Street s1{0, std::make_pair(0, 1), 2.}; Street s2{1, std::make_pair(1, 2), 5.}; Street s3{2, std::make_pair(0, 2), 10.}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2, s3); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; @@ -348,7 +348,7 @@ TEST_CASE("Dynamics") { GIVEN( "A dynamics objects, many streets and many itinearies with same " "destination") { - Graph graph2{}; + RoadNetwork graph2{}; graph2.importMatrix("./data/matrix.dat"); Dynamics dynamics{graph2, false, 69}; dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 118))); @@ -372,7 +372,7 @@ TEST_CASE("Dynamics") { Street s2{1, std::make_pair(1, 2), 5.}; Street s3{2, std::make_pair(0, 3), 5.}; Street s4{3, std::make_pair(3, 2), 5.}; - Graph graph; + RoadNetwork graph; graph.addStreets(s1, s2, s3, s4); graph.buildAdj(); Dynamics dynamics{graph, false, 69}; @@ -407,7 +407,7 @@ TEST_CASE("Dynamics") { Street s2{1, std::make_pair(1, 2), 7., 70.}; Street s3{2, std::make_pair(0, 3), 9., 90.}; Street s4{3, std::make_pair(3, 2), 10., 100.}; - Graph graph; + RoadNetwork graph; graph.addStreets(s1, s2, s3, s4); graph.buildAdj(); Dynamics dynamics{graph, false, 69}; @@ -442,7 +442,7 @@ TEST_CASE("Dynamics") { Street s1{0, std::make_pair(0, 1), 2.}; Street s2{1, std::make_pair(1, 2), 5.}; Street s3{2, std::make_pair(0, 2), 10.}; - Graph graph; + RoadNetwork graph; graph.addStreets(s1, s2, s3); graph.buildAdj(); Dynamics dynamics{graph, false, 69}; @@ -473,7 +473,7 @@ TEST_CASE("Dynamics") { GIVEN("A dynamics object, an itinerary and an agent") { Street s1{0, std::make_pair(0, 1), 13.8888888889}; Street s2{1, std::make_pair(1, 0), 13.8888888889}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; @@ -497,7 +497,7 @@ TEST_CASE("Dynamics") { GIVEN("A dynamics object, an itinerary and an agent") { Street s1{0, std::make_pair(0, 1), 13.8888888889}; Street s2{1, std::make_pair(1, 0), 13.8888888889}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; @@ -529,7 +529,7 @@ TEST_CASE("Dynamics") { Street s1_0{3, std::make_pair(1, 0), 30., 15.}; Street s1_2{5, std::make_pair(1, 2), 30., 15.}; Street s2_1{7, std::make_pair(2, 1), 30., 15.}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s0_1, s1_0, s1_2, s2_1); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; @@ -562,23 +562,23 @@ TEST_CASE("Dynamics") { GIVEN( "A dynamics object, a network with traffic lights, an itinerary and " "an agent") { - TrafficLight tl{1, 4}; Street s1{1, std::make_pair(0, 1), 30., 15.}; Street s2{7, std::make_pair(1, 2), 30., 15.}; Street s3{16, std::make_pair(3, 1), 30., 15.}; Street s4{9, std::make_pair(1, 4), 30., 15.}; + RoadNetwork graph2; + graph2.addNode(1, 4); + graph2.addStreets(s1, s2, s3, s4); + graph2.buildAdj(); + auto& tl = graph2.node(1); tl.setCycle(1, dsm::Direction::RIGHT, {2, 0}); tl.setCycle(7, dsm::Direction::RIGHT, {2, 0}); tl.setCycle(16, dsm::Direction::RIGHT, {2, 2}); tl.setCycle(9, dsm::Direction::RIGHT, {2, 2}); - Graph graph2; - graph2.addNode(std::make_unique(tl)); - graph2.addStreets(s1, s2, s3, s4); - graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; - dynamics.addItinerary(std::unique_ptr(new Itinerary(0, 2))); + dynamics.addItinerary(2, 2); dynamics.updatePaths(); - dynamics.addAgent(0, 0, 0); + dynamics.addAgent(0, 2, 0); WHEN("We evolve the dynamics") { dynamics.evolve(false); THEN( @@ -615,20 +615,18 @@ TEST_CASE("Dynamics") { Street s4_1{21, std::make_pair(4, 1), 30., 15.}; Street s1_4{9, std::make_pair(1, 4), 30., 15.}; - Graph graph2; + RoadNetwork graph2; { - auto tl = TrafficLight{1, 6}; + graph2.addNode(1, 6, std::make_pair(0, 0)); + auto& tl = graph2.node(1); tl.setCycle(1, dsm::Direction::RIGHTANDSTRAIGHT, {2, 2}); tl.setCycle(1, dsm::Direction::LEFT, {1, 4}); tl.setCycle(11, dsm::Direction::ANY, {3, 2}); tl.setComplementaryCycle(8, 11); tl.setComplementaryCycle(21, 11); - tl.setCoords({0., 0.}); - - graph2.addNode(std::make_unique(tl)); } graph2.addStreets(s0_1, s1_0, s1_2, s2_1, s3_1, s1_3, s4_1, s1_4); - auto const& nodes = graph2.nodeSet(); + auto const& nodes = graph2.nodes(); nodes.at(0)->setCoords({0., -1.}); nodes.at(2)->setCoords({0., 1.}); nodes.at(3)->setCoords({-1., 0.}); @@ -680,21 +678,19 @@ TEST_CASE("Dynamics") { Street s4_1{21, std::make_pair(4, 1), 30., 15.}; Street s1_4{9, std::make_pair(1, 4), 30., 15.}; - Graph graph2; + RoadNetwork graph2; { - auto tl = TrafficLight{1, 6}; + graph2.addNode(1, 6, std::make_pair(0, 0)); + auto& tl = graph2.node(1); // Now testing red light = NO PHASE tl.setCycle(1, dsm::Direction::RIGHTANDSTRAIGHT, {2, 0}); tl.setCycle(1, dsm::Direction::LEFT, {1, 2}); tl.setCycle(11, dsm::Direction::ANY, {3, 0}); tl.setComplementaryCycle(8, 11); tl.setComplementaryCycle(21, 11); - tl.setCoords({0., 0.}); - - graph2.addNode(std::make_unique(tl)); } graph2.addStreets(s0_1, s1_0, s1_2, s2_1, s3_1, s1_3, s4_1, s1_4); - auto const& nodes = graph2.nodeSet(); + auto const& nodes = graph2.nodes(); nodes.at(0)->setCoords({0., -1.}); nodes.at(2)->setCoords({0., 1.}); nodes.at(3)->setCoords({-1., 0.}); @@ -746,7 +742,7 @@ TEST_CASE("Dynamics") { Street s_31{16, std::make_pair(3, 1), length, max_speed}; Street s_14{9, std::make_pair(1, 4), length, max_speed}; Street s_41{21, std::make_pair(4, 1), length, max_speed}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s_01, s_10, s_12, s_21, s_13, s_31, s_14, s_41); graph2.buildAdj(); auto& tl = graph2.makeTrafficLight(1, 8, 3); @@ -800,7 +796,7 @@ TEST_CASE("Dynamics") { Street s2{7, std::make_pair(2, 1), 10., 10.}; Street s3{3, std::make_pair(1, 0), 10., 10.}; Street s4{5, std::make_pair(1, 2), 10., 10.}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2, s3, s4); graph2.buildAdj(); auto& rb = graph2.makeRoundabout(1); @@ -838,7 +834,7 @@ TEST_CASE("Dynamics") { GIVEN("A dynamics with a two-streets network and an agent") { Street s1{0, std::make_pair(0, 1), 3.}; Street s2{1, std::make_pair(1, 2), 1.}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; @@ -862,7 +858,7 @@ TEST_CASE("Dynamics") { "agent") { Street s1{0, std::make_pair(0, 1), 3.}; Street s2{1, std::make_pair(1, 2), 1.}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2); graph2.buildAdj(); graph2.makeStochasticStreet(1, 0.3); @@ -908,10 +904,10 @@ TEST_CASE("Dynamics") { Street s2{1, std::make_pair(1, 2), 30., 15.}; Street s3{2, std::make_pair(3, 1), 30., 15.}; Street s4{3, std::make_pair(1, 4), 30., 15.}; - Graph graph2; + RoadNetwork graph2; graph2.addStreets(s1, s2, s3, s4); graph2.buildAdj(); - for (const auto& [nodeId, node] : graph2.nodeSet()) { + for (const auto& [nodeId, node] : graph2.nodes()) { node->setCapacity(4); node->setTransportCapacity(4); } @@ -925,7 +921,7 @@ TEST_CASE("Dynamics") { for (const auto& [agentId, agent] : dynamics.agents()) { meanSpeed += agent->speed(); } - auto const& pStreet{dynamics.graph().street(1)}; + auto const& pStreet{dynamics.graph().edge(1)}; meanSpeed /= (pStreet->nExitingAgents() + pStreet->movingAgents().size()); CHECK_EQ(dynamics.streetMeanSpeed(1), meanSpeed); // I don't think the mean speed of agents should be equal to the street's @@ -951,7 +947,7 @@ TEST_CASE("Dynamics") { } SUBCASE("Intersection priorities") { GIVEN("A dynamics object with five nodes and eight streets") { - Graph graph2; + RoadNetwork graph2; graph2.addNode(0, std::make_pair(0, 0)); graph2.addNode(1, std::make_pair(-1, 1)); // A graph2.addNode(2, std::make_pair(1, 1)); // B @@ -1020,7 +1016,7 @@ TEST_CASE("Dynamics") { } SUBCASE("meanSpireFlow") { GIVEN("A network with a spireStreet and a normal street") { - Graph graph2; + RoadNetwork graph2; graph2.addEdge(0, std::make_pair(0, 1), 10., 5.); graph2.addEdge(1, std::make_pair(1, 2), 10., 10.); graph2.buildAdj(); @@ -1048,12 +1044,12 @@ TEST_CASE("Dynamics") { } SUBCASE("meanSpireFlow") { GIVEN("A network with a spireStreet and a normal street") { - Graph graph2; + RoadNetwork graph2; graph2.addEdge(0, std::make_pair(0, 1), 10., 5.); - graph2.addEdge(1, std::make_pair(1, 2), 10., 10.); + graph2.addEdge(1, std::make_pair(1, 2), 10., 10.); graph2.buildAdj(); Dynamics dynamics{graph2, false, 69}; - dynamics.addItinerary(std::unique_ptr(new Itinerary(2, 2))); + dynamics.addItinerary(2, 2); dynamics.updatePaths(); dynamics.addAgent(0, 2, 0); WHEN("We evolve the dynamics") { diff --git a/test/Test_graph.cpp b/test/Test_graph.cpp index fe1fd2abe..096b79dd2 100644 --- a/test/Test_graph.cpp +++ b/test/Test_graph.cpp @@ -2,7 +2,7 @@ #include #include -#include "Graph.hpp" +#include "RoadNetwork.hpp" #include "Node.hpp" #include "Road.hpp" #include "Street.hpp" @@ -10,7 +10,7 @@ #include "doctest.h" -using Graph = dsm::Graph; +using RoadNetwork = dsm::RoadNetwork; using AdjacencyMatrix = dsm::AdjacencyMatrix; using Street = dsm::Street; using Road = dsm::Road; @@ -31,15 +31,15 @@ bool checkPath(const std::vector& path1, const std::vector& path2) { return equal; } -TEST_CASE("Graph") { +TEST_CASE("RoadNetwork") { Road::setMeanVehicleLength(5.); SUBCASE("Constructor_1") { - Graph graph{}; + RoadNetwork graph{}; graph.addEdge(1, std::make_pair(0, 1)); graph.buildAdj(); CHECK_EQ(graph.nEdges(), 1); CHECK_EQ(graph.nNodes(), 2); - CHECK_EQ(graph.adjMatrix().size(), graph.nEdges()); + CHECK_EQ(graph.adjacencyMatrix().size(), graph.nEdges()); } SUBCASE("Constructor_2") { @@ -49,14 +49,14 @@ TEST_CASE("Graph") { sm.insert(1, 2); sm.insert(2, 3); sm.insert(3, 2); - Graph graph{sm}; + RoadNetwork graph{sm}; CHECK_EQ(graph.nNodes(), 4); CHECK_EQ(graph.nEdges(), 5); - CHECK_EQ(graph.adjMatrix().size(), graph.nEdges()); - CHECK(graph.adjMatrix().contains(1, 2)); - CHECK(graph.adjMatrix().contains(2, 3)); - CHECK(graph.adjMatrix().contains(3, 2)); - CHECK_FALSE(graph.adjMatrix().contains(2, 1)); + CHECK_EQ(graph.adjacencyMatrix().size(), graph.nEdges()); + CHECK(graph.adjacencyMatrix().contains(1, 2)); + CHECK(graph.adjacencyMatrix().contains(2, 3)); + CHECK(graph.adjacencyMatrix().contains(3, 2)); + CHECK_FALSE(graph.adjacencyMatrix().contains(2, 1)); } SUBCASE("Construction with addStreet") { @@ -65,7 +65,7 @@ TEST_CASE("Graph") { Street s3(3, std::make_pair(0, 2)); Street s4(4, std::make_pair(0, 3)); Street s5(5, std::make_pair(2, 3)); - Graph graph; + RoadNetwork graph; graph.addStreet(s1); graph.addStreet(s2); graph.addStreet(s3); @@ -75,11 +75,11 @@ TEST_CASE("Graph") { CHECK_EQ(graph.nEdges(), 5); CHECK_EQ(graph.nNodes(), 4); - CHECK_EQ(graph.adjMatrix().size(), 5); - CHECK(graph.adjMatrix().contains(0, 1)); - CHECK(graph.adjMatrix().contains(1, 2)); - CHECK(graph.adjMatrix().contains(0, 2)); - CHECK_FALSE(graph.adjMatrix().contains(1, 3)); + CHECK_EQ(graph.adjacencyMatrix().size(), 5); + CHECK(graph.adjacencyMatrix().contains(0, 1)); + CHECK(graph.adjacencyMatrix().contains(1, 2)); + CHECK(graph.adjacencyMatrix().contains(0, 2)); + CHECK_FALSE(graph.adjacencyMatrix().contains(1, 3)); } SUBCASE("Construction with addStreets") { @@ -88,17 +88,17 @@ TEST_CASE("Graph") { Street s3(3, std::make_pair(0, 2)); Street s4(4, std::make_pair(0, 3)); Street s5(5, std::make_pair(2, 3)); - Graph graph; + RoadNetwork graph; graph.addStreets(s1, s2, s3, s4, s5); graph.buildAdj(); CHECK_EQ(graph.nEdges(), 5); CHECK_EQ(graph.nNodes(), 4); - CHECK_EQ(graph.adjMatrix().size(), graph.nEdges()); - CHECK(graph.adjMatrix().contains(0, 1)); - CHECK(graph.adjMatrix().contains(1, 2)); - CHECK(graph.adjMatrix().contains(0, 2)); - CHECK_FALSE(graph.adjMatrix().contains(1, 3)); + CHECK_EQ(graph.adjacencyMatrix().size(), graph.nEdges()); + CHECK(graph.adjacencyMatrix().contains(0, 1)); + CHECK(graph.adjacencyMatrix().contains(1, 2)); + CHECK(graph.adjacencyMatrix().contains(0, 2)); + CHECK_FALSE(graph.adjacencyMatrix().contains(1, 3)); } SUBCASE("importMatrix - dsm") { @@ -107,15 +107,15 @@ TEST_CASE("Graph") { // WHEN: we import a .dsm file // THEN: the graph's adjacency matrix is the same as the one in the file GIVEN("An empty graph") { - Graph graph{}; + RoadNetwork graph{}; WHEN("A matrix in dsm format is imported") { graph.importMatrix("./data/matrix.dsm"); THEN("The graph is correctly built") { - CHECK_EQ(graph.adjMatrix().n(), 3); - CHECK(graph.adjMatrix().operator()(2, 2)); - CHECK(graph.adjMatrix().operator()(2, 0)); - CHECK(graph.adjMatrix().operator()(1, 0)); - CHECK(graph.adjMatrix().operator()(0, 1)); + CHECK_EQ(graph.adjacencyMatrix().n(), 3); + CHECK(graph.adjacencyMatrix().operator()(2, 2)); + CHECK(graph.adjacencyMatrix().operator()(2, 0)); + CHECK(graph.adjacencyMatrix().operator()(1, 0)); + CHECK(graph.adjacencyMatrix().operator()(0, 1)); CHECK_EQ(graph.nNodes(), 3); CHECK_EQ(graph.nEdges(), 4); } @@ -124,11 +124,11 @@ TEST_CASE("Graph") { WHEN("The exported one is imported") { graph.importMatrix("./data/temp.dsm"); THEN("The graph is correctly built") { - CHECK_EQ(graph.adjMatrix().n(), 3); - CHECK(graph.adjMatrix().operator()(2, 2)); - CHECK(graph.adjMatrix().operator()(2, 0)); - CHECK(graph.adjMatrix().operator()(1, 0)); - CHECK(graph.adjMatrix().operator()(0, 1)); + CHECK_EQ(graph.adjacencyMatrix().n(), 3); + CHECK(graph.adjacencyMatrix().operator()(2, 2)); + CHECK(graph.adjacencyMatrix().operator()(2, 0)); + CHECK(graph.adjacencyMatrix().operator()(1, 0)); + CHECK(graph.adjacencyMatrix().operator()(0, 1)); CHECK_EQ(graph.nNodes(), 3); CHECK_EQ(graph.nEdges(), 4); } @@ -136,10 +136,10 @@ TEST_CASE("Graph") { } } SUBCASE("Coordinates import/export") { - GIVEN("A Graph object with the adj matrix imported") { - Graph graph{}; + GIVEN("A RoadNetwork object with the adj matrix imported") { + RoadNetwork graph{}; graph.importMatrix("./data/matrix.dsm"); - auto const& nodes = graph.nodeSet(); + auto const& nodes = graph.nodes(); WHEN("We import the coordinates in dsm format") { graph.importCoordinates("./data/coords.dsm"); THEN("The coordinates are correctly imported") { @@ -148,14 +148,14 @@ TEST_CASE("Graph") { CHECK_EQ(nodes.at(2)->coords(), std::make_pair(2., 0.)); } graph.buildAdj(); - auto const& adj{graph.adjMatrix()}; + auto const& adj{graph.adjacencyMatrix()}; THEN("The adjacency matrix is correctly built") { CHECK(adj(0, 1)); CHECK(adj(1, 0)); CHECK(adj(2, 0)); CHECK(adj(2, 2)); } - auto const& streets{graph.streetSet()}; + auto const& streets{graph.edges()}; THEN("The streets angles are correctly computed") { CHECK_EQ(streets.at(1)->angle(), std::numbers::pi / 2); CHECK_EQ(streets.at(3)->angle(), 3 * std::numbers::pi / 2); @@ -178,32 +178,32 @@ TEST_CASE("Graph") { } } SUBCASE("importMatrix - raw matrix") { - Graph graph{}; + RoadNetwork graph{}; graph.importMatrix("./data/rawMatrix.txt", false); - CHECK_EQ(graph.adjMatrix().n(), 3); - CHECK(graph.adjMatrix().operator()(0, 1)); - CHECK(graph.adjMatrix().operator()(1, 0)); - CHECK(graph.adjMatrix().operator()(1, 2)); - CHECK(graph.adjMatrix().operator()(2, 1)); + CHECK_EQ(graph.adjacencyMatrix().n(), 3); + CHECK(graph.adjacencyMatrix().operator()(0, 1)); + CHECK(graph.adjacencyMatrix().operator()(1, 0)); + CHECK(graph.adjacencyMatrix().operator()(1, 2)); + CHECK(graph.adjacencyMatrix().operator()(2, 1)); CHECK_EQ(graph.nNodes(), 3); CHECK_EQ(graph.nEdges(), 4); - CHECK_EQ(graph.streetSet()[1]->length(), 500); - CHECK_EQ(graph.streetSet()[3]->length(), 200); - CHECK_EQ(graph.streetSet()[5]->length(), 1); - CHECK_EQ(graph.streetSet()[7]->length(), 3); + CHECK_EQ(graph.edges().at(1)->length(), 500); + CHECK_EQ(graph.edges().at(3)->length(), 200); + CHECK_EQ(graph.edges().at(5)->length(), 1); + CHECK_EQ(graph.edges().at(7)->length(), 3); } SUBCASE("importMatrix - EXCEPTIONS") { // This tests the importMatrix throws an exception when the file has not the correct format or is not found // GIVEN: a graph // WHEN: we import a file with a wrong format // THEN: an exception is thrown - Graph graph{}; + RoadNetwork graph{}; CHECK_THROWS(graph.importMatrix("./data/matrix.nogood")); CHECK_THROWS(graph.importMatrix("./data/not_found.dsm")); } SUBCASE("importOSMNodes and importOSMEdges") { GIVEN("A graph object") { - Graph graph{}; + RoadNetwork graph{}; WHEN("We import nodes and edges from OSM") { graph.importOSMNodes("./data/postua_nodes.csv"); graph.importOSMEdges("./data/postua_edges.csv"); @@ -227,7 +227,7 @@ TEST_CASE("Graph") { } THEN("We are able to build the adjacency matrix") { graph.buildAdj(); - CHECK_EQ(graph.adjMatrix().size(), nEdges); + CHECK_EQ(graph.adjacencyMatrix().size(), nEdges); } } WHEN("We import many nodes and edges from OSM") { @@ -253,7 +253,7 @@ TEST_CASE("Graph") { } THEN("We are able to build the adjacency matrix") { graph.buildAdj(); - CHECK_EQ(graph.adjMatrix().size(), nEdges); + CHECK_EQ(graph.adjacencyMatrix().size(), nEdges); } } } @@ -262,7 +262,7 @@ TEST_CASE("Graph") { /// GIVEN: a graph /// WHEN: we add a street /// THEN: the street is added - Graph graph{}; + RoadNetwork graph{}; Street street{1, std::make_pair(0, 1), 1.}; graph.addStreet(street); auto result = graph.street(0, 1); @@ -275,7 +275,7 @@ TEST_CASE("Graph") { } SUBCASE("make trafficlight") { GIVEN("A graph object with two nodes and one street") { - Graph graph{}; + RoadNetwork graph{}; graph.addStreet(Street{1, std::make_pair(0, 1)}); graph.buildAdj(); WHEN("We make node 0 a traffic light") { @@ -290,7 +290,7 @@ TEST_CASE("Graph") { } SUBCASE("make roundabout") { GIVEN("A graph object with two nodes and one street") { - Graph graph{}; + RoadNetwork graph{}; graph.addStreet(Street{1, std::make_pair(0, 1)}); graph.buildAdj(); WHEN("We make node 0 a roundabout") { @@ -301,12 +301,12 @@ TEST_CASE("Graph") { } SUBCASE("make spire street") { GIVEN("A graph object with two nodes and one street") { - Graph graph{}; + RoadNetwork graph{}; graph.addStreet(Street{0, std::make_pair(0, 1)}); graph.buildAdj(); WHEN("We make the street a spire street") { graph.makeSpireStreet(1); - THEN("The street is a spire street") { CHECK(graph.street(1)->isSpire()); } + THEN("The street is a spire street") { CHECK(graph.edge(1)->isSpire()); } } } } @@ -319,7 +319,7 @@ TEST_CASE("Dijkstra") { Street s3{2, std::make_pair(2, 3), 4.}; Street s4{3, std::make_pair(3, 0), 5.}; Street s5{4, std::make_pair(0, 2), 6.}; - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3, s4, s5); graph.buildAdj(); auto result = graph.shortestPath(0, 1); @@ -340,7 +340,7 @@ TEST_CASE("Dijkstra") { Street s1(0, std::make_pair(0, 1), 1.); Street s2(1, std::make_pair(1, 2), 1.); Street s3(2, std::make_pair(0, 2), 6.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3); graph.buildAdj(); auto result = graph.shortestPath(0, 2); @@ -355,7 +355,7 @@ TEST_CASE("Dijkstra") { Street s1(0, std::make_pair(0, 1), 5.); Street s2(1, std::make_pair(1, 2), 4.); Street s3(2, std::make_pair(0, 2), 6.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3); graph.buildAdj(); auto result = graph.shortestPath(0, 2); @@ -381,7 +381,7 @@ TEST_CASE("Dijkstra") { Street s12(11, std::make_pair(4, 1), 1.); Street s13(12, std::make_pair(3, 1), 5.); Street s14(13, std::make_pair(4, 3), 7.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14); graph.buildAdj(); auto result = graph.shortestPath(2, 4); @@ -429,7 +429,7 @@ TEST_CASE("Dijkstra") { Street s16(15, std::make_pair(5, 4), 6.); Street s17(16, std::make_pair(6, 4), 2.); Street s18(17, std::make_pair(6, 5), 6.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets( s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18); graph.buildAdj(); @@ -495,7 +495,7 @@ TEST_CASE("Dijkstra") { Street s16(15, std::make_pair(5, 2), 2.); Street s17(16, std::make_pair(4, 3), 6.); Street s18(17, std::make_pair(4, 5), 9.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets( s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18); graph.buildAdj(); @@ -511,7 +511,7 @@ TEST_CASE("Dijkstra") { Street s1(0, std::make_pair(1, 2), 1.); Street s2(1, std::make_pair(0, 2), 6.); Street s3(2, std::make_pair(2, 0), 6.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3); graph.buildAdj(); auto result = graph.shortestPath(0, 1); @@ -522,7 +522,7 @@ TEST_CASE("Dijkstra") { Street s1(0, std::make_pair(1, 2), 1.); Street s2(1, std::make_pair(0, 2), 6.); Street s3(2, std::make_pair(2, 0), 6.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3); graph.buildAdj(); auto result = graph.shortestPath(3, 1); @@ -533,7 +533,7 @@ TEST_CASE("Dijkstra") { Street s1(0, std::make_pair(1, 2), 1.); Street s2(1, std::make_pair(0, 2), 6.); Street s3(2, std::make_pair(2, 0), 6.); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3); graph.buildAdj(); auto result = graph.shortestPath(1, 3); @@ -541,8 +541,8 @@ TEST_CASE("Dijkstra") { } SUBCASE("street and oppositeStreet") { - GIVEN("A Graph object with two streets") { - Graph graph{}; + GIVEN("A RoadNetwork object with two streets") { + RoadNetwork graph{}; Street street{1, std::make_pair(0, 1), 1.}; Street opposite{2, std::make_pair(1, 0), 1.}; graph.addStreets(street, opposite); @@ -580,18 +580,18 @@ TEST_CASE("Dijkstra") { } SUBCASE("equal length") { - Graph graph{}; + RoadNetwork graph{}; graph.importMatrix("./data/matrix.dat", false); // check correct import - CHECK_EQ(graph.adjMatrix().n(), 120); - CHECK_EQ(graph.adjMatrix().size(), 436); + CHECK_EQ(graph.adjacencyMatrix().n(), 120); + CHECK_EQ(graph.adjacencyMatrix().size(), 436); // check that the path exists - CHECK(graph.adjMatrix().operator()(46, 58)); - CHECK(graph.adjMatrix().operator()(58, 70)); - CHECK(graph.adjMatrix().operator()(70, 82)); - CHECK(graph.adjMatrix().operator()(82, 94)); - CHECK(graph.adjMatrix().operator()(94, 106)); - CHECK(graph.adjMatrix().operator()(106, 118)); + CHECK(graph.adjacencyMatrix().operator()(46, 58)); + CHECK(graph.adjacencyMatrix().operator()(58, 70)); + CHECK(graph.adjacencyMatrix().operator()(70, 82)); + CHECK(graph.adjacencyMatrix().operator()(82, 94)); + CHECK(graph.adjacencyMatrix().operator()(94, 106)); + CHECK(graph.adjacencyMatrix().operator()(106, 118)); auto result = graph.shortestPath(46, 118); CHECK(result.has_value()); @@ -602,12 +602,12 @@ TEST_CASE("Dijkstra") { Street s2(1, std::make_pair(1, 2), 40., 30., 2); Street s3(2, std::make_pair(3, 1), 75., 30., 3); Street s4(3, std::make_pair(1, 4), 55., 30., 1); - Graph graph{}; + RoadNetwork graph{}; graph.addStreets(s1, s2, s3, s4); graph.buildAdj(); WHEN("We adjust node capacities") { graph.adjustNodeCapacities(); - auto const& nodes = graph.nodeSet(); + auto const& nodes = graph.nodes(); THEN("The node capacities are correct") { CHECK_EQ(nodes.at(0)->capacity(), 1); CHECK_EQ(nodes.at(1)->capacity(), 4); @@ -625,7 +625,7 @@ TEST_CASE("Dijkstra") { } WHEN("We normalize street capacities") { // graph.normalizeStreetCapacities(); - auto const& streets = graph.streetSet(); + auto const& streets = graph.edges(); THEN("The street capacities are correct") { CHECK_EQ(streets.at(1)->capacity(), 2); CHECK_EQ(streets.at(7)->capacity(), 16);