"""calculate bootstrap bounds on a sample game"""
import argparse
import json
import sys
import numpy as np
from gameanalysis import bootstrap
from gameanalysis import gameio
from gameanalysis import regret
from gameanalysis import scriptutils
CHOICES = {
'regret': (bootstrap.mixture_regret, regret.mixture_regret),
'surplus': (bootstrap.mixture_welfare, regret.mixed_social_welfare),
}
[docs]def add_parser(subparsers):
parser = subparsers.add_parser('sgboot', help="""Bootstrap on sample
games""", description="""Compute bootstrap
statistics using a sample game with data for every profile in the support of
the subgame and potentially deviations. The return value is a list with an
entry for each mixture in order. Each element is a dictionary mapping
percentile to value.""")
parser.add_argument('--input', '-i', metavar='<input-file>',
default=sys.stdin, type=argparse.FileType('r'),
help="""Input sample game to run bootstrap on.
(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('profiles', metavar='<profile>', nargs='+',
help="""File or string with profiles from input game
for which regrets should be calculated. This file can
be a list or a single profile""")
parser.add_argument('-t', '--type', default='regret', choices=CHOICES,
help="""What to return. regret - returns the regret of
each profile. surplus - returns the bootstrap surplus
of every profile. (default: %(default)s)""")
parser.add_argument('--processes', metavar='num-processes', type=int,
help="""The number of processes when constructing
bootstrap samples. Default will use all the cores
available.""")
parser.add_argument('--percentiles', '-p', metavar='percentile',
type=float, nargs='+', help="""Percentiles to return in
[0, 100]. By default all bootstrap values will be
returned sorted.""")
parser.add_argument('--num-bootstraps', '-n', metavar='num-bootstraps',
default=101, type=int, help="""The number of bootstrap
samples to acquire. More samples takes longer, but in general the percentiles
requested should be a multiple of this number minus 1, otherwise there will be
some error due to linear interpolation between points. (default:
%(default)s)""")
parser.add_argument('--mean', '-m', action='store_true', help="""Also
compute the mean statistic and return it as well. This
will be in each dictionary with the key 'mean'.""")
return parser
[docs]def main(args):
game, serial = gameio.read_samplegame(json.load(args.input))
profiles = np.concatenate([serial.from_prof_json(p)[None] for p
in scriptutils.load_profiles(args.profiles)])
bootf, meanf = CHOICES[args.type]
results = bootf(game, profiles, args.num_bootstraps, args.percentiles,
args.processes)
if args.percentiles is None:
args.percentiles = np.linspace(0, 100, args.num_bootstraps)
percentile_strings = [str(p).rstrip('0').rstrip('.')
for p in args.percentiles]
jresults = [{p: v.item() for p, v in zip(percentile_strings, boots)}
for boots in results]
if args.mean:
for jres, mix in zip(jresults, profiles):
jres['mean'] = meanf(game, mix)
json.dump(jresults, args.output)
args.output.write('\n')