Skip to content

Commit

Permalink
Fix memory-one error in compute FSM memory
Browse files Browse the repository at this point in the history
  • Loading branch information
gaffney2010 committed Feb 27, 2019
1 parent b3efe69 commit 0e7b5ca
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 18 deletions.
25 changes: 13 additions & 12 deletions axelrod/compute_finite_state_machine_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,6 @@ def get_memory_from_transitions(
ordered_memit_tuple(x_successor, y_successor)
)

if len(pair_nodes) == 0:
# If there are no pair of tied memits, then either no memits are needed
# to break a tie (i.e. all next_actions are the same) or the first memit
# breaks a tie (i.e. memory 1)
next_action_set = set()
for trans in transition_iterator(transitions):
next_action_set.add(trans.next_action)
if len(next_action_set) == 1:
return 0
return 1

# Get next_action for each memit. Used to decide if they are in conflict,
# because we only have undecidability if next_action doesn't match.
next_action_by_memit = dict()
Expand All @@ -261,5 +250,17 @@ def get_memory_from_transitions(
path_length = longest_path(pair_edges, pair) + 1
if record < path_length:
record = path_length
return record

if record > 0:
return record

# If there are no pair of tied memits (for which the next action are
# distinct), then either no memits are needed to break a tie (i.e. all
# next_actions are the same) or the first memit breaks a tie (i.e. memory 1)
next_action_set = set()
for trans in transition_iterator(transitions):
next_action_set.add(trans.next_action)
if len(next_action_set) == 1:
return 0
return 1

23 changes: 17 additions & 6 deletions axelrod/tests/unit/test_compute_finite_state_machine_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ def test_two_state_memory_two(self):
"""If all D lead to state 0 and all C lead to state 1. We make it so
that all paths out of state 0 plays Cooperator and state 1 plays
Defector.
In this case, we must know what state we're in to know how to respond to
the opponent's previou action, but we cannot determine from our own
previous action; we must look at opponent's action from two turns ago.
Expand All @@ -88,11 +87,26 @@ def test_two_state_tft(self):
trans_dict = self.transitions_to_dict(transitions)
self.assertEqual(get_memory_from_transitions(trans_dict), 1)

def test_three_state_tft(self):
"""Tit-for-tat again, but using three states, and a complex web of
transitions between them.
"""
transitions = (
(0, C, 1, C),
(0, D, 1, D),
(1, C, 2, C),
(1, D, 0, D),
(2, C, 0, C),
(2, D, 2, D)
)

trans_dict = self.transitions_to_dict(transitions)
self.assertEqual(get_memory_from_transitions(trans_dict), 1)

def test_two_state_inf_memory(self):
"""A C will cause the FSM to stay in the same state, and D causes to
change states. Will always respond to a C with a C. Will respond to a
D with a C in state 0, but with a D in state 1.
So we need to know the state to know how to respond to a D. But since
an arbitarily long sequence of C/C may occur, we need infinite memory.
"""
Expand Down Expand Up @@ -125,7 +139,6 @@ def test_tit_for_two_tat(self):
let states 1 and 2 be the cooperating states, with state 2 being the
state after one opponent defection. And states 3 and 4 are the
defecting states, with state 4 after 1 opponent cooperation.
The memory should be two, because if the last two moves don't match,
then we can look to see what we did in the last move. If the do match,
then we can respond in kind.
Expand Down Expand Up @@ -176,12 +189,10 @@ def test_tit_for_five_tat(self):
def test_fortress_3(self):
"""Tests Fortress-3, which Defects unless the opponent D twice in a row.
In that case C, and continue to C for as long as the opponent does.
We know we're in state 3 if our own previous move was a C. Otherwise, C
if and only if the opponent's previous two moves were D. [Unless we
were in state 3 last turn, in which case we would have C'd two turns
ago.]
So the memory should be 2.
"""
transitions = (
Expand Down Expand Up @@ -267,7 +278,6 @@ def test_transient_state(self):
"""Test a setup where we a transient state (no incoming transitions)
goes into a Fortress3 (and D) if the opponent D, and goes into a
Cooperator if the opponent C.
The transient state is state 0. Fortress3 starts at state 1. And
the Cooperator is state 4.
"""
Expand Down Expand Up @@ -336,3 +346,4 @@ def test_evolved_fsm_4(self):

trans_dict = self.transitions_to_dict(transitions)
self.assertEqual(get_memory_from_transitions(trans_dict), float("inf"))

0 comments on commit 0e7b5ca

Please sign in to comment.