コード例 #1
0
    def __init__(self, name: str = "controller",
                 oef_addr: str = "127.0.0.1",
                 oef_port: int = 10000,
                 version: int = 1,
                 monitor: Optional[Monitor] = None,
                 **kwargs):
        """
        Initialize a Controller Agent for TAC.

        :param name: The name of the OEF Agent.
        :param oef_addr: the OEF address.
        :param oef_port: the OEF listening port.
        :param version: the version of the TAC controller.
        :param monitor: the GUI monitor. If None, defaults to a null (dummy) monitor.
        """
        self.name = name
        self.crypto = Crypto()
        super().__init__(self.crypto.public_key, oef_addr, oef_port, loop=asyncio.new_event_loop())
        logger.debug("[{}]: Initialized myself as Controller Agent :\n{}".format(self.name, pprint.pformat(vars())))

        self.dispatcher = ControllerDispatcher(self)
        self.monitor = NullMonitor() if monitor is None else monitor  # type: Monitor

        self.version = version
        self.game_handler = None  # type: Optional[GameHandler]

        self.last_activity = datetime.datetime.now()

        self._message_processing_task = None
        self._timeout_checker_task = None

        self._is_running = False
        self._terminated = False
コード例 #2
0
    def setup_class(cls):
        """Test that if the controller agent does not receive enough registrations, it stops."""
        tac_parameters = TACParameters(min_nb_agents=2,
                                       start_time=datetime.datetime.now(),
                                       registration_timeout=5)
        cls.controller_agent = ControllerAgent('controller', '127.0.0.1',
                                               10000, tac_parameters,
                                               NullMonitor())

        cls.controller_agent.mailbox.connect()
        job = Thread(target=cls.controller_agent.start)
        job.start()

        cls.crypto = Crypto()
        cls.agent1 = TOEFAgent(cls.crypto.public_key,
                               oef_addr='127.0.0.1',
                               oef_port=10000)
        cls.agent1.connect()

        tac_msg = TACMessage(tac_type=TACMessage.Type.REGISTER,
                             agent_name='agent_name')
        tac_bytes = TACSerializer().encode(tac_msg)
        cls.agent1.outbox.put_message(
            to=cls.controller_agent.crypto.public_key,
            sender=cls.crypto.public_key,
            protocol_id=TACMessage.protocol_id,
            message=tac_bytes)

        job.join()
コード例 #3
0
 def setup_class(cls):
     """Test that if the controller agent does not receive enough registrations, it stops."""
     tac_parameters = TACParameters(min_nb_agents=2,
                                    start_time=datetime.datetime.now(),
                                    registration_timeout=5)
     cls.controller_agent = ControllerAgent('controller', '127.0.0.1',
                                            10000, tac_parameters,
                                            NullMonitor())
コード例 #4
0
    def setup_class(cls):
        """Class setup."""
        cls.tac_version_id = "1"
        cls.agent_version = "v1"
        cls.baseline_agents = _init_baseline_agents(5, cls.agent_version,
                                                    "127.0.0.1", 10000,
                                                    cls.tac_version_id)

        cls.tac_parameters = TACParameters(
            min_nb_agents=5,
            money_endowment=200,
            nb_goods=5,
            tx_fee=1.0,
            base_good_endowment=2,
            lower_bound_factor=0,
            upper_bound_factor=0,
            start_time=datetime.datetime.now() + datetime.timedelta(0, 2),
            registration_timeout=8,
            competition_timeout=20,
            inactivity_timeout=15,
            version_id=cls.tac_version_id,
        )

        cls.tac_controller = ControllerAgent("controller", "127.0.0.1", 10000,
                                             cls.tac_parameters, NullMonitor())

        # run the simulation
        try:
            controller_thread = Thread(target=cls.tac_controller.start)

            baseline_threads = [
                Thread(target=_run_baseline_agent, args=[baseline_agent, "v1"])
                for baseline_agent in cls.baseline_agents
            ]

            # launch all thread.
            all_threads = [controller_thread] + baseline_threads
            for thread in all_threads:
                thread.start()

            # wait for every thread. This part is blocking.
            for thread in all_threads:
                thread.join()
        except Exception as e:
            pytest.fail("Got exception: {}".format(e))
