Skip to main content
AgentModel is the central class of the Emergent framework. It manages a graph of agents, their data, and the simulation loop, including initialization, per-tick logic, and convergence detection.

Default parameters

The following parameters are set on construction and can be modified at any time via update_parameters or subscript assignment.
ParameterDefaultDescription
num_nodes3Number of nodes in the graph
graph_type"complete"Graph topology: "complete", "cycle", or anything else (wheel)
convergence_data_keyNoneNode attribute key to watch for convergence
convergence_std_dev100Convergence threshold (standard deviation)
MAX_TIMESTEPS100000Maximum timesteps before the simulation is forced to stop

__init__()

Initializes the model with default parameters and an uninitialized graph.
model = AgentModel()
After construction, the graph is None. You must call initialize_graph() before running the simulation. The initial_data_function and timestep_function attributes are also None until explicitly set.

update_parameters

model.update_parameters(parameters: dict) -> None
Merges the provided dictionary into the model’s parameters. Existing keys are overwritten; new keys are added.
parameters
dict
required
A dictionary of parameter names to their new values. Any key is accepted, including custom keys beyond the four built-in parameters.
model.update_parameters({
    "num_nodes": 10,
    "graph_type": "cycle",
    "convergence_data_key": "opinion",
    "convergence_std_dev": 5,
})

delete_parameters

model.delete_parameters(parameters: list = None) -> bool
Deletes specified parameter keys from the model, or resets all parameters to their defaults if no argument is provided.
parameters
list
A list of parameter key strings to delete. If omitted or None, all parameters are reset to their default values. Built-in parameter keys (num_nodes, graph_type, convergence_data_key, convergence_std_dev) and keys that do not exist will raise a KeyError.
return
bool
Returns True if the deletion was successful.
Passing a built-in parameter key (num_nodes, graph_type, convergence_data_key, convergence_std_dev) or a non-existent key raises KeyError. Use update_parameters to change built-in values.
# Add and then remove a custom parameter
model.update_parameters({"my_custom_param": 42})
model.delete_parameters(["my_custom_param"])

# Reset all parameters to defaults
model.delete_parameters()

list_parameters

model.list_parameters() -> list
Returns a list of all current parameter keys, including any custom keys added via update_parameters.
return
list
A list of parameter name strings in their current insertion order.
keys = model.list_parameters()
# ["num_nodes", "graph_type", "convergence_data_key", "convergence_std_dev"]

change_max_timesteps

model.change_max_timesteps(timesteps: int) -> None
Overrides the internal MAX_TIMESTEPS limit used by run_to_convergence. The default limit is 100000.
timesteps
int
required
The new maximum number of timesteps. The simulation will stop after this many ticks even if convergence has not been reached.
model.change_max_timesteps(500)

Subscript access — model[key] / model[key] = value

The model supports subscript syntax for reading and writing individual parameters.
# Get a parameter value
value = model["num_nodes"]

# Set a parameter value
model["num_nodes"] = 20
model["convergence_data_key"] = "opinion"
Subscript access is equivalent to reading or writing directly into the parameters dictionary. It works for both built-in parameters and any custom keys you have added.

set_graph

model.set_graph(graph: nx.Graph) -> None
Directly assigns a pre-built NetworkX graph to the model, bypassing initialize_graph. Use this when you need full control over graph topology.
graph
nx.Graph
required
A NetworkX Graph instance. Passing a value that is not a nx.Graph raises an Exception.
Passing a value that is not a nx.Graph instance raises Exception: The passed parameter is not a graph object.
import networkx as nx

g = nx.barabasi_albert_graph(50, 3)
model.set_graph(g)

get_graph

model.get_graph() -> nx.Graph
Returns the model’s current graph object.
return
nx.Graph
The nx.Graph instance currently held by the model. Returns None if the graph has not been initialized or set.
graph = model.get_graph()
print(graph.number_of_nodes())

set_initial_data_function

model.set_initial_data_function(initial_data_function: Callable) -> None
Attaches the function that initialize_graph will call once per node to produce its starting data. The function receives the model instance and must return a dictionary.
initial_data_function
Callable
required
A callable with the signature (model: AgentModel) -> dict. The returned dictionary is merged into the node’s attribute store.
def my_initial_data(model):
    return {"opinion": random.uniform(0, 1)}

model.set_initial_data_function(my_initial_data)

set_timestep_function

model.set_timestep_function(timestep_function: Callable) -> None
Attaches the function that timestep will invoke on each tick. The function receives the model instance and is responsible for updating node data directly on the graph.
timestep_function
Callable
required
A callable with the signature (model: AgentModel) -> None. The function should mutate node attributes on model.get_graph() directly.
def my_timestep(model):
    g = model.get_graph()
    for node, data in g.nodes(data=True):
        neighbors = list(g.neighbors(node))
        if neighbors:
            avg = sum(g.nodes[n]["opinion"] for n in neighbors) / len(neighbors)
            g.nodes[node]["opinion"] = avg

model.set_timestep_function(my_timestep)

initialize_graph

model.initialize_graph() -> None
Builds the graph from the current num_nodes and graph_type parameters, then seeds each node by calling initial_data_function once per node. Supported graph_type values:
ValueGraph topology
"complete"nx.complete_graph — every node connected to every other
"cycle"nx.cycle_graph — nodes arranged in a ring
anything elsenx.wheel_graph — one hub node connected to all others
Raises Exception: Initial data function is not set. if set_initial_data_function has not been called before initialize_graph.
model["num_nodes"] = 10
model["graph_type"] = "cycle"
model.set_initial_data_function(my_initial_data)
model.initialize_graph()

timestep

model.timestep() -> None
Executes one tick of the simulation by invoking the attached timestep_function.
Raises Exception: Timestep function is not set. if set_timestep_function has not been called.
for _ in range(100):
    model.timestep()

run_to_convergence

model.run_to_convergence() -> int
Runs timestep in a loop until the model is considered converged (via is_converged) or MAX_TIMESTEPS is reached, whichever comes first. Convergence is determined by convergence_data_key and convergence_std_dev. The loop checks convergence before each tick, so a model that starts converged returns 0.
return
int
The number of timesteps executed before the simulation stopped.
Raises Exception: No convergence data key specified if convergence_data_key is None.
model["convergence_data_key"] = "opinion"
model["convergence_std_dev"] = 0.01

ticks = model.run_to_convergence()
print(f"Converged after {ticks} timesteps")

is_converged

model.is_converged(data_key: str, std_dev: float) -> bool
Checks whether the values stored under data_key across all nodes have a standard deviation at or below std_dev.
data_key
str
required
The node attribute key whose values are collected across all nodes and tested for convergence.
std_dev
float
required
The maximum allowable standard deviation. The model is considered converged when the actual standard deviation is less than or equal to this value.
return
bool
True if the standard deviation of data_key values across all nodes is less than or equal to std_dev. False otherwise.
if model.is_converged("opinion", std_dev=0.01):
    print("Agents have reached consensus.")

Build docs developers (and LLMs) love