A toroidal-grid implementation of Thomas Schelling's famous model of segregation. This project simulates how even a generally tolerant society (tolerance of each individual is high) can lead to wide scale societal segregation, using matplotlib for graphs, pygame for simulation, and multiprocessing to speed up collection of data.
- Toroidal Grid: Uses a toroidal (wrap-around) board, simulating an infinite surface to remove any boundary bias.
- Visual Mode: Uses
pygameto see how the board evolves over time, andmatplotlibto graph time series data of 'unhappy agents' and 'measure of segregation'. Automatically saves grid state and graph state at the end of simulation to track data. - Non-Visual Mode: Optimised background processing that disables rendering to maximise speed (~10x faster), and still automatically saves grid state and graph state at the end of each simulation to track data.
- Multiprocessing: In non-visual mode, using
multiprocessingutilises all CPU-cores to run multiple simulations in parallel. - Data Collection: Automatically saves the data to a .csv for later graphing
-
Clone the repo:
git clone [https://github.com/arnavlul/schellings-segregation-model.git](https://github.com/arnavlul/schellings-segregation-model/) cd schellings-segregation-model -
Install the required dependencies:
pip install numpy matplotlib pygame
There are 2 ways to run the simulation:
- Single simulation:
python base_model.py- Input threshold (0-1)
- Input grid size (100-200 Recommended)
- Pressing
SPACEwith pygame window in focus pauses simulation - Use sliders to adjust the graphs dynamically
- Do not move matplotlib graph if pygame window isn't paused / has stopped
- Batch simulation: Use this to collect data across a range of thresholds.
python tester.py- Input starting and ending threshold values, precision of threshold values (0.01 recommended), visualise or not, number of times to compute at each threshold (to get average), and number of cores to use
- Saves data to csv
- Plotting final graph:
python plotter.py- Plots the schelling_stats.csv file generated if batch simulation is done
base_model.pytester.pyplotter.pyschelling_stats.csv: This file will be created if the batch simulation (tester.py) is runstate_graphs/: Where matplotlib graphs are savedstate_pics/: Where pygame grids are saved
Schelling's Model demonstrates that even having a mild individual preference (eg. Wanting only 35% of your neighbours to be like you), leads to wide scale societal segregation, with the amount of segregation increasing with increase in % of like neighbours an individual wants around.
- Threshold: The minimum % of like people, a cell wants around it to be happy.
- Segregation Index: Calculating the average similarity of every agent's neighbourhood (8 surrounding cells)
- Initial Distribution: Cells are first randomly generated with the following distribution: 20% unoccupied, 40% 1 (red), and 40% 2 (blue)
- Scan: At each time step, the grid is traversed; unhappy agents and unoccupied cells are noted.
- Relocate: Unhappy agents are moved to a random cell.
- Terminate: The loop breaks when everyone is happy, or if the system reaches a "stagnation" or "oscillation" state.
- At low thresholds (1-30%), individuals are homogenously mixed.
- After ~30-35%: communities can visibly be seen as being more segregated than not.
- Segregation (and similarly size of communities) keeps increasing with increase in threshold.
- At 75% and greater: The amount of like cells an individual wants exceeds a number that isn't possible. This is known as "Structural Incompatibility". This happens when the demand exceeds the available "packing density" of the grid. Say if an individual wants 90% of like cells, that isn't possible, as out of the 8 surrounding cells, even if 1 is the other colour it will turn it 87.5%, so all cells surrounding an individual NEED to be the same colour. Which isn't possible if the grid is 40-40 with the number of the 2 types of people. No stable communities can be formed, since each time the cells relocate, they are always unhappy.
- The code doesn't strictly stop when number of unhappy people reaches 0, it stops using 2 rules: (1) If at the last 50 steps, there isn't sufficient movement in the number of unhappy people (to combat stagnation) (2) If there is movement but the min(number of unhappy people) doesn't change in 200 steps (to combat oscillating behaviour)
- The measure of segregation is averaging the number of like people in a person's neighbourhood, which only captures local interactions. Better measures can be used, such as the 'Interface Percentage' which as far as i can tell is the standard; or number of clusters (through something like Hoshen-Kopelman)
- Right now if agents are unhappy, they randomly move to another cell. This doesn't model real life behaviour as agents wouldn't move to a cell that would make the situation worse. So better to keep track of ideal cells for an agent, and move them there; if no ideal cells, only then move the agent randomly (or some other similar method).






