Example #1
0
def test_times_are_calculated(n_outcomes, n_negotiators, n_steps):
    mechanism = SAOMechanism(outcomes=n_outcomes, n_steps=8)
    ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i])
    assert mechanism.state.step == 0
    _strt = time.perf_counter()
    for _ in range(n_steps):
        # print(f"Stepping: {_}")
        mechanism.step()
    time.sleep(0.01)
    duration = time.perf_counter() - _strt
    # assert mechanism.current_step == n_steps
    assert mechanism._current_offer is not None
    assert len(mechanism.stats) == 3
    stats = mechanism.stats
    assert "round_times" in stats.keys()
    assert 0 < sum(stats["round_times"]) < duration
    assert "times" in stats.keys()
    assert "exceptions" in stats.keys()
    assert stats["times"] is not None
    assert stats["exceptions"] is not None
    assert len(stats["times"]) == n_negotiators
    assert len(stats["exceptions"]) == 0
    for i in range(n_negotiators):
        assert 0 < stats["times"][mechanism.negotiators[i].id] < duration
        assert len(stats["exceptions"][mechanism.negotiators[i].id]) == 0
    assert 0 < sum(stats["times"].values()) < duration
Example #2
0
def test_pickling_mechanism(tmp_path):
    import dill as pickle

    file = tmp_path / "mechanism.pck"
    n_outcomes, n_negotiators = 5, 3
    mechanism = SAOMechanism(
        outcomes=n_outcomes,
        n_steps=3,
        offering_is_accepting=True,
        avoid_ultimatum=False,
    )
    ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i])

    assert mechanism.state.step == 0
    with open(file, "wb") as f:
        pickle.dump(mechanism, f)
    with open(file, "rb") as f:
        pickle.load(f)
    assert mechanism.state.step == 0
    mechanism.step()
    with open(file, "wb") as f:
        pickle.dump(mechanism, f)
    with open(file, "rb") as f:
        pickle.load(f)
    assert mechanism.state.step == 1
Example #3
0
def test_exceptions_are_saved():
    n_outcomes, n_negotiators = 10, 2
    mechanism = SAOMechanism(
        outcomes=n_outcomes, n_steps=n_outcomes, ignore_negotiator_exceptions=True
    )
    ufuns = MappingUtilityFunction.generate_random(
        n_negotiators, outcomes=mechanism.outcomes
    )
    mechanism.add(AspirationNegotiator(name=f"agent{0}"), ufun=ufuns[0])
    mechanism.add(MyRaisingNegotiator(name=f"agent{1}"), ufun=ufuns[1])
    assert mechanism.state.step == 0
    mechanism.step()
    mechanism.step()
    mechanism.step()
    assert mechanism.state.step == 1
    assert mechanism._current_offer is not None
    assert len(mechanism.stats) == 3
    stats = mechanism.stats
    assert "times" in stats.keys()
    assert "exceptions" in stats.keys()
    assert stats["exceptions"] is not None
    assert len(stats["exceptions"]) == 1
    # print(stats["exceptions"][mechanism.negotiators[1].id])
    assert len(stats["exceptions"][mechanism.negotiators[1].id]) == 1
    assert exception_str in stats["exceptions"][mechanism.negotiators[1].id][0]
    assert len(stats["exceptions"][mechanism.negotiators[0].id]) == 0
Example #4
0
def test_mechanism_can_run(n_negotiators):
    n_outcomes = 5
    mechanism = SAOMechanism(outcomes=n_outcomes, n_steps=3)
    ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i])
    assert mechanism.state.step == 0
    mechanism.step()
    mechanism.run()
Example #5
0
def test_round_n_agents(n_negotiators):
    n_outcomes = 5
    mechanism = SAOMechanism(outcomes=n_outcomes, n_steps=3)
    ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i])
    assert mechanism.state.step == 0
    mechanism.step()
    assert mechanism.state.step == 1
    assert mechanism._current_offer is not None
Example #6
0
 def on_new_cfp(self, cfp: "CFP"):
     """Call whenever a CFP is posted. """
     if cfp.publisher != self.id:
         self.request_negotiation(
             cfp=cfp,
             negotiator=AspirationNegotiator(
                 ufun=self.output_negotiator_ufun
                 if cfp.is_buy
                 else self.input_negotiator_ufun,
                 aspiration_type=self.agent_aspiration_type,
             ),
         )
