def eval(self, offer: Optional["Outcome"]) -> Optional[UtilityValue]: if offer is None: return self.reserved_value if self.issue_utilities is None: raise ValueError( "No issue utilities were set. Call set_params() or use the constructor" ) u = {} for k in ikeys(self.issue_utilities): v = iget(offer, k) u[k] = gmap(iget(self.issue_utilities, k), v) return self.f(u)
def xml(self, issues: List[Issue]) -> str: output = "" keys = list(ikeys(issues)) for i, k in enumerate(keys): issue_name = iget(issues, k).name output += f'<issue index="{i+1}" etype="discrete" type="discrete" vtype="discrete" name="{issue_name}">\n' vals = iget(issues, k).all for indx, u in enumerate(vals): output += ( f' <item index="{indx+1}" value="{u}" evaluation="{u}" />\n' ) output += "</issue>\n" for i, k in enumerate(keys): output += ( f'<weight index="{i+1}" value="{iget(self.weights, k)}">\n</weight>\n' ) return output
def eval(self, offer: Optional["Outcome"]) -> Optional[UtilityValue]: if offer is None: return self.reserved_value u = ExactUtilityValue(0.0) for k in ikeys(self.issue_utilities): if isinstance(offer, tuple): v = iget(offer, self.issue_indices[k]) else: v = iget(offer, k) current_utility = gmap(iget(self.issue_utilities, k), v) if current_utility is None: return None w = iget(self.weights, k) # type: ignore if w is None: return None try: u += w * current_utility except FloatingPointError: continue return u
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))
def __init__( self, outcomes: Iterable["Outcome"], distributions: Iterable["UtilityDistribution"] = None, issue_names: Iterable[str] = None, name=None, reserved_value: UtilityValue = float("-inf"), ami: AgentMechanismInterface = None, outcome_type: Optional[Type] = None, id=None, ): super().__init__( name=name, outcome_type=outcome_type, reserved_value=reserved_value, ami=ami, id=id, ) outcomes, distributions = ( list(outcomes), (list(distributions) if distributions is not None else None), ) if len(outcomes) < 1: raise ValueError( "IPUtilityFunction cannot be initialized with zero outcomes") self.tupelized = False self.n_issues = len(outcomes[0]) if issue_names is None: self.issue_names = sorted(ikeys(outcomes[0])) else: self.issue_names = range(len(outcomes[0])) self.issue_keys = dict(zip(range(self.n_issues), self.issue_names)) if not isinstance(outcomes[0], tuple): outcomes = [ tuple(iget(_, key, None) for key in self.issue_names) for _ in outcomes ] self.tupelized = True if distributions is None: distributions = [ UtilityDistribution(dtype="uniform", loc=0.0, scale=1.0) for _ in range(len(outcomes)) ] self.distributions = dict(zip(outcomes, distributions))
def xml(self, issues: List[Issue]) -> str: """Generates an XML string representing the utility function Args: 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> <BLANKLINE> >>> 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> <BLANKLINE> """ output = "" keys = list(ikeys(issues)) for i, k in enumerate(keys): issue = iget(issues, k) issue_name = issue.name if issue.is_float(): output += f'<issue index="{i + 1}" etype="real" type="real" vtype="real" name="{issue_name}">\n' output += f'<range lowerbound = {issue.min_value} upperbound = {issue.max_value} ></range>' # elif issue.is_integer(): # output += f'<issue index="{i + 1}" etype="integer" type="integer" vtype="integer" name="{issue_name}">\n' # output += f'<range lowerbound = {issue.min_value} upperbound = {issue.max_value} ></range>' else: output += f'<issue index="{i+1}" etype="discrete" type="discrete" vtype="discrete" name="{issue_name}">\n' vals = iget(issues, k).all for indx, v in enumerate(vals): try: u = gmap(iget(self.issue_utilities, issue_name), v) except: u = gmap(iget(self.issue_utilities, k), v) v_ = (v if not (isinstance(v, tuple) or isinstance(v, list)) else "-".join([str(_) for _ in v])) output += ( f' <item index="{indx+1}" value="{v_}" evaluation="{u}" />\n' ) output += "</issue>\n" if isinstance(issues, dict): if isinstance(self.weights, dict): weights = self.weights else: weights = {k: v for k, v in zip(ikeys(issues), self.weights)} else: if isinstance(self.weights, list): weights = self.weights else: weights = list(self.weights.get(i.name, 1.0) for i in issues) for i, k in enumerate(keys): output += f'<weight index="{i+1}" value="{iget(weights, k)}">\n</weight>\n' return output
def xml(self, issues: List[Issue]) -> str: """Generates an XML string representing the utility function Args: issues: Examples: >>> issues = [Issue(values=10, name='i1'), Issue(values=4, name='i2')] >>> f = LinearUtilityFunction(weights=[1.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" /> <item index="2" value="1" evaluation="1" /> <item index="3" value="2" evaluation="2" /> <item index="4" value="3" evaluation="3" /> <item index="5" value="4" evaluation="4" /> <item index="6" value="5" evaluation="5" /> <item index="7" value="6" evaluation="6" /> <item index="8" value="7" evaluation="7" /> <item index="9" value="8" evaluation="8" /> <item index="10" value="9" evaluation="9" /> </issue> <issue index="2" etype="discrete" type="discrete" vtype="discrete" name="i2"> <item index="1" value="0" evaluation="0" /> <item index="2" value="1" evaluation="1" /> <item index="3" value="2" evaluation="2" /> <item index="4" value="3" evaluation="3" /> </issue> <weight index="1" value="1.0"> </weight> <weight index="2" value="4.0"> </weight> <BLANKLINE> """ output = "" keys = list(ikeys(issues)) for i, k in enumerate(keys): issue = iget(issues, k) issue_name = issue.name if issue.is_float(): output += f'<issue index="{i + 1}" etype="real" type="real" vtype="real" name="{issue_name}">\n' output += f'<range lowerbound = {issue.min_value} upperbound = {issue.max_value} ></range>' # elif issue.is_integer(): # output += f'<issue index="{i + 1}" etype="integer" type="integer" vtype="integer" name="{issue_name}">\n' # output += f'<range lowerbound = {issue.min_value} upperbound = {issue.max_value} ></range>' else: output += f'<issue index="{i+1}" etype="discrete" type="discrete" vtype="discrete" name="{issue_name}">\n' vals = iget(issues, k).all bias = iget(self.biases, k, 0.0) for indx, u in enumerate(vals): uu = issue.value_type(u + bias) output += f' <item index="{indx+1}" value="{uu}" evaluation="{u}" />\n' output += "</issue>\n" if isinstance(issues, dict): if isinstance(self.weights, dict): weights = self.weights else: weights = {k: v for k, v in zip(ikeys(issues), self.weights)} else: if isinstance(self.weights, list) or isinstance( self.weights, tuple): weights = list(self.weights) else: weights = list(self.weights.get(i.name, 1.0) for i in issues) for i, k in enumerate(keys): output += f'<weight index="{i+1}" value="{iget(weights, k)}">\n</weight>\n' return output
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