Source code for whynot.simulators.schelling.simulator
"""Simulate and analyze runs from the Schelling segregation model."""
import dataclasses
from mesa.batchrunner import BatchRunner
import numpy as np
from whynot.simulators.schelling.model import Schelling
[docs]@dataclasses.dataclass
class Config:
# pylint:disable-msg=too-few-public-methods
"""Parameterization of the Schelling dynamics."""
#: Vertical size of the grid
height: int = 10
#: Horizontal size of the grid
width: int = 10
#: Agent density
density: float = 0.8
#: Fraction of "minority" agents
minority_pc: float = 0.2
#: Agent propensity to live near other agents of the same type.
homophily: float = 5.0
#: How much education changes homophily
education_boost: float = -1.0
#: What percentage of agent receive education
education_pc: float = 0.0
def get_segregation(model):
"""Find the fraction of agents that only have neighbors of their same type."""
segregated_agents = 0
for agent in model.schedule.agents:
segregated = True
for neighbor in model.grid.neighbor_iter(agent.pos):
if neighbor.type != agent.type:
segregated = False
break
if segregated:
segregated_agents += 1
if model.schedule.get_agent_count() == 0:
return 0.0
return segregated_agents / model.schedule.get_agent_count()
def simulate(config, rollouts=10, seed=None):
"""Simulate repeated runs of the Schelling model for config.
Parameters
----------
config: whynot.simulators.Schelling
Configuration of the grid, agent properties, and model dynamics.
rollouts: int
How many times to run the model for the same configuration.
seed: int
(Optional) Seed all randomness in rollouts
Returns
-------
segregated_fraction: pd.Series
What fraction of the agents are segrated at the end of the run
for each rollout.
"""
model_reporters = {"Segregated_Agents": get_segregation}
rng = np.random.RandomState(seed)
param_sweep = BatchRunner(
Schelling,
fixed_parameters=dataclasses.asdict(config),
max_steps=200,
model_reporters=model_reporters,
display_progress=False,
# Use a different seed for each rollout
variable_parameters={"seed": rng.randint(9999999, size=rollouts)},
# Single rollout for each seed
iterations=1,
)
param_sweep.run_all()
dataframe = param_sweep.get_model_vars_dataframe()
# Currently just reports the fraction segregated.
return dataframe.Segregated_Agents.mean()
if __name__ == "__main__":
print(simulate(Config()))