mesa/computation.py

271 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 图对象