Пример #1
0
def test_hash_array():
    """Test that hash array works"""
    arrayset = {utils.hash_array([3, 4, 5]), utils.hash_array([6, 7])}

    assert utils.hash_array([3, 4, 5]) in arrayset
    assert utils.hash_array([6, 7]) in arrayset
    assert utils.hash_array([3, 4, 6]) not in arrayset
Пример #2
0
def test_hash_array():
    """Test that hash array works"""
    arrayset = {utils.hash_array([3, 4, 5]), utils.hash_array([6, 7])}

    assert utils.hash_array([3, 4, 5]) in arrayset
    assert utils.hash_array([6, 7]) in arrayset
    assert utils.hash_array([3, 4, 6]) not in arrayset
Пример #3
0
def test_subgame_extract_1():
    string, _ = run('sub', '-n', '-t', 'background',
                    'markov:rmin_500_rmax_1000_thresh_0.8_priceVarEst_1e9',
                    'hft', 'noop', '-s', '0', '3', '4', input=GAME_STR)

    expected = {utils.hash_array([False,  True,  True, False, False, False,
                                  False, False, False]),
                utils.hash_array([True, False, False,  True,  True, False,
                                  False, False, False])}
    assert {utils.hash_array(SERIAL.from_subgame_json(s))
            for s in json.loads(string)} == expected
Пример #4
0
 async def sample_payoffs(self, profile):
     gu.check(self._is_open, "not open")
     self._check_fetcher()
     hprof = gu.hash_array(profile)
     data = self._profiles.setdefault(
         hprof, ([0], [0], [0], [None], asyncio.Queue()))
     scheduled, _, claimed, prof_id, pays = data
     claimed[0] += 1
     if scheduled[0] < claimed[0]:
         scheduled[0] += self._simult_obs
         async with self._sched_lock:
             for _ in range(self._simult_obs):
                 await self._scheduled.acquire()
             pid = prof_id[0]
             if pid is not None:
                 await self._sched.remove_profile(pid)
             assignment = self._game.profile_to_repr(profile)
             prof_id[0] = (await
                           self._sched.add_profile(assignment,
                                                   scheduled[0]))["id"]
             if pid is None:
                 self._prof_ids[prof_id[0]] = data
     pay = await pays.get()
     self._check_fetcher()
     return pay
Пример #5
0
    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
Пример #6
0
def sample_profiles(base, num): # pylint: disable=inconsistent-return-statements
    """Generate unique profiles from a game

    Parameters
    ----------
    base : RsGame
        Game to generate random profiles from.
    num : int
        Number of profiles to sample from the game.
    """
    if num == base.num_all_profiles: # pylint: disable=no-else-return
        return base.all_profiles()
    elif num == 0:
        return np.empty((0, base.num_strats), int)
    elif base.num_all_profiles <= np.iinfo(int).max:
        inds = rand.choice(base.num_all_profiles, num, replace=False)
        return base.profile_from_id(inds)
    else:
        # Number of times we have to re-query
        ratio = (sps.digamma(float(base.num_all_profiles)) -
                 sps.digamma(float(base.num_all_profiles - num)))
        # Max is for underflow
        num_per = max(round(float(ratio * base.num_all_profiles)), num)
        profiles = set()
        while len(profiles) < num:
            profiles.update(
                utils.hash_array(p) for p in base.random_profiles(num_per))
        profiles = np.stack([h.array for h in profiles])
        inds = rand.choice(profiles.shape[0], num, replace=False)
        return profiles[inds]
