예제 #1
0
    def __init__(
        self,
        issues: List["Issue"] = None,
        outcomes: Union[int, List["Outcome"]] = None,
        n_steps: int = None,
        time_limit: float = None,
        step_time_limit: float = None,
        max_n_agents: int = None,
        dynamic_entry=False,
        cache_outcomes=True,
        max_n_outcomes: int = 1000000,
        keep_issue_names=None,
        annotation: Optional[Dict[str, Any]] = None,
        state_factory=MechanismState,
        enable_callbacks=False,
        checkpoint_every: int = 1,
        checkpoint_folder: Optional[Union[str, Path]] = None,
        checkpoint_filename: str = None,
        extra_checkpoint_info: Dict[str, Any] = None,
        single_checkpoint: bool = True,
        exist_ok: bool = True,
        name=None,
        outcome_type=tuple,
    ):
        """

        Args:
            issues: List of issues to use (optional as you can pass `outcomes`)
            outcomes: List of outcomes (optional as you can pass `issues`). If an int then it is the number of outcomes
            n_steps: Number of rounds allowed (None means infinity)
            time_limit: Number of real seconds allowed (None means infinity)
            max_n_agents:  Maximum allowed number of agents
            dynamic_entry: Allow agents to enter/leave negotiations between rounds
            cache_outcomes: If true, a list of all possible outcomes will be cached
            max_n_outcomes: The maximum allowed number of outcomes in the cached set
            keep_issue_names: DEPRICATED. Use `outcome_type` instead. If True, dicts with issue names will be used for outcomes otherwise tuples
            annotation: Arbitrary annotation
            state_factory: A callable that receives an arbitrary set of key-value pairs and return a MechanismState
                          descendant object
            checkpoint_every: The number of steps to checkpoint after. Set to <= 0 to disable
            checkpoint_folder: The folder to save checkpoints into. Set to None to disable
            checkpoint_filename: The base filename to use for checkpoints (multiple checkpoints will be prefixed with
                                 step number).
            single_checkpoint: If true, only the most recent checkpoint will be saved.
            extra_checkpoint_info: Any extra information to save with the checkpoint in the corresponding json file as
                                   a dictionary with string keys
            exist_ok: IF true, checkpoints override existing checkpoints with the same filename.
            name: Name of the mechanism session. Should be unique. If not given, it will be generated.
            outcome_type: The type used for representing outcomes. Can be tuple, dict or any `OutcomeType`
        """
        super().__init__(name=name)
        CheckpointMixin.checkpoint_init(
            self,
            step_attrib="_step",
            every=checkpoint_every,
            folder=checkpoint_folder,
            filename=checkpoint_filename,
            info=extra_checkpoint_info,
            exist_ok=exist_ok,
            single=single_checkpoint,
        )
        time_limit = time_limit if time_limit is not None else float("inf")
        step_time_limit = (
            step_time_limit if step_time_limit is not None else float("inf")
        )
        if keep_issue_names is not None:
            warnings.warn(
                "keep_issue_names is depricated. Use outcome_type instead.\n"
                "keep_issue_names=True <--> outcome_type=dict\n"
                "keep_issue_names=False <--> outcome_type=tuple\n",
                DeprecationWarning,
            )
            outcome_type = dict if keep_issue_names else tuple
        keep_issue_names = not issubclass(outcome_type, tuple)
        # parameters fixed for all runs
        if issues is None:
            if outcomes is None:
                __issues = []
                outcomes = []
            else:
                if isinstance(outcomes, int):
                    outcomes = [(_,) for _ in range(outcomes)]
                else:
                    outcomes = list(outcomes)
                n_issues = len(outcomes[0])
                issues = []
                issue_names = ikeys(outcomes[0])
                for issue in range(n_issues):
                    vals = list(set([_[issue] for _ in outcomes]))
                    issues.append(vals)
                __issues = [
                    Issue(_, name=name_) for _, name_ in zip(issues, issue_names)
                ]
        else:
            __issues = list(issues)
            if outcomes is None and cache_outcomes:
                try:
                    if len(__issues) == 0:
                        outcomes = []
                    else:
                        n_outcomes = 1
                        for issue in __issues:
                            if issue.is_uncountable():
                                break
                            n_outcomes *= issue.cardinality
                            if n_outcomes > max_n_outcomes:
                                break
                        else:
                            outcomes = enumerate_outcomes(__issues, astype=outcome_type)

                except ValueError:
                    pass
            elif outcomes is not None:
                issue_names = [_.name for _ in issues]
                assert (not keep_issue_names and isinstance(outcomes[0], tuple)) or (
                    keep_issue_names and not isinstance(outcomes[0], tuple)
                ), (
                    f"Either you request to keep issue"
                    f" names but use tuple outcomes or "
                    f"vice versa (names={keep_issue_names}"
                    f", type={type(outcomes[0])})"
                )
                if keep_issue_names:
                    for i, outcome in enumerate(outcomes):
                        assert list(outcome.keys()) == issue_names
                else:
                    for i, outcome in enumerate(outcomes):
                        assert len(outcome) == len(issue_names)

        self.__outcomes = outcomes
        # we have now __issues is a List[Issue] and __outcomes is Optional[List[Outcome]]

        # create a couple of ways to access outcomes by indices effeciently
        self.outcome_indices = []
        self.__outcome_index = None
        if self.__outcomes is not None and cache_outcomes:
            self.outcome_indices = range(len(self.__outcomes))
            self.__outcome_index = dict(
                zip(
                    (outcome_as_tuple(o) for o in self.__outcomes),
                    range(len(self.__outcomes)),
                )
            )

        self.id = str(uuid.uuid4())
        self.ami = AgentMechanismInterface(
            id=self.id,
            n_outcomes=None if outcomes is None else len(outcomes),
            issues=__issues,
            outcomes=self.__outcomes,
            time_limit=time_limit,
            n_steps=n_steps,
            step_time_limit=step_time_limit,
            dynamic_entry=dynamic_entry,
            max_n_agents=max_n_agents,
            annotation=annotation,
            outcome_type=dict if keep_issue_names else tuple,
        )
        self.ami._mechanism = self

        self._history = []
        # if self.ami.issues is not None:
        #     self.ami.issues = tuple(self.ami.issues)
        # if self.ami.outcomes is not None:
        #     self.ami.outcomes = tuple(self.ami.outcomes)
        self._state_factory = state_factory

        self._requirements = {}
        self._negotiators = []
        self._negotiator_map: Dict[str, "SAONegotiator"] = dict()
        self._roles = []
        self._start_time = None
        self._started = False
        self._step = 0
        self._n_accepting_agents = 0
        self._broken = False
        self._agreement = None
        self._timedout = False
        self._running = False
        self._error = False
        self._error_details = ""
        self._waiting = False
        self.__discrete_outcomes: List[Outcome] = None
        self._enable_callbacks = enable_callbacks

        self.agents_of_role = defaultdict(list)
        self.role_of_agent = {}