コード例 #5
0
ファイル: controller.py プロジェクト: jrriehl/agents-tac
class ControllerAgent(OEFAgent):
    """Class for a controller agent."""

    CONTROLLER_DATAMODEL = DataModel("tac", [
        AttributeSchema("version", int, True,
                        "Version number of the TAC Controller Agent."),
    ])

    def __init__(self,
                 name: str = "controller",
                 oef_addr: str = "127.0.0.1",
                 oef_port: int = 10000,
                 version: int = 1,
                 monitor: Optional[Monitor] = None,
                 **kwargs):
        """
        Initialize a Controller Agent for TAC.

        :param name: The name of the OEF Agent.
        :param oef_addr: the OEF address.
        :param oef_port: the OEF listening port.
        :param version: the version of the TAC controller.
        :param monitor: the dashboard monitor. If None, defaults to a null (dummy) monitor.
        """
        self.name = name
        self.crypto = Crypto()
        super().__init__(self.crypto.public_key,
                         oef_addr,
                         oef_port,
                         loop=asyncio.new_event_loop())
        logger.debug(
            "[{}]: Initialized myself as Controller Agent :\n{}".format(
                self.name, pprint.pformat(vars())))

        self.dispatcher = ControllerDispatcher(self)
        self.monitor = NullMonitor(
        ) if monitor is None else monitor  # type: Monitor

        self.version = version
        self.game_handler = None  # type: Optional[GameHandler]

        self.last_activity = datetime.datetime.now()

        self._message_processing_task = None
        self._timeout_checker_task = None

        self._is_running = False
        self._terminated = False

    def on_message(self, msg_id: int, dialogue_id: int, origin: str,
                   content: bytes) -> None:
        """
        Handle a simple message.

        The TAC Controller expects that 'content' is a Protobuf serialization of a tac.messages.Request object.
        The request is dispatched to the right request handler (using the ControllerDispatcher).
        The handler returns an optional response, that is sent back to the sender.
        Notice: the message sent back has the same message id, such that the client knows to which request the response is associated to.

        :param msg_id: the message id
        :param dialogue_id: the dialogue id
        :param origin: the public key of the sender.
        :param content: the content of the message.
        :return: None
        """
        logger.debug(
            "[{}] on_message: msg_id={}, dialogue_id={}, origin={}".format(
                self.name, msg_id, dialogue_id, origin))
        self.update_last_activity()
        response = self.dispatcher.process_request(
            content, origin)  # type: Optional[Response]
        if response is not None:
            self.send_message(msg_id, dialogue_id, origin,
                              response.serialize())

    def on_oef_error(self, answer_id: int,
                     operation: OEFErrorOperation) -> None:
        """
        Handle an oef error.

        :param answer_id: the answer id
        :param operation: the oef operation

        :return: None
        """
        logger.error(
            "[{}]: Received OEF error: answer_id={}, operation={}".format(
                self.name, answer_id, operation))

    def on_dialogue_error(self, answer_id: int, dialogue_id: int,
                          origin: str) -> None:
        """
        Handle a dialogue error.

        :param answer_id: the answer id
        :param dialogue_id: the dialogue id
        :param origin: the public key of the sending agent

        :return: None
        """
        logger.error(
            "[{}]: Received Dialogue error: answer_id={}, dialogue_id={}, origin={}"
            .format(self.name, answer_id, dialogue_id, origin))

    def register(self):
        """
        Register on the OEF as a TAC controller agent.

        :return: None.
        """
        desc = Description({"version": 1},
                           data_model=self.CONTROLLER_DATAMODEL)
        logger.debug("[{}]: Registering with {} data model".format(
            self.name, desc.data_model.name))
        self.register_service(0, desc)

    def dump(self, directory: str, experiment_name: str) -> None:
        """
        Dump the details of the simulation.

        :param directory: the directory where experiments details are listed.
        :param experiment_name: the name of the folder where the data about experiment will be saved.
        :return: None.
        """
        experiment_dir = directory + "/" + experiment_name

        if self.game_handler is None or not self.game_handler.is_game_running(
        ):
            logger.warning(
                "[{}]: Game not present. Using empty dictionary.".format(
                    self.name))
            game_dict = {}  # type: Dict[str, Any]
        else:
            game_dict = self.game_handler.current_game.to_dict()

        os.makedirs(experiment_dir, exist_ok=True)
        with open(os.path.join(experiment_dir, "game.json"), "w") as f:
            json.dump(game_dict, f)

    def terminate(self) -> None:
        """
        Terminate the controller agent.

        :return: None
        """
        if self._is_running:
            logger.debug("[{}]: Terminating the controller...".format(
                self.name))
            self._is_running = False
            self.game_handler.notify_tac_cancelled()
            self._loop.call_soon_threadsafe(self.stop)
            self._message_processing_task.join()
            self._message_processing_task = None
            if self.monitor.is_running:
                self.monitor.stop()

    def check_inactivity_timeout(self, rate: Optional[float] = 2.0) -> None:
        """
        Check periodically if the timeout for inactivity or competition expired.

        :param: rate: at which rate (in seconds) the frequency of the check.
        :return: None
        """
        logger.debug(
            "[{}]: Started job to check for inactivity of {} seconds. Checking rate: {}"
            .format(
                self.name,
                self.game_handler.tac_parameters.inactivity_timedelta.
                total_seconds(), rate))
        while True:
            if self._is_running is False:
                return
            time.sleep(rate)
            current_time = datetime.datetime.now()
            inactivity_duration = current_time - self.last_activity
            if inactivity_duration > self.game_handler.tac_parameters.inactivity_timedelta:
                logger.debug(
                    "[{}]: Inactivity timeout expired. Terminating...".format(
                        self.name))
                self.terminate()
                return
            elif current_time > self.game_handler.tac_parameters.end_time:
                logger.debug(
                    "[{}]: Competition timeout expired. Terminating...".format(
                        self.name))
                self.terminate()
                return

    def update_last_activity(self):
        """Update the last activity tracker."""
        self.last_activity = datetime.datetime.now()

    def handle_competition(self, tac_parameters: TACParameters):
        """
        Start a Trading Agent Competition.

        :param tac_parameters: the parameter of the competition.
        :return:
        """
        logger.debug("[{}]: Starting competition with parameters: {}".format(
            self.name, pprint.pformat(tac_parameters.__dict__)))
        self._is_running = True
        self._message_processing_task = Thread(target=self.run)

        self.monitor.start(None)
        self.monitor.update()

        self.game_handler = GameHandler(self, tac_parameters)
        self._message_processing_task.start()

        if self.game_handler.handle_registration_phase():
            # start the inactivity timeout.
            self._timeout_checker_task = Thread(
                target=self.check_inactivity_timeout)
            self._timeout_checker_task.run()
        else:
            self.terminate()

    def wait_and_handle_competition(self,
                                    tac_parameters: TACParameters) -> None:
        """
        Wait until the current time is greater than the start time, then, start the TAC.

        :param tac_parameters: the parameters for TAC.
        :return: None
        """
        now = datetime.datetime.now()
        logger.debug(
            "[{}]: waiting for starting the competition: start_time={}, current_time={}, timedelta ={}s"
            .format(self.name, str(tac_parameters.start_time), str(now),
                    (tac_parameters.start_time - now).total_seconds()))

        seconds_to_wait = (tac_parameters.start_time - now).total_seconds()
        time.sleep(0.5 if seconds_to_wait < 0 else seconds_to_wait)
        self.handle_competition(tac_parameters)
