-
Notifications
You must be signed in to change notification settings - Fork 263
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
Adding MemoryDecay strategy. Check if ready to merge, please. #1137
Changes from 21 commits
bcd3e59
5602605
3f5426d
0ce447f
43a8a0d
404148e
211bf0f
e318b9a
119187a
e05efaf
0f249a6
d03bfad
b13051d
3de5a04
e65018c
ebf0f9c
0147cd9
63a3922
b7e4d8c
fdc4741
91202c7
ea68662
3de65d8
4e51db7
46ffad9
67dcac4
f1a75c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
from numpy.random import choice | ||
import random | ||
|
||
from axelrod.strategies import TitForTat | ||
from axelrod.action import Action | ||
from axelrod.player import Player, obey_axelrod | ||
from axelrod.strategy_transformers import NiceTransformer | ||
|
@@ -533,3 +535,80 @@ def __init__(self): | |
<= 1] | ||
super().__init__(team=team) | ||
self.classifier["long_run_time"] = False | ||
|
||
class MemoryDecay(MetaPlayer): | ||
""" | ||
A player utilizes the (default) Tit for Tat strategy for the first (default) 15 turns, | ||
at the same time memorizing the opponent's decisions. After the 15 turns have | ||
passed, the player calculates a 'net cooperation score' (NCS) for his opponent, | ||
weighing decisions to Cooperate as (default) 1, and to Defect as (default) | ||
-2. If the opponent's NCS is below 0, the play defects; otherwise, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo: 'play' should be 'player' |
||
they cooperate. | ||
|
||
The player's memories of the opponent's decisions have a random chance to be | ||
altered (i.e., a C decision becomes D or vice versa; default probability | ||
is 0.03) or deleted (default probability is 0.1). | ||
|
||
It's necessary to specify EXACT name of the starting strategy if changing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need for the capitals and should instead read '... specify the exact name ...' |
||
the default. Possible strategies can be accessed with the .team attribute. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also: this is no longer correct. This argument is now an player class. Perhaps change this whole paragraph to just say something like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've changed this according to your recommendation :) |
||
|
||
Name: Memory Decay | ||
""" | ||
name = 'Memory Decay' | ||
classifier = { | ||
'memory_depth' : float('inf'), | ||
'long_run_time' : False, | ||
'stochastic' : True, | ||
'makes_use_of' : set(), | ||
'inspects_source' : False, | ||
'manipulates_source' : False, | ||
'manipulates_state' : False | ||
} | ||
|
||
def __init__(self, p_memory_delete: float = 0.1, p_memory_alter: float = 0.03, | ||
loss_value: float = -2, gain_value: float = 1, | ||
memory: list = None, start_strategy: Player = TitForTat, | ||
start_strategy_duration: int = 15): | ||
super().__init__() | ||
self.p_memory_delete = p_memory_delete | ||
self.p_memory_alter = p_memory_alter | ||
self.loss_value = loss_value | ||
self.gain_value = gain_value | ||
self.memory = [] if memory == None else memory | ||
self.start_strategy_duration = start_strategy_duration | ||
self.team = [start_strategy()] | ||
|
||
# translates the actions (D and C) to numeric values (loss_value and | ||
# gain_value) | ||
def gain_loss_tr(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you rename this to |
||
self.gloss_values = [*map(lambda x: self.loss_value if x == D else | ||
self.gain_value, self.memory)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is tricky to read - could you expand it to use a few much simpler lines of code rather than fitting all into one line? |
||
|
||
# alters memory entry, i.e. puts C if there's a D and vice versa | ||
def mem_alter(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please use a full name for the method |
||
alter = choice(range(0, len(self.memory))) | ||
self.memory[alter] = self.memory[alter].flip() | ||
|
||
# deletes memory entry | ||
def mem_delete(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you use a fuller name e.g. |
||
self.memory.pop(choice(range(0, len(self.memory)))) | ||
|
||
def strategy(self, opponent): | ||
try: | ||
self.memory.append(opponent.history[-1]) | ||
except IndexError: | ||
pass | ||
if len(self.history) < self.start_strategy_duration: | ||
play = self.team[0].strategy(opponent) | ||
self.team[0].history.append(play) | ||
return play | ||
else: | ||
if random.random() <= self.p_memory_alter: | ||
self.mem_alter() | ||
if random.random() <= self.p_memory_delete: | ||
self.mem_delete() | ||
self.gain_loss_tr() | ||
if sum(self.gloss_values) < 0: | ||
return D | ||
else: | ||
return C |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -585,3 +585,77 @@ def test_strategy(self): | |
actions = [(C, C), (C, D), (D, C), (D, D), (D, C)] | ||
self.versus_test(opponent=axelrod.Alternator(), | ||
expected_actions=actions) | ||
|
||
"""Tests for the Memory Decay strategy""" | ||
|
||
class TestMemoryDecay(TestPlayer): | ||
|
||
name = 'MemoryDecay' | ||
player = axelrod.meta.MemoryDecay | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This strategy will need to be added to the |
||
expected_classifier = { | ||
'memory_depth': float('inf'), | ||
'stochastic': True, | ||
'makes_use_of': set([]), | ||
'long_run_time': False, | ||
'inspects_source': False, | ||
'manipulates_source': False, | ||
'manipulates_state': False | ||
} | ||
|
||
def test_strategy(self): | ||
#Test TitForTat behavior in first 15 turns | ||
opponent = axelrod.Cooperator() | ||
actions = list([(C, C)]) * 15 | ||
self.versus_test(opponent, expected_actions=actions) | ||
|
||
opponent = axelrod.Defector() | ||
actions = [(C, D)] + list([(D, D)]) * 14 | ||
self.versus_test(opponent, expected_actions=actions) | ||
|
||
opponent = axelrod.Alternator() | ||
actions = [(C, C)] + [(C, D), (D, C)] * 7 | ||
self.versus_test(opponent, expected_actions=actions) | ||
|
||
opponent_actions = [C, D, D, C, D, C, C, D, C, D, D, C, C, D, D] | ||
opponent = axelrod.MockPlayer(actions =opponent_actions) | ||
mem_actions = [C, C, D, D, C, D, C, C, D, C, D, D, C, C, D] | ||
actions = list(zip(mem_actions, opponent_actions)) | ||
self.versus_test(opponent, expected_actions=actions) | ||
|
||
opponent = axelrod.Random() | ||
actions = [(C, D), (D, D), (D, C), (C, C), (C, D), (D, C)] | ||
self.versus_test(opponent, expected_actions=actions, seed=0) | ||
|
||
#Test alternative starting strategies | ||
opponent = axelrod.Cooperator() | ||
actions = list([(D, C)]) * 15 | ||
self.versus_test(opponent, expected_actions=actions, | ||
init_kwargs = {'start_strategy': 'Defector'}) | ||
|
||
opponent = axelrod.Cooperator() | ||
actions = list([(C, C)]) * 15 | ||
self.versus_test(opponent, expected_actions=actions, | ||
init_kwargs = {'start_strategy': 'Cooperator'}) | ||
|
||
opponent = axelrod.Cooperator() | ||
actions = [(C, C)] + list([(D, C), (C, C)]) * 7 | ||
self.versus_test(opponent, expected_actions=actions, | ||
init_kwargs = {'start_strategy': 'Alternator'}) | ||
|
||
#Test net-cooperation-score (NCS) based decisions in subsequent turns | ||
opponent = axelrod.Cooperator() | ||
actions = [(C, C)] * 15 + [(C, C)] | ||
self.versus_test(opponent, expected_actions=actions, seed=1, | ||
init_kwargs = {'memory': [D] * 5 + [C] * 10}) | ||
|
||
opponent = axelrod.Cooperator() | ||
actions = [(C, C)] * 15 + [(C, C)] | ||
self.versus_test(opponent, expected_actions=actions, seed=1, | ||
init_kwargs = {'memory': [D] * 4 + [C] * 11}) | ||
|
||
opponent = axelrod.Defector() | ||
actions = [(C, D)] * 7 + [((D, D))] | ||
self.versus_test(opponent, expected_actions=actions, seed=4, | ||
init_kwargs = {'memory': [C] * 12, | ||
'start_strategy': 'Defector', | ||
'start_strategy_duration': 0}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use 'its' or 'their' instead of 'his'