Skip to content
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

Implement transitive fingerprint #1125

Merged
merged 19 commits into from
Aug 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion axelrod/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
from .tournament import Tournament
from .result_set import ResultSet, ResultSetFromFile
from .ecosystem import Ecosystem
from .fingerprint import AshlockFingerprint
from .fingerprint import AshlockFingerprint, TransitiveFingerprint

208 changes: 199 additions & 9 deletions axelrod/fingerprint.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from collections import namedtuple
import csv
import os
from collections import namedtuple
from tempfile import mkstemp

import matplotlib.pyplot as plt
import numpy as np
import tqdm
from mpl_toolkits.axes_grid1 import make_axes_locatable

import axelrod as axl
from axelrod import Player
Expand Down Expand Up @@ -154,7 +157,7 @@ def generate_data(interactions: dict, points: list, edges: list) -> dict:

Parameters
----------
interactions : dictionary
interactions : dict
A dictionary mapping edges to the corresponding interactions of
those players.
points : list
Expand All @@ -166,7 +169,7 @@ def generate_data(interactions: dict, points: list, edges: list) -> dict:

Returns
----------
point_scores : dictionary
point_scores : dict
A dictionary where the keys are Points of the form (x, y) and
the values are the mean score for the corresponding interactions.
"""
Expand Down Expand Up @@ -265,7 +268,7 @@ def fingerprint(
self, turns: int = 50, repetitions: int = 10, step: float = 0.01,
processes: int=None, filename: str = None, in_memory: bool = False,
progress_bar: bool = True
) -> dict:
) -> dict:
"""Build and play the spatial tournament.

