Source code for gameanalysis.script.learning

"""Analyze a game using gp learn"""
import argparse
import json
import sys

from gameanalysis import gameio
from gameanalysis import nash
from gameanalysis import regret
from gameanalysis import gpgame


[docs]def add_parser(subparsers): parser = subparsers.add_parser( 'learning', help="""Analyze game using learning""", description="""Perform game analysis""") parser.add_argument( '--input', '-i', metavar='<input-file>', default=sys.stdin, type=argparse.FileType('r'), help="""Input file for script. (default: stdin)""") parser.add_argument( '--output', '-o', metavar='<output-file>', default=sys.stdout, type=argparse.FileType('w'), help="""Output file for script. (default: stdout)""") parser.add_argument( '--dist-thresh', metavar='<distance-threshold>', type=float, default=1e-3, help="""L2 norm threshold, inside of which, equilibria are considered identical. (default: %(default)g)""") parser.add_argument( '--regret-thresh', '-r', metavar='<regret-threshold>', type=float, default=1e-3, help="""Maximum regret to consider an equilibrium confirmed. (default: %(default)g)""") parser.add_argument( '--supp-thresh', '-t', metavar='<support-threshold>', type=float, default=1e-3, help="""Maximum probability to consider a strategy in support. (default: %(default)g)""") parser.add_argument( '--rand-restarts', metavar='<random-restarts>', type=int, default=0, help="""The number of random points to add to nash equilibrium finding. (default: %(default)d)""") parser.add_argument( '--max-iters', '-m', metavar='<maximum-iterations>', type=int, default=10000, help="""The maximum number of iterations to run through replicator dynamics. (default: %(default)d)""") parser.add_argument( '--converge-thresh', '-c', metavar='<convergence-threshold>', type=float, default=1e-8, help="""The convergence threshold for replicator dynamics. (default: %(default)g)""") parser.add_argument( '--processes', '-p', metavar='<num-procs>', type=int, help="""Number of processes to use to run nash finding. (default: number of cores)""") parser.add_argument( '--one', action='store_true', help="""If specified, run a potentially expensive algorithm to guarantee an approximate equilibrium, if none are found via other methods.""") return parser
[docs]def main(args): game, serial = gameio.read_game(json.load(args.input)) # create gpgame lgame = gpgame.PointGPGame(game) # mixed strategy nash equilibria search methods = {'replicator': {'max_iters': args.max_iters, 'converge_thresh': args.converge_thresh}} mixed_equilibria = game.trim_mixture_support( nash.mixed_nash(lgame, regret_thresh=args.regret_thresh, dist_thresh=args.dist_thresh, processes=args.processes, at_least_one=args.one, **methods), args.supp_thresh) equilibria = [(eqm, regret.mixture_regret(lgame, eqm)) for eqm in mixed_equilibria] # Output game args.output.write('Game Learning\n') args.output.write('=============\n') args.output.write(serial.to_game_printstr(game)) args.output.write('\n\n') # Output social welfare args.output.write('Social Welfare\n') args.output.write('--------------\n') welfare, profile = regret.max_pure_social_welfare(game) args.output.write('\nMaximum social welfare profile:\n') args.output.write(serial.to_prof_printstr(profile)) args.output.write('Welfare: {:.4f}\n\n'.format(welfare)) if game.num_roles > 1: for role, welfare, profile in zip( serial.role_names, *regret.max_pure_social_welfare(game, True)): args.output.write('Maximum "{}" welfare profile:\n'.format( role)) args.output.write(serial.to_prof_printstr(profile)) args.output.write('Welfare: {:.4f}\n\n'.format(welfare)) args.output.write('\n') # Output Equilibria args.output.write('Equilibria\n') args.output.write('----------\n') if equilibria: args.output.write('Found {:d} equilibri{}\n\n'.format( len(equilibria), 'um' if len(equilibria) == 1 else 'a')) for i, (eqm, reg) in enumerate(equilibria, 1): args.output.write('Equilibrium {:d}:\n'.format(i)) args.output.write(serial.to_mix_printstr(eqm)) args.output.write('Regret: {:.4f}\n\n'.format(reg)) else: args.output.write('Found no equilibria\n\n') # pragma: no cover args.output.write('\n') # Output json data args.output.write('Json Data\n') args.output.write('=========\n') json_data = { 'equilibria': [serial.to_mix_json(eqm) for eqm, _ in equilibria]} json.dump(json_data, args.output) args.output.write('\n')