Пример #7
0
def test_sample_game_payoff():
    profiles = [
        [0, 4, 0, 9],
        [0, 4, 1, 8],
        [0, 4, 4, 5],
        [0, 4, 3, 6],
    ]
    payoffs = [
        [
            [[0] * 4, [1, 2, 3, 4], [0] * 4, [5, 6, 7, 8]],
        ],
        [
            [[0, 0], [0, 0], [9, 10], [0, 0]],
        ],
        [
            [[0] * 3, [0] * 3, [0] * 3, [11, 12, 13]],
        ],
        [
            [[0] * 5, [14, 15, 16, 17, 18], [0] * 5, [0] * 5],
        ],
    ]
    game = rsgame.SampleGame([4, 9], 2, profiles, payoffs)
    red = reduction.DeviationPreserving([2, 2], [4, 9], [2, 3])
    red_game = red.reduce_game(game)

    prof_map = dict(zip(
        map(utils.hash_array, red_game.profiles),
        itertools.chain.from_iterable(red_game.sample_payoffs)))

    payoffs = prof_map[utils.hash_array([0, 2, 0, 3])]
    actual = payoffs[1]
    expected = [1, 2, 3, 4]
    assert np.setxor1d(actual, expected).size == 0
    actual = payoffs[3]
    expected = [5, 6, 7, 8]
    assert np.setxor1d(actual, expected).size == 0

    payoffs = prof_map[utils.hash_array([0, 2, 1, 2])]
    actual = payoffs[1]
    expected = [14, 15, 16, 17, 18]
    assert np.setxor1d(actual, expected).size == 3
    actual = payoffs[2]
    expected = [9, 10]
    assert np.setxor1d(actual, expected).size == 0
    actual = payoffs[3]
    expected = [11, 12, 13]
    assert np.setxor1d(actual, expected).size == 1
Пример #8
0
 async def sample_payoffs(self, profile):
     index = hash(utils.hash_array(profile)) % self._max_size
     params = self._params.get(index, None)
     if params is None:
         params = self._param_dist()
         self._params[index] = params
     payoff = self._game.get_payoffs(profile) + self._noise_dist(*params)
     payoff[profile == 0] = 0
     payoff.setflags(write=False)
     return payoff
Пример #9
0
    def update(self):
        """Schedules as many profiles as possible"""
        changed = False

        count_left = self._max_profiles
        all_profiles = self._scheduler.get_info(True).scheduling_requirements
        for prof in all_profiles or ():
            if prof.id in self._sid_payoffs:
                # If prof.id is not in self._sid_payoffs, then we haven't
                # scheduled it, so we don't care
                sid, count_ptr, payoffs = self._sid_payoffs[prof.id]
                if prof.current_count < prof.requirement:
                    count_left -= 1

                elif prof.current_count > count_ptr[0]:
                    count_ptr[0] = prof.current_count
                    np.copyto(payoffs, self._serial.from_payoff_symgrp(
                        prof.get_info().symmetry_groups))
                    changed = True

        # Loop over necessary that we can schedule
        while count_left > 0 and self._queue:
            numobs, profiles = self._queue[0]
            profile = next(profiles)

            if profile is _END:  # Reached end of list
                self._queue.popleft()

            else:  # Process profile
                phash = utils.hash_array(profile)
                if phash in self._phash_payoffs:
                    sid, [count], _ = self._phash_payoffs[phash]
                    self._explored_sids.add(sid)
                    if numobs > count:
                        sprof = self._scheduler.profile(
                            id=sid,
                            assignment=self._serial.to_prof_string(profile))
                        sprof.update_count(numobs)
                        count_left -= 1
                        changed = True
                else:
                    string = self._serial.to_prof_string(profile)
                    self._log.log(1, 'Scheduling profile: %s', string)
                    sid = self._scheduler.add_profile(string, numobs).id
                    self._explored_sids.add(sid)
                    tup = (sid, [0],
                           np.empty(self._serial.num_role_strats))
                    self._phash_payoffs[phash] = tup
                    self._sid_payoffs[sid] = tup
                    count_left -= 1
                    changed = True

        return changed
Пример #10
0
    async def sample_payoffs(self, profile):
        hprof = utils.hash_array(profile)
        pays, params = self._paymap.get(hprof, (None, None))
        if pays is None:
            params = self._param_dist()
            pays = self._sgame.get_sample_payoffs(profile)
            self._paymap[hprof] = (pays, params)

        pay = pays[random.randrange(pays.shape[0])]
        payoff = pay + self._noise_dist(*params)
        payoff[profile == 0] = 0
        payoff.setflags(write=False)
        return payoff
Пример #11
0
    def get_payoffs(self, profile):
        """Returns an array of profile payoffs

        if default is not None and game doesn't have profile data, then an
        array populated by default is returned."""
        profile = np.asarray(profile, int)
        assert self.verify_profile(profile)
        hashed = utils.hash_array(profile)
        if hashed not in self._profile_id_map:
            pay = np.zeros(self.num_role_strats)
            pay[profile > 0] = np.nan
            return pay
        else:
            return self._profile_id_map[hashed]
