Skip to content

Commit fe3b83b

Browse files
committedApr 12, 2020
Replace makes_use_of classifier
1 parent 53600a9 commit fe3b83b

File tree

6 files changed

+179
-132
lines changed

6 files changed

+179
-132
lines changed
 

‎axelrod/classifier.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import warnings
1515
import yaml
1616

17+
from axelrod.makes_use_of import makes_use_of
1718
from axelrod.player import Player
1819

1920
ALL_CLASSIFIERS_PATH = "data/all_classifiers.yml"
@@ -59,12 +60,18 @@ def classify_player(self, player: Type[Player]) -> T:
5960

6061

6162
stochastic = Classifier[bool]("stochastic", lambda _: False)
62-
memory_depth = Classifier[Union[float, int]]("memory_depth", lambda _: float("inf"))
63-
makes_use_of = Classifier[Optional[Set[Text]]]("makes_use_of", lambda _: None)
63+
memory_depth = Classifier[Union[float, int]](
64+
"memory_depth", lambda _: float("inf")
65+
)
66+
makes_use_of = Classifier[Optional[Set[Text]]]("makes_use_of", makes_use_of)
6467
long_run_time = Classifier[bool]("long_run_time", lambda _: False)
6568
inspects_source = Classifier[Optional[bool]]("inspects_source", lambda _: None)
66-
manipulates_source = Classifier[Optional[bool]]("manipulates_source", lambda _: None)
67-
manipulates_state = Classifier[Optional[bool]]("manipulates_state", lambda _: None)
69+
manipulates_source = Classifier[Optional[bool]](
70+
"manipulates_source", lambda _: None
71+
)
72+
manipulates_state = Classifier[Optional[bool]](
73+
"manipulates_state", lambda _: None
74+
)
6875

6976
# Should list all known classifiers.
7077
all_classifiers = [

‎axelrod/data/all_classifiers.yml

+85-101
Large diffs are not rendered by default.

‎axelrod/makes_use_of.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
import inspect
22
import re
3-
from typing import Set, Text, Type
3+
from typing import Callable, Set, Text, Type
44

55
from axelrod.player import Player
66

77

8+
def method_makes_use_of(method: Callable) -> Set[Text]:
9+
result = set()
10+
method_code = inspect.getsource(method)
11+
attr_string = r".match_attributes\[\"(\w+)\"\]"
12+
all_attrs = re.findall(attr_string, method_code)
13+
for attr in all_attrs:
14+
result.add(attr)
15+
return result
16+
17+
818
def makes_use_of(player: Type[Player]) -> Set[Text]:
919
result = set()
1020
for method in inspect.getmembers(player, inspect.ismethod):
1121
if method[0] == "__init__":
1222
continue
13-
method_code = inspect.getsource(method[1])
14-
attr_string = r"self.match_attributes\[\"(\w+)\"\]"
15-
all_attrs = re.findall(attr_string, method_code)
16-
for attr in all_attrs:
17-
result.add(attr)
23+
result.update(method_makes_use_of(method[1]))
1824
return result

‎axelrod/strategies/meta.py

+34-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
)
2121

2222
# Needs to be computed manually to prevent circular dependency
23-
ordinary_strategies = [s for s in all_strategies if Classifiers.obey_axelrod(s())]
23+
ordinary_strategies = [
24+
s for s in all_strategies if Classifiers.obey_axelrod(s())
25+
]
2426

2527
C, D = Action.C, Action.D
2628

@@ -70,8 +72,11 @@ def __init__(self, team=None):
7072
]:
7173
self.classifier[key] = any(map(Classifiers[key], self.team))
7274

75+
self.classifier["makes_use_of"] = set()
7376
for t in self.team:
74-
self.classifier["makes_use_of"].update(Classifiers["makes_use_of"](t))
77+
new_uses = Classifiers["makes_use_of"](t)
78+
if new_uses:
79+
self.classifier["makes_use_of"].update(new_uses)
7580

7681
self._last_results = None
7782

@@ -329,7 +334,11 @@ class MetaMajorityMemoryOne(MetaMajority):
329334
name = "Meta Majority Memory One"
330335

