Skip to content

Commit c3bf939

Browse files
authored
Add random agents management (#234)
* Init random Agents * Manage Random agents * addRandomAgents * Less variables is better * End adding random agents * Update version * ops * Fix stalingrado
1 parent 383d412 commit c3bf939

File tree

10 files changed

+134
-50
lines changed

10 files changed

+134
-50
lines changed

examples/slow_charge_rb.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ int main(int argc, char** argv) {
135135
std::cout << "Number of exits: " << n << '\n';
136136

137137
dynamics.setErrorProbability(0.05);
138-
dynamics.setMaxFlowPercentage(0.7707);
138+
dynamics.setPassageProbability(0.7707);
139139
// dynamics.setForcePriorities(true);
140140
dynamics.setSpeedFluctuationSTD(0.1);
141141

examples/stalingrado.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ int main() {
5151
Street s01{1, 2281 / 8, 2281., 13.9, std::make_pair(0, 1)};
5252
Street s12{7, 118 / 8, 118., 13.9, std::make_pair(1, 2)};
5353
Street s23{13, 222 / 8, 222., 13.9, std::make_pair(2, 3)};
54-
Street s34{19, 651 / 4, 651., 13.9, std::make_pair(3, 4)};
54+
Street s34{19, 1, 651., 13.9, std::make_pair(3, 4), 2};
5555
// Viale Aldo Moro
5656
TrafficLight tl1{1, 132};
5757
tl1.setCycle(s01.id(), dsm::Direction::ANY, {62, 0});
@@ -76,6 +76,8 @@ int main() {
7676
graph.addNode(std::make_unique<TrafficLight>(tl4));
7777
graph.addStreets(s01, s12, s23, s34);
7878
graph.buildAdj();
79+
graph.adjustNodeCapacities();
80+
graph.normalizeStreetCapacities();
7981
auto& spire = graph.makeSpireStreet(19);
8082

8183
std::cout << "Intersections: " << graph.nNodes() << '\n';
@@ -84,7 +86,7 @@ int main() {
8486
// Create the dynamics
8587
Dynamics dynamics{graph, 69, 0.95};
8688
dynamics.setSpeedFluctuationSTD(0.2);
87-
Itinerary itinerary{0, 4};
89+
Itinerary itinerary{4, 4};
8890
dynamics.addItinerary(itinerary);
8991
dynamics.updatePaths();
9092

@@ -108,7 +110,7 @@ int main() {
108110
if (progress % 300 == 0) {
109111
ofs << progress << ';' << spire.outputCounts(true) << std::endl;
110112
}
111-
dynamics.addAgents(0, *it / 2, 0);
113+
dynamics.addAgents(4, *it / 2, 0);
112114
}
113115
dynamics.evolve(false);
114116
++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 = 5;
9+
static constexpr uint8_t DSM_VERSION_PATCH = 6;
1010

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

src/dsm/headers/Agent.hpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ namespace dsm {
4242
public:
4343
/// @brief Construct a new Agent object
4444
/// @param id The agent's id
45-
/// @param itineraryId The agent's itinerary
45+
/// @param itineraryId Optional, The agent's destination node. If not provided, the agent is a random agent
4646
/// @param srcNodeId Optional, The id of the source node of the agent
47-
Agent(Id id, Id itineraryId, std::optional<Id> srcNodeId = std::nullopt);
47+
Agent(Id id,
48+
std::optional<Id> itineraryId = std::nullopt,
49+
std::optional<Id> srcNodeId = std::nullopt);
4850
/// @brief Construct a new Agent object
4951
/// @param id The agent's id
5052
/// @param itineraryIds The agent's itinerary
@@ -123,13 +125,17 @@ namespace dsm {
123125
/// @brief Get the agent's travel time
124126
/// @return The agent's travel time
125127
unsigned int time() const { return m_time; }
128+
/// @brief Return true if the agent is a random agent
129+
/// @return True if the agent is a random agent, false otherwise
130+
bool isRandom() const { return m_trip.empty(); }
126131
};
127132

128133
template <typename delay_t>
129134
requires(is_numeric_v<delay_t>)
130-
Agent<delay_t>::Agent(Id id, Id itineraryId, std::optional<Id> srcNodeId)
135+
Agent<delay_t>::Agent(Id id, std::optional<Id> itineraryId, std::optional<Id> srcNodeId)
131136
: m_id{id},
132-
m_trip{itineraryId},
137+
m_trip{itineraryId.has_value() ? std::vector<Id>{itineraryId.value()}
138+
: std::vector<Id>{}},
133139
m_srcNodeId{srcNodeId},
134140
m_delay{0},
135141
m_speed{0.},

src/dsm/headers/Dynamics.hpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ namespace dsm {
193193
const TContainer& src_weights,
194194
const TContainer& dst_weights);
195195

196+
void addRandomAgents(Size nAgents, std::optional<Id> srcNodeId = std::nullopt);
197+
196198
/// @brief Remove an agent from the simulation
197199
/// @param agentId the id of the agent to remove
198200
void removeAgent(Size agentId);
@@ -239,6 +241,9 @@ namespace dsm {
239241
/// @brief Get the agents
240242
/// @return const std::unordered_map<Id, Agent<Id>>&, The agents
241243
const std::map<Id, std::unique_ptr<agent_t>>& agents() const { return m_agents; }
244+
/// @brief Get the number of agents currently in the simulation
245+
/// @return Size The number of agents
246+
const Size nAgents() const { return m_agents.size(); }
242247
/// @brief Get the time
243248
/// @return Time The time
244249
Time time() const { return m_time; }
@@ -556,13 +561,28 @@ namespace dsm {
556561
}
557562
}
558563

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+
559580
template <typename agent_t>
560581
void Dynamics<agent_t>::removeAgent(Size agentId) {
561582
m_agents.erase(agentId);
562583
}
563584

564585
template <typename agent_t>
565-
566586
template <typename T1, typename... Tn>
567587
requires(std::is_convertible_v<T1, Size> && (std::is_convertible_v<Tn, Size> && ...))
568588
void Dynamics<agent_t>::removeAgents(T1 id, Tn... ids) {

src/dsm/headers/Graph.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ namespace dsm {
143143
}
144144
}
145145

146-
void Graph::importMatrix(const std::string& fileName, bool isAdj) {
146+
void Graph::importMatrix(const std::string& fileName, bool isAdj, double defaultSpeed) {
147147
// check the file extension
148148
std::string fileExt = fileName.substr(fileName.find_last_of(".") + 1);
149149
if (fileExt == "dsm") {
@@ -178,6 +178,7 @@ namespace dsm {
178178
if (!isAdj) {
179179
m_streets[index]->setLength(val);
180180
}
181+
m_streets[index]->setMaxSpeed(defaultSpeed);
181182
}
182183
} else {
183184
// default case: read the file as a matrix with the first two elements being the number of rows and columns and
@@ -223,6 +224,7 @@ namespace dsm {
223224
if (!isAdj) {
224225
m_streets[index]->setLength(value);
225226
}
227+
m_streets[index]->setMaxSpeed(defaultSpeed);
226228
}
227229
++index;
228230
}

src/dsm/headers/Graph.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,12 @@ namespace dsm {
121121
/// the number of rows and columns and the following elements being the matrix elements.
122122
/// @param fileName The name of the file to import the adjacency matrix from.
123123
/// @param isAdj A boolean value indicating if the file contains the adjacency matrix or the distance matrix.
124+
/// @param defaultSpeed The default speed limit for the streets
124125
/// @throws std::invalid_argument if the file is not found or invalid
125126
/// The matrix format is deduced from the file extension. Currently only .dsm files are supported.
126-
void importMatrix(const std::string& fileName, bool isAdj = true);
127+
void importMatrix(const std::string& fileName,
128+
bool isAdj = true,
129+
double defaultSpeed = 13.8888888889);
127130
/// @brief Import the graph's nodes from a file
128131
/// @param fileName The name of the file to import the nodes from.
129132
/// @throws std::invalid_argument if the file is not found, invalid or the format is not supported

src/dsm/headers/RoadDynamics.hpp

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace dsm {
4343
protected:
4444
Time m_previousOptimizationTime;
4545
double m_errorProbability;
46-
double m_maxFlowPercentage;
46+
double m_passageProbability;
4747
std::vector<double> m_travelTimes;
4848
std::unordered_map<Id, Id> m_agentNextStreetId;
4949
bool m_forcePriorities;
@@ -88,11 +88,8 @@ namespace dsm {
8888
/// @param errorProbability The error probability
8989
/// @throw std::invalid_argument If the error probability is not between 0 and 1
9090
void setErrorProbability(double errorProbability);
91-
/// @brief Set the maximum flow percentage
92-
/// @param maxFlowPercentage The maximum flow percentage
93-
/// @details The maximum flow percentage is the percentage of the maximum flow that a street can transmit. Default is 1 (100%).
94-
/// @throw std::invalid_argument If the maximum flow percentage is not between 0 and 1
95-
void setMaxFlowPercentage(double maxFlowPercentage);
91+
92+
void setPassageProbability(double passageProbability);
9693
/// @brief Set the force priorities flag
9794
/// @param forcePriorities The flag
9895
/// @details If true, if an agent cannot move to the next street, the whole node is skipped
@@ -151,7 +148,7 @@ namespace dsm {
151148
: Dynamics<Agent<delay_t>>(graph, seed),
152149
m_previousOptimizationTime{0},
153150
m_errorProbability{0.},
154-
m_maxFlowPercentage{1.},
151+
m_passageProbability{1.},
155152
m_forcePriorities{false} {
156153
for (const auto& [streetId, street] : this->m_graph.streetSet()) {
157154
m_streetTails.emplace(streetId, 0);
@@ -183,13 +180,16 @@ namespace dsm {
183180
Id RoadDynamics<delay_t>::m_nextStreetId(Id agentId,
184181
Id nodeId,
185182
std::optional<Id> streetId) {
183+
auto const& pAgent{this->m_agents[agentId]};
186184
auto possibleMoves = this->m_graph.adjMatrix().getRow(nodeId, true);
187-
std::uniform_real_distribution<double> uniformDist{0., 1.};
188-
if (this->m_itineraries.size() > 0 &&
189-
uniformDist(this->m_generator) > m_errorProbability) {
190-
const auto& it = this->m_itineraries[this->m_agents[agentId]->itineraryId()];
191-
if (it->destination() != nodeId) {
192-
possibleMoves = it->path().getRow(nodeId, true);
185+
if (!pAgent->isRandom()) {
186+
std::uniform_real_distribution<double> uniformDist{0., 1.};
187+
if (this->m_itineraries.size() > 0 &&
188+
uniformDist(this->m_generator) > m_errorProbability) {
189+
const auto& it = this->m_itineraries[pAgent->itineraryId()];
190+
if (it->destination() != nodeId) {
191+
possibleMoves = it->path().getRow(nodeId, true);
192+
}
193193
}
194194
}
195195
assert(possibleMoves.size() > 0);
@@ -233,8 +233,7 @@ namespace dsm {
233233
auto const nLanes = pStreet->nLanes();
234234
std::uniform_real_distribution<double> uniformDist{0., 1.};
235235
for (auto queueIndex = 0; queueIndex < nLanes; ++queueIndex) {
236-
if (uniformDist(this->m_generator) > m_maxFlowPercentage ||
237-
pStreet->queue(queueIndex).empty()) {
236+
if (pStreet->queue(queueIndex).empty()) {
238237
continue;
239238
}
240239
const auto agentId{pStreet->queue(queueIndex).front()};
@@ -254,8 +253,23 @@ namespace dsm {
254253
continue;
255254
}
256255
}
257-
if (destinationNode->id() ==
258-
this->m_itineraries[pAgent->itineraryId()]->destination()) {
256+
auto const bCanPass = uniformDist(this->m_generator) < m_passageProbability;
257+
bool bArrived{false};
258+
if (!bCanPass) {
259+
if (pAgent->isRandom()) {
260+
m_agentNextStreetId.erase(agentId);
261+
bArrived = true;
262+
} else {
263+
continue;
264+
}
265+
}
266+
if (!pAgent->isRandom()) {
267+
if (destinationNode->id() ==
268+
this->m_itineraries[pAgent->itineraryId()]->destination()) {
269+
bArrived = true;
270+
}
271+
}
272+
if (bArrived) {
259273
pStreet->dequeue(queueIndex);
260274
m_travelTimes.push_back(pAgent->time());
261275
if (reinsert_agents) {
@@ -345,6 +359,8 @@ namespace dsm {
345359
template <typename delay_t>
346360
requires(is_numeric_v<delay_t>)
347361
void RoadDynamics<delay_t>::m_evolveAgents() {
362+
std::uniform_int_distribution<Id> nodeDist{
363+
0, static_cast<Id>(this->m_graph.nNodes() - 1)};
348364
for (const auto& [agentId, agent] : this->m_agents) {
349365
if (agent->delay() > 0) {
350366
const auto& street{this->m_graph.streetSet()[agent->streetId().value()]};
@@ -361,12 +377,18 @@ namespace dsm {
361377
agent->decrementDelay();
362378
if (agent->delay() == 0) {
363379
auto const nLanes = street->nLanes();
364-
if (this->m_itineraries[agent->itineraryId()]->destination() ==
365-
street->nodePair().second) {
366-
agent->updateItinerary();
380+
bool bArrived{false};
381+
if (!agent->isRandom()) {
382+
if (this->m_itineraries[agent->itineraryId()]->destination() ==
383+
street->nodePair().second) {
384+
agent->updateItinerary();
385+
}
386+
if (this->m_itineraries[agent->itineraryId()]->destination() ==
387+
street->nodePair().second) {
388+
bArrived = true;
389+
}
367390
}
368-
if (this->m_itineraries[agent->itineraryId()]->destination() ==
369-
street->nodePair().second) {
391+
if (bArrived) {
370392
std::uniform_int_distribution<size_t> laneDist{
371393
0, static_cast<size_t>(nLanes - 1)};
372394
street->enqueue(agentId, laneDist(this->m_generator));
@@ -398,8 +420,9 @@ namespace dsm {
398420
}
399421
} else if (!agent->streetId().has_value() &&
400422
!m_agentNextStreetId.contains(agentId)) {
401-
assert(agent->srcNodeId().has_value());
402-
const auto& srcNode{this->m_graph.nodeSet()[agent->srcNodeId().value()]};
423+
Id srcNodeId = agent->srcNodeId().has_value() ? agent->srcNodeId().value()
424+
: nodeDist(this->m_generator);
425+
const auto& srcNode{this->m_graph.nodeSet()[srcNodeId]};
403426
if (srcNode->isFull()) {
404427
continue;
405428
}
@@ -436,13 +459,12 @@ namespace dsm {
436459

437460
template <typename delay_t>
438461
requires(is_numeric_v<delay_t>)
439-
void RoadDynamics<delay_t>::setMaxFlowPercentage(double maxFlowPercentage) {
440-
if (maxFlowPercentage < 0. || maxFlowPercentage > 1.) {
441-
throw std::invalid_argument(
442-
buildLog(std::format("The maximum flow percentage ({}) must be between 0 and 1",
443-
maxFlowPercentage)));
462+
void RoadDynamics<delay_t>::setPassageProbability(double passageProbability) {
463+
if (passageProbability < 0. || passageProbability > 1.) {
464+
throw std::invalid_argument(buildLog(std::format(
465+
"The passage probability ({}) must be between 0 and 1", passageProbability)));
444466
}
445-
m_maxFlowPercentage = maxFlowPercentage;
467+
m_passageProbability = passageProbability;
446468
}
447469

448470
template <typename delay_t>

test/Test_agent.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,12 @@ TEST_CASE("Agent") {
4444
}
4545
}
4646
}
47+
GIVEN("An agent it") {
48+
uint16_t agentId{1};
49+
WHEN("The agent is constructed") {
50+
auto randomAgent = Agent{agentId};
51+
THEN("The agent is a random agent") { CHECK(randomAgent.isRandom()); }
52+
}
53+
}
4754
}
4855
}

0 commit comments

Comments
 (0)