remove disrupt to removed, 3 status (Normal / Affected / Removed) + size_stat

This commit is contained in:
HaoYizhi 2023-07-02 13:00:13 +08:00
parent fe58a2cf9a
commit baf60ffd76
10 changed files with 40 additions and 73 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -79,8 +79,8 @@ class ControllerDB:
for product_code in row.index[row == 1].to_list(): for product_code in row.index[row == 1].to_list():
dct = {code: [product_code]} dct = {code: [product_code]}
list_dct.append(dct) list_dct.append(dct)
# list_dct = [{'140': ['1.4.5.1']}] list_dct = [{'140': ['1.4.5.1']}]
list_dct = [{'133': ['1.4.4.1']}] # list_dct = [{'133': ['1.4.4.1']}]
# list_dct = [{'2': ['1.1.3']}] # list_dct = [{'2': ['1.1.3']}]
# list_dct = [{'135': ['1.3.2.1']}] # list_dct = [{'135': ['1.3.2.1']}]
# list_dct = [{'79': ['2.1.3.4']}] # list_dct = [{'79': ['2.1.3.4']}]
@ -128,7 +128,7 @@ class ControllerDB:
dct_lst_init_disrupt_firm_prod, g_bom, dct_lst_init_disrupt_firm_prod, g_bom,
n_max_trial, prf_size, prf_conn, n_max_trial, prf_size, prf_conn,
cap_limit_prob_type, cap_limit_level, cap_limit_prob_type, cap_limit_level,
diff_new_conn, crit_supplier, diff_disrupt, diff_new_conn, crit_supplier,
proactive_ratio, remove_t, netw_prf_n): proactive_ratio, remove_t, netw_prf_n):
e = Experiment( e = Experiment(
idx_scenario=idx_scenario, idx_scenario=idx_scenario,
@ -144,7 +144,6 @@ class ControllerDB:
cap_limit_level=cap_limit_level, cap_limit_level=cap_limit_level,
diff_new_conn=diff_new_conn, diff_new_conn=diff_new_conn,
crit_supplier=crit_supplier, crit_supplier=crit_supplier,
diff_disrupt=diff_disrupt,
proactive_ratio=proactive_ratio, proactive_ratio=proactive_ratio,
remove_t=remove_t, remove_t=remove_t,
netw_prf_n=netw_prf_n netw_prf_n=netw_prf_n

30
firm.py
View File

@ -11,8 +11,7 @@ class FirmAgent(ap.Agent):
self.code = code self.code = code
self.name = name self.name = name
self.type_region = type_region self.type_region = type_region
self.ori_size = revenue_log self.size_stat = []
self.size = revenue_log
self.dct_prod_up_prod_stat = {} self.dct_prod_up_prod_stat = {}
self.dct_prod_capacity = {} self.dct_prod_capacity = {}
@ -29,11 +28,15 @@ class FirmAgent(ap.Agent):
self.flt_diff_new_conn = float(self.p.diff_new_conn) self.flt_diff_new_conn = float(self.p.diff_new_conn)
self.flt_crit_supplier = float(self.p.crit_supplier) self.flt_crit_supplier = float(self.p.crit_supplier)
# init size_stat (self para)
# (size, time step), ts -1 denotes initialization
self.size_stat.append((revenue_log, -1))
# init dct_prod_up_prod_stat (self para) # init dct_prod_up_prod_stat (self para)
for prod in a_lst_product: for prod in a_lst_product:
self.dct_prod_up_prod_stat[prod] = { self.dct_prod_up_prod_stat[prod] = {
# (Normal / Affected / Disrupted / Removed, time step) # (Normal / Affected / Removed, time step)
'status': [('N', 0)], 'status': [('N', -1)], # ts -1 denotes initialization
# have or have no supply # have or have no supply
'supply': dict.fromkeys(prod.a_predecessors(), True) 'supply': dict.fromkeys(prod.a_predecessors(), True)
} }
@ -45,7 +48,7 @@ class FirmAgent(ap.Agent):
"cap_limit_prob_type other than uniform, normal" "cap_limit_prob_type other than uniform, normal"
if self.str_cap_limit_prob_type == 'uniform': if self.str_cap_limit_prob_type == 'uniform':
extra_cap_mean = \ extra_cap_mean = \
self.size / self.flt_cap_limit_level self.size_stat[0][0] / self.flt_cap_limit_level
extra_cap = self.model.nprandom.integers(extra_cap_mean-2, extra_cap = self.model.nprandom.integers(extra_cap_mean-2,
extra_cap_mean+2) extra_cap_mean+2)
extra_cap = 0 if round(extra_cap) < 0 else round(extra_cap) extra_cap = 0 if round(extra_cap) < 0 else round(extra_cap)
@ -53,7 +56,7 @@ class FirmAgent(ap.Agent):
self.dct_prod_capacity[product] = extra_cap self.dct_prod_capacity[product] = extra_cap
elif self.str_cap_limit_prob_type == 'normal': elif self.str_cap_limit_prob_type == 'normal':
extra_cap_mean = \ extra_cap_mean = \
self.size / self.flt_cap_limit_level self.size_stat[0][0] / self.flt_cap_limit_level
extra_cap = self.model.nprandom.normal(extra_cap_mean, 1) extra_cap = self.model.nprandom.normal(extra_cap_mean, 1)
extra_cap = 0 if round(extra_cap) < 0 else round(extra_cap) extra_cap = 0 if round(extra_cap) < 0 else round(extra_cap)
# print(firm_agent.name, extra_cap) # print(firm_agent.name, extra_cap)
@ -133,7 +136,7 @@ class FirmAgent(ap.Agent):
lst_size = \ lst_size = \
[size for size in [size for size in
self.dct_cand_alt_supp_up_prod_disrupted[ self.dct_cand_alt_supp_up_prod_disrupted[
product].size] product].size_stat[-1][0]]
lst_prob = [size / sum(lst_size) lst_prob = [size / sum(lst_size)
for size in lst_size] for size in lst_size]
select_alt_supply = self.model.nprandom.choice( select_alt_supply = self.model.nprandom.choice(
@ -146,7 +149,8 @@ class FirmAgent(ap.Agent):
# select based on size of connected firm or not # select based on size of connected firm or not
if self.is_prf_size: if self.is_prf_size:
lst_firm_size = \ lst_firm_size = \
[firm.size for firm in lst_firm_connect] [firm.size_stat[-1][0]
for firm in lst_firm_connect]
lst_prob = \ lst_prob = \
[size / sum(lst_firm_size) [size / sum(lst_firm_size)
for size in lst_firm_size] for size in lst_firm_size]
@ -215,7 +219,7 @@ class FirmAgent(ap.Agent):
# handling based on size or not # handling based on size or not
if self.is_prf_size: if self.is_prf_size:
lst_firm_size = \ lst_firm_size = \
[firm.size for firm in lst_firm] [firm.size_stat[-1][0] for firm in lst_firm]
lst_prob = \ lst_prob = \
[size / sum(lst_firm_size) [size / sum(lst_firm_size)
for size in lst_firm_size] for size in lst_firm_size]
@ -230,7 +234,8 @@ class FirmAgent(ap.Agent):
# handling based on size of connected firm or not # handling based on size of connected firm or not
if self.is_prf_size: if self.is_prf_size:
lst_firm_size = \ lst_firm_size = \
[firm.size for firm in lst_firm_connect] [firm.size_stat[-1][0]
for firm in lst_firm_connect]
lst_prob = \ lst_prob = \
[size / sum(lst_firm_size) [size / sum(lst_firm_size)
for size in lst_firm_size] for size in lst_firm_size]
@ -273,6 +278,11 @@ class FirmAgent(ap.Agent):
else: else:
down_firm.dct_cand_alt_supp_up_prod_disrupted[product].remove(self) down_firm.dct_cand_alt_supp_up_prod_disrupted[product].remove(self)
print(
f"{self.name} denied {product.code} request "
f"from {down_firm.name}"
)
def clean_before_trial(self): def clean_before_trial(self):
self.dct_request_prod_from_firm = {} self.dct_request_prod_from_firm = {}

View File

@ -22,7 +22,6 @@ class Model(ap.Model):
# external variable # external variable
self.int_n_max_trial = int(self.p.n_max_trial) self.int_n_max_trial = int(self.p.n_max_trial)
self.is_prf_size = bool(self.p.prf_size) self.is_prf_size = bool(self.p.prf_size)
self.flt_diff_disrupt = float(self.p.diff_disrupt)
self.proactive_ratio = float(self.p.proactive_ratio) self.proactive_ratio = float(self.p.proactive_ratio)
self.remove_t = int(self.p.remove_t) self.remove_t = int(self.p.remove_t)
self.int_netw_prf_n = int(self.p.netw_prf_n) self.int_netw_prf_n = int(self.p.netw_prf_n)
@ -227,7 +226,8 @@ class Model(ap.Model):
assert product in firm.dct_prod_up_prod_stat.keys(), \ assert product in firm.dct_prod_up_prod_stat.keys(), \
f"product {product.code} not in firm {firm.code}" f"product {product.code} not in firm {firm.code}"
firm.dct_prod_up_prod_stat[ firm.dct_prod_up_prod_stat[
product]['status'].append(('D', self.t)) product]['status'].append(('A', self.t))
print(f"initial removal {firm.name} {product.code}")
# proactive strategy # proactive strategy
# get all the firm prod affected # get all the firm prod affected
@ -297,7 +297,7 @@ class Model(ap.Model):
for path in lst_shortest_path]) \ for path in lst_shortest_path]) \
/ len(lst_shortest_path) / len(lst_shortest_path)
drs = n2n_betweenness / \ drs = n2n_betweenness / \
(len(lst_cand) * di_supp_firm.size) (len(lst_cand) * di_supp_firm.size_stat[-1][0])
dct_drs[di_supp_code] = drs dct_drs[di_supp_code] = drs
dct_drs = dict(sorted( dct_drs = dict(sorted(
dct_drs.items(), key=lambda kv: kv[1], reverse=True)) dct_drs.items(), key=lambda kv: kv[1], reverse=True))
@ -341,23 +341,25 @@ class Model(ap.Model):
for firm in self.a_lst_total_firms: for firm in self.a_lst_total_firms:
for prod in firm.dct_prod_up_prod_stat.keys(): 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]['status'][-1]
if status == 'D': if status == 'A':
firm.size -= \ size = firm.size_stat[-1][0] - \
firm.ori_size \ firm.size_stat[0][0] \
/ len(firm.dct_prod_up_prod_stat.keys()) \ / len(firm.dct_prod_up_prod_stat.keys()) \
/ self.remove_t / self.remove_t
print(self.t, firm.name, prod.code, firm.size) firm.size_stat.append((size, self.t))
print(f'in ts {self.t}, reduce {firm.name} size '
f'to {firm.size_stat[-1][0]} due to {prod.code}')
if self.t - ts + 1 == self.remove_t: if self.t - ts + 1 == self.remove_t:
# turn disrupted firm into removed firm # turn disrupted firm into removed firm
firm.dct_prod_up_prod_stat[ firm.dct_prod_up_prod_stat[
prod]['status'].append(('R', self.t)) prod]['status'].append(('R', self.t))
# stop simulation if all firm returned to normal except inital removal # stop simulation if any firm still in affected except inital removal
if self.t > 0: if self.t > 0:
for firm in self.a_lst_total_firms: for firm in self.a_lst_total_firms:
for prod in firm.dct_prod_up_prod_stat.keys(): 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]['status'][-1]
if status == 'D' and ts != 0: if status == 'A' and ts != 0:
print("not stop because", firm.name, prod.code) print("not stop because", firm.name, prod.code)
break break
else: else:
@ -374,7 +376,7 @@ class Model(ap.Model):
for firm in self.a_lst_total_firms: for firm in self.a_lst_total_firms:
for prod in firm.dct_prod_up_prod_stat.keys(): 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]['status'][-1]
if status == 'D' and ts == self.t-1: if status == 'A' and ts == self.t-1:
firm.remove_edge_to_cus_affect_cus_up_prod(prod) firm.remove_edge_to_cus_affect_cus_up_prod(prod)
for n_trial in range(self.int_n_max_trial): for n_trial in range(self.int_n_max_trial):
@ -387,7 +389,7 @@ class Model(ap.Model):
lst_seek_prod = [] lst_seek_prod = []
for prod in firm.dct_prod_up_prod_stat.keys(): 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]['status'][-1][0]
if status != 'N': if status == 'A':
for supply in firm.dct_prod_up_prod_stat[ for supply in firm.dct_prod_up_prod_stat[
prod]['supply'].keys(): prod]['supply'].keys():
if not firm.dct_prod_up_prod_stat[ if not firm.dct_prod_up_prod_stat[
@ -414,49 +416,6 @@ class Model(ap.Model):
# do not use: # do not use:
# self.a_lst_total_firms.dct_request_prod_from_firm = {} why? # self.a_lst_total_firms.dct_request_prod_from_firm = {} why?
# 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 == '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_lost == 0:
continue
else:
lost_percent = n_up_product_lost / len(
product.a_predecessors())
# firm (affected) + other firm (same product, normal)
lst_firm = [firm]
lst_firm += \
[firm for firm
in self.a_lst_total_firms
if firm.is_prod_in_current_normal(product)]
lst_size = [firm.size for firm in lst_firm]
std_size = (firm.size - min(lst_size) +
1) / (max(lst_size) - min(lst_size) + 1)
prob_disrupt = 1 - std_size * (1 - lost_percent)
# damp prob
prob_disrupt = prob_disrupt ** self.flt_diff_disrupt
# sample prob
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_disrupt,
1 - prob_disrupt]):
firm.dct_prod_up_prod_stat[
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))
def end(self): def end(self):
print('/' * 20, 'output', '/' * 20) print('/' * 20, 'output', '/' * 20)

