コード例 #1
0
ファイル: asyncgame.py プロジェクト: qiji00626/quiesce
def mix(agame0, agame1, prob):
    """Mix two async games"""
    utils.check(
        rsgame.empty_copy(agame0) == rsgame.empty_copy(agame1),
        "games must have identically structure",
    )
    return _MixedAsyncGame(agame0, agame1, prob)
コード例 #2
0
async def test_trace(game, sim_sched, tmpdir, red):
    """Test tracing"""
    conf_file = str(tmpdir.join("conf.json"))
    with open(conf_file, "w") as fil:
        json.dump(
            {
                "markup": "standard",
                "max_value": 1,
                "arrivals": "simple",
                "market": "call",
            },
            fil,
        )
    prof_data = str(tmpdir.join("data.json"))
    with stdout() as out, stderr() as err:
        assert await run(
            "trace",
            sim_sched + ",save:" + prof_data,
            sim_sched + ",conf:" + conf_file,
            *red
        ), err.getvalue()
    traces = json.loads(out.getvalue())
    verify_trace_json(game, traces)
    with open(prof_data) as fil:
        data = gamereader.load(fil)
    assert rsgame.empty_copy(game) == rsgame.empty_copy(data)
コード例 #3
0
ファイル: schedgame.py プロジェクト: tfeng90/quiesce
 def __init__(self, sched, red, red_players):
     super().__init__(sched.role_names, sched.strat_names,
                      sched.num_role_players)
     self._sched = sched
     self._rgame = rsgame.empty_copy(
         red.reduce_game(rsgame.empty_copy(self), red_players))
     self._red = red
     self._profiles = {}
コード例 #4
0
async def test_basic_profile_sample():
    """Test basic profile in sample game"""
    sgame = gamegen.samplegame([4, 3], [3, 4])
    profs = sgame.random_profiles(20)

    sched = gamesched.samplegamesched(sgame)
    assert rsgame.empty_copy(sched) == rsgame.empty_copy(sgame)
    paylist = await asyncio.gather(*[sched.sample_payoffs(p) for p in profs])
    pays = np.stack(paylist)
    assert np.allclose(pays[profs == 0], 0)
    assert str(sched) == repr(sgame)
コード例 #5
0
ファイル: test_script.py プロジェクト: tfeng90/quiesce
async def test_prof_data(game, game_sched, tmpdir):
    """Test game scheduler"""
    prof_file = str(tmpdir.join('profs.json'))
    with stdout() as out, stderr() as err:
        assert await run(
            'brute', game_sched + ',sample:,save:' + prof_file), err.getvalue()
        for eqm in json.loads(out.getvalue()):
            game.mixture_from_json(eqm['equilibrium'])
    with open(prof_file) as fil:
        prof_game = gamereader.load(fil)
    assert rsgame.empty_copy(game) == rsgame.empty_copy(prof_game)
コード例 #6
0
ファイル: schedgame.py プロジェクト: tfeng90/quiesce
 def _rprofs(self, rest):
     """Get the restricted profiles for a restriction"""
     return restrict.translate(
         self._red.expand_profiles(
             rsgame.empty_copy(self).restrict(rest),
             self._rgame.restrict(rest).all_profiles()),
         rest)
コード例 #7
0
ファイル: eosched.py プロジェクト: qiji00626/quiesce
    async def aopen(self):  # pylint: disable=too-many-locals
        """Open the eosched"""
        gu.check(not self._is_open, "already open")
        try:
            game = await self._api.get_game(self._game_id)
            obs = await game.get_observations()
            gu.check(
                rsgame.empty_copy(self._game) == rsgame.empty_json(obs),
                "egtaonline game didn't match specified game",
            )
            conf = dict(obs.get("configuration", ()) or ())
            profiles = obs.get("profiles", ()) or ()

            # Parse profiles
            num_profs = len(profiles)
            num_pays = 0
            for jprof in profiles:
                pid = jprof["id"]
                prof, spays = self._game.profsamplepay_from_json(jprof)
                spays.setflags(write=False)
                hprof = gu.hash_array(prof)
                pays = asyncio.Queue()
                num_spays = len(spays)
                num_pays += num_spays
                for pay in spays:
                    pays.put_nowait(pay)
                data = ([num_spays], [num_spays], [0], [pid], pays)
                self._profiles[hprof] = data
                self._prof_ids[pid] = data
            logging.info(
                "found %d existing profiles with %d payoffs in game %d",
                num_profs,
                num_pays,
                self._game_id,
            )

            # Create and start scheduler
            self._sched = await obs.create_generic_scheduler(
                "egta_" + eu.random_string(20),
                True,
                self._obs_memory,
                self._obs_time,
                self._simult_obs,
                1,
                conf,
            )
            logging.warning(
                "created scheduler %d for running simulations of game %d: "
                "https://%s/generic_schedulers/%d",
                self._sched["id"],
                self._game_id,
                self._api.domain,
                self._sched["id"],
            )
            self._fetcher = asyncio.ensure_future(self._fetch())
            self._is_open = True
        except Exception as ex:
            await self.aclose()
            raise ex
        return self