Example #7
0
def test_checkpointing_mechanism(tmp_path):
    file = tmp_path
    n_outcomes, n_negotiators = 5, 3
    mechanism = SAOMechanism(
        outcomes=n_outcomes,
        n_steps=3,
        offering_is_accepting=True,
        avoid_ultimatum=False,
    )
    ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i])

    assert mechanism.state.step == 0
    file_name = mechanism.checkpoint(file)

    info = SAOMechanism.checkpoint_info(file_name)
    assert isinstance(info["time"], str)
    assert info["step"] == 0
    assert info["type"].endswith("SAOMechanism")
    assert info["id"] == mechanism.id
    assert info["name"] == mechanism.name

    mechanism, info = SAOMechanism.from_checkpoint(file_name, return_info=True)
    assert isinstance(info["time"], str)
    assert info["step"] == 0
    assert info["type"].endswith("SAOMechanism")
    assert info["id"] == mechanism.id
    assert info["name"] == mechanism.name

    assert mechanism.state.step == 0
    mechanism.step()

    file_name = mechanism.checkpoint(file)

    info = SAOMechanism.checkpoint_info(file_name)
    assert isinstance(info["time"], str)
    assert info["step"] == 1
    assert info["type"].endswith("SAOMechanism")
    assert info["id"] == mechanism.id
    assert info["name"] == mechanism.name

    mechanism, info = SAOMechanism.from_checkpoint(file_name, return_info=True)
    assert isinstance(info["time"], str)
    assert info["step"] == 1
    assert info["type"].endswith("SAOMechanism")
    assert info["id"] == mechanism.id
    assert info["name"] == mechanism.name

    mechanism.run()
Example #8
0
    def respond_to_negotiation_request(self, cfp: "CFP", partner: str) -> Optional[Negotiator]:
        """Called whenever someone (partner) is requesting a negotiation with the agent about a Call-For-Proposals
        (cfp) that was earlier published by this agent to the bulletin-board

        Returning `None` means rejecting to enter this negotiation

        """
        if cfp.publisher == self.id and cfp.is_buy:
            neg_ufun = self.input_negotiator_ufun
        elif cfp.publisher == self.id and not cfp.is_buy:
            neg_ufun = self.output_negotiator_ufun
        else:
            if self.verbose:
                print(f'--- WARNING!!! WARNING!!! Rejecting a negotiation --- ')
            return None
        return AspirationNegotiator(ufun=neg_ufun, aspiration_type=self.agent_aspiration_type)
Example #9
0
 def test_loading_laptop_no_names(self, data_folder):
     domain, agents_info, issues = load_genius_domain_from_folder(
         os.path.join(data_folder, "Laptop"),
         force_single_issue=True,
         keep_issue_names=False,
         keep_value_names=False,
         agent_factories=lambda: AspirationNegotiator(),
     )
     # [domain.add(LimitedOutcomesNegotiator(outcomes=n_outcomes)
     #            , ufun=_['ufun']) for _ in agents_info]
     front, _ = domain.pareto_frontier(sort_by_welfare=True)
     assert front == [
         (0.7715533992081258, 0.8450562871935449),
         (0.5775524426410947, 1.0),
         (1.0, 0.5136317604069089),
         (0.8059990434329689, 0.6685754732133642),
     ]
Example #10
0
def test_mechanism_runall(n_negotiators, oia):
    n_outcomes = 5
    mechanisms = []
    for _ in range(10):
        mechanism = SAOMechanism(
            outcomes=n_outcomes,
            n_steps=random.randint(3, 20),
            offering_is_accepting=oia,
            avoid_ultimatum=False,
        )
        ufuns = MappingUtilityFunction.generate_random(1, outcomes=n_outcomes)
        for i in range(n_negotiators):
            mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[0])
        mechanisms.append(mechanism)

    states = SAOMechanism.runall(mechanisms)
    assert len(states) == 10
    assert not any(_.running for _ in states)
