LinearUtilityAggregationFunction

class negmas.utilities.LinearUtilityAggregationFunction(issue_utilities: Union[MutableMapping[Any, Union[Callable[[Any], Any], Mapping, Sequence]], Sequence[Union[Callable[[Any], Any], Mapping, Sequence]]], weights: Optional[Union[Mapping[Any, float], Sequence[float]]] = None, name: Optional[str] = None, reserved_value: Union[negmas.helpers.Distribution, float] = - inf, ami: Optional[negmas.common.AgentMechanismInterface] = None, outcome_type: Optional[Type] = None, id: Optional[str] = None)[source]

Bases: negmas.utilities.UtilityFunction

A linear aggregation utility function for multi-issue negotiations.

Models a linear utility function using predefined weights:.

Parameters
  • issue_utilities – utility functions for individual issues

  • weights – weights for combining issue_utilities

  • name – name of the utility function. If None a random name will be generated.

Notes

The utility value is calculated as:

\[u = \sum_{i=0}^{n_{outcomes}-1} {w_i * u_i(\omega_i)}\]

Examples

>>> from negmas.utilities.nonlinear import MappingUtilityFunction
>>> issues = [Issue((10.0, 20.0), 'price'), Issue(['delivered', 'not delivered'], 'delivery')
...           , Issue(5, 'quality')]
>>> print(list(map(str, issues)))
['price: (10.0, 20.0)', "delivery: ['delivered', 'not delivered']", 'quality: (0, 4)']
>>> f = LinearUtilityAggregationFunction({'price': lambda x: 2.0*x
...                          , 'delivery': {'delivered': 10, 'not delivered': -10}
...                          , 'quality': MappingUtilityFunction(lambda x: x-3)}
...         , weights={'price': 1.0, 'delivery': 2.0, 'quality': 4.0})
>>> float(f({'quality': 2, 'price': 14.0, 'delivery': 'delivered'})
...       ) -  (1.0*(2.0*14)+2.0*10+4.0*(2.0-3.0))
0.0
>>> f = LinearUtilityAggregationFunction({'price': lambda x: 2.0*x
...                          , 'delivery': {'delivered': 10, 'not delivered': -10}}
...         , weights={'price': 1.0, 'delivery': 2.0})
>>> float(f({'quality': 2, 'price': 14.0, 'delivery': 'delivered'})) - (1.0*(2.0*14)+2.0*10)
0.0

You can use lists instead of dictionaries for defining outcomes, weights but that is less readable

>>> f = LinearUtilityAggregationFunction([lambda x: 2.0*x
...                          , {'delivered': 10, 'not delivered': -10}
...                          , MappingUtilityFunction(lambda x: x-3)]
...         , weights=[1.0, 2.0, 4.0])
>>> float(f((14.0, 'delivered', 2))) - (1.0*(2.0*14)+2.0*10+4.0*(2.0-3.0))
0.0
Remarks:

The mapping need not use all the issues in the output as the last example show.

Methods Summary

eval(offer)

Calculate the utility value for a given outcome.

from_dict(d)

random(issues[, reserved_value, normalized])

Generates a random ufun of the given type

to_dict()

utility_range([issues, outcomes, …])

Finds the range of the given utility function for the given outcomes

xml(issues)

Generates an XML string representing the utility function

Methods Documentation

eval(offer: Optional[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]])Optional[Union[negmas.helpers.Distribution, float]][source]

Calculate the utility value for a given outcome.

Parameters

offer – The offer to be evaluated.

Returns

The utility_function value which may be a distribution.

If None it means the utility_function value cannot be calculated.

Return type

UtilityValue

Remarks:
  • You cannot return None from overriden eval() functions but raise an exception (ValueError) if it was not possible to calculate the UtilityValue.

  • Typehint the return type as a UtilityValue instead of a float for the benefit of inspection code.

  • Return the reserved value if the offer was None

  • NEVER call the baseclass using super() when overriding this method. Calling super will lead to an infinite loop.

  • The default implementation assumes that is_better is defined and uses it to do the evaluation. Note that the default implementation of is_better does assume that eval is defined and uses it. This means that failing to define both leads to an infinite loop.

classmethod from_dict(d)[source]
classmethod random(issues: List[negmas.outcomes.Issue], reserved_value=(0.0, 1.0), normalized=True, **kwargs)[source]

Generates a random ufun of the given type

