Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

116 changes: 0 additions & 116 deletions examples/PD_Grid/pd_grid.py

This file was deleted.

234 changes: 234 additions & 0 deletions examples/pd_grid/analysis.ipynb

Large diffs are not rendered by default.

Empty file.
52 changes: 52 additions & 0 deletions examples/pd_grid/pd_grid/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import random

from mesa import Agent


class PDAgent(Agent):
''' Agent member of the iterated, spatial prisoner's dilemma model. '''

def __init__(self, pos, model, starting_move=None):
'''
Create a new Prisoner's Dilemma agent.

Args:
pos: (x, y) tuple of the agent's position.
model: model instance
starting_move: If provided, determines the agent's initial state:
C(ooperating) or D(efecting). Otherwise, random.
'''
super().__init__(pos, model)
self.pos = pos
self.score = 0
if starting_move:
self.move = starting_move
else:
self.move = random.choice(["C", "D"])
self.next_move = None

@property
def isCooroperating(self):
return self.move == "C"

def step(self):
''' Get the neighbors' moves, and change own move accordingly. '''
neighbors = self.model.grid.get_neighbors(self.pos, True,
include_center=True)
best_neighbor = max(neighbors, key=lambda a: a.score)
self.next_move = best_neighbor.move

if self.model.schedule_type != "Simultaneous":
self.advance()

def advance(self):
self.move = self.next_move
self.score += self.increment_score()

def increment_score(self):
neighbors = self.model.grid.get_neighbors(self.pos, True)
if self.model.schedule_type == "Simultaneous":
moves = [neighbor.next_move for neighbor in neighbors]
else:
moves = [neighbor.move for neighbor in neighbors]
return sum(self.model.payoff[(self.move, move)] for move in moves)
58 changes: 58 additions & 0 deletions examples/pd_grid/pd_grid/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from mesa import Model
from mesa.time import BaseScheduler, RandomActivation, SimultaneousActivation
from mesa.space import SingleGrid
from mesa.datacollection import DataCollector

from .agent import PDAgent


class PDModel(Model):
''' Model class for iterated, spatial prisoner's dilemma model. '''

schedule_types = {"Sequential": BaseScheduler,
"Random": RandomActivation,
"Simultaneous": SimultaneousActivation}

# This dictionary holds the payoff for this agent,
# keyed on: (my_move, other_move)

payoff = {("C", "C"): 1,
("C", "D"): 0,
("D", "C"): 1.6,
("D", "D"): 0}

def __init__(self, height, width, schedule_type, payoffs=None):
'''
Create a new Spatial Prisoners' Dilemma Model.

Args:
height, width: Grid size. There will be one agent per grid cell.
schedule_type: Can be "Sequential", "Random", or "Simultaneous".
Determines the agent activation regime.
payoffs: (optional) Dictionary of (move, neighbor_move) payoffs.
'''
self.running = True
self.grid = SingleGrid(height, width, torus=True)
self.schedule_type = schedule_type
self.schedule = self.schedule_types[self.schedule_type](self)

# Create agents
for x in range(width):
for y in range(height):
agent = PDAgent((x, y), self)
self.grid.place_agent(agent, (x, y))
self.schedule.add(agent)

self.datacollector = DataCollector({
"Cooperating_Agents":
lambda m: len([a for a in m.schedule.agents if a.move == "C"])
})

def step(self):
self.datacollector.collect(self)
self.schedule.step()

def run(self, n):
''' Run the model for n steps. '''
for _ in range(n):
self.step()
18 changes: 18 additions & 0 deletions examples/pd_grid/pd_grid/portrayal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
def portrayPDAgent(agent):
'''
This function is registered with the visualization server to be called
each tick to indicate how to draw the agent in its current state.
:param agent: the agent in the simulation
:return: the portrayal dictionary
'''
assert agent is not None
return {
"Shape": "rect",
"w": 1,
"h": 1,
"Filled": "true",
"Layer": 0,
"x": agent.pos[0],
"y": agent.pos[1],
"Color": "blue" if agent.isCooroperating else "red"
}
12 changes: 12 additions & 0 deletions examples/pd_grid/pd_grid/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from mesa.visualization.ModularVisualization import ModularServer
from mesa.visualization.modules import CanvasGrid

from .portrayal import portrayPDAgent
from .model import PDModel


# Make a world that is 50x50, on a 500x500 display.
canvas_element = CanvasGrid(portrayPDAgent, 50, 50, 500, 500)

server = ModularServer(PDModel, [canvas_element], "Prisoner's Dilemma", 50, 50,
'Random')
13 changes: 10 additions & 3 deletions examples/PD_Grid/readme.md → examples/pd_grid/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Summary

The Demographic Prisoner's Dilemma is a family of variants on the classic two-player [Prisoner's Dilemma]. The model consists of agents, each with a strategy of either Cooperate or Defect. Each agent's payoff is based on its strategy and the strategies of its spatial neighbors. After each step of the model, the agents adopt the strategy of their neighbor with the highest total score.
The Demographic Prisoner's Dilemma is a family of variants on the classic two-player [Prisoner's Dilemma]. The model consists of agents, each with a strategy of either Cooperate or Defect. Each agent's payoff is based on its strategy and the strategies of its spatial neighbors. After each step of the model, the agents adopt the strategy of their neighbor with the highest total score.

The model payoff table is:

Expand All @@ -13,15 +13,22 @@ The model payoff table is:

Where *D* is the defection bonus, generally set higher than 1. In these runs, the defection bonus is set to $D=1.6$.

The Demographic Prisoner's Dilemma demonstrates how simple rules can lead to the emergence of widespread cooperation, despite the Defection strategy dominiating each individual interaction game. However, it is also interesting for another reason: it is known to be sensitive to the activation regime employed in it.
The Demographic Prisoner's Dilemma demonstrates how simple rules can lead to the emergence of widespread cooperation, despite the Defection strategy dominating each individual interaction game. However, it is also interesting for another reason: it is known to be sensitive to the activation regime employed in it.

## How to Run

##### Web based model simulation

Run ``python run.py``.

##### Jupyter Notebook

Launch the ``Demographic Prisoner's Dilemma Activation Schedule.ipynb`` notebook and run the code.

## Files

* ``pd_grid.py``: has the model and agent classes; the model takes a schedule_type string as an argument, which determines what schedule type the model uses: Sequential, Random or Simultaneous.
* ``run.py`` is the entry point for the font-end simulations.
* ``pd_grid/``: contains the model and agent classes; the model takes a ``schedule_type`` string as an argument, which determines what schedule type the model uses: Sequential, Random or Simultaneous.
* ``Demographic Prisoner's Dilemma Activation Schedule.ipynb``: Jupyter Notebook for running the scheduling experiment. This runs the model three times, one for each activation type, and demonstrates how the activation regime drives the model to different outcomes.

## Further Reading
Expand Down
3 changes: 3 additions & 0 deletions examples/pd_grid/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from pd_grid.server import server

server.launch()