Skip to content

Commit 39997a3

Browse files
authored
Refactor addAgent(s) functions (#235)
* Refactor `addAgent(s)` functions * Remove unused functions * Move specific adders from Dynamics to RoadDynamics * Update script * Update version
1 parent c3bf939 commit 39997a3

File tree

5 files changed

+212
-288
lines changed

5 files changed

+212
-288
lines changed

examples/stalingrado.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ int main() {
110110
if (progress % 300 == 0) {
111111
ofs << progress << ';' << spire.outputCounts(true) << std::endl;
112112
}
113-
dynamics.addAgents(4, *it / 2, 0);
113+
dynamics.addAgents(*it / 2, 4, 0);
114114
}
115115
dynamics.evolve(false);
116116
++progress;

src/dsm/dsm.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
static constexpr uint8_t DSM_VERSION_MAJOR = 2;
88
static constexpr uint8_t DSM_VERSION_MINOR = 2;
9-
static constexpr uint8_t DSM_VERSION_PATCH = 6;
9+
static constexpr uint8_t DSM_VERSION_PATCH = 7;
1010

1111
static auto const DSM_VERSION =
1212
std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH);

src/dsm/headers/Dynamics.hpp

Lines changed: 24 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -147,25 +147,18 @@ namespace dsm {
147147
void setDestinationNodes(const std::span<Id>& destinationNodes,
148148
bool updatePaths = true);
149149

150-
/// @brief Add an agent to the simulation
151-
/// @param agent The agent
152-
void addAgent(const agent_t& agent);
153150
/// @brief Add an agent to the simulation
154151
/// @param agent std::unique_ptr to the agent
155152
void addAgent(std::unique_ptr<agent_t> agent);
156-
/// @brief Add an agent with given source node and itinerary
157-
/// @param srcNodeId The id of the source node
158-
/// @param itineraryId The id of the itinerary
159-
/// @throws std::invalid_argument If the source node or the itinerary are not found
160-
void addAgent(Id srcNodeId, Id itineraryId);
161-
/// @brief Add a pack of agents to the simulation
162-
/// @param itineraryId The index of the itinerary
163-
/// @param nAgents The number of agents to add
164-
/// @throw std::invalid_argument If the itinerary is not found
165-
/// @details adds nAgents agents with the same itinerary of id itineraryId
166-
void addAgents(Id itineraryId,
167-
Size nAgents = 1,
168-
std::optional<Id> srcNodeId = std::nullopt);
153+
154+
template <typename... TArgs>
155+
requires(std::is_constructible_v<agent_t, TArgs...>)
156+
void addAgent(TArgs&&... args);
157+
158+
template <typename... TArgs>
159+
requires(std::is_constructible_v<agent_t, Id, TArgs...>)
160+
void addAgents(Size nAgents, TArgs&&... args);
161+
169162
/// @brief Add a pack of agents to the simulation
170163
/// @param agents Parameter pack of agents
171164
template <typename... Tn>
@@ -180,27 +173,12 @@ namespace dsm {
180173
/// @brief Add a set of agents to the simulation
181174
/// @param agents Generic container of agents, represented by an std::span
182175
void addAgents(std::span<agent_t> agents);
183-
/// @brief Add a set of agents to the simulation
184-
/// @param nAgents The number of agents to add
185-
/// @param uniformly If true, the agents are added uniformly on the streets
186-
/// @throw std::runtime_error If there are no itineraries
187-
virtual void addAgentsUniformly(Size nAgents,
188-
std::optional<Id> itineraryId = std::nullopt);
189-
template <typename TContainer>
190-
requires(std::is_same_v<TContainer, std::unordered_map<Id, double>> ||
191-
std::is_same_v<TContainer, std::map<Id, double>>)
192-
void addAgentsRandomly(Size nAgents,
193-
const TContainer& src_weights,
194-
const TContainer& dst_weights);
195-
196-
void addRandomAgents(Size nAgents, std::optional<Id> srcNodeId = std::nullopt);
197176

198177
/// @brief Remove an agent from the simulation
199178
/// @param agentId the id of the agent to remove
200179
void removeAgent(Size agentId);
201180
template <typename T1, typename... Tn>
202-
requires(std::is_convertible_v<T1, Size> &&
203-
(std::is_convertible_v<Tn, Size> && ...))
181+
requires(std::is_convertible_v<T1, Id> && (std::is_convertible_v<Tn, Size> && ...))
204182
/// @brief Remove a pack of agents from the simulation
205183
/// @param id the id of the first agent to remove
206184
/// @param ids the pack of ides of the agents to remove
@@ -333,19 +311,6 @@ namespace dsm {
333311
}
334312
}
335313

336-
template <typename agent_t>
337-
void Dynamics<agent_t>::addAgent(const agent_t& agent) {
338-
if (m_agents.size() + 1 > m_graph.maxCapacity()) {
339-
throw std::overflow_error(buildLog(
340-
std::format("Graph is already holding the max possible number of agents ({})",
341-
m_graph.maxCapacity())));
342-
}
343-
if (m_agents.contains(agent.id())) {
344-
throw std::invalid_argument(
345-
buildLog(std::format("Agent with id {} already exists.", agent.id())));
346-
}
347-
m_agents.emplace(agent.id(), std::make_unique<agent_t>(agent));
348-
}
349314
template <typename agent_t>
350315
void Dynamics<agent_t>::addAgent(std::unique_ptr<agent_t> agent) {
351316
if (m_agents.size() + 1 > m_graph.maxCapacity()) {
@@ -359,47 +324,24 @@ namespace dsm {
359324
}
360325
m_agents.emplace(agent->id(), std::move(agent));
361326
}
327+
362328
template <typename agent_t>
363-
void Dynamics<agent_t>::addAgent(Id srcNodeId, Id itineraryId) {
364-
if (m_agents.size() + 1 > m_graph.maxCapacity()) {
365-
throw std::overflow_error(buildLog(
366-
std::format("Graph is already holding the max possible number of agents ({})",
367-
m_graph.maxCapacity())));
368-
}
369-
if (!(srcNodeId < m_graph.nodeSet().size())) {
370-
throw std::invalid_argument(
371-
buildLog(std::format("Node with id {} not found", srcNodeId)));
372-
}
373-
if (!(m_itineraries.contains(itineraryId))) {
374-
throw std::invalid_argument(
375-
buildLog(std::format("Itinerary with id {} not found", itineraryId)));
376-
}
377-
Size agentId{0};
378-
if (!m_agents.empty()) {
379-
agentId = m_agents.rbegin()->first + 1;
380-
}
381-
this->addAgent(agent_t{agentId, itineraryId, srcNodeId});
329+
template <typename... TArgs>
330+
requires(std::is_constructible_v<agent_t, TArgs...>)
331+
void Dynamics<agent_t>::addAgent(TArgs&&... args) {
332+
addAgent(std::make_unique<agent_t>(std::forward<TArgs>(args)...));
382333
}
334+
383335
template <typename agent_t>
384-
void Dynamics<agent_t>::addAgents(Id itineraryId,
385-
Size nAgents,
386-
std::optional<Id> srcNodeId) {
387-
if (m_agents.size() + nAgents > m_graph.maxCapacity()) {
388-
throw std::overflow_error(buildLog(
389-
std::format("Graph is already holding the max possible number of agents ({})",
390-
m_graph.maxCapacity())));
391-
}
392-
auto itineraryIt{m_itineraries.find(itineraryId)};
393-
if (itineraryIt == m_itineraries.end()) {
394-
throw std::invalid_argument(
395-
buildLog(std::format("Itinerary with id {} not found", itineraryId)));
396-
}
397-
Size agentId{0};
336+
template <typename... TArgs>
337+
requires(std::is_constructible_v<agent_t, Id, TArgs...>)
338+
void Dynamics<agent_t>::addAgents(Size nAgents, TArgs&&... args) {
339+
Id agentId{0};
398340
if (!m_agents.empty()) {
399341
agentId = m_agents.rbegin()->first + 1;
400342
}
401-
for (Size i{0}; i < nAgents; ++i, ++agentId) {
402-
this->addAgent(agent_t{agentId, itineraryId, srcNodeId});
343+
for (size_t i{0}; i < nAgents; ++i, ++agentId) {
344+
addAgent(std::make_unique<agent_t>(agentId, std::forward<TArgs>(args)...));
403345
}
404346
}
405347

@@ -412,171 +354,17 @@ namespace dsm {
412354
template <typename T1, typename... Tn>
413355
requires(is_agent_v<T1> && (is_agent_v<Tn> && ...))
414356
void Dynamics<agent_t>::addAgents(T1 agent, Tn... agents) {
415-
addAgent(agent);
357+
addAgent(std::make_unique<agent_t>(agent));
416358
addAgents(agents...);
417359
}
418360

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

431-
template <typename agent_t>
432-
void Dynamics<agent_t>::addAgentsUniformly(Size nAgents,
433-
std::optional<Id> itineraryId) {
434-
if (m_agents.size() + nAgents > m_graph.maxCapacity()) {
435-
throw std::overflow_error(buildLog(
436-
std::format("Graph is already holding the max possible number of agents ({})",
437-
this->m_graph.maxCapacity())));
438-
}
439-
if (m_itineraries.empty()) {
440-
// TODO: make this possible for random agents
441-
throw std::invalid_argument(
442-
buildLog("It is not possible to add random agents without itineraries."));
443-
}
444-
const bool randomItinerary{!itineraryId.has_value()};
445-
std::uniform_int_distribution<Size> itineraryDist{
446-
0, static_cast<Size>(m_itineraries.size() - 1)};
447-
std::uniform_int_distribution<Size> streetDist{
448-
0, static_cast<Size>(m_graph.streetSet().size() - 1)};
449-
for (Size i{0}; i < nAgents; ++i) {
450-
if (randomItinerary) {
451-
auto itineraryIt{m_itineraries.begin()};
452-
std::advance(itineraryIt, itineraryDist(m_generator));
453-
itineraryId = itineraryIt->first;
454-
}
455-
Id agentId{0};
456-
if (!m_agents.empty()) {
457-
agentId = m_agents.rbegin()->first + 1;
458-
}
459-
Id streetId{0};
460-
do {
461-
// I dunno why this works and the following doesn't
462-
const auto& streetSet = m_graph.streetSet();
463-
auto streetIt = streetSet.begin();
464-
// auto streetIt = this->m_graph->streetSet().begin();
465-
Size step = streetDist(m_generator);
466-
std::advance(streetIt, step);
467-
streetId = streetIt->first;
468-
} while (m_graph.streetSet()[streetId]->isFull());
469-
const auto& street{m_graph.streetSet()[streetId]};
470-
agent_t agent{agentId, itineraryId.value(), street->nodePair().first};
471-
agent.setStreetId(streetId);
472-
this->addAgent(agent);
473-
this->setAgentSpeed(agentId);
474-
m_agents[agentId]->incrementDelay(
475-
std::ceil(street->length() / m_agents[agentId]->speed()));
476-
street->addAgent(agentId);
477-
++agentId;
478-
}
479-
}
480-
481-
template <typename agent_t>
482-
template <typename TContainer>
483-
requires(std::is_same_v<TContainer, std::unordered_map<Id, double>> ||
484-
std::is_same_v<TContainer, std::map<Id, double>>)
485-
void Dynamics<agent_t>::addAgentsRandomly(Size nAgents,
486-
const TContainer& src_weights,
487-
const TContainer& dst_weights) {
488-
if (src_weights.size() == 1 && dst_weights.size() == 1 &&
489-
src_weights.begin()->first == dst_weights.begin()->first) {
490-
throw std::invalid_argument(buildLog(
491-
std::format("The only source node {} is also the only destination node.",
492-
src_weights.begin()->first)));
493-
}
494-
auto const srcSum{std::accumulate(
495-
src_weights.begin(),
496-
src_weights.end(),
497-
0.,
498-
[](double sum, const std::pair<Id, double>& p) {
499-
if (p.second < 0.) {
500-
throw std::invalid_argument(buildLog(std::format(
501-
"Negative weight ({}) for source node {}.", p.second, p.first)));
502-
}
503-
return sum + p.second;
504-
})};
505-
auto const dstSum{std::accumulate(
506-
dst_weights.begin(),
507-
dst_weights.end(),
508-
0.,
509-
[](double sum, const std::pair<Id, double>& p) {
510-
if (p.second < 0.) {
511-
throw std::invalid_argument(buildLog(std::format(
512-
"Negative weight ({}) for destination node {}.", p.second, p.first)));
513-
}
514-
return sum + p.second;
515-
})};
516-
std::uniform_real_distribution<double> srcUniformDist{0., srcSum};
517-
std::uniform_real_distribution<double> dstUniformDist{0., dstSum};
518-
while (nAgents > 0) {
519-
Id srcId{0}, dstId{0};
520-
if (dst_weights.size() == 1) {
521-
dstId = dst_weights.begin()->first;
522-
srcId = dstId;
523-
}
524-
double dRand, sum;
525-
while (srcId == dstId) {
526-
dRand = srcUniformDist(m_generator);
527-
sum = 0.;
528-
for (const auto& [id, weight] : src_weights) {
529-
srcId = id;
530-
sum += weight;
531-
if (dRand < sum) {
532-
break;
533-
}
534-
}
535-
}
536-
if (src_weights.size() > 1) {
537-
dstId = srcId;
538-
}
539-
while (dstId == srcId) {
540-
dRand = dstUniformDist(m_generator);
541-
sum = 0.;
542-
for (const auto& [id, weight] : dst_weights) {
543-
dstId = id;
544-
sum += weight;
545-
if (dRand < sum) {
546-
break;
547-
}
548-
}
549-
}
550-
// find the itinerary with the given destination as destination
551-
auto itineraryIt{std::find_if(
552-
m_itineraries.begin(), m_itineraries.end(), [dstId](const auto& itinerary) {
553-
return itinerary.second->destination() == dstId;
554-
})};
555-
if (itineraryIt == m_itineraries.end()) {
556-
throw std::invalid_argument(
557-
buildLog(std::format("Itinerary with destination {} not found.", dstId)));
558-
}
559-
this->addAgent(srcId, itineraryIt->first);
560-
--nAgents;
561-
}
562-
}
563-
564-
template <typename agent_t>
565-
void Dynamics<agent_t>::addRandomAgents(Size nAgents, std::optional<Id> srcNodeId) {
566-
if (m_agents.size() + nAgents > m_graph.maxCapacity()) {
567-
throw std::overflow_error(buildLog(
568-
std::format("Graph is already holding the max possible number of agents ({})",
569-
m_graph.maxCapacity())));
570-
}
571-
Id agentId{0};
572-
if (!m_agents.empty()) {
573-
agentId = m_agents.rbegin()->first + 1;
574-
}
575-
for (auto i{0}; i < nAgents; ++i, ++agentId) {
576-
this->addAgent(agent_t{agentId, srcNodeId});
577-
}
578-
}
579-
580368
template <typename agent_t>
581369
void Dynamics<agent_t>::removeAgent(Size agentId) {
582370
m_agents.erase(agentId);

0 commit comments

Comments
 (0)