Пример #12
0
 async def _get_game(self, profs):
     """Get a game from the profiles to sample"""
     futures = []
     for prof in profs:
         hprof = utils.hash_array(prof)
         future = self._profiles.get(hprof, None)
         if future is None:
             future = asyncio.ensure_future(
                 self._sched.sample_payoffs(prof))
             self._profiles[hprof] = future
         futures.append(future)
     lpays = await asyncio.gather(*futures)
     pays = np.stack(lpays)
     return paygame.game_replace(self, profs, pays)
Пример #13
0
    def __init__(self, game, serializer, scheduler, max_profiles, log,
                 profiles=()):
        self._game = game
        self._serial = serializer
        self._scheduler = scheduler
        self._max_profiles = max_profiles
        self._log = log

        self._queue = collections.deque()
        # Profile hashes: utils.hash_array, Simulator ids: profile.id
        self._phash_payoffs = {}
        self._sid_payoffs = {}
        self._explored_sids = set()

        for jprof in profiles:
            phash = utils.hash_array(serializer.from_prof_symgrp(
                jprof['symmetry_groups']))
            sid = jprof['id']
            payoff = serializer.from_payoff_symgrp(jprof['symmetry_groups'])
            data = (sid, [jprof['observations_count']], payoff)
            self._phash_payoffs[phash] = data
            self._sid_payoffs[sid] = data
Пример #14
0
    async def sample_payoffs(self, profile):
        utils.check(self._is_open, "must enter scheduler")
        hprof = utils.hash_array(profile)
        counter, queue = self._extra_profs.get(hprof, (None, None))
        if counter is not None:
            # Already scheduling some profiles
            if next(counter) >= self._count:
                self._extra_profs.pop(hprof)
            pay = await queue.get()
            logging.debug("read payoff for profile: %s",
                          self.profile_to_repr(profile))
            return pay

        else:
            # Need to schedule new profiles
            direc = os.path.join(self._prof_dir.name, str(self._num))
            self._num += 1
            queue = asyncio.Queue()
            if self._count > 1:
                self._extra_profs[hprof] = (itertools.count(2), queue)
            os.makedirs(direc)
            self._base["assignment"] = self._game.profile_to_assignment(
                profile)
            with open(os.path.join(direc, "simulation_spec.json"), "w") as fil:
                json.dump(self._base, fil)
            logging.debug(
                "scheduled %d profile%s: %s",
                self._count,
                "" if self._count == 1 else "s",
                self.profile_to_repr(profile),
            )

            # Limit simultaneous processes
            async with self._procs:
                proc = await asyncio.create_subprocess_exec(
                    os.path.join("script", "batch"),
                    direc,
                    str(self._count),
                    cwd=self._sim_root,
                    stderr=asyncio.subprocess.PIPE,
                    stdout=asyncio.subprocess.DEVNULL,
                )
                _, err = await proc.communicate()
            utils.check(
                proc.returncode == 0,
                "process failed with returncode {:d} and stderr {}",
                proc.returncode,
                err,
            )
            obs_files = (f for f in os.listdir(direc)
                         if "observation" in f and f.endswith(".json"))
            for _ in range(self._count):
                obs_file = next(obs_files, None)
                utils.check(
                    obs_file is not None,
                    "simulation didn't write enough observation files",
                )
                with open(os.path.join(direc, obs_file)) as fil:
                    pay = self._game.payoff_from_json(json.load(fil))
                    pay.setflags(write=False)
                    queue.put_nowait(pay)
            obs_file = next(obs_files, None)
            utils.check(obs_file is None,
                        "simulation wrote too many observation files")
            shutil.rmtree(direc)
            pay = queue.get_nowait()
            logging.debug("read payoff for profile: %s",
                          self.profile_to_repr(profile))
            return pay
Пример #15
0
 def __contains__(self, profile):
     """Returns true if all data for that profile exists"""
     # TODO This may be slow. Potentially we should just keep a set of all
     # the ones with complete data...
     return (utils.hash_array(np.asarray(profile, int))
             in self._complete_profiles)
Пример #16
0
def test_hash_array():
    arrayset = {utils.hash_array([3, 4, 5]), utils.hash_array([6, 7])}

    assert utils.hash_array([3, 4, 5]) in arrayset
    assert utils.hash_array([6, 7]) in arrayset
    assert utils.hash_array([3, 4, 6]) not in arrayset