Queueing System
Overview¶
The Queue class is a core component designed to optimize the computational efficiency of your agent-based simulations. In large-scale epidemiological models, where thousands or millions of agents may be able to interact, iterating over all agents at every simulation step can be computationally prohibitive ($O(n^2)$). The Queue class addresses this challenge by selectively activating agents for processing. Specifically, it ensures that only agents in relevant states (such as those infected or those with infected neighbors) are processed during each simulation step. This selective queuing mechanism reduces unnecessary computations, focusing resources on agents that are likely to change state or influence others. This allows for larger simulations, and contributes greatly to the overall speed of epiworld.
The Queue class is tightly integrated with the Model class, which provides the broader context for agent-based simulations. The queue interacts with the model to access agent states, network structures, and other simulation parameters. This integration allows the queue to dynamically adjust its contents based on the evolving state of the simulation. For example, when an agent transitions to an infected state, the queue can add the agent and its neighbors for processing. Similarly, when an agent recovers or is removed from the simulation, the queue can remove the agent and its neighbors.
The queue operates on the principle of dynamic activation. Agents are added to the queue when their state or the state of their neighbors changes in a way that makes them relevant to the simulation. For example, an agent transitioning to an infected state would be added to the queue, along with its neighbors, as they are now at risk of infection. Conversely, agents are removed from the queue when their state or the state of their neighbors no longer requires processing. This dynamic management of the queue ensures that the simulation remains efficient while maintaining accuracy.
However, it is worth noting that the performance gains depend on the sparsity of the network and the frequency of state transitions. In densely connected networks or scenarios with high state transition rates, the overhead of managing the queue may offset the benefits. In such cases, alternative queuing strategies or optimizations may be required.
Implementation¶
The Queue class is implemented as a template and encapsulates several key data members and methods that govern its behavior.
Members¶
std::vector<epiworld_fast_int> active: tracks the activation status of agents and their neighbors. Each element corresponds to an agent, with the value indicating the number of times the agent has been activated.Model<TSeq> * model: A pointer to the associatedModelinstance. This allows the queue to interact with the broader simulation framework, accessing agent states and network structures as needed.int n_in_queue: The number of agents currently in the queue. This counter provides a quick way to determine the queue's size without iterating over theactivevector.
Methods¶
void operator+=(Agent<TSeq> * p): Adds an agent and its neighbors to the queue. This method increments the activation counters for the agent and its neighbors, ensuring they are processed in subsequent simulation steps.void operator-=(Agent<TSeq> * p): Removes an agent and its neighbors from the queue. This method decrements the activation counters, removing agents from the queue when their counters reach zero.epiworld_fast_int & operator[](epiworld_fast_uint i): Provides access to the activation status of a specific agent. This method allows direct manipulation of theactivevector, enabling advanced customization.void reset(): Resets the queue, clearing all activation statuses. This method is typically called at the start of a new simulation step to prepare the queue for the next round of processing.bool operator==(const Queue<TSeq> & other) const: Compares two queues for equality. This method checks whether theactivevectors of the two queues are identical, providing a way to verify the consistency of the queue's state.bool operator!=(const Queue<TSeq> & other) const: Compares two queues for inequality. This method is implemented as the negation of the equality operator.
Usage Example¶
The following example demonstrates how to interact with the Queue class in the context of a simulation. This includes adding agents to the queue, removing them, and resetting the queue at the start of a new simulation step.
#include "epiworld/queue-bones.hpp"
#include "epiworld/agent-bones.hpp"
#include "epiworld/model-bones.hpp"
void simulate_step(Queue<int> &queue, Model<int> &model) {
// Example: Adding an agent to the queue
Agent<int> *agent = model.get_agent(0); // Retrieve the first agent
queue += agent; // Add the agent and its neighbors to the queue
// Example: Processing agents in the queue
for (size_t i = 0; i < model.size(); ++i) {
// Check if the agent is active
if (queue[i] > 0) {
// Perform some operation on the active agent
std::cout << "Processing agent " << i << std::endl;
}
}
// Example: Removing an agent from the queue
queue -= agent; // Remove the agent and its neighbors from the queue
// Example: Resetting the queue at the start of a new step
queue.reset();
}
In this example:
- The += operator is used to add an agent and its neighbors to the queue. This ensures that the agent and its neighbors are processed in the current simulation step.
- The queue[i] method is used to check the activation status of an agent. Only active agents are processed.
- The -= operator is used to remove an agent and its neighbors from the queue. This is useful for deactivating agents that no longer need to be processed.
- The reset method is called at the start of a new simulation step to clear the queue and prepare it for the next round of processing.