331336
def __init__(self):
332-
team = [s for s in ordinary_strategies if Classifiers["memory_depth"](s()) <= 1]
337+
team = [
338+
s
339+
for s in ordinary_strategies
340+
if Classifiers["memory_depth"](s()) <= 1
341+
]
333342
super().__init__(team=team)
334343
self.classifier["long_run_time"] = False
335344

@@ -383,7 +392,11 @@ class MetaWinnerMemoryOne(MetaWinner):
383392
name = "Meta Winner Memory One"
384393

385394
def __init__(self):
386-
team = [s for s in ordinary_strategies if Classifiers["memory_depth"](s()) <= 1]
395+
team = [
396+
s
397+
for s in ordinary_strategies
398+
if Classifiers["memory_depth"](s()) <= 1
399+
]
387400
super().__init__(team=team)
388401
self.classifier["long_run_time"] = False
389402

@@ -437,7 +450,9 @@ class MetaWinnerDeterministic(MetaWinner):
437450
name = "Meta Winner Deterministic"
438451

439452
def __init__(self):
440-
team = [s for s in ordinary_strategies if not Classifiers["stochastic"](s())]
453+
team = [
454+
s for s in ordinary_strategies if not Classifiers["stochastic"](s())
455+
]
441456
super().__init__(team=team)
442457
self.classifier["stochastic"] = False
443458

@@ -453,7 +468,9 @@ class MetaWinnerStochastic(MetaWinner):
453468
name = "Meta Winner Stochastic"
454469

455470
def __init__(self):
456-
team = [s for s in ordinary_strategies if Classifiers["stochastic"](s())]
471+
team = [
472+
s for s in ordinary_strategies if Classifiers["stochastic"](s())
473+
]
457474
super().__init__(team=team)
458475

459476

@@ -508,7 +525,9 @@ class NMWEDeterministic(NiceMetaWinnerEnsemble):
508525
name = "NMWE Deterministic"
509526

510527
def __init__(self):
511-
team = [s for s in ordinary_strategies if not Classifiers["stochastic"](s())]
528+
team = [
529+
s for s in ordinary_strategies if not Classifiers["stochastic"](s())
530+
]
512531
super().__init__(team=team)
513532
self.classifier["stochastic"] = True
514533

@@ -524,7 +543,9 @@ class NMWEStochastic(NiceMetaWinnerEnsemble):
524543
name = "NMWE Stochastic"
525544

526545
def __init__(self):
527-
team = [s for s in ordinary_strategies if Classifiers["stochastic"](s())]
546+
team = [
547+
s for s in ordinary_strategies if Classifiers["stochastic"](s())
548+
]
528549
super().__init__(team=team)
529550

530551

@@ -577,7 +598,11 @@ class NMWEMemoryOne(NiceMetaWinnerEnsemble):
577598
name = "NMWE Memory One"
578599

579600
def __init__(self):
580-
team = [s for s in ordinary_strategies if Classifiers["memory_depth"](s()) <= 1]
601+
team = [
602+
s
603+
for s in ordinary_strategies
604+
if Classifiers["memory_depth"](s()) <= 1
605+
]
581606
super().__init__(team=team)
582607
self.classifier["long_run_time"] = False
583608

‎axelrod/strategy_transformers.py

+33-12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from axelrod.strategies.sequence_player import SequencePlayer
1818
from .action import Action
19+
from .makes_use_of import method_makes_use_of
1920
from .player import Player
2021
from .random_ import random_choice
2122

@@ -27,7 +28,9 @@
2728
# Alternator.
2829

2930

30-
def StrategyTransformerFactory(strategy_wrapper, name_prefix=None, reclassifier=None):
31+
def StrategyTransformerFactory(
32+
strategy_wrapper, name_prefix=None, reclassifier=None
33+
):
3134
"""Modify an existing strategy dynamically by wrapping the strategy
3235
method with the argument `strategy_wrapper`.
3336
@@ -130,6 +133,11 @@ def strategy(self, opponent):
130133
classifier = reclassifier(original_classifier, *args, **kwargs)
131134
else:
132135
classifier = original_classifier
136+
strategy_wrapper_uses = method_makes_use_of(strategy_wrapper)
137+
if "makes_use_of" in classifier:
138+
classifier["makes_use_of"].update(strategy_wrapper_uses)
139+
elif strategy_wrapper_uses:
140+
classifier["makes_use_of"] = strategy_wrapper_uses
133141

134142
# Define the new __repr__ method to add the wrapper arguments
135143
# at the end of the name
@@ -232,7 +240,11 @@ class DecoratorReBuilder(object):
232240
"""
233241