コード例 #8
0
ファイル: eosched.py プロジェクト: qiji00626/quiesce
    def __init__(  # pylint: disable=too-many-arguments
        self,
        game,
        api,
        game_id,
        sleep_time,
        simultaneous_obs,
        max_scheduled,
        obs_memory,
        obs_time,
    ):
        super().__init__(game.role_names, game.strat_names,
                         game.num_role_players)
        self._api = api
        self._game = paygame.samplegame_copy(rsgame.empty_copy(game))
        self._game_id = game_id

        self._sleep_time = sleep_time
        self._obs_memory = obs_memory
        self._obs_time = obs_time
        self._simult_obs = simultaneous_obs

        self._is_open = False
        self._profiles = {}
        self._prof_ids = {}
        self._sched = None
        self._fetcher = None
        self._sched_lock = asyncio.Lock()
        self._scheduled = asyncio.BoundedSemaphore(max_scheduled *
                                                   simultaneous_obs)
コード例 #9
0
ファイル: learning.py プロジェクト: egtaonline/GameAnalysis
    def restrict(self, restriction):
        restriction = np.asarray(restriction, bool)
        base = rsgame.empty_copy(self).restrict(restriction)

        size_mask = restriction.repeat(self._sizes)
        sizes = self._sizes[restriction]
        profiles = self._profiles[size_mask]
        lengths = self._lengths[restriction]
        zeros = (profiles[:, ~restriction] /
                 lengths[:, ~restriction].repeat(sizes, 0))
        removed = np.exp(-np.einsum('ij,ij->i', zeros, zeros) / 2) # pylint: disable=invalid-unary-operand-type
        uprofs, inds = np.unique(
            recfunctions.merge_arrays([
                np.arange(restriction.sum()).repeat(sizes).view([('s', int)]),
                utils.axis_to_elem(profiles[:, restriction])], flatten=True),
            return_inverse=True)
        new_alpha = np.bincount(inds, removed * self._alpha[size_mask])
        new_sizes = np.diff(np.concatenate([
            [-1], np.flatnonzero(np.diff(uprofs['s'])),
            [new_alpha.size - 1]]))

        return _RbfGpGame(
            base.role_names, base.strat_names, base.num_role_players,
            self._offset[restriction], self._coefs[restriction],
            lengths[:, restriction], new_sizes, uprofs['axis'], new_alpha)
コード例 #10
0
 def __init__(self, sched):
     super().__init__(sched.role_names, sched.strat_names,
                      sched.num_role_players)
     self._sched = sched
     self._game = paygame.samplegame_copy(rsgame.empty_copy(self))
     self._profiles = []
     self._payoffs = []
コード例 #11
0
ファイル: test_asyncgame.py プロジェクト: qiji00626/quiesce
async def test_basic_asyncgame():
    """Test that wrapped async games work"""
    game = gamegen.game([4, 3], [3, 4])
    agame = asyncgame.wrap(game)
    rest = agame.random_restriction()
    rgame = await agame.get_restricted_game(rest)
    assert rgame.is_complete()
    assert rsgame.empty_copy(rgame) == rsgame.empty_copy(game.restrict(rest))

    dgame = await agame.get_deviation_game(rest)
    mix = restrict.translate(rgame.random_mixture(), rest)
    assert not np.isnan(dgame.deviation_payoffs(mix)).any()

    dup = asyncgame.wrap(game)
    assert hash(dup) == hash(agame)
    assert dup == agame
コード例 #12
0
    def restrict(self, restriction):
        restriction = np.asarray(restriction, bool)
        base = rsgame.empty_copy(self).restrict(restriction)

        size_mask = restriction.repeat(self._sizes)
        sizes = self._sizes[restriction]
        profiles = self._profiles[size_mask]
        lengths = self._lengths[restriction]
        zeros = (profiles[:, ~restriction] /
                 lengths[:, ~restriction].repeat(sizes, 0))
        removed = np.exp(-np.einsum('ij,ij->i', zeros, zeros) / 2)  # pylint: disable=invalid-unary-operand-type
        uprofs, inds = np.unique(recfunctions.merge_arrays([
            np.arange(restriction.sum()).repeat(sizes).view([('s', int)]),
            utils.axis_to_elem(profiles[:, restriction])
        ],
                                                           flatten=True),
                                 return_inverse=True)
        new_alpha = np.bincount(inds, removed * self._alpha[size_mask])
        new_sizes = np.diff(
            np.concatenate([[-1],
                            np.flatnonzero(np.diff(uprofs['s'])),
                            [new_alpha.size - 1]]))

        return _RbfGpGame(base.role_names, base.strat_names,
                          base.num_role_players, self._offset[restriction],
                          self._coefs[restriction], lengths[:, restriction],
                          new_sizes, uprofs['axis'], new_alpha)
