Example #1
0
 def outcome_index(self, outcome) -> Optional[int]:
     """Returns the index of the outcome if that was possible"""
     if self.__outcomes is None:
         return None
     if self.__outcome_index is not None:
         return self.__outcome_index[outcome_as_tuple(outcome)]
     return self.__outcomes.index(outcome)
Example #2
0
def test_ufun_range_general(n_issues):
    issues = [Issue(values=(0.0, 1.0), name=f"i{i}") for i in range(n_issues)]
    rs = [(i + 1.0) * random.random() for i in range(n_issues)]
    ufun = MappingUtilityFunction(
        mapping=lambda x: sum(r * v for r, v in zip(rs, outcome_as_tuple(x))),
        outcome_type=tuple,
    )
    assert ufun([0.0] * n_issues) == 0.0
    assert ufun([1.0] * n_issues) == sum(rs)
    rng = utility_range(ufun, issues=issues)
    assert rng[0] >= 0.0
    assert rng[1] <= sum(rs)
Example #3
0
    def eval(self, offer: Optional[Outcome]) -> Optional[UtilityValue]:
        # noinspection PyBroadException
        if offer is None:
            return self.reserved_value
        try:
            if isinstance(offer, dict) and isinstance(self.mapping, dict):
                m = gmap(self.mapping, outcome_as_tuple(offer))
            else:
                m = gmap(self.mapping, offer)
        except Exception:
            return self.default

        return m
Example #4
0
    def eval(self, offer: Optional["Outcome"]) -> Optional[UtilityValue]:
        if offer is None:
            return self.reserved_value
        # offer = outcome_for(offer, self.ami) if self.ami is not None else offer
        u = ExactUtilityValue(0.0)
        if isinstance(self.weights, dict):
            if isinstance(offer, dict):
                for k, w in self.weights.items():
                    u += w * (iget(offer, k, self.missing_value) +
                              self.biases.get(k, 0))
                return u
            else:
                if self.ami is not None:
                    newoffer = dict()
                    for i, v in enumerate(offer):
                        newoffer[self.ami.issues[i].name] = v
                elif self.issue_names is not None:
                    newoffer = dict()
                    for i, v in enumerate(offer):
                        newoffer[self.issue_names[i]] = v
                elif self.issues is not None:
                    newoffer = dict()
                    for i, v in enumerate(offer):
                        newoffer[self.issues[i].name] = v
                else:
                    raise ValueError(
                        f"Cannot find issue names but weights are given as a dict."
                    )
                for k, w in self.weights.items():
                    u += w * (iget(offer, k, self.missing_value) +
                              self.biases.get(k, 0))
                return u

        offer = outcome_as_tuple(offer)
        return sum(w * (v + b)
                   for w, b, v in zip(self.weights, self.biases, offer))
Example #5
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 = {}
Example #6
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,
        )