コード例 #6
0
ファイル: controller.py プロジェクト: jrriehl/agents-tac
def main(name: str = "controller",
         nb_agents: int = 5,
         nb_goods: int = 5,
         money_endowment: int = 200,
         base_good_endowment: int = 2,
         lower_bound_factor: int = 0,
         upper_bound_factor: int = 0,
         tx_fee: float = 1.0,
         oef_addr: str = "127.0.0.1",
         oef_port: int = 10000,
         start_time: Union[str,
                           datetime.datetime] = str(datetime.datetime.now() +
                                                    datetime.timedelta(0, 10)),
         registration_timeout: int = 10,
         inactivity_timeout: int = 60,
         competition_timeout: int = 240,
         whitelist_file: Optional[str] = None,
         verbose: bool = False,
         dashboard: bool = False,
         visdom_addr: str = "localhost",
         visdom_port: int = 8097,
         data_output_dir: str = "data",
         experiment_id: Optional[str] = None,
         seed: int = 42,
         version: int = 1,
         **kwargs):
    """Run the controller script."""
    agent = None  # type: Optional[ControllerAgent]
    random.seed(seed)

    if verbose:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    monitor = VisdomMonitor(
        visdom_addr=visdom_addr,
        visdom_port=visdom_port) if dashboard else NullMonitor()

    try:

        agent = ControllerAgent(name=name,
                                oef_addr=oef_addr,
                                oef_port=oef_port,
                                monitor=monitor,
                                version=version)

        whitelist = set(
            open(whitelist_file).read().splitlines(
                keepends=False)) if whitelist_file else None
        tac_parameters = TACParameters(
            min_nb_agents=nb_agents,
            money_endowment=money_endowment,
            nb_goods=nb_goods,
            tx_fee=tx_fee,
            base_good_endowment=base_good_endowment,
            lower_bound_factor=lower_bound_factor,
            upper_bound_factor=upper_bound_factor,
            start_time=dateutil.parser.parse(start_time)
            if type(start_time) == str else start_time,
            registration_timeout=registration_timeout,
            competition_timeout=competition_timeout,
            inactivity_timeout=inactivity_timeout,
            whitelist=whitelist)

        agent.connect()
        agent.register()
        agent.wait_and_handle_competition(tac_parameters)

    except Exception as e:
        logger.exception(e)
    except KeyboardInterrupt:
        logger.debug("Controller interrupted...")
    finally:
        if agent is not None:
            agent.terminate()
            experiment_name = experiment_id if experiment_id is not None else str(
                datetime.datetime.now()).replace(" ", "_")
            agent.dump(data_output_dir, experiment_name)
            if agent.game_handler is not None and agent.game_handler.is_game_running(
            ):
                game_stats = GameStats(agent.game_handler.current_game)
                game_stats.dump(data_output_dir, experiment_name)