コード例 #13
0
async def test_basic_profile(_):
    """Test that profiles are saved"""
    sgame = gamegen.samplegame([4, 3], [3, 4], 0)
    profs = sgame.all_profiles()

    basesched = gamesched.samplegamesched(sgame)
    sched = savesched.savesched(basesched)
    assert str(sched) == str(basesched)
    assert rsgame.empty_copy(sgame) == rsgame.empty_copy(sched)
    await asyncio.gather(*[sched.sample_payoffs(p) for p in profs[:10]])
    sched.get_game()

    sched = savesched.savesched(gamesched.samplegamesched(sgame))
    await asyncio.gather(*[sched.sample_payoffs(p) for p in profs])
    savegame = sched.get_game()
    assert sgame == savegame
    assert sgame == sched.get_game()
コード例 #14
0
 def restrict(self, restriction):
     base = rsgame.empty_copy(self).restrict(restriction)
     new_rest = self._rest.copy()
     new_rest[new_rest] = restriction
     regs = tuple(reg for reg, m in zip(self._regressors, restriction) if m)
     return _DevRegressionGame(base, regs, self._offset[restriction],
                               self._scale[restriction],
                               self._min_payoffs[restriction],
                               self._max_payoffs[restriction], new_rest)
コード例 #15
0
ファイル: learning.py プロジェクト: egtaonline/GameAnalysis
 def restrict(self, restriction):
     base = rsgame.empty_copy(self).restrict(restriction)
     new_rest = self._rest.copy()
     new_rest[new_rest] = restriction
     regs = tuple(reg for reg, m in zip(self._regressors, restriction) if m)
     return _DevRegressionGame(
         base, regs, self._offset[restriction], self._scale[restriction],
         self._min_payoffs[restriction], self._max_payoffs[restriction],
         new_rest)
コード例 #16
0
 def restrict(self, restriction):
     restriction = np.asarray(restriction, bool)
     base = rsgame.empty_copy(self).restrict(restriction)
     action_weights = self.action_weights[:, restriction]
     func_mask = np.any(~np.isclose(action_weights, 0), 1)
     return _AgfnGame(base.role_names, base.strat_names,
                      base.num_role_players, action_weights[func_mask],
                      self.function_inputs[:, func_mask][restriction],
                      self.function_table[func_mask],
                      self.offsets[restriction])
コード例 #17
0
def test_random_game_addition(strats):
    """Test random addition"""
    mpayoffs = rand.random(tuple(strats) + (len(strats),))
    matg = matgame.matgame(mpayoffs)
    payoffs = rand.random(matg.payoffs().shape)
    payoffs[matg.profiles() == 0] = 0
    game = paygame.game_replace(matg, matg.profiles(), payoffs)
    assert paygame.game_copy(matg + game) == game + matg

    empty = rsgame.empty_copy(matg)
    assert matg + empty == empty
コード例 #18
0
ファイル: test_script.py プロジェクト: tfeng90/quiesce
async def test_trace(game, sim_sched, tmpdir, red):
    """Test tracing"""
    conf_file = str(tmpdir.join('conf.json'))
    with open(conf_file, 'w') as fil:
        json.dump({
            'markup': 'standard',
            'max_value': 1,
            'arrivals': 'simple',
            'market': 'call',
        }, fil)
    prof_data = str(tmpdir.join('data.json'))
    with stdout() as out, stderr() as err:
        assert await run(
            'trace', sim_sched + ',save:' + prof_data, sim_sched + ',conf:' +
            conf_file, *red), err.getvalue()
    traces = json.loads(out.getvalue())
    verify_trace_json(game, traces)
    with open(prof_data) as fil:
        data = gamereader.load(fil)
    assert rsgame.empty_copy(game) == rsgame.empty_copy(data)
コード例 #19
0
ファイル: test_asyncgame.py プロジェクト: qiji00626/quiesce
async def test_mix_asyncgame():
    """Test that that mixture async games work"""
    game0 = gamegen.game([4, 3], [3, 4])
    game1 = gamegen.game([4, 3], [3, 4])
    agame = asyncgame.mix(asyncgame.wrap(game0), asyncgame.wrap(game1), 0.4)
    assert agame.get_game() == rsgame.mix(game0, game1, 0.4)
    assert str(agame) == "{} - 0.4 - {}".format(repr(game0), repr(game1))

    rest = agame.random_restriction()
    rgame = await agame.get_restricted_game(rest)
    assert rgame.is_complete()
    assert rsgame.empty_copy(rgame) == rsgame.empty_copy(game0.restrict(rest))

    dgame = await agame.get_deviation_game(rest)
    mix = restrict.translate(rgame.random_mixture(), rest)
    assert not np.isnan(dgame.deviation_payoffs(mix)).any()

    dup = asyncgame.mix(asyncgame.wrap(game0), asyncgame.wrap(game1), 0.4)
    assert hash(dup) == hash(agame)
    assert dup == agame
