scml.oneshot.agent ================== .. py:module:: scml.oneshot.agent .. autoapi-nested-parse:: Implements the base classes for all agents that can join a `SCML2020OneShotWorld`. Remarks: - You can access all of the negotiators associated with the agent using `self.negotiators` which is a dictionary mapping the `negotiator_id` to a tuple of two values: The `SAONegotiator` object and a key-value context dictionary. In 2021, the context will always be empty. - The `negotiator_id` associated with a negotiation with some partner will be the same as the agent ID of that partner. This means that all negotiators engaged with some partner over all simulation steps will have the same ID which is useful if you are keeping information about past negotiations and partner behavior. Classes ------- .. autoapisummary:: scml.oneshot.agent.OneShotAgent scml.oneshot.agent.OneShotSyncAgent scml.oneshot.agent.OneShotSingleAgreementAgent scml.oneshot.agent.EndingNegotiator scml.oneshot.agent.OneShotIndNegotiatorsAgent Module Contents --------------- .. py:class:: OneShotAgent(owner=None, ufun: scml.oneshot.OneShotUFun | None = None, name=None) Bases: :py:obj:`negmas.SAOController`, :py:obj:`negmas.Entity`, :py:obj:`abc.ABC` Base class for all agents in the One-Shot game. Remarks: - You can access all of the negotiators associated with the agent using `self.negotiators` which is a dictionary mapping the `negotiator_id` to a tuple of two values: The `SAONegotiator` object and a key-value context dictionary. In 2021, the context will always be empty. - The `negotiator_id` associated with a negotiation with some partner will be the same as the agent ID of that partner. This means that all negotiators engaged with some partner over all simulation steps will have the same ID which is useful if you are keeping information about past negotiations and partner behavior. .. py:attribute:: _awi :value: None .. py:attribute:: _owner :value: None .. py:property:: awi :type: scml.oneshot.OneShotAWI Returns a `OneShotAWI` object for accessing the simulation. .. py:property:: running_negotiations :type: list[negmas.situated.RunningNegotiationInfo] The negotiations currently requested by the agent. :returns: A list of negotiation information objects (`RunningNegotiationInfo`) .. py:property:: unsigned_contracts :type: list[negmas.Contract] All contracts that are not yet signed. .. py:method:: init() Called once after the AWI is set. Remarks: - Use this for any proactive initialization code. .. py:method:: make_ufun(add_exogenous=False) Creates a utility function for the agent. :param add_exogenous: If `True` then the exogenous contracts of the agent will be automatically added whenever the ufun is evaluated for any set of contracts, offers or otherwise. Remarks: - You can always as assume that self.ufun returns the ufun for your. You will not need to directly use this method in most cases. .. py:method:: before_step() Called at the beginning of every step. Remarks: - Use this for any proactive code that needs to be done every simulation step. .. py:method:: step() Called at the end of every step. Remarks: - Use this for any proactive code that needs to be done every simulation step. .. py:method:: connect_to_oneshot_adapter(owner) Connects the agent to its adapter (used internally) .. py:method:: connect_to_2021_adapter(owner) Connects the agent to its adapter (used internally) .. py:method:: propose(negotiator_id: str, state: negmas.SAOState) -> negmas.Outcome | None :abstractmethod: Proposes an offer to one of the partners. :param negotiator_id: ID of the negotiator (and partner) :param state: Mechanism state including current step :returns: an outcome to offer. .. py:method:: respond(negotiator_id: str, state: negmas.SAOState, source=None) -> negmas.ResponseType Responds to an offer from one of the partners. :param negotiator_id: ID of the negotiator (and partner) :param state: Mechanism state including current step :returns: A response type which can either be reject, accept, or end negotiation. Remarks: default behavior is to accept only if the current offer is the same or has a higher utility compared with what the agent would have proposed in the given state and reject otherwise .. py:property:: internal_state :type: dict[str, Any] Returns the internal state of the agent for debugging purposes. Remarks: - In your agent, you can add any key-value pair to this dict and then use agent_log_* methods to log this information at any point. .. py:method:: on_negotiation_failure(partners: list[str], annotation: dict[str, Any], mechanism: negmas.sao.SAONMI, state: negmas.SAOState) -> None Called whenever a negotiation ends without agreement. :param partners: List of the partner IDs consisting from self and the opponent. :param annotation: The annotation of the negotiation including the seller ID, buyer ID, and the product. :param mechanism: The `NegotiatorMechanismInterface` instance containing all information about the negotiation. :param state: The final state of the negotiation of the type `SAOState` including the agreement if any. .. py:method:: on_negotiation_success(contract: negmas.Contract, mechanism: negmas.sao.SAONMI) -> None Called whenever a negotiation ends with agreement. :param contract: The `Contract` agreed upon. :param mechanism: The `NegotiatorMechanismInterface` instance containing all information about the negotiation that led to the `Contract` if any. .. py:method:: sign_all_contracts(contracts: list[negmas.Contract]) -> list[str | None] Signs all contracts (used internally) .. py:method:: on_contract_executed(contract) -> None .. py:method:: on_contract_breached(contract, breaches, resolution) -> None .. py:method:: get_negotiator(partner_id: str) -> negmas.sao.SAONegotiator Returns the negotiator corresponding to the given partner ID. Remarks: - Note that the negotiator ID and the partner ID are always the same. .. py:method:: get_ami(partner_id: str) -> negmas.sao.SAONMI Returns the `SAONMI` (Agent Mechanism Interface) connecting the agent to the negotiation mechanism for the given partner. .. py:method:: get_nmi(partner_id: str) -> negmas.sao.SAONMI Returns the `SAONMI` (Agent Mechanism Interface) connecting the agent to the negotiation mechanism for the given partner. .. py:class:: OneShotSyncAgent(*args, **kwargs) Bases: :py:obj:`negmas.SAOSyncController`, :py:obj:`OneShotAgent`, :py:obj:`abc.ABC` An agent that automatically accumulate offers from opponents and allows you to control all negotiations centrally in the `counter_all` method. .. py:method:: counter_all(offers: dict[str, negmas.Outcome | None], states: dict[str, negmas.SAOState]) -> dict[str, negmas.SAOResponse] :abstractmethod: Calculate a response to all offers from all negotiators (negotiator ID is the key). :param offers: Maps negotiator IDs to offers :param states: Maps negotiator IDs to offers AT the time the offers were made. :returns: A dictionary mapping negotiator ID to an `SAOResponse`. The response per agent consist of a tuple. In case of acceptance or ending the negotiation the second item of the tuple should be None. In case of rejection, the second item should be the counter offer. Remarks: - The response type CANNOT be WAIT. - If the system determines that a loop is formed, the agent may receive this call for a subset of negotiations not all of them. .. py:method:: first_proposals() -> dict[str, negmas.Outcome | None] :abstractmethod: Gets a set of proposals to use for initializing the negotiation. :returns: A dictionary mapping each negotiator (in self.negotiators dict) to an outcome to be used as the first proposal if the agent is to start a negotiation. .. py:method:: sign_all_contracts(contracts: list[negmas.Contract]) -> list[str | None] Signs all contracts (used internally) .. py:class:: OneShotSingleAgreementAgent(*args, strict: bool = False, **kwargs) Bases: :py:obj:`negmas.SAOSingleAgreementController`, :py:obj:`OneShotSyncAgent` A synchronized agent that tries to get no more than one agreement. This controller manages a set of negotiations from which only a single one -- at most -- is likely to result in an agreement. To guarantee a single agreement, pass `strict=True` The general algorithm for this controller is something like this: - Receive offers from all partners. - Find the best offer among them by calling the abstract `best_offer` method. - Check if this best offer is acceptable using the abstract `is_acceptable` method. - If the best offer is acceptable, accept it and end all other negotiations. - If the best offer is still not acceptable, then all offers are rejected and with the partner who sent it receiving the result of `best_outcome` while the rest of the partners receive the result of `make_outcome`. - The default behavior of `best_outcome` is to return the outcome with maximum utility. - The default behavior of `make_outcome` is to return the best offer received in this round if it is valid for the respective negotiation and the result of `best_outcome` otherwise. :param strict: If True the controller is **guaranteed** to get a single agreement but it will have to send no-response repeatedly so there is a higher chance of never getting an agreement when two of those controllers negotiate with each other .. py:method:: is_acceptable(offer: negmas.Outcome, source: str, state: negmas.SAOState) -> bool :abstractmethod: Should decide if the given offer is acceptable :param offer: The offer being tested :param source: The ID of the negotiator that received this offer :param state: The state of the negotiation handled by that negotiator Remarks: - If True is returned, this offer will be accepted and all other negotiations will be ended. .. py:method:: best_offer(offers: dict[str, negmas.Outcome]) -> str | None :abstractmethod: Return the ID of the negotiator with the best offer :param offers: A mapping from negotiator ID to the offer it received :returns: The ID of the negotiator with best offer. Ties should be broken. Return None only if there is no way to calculate the best offer. .. py:method:: is_better(a: negmas.Outcome | None, b: negmas.Outcome | None, negotiator: str, state: negmas.SAOState) -> bool :abstractmethod: Compares two outcomes of the same negotiation :param a: "Outcome" :param b: "Outcome" :param negotiator: The negotiator for which the comparison is to be made :param state: Current state of the negotiation :returns: True if utility(a) > utility(b) .. py:class:: EndingNegotiator(preferences: negmas.preferences.preferences.Preferences | None = None, ufun: negmas.preferences.base_ufun.BaseUtilityFunction | None = None, name: str | None = None, parent: negmas.negotiators.Controller | None = None, owner: negmas.situated.Agent | None = None, id: str | None = None, type_name: str | None = None, can_propose: bool = True, **kwargs) Bases: :py:obj:`negmas.sao.SAONegotiator`, :py:obj:`negmas.ControlledNegotiator` Base class for all SAO negotiators. Implemented by implementing propose() and respond() methods. :param name: Negotiator name :param parent: Parent controller if any :param preferences: The preferences of the negotiator :param ufun: The utility function of the negotiator (overrides preferences if given) :param owner: The `Agent` that owns the negotiator. Remarks: - The only method that **must** be implemented by any SAONegotiator is `propose`. - The default `respond` method, accepts offers with a utility value no less than whatever `propose` returns with the same mechanism state. - A default implementation of respond() is provided which simply accepts any offer better than the last offer I gave or the next one I would have given in the current state. .. seealso:: `SAOCallNegotiator` .. py:method:: propose(state) Propose an offer or None to refuse. :param state: `GBState` giving current state of the negotiation. :returns: The outcome being proposed or None to refuse to propose Remarks: - This function guarantees that no agents can propose something with a utility value .. py:method:: respond(state, source=None) Called to respond to an offer. This is the method that should be overriden to provide an acceptance strategy. :param state: a `SAOState` giving current state of the negotiation. :param source: The ID of the negotiator that gave this offer :returns: The response to the offer :rtype: ResponseType Remarks: - The default implementation never ends the negotiation - The default implementation asks the negotiator to `propose`() and accepts the `offer` if its utility was at least as good as the offer that it would have proposed (and above the reserved value). - The current offer to respond to can be accessed through `state.current_offer` .. py:class:: OneShotIndNegotiatorsAgent(*args, default_negotiator_type='negmas.sao.AspirationNegotiator', default_negotiator_params=None, normalize_ufuns=False, set_reservation=False, **kwargs) Bases: :py:obj:`OneShotAgent` A one-shot agent that deligates all of its decisions to a set of independent negotiators (one per partner per day). :param default_negotiator_type: An `SAONegotiator` descendent to be used for creating all negotiators. It can be passed either as a class object or a string with the full class name (e.g. "negmas.sao.AspirationNegotiator"). :param default_negotiator_type: A dict specifying the paratmers used to create negotiators. :param normalize_ufuns: If true, all utility functions will be normalized to have a maximum of 1.0 (the minimum value may be negative). :param set_reservation: If given, the reserved value of all ufuns will be guaranteed to be between the minimum and maximum of the ufun. This is needed to avoid failures of some GeniusNegotiators. Remarks: - To use this class, you need to override `generate_ufuns`. If you want to change the negotiator type used depending on the partner, you can also override `generate_negotiator`. - If you are using a `GeniusNegotiator` you must guarantee the following: - All ufuns are of the type `LinearAdditiveUtilityFunction`. - All ufuns are normalized with a maximum value of 1.0. You can use `normalize_ufuns=True` to gruarantee that. - All ufuns have a finite reserved value and at least one outcome is above it. You can guarantee that by using `set_reservation=True`. - All weights of the `LinearAdditiveUtilityFunction` must be between zero and one and the weights must sum to one. .. py:attribute:: _default_negotiator_type :value: 'negmas.sao.AspirationNegotiator' .. py:attribute:: _default_negotiator_params .. py:attribute:: _ufuns .. py:attribute:: _normalize :value: False .. py:attribute:: _set_reservation :value: False .. py:method:: generate_ufuns() -> dict[str, negmas.preferences.UtilityFunction] :abstractmethod: Returns a utility function for each partner. All ufuns **MUST** be of type `LinearAdditiveUtilityFunction` if a genius negotiator is used. .. py:method:: generate_negotiator(partner_id: str) -> negmas.sao.SAONegotiator Returns a negotiator to be used with some partner. Remarks: The default implementation will use the `default_negotiator_type` and `default_negotiator_params`. .. py:method:: _urange(u: negmas.preferences.UtilityFunction, issues: tuple[negmas.Issue, Ellipsis]) .. py:method:: _unorm(u: negmas.preferences.UtilityFunction, mn, mx) .. py:method:: _get_ufuns() Internal method that makes sure the reservation value is set to a meaningful value and that the ufun is normalized if needed .. py:method:: init() Called once after the AWI is set. Remarks: - Use this for any proactive initialization code. .. py:method:: step() Called at the end of every step. Remarks: - Use this for any proactive code that needs to be done every simulation step. .. py:method:: make_negotiator(negotiator_type=None, name: str | None = None, **kwargs) -> negmas.ControlledSAONegotiator Creates a negotiator but does not add it to the controller. Call `add_negotiator` to add it. :param negotiator_type: Type of the negotiator to be created. :param name: negotiator name :param \*\*kwargs: any key-value pairs to be passed to the negotiator constructor :returns: The negotiator to be controlled. None for failure Remarks: If you would like not to negotiate, just return `EndingNegotiator()` instead of None. The value None should only be returned if an exception is to be thrown. .. py:method:: propose(negotiator_id, state) Proposes an offer to one of the partners. :param negotiator_id: ID of the negotiator (and partner) :param state: Mechanism state including current step :returns: an outcome to offer.