"""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')