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 examples/stalingrado.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ int main() {
if (progress % 300 == 0) {
ofs << progress << ';' << spire.outputCounts(true) << std::endl;
}
dynamics.addAgents(4, *it / 2, 0);
dynamics.addAgents(*it / 2, 4, 0);
}
dynamics.evolve(false);
++progress;
Expand Down
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 = 6;
static constexpr uint8_t DSM_VERSION_PATCH = 7;

static auto const DSM_VERSION =
std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH);
Expand Down
260 changes: 24 additions & 236 deletions src/dsm/headers/Dynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,25 +147,18 @@
void setDestinationNodes(const std::span<Id>& destinationNodes,
bool updatePaths = true);

/// @brief Add an agent to the simulation
/// @param agent The agent
void addAgent(const agent_t& agent);
/// @brief Add an agent to the simulation
/// @param agent std::unique_ptr to the agent
void addAgent(std::unique_ptr<agent_t> agent);
/// @brief Add an agent with given source node and itinerary
/// @param srcNodeId The id of the source node
/// @param itineraryId The id of the itinerary
/// @throws std::invalid_argument If the source node or the itinerary are not found
void addAgent(Id srcNodeId, Id itineraryId);
/// @brief Add a pack of agents to the simulation
/// @param itineraryId The index of the itinerary
/// @param nAgents The number of agents to add
/// @throw std::invalid_argument If the itinerary is not found
/// @details adds nAgents agents with the same itinerary of id itineraryId
void addAgents(Id itineraryId,
Size nAgents = 1,
std::optional<Id> srcNodeId = std::nullopt);

template <typename... TArgs>
requires(std::is_constructible_v<agent_t, TArgs...>)
void addAgent(TArgs&&... args);

template <typename... TArgs>
requires(std::is_constructible_v<agent_t, Id, TArgs...>)
void addAgents(Size nAgents, TArgs&&... args);

/// @brief Add a pack of agents to the simulation
/// @param agents Parameter pack of agents
template <typename... Tn>
Expand All @@ -180,27 +173,12 @@
/// @brief Add a set of agents to the simulation
/// @param agents Generic container of agents, represented by an std::span
void addAgents(std::span<agent_t> agents);
/// @brief Add a set of agents to the simulation
/// @param nAgents The number of agents to add
/// @param uniformly If true, the agents are added uniformly on the streets
/// @throw std::runtime_error If there are no itineraries
virtual void addAgentsUniformly(Size nAgents,
std::optional<Id> itineraryId = std::nullopt);
template <typename TContainer>
requires(std::is_same_v<TContainer, std::unordered_map<Id, double>> ||
std::is_same_v<TContainer, std::map<Id, double>>)
void addAgentsRandomly(Size nAgents,
const TContainer& src_weights,
const TContainer& dst_weights);

void addRandomAgents(Size nAgents, std::optional<Id> srcNodeId = std::nullopt);

/// @brief Remove an agent from the simulation
/// @param agentId the id of the agent to remove
void removeAgent(Size agentId);
template <typename T1, typename... Tn>
requires(std::is_convertible_v<T1, Size> &&
(std::is_convertible_v<Tn, Size> && ...))
requires(std::is_convertible_v<T1, Id> && (std::is_convertible_v<Tn, Size> && ...))
/// @brief Remove a pack of agents from the simulation
/// @param id the id of the first agent to remove
/// @param ids the pack of ides of the agents to remove
Expand Down Expand Up @@ -333,19 +311,6 @@
}
}

template <typename agent_t>
void Dynamics<agent_t>::addAgent(const agent_t& agent) {
if (m_agents.size() + 1 > m_graph.maxCapacity()) {
throw std::overflow_error(buildLog(
std::format("Graph is already holding the max possible number of agents ({})",
m_graph.maxCapacity())));
}
if (m_agents.contains(agent.id())) {
throw std::invalid_argument(
buildLog(std::format("Agent with id {} already exists.", agent.id())));
}
m_agents.emplace(agent.id(), std::make_unique<agent_t>(agent));
}
template <typename agent_t>
void Dynamics<agent_t>::addAgent(std::unique_ptr<agent_t> agent) {
if (m_agents.size() + 1 > m_graph.maxCapacity()) {
Expand All @@ -359,47 +324,24 @@
}
m_agents.emplace(agent->id(), std::move(agent));
}