Example #11
0
def test_auto_checkpoint(tmp_path, single_checkpoint, checkpoint_every, exist_ok):
    import shutil

    new_folder: Path = tmp_path / unique_name("empty", sep="")
    new_folder.mkdir(parents=True, exist_ok=True)
    shutil.rmtree(new_folder)
    new_folder.mkdir(parents=True, exist_ok=True)
    filename = "mechanism"

    n_outcomes, n_negotiators = 5, 3
    n_steps = 50
    mechanism = SAOMechanism(
        outcomes=n_outcomes,
        n_steps=n_steps,
        offering_is_accepting=True,
        avoid_ultimatum=False,
        checkpoint_every=checkpoint_every,
        checkpoint_folder=new_folder,
        checkpoint_filename=filename,
        extra_checkpoint_info=None,
        exist_ok=exist_ok,
        single_checkpoint=single_checkpoint,
    )
    ufuns = MappingUtilityFunction.generate_random(n_negotiators, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(
            AspirationNegotiator(name=f"agent{i}"),
            ufun=ufuns[i],
            aspiration_type="conceder",
        )

    mechanism.run()

    if 0 < checkpoint_every <= n_steps:
        if single_checkpoint:
            assert len(list(new_folder.glob("*"))) == 2
        else:
            assert len(list(new_folder.glob("*"))) >= 2 * (
                max(1, mechanism.state.step // checkpoint_every)
            )
    elif checkpoint_every > n_steps:
        assert len(list(new_folder.glob("*"))) == 2
    else:
        assert len(list(new_folder.glob("*"))) == 0
Example #12
0
def test_mechanism_runs_with_offering_not_accepting(n_negotiators, oia):
    n_outcomes = 5
    mechanism = SAOMechanism(
        outcomes=n_outcomes, n_steps=3, offering_is_accepting=oia, avoid_ultimatum=False
    )
    ufuns = MappingUtilityFunction.generate_random(1, outcomes=n_outcomes)
    for i in range(n_negotiators):
        mechanism.add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[0])
    assert mechanism.state.step == 0
    mechanism.step()
    assert mechanism._current_proposer.name == "agent0"
    assert mechanism._n_accepting == n_negotiators + int(oia) - 1
    assert (mechanism.agreement is not None) is oia
    if mechanism.agreement is not None:
        return
    mechanism.step()
    assert mechanism._current_proposer.name == "agent0"
    assert mechanism._n_accepting == n_negotiators
    assert mechanism.agreement is not None
Example #13
0
def test_single_agreement_gets_one_agreement(n_negs, strict):
    from negmas.mechanisms import Mechanism
    from negmas.sao import AspirationNegotiator, SAOSingleAgreementRandomController

    c = SAOSingleAgreementRandomController(strict=strict)
    negs = [
        SAOMechanism(
            issues=[Issue((0.0, 1.0), "price")], n_steps=50, outcome_type=tuple
        )
        for _ in range(n_negs)
    ]
    for i, neg in enumerate(negs):
        neg.add(
            AspirationNegotiator(aspiration_type="linear", name=f"opponent-{i}"),
            ufun=LinearUtilityFunction(weights=[1.0]),
        )
        neg.add(c.create_negotiator(name=f"against-{i}"))

    Mechanism.runall(negs, True)
    agreements = [neg.state.agreement for neg in negs]
    if strict:
        # assert that the controller never had multiple agreements
        assert sum(_ is not None for _ in agreements) == 1
    else:
        # assert that the controller never accepted twice. It may still have multiple agreements though
        assert (
            len(
                [
                    neg.state.agreement
                    for neg in negs
                    if neg.state.agreement is not None
                    and neg.state.current_proposer.startswith("opponent")
                ]
            )
            < 2
        )
Example #14
0
def test_sync_controller(n_negotiations, n_negotiators, oia):
    n_outcomes = 2

    mechanisms = []
    controller = MySAOSync()
    for i in range(n_negotiators):
        mechanisms.append(
            SAOMechanism(
                outcomes=n_outcomes,
                n_steps=5,
                offering_is_accepting=oia,
                avoid_ultimatum=False,
            )
        )
        ufuns = MappingUtilityFunction.generate_random(
            n_negotiators, outcomes=n_outcomes
        )
        for i in range(n_negotiators):
            mechanisms[-1].add(AspirationNegotiator(name=f"agent{i}"), ufun=ufuns[i])

        mechanisms[-1].add(controller.create_negotiator())

    states = SAOMechanism.runall(mechanisms)
    assert all(_.agreement is not None for _ in states)
Example #15
0
    def step(self):
        """Called at every production step by the world"""

        # Book keeping
        for p in range(0, self.num_intermediate_products + 2):
            self.storage_history[p].append(self.awi.state.storage[p])
        self.wallet_history.append(self.awi.state.wallet)

        # ---------------- MPNVM STUFF --------
        # Plan how many inputs to go for. We ask the brain for the number of inputs. If the brain could not find data, we go for a fixed number.
        plan_for_inputs = self.agent_brain.get_plan_for_inputs(self.current_step + 1, self.verbose) if self.agent_brain.there_is_data else [self.fixed_number_of_inputs]

        # Post a call for proposal to buy inputs using the plan computed before. We limit the call for buy stuff up to 15 steps before the end of game.
        # @todo There could be a further optimization problem here, as in, how many CFPs to post? At the moment we just post one.
        if self.current_step <= self.limit_post_cfps and self.storage_history[self.output_index][-1] <= self.limit_sign_storage:
            self.awi.register_cfp(CFP(is_buy=True,
                                      publisher=self.name,
                                      product=self.input_index,
                                      # @todo The time of negotiation matters a lot for longer chains. For chain of size 4, +5, +15 worked.
                                      time=(self.current_step + self.cfp_time_lower_bound, self.current_step + self.cfp_time_upper_bound),
                                      unit_price=(0.0, self.expected_catalog_prices[self.input_index]),
                                      quantity=(max(1, plan_for_inputs[0] - self.cfp_qtty_range_width), plan_for_inputs[0] + self.cfp_qtty_range_width)))

        # Send all inputs to production to get outputs. We always turn every input into output. We don't hold on to inputs.
        schedule_for_production = 0
        for l in range(0, 10):
            if self.storage_history[self.input_index][-1] > 0 and \
                    schedule_for_production <= self.storage_history[self.input_index][-1] and \
                    self.awi.current_step < self.awi.n_steps - 1:
                self.awi.schedule_production(l, self.awi.current_step)
                self.simulator.schedule(Job(profile=l, time=self.awi.current_step, line=-1, action='run', contract=None, override=False))
                schedule_for_production += 1

        # Read all the CFPs and engage in negotiations with agents that want to buy our output.
        the_cfps = self.awi.bb_query('cfps', None)
        if the_cfps:
            for i, c in the_cfps.items():
                c: CFP
                # Negotiate about outputs. It is highly unlikely the agent can have any output product ready before parameter self.start_sell_negotiation_bound
                if c.publisher != self.id and c.is_buy and c.product == self.output_index and c.min_time >= self.start_sell_negotiation_bound:
                    self.request_negotiation(cfp=c, negotiator=AspirationNegotiator(ufun=self.output_negotiator_ufun,
                                                                                    aspiration_type=self.agent_aspiration_type))
                # @todo Negotiate about inputs. This is currently not active, as in the case of inputs our agent is proactive. Should we activate it?
                # elif not c.is_buy and c.product == self.input_index:
                #    self.request_negotiation(cfp=c, negotiator=AspirationNegotiator(name="my-goog-buyer", ufun=self.input_negotiator_ufun))

        # ---------------- MIDDLE MAN STUFF --------
        # @todo Add parameters for the ranges over which we post CFPs for the middle man.
        if self.middle_man_active:
            # First, post CFP to buy and sell stuff, up to time given by parameter self.limit_post_cfps.
            if self.current_step <= self.limit_post_cfps:
                for p in self.middle_man_products:
                    # Post a CFP to buy stuff to be later resold
                    self.awi.register_cfp(CFP(is_buy=True,
                                              publisher=self.name,
                                              product=p,
                                              time=(self.current_step + self.cfp_time_lower_bound, self.current_step + self.cfp_time_upper_bound),
                                              unit_price=(0.0, self.expected_catalog_prices[p]),
                                              quantity=(1, 5)))
                    # Post a CFP to sell stuff
                    self.awi.register_cfp(CFP(is_buy=False,
                                              publisher=self.name,
                                              product=p,
                                              time=(self.current_step + self.cfp_time_lower_bound, self.current_step + self.cfp_time_upper_bound),
                                              unit_price=(3.5, 25.5),
                                              quantity=(1, 5)))
            if the_cfps:
                for i, c, in the_cfps.items():
                    c: CFP
                    # Make sure we don't respond to ourselves.
                    if c.publisher != self.id:
                        # Respond to CFPs when we try to buy stuff for the middle man
                        if c.product in self.middle_man_products and not c.is_buy:
                            # print(f'Responding to a cfp from {c.publisher} to buy {c.product}. Here it is: CFP = {c}')
                            self.request_negotiation(cfp=c, negotiator=AspirationNegotiator(ufun=self.input_negotiator_ufun, aspiration_type=self.agent_aspiration_type))
                        # Respond to CFPs when we try to sell stuff for the middle man
                        if c.product in self.middle_man_products and c.is_buy:
                            # print(f'Responding to a cfp to sell CFP for product {c.product} by {c.publisher},  CFP = {c}')
                            self.request_negotiation(cfp=c, negotiator=AspirationNegotiator(ufun=self.output_negotiator_ufun,
                                                                                            aspiration_type=self.agent_aspiration_type,
                                                                                            max_aspiration=0.95))

        # DEBUG INFO
        if self.verbose:
            # Print some debug info for development purposes.
            self.print_debug_info(plan_for_inputs, self.storage_history[self.input_index][-1], self.storage_history[self.output_index][-1])

        # Save results of the hyper-parameter optimization
        if self.current_step + 1 == self.awi.n_steps:
            if not os.path.exists('my_results'):
                os.makedirs('my_results')
            results_file_name = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
            with open(f'my_results/{results_file_name}.dat', 'w') as file:
                file.write(f'{self.marginal_calculation_on_sign_contract},'
                           f'{self.limit_sign_storage},'
                           f'{self.limit_number_buys_contracts_at_t},'
                           f'{self.limit_number_sales_contracts_at_t},'
                           f'{self.cfp_qtty_range_width},'
                           f'{self.input_index},{self.output_index},'
                           f'{self.num_intermediate_products},'
                           f'{self.wallet_history[-1]}')
Example #16
0
def test_aspiration_continuous_issues(
    n_negotiators, n_issues, presort, randomize_offers
):
    for _ in range(5):
        mechanism = SAOMechanism(
            issues=[Issue(values=(0.0, 1.0), name=f"i{i}") for i in range(n_issues)],
            n_steps=10,
        )
        ufuns = [
            LinearUtilityFunction(
                weights=[3.0 * random.random(), 2.0 * random.random()],
                reserved_value=0.0,
            )
            for _ in range(n_negotiators)
        ]
        best_outcome = tuple([1.0] * n_issues)
        worst_outcome = tuple([0.0] * n_issues)
        i = 0
        assert mechanism.add(
            AspirationNegotiator(
                name=f"agent{i}",
                presort=presort,
                randomize_offer=randomize_offers,
                ufun=ufuns[i],
                ufun_max=ufuns[i](best_outcome),
                ufun_min=ufuns[i](worst_outcome),
            )
        ), "Cannot add negotiator"
        for i in range(1, n_negotiators):
            assert mechanism.add(
                AspirationNegotiator(
                    name=f"agent{i}",
                    presort=presort,
                    randomize_offer=randomize_offers,
                    ufun_max=ufuns[i](best_outcome),
                    ufun_min=ufuns[i](worst_outcome),
                ),
                ufun=ufuns[i],
            ), "Cannot add negotiator"
        assert mechanism.state.step == 0
        agents = dict(zip([_.id for _ in mechanism.negotiators], mechanism.negotiators))
        offers = defaultdict(list)
        while not mechanism.state.ended:
            mechanism.step()
            for neg_id, offer in mechanism.state.new_offers:
                assert neg_id in agents.keys()
                neg = agents[neg_id]
                prev = offers[neg_id]
                last_offer = prev[-1] if len(prev) > 0 else float("inf")
                if randomize_offers:
                    assert neg.utility_function(offer) <= neg.utility_function(
                        best_outcome
                    )
                else:
                    assert neg.utility_function(offer) <= last_offer
                    if not presort:
                        assert (
                            -neg.tolerance
                            <= (
                                neg.utility_function(offer)
                                - neg.aspiration(
                                    (mechanism.state.step) / mechanism.n_steps
                                )
                                * neg.utility_function(best_outcome)
                            )
                            < pow(neg.tolerance, 0.5 / neg.n_trials) + neg.tolerance
                        )
                    # else:
                    #     assert -neg.tolerance <= (
                    #         neg.utility_function(offer)
                    #         - neg.aspiration(
                    #             (mechanism.state.step - 1) / mechanism.n_steps
                    #         )
                    #         * neg.utility_function(best_outcome)
                    #     )

                offers[neg_id].append(neg.utility_function(offer))