Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/dsm/dsm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

static constexpr uint8_t DSM_VERSION_MAJOR = 2;
static constexpr uint8_t DSM_VERSION_MINOR = 2;
static constexpr uint8_t DSM_VERSION_PATCH = 2;
static constexpr uint8_t DSM_VERSION_PATCH = 3;

static auto const DSM_VERSION =
std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH);
Expand Down
73 changes: 52 additions & 21 deletions src/dsm/headers/Agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,42 @@
#include "../utility/Typedef.hpp"

#include <concepts>
#include <stdexcept>
#include <limits>
#include <optional>
#include <stdexcept>
#include <vector>

namespace dsm {
/// @brief The Agent class represents an agent in the network.
/// @tparam Id, The type of the agent's id. It must be an unsigned integral type.
/// @tparam Size, The type of the size of a street. It must be an unsigned integral type.
/// @tparam delay_t, The type of the agent's delay. It must be a numeric type (see utility/TypeTraits/is_numeric.hpp).
template <typename delay_t>
requires(is_numeric_v<delay_t>)
class Agent {
private:
Id m_id;
Id m_itineraryId;
std::vector<Id> m_trip;
std::optional<Id> m_streetId;
std::optional<Id> m_srcNodeId;
delay_t m_delay;
double m_speed;
double m_distance; // Travelled distance
unsigned int m_time; // Travelled time
size_t m_itineraryIdx;

public:
/// @brief Construct a new Agent object
/// @param id The agent's id
/// @param itineraryId The agent's itinerary
Agent(Id id, Id itineraryId);
/// @param srcNodeId Optional, The id of the source node of the agent
Agent(Id id, Id itineraryId, std::optional<Id> srcNodeId = std::nullopt);
/// @brief Construct a new Agent object
/// @param id The agent's id
/// @param itineraryId The agent's itinerary
/// @param srcNodeId The id of the source node of the agent
Agent(Id id, Id itineraryId, Id srcNodeId);
/// @param itineraryIds The agent's itinerary
/// @param srcNodeId Optional, The id of the source node of the agent
Agent(Id id, std::vector<Id> const& trip, std::optional<Id> srcNodeId = std::nullopt);
/// @brief Set the street occupied by the agent
/// @param streetId The id of the street currently occupied by the agent
void setStreetId(Id streetId) { m_streetId = streetId; }
/// @brief Set the source node id of the agent
/// @param srcNodeId The id of the source node of the agent
void setSourceNodeId(Id srcNodeId) { m_srcNodeId = srcNodeId; }
/// @brief Set the agent's itinerary
/// @param itineraryId The agent's itinerary
void setItineraryId(Id itineraryId) { m_itineraryId = itineraryId; }
/// @brief Set the agent's speed
/// @param speed, The agent's speed
/// @throw std::invalid_argument, if speed is negative
Expand Down Expand Up @@ -87,13 +82,29 @@
void incrementTime(unsigned int const time);
/// @brief Reset the agent's time to 0
void resetTime() { m_time = 0; }
/// @brief Update the agent's itinerary
/// @details If possible, the agent's itinerary is updated by removing the first element
/// from the itinerary's vector.
void updateItinerary();
/// @brief Reset the agent
/// @details Reset the following values:
/// - street id = std::nullopt
/// - delay = 0
/// - speed = 0
/// - distance = 0
/// - time = 0
/// - itinerary index = 0
void reset();

/// @brief Get the agent's id
/// @return The agent's id
Id id() const { return m_id; }
/// @brief Get the agent's itinerary
/// @return The agent's itinerary
Id itineraryId() const { return m_itineraryId; }
Id itineraryId() const { return m_trip[m_itineraryIdx]; }
/// @brief Get the agent's trip
/// @return The agent's trip
std::vector<Id> const& trip() const { return m_trip; }
/// @brief Get the id of the street currently occupied by the agent
/// @return The id of the street currently occupied by the agent
std::optional<Id> streetId() const { return m_streetId; }
Expand All @@ -116,24 +127,27 @@

template <typename delay_t>
requires(is_numeric_v<delay_t>)
Agent<delay_t>::Agent(Id id, Id itineraryId)
Agent<delay_t>::Agent(Id id, Id itineraryId, std::optional<Id> srcNodeId)
: m_id{id},
m_itineraryId{itineraryId},
m_trip{itineraryId},
m_srcNodeId{srcNodeId},
m_delay{0},
m_speed{0.},
m_distance{0.},
m_time{0} {}
m_time{0},

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
m_itineraryIdx{0} {}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
Agent<delay_t>::Agent(Id id, Id itineraryId, Id srcNodeId)
Agent<delay_t>::Agent(Id id, std::vector<Id> const& trip, std::optional<Id> srcNodeId)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
: m_id{id},
m_itineraryId{itineraryId},
m_trip{trip},
m_srcNodeId{srcNodeId},
m_delay{0},
m_speed{0.},
m_distance{0.},
m_time{0} {}
m_time{0},

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
m_itineraryIdx{0} {}

template <typename delay_t>
requires(is_numeric_v<delay_t>)
Expand All @@ -143,6 +157,23 @@
}
m_speed = speed;
}
template <typename delay_t>
requires(is_numeric_v<delay_t>)
void Agent<delay_t>::updateItinerary() {
if (m_itineraryIdx < m_trip.size() - 1) {
++m_itineraryIdx;
}
}
template <typename delay_t>
requires(is_numeric_v<delay_t>)
void Agent<delay_t>::reset() {
m_streetId = std::nullopt;
m_delay = 0;
m_speed = 0.;
m_distance = 0.;
m_time = 0;
m_itineraryIdx = 0;
}
template <typename delay_t>
requires(is_numeric_v<delay_t>)
void Agent<delay_t>::incrementDelay() {
Expand Down
9 changes: 3 additions & 6 deletions src/dsm/headers/Dynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ namespace dsm {
/// @brief Update the path of a single itinerary using Dijsktra's algorithm
/// @param pItinerary An std::unique_prt to the itinerary
void m_updatePath(const std::unique_ptr<Itinerary>& pItinerary) {
const Size dimension = m_graph.adjMatrix().getRowDim();
const auto destinationID = pItinerary->destination();
Size const dimension = m_graph.adjMatrix().getRowDim();
auto const destinationID = pItinerary->destination();
SparseMatrix<bool> path{dimension, dimension};
// cycle over the nodes
for (const auto& [nodeId, node] : m_graph.nodeSet()) {
Expand Down Expand Up @@ -403,10 +403,7 @@ namespace dsm {
agentId = m_agents.rbegin()->first + 1;
}
for (Size i{0}; i < nAgents; ++i, ++agentId) {
this->addAgent(Agent<delay_t>{agentId, itineraryId});
if (srcNodeId.has_value()) {
m_agents[agentId]->setSourceNodeId(srcNodeId.value());
}
this->addAgent(Agent<delay_t>{agentId, itineraryId, srcNodeId});
}
}

Expand Down
8 changes: 0 additions & 8 deletions src/dsm/headers/Itinerary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@
namespace dsm {
Itinerary::Itinerary(Id id, Id destination) : m_id{id}, m_destination{destination} {}

Itinerary::Itinerary(Id id, Id destination, SparseMatrix<bool> path)
: m_id{id}, m_path{std::move(path)}, m_destination{destination} {}

void Itinerary::setDestination(Id destination) {
m_destination = destination;
this->m_path.clear();
}

void Itinerary::setPath(SparseMatrix<bool> path) {
if (path.getRowDim() != path.getColDim()) {
throw std::invalid_argument(buildLog(
Expand Down
9 changes: 1 addition & 8 deletions src/dsm/headers/Itinerary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,14 @@ namespace dsm {
class Itinerary {
private:
Id m_id;
SparseMatrix<bool> m_path;
Id m_destination;
SparseMatrix<bool> m_path;

public:
/// @brief Construct a new Itinerary object
/// @param destination The itinerary's destination
Itinerary(Id id, Id destination);
/// @brief Construct a new Itinerary object
/// @param destination The itinerary's destination
/// @param path An adjacency matrix made by a SparseMatrix representing the itinerary's path
Itinerary(Id id, Id destination, SparseMatrix<bool> path);

/// @brief Set the itinerary's destination
/// @param destination The itinerary's destination
void setDestination(Id destination);
/// @brief Set the itinerary's path
/// @param path An adjacency matrix made by a SparseMatrix representing the itinerary's path
/// @throw std::invalid_argument, if the itinerary's source or destination is not in the path's
Expand Down
24 changes: 11 additions & 13 deletions src/dsm/headers/RoadDynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,11 @@
continue;
}
const auto agentId{pStreet->queue(queueIndex).front()};
if (this->m_agents[agentId]->delay() > 0) {
auto const& pAgent{this->m_agents[agentId]};
if (pAgent->delay() > 0) {
continue;
}
this->m_agents[agentId]->setSpeed(0.);
pAgent->setSpeed(0.);
const auto& destinationNode{this->m_graph.nodeSet()[pStreet->nodePair().second]};
if (destinationNode->isFull()) {
continue;
Expand All @@ -259,19 +260,12 @@
}
}
if (destinationNode->id() ==
this->m_itineraries[this->m_agents[agentId]->itineraryId()]->destination()) {
this->m_itineraries[pAgent->itineraryId()]->destination()) {
pStreet->dequeue(queueIndex);
m_travelTimes.push_back(this->m_agents[agentId]->time());
m_travelTimes.push_back(pAgent->time());

Check notice

Code scanning / Cppcheck (reported by Codacy)

time is Y2038-unsafe Note

time is Y2038-unsafe
if (reinsert_agents) {
// take last agent id in map
Agent<delay_t> newAgent{static_cast<Id>(this->m_agents.rbegin()->first + 1),
this->m_agents[agentId]->itineraryId(),
this->m_agents[agentId]->srcNodeId().value()};
if (this->m_agents[agentId]->srcNodeId().has_value()) {
newAgent.setSourceNodeId(this->m_agents[agentId]->srcNodeId().value());
}
this->removeAgent(agentId);
this->addAgent(newAgent);
// reset Agent's values
pAgent->reset();
} else {
this->removeAgent(agentId);
}
Expand Down Expand Up @@ -372,6 +366,10 @@
agent->decrementDelay();
if (agent->delay() == 0) {
auto const nLanes = street->nLanes();
if (this->m_itineraries[agent->itineraryId()]->destination() ==
street->nodePair().second) {
agent->updateItinerary();
}
if (this->m_itineraries[agent->itineraryId()]->destination() ==
street->nodePair().second) {
std::uniform_int_distribution<size_t> laneDist{
Expand Down
53 changes: 42 additions & 11 deletions test/Test_dynamics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,7 @@
CHECK_EQ(dynamics.agents().at(0)->speed(), 13.8888888889);
}
dynamics.evolve(false);
THEN("And again, reaching the destination") {
CHECK_EQ(dynamics.agents().size(), 0);
}
THEN("And again, reaching the destination") { CHECK(dynamics.agents().empty()); }
}
}
GIVEN("A dynamics object, an itinerary and an agent") {
Expand All @@ -500,9 +498,7 @@
CHECK_EQ(dynamics.agents().at(0)->distance(), 13.8888888889);
}
dynamics.evolve(false);
THEN("The agent reaches the destination") {
CHECK_EQ(dynamics.agents().size(), 0);
}
THEN("The agent reaches the destination") { CHECK(dynamics.agents().empty()); }
}
}
GIVEN("A dynamics object, an itinerary and an agent") {
Expand All @@ -529,13 +525,48 @@
dynamics.evolve(true);
THEN("The agent is reinserted") {
CHECK_EQ(dynamics.agents().size(), 1);
CHECK_EQ(dynamics.agents().at(1)->time(), 1);
CHECK_EQ(dynamics.agents().at(1)->delay(), 0);
CHECK_FALSE(dynamics.agents().at(1)->streetId().has_value());
CHECK_EQ(dynamics.agents().at(1)->speed(), 0.);
CHECK_EQ(dynamics.agents().at(0)->time(), 1);

Check notice

Code scanning / Cppcheck (reported by Codacy)

time is Y2038-unsafe Note test

time is Y2038-unsafe
CHECK_EQ(dynamics.agents().at(0)->delay(), 0);
CHECK_FALSE(dynamics.agents().at(0)->streetId().has_value());
CHECK_EQ(dynamics.agents().at(0)->speed(), 0.);
}
}
}
GIVEN("A simple network and an agent with forced itinerary") {
Street s0_1{1, 1, 30., 15., std::make_pair(0, 1)};
Street s1_0{3, 1, 30., 15., std::make_pair(1, 0)};
Street s1_2{5, 1, 30., 15., std::make_pair(1, 2)};
Street s2_1{7, 1, 30., 15., std::make_pair(2, 1)};
Graph graph2;
graph2.addStreets(s0_1, s1_0, s1_2, s2_1);
graph2.buildAdj();
Dynamics dynamics{graph2, 69};
std::vector<dsm::Id> dsts{1, 2};
dynamics.setDestinationNodes(dsts);
std::vector<dsm::Id> trip{2, 1};
Agent agent{0, trip, 0};
dynamics.addAgent(agent);
auto const& pAgent{dynamics.agents().at(0)};
WHEN("We evolve the dynamics") {
dynamics.evolve(false);
dynamics.evolve(false);
dynamics.evolve(false);
dynamics.evolve(false);
dynamics.evolve(false);
THEN("The agent goes first into node 2") {
CHECK_EQ(pAgent->streetId().value(), 5);
CHECK_EQ(pAgent->distance(), 60.);
}
dynamics.evolve(false);
dynamics.evolve(false);
THEN("The agent goes then to node 1") {
CHECK_EQ(pAgent->streetId().value(), 7);
CHECK_EQ(pAgent->distance(), 90.);
}
dynamics.evolve(false);
THEN("The agent reaches the destination") { CHECK(dynamics.agents().empty()); }
}
}
}
SUBCASE("TrafficLights") {
GIVEN(
Expand Down Expand Up @@ -836,7 +867,7 @@
THEN("The agent with priority leaves the roundabout") {
CHECK_EQ(dynamics.agents().at(0)->streetId().value(), 5);
CHECK_EQ(dynamics.agents().at(1)->streetId().value(), 3);
CHECK_EQ(rb.agents().size(), 0);
CHECK(rb.agents().empty());
}
}
}
Expand Down
38 changes: 3 additions & 35 deletions test/Test_itinerary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ using Itinerary = dsm::Itinerary;

TEST_CASE("Itinerary") {
SUBCASE("Constructors") {
GIVEN("An itinerary and its destination ids") {
uint8_t itineraryId{0};
uint8_t destinationId{2};
GIVEN("Some parameters") {
dsm::Id itineraryId{0};
dsm::Id destinationId{2};
WHEN("The Itinerary is constructed") {
Itinerary itinerary{itineraryId, destinationId};
THEN("The source and destination are set correctly") {
Expand All @@ -19,37 +19,5 @@ TEST_CASE("Itinerary") {
}
}
}
GIVEN("An itinerary id, its destination id and a transition matrix") {
uint8_t itineraryId{0};
uint8_t destinationId{2};
dsm::SparseMatrix<bool> path{1, 1};
WHEN("The Itinerary is constructed") {
Itinerary itinerary{itineraryId, destinationId, path};
THEN("The source, destination, and path are set correctly") {
CHECK_EQ(itinerary.id(), itineraryId);
CHECK_EQ(itinerary.destination(), destinationId);
CHECK_EQ(itinerary.path().getRowDim(), 1);
CHECK_EQ(itinerary.path().getColDim(), 1);
}
}
}
}
SUBCASE("Set destination") {
GIVEN("An itinerary id, its destination id and a transition matrix") {
uint8_t itineraryId{0};
uint8_t destinationId{2};
dsm::SparseMatrix<bool> path{1, 1};
Itinerary itinerary{itineraryId, destinationId, path};
WHEN("The destination is set") {
uint8_t newDestinationId{3};
itinerary.setDestination(newDestinationId);
THEN("The destination is set correctly and the path is cleared") {
CHECK_EQ(itinerary.destination(), newDestinationId);
CHECK_EQ(itinerary.path().getRowDim(), 0);
CHECK_EQ(itinerary.path().getColDim(), 0);
CHECK_EQ(itinerary.path().size(), 0);
}
}
}
}
}
Loading