scml.oneshot.ufun ================= .. py:module:: scml.oneshot.ufun Classes ------- .. autoapisummary:: scml.oneshot.ufun.UFunLimit scml.oneshot.ufun.UtilityInfo scml.oneshot.ufun.OneShotUFun Module Contents --------------- .. py:class:: UFunLimit Bases: :py:obj:`tuple` .. py:attribute:: utility .. py:attribute:: input_quantity .. py:attribute:: input_price .. py:attribute:: output_quantity .. py:attribute:: output_price .. py:attribute:: exogenous_input_quantity .. py:attribute:: exogenous_input_price .. py:attribute:: exogenous_output_quantity .. py:attribute:: exogenous_output_price .. py:attribute:: inventory_input .. py:attribute:: inventory_output .. py:attribute:: producible .. py:class:: UtilityInfo .. py:attribute:: producible :type: int .. py:attribute:: total_input :type: int .. py:attribute:: total_output :type: int .. py:attribute:: shortfall_quantity :type: int .. py:attribute:: shortfall_penalty :type: float .. py:attribute:: remaining_quantity :type: int .. py:attribute:: disposal_cost :type: float .. py:attribute:: storage_cost :type: float .. py:attribute:: utility :type: float .. py:class:: OneShotUFun(ex_pin: int, ex_qin: int, ex_pout: int, ex_qout: int, input_product: int, input_agent: bool, output_agent: bool, production_cost: float, disposal_cost: float, storage_cost: float, shortfall_penalty: float, input_penalty_scale: float | None, output_penalty_scale: float | None, storage_penalty_scale: float | None, n_input_negs: int, n_output_negs: int, current_step: int, agent_id: str | None, time_range: tuple[int, int], inventory_in: int = 0, inventory_out: int = 0, input_qrange: tuple[int, int] = (0, 0), input_prange: tuple[int, int] = (0, 0), output_qrange: tuple[int, int] = (0, 0), output_prange: tuple[int, int] = (0, 0), force_exogenous: bool = True, n_lines: int = 10, normalized: bool = False, current_balance: int | float = float('inf'), suppliers: set[str] = set(), consumers: set[str] = set(), perishable=True, **kwargs) Bases: :py:obj:`negmas.preferences.StationaryMixin`, :py:obj:`negmas.preferences.UtilityFunction` Calculates the utility function of a list of contracts or offers. :param force_exogenous: Is the agent forced to accept exogenous contracts given through `ex_*` arguments? :param ex_pin: total price of exogenous inputs for this agent :param ex_qin: total quantity of exogenous inputs for this agent :param ex_pout: total price of exogenous outputs for this agent :param ex_qout: total quantity of exogenous outputs for this agent. :param cost: production cost of the agent. :param disposal_cost: disposal cost per unit of input/output. :param shortfall_penalty: penalty for failure to deliver one unit of output. :param input_agent: Is the agent an input agent which means that its input product is the raw material :param output_agent: Is the agent an output agent which means that its output product is the final product :param n_lines: Number of production lines. If None, will be read through the AWI. :param input_product: Index of the input product. If None, will be read through the AWI :param input_qrange: A 2-int tuple giving the range of input quantities negotiated. If not given will be read through the AWI :param input_prange: A 2-int tuple giving the range of input unit prices negotiated. If not given will be read through the AWI :param output_qrange: A 2-int tuple giving the range of output quantities negotiated. If not given will be read through the AWI :param output_prange: A 2-int tuple giving the range of output unit prices negotiated. If not given will be read through the AWI :param n_input_negs: How many input negotiations are allowed. If not given, it will be the number of suppliers as given by the AWI :param n_output_negs: How many output negotiations are allowed. If not given, it will be the number of consumers as given by the AWI :param current_step: Current simulation step. Needed only for `ufun_range` when returning best outcomes :param normalized: If given the values returned by `from_*`, `utility_range` and `__call__` will all be normalized between zero and one. Remarks: - The utility function assumes that the agent will have to pay for all its input products but will receive money only for the output products it could generate and sell. - The utility function respects production capacity (n. lines). The agent cannot produce more than the number of lines it has. - disposal cost is paid for items bought but not produced only. Items consumed in production (i.e. sold) are not counted. .. py:attribute:: agent_id .. py:attribute:: time_range .. py:attribute:: suppliers .. py:attribute:: consumers .. py:attribute:: current_balance .. py:attribute:: normalized :value: False .. py:attribute:: input_penalty_scale .. py:attribute:: storage_penalty_scale .. py:attribute:: output_penalty_scale .. py:attribute:: current_step .. py:attribute:: inventory_in :value: 0 .. py:attribute:: inventory_out :value: 0 .. py:attribute:: n_input_negs .. py:attribute:: perishable :value: True .. py:attribute:: n_output_negs .. py:attribute:: force_exogenous :value: True .. py:attribute:: n_lines :value: 10 .. py:attribute:: input_product .. py:attribute:: reserved_value .. py:attribute:: _signed_agreements :type: list[tuple[int, int, int]] :value: [] .. py:attribute:: _signed_is_output :type: list[bool] :value: [] .. py:attribute:: _registered_sale_failures :type: set[str] .. py:attribute:: _registered_supply_failures :type: set[str] .. py:property:: best_option :type: UFunLimit Best possible options .. py:property:: worst_option :type: UFunLimit Best possible options .. py:method:: register_supply_failure(supplier_id: str) .. py:method:: register_sale_failure(consumer_id: str) .. py:method:: register_sale(q: int, p: int, t: int) Registers a sale to be considered when calculating utilities .. py:method:: register_supply(q: int, p: int, t: int) Registers a supply to be considered when calculating utilities .. py:method:: xml(issues) -> str :abstractmethod: .. py:method:: eval(offer: tuple[int, int, int] | None) -> float Calculates the utility function given a single contract. Remarks: - This method calculates the utility value of a single offer assuming all other negotiations end in failure. - It can only be called for agents that exist in the first or last layer of the production graph. .. py:method:: from_contracts(contracts: Iterable[negmas.Contract], return_info: Literal[False] = False, ignore_exogenous=True) -> float from_contracts(contracts: Iterable[negmas.Contract], return_info: Literal[True], ignore_exogenous=True) -> UtilityInfo Calculates the utility function given a list of contracts :param contracts: A list/tuple of contracts :param ignore_exogenous: If given, any contracts with a system agent will be ignored. Remarks: - This method ignores any unsigned contracts passed to it. - We do not consider time at all so it is implicitly assumed that all contracts have the same delivery time value. - The reason for having the `ignore_exogenous` parameter is to avoid double counting exogenous contracts if their information is passed during construction of the ufun and they also exist in the list of `contracts` passed here. .. py:method:: outcome_as_tuple(offer) :staticmethod: .. py:method:: from_offers(offers: tuple[tuple[int, int, int | float] | None, Ellipsis] | dict[str, tuple[int, int, int] | None], outputs: tuple[bool, Ellipsis] | None = None, return_info: Literal[False] = False, ignore_signed_contracts: bool = True) -> float from_offers(offers: tuple[tuple[int, int, int | float] | None, Ellipsis] | dict[str, tuple[int, int, int] | None], outputs: tuple[bool, Ellipsis] | None, return_info: Literal[True], ignore_signed_contracts: bool = True) -> UtilityInfo Calculates the utility value given a list of offers and whether each offer is for output or not (= input). :param offers: An iterable (e.g. list) of tuples each with three values: (quantity, time, unit price) IN THAT ORDER. Time is ignored and can be set to any value. :param outputs: An iterable of the same length as offers of booleans specifying for each offer whether it is an offer for buying the agent's output product. :param return_info: If true, detailed utility information is returned as Utility Info :param ignore_signed_contracts: If true, ignores the registered signed contracts. This means that only exogenous contracts and offers will be used in evaluating the utility. Remarks: - This method takes into account the exogenous contract information passed when constructing the ufun. - You can pass a dictionary mapping partner ID to an offer and the system will use the correct value for the corresponding outputs array. .. py:method:: from_aggregates(qin: int, qout_signed: int, qout_sold: int, pin: int, pout: int, input_penalty: float, output_penalty: float, storage_penalty: float) -> float Calculates the utility from aggregates of input/output quantity/prices :param qin: Input quantity (total including all exogenous contracts). :param qout_signed: Output quantity (total including all exogenous contracts) that the agent agreed to sell. :param qout_sold: Output quantity (total including all exogenous contracts) that the agent will actually sell. :param pin: Input total price (i.e. unit price * qin). :param pout: Output total price (i.e. unit price * qin). :param input_penalty: total disposal cost :param output_penalty: total shortfall penalty :param storage_penalty: total storage penalty Remarks: - Most likely, you do not need to directly call this method. Consider `from_offers` and `from_contracts` that take current balance and exogenous contract information (passed during ufun construction) into account. - The method respects production capacity (n. lines). The agent cannot produce more than the number of lines it has. - This method does not take exogenous contracts or current balance into account. - The method assumes that the agent CAN pay for all input and production. .. py:method:: breach_level(qin: int = 0, qout: int = 0) Calculates the breach level that would result from a given quantities .. py:method:: is_breach(qin: int = 0, qout: int = 0) Whether the given quantities would lead to a breach. .. py:property:: max_utility The maximum possible utility value .. py:property:: min_utility The minimum possible utility value .. py:method:: minmax(*args, **kwargs) -> tuple[float, float] Finds the range of the given utility function for the given outcomes :param self: The utility function :param issues: List of issues (optional) :param outcomes: A collection of outcomes (optional) :param max_cardinality: the maximum number of outcomes to try sampling (if sampling is used and outcomes are not given) :param above_reserve: If given, the minimum and maximum will be set to reserved value if they were less than it. :returns: (lowest, highest) utilities in that order .. py:method:: extreme_outcomes(outcome_space: negmas.outcomes.OutcomeSpace | None = None, issues: Iterable[negmas.outcomes.Issue] | None = None, outcomes: Iterable[negmas.outcomes.Outcome] | None = None, max_cardinality=1000) -> tuple[negmas.outcomes.Outcome, negmas.outcomes.Outcome] .. py:method:: utility_range(outcome_space: negmas.outcomes.OutcomeSpace | None = None, issues: list[negmas.outcomes.Issue] | None = None, outcomes: list[negmas.outcomes.Outcome] | None = None, return_outcomes=False, max_n_outcomes=1000) -> tuple[float, float] | tuple[float, float, negmas.outcomes.Outcome, negmas.outcomes.Outcome] Finds the utility range and optionally returns the corresponding outcomes from a given issue space or in a single negotiation. :param issues: The set of issues of the negotiation. If not given it will be read from the AWI. Note that you cannot specify these issues except for agent in the first or last layer of the production graph (because otherwise, the agent cannot know whether this negotiation is for buying of selling). :param outcomes: A list of outcomes to consider. Using outcomes is much slower than using issues and you should never pass both. :param infeasible_cutoff: A utility value under which we consider the outcome infeasible. :param return_outcomes: If given the worst and best outcomes (in that order) will be returned. :param max_n_outcomes: Maximum number of outcomes to try. Not used. :returns: A tuple of worst and best utility values if `return_outcomes` is `False`. otherwise, the worst and best outcomes are appended to the returned utilities leading to a 4-items tuple instead of two. Remarks: - You will get a warning if you use a list of outcomes here because it is too slow. - You should only pass `issues` if you know that the agent is either an input agent or an output agent. Agents in the middle of the production graph cannot know whether these issues are for buying of for selling. To find the utility range for these agents, you can use `worst` and `best` that allow specifying input and output issues separately. - It is always assumed that the range required is for a single negotiation not a set of negotiations and under the assumption that all other negotiations if any will end in failure .. py:method:: _is_midlevel() .. py:method:: find_limit(best: bool, n_input_negs=None, n_output_negs=None, secured_input_quantity=0, secured_input_unit_price=0.0, secured_output_quantity=0, secured_output_unit_price=0.0, ignore_signed_contracts: bool = True) -> UFunLimit Finds either the maximum or the minimum of the ufun. :param best: Best(max) or worst (min) ufun value? :param n_input_negs: How many input negs are we to consider? None means all :param n_output_negs: How many output negs are we to consider? None means all :param secured_input_quantity: A quantity that MUST be bought :param secured_input_unit_price: The (average) unit price of the quantity that MUST be bought. :param secured_output_quantity: A quantity that MUST be sold. :param secured_output_unit_price: The (average) unit price of the quantity that MUST be sold. :param ignore_signed_contracts: If True all signed contracts will be ignored. Use secured_* to pass this information if you need to in this case. Remarks: - You can use the `secured_*` arguments and control over the number of negotiations to consider to find the utility limits **given** some already concluded and signed contracts .. py:method:: best() -> negmas.outcomes.Outcome .. py:method:: worst() -> negmas.outcomes.Outcome .. py:method:: find_limit_brute_force(best, n_input_negs=None, n_output_negs=None, secured_input_quantity=0, secured_input_unit_price=0.0, secured_output_quantity=0, secured_output_unit_price=0.0, ignore_signed_contracts=True) -> UFunLimit Finds either the maximum and the minimum of the ufun. :param best: Best(max) or worst (min) ufun value? :param n_input_negs: How many input negs are we to consider? None means all :param n_output_negs: How many output negs are we to consider? None means all :param secured_input_quantity: A quantity that MUST be bought :param secured_input_unit_price: The (average) unit price of the quantity that MUST be bought. :param secured_output_quantity: A quantity that MUST be sold. :param secured_output_unit_price: The (average) unit price of the quantity that MUST be sold. Remarks: - You can use the `secured_*` arguments and control over the number of negotiations to consider to find the utility limits **given** some already concluded and signed contracts - Note that this function CANNOT take into account the sales or supplies already signed (and registered via `register_sale` and/or `register_supply`). You MUST pass the quantities and prices for signed contracts through the secured_* parameters. :returns: worst and best outcome information in the form of `UFunLimit` tuple. .. py:method:: ok_to_buy_at(unit_price: float) -> bool Checks if the unit price can -- even in principle -- be acceptable for buying Remarks: - This method is **very** optimistic. If it returns `False`, an agent should **never** buy at this price. If it returns `True`, it may *still be a bad idea* to buy at this price. - If we **buy** at this price, the **best** case scenario is that we pay it and pay production cost then receive the unit price of one output. - If we do **not** buy at this price, the **worst** case scenario is that we will pay shortfall penalty for one item - We should **NOT** buy if the best case scenario when buying is worse than the worst case scenario when not buying. - If called for agents not at the end of the production chain, it will always return `True` because in these cases we do not know what the the unit price for the output so there is nothing to compare with. .. py:method:: ok_to_sell_at(unit_price: float) -> bool Checks if the unit price can -- even in principle -- be acceptable for selling Remarks: - This method is **very** optimistic. If it returns `False`, an agent should **never** sell at this price. If it returns `True`, it may *still be a bad idea* to sell at this price. - Sales decisions does not affect in any way the amount we pay for input materials. It only affects the amount we produce, the amout we get paid in sales and the amount we pay as disposal cost and shortfall penalty. - If we agree to sell an item at this price, the best case scenario is that we can actually produce this item and sell it. We pay production cost and receive the given unit price. - If we do **not** sell at this price, the worst case scenario is that we really needed that sale. In this case, we will pay disposal cost for one item. - We should **NOT** sell if the best case scenario when selling is worse than the worst case scenario when not selling. - If called for agents not at the beginning of the production chain, it will always return `True` because in these cases we do not know what the the unit price for the input so there is nothing to compare with.