Skip to content

Commit 25eb130

Browse files
committed
Merge branch 'fix-rs' of https://github.com/gaffney2010/Axelrod
2 parents 5090660 + 43eb61e commit 25eb130

File tree

8 files changed

+539
-34
lines changed

8 files changed

+539
-34
lines changed

axelrod/result_set.py

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import csv
33
import itertools
44
from multiprocessing import cpu_count
5+
from typing import List
56
import warnings
67

78
import numpy as np
@@ -117,9 +118,12 @@ def _reshape_out(
117118
alternative=0,
118119
)
119120

120-
self.wins = self._reshape_two_dim_list(sum_per_player_repetition_df["Win"])
121-
self.scores = self._reshape_two_dim_list(sum_per_player_repetition_df["Score"])
122-
self.normalised_scores = self._reshape_two_dim_list(normalised_scores_series)
121+
self.wins = self._reshape_two_dim_list(
122+
sum_per_player_repetition_df["Win"])
123+
self.scores = self._reshape_two_dim_list(
124+
sum_per_player_repetition_df["Score"])
125+
self.normalised_scores = self._reshape_two_dim_list(
126+
normalised_scores_series)
123127

124128
self.cooperation = self._build_cooperation(
125129
sum_per_player_opponent_df["Cooperation count"]
@@ -166,7 +170,8 @@ def _reshape_out(
166170
self.ranked_names = self._build_ranked_names()
167171

168172
self.payoff_matrix = self._build_summary_matrix(self.payoffs)
169-
self.payoff_stddevs = self._build_summary_matrix(self.payoffs, func=np.std)
173+
self.payoff_stddevs = self._build_summary_matrix(self.payoffs,
174+
func=np.std)
170175

171176
self.payoff_diffs_means = self._build_payoff_diffs_means()
172177
self.cooperating_rating = self._build_cooperating_rating()
@@ -266,7 +271,9 @@ def _build_good_partner_matrix(self, good_partner_series):
266271
# interactions.
267272
row.append(0)
268273
else:
269-
row.append(good_partner_dict.get((player_index, opponent_index), 0))
274+
row.append(
275+
good_partner_dict.get((player_index, opponent_index),
276+
0))
270277
good_partner_matrix.append(row)
271278
return good_partner_matrix
272279

@@ -334,13 +341,15 @@ def _build_normalised_state_distribution(self):
334341
for counter in player:
335342
total = sum(counter.values())
336343
counters.append(
337-
Counter({key: value / total for key, value in counter.items()})
344+
Counter(
345+
{key: value / total for key, value in counter.items()})
338346
)
339347
normalised_state_distribution.append(counters)
340348
return normalised_state_distribution
341349

342350
@update_progress_bar
343-
def _build_state_to_action_distribution(self, state_to_action_distribution_series):
351+
def _build_state_to_action_distribution(self,
352+
state_to_action_distribution_series):
344353
state_to_action_key_map = {
345354
"CC to C count": ((C, C), C),
346355
"CC to D count": ((C, C), D),
@@ -396,7 +405,8 @@ def _build_normalised_state_to_action_distribution(self):
396405
return normalised_state_to_action_distribution
397406

398407
@update_progress_bar
399-
def _build_initial_cooperation_count(self, initial_cooperation_count_series):
408+
def _build_initial_cooperation_count(self,
409+
initial_cooperation_count_series):
400410
initial_cooperation_count_dict = initial_cooperation_count_series.to_dict()
401411
initial_cooperation_count = [
402412
initial_cooperation_count_dict.get(player_index, 0)
@@ -411,7 +421,7 @@ def _build_normalised_cooperation(self):
411421
normalised_cooperation = [
412422
list(np.nan_to_num(row))
413423
for row in np.array(self.cooperation)
414-
/ sum(map(np.array, self.match_lengths))
424+
/ sum(map(np.array, self.match_lengths))
415425
]
416426
return normalised_cooperation
417427

@@ -426,7 +436,8 @@ def _build_initial_cooperation_rate(self, interactions_series):
426436
with warnings.catch_warnings():
427437
warnings.simplefilter("ignore")
428438
initial_cooperation_rate = list(
429-
np.nan_to_num(np.array(self.initial_cooperation_count) / interactions_array)
439+
np.nan_to_num(np.array(
440+
self.initial_cooperation_count) / interactions_array)
430441
)
431442
return initial_cooperation_rate
432443

@@ -451,7 +462,8 @@ def _build_eigenmoses_rating(self):
451462
The eigenmoses rating as defined in:
452463
http://www.scottaaronson.com/morality.pdf
453464
"""
454-
eigenvector, eigenvalue = eigen.principal_eigenvector(self.vengeful_cooperation)
465+
eigenvector, eigenvalue = eigen.principal_eigenvector(
466+
self.vengeful_cooperation)
455467

456468
return eigenvector.tolist()
457469

@@ -575,7 +587,8 @@ def _build_tasks(self, df):
575587
]
576588
sum_per_player_opponent_task = df.groupby(groups)[columns].sum()
577589

578-
ignore_self_interactions_task = df["Player index"] != df["Opponent index"]
590+
ignore_self_interactions_task = df["Player index"] != df[
591+
"Opponent index"]
579592
adf = df[ignore_self_interactions_task]
580593

581594
groups = ["Player index", "Repetition"]
@@ -589,7 +602,8 @@ def _build_tasks(self, df):
589602
groups = ["Player index"]
590603
column = "Initial cooperation"
591604
initial_cooperation_count_task = adf.groupby(groups)[column].sum()
592-
interactions_count_task = adf.groupby("Player index")["Player index"].count()
605+
interactions_count_task = adf.groupby("Player index")[
606+
"Player index"].count()
593607

594608
return (
595609
mean_per_reps_player_opponent_task,
@@ -609,6 +623,18 @@ def __eq__(self, other):
609623
other : axelrod.ResultSet
610624
Another results set against which to check equality
611625
"""
626+
627+
def list_equal_with_nans(v1: List[float], v2: List[float]) -> bool:
628+
"""Matches lists, accounting for NaNs."""
629+
if len(v1) != len(v2):
630+
return False
631+
for i1, i2 in zip(v1, v2):
632+
if np.isnan(i1) and np.isnan(i2):
633+
continue
634+
if i1 != i2:
635+
return False
636+
return True
637+
612638
return all(
613639
[
614640
self.wins == other.wins,
@@ -628,8 +654,10 @@ def __eq__(self, other):
628654
self.cooperating_rating == other.cooperating_rating,
629655
self.good_partner_matrix == other.good_partner_matrix,
630656
self.good_partner_rating == other.good_partner_rating,
631-
self.eigenmoses_rating == other.eigenmoses_rating,
632-
self.eigenjesus_rating == other.eigenjesus_rating,
657+
list_equal_with_nans(self.eigenmoses_rating,
658+
other.eigenmoses_rating),
659+
list_equal_with_nans(self.eigenjesus_rating,
660+
other.eigenjesus_rating),
633661
]
634662
)
635663

@@ -699,7 +727,8 @@ def summarise(self):
699727
rates = []
700728
for state in states:
701729
counts = [
702-
counter[(state, C)] for counter in player if counter[(state, C)] > 0
730+
counter[(state, C)] for counter in player if
731+
counter[(state, C)] > 0
703732
]
704733

705734
if len(counts) > 0:
@@ -722,7 +751,8 @@ def summarise(self):
722751

723752
summary_data = []
724753
for rank, i in enumerate(self.ranking):
725-
data = list(summary_measures[i]) + state_prob[i] + state_to_C_prob[i]
754+
data = list(summary_measures[i]) + state_prob[i] + state_to_C_prob[
755+
i]
726756
summary_data.append(self.player(rank, *data))
727757

728758
return summary_data

axelrod/strategies/_strategies.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
Michaelos,
209209
NTitsForMTats,
210210
OmegaTFT,
211+
OriginalGradual,
211212
RandomTitForTat,
212213
SlowTitForTwoTats2,
213214
SneakyTitForTat,

axelrod/strategies/titfortat.py

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,18 +384,27 @@ def strategy(self, opponent: Player) -> Action:
384384
return move
385385

386386

387-
class Gradual(Player):
387+
class OriginalGradual(Player):
388388
"""
389389
A player that punishes defections with a growing number of defections
390-
but after punishing enters a calming state and cooperates no matter what
391-
the opponent does for two rounds.
390+
but after punishing for `punishment_limit` number of times enters a calming
391+
state and cooperates no matter what the opponent does for two rounds.
392+
393+
The `punishment_limit` is incremented whenever the opponent defects and the
394+
strategy is not in either calming or punishing state.
395+
396+
Note that `Gradual` appears in [CRISTAL-SMAC2018]_ however that version of
397+
`Gradual` does not give the results reported in [Beaufils1997]_ which is the
398+
paper that first introduced the strategy. For a longer discussion of this
399+
see: https://github.com/Axelrod-Python/Axelrod/issues/1294. This is why this
400+
strategy has been renamed to `OriginalGradual`.
392401
393402
Names:
394403
395404
- Gradual: [Beaufils1997]_
396405
"""
397406

398-
name = "Gradual"
407+
name = "Original Gradual"
399408
classifier = {
400409
"memory_depth": float("inf"),
401410
"stochastic": False,
@@ -439,6 +448,67 @@ def strategy(self, opponent: Player) -> Action:
439448
return C
440449

441450

451+
class Gradual(Player):
452+
"""
453+
Similar to OriginalGradual, this is a player that punishes defections with a
454+
growing number of defections but after punishing for `punishment_limit`
455+
number of times enters a calming state and cooperates no matter what the
456+
opponent does for two rounds.
457+
458+
This version of Gradual is an update of `OriginalGradual` and the difference
459+
is that the `punishment_limit` is incremented whenever the opponent defects
460+
(regardless of the state of the player).
461+
462+
Note that this version of `Gradual` appears in [CRISTAL-SMAC2018]_ however
463+
this version of
464+
`Gradual` does not give the results reported in [Beaufils1997]_ which is the
465+
paper that first introduced the strategy. For a longer discussion of this
466+
see: https://github.com/Axelrod-Python/Axelrod/issues/1294.
467+
468+
This version is based on https://github.com/cristal-smac/ipd/blob/master/src/strategies.py#L224
469+
470+
Names:
471+
472+
- Gradual: [CRISTAL-SMAC2018]_
473+
"""
474+
475+
name = "Gradual"
476+
classifier = {
477+
"memory_depth": float("inf"),
478+
"stochastic": False,
479+
"makes_use_of": set(),
480+
"long_run_time": False,
481+
"inspects_source": False,
482+
"manipulates_source": False,
483+
"manipulates_state": False,
484+
}
485+
486+
def __init__(self) -> None:
487+
488+
super().__init__()
489+
self.calm_count = 0
490+
self.punish_count = 0
491+
492+
def strategy(self, opponent: Player) -> Action:
493+
494+
if len(self.history) == 0:
495+
return C
496+
497+
if self.punish_count > 0:
498+
self.punish_count -= 1
499+
return D
500+
501+
if self.calm_count > 0:
502+
self.calm_count -= 1
503+
return C
504+
505+
if opponent.history[-1] == D:
506+
self.punish_count = opponent.defections - 1
507+
self.calm_count = 2
508+
return D
509+
return C
510+
511+
442512
@TrackHistoryTransformer(name_prefix=None)
443513
class ContriteTitForTat(Player):
444514
"""

0 commit comments

Comments
 (0)