scml.scml2020.services ====================== .. py:module:: scml.scml2020.services .. autoapi-nested-parse:: Services are classes that provide functionality that can be used by agents or components. The do not hook into or override any methods of the SCML2020Agent class. Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/scml/scml2020/services/controllers/index /autoapi/scml/scml2020/services/simulators/index Attributes ---------- .. autoapisummary:: scml.scml2020.services.__all__ Classes ------- .. autoapisummary:: scml.scml2020.services.FactorySimulator scml.scml2020.services.StepController scml.scml2020.services.SyncController Functions --------- .. autoapisummary:: scml.scml2020.services.transaction scml.scml2020.services.temporary_transaction Package Contents ---------------- .. py:class:: FactorySimulator(profile: scml.scml2020.common.FactoryProfile, initial_balance: int, bankruptcy_limit: int, spot_market_global_loss: float, catalog_prices: numpy.ndarray, n_steps: int, initial_inventory: numpy.ndarray = None) A simulator that can be used to predict future state of a factory given some combination of operations (sell, buy, schedule). .. py:attribute:: _n_steps .. py:attribute:: _catalog_prices .. py:attribute:: _initial_balance .. py:attribute:: _initial_inventory .. py:attribute:: _profile .. py:attribute:: _n_products .. py:attribute:: _reserved_inventory .. py:attribute:: _bankrupt_at :value: 9223372036854775807 .. py:attribute:: bankruptcy_limit .. py:attribute:: spot_market_global_loss .. py:attribute:: _n_lines .. py:attribute:: _balance .. py:attribute:: _inventory :value: None .. py:attribute:: commands .. py:attribute:: _fixed_before :value: 0 .. py:attribute:: _bookmarks :type: List[_FullBookmark] :value: [] .. py:attribute:: _active_bookmark :type: Optional[_FullBookmark] :value: None .. py:property:: n_steps :type: int Number of steps to predict ahead. .. py:property:: initial_balance :type: int Initial cash in balance .. py:property:: initial_inventory :type: numpy.array Initial inventory .. py:property:: n_lines Number of lines .. py:property:: final_balance :type: int Returns the final balance of the agent at the end of the simulation .. py:method:: final_score(prices: Optional[numpy.ndarray]) -> int Returns the final balance of the agent at the end of the simulation .. py:method:: inventory_at(t: int) -> numpy.array Returns the inventory of all products *at* time t :param t: Time :returns: An array of size `n_products` giving the quantity of each product in inventory at time-step `t`. .. seealso:: `inventory_to` `balance_at` .. py:method:: line_schedules_at(t: int) -> numpy.array Returns the schedule of each line at a given timestep :param t: time :returns: An array of `n_lines` values giving the schedule up at `t`. Remarks: - A `NO_COMMAND` value means no production, otherwise the index of the process being run .. py:method:: reserved_inventory_to(t: int) -> numpy.array Returns the *reserved* inventory of all products *up to* time t :param t: Time :returns: An array of size `n_products` * `t` giving the quantity of each product reserved at every step up to `t`. Remarks: - Reserved inventory *is counted* in calls to `inventory_at` , `total_inventory_at` , `inventory_to` , `total_inventory_to` - Reserving quantities of products is a tool that can be used to avoid double counting availability of given products in the inventory for multiple contracts. .. seealso:: `total_inventory_at` `inventory_at` `reserved_inventory_at` .. py:method:: reserved_inventory_at(t: int) -> numpy.array Returns the *reserved* inventory of all products *at* time t :param t: Time :returns: An array of size `n_products` giving the quantity of each product reserved at time-step `t`. Remarks: - Reserved inventory *is counted* in calls to `inventory_at` , `total_inventory_at` , `inventory_to` , `total_inventory_to` - Reserving quantities of products is a tool that can be used to avoid double counting availability of given products in the inventory for multiple contracts. .. seealso:: `total_inventory_to` `inventory_to` `reserved_inventory_at` .. py:method:: available_inventory_to(t: int) -> numpy.array Returns the *available* inventory of all products *up to* time t. :param t: Time :returns: An array of size `n_products` * `t` giving the quantity of each product available at every step up to `t`. Remarks: - Available inventory is defined as the difference between inventory and reserved inventory. - Reserved inventory *is counted* in calls to `inventory_at` , `total_inventory_at` , `inventory_to` , `total_inventory_to` - Reserving quantities of products is a tool that can be used to avoid double counting availability of given products in the inventory for multiple contracts. .. seealso:: `total_inventory_to` `inventory_to` `reserved_inventory_to` .. py:method:: available_inventory_at(t: int) -> numpy.array Returns the *available* inventory of all products *at* time t :param t: Time :returns: An array of size `n_products` giving the quantity of each product available at time-step `t`. Remarks: - Available inventory is defined as the difference between inventory and reserved inventory. - Reserved inventory *is counted* in calls to `inventory_at` , `total_inventory_at` , `inventory_to` , `total_inventory_to` - Reserving quantities of products is a tool that can be used to avoid double counting availability of given products in the inventory for multiple contracts. .. seealso:: `total_inventory_to` `inventory_to` `reserved_inventory_at` .. py:method:: is_bankrupt() -> bool Checks if the agent will go bankrupt given all the info so far .. py:method:: balance_to(t: int) -> numpy.array Returns the balance fo the factory until and including time t. :param t: time Remarks: - The balance is defined as the cash in balance .. py:method:: score(inventory_weight=0.5) -> float Estimates the final score of the agent :param inventory_weight: The weight of the inventory that remains at the end of the simulation Remarks: - It uses the catalog prices for price estimation. This may be inaccurate. There is no way to know the actual trading prices of the market that are used to calculate the real score .. py:method:: balance_at(t: int) -> numpy.array Returns the balance of the factory at time t. :param t: time Remarks: - The balance is defined as the cash in balance .. py:method:: inventory_to(t: int) -> numpy.array Returns the balance fo the factory *up to* time t. :param t: time Remarks: - The balance is defined as the cash in balance .. py:method:: line_schedules_to(t: int) -> numpy.array .. py:method:: receive(payment: int, t: int) -> bool Simulates receiving payment at time t :param payment: Amount received :param t: time :returns: Success or failure .. py:method:: reserve(product: int, quantity: int, t: int) -> bool Simulates reserving the given quantity of the given product at times >= t. :param product: Index/ID of the product being reserved :param quantity: quantity being reserved :param t: time :returns: Success/failure Remarks: - Reserved products do not show in calls to `inventory_at` , `inventory_to` etc. - Reserving a product does nothing more than mark some quantity as reserved for calls to `reserved_inventory_at` and `available_inventory_at`. - This feature can be used to simulate inventory hiding commands in the real factory and to avoid double counting of inventory when calculating needs for future contracts. .. py:method:: pay(payment: int, t: int, ignore_money_shortage: bool = True) -> bool Simulate payment at time t :param payment: Amount payed :param t: time :param ignore_money_shortage: If True, shortage in money will be ignored and the balance can go negative :returns: Success or failure .. py:method:: transport_to(product: int, quantity: int, t: int, ignore_inventory_shortage: bool = True) -> bool Simulates transporting products to/from inventory at time t :param product: product ID (index) :param quantity: quantity to transport :param t: time :param ignore_inventory_shortage: Ignore shortage in the `product` which may lead to negative inventory[product] :returns: Success or failure .. py:method:: buy(product: int, quantity: int, price: int, t: int, ignore_money_shortage: bool = True) -> bool Buy a given quantity of a product for a given price at some time t :param product: Product to buy (ID/index) :param quantity: quantity to buy :param price: unit price :param t: time :param ignore_money_shortage: If True, shortage in money will be ignored and the balance can go negative :returns: Success or failure Remarks: - buy cannot ever have inventory shortage .. seealso:: `sell` .. py:method:: sell(product: int, quantity: int, price: int, t: int, ignore_inventory_shortage: bool = True) -> bool sell a given quantity of a product for a given price at some time t :param product: Index/ID of the product to be sold :param quantity: quantity to be sold :param price: unit price :param t: time :param ignore_inventory_shortage: If True, shortage in inventory will be ignored and the inventory can go negative :returns: Success or failure Remarks: - sell cannot ever have space shortage .. seealso:: `buy` .. py:method:: available_for_production(repeats: int, step: Union[int, Tuple[int, int]] = ANY_STEP, line: int = ANY_LINE, override: bool = True, method: str = 'latest') -> Tuple[numpy.ndarray, numpy.ndarray] Finds available times and lines for scheduling production. :param repeats: How many times to repeat the process :param step: The simulation step or a range of steps. The special value ANY_STEP gives the factory the freedom to schedule production at any step in the present or future. :param line: The production line. The special value ANY_LINE gives the factory the freedom to use any line :param override: Whether to override any existing commands at that line at that time. :param method: When to schedule the command if step was set to a range. Options are latest, earliest, all :returns: Tuple[np.ndarray, np.ndarray] The steps and lines at which production is scheduled. Remarks: - You cannot order production in the past or in the current step - Ordering production, will automatically update inventory and balance for all simulation steps assuming that this production will be carried out. At the indicated `step` if production was not possible (due to insufficient funds or insufficient inventory of the input product), the predictions for the future will be corrected. .. py:method:: order_production(process: int, steps: numpy.ndarray, lines: numpy.ndarray) -> None Orders production of the given process :param process: The process to run :param steps: The time steps to run the process at as an np.ndarray :param lines: The corresponding lines to run the process at Remarks: - len(steps) must equal len(lines) - No checks are done in this function. It is expected to be used after calling `available_for_production` .. py:method:: schedule(process: int, quantity: int, t: Union[int, Tuple[int, int]] = ANY_STEP, line: int = ANY_LINE, override=True, method: str = 'latest', ignore_inventory_shortage=True, ignore_money_shortage=True) -> bool Simulates scheduling the given job at its `time` and `line` optionally overriding whatever was already scheduled :param process: The process to run :param quantity: The quantity to be produced :param t: The time-step step :param line: The line :param ignore_inventory_shortage: If true shortages in inputs will be ignored :param ignore_money_shortage: If true, shortage in money will be ignored :param override: Whether the job should override any already registered job at its time-step :param method: The method employed for scheduling. Supported methods are latest, earliest :returns: Success/failure .. py:method:: fix_before(t: int) -> bool Fix the history before this point :param t: time :returns: Success/failure Remarks: - After this function is called at any time-step `t`, there is no way to change any component of the factory state at any timestep before `t`. - This function is useful for *fixing* any difference between the simulator and the real state (in conjunction with `set_state`). .. seealso:: `set_state` `fixed_before` .. py:property:: fixed_before Gives the time before which the schedule is fixed. .. seealso:: `fix_before` .. py:method:: delete_bookmark(bookmark_id: int) -> bool Commits everything since the bookmark so it cannot be rolled back :param bookmark_id The bookmark ID returned from bookmark: :returns: Success/failure Remarks: - You can delete bookmarks in the reverse order of their creation only. If the bookmark ID given here is not the one at the top of the bookmarks stack, the deletion will fail (return False). .. seealso:: `delete_bookmark` `rollback` `transaction` `temporary_transaction` .. py:method:: bookmark() -> int Sets a bookmark to the current location :returns: bookmark ID Remarks: - Bookmarks can be used to implement transactions. .. seealso:: `delete_bookmark` `rollback` `transaction` `temporary_transaction` .. py:method:: rollback(bookmark_id: int) -> bool Rolls back to the given bookmark ID :param bookmark_id The bookmark ID returned from bookmark: Remarks: - You can only rollback in the reverse order of bookmarks. If the bookmark ID given here is not the one at the top of the bookmarks stack, the rollback will fail (return False) .. seealso:: `delete_bookmark` `rollback` `transaction` `temporary_transaction` .. py:method:: set_state(t: int, inventory: numpy.array, balance: int, commands: numpy.array) -> None Sets the current state at the given time-step. It implicitly causes a fix_before(t + 1) :param t: Time step to set the state at :param inventory: quantity of every product (array of integers of size `n_products`) :param balance: Cash in balance :param commands: Line schedules (array of process numbers/NO_PRODUCTION of size `n_lines`) .. py:function:: transaction(simulator) Runs the simulated actions then confirms them if they are not rolled back .. py:function:: temporary_transaction(simulator) Runs the simulated actions then rolls them back .. py:class:: StepController(*args, target_quantity: int, is_seller: bool, step: int, urange: Tuple[int, int], product: int, partners: List[str], negotiator_type: negmas.sao.SAONegotiator, horizon: int, awi: negmas.AgentWorldInterface, parent_name: str, negotiations_concluded_callback: Callable[[int, bool], None], negotiator_params: Dict[str, Any] = None, max_retries: int = 2, **kwargs) Bases: :py:obj:`negmas.sao.SAOController`, :py:obj:`negmas.events.Notifier` A controller for managing a set of negotiations about selling or buying (but not both) starting/ending at some specific time-step. :param target_quantity: The quantity to be secured :param is_seller: Is this a seller or a buyer :param parent_name: Name of the parent :param horizon: How many steps in the future to allow negotiations for selling to go for. :param step: The simulation step that this controller is responsible about :param urange: The range of unit prices used for negotiation :param product: The product that this controller negotiates about :param partners: A list of partners to negotiate with :param negotiator_type: The type of the single negotiator used for all negotiations. :param negotiator_params: The parameters of the negotiator used for all negotiations :param max_retries: How many times can the controller try negotiating with each partner. :param negotiations_concluded_callback: A method to be called with the step of this controller and whether is it a seller when all negotiations are concluded :param \*args: Position arguments passed to the base Controller constructor :param \*\*kwargs: Keyword arguments passed to the base Controller constructor Remarks: - It uses whatever negotiator type on all of its negotiations and it assumes that the ufun will never change - Once it accumulates the required quantity, it ends all remaining negotiations - It assumes that all ufuns are identical so there is no need to keep a separate negotiator for each one and it instantiates a single negotiator that dynamically changes the AMI but always uses the same ufun. .. py:attribute:: parent_name .. py:attribute:: awi .. py:attribute:: horizon .. py:attribute:: negotiations_concluded_callback .. py:attribute:: is_seller .. py:attribute:: target .. py:attribute:: urange .. py:attribute:: partners .. py:attribute:: product .. py:attribute:: __negotiator :value: None .. py:attribute:: secured :value: 0 .. py:attribute:: completed .. py:attribute:: step .. py:attribute:: retries :type: Dict[str, int] .. py:attribute:: max_retries :value: 2 .. py:method:: join(negotiator_id: str, nmi: negmas.common.NegotiatorMechanismInterface, state: negmas.MechanismState, *, preferences: Optional[negmas.Preferences] = None, ufun: Optional[negmas.UtilityFunction] = None, role: str = 'agent') -> bool Called by the mechanism when the agent is about to enter a negotiation. It can prevent the agent from entering :param negotiator_id: The negotiator ID :param nmi: The negotiation. :type nmi: AgentMechanismInterface :param state: The current state of the negotiation :type state: TState :param preferences: The preferences. :type preferences: Preferences :param ufun: The ufun function to use before any discounting (overrides preferences) :type ufun: BaseUtilityFunction :param role: role of the agent. :type role: str :returns: bool indicating whether or not the agent accepts to enter.If False is returned it will not enter the negotiation. .. py:method:: propose(negotiator_id: str, state: negmas.MechanismState) -> Optional[negmas.Outcome] .. py:method:: respond(negotiator_id: str, state: negmas.MechanismState, source: str = '') -> negmas.ResponseType .. py:method:: __str__() .. py:method:: create_negotiator(negotiator_type: Union[str, Type[negmas.ControlledNegotiator]] = None, name: str = None, cntxt: Any = None, **kwargs) -> negmas.ControlledNegotiator Creates a negotiator passing it the context :param negotiator_type: Type of the negotiator to be created :param name: negotiator name :param cntxt: The context to be associated with this negotiator. :param \*\*kwargs: any key-value pairs to be passed to the negotiator constructor :returns: The negotiator to be controlled. None for failure .. py:method:: time_range(step, is_seller) .. py:method:: on_negotiation_end(negotiator_id: str, state: negmas.MechanismState) -> None A call back called at each negotiation end :param negotiator_id: The negotiator ID :param state: `TState` or one of its descendants giving the state at which the negotiation ended. .. py:class:: SyncController(*args, is_seller: bool, parent: scml.scml2020.components.trading.PredictionBasedTradingStrategy, price_weight=0.7, utility_threshold=0.9, time_threshold=0.9, **kwargs) Bases: :py:obj:`negmas.sao.SAOSyncController` Will try to get the best deal which is defined as being nearest to the agent needs and with lowest price .. py:attribute:: _is_seller .. py:attribute:: __parent .. py:attribute:: _time_threshold :value: 0.9 .. py:attribute:: _price_weight :value: 0.7 .. py:attribute:: _utility_threshold :value: 0.9 .. py:attribute:: _best_utils :type: Dict[str, float] .. py:method:: utility(offer: Tuple[int, int, int], max_price: int) -> float A simple utility function Remarks: - If the time is invalid or there is no need to get any more agreements at the given time, return -1000 - Otherwise use the price-weight to calculate a linear combination of the price and the how much of the needs is satisfied by this contract .. py:method:: is_valid(negotiator_id: str, offer: negmas.Outcome) -> bool .. py:method:: counter_all(offers: Dict[str, negmas.Outcome], states: Dict[str, negmas.sao.SAOState]) -> Dict[str, negmas.sao.SAOResponse] 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. Remarks: - The response type CANNOT be WAIT. .. py:method:: best_proposal(nid: str) -> Tuple[Optional[negmas.Outcome], float] Finds the best proposal for the given negotiation :param nid: Negotiator ID :returns: The outcome with highest utility and the corresponding utility .. py:method:: first_proposals() -> Dict[str, negmas.Outcome] Gets a set of proposals to use for initializing the negotiation. .. py:data:: __all__