Skip to content

Commit 0e7b5ca

Browse files
author
gaffney2010
committed
Fix memory-one error in compute FSM memory
1 parent b3efe69 commit 0e7b5ca

File tree

2 files changed

+30
-18
lines changed

2 files changed

+30
-18
lines changed

axelrod/compute_finite_state_machine_memory.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,6 @@ def get_memory_from_transitions(
231231
ordered_memit_tuple(x_successor, y_successor)
232232
)
233233

234-
if len(pair_nodes) == 0:
235-
# If there are no pair of tied memits, then either no memits are needed
236-
# to break a tie (i.e. all next_actions are the same) or the first memit
237-
# breaks a tie (i.e. memory 1)
238-
next_action_set = set()
239-
for trans in transition_iterator(transitions):
240-
next_action_set.add(trans.next_action)
241-
if len(next_action_set) == 1:
242-
return 0
243-
return 1
244-
245234
# Get next_action for each memit. Used to decide if they are in conflict,
246235
# because we only have undecidability if next_action doesn't match.
247236
next_action_by_memit = dict()
@@ -261,5 +250,17 @@ def get_memory_from_transitions(
261250
path_length = longest_path(pair_edges, pair) + 1
262251
if record < path_length:
263252
record = path_length
264-
return record
253+
254+
if record > 0:
255+
return record
256+
257+
# If there are no pair of tied memits (for which the next action are
258+
# distinct), then either no memits are needed to break a tie (i.e. all
259+
# next_actions are the same) or the first memit breaks a tie (i.e. memory 1)
260+
next_action_set = set()
261+
for trans in transition_iterator(transitions):
262+
next_action_set.add(trans.next_action)
263+
if len(next_action_set) == 1:
264+
return 0
265+
return 1
265266

axelrod/tests/unit/test_compute_finite_state_machine_memory.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ def test_two_state_memory_two(self):
6969
"""If all D lead to state 0 and all C lead to state 1. We make it so
7070
that all paths out of state 0 plays Cooperator and state 1 plays
7171
Defector.
72-
7372
In this case, we must know what state we're in to know how to respond to
7473
the opponent's previou action, but we cannot determine from our own
7574
previous action; we must look at opponent's action from two turns ago.
@@ -88,11 +87,26 @@ def test_two_state_tft(self):
8887
trans_dict = self.transitions_to_dict(transitions)
8988
self.assertEqual(get_memory_from_transitions(trans_dict), 1)
9089

90+
def test_three_state_tft(self):
91+
"""Tit-for-tat again, but using three states, and a complex web of
92+
transitions between them.
93+
"""
94+
transitions = (
95+
(0, C, 1, C),
96+
(0, D, 1, D),
97+
(1, C, 2, C),
98+
(1, D, 0, D),
99+
(2, C, 0, C),
100+
(2, D, 2, D)
101+
)
102+
103+
trans_dict = self.transitions_to_dict(transitions)
104+
self.assertEqual(get_memory_from_transitions(trans_dict), 1)
105+
91106
def test_two_state_inf_memory(self):
92107
"""A C will cause the FSM to stay in the same state, and D causes to
93108
change states. Will always respond to a C with a C. Will respond to a
94109
D with a C in state 0, but with a D in state 1.
95-
96110
So we need to know the state to know how to respond to a D. But since
97111
an arbitarily long sequence of C/C may occur, we need infinite memory.
98112
"""
@@ -125,7 +139,6 @@ def test_tit_for_two_tat(self):
125139
let states 1 and 2 be the cooperating states, with state 2 being the
126140
state after one opponent defection. And states 3 and 4 are the
127141
defecting states, with state 4 after 1 opponent cooperation.
128-
129142
The memory should be two, because if the last two moves don't match,
130143
then we can look to see what we did in the last move. If the do match,
131144
then we can respond in kind.
@@ -176,12 +189,10 @@ def test_tit_for_five_tat(self):
176189
def test_fortress_3(self):
177190
"""Tests Fortress-3, which Defects unless the opponent D twice in a row.
178191
In that case C, and continue to C for as long as the opponent does.
179-
180192
We know we're in state 3 if our own previous move was a C. Otherwise, C
181193
if and only if the opponent's previous two moves were D. [Unless we
182194
were in state 3 last turn, in which case we would have C'd two turns
183195
ago.]
184-
185196
So the memory should be 2.
186197
"""
187198
transitions = (
@@ -267,7 +278,6 @@ def test_transient_state(self):
267278
"""Test a setup where we a transient state (no incoming transitions)
268279
goes into a Fortress3 (and D) if the opponent D, and goes into a
269280
Cooperator if the opponent C.
270-
271281
The transient state is state 0. Fortress3 starts at state 1. And
272282
the Cooperator is state 4.
273283
"""
@@ -336,3 +346,4 @@ def test_evolved_fsm_4(self):
336346

337347
trans_dict = self.transitions_to_dict(transitions)
338348
self.assertEqual(get_memory_from_transitions(trans_dict), float("inf"))
349+

0 commit comments

Comments
 (0)