예제 #1
0
    def from_ufun(
        cls,
        u: MappingUtilityFunction,
        range: Tuple[float, float] = (0.0, 1.0),
        uncertainty: float = 0.5,
        variability: float = 0.0,
    ) -> "IPUtilityFunction":
        """
        Generates a distribution from which `u` may have been sampled
        Args:
            u:
            range: range of the utility_function values
            uncertainty: uncertainty level

        Examples:

            - No uncertainty
            >>> u = MappingUtilityFunction(mapping=dict(zip([('o1',), ('o2',)], [0.3, 0.7])))
            >>> p = IPUtilityFunction.from_ufun(u, uncertainty=0.0)
            >>> print(p)
            {('o1',): U(0.3, 0.3), ('o2',): U(0.7, 0.7)}

            - Full uncertainty
            >>> u = MappingUtilityFunction(mapping=dict(zip([('o1',), ('o2',)], [0.3, 0.7])))
            >>> p = IPUtilityFunction.from_ufun(u, uncertainty=1.0)
            >>> print(p)
            {('o1',): U(0.0, 1.0), ('o2',): U(0.0, 1.0)}

            - some uncertainty
            >>> u = MappingUtilityFunction(mapping=dict(zip([('o1',), ('o2',)], [0.3, 0.7])))
            >>> p = IPUtilityFunction.from_ufun(u, uncertainty=0.1)
            >>> print([_.scale for _ in p.distributions.values()])
            [0.1, 0.1]
            >>> for k, v in p.distributions.items():
            ...     assert v.loc <= u(k)


        Returns:
            a new IPUtilityFunction
        """
        if isinstance(u.mapping, dict):
            return cls.from_mapping(
                u.mapping,
                range=range,
                uncertainty=uncertainty,
                variability=variability,
                reserved_value=u.reserved_value,
            )
        return cls.from_mapping(
            dict(zip(ikeys(u.mapping), ivalues(u.mapping))),
            range=range,
            uncertainty=uncertainty,
            variability=variability,
            reserved_value=u.reserved_value,
        )
예제 #2
0
    def eval(self, offer: "Outcome") -> UtilityValue:
        """Calculate the utility_function value for a given outcome.

        Args:
            offer: The offer to be evaluated.


        Remarks:
            - You cannot return None from overriden apply() functions but raise an exception (ValueError) if it was
              not possible to calculate the UtilityValue.
            - Return A UtilityValue not a float for real-valued utilities for the benefit of inspection code.

        Returns:
            UtilityValue: The utility_function value which may be a distribution. If `None` it means the utility_function value cannot be
            calculated.
        """
        if offer is None:
            return self.reserved_value
        if self.tupelized and not isinstance(offer, tuple):
            offer = tuple(ivalues(offer))
        return self.distributions[offer]
예제 #3
0
    def xml(self, issues: List[Issue]) -> str:
        """Represents the function as XML

        Args:
            issues:

        Examples:

            >>> f = HyperRectangleUtilityFunction(outcome_ranges=[
            ...                                        {0: (1.0, 2.0), 1: (1.0, 2.0)},
            ...                                        {0: (1.4, 2.0), 2: (2.0, 3.0)}]
            ...                                , utilities= [2.0, 9.0 + 4.0])
            >>> print(f.xml([Issue((0.0, 4.0), name='0'), Issue((0.0, 9.0), name='1')
            ... , Issue((0.0, 9.0), name='2')]).strip())
            <issue index="1" name="0" vtype="real" type="real" etype="real">
                <range lowerbound="0.0" upperbound="4.0"></range>
            </issue><issue index="2" name="1" vtype="real" type="real" etype="real">
                <range lowerbound="0.0" upperbound="9.0"></range>
            </issue><issue index="3" name="2" vtype="real" type="real" etype="real">
                <range lowerbound="0.0" upperbound="9.0"></range>
            </issue><utility_function maxutility="-1.0">
                <ufun type="PlainUfun" weight="1" aggregation="sum">
                    <hyperRectangle utility_function="2.0">
                        <INCLUDES index="0" min="1.0" max="2.0" />
                        <INCLUDES index="1" min="1.0" max="2.0" />
                    </hyperRectangle>
                    <hyperRectangle utility_function="13.0">
                        <INCLUDES index="0" min="1.4" max="2.0" />
                        <INCLUDES index="2" min="2.0" max="3.0" />
                    </hyperRectangle>
                </ufun>
            </utility_function>

        """
        output = ""
        for i, issue in enumerate(ivalues(issues)):
            name = issue.name
            if isinstance(issue.values, tuple):
                output += (
                    f'<issue index="{i+1}" name="{name}" vtype="real" type="real" etype="real">\n'
                    f'    <range lowerbound="{issue.values[0]}" upperbound="{issue.values[1]}"></range>\n'
                    f"</issue>")
            elif isinstance(issue.values, int):
                output += (
                    f'<issue index="{i+1}" name="{name}" vtype="integer" type="integer" etype="integer" '
                    f'lowerbound="0" upperbound="{issue.values - 1}"/>\n')
            else:
                output += (
                    f'<issue index="{i+1}" name="{name}" vtype="integer" type="integer" etype="integer" '
                    f'lowerbound="{min(issue.values)}" upperbound="{max(issue.values)}"/>\n'
                )
        # todo find the real maxutility
        output += '<utility_function maxutility="-1.0">\n    <ufun type="PlainUfun" weight="1" aggregation="sum">\n'
        for rect, u, w in zip(self.outcome_ranges, self.mappings,
                              self.weights):
            output += f'        <hyperRectangle utility_function="{u * w}">\n'
            for indx in ikeys(rect):
                values = iget(rect, indx, None)
                if values is None:
                    continue
                if isinstance(values, float) or isinstance(values, int):
                    mn, mx = values, values
                elif isinstance(values, tuple):
                    mn, mx = values
                else:
                    mn, mx = min(values), max(values)
                output += (
                    f'            <INCLUDES index="{indx}" min="{mn}" max="{mx}" />\n'
                )
            output += f"        </hyperRectangle>\n"
        output += "    </ufun>\n</utility_function>"
        return output