コード例 #20
0
def test_random_game_addition(strats):
    """Test random addition"""
    mpayoffs = rand.random(tuple(strats) + (len(strats), ))
    matg = matgame.matgame(mpayoffs)
    payoffs = rand.random(matg.payoffs().shape)
    payoffs[matg.profiles() == 0] = 0
    game = paygame.game_replace(matg, matg.profiles(), payoffs)
    assert paygame.game_copy(matg + game) == game + matg

    empty = rsgame.empty_copy(matg)
    assert matg + empty == empty
コード例 #21
0
ファイル: test_simsched.py プロジェクト: qiji00626/quiesce
async def test_basic_profile(conf, game):
    """Test sampling a basic profile"""
    profs = game.random_profiles(20)
    cmd = ["python3", "cdasim/sim.py", "--single", "1"]

    async with simsched.simsched(game, conf, cmd) as sched:
        assert str(sched) == "python3 cdasim/sim.py --single 1"
        assert rsgame.empty_copy(sched) == game
        awaited = await asyncio.gather(
            *[sched.sample_payoffs(p) for p in profs])
    pays = np.stack(awaited)
    assert pays.shape == profs.shape
    assert np.allclose(pays[profs == 0], 0)
    assert np.any(pays != 0)
コード例 #22
0
ファイル: test_eosched.py プロジェクト: qiji00626/quiesce
async def test_basic_profile(game):
    """Test scheduling a standard profile"""
    async with mockserver.server() as server, api.api() as egta:
        sim = await egta.get_simulator(
            server.create_simulator("sim",
                                    "1",
                                    delay_dist=lambda: random.random() / 10))
        strats = dict(zip(game.role_names, game.strat_names))
        symgrps = list(
            zip(game.role_names, game.num_role_players, game.strat_names))
        await sim.add_strategies(strats)
        egame = await egta.get_canon_game(sim["id"], symgrps)

        profs = game.random_profiles(20)

        # Schedule all new profiles and verify it works
        async with eosched.eosched(game, egta, egame["id"], 0.1, 1, 10, 0,
                                   0) as sched:
            assert str(sched) == str(egame["id"])
            assert game == rsgame.empty_copy(sched)
            awaited = await asyncio.gather(
                *[sched.sample_payoffs(p) for p in profs])
        pays = np.stack(awaited)
        assert np.allclose(pays[profs == 0], 0)

        # Schedule old profiles and verify it still works
        async with eosched.eosched(game, egta, egame["id"], 0.1, 1, 10, 0,
                                   0) as sched:
            awaited = await asyncio.gather(
                *[sched.sample_payoffs(p) for p in profs])
        pays = np.stack(awaited)
        assert np.allclose(pays[profs == 0], 0)

        # Schedule two at a time, in two batches
        async with eosched.eosched(game, egta, egame["id"], 0.1, 2, 10, 0,
                                   0) as base_sched:
            sched = countsched.countsched(base_sched, 2)
            awaited = await asyncio.gather(
                *[sched.sample_payoffs(p) for p in profs])
        pays = np.stack(awaited)
        assert np.allclose(pays[profs == 0], 0)

        # Try again now that everything should be scheduled
        async with eosched.eosched(game, egta, egame["id"], 0.1, 2, 10, 0,
                                   0) as base_sched:
            sched = countsched.countsched(base_sched, 2)
            awaited = await asyncio.gather(
                *[sched.sample_payoffs(p) for p in profs])
        pays = np.stack(awaited)
        assert np.allclose(pays[profs == 0], 0)
コード例 #23
0
async def test_no_conf(game):
    """Test scheduler without a configuration"""
    profs = game.random_profiles(20)
    zipf = "cdasim/cdasim.zip"

    with zipsched.zipsched(game, {}, zipf) as sched:
        assert rsgame.empty_copy(sched) == game
        awaited = await asyncio.gather(
            *[sched.sample_payoffs(p) for p in profs])

    pays = np.stack(awaited)
    assert pays.shape == profs.shape
    assert np.allclose(pays[profs == 0], 0)
    assert np.any(pays != 0)
コード例 #24
0
async def test_basic_profile(conf, game):
    """Test scheduling a basic profile"""
    profs = game.random_profiles(20)
    zipf = "cdasim/cdasim.zip"

    with zipsched.zipsched(game, conf, zipf) as sched:
        assert str(sched) is not None
        assert rsgame.empty_copy(sched) == game
        awaited = await asyncio.gather(
            *[sched.sample_payoffs(p) for p in profs])

    pays = np.stack(awaited)
    assert pays.shape == profs.shape
    assert np.allclose(pays[profs == 0], 0)
    assert np.any(pays != 0)
