def test_alternating_offers_mechanism_fails_on_no_offerer(): p = SAOMechanism( outcomes=10, n_steps=10, dynamic_entry=False, publish_n_acceptances=True, publish_proposer=True, ) to_be_offered = [(0, ), (1, ), (2, )] to_be_accepted = [(2, )] a1 = LimitedOutcomesAcceptor(acceptable_outcomes=to_be_offered) a2 = LimitedOutcomesAcceptor(acceptable_outcomes=to_be_accepted) p.add(a1, ufun=MappingUtilityFunction(lambda x: x[0] + 1.0)) p.add(a2, ufun=MappingUtilityFunction(lambda x: x[0] + 1.0)) try: p.run() except RuntimeError: pass a1offers = [ s.current_offer for s in p.history if s.current_proposer == a1.id ] a2offers = [ s.current_offer for s in p.history if s.current_proposer == a2.id ] assert len(p.history) > 0 assert len(a2offers) == 0, "acceptor did not offer" assert len(a1offers) == 0, "acceptor did not offer" assert p.agreement is None, "no agreement"
def ranking_error( self, gt: Union[List[float], Dict[Outcome, float], UtilityFunction], tolerance: float = 0.0, ) -> float: """ Evaluates the utility function against gt counting differences in ranking only Args: gt: Ground truth ufun tolerance: a small tolerance when finding if the ranking is respected Returns: A value between zero and one indicating the ranking error """ if isinstance(gt, list): gt = dict(zip(self.outcomes, gt)) if not isinstance(gt, UtilityFunction): gt = MappingUtilityFunction(gt) rank = ranking(self, self.outcomes) return sum( int(float(gt(w1)) + tolerance < float(gt(w2))) for w1, w2 in zip(rank[:-1], rank[1:])) / (len(self.outcomes) - 1)
def test_loops_are_broken(keep_order): """Tests that loops formed by concurrent negotiations are broken for syn controllers""" from negmas.mechanisms import Mechanism from negmas.sao import SAOSingleAgreementAspirationController a, b, c = ( SAOSingleAgreementAspirationController( ufun=MappingUtilityFunction(lambda x: x["price"]), strict=False), SAOSingleAgreementAspirationController( ufun=MappingUtilityFunction(lambda x: x["price"]), strict=False), SAOSingleAgreementAspirationController( ufun=MappingUtilityFunction(lambda x: x["price"]), strict=False), ) n1 = SAOMechanism( name="ab", issues=[Issue((0.0, 1.0), "price")], n_steps=50, outcome_type=dict, ) n2 = SAOMechanism( name="ac", issues=[Issue((0.0, 1.0), "price")], n_steps=50, outcome_type=dict, ) n3 = SAOMechanism( name="bc", issues=[Issue((0.0, 1.0), "price")], n_steps=50, outcome_type=dict, ) n1.add(a.create_negotiator(name="a>b")) n1.add(b.create_negotiator(name="b>a")) n2.add(a.create_negotiator(name="a>c")) n2.add(c.create_negotiator(name="c>a")) n3.add(b.create_negotiator(name="b>c")) n3.add(c.create_negotiator(name="c>b")) negs = [n1, n2, n3] Mechanism.runall(negs, keep_order) agreements = [neg.state.agreement for neg in negs] assert sum(_ is not None for _ in agreements) > 0
def _respond_to_negotiation_request( self, initiator: str, partners: List[str], issues: List[Issue], annotation: Dict[str, Any], mechanism: AgentMechanismInterface, role: Optional[str], req_id: Optional[str], ) -> Optional[Negotiator]: negotiator = AspirationNegotiator(ufun=MappingUtilityFunction( mapping=lambda x: 1.0 - x["i1"] / 10.0)) return negotiator
def test_lap_ufun_full_ranking(): issues = [Issue(5, "Price"), Issue(5, "Distance")] gt = {(o["Price"], o["Distance"]): 0.2 * o["Price"] - 0.45 * o["Distance"] for o in Issue.enumerate(issues, astype=dict)} full_ranking = [ _[0] for _ in sorted( zip(gt.keys(), gt.values()), key=lambda x: x[1], reverse=True) ] for kind in ("error_sums", "errors"): ufun = RankingLAPUfunLearner(issues=issues, degree=1, kind=kind) ufun.fit(ranking_list=full_ranking) learned_ranking = [ _[0] for _ in sorted( zip(ufun.uvals.keys(), ufun.uvals.values()), key=lambda x: x[1], reverse=True, ) ] if kind == "error_sums": assert full_ranking == learned_ranking, f"Failed on {kind}" assert (ufun.ranking_error(gt=MappingUtilityFunction( lambda o: 0.2 * o[0] - 0.45 * o[1])) == 0.0)
def value_error( self, gt: Union[List[float], Dict[Outcome, float], UtilityFunction] ) -> Tuple[float, float]: """ Finds the error in ufun values against gt (after normalization from 0-1) Args: gt: Ground truth Returns: Mean and std. dev of errors """ if isinstance(gt, list): gt = dict(zip(self.outcomes, gt)) if not isinstance(gt, UtilityFunction): gt = MappingUtilityFunction(gt) data = np.array([[float(gt(outcome)), float(self(outcome))] for outcome in self.outcomes]) mx, mn = data.max(axis=0), data.min(axis=0) data = (data - mn) / (mx - mn) err = (data[:, 0] - data[:, 1])**2 return float(np.sqrt(np.mean(err))), float(np.std(err))
def init(self): """Called once after the agent-world interface is initialized""" # We assume the agent only takes one kind of input. if len(self.consuming.keys()) != 1: raise Exception('The agent is design to consume only one input') self.input_index = list(self.consuming.keys())[0] # We assume the agent only produced one kind of output. if len(self.producing.keys()) != 1: raise Exception('The agent is design to produce only one output') self.output_index = list(self.producing.keys())[0] self.production_cost = self.line_profiles[0][0].cost self.num_intermediate_products = len(self.awi.processes) - 1 # Compute Expected Catalog Prices self.expected_catalog_prices[0] = 1.0 for p in range(1, self.num_intermediate_products + 2): self.expected_catalog_prices[p] = 1.15 * (self.expected_catalog_prices[p - 1] + 2.5) # Initialize book keeping structures. for p in range(0, self.num_intermediate_products + 2): self.storage_history[p] = [] self.contracted_buys_at_t[p], self.contracted_sales_at_t[p], self.executed_buys_at_t[p], self.executed_sales_at_t[p] = {}, {}, {}, {} self.signed_contracts_for_factory = {t: [] for t in range(0, self.awi.n_steps)} for t in range(0, self.awi.n_steps): self.contracted_buys_at_t[p][t] = 0 self.contracted_sales_at_t[p][t] = 0 self.executed_buys_at_t[p][t] = (0, 0) self.executed_sales_at_t[p][t] = (0, 0) # Initialize the negotiator that will negotiate for inputs self.input_negotiator_ufun = MappingUtilityFunction(mapping=lambda outcome: 1 - outcome['unit_price'], reserved_value=INVALID_UTILITY) # Initialize the negotiator that will negotiate for outputs self.output_negotiator_ufun = MappingUtilityFunction( mapping=lambda outcome: (math.exp(outcome['unit_price']) - 1.5) * outcome['quantity'] if outcome["unit_price"] > 0.0 else INVALID_UTILITY) # Set the time limit for posting CFPs. self.limit_post_cfps = self.awi.n_steps - 16 # Set the time limit to sign CFPs to buy input self.limit_sign_time_input_product = self.awi.n_steps - 10 # Initialize the brain of the agent. The brain takes in the input product, the output product, cost of production and num_intm_products. self.agent_brain = AgentBrain(game_length=self.awi.n_steps, input_product_index=self.input_index, output_product_index=self.output_index, production_cost=self.production_cost, num_intermediate_products=self.num_intermediate_products, verbose=self.verbose) # Register interest in all products. self.awi.unregister_interest([self.input_index, self.output_index]) self.awi.register_interest([p for p in range(0, self.num_intermediate_products + 2)]) if self.verbose: # Print some init info for informational purposes print(f'\n+++++++++++++++++++++++++++++++++++++++\n' f'Starting game with a total of {self.awi.n_steps} steps\n' f'\t Expected catalog prices = {self.expected_catalog_prices}\n' f'\t There are {self.num_intermediate_products} intermediate products. \n' f'\t SCML2020World processes = {self.awi.processes}\n' f'\t My Cost = {self.line_profiles[0][0].cost}\n' f'\t I, {self.id}, consume {self.input_index} and produce {self.output_index}\n' f'\t Is the middle man active? {self.middle_man_active}\n' f'+++++++++++++++++++++++++++++++++++++++\n') print(f'Parameters: ' f'\n\t hyper_parameter_optimization = {self.hyper_parameter_optimization}' f'\n\t agent_aspiration_type = {self.agent_aspiration_type}' f'\n\t limit_sign_storage = {self.limit_sign_storage}' f'\n\t limit_number_sales_contracts_at_t = {self.limit_number_sales_contracts_at_t}' f'\n\t limit_number_buys_contracts_at_t = {self.limit_number_buys_contracts_at_t}' f'\n\t cfp_qtty_range_width = {self.cfp_qtty_range_width}' f'\n ------------------------------------') # Which products will the middle man buy and sell? self.middle_man_products = {p for p in range(0, self.num_intermediate_products + 2) if p != self.input_index and p != self.output_index} if self.verbose: print(f'The middle man can buy and sell {self.middle_man_products}')
if self.ami: # the ami is not None, means, can use the factor defined by user! # return self.delta**(getattr(self.ami.state, self.factor) - 1) * sum(w * v for w, v in zip(self.weights, offer)) return sum(w * v for w, v in zip(self.weights, offer)) else: return sum(w * v for w, v in zip(self.weights, offer)) 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 __str__(self): return f"w: {self.weights}, delta: {self.delta}, factor: {self.factor}" MyOpponentUtilityFunction = MappingUtilityFunction( lambda x: random.random() * x[0])