diff --git a/__pycache__/controller_db.cpython-38.pyc b/__pycache__/controller_db.cpython-38.pyc index 63207e0..bf68348 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 ea365f5..319af18 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 51763fc..57ddfca 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 03a1404..09a03a1 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 a9646ff..1e1b50d 100644 --- a/controller_db.py +++ b/controller_db.py @@ -117,7 +117,7 @@ class ControllerDB: 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_new_conn, proactive_ratio, remove_t, netw_prf_n): e = Experiment( idx_scenario=idx_scenario, @@ -132,7 +132,6 @@ class ControllerDB: cap_limit_prob_type=cap_limit_prob_type, cap_limit_level=cap_limit_level, diff_new_conn=diff_new_conn, - crit_supplier=crit_supplier, proactive_ratio=proactive_ratio, remove_t=remove_t, netw_prf_n=netw_prf_n diff --git a/firm.py b/firm.py index 692bea7..c5e273b 100644 --- a/firm.py +++ b/firm.py @@ -1,5 +1,4 @@ import agentpy as ap -import math class FirmAgent(ap.Agent): @@ -26,7 +25,6 @@ class FirmAgent(ap.Agent): self.str_cap_limit_prob_type = str(self.p.cap_limit_prob_type) self.flt_cap_limit_level = float(self.p.cap_limit_level) self.flt_diff_new_conn = float(self.p.diff_new_conn) - self.flt_crit_supplier = float(self.p.crit_supplier) # init size_stat (self para) # (size, time step) @@ -36,9 +34,14 @@ class FirmAgent(ap.Agent): for prod in a_lst_product: self.dct_prod_up_prod_stat[prod] = { # (Normal / Disrupted / Removed, time step) - 'status': [('N', 0)], + 'p_stat': [('N', 0)], # have or have no supply - 'supply': dict.fromkeys(prod.a_predecessors(), True) + 'supply': dict.fromkeys(prod.a_predecessors(), True), + # supply for each component and respective disrupted supplier + # lst_disrupt_firm is refreshed to [] at each update + 's_stat': dict.fromkeys(prod.a_predecessors(), + {'stat': True, + 'lst_disrupt_firm': []}) } # init extra capacity (self para) @@ -62,45 +65,58 @@ class FirmAgent(ap.Agent): # print(firm_agent.name, extra_cap) self.dct_prod_capacity[product] = extra_cap - def remove_edge_to_cus_disrupt_cus_up_prod(self, disrupted_prod): + def remove_edge_to_cus(self, disrupted_prod): # para disrupted_prod 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 == disrupted_prod.code: + # update customer up product supplier status + customer = ap.AgentIter(self.model, n2).to_list()[0] + for prod in customer.dct_prod_up_prod_stat.keys(): + if disrupted_prod in \ + customer.dct_prod_up_prod_stat[ + prod]['s_stat'].keys(): + if self not in customer.dct_prod_up_prod_stat[ + prod]['s_stat'][disrupted_prod][ + 'lst_disrupt_firm']: + customer.dct_prod_up_prod_stat[ + prod]['s_stat'][disrupted_prod][ + 'lst_disrupt_firm'].append(self) # remove edge to customer self.firm_network.graph.remove_edge(n1, n2, key) - # 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, - keys=True, - data='Product')) - lst_select_in_edge = [ - edge for edge in lst_in_edge - if edge[-1] == disrupted_prod.code - ] - prob_lost_supp = math.exp(-1 * self.flt_crit_supplier * - len(lst_select_in_edge)) - if self.model.nprandom.choice([True, False], - 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 disrupted_prod in \ - customer.dct_prod_up_prod_stat[ - prod]['supply'].keys(): - customer.dct_prod_up_prod_stat[ - prod]['supply'][disrupted_prod] = False - status, _ = customer.dct_prod_up_prod_stat[ - prod]['status'][-1] - if status != 'D': - customer.dct_prod_up_prod_stat[ - prod]['status'].append(('D', self.model.t)) - # print(self.name, disrupted_prod.code, 'disrupt', - # customer.name, prod.code) + def disrupt_cus_prod(self, prod, disrupted_up_prod): + # para prod is the product that has disrupted_up_prod + # para disrupted_up_prod is the product that + # self's component exists disrupted supplier + num_lost = \ + len(self.dct_prod_up_prod_stat[prod]['s_stat'] + [disrupted_up_prod]['lst_disrupt_firm']) + num_remain = \ + len([u for u, _, _, d in + self.firm_network.graph.in_edges(self.get_firm_network_node(), + keys=True, + data='Product') + if d == disrupted_up_prod.code]) + lost_percent = num_lost / (num_lost + num_remain) + lst_size = \ + [firm.size_stat[-1][0] for firm in self.model.a_lst_total_firms] + std_size = (self.size_stat[-1][0] - min(lst_size) + 1) \ + / (max(lst_size) - min(lst_size) + 1) + prob_disrupt = 1 - std_size * (1 - lost_percent) + if self.model.nprandom.choice([True, False], + p=[prob_disrupt, + 1 - prob_disrupt]): + self.dct_n_trial_up_prod_disrupted[disrupted_up_prod] = 0 + self.dct_prod_up_prod_stat[ + prod]['s_stat'][disrupted_up_prod]['stat'] = False + status, _ = self.dct_prod_up_prod_stat[ + prod]['p_stat'][-1] + if status != 'D': + self.dct_prod_up_prod_stat[ + prod]['p_stat'].append(('D', self.model.t)) def seek_alt_supply(self, product): # para product is the product that self is seeking @@ -270,7 +286,7 @@ class FirmAgent(ap.Agent): down_firm.dct_prod_up_prod_stat[ prod]['supply'][product] = True down_firm.dct_prod_up_prod_stat[ - prod]['status'].append(('N', self.model.t)) + prod]['p_stat'].append(('N', self.model.t)) del down_firm.dct_n_trial_up_prod_disrupted[product] del down_firm.dct_cand_alt_supp_up_prod_disrupted[product] @@ -296,17 +312,21 @@ class FirmAgent(ap.Agent): # update the status of firm for prod in self.dct_prod_up_prod_stat.keys(): - status, ts = self.dct_prod_up_prod_stat[prod]['status'][-1] + status, ts = self.dct_prod_up_prod_stat[prod]['p_stat'][-1] if ts != self.model.t: - self.dct_prod_up_prod_stat[prod]['status'].append( + self.dct_prod_up_prod_stat[prod]['p_stat'].append( (status, self.model.t)) + # refresh lst_disrupt_firm + for up_prod in self.dct_prod_up_prod_stat[prod]['s_stat'].keys(): + self.dct_prod_up_prod_stat[prod][ + 's_stat'][up_prod]['lst_disrupt_firm'] = [] def get_firm_network_node(self): return self.firm_network.positions[self] def is_prod_in_current_normal(self, prod): if prod in self.dct_prod_up_prod_stat.keys(): - if self.dct_prod_up_prod_stat[prod]['status'][-1][0] == 'N': + if self.dct_prod_up_prod_stat[prod]['p_stat'][-1][0] == 'N': return True else: return False diff --git a/model.py b/model.py index b4e9118..9f086c1 100644 --- a/model.py +++ b/model.py @@ -228,7 +228,7 @@ class Model(ap.Model): assert product in firm.dct_prod_up_prod_stat.keys(), \ f"product {product.code} not in firm {firm.code}" firm.dct_prod_up_prod_stat[ - product]['status'].append(('D', self.t)) + product]['p_stat'].append(('D', self.t)) # print(f"initial disruption {firm.name} {product.code}") # proactive strategy @@ -349,7 +349,7 @@ class Model(ap.Model): # 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] + status, ts = firm.dct_prod_up_prod_stat[prod]['p_stat'][-1] if status == 'D': size = firm.size_stat[-1][0] - \ firm.size_stat[0][0] \ @@ -360,19 +360,19 @@ class Model(ap.Model): # f'to {firm.size_stat[-1][0]} due to {prod.code}') lst_is_disrupt = \ [stat == 'D' for stat, _ in - firm.dct_prod_up_prod_stat[prod]['status'] + firm.dct_prod_up_prod_stat[prod]['p_stat'] [-1 * self.remove_t:]] if all(lst_is_disrupt): # turn disrupted firm into removed firm # when last self.remove_t times status is all disrupted firm.dct_prod_up_prod_stat[ - prod]['status'].append(('R', self.t)) + prod]['p_stat'].append(('R', self.t)) # stop simulation if any firm still in disrupted 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, _ = firm.dct_prod_up_prod_stat[prod]['status'][-1] + status, _ = firm.dct_prod_up_prod_stat[prod]['p_stat'][-1] is_init = \ firm in self.dct_lst_init_disrupt_firm_prod.keys() \ and prod in self.dct_lst_init_disrupt_firm_prod[firm] @@ -397,9 +397,17 @@ class Model(ap.Model): for prod in firm.dct_prod_up_prod_stat.keys(): # repetition of disrupted firm that last for multiple ts is ok, # as their edge has already been removed - status, ts = firm.dct_prod_up_prod_stat[prod]['status'][-1] + status, ts = firm.dct_prod_up_prod_stat[prod]['p_stat'][-1] if status == 'D' and ts == self.t-1: - firm.remove_edge_to_cus_disrupt_cus_up_prod(prod) + firm.remove_edge_to_cus(prod) + + for firm in self.a_lst_total_firms: + for prod in firm.dct_prod_up_prod_stat.keys(): + for up_prod in firm.dct_prod_up_prod_stat[prod][ + 's_stat'].keys(): + if firm.dct_prod_up_prod_stat[prod][ + 's_stat'][up_prod]['lst_disrupt_firm']: + firm.disrupt_cus_prod(prod, up_prod) for n_trial in range(self.int_n_max_trial): # print('=' * 10, 'trial', n_trial, '=' * 10) @@ -410,7 +418,7 @@ class Model(ap.Model): for firm in self.a_lst_total_firms: lst_seek_prod = [] for prod in firm.dct_prod_up_prod_stat.keys(): - status = firm.dct_prod_up_prod_stat[prod]['status'][-1][0] + status = firm.dct_prod_up_prod_stat[prod]['p_stat'][-1][0] if status == 'D': for supply in firm.dct_prod_up_prod_stat[ prod]['supply'].keys(): @@ -448,11 +456,11 @@ class Model(ap.Model): for prod, dct_status_supply in \ firm.dct_prod_up_prod_stat.items(): lst_is_normal = [stat == 'N' for stat, _ - in dct_status_supply['status']] + in dct_status_supply['p_stat']] if not all(lst_is_normal): # print(f"{firm.name} {prod.code}:") - # print(dct_status_supply['status']) - for status, ts in dct_status_supply['status']: + # print(dct_status_supply['p_stat']) + for status, ts in dct_status_supply['p_stat']: db_r = Result(s_id=self.sample.id, id_firm=firm.code, id_product=prod.code, diff --git a/oa_with_exp.csv b/oa_with_exp.csv index 5ee736e..6797bc2 100644 --- a/oa_with_exp.csv +++ b/oa_with_exp.csv @@ -1,37 +1,37 @@ X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18,X19,X20,X21,X22,X23 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -1,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1 -2,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2 -0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,2,2,2,2 -1,0,0,0,1,1,1,2,2,2,0,0,1,1,1,1,1,1,2,0,0,0,0 -2,0,0,0,2,2,2,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1 -0,0,0,1,0,1,2,0,1,2,1,1,0,0,0,1,1,1,2,0,1,1,2 -1,0,0,1,1,2,0,1,2,0,1,1,0,0,0,1,1,1,0,1,2,2,0 -2,0,0,1,2,0,1,2,0,1,1,1,0,0,0,1,1,1,1,2,0,0,1 -0,0,1,0,0,2,1,0,2,1,1,1,0,1,1,0,0,1,2,1,0,2,1 -1,0,1,0,1,0,2,1,0,2,1,1,0,1,1,0,0,1,0,2,1,0,2 -2,0,1,0,2,1,0,2,1,0,1,1,0,1,1,0,0,1,1,0,2,1,0 -0,0,1,1,1,2,0,2,1,0,0,1,1,0,1,0,1,0,2,2,1,0,1 -1,0,1,1,2,0,1,0,2,1,0,1,1,0,1,0,1,0,0,0,2,1,2 -2,0,1,1,0,1,2,1,0,2,0,1,1,0,1,0,1,0,1,1,0,2,0 -0,0,1,1,1,2,1,0,0,2,1,0,1,1,0,1,0,0,1,2,2,1,0 -1,0,1,1,2,0,2,1,1,0,1,0,1,1,0,1,0,0,2,0,0,2,1 -2,0,1,1,0,1,0,2,2,1,1,0,1,1,0,1,0,0,0,1,1,0,2 -0,1,0,1,1,0,2,2,2,0,1,0,0,1,1,0,1,0,1,1,0,1,2 -1,1,0,1,2,1,0,0,0,1,1,0,0,1,1,0,1,0,2,2,1,2,0 -2,1,0,1,0,2,1,1,1,2,1,0,0,1,1,0,1,0,0,0,2,0,1 -0,1,0,1,1,1,2,2,0,1,0,1,1,1,0,0,0,1,0,0,2,2,1 -1,1,0,1,2,2,0,0,1,2,0,1,1,1,0,0,0,1,1,1,0,0,2 -2,1,0,1,0,0,1,1,2,0,0,1,1,1,0,0,0,1,2,2,1,1,0 -0,1,0,0,2,1,0,1,2,2,1,1,1,0,1,1,0,0,0,2,0,1,1 -1,1,0,0,0,2,1,2,0,0,1,1,1,0,1,1,0,0,1,0,1,2,2 -2,1,0,0,1,0,2,0,1,1,1,1,1,0,1,1,0,0,2,1,2,0,0 -0,1,1,1,2,1,1,1,0,0,0,0,0,0,1,1,0,1,2,1,2,0,2 -1,1,1,1,0,2,2,2,1,1,0,0,0,0,1,1,0,1,0,2,0,1,0 -2,1,1,1,1,0,0,0,2,2,0,0,0,0,1,1,0,1,1,0,1,2,1 -0,1,1,0,2,2,2,1,2,1,1,0,1,0,0,0,1,1,1,0,1,0,0 -1,1,1,0,0,0,0,2,0,2,1,0,1,0,0,0,1,1,2,1,2,1,1 -2,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,1,1,0,2,0,2,2 -0,1,1,0,2,0,1,2,1,2,0,1,0,1,0,1,1,0,0,1,1,2,0 -1,1,1,0,0,1,2,0,2,0,0,1,0,1,0,1,1,0,1,2,2,0,1 -2,1,1,0,1,2,0,1,0,1,0,1,0,1,0,1,1,0,2,0,0,1,2 +1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1 +2,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2 +0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,2,2,2,2 +1,0,0,0,1,1,1,2,2,0,0,1,1,1,1,1,1,2,2,0,0,0,0 +2,0,0,0,2,2,2,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1 +0,0,0,1,0,1,2,0,1,1,1,0,0,0,1,1,1,2,2,0,1,1,2 +1,0,0,1,1,2,0,1,2,1,1,0,0,0,1,1,1,0,0,1,2,2,0 +2,0,0,1,2,0,1,2,0,1,1,0,0,0,1,1,1,1,1,2,0,0,1 +0,0,1,0,0,2,1,0,2,1,1,0,1,1,0,0,1,1,2,1,0,2,1 +1,0,1,0,1,0,2,1,0,1,1,0,1,1,0,0,1,2,0,2,1,0,2 +2,0,1,0,2,1,0,2,1,1,1,0,1,1,0,0,1,0,1,0,2,1,0 +0,0,1,1,1,2,0,2,1,0,1,1,0,1,0,1,0,0,2,2,1,0,1 +1,0,1,1,2,0,1,0,2,0,1,1,0,1,0,1,0,1,0,0,2,1,2 +2,0,1,1,0,1,2,1,0,0,1,1,0,1,0,1,0,2,1,1,0,2,0 +0,0,1,1,1,2,1,0,0,1,0,1,1,0,1,0,0,2,1,2,2,1,0 +1,0,1,1,2,0,2,1,1,1,0,1,1,0,1,0,0,0,2,0,0,2,1 +2,0,1,1,0,1,0,2,2,1,0,1,1,0,1,0,0,1,0,1,1,0,2 +0,1,0,1,1,0,2,2,2,1,0,0,1,1,0,1,0,0,1,1,0,1,2 +1,1,0,1,2,1,0,0,0,1,0,0,1,1,0,1,0,1,2,2,1,2,0 +2,1,0,1,0,2,1,1,1,1,0,0,1,1,0,1,0,2,0,0,2,0,1 +0,1,0,1,1,1,2,2,0,0,1,1,1,0,0,0,1,1,0,0,2,2,1 +1,1,0,1,2,2,0,0,1,0,1,1,1,0,0,0,1,2,1,1,0,0,2 +2,1,0,1,0,0,1,1,2,0,1,1,1,0,0,0,1,0,2,2,1,1,0 +0,1,0,0,2,1,0,1,2,1,1,1,0,1,1,0,0,2,0,2,0,1,1 +1,1,0,0,0,2,1,2,0,1,1,1,0,1,1,0,0,0,1,0,1,2,2 +2,1,0,0,1,0,2,0,1,1,1,1,0,1,1,0,0,1,2,1,2,0,0 +0,1,1,1,2,1,1,1,0,0,0,0,0,1,1,0,1,0,2,1,2,0,2 +1,1,1,1,0,2,2,2,1,0,0,0,0,1,1,0,1,1,0,2,0,1,0 +2,1,1,1,1,0,0,0,2,0,0,0,0,1,1,0,1,2,1,0,1,2,1 +0,1,1,0,2,2,2,1,2,1,0,1,0,0,0,1,1,1,1,0,1,0,0 +1,1,1,0,0,0,0,2,0,1,0,1,0,0,0,1,1,2,2,1,2,1,1 +2,1,1,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,0,2,0,2,2 +0,1,1,0,2,0,1,2,1,0,1,0,1,0,1,1,0,2,0,1,1,2,0 +1,1,1,0,0,1,2,0,2,0,1,0,1,0,1,1,0,0,1,2,2,0,1 +2,1,1,0,1,2,0,1,0,0,1,0,1,0,1,1,0,1,2,0,0,1,2 diff --git a/oa_with_exp.xlsx b/oa_with_exp.xlsx index b89df29..4c2a583 100644 Binary files a/oa_with_exp.xlsx and b/oa_with_exp.xlsx differ diff --git a/oa_without_exp.csv b/oa_without_exp.csv index 66c1886..829a8fc 100644 --- a/oa_without_exp.csv +++ b/oa_without_exp.csv @@ -1,2 +1,2 @@ -X1,X2,X3,X4,X5,X6,X7,X8,X9,X10 -0,0,0,0,0,0,0,0,0,0 +X1,X2,X3,X4,X5,X6,X7,X8,X9 +0,0,0,0,0,0,0,0,0 diff --git a/orm.py b/orm.py index 649bff0..bf6f2a1 100644 --- a/orm.py +++ b/orm.py @@ -60,7 +60,6 @@ class Experiment(Base): cap_limit_prob_type = Column(String(16), nullable=False) 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) proactive_ratio = Column(DECIMAL(8, 4), nullable=False) remove_t = Column(Integer, nullable=False) netw_prf_n = Column(Integer, nullable=False) diff --git a/xv_with_exp.csv b/xv_with_exp.csv index 7428909..35aa6de 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,proactive_ratio,remove_t,netw_prf_n -7,TRUE,TRUE,uniform,5,0.3,2,0.3,3,3 -5,FALSE,FALSE,normal,10,0.5,1,0.5,5,2 -3,,,,15,0.7,0.5,0.7,7,1 +n_max_trial,prf_size,prf_conn,cap_limit_prob_type,cap_limit_level,diff_new_conn,proactive_ratio,remove_t,netw_prf_n +7,TRUE,TRUE,uniform,5,0.3,0.3,3,3 +5,FALSE,FALSE,normal,10,0.5,0.5,5,2 +3,,,,15,0.7,0.7,7,1 diff --git a/xv_without_exp.csv b/xv_without_exp.csv index 818ef2b..2da3b75 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,proactive_ratio,remove_t,netw_prf_n -5,TRUE,TRUE,uniform,10,0.5,1,0,5,2 +n_max_trial,prf_size,prf_conn,cap_limit_prob_type,cap_limit_level,diff_new_conn,proactive_ratio,remove_t,netw_prf_n +5,TRUE,TRUE,uniform,10,0.5,0,5,2