def test_mixed_profile_detection(self): self.assertFalse(RSG.is_profile_array(self.cliques.toProfile( \ self.cliques.uniformMixture()))) self.assertFalse(RSG.is_mixture_array(self.cliques.toProfile( \ self.cliques.uniformMixture()))) self.assertFalse(RSG.is_pure_profile(self.cliques.toProfile( \ self.cliques.uniformMixture()))) self.assertTrue(RSG.is_mixed_profile(self.cliques.toProfile( \ self.cliques.uniformMixture())))
def test_pure_profile_detection(self): self.assertFalse(RSG.is_profile_array(self.cliques.toProfile( \ self.cliques.counts[0]))) self.assertFalse(RSG.is_mixture_array(self.cliques.toProfile( \ self.cliques.counts[0]))) self.assertTrue(RSG.is_pure_profile(self.cliques.toProfile( \ self.cliques.counts[0]))) self.assertFalse(RSG.is_mixed_profile(self.cliques.toProfile( \ self.cliques.counts[0])))
def CPSD(game): """ conditional strict pure-strategy dominance criterion for IEDS The criterion is 'conditional' in that it will eliminate strategies that are dominated given all available data in a partial game. """ dominated = {r:set() for r in game.roles} for r in game.roles: for s1, s2 in RSG.product(game.strategies[r], repeat=2): if s1 == s2: continue for profile in game: v1 = v2 = float('-inf') try: v1 = game.getPayoff(profile, r, s1) except KeyError: continue try: v2 = game.getPayoff(profile.remove(r,s1).add(r,s2), r, s2) except KeyError: break if v1 >= v2: break if v1 < v2: dominated[r].add(s1) return game.subgame(strategies={r:set(game.strategies[r]) - dominated[r] \ for r in game.roles})
def RD(game, mixedProfile=None, array_data=None, iters=10000, thresh=1e-8, \ verbose=False): """ Replicator dynamics. """ if not mixedProfile: mixedProfile = game.uniformMixedProfile() if not array_data: array_data = [(prof.countArray(game), prof.valueArray(game), \ prof.repetitionsArray(game)) for prof in game] mix = mixedProfile.probArray(game) minPayoffs = np.zeros(mix.shape, dtype=float) for i,r in enumerate(game.roles): minPayoffs[:,i].fill(min(game.payoffList(r))) e = np.finfo(np.float64).tiny for i in range(iters): old_mix = mix EVs = sum([payoff_arr * (mix**count_arr).prod() * reps_arr / (mix+e) \ for count_arr, payoff_arr, reps_arr in array_data]) mix = (EVs - minPayoffs) * mix mix /= sum(mix) if max(abs(mix - old_mix).flat) <= thresh: break eq = RSG.Profile({r:RSG.SymmetricProfile([RSG.mixture(game.strategies[r],\ mix[:len(game.strategies[r]), i])]*game.counts[r]) for i,r in \ enumerate(game.roles)}) if verbose: print "iterations =", i, "...", eq, "... regret =", game.exactRegret(eq) return eq
def PSD(game): """ confirmed strict pure-strategy dominance criterion for IEDS This criterion differs from CPSD in that it will only declare a strategy dominated if all profiles in which both it and the dominating strategy appear have payoff data available. """ dominated = {r:set() for r in game.roles} for r in game.roles: for s1, s2 in RSG.product(game.strategies[r], repeat=2): if s1 == s2: continue data_missing = False for profile in game: v1 = v2 = float('-inf') try: v1 = game.getPayoff(profile, r, s1) v2 = game.getPayoff(profile.remove(r,s1).add(r,s2), r, s2) if v1 >= v2: break except KeyError: data_missing = True break if v1 < v2 and not data_missing: dominated[r].add(s1) return game.subgame(strategies={r:set(game.strategies[r]) - dominated[r] \ for r in game.roles})
if max(abs(mix - old_mix).flat) <= thresh: break eq = RSG.Profile({r:RSG.SymmetricProfile([RSG.mixture(game.strategies[r],\ mix[:len(game.strategies[r]), i])]*game.counts[r]) for i,r in \ enumerate(game.roles)}) if verbose: print "iterations =", i, "...", eq, "... regret =", game.exactRegret(eq) return eq from sys import argv from os.path import abspath from argparse import ArgumentParser if __name__ == "__main__": print "command: " + RSG.list_repr(argv, sep=" ") + "\n" parser = ArgumentParser() parser.add_argument("file", type=str, help="Game file to be analyzed. " +\ "Suported file types: EGAT symmetric XML, EGAT strategic XML, " +\ "testbed role-symmetric JSON.") parser.add_argument("-r", metavar="REGRET", type=float, default=0, \ help="Max allowed regret for approximate Nash equilibria") parser.add_argument("-d", metavar="DISTANCE", type=float, default=1e-2, \ help="L2-distance threshold to consider equilibria distinct") # parser.add_argument("--subgames", type=str, help="optinal files " +\ # "containing known full subgames; useful for speeding up " +\ # "clique-finding", default = "", nargs="*") args = parser.parse_args() input_game = GameIO.readGame(args.file) print "input game =", abspath(args.file), "\n", input_game, "\n\n"