5.1 Model Compilation
During each simulation cycle, the simulator spawns a set of concurrent processes, one for each individual, that run the individual and connection dynamics rules for it and update its state. All types of dynamics (policy, individual, or connection) are specified as lists of IF.DO rules of the form
which the simulator compiles into Elixir functions. In the case of individual dynamics rules, these functions have, in pseudocode, the general form
where this and updated\(\_\)this refer to the current state of the individual executing this rule and the one resulting from executing the do-part of the rule, respectively. In addition, global refers to the current state of the policy and cycle is the current simulation cycle number. To avoid indeterminate updating of agent states in a concurrent rule execution environment each individual dynamics rule can only update the state of the individual executing the rule.
Conceptually, individual dynamics rules utilize:
•
attribute values for the individual involved,
•
macroscopic connection data (e.g., number of incoming/outgoing connections for the individual),
•
existence, filtering and/or comparison of certain connection attribute values in incoming connections,
•
results of aggregated function evaluations on attributes of incoming connections (e.g., sum, threshold, mean, min/max),
•
current values of policy attributes.
As a result, these rules update the attributes of the individual involved and/or manage outgoing connections (e.g., remove/create/update outgoing connections). To model reproduction phenomena in the population the execution of an individual dynamics rule can add new nodes in the population as a side effect. We achieve management of these side effects in a consistent way in a concurrent environment by modelling the population as a separate concurrent process in the simulator. Such a process has its own state and receives messages from individuals to update its state. The population state includes a list of the concurrent processes corresponding to the list of individuals in the population. This list is updated every time an individual is added/removed from the population.
Connection dynamics rules, are compiled into functions that have the following form:
Compared to the previous case, such functions have two additional arguments/variables: edge and updated\(\_\)edge that refer to the state of the specific connection that runs the rule and the one resulting from executing the do-part of the rule, respectively. In addition, distal refers to the state of the individual at the receiving end of the connection. To avoid indeterminate updating of agent states in a concurrent rule execution environment each connection dynamics rule can only update the state of the connection executing the rule and not the state of the node at the receiving end of the edge. Conceptually, connection dynamics rules access attributes of individuals at both ends of the connection along with attributes of the specific connection to update the attributes of that connection.
Finally, policy dynamics rules are compiled similar to the individual dynamics rules as
This is the case, because policy state is implemented as a unique, special individual with its own attributes that correspond to the policy attributes and with no connections to the rest of the population. Conceptually, policy dynamics rules utilize current values of policy attributes while also computing aggregated population attributes based on attributes of individuals to update policy parameters at the end of each simulation cycle. This is why the function takes a third argument referred to as size with a value equal to the size of the current population. In addition, policy dynamics rules can add/remove individuals from the population to model either policy interventions (e.g., changes in the workforce) or exogenous influences on the population (e.g., migration). In this case, each new individual is responsible for forming connections with the rest of the population through its individual dynamics rules.
For example,
represents a connection dynamics rule that computes the influence of a connection as the product of the source node’s radicalization status times the contact strength of the connection, assuming that the source is not in isolation. Politika represents the state of the connection running the rule with the edge variable. It represents the state of the individual from which the edge originates (the source) with the this variable.
5.2 Concurrent Execution
The simulator permits the concurrent simulation of the behavior for all individuals based on BEAM, the Erlang runtime system with built-in support for concurrency and distribution of processing tasks in different nodes of a server cluster. The need to create computationally efficient simulations through concurrency requires the design of a global execution scheme at the population level that guarantees proper updating of attributes in all individuals and their connections. In particular, this scheme needs to:
•
provide immutable state for each attribute that avoids situations in which attributes accidentally change as a result of various side effects during computation,
•
ensure that at each point in time only one process updates an attribute, otherwise the outcome of the updating process can be undetermined.
The first requirement is satisfied through the use of a functional programming language such as Elixir where all variables have immutable state as each variable update results in a new copy of the variable. Therefore, data objects generated at different times remain distinct and in-place updating of data structures is avoided.
The second requirement necessitates a careful structuring of all computations involved that can provide correct updating of all attributes but also ensure the autonomous behavior of each individual in the simulation. To this end, each connection dynamics rule updates only the attributes for the connection it is applied on, while attributes for individuals are updated only through the application of individual dynamics rules for each individual. Therefore, in its outgoing connections each individual has read/generate/remove permissions via its individual dynamics rules and read/write permissions via its connection dynamics rules. Each individual has only read permissions on its incoming connections. This scheme allows the simulator to run the individual and connection dynamics rules for each individual concurrently as depicted in Figure
4. As this figure shows during such execution each individual runs first its connection and then its individual dynamics rules sequentially in the order specified by the simulation designer for each rule type. This ensures that connection dynamics rules always use the values of the individual attributes set at the end of the previous simulation cycle thus facilitating monitoring of their dynamics and providing consistency in their behavior. In addition, it ensures that only one rule can update an individual/connection attribute at each time, while also allowing the designer to code for scripted behaviors in individuals that assume a specific execution order of their relevant rules (e.g., when coding the steps in a financial transaction). Finally, policy dynamics rules are executed sequentially in the order specified by the designer at the end of each simulation cycle, since they utilize aggregated individual attributes. Such rules can only read attributes of individuals while they can read and update policy attributes. Overall, this scheme ensures the proper updating of individual, connection and policy attributes in a concurrent execution environment, because for each one of them there is a unique way of modifying it at each point in time.
The simulator takes into consideration the fact that a computing system has a finite set of schedulers that can execute concurrent tasks, as this is related to the number of processor cores available. Therefore, at the start of each cycle the simulator divides the population into chunks based on the list of concurrent processes corresponding to individuals in the population state. Chunks are executed sequentially, while the dynamics for the individuals at each such chunk are executed concurrently. For example, if chunks A and B consist of 100 individuals each, then the simulator will execute concurrently all the individuals in chunk A followed by the concurrent execution of all the individuals in chunk B. Chunk size is chosen to optimize the size of the execution queue for each scheduler. Furthermore, to avoid artifacts resulting from the use of fixed chunks during the simulation that result in a fixed execution order among the individuals in the population (e.g., the dynamics of Individual 1 are computed always before that of Individual 2), the simulator generates randomly a new set of chunks at the start of each simulation cycle.
Compilation of rules into Elixir functions presents a security threat for a web-based simulator, since it could allow the execution of malicious code at the server hidden in one of the dynamics rules. To increase the possibility of detecting such threats, the simulator performs a static security analysis of the code of the rule that is turned into a function. In particular, the simulator maintains a list of Elixir and Erlang built-in functions that are considered to be safe. These include arithmetic (e.g., +, *) and comparison (e.g., max, min, ==) build-in Elixir functions that are further enriched with many simulator-specific functions we have implemented mainly for:
(1)
computing aggregated functions over individuals and over their incoming edges,
(2)
allowing the generation or deletion of edges from an individual that satisfy relevant criteria,
(3)
adding/removing individuals in the population that satisfy relevant criteria.
If an unsafe function is detected in the model, then compilation stops and the particular simulation task is aborted.
Furthermore, we seek to increase the reliability of our web-based simulator by monitoring the use of server resources during simulation. More specifically, the simulator examines the available memory for operations at the end of each cycle. If this is below a critical threshold that is specific to the server running the simulation, then no new cycle of the simulation runs, the results of the current execution cycle are stored in the database, and the user is informed about the number of cycles that the system was able to execute and the breach of the memory threshold. This allows the system to abort simulations that utilize population and connection magnitudes beyond the capabilities of the servers running the system. At its current state, Politika runs on a minimal server with two cores and 6 MB RAM. It is able to reliably execute the simulation model of Figure
3 for a population of up to 30K individuals.