to_dict()[source]
utility_range(issues: Optional[List[negmas.outcomes.Issue]] = None, outcomes: Optional[Collection[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]]] = None, infeasible_cutoff: Optional[float] = None, return_outcomes=False, max_n_outcomes=1000, ami=None)Union[Tuple[Union[negmas.helpers.Distribution, float], Union[negmas.helpers.Distribution, float]], Tuple[Union[negmas.helpers.Distribution, float], Union[negmas.helpers.Distribution, float], Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]], Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]]][source]

Finds the range of the given utility function for the given outcomes

Parameters
  • self – The utility function

  • issues – List of issues (optional)

  • outcomes – A collection of outcomes (optional)

  • infeasible_cutoff – A value under which any utility is considered infeasible and is not used in calculation

  • return_outcomes – If true, will also return an outcome for min and max utils

  • max_n_outcomes – the maximum number of outcomes to try sampling (if sampling is used and outcomes are not given)

  • ami – Optional AMI to use

Returns

A utility function that is guaranteed to be normalized for the set of given outcomes

Return type

UtilityFunction

xml(issues: List[negmas.outcomes.Issue])str[source]

Generates an XML string representing the utility function

Parameters

issues

Examples

>>> from negmas.utilities.nonlinear import MappingUtilityFunction
>>> issues = [Issue(values=10, name='i1'), Issue(values=['delivered', 'not delivered'], name='i2')
...     , Issue(values=4, name='i3')]
>>> f = LinearUtilityAggregationFunction([lambda x: 2.0*x
...                          , {'delivered': 10, 'not delivered': -10}
...                          , MappingUtilityFunction(lambda x: x-3)]
...         , weights=[1.0, 2.0, 4.0])
>>> print(f.xml(issues))
<issue index="1" etype="discrete" type="discrete" vtype="discrete" name="i1">
    <item index="1" value="0" evaluation="0.0" />
    <item index="2" value="1" evaluation="2.0" />
    <item index="3" value="2" evaluation="4.0" />
    <item index="4" value="3" evaluation="6.0" />
    <item index="5" value="4" evaluation="8.0" />
    <item index="6" value="5" evaluation="10.0" />
    <item index="7" value="6" evaluation="12.0" />
    <item index="8" value="7" evaluation="14.0" />
    <item index="9" value="8" evaluation="16.0" />
    <item index="10" value="9" evaluation="18.0" />
</issue>
<issue index="2" etype="discrete" type="discrete" vtype="discrete" name="i2">
    <item index="1" value="delivered" evaluation="10" />
    <item index="2" value="not delivered" evaluation="-10" />
</issue>
<issue index="3" etype="discrete" type="discrete" vtype="discrete" name="i3">
    <item index="1" value="0" evaluation="-3" />
    <item index="2" value="1" evaluation="-2" />
    <item index="3" value="2" evaluation="-1" />
    <item index="4" value="3" evaluation="0" />
</issue>
<weight index="1" value="1.0">
</weight>
<weight index="2" value="2.0">
</weight>
<weight index="3" value="4.0">
</weight>

>>> print(f.xml({i:_ for i, _ in enumerate(issues)}))
<issue index="1" etype="discrete" type="discrete" vtype="discrete" name="i1">
    <item index="1" value="0" evaluation="0.0" />
    <item index="2" value="1" evaluation="2.0" />
    <item index="3" value="2" evaluation="4.0" />
    <item index="4" value="3" evaluation="6.0" />
    <item index="5" value="4" evaluation="8.0" />
    <item index="6" value="5" evaluation="10.0" />
    <item index="7" value="6" evaluation="12.0" />
    <item index="8" value="7" evaluation="14.0" />
    <item index="9" value="8" evaluation="16.0" />
    <item index="10" value="9" evaluation="18.0" />
</issue>
<issue index="2" etype="discrete" type="discrete" vtype="discrete" name="i2">
    <item index="1" value="delivered" evaluation="10" />
    <item index="2" value="not delivered" evaluation="-10" />
</issue>
<issue index="3" etype="discrete" type="discrete" vtype="discrete" name="i3">
    <item index="1" value="0" evaluation="-3" />
    <item index="2" value="1" evaluation="-2" />
    <item index="3" value="2" evaluation="-1" />
    <item index="4" value="3" evaluation="0" />
</issue>
<weight index="1" value="1.0">
</weight>
<weight index="2" value="2.0">
</weight>
<weight index="3" value="4.0">
</weight>