def register_product_cfps(self, p: int, t: int, profile: ConsumptionProfile, sp=dict()): current_schedule = profile.schedule_at(t) product = self.products[p] awi: SCMLAWI = self.awi if current_schedule <= 0: awi.bb_remove( section="cfps", query={ "publisher": self.id, "time": t, "product_index": p }, ) return max_price = (ScheduleDrivenConsumer.RELATIVE_MAX_PRICE * product.catalog_price if product.catalog_price is not None else ScheduleDrivenConsumer.MAX_UNIT_PRICE) if sp.get(p) != None and sp[p] > product.catalog_price: max_price = ScheduleDrivenConsumer.RELATIVE_MAX_PRICE * sp[p] cfps = awi.bb_query(section="cfps", query={ "publisher": self.id, "time": t, "product": p }) if cfps is not None and len(cfps) > 0: for _, cfp in cfps.items(): if cfp.max_quantity != current_schedule: cfp = CFP( is_buy=True, publisher=self.id, product=p, time=t, unit_price=(0, max_price), quantity=(1, current_schedule), ) awi.bb_remove( section="cfps", query={ "publisher": self.id, "time": t, "product": p }, ) awi.register_cfp(cfp) break else: cfp = CFP( is_buy=True, publisher=self.id, product=p, time=t, unit_price=(0, max_price), quantity=(1, current_schedule), ) awi.register_cfp(cfp)
def register_cfp(self, cfp: CFP) -> None: """Registers a CFP""" self._world.n_new_cfps += 1 cfp.money_resolution = self._world.money_resolution cfp.publisher = ( self.agent.id ) # force the publisher to be the agent using this AWI. self.logdebug(f"{self.agent.name} registered CFP {str(cfp)}") self.bb_record(section="cfps", key=cfp.id, value=cfp)
def step(self): self.maxdebt = max([0, 30 - 30 * self.awi.current_step/self.awi.n_steps]) for key, item in self.cfp_records.items(): if item.lastSigned < self.awi.current_step - 4 and item.retracted < self.awi.current_step - 4: if len(item.HistoryMin) > 1: item.HistoryMin.remove(min(item.HistoryMin)) #item.HistoryMin.pop() if len(item.HistoryMax) > 1: #item.HistoryMax.pop() item.HistoryMax.remove(max(item.HistoryMax)) self.recalculate_prices(key) item.retracted = self.awi.current_step #print("step: ", self.awi.current_step) for key, item in self.cfp_records.items(): if item.transformable: stock = self.cfp_records[item.source_of].stock if key in self.awi.state.storage: for i in range(min([10,self.awi.state.storage[key]])): self.awi.schedule_production(self.lastLine, self.awi.current_step+1) self.lastLine = (self.lastLine + 1) % 10 else: stock = item.stock if item.id not in self.producing.keys() and stock <= item.minstock \ and (item.Asked < self.awi.current_step - 2) and self.awi.n_steps - 6 > self.awi.current_step: queries = 1 if item.id in self.consuming.keys(): queries = 3 for i in range(queries): cfp = CFP(is_buy=True, publisher=self.id, product=item.id , time= (self.awi.current_step + 4 +i, min([self.awi.current_step + 6+i, self.awi.n_steps-1])) , unit_price=self.generate_price_ranges(0, self.products[item.id].catalog_price + self.products[item.id].catalog_price * self.cfp_records[item.id].BuyThreshold) , quantity=3) self.awi.register_cfp(cfp) item.Asked = self.awi.current_step if item.stock > 0 and item.id not in self.consuming.keys(): for unit in range(item.stock): unit_price = self.generate_price_ranges(item.MaxPrice - item.MaxPrice * item.BuyThreshold, item.MaxPrice + item.MaxPrice * item.SellThreshold) cfp = CFP(is_buy=False, publisher=self.id, product=item.id , time=max([2 + (2 * item.id), self.awi.current_step + 6]), unit_price=unit_price, quantity=1) self.awi.register_cfp(cfp) item.Asked = self.awi.current_step
def step(self): for product in self.awi.products: cfp = CFP( is_buy=False, publisher=self.id, product=product.id, time=(self.awi.current_step + 2, self.awi.current_step + 6), unit_price=0.0000893, quantity=(5, 10), ) self.awi.register_cfp(cfp)
def post_cfps_2(self): for step in range(10): my_cfp = CFP(is_buy=True, product=self.raw_material_type, publisher=self.id, quantity=(1, 1 + random.randint(0, 10)), time=random.randint(0, 15) + self.current_step, unit_price=(0.5, self.get_target_price()), money_resolution=0.1, id="NORMAL : " + str(time), penalty=10000) self.awi.register_cfp(my_cfp)
def generateDecoyCFPs(self): for i in range(1, 100): decoyCFP = CFP(is_buy=True, product=int(random.uniform(1, len(self.products))), publisher=self.id, signing_delay=int(random.uniform(1, 9)), quantity=1, time=int(random.uniform(1, 5)), unit_price=(0, 100), money_resolution=0.1, id="DECOY : " + str(i)) self.decoyCFPs.append(decoyCFP) self.awi.register_cfp(decoyCFP)
def post_cfps(self): alpha = 16 for step in range(15): my_cfp = CFP(is_buy=True, product=self.raw_material_type, publisher=self.id, quantity=(1, step + alpha), time=min(step + self.current_step, self.awi.n_steps - 2), unit_price=(0.5, self.get_target_price()), money_resolution=0.1, id="NORMAL : " + str(time), penalty=10000) self.awi.register_cfp(my_cfp)
def _execute_schedule(self, schedule: ScheduleInfo, contract: Contract) -> None: ###contact if self.simulator is None: raise ValueError("No factory simulator is defined") awi: SCMLAWI = self.awi total = contract.agreement["unit_price"] * contract.agreement[ "quantity"] product = contract.annotation["cfp"].product if contract.annotation["buyer"] == self.id: self.simulator.buy( product=product, quantity=contract.agreement["quantity"], price=total, t=contract.agreement["time"], ) if total <= 0 or self.max_insurance_premium <= 0.0 or contract is None: return relative_premium = awi.evaluate_insurance(contract=contract) if relative_premium is None: return premium = relative_premium * total if relative_premium <= self.max_insurance_premium: self.awi.logdebug( f"{self.name} buys insurance @ {premium:0.02} ({relative_premium:0.02%}) for {str(contract)}" ) awi.buy_insurance(contract=contract) self.simulator.pay(premium, self.awi.current_step) return # I am a seller self.simulator.sell( product=product, quantity=contract.agreement["quantity"], price=total, t=contract.agreement["time"], ) for job in schedule.jobs: if job.action == "run": awi.schedule_job(job, contract=contract) elif job.action == "stop": awi.stop_production( line=job.line, step=job.time, contract=contract, override=job.override, ) else: awi.schedule_job(job, contract=contract) self.simulator.schedule(job=job, override=False) for need in schedule.needs: if need.quantity_to_buy <= 0: continue product_id = need.product # self.simulator.reserve(product=product_id, quantity=need.quantity_to_buy, t=need.step) if self.use_consumer: self.consumer.profiles[product_id].schedule[ need.step] += need.quantity_to_buy self.consumer.register_product_cfps( p=product_id, t=need.step, profile=self.consumer.profiles[product_id], sp=self.sold, ### ) continue # logger.debug('seller') product = self.products[product_id] if product.catalog_price is None: if self.sold.get(product_id) == None: price_range = (0.0, 100.0) else: price_range = (0.5, 1.5 * self.sold(product_id)) else: # logger.debug(product) # logger.debug(product.catalog_price) if self.sold.get(product_id) != None: product_price = max(self.sold(product_id), product.catalog_price) price_range = (0.5, 1.5 * product_price) # @todo check this. This error is raised sometimes if need.step < awi.current_step: continue # raise ValueError(f'need {need} at {need.step} while running at step {awi.current_step}') time = (need.step if self.max_storage is not None else (awi.current_step, need.step)) cfp = CFP( is_buy=True, publisher=self.id, product=product_id, time=time, unit_price=price_range, quantity=(1, int(1.1 * need.quantity_to_buy)), ) awi.register_cfp(cfp)
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]}')