View File

@ -1,2 +1,2 @@
X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11 X1,X2,X3,X4,X5,X6,X7,X8,X9,X10
0,0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0

1 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11
2 0 0 0 0 0 0 0 0 0 0 0

1
orm.py
View File

@ -61,7 +61,6 @@ class Experiment(Base):
cap_limit_level = Column(DECIMAL(8, 4), nullable=False) cap_limit_level = Column(DECIMAL(8, 4), nullable=False)
diff_new_conn = Column(DECIMAL(8, 4), nullable=False) diff_new_conn = Column(DECIMAL(8, 4), nullable=False)
crit_supplier = Column(DECIMAL(8, 4), nullable=False) crit_supplier = Column(DECIMAL(8, 4), nullable=False)
diff_disrupt = Column(DECIMAL(8, 4), nullable=False)
proactive_ratio = Column(DECIMAL(8, 4), nullable=False) proactive_ratio = Column(DECIMAL(8, 4), nullable=False)
remove_t = Column(Integer, nullable=False) remove_t = Column(Integer, nullable=False)
netw_prf_n = Column(Integer, nullable=False) netw_prf_n = Column(Integer, nullable=False)

View File

@ -1,2 +1,2 @@
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 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
10,TRUE,TRUE,uniform,10,0.5,0.1,0.01,1,5,2 10,TRUE,TRUE,uniform,10,0.1,0.1,1,5,2

1 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
2 10 TRUE TRUE uniform 10 0.5 0.1 0.1 0.01 1 5 2