Skip to content

SteinAndRapoport Strategy #1012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 22, 2017
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
19 changes: 13 additions & 6 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
environment:
matrix:
- PYTHON: "C:\\Python35"
- PYTHON: "C:\\Python36"
- PYTHON_VERSION: "3.5"
MINICONDA: "C:\\Miniconda35"
- PYTHON_VERSION: "3.6"
MINICONDA: "C:\\Miniconda36"
install:
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
- "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%PATH%"
- "conda config --set always_yes yes --set changeps1 no"
- "conda update -q conda"
- "conda create -q -n test-environment python=%PYTHON_VERSION% scipy>=0.19.0 numpy>=1.9.2"
- "activate test-environment"
- "python -m pip install -r requirements.txt"
build: off
test_script:
- "%PYTHON%\\python.exe -m unittest discover"
- "%PYTHON%\\python.exe doctests.py"
- "%PYTHON%\\python.exe setup.py install"
- "python -m unittest discover"
- "python doctests.py"
- "python setup.py install"
3 changes: 2 additions & 1 deletion axelrod/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ def clone(self):
return new_player

def reset(self):
"""Resets history.
"""
Resets history.
When creating strategies that create new attributes then this method
should be re-written (in the inherited class) and should not only reset
history but also rest all other attributes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a little clumsy and not as clear as it could be. How about:

"""Resets a player to its initial state

This method is called at the beginning of each match (between a pair of players) to reset a player's state to its initial starting point. It ensures that no 'memory' of previous matches is carried forward.

The default method resets a player's history, cooperations, defections and state_distribution. Players which have further attributes need to override this method and ensure those additional attributes are also reset.
"""

Copy link
Member

@drvinceknight drvinceknight May 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @MariosZoulias, this has turned up in this PR because I put a line break on line 244 (I shouldn't have done that), the text wasn't changed by either of us but if you could make the improvements suggested by @meatballs that would be helpful. This file is in Axelrod/axelrod/player.py.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's sort this out separately. I'll merge this PR and put another one in for the docstring

Expand Down
3 changes: 2 additions & 1 deletion axelrod/strategies/_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .averagecopier import AverageCopier, NiceAverageCopier
from .axelrod_first import (
Davis, RevisedDowning, Feld, Grofman, Nydegger, Joss, Shubik, Tullock,
UnnamedStrategy)
UnnamedStrategy, SteinAndRapoport)
from .axelrod_second import Champion, Eatherley, Tester
from .backstabber import BackStabber, DoubleCrosser
from .better_and_better import BetterAndBetter
Expand Down Expand Up @@ -232,6 +232,7 @@
SolutionB5,
SpitefulTitForTat,
Stalker,
SteinAndRapoport,
StochasticCooperator,
StochasticWSLS,
SuspiciousTitForTat,
Expand Down
66 changes: 66 additions & 0 deletions axelrod/strategies/axelrod_first.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from axelrod.player import Player
from axelrod.random_ import random_choice
from.memoryone import MemoryOnePlayer
from axelrod.strategy_transformers import FinalTransformer
from scipy.stats import chisquare

from typing import List, Dict, Tuple

Expand Down Expand Up @@ -487,3 +489,67 @@ class UnnamedStrategy(Player):
def strategy(opponent: Player) -> Action:
r = random.uniform(3, 7) / 10
return random_choice(r)

@FinalTransformer((D, D), name_prefix=None)
class SteinAndRapoport(Player):
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't quite formatted correctly (see: http://axelrod.readthedocs.io/en/stable/tutorials/contributing/strategy/docstrings.html).