예제 #2
0
    def __init__(
        self,
        issues: List['Issue'] = None,
        outcomes: Union[int, List['Outcome']] = None,
        n_steps: int = None,
        time_limit: float = None,
        max_n_agents: int = None,
        dynamic_entry=False,
        cache_outcomes=True,
        max_n_outcomes: int = 1000000,
        keep_issue_names=True,
        annotation: Optional[Dict[str, Any]] = None,
        state_factory=MechanismState,
        name=None,
    ):
        """

        Args:
            issues: List of issues to use (optional as you can pass `outcomes`)
            outcomes: List of outcomes (optional as you can pass `issues`). If an int then it is the number of outcomes
            n_steps: Number of rounds allowed (None means infinity)
            time_limit: Number of real seconds allowed (None means infinity)
            max_n_agents:  Maximum allowed number of agents
            dynamic_entry: Allow agents to enter/leave negotiations between rounds
            cache_outcomes: If true, a list of all possible outcomes will be cached
            max_n_outcomes: The maximum allowed number of outcomes in the cached set
            keep_issue_names: If True, dicts with issue names will be used for outcomes otherwise tuples
            annotation: Arbitrary annotation
            state_factory: A callable that receives an arbitrary set of key-value pairs and return a MechanismState
            descendant object
            name: Name of the mechanism session. Should be unique. If not given, it will be generated.
        """
        super().__init__(name=name)
        # parameters fixed for all runs
        if issues is None:
            if outcomes is None:
                raise ValueError(
                    'Not issues or outcomes are given to this mechanism. Cannot be constructed'
                )
            else:
                if isinstance(outcomes, int):
                    outcomes = [(_, ) for _ in range(outcomes)]
                else:
                    outcomes = list(outcomes)
                n_issues = len(outcomes[0])
                issues = []
                issue_names = ikeys(outcomes[0])
                for issue in range(n_issues):
                    vals = list(set([_[issue] for _ in outcomes]))
                    issues.append(vals)
                __issues = [
                    Issue(_, name=name_)
                    for _, name_ in zip(issues, issue_names)
                ]
        else:
            __issues = list(issues)
            if outcomes is None and cache_outcomes:
                try:
                    if len(__issues) == 0:
                        outcomes = []
                    else:
                        n_outcomes = 1
                        for issue in __issues:
                            if issue.is_continuous():
                                break
                            n_outcomes *= issue.cardinality()
                            if n_outcomes > max_n_outcomes:
                                break
                        else:
                            outcomes = enumerate_outcomes(
                                __issues, keep_issue_names=keep_issue_names)

                except ValueError:
                    pass
            elif outcomes is not None:
                issue_names = [_.name for _ in issues]
                assert (keep_issue_names and isinstance(outcomes[0], dict)) or \
                       (not keep_issue_names and isinstance(outcomes[0], tuple)), f"Either you request to keep issue" \
                    f" names but use tuple outcomes or " \
                    f"vice versa (names={keep_issue_names}" \
                    f", type={type(outcomes[0])})"
                if keep_issue_names:
                    for i, outcome in enumerate(outcomes):
                        assert list(outcome.keys()) == issue_names
                else:
                    for i, outcome in enumerate(outcomes):
                        assert len(outcome) == len(issue_names)

        __outcomes = outcomes
        # we have now __issues is a List[Issue] and __outcomes is Optional[List[Outcome]]

        # create a couple of ways to access outcomes by indices effeciently
        self.outcome_index = lambda x: None
        self.outcome_indices = []
        if __outcomes is not None and cache_outcomes:
            self.outcome_indices = range(len(__outcomes))
            try:
                _outcome_index = dict(zip(__outcomes, self.outcome_indices))
                self.outcome_index = lambda x: _outcome_index[x]
            except:
                self.outcome_index = lambda x: __outcomes.index(x)

        self.id = str(uuid.uuid4())
        self.info = MechanismInfo(
            id=self.id,
            n_outcomes=None if outcomes is None else len(outcomes),
            issues=__issues,
            outcomes=__outcomes,
            time_limit=time_limit,
            n_steps=n_steps,
            dynamic_entry=dynamic_entry,
            max_n_agents=max_n_agents,
            annotation=annotation)

        self._history = []
        # if self.info.issues is not None:
        #     self.info.issues = tuple(self.info.issues)
        # if self.info.outcomes is not None:
        #     self.info.outcomes = tuple(self.info.outcomes)
        self._state_factory = state_factory
        Mechanism.all[self.id] = self

        self._requirements = {}
        self._agents = []
        self._roles = []
        self._start_time = None
        self._started = False
        self._step = 0
        self._n_accepting_agents = 0
        self._broken = False
        self._agreement = None
        self._timedout = False
        self._running = False
        self._error = False
        self._error_details = ''
        self.__discrete_outcomes: List[Outcome] = None

        self.agents_of_role = defaultdict(list)
        self.role_of_agent = {}
