# Source code for axelrod.strategies.ann

```
from typing import List, Tuple
import numpy as np
from axelrod.action import Action
from axelrod.load_data_ import load_weights
from axelrod.player import Player
C, D = Action.C, Action.D
nn_weights = load_weights()
# Neural Network and Activation functions
relu = np.vectorize(lambda x: max(x, 0))
[docs]def compute_features(player: Player, opponent: Player) -> List[int]:
"""
Compute history features for Neural Network:
* Opponent's first move is C
* Opponent's first move is D
* Opponent's second move is C
* Opponent's second move is D
* Player's previous move is C
* Player's previous move is D
* Player's second previous move is C
* Player's second previous move is D
* Opponent's previous move is C
* Opponent's previous move is D
* Opponent's second previous move is C
* Opponent's second previous move is D
* Total opponent cooperations
* Total opponent defections
* Total player cooperations
* Total player defections
* Round number
"""
if len(opponent.history) == 0:
opponent_first_c = 0
opponent_first_d = 0
opponent_second_c = 0
opponent_second_d = 0
my_previous_c = 0
my_previous_d = 0
my_previous2_c = 0
my_previous2_d = 0
opponent_previous_c = 0
opponent_previous_d = 0
opponent_previous2_c = 0
opponent_previous2_d = 0
elif len(opponent.history) == 1:
opponent_first_c = 1 if opponent.history[0] == C else 0
opponent_first_d = 1 if opponent.history[0] == D else 0
opponent_second_c = 0
opponent_second_d = 0
my_previous_c = 1 if player.history[-1] == C else 0
my_previous_d = 1 if player.history[-1] == D else 0
my_previous2_c = 0
my_previous2_d = 0
opponent_previous_c = 1 if opponent.history[-1] == C else 0
opponent_previous_d = 1 if opponent.history[-1] == D else 0
opponent_previous2_c = 0
opponent_previous2_d = 0
else:
opponent_first_c = 1 if opponent.history[0] == C else 0
opponent_first_d = 1 if opponent.history[0] == D else 0
opponent_second_c = 1 if opponent.history[1] == C else 0
opponent_second_d = 1 if opponent.history[1] == D else 0
my_previous_c = 1 if player.history[-1] == C else 0
my_previous_d = 1 if player.history[-1] == D else 0
my_previous2_c = 1 if player.history[-2] == C else 0
my_previous2_d = 1 if player.history[-2] == D else 0
opponent_previous_c = 1 if opponent.history[-1] == C else 0
opponent_previous_d = 1 if opponent.history[-1] == D else 0
opponent_previous2_c = 1 if opponent.history[-2] == C else 0
opponent_previous2_d = 1 if opponent.history[-2] == D else 0
# Remaining Features
total_opponent_c = opponent.cooperations
total_opponent_d = opponent.defections
total_player_c = player.cooperations
total_player_d = player.defections
return [
opponent_first_c,
opponent_first_d,
opponent_second_c,
opponent_second_d,
my_previous_c,
my_previous_d,
my_previous2_c,
my_previous2_d,
opponent_previous_c,
opponent_previous_d,
opponent_previous2_c,
opponent_previous2_d,
total_opponent_c,
total_opponent_d,
total_player_c,
total_player_d,
len(player.history),
]
[docs]def activate(
bias: List[float], hidden: List[float], output: List[float], inputs: List[int]
) -> float:
"""
Compute the output of the neural network:
output = relu(inputs * hidden_weights + bias) * output_weights
"""
inputs = np.array(inputs)
hidden_values = bias + np.dot(hidden, inputs)
hidden_values = relu(hidden_values)
output_value = np.dot(hidden_values, output)
return output_value
[docs]def split_weights(
weights: List[float], num_features: int, num_hidden: int
) -> Tuple[List[List[float]], List[float], List[float]]:
"""Splits the input vector into the the NN bias weights and layer
parameters."""
# Check weights is the right length
expected_length = num_hidden * 2 + num_features * num_hidden
if expected_length != len(weights):
raise ValueError("NN weights array has an incorrect size.")
number_of_input_to_hidden_weights = num_features * num_hidden
number_of_hidden_to_output_weights = num_hidden
input2hidden = []
for i in range(0, number_of_input_to_hidden_weights, num_features):
input2hidden.append(weights[i : i + num_features])
start = number_of_input_to_hidden_weights
end = number_of_input_to_hidden_weights + number_of_hidden_to_output_weights
hidden2output = weights[start:end]
bias = weights[end:]
return (input2hidden, hidden2output, bias)
[docs]class ANN(Player):
"""Artificial Neural Network based strategy.
A single layer neural network based strategy, with the following
features:
* Opponent's first move is C
* Opponent's first move is D
* Opponent's second move is C
* Opponent's second move is D
* Player's previous move is C
* Player's previous move is D
* Player's second previous move is C
* Player's second previous move is D
* Opponent's previous move is C
* Opponent's previous move is D
* Opponent's second previous move is C
* Opponent's second previous move is D
* Total opponent cooperations
* Total opponent defections
* Total player cooperations
* Total player defections
* Round number
Original Source: https://gist.github.com/mojones/550b32c46a8169bb3cd89d917b73111a#file-ann-strategy-test-L60
Names
- Artificial Neural Network based strategy: Original name by Martin Jones
"""
name = "ANN"
classifier = {
"memory_depth": float("inf"),
"stochastic": False,
"inspects_source": False,
"makes_use_of": set(),
"manipulates_source": False,
"manipulates_state": False,
"long_run_time": False,
}
def __init__(
self, weights: List[float], num_features: int, num_hidden: int
) -> None:
super().__init__()
(i2h, h2o, bias) = split_weights(weights, num_features, num_hidden)
self.input_to_hidden_layer_weights = np.matrix(i2h)
self.hidden_to_output_layer_weights = np.array(h2o)
self.bias_weights = np.array(bias)
[docs] def strategy(self, opponent: Player) -> Action:
features = compute_features(self, opponent)
output = activate(
self.bias_weights,
self.input_to_hidden_layer_weights,
self.hidden_to_output_layer_weights,
features,
)
if output > 0:
return C
else:
return D
[docs]class EvolvedANN(ANN):
"""
A strategy based on a pre-trained neural network with 17 features and a
hidden layer of size 10.
Trained using the `axelrod_dojo` version: 0.0.8
Training data is archived at doi.org/10.5281/zenodo.1306926
Names:
- Evolved ANN: Original name by Martin Jones.
"""
name = "Evolved ANN"
def __init__(self) -> None:
num_features, num_hidden, weights = nn_weights["Evolved ANN"]
super().__init__(weights, num_features, num_hidden)
[docs]class EvolvedANN5(ANN):
"""
A strategy based on a pre-trained neural network with 17 features and a
hidden layer of size 5.
Trained using the `axelrod_dojo` version: 0.0.8
Training data is archived at doi.org/10.5281/zenodo.1306931
Names:
- Evolved ANN 5: Original name by Marc Harper.
"""
name = "Evolved ANN 5"
def __init__(self) -> None:
num_features, num_hidden, weights = nn_weights["Evolved ANN 5"]
super().__init__(weights, num_features, num_hidden)
[docs]class EvolvedANNNoise05(ANN):
"""
A strategy based on a pre-trained neural network with a hidden layer of
size 5, trained with noise=0.05.
Trained using the `axelrod_dojo` version: 0.0.8
Training data i archived at doi.org/10.5281/zenodo.1314247.
Names:
- Evolved ANN Noise 5: Original name by Marc Harper.
"""
name = "Evolved ANN 5 Noise 05"
def __init__(self) -> None:
num_features, num_hidden, weights = nn_weights["Evolved ANN 5 Noise 05"]
super().__init__(weights, num_features, num_hidden)
```