234242
def __call__(
235-
self, factory_args: tuple, args: tuple, kwargs: dict, instance_name_prefix: str
243+
self,
244+
factory_args: tuple,
245+
args: tuple,
246+
kwargs: dict,
247+
instance_name_prefix: str,
236248
) -> Any:
237249

238250
decorator_class = StrategyTransformerFactory(*factory_args)
@@ -246,7 +258,9 @@ class StrategyReBuilder(object):
246258
that could not normally be pickled.
247259
"""
248260

249-
def __call__(self, decorators: list, import_name: str, module_name: str) -> Player:
261+
def __call__(
262+
self, decorators: list, import_name: str, module_name: str
263+
) -> Player:
250264

251265
module_ = import_module(module_name)
252266
import_class = getattr(module_, import_name)
@@ -275,7 +289,9 @@ def __call__(self, PlayerClass):
275289
return Composition()
276290

277291

278-
def generic_strategy_wrapper(player, opponent, proposed_action, *args, **kwargs):
292+
def generic_strategy_wrapper(
293+
player, opponent, proposed_action, *args, **kwargs
294+
):
279295
"""
280296
Strategy wrapper functions should be of the following form.
281297
@@ -307,7 +323,9 @@ def flip_wrapper(player, opponent, action):
307323
return action.flip()
308324

309325

310-
FlipTransformer = StrategyTransformerFactory(flip_wrapper, name_prefix="Flipped")
326+
FlipTransformer = StrategyTransformerFactory(
327+
flip_wrapper, name_prefix="Flipped"
328+
)
311329

312330

313331
def dual_wrapper(player, opponent: Player, proposed_action: Action) -> Action:
@@ -377,7 +395,9 @@ def forgiver_reclassifier(original_classifier, p):
377395

378396

379397
ForgiverTransformer = StrategyTransformerFactory(
380-
forgiver_wrapper, name_prefix="Forgiving", reclassifier=forgiver_reclassifier
398+
forgiver_wrapper,
399+
name_prefix="Forgiving",
400+
reclassifier=forgiver_reclassifier,
381401
)
382402

383403

@@ -442,7 +462,6 @@ def final_sequence(player, opponent, action, seq):
442462

443463
def final_reclassifier(original_classifier, seq):
444464
"""Reclassify the strategy"""
445-
original_classifier["makes_use_of"].update(["length"])
446465
original_classifier["memory_depth"] = max(
447466
len(seq), original_classifier["memory_depth"]
448467
)
@@ -495,14 +514,18 @@ def grudge_wrapper(player, opponent, action, grudges):
495514
return action
496515

497516

498-
GrudgeTransformer = StrategyTransformerFactory(grudge_wrapper, name_prefix="Grudging")
517+
GrudgeTransformer = StrategyTransformerFactory(
518+
grudge_wrapper, name_prefix="Grudging"
519+
)
499520

500521

501522
def apology_wrapper(player, opponent, action, myseq, opseq):
502523
length = len(myseq)
503524
if len(player.history) < length:
504525
return action
505-
if (myseq == player.history[-length:]) and (opseq == opponent.history[-length:]):
526+
if (myseq == player.history[-length:]) and (
527+
opseq == opponent.history[-length:]
528+
):
506529
return C
507530
return action
508531

@@ -535,9 +558,7 @@ def mixed_wrapper(player, opponent, action, probability, m_player):
535558
probability = [probability]
536559

537560
# If a probability distribution, players is passed
538-
if isinstance(probability, Iterable) and isinstance(
539-
m_player, Iterable
540-
):
561+
if isinstance(probability, Iterable) and isinstance(m_player, Iterable):
541562
mutate_prob = sum(probability) # Prob of mutation
542563
if mutate_prob > 0:
543564
# Distribution of choice of mutation:

‎test_outputs/classifier_test.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Cooperator:
2+
name: Cooperator
3+
Defector:
4+
name: Defector

0 commit comments

Comments
 (0)
Please sign in to comment.