forked from projectmesa/mesa
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
75 changed files
with
4,018 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Mesa core examples | ||
This folder contains a collection of example models built using Mesa. These core models are maintained by the Mesa team and are intended to demonstrate the capabilities of Mesa. | ||
|
||
More user examples and showcases can be found in the [mesa-examples](https://github.com/projectmesa/mesa-examples) repository. | ||
|
||
## Basic Examples | ||
The basic examples are relatively simple and only use stable Mesa features. They are good starting points for learning how to use Mesa. | ||
|
||
### [Boltzmann Wealth Model](basic/boltzmann_wealth_model) | ||
Completed code to go along with the [tutorial](https://mesa.readthedocs.io/latest/tutorials/intro_tutorial.html) on making a simple model of how a highly-skewed wealth distribution can emerge from simple rules. | ||
|
||
### [Boids Flockers Model](basic/boid_flockers) | ||
[Boids](https://en.wikipedia.org/wiki/Boids)-style flocking model, demonstrating the use of agents moving through a continuous space following direction vectors. | ||
|
||
### [Conway's Game of Life](basic/conways_game_of_life) | ||
Implementation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life), a cellular automata where simple rules can give rise to complex patterns. | ||
|
||
### [Schelling Segregation Model](basic/schelling) | ||
Mesa implementation of the classic [Schelling segregation](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/) model. | ||
|
||
### [Virus on a Network Model](basic/virus_on_network) | ||
This model is based on the NetLogo [Virus on a Network](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork) model. | ||
|
||
## Advanced Examples | ||
The advanced examples are more complex and may use experimental Mesa features. They are good starting points for learning how to build more complex models. | ||
|
||
### [Epstein Civil Violence Model](advanced/epstein_civil_violence) | ||
Joshua Epstein's [model](http://www.uvm.edu/~pdodds/files/papers/others/2002/epstein2002a.pdf) of how a decentralized uprising can be suppressed or reach a critical mass of support. | ||
|
||
### [Demographic Prisoner's Dilemma on a Grid](advanced/pd_grid) | ||
Grid-based demographic prisoner's dilemma model, demonstrating how simple rules can lead to the emergence of widespread cooperation -- and how a model activation regime can change its outcome. | ||
|
||
### [Sugarscape Model with Traders](advanced/sugarscape_g1mt) | ||
This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of *Growing Artificial Societies: Social Science from the Bottom Up (1996)*. The model shows how emergent price equilibrium can happen via decentralized dynamics. | ||
|
||
### [Wolf-Sheep Predation Model](advanced/wolf_sheep) | ||
Implementation of an ecological model of predation and reproduction, based on the NetLogo [Wolf Sheep Predation](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation) model. |
116 changes: 116 additions & 0 deletions
116
examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Epstein Civil Violence Model | ||
|
||
## Summary | ||
|
||
This model is based on Joshua Epstein's simulation of how civil unrest grows and is suppressed. Citizen agents wander the grid randomly, and are endowed with individual risk aversion and hardship levels; there is also a universal regime legitimacy value. There are also Cop agents, who work on behalf of the regime. Cops arrest Citizens who are actively rebelling; Citizens decide whether to rebel based on their hardship and the regime legitimacy, and their perceived probability of arrest. | ||
|
||
The model generates mass uprising as self-reinforcing processes: if enough agents are rebelling, the probability of any individual agent being arrested is reduced, making more agents more likely to join the uprising. However, the more rebelling Citizens the Cops arrest, the less likely additional agents become to join. | ||
|
||
## How to Run | ||
|
||
To run the model interactively, run ``EpsteinCivilViolenceServer.py`` in this directory. e.g. | ||
|
||
``` | ||
$ python EpsteinCivilViolenceServer.py | ||
``` | ||
|
||
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run. | ||
|
||
## Files | ||
|
||
* ``EpsteinCivilViolence.py``: Core model and agent code. | ||
* ``EpsteinCivilViolenceServer.py``: Sets up the interactive visualization. | ||
* ``Epstein Civil Violence.ipynb``: Jupyter notebook conducting some preliminary analysis of the model. | ||
|
||
## Further Reading | ||
|
||
This model is based adapted from: | ||
|
||
[Epstein, J. “Modeling civil violence: An agent-based computational approach”, Proceedings of the National Academy of Sciences, Vol. 99, Suppl. 3, May 14, 2002](http://www.pnas.org/content/99/suppl.3/7243.short) | ||
|
||
A similar model is also included with NetLogo: | ||
|
||
Wilensky, U. (2004). NetLogo Rebellion model. http://ccl.northwestern.edu/netlogo/models/Rebellion. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. |
Empty file.
158 changes: 158 additions & 0 deletions
158
examples/advanced/epstein_civil_violence/epstein_civil_violence/agent.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import math | ||
|
||
import mesa | ||
|
||
|
||
class EpsteinAgent(mesa.experimental.cell_space.CellAgent): | ||
def update_neighbors(self): | ||
""" | ||
Look around and see who my neighbors are | ||
""" | ||
self.neighborhood = self.cell.get_neighborhood(radius=self.vision) | ||
|
||
self.neighbors = self.neighborhood.agents | ||
self.empty_neighbors = [c for c in self.neighborhood if c.is_empty] | ||
|
||
|
||
class Citizen(EpsteinAgent): | ||
""" | ||
A member of the general population, may or may not be in active rebellion. | ||
Summary of rule: If grievance - risk > threshold, rebel. | ||
Attributes: | ||
hardship: Agent's 'perceived hardship (i.e., physical or economic | ||
privation).' Exogenous, drawn from U(0,1). | ||
regime_legitimacy: Agent's perception of regime legitimacy, equal | ||
across agents. Exogenous. | ||
risk_aversion: Exogenous, drawn from U(0,1). | ||
threshold: if (grievance - (risk_aversion * arrest_probability)) > | ||
threshold, go/remain Active | ||
vision: number of cells in each direction (N, S, E and W) that agent | ||
can inspect | ||
condition: Can be "Quiescent" or "Active;" deterministic function of | ||
greivance, perceived risk, and | ||
grievance: deterministic function of hardship and regime_legitimacy; | ||
how aggrieved is agent at the regime? | ||
arrest_probability: agent's assessment of arrest probability, given | ||
rebellion | ||
""" | ||
|
||
def __init__( | ||
self, | ||
model, | ||
hardship, | ||
regime_legitimacy, | ||
risk_aversion, | ||
threshold, | ||
vision, | ||
): | ||
""" | ||
Create a new Citizen. | ||
Args: | ||
model: the model to which the agent belongs | ||
hardship: Agent's 'perceived hardship (i.e., physical or economic | ||
privation).' Exogenous, drawn from U(0,1). | ||
regime_legitimacy: Agent's perception of regime legitimacy, equal | ||
across agents. Exogenous. | ||
risk_aversion: Exogenous, drawn from U(0,1). | ||
threshold: if (grievance - (risk_aversion * arrest_probability)) > | ||
threshold, go/remain Active | ||
vision: number of cells in each direction (N, S, E and W) that | ||
agent can inspect. Exogenous. | ||
model: model instance | ||
""" | ||
super().__init__(model) | ||
self.hardship = hardship | ||
self.regime_legitimacy = regime_legitimacy | ||
self.risk_aversion = risk_aversion | ||
self.threshold = threshold | ||
self.condition = "Quiescent" | ||
self.vision = vision | ||
self.jail_sentence = 0 | ||
self.grievance = self.hardship * (1 - self.regime_legitimacy) | ||
self.arrest_probability = None | ||
|
||
def step(self): | ||
""" | ||
Decide whether to activate, then move if applicable. | ||
""" | ||
if self.jail_sentence: | ||
self.jail_sentence -= 1 | ||
return # no other changes or movements if agent is in jail. | ||
self.update_neighbors() | ||
self.update_estimated_arrest_probability() | ||
net_risk = self.risk_aversion * self.arrest_probability | ||
if self.grievance - net_risk > self.threshold: | ||
self.condition = "Active" | ||
else: | ||
self.condition = "Quiescent" | ||
|
||
if self.model.movement and self.empty_neighbors: | ||
new_cell = self.random.choice(self.empty_neighbors) | ||
self.move_to(new_cell) | ||
|
||
def update_estimated_arrest_probability(self): | ||
""" | ||
Based on the ratio of cops to actives in my neighborhood, estimate the | ||
p(Arrest | I go active). | ||
""" | ||
cops_in_vision = len([c for c in self.neighbors if isinstance(c, Cop)]) | ||
actives_in_vision = 1.0 # citizen counts herself | ||
for c in self.neighbors: | ||
if ( | ||
isinstance(c, Citizen) | ||
and c.condition == "Active" | ||
and c.jail_sentence == 0 | ||
): | ||
actives_in_vision += 1 | ||
self.arrest_probability = 1 - math.exp( | ||
-1 * self.model.arrest_prob_constant * (cops_in_vision / actives_in_vision) | ||
) | ||
|
||
|
||
class Cop(EpsteinAgent): | ||
""" | ||
A cop for life. No defection. | ||
Summary of rule: Inspect local vision and arrest a random active agent. | ||
Attributes: | ||
unique_id: unique int | ||
x, y: Grid coordinates | ||
vision: number of cells in each direction (N, S, E and W) that cop is | ||
able to inspect | ||
""" | ||
|
||
def __init__(self, model, vision): | ||
""" | ||
Create a new Cop. | ||
Args: | ||
x, y: Grid coordinates | ||
vision: number of cells in each direction (N, S, E and W) that | ||
agent can inspect. Exogenous. | ||
model: model instance | ||
""" | ||
super().__init__(model) | ||
self.vision = vision | ||
|
||
def step(self): | ||
""" | ||
Inspect local vision and arrest a random active agent. Move if | ||
applicable. | ||
""" | ||
self.update_neighbors() | ||
active_neighbors = [] | ||
for agent in self.neighbors: | ||
if ( | ||
isinstance(agent, Citizen) | ||
and agent.condition == "Active" | ||
and agent.jail_sentence == 0 | ||
): | ||
active_neighbors.append(agent) | ||
if active_neighbors: | ||
arrestee = self.random.choice(active_neighbors) | ||
sentence = self.random.randint(0, self.model.max_jail_term) | ||
arrestee.jail_sentence = sentence | ||
arrestee.condition = "Quiescent" | ||
if self.model.movement and self.empty_neighbors: | ||
new_pos = self.random.choice(self.empty_neighbors) | ||
self.move_to(new_pos) |
Oops, something went wrong.