Note
You can download this demonstration as a Jupyter Notebook
here
Button network
This notebook presents an agent-based model of randomly connecting buttons. It demonstrates how to use the agentpy package to work with networks and visualize averaged time-series for discrete parameter samples.
[1]:
# Model design
import agentpy as ap
import networkx as nx
# Visualization
import seaborn as sns
About the model
This model is based on the Agentbase Button model by Wybo Wiersma and the following analogy from Stuart Kauffman:
“Suppose you take 10,000 buttons and spread them out on a hardwood floor. You have a large spool of red thread. Now, what you do is you pick up a random pair of buttons and you tie them together with a piece of red thread. Put them down and pick up another random pair of buttons and tie them together with a red thread, and you just keep doing this. Every now and then lift up a button and see how many buttons you’ve lifted with your first button. A connective cluster of buttons is called a cluster or a component. When you have 10,000 buttons and only a few threads that tie them together, most of the times you’d pick up a button you’ll pick up a single button.
As the ratio of threads to buttons increases, you’re going to start to get larger clusters, three or four buttons tied together; then larger and larger clusters. At some point, you will have a number of intermediate clusters, and when you add a few more threads, you’ll have linked up the intermediate-sized clusters into one giant cluster.
So that if you plot on an axis, the ratio of threads to buttons: 10,000 buttons and no threads; 10,000 buttons and 5,000 threads; and so on, you’ll get a curve that is flat, and then all of a sudden it shoots up when you get this giant cluster. This steep curve is in fact evidence of a phase transition.
If there were an infinite number of threads and an infinite number of buttons and one just tuned the ratios, this would be a step function; it would come up in a sudden jump. So it’s a phase transition like ice freezing.
Now, the image you should take away from this is if you connect enough buttons all of a sudden they all go connected. To think about the origin of life, we have to think about the same thing.”
Model definition
[2]:
class ButtonModel(ap.Model):
def setup(self):
# Create a graph with n agents
self.buttons = ap.Network(self)
self.agents = ap.AgentList(self, self.p.n)
self.buttons.add_agents(self.agents)
self.agents.node = self.buttons.nodes
self.threads = 0
def update(self):
# Record size of the biggest cluster
clusters = nx.connected_components(self.buttons.graph)
max_cluster_size = max([len(g) for g in clusters]) / self.p.n
self.record('max_cluster_size', max_cluster_size)
# Record threads to button ratio
self.record('threads_to_button', self.threads / self.p.n)
def step(self):
# Create random edges based on parameters
for _ in range(int(self.p.n * self.p.speed)):
self.buttons.graph.add_edge(*self.agents.random(2).node)
self.threads += 1
Multi-run experiment
[3]:
# Define parameter ranges
parameter_ranges = {
'steps': 30, # Number of simulation steps
'speed': 0.05, # Speed of connections per step
'n': ap.Values(100, 1000, 10000) # Number of agents
}
# Create sample for different values of n
sample = ap.Sample(parameter_ranges)
# Keep dynamic variables
exp = ap.Experiment(ButtonModel, sample, iterations=25, record=True)
# Perform 75 separate simulations (3 parameter combinations * 25 repetitions)
results = exp.run()
Scheduled runs: 75
Completed: 75, estimated time remaining: 0:00:00
Experiment finished
Run time: 0:00:36.012666
[4]:
# Plot averaged time-series for discrete parameter samples
sns.set_theme()
sns.lineplot(
data=results.arrange_variables(),
x='threads_to_button',
y='max_cluster_size',
hue='n'
);