def nearby_profs(self, prof, num_devs): """Returns profiles reachable by at most num_devs deviations""" # XXX this is the bottleneck for gpgame.neighbor_EVs. It seems like # there should be some clever way to speed it up. assert num_devs >= 0 dev_players = utils.acomb(self.num_roles, num_devs, True) mask = np.all(dev_players <= self.num_players, 1) dev_players = dev_players[mask] supp = prof > 0 sub = subgame.subgame(rsgame.BaseGame(self), supp) profs = [prof[None]] for players in dev_players: to_dev_profs = rsgame.BaseGame( players, self.num_strategies).all_profiles() from_dev_profs = subgame.translate( rsgame.BaseGame(players, sub.num_strategies).all_profiles(), supp) before_devs = prof - from_dev_profs before_devs = before_devs[np.all(before_devs >= 0, 1)] before_devs = utils.unique_axis(before_devs) nearby = before_devs[:, None] + to_dev_profs nearby.shape = (-1, self.num_role_strats) profs.append(utils.unique_axis(nearby)) profs = np.concatenate(profs) return utils.unique_axis(profs)
def test_elem_axis(): x = np.array([[5.4, 2.2], [5.7, 2.8], [9.6, 1.2]], float) assert np.all(x == utils.elem_to_axis(utils.axis_to_elem(x), float)) assert np.all(x.astype(int) == utils.elem_to_axis(utils.axis_to_elem(x.astype(int)), int)) assert utils.unique_axis(x).shape == (3, 2) array, counts = utils.unique_axis(x.astype(int), return_counts=True) assert array.shape == (2, 2) assert not np.setxor1d(counts, [2, 1]).size
def add_profiles(game, prob_or_count=1.0, distribution=default_distribution): """Add profiles to a base game Parameters ---------- distribution : (shape) -> ndarray, optional Distribution function to draw profiles from. prob_or_count : float or int, optional If a float, the probability to add a profile from the full game. If an int, the number of profiles to add. independent : bool, optional If true then each profile has `prob` probability of being added, else `num_all_profiles * prob` profiles will be kept. """ # First turn input into number of profiles to compute num_profs = game.num_all_profiles if isinstance(prob_or_count, float): assert 0 <= prob_or_count <= 1 if num_profs <= np.iinfo(int).max: num = rand.binomial(num_profs, prob_or_count) else: num = round(float(num_profs * prob_or_count)) else: assert 0 <= prob_or_count <= num_profs num = prob_or_count # Generate profiles based number and size of game # Ratio of the expected number of profiles we'd have to draw at random to # produce num unique relative to the number of total profiles ratio = sps.digamma(float(num_profs)) - sps.digamma(float(num_profs - num)) if num == num_profs: profiles = game.all_profiles() elif num == 0: profiles = np.empty((0, game.num_role_strats), int) elif ratio >= 1: inds = rand.choice(num_profs, num, replace=False) profiles = game.all_profiles()[inds] else: profiles = np.empty((0, game.num_role_strats), int) num_per = max(round(float(ratio * num_profs)), num) # Max => underflow mix = game.uniform_mixture() while profiles.shape[0] < num: profiles = np.concatenate([profiles, game.random_profiles(num_per, mix)]) profiles = utils.unique_axis(profiles) inds = rand.choice(profiles.shape[0], num, replace=False) profiles = profiles[inds] # Fill out game with profiles payoffs = np.zeros(profiles.shape) mask = profiles > 0 payoffs[mask] = distribution(mask.sum()) return rsgame.game_copy(game, profiles, payoffs, False)
def reduce_profiles(self, profiles, return_contributions=False): """Reduces a set of profiles If `return_contributions` returns ancillary information. Returns ------- red_profs The reduced profiles red_inds Index in red_profs for each payoff value that was reduced. full_inds Index into profiles for each payoff value that was reduced. strat_inds Index into a profile for the index of each payoff. Parallel with red_inds and full_inds. """ profiles = np.asarray(profiles, int) num_profs = profiles.shape[0] dev_profs = profiles[:, None] - np.eye(self.full_game.num_role_strats, dtype=int) dev_profs = np.reshape(dev_profs, (-1, self.full_game.num_role_strats)) dev_full_players = self._devs(self.full_game.num_players, num_profs) dev_red_players = self._devs(self.red_game.num_players, num_profs) mask = ~np.any(dev_profs < 0, 1) red_profs, reduced = _reduce_rsym_profiles( self.full_game, dev_profs[mask], dev_full_players[mask], dev_red_players[mask]) devs = np.eye(self.full_game.num_role_strats, dtype=int)[None]\ .repeat(num_profs, 0)\ .reshape((-1, self.full_game.num_role_strats))[mask][reduced] red_profs += devs red_profs, red_inds = utils.unique_axis(red_profs, return_inverse=True) if not return_contributions: return red_profs else: full_inds = np.arange(num_profs)[:, None].repeat( self.full_game.num_role_strats, 1).flat[mask][reduced] strat_inds = devs.nonzero()[1] return red_profs, red_inds, full_inds, strat_inds