コード例 #25
0
ファイル: zipsched.py プロジェクト: qiji00626/quiesce
    def __init__(self, game, conf, zipf, *, max_procs=4, simultaneous_obs=1):
        super().__init__(game.role_names, game.strat_names,
                         game.num_role_players)
        self._game = paygame.game_copy(rsgame.empty_copy(game))
        self.conf = conf
        self.zipf = zipf

        self._extra_profs = {}
        self._base = {}
        self._count = simultaneous_obs
        self._is_open = False
        self._sim_dir = None
        self._prof_dir = None
        self._sim_root = None

        self._num = 0
        self._procs = asyncio.Semaphore(max_procs)
コード例 #26
0
ファイル: simsched.py プロジェクト: qiji00626/quiesce
    def __init__(self, game, config, command, buff_size=65536):
        super().__init__(game.role_names, game.strat_names,
                         game.num_role_players)
        self._game = paygame.game_copy(rsgame.empty_copy(game))
        self._base = {"configuration": config}
        self.command = command
        self.buff_size = buff_size

        self._is_open = False
        self._proc = None
        self._reader = None
        self._read_queue = asyncio.Queue()
        self._write_lock = asyncio.Lock()
        self._buffer_empty = asyncio.Event()
        self._buffer_bytes = 0
        self._line_bytes = collections.deque()

        self._buffer_empty.set()
コード例 #27
0
def test_neighbor():  # pylint: disable=too-many-locals
    """Test neighbor games"""
    game = gamegen.sparse_game([2, 3], [3, 2], 10)
    model = gp.GaussianProcessRegressor(1.0 * gp.kernels.RBF(2, [1, 3]) +
                                        gp.kernels.WhiteKernel(1),
                                        normalize_y=True)
    learn = learning.neighbor(learning.sklgame_train(game, model))
    full = paygame.game_copy(learn)

    errors = np.zeros(game.num_strats)
    for i, mix in enumerate(
            itertools.chain(game.random_mixtures(20),
                            game.random_sparse_mixtures(20)), 1):
        tdev = full.deviation_payoffs(mix)
        dev, _ = learn.deviation_payoffs(mix, jacobian=True)
        err = (tdev - dev)**2 / (np.abs(dev) + 1e-5)
        errors += (err - errors) / i
    assert np.all(errors < 5)

    submask = game.random_restriction()
    sublearn = learn.restrict(submask)
    subfull = full.restrict(submask)
    assert np.allclose(sublearn.get_payoffs(subfull.profiles()),
                       subfull.payoffs())

    norm = learn.normalize()
    assert np.allclose(norm.min_role_payoffs(), 0)
    assert np.allclose(norm.max_role_payoffs(), 1)

    assert learning.neighbor(learn, learn.num_neighbors) == learn

    learn = learning.neighbor(learning.rbfgame_train(game))
    jgame = json.dumps(learn.to_json())
    copy = learning.neighbor_json(json.loads(jgame))
    assert hash(copy) == hash(learn)
    assert copy == learn
    assert learn + copy == copy + learn

    empty = rsgame.empty_copy(learn)
    assert learn + empty == empty
コード例 #28
0
def main(args):
    """Sample objects entry point"""
    game = rsgame.empty_copy(gamereader.load(args.input))
    if args.seed is not None:
        # Python hash is randomly salted, so we use this to guarantee
        # determinism
        np.random.seed(int(
            hashlib.sha256(args.seed.encode('utf8')).hexdigest()[:8], 16))

    if args.types in RESTS:
        objs = (game.restriction_to_json(rest) for rest
                in game.random_restrictions(
                    args.num, strat_prob=args.prob,
                    normalize=args.unnormalize))

    elif args.types in MIXES:
        if args.sparse is _NOSPARSE:
            mix = game.random_mixtures(args.num, alpha=args.alpha)
        else:
            mix = game.random_sparse_mixtures(args.num, alpha=args.alpha,
                                              support_prob=args.sparse)
        objs = (game.mixture_to_json(m) for m in mix)

    elif args.types in PROFS:  # pragma: no branch
        if args.mix is None:
            prof = game.round_mixture_to_profile(
                game.random_mixtures(args.num, alpha=args.alpha))
        else:
            mix = game.mixture_from_json(json.load(args.mix))
            prof = game.random_profiles(args.num, mix)
        objs = (game.profile_to_json(p) for p in prof)

    # We sort the keys when a seed is set to guarantee identical output.  This
    # technically shouldn't be necessary, but on the off chance that a
    # simulator depends on the order, we want to make sure we produce identical
    # results.
    for obj in objs:
        json.dump(obj, args.output, sort_keys=args.seed is not None)
        args.output.write('\n')