예제 #4
0
파일: inout.py 프로젝트: eareyan/negmas
def load_genius_domain(domain_file_name: str
                       , utility_file_names: Optional[List[str]] = None
                       ,
                       agent_factories: Optional[Union[Callable[[], Negotiator], List[Callable[[], Negotiator]]]] = None
                       , force_single_issue=False
                       , cache_and_discretize_outcomes=False
                       , max_n_outcomes: int = 1e6
                       , n_discretization: Optional[int] = None
                       , keep_issue_names=True
                       , keep_value_names=True
                       , normalize_utilities=True
                       , n_steps=None
                       , time_limit=3 * 60  # GENIUS uses 3min time limit by default
                       , max_n_agents=None
                       , dynamic_entry=True
                       , safe_parsing=False
                       , ignore_reserved=False
                       , ignore_discount=False
                       ) \
    -> Tuple[Optional[SAOMechanism], List[dict], Union[Dict[str, Issue], List[Issue]]]:
    """
    Loads a genius domain, creates appropriate negotiators if necessary

    Args:
        domain_file_name:
        utility_file_names:
        agent_factories:
        force_single_issue:
        cache_and_discretize_outcomes:
        max_n_outcomes:
        n_discretization:
        keep_issue_names:
        keep_value_names:
        normalize_utilities:
        n_steps:
        time_limit:
        max_n_agents:
        dynamic_entry:
        safe_parsing:
        ignore_reserved:
        ignore_discount:

    Returns:
        - mechanism (SAOMechanism): A mechanism for the given issues
        - agent_info (List[Dict]): All Negotiator functions from the given file
        - issues Union[Issue, Dict[str, Issue], List[Issue]]] : The issues

    """
    issues, issues_details, mechanism = None, None, None
    if domain_file_name is not None:
        domain_file_name = str(domain_file_name)
        issues_details, _ = Issue.from_genius(
            domain_file_name,
            force_single_issue=False,
            keep_issue_names=True,
            keep_value_names=True,
            safe_parsing=safe_parsing,
            n_discretization=n_discretization)
        if force_single_issue:
            issues, _ = Issue.from_genius(
                domain_file_name,
                force_single_issue=force_single_issue,
                keep_issue_names=keep_issue_names,
                keep_value_names=keep_value_names,
                max_n_outcomes=max_n_outcomes,
                n_discretization=n_discretization)
            if issues is None:
                return None, [], []
        else:
            issues, _ = Issue.from_genius(
                domain_file_name,
                force_single_issue=force_single_issue,
                keep_issue_names=keep_issue_names,
                keep_value_names=keep_value_names,
                safe_parsing=safe_parsing,
                n_discretization=n_discretization)

    agent_info = []
    if utility_file_names is None:
        utility_file_names = []
    utility_file_names = [str(_) for _ in utility_file_names]
    for ufname in utility_file_names:
        utility, discount_factor = UtilityFunction.from_genius(
            file_name=ufname,
            force_single_issue=force_single_issue,
            keep_issue_names=keep_issue_names,
            keep_value_names=keep_value_names,
            normalize_utility=normalize_utilities,
            domain_issues=issues_details,
            safe_parsing=safe_parsing,
            max_n_outcomes=max_n_outcomes,
            ignore_discount=ignore_discount,
            ignore_reserved=ignore_reserved)
        agent_info.append({
            'ufun':
            utility,
            'reserved_value_func':
            utility.reserved_value if utility is not None else 0.0,
            'discount_factor':
            discount_factor
        })
    outcomes = None
    try:
        if force_single_issue or cache_and_discretize_outcomes or len(
                issues) == 1:
            n_outcomes: float = functools.reduce(
                operator.mul, (float(_.cardinality()) if not _.is_continuous()
                               else float(n_discretization)
                               if n_discretization is not None else np.inf
                               for _ in ivalues(issues)), 1.0)
            if n_outcomes < max_n_outcomes:
                outcomes = enumerate_outcomes(
                    issues, keep_issue_names=keep_issue_names)
    except ValueError:
        pass
    if domain_file_name is not None:
        mechanism_name = domain_file_name.split('/')[-1][:-4].replace(
            '-domain', '').replace('_domain', '').replace('domain', '')
        mechanism = SAOMechanism(issues=issues,
                                 outcomes=outcomes,
                                 n_steps=n_steps,
                                 time_limit=time_limit,
                                 max_n_agents=max_n_agents,
                                 dynamic_entry=dynamic_entry,
                                 name=mechanism_name,
                                 keep_issue_names=keep_issue_names)
        if agent_info is not None and len(agent_info) > 0:
            for info in agent_info:
                info['ufun'] = info['ufun'] if info['discount_factor'] is None or info['discount_factor'] == 1.0 else \
                    make_discounted_ufun(ufun=info['ufun'], info=mechanism.info
                                         , discount_per_round=info['discount_factor'], power_per_round=1.0)

    if agent_factories is not None and agent_info is not None and len(
            agent_info) > 0:
        if not isinstance(agent_factories, Iterable):
            agent_factories = [agent_factories] * len(agent_info)
        agents = [factory() for factory in agent_factories[0:len(agent_info)]]
        for a, info in zip(agents, agent_info):
            mechanism.add(a, ufun=info['ufun'])

    return mechanism, agent_info, (issues
                                   if not force_single_issue else [issues])