271 lines
13 KiB
Python
271 lines
13 KiB
Python
import json
|
||
import os
|
||
import datetime
|
||
|
||
import networkx as nx
|
||
import pandas as pd
|
||
from mesa import Model
|
||
|
||
from typing import TYPE_CHECKING
|
||
|
||
from my_model import MyModel
|
||
|
||
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}
|
||
|
||
product_network_test = nx.adjacency_graph(json.loads(dct_sample_para['g_bom']))
|
||
|
||
model = MyModel(dct_sample_para)
|
||
for i in range(1):
|
||
model.step()
|
||
print(i, datetime.datetime.now())
|
||
model.end()
|
||
return False
|
||
|
||
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 图对象
|