diff --git a/__pycache__/controller_db.cpython-38.pyc b/__pycache__/controller_db.cpython-38.pyc index c779c07..f446f0c 100644 Binary files a/__pycache__/controller_db.cpython-38.pyc and b/__pycache__/controller_db.cpython-38.pyc differ diff --git a/__pycache__/firm.cpython-38.pyc b/__pycache__/firm.cpython-38.pyc index dac7180..170a168 100644 Binary files a/__pycache__/firm.cpython-38.pyc and b/__pycache__/firm.cpython-38.pyc differ diff --git a/__pycache__/model.cpython-38.pyc b/__pycache__/model.cpython-38.pyc index a6d75f7..20f6e14 100644 Binary files a/__pycache__/model.cpython-38.pyc and b/__pycache__/model.cpython-38.pyc differ diff --git a/__pycache__/orm.cpython-38.pyc b/__pycache__/orm.cpython-38.pyc index cada252..61ffc60 100644 Binary files a/__pycache__/orm.cpython-38.pyc and b/__pycache__/orm.cpython-38.pyc differ diff --git a/controller_db.py b/controller_db.py index 8c258ac..f7a1c01 100644 --- a/controller_db.py +++ b/controller_db.py @@ -51,11 +51,11 @@ class ControllerDB: Firm['Code'] = Firm['Code'].astype('string') Firm.fillna(0, inplace=True) - # fill dct_lst_init_remove_firm_prod + # fill dct_lst_init_disrupt_firm_prod list_dct = [] if self.is_with_exp: str_sql = "select e_id, count, max_max_ts, " \ - "dct_lst_init_remove_firm_prod from " \ + "dct_lst_init_disrupt_firm_prod from " \ "iiabmdb.without_exp_experiment as a " \ "inner join " \ "(select e_id, count(id) as count, max(max_ts) as max_max_ts "\ @@ -67,11 +67,11 @@ class ControllerDB: "on a.id = b.e_id " \ "order by count desc;" result = pd.read_sql(sql=str_sql, con=engine) - result['dct_lst_init_remove_firm_prod'] = \ - result['dct_lst_init_remove_firm_prod'].apply( + result['dct_lst_init_disrupt_firm_prod'] = \ + result['dct_lst_init_disrupt_firm_prod'].apply( lambda x: pickle.loads(x)) list_dct = result.loc[result['count'] > 10, - 'dct_lst_init_remove_firm_prod'].to_list() + 'dct_lst_init_disrupt_firm_prod'].to_list() else: for _, row in Firm.iterrows(): code = row['Code'] @@ -125,17 +125,17 @@ class ControllerDB: f"init_removal {idx_init_removal}!") def add_experiment_1(self, idx_scenario, idx_init_removal, - dct_lst_init_remove_firm_prod, g_bom, + dct_lst_init_disrupt_firm_prod, g_bom, n_max_trial, prf_size, prf_conn, cap_limit_prob_type, cap_limit_level, - diff_new_conn, crit_supplier, diff_remove, - proactive_ratio, drop_t, netw_prf_n): + diff_new_conn, crit_supplier, diff_disrupt, + proactive_ratio, remove_t, netw_prf_n): e = Experiment( idx_scenario=idx_scenario, idx_init_removal=idx_init_removal, n_sample=int(self.dct_parameter['n_sample']), n_iter=int(self.dct_parameter['n_iter']), - dct_lst_init_remove_firm_prod=dct_lst_init_remove_firm_prod, + dct_lst_init_disrupt_firm_prod=dct_lst_init_disrupt_firm_prod, g_bom=g_bom, n_max_trial=n_max_trial, prf_size=prf_size, @@ -144,9 +144,9 @@ class ControllerDB: cap_limit_level=cap_limit_level, diff_new_conn=diff_new_conn, crit_supplier=crit_supplier, - diff_remove=diff_remove, + diff_disrupt=diff_disrupt, proactive_ratio=proactive_ratio, - drop_t=drop_t, + remove_t=remove_t, netw_prf_n=netw_prf_n ) db_session.add(e) diff --git a/firm.py b/firm.py index b763afe..a88c479 100644 --- a/firm.py +++ b/firm.py @@ -14,13 +14,13 @@ class FirmAgent(ap.Agent): self.ori_size = revenue_log self.size = revenue_log self.a_lst_product = a_lst_product - self.a_lst_product_removed = ap.AgentList(self.model, []) + self.a_lst_product_disrupted = ap.AgentList(self.model, []) self.dct_prod_up_prod_stat = {} self.dct_prod_capacity = {} # para in trial - self.dct_n_trial_up_prod_removed = {} - self.dct_cand_alt_supply_up_prod_removed = {} + self.dct_n_trial_up_prod_disrupted = {} + self.dct_cand_alt_supp_up_prod_disrupted = {} self.dct_request_prod_from_firm = {} # external variable @@ -34,7 +34,7 @@ class FirmAgent(ap.Agent): # init dct_prod_up_prod_stat (self para) for prod in a_lst_product: self.dct_prod_up_prod_stat[prod] = { - # Normal / Disrupted / Removed + time step + # (Normal / Affected / Disrupted / Removed, time step) 'status': [('N', 0)], # have or have no supply 'supply': dict.fromkeys(prod.a_predecessors(), True) @@ -61,16 +61,17 @@ class FirmAgent(ap.Agent): # print(firm_agent.name, extra_cap) self.dct_prod_capacity[product] = extra_cap - def remove_edge_to_cus_remove_cus_up_prod(self, remove_product): + def remove_edge_to_cus_affect_cus_up_prod(self, disrupted_prod): + # para remove_product is the product that self got disrupted lst_out_edge = list( self.firm_network.graph.out_edges( self.firm_network.positions[self], keys=True, data='Product')) for n1, n2, key, product_code in lst_out_edge: - if product_code == remove_product.code: - # remove edge + if product_code == disrupted_prod.code: + # remove edge to customer self.firm_network.graph.remove_edge(n1, n2, key) - # remove customer up product conditionally + # customer up product affected conditionally customer = ap.AgentIter(self.model, n2).to_list()[0] lst_in_edge = list( self.firm_network.graph.in_edges(n2, @@ -78,45 +79,44 @@ class FirmAgent(ap.Agent): data='Product')) lst_select_in_edge = [ edge for edge in lst_in_edge - if edge[-1] == remove_product.code + if edge[-1] == disrupted_prod.code ] - prod_remove = math.exp(-1 * self.flt_crit_supplier * - len(lst_select_in_edge)) + prob_lost_supp = math.exp(-1 * self.flt_crit_supplier * + len(lst_select_in_edge)) if self.model.nprandom.choice([True, False], - p=[prod_remove, - 1 - prod_remove]): - customer.dct_n_trial_up_prod_removed[remove_product] = 0 + p=[prob_lost_supp, + 1 - prob_lost_supp]): + customer.dct_n_trial_up_prod_disrupted[disrupted_prod] = 0 for prod in customer.dct_prod_up_prod_stat.keys(): - if remove_product in \ + if disrupted_prod in \ customer.dct_prod_up_prod_stat[ prod]['supply'].keys(): customer.dct_prod_up_prod_stat[ - prod]['supply'][remove_product] = False + prod]['supply'][disrupted_prod] = False customer.dct_prod_up_prod_stat[ - prod]['status'].append(('D', self.model.t)) - print(self.name, remove_product.code, 'affect', + prod]['status'].append(('A', self.model.t)) + print(self.name, disrupted_prod.code, 'affect', customer.name, prod.code) def seek_alt_supply(self, product): # para product is the product that self is seeking - # for product in self.a_lst_up_product_removed: print(f"{self.name} seek alt supply for {product.code}") - if self.dct_n_trial_up_prod_removed[ + if self.dct_n_trial_up_prod_disrupted[ product] <= self.model.int_n_max_trial: - if self.dct_n_trial_up_prod_removed[product] == 0: + if self.dct_n_trial_up_prod_disrupted[product] == 0: # select a list of candidate firm that has the product - self.dct_cand_alt_supply_up_prod_removed[product] = \ + self.dct_cand_alt_supp_up_prod_disrupted[product] = \ self.model.a_lst_total_firms.select([ product in firm.a_lst_product - and product not in firm.a_lst_product_removed + and product not in firm.a_lst_product_disrupted for firm in self.model.a_lst_total_firms ]) - if self.dct_cand_alt_supply_up_prod_removed[product]: + if self.dct_cand_alt_supp_up_prod_disrupted[product]: # select based on connection lst_firm_connect = [] if self.is_prf_conn: for firm in \ - self.dct_cand_alt_supply_up_prod_removed[product]: + self.dct_cand_alt_supp_up_prod_disrupted[product]: out_edges = self.model.firm_network.graph.out_edges( self.model.firm_network.positions[firm], keys=True) in_edges = self.model.firm_network.graph.in_edges( @@ -135,16 +135,16 @@ class FirmAgent(ap.Agent): if self.is_prf_size: lst_size = \ [size for size in - self.dct_cand_alt_supply_up_prod_removed[ + self.dct_cand_alt_supp_up_prod_disrupted[ product].size] lst_prob = [size / sum(lst_size) for size in lst_size] select_alt_supply = self.model.nprandom.choice( - self.dct_cand_alt_supply_up_prod_removed[product], + self.dct_cand_alt_supp_up_prod_disrupted[product], p=lst_prob) else: select_alt_supply = self.model.nprandom.choice( - self.dct_cand_alt_supply_up_prod_removed[product]) + self.dct_cand_alt_supp_up_prod_disrupted[product]) elif len(lst_firm_connect) > 0: # select based on size of connected firm or not if self.is_prf_size: @@ -182,7 +182,7 @@ class FirmAgent(ap.Agent): select_alt_supply.dct_request_prod_from_firm.items() }) - self.dct_n_trial_up_prod_removed[product] += 1 + self.dct_n_trial_up_prod_disrupted[product] += 1 def handle_request(self): print(self.name, 'handle_request') @@ -266,23 +266,23 @@ class FirmAgent(ap.Agent): prod]['supply'][product] = True down_firm.dct_prod_up_prod_stat[ prod]['status'].append(('N', self.model.t)) - del down_firm.dct_n_trial_up_prod_removed[product] - del down_firm.dct_cand_alt_supply_up_prod_removed[product] + del down_firm.dct_n_trial_up_prod_disrupted[product] + del down_firm.dct_cand_alt_supp_up_prod_disrupted[product] print( f"{self.name} accept {product.code} request " f"from {down_firm.name}" ) else: - down_firm.dct_cand_alt_supply_up_prod_removed[product].remove(self) + down_firm.dct_cand_alt_supp_up_prod_disrupted[product].remove(self) def clean_before_trial(self): self.dct_request_prod_from_firm = {} def clean_before_time_step(self): - self.dct_n_trial_up_prod_removed = \ - dict.fromkeys(self.dct_n_trial_up_prod_removed.keys(), 0) - self.dct_cand_alt_supply_up_prod_removed = {} + self.dct_n_trial_up_prod_disrupted = \ + dict.fromkeys(self.dct_n_trial_up_prod_disrupted.keys(), 0) + self.dct_cand_alt_supp_up_prod_disrupted = {} def get_firm_network_node(self): return self.firm_network.positions[self] diff --git a/model.py b/model.py index 6755685..b1374a6 100644 --- a/model.py +++ b/model.py @@ -17,14 +17,14 @@ class Model(ap.Model): self.product_network = None # agentpy network self.firm_network = None # agentpy network self.firm_prod_network = None # networkx - self.dct_lst_remove_firm_prod = self.p.dct_lst_init_remove_firm_prod + self.dct_lst_disrupt_firm_prod = self.p.dct_lst_init_disrupt_firm_prod # external variable self.int_n_max_trial = int(self.p.n_max_trial) self.is_prf_size = bool(self.p.prf_size) - self.flt_diff_remove = float(self.p.diff_remove) + self.flt_diff_disrupt = float(self.p.diff_disrupt) self.proactive_ratio = float(self.p.proactive_ratio) - self.drop_t = int(self.p.drop_t) + self.remove_t = int(self.p.remove_t) self.int_netw_prf_n = int(self.p.netw_prf_n) # init graph bom @@ -210,29 +210,29 @@ class Model(ap.Model): self.firm_network.add_agents([firm_agent], [ag_node]) self.a_lst_total_firms = ap.AgentList(self, self.firm_network.agents) - # init dct_list_remove_firm_prod (from string to agent) + # init dct_lst_disrupt_firm_prod (from string to agent) t_dct = {} - for firm_code, lst_product in self.dct_lst_remove_firm_prod.items(): + for firm_code, lst_product in self.dct_lst_disrupt_firm_prod.items(): firm = self.a_lst_total_firms.select( self.a_lst_total_firms.code == firm_code)[0] t_dct[firm] = self.a_lst_total_products.select([ code in lst_product for code in self.a_lst_total_products.code ]) - self.dct_lst_remove_firm_prod = t_dct + self.dct_lst_disrupt_firm_prod = t_dct - # set the initial firm product that are removed + # set the initial firm product that are disrupted print('\n', '=' * 20, 'step', self.t, '=' * 20) - for firm, a_lst_product in self.dct_lst_remove_firm_prod.items(): + for firm, a_lst_product in self.dct_lst_disrupt_firm_prod.items(): for product in a_lst_product: assert product in firm.a_lst_product, \ f"product {product.code} not in firm {firm.code}" - firm.a_lst_product_removed.append(product) + firm.a_lst_product_disrupted.append(product) firm.dct_prod_up_prod_stat[ - product]['status'].append(('R', self.t)) + product]['status'].append(('D', self.t)) # proactive strategy # get all the firm prod affected - for firm, a_lst_product in self.dct_lst_remove_firm_prod.items(): + for firm, a_lst_product in self.dct_lst_disrupt_firm_prod.items(): for product in a_lst_product: init_node = \ [n for n, v in @@ -290,7 +290,7 @@ class Model(ap.Model): for firm in self.a_lst_total_firms])[0] lst_cand = self.model.a_lst_total_firms.select([ di_supp_prod in firm.a_lst_product - and di_supp_prod not in firm.a_lst_product_removed + and di_supp_prod not in firm.a_lst_product_disrupted for firm in self.model.a_lst_total_firms ]) n2n_betweenness = \ @@ -312,7 +312,7 @@ class Model(ap.Model): # find a dfferent firm can produce the same product lst_cand = self.model.a_lst_total_firms.select([ di_supp_prod in firm.a_lst_product - and di_supp_prod not in firm.a_lst_product_removed + and di_supp_prod not in firm.a_lst_product_disrupted and firm.code != di_supp_node['Firm_Code'] for firm in self.model.a_lst_total_firms ]) @@ -339,24 +339,25 @@ class Model(ap.Model): def update(self): self.a_lst_total_firms.clean_before_time_step() - # reduce the size of removed firm + # reduce the size of disrupted firm for firm in self.a_lst_total_firms: for prod in firm.dct_prod_up_prod_stat.keys(): status, ts = firm.dct_prod_up_prod_stat[prod]['status'][-1] - if status == 'R': + if status == 'D': firm.size -= \ - firm.ori_size / len(firm.a_lst_product) / self.drop_t + firm.ori_size / len(firm.a_lst_product) / self.remove_t print(self.t, firm.name, prod.code, firm.size) - if self.t - ts + 1 == self.drop_t: + if self.t - ts + 1 == self.remove_t: + # turn disrupted firm into removed firm firm.dct_prod_up_prod_stat[ - prod]['status'].append(('N', self.t)) + prod]['status'].append(('R', self.t)) # stop simulation if all firm returned to normal except inital removal if self.t > 0: for firm in self.a_lst_total_firms: for prod in firm.dct_prod_up_prod_stat.keys(): status, ts = firm.dct_prod_up_prod_stat[prod]['status'][-1] - if status == 'R' and ts != 0: + if status == 'D' and ts != 0: print("not stop because", firm.name, prod.code) break else: @@ -369,12 +370,12 @@ class Model(ap.Model): def step(self): print('\n', '=' * 20, 'step', self.t, '=' * 20) - # remove_edge_to_cus_and_cus_up_prod + # remove edge to customer and affect customer up product for firm in self.a_lst_total_firms: for prod in firm.dct_prod_up_prod_stat.keys(): status, ts = firm.dct_prod_up_prod_stat[prod]['status'][-1] - if status == 'R' and ts == self.t-1: - firm.remove_edge_to_cus_remove_cus_up_prod(prod) + if status == 'D' and ts == self.t-1: + firm.remove_edge_to_cus_affect_cus_up_prod(prod) for n_trial in range(self.int_n_max_trial): print('=' * 10, 'trial', n_trial, '=' * 10) @@ -413,45 +414,46 @@ class Model(ap.Model): # do not use: # self.a_lst_total_firms.dct_request_prod_from_firm = {} why? - # turn disrupted firm into removed firm conditionally + # turn affected firm into disrupted firm conditionally for firm in self.a_lst_total_firms: for product in firm.dct_prod_up_prod_stat.keys(): status = firm.dct_prod_up_prod_stat[product]['status'][-1][0] - if status == 'D': - print(firm.name, 'disrupted product: ', product.code) - n_up_product_removed = \ + if status == 'A': + print(firm.name, 'affected product: ', product.code) + n_up_product_lost = \ sum([not stat for stat in firm.dct_prod_up_prod_stat[ product]['supply'].values()]) - if n_up_product_removed == 0: + if n_up_product_lost == 0: continue else: - lost_percent = n_up_product_removed / len( + lost_percent = n_up_product_lost / len( product.a_predecessors()) lst_size = self.a_lst_total_firms.size lst_size = [firm.size for firm in self.a_lst_total_firms if product in firm.a_lst_product and product - not in firm.a_lst_product_removed + not in firm.a_lst_product_disrupted ] std_size = (firm.size - min(lst_size) + 1) / (max(lst_size) - min(lst_size) + 1) - prob_remove = 1 - std_size * (1 - lost_percent) + prob_disrupt = 1 - std_size * (1 - lost_percent) # damp prob - prob_remove = prob_remove ** self.flt_diff_remove + prob_disrupt = prob_disrupt ** self.flt_diff_disrupt # sample prob - prob_remove = self.nprandom.uniform( - prob_remove - 0.1, prob_remove + 0.1) - prob_remove = 1 if prob_remove > 1 else prob_remove - prob_remove = 0 if prob_remove < 0 else prob_remove + prob_disrupt = self.nprandom.uniform( + prob_disrupt - 0.1, prob_disrupt + 0.1) + prob_disrupt = 1 if prob_disrupt > 1 else prob_disrupt + prob_disrupt = 0 if prob_disrupt < 0 else prob_disrupt if self.nprandom.choice([True, False], - p=[prob_remove, - 1 - prob_remove]): - firm.a_lst_product_removed.append(product) + p=[prob_disrupt, + 1 - prob_disrupt]): + firm.a_lst_product_disrupted.append(product) firm.dct_prod_up_prod_stat[ - product]['status'].append(('R', self.t)) - print(firm.name, 'removed product: ', product.code) + product]['status'].append(('D', self.t)) + print(firm.name, 'disrupted product:', + product.code) else: firm.dct_prod_up_prod_stat[ product]['status'].append(('N', self.t)) @@ -473,7 +475,7 @@ class Model(ap.Model): # lst_result_info.append(db_r) # db_session.bulk_save_objects(lst_result_info) # db_session.commit() - # for t, dct in self.lst_dct_lst_remove_firm_prod: + # for t, dct in self.lst_dct_lst_disrupt_firm_prod: # for firm, a_lst_product in dct.items(): # for product in a_lst_product: # # only firm disrupted can be removed theoretically diff --git a/orm.py b/orm.py index ef29dcf..39f82c2 100644 --- a/orm.py +++ b/orm.py @@ -51,7 +51,7 @@ class Experiment(Base): n_iter = Column(Integer, nullable=False) # variables - dct_lst_init_remove_firm_prod = Column(PickleType, nullable=False) + dct_lst_init_disrupt_firm_prod = Column(PickleType, nullable=False) g_bom = Column(Text(4294000000), nullable=False) n_max_trial = Column(Integer, nullable=False) @@ -61,9 +61,9 @@ class Experiment(Base): cap_limit_level = Column(DECIMAL(8, 4), nullable=False) diff_new_conn = Column(DECIMAL(8, 4), nullable=False) crit_supplier = Column(DECIMAL(8, 4), nullable=False) - diff_remove = Column(DECIMAL(8, 4), nullable=False) + diff_disrupt = Column(DECIMAL(8, 4), nullable=False) proactive_ratio = Column(DECIMAL(8, 4), nullable=False) - drop_t = Column(Integer, nullable=False) + remove_t = Column(Integer, nullable=False) netw_prf_n = Column(Integer, nullable=False) sample = relationship( diff --git a/xv_with_exp.csv b/xv_with_exp.csv index cae89dc..e002363 100644 --- a/xv_with_exp.csv +++ b/xv_with_exp.csv @@ -1,4 +1,4 @@ -n_max_trial,prf_size,prf_conn,cap_limit_prob_type,cap_limit_level,diff_new_conn,crit_supplier,diff_remove,proactive_ratio,drop_t,netw_prf_n +n_max_trial,prf_size,prf_conn,cap_limit_prob_type,cap_limit_level,diff_new_conn,crit_supplier,diff_disrupt,proactive_ratio,remove_t,netw_prf_n 15,TRUE,TRUE,uniform,5,0.3,2,0.5,0.3,3,3 10,FALSE,FALSE,normal,10,0.5,1,1,0.5,5,2 5,,,,15,0.7,0.5,2,0.7,7,1 diff --git a/xv_without_exp.csv b/xv_without_exp.csv index 4c5fda0..22d96de 100644 --- a/xv_without_exp.csv +++ b/xv_without_exp.csv @@ -1,2 +1,2 @@ -n_max_trial,prf_size,prf_conn,cap_limit_prob_type,cap_limit_level,diff_new_conn,crit_supplier,diff_remove,proactive_ratio,drop_t,netw_prf_n +n_max_trial,prf_size,prf_conn,cap_limit_prob_type,cap_limit_level,diff_new_conn,crit_supplier,diff_disrupt,proactive_ratio,remove_t,netw_prf_n 10,TRUE,TRUE,uniform,10,0.1,1,0.01,0,5,2