Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
tpike3 authored Oct 16, 2024
2 parents 55f8f6a + d7a3834 commit 8f31aa1
Show file tree
Hide file tree
Showing 75 changed files with 4,018 additions and 59 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ jobs:
- if: matrix.os == 'ubuntu'
name: Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}

examples:
runs-on: ubuntu-latest
Expand Down
5 changes: 3 additions & 2 deletions codecov.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ coverage:
status:
project:
default:
target: 90%
target: 80%
threshold: 1%

ignore:
- "**experimental/"
- "benchmarks/**"
- "mesa/experimental/**"
- "mesa/visualization/**"

comment: off
4 changes: 2 additions & 2 deletions docs/tutorials/MoneyModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ def step(self):
class MoneyModel(mesa.Model):
"""A model with some number of agents."""

def __init__(self, N, width, height):
def __init__(self, N, width, height, seed=None):
"""Initialize a MoneyModel instance.
Args:
N: The number of agents.
width: width of the grid.
height: Height of the grid.
"""
super().__init__()
super().__init__(seed=seed)
self.num_agents = N
self.grid = mesa.space.MultiGrid(width, height, True)
self.schedule = mesa.time.RandomActivation(self)
Expand Down
37 changes: 37 additions & 0 deletions examples/README.md
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 examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions examples/advanced/epstein_civil_violence/Readme.md
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.
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)
Loading

0 comments on commit 8f31aa1

Please sign in to comment.