コード例 #29
0
def test_missing_data_maximal_restrictions(base, prob):
    """Test missing data"""
    game = gamegen.game_replace(base, prob)
    rests = restrict.maximal_restrictions(game)

    if rests.size:
        maximal = np.all(rests <= rests[:, None], -1)
        np.fill_diagonal(maximal, False)
        assert not maximal.any(), \
            'One maximal restriction dominated another'

    for rest in rests:
        rgame = rsgame.empty_copy(game).restrict(rest)
        restprofs = restrict.translate(rgame.all_profiles(), rest)
        assert all(p in game for p in restprofs), \
            "Maximal restriction didn't have all profiles"
        for dev in np.nonzero(~rest)[0]:
            devprofs = restrict.additional_strategy_profiles(
                game, rest, dev)
            assert not all(p in game for p in devprofs), (  # pragma: no branch
                'Maximal restriction could be bigger {} {}'.format(
                    dev, rest))
コード例 #30
0
ファイル: dominance.py プロジェクト: egtaonline/GameAnalysis
def iterated_elimination(game, criterion, *, conditional=True):
    """Return a restriction resulting from iterated elimination of strategies

    Parameters
    ----------
    game : Game
        The game to run iterated elimination on
    criterion : {'weakdom', 'strictdom', 'neverbr'}
        The criterion to use to eliminated strategies.
    conditional : bool
        Whether to use conditional criteria. In general, conditional set to
        true will assume that unobserved payoffs are large. See the other
        methods for a more detailed explanation
    """
    # There's a few recomputed things that could be passed to save computation
    # time, but they're minimal and probably not that important
    cfunc = _CRITERIA[criterion]

    egame = rsgame.empty_copy(game)
    gains = _gains(game)
    supports = game.profiles() > 0

    rest = np.ones(game.num_strats, bool)
    mask = ~cfunc(egame, gains, supports, conditional)
    while (not np.all(mask) and np.any(np.add.reduceat(
            mask, egame.role_starts) > 1)):
        rest[rest] = mask
        prof_mask = ~np.any(supports & ~mask, -1)
        to_in_mask = mask[egame.dev_to_indices]
        from_in_mask = mask[egame.dev_from_indices]

        egame = egame.restrict(mask)
        gains = gains[prof_mask][:, to_in_mask & from_in_mask]
        supports = supports[prof_mask][:, mask]
        mask = ~cfunc(egame, gains, supports, conditional)

    rest[rest] = mask
    return rest
コード例 #31
0
def iterated_elimination(game, criterion, *, conditional=True):
    """Return a restriction resulting from iterated elimination of strategies

    Parameters
    ----------
    game : Game
        The game to run iterated elimination on
    criterion : {'weakdom', 'strictdom', 'neverbr'}
        The criterion to use to eliminated strategies.
    conditional : bool
        Whether to use conditional criteria. In general, conditional set to
        true will assume that unobserved payoffs are large. See the other
        methods for a more detailed explanation
    """
    # There's a few recomputed things that could be passed to save computation
    # time, but they're minimal and probably not that important
    cfunc = _CRITERIA[criterion]

    egame = rsgame.empty_copy(game)
    gains = _gains(game)
    supports = game.profiles() > 0

    rest = np.ones(game.num_strats, bool)
    mask = ~cfunc(egame, gains, supports, conditional)
    while (not np.all(mask)
           and np.any(np.add.reduceat(mask, egame.role_starts) > 1)):
        rest[rest] = mask
        prof_mask = ~np.any(supports & ~mask, -1)
        to_in_mask = mask[egame.dev_to_indices]
        from_in_mask = mask[egame.dev_from_indices]

        egame = egame.restrict(mask)
        gains = gains[prof_mask][:, to_in_mask & from_in_mask]
        supports = supports[prof_mask][:, mask]
        mask = ~cfunc(egame, gains, supports, conditional)

    rest[rest] = mask
    return rest
コード例 #32
0
 def restrict(self, restriction):
     base = rsgame.empty_copy(self).restrict(restriction)
     matrix = self._payoff_matrix
     for i, mask in enumerate(np.split(restriction, self.role_starts[1:])):
         matrix = matrix[(slice(None),) * i + (mask,)]
     return _MatrixGame(base.role_names, base.strat_names, matrix.copy())
