import random from .commoditys import commoditys as cm from .exchange import Exchange from .business import Price_Believe_Business import uuid import time import logging from concurrent.futures import ThreadPoolExecutor import log class Simulation(): """ Class for controlling the different calculation steps of the Simulation. """ def __init__(self) -> None: self.timings={} self.tick_funcs={} self.reset_funcs={} self.tick_count=0 self.episode_count=-1 self.cells={} self.populated_cells={} self.businesses=[] self.production_util={} self.episode_tax=1 self.taskpool=ThreadPoolExecutor() self.setup_timing(["dss","dsa","dab","dbl","dt"]) for k in cm.productions.items(): l=k[1] for i in l: self.production_util[i["id"]]=0 self.cx=Exchange() pass def set_cells(self,cells): for c in cells: self.cells[c.name]=c self.populated_cells[c.name]=0 def set_businesses(self,bus): self.businesses=bus def seed(self,a): """ Sets the random seed """ random.seed(a) def register_agent(self,id,tickfunc,resetfunc): self.tick_funcs[id]=tickfunc self.reset_funcs[id]=resetfunc def unregister_agent(self,id): """ Unregisters agent """ self.tick_funcs.pop(id,None) self.reset_funcs.pop(id,None) def tick_agents_random_order(self): """ Ticks all agents in a Random Order """ keys=list(self.tick_funcs.keys()) random.shuffle(keys) tasks=[] for k in keys: fun=self.tick_funcs[k] fun(self.tick_count,self.episode_count) self.taskpool.map(self._execute_tick,tasks) def _execute_tick(args): fun=args[0] fun(args[1],args[2]) def tick(self,episode_length): """ Executes a tick of the simulation """ start=time.time() for cell_id,c in self.cells.items(): c.setup_demand_for_step(episode_length) setup=time.time() self.tick_agents_random_order() agentstep=time.time() for b in self.businesses: b.tick(self.tick_count) busstep=time.time() self.tick_count+=1 self.log_cxs_tick(episode_length) #self.log_business_tick(episode_length) logstep=time.time() self.timings["dss"]+=setup-start self.timings["dsa"]+=agentstep-setup self.timings["dsap"]=self.timings["dsa"]/(len(self.tick_funcs)+1) self.timings["dab"]+=(busstep-agentstep)/(len(self.businesses)+1) self.timings["dbl"]+=logstep-busstep self.timings["dt"]+=logstep-start def reset(self): """ Resets all agents to new Episode """ self.log_cxs_episode() self.log_business_episode() for k,v in self.reset_funcs.items(): v(self.episode_count) for cell_id,cell in self.cells.items(): cell.setup_supply_for_episode() toclose=[] for b in self.businesses: #tax business b.balance-=self.episode_tax b.tick_episode(self.episode_count) if b.balance<=0: toclose.append(b.id) for close in toclose: self.remove_business(close) self.timings["numBus"]=len(self.businesses) self.timings["tickfuncs"]=len(self.tick_funcs) self.timings["episode"]=self.episode_count log.PerformanceData.append(self.timings.copy()) self.setup_timing(["dss","dsa","dsap","dab","dbl","dt"]) self.tick_count=0 self.episode_count+=1 def get_underutelized_prods(self,threshold): """ Returns all productions that fall under the given threshold """ under=[] for k,v in self.production_util.items(): if v0: # we need to create more businesses selected_prod=random.choice(under_prods) else: selected_prod=self.get_max_profit_prod() prod=cm.productions_id_map[selected_prod] # Now select cell to place business cells=self.select_business_cell(prod) cell_id=random.choice(cells) cell=self.cells[cell_id] cxs=[cell.exchange,self.cx] business=Price_Believe_Business.Price_Believe_Business(uuid.UUID(int=random.getrandbits(128)),prod,1000,cxs,self,cell_id) self.businesses.append(business) self.production_util[selected_prod]+=1 self.populated_cells[cell_id]+=1 return business def remove_business(self,id): bus=None for busl in self.businesses: if busl.id==id: bus=busl break bus.close_business() self.businesses.remove(bus) self.production_util[bus.production["id"]]-=1 self.populated_cells[bus.location]-=1 def get_max_profit_prod(self): """ Returns the prod with the highest profit in last episode """ profit={} for b in self.businesses: id=b.production["id"] diff=b.balance-b.balance_history[-2] if id not in profit: profit[id]=0 profit[id]+=diff best=None bestv=-1000000000000 for k,v in profit.items(): if bestv0: cell=self.cells[id] lcx=cell.exchange name="lcx_{}".format(id) lcx.log_episode(name,self.episode_count) self.cx.log_episode("cx",self.episode_count) def log_business_tick(self,episode_length): for bus in self.businesses: bus.log(self.episode_count,episode_length,self.tick_count) def log_business_episode(self): for bus in self.businesses: bus.log(self.episode_count,1,0) def setup_timing(self,metrics): for met in metrics: self.timings[met]=0