Can you remove one indentation level for the description (it should be at the same level as the """).

Then can you add:

Names:
- SteinAndRapoport [Axelrod1980]_

A player who plays according to statistic methods.
Begins by playing C for the first four (4) rounds, then it plays
tit for tat and at the last 2 round it Defects. Every 15 turns it
runs a chi-squared test to check whether the opponent behaves randomly
or not. In case the opponent behaves randomly then Stein and Rapoport
Defects until the next 15 round (where we check again), otherwise it
still plays TitForTat.0

Names:

- SteinAndRapoport [Axelrod1980]_
"""

name = 'Stein and Rapoport'
classifier = {
'memory_depth': 15,
'stochastic': False,
'makes_use_of': {"length"},
'long_run_time': False,
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def __init__(self, alpha: float=0.05) -> None:
"""
Parameters
----------
alpha, float
The significant level of pvalue from chi-squared test
0.05 by default according to literature
"""
super().__init__()
self.alpha = alpha
self.opponent_is_random = None

def strategy(self , opponent: Player) -> Action:
round_number = len(self.history) + 1

# First 4 moves
if round_number < 5:
return C
# For first 15 rounds tit for tat as we do not know opponents strategy
elif round_number < 15:
return opponent.history[-1]

if round_number % 15 == 0:
p_value = chisquare([opponent.cooperations,
opponent.defections]).pvalue
self.opponent_is_random = p_value >= self.alpha

if self.opponent_is_random:
# Defect if opponent plays randomly
return D
else: # TitForTatat if opponent plays not randomly
return opponent.history[-1]

def reset(self):
super().reset()
self.random_opponent = None
77 changes: 77 additions & 0 deletions axelrod/tests/strategies/test_axelrod_first.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,80 @@ def test_strategy(self):
actions = [(C, C), (C, C), (D, C), (C, C), (C, C), (D, C)]
self.versus_test(axelrod.Cooperator(), expected_actions=actions,
seed=10)


class SteinAndRapoport(TestPlayer):

name = "Stein and Rapoport: 0.05: ('D', 'D')"
player = axelrod.SteinAndRapoport
expected_classifier = {
'memory_depth': 15,
'long_run_time': False,
'stochastic': False,
'makes_use_of': {'length'},
'inspects_source': False,
'manipulates_source': False,
'manipulates_state': False
}

def test_init(self):
player = self.player()
self.assertEqual(player.alpha, 0.05)
self.assertIsNone(player.opponent_is_random)

player = self.player(alpha=.5)
self.assertEqual(player.alpha, 0.5)
self.assertIsNone(player.opponent_is_random)

def test_strategy(self):
self.first_play_test(C)

# Our Player (SteinAndRapoport) vs Cooperator
# After 15th round (pvalue < alpha) still plays titfortat
# Note it always defects on the last two rounds
opponent = axelrod.Cooperator()
actions = [(C, C)] * 17 + [(D, C)] * 2
self.versus_test(opponent, expected_actions=actions,
attrs={"opponent_is_random": False})

actions = actions[:-2] + [(C, C)] * 2
self.versus_test(opponent, expected_actions=actions[:-2],
match_attributes={"length": -1},
attrs={"opponent_is_random": False})

# Our Player (SteinAndRapoport) vs Defector
# After 15th round (pvalue < alpha) still plays titfortat
opponent = axelrod.Defector()
actions = [(C, D)] * 4 + [(D, D)] * 15
self.versus_test(opponent, expected_actions=actions,
attrs={"opponent_is_random": False})

# Our Player (SteinAndRapoport) vs Alternator
# After 15th round (pvalue > alpha) starts defect
opponent = axelrod.Alternator()
actions = [(C, C), (C, D), (C, C), (C, D)]

# On 15th round carry out chisquare test
actions += [(D, C), (C, D)] * 5 + [(D, C)]

# Defect throughout
actions += [(D, D), (D, C), (D, D), (D, C)]

self.versus_test(opponent, expected_actions=actions,
attrs={"opponent_is_random": True})

# The test is carried out again every 15 rounds.
# If the strategy alternates for the first 12 rounds and then cooperates
# it is no longer recognised as random
opponent = axelrod.MockPlayer([C, D] * 6 + [C] * 50)

actions = [(C, C), (C, D), (C, C), (C, D)]
# On 15th round carry out chisquare test
actions += [(D, C), (C, D)] * 4 + [(D, C), (C, C), (D, C)]
# Defect throughout and carry out chisquare test on round 30
# Opponent is no longer recognised as random, revert to TfT
actions += [(D, C)] * 14 + [(C, C)]
self.versus_test(opponent, expected_actions=actions,
match_attributes={"length": -1},
attrs={"opponent_is_random": False})

8 changes: 4 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import mock

MOCK_MODULES = [
'numpy', 'numpy.linalg', 'numpy.random', 'matplotlib.pyplot', 'matplotlib',
'matplotlib.transforms', 'mpl_toolkits.axes_grid1', 'dill', 'multiprocess',
'prompt_toolkit', 'prompt_toolkit.token', 'prompt_toolkit.styles',
'prompt_toolkit.validation']
'scipy', 'scipy.stats','numpy', 'numpy.linalg', 'numpy.random',
'matplotlib.pyplot', 'matplotlib','matplotlib.transforms',
'mpl_toolkits.axes_grid1', 'dill', 'multiprocess','prompt_toolkit',
'prompt_toolkit.token', 'prompt_toolkit.styles','prompt_toolkit.validation']
for mod_name in MOCK_MODULES:
sys.modules[mod_name] = mock.Mock()

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/overview_of_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Strategies in the Axelrod's first tournament:
+--------------------------+-------------------------------------------+--------------------------+
| `Shubik`_ | Shubik (author's name) | :code:`Shubik` |
+--------------------------+-------------------------------------------+--------------------------+
| `Stein and Rapoport`_ | Stein and Rapoport (authors' names) | Not Implemented |
| `Stein and Rapoport`_ | Stein and Rapoport (authors' names) | :code:`SteinAndRapoport` |
+--------------------------+-------------------------------------------+--------------------------+
| `Grudger`_ | Grudger (by Friedman) | :code:`Grudger` |
+--------------------------+-------------------------------------------+--------------------------+
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/advanced/classification_of_strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ length of each match of the tournament::
... }
>>> strategies = axl.filtered_strategies(filterset)
>>> len(strategies)
26
27

Note that in the filterset dictionary, the value for the 'makes_use_of' key
must be a list. Here is how we might identify the number of strategies that use
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ matplotlib>=1.4.2
hypothesis>=3.2
tqdm>=3.4.0
prompt-toolkit>=1.0.7
scipy>=0.19.0