2024-08-24 11:20:13 +08:00
|
|
|
|
import json
|
2024-08-24 16:13:37 +08:00
|
|
|
|
from random import shuffle
|
2024-09-24 19:21:59 +08:00
|
|
|
|
import platform
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
|
|
|
|
import networkx as nx
|
|
|
|
|
import pandas as pd
|
|
|
|
|
from mesa import Model
|
2024-08-24 16:13:37 +08:00
|
|
|
|
from mesa.space import MultiGrid, NetworkGrid
|
2024-08-24 11:20:13 +08:00
|
|
|
|
from mesa.datacollection import DataCollector
|
|
|
|
|
|
2024-09-17 14:17:58 +08:00
|
|
|
|
import numpy as np
|
2024-11-28 18:56:24 +08:00
|
|
|
|
from mesa_viz_tornado.modules import NetworkModule
|
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
from firm import FirmAgent
|
2024-09-24 19:21:59 +08:00
|
|
|
|
from orm import db_session, Result
|
2024-08-24 11:20:13 +08:00
|
|
|
|
from product import ProductAgent
|
|
|
|
|
|
2024-11-28 18:56:24 +08:00
|
|
|
|
from mesa.visualization import ModularServer
|
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
|
|
|
|
class MyModel(Model):
|
|
|
|
|
def __init__(self, params):
|
2024-09-18 16:59:32 +08:00
|
|
|
|
# 属性
|
2024-09-13 16:58:14 +08:00
|
|
|
|
self.is_prf_size = params['prf_size']
|
2024-08-24 19:30:16 +08:00
|
|
|
|
self.prf_conn = params['prf_conn']
|
|
|
|
|
self.cap_limit_prob_type = params['cap_limit_prob_type']
|
|
|
|
|
self.cap_limit_level = params['cap_limit_level']
|
|
|
|
|
self.diff_new_conn = params['diff_new_conn']
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
2024-09-13 16:58:14 +08:00
|
|
|
|
self.firm_network = nx.MultiDiGraph() # 有向多重图
|
|
|
|
|
self.firm_prod_network = nx.MultiDiGraph()
|
|
|
|
|
self.product_network = nx.MultiDiGraph() # 有向多重图
|
|
|
|
|
|
|
|
|
|
# NetworkGrid 用于管理网格
|
2024-08-24 16:13:37 +08:00
|
|
|
|
# NetworkX 图对象
|
|
|
|
|
self.t = 0
|
2024-08-24 19:30:16 +08:00
|
|
|
|
self.network_graph = nx.MultiDiGraph()
|
2024-08-24 16:13:37 +08:00
|
|
|
|
self.grid = NetworkGrid(self.network_graph)
|
|
|
|
|
|
|
|
|
|
self.data_collector = DataCollector(
|
|
|
|
|
agent_reporters={"Product": "name"}
|
|
|
|
|
)
|
2024-09-18 16:59:32 +08:00
|
|
|
|
|
2024-09-17 14:17:58 +08:00
|
|
|
|
# initialize graph bom
|
|
|
|
|
self.G_bom = nx.adjacency_graph(json.loads(params['g_bom']))
|
|
|
|
|
|
|
|
|
|
# Create the firm-product network graph
|
|
|
|
|
self.G_FirmProd = nx.MultiDiGraph()
|
|
|
|
|
# Create the firm network graph
|
|
|
|
|
self.G_Firm = nx.MultiDiGraph()
|
2024-08-24 19:30:16 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
self.company_agents = []
|
|
|
|
|
self.product_agents = []
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
2024-09-17 14:17:58 +08:00
|
|
|
|
self.nprandom = np.random.default_rng(params['seed'])
|
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
# Initialize parameters from `params`
|
|
|
|
|
self.sample = params['sample']
|
|
|
|
|
self.int_stop_ts = 0
|
|
|
|
|
self.int_n_iter = int(params['n_iter'])
|
|
|
|
|
self.dct_lst_init_disrupt_firm_prod = params['dct_lst_init_disrupt_firm_prod']
|
2024-09-18 16:59:32 +08:00
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
# external variable
|
|
|
|
|
self.int_n_max_trial = int(params['n_max_trial'])
|
|
|
|
|
self.is_prf_size = bool(params['prf_size'])
|
|
|
|
|
self.remove_t = int(params['remove_t'])
|
|
|
|
|
self.int_netw_prf_n = int(params['netw_prf_n'])
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-09-18 16:59:32 +08:00
|
|
|
|
# 方法执行
|
2024-08-24 16:13:37 +08:00
|
|
|
|
self.initialize_product_network(params)
|
2024-08-24 11:20:13 +08:00
|
|
|
|
self.initialize_firm_network()
|
2024-08-24 16:13:37 +08:00
|
|
|
|
self.initialize_firm_product_network()
|
2024-09-13 16:58:14 +08:00
|
|
|
|
self.add_edges_to_firm_network()
|
|
|
|
|
self.connect_unconnected_nodes()
|
2024-09-20 09:26:39 +08:00
|
|
|
|
self.resource_integration()
|
|
|
|
|
self.j_comp_consumed_produced()
|
2024-08-24 11:20:13 +08:00
|
|
|
|
self.initialize_agents()
|
2024-08-24 16:13:37 +08:00
|
|
|
|
self.initialize_disruptions()
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
def initialize_product_network(self, params):
|
2024-09-13 16:58:14 +08:00
|
|
|
|
try:
|
|
|
|
|
self.product_network = nx.adjacency_graph(json.loads(params['g_bom']))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Failed to initialize product network: {e}")
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 赋予 产业的量
|
|
|
|
|
# 产业种类
|
2024-09-29 16:41:34 +08:00
|
|
|
|
data = pd.read_csv('input_data/input_product_data/BomNodes.csv')
|
2024-09-21 22:39:09 +08:00
|
|
|
|
data['Code'] = data['Code'].astype('string')
|
|
|
|
|
self.type2 = data
|
2024-11-28 18:56:24 +08:00
|
|
|
|
self.id_code = data.groupby('Code')['Index'].apply(list)
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 设备c折旧比值
|
2024-09-21 22:39:09 +08:00
|
|
|
|
###
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
|
|
|
|
def initialize_firm_network(self):
|
2024-09-17 14:17:58 +08:00
|
|
|
|
# Read the firm data
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-09-29 16:41:34 +08:00
|
|
|
|
firm = pd.read_csv("input_data/input_firm_data/Firm_amended.csv")
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-10-22 10:51:02 +08:00
|
|
|
|
firm['Code'] = firm['Code'].astype(str)
|
|
|
|
|
|
2024-09-18 16:59:32 +08:00
|
|
|
|
firm.fillna(0, inplace=True)
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-11-28 18:56:24 +08:00
|
|
|
|
firm_attr = firm.loc[:, ["Code", "Type_Region", "Revenue_Log"]]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
firm_industry_relation = pd.read_csv("input_data/firm_industry_relation.csv")
|
|
|
|
|
firm_industry_relation['Firm_Code'] = firm_industry_relation['Firm_Code'].astype('string')
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
|
|
|
|
firm_product = []
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
grouped = firm_industry_relation.groupby('Firm_Code')['Product_Code'].apply(list)
|
|
|
|
|
firm_product.append(grouped)
|
|
|
|
|
|
|
|
|
|
firm_attr['Product_Code'] = firm_attr['Code'].map(grouped)
|
2024-09-18 16:59:32 +08:00
|
|
|
|
firm_attr.set_index('Code', inplace=True)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
2024-11-28 18:56:24 +08:00
|
|
|
|
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
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
2024-11-28 18:56:24 +08:00
|
|
|
|
self.G_Firm.add_nodes_from(firm["Code"])
|
2024-09-17 14:17:58 +08:00
|
|
|
|
# Assign attributes to the firm nodes
|
2024-09-18 16:59:32 +08:00
|
|
|
|
firm_labels_dict = {code: firm_attr.loc[code].to_dict() for code in self.G_Firm.nodes}
|
2024-09-17 14:17:58 +08:00
|
|
|
|
nx.set_node_attributes(self.G_Firm, firm_labels_dict)
|
|
|
|
|
|
2024-09-18 16:59:32 +08:00
|
|
|
|
self.Firm = firm
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
|
|
|
|
def initialize_firm_product_network(self):
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
firm_industry_relation = pd.read_csv("input_data/firm_industry_relation.csv")
|
|
|
|
|
firm_industry_relation['Firm_Code'] = firm_industry_relation['Firm_Code'].astype('string')
|
2024-11-28 18:56:24 +08:00
|
|
|
|
firm_industry_relation['Product_Code'] = firm_industry_relation['Product_Code'].apply(lambda x: [x])
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 将 'firm_prod' 表中的每一行作为图中的节点
|
|
|
|
|
self.G_FirmProd.add_nodes_from(firm_industry_relation.index)
|
|
|
|
|
# 为每个节点分配属性
|
2024-09-21 22:39:09 +08:00
|
|
|
|
|
2024-11-28 18:56:24 +08:00
|
|
|
|
# 遍历'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
|
2024-09-21 22:39:09 +08:00
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
firm_prod_labels_dict = {code: firm_industry_relation.loc[code].to_dict() for code in
|
|
|
|
|
firm_industry_relation.index}
|
2024-09-17 14:17:58 +08:00
|
|
|
|
nx.set_node_attributes(self.G_FirmProd, firm_prod_labels_dict)
|
2024-09-13 16:58:14 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
def add_edges_to_firm_network(self):
|
2024-09-17 14:17:58 +08:00
|
|
|
|
""" 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):
|
2024-08-24 16:13:37 +08:00
|
|
|
|
lst_pred_product_code = []
|
2024-09-17 14:17:58 +08:00
|
|
|
|
for product_code in self.G_Firm.nodes[node]['Product_Code']:
|
|
|
|
|
lst_pred_product_code += list(self.G_bom.predecessors(product_code))
|
2024-08-24 16:13:37 +08:00
|
|
|
|
lst_pred_product_code = list(set(lst_pred_product_code))
|
2024-09-17 14:17:58 +08:00
|
|
|
|
lst_pred_product_code = list(sorted(lst_pred_product_code)) # Ensure consistency
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
|
|
|
|
for pred_product_code in lst_pred_product_code:
|
2024-09-17 14:17:58 +08:00
|
|
|
|
# Get a list of firms producing the component (pred_product_code)
|
2024-09-21 22:39:09 +08:00
|
|
|
|
lst_pred_firm = [firm_code for firm_code, product in self.firm_prod_labels_dict.items() if
|
|
|
|
|
pred_product_code in product]
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
|
|
|
|
# Select multiple suppliers (multi-sourcing)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
n_pred_firm = self.int_netw_prf_n
|
|
|
|
|
if n_pred_firm > len(lst_pred_firm):
|
|
|
|
|
n_pred_firm = len(lst_pred_firm)
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
if self.is_prf_size:
|
2024-10-22 10:51:02 +08:00
|
|
|
|
# 获取 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:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
# print("警告: lst_pred_firm_size 为空或总和为 0,无法生成概率分布")
|
2024-10-22 10:51:02 +08:00
|
|
|
|
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):
|
2024-11-28 18:56:24 +08:00
|
|
|
|
# print(f"警告: 概率总和为 {sum(lst_prob)},现在进行修正")
|
2024-10-22 10:51:02 +08:00
|
|
|
|
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)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
else:
|
2024-10-22 10:51:02 +08:00
|
|
|
|
# 直接进行随机选择
|
2024-09-17 14:17:58 +08:00
|
|
|
|
lst_choose_firm = self.nprandom.choice(lst_pred_firm, n_pred_firm, replace=False)
|
|
|
|
|
|
|
|
|
|
# Add edges from predecessor firms to current node (firm)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
lst_add_edge = [(pred_firm, node, {'Product': pred_product_code}) for pred_firm in lst_choose_firm]
|
2024-09-17 14:17:58 +08:00
|
|
|
|
self.G_Firm.add_edges_from(lst_add_edge)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
2024-09-17 14:17:58 +08:00
|
|
|
|
# Add edges to firm-product network
|
|
|
|
|
self.add_edges_to_firm_product_network(node, pred_product_code, lst_choose_firm)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
2024-09-17 14:17:58 +08:00
|
|
|
|
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)
|
|
|
|
|
|
2024-11-28 18:56:24 +08:00
|
|
|
|
if len(lst_use_pred_prod_code) == 0:
|
|
|
|
|
print("错误")
|
|
|
|
|
|
|
|
|
|
pred_node_list = []
|
2024-09-17 14:17:58 +08:00
|
|
|
|
for pred_firm in lst_choose_firm:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
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 = []
|
2024-09-17 14:17:58 +08:00
|
|
|
|
for use_pred_prod_code in lst_use_pred_prod_code:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
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
|
2024-12-08 18:43:33 +08:00
|
|
|
|
if current_node != -1 and pred_node != -1:
|
2024-09-17 14:17:58 +08:00
|
|
|
|
self.G_FirmProd.add_edge(pred_node, current_node)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
|
|
|
|
def connect_unconnected_nodes(self):
|
2024-09-17 14:17:58 +08:00
|
|
|
|
""" Connect unconnected nodes in the firm network """
|
|
|
|
|
for node in nx.nodes(self.G_Firm):
|
|
|
|
|
if self.G_Firm.degree(node) == 0:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
current_node_list = []
|
2024-09-17 14:17:58 +08:00
|
|
|
|
for product_code in self.G_Firm.nodes[node]['Product_Code']:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
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
|
2024-09-17 14:17:58 +08:00
|
|
|
|
lst_succ_product_code = list(self.G_bom.successors(product_code))
|
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
for succ_product_code in lst_succ_product_code:
|
2024-09-21 22:39:09 +08:00
|
|
|
|
lst_succ_firm = [firm_code for firm_code, product in self.firm_prod_labels_dict.items() if
|
|
|
|
|
succ_product_code in product]
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
n_succ_firm = self.int_netw_prf_n
|
|
|
|
|
if n_succ_firm > len(lst_succ_firm):
|
|
|
|
|
n_succ_firm = len(lst_succ_firm)
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
if self.is_prf_size:
|
2024-09-17 14:17:58 +08:00
|
|
|
|
lst_succ_firm_size = [self.G_Firm.nodes[succ_firm]['Revenue_Log'] for succ_firm in
|
2024-08-24 16:13:37 +08:00
|
|
|
|
lst_succ_firm]
|
2024-11-28 18:56:24 +08:00
|
|
|
|
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)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
else:
|
2024-09-17 14:17:58 +08:00
|
|
|
|
lst_choose_firm = self.nprandom.choice(lst_succ_firm, n_succ_firm, replace=False)
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
2024-09-17 14:17:58 +08:00
|
|
|
|
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
|
2024-11-28 18:56:24 +08:00
|
|
|
|
succ_node_list = []
|
2024-08-24 16:13:37 +08:00
|
|
|
|
for succ_firm in lst_choose_firm:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
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)
|
2024-12-08 18:43:33 +08:00
|
|
|
|
if len(succ_node_list) != 0:
|
2024-11-28 18:56:24 +08:00
|
|
|
|
succ_node = succ_node_list[0]
|
|
|
|
|
else:
|
2024-12-08 18:43:33 +08:00
|
|
|
|
succ_node = -1
|
2024-11-28 18:56:24 +08:00
|
|
|
|
|
|
|
|
|
if current_node != -1 and succ_node != -1:
|
|
|
|
|
self.G_FirmProd.add_edge(current_node, succ_node)
|
2024-09-17 14:17:58 +08:00
|
|
|
|
|
|
|
|
|
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 图对象
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
|
|
|
|
def initialize_agents(self):
|
2024-08-24 16:13:37 +08:00
|
|
|
|
""" Initialize agents and add them to the model. """
|
2024-09-21 22:39:09 +08:00
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
for ag_node, attr in self.product_network.nodes(data=True):
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 产业种类
|
2024-12-08 18:43:33 +08:00
|
|
|
|
|
|
|
|
|
type2 = self.type2[self.type2["Index"] == ag_node]["产业种类"]
|
2024-09-21 22:39:09 +08:00
|
|
|
|
# depreciation ratio 折旧比值
|
2024-11-28 18:56:24 +08:00
|
|
|
|
# product_id = product_id.iloc[0]
|
2024-12-08 18:43:33 +08:00
|
|
|
|
product = ProductAgent(ag_node, self, name=attr['Name'], type2=type2)
|
2024-08-24 19:30:16 +08:00
|
|
|
|
self.add_agent(product)
|
|
|
|
|
# self.grid.place_agent(product, ag_node)
|
2024-09-13 16:58:14 +08:00
|
|
|
|
##print(f"Product agent created: {product.name}, ID: {product.unique_id}")
|
|
|
|
|
|
2024-08-24 16:13:37 +08:00
|
|
|
|
for ag_node, attr in self.firm_network.nodes(data=True):
|
2024-08-24 19:30:16 +08:00
|
|
|
|
a_lst_product = [agent for agent in self.product_agents if agent.unique_id in attr['Product_Code']]
|
2024-09-21 22:39:09 +08:00
|
|
|
|
firm_id = self.Firm['Code'] == ag_node
|
|
|
|
|
n_equip_c = self.Firm.loc[firm_id, '设备数量'].values[0]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-12-08 18:43:33 +08:00
|
|
|
|
demand_quantity = self.data_consumed[self.data_consumed['Firm_Code'] == ag_node]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-12-08 18:43:33 +08:00
|
|
|
|
production_output = self.data_produced[self.data_consumed['Firm_Code'] == ag_node]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-09-21 22:39:09 +08:00
|
|
|
|
# c购买价格? 数据预处理
|
|
|
|
|
# c_price = self.Firm.loc[self.Firm['Code'] == ag_node, 'c_price'].values[0]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
# 资源 资源库存信息 利用 firm_resource
|
2024-09-21 22:39:09 +08:00
|
|
|
|
R = self.firm_resource_R.loc[firm_id].to_list()[0]
|
|
|
|
|
P = self.firm_resource_P.loc[firm_id].to_list()[0]
|
|
|
|
|
C = self.firm_resource_C.loc[firm_id].to_list()[0]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
firm_agent = FirmAgent(
|
2024-08-24 16:13:37 +08:00
|
|
|
|
ag_node, self,
|
2024-08-24 11:20:13 +08:00
|
|
|
|
type_region=attr['Type_Region'],
|
|
|
|
|
revenue_log=attr['Revenue_Log'],
|
2024-09-20 09:26:39 +08:00
|
|
|
|
n_equip_c=n_equip_c,
|
2024-08-24 19:30:16 +08:00
|
|
|
|
a_lst_product=a_lst_product,
|
2024-09-20 09:26:39 +08:00
|
|
|
|
demand_quantity=demand_quantity,
|
|
|
|
|
production_output=production_output,
|
2024-09-21 22:39:09 +08:00
|
|
|
|
# c_price=c_price,
|
2024-09-20 09:26:39 +08:00
|
|
|
|
R=R,
|
|
|
|
|
P=P,
|
|
|
|
|
C=C
|
2024-08-24 11:20:13 +08:00
|
|
|
|
)
|
2024-08-24 19:30:16 +08:00
|
|
|
|
self.add_agent(firm_agent)
|
2024-09-13 16:58:14 +08:00
|
|
|
|
|
|
|
|
|
##print(f"Firm agent created: {firm_agent.unique_id}, Products: {[p.name for p in a_lst_product]}")
|
2024-08-24 19:30:16 +08:00
|
|
|
|
# self.grid.place_agent(firm_agent, ag_node)
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
|
|
|
|
def initialize_disruptions(self):
|
2024-09-13 16:58:14 +08:00
|
|
|
|
# 初始化一部字典,用于存储每个公司及其对应的受干扰产品列表
|
|
|
|
|
t_dct = {}
|
|
|
|
|
|
|
|
|
|
# 遍历初始公司-产品干扰数据,将其转化为基于公司和产品的映射
|
2024-08-24 16:13:37 +08:00
|
|
|
|
for firm_code, lst_product in self.dct_lst_init_disrupt_firm_prod.items():
|
2024-09-13 16:58:14 +08:00
|
|
|
|
# 从 company_agents 列表中选择指定公司
|
2024-09-17 14:17:58 +08:00
|
|
|
|
firms = [firm for firm in self.company_agents if firm.unique_id == firm_code]
|
|
|
|
|
firm = firms[0] if firms else None
|
2024-09-13 16:58:14 +08:00
|
|
|
|
|
|
|
|
|
# 从总产品列表中选择该公司受干扰的产品
|
|
|
|
|
disrupted_products = [product for product in self.product_agents if product.unique_id in lst_product]
|
|
|
|
|
|
|
|
|
|
# 将公司与其受干扰的产品映射到字典中
|
2024-09-24 19:21:59 +08:00
|
|
|
|
if firm is not None:
|
|
|
|
|
t_dct[firm] = disrupted_products
|
2024-09-13 16:58:14 +08:00
|
|
|
|
|
|
|
|
|
# 更新 self.dct_lst_init_disrupt_firm_prod 字典,存储公司及其受干扰的产品
|
|
|
|
|
self.dct_lst_init_disrupt_firm_prod = t_dct
|
|
|
|
|
|
|
|
|
|
# 设置初始受干扰的公司产品状态
|
|
|
|
|
for firm, a_lst_product in self.dct_lst_init_disrupt_firm_prod.items():
|
|
|
|
|
for product in a_lst_product:
|
|
|
|
|
# 确保产品存在于公司的生产状态字典中
|
|
|
|
|
assert product in firm.dct_prod_up_prod_stat.keys(), \
|
|
|
|
|
f"Product {product.code} not in firm {firm.code}"
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
2024-09-13 16:58:14 +08:00
|
|
|
|
# 将产品状态更新为干扰状态,并记录干扰时间
|
|
|
|
|
firm.dct_prod_up_prod_stat[product]['p_stat'].append(('D', self.t))
|
2024-08-24 16:13:37 +08:00
|
|
|
|
|
|
|
|
|
def add_agent(self, agent):
|
|
|
|
|
if isinstance(agent, FirmAgent):
|
|
|
|
|
self.company_agents.append(agent)
|
|
|
|
|
elif isinstance(agent, ProductAgent):
|
|
|
|
|
self.product_agents.append(agent)
|
2024-08-24 11:20:13 +08:00
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
def resource_integration(self):
|
2024-09-29 16:41:34 +08:00
|
|
|
|
data_R = pd.read_csv("input_data/input_firm_data/firms_materials.csv")
|
|
|
|
|
data_C = pd.read_csv("input_data/input_firm_data/firms_devices.csv")
|
|
|
|
|
data_P = pd.read_csv("input_data/input_firm_data/firms_products.csv")
|
|
|
|
|
device_salvage_values = pd.read_csv('input_data/device_salvage_values.csv')
|
2024-09-21 22:39:09 +08:00
|
|
|
|
|
|
|
|
|
self.device_salvage_values = device_salvage_values
|
|
|
|
|
|
|
|
|
|
data_merged_C = pd.merge(data_C, device_salvage_values, on='设备id', how='left')
|
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
firm_resource_R = (data_R.groupby('Firm_Code')[['材料id', '材料数量']]
|
|
|
|
|
.apply(lambda x: x.values.tolist()))
|
2024-09-21 22:39:09 +08:00
|
|
|
|
firm_resource_C = (data_merged_C.groupby('Firm_Code')[['设备id', '设备数量', '设备残值']]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
.apply(lambda x: x.values.tolist()))
|
|
|
|
|
|
2024-09-21 22:39:09 +08:00
|
|
|
|
firm_resource_P = (data_P.groupby('Firm_Code')[['产品id', '产品数量']]
|
2024-09-20 09:26:39 +08:00
|
|
|
|
.apply(lambda x: x.values.tolist()))
|
|
|
|
|
|
|
|
|
|
self.firm_resource_R = firm_resource_R
|
|
|
|
|
self.firm_resource_C = firm_resource_C
|
|
|
|
|
self.firm_resource_P = firm_resource_P
|
|
|
|
|
|
|
|
|
|
def j_comp_consumed_produced(self):
|
2024-12-08 18:43:33 +08:00
|
|
|
|
# 着重修改这 然后考虑逻辑 如何传递值
|
|
|
|
|
data_consumed = pd.read_csv('input_data/input_firm_data/firms_materials.csv')
|
|
|
|
|
data_produced = pd.read_csv('input_data/input_firm_data/firms_products.csv')
|
|
|
|
|
|
|
|
|
|
data_not_consumed = data_consumed.groupby('Firm_Code')[['消耗材料id', '材料数量']] \
|
|
|
|
|
.apply(lambda x: dict(zip(x['消耗材料id'], x['材料数量']))) \
|
|
|
|
|
.reset_index(name='Material_not_Consumed')
|
2024-09-21 22:39:09 +08:00
|
|
|
|
|
2024-12-08 18:43:33 +08:00
|
|
|
|
# 这里简单设置为折半 考虑 企业的设备量
|
|
|
|
|
# 可以引入 换算率 也就是 材料——计算产品比例 通过上游产业 现在假设为 2:1 的比例
|
|
|
|
|
data_consumed = data_consumed.groupby('Firm_Code')[['消耗材料id', '材料数量']] \
|
|
|
|
|
.apply(lambda x: dict(zip(x['消耗材料id'], x['材料数量'] / 2))) \
|
|
|
|
|
.reset_index(name='Material_not_Consumed')
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
self.data_consumed = data_consumed
|
2024-12-08 18:43:33 +08:00
|
|
|
|
self.data_produced = data_consumed / 2
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
2024-08-24 11:20:13 +08:00
|
|
|
|
def step(self):
|
2024-08-24 16:13:37 +08:00
|
|
|
|
# 1. Remove edge to customer and disrupt customer up product
|
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
for prod in firm.dct_prod_up_prod_stat.keys():
|
|
|
|
|
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(prod)
|
|
|
|
|
|
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
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]['set_disrupt_firm']:
|
|
|
|
|
firm.disrupt_cus_prod(prod, up_prod)
|
|
|
|
|
|
|
|
|
|
# 2. Trial Process
|
|
|
|
|
for n_trial in range(self.int_n_max_trial):
|
|
|
|
|
shuffle(self.company_agents) # 手动打乱代理顺序
|
|
|
|
|
|
|
|
|
|
is_stop_trial = True
|
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
lst_seek_prod = []
|
|
|
|
|
for prod in firm.dct_prod_up_prod_stat.keys():
|
|
|
|
|
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]['s_stat'].keys():
|
|
|
|
|
if not firm.dct_prod_up_prod_stat[prod]['s_stat'][supply]['stat']:
|
|
|
|
|
lst_seek_prod.append(supply)
|
|
|
|
|
lst_seek_prod = list(set(lst_seek_prod))
|
|
|
|
|
if len(lst_seek_prod) > 0:
|
|
|
|
|
is_stop_trial = False
|
|
|
|
|
for supply in lst_seek_prod:
|
|
|
|
|
firm.seek_alt_supply(supply)
|
|
|
|
|
if is_stop_trial:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
# Handle requests
|
|
|
|
|
shuffle(self.company_agents) # 手动打乱代理顺序
|
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
if len(firm.dct_request_prod_from_firm) > 0:
|
|
|
|
|
firm.handle_request()
|
|
|
|
|
|
|
|
|
|
# Reset dct_request_prod_from_firm
|
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
firm.clean_before_trial()
|
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 3. 判断是否需要购买资源 判断是否需要购买机器
|
|
|
|
|
purchase_material_firms = {}
|
|
|
|
|
purchase_machinery_firms = {}
|
|
|
|
|
material_list = []
|
|
|
|
|
machinery_list = []
|
2024-10-22 10:51:02 +08:00
|
|
|
|
list_seek_material_firm = [] # 每一个收到请求的企业
|
|
|
|
|
list_seek_machinery_firm = [] # 每一个收到请求的企业
|
2024-09-21 22:39:09 +08:00
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
# 资源
|
|
|
|
|
for sub_list in firm.R:
|
|
|
|
|
if sub_list[1] <= firm.s_r:
|
|
|
|
|
required_material_quantity = firm.S_r - sub_list[1]
|
2024-09-21 22:39:09 +08:00
|
|
|
|
(material_list.append([sub_list[0], required_material_quantity]))
|
|
|
|
|
purchase_material_firms[firm] = material_list
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 设备
|
|
|
|
|
for sub_list in firm.C:
|
|
|
|
|
# 对于设备的required_machinery_quantity 要有所改变 根据残值而言! 每一个周期固定减少残值值 x firm 里面定义
|
|
|
|
|
sub_list[2] -= firm.x
|
|
|
|
|
if sub_list[2] <= 0: # 残值小于等于 0 时
|
|
|
|
|
sub_list[1] -= 1
|
2024-09-21 22:39:09 +08:00
|
|
|
|
required_machinery_quantity = 1 # 补回原来的量 也就是 1
|
2024-09-20 09:26:39 +08:00
|
|
|
|
(machinery_list
|
|
|
|
|
.append([sub_list[0], required_machinery_quantity]))
|
2024-09-21 22:39:09 +08:00
|
|
|
|
purchase_machinery_firms[firm] = machinery_list
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
# 寻源并发送请求 决定是否接受供应 并更新
|
2024-09-21 22:39:09 +08:00
|
|
|
|
for material_firm_key, sub_list_values in purchase_material_firms.items():
|
|
|
|
|
for mater_list in sub_list_values:
|
|
|
|
|
result = material_firm_key.seek_material_supply(mater_list[0])
|
2024-10-21 17:41:50 +08:00
|
|
|
|
# 如果 result 不等于 -1,才将其添加到 list_seek_material_firm 列表中
|
2024-09-21 22:39:09 +08:00
|
|
|
|
if result != -1:
|
|
|
|
|
list_seek_material_firm.append(result)
|
2024-09-20 09:26:39 +08:00
|
|
|
|
|
|
|
|
|
if len(list_seek_material_firm) != 0:
|
|
|
|
|
for seek_material_firm in list_seek_material_firm:
|
2024-09-21 22:39:09 +08:00
|
|
|
|
seek_material_firm.handle_material_request(mater_list) # 更新产品
|
2024-09-20 09:26:39 +08:00
|
|
|
|
for R_list in firm.R:
|
|
|
|
|
R_list[1] = firm.S_r
|
|
|
|
|
|
2024-09-21 22:39:09 +08:00
|
|
|
|
for machinery_firm, sub_list in purchase_machinery_firms.items():
|
|
|
|
|
for machi_list in sub_list:
|
|
|
|
|
# 执行一次调用 machinery_firm.seek_machinery_supply(machinery_list[0])
|
|
|
|
|
result = machinery_firm.seek_machinery_supply(machi_list[0])
|
2024-10-21 17:41:50 +08:00
|
|
|
|
# 如果 result 不等于 -1,才将其添加到 list_seek_machinery_firm 列表中
|
2024-09-21 22:39:09 +08:00
|
|
|
|
if result != -1:
|
|
|
|
|
list_seek_machinery_firm.append(result)
|
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
if len(list_seek_machinery_firm) != 0:
|
|
|
|
|
for seek_machinery_firm in list_seek_machinery_firm:
|
2024-09-21 22:39:09 +08:00
|
|
|
|
seek_machinery_firm.handle_machinery_request(machi_list)
|
2024-09-20 09:26:39 +08:00
|
|
|
|
for C_list, C0_list in zip(firm.C, firm.C0):
|
|
|
|
|
C_list[1] = C0_list[1] # 赋值回去
|
|
|
|
|
C_list[2] = C0_list[2]
|
|
|
|
|
# 消耗资源过程
|
2024-12-08 18:43:33 +08:00
|
|
|
|
# 这里需要修改
|
|
|
|
|
for r_id, r_nums in firm.R.items():
|
|
|
|
|
for consumed_id, consumed_nums in firm.c_consumption:
|
|
|
|
|
if consumed_id == r_id:
|
|
|
|
|
r_nums = r_nums - consumed_nums
|
2024-11-28 18:56:24 +08:00
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
# 生产产品过程
|
2024-12-08 18:43:33 +08:00
|
|
|
|
for p_id, p_nums in firm.P.items():
|
|
|
|
|
for product_id, product_nums in firm.c_consumption:
|
|
|
|
|
if product_id == p_id:
|
|
|
|
|
p_nums = p_nums + product_nums
|
|
|
|
|
|
2024-09-20 09:26:39 +08:00
|
|
|
|
firm.refresh_R()
|
|
|
|
|
# 刷新 C状态
|
|
|
|
|
firm.refresh_C()
|
|
|
|
|
# 刷新 P状态
|
|
|
|
|
firm.refresh_P()
|
2024-08-24 16:13:37 +08:00
|
|
|
|
# Increment the time step
|
|
|
|
|
self.t += 1
|
2024-09-24 19:21:59 +08:00
|
|
|
|
|
|
|
|
|
def end(self):
|
|
|
|
|
# print('/' * 20, 'output', '/' * 20)
|
|
|
|
|
|
|
|
|
|
qry_result = db_session.query(Result).filter_by(s_id=self.sample.id)
|
|
|
|
|
if qry_result.count() == 0:
|
|
|
|
|
lst_result_info = []
|
|
|
|
|
for firm in self.company_agents:
|
|
|
|
|
for prod, dct_status_supply in \
|
|
|
|
|
firm.dct_prod_up_prod_stat.items():
|
|
|
|
|
lst_is_normal = [stat == 'N' for stat, _
|
|
|
|
|
in dct_status_supply['p_stat']]
|
|
|
|
|
if not all(lst_is_normal):
|
|
|
|
|
# print(f"{firm.name} {prod.code}:")
|
|
|
|
|
# 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.unique_id,
|
|
|
|
|
id_product=prod.unique_id,
|
|
|
|
|
ts=ts,
|
|
|
|
|
status=status)
|
|
|
|
|
lst_result_info.append(db_r)
|
|
|
|
|
db_session.bulk_save_objects(lst_result_info)
|
|
|
|
|
db_session.commit()
|
|
|
|
|
self.sample.is_done_flag = 1
|
|
|
|
|
self.sample.computer_name = platform.node()
|
|
|
|
|
self.sample.stop_t = self.int_stop_ts
|
|
|
|
|
db_session.commit()
|