예제 #3
0
    def __init__(
        self,
        issues: List["Issue"] = None,
        outcomes: Union[int, List["Outcome"]] = None,
        n_steps: int = None,
        time_limit: float = None,
        step_time_limit: float = None,
        negotiator_time_limit: float = None,
        max_n_agents: int = None,
        dynamic_entry=False,
        cache_outcomes=True,
        max_n_outcomes: int = 1000000,
        keep_issue_names=None,
        annotation: Optional[Dict[str, Any]] = None,
        state_factory=MechanismState,
        enable_callbacks=False,
        checkpoint_every: int = 1,
        checkpoint_folder: Optional[Union[str, Path]] = None,
        checkpoint_filename: str = None,
        extra_checkpoint_info: Dict[str, Any] = None,
        single_checkpoint: bool = True,
        exist_ok: bool = True,
        name=None,
        outcome_type=tuple,
        genius_port: int = DEFAULT_JAVA_PORT,
        id: str = None,
    ):
        super().__init__(name, id=id)
        CheckpointMixin.checkpoint_init(
            self,
            step_attrib="_step",
            every=checkpoint_every,
            folder=checkpoint_folder,
            filename=checkpoint_filename,
            info=extra_checkpoint_info,
            exist_ok=exist_ok,
            single=single_checkpoint,
        )
        time_limit = time_limit if time_limit is not None else float("inf")
        step_time_limit = (step_time_limit
                           if step_time_limit is not None else float("inf"))
        negotiator_time_limit = (negotiator_time_limit if negotiator_time_limit
                                 is not None else float("inf"))

        if keep_issue_names is not None:
            warnings.warn(
                "keep_issue_names is depricated. Use outcome_type instead.\n"
                "keep_issue_names=True <--> outcome_type=dict\n"
                "keep_issue_names=False <--> outcome_type=tuple\n",
                DeprecationWarning,
            )
            outcome_type = dict if keep_issue_names else tuple
        keep_issue_names = not issubclass(outcome_type, tuple)
        # parameters fixed for all runs
        if issues is None:
            if outcomes is None:
                __issues = []
                outcomes = []
            else:
                if isinstance(outcomes, int):
                    outcomes = [(_, ) for _ in range(outcomes)]
                else:
                    outcomes = list(outcomes)
                n_issues = len(outcomes[0])
                issues = []
                issue_names = ikeys(outcomes[0])
                for issue in range(n_issues):
                    vals = list(set([_[issue] for _ in outcomes]))
                    issues.append(vals)
                __issues = [
                    Issue(_, name=name_)
                    for _, name_ in zip(issues, issue_names)
                ]
        else:
            __issues = list(issues)
            if outcomes is None and cache_outcomes:
                try:
                    if len(__issues) == 0:
                        outcomes = []
                    else:
                        n_outcomes = 1
                        for issue in __issues:
                            if issue.is_uncountable():
                                break
                            n_outcomes *= issue.cardinality
                            if n_outcomes > max_n_outcomes:
                                break
                        else:
                            outcomes = enumerate_outcomes(__issues,
                                                          astype=outcome_type)

                except ValueError:
                    pass
            elif outcomes is not None:
                issue_names = [_.name for _ in issues]
                assert (not keep_issue_names
                        and isinstance(outcomes[0], tuple)) or (
                            keep_issue_names
                            and not isinstance(outcomes[0], tuple)), (
                                f"Either you request to keep issue"
                                f" names but use tuple outcomes or "
                                f"vice versa (names={keep_issue_names}"
                                f", type={type(outcomes[0])})")
                if keep_issue_names:
                    for outcome in outcomes:
                        assert list(outcome.keys()) == issue_names
                else:
                    for i, outcome in enumerate(outcomes):
                        assert len(outcome) == len(issue_names)

        self.__outcomes = outcomes
        # we have now __issues is a List[Issue] and __outcomes is Optional[List[Outcome]]

        # create a couple of ways to access outcomes by indices effeciently
        self.outcome_indices = []
        self.__outcome_index = None
        if self.__outcomes is not None and cache_outcomes:
            self.outcome_indices = range(len(self.__outcomes))
            self.__outcome_index = dict(
                zip(
                    (outcome_as_tuple(o) for o in self.__outcomes),
                    range(len(self.__outcomes)),
                ))

        self.id = str(uuid.uuid4())
        _imap = dict(zip((_.name for _ in __issues), range(len(__issues))))
        _imap.update(
            dict(zip(range(len(__issues)), (_.name for _ in __issues))))
        self.ami = AgentMechanismInterface(
            id=self.id,
            n_outcomes=None if outcomes is None else len(outcomes),
            issues=__issues,
            outcomes=self.__outcomes,
            time_limit=time_limit,
            n_steps=n_steps,
            step_time_limit=step_time_limit,
            negotiator_time_limit=negotiator_time_limit,
            dynamic_entry=dynamic_entry,
            max_n_agents=max_n_agents,
            annotation=annotation,
            outcome_type=dict if keep_issue_names else tuple,
            imap=_imap,
        )
        self.ami._mechanism = self

        self._history: List[MechanismState] = []
        self._stats: Dict[str, Any] = dict()
        self._stats["round_times"] = list()
        self._stats["times"] = defaultdict(float)
        self._stats["exceptions"] = defaultdict(list)
        # if self.ami.issues is not None:
        #     self.ami.issues = tuple(self.ami.issues)
        # if self.ami.outcomes is not None:
        #     self.ami.outcomes = tuple(self.ami.outcomes)
        self._state_factory = state_factory

        self._requirements = {}
        self._negotiators = []
        self._negotiator_map: Dict[str, "SAONegotiator"] = dict()
        self._roles = []
        self._start_time = None
        self._started = False
        self._step = 0
        self._n_accepting_agents = 0
        self._broken = False
        self._agreement = None
        self._timedout = False
        self._running = False
        self._error = False
        self._error_details = ""
        self._waiting = False
        self.__discrete_outcomes: List[Outcome] = None
        self._enable_callbacks = enable_callbacks

        self.agents_of_role = defaultdict(list)
        self.role_of_agent = {}
        # mechanisms do not differentiate between RANDOM_JAVA_PORT and ANY_JAVA_PORT.
        # if either is given as the genius_port, it will fix a port and all negotiators
        # that are not explicitly assigned to a port (by passing port>0 to them) will just
        # use that port.
        self.genius_port = genius_port if genius_port > 0 else get_free_tcp_port(
        )

        self.params = dict(
            dynamic_entry=dynamic_entry,
            genius_port=genius_port,
            cache_outcomes=cache_outcomes,
            annotation=annotation,
        )