<jupyter_start><jupyter_text>Button networkThis notebook presents an agent-based model of randomly connecting buttons.It demonstrates how to use the [agentpy](https://agentpy.readthedocs.io) packageto work with networks and visualize averaged time-series for discrete parameter samples.<jupyter_code># Model design
import agentpy as ap
import networkx as nx
import random

# Visualization
import seaborn as sns<jupyter_output><empty_output><jupyter_text>About the modelThis model is based on the [Agentbase Button model](http://agentbase.org/model.html?f4c4388138450bdf9732) by <NAME> and the following analogy from [<NAME>](http://www.pbs.org/lifebeyondearth/resources/intkauffmanpop.html): > "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<jupyter_code># Define the model

class ButtonModel(ap.Model):
    
    def setup(self):
        
        # Create a graph with n agents
        self.buttons = self.add_network()
        self.buttons.add_agents(self.p.n)
        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, replace=False))
            self.threads += 1<jupyter_output><empty_output><jupyter_text>Multi-run experiment<jupyter_code># Define parameter ranges
parameter_ranges = {
    'steps': 30,  # Number of simulation steps
    'speed': 0.05,  # Speed of connections per step
    'n': (100, 1000, 10000)  # Number of agents
}

# Create sample for different values of n
sample = ap.sample_discrete(parameter_ranges) 

# Keep dynamic variables
exp = ap.Experiment(ButtonModel, sample, iterations=25, record=True) 

# Perform 75 seperate simulations (3 parameter combinations * 25 repetitions)
results = exp.run() 
# Plot averaged time-series for discrete parameter samples

sns.set()
data = results.arrange_variables()
ax = sns.lineplot(data=data, x='threads_to_button', y='max_cluster_size', hue='n')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07043626614672191, 'fraction_numerical': 0.0160857908847185, 'mean_word_length': 3.903225806451613, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 24, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '54138', 'license': 'MIT', 'n_tokens_mistral': 1174, 'n_tokens_neox': 1097, 'n_words': 519, 'path': 'notebooks/agentpy_button_network.ipynb', 'repo_name': 'JoelForamitti/agentpy_workshop', 'size': '4118'}