Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
72 changes: 53 additions & 19 deletions src/dsm/headers/Agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,45 @@
#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; }
void setItineraryId(std::vector<Id> itineraryId) { m_trip = 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 +85,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 +130,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 +160,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
Loading
Loading