2024-11-28 18:56:24 +08:00
|
|
|
|
import json
|
2024-08-24 11:20:13 +08:00
|
|
|
|
import os
|
|
|
|
|
import datetime
|
2024-11-28 18:56:24 +08:00
|
|
|
|
|
|
|
|
|
import networkx as nx
|
2024-12-08 18:43:33 +08:00
|
|
|
|
import pandas as pd
|
2024-08-24 16:13:37 +08:00
|
|
|
|
from mesa import Model
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
|
|
|
|
from typing import TYPE_CHECKING
|
2024-08-24 19:30:16 +08:00
|
|
|
|
|
2024-09-13 16:58:14 +08:00
|
|
|
|
from my_model import MyModel
|
2024-08-24 19:30:16 +08:00
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
from controller_db import ControllerDB
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Computation:
|
|
|
|
|
|
|
|
|
|
def __init__(self, c_db: 'ControllerDB'):
|
|
|
|
|
# 控制不同进程 计算不同的样本 但使用同一个 数据库 c_db
|
|
|
|
|
self.c_db = c_db
|
|
|
|
|
self.pid = os.getpid()
|
|
|
|
|
|
|
|
|
|
def run(self, str_code='0', s_id=None):
|
|
|
|
|
sample_random = self.c_db.fetch_a_sample(s_id)
|
|
|
|
|
if sample_random is None:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# lock this row by update is_done_flag to 0 将运行后的样本设置为 flag 0
|
|
|
|
|
self.c_db.lock_the_sample(sample_random)
|
|
|
|
|
print(
|
|
|
|
|
f"Pid {self.pid} ({str_code}) is running "
|
|
|
|
|
f"sample {sample_random.id} at {datetime.datetime.now()}")
|
|
|
|
|
# 将sample 对应的 experiment 的一系列值 和 参数值 传入 模型 中 包括列名 和 值
|
|
|
|
|
dct_exp = {column: getattr(sample_random.experiment, column)
|
|
|
|
|
for column in sample_random.experiment.__table__.c.keys()}
|
|
|
|
|
# 删除不需要的 主键
|
|
|
|
|
del dct_exp['id']
|
|
|
|
|
|
|
|
|
|
dct_sample_para = {'sample': sample_random,
|
|
|
|
|
'seed': sample_random.seed,
|
|
|
|
|
**dct_exp}
|
2024-11-28 18:56:24 +08:00
|
|
|
|
|
|
|
|
|
product_network_test = nx.adjacency_graph(json.loads(dct_sample_para['g_bom']))
|
|
|
|
|
|
2024-08-24 19:30:16 +08:00
|
|
|
|
model = MyModel(dct_sample_para)
|
2024-09-24 19:21:59 +08:00
|
|
|
|
for i in range(1):
|
2024-08-24 16:13:37 +08:00
|
|
|
|
model.step()
|
2024-09-24 19:21:59 +08:00
|
|
|
|
print(i, datetime.datetime.now())
|
|
|
|
|
model.end()
|
2024-08-24 11:20:13 +08:00
|
|
|
|
return False
|
2024-12-08 18:43:33 +08:00
|
|
|
|
|
|
|
|
|
def initialize_firm_network(self):
|
|
|
|
|
# Read the firm data
|
|
|
|
|
|
|
|
|
|
firm = pd.read_csv("input_data/input_firm_data/Firm_amended.csv")
|
|
|
|
|
|
|
|
|
|
firm['Code'] = firm['Code'].astype(str)
|
|
|
|
|
|
|
|
|
|
firm.fillna(0, inplace=True)
|
|
|
|
|
|
|
|
|
|
firm_attr = firm.loc[:, ["Code", "Type_Region", "Revenue_Log"]]
|
|
|
|
|
|
|
|
|
|
firm_industry_relation = pd.read_csv("input_data/firm_industry_relation.csv")
|
|
|
|
|
firm_industry_relation['Firm_Code'] = firm_industry_relation['Firm_Code'].astype('string')
|
|
|
|
|
|
|
|
|
|
firm_product = []
|
|
|
|
|
|
|
|
|
|
grouped = firm_industry_relation.groupby('Firm_Code')['Product_Code'].apply(list)
|
|
|
|
|
firm_product.append(grouped)
|
|
|
|
|
|
|
|
|
|
firm_attr['Product_Code'] = firm_attr['Code'].map(grouped)
|
|
|
|
|
firm_attr.set_index('Code', inplace=True)
|
|
|
|
|
|
|
|
|
|
grouped = firm_industry_relation.groupby('Firm_Code')
|
|
|
|
|
self.firm_prod_labels_dict = {code: group['Product_Code'].tolist() for code, group in grouped}
|
|
|
|
|
|
|
|
|
|
# 遍历'Product_Code' 与 index 交换
|
|
|
|
|
for index, row in firm_attr.iterrows():
|
|
|
|
|
id_index_list = []
|
|
|
|
|
for i in row['Product_Code']:
|
|
|
|
|
for key_values in self.id_code.items():
|
|
|
|
|
if int(key_values[0]) == i:
|
|
|
|
|
for id in key_values[1]:
|
|
|
|
|
id_index_list.append(id)
|
|
|
|
|
firm_attr.at[index, 'Product_Code'] = id_index_list
|
|
|
|
|
|
|
|
|
|
self.G_Firm.add_nodes_from(firm["Code"])
|
|
|
|
|
# Assign attributes to the firm nodes
|
|
|
|
|
firm_labels_dict = {code: firm_attr.loc[code].to_dict() for code in self.G_Firm.nodes}
|
|
|
|
|
nx.set_node_attributes(self.G_Firm, firm_labels_dict)
|
|
|
|
|
|
|
|
|
|
self.Firm = firm
|
|
|
|
|
|
|
|
|
|
def initialize_firm_product_network(self):
|
|
|
|
|
|
|
|
|
|
firm_industry_relation = pd.read_csv("input_data/firm_industry_relation.csv")
|
|
|
|
|
firm_industry_relation['Firm_Code'] = firm_industry_relation['Firm_Code'].astype('string')
|
|
|
|
|
firm_industry_relation['Product_Code'] = firm_industry_relation['Product_Code'].apply(lambda x: [x])
|
|
|
|
|
# 将 'firm_prod' 表中的每一行作为图中的节点
|
|
|
|
|
self.G_FirmProd.add_nodes_from(firm_industry_relation.index)
|
|
|
|
|
# 为每个节点分配属性
|
|
|
|
|
|
|
|
|
|
# 遍历'Product_Code' 与 index 交换
|
|
|
|
|
for index, row in firm_industry_relation.iterrows():
|
|
|
|
|
id_index_list = []
|
|
|
|
|
for i in row['Product_Code']:
|
|
|
|
|
for key_values in self.id_code.items():
|
|
|
|
|
if int(key_values[0]) == i:
|
|
|
|
|
for id in key_values[1]:
|
|
|
|
|
id_index_list.append(id)
|
|
|
|
|
firm_industry_relation.at[index, 'Product_Code'] = id_index_list
|
|
|
|
|
|
|
|
|
|
firm_prod_labels_dict = {code: firm_industry_relation.loc[code].to_dict() for code in
|
|
|
|
|
firm_industry_relation.index}
|
|
|
|
|
nx.set_node_attributes(self.G_FirmProd, firm_prod_labels_dict)
|
|
|
|
|
|
|
|
|
|
def add_edges_to_firm_network(self):
|
|
|
|
|
""" Add edges between firms based on the product BOM relationships """
|
|
|
|
|
# Add edges to G_Firm according to G_bom
|
|
|
|
|
for node in nx.nodes(self.G_Firm):
|
|
|
|
|
lst_pred_product_code = []
|
|
|
|
|
for product_code in self.G_Firm.nodes[node]['Product_Code']:
|
|
|
|
|
lst_pred_product_code += list(self.G_bom.predecessors(product_code))
|
|
|
|
|
lst_pred_product_code = list(set(lst_pred_product_code))
|
|
|
|
|
lst_pred_product_code = list(sorted(lst_pred_product_code)) # Ensure consistency
|
|
|
|
|
|
|
|
|
|
for pred_product_code in lst_pred_product_code:
|
|
|
|
|
# Get a list of firms producing the component (pred_product_code)
|
|
|
|
|
lst_pred_firm = [firm_code for firm_code, product in self.firm_prod_labels_dict.items() if
|
|
|
|
|
pred_product_code in product]
|
|
|
|
|
|
|
|
|
|
# Select multiple suppliers (multi-sourcing)
|
|
|
|
|
n_pred_firm = self.int_netw_prf_n
|
|
|
|
|
if n_pred_firm > len(lst_pred_firm):
|
|
|
|
|
n_pred_firm = len(lst_pred_firm)
|
|
|
|
|
|
|
|
|
|
if self.is_prf_size:
|
|
|
|
|
# 获取 firm 的 size 列表
|
|
|
|
|
lst_pred_firm_size = [self.G_Firm.nodes[pred_firm]['Revenue_Log'] for pred_firm in lst_pred_firm]
|
|
|
|
|
# 检查 lst_pred_firm_size 是否为空或总和为 0
|
|
|
|
|
if len(lst_pred_firm_size) == 0 or sum(lst_pred_firm_size) == 0:
|
|
|
|
|
# print("警告: lst_pred_firm_size 为空或总和为 0,无法生成概率分布")
|
|
|
|
|
lst_choose_firm = [] # 返回空结果,或根据需要处理
|
|
|
|
|
else:
|
|
|
|
|
# 计算总和
|
|
|
|
|
sum_pred_firm_size = sum(lst_pred_firm_size)
|
|
|
|
|
# 归一化生成 lst_prob
|
|
|
|
|
lst_prob = [size / sum_pred_firm_size for size in lst_pred_firm_size]
|
|
|
|
|
# 使用 np.isclose() 确保概率总和接近 1
|
|
|
|
|
if not np.isclose(sum(lst_prob), 1.0):
|
|
|
|
|
# print(f"警告: 概率总和为 {sum(lst_prob)},现在进行修正")
|
|
|
|
|
lst_prob = [prob / sum(lst_prob) for prob in lst_prob]
|
|
|
|
|
# 确保没有负值或 0
|
|
|
|
|
lst_prob = [max(0, prob) for prob in lst_prob]
|
|
|
|
|
# 根据修正后的概率选择 firm
|
|
|
|
|
lst_choose_firm = self.nprandom.choice(lst_pred_firm, n_pred_firm, replace=False, p=lst_prob)
|
|
|
|
|
else:
|
|
|
|
|
# 直接进行随机选择
|
|
|
|
|
lst_choose_firm = self.nprandom.choice(lst_pred_firm, n_pred_firm, replace=False)
|
|
|
|
|
|
|
|
|
|
# Add edges from predecessor firms to current node (firm)
|
|
|
|
|
lst_add_edge = [(pred_firm, node, {'Product': pred_product_code}) for pred_firm in lst_choose_firm]
|
|
|
|
|
self.G_Firm.add_edges_from(lst_add_edge)
|
|
|
|
|
|
|
|
|
|
# Add edges to firm-product network
|
|
|
|
|
self.add_edges_to_firm_product_network(node, pred_product_code, lst_choose_firm)
|
|
|
|
|
|
|
|
|
|
def add_edges_to_firm_product_network(self, node, pred_product_code, lst_choose_firm):
|
|
|
|
|
""" Helper function to add edges to the firm-product network """
|
|
|
|
|
set_node_prod_code = set(self.G_Firm.nodes[node]['Product_Code'])
|
|
|
|
|
set_pred_succ_code = set(self.G_bom.successors(pred_product_code))
|
|
|
|
|
lst_use_pred_prod_code = list(set_node_prod_code & set_pred_succ_code)
|
|
|
|
|
|
|
|
|
|
if len(lst_use_pred_prod_code) == 0:
|
|
|
|
|
print("错误")
|
|
|
|
|
|
|
|
|
|
pred_node_list = []
|
|
|
|
|
for pred_firm in lst_choose_firm:
|
|
|
|
|
for n, v in self.G_FirmProd.nodes(data=True):
|
|
|
|
|
for v1 in v['Product_Code']:
|
|
|
|
|
if v1 == pred_product_code and v['Firm_Code'] == pred_firm:
|
|
|
|
|
pred_node_list.append(n)
|
|
|
|
|
if len(pred_node_list) != 0:
|
|
|
|
|
pred_node = pred_node_list[0]
|
|
|
|
|
else:
|
|
|
|
|
pred_node = -1
|
|
|
|
|
current_node_list = []
|
|
|
|
|
for use_pred_prod_code in lst_use_pred_prod_code:
|
|
|
|
|
for n, v in self.G_FirmProd.nodes(data=True):
|
|
|
|
|
for v1 in v['Product_Code']:
|
|
|
|
|
if v1 == use_pred_prod_code and v['Firm_Code'] == node:
|
|
|
|
|
current_node_list.append(n)
|
|
|
|
|
if len(current_node_list) != 0:
|
|
|
|
|
current_node = current_node_list[0]
|
|
|
|
|
else:
|
|
|
|
|
current_node = -1
|
|
|
|
|
if current_node != -1 and pred_node != -1:
|
|
|
|
|
self.G_FirmProd.add_edge(pred_node, current_node)
|
|
|
|
|
|
|
|
|
|
def connect_unconnected_nodes(self):
|
|
|
|
|
""" Connect unconnected nodes in the firm network """
|
|
|
|
|
for node in nx.nodes(self.G_Firm):
|
|
|
|
|
if self.G_Firm.degree(node) == 0:
|
|
|
|
|
current_node_list = []
|
|
|
|
|
for product_code in self.G_Firm.nodes[node]['Product_Code']:
|
|
|
|
|
for n, v in self.G_FirmProd.nodes(data=True):
|
|
|
|
|
for v1 in v['Product_Code']:
|
|
|
|
|
if v['Firm_Code'] == node and v1 == product_code:
|
|
|
|
|
current_node_list.append(n)
|
|
|
|
|
if len(current_node_list) != 0:
|
|
|
|
|
current_node = current_node_list[0]
|
|
|
|
|
else:
|
|
|
|
|
current_node = -1
|
|
|
|
|
lst_succ_product_code = list(self.G_bom.successors(product_code))
|
|
|
|
|
|
|
|
|
|
for succ_product_code in lst_succ_product_code:
|
|
|
|
|
lst_succ_firm = [firm_code for firm_code, product in self.firm_prod_labels_dict.items() if
|
|
|
|
|
succ_product_code in product]
|
|
|
|
|
|
|
|
|
|
n_succ_firm = self.int_netw_prf_n
|
|
|
|
|
if n_succ_firm > len(lst_succ_firm):
|
|
|
|
|
n_succ_firm = len(lst_succ_firm)
|
|
|
|
|
|
|
|
|
|
if self.is_prf_size:
|
|
|
|
|
lst_succ_firm_size = [self.G_Firm.nodes[succ_firm]['Revenue_Log'] for succ_firm in
|
|
|
|
|
lst_succ_firm]
|
|
|
|
|
if len(lst_succ_firm_size) == 0 or sum(lst_succ_firm_size) == 0:
|
|
|
|
|
# print("警告: lst_pred_firm_size 为空或总和为 0,无法生成概率分布")
|
|
|
|
|
lst_choose_firm = [] # 返回空结果,或根据需要处理
|
|
|
|
|
else:
|
|
|
|
|
# 计算总和
|
|
|
|
|
sum_pred_firm_size = sum(lst_succ_firm_size)
|
|
|
|
|
# 归一化生成 lst_prob
|
|
|
|
|
lst_prob = [size / sum_pred_firm_size for size in lst_succ_firm_size]
|
|
|
|
|
# 使用 np.isclose() 确保概率总和接近 1
|
|
|
|
|
if not np.isclose(sum(lst_prob), 1.0):
|
|
|
|
|
# print(f"警告: 概率总和为 {sum(lst_prob)},现在进行修正")
|
|
|
|
|
lst_prob = [prob / sum(lst_prob) for prob in lst_prob]
|
|
|
|
|
|
|
|
|
|
# 确保没有负值或 0
|
|
|
|
|
lst_prob = [max(0, prob) for prob in lst_prob]
|
|
|
|
|
|
|
|
|
|
lst_choose_firm = self.nprandom.choice(lst_succ_firm, n_succ_firm, replace=False,
|
|
|
|
|
p=lst_prob)
|
|
|
|
|
else:
|
|
|
|
|
lst_choose_firm = self.nprandom.choice(lst_succ_firm, n_succ_firm, replace=False)
|
|
|
|
|
|
|
|
|
|
lst_add_edge = [(node, succ_firm, {'Product': product_code}) for succ_firm in
|
|
|
|
|
lst_choose_firm]
|
|
|
|
|
self.G_Firm.add_edges_from(lst_add_edge)
|
|
|
|
|
|
|
|
|
|
# Add edges to firm-product network
|
|
|
|
|
succ_node_list = []
|
|
|
|
|
for succ_firm in lst_choose_firm:
|
|
|
|
|
for n, v in self.G_FirmProd.nodes(data=True):
|
|
|
|
|
for v1 in v['Product_Code']:
|
|
|
|
|
if v1 == succ_product_code and v['Firm_Code'] == succ_firm:
|
|
|
|
|
succ_node_list.append(n)
|
|
|
|
|
if len(succ_node_list) != 0:
|
|
|
|
|
succ_node = succ_node_list[0]
|
|
|
|
|
else:
|
|
|
|
|
succ_node = -1
|
|
|
|
|
|
|
|
|
|
if current_node != -1 and succ_node != -1:
|
|
|
|
|
self.G_FirmProd.add_edge(current_node, succ_node)
|
|
|
|
|
|
|
|
|
|
self.sample.g_firm = json.dumps(nx.adjacency_data(self.G_Firm))
|
|
|
|
|
self.firm_network = self.G_Firm # 直接使用 networkx 图对象
|
|
|
|
|
self.firm_prod_network = self.G_FirmProd # 直接使用 networkx 图对象
|