Axelrod-Python/Axelrod

5.0.0 discussion -- Abstract base classes for players

Opened this issue · 11 comments

I've been working on a number of separate branches and problems and would like some feedback on a proposal before I sink a lot of time into it.

For the namespace reorganization for Axelrod (#1175) we need an abstract player class. A lot of the core functionality of the class can move out (cloning for example); the IPD class just needs to additionally track cooperations, defections, and the state distribution (or perhaps on a History class). To use the dojo on the ultimatum game we need resetting, cloning, and such as well.

For the new style of mutation for the dojo and Moran class (see the mutation branch), I think it makes sense to introduce an intermediate ABC that defines mutation and crossover methods. IIRC we needed the params classes in the dojo because Players couldn't be picked, however I think that's no longer the case, so all that functionality can (and I think should) move into the main library.

So I'd like to do the following:

  • introduce an ABC chain of Player --> MutablePlayer --> IPDPlayer (and soon UltimatumPlayer)
  • enhance the Moran process to handle the new style of mutation and move the functionality of the Params classes in the dojo to the main library
  • Release new versions of the main library and the dojo simultaneously
  • Start on 5.0.0 by reorganizing the namespace and then merge in the Ultimatum player code

Thoughts?

This all sounds very good.

  • introduce an ABC chain of Player --> MutablePlayer --> IPDPlayer (and soon UltimatumPlayer)

Could the MutablePlayer class not just be the base class? I suspect you've thought about this and there's a good reason, it's not immediately apparent to me.

  • Release new versions of the main library and the dojo simultaneously

For the axelrod library this would be on the master branch right?

however I think that's no longer the case, so all that functionality can (and I think should) move into the main library.

Is there merit in perhaps bringing the dojo in to the axelrod library itself? I'm generally more of a fan of keeping them separated but given the proposed changes it feels like they'll be much closer linked.

>>> axelrod.dojo.train # Or whatever?
  • Start on 5.0.0 by reorganizing the namespace and then merge in the Ultimatum player code

This would all be on the 5.0.0 branch right?

Mutable could be the base class I suppose. This would be on the master branch.

We may want to fold in the dojo once the rest of this is done. I hadn't thought about that yet.

Starting with the namespace reorg the changes would be on the 5.0.0 branch.

Sounds good to me @marcharper.

What was the intended difference between Player and MutablePlayer?

Mainly that most Players aren't naturally mutable. Some of the generic classes like LookerUp and the FSM player are, but the ones implemented from Axelrod's tournaments generally are not. One can imagine wanting to check if a player is mutable, which could be at the method class level or whether certain methods are implemented, or a new classifier entry.

Note for this one I went with EvolvablePlayer instead of MutablePlayer.

Creating an abstract player still needs to be done right? I would like to tackle this.

My thought is that we can call the abstract player AbstractPlayer, the current implementation FsmPlayer, and somewhere in init say that Player=FsmPlayer. This makes the change non-API breaking, and in a future change, we can make Player=AbstractPlayer.

Because this doesn't break API, dojo would be okay, and we can do the namespace re-org later.

For now, we can make everything work only with FsmPlayer, and start generalizing things piecemeal.

Does this make sense, and are you okay with me taking a stab at it?

I'm fine with you taking a stab at it. Let me record some thoughts here that may help.

One thing we should change for the IPD player, which is API breaking, is that the strategy method should only take the opponent's history as an argument (or a joint history class, if we wanted to make one). This makes the cheating strategies impossible since they rely on manipulating the opponent's code. We might optionally supply some unique ID for the player but that's typically not done in the standard game. However you can imagine a strategy that wants to accumulate knowledge from many matches, or to play many opponents simultaneously, so it's worth thinking about what that would look like.

Note also that in #1288 I'm moving the play function to Match (#1181 ). Basically the issue is that we have code in Player that doesn't belong there and won't generalize well. I'd expect properties like name, the need to clone a player, and so on to be generally needed, but game specifics like the number of cooperations belong elsewhere (and were moved to the History class). In the early days of the library we didn't setup a clean class hierarchy as the original goal was to try to reproduce R. Axelrod's tournaments, and the library morphed into quite a bit more. Even the Match class wasn't added until later on.

Some open questions on how to proceed to supporting new game types:

(1) Assuming we have new Player types for different games (see e.g. the ultimatum branch, which is a non-matrix game), can we design Match, Tournament, and MoranProcess to work generically without knowledge of the details of the game and how the players work?

(2) Can we reduce adding a new game to simply defining a new Game class (with a scoring function) and a new intermediate abstract player class? Perhaps also an optimized history class?

A first step perhaps is to try to separate the layers for IPD games so that we have a clean "plugin style" way of adding new games. I.e. we'd have an AbstractPlayer class, AbstractIPDPlayer as a descendant, and then IPD specifics like FSMPlayer as further descendants. It's worth thinking about where Evolvable Players should be in the hierarchy. Similarly we'd have an AbstractGame, IPDGame, UltimatumGame, etc. Hopefully we don't also need a Match and Tournament class for each game.

One thing we change do for the IPD player, which is API breaking

I can't think of a way to make backwards compatible. How do we roll out an API change? We can take both arguments for a while with a deprecation warning, maybe...

Actually as I think more about this, we may need to break API to support multiple players and to support different result sets...

or a joint history class, if we wanted to make one

I thought I saw that you made a History class, but it's not being passed in to strategies.

Note also that in #1288 I'm moving the play function to Match (#1181 ).

I will wait for that.

Some open questions on how to proceed to supporting new game types:

I think the question in both is: Do we derive Match, Tournament, MoranProcess, ... classes or do we just let things get passed in? (Maybe the Game class can store everything we need.) I won't try to answer that here.

A first step perhaps is to try to separate the layers for IPD games so that we have a clean "plugin style" way of adding new games.

Yea, this is what I'm thinking.

AbstractIPDPlayer as a descendant

I was thinking of calling this IPDPlayer (IpdPlayer?).

We can break the API, but it's best to make the breaking changes as a batch, and with a new major release version. I think we won't really know the best collection of classes until we work through some of the new game types.

We can break the API, but it's best to make the breaking changes as a batch, and with a new major release version.

Yeah, our previously discussed plan was to make all 5.0.0 PRs to a 5.0.0 branch and at some point in the future merge that in to master.