Creates the probes and their edges then builds a spatial tournament.
Expand All @@ -276,16 +279,16 @@ def fingerprint(

Parameters
----------
turns : integer, optional
turns : int, optional
The number of turns per match
repetitions : integer, optional
repetitions : int, optional
The number of times the round robin should be repeated
step : float, optional
The separation between each Point. Smaller steps will
produce more Points that will be closer together.
processes : integer, optional
processes : int, optional
The number of processes to be used for parallel processing
filename: string, optional
filename: str, optional
The name of the file for self.spatial_tournament's interactions.
if None and in_memory=False, will auto-generate a filename.
in_memory: bool
Expand All @@ -296,7 +299,7 @@ def fingerprint(

Returns
----------
self.data : dictionary
self.data : dict
A dictionary where the keys are coordinates of the form (x, y) and
the values are the mean score for the corresponding interactions.
"""
Expand Down Expand Up @@ -379,3 +382,190 @@ def plot(self, cmap: str = 'seismic', interpolation: str = 'none',
if title is not None:
plt.title(title)
return fig


class TransitiveFingerprint(object):
def __init__(self, strategy, opponents=None, number_of_opponents=50):
"""
Parameters
----------
strategy : class or instance
A class that must be descended from axelrod.Player or an instance of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean "axelrod.Player or a descendent" -- I don't believe an instance of axelrod.Player would work here.

axelrod.Player.
opponents : list of instances
A list that contains a list of opponents
Default: A spectrum of Random players
number_of_opponents: int
The number of Random opponents
Default: 50
"""
self.strategy = strategy

if opponents is None:
self.opponents = [axl.Random(p) for p in
np.linspace(0, 1, number_of_opponents)]
else:
self.opponents = opponents

def fingerprint(self, turns: int = 50, repetitions: int = 1000,
noise: float = None, processes: int = None,
filename: str = None,
progress_bar: bool = True) -> np.array:
"""Creates a spatial tournament to run the necessary matches to obtain
fingerprint data.

Creates the opponents and their edges then builds a spatial tournament.

Parameters
----------
turns : int, optional
The number of turns per match
repetitions : int, optional
The number of times the round robin should be repeated
noise : float, optional
The probability that a player's intended action should be flipped
processes : int, optional
The number of processes to be used for parallel processing
filename: str, optional
The name of the file for spatial tournament's interactions.
if None, a filename will be generated.
progress_bar : bool
Whether or not to create a progress bar which will be updated

Returns
----------
self.data : np.array
A numpy array containing the mean cooperation rate against each
opponent in each turn. The ith row corresponds to the ith opponent
and the jth column the jth turn.
"""

if isinstance(self.strategy, axl.Player):
players = [self.strategy] + self.opponents
else:
players = [self.strategy()] + self.opponents

temp_file_descriptor = None
if filename is None:
temp_file_descriptor, filename = mkstemp()

edges = [(0, k + 1) for k in range(len(self.opponents))]
tournament = axl.Tournament(players=players,
edges=edges, turns=turns, noise=noise,
repetitions=repetitions)
tournament.play(filename=filename, build_results=False,
progress_bar=progress_bar, processes=processes)

self.data = self.analyse_cooperation_ratio(filename)

if temp_file_descriptor is not None:
os.close(temp_file_descriptor)
os.remove(filename)

return self.data

@staticmethod
def analyse_cooperation_ratio(filename):
"""Generates the data used from the tournament

Return an M by N array where M is the number of opponents and N is the
number of turns.

Parameters
----------
filename : str
The filename of the interactions

Returns
----------
self.data : np.array
A numpy array containing the mean cooperation rate against each
opponent in each turn. The ith row corresponds to the ith opponent
and the jth column the jth turn.
"""
did_c = np.vectorize(lambda action: int(action == 'C'))

cooperation_rates = {}
with open(filename, "r") as f:
reader = csv.reader(f)
for row in reader:
opponent_index, player_history = int(row[1]), list(row[4])
if opponent_index in cooperation_rates:
cooperation_rates[opponent_index].append(did_c(player_history))
else:
cooperation_rates[opponent_index] = [did_c(player_history)]

for index, rates in cooperation_rates.items():
cooperation_rates[index] = np.mean(rates, axis=0)

return np.array([cooperation_rates[index]
for index in cooperation_rates])

def plot(self, cmap: str = 'viridis', interpolation: str = 'none',
title: str = None, colorbar: bool = True, labels: bool = True,
display_names: bool = False,
ax: plt.Figure = None) -> plt.Figure:
"""Plot the results of the spatial tournament.
Parameters
----------
cmap : str, optional
A matplotlib colour map, full list can be found at
http://matplotlib.org/examples/color/colormaps_reference.html
interpolation : str, optional
A matplotlib interpolation, full list can be found at
http://matplotlib.org/examples/images_contours_and_fields/interpolation_methods.html
title : str, optional
A title for the plot
colorbar : bool, optional
Choose whether the colorbar should be included or not
labels : bool, optional
Choose whether the axis labels and ticks should be included
display_names : bool, optional
Choose whether to display the names of the strategies
ax: matplotlib axis
Allows the plot to be written to a given matplotlib axis.
Default is None.
Returns
----------
figure : matplotlib figure
A heat plot of the results of the spatial tournament
"""
if ax is None:
fig, ax = plt.subplots()
else:
ax = ax

fig = ax.get_figure()
mat = ax.imshow(self.data, cmap=cmap, interpolation=interpolation)

width = len(self.data) / 2
height = width
fig.set_size_inches(width, height)

plt.xlabel('turns')
ax.tick_params(axis='both', which='both', length=0)

if display_names:
plt.yticks(range(len(self.opponents)), [str(player) for player in
self.opponents])
else:
plt.yticks([0, len(self.opponents) - 1], [0, 1])
plt.ylabel("Probability of cooperation")

if not labels:
plt.axis('off')

if title is not None:
plt.title(title)

if colorbar:
max_score = 0
min_score = 1
ticks = [min_score, 1 / 2, max_score]

divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
cbar = fig.colorbar(mat, cax=cax, ticks=ticks)

plt.tight_layout()
return fig
Loading