コード例 #33
0
def trace_equilibrium(  # pylint: disable=too-many-locals
        game0,
        game1,
        peq,
        eqm,
        target,
        *,
        regret_thresh=1e-3,
        max_step=0.1,
        singular=1e-7,
        **ivp_args):
    """Try to trace an equilibrium out to target

    Takes two games, a fraction that they're mixed (`peq`), and an equilibrium
    of the mixed game (`eqm`). It then attempts to find the equilibrium at the
    `target` mixture. It may not reach target, but will return as far as it
    got. The return value is two parallel arrays for the probabilities with
    known equilibria and the equilibria.

    Parameters
    ----------
    game0 : RsGame
        The first game that's merged. Represents the payoffs when `peq` is 0.
    game1 : RsGame
        The second game that's merged. Represents the payoffs when `peq` is 1.
    peq : float
        The amount that the two games are merged such that `eqm` is an
        equilibrium. Must be in [0, 1].
    eqm : ndarray
        An equilibrium when `game0` and `game1` are merged a `peq` fraction.
    target : float
        The desired mixture probability to have an equilibrium at.
    regret_thresh : float, optional
        The amount of gain from deviating to a strategy outside support can
        have before it's considered a beneficial deviation and the tracing
        stops. This should be larger than zero as most equilibria are
        approximate due to floating point precision.
    max_step : float, optional
        The maximum step to take in t when evaluating.
    singular : float, optional
        An absolute determinant below this value is considered singular.
        Occasionally the derivative doesn't exist, and this is one way in which
        that manifests. This values regulate when ODE solving terminates due to
        a singular matrix.
    ivp_args
        Any remaining keyword arguments are passed to the ivp solver.
    """
    egame = rsgame.empty_copy(game0)
    eqm = np.asarray(eqm, float)
    utils.check(egame.is_mixture(eqm), "equilibrium wasn't a valid mixture")
    utils.check(
        regret.mixture_regret(rsgame.mix(game0, game1, peq), eqm) <=
        regret_thresh + 1e-7, "equilibrium didn't have regret below threshold")
    ivp_args.update(max_step=max_step)

    # It may be handy to have the derivative of this so that the ode solver can
    # be more efficient, except that computing the derivative w.r.t. t requires
    # the hessian of the deviation payoffs, which would be complicated and so
    # far has no use anywhere else.
    def ode(prob, mix_neg):
        """ODE function for solve_ivp"""
        div = np.zeros(egame.num_strats)
        mix = egame.trim_mixture_support(mix_neg, thresh=0)
        supp = mix > 0
        rgame = egame.restrict(supp)

        dev1, jac1 = game0.deviation_payoffs(mix, jacobian=True)
        dev2, jac2 = game1.deviation_payoffs(mix, jacobian=True)

        gvals = (dev1 - dev2)[supp]
        fvecs = ((1 - prob) * jac1 + prob * jac2)[supp][:, supp]

        gvec = np.concatenate([
            np.delete(np.diff(gvals), rgame.role_starts[1:] - 1),
            np.zeros(egame.num_roles)
        ])
        fmat = np.concatenate([
            np.delete(np.diff(fvecs, 1, 0), rgame.role_starts[1:] - 1, 0),
            np.eye(egame.num_roles).repeat(rgame.num_role_strats, 1)
        ])
        if singular < np.abs(np.linalg.det(fmat)):
            div[supp] = np.linalg.solve(fmat, gvec)
        return div

    def below_regret_thresh(prob, mix_neg):
        """Event for regret going above threshold"""
        mix = egame.trim_mixture_support(mix_neg, thresh=0)
        reg = regret.mixture_regret(rsgame.mix(game0, game1, prob), mix)
        return reg - regret_thresh

    below_regret_thresh.terminal = True
    below_regret_thresh.direction = 1

    def singular_jacobian(prob, mix_neg):
        """Event for when jacobian is singular"""
        mix = egame.trim_mixture_support(mix_neg, thresh=0)
        supp = mix > 0
        rgame = egame.restrict(supp)
        _, jac1 = game0.deviation_payoffs(mix, jacobian=True)
        _, jac2 = game1.deviation_payoffs(mix, jacobian=True)
        fvecs = ((1 - prob) * jac1 + prob * jac2)[supp][:, supp]
        fmat = np.concatenate([
            np.delete(np.diff(fvecs, 1, 0), rgame.role_starts[1:] - 1, 0),
            np.eye(egame.num_roles).repeat(rgame.num_role_strats, 1)
        ])
        return np.abs(np.linalg.det(fmat)) - singular

    singular_jacobian.terminal = True
    singular_jacobian.direction = -1

    events = [below_regret_thresh, singular_jacobian]

    # This is to scope the index
    def create_support_loss(ind):
        """Create support loss for every ind"""
        def support_loss(_, mix):
            """Support loss event"""
            return mix[ind]

        support_loss.direction = -1
        return support_loss

    for strat in range(egame.num_strats):
        events.append(create_support_loss(strat))

    with np.errstate(divide='ignore'):
        res = integrate.solve_ivp(ode, [peq, target],
                                  eqm,
                                  events=events,
                                  **ivp_args)
    return res.t, egame.trim_mixture_support(res.y.T, thresh=0)
コード例 #34
0
ファイル: conv.py プロジェクト: egtaonline/GameAnalysis
import sys

from gameanalysis import gambit
from gameanalysis import gamereader
from gameanalysis import matgame
from gameanalysis import paygame
from gameanalysis import rsgame