コード例 #7
0
ファイル: agent.py プロジェクト: echallenge/agents-tac
def main(name: str = "controller",
         nb_agents: int = 5,
         nb_goods: int = 5,
         money_endowment: int = 200,
         base_good_endowment: int = 2,
         lower_bound_factor: int = 0,
         upper_bound_factor: int = 0,
         tx_fee: float = 1.0,
         oef_addr: str = "127.0.0.1",
         oef_port: int = 10000,
         start_time: str = str(datetime.datetime.now() +
                               datetime.timedelta(0, 10)),
         registration_timeout: int = 10,
         inactivity_timeout: int = 60,
         competition_timeout: int = 240,
         whitelist_file: Optional[str] = None,
         verbose: bool = False,
         dashboard: bool = False,
         visdom_addr: str = "localhost",
         visdom_port: int = 8097,
         data_output_dir: str = "data",
         version_id: str = str(random.randint(0, 10000)),
         seed: int = 42,
         **kwargs):
    """Run the controller script."""
    agent = None  # type: Optional[ControllerAgent]
    random.seed(seed)

    if verbose:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    try:
        monitor = (VisdomMonitor(visdom_addr=visdom_addr,
                                 visdom_port=visdom_port)
                   if dashboard else NullMonitor())
        whitelist = (set(
            open(whitelist_file).read().splitlines(
                keepends=False)) if whitelist_file else None)
        tac_parameters = TACParameters(
            min_nb_agents=nb_agents,
            money_endowment=money_endowment,
            nb_goods=nb_goods,
            tx_fee=tx_fee,
            base_good_endowment=base_good_endowment,
            lower_bound_factor=lower_bound_factor,
            upper_bound_factor=upper_bound_factor,
            start_time=dateutil.parser.parse(str(start_time)),
            registration_timeout=registration_timeout,
            competition_timeout=competition_timeout,
            inactivity_timeout=inactivity_timeout,
            whitelist=whitelist,
            data_output_dir=data_output_dir,
            version_id=version_id,
        )
        agent = ControllerAgent(
            name=name,
            oef_addr=oef_addr,
            oef_port=oef_port,
            tac_parameters=tac_parameters,
            monitor=monitor,
        )
        agent.start()

    except Exception as e:
        logger.exception(e)
    except KeyboardInterrupt:
        logger.debug("Controller interrupted...")
    finally:
        if agent is not None:
            agent.stop()
            agent.teardown()