|
| 1 | +"""Memory Two strategies.""" |
| 2 | + |
| 3 | +import itertools |
| 4 | +import warnings |
| 5 | +from typing import Tuple, Dict |
| 6 | + |
1 | 7 | from axelrod.action import Action |
2 | 8 | from axelrod.player import Player |
| 9 | +from axelrod.random_ import random_choice |
3 | 10 | from .titfortat import TitForTat, TitFor2Tats |
4 | 11 | from .defector import Defector |
5 | 12 |
|
| 13 | + |
6 | 14 | C, D = Action.C, Action.D |
7 | 15 |
|
8 | 16 |
|
| 17 | +class MemoryTwoPlayer(Player): |
| 18 | + """ |
| 19 | + Uses a sixteen-vector for strategies based on the 16 conditional probabilities |
| 20 | + P(X | I,J,K,L) where X, I, J, K, L in [C, D] and I, J are the players last |
| 21 | + two moves and K, L are the opponents last two moves. These conditional |
| 22 | + probabilities are the following: |
| 23 | + 1. P(C|CC, CC) |
| 24 | + 2. P(C|CC, CD) |
| 25 | + 3. P(C|CC, DC) |
| 26 | + 4. P(C|CC, DD) |
| 27 | + 5. P(C|CD, CC) |
| 28 | + 6. P(C|CD, CD) |
| 29 | + 7. P(C|CD, DC) |
| 30 | + 8. P(C|CD, DD) |
| 31 | + 9. P(C|DC, CC) |
| 32 | + 10. P(C|DC, CD) |
| 33 | + 11. P(C|DC, DC) |
| 34 | + 12. P(C|DC, DD) |
| 35 | + 13. P(C|DD, CC) |
| 36 | + 14. P(C|DD, CD) |
| 37 | + 15. P(C|DD, DC) |
| 38 | + 16. P(C|DD, DD)) |
| 39 | + Cooperator is set as the default player if sixteen_vector is not given. |
| 40 | +
|
| 41 | + Names |
| 42 | +
|
| 43 | + - Memory Two: [Hilbe2017]_ |
| 44 | + """ |
| 45 | + |
| 46 | + name = 'Generic Memory Two Player' |
| 47 | + classifier = { |
| 48 | + 'memory_depth': 2, |
| 49 | + 'stochastic': False, |
| 50 | + 'makes_use_of': set(), |
| 51 | + 'long_run_time': False, |
| 52 | + 'inspects_source': False, |
| 53 | + 'manipulates_source': False, |
| 54 | + 'manipulates_state': False |
| 55 | + } |
| 56 | + |
| 57 | + def __init__(self, sixteen_vector: Tuple[float, ...] = None, |
| 58 | + initial: Action = C) -> None: |
| 59 | + """ |
| 60 | + Parameters |
| 61 | + ---------- |
| 62 | +
|
| 63 | + sixteen_vector: list or tuple of floats of length 16 |
| 64 | + The response probabilities to the preceding round of play |
| 65 | + initial: C or D |
| 66 | + The initial 2 moves |
| 67 | + """ |
| 68 | + super().__init__() |
| 69 | + self._initial = initial |
| 70 | + self.set_initial_sixteen_vector(sixteen_vector) |
| 71 | + |
| 72 | + def set_initial_sixteen_vector(self, sixteen_vector): |
| 73 | + if sixteen_vector is None: |
| 74 | + sixteen_vector = tuple([1] * 16) |
| 75 | + warnings.warn("Memory two player is set to default, Cooperator.") |
| 76 | + |
| 77 | + self.set_sixteen_vector(sixteen_vector) |
| 78 | + if self.name == 'Generic Memory Two Player': |
| 79 | + self.name = "%s: %s" % (self.name, sixteen_vector) |
| 80 | + |
| 81 | + def set_sixteen_vector(self, sixteen_vector: Tuple): |
| 82 | + if not all(0 <= p <= 1 for p in sixteen_vector): |
| 83 | + raise ValueError("An element in the probability vector, {}, is not " |
| 84 | + "between 0 and 1.".format(str(sixteen_vector))) |
| 85 | + |
| 86 | + states = [(hist[:2], hist[2:]) |
| 87 | + for hist in list(itertools.product((C, D), repeat=4))] |
| 88 | + |
| 89 | + self._sixteen_vector = dict(zip(states, sixteen_vector)) # type: Dict[tuple, float] |
| 90 | + self.classifier['stochastic'] = any(0 < x < 1 for x in set(sixteen_vector)) |
| 91 | + |
| 92 | + def strategy(self, opponent: Player) -> Action: |
| 93 | + if len(opponent.history) <= 1: |
| 94 | + return self._initial |
| 95 | + # Determine which probability to use |
| 96 | + p = self._sixteen_vector[(tuple(self.history[-2:]), |
| 97 | + tuple(opponent.history[-2:]))] |
| 98 | + # Draw a random number in [0, 1] to decide |
| 99 | + return random_choice(p) |
| 100 | + |
| 101 | + |
| 102 | +class AON2(MemoryTwoPlayer): |
| 103 | + """ |
| 104 | + AON2 a memory two strategy introduced in [Hilbe2017]_. It belongs to the |
| 105 | + AONk (all-or-none) family of strategies. These strategies were designed to |
| 106 | + satisfy the three following properties: |
| 107 | +
|
| 108 | + 1. Mutually Cooperative. A strategy is mutually cooperative if there are |
| 109 | + histories for which the strategy prescribes to cooperate, and if it continues |
| 110 | + to cooperate after rounds with mutual cooperation (provided the last k actions |
| 111 | + of the focal player were actually consistent). |
| 112 | +
|
| 113 | + 2. Error correcting. A strategy is error correcting after at most k rounds if, |
| 114 | + after any history, it generally takes a group of players at most k + 1 rounds |
| 115 | + to re-establish mutual cooperation. |
| 116 | +
|
| 117 | + 3. Retaliating. A strategy is retaliating for at least k rounds if, after |
| 118 | + rounds in which the focal player cooperated while the coplayer defected, |
| 119 | + the strategy responds by defecting the following k rounds. |
| 120 | +
|
| 121 | + In [Hilbe2017]_ the following vectors are reported as "equivalent" to AON2 |
| 122 | + with their respective self-cooperation rate (note that these are not the same): |
| 123 | + |
| 124 | + 1. [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], self-cooperation |
| 125 | + rate: 0.952 |
| 126 | + 2. [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], self-cooperation |
| 127 | + rate: 0.951 |
| 128 | + 3. [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], self-cooperation |
| 129 | + rate: 0.951 |
| 130 | + 4. [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1], self-cooperation |
| 131 | + rate: 0.952 |
| 132 | +
|
| 133 | + AON2 is implemented using vector 1 due its self-cooperation rate. |
| 134 | +
|
| 135 | + In essence it is a strategy that starts off by cooperating and will cooperate |
| 136 | + again only after the states (CC, CC), (CD, CD), (DC, DC), (DD, DD). |
| 137 | +
|
| 138 | + Names: |
| 139 | +
|
| 140 | + - AON2: [Hilbe2017]_ |
| 141 | + """ |
| 142 | + |
| 143 | + name = 'AON2' |
| 144 | + classifier = { |
| 145 | + 'memory_depth': 2, |
| 146 | + 'stochastic': False, |
| 147 | + 'makes_use_of': set(), |
| 148 | + 'long_run_time': False, |
| 149 | + 'inspects_source': False, |
| 150 | + 'manipulates_source': False, |
| 151 | + 'manipulates_state': False |
| 152 | + } |
| 153 | + |
| 154 | + def __init__(self) -> None: |
| 155 | + sixteen_vector = (1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) |
| 156 | + super().__init__(sixteen_vector) |
| 157 | + |
| 158 | + |
| 159 | +class DelayedAON1(MemoryTwoPlayer): |
| 160 | + """ |
| 161 | + Delayed AON1 a memory two strategy also introduced in [Hilbe2017]_ and belongs |
| 162 | + to the AONk family. Note that AON1 is equivalent to Win Stay Lose Shift. |
| 163 | +
|
| 164 | + In [Hilbe2017]_ the following vectors are reported as "equivalent" to Delayed |
| 165 | + AON1 with their respective self-cooperation rate (note that these are not the |
| 166 | + same): |
| 167 | +
|
| 168 | + 1. [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1], self-cooperation |
| 169 | + rate: 0.952 |
| 170 | + 2. [1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], self-cooperation |
| 171 | + rate: 0.970 |
| 172 | + 3. [1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1], self-cooperation |
| 173 | + rate: 0.971 |
| 174 | +
|
| 175 | + Delayed AON1 is implemented using vector 3 due its self-cooperation rate. |
| 176 | +
|
| 177 | + In essence it is a strategy that starts off by cooperating and will cooperate |
| 178 | + again only after the states (CC, CC), (CD, CD), (CD, DD), (DD, CD), |
| 179 | + (DC, DC) and (DD, DD). |
| 180 | +
|
| 181 | + Names: |
| 182 | +
|
| 183 | + - Delayed AON1: [Hilbe2017]_ |
| 184 | + """ |
| 185 | + |
| 186 | + name = 'Delayed AON1' |
| 187 | + classifier = { |
| 188 | + 'memory_depth': 2, |
| 189 | + 'stochastic': False, |
| 190 | + 'makes_use_of': set(), |
| 191 | + 'long_run_time': False, |
| 192 | + 'inspects_source': False, |
| 193 | + 'manipulates_source': False, |
| 194 | + 'manipulates_state': False |
| 195 | + } |
| 196 | + |
| 197 | + def __init__(self) -> None: |
| 198 | + sixteen_vector = (1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1) |
| 199 | + super().__init__(sixteen_vector) |
| 200 | + |
| 201 | + |
9 | 202 | class MEM2(Player): |
10 | 203 | """A memory-two player that switches between TFT, TFTT, and ALLD. |
11 | 204 |
|
|
0 commit comments