_TYPES = {
    'emptygame': (
        ['empty'], 'Strip payoff data', """Strip all payoff data from a game
        and return only its base structure---role and strategy names and player
        counts.""",
        lambda game, out: json.dump(
            rsgame.empty_copy(game).to_json(), out)),
    'game': (
        [], 'Sparse payoff format', """Convert a game to a sparse mapping of
        profiles to their corresponding payoff data.""",
        lambda game, out: json.dump(
            paygame.game_copy(game).to_json(), out)),
    'samplegame': (
        ['samp'], 'Multiple payoffs per profile', """Convert a game to a format
        with a sparse mapping of profiles to potentially several samples of
        payoff data. There should be little reason to convert a non-samplegame
        to a samplegame as all profiles will have exactly one sample.""",
        lambda game, out: json.dump(
            paygame.samplegame_copy(game).to_json(), out)),
    'matgame': (
        ['mat'], 'Asymmetric format', """Convert a game to a compact
        representation for asymmetric games. If the input game is not
コード例 #35
0
ファイル: trace.py プロジェクト: tfeng90/quiesce
async def trace_all_equilibria(  # pylint: disable=too-many-locals
        agame0,
        agame1,
        *,
        regret_thresh=1e-3,
        dist_thresh=0.1,
        max_step=0.1,
        executor=None,
        **innerloop_args):
    """Trace out all equilibria between all games

    Parameters
    ----------
    agame0 : AsyncGame
        The game that is played when time is 0.
    agame1 : AsyncGame
        The game that is played when time is 1.
    regret_thresh : float, optional
        The threshold for epsilon regret for equilibria returned.
    exectutor : Executor, optional
        The executor to run computation intensive operations in.
    """
    utils.check(
        rsgame.empty_copy(agame0) == rsgame.empty_copy(agame1),
        'games must have same structure')
    loop = asyncio.get_event_loop()
    trace_args = dict(regret_thresh=regret_thresh, max_step=max_step)
    innerloop_args.update(executor=executor,
                          regret_thresh=regret_thresh,
                          dist_thresh=dist_thresh)

    async def trace_eqm(eqm, prob):
        """Trace and equilibrium out from prob"""
        game0 = agame0.get_game()
        game1 = agame1.get_game()
        (pr0, eqa0), (pr1, eqa1) = await asyncio.gather(
            loop.run_in_executor(
                executor,
                functools.partial(trace.trace_equilibrium, game0, game1, prob,
                                  eqm, 0, **trace_args)),
            loop.run_in_executor(
                executor,
                functools.partial(trace.trace_equilibrium, game0, game1, prob,
                                  eqm, 1, **trace_args)))
        return (np.concatenate([pr0[::-1], pr1[1:]]),
                np.concatenate([eqa0[::-1], eqa1[1:]]))

    async def trace_between(lower, upper):
        """Trace between times lower and upper"""
        if upper <= lower:
            return ()
        mid = (lower + upper) / 2

        midgame = asyncgame.mix(agame0, agame1, mid)
        eqa = await innerloop.inner_loop(midgame, **innerloop_args)

        if not eqa.size:  # pragma: no cover
            logging.warning('found no equilibria in %s', midgame)
            return ()

        traces = await asyncio.gather(*[trace_eqm(eqm, mid) for eqm in eqa])

        lupper = min(t[0] for t, _ in traces)
        ulower = max(t[-1] for t, _ in traces)
        logging.warning('traced %s out to %g - %g', midgame, lupper, ulower)

        lower_traces, upper_traces = await asyncio.gather(
            trace_between(lower, lupper), trace_between(ulower, upper))
        # Lazily extend them
        return itertools.chain(lower_traces, traces, upper_traces)

    traces = list(await trace_between(0.0, 1.0))
    game0, game1 = agame0.get_game(), agame1.get_game()
    traces = _merge_traces(game0, game1, traces, dist_thresh, trace_args)
    for probs, eqa in traces:
        _smooth_trace(game0, game1, probs, eqa, trace_args)
        _smooth_trace(game0, game1, probs[::-1], eqa[::-1], trace_args)
    return sorted(traces, key=lambda tr: (tr[0][0], tr[0][-1]))
コード例 #36
0
import itertools
import json
import sys

from gameanalysis import gambit
from gameanalysis import gamereader
from gameanalysis import matgame
from gameanalysis import paygame
from gameanalysis import rsgame

_TYPES = {
    'emptygame':
    (['empty'], 'Strip payoff data', """Strip all payoff data from a game
        and return only its base structure---role and strategy names and player
        counts.""",
     lambda game, out: json.dump(rsgame.empty_copy(game).to_json(), out)),
    'game':
    ([], 'Sparse payoff format', """Convert a game to a sparse mapping of
        profiles to their corresponding payoff data.""",
     lambda game, out: json.dump(paygame.game_copy(game).to_json(), out)),
    'samplegame':
    (['samp'], 'Multiple payoffs per profile', """Convert a game to a format
        with a sparse mapping of profiles to potentially several samples of
        payoff data. There should be little reason to convert a non-samplegame
        to a samplegame as all profiles will have exactly one sample.""",
     lambda game, out: json.dump(paygame.samplegame_copy(game).to_json(), out)
     ),
    'matgame':
    (['mat'], 'Asymmetric format', """Convert a game to a compact
        representation for asymmetric games. If the input game is not
        asymmetric, role names will be duplicated and modified to allow for the