template <typename agent_t>
void Dynamics<agent_t>::addAgent(Id srcNodeId, Id itineraryId) {
if (m_agents.size() + 1 > m_graph.maxCapacity()) {
throw std::overflow_error(buildLog(
std::format("Graph is already holding the max possible number of agents ({})",
m_graph.maxCapacity())));
}
if (!(srcNodeId < m_graph.nodeSet().size())) {
throw std::invalid_argument(
buildLog(std::format("Node with id {} not found", srcNodeId)));
}
if (!(m_itineraries.contains(itineraryId))) {
throw std::invalid_argument(
buildLog(std::format("Itinerary with id {} not found", itineraryId)));
}
Size agentId{0};
if (!m_agents.empty()) {
agentId = m_agents.rbegin()->first + 1;
}
this->addAgent(agent_t{agentId, itineraryId, srcNodeId});
template <typename... TArgs>
requires(std::is_constructible_v<agent_t, TArgs...>)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
void Dynamics<agent_t>::addAgent(TArgs&&... args) {
addAgent(std::make_unique<agent_t>(std::forward<TArgs>(args)...));
}

template <typename agent_t>
void Dynamics<agent_t>::addAgents(Id itineraryId,
Size nAgents,
std::optional<Id> srcNodeId) {
if (m_agents.size() + nAgents > m_graph.maxCapacity()) {
throw std::overflow_error(buildLog(
std::format("Graph is already holding the max possible number of agents ({})",
m_graph.maxCapacity())));
}
auto itineraryIt{m_itineraries.find(itineraryId)};
if (itineraryIt == m_itineraries.end()) {
throw std::invalid_argument(
buildLog(std::format("Itinerary with id {} not found", itineraryId)));
}
Size agentId{0};
template <typename... TArgs>
requires(std::is_constructible_v<agent_t, Id, TArgs...>)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
void Dynamics<agent_t>::addAgents(Size nAgents, TArgs&&... args) {
Id agentId{0};
if (!m_agents.empty()) {
agentId = m_agents.rbegin()->first + 1;
}
for (Size i{0}; i < nAgents; ++i, ++agentId) {
this->addAgent(agent_t{agentId, itineraryId, srcNodeId});
for (size_t i{0}; i < nAgents; ++i, ++agentId) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
addAgent(std::make_unique<agent_t>(agentId, std::forward<TArgs>(args)...));
}
}

Expand All @@ -412,171 +354,17 @@
template <typename T1, typename... Tn>
requires(is_agent_v<T1> && (is_agent_v<Tn> && ...))
void Dynamics<agent_t>::addAgents(T1 agent, Tn... agents) {
addAgent(agent);
addAgent(std::make_unique<agent_t>(agent));
addAgents(agents...);
}

template <typename agent_t>
void Dynamics<agent_t>::addAgents(std::span<agent_t> agents) {
if (this->m_agents.size() + agents.size() > this->m_graph.maxCapacity()) {
throw std::overflow_error(buildLog(
std::format("Graph is already holding the max possible number of agents ({})",
this->m_graph.maxCapacity())));
}
std::ranges::for_each(agents, [this](const auto& agent) -> void {
this->m_agents.push_back(std::make_unique(agent));
addAgent(std::make_unique<agent_t>(agent));
});
}

template <typename agent_t>
void Dynamics<agent_t>::addAgentsUniformly(Size nAgents,
std::optional<Id> itineraryId) {
if (m_agents.size() + nAgents > m_graph.maxCapacity()) {
throw std::overflow_error(buildLog(
std::format("Graph is already holding the max possible number of agents ({})",
this->m_graph.maxCapacity())));
}
if (m_itineraries.empty()) {
// TODO: make this possible for random agents
throw std::invalid_argument(
buildLog("It is not possible to add random agents without itineraries."));
}
const bool randomItinerary{!itineraryId.has_value()};
std::uniform_int_distribution<Size> itineraryDist{
0, static_cast<Size>(m_itineraries.size() - 1)};
std::uniform_int_distribution<Size> streetDist{
0, static_cast<Size>(m_graph.streetSet().size() - 1)};
for (Size i{0}; i < nAgents; ++i) {
if (randomItinerary) {
auto itineraryIt{m_itineraries.begin()};
std::advance(itineraryIt, itineraryDist(m_generator));
itineraryId = itineraryIt->first;
}
Id agentId{0};
if (!m_agents.empty()) {
agentId = m_agents.rbegin()->first + 1;
}
Id streetId{0};
do {
// I dunno why this works and the following doesn't
const auto& streetSet = m_graph.streetSet();
auto streetIt = streetSet.begin();
// auto streetIt = this->m_graph->streetSet().begin();
Size step = streetDist(m_generator);
std::advance(streetIt, step);
streetId = streetIt->first;
} while (m_graph.streetSet()[streetId]->isFull());
const auto& street{m_graph.streetSet()[streetId]};
agent_t agent{agentId, itineraryId.value(), street->nodePair().first};
agent.setStreetId(streetId);
this->addAgent(agent);
this->setAgentSpeed(agentId);
m_agents[agentId]->incrementDelay(
std::ceil(street->length() / m_agents[agentId]->speed()));
street->addAgent(agentId);
++agentId;
}
}

template <typename agent_t>
template <typename TContainer>
requires(std::is_same_v<TContainer, std::unordered_map<Id, double>> ||
std::is_same_v<TContainer, std::map<Id, double>>)
void Dynamics<agent_t>::addAgentsRandomly(Size nAgents,
const TContainer& src_weights,
const TContainer& dst_weights) {
if (src_weights.size() == 1 && dst_weights.size() == 1 &&
src_weights.begin()->first == dst_weights.begin()->first) {
throw std::invalid_argument(buildLog(
std::format("The only source node {} is also the only destination node.",
src_weights.begin()->first)));
}
auto const srcSum{std::accumulate(
src_weights.begin(),
src_weights.end(),
0.,
[](double sum, const std::pair<Id, double>& p) {
if (p.second < 0.) {
throw std::invalid_argument(buildLog(std::format(
"Negative weight ({}) for source node {}.", p.second, p.first)));
}
return sum + p.second;
})};
auto const dstSum{std::accumulate(
dst_weights.begin(),
dst_weights.end(),
0.,
[](double sum, const std::pair<Id, double>& p) {
if (p.second < 0.) {
throw std::invalid_argument(buildLog(std::format(
"Negative weight ({}) for destination node {}.", p.second, p.first)));
}
return sum + p.second;
})};
std::uniform_real_distribution<double> srcUniformDist{0., srcSum};
std::uniform_real_distribution<double> dstUniformDist{0., dstSum};
while (nAgents > 0) {
Id srcId{0}, dstId{0};
if (dst_weights.size() == 1) {
dstId = dst_weights.begin()->first;
srcId = dstId;
}
double dRand, sum;
while (srcId == dstId) {
dRand = srcUniformDist(m_generator);
sum = 0.;
for (const auto& [id, weight] : src_weights) {
srcId = id;
sum += weight;
if (dRand < sum) {
break;
}
}
}
if (src_weights.size() > 1) {
dstId = srcId;
}
while (dstId == srcId) {
dRand = dstUniformDist(m_generator);
sum = 0.;
for (const auto& [id, weight] : dst_weights) {
dstId = id;
sum += weight;
if (dRand < sum) {
break;
}
}
}
// find the itinerary with the given destination as destination
auto itineraryIt{std::find_if(
m_itineraries.begin(), m_itineraries.end(), [dstId](const auto& itinerary) {
return itinerary.second->destination() == dstId;
})};
if (itineraryIt == m_itineraries.end()) {
throw std::invalid_argument(
buildLog(std::format("Itinerary with destination {} not found.", dstId)));
}
this->addAgent(srcId, itineraryIt->first);
--nAgents;
}
}

template <typename agent_t>
void Dynamics<agent_t>::addRandomAgents(Size nAgents, std::optional<Id> srcNodeId) {
if (m_agents.size() + nAgents > m_graph.maxCapacity()) {
throw std::overflow_error(buildLog(
std::format("Graph is already holding the max possible number of agents ({})",
m_graph.maxCapacity())));
}
Id agentId{0};
if (!m_agents.empty()) {
agentId = m_agents.rbegin()->first + 1;
}
for (auto i{0}; i < nAgents; ++i, ++agentId) {
this->addAgent(agent_t{agentId, srcNodeId});
}
}

template <typename agent_t>
void Dynamics<agent_t>::removeAgent(Size agentId) {
m_agents.erase(agentId);
Expand Down
Loading
Loading