def test_size_3_with_loops(self): g = graph.complete_graph(3, loops=True) self.assertEqual(g.vertices, [0, 1, 2]) edges = [(0, 1), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1), (0, 0), (1, 1), (2, 2)] self.assertEqual(g.edges, edges) self.assertEqual(g.directed, False)
def test_size_4_with_loops(self): g = graph.complete_graph(4, loops=True) self.assertEqual(g.vertices, [0, 1, 2, 3]) edges = [ (0, 1), (1, 0), (0, 2), (2, 0), (0, 3), (3, 0), (1, 2), (2, 1), (1, 3), (3, 1), (2, 3), (3, 2), (0, 0), (1, 1), (2, 2), (3, 3), ] self.assertEqual(g.edges, edges) self.assertEqual(g.directed, False) neighbors = range(4) for vertex in range(4): self.assertEqual(set(g.out_vertices(vertex)), set(neighbors)) self.assertEqual(set(g.in_vertices(vertex)), set(neighbors))
def test_size_4(self): g = graph.complete_graph(4, loops=False) self.assertEqual(g.vertices, [0, 1, 2, 3]) edges = [ (0, 1), (1, 0), (0, 2), (2, 0), (0, 3), (3, 0), (1, 2), (2, 1), (1, 3), (3, 1), (2, 3), (3, 2), ] self.assertEqual(g.edges, edges) self.assertEqual(g.directed, False) for vertex, neighbors in [ (0, (1, 2, 3)), (1, (0, 2, 3)), (2, (0, 1, 3)), (3, (0, 1, 2)), ]: self.assertEqual(set(g.out_vertices(vertex)), set(neighbors)) for vertex, neighbors in [ (0, (1, 2, 3)), (1, (0, 2, 3)), (2, (0, 1, 3)), (3, (0, 1, 2)), ]: self.assertEqual(set(g.in_vertices(vertex)), set(neighbors))
def test_size_2_with_loops(self): g = graph.complete_graph(2, loops=True) self.assertEqual(g.vertices, [0, 1]) self.assertEqual(g.edges, [(0, 1), (1, 0), (0, 0), (1, 1)]) self.assertEqual(g.directed, False)
def __init__(self, players: List[Player], turns: int = DEFAULT_TURNS, prob_end: float = None, noise: float = 0, game: Game = None, deterministic_cache: DeterministicCache = None, mutation_rate: float = 0.0, mode: str = "bd", interaction_graph: Graph = None, reproduction_graph: Graph = None, fitness_transformation: Callable = None, mutation_method="transition", stop_on_fixation=True, seed=None) -> None: """ An agent based Moran process class. In each round, each player plays a Match with each other player. Players are assigned a fitness score by their total score from all matches in the round. A player is chosen to reproduce proportionally to fitness, possibly mutated, and is cloned. The clone replaces a randomly chosen player. If the mutation_rate is 0, the population will eventually fixate on exactly one player type. In this case a StopIteration exception is raised and the play stops. If the mutation_rate is not zero, then the process will iterate indefinitely, so mp.play() will never exit, and you should use the class as an iterator instead. When a player mutates it chooses a random player type from the initial population. This is not the only method yet emulates the common method in the literature. It is possible to pass interaction graphs and reproduction graphs to the Moran process. In this case, in each round, each player plays a Match with each neighboring player according to the interaction graph. Players are assigned a fitness score by their total score from all matches in the round. A player is chosen to reproduce proportionally to fitness, possibly mutated, and is cloned. The clone replaces a randomly chosen neighboring player according to the reproduction graph. Parameters ---------- players turns: The number of turns in each pairwise interaction prob_end : The probability of a given turn ending a match noise: The background noise, if any. Randomly flips plays with probability `noise`. game: axelrod.Game The game object used to score matches. deterministic_cache: A optional prebuilt deterministic cache mutation_rate: The rate of mutation. Replicating players are mutated with probability `mutation_rate` mode: Birth-Death (bd) or Death-Birth (db) interaction_graph: Axelrod.graph.Graph The graph in which the replicators are arranged reproduction_graph: Axelrod.graph.Graph The reproduction graph, set equal to the interaction graph if not given fitness_transformation: A function mapping a score to a (non-negative) float mutation_method: A string indicating if the mutation method should be between original types ("transition") or based on the player's mutation method, if present ("atomic"). stop_on_fixation: A bool indicating if the process should stop on fixation seed: int A random seed for reproducibility """ m = mutation_method.lower() if m in ["atomic", "transition"]: self.mutation_method = m else: raise ValueError( "Invalid mutation method {}".format(mutation_method)) assert (mutation_rate >= 0) and (mutation_rate <= 1) assert (noise >= 0) and (noise <= 1) mode = mode.lower() assert mode in ["bd", "db"] self.mode = mode if deterministic_cache is not None: self.deterministic_cache = deterministic_cache else: self.deterministic_cache = DeterministicCache() self.turns = turns self.prob_end = prob_end self.game = game self.noise = noise self.initial_players = players # save initial population self.players = [] # type: List self.populations = [] # type: List self.score_history = [] # type: List self.winning_strategy_name = None # type: Optional[str] self.mutation_rate = mutation_rate self.stop_on_fixation = stop_on_fixation self._random = RandomGenerator(seed=seed) self._bulk_random = BulkRandomGenerator(self._random.random_seed_int()) self.set_players() # Build the set of mutation targets # Determine the number of unique types (players) keys = set([str(p) for p in players]) # Create a dictionary mapping each type to a set of representatives # of the other types d = dict() for p in players: d[str(p)] = p mutation_targets = dict() for key in sorted(keys): mutation_targets[key] = [ v for (k, v) in sorted(d.items()) if k != key ] self.mutation_targets = mutation_targets if interaction_graph is None: interaction_graph = complete_graph(len(players), loops=False) if reproduction_graph is None: reproduction_graph = Graph(interaction_graph.edges, directed=interaction_graph.directed) reproduction_graph.add_loops() # Check equal vertices v1 = interaction_graph.vertices v2 = reproduction_graph.vertices assert list(v1) == list(v2) self.interaction_graph = interaction_graph self.reproduction_graph = reproduction_graph self.fitness_transformation = fitness_transformation # Map players to graph vertices self.locations = sorted(interaction_graph.vertices) self.index = dict( zip(sorted(interaction_graph.vertices), range(len(players)))) self.fixated = self.fixation_check()