Skip to content

Commit 15cb4a2

Browse files
committed
Moved chi-squared to its own function.
1 parent 72f5edb commit 15cb4a2

File tree

2 files changed

+38
-29
lines changed

2 files changed

+38
-29
lines changed

axelrod/strategies/axelrod_second.py

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,8 +1092,6 @@ def __init__(self):
10921092
self.prob = 0.25 # After turn 37, probability that we'll defect
10931093

10941094
self.move_history = np.zeros([4, 2])
1095-
# Will cache value only for testing purposes, not used otherwise
1096-
self.chi_squared = None
10971095

10981096
self.more_coop = 0 # This schedules cooperation for future turns
10991097
# Initial last_generous_n_turns_ago to 3 because this counts up and
@@ -1127,35 +1125,21 @@ def try_return(self, to_return, lower_flags=True, inc_parity=False):
11271125

11281126
return to_return
11291127

1130-
def detect_random(self, turn):
1128+
def calculate_chi_squared(self, turn):
11311129
"""
1132-
Calculates a modified Pearson's Chi Squared statistic on self.history,
1133-
and returns True (is random) if and only if the statistic is less than
1134-
or equal to 3.
1135-
11361130
Pearson's Chi Squared statistic = sum[ (E_i-O_i)^2 / E_i ], where O_i
11371131
are the observed matrix values, and E_i is calculated as number (of
11381132
defects) in the row times the number in the column over (total number
1139-
in the matrix minus 1).
1140-
1141-
We say this is modified because it differs from a usual Chi-Squared
1142-
test in that:
1143-
1144-
- Terms where expected counts are less than 1 get excluded.
1145-
- There's a check at the beginning on the first cell of the matrix.
1146-
- There's a check at the beginning for the recorded number of defects.
1133+
in the matrix minus 1). Equivalently, we expect we expect (for an
1134+
independent distribution) the total number of recorded turns times the
1135+
portion in that row times the portion in that column.
11471136
1137+
In this function, the statistic is non-standard in that it excludes
1138+
summands where E_i <= 1.
11481139
"""
1140+
11491141
denom = turn - 2
11501142

1151-
if self.move_history[0, 0] / denom >= 0.8:
1152-
return False
1153-
if self.recorded_defects / denom < 0.25 or self.recorded_defects / denom > 0.75:
1154-
return False
1155-
1156-
# In each cell, we expect (for an independent distribution) the total
1157-
# number of recorded turns times the portion in that row times the
1158-
# portion in that column
11591143
expected_matrix = np.outer(self.move_history.sum(axis=1),
11601144
self.move_history.sum(axis=0)) / denom
11611145

@@ -1166,10 +1150,30 @@ def detect_random(self, turn):
11661150
if expect > 1.0:
11671151
chi_squared += (expect - self.move_history[i, j]) ** 2 / expect
11681152

1169-
# Caching value only for testing purposes, not used otherwise
1170-
self.chi_squared = round(chi_squared, 3)
1153+
return chi_squared
1154+
1155+
def detect_random(self, turn):
1156+
"""
1157+
We check if the top-left cell of the matrix (corresponding to all
1158+
Cooperations) has over 80% of the turns. In which case, we label
1159+
non-random.
1160+
1161+
Then we check if over 75% or under 25% of the opponent's turns are
1162+
Defections. If so, then we label as non-random.
1163+
1164+
Otherwise we calculates a modified Pearson's Chi Squared statistic on
1165+
self.history, and returns True (is random) if and only if the statistic
1166+
is less than or equal to 3.
1167+
"""
1168+
1169+
denom = turn - 2
1170+
1171+
if self.move_history[0, 0] / denom >= 0.8:
1172+
return False
1173+
if self.recorded_defects / denom < 0.25 or self.recorded_defects / denom > 0.75:
1174+
return False
11711175

1172-
if chi_squared > 3:
1176+
if self.calculate_chi_squared(turn) > 3:
11731177
return False
11741178
return True
11751179

axelrod/tests/strategies/test_axelrod_second.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -822,15 +822,20 @@ def test_strategy(self):
822822
self.versus_test(axelrod.Defector(), expected_actions=actions, attrs={"recorded_defects": 119})
823823

824824
# Detect random
825-
actions = [(C, D), (D, C), (C, D), (D, C), (C, D), (C, D), (D, D),
825+
expected_actions = [(C, D), (D, C), (C, D), (D, C), (C, D), (C, D), (D, D),
826826
(D, C), (C, D), (D, C), (C, C), (C, D), (D, D), (D, C),
827827
(C, D), (D, D), (D, C), (C, C), (C, D), (D, C), (C, D),
828828
(D, D), (D, C), (C, D), (D, D), (D, D), (C, D), (D, C),
829829
(C, C)]
830830
# Enter defect mode.
831-
actions += [(D, C)]
832-
self.versus_test(axelrod.Random(0.5), expected_actions=actions, seed=10, attrs={"chi_squared": 2.395})
831+
expected_actions += [(D, C)]
832+
random.seed(10)
833+
player = self.player()
834+
match = axelrod.Match((player, axelrod.Random()), turns=len(expected_actions))
833835
# The history matrix will be [[0, 2], [5, 6], [3, 6], [4, 2]]
836+
actions = match.play()
837+
self.assertEqual(actions, expected_actions) # Just to be consistant with the current test.
838+
self.assertEqual(round(player.calculate_chi_squared(len(expected_actions)),3), 2.395)
834839

835840
# Come back out of defect mode
836841
opponent_actions = [D, C, D, C, D, D, D, C, D, C, C, D, D, C, D, D, C,

0 commit comments

Comments
 (0)