├── LICENSE ├── README.md ├── agent.py ├── configs └── cflp_config.json ├── data └── test_cls_data_cflp.pkl ├── env.py ├── generate_data.py ├── models ├── __init__.py ├── decoder.py ├── decoder_utils.py ├── encoder.py ├── encoder_nohigh.py ├── graph_transformer.py └── layers.py ├── process_data_new.py ├── run.py ├── sample.py ├── test_results ├── result_of_0.pkl ├── result_of_1.pkl ├── result_of_10.pkl ├── result_of_100.pkl ├── result_of_101.pkl ├── result_of_102.pkl ├── result_of_103.pkl ├── result_of_104.pkl ├── result_of_105.pkl ├── result_of_106.pkl ├── result_of_107.pkl ├── result_of_108.pkl ├── result_of_109.pkl ├── result_of_11.pkl ├── result_of_110.pkl ├── result_of_111.pkl ├── result_of_112.pkl ├── result_of_113.pkl ├── result_of_114.pkl ├── result_of_115.pkl ├── result_of_116.pkl ├── result_of_117.pkl ├── result_of_118.pkl ├── result_of_119.pkl ├── result_of_12.pkl ├── result_of_120.pkl ├── result_of_121.pkl ├── result_of_122.pkl ├── result_of_123.pkl ├── result_of_124.pkl ├── result_of_125.pkl ├── result_of_126.pkl ├── result_of_127.pkl ├── result_of_128.pkl ├── result_of_129.pkl ├── result_of_130.pkl ├── result_of_131.pkl ├── result_of_132.pkl ├── result_of_133.pkl ├── result_of_134.pkl ├── result_of_135.pkl ├── result_of_136.pkl ├── result_of_137.pkl ├── result_of_138.pkl ├── result_of_139.pkl ├── result_of_140.pkl ├── result_of_141.pkl ├── result_of_142.pkl ├── result_of_144.pkl ├── result_of_145.pkl ├── result_of_146.pkl ├── result_of_148.pkl ├── result_of_149.pkl ├── result_of_15.pkl ├── result_of_150.pkl ├── result_of_152.pkl ├── result_of_153.pkl ├── result_of_154.pkl ├── result_of_156.pkl ├── result_of_157.pkl ├── result_of_158.pkl ├── result_of_16.pkl ├── result_of_160.pkl ├── result_of_161.pkl ├── result_of_162.pkl ├── result_of_164.pkl ├── result_of_165.pkl ├── result_of_166.pkl ├── result_of_168.pkl ├── result_of_169.pkl ├── result_of_17.pkl ├── result_of_170.pkl ├── result_of_172.pkl ├── result_of_173.pkl ├── result_of_174.pkl ├── result_of_176.pkl ├── result_of_177.pkl ├── result_of_178.pkl ├── result_of_180.pkl ├── result_of_181.pkl ├── result_of_182.pkl ├── result_of_184.pkl ├── result_of_185.pkl ├── result_of_186.pkl ├── result_of_187.pkl ├── result_of_188.pkl ├── result_of_189.pkl ├── result_of_190.pkl ├── result_of_192.pkl ├── result_of_193.pkl ├── result_of_194.pkl ├── result_of_196.pkl ├── result_of_197.pkl ├── result_of_198.pkl ├── result_of_2.pkl ├── result_of_40.pkl ├── result_of_41.pkl ├── result_of_42.pkl ├── result_of_43.pkl ├── result_of_44.pkl ├── result_of_5.pkl ├── result_of_6.pkl └── result_of_7.pkl ├── test_scenarios ├── scene_200_0.pkl ├── scene_200_1.pkl ├── scene_200_10.pkl ├── scene_200_100.pkl ├── scene_200_101.pkl ├── scene_200_102.pkl ├── scene_200_103.pkl ├── scene_200_104.pkl ├── scene_200_105.pkl ├── scene_200_106.pkl ├── scene_200_107.pkl ├── scene_200_108.pkl ├── scene_200_109.pkl ├── scene_200_11.pkl ├── scene_200_110.pkl ├── scene_200_111.pkl ├── scene_200_112.pkl ├── scene_200_113.pkl ├── scene_200_114.pkl ├── scene_200_115.pkl ├── scene_200_116.pkl ├── scene_200_117.pkl ├── scene_200_118.pkl ├── scene_200_119.pkl ├── scene_200_12.pkl ├── scene_200_120.pkl ├── scene_200_121.pkl ├── scene_200_122.pkl ├── scene_200_123.pkl ├── scene_200_124.pkl ├── scene_200_125.pkl ├── scene_200_126.pkl ├── scene_200_127.pkl ├── scene_200_128.pkl ├── scene_200_129.pkl ├── scene_200_130.pkl ├── scene_200_131.pkl ├── scene_200_132.pkl ├── scene_200_133.pkl ├── scene_200_134.pkl ├── scene_200_135.pkl ├── scene_200_136.pkl ├── scene_200_137.pkl ├── scene_200_138.pkl ├── scene_200_139.pkl ├── scene_200_140.pkl ├── scene_200_141.pkl ├── scene_200_142.pkl ├── scene_200_144.pkl ├── scene_200_145.pkl ├── scene_200_146.pkl ├── scene_200_148.pkl ├── scene_200_149.pkl ├── scene_200_15.pkl ├── scene_200_150.pkl ├── scene_200_152.pkl ├── scene_200_153.pkl ├── scene_200_154.pkl ├── scene_200_156.pkl ├── scene_200_157.pkl ├── scene_200_158.pkl ├── scene_200_16.pkl ├── scene_200_160.pkl ├── scene_200_161.pkl ├── scene_200_162.pkl ├── scene_200_164.pkl ├── scene_200_165.pkl ├── scene_200_166.pkl ├── scene_200_168.pkl ├── scene_200_169.pkl ├── scene_200_17.pkl ├── scene_200_170.pkl ├── scene_200_172.pkl ├── scene_200_173.pkl ├── scene_200_174.pkl ├── scene_200_176.pkl ├── scene_200_177.pkl ├── scene_200_178.pkl ├── scene_200_180.pkl ├── scene_200_181.pkl ├── scene_200_182.pkl ├── scene_200_184.pkl ├── scene_200_185.pkl ├── scene_200_186.pkl ├── scene_200_187.pkl ├── scene_200_188.pkl ├── scene_200_189.pkl ├── scene_200_190.pkl ├── scene_200_192.pkl ├── scene_200_193.pkl ├── scene_200_194.pkl ├── scene_200_196.pkl ├── scene_200_197.pkl ├── scene_200_198.pkl ├── scene_200_2.pkl ├── scene_200_40.pkl ├── scene_200_41.pkl ├── scene_200_42.pkl ├── scene_200_43.pkl ├── scene_200_44.pkl ├── scene_200_5.pkl ├── scene_200_6.pkl └── scene_200_7.pkl ├── trainer.py └── utils ├── __init__.py ├── cflpdata.py ├── processer.py └── solver_return_x.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Yang Wu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HGCN2SP: Hierarchical Graph Convolutional Network for Two-Stage Stochastic Programming 2 | Author: Yang Wu, Yifan Zhang, Zhenxing Liang, Jian Cheng 3 | 4 | ## 项目概述 5 | 6 | HGCN2SP是一个创新的框架,结合了层次化图卷积网络和强化学习方法,用于解决两阶段随机规划问题。本项目聚焦于CFLP,通过学习场景特征,实现高效的求解。 7 | 8 | 9 | ## 环境需求 10 | 11 | - Python 3.8+ 12 | - PyTorch 1.10+ 13 | - PyG (PyTorch Geometric) 14 | - Gurobi 15 | - NumPy, tqdm, wandb (可选) 16 | 17 | ## 项目结构 18 | 19 | ``` 20 | HGCN2SP/ 21 | ├── configs # 配置文件目录 22 | ├── data # 存储训练和测试数据 23 | ├── eval_instance # 存储验证数据 24 | ├── model_path # 存储模型权重 25 | ├── models # 网络模型组件 26 | ├── test_csv # 存储测试csv 27 | ├── train/test_scenarios # 存储训练/测试实例 28 | ├── train/test_results # 存储训练/测试标准结果 29 | ├── utils # 工具库 30 | ├── agent.py # 智能体模型定义 31 | ├── env.py # 环境交互接口 32 | ├── sample.py # 数据采样器 33 | ├── trainer.py # PPO训练器 34 | ├── generate_data.py # 数据生成脚本 35 | ├── process_data_new.py # 数据预处理脚本 36 | ├── run.py # 主运行脚本 37 | 38 | ``` 39 | 40 | ## 运行流程 41 | 42 | ### 第一步:生成问题实例数据 43 | 44 | 首先需要生成CFLP问题实例及其最优解: 45 | 46 | ```bash 47 | python generate_data.py --seed 0 --num_total_ins 100 --file_path ./train_scenarios --result_path ./train_results 48 | ``` 49 | 50 | 参数说明: 51 | - `--seed`: 随机种子 52 | - `--num_total_ins`: 生成的问题实例数量 53 | - `--file_path`: 问题实例存储路径 54 | - `--result_path`: 求解结果存储路径 55 | 56 | ### 第二步:数据预处理 57 | 58 | 处理原始数据,创建数据集: 59 | 60 | ```bash 61 | python process_data_new.py 62 | ``` 63 | 64 | 该脚本会根据配置文件中指定的路径读取问题实例和求解结果,构建适合模型输入的数据结构。使用时请修改里面的参数以免报错。 65 | 66 | ### 第三步:模型训练与评估 67 | 68 | 运行主脚本进行模型训练/测试: 69 | 70 | ```bash 71 | python run.py --config_file ./configs/cflp_config.json 72 | ``` 73 | 74 | 参数说明: 75 | - `--config_file`: 配置文件路径 76 | 77 | 训练时请将Args中的mode修改为"train",测试时修改为"test",并更新model_test_path字段 78 | 79 | 80 | ## 配置文件说明 81 | 82 | 配置文件`cflp_config.json`包含以下主要部分: 83 | 84 | 1. **Policy**: 控制策略网络结构 85 | - `var_dim`, `con_dim`: 变量和约束特征维度 86 | - `l_hid_dim`, `h_hid_dim`: 局部和全局隐藏层维度 87 | - `n_heads`: 注意力头数量 88 | 89 | 2. **TrainData/TestData**: 数据配置 90 | - `n_scenarios`: 场景数量 91 | - `pkl_folder`, `result_folder`: 数据和结果路径 92 | - `save_path`, `cls_path`: 处理后数据保存路径 93 | 94 | 3. **train**: 训练配置 95 | - `sel_num`: 选择的场景数量 96 | - `decode_type`: 解码策略类型 97 | - `eval_cls_loc`: 验证数据路径 98 | - `eval_result`: 验证数据结果路径 99 | - `eval_epoch`: 评估频率 100 | 101 | 4. **test**: 测试配置 102 | - `sel_num`: 测试时选择的场景数量 103 | - `decode_type`: 测试解码策略 104 | 105 | 修改配置文件可以调整网络结构、训练参数和数据路径等设置,请根据实际路径修改配置。 106 | 107 | ## 引用 108 | 109 | 如果您在研究中使用了HGCN2SP,请引用我们的论文: 110 | 111 | ```bibtex 112 | @inproceedings{wu2024hgcn2sp, 113 | title={HGCN2SP: hierarchical graph convolutional network for two-stage stochastic programming}, 114 | author={Wu, Yang and Zhang, Yifan and Liang, Zhenxing and Cheng, Jian}, 115 | booktitle={Forty-first International Conference on Machine Learning}, 116 | year={2024} 117 | } 118 | ``` 119 | 120 | 121 | -------------------------------------------------------------------------------- /agent.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from models import Encoder, DecoderCell, CriticCell 4 | 5 | class Agent(nn.Module): 6 | def __init__(self, policy_param, train_param, device): 7 | super().__init__() 8 | self.features_extractor = Encoder( 9 | policy_param['var_dim'], 10 | policy_param['con_dim'], 11 | policy_param['l_hid_dim'], 12 | policy_param['scenario_dim'], 13 | policy_param['h_hid_dim'], 14 | policy_param['h_out_dim'] 15 | ) 16 | self.actor = DecoderCell( 17 | policy_param['scenario_dim'], 18 | policy_param['n_heads'], 19 | policy_param['clip'] 20 | ) 21 | self.critic = CriticCell() 22 | self.device = device 23 | self.decode_type = train_param['decode_type'] 24 | self.cluster_k = train_param['sel_num'] 25 | 26 | def get_action_and_value(self, x, action=None, decode_type="sampling", cluster_k=None, mode = "train"): 27 | self.decode_type = decode_type 28 | batch_feat = [] 29 | batch_edge = [] 30 | for i in range(len(x)): 31 | x[i] = x[i].to(self.device) 32 | feat, c = self.features_extractor(x[i]) 33 | batch_feat.append(feat) 34 | batch_edge.append(c) 35 | x[i] = x[i].cpu() 36 | batch_feat = torch.stack(batch_feat) 37 | batch_edge = torch.stack(batch_edge) 38 | encoder_output = (batch_feat, batch_edge) 39 | if action is not None: 40 | action = action.to(torch.int64) 41 | if cluster_k is not None: 42 | self.cluster_k = cluster_k 43 | if mode == "train": 44 | action, logprob, entropy = self.actor( 45 | self.device, encoder_output, 46 | return_cost=False, 47 | cluster_k=self.cluster_k, 48 | decode_type=self.decode_type, 49 | action=action 50 | ) 51 | value = self.critic(batch_edge, batch_feat) 52 | return action, logprob, entropy, value 53 | elif mode == "test": 54 | action, logprob = self.actor( 55 | self.device, encoder_output, 56 | return_cost=True, 57 | cluster_k=self.cluster_k, 58 | decode_type=self.decode_type, 59 | action=action 60 | ) 61 | return action, logprob 62 | else: 63 | raise ValueError("mode should be 'train' or 'test'") -------------------------------------------------------------------------------- /configs/cflp_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Policy": { 3 | "sparse":true, 4 | "var_dim":2, 5 | "con_dim":1, 6 | "l_hid_dim":128, 7 | "scenario_dim":64, 8 | "h_hid_dim":128, 9 | "h_out_dim":64, 10 | "n_heads": 8, 11 | "clip":10.0 12 | }, 13 | "TrainData":{ 14 | "n_scenarios":200, 15 | "pkl_folder":"./train_scenarios/", 16 | "result_folder":"./train_results/", 17 | "save_path":"./data/train_data_cflp.pt", 18 | "cls_path":"./data/train_cls_data_cflp.pkl" 19 | }, 20 | "TestData":{ 21 | "n_scenarios":200, 22 | "pkl_folder":"./test_scenarios/", 23 | "result_folder":"./test_results/", 24 | "save_path":"/data/test_data_cflp.pt", 25 | "cls_path":"./data/test_cls_data_cflp.pkl" 26 | }, 27 | "Env": { 28 | "value_net":true, 29 | "critic_net":true 30 | }, 31 | "train":{ 32 | "sel_num": 5, 33 | "n_scenarios":200, 34 | "decode_type":"greedy", 35 | "eval_epoch":2, 36 | "eval_path":"./eval_instance", 37 | "model_path":"./model_path", 38 | "eval_pt":"eval_data_cflp.pt", 39 | "eval_cls":"eval_cls_data_cflp.pkl", 40 | "eval_cls_loc": "./train_scenarios", 41 | "eval_result":"./train_results" 42 | }, 43 | "test":{ 44 | "sel_num":5, 45 | "decode_type":"greedy" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /data/test_cls_data_cflp.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/data/test_cls_data_cflp.pkl -------------------------------------------------------------------------------- /env.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pickle 3 | import numpy as np 4 | import torch 5 | import random 6 | import torch.multiprocessing as mp 7 | from utils import solve_cflp_softmax_new 8 | 9 | class CFLPEnv: 10 | def __init__(self, data, bs, clusters, k, batch_size, process=2, device=None): 11 | self.data = data 12 | self.used = list(range(len(data))) 13 | self.bs = bs 14 | self.clusters = clusters 15 | self.k = k 16 | self.batch_size = batch_size 17 | self.process = process 18 | self.device = device 19 | 20 | def reset(self, seed=None): 21 | if seed is not None: 22 | random.seed(seed) 23 | random.shuffle(self.used) 24 | self.loc = 0 25 | self.batch_data = [] 26 | self.batch_bs = [] 27 | self.batch_clusters = [] 28 | for start in range(0, len(self.data), self.batch_size): 29 | end = start + self.batch_size 30 | if end >= len(self.data): 31 | end = len(self.data) 32 | self.batch_data.append([self.data[i] for i in self.used[start:end]]) 33 | self.batch_bs.append([self.bs[i] for i in self.used[start:end]]) 34 | self.batch_clusters.append([self.clusters[i] for i in self.used[start:end]]) 35 | return self.batch_data[self.loc], {} 36 | 37 | def rein_reward(self, action, iteration, alpha=0.001): 38 | action = torch.from_numpy(action) 39 | chunks = action.unbind(0) 40 | param_values = self.batch_clusters[self.loc] 41 | with mp.Pool(processes=self.process) as pool: 42 | results = pool.map(solve_cflp_softmax_new, zip(param_values, chunks, [True]*self.batch_size)) 43 | rewards = torch.stack(results) 44 | base_cost = torch.from_numpy(np.array(self.batch_bs[self.loc])) 45 | cost = torch.sum((base_cost[:, :-1] == rewards[:, :-2]), dim=1)/(rewards.shape[-1]-2) 46 | time = rewards[:, -2] 47 | rewards = 25 * (cost - alpha * time) 48 | return rewards.numpy() 49 | 50 | def step(self, action, iteration): 51 | reward = self.rein_reward(action, iteration) 52 | terminations = np.array([True]*self.batch_size) 53 | truncations = np.array([True]*self.batch_size) 54 | info = {} 55 | self.loc += 1 56 | if self.loc >= len(self.batch_data): 57 | obs, _ = self.reset() 58 | else: 59 | obs = self.batch_data[self.loc] 60 | return obs, reward, terminations, truncations, info 61 | 62 | def close(self): 63 | print("EndEnv...") -------------------------------------------------------------------------------- /generate_data.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import pickle 3 | import time 4 | import torch 5 | import argparse 6 | import numpy as np 7 | from tqdm import tqdm 8 | import gurobipy as gp 9 | 10 | # from stochoptim.stochprob.facility_location.facility_location_problem and add "demands" 11 | def generate_random_parameters(n_facility_locations, n_client_locations, n_zones, seed=None): 12 | """Generate randomly a set of deterministic parameters of the facility location problem""" 13 | if seed is not None: 14 | np.random.seed(seed) 15 | 16 | 17 | return {"pos_client": np.random.rand(n_client_locations, 2), 18 | "pos_facility": np.random.rand(n_facility_locations, 2), 19 | "opening_cost": np.random.uniform(600, 1500, n_facility_locations), 20 | "facility_capacity": np.random.uniform(100, 150, n_facility_locations), 21 | "max_facilities": 8, 22 | "min_facilities_in_zone": np.array([1] * n_zones), 23 | "facility_in_zone": np.random.choice(range(n_zones), size=n_facility_locations), 24 | "penalty": 1000 * np.ones(n_facility_locations), 25 | "demands": np.random.randint(5, 105 + 1, size=n_client_locations)} 26 | 27 | 28 | def solve_cflp_relax(cluster_dict, idx): 29 | """Formulates two stage extensive form and solves""" 30 | n_customers = cluster_dict["n_customers"] 31 | n_facilities = cluster_dict["n_facilities"] 32 | n_scenarios = np.random.choice(range(cluster_dict['n_scenarios']), size=100, replace=False) 33 | 34 | prob = 1.0/len(n_scenarios) 35 | model = gp.Model() 36 | var_dict = {} 37 | 38 | # 目标函数 39 | # 每个设施的二进制变量 第一阶段 40 | for i in range(n_facilities): 41 | var_name = f"x_{i}" 42 | var_dict[var_name] = model.addVar( 43 | lb=0.0, 44 | ub=1.0, 45 | obj=cluster_dict["first_stage"]["facilities_cost"][i], 46 | vtype="B", 47 | name=var_name, 48 | ) 49 | #第一阶段约束 设施数不大于v 50 | cons = 0 51 | for i in range(n_facilities): 52 | cons += var_dict[f"x_{i}"] 53 | model.addConstr(cons<=cluster_dict['first_stage']['constraint'], name = f"v") 54 | 55 | for s in n_scenarios: 56 | # 第二阶段 57 | for i in range(n_customers): 58 | for j in range(n_facilities): 59 | var_name = f"y_{i}_{j}_{s}" 60 | var_dict[var_name] = model.addVar( 61 | lb=0.0, 62 | ub=1.0, 63 | obj=prob * cluster_dict["second_stage"]["trans_cost"][i][j], 64 | vtype="B", 65 | name=var_name, 66 | ) 67 | for j in range(n_facilities): 68 | var_name = f"z_{j}_{s}" 69 | var_dict[var_name] = model.addVar( 70 | lb=0.0, 71 | obj=prob * cluster_dict["second_stage"]["recourse_costs"], 72 | vtype="C", 73 | name=var_name, 74 | ) 75 | 76 | # 约束条件 77 | #约束1 78 | for j in range(n_facilities): 79 | cons = (-1.0)*cluster_dict['second_stage']["qx"][j] * var_dict[f"x_{j}"] - var_dict[f"z_{j}_{s}"]*cluster_dict['second_stage']['z_coeff'] 80 | for i in range(n_customers): 81 | cons+= cluster_dict['second_stage']["q_c_f"][s][i][j]*var_dict[f"y_{i}_{j}_{s}"] 82 | model.addConstr(cons<=0, name = f"c_{j}_{s}") 83 | #约束2 84 | for j in range(n_facilities): 85 | cons = var_dict[f"z_{j}_{s}"] - cluster_dict['second_stage']['M'] * var_dict[f"x_{j}"] 86 | model.addConstr(cons<=0, name = f"d_{j}_{s}") 87 | #约束3 88 | for i in range(n_customers): 89 | cons = (-1)*cluster_dict['second_stage']["h"][s][i] 90 | for j in range(n_facilities): 91 | cons+=var_dict[f"y_{i}_{j}_{s}"] 92 | model.addConstr(cons==0, name = f"t_{i}_{s}") 93 | 94 | model.update() 95 | 96 | #set param 97 | model.setParam('OutputFlag', 0) 98 | model.setParam("MIPGap", 0.000) 99 | model.setParam("TimeLimit", 10800) 100 | 101 | # 设置线程数 102 | model.setParam('Threads', 4) 103 | 104 | model.optimize() 105 | 106 | # 获取第一阶段变量的取值 107 | variable_values = {var.varName: var.x for var in model.getVars() if 'x' in var.varName} 108 | 109 | solving_results = {} 110 | solving_results["primal"] = model.objVal 111 | solving_results["time"] = model.Runtime 112 | solving_results['scenarios'] = n_scenarios 113 | solving_results['index'] = idx 114 | solving_results['X'] = variable_values 115 | 116 | #print("solving_results:",solving_results) 117 | return solving_results 118 | 119 | 120 | 121 | def main(args): 122 | torch.manual_seed(args.seed) 123 | if torch.cuda.is_available(): 124 | torch.cuda.manual_seed(args.seed) 125 | 126 | # first-stage dataset 127 | n_facility_locations = 10 128 | n_client_locations = 20 129 | n_zones = 1 130 | #------------ 131 | client_node = [] 132 | facility_node = [] 133 | dist = [] 134 | n_scenarios = 200 135 | p = 0.8 136 | n_procs = 3 137 | #------------------ 138 | scenarios = [] 139 | all_tran_cost = [] 140 | hs = [] 141 | demands = [] 142 | z_coeffs = [] 143 | recourse_costs = [] 144 | fac_costs = [] 145 | fac_capacity = [] 146 | cls = [] 147 | 148 | for i in tqdm(range(args.num_total_ins)): 149 | param = generate_random_parameters(n_facility_locations, n_client_locations, n_zones) 150 | pos_c = param['pos_client'] 151 | pos_f = param['pos_facility'] 152 | 153 | fac_costs.append(param['opening_cost']) 154 | fac_capacity.append(param['facility_capacity']) 155 | 156 | open_cost = param['opening_cost']/1500. 157 | fac_cap = param['facility_capacity']/150. 158 | 159 | z_coeff = np.ones(n_facility_locations) 160 | recourse_cost = np.ones(n_facility_locations)*1000 161 | z_coeffs.append(z_coeff) 162 | recourse_costs.append(recourse_cost) 163 | 164 | facility_node.append(np.concatenate((pos_f,open_cost[:,None],fac_cap[:,None]),axis=1)) ### n_facility_locations*4 165 | client_node.append(pos_c) 166 | tran_cost = np.sqrt( 167 | (pos_c[:,0].reshape((-1, 1)) - pos_f[:,0].reshape((1, -1))) ** 2 168 | + (pos_c[:,1].reshape((-1, 1)) - pos_f[:,1].reshape((1, -1))) ** 2) \ 169 | * 10 * param['demands'].reshape((-1, 1)) 170 | all_tran_cost.append(tran_cost) 171 | customer_presence = np.random.binomial(1, np.random.uniform(0.8, 172 | 0.9, 173 | n_client_locations), 174 | (n_scenarios, n_client_locations)) 175 | hs.append(customer_presence) 176 | q_c_f = np.random.uniform(20, 80, size=(n_scenarios, n_client_locations, n_facility_locations)) 177 | demands.append(q_c_f) 178 | 179 | #创建字典 并存储 180 | cluster_dict={} 181 | cluster_dict['n_customers']=n_client_locations 182 | cluster_dict['n_facilities']=n_facility_locations 183 | cluster_dict['n_scenarios']=n_scenarios 184 | cluster_dict['first_stage']={} 185 | cluster_dict['first_stage']['facilities_cost']= param['opening_cost'] #对应of 186 | cluster_dict['first_stage']['constraint']=8 #v的值 187 | cluster_dict['second_stage']={} 188 | cluster_dict['second_stage']['recourse_costs'] = 1000 #bf 189 | cluster_dict['second_stage']["q_c_f"] = q_c_f #qcf 190 | cluster_dict['second_stage']["qx"]= param['facility_capacity'] 191 | cluster_dict['second_stage']['M']= 1e4 192 | cluster_dict['second_stage']["h"]= customer_presence 193 | cluster_dict['second_stage']['trans_cost'] = tran_cost 194 | cluster_dict['second_stage']['z_coeff'] = 1 195 | cluster_dict['pos_c'] = pos_c 196 | cluster_dict['pos_f'] = pos_f 197 | file_path = os.path.join(args.file_path, f"scene_200_{i}.pkl") 198 | with open(file_path, 'wb') as file: 199 | pickle.dump(cluster_dict, file) 200 | 201 | # 求解结果 202 | results = solve_cflp_relax(cluster_dict, i) 203 | file_path = os.path.join(args.result_path, f"result_of_{i}.pkl") 204 | with open(file_path, 'wb') as rf: 205 | pickle.dump(results, rf) 206 | 207 | 208 | 209 | if __name__ == '__main__': 210 | parser = argparse.ArgumentParser() 211 | parser.add_argument("--seed", type=int, default=0) 212 | parser.add_argument("--num_total_ins", type=int, default=10) 213 | parser.add_argument("--file_path", type=str, default="./train_scenarios") 214 | parser.add_argument("--result_path", type=str, default="./train_results") 215 | args = parser.parse_args() 216 | main(args) 217 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | from .encoder import Encoder 2 | from .encoder_nohigh import Encoder_Nohigh 3 | from .decoder import DecoderCell, CriticCell, ValueCell 4 | from .graph_transformer import Graph_Transformer 5 | from .decoder_utils import Env, TopKSampler, CategoricalSampler 6 | -------------------------------------------------------------------------------- /models/decoder.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | import torch 4 | import torch.nn as nn 5 | from tqdm import tqdm 6 | # from . import layers 7 | from .layers import MultiHeadAttention, DotProductAttention 8 | from .decoder_utils import TopKSampler, CategoricalSampler, Env 9 | import os 10 | 11 | 12 | def orthogonal_init(layer, gain=1.0): 13 | nn.init.orthogonal_(layer.weight, gain=gain) 14 | if layer.bias is not None: 15 | nn.init.constant_(layer.bias, 0) 16 | 17 | class ValueCell(nn.Module): 18 | def __init__(self, embed_dim = 64,**kwargs): 19 | super().__init__(**kwargs) 20 | self.embed_dim = embed_dim 21 | self.Wv = nn.Linear(embed_dim, embed_dim, bias = False) 22 | self.Wq = nn.Linear(embed_dim, embed_dim, bias = False) 23 | self.Wk = nn.Linear(embed_dim, embed_dim, bias = False) 24 | self.MLP = nn.Sequential( 25 | self.layer_init(nn.Linear(embed_dim, 128)), #原始数据是32 26 | nn.Tanh(), 27 | self.layer_init(nn.Linear(128, 256)), 28 | nn.Tanh(), 29 | self.layer_init(nn.Linear(256, 1), std=1.0), 30 | ) 31 | self.scale = math.sqrt(embed_dim) 32 | self.inint_weight() 33 | 34 | def inint_weight(self): 35 | orthogonal_init(self.Wv) 36 | orthogonal_init(self.Wq) 37 | orthogonal_init(self.Wk) 38 | 39 | def layer_init(self, layer, std=np.sqrt(2), bias_const=0.0): 40 | torch.nn.init.orthogonal_(layer.weight, std) 41 | torch.nn.init.constant_(layer.bias, bias_const) 42 | return layer 43 | 44 | 45 | def forward(self, graph, x): 46 | Q = self.Wq(graph[:, None, :]) 47 | K = self.Wk(x) 48 | V = self.Wv(x) 49 | logits = torch.matmul(Q, K.transpose(-1,-2)) / self.scale 50 | attn_weights = nn.functional.softmax(logits , dim=-1) 51 | attended_values = torch.matmul(attn_weights, V).squeeze(dim = 1) 52 | value = self.MLP(attended_values) 53 | return value 54 | 55 | class CriticCell(nn.Module): 56 | def __init__(self, embed_dim = 64, is_init = True,**kwargs): 57 | super().__init__(**kwargs) 58 | self.embed_dim = embed_dim 59 | self.Wv = nn.Linear(embed_dim, embed_dim, bias = False) 60 | self.Wq = nn.Linear(embed_dim, embed_dim, bias = False) 61 | self.Wk = nn.Linear(embed_dim, embed_dim, bias = False) 62 | self.MLP = nn.Sequential( 63 | self.layer_init(nn.Linear(embed_dim, 128)), #原始数据是32 64 | nn.Tanh(), 65 | nn.Dropout(p=0.5), 66 | self.layer_init(nn.Linear(128, 256)), 67 | nn.Tanh(), 68 | self.layer_init(nn.Linear(256, 1), std=1.0), 69 | ) 70 | self.scale = math.sqrt(embed_dim) 71 | if is_init: 72 | self.init_parameters() 73 | 74 | 75 | def layer_init(self, layer, std=np.sqrt(2), bias_const=0.0): 76 | torch.nn.init.orthogonal_(layer.weight, gain=1.0) 77 | torch.nn.init.constant_(layer.bias, bias_const) 78 | return layer 79 | 80 | def init_parameters(self): #初始化参数 81 | orthogonal_init(self.Wv) 82 | orthogonal_init(self.Wq) 83 | orthogonal_init(self.Wk) 84 | 85 | 86 | def forward(self, graph, x): 87 | Q = self.Wq(graph[:, None, :]) 88 | K = self.Wk(x) 89 | V = self.Wv(x) 90 | logits = torch.matmul(Q, K.transpose(-1,-2)) / self.scale 91 | attn_weights = nn.functional.softmax(logits , dim=-1) 92 | attended_values = torch.matmul(attn_weights, V).squeeze(dim = 1) 93 | value = self.MLP(attended_values) 94 | return value 95 | 96 | class DecoderCell(nn.Module): 97 | def __init__(self, embed_dim = 64, n_heads = 8, clip = 10., **kwargs): 98 | super().__init__(**kwargs) 99 | 100 | self.embed_dim = embed_dim 101 | 102 | self.Wk1 = nn.Linear(embed_dim, embed_dim, bias = False) 103 | self.Wv = nn.Linear(embed_dim, embed_dim, bias = False) 104 | self.Wk2 = nn.Linear(embed_dim, embed_dim, bias = False) 105 | self.Wq_fixed = nn.Linear(embed_dim, embed_dim, bias = False) #不变的全局信息 106 | self.Wout = nn.Linear(embed_dim, embed_dim, bias = False) #单头注意力的Q 107 | self.Wq_step = nn.Linear(2*embed_dim, embed_dim, bias = False) #根据实际情况更改conext 108 | self.W_placeholder = nn.Parameter(torch.Tensor(2 * embed_dim)) #初始t=1的context变量 109 | self.W_placeholder.data.uniform_(-1, 1) 110 | 111 | 112 | self.MHA = MultiHeadAttention(n_heads = n_heads, embed_dim = embed_dim, need_W = False) 113 | self.SHA = DotProductAttention(clip = clip, return_logits = True, head_depth = embed_dim) 114 | self.env = Env 115 | self.init_parameters() 116 | 117 | def init_parameters(self): 118 | orthogonal_init(self.Wk1) 119 | orthogonal_init(self.Wv) 120 | orthogonal_init(self.Wk2) 121 | orthogonal_init(self.Wq_fixed) 122 | orthogonal_init(self.Wq_step) 123 | orthogonal_init(self.Wout, gain=0.01) 124 | 125 | 126 | def compute_static(self, node_embeddings, graph_embedding): #固定不变的参数 127 | self.Q_fixed = self.Wq_fixed(graph_embedding[:,None,:]) #多头的Q 128 | self.K1 = self.Wk1(node_embeddings) 129 | self.V = self.Wv(node_embeddings) #多头的K和V 130 | self.K2 = self.Wk2(node_embeddings) #单头的K 131 | 132 | def compute_dynamic(self, mask, step_context): 133 | Q_step = self.Wq_step(step_context) 134 | Q1 = self.Q_fixed + Q_step 135 | Q2 = self.MHA([Q1, self.K1, self.V], mask = mask) 136 | Q2 = self.Wout(Q2) 137 | logits = self.SHA([Q2, self.K2, None], mask = mask) 138 | return logits.squeeze(dim = 1) #-->输出为(batch, n_nodes) 139 | 140 | def forward(self, device, encoder_output, return_cost = True, cluster_k = 3, decode_type = 'sampling', cls = None, action = None): 141 | node_embeddings, graph_embedding = encoder_output 142 | self.compute_static(node_embeddings, graph_embedding) 143 | env = Env(device, node_embeddings) 144 | mask = env._create_t1() 145 | 146 | step_context = self.W_placeholder[None, None, :].expand(env.batch, 1, self.W_placeholder.size(-1)) 147 | 148 | selecter = {'greedy': TopKSampler(), 'sampling': CategoricalSampler()}.get(decode_type, None) 149 | log_ps, tours = [], [] 150 | 151 | for i in range(cluster_k): 152 | logits = self.compute_dynamic(mask, step_context) 153 | log_p = torch.log_softmax(logits, dim = -1) 154 | next_node = selecter(log_p) 155 | mask, step_context= env._get_step(next_node) 156 | tours.append(next_node.squeeze(1)) #选择的场景 157 | log_ps.append(log_p) #概率 158 | if env.visited_scenarios.all(): 159 | break 160 | 161 | pi = torch.stack(tours, 1) 162 | if action is not None: 163 | pi = action 164 | 165 | 166 | ll = env.get_log_likelihood(torch.stack(log_ps, 1), pi) 167 | entropy = env.get_entropy(torch.stack(log_ps, 1), pi) 168 | 169 | 170 | if return_cost: 171 | log_p = torch.gather(input = torch.stack(log_ps, 1), dim = 2, index = pi[:,:,None]) 172 | return pi, log_p 173 | return pi, ll, entropy -------------------------------------------------------------------------------- /models/decoder_utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.multiprocessing as mp 4 | import os #控制程序结束 可以定位查看结果 os._exit(0) 5 | 6 | 7 | class Env(): 8 | def __init__(self, device, node_embeddings): 9 | super().__init__() 10 | """ 11 | node_embeddings: (batch, n_nodes, embed_dim) 12 | h1:(batch, 1, embed_dim) 13 | Nodes that have been visited will be marked with True. 14 | """ 15 | self.device = device 16 | self.node_embeddings = node_embeddings 17 | self.batch, self.n_nodes, self.embed_dim = node_embeddings.size() 18 | self.h1 = None #context中不变的部分 19 | self.visited_scenarios = torch.zeros((self.batch, self.n_nodes, 1), dtype = torch.bool).to(self.device) 20 | 21 | def _create_t1(self): 22 | mask_t1 = self.visited_scenarios.to(self.device) 23 | return mask_t1 24 | 25 | def _get_step(self, next_node): 26 | one_hot = torch.eye(self.n_nodes)[next_node.cpu()] 27 | visited_mask = one_hot.type(torch.bool).permute(0,2,1).to(self.device) 28 | self.visited_scenarios = self.visited_scenarios | visited_mask 29 | mask_t1 = self.visited_scenarios.to(self.device) 30 | prev_node_embedding = torch.gather(input = self.node_embeddings, dim = 1, index = next_node[:,:,None].repeat(1,1,self.embed_dim)) 31 | if self.h1 == None: 32 | self.h1 = prev_node_embedding 33 | else : 34 | self.h1 = (self.h1 + prev_node_embedding) / 2 35 | step_context = torch.cat([prev_node_embedding, self.h1], dim = -1).to(self.device) 36 | return mask_t1, step_context 37 | 38 | def get_log_likelihood(self, _log_p, pi): 39 | """ _log_p: (batch, decode_step, n_nodes) 40 | pi: (batch, decode_step) 41 | """ 42 | log_p = torch.gather(input = _log_p, dim = 2, index = pi[:,:,None]) #gather中dim等于k就在这个维度上每次寻找相应值 43 | return torch.sum(log_p.squeeze(-1), 1) 44 | 45 | def get_entropy(self, _log_p, pi): 46 | """_log_p: (batch, decode_step, n_nodes) 47 | pi: (batch, decode_step) 48 | """ 49 | log_p = torch.gather(input=_log_p, dim=2, index=pi[:, :, None]) 50 | prob = torch.exp(log_p.squeeze(-1)) 51 | entropy = torch.sum(-prob * log_p.squeeze(-1), dim=1) 52 | return entropy 53 | 54 | 55 | #选点器 56 | class Sampler(nn.Module): 57 | """ args; logits: (batch, n_nodes) 58 | return; next_node: (batch, 1) 59 | TopKSampler <=> greedy; sample one with biggest probability 60 | CategoricalSampler <=> sampling; randomly sample one from possible distribution based on probability 61 | """ 62 | def __init__(self, n_samples = 1, **kwargs): 63 | super().__init__(**kwargs) 64 | self.n_samples = n_samples 65 | 66 | class TopKSampler(Sampler): 67 | def forward(self, logits): 68 | return torch.topk(logits, self.n_samples, dim = 1)[1]# == torch.argmax(log_p, dim = 1).unsqueeze(-1) 69 | 70 | class CategoricalSampler(Sampler): 71 | def forward(self, logits): 72 | return torch.multinomial(logits.exp(), self.n_samples) -------------------------------------------------------------------------------- /models/encoder.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch_geometric.nn import GCNConv, global_add_pool, global_mean_pool 5 | from torch_geometric.loader import DataLoader 6 | from torch.nn.functional import cosine_similarity 7 | import scipy.sparse as sp 8 | import numpy as np 9 | from torch_geometric.data import Data 10 | import math 11 | import os 12 | 13 | class Encoder(nn.Module): 14 | def __init__(self, var_dim, con_dim, low_hid_dim, scenario_dim, high_hid_dim, high_out_dim, activation='prelu'): 15 | super(Encoder, self).__init__() 16 | self.mlp_var = nn.Linear(var_dim, low_hid_dim) 17 | self.mlp_con = nn.Linear(con_dim, low_hid_dim) 18 | self.conv1 = GCNConv(low_hid_dim, scenario_dim) 19 | self.conv2 = GCNConv(scenario_dim, high_hid_dim) 20 | self.conv3 = GCNConv(high_hid_dim, high_out_dim) 21 | self.act = nn.Tanh() 22 | self.dropout = nn.Dropout(p=0.5) 23 | self.bn1 = nn.BatchNorm1d(low_hid_dim) 24 | self.bn2 = nn.BatchNorm1d(scenario_dim) 25 | self.bn3 = nn.BatchNorm1d(high_hid_dim) 26 | self.init_weights() 27 | 28 | def init_weights(self): 29 | # 使用正交初始化对线性层进行初始化 30 | nn.init.orthogonal_(self.mlp_var.weight) 31 | nn.init.orthogonal_(self.mlp_con.weight) 32 | if self.mlp_var.bias is not None: 33 | nn.init.zeros_(self.mlp_var.bias) 34 | if self.mlp_con.bias is not None: 35 | nn.init.zeros_(self.mlp_con.bias) 36 | 37 | # 对GCN层进行初始化 38 | # 注意:GCNConv的权重初始化可能需要根据实现细节进行调整 39 | for conv in [self.conv1, self.conv2, self.conv3]: 40 | nn.init.orthogonal_(conv.lin.weight) 41 | 42 | 43 | def filter_adj(self, adj, thre): 44 | adj[adj < thre] = 0. 45 | adj = adj.cpu().numpy() 46 | scenario_adj = sp.coo_matrix(adj) 47 | scenario_attr = torch.from_numpy(scenario_adj.data).cuda() 48 | scenario_adj = torch.stack([torch.from_numpy(scenario_adj.row), torch.from_numpy(scenario_adj.col)], dim=0).cuda() 49 | 50 | return scenario_adj, scenario_attr 51 | 52 | def forward(self, graph, thre=0.7):#x, edge_index, batch, edge_adj, edge_adj_attr, edge_attr): 53 | 54 | mask_var = (graph.mark==0) 55 | mask_con = (graph.mark==1) 56 | 57 | var_feat = self.act(self.mlp_var(graph.x[mask_var])) 58 | con_feat = self.act(self.mlp_con(graph.x[mask_con][:,0:1])) 59 | 60 | x = torch.cat((con_feat, var_feat), dim=0) 61 | x = self.bn1(x) 62 | 63 | x = self.dropout(x) 64 | 65 | x = self.conv1(x, graph.edge_index, graph.edge_attr).float() 66 | 67 | x = self.bn2(x) 68 | x = self.act(x) 69 | x = self.dropout(x) 70 | 71 | # 全局平均池化 1 200 dim 72 | x = global_mean_pool(x, graph.batch).float() 73 | 74 | edge_scenario,attr_scenario = self.filter_adj(graph.scen_adj, thre) 75 | 76 | g = Data(x=x, edge_index= edge_scenario, edge_attr= attr_scenario) 77 | 78 | feat = self.conv2(g.x, g.edge_index).float() 79 | 80 | feat = self.bn3(feat) 81 | 82 | feat = self.act(feat) 83 | 84 | feat =self.dropout(feat) 85 | 86 | feat = self.act(self.conv3(feat, g.edge_index)).float() 87 | 88 | return feat, torch.mean(feat, 0) 89 | 90 | 91 | -------------------------------------------------------------------------------- /models/encoder_nohigh.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch_geometric.nn import GCNConv, global_add_pool, global_mean_pool 5 | from torch_geometric.loader import DataLoader 6 | from torch.nn.functional import cosine_similarity 7 | import scipy.sparse as sp 8 | import numpy as np 9 | from torch_geometric.data import Data 10 | import math 11 | from .layers import GCN, AvgReadout 12 | import os 13 | class Encoder_Nohigh(nn.Module): 14 | def __init__(self, var_dim, con_dim, low_hid_dim, scenario_dim, high_hid_dim, high_out_dim, activation='prelu'): 15 | super(Encoder_Nohigh, self).__init__() 16 | self.mlp_var = nn.Linear(var_dim, low_hid_dim) 17 | self.mlp_con = nn.Linear(con_dim, low_hid_dim) 18 | self.conv1 = GCNConv(low_hid_dim, scenario_dim) 19 | self.conv2 = GCNConv(scenario_dim, high_hid_dim) 20 | self.conv3 = GCNConv(high_hid_dim, high_out_dim) 21 | self.act = nn.Tanh() 22 | self.dropout = nn.Dropout(p=0.5) 23 | self.bn1 = nn.BatchNorm1d(low_hid_dim) 24 | self.bn2 = nn.BatchNorm1d(scenario_dim) 25 | self.bn3 = nn.BatchNorm1d(high_hid_dim) 26 | self.init_weights() 27 | 28 | def init_weights(self): 29 | # 使用正交初始化对线性层进行初始化 30 | nn.init.orthogonal_(self.mlp_var.weight) 31 | nn.init.orthogonal_(self.mlp_con.weight) 32 | if self.mlp_var.bias is not None: 33 | nn.init.zeros_(self.mlp_var.bias) 34 | if self.mlp_con.bias is not None: 35 | nn.init.zeros_(self.mlp_con.bias) 36 | 37 | # 对GCN层进行初始化 38 | # 注意:GCNConv的权重初始化可能需要根据实现细节进行调整 39 | for conv in [self.conv1, self.conv2, self.conv3]: 40 | nn.init.orthogonal_(conv.lin.weight) 41 | 42 | 43 | def filter_adj(self, adj, thre): 44 | adj[adj < thre] = 0. 45 | adj = adj.cpu().numpy() 46 | scenario_adj = sp.coo_matrix(adj) 47 | scenario_attr = torch.from_numpy(scenario_adj.data).cuda() 48 | scenario_adj = torch.stack([torch.from_numpy(scenario_adj.row), torch.from_numpy(scenario_adj.col)], dim=0).cuda() 49 | 50 | return scenario_adj, scenario_attr 51 | 52 | def forward(self, graph, thre=0.7):#x, edge_index, batch, edge_adj, edge_adj_attr, edge_attr): 53 | # 第一层GCN 54 | 55 | mask_var = (graph.mark==0) 56 | mask_con = (graph.mark==1) 57 | 58 | var_feat = self.act(self.mlp_var(graph.x[mask_var])) 59 | con_feat = self.act(self.mlp_con(graph.x[mask_con][:,0:1])) 60 | 61 | x = torch.cat((con_feat, var_feat), dim=0) 62 | 63 | x = self.bn1(x) 64 | 65 | x = self.dropout(x) 66 | 67 | x = self.conv1(x, graph.edge_index, graph.edge_attr).float() 68 | 69 | x = self.bn2(x) 70 | 71 | x = self.act(x) 72 | 73 | x = self.dropout(x) 74 | 75 | # 全局平均池化 76 | x = global_mean_pool(x, graph.batch).float() 77 | 78 | feat = self.act(x) 79 | 80 | return feat, torch.mean(feat, 0) 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /models/graph_transformer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | class Graph_Transformer(nn.Module): 5 | def __init__(self, encoder_model, decoder_model, device, cluster_k = 3, decode_type = 'sampling', return_pi = True): 6 | super(Graph_Transformer, self).__init__() 7 | self.encoder = encoder_model 8 | self.decoder = decoder_model 9 | self.device = device 10 | self.return_pi = return_pi 11 | self.k = cluster_k 12 | self.decode_type = decode_type 13 | 14 | def forward(self, seq1, seq2, number, adj, edge_adj, sparse, cls, decode_type = 'sampling'): 15 | self.decode_type = decode_type 16 | encoder_output = self.encoder(seq1, seq2, number, adj, edge_adj, sparse) 17 | cost, ll, pi = self.decoder(self.device, encoder_output, self.return_pi, self.k, self.decode_type, cls) 18 | return cost, ll, pi 19 | -------------------------------------------------------------------------------- /models/layers.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import math 4 | 5 | class DotProductAttention(nn.Module): 6 | def __init__(self, clip = None, return_logits = False, head_depth = 16, inf = 1e+10, **kwargs): 7 | super().__init__(**kwargs) 8 | self.clip = clip 9 | self.return_logits = return_logits 10 | self.inf = inf 11 | self.scale = math.sqrt(head_depth) 12 | 13 | def forward(self, x, mask = None): 14 | """ Q: (batch, n_heads, q_seq(=n_nodes or =1), head_depth) 15 | K: (batch, n_heads, k_seq(=n_nodes), head_depth) 16 | logits: (batch, n_heads, q_seq(this could be 1), k_seq) 17 | mask: (batch, n_nodes, 1), e.g. tf.Tensor([[ True], [ True], [False]]) 18 | mask[:,None,None,:,0]: (batch, 1, 1, n_nodes) ==> broadcast depending on logits shape 19 | [True] -> [1 * -np.inf], [False] -> [logits] 20 | K.transpose(-1,-2).size() == K.permute(0,1,-1,-2).size() 21 | """ 22 | Q, K, V = x 23 | logits = torch.matmul(Q, K.transpose(-1,-2)) / self.scale 24 | 25 | if self.clip is not None: 26 | logits = self.clip * torch.tanh(logits) 27 | 28 | if self.return_logits: 29 | if mask is not None: 30 | return logits.masked_fill(mask.permute(0,2,1) == True, -self.inf) 31 | return logits 32 | 33 | if mask is not None: 34 | logits = logits.masked_fill(mask[:,None,None,:,0].repeat(1,logits.size(1),1,1) == True, -self.inf) 35 | 36 | probs = torch.softmax(logits, dim = -1) 37 | 38 | return torch.matmul(probs, V) 39 | 40 | class MultiHeadAttention(nn.Module): 41 | def __init__(self, n_heads = 8, embed_dim = 128, clip = None, return_logits = None, need_W = None): 42 | super().__init__() 43 | self.n_heads = n_heads 44 | self.embed_dim = embed_dim 45 | self.head_depth = self.embed_dim // self.n_heads 46 | if self.embed_dim % self.n_heads != 0: 47 | raise ValueError("embed_dim = n_heads * head_depth") 48 | 49 | self.need_W = need_W 50 | self.attention = DotProductAttention(clip = clip, return_logits = return_logits, head_depth = self.head_depth) 51 | if self.need_W: 52 | self.Wk = nn.Linear(embed_dim, embed_dim, bias = False) 53 | self.Wv = nn.Linear(embed_dim, embed_dim, bias = False) 54 | self.Wq = nn.Linear(embed_dim, embed_dim, bias = False) 55 | self.Wout = nn.Linear(embed_dim, embed_dim, bias = False) 56 | self.init_parameters() 57 | 58 | def init_parameters(self): #初始化参数 59 | for name, param in self.named_parameters(): 60 | if name == 'Wout.weight': 61 | stdv = 1. / math.sqrt(param.size(-1)) 62 | elif name in ['Wk.weight', 'Wv.weight', 'Wq.weight']: 63 | stdv = 1. / math.sqrt(self.head_depth) 64 | else: 65 | raise ValueError 66 | param.data.uniform_(-stdv, stdv) 67 | 68 | def split_heads(self, T): 69 | """ https://qiita.com/halhorn/items/c91497522be27bde17ce 70 | T: (batch, n_nodes, self.embed_dim) 71 | T reshaped: (batch, n_nodes, self.n_heads, self.head_depth) 72 | return: (batch, self.n_heads, n_nodes, self.head_depth) 73 | 74 | https://raishi12.hatenablog.com/entry/2020/04/20/221905 75 | """ 76 | shape = T.size()[:-1] + (self.n_heads, self.head_depth) 77 | T = T.view(*shape) 78 | return T.permute(0,2,1,3) 79 | 80 | def combine_heads(self, T): 81 | """ T: (batch, self.n_heads, n_nodes, self.head_depth) 82 | T transposed: (batch, n_nodes, self.n_heads, self.head_depth) 83 | return: (batch, n_nodes, self.embed_dim) 84 | """ 85 | T = T.permute(0,2,1,3).contiguous() 86 | shape = T.size()[:-2] + (self.embed_dim, ) 87 | return T.view(*shape) 88 | 89 | def forward(self, x, mask = None): 90 | """ q, k, v = x 91 | encoder arg x: [x, x, x] 92 | shape of q: (batch, n_nodes, embed_dim) 93 | output[0] - output[h_heads-1]: (batch, n_nodes, head_depth) 94 | --> concat output: (batch, n_nodes, head_depth * h_heads) 95 | return output: (batch, n_nodes, embed_dim) 96 | """ 97 | Q, K, V = x 98 | if self.need_W: 99 | Q, K, V = self.Wq(Q), self.Wk(K), self.Wv(V) 100 | Q, K, V = list(map(self.split_heads, [Q, K, V])) 101 | output = self.attention([Q, K, V], mask = mask) 102 | output = self.combine_heads(output) 103 | if self.need_W: 104 | return self.Wout(output) 105 | return output 106 | 107 | class GCN(nn.Module): 108 | def __init__(self, in_ft, out_ft, act, bias=True): 109 | super(GCN, self).__init__() 110 | self.fc = nn.Linear(in_ft, out_ft, bias=False) 111 | self.act = nn.PReLU() if act == 'prelu' else act 112 | 113 | if bias: 114 | self.bias = nn.Parameter(torch.FloatTensor(out_ft)) 115 | self.bias.data.fill_(0.0) 116 | else: 117 | self.register_parameter('bias', None) 118 | 119 | for m in self.modules(): 120 | self.weights_init(m) 121 | 122 | def weights_init(self, m): 123 | if isinstance(m, nn.Linear): 124 | torch.nn.init.xavier_uniform_(m.weight.data) 125 | if m.bias is not None: 126 | m.bias.data.fill_(0.0) 127 | 128 | # Shape of seq: (batch, nodes, features) 129 | def forward(self, seq, adj, sparse=False): 130 | seq_fts = self.fc(seq) 131 | if sparse and adj.is_sparse and adj.ndimension() == 2: 132 | out = torch.unsqueeze(torch.spmm(adj, torch.squeeze(seq_fts, 0)), 0) 133 | else: 134 | out = torch.bmm(adj, seq_fts) 135 | if self.bias is not None: 136 | out += self.bias 137 | 138 | return self.act(out) 139 | 140 | class AvgReadout(nn.Module): 141 | def __init__(self): 142 | super(AvgReadout, self).__init__() 143 | 144 | def forward(self, seq, msk): 145 | if msk is None: 146 | return torch.mean(seq, 1) 147 | else: 148 | msk = torch.unsqueeze(msk, -1) 149 | return torch.sum(seq * msk, 1) / torch.sum(msk) -------------------------------------------------------------------------------- /process_data_new.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | import pickle 3 | import time 4 | import torch 5 | import argparse, os, json 6 | import os 7 | import random 8 | import numpy as np 9 | import scipy.sparse as sp 10 | import torch 11 | import torch.nn.functional as F 12 | from tqdm import tqdm 13 | import os,pickle 14 | from scipy.sparse import load_npz, lil_matrix 15 | from utils.processer import normalize_adj, sparse_mx_to_torch_sparse_tensor, preprocess_features 16 | from utils.cflpdata import CustomDataset 17 | from scipy.sparse import csr_matrix 18 | import pickle 19 | from torch_geometric.data import Data, Batch 20 | from multiprocessing import Manager, Pool 21 | 22 | 23 | #文件排序 -------------------------- 24 | def sort_key(file_name): 25 | start_index = file_name.rindex("_") + 1 # 获取标号的起始索引 26 | end_index = file_name.index(".") # 获取标号的结束索引 27 | label = int(file_name[start_index:end_index]) # 提取标号并转换为整数 28 | return label 29 | 30 | 31 | #提取问题特征 -------------------------- 32 | def _get_cflp_features(cluster_dict): 33 | #获取基本数据 顾客数 设施数 以及 场景数 34 | n_customers = cluster_dict["n_customers"] 35 | n_facilities = cluster_dict["n_facilities"] 36 | n_scenarios = cluster_dict["n_scenarios"] 37 | 38 | adjs = [] 39 | all_feature = None 40 | cons_feature = None 41 | cflp_feature = [] # 标记某个场景的特征 42 | # 使用 get 方法判断键 'd' 是否存在 43 | if cluster_dict["second_stage"].get('z_coeff') is None: 44 | cluster_dict["second_stage"]['z_coeff'] = 1 45 | 46 | #分场景保存数据 47 | for s in range(n_scenarios): 48 | con_index = 0 49 | cflp_feature = [] #更新特征 50 | data = [] 51 | row = [] 52 | col = [] 53 | 54 | cons_number = n_customers + n_facilities + 1 55 | #约束阶段 56 | #第一阶段约束 对设施数的限制 57 | cons = [] 58 | cons_a = [] 59 | cons_b = [] 60 | for j in range(n_facilities): 61 | cons_a.append(1) 62 | cons_b.append(cluster_dict["first_stage"]["facilities_cost"][j]) 63 | #邻接矩阵 64 | data.append(1) 65 | row.append(con_index) 66 | col.append(cons_number+j) 67 | 68 | cons_a.append(-cluster_dict['first_stage']['constraint']) 69 | cons_b.append(0) 70 | cons_a = np.array(cons_a) 71 | cons_b = np.array(cons_b) 72 | obj = np.dot(cons_a,cons_b) / (np.linalg.norm(cons_a)*np.linalg.norm(cons_b)) 73 | cons.append(obj) 74 | cflp_feature.append(cons) 75 | 76 | con_index += 1 77 | 78 | 79 | #第二阶段约束 注意每个场景都有以下两个约束 80 | #约束 1 需求约束 81 | for j in range(n_facilities): 82 | cons = [] 83 | cons_a = [] 84 | cons_b = [] 85 | cons_a.append((-1.0)*cluster_dict['second_stage']["qx"][j]) #xj 86 | cons_a.append(cluster_dict["second_stage"]['z_coeff']) #zj cluster_dict["second_stage"]["recourse_costs"][s] 87 | cons_b.append(cluster_dict["first_stage"]["facilities_cost"][j]) 88 | cons_b.append(cluster_dict["second_stage"]["recourse_costs"]) 89 | for i in range(n_customers): #yij 90 | cons_a.append(cluster_dict['second_stage']["q_c_f"][s][i][j]) 91 | cons_b.append(cluster_dict["second_stage"]["trans_cost"][i][j]) 92 | #邻接矩阵 93 | data.append(cluster_dict['second_stage']["q_c_f"][s][i][j]) 94 | row.append(con_index) 95 | col.append(cons_number+n_facilities+i*n_facilities+j) 96 | cons_a = np.array(cons_a) 97 | cons_b = np.array(cons_b) 98 | obj = np.dot(cons_a,cons_b) / (np.linalg.norm(cons_a)*np.linalg.norm(cons_b)) 99 | cons.append(obj) 100 | cflp_feature.append(cons) 101 | 102 | #邻接矩阵 103 | data.append((-1.0)*cluster_dict['second_stage']["qx"][j]) 104 | row.append(con_index) 105 | col.append(cons_number+j) 106 | data.append(cluster_dict["second_stage"]['z_coeff']) #cluster_dict["second_stage"]["recourse_costs"][s] 107 | row.append(con_index) 108 | col.append(cons_number+n_facilities+n_facilities*n_customers+j) 109 | 110 | con_index += 1 111 | 112 | #约束2 存在约束 113 | for i in range(n_customers): 114 | cons = [] 115 | cons_a = [] 116 | cons_b = [] 117 | cons_a.append((-1)*cluster_dict['second_stage']["h"][s][i]) #hsi 118 | cons_b.append(0) 119 | for j in range(n_facilities): 120 | cons_a.append(1) 121 | cons_b.append(cluster_dict["second_stage"]["trans_cost"][i][j]) 122 | #邻接矩阵 123 | data.append(1) 124 | row.append(con_index) 125 | col.append(cons_number+n_facilities+i*n_facilities+j) 126 | cons_a = np.array(cons_a) 127 | cons_b = np.array(cons_b) 128 | obj = np.dot(cons_a,cons_b) / (np.linalg.norm(cons_a)*np.linalg.norm(cons_b)) 129 | cons.append(obj) 130 | cflp_feature.append(cons) 131 | 132 | con_index += 1 133 | 134 | #生成约束的特征以及adj 135 | features = np.array(cflp_feature) 136 | features = lil_matrix(features.astype(float)) 137 | #features, _ = preprocess_features(features) 138 | features = features.todense() 139 | features = torch.FloatTensor(features[np.newaxis]) 140 | if cons_feature == None: 141 | cons_feature = features 142 | else : 143 | cons_feature = torch.cat((cons_feature, features), dim = 0) 144 | 145 | feature_size = len(cflp_feature) + n_facilities + n_facilities * n_customers + n_facilities 146 | data = np.array(data) 147 | row = np.array(row) 148 | col = np.array(col) 149 | adj = csr_matrix((data, (row, col)), shape=(feature_size, feature_size)) 150 | adj = normalize_adj(adj + sp.eye(adj.shape[0])) 151 | adjs.append(adj) 152 | 153 | cflp_feature = [] 154 | # xj 155 | for j in range(n_facilities): 156 | var = [] 157 | var.append(cluster_dict["first_stage"]["facilities_cost"][j]) 158 | var.append(cluster_dict['second_stage']["qx"][j]) 159 | cflp_feature.append(var) 160 | 161 | #yij 162 | for i in range(n_customers): 163 | for j in range(n_facilities): 164 | var = [] 165 | var.append(cluster_dict['second_stage']["q_c_f"][s][i][j]) 166 | var.append(cluster_dict['second_stage']["h"][s][i]) 167 | cflp_feature.append(var) 168 | 169 | #zj 170 | for j in range(n_facilities): 171 | var = [] 172 | var.append(cluster_dict["second_stage"]["recourse_costs"]) 173 | var.append(cluster_dict["second_stage"]['z_coeff']) 174 | cflp_feature.append(var) 175 | 176 | #生成场景的特征以及adj 177 | features = np.array(cflp_feature) 178 | features = lil_matrix(features.astype(float)) 179 | #features, _ = preprocess_features(features) 180 | features = features.todense() 181 | features = torch.FloatTensor(features[np.newaxis]) 182 | if all_feature == None: 183 | all_feature = features 184 | else : 185 | all_feature = torch.cat((all_feature, features), dim = 0) 186 | 187 | return adjs, all_feature, cons_feature 188 | 189 | 190 | #生成batch数据 -------------------------- 191 | def padding_feat(feat): 192 | a,b,c = feat.shape 193 | 194 | # Desired size [200, 220, 2] 195 | desired_size = (a, b, 2) 196 | 197 | # Create a new tensor of the desired size filled with zeros 198 | new_tensor = torch.zeros(desired_size) 199 | 200 | # Copy the original tensor into the new tensor 201 | # The original tensor is copied into the top left corner of the new tensor 202 | new_tensor[:a, :b,:1] = feat 203 | return new_tensor 204 | 205 | def build_batch_data(all_adjs,all_var_feats,all_con_feats, all_edge_scen): 206 | batch_datas = [] 207 | for i in tqdm(range(len(all_adjs)), desc="处理batch"): 208 | adjs = all_adjs[i] 209 | var_feats = all_var_feats[i] 210 | con_feats = padding_feat(all_con_feats[i]) 211 | feats = torch.cat((con_feats,var_feats),dim=1) 212 | mark_node = torch.zeros(feats.shape[1],) 213 | mark_node[:con_feats.shape[1]] = 1 214 | edge_indices = [torch.stack([torch.from_numpy(adjs[i].row), torch.from_numpy(adjs[i].col)], dim=0) for i in range(len(adjs))] 215 | values = [torch.from_numpy(adjs[i].data) for i in range(len(adjs))] 216 | datas = [Data(x=feats[i], edge_index= edge_indices[i], edge_attr= values[i], mark=mark_node) for i in range(len(adjs))] 217 | batched_data = Batch.from_data_list(datas) 218 | graph = Data(x=batched_data.x, edge_index=batched_data.edge_index, edge_attr=batched_data.edge_attr, batch=batched_data.batch, scen_adj= all_edge_scen[i], mark=batched_data.mark, ptr= batched_data.ptr ) 219 | 220 | batch_datas.append(graph) 221 | return batch_datas 222 | 223 | 224 | #处理特征为batch图数据 -------------------------- 225 | def process_cluster_file(cluster_file, cluster_dict, feature_type, mp_data_list): 226 | print("Now:", cluster_file) 227 | if feature_type == 'cflp': 228 | adjs, all_feature, cons_feature = _get_cflp_features(cluster_dict) 229 | edge_adj = torch.from_numpy(cluster_dict['second_stage']["h"]).float() 230 | edge_adj = F.cosine_similarity(edge_adj.unsqueeze(1), edge_adj.unsqueeze(0), dim=2) 231 | print("!!Done:", cluster_file) 232 | mp_data_list.append((cluster_file, adjs, all_feature, cons_feature, edge_adj)) 233 | 234 | def process_data(source_folder, cluster_dicts, feature_type, process_type): 235 | if process_type == "train": 236 | print(f"{process_type}...") 237 | all_adjs, all_var_feats, all_con_feats, all_edge_scen, cls = [], [], [], [], [] 238 | start = time.time() 239 | 240 | # 设置使用的进程数量 241 | num_processes = 2 # 根据实际情况设置进程数量 242 | 243 | with Manager() as manager: 244 | mp_data_list = manager.list() 245 | pool = Pool(num_processes) 246 | 247 | for cluster_file in tqdm(cluster_dicts, desc="处理进度", unit="文件"): 248 | orin_file = cluster_file 249 | cluster_file = os.path.join(source_folder, cluster_file) 250 | with open(cluster_file, "rb") as f: 251 | cluster_dict = pickle.load(f) 252 | pool.apply_async(process_cluster_file, args=(orin_file, cluster_dict, feature_type, mp_data_list)) 253 | 254 | pool.close() # 关闭进程池 255 | pool.join() # 等待所有任务完成 256 | 257 | data = list(mp_data_list) 258 | 259 | for l in range(len(data)): 260 | cluster_file, adjs, all_feature, cons_feature, edge_adj = data[l] 261 | cls.append(cluster_file) 262 | all_edge_scen.append(edge_adj) 263 | all_adjs.append(adjs) 264 | all_var_feats.append(all_feature) 265 | all_con_feats.append(cons_feature) 266 | 267 | print("used time:", time.time() - start) 268 | 269 | 270 | batch_graphs = build_batch_data(all_adjs,all_var_feats,all_con_feats,all_edge_scen) 271 | 272 | total_size = len(batch_graphs) 273 | 274 | # change !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 275 | train_size = 8192 276 | 277 | 278 | # 创建随机的索引列表 279 | index_list = list(range(total_size)) 280 | random.shuffle(index_list) 281 | 282 | # 划分训练集和测试集的索引 283 | train_index = index_list[:train_size] 284 | eval_index = index_list[train_size:] 285 | 286 | train_dataset = [batch_graphs[i] for i in train_index] 287 | train_cls = [cls[i] for i in train_index] 288 | eval_dataset = [batch_graphs[i] for i in eval_index] 289 | eval_cls = [cls[i] for i in eval_index] 290 | 291 | return train_dataset, train_cls, eval_dataset, eval_cls 292 | 293 | else: 294 | print(f"{process_type}...") 295 | all_adjs, all_var_feats, all_con_feats, all_edge_scen, cls = [], [], [], [], [] 296 | start = time.time() 297 | # 设置使用的进程数量 298 | num_processes = 2 # 根据实际情况设置进程数量 299 | 300 | with Manager() as manager: 301 | mp_data_list = manager.list() 302 | pool = Pool(num_processes) 303 | 304 | for cluster_file in tqdm(cluster_dicts, desc="处理进度", unit="文件"): 305 | orin_file = cluster_file 306 | cluster_file = os.path.join(source_folder, cluster_file) 307 | with open(cluster_file, "rb") as f: 308 | cluster_dict = pickle.load(f) 309 | pool.apply_async(process_cluster_file, args=(orin_file, cluster_dict, feature_type, mp_data_list)) 310 | 311 | pool.close() # 关闭进程池 312 | pool.join() # 等待所有任务完成 313 | 314 | data = list(mp_data_list) 315 | 316 | for l in range(len(data)): 317 | cluster_file, adjs, all_feature, cons_feature, edge_adj = data[l] 318 | cls.append(cluster_file) 319 | all_edge_scen.append(edge_adj) 320 | all_adjs.append(adjs) 321 | all_var_feats.append(all_feature) 322 | all_con_feats.append(cons_feature) 323 | 324 | print("used time:", time.time() - start) 325 | batch_graphs = build_batch_data(all_adjs,all_var_feats,all_con_feats,all_edge_scen) 326 | total_size = len(batch_graphs) 327 | index_list = list(range(total_size)) 328 | test_index = index_list 329 | test_dataset = [batch_graphs[i] for i in test_index] 330 | test_cls = [cls[i] for i in test_index] 331 | 332 | return test_dataset, test_cls, 0, 0 333 | 334 | 335 | 336 | 337 | if __name__ == "__main__": 338 | parser = argparse.ArgumentParser(description="Gnn_Transformer for two_stage") 339 | parser.add_argument('--config_file', type=str, default='./configs/cflp_config.json', help="base config json dir") 340 | parser.add_argument('--scenarios_folder', type=str, default='./train_scenarios/', help="base scenarios folder") 341 | parser.add_argument('--feature_type', type=str, default='cflp', help="type of problem") 342 | parser.add_argument('--process_type', type=str, default='train', help="type of process") 343 | args = parser.parse_args() 344 | source_folder = args.scenarios_folder 345 | all_kwargs = json.load(open(args.config_file, 'r')) 346 | if args.process_type == 'train': 347 | train_data_param = all_kwargs['TrainData'] 348 | else: 349 | test_data_param = all_kwargs['TestData'] 350 | print("TYPE:", args.feature_type) 351 | 352 | cluster_dicts = sorted(os.listdir(source_folder), key=sort_key) 353 | 354 | #-------------------------------------- 选择多少个数据 !!!!!!!!! 355 | k = min(8292, len(cluster_dicts)) #前k个 356 | 357 | cluster_dicts = cluster_dicts[:k] 358 | #-------------------------------------- 359 | 360 | #存储数据集 361 | if args.process_type == 'train': 362 | #train 363 | train_save_path = train_data_param['save_path'] #训练集特征的位置 364 | train_cls_path = train_data_param['cls_path'] #训练集场景字典的位置 365 | 366 | #eval 367 | eval_save_path = os.path.join(all_kwargs['train']['eval_path'], all_kwargs['train']['eval_pt']) #验证集特征的位置 368 | eval_cls_path = os.path.join(all_kwargs['train']['eval_path'], all_kwargs['train']['eval_cls']) #验证集场景字典的位置 369 | train_dataset, train_cls, eval_dataset, eval_cls= process_data(source_folder, cluster_dicts, feature_type=args.feature_type, process_type=args.process_type) 370 | torch.save(train_dataset, train_save_path) 371 | torch.save(eval_dataset, eval_save_path) 372 | with open(train_cls_path, 'wb') as f: 373 | pickle.dump(train_cls, f) 374 | with open(eval_cls_path, 'wb') as f: 375 | pickle.dump(eval_cls, f) 376 | 377 | print("!!Done Process Train Data!!") 378 | else: 379 | #test 380 | test_save_path = test_data_param['save_path'] #测试集特征的位置 381 | test_cls_path = test_data_param['cls_path'] #测试集场景字典的位置 382 | test_dataset, test_cls, _, _ = process_data(source_folder, cluster_dicts, feature_type=args.feature_type, process_type=args.process_type) 383 | torch.save(test_dataset, test_save_path) 384 | 385 | with open(test_cls_path, 'wb') as f: 386 | pickle.dump(test_cls, f) 387 | print("!!Done Process Test Data!!") -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | # docs and experiment results can be found at https://docs.cleanrl.dev/rl-algorithms/ppo/#ppo_continuous_actionpy 2 | from dataclasses import dataclass 3 | import os 4 | import time 5 | import torch 6 | import numpy as np 7 | import wandb 8 | from agent import Agent 9 | from env import CFLPEnv 10 | from sample import Sampler 11 | import argparse 12 | import json 13 | import pickle 14 | import random 15 | import pandas as pd 16 | import tyro 17 | from utils import solve_cflp_softmax_new 18 | from trainer import PPOTrainer 19 | 20 | @dataclass 21 | class Args: 22 | exp_name: str = os.path.basename(__file__)[: -len(".py")] 23 | """实验的名称""" 24 | device_id: int = 3 25 | """device的id 位置""" 26 | seed: int = 16 27 | """实验的随机种子""" 28 | torch_deterministic: bool = True 29 | """如果设置为True,则`torch.backends.cudnn.deterministic=False`""" 30 | cuda: bool = True 31 | """如果设置为True,则默认启用cuda""" 32 | track: bool = False 33 | """如果设置为True,则使用Weights and Biases跟踪此实验""" 34 | wandb_project_name: str = "" 35 | """Weights and Biases的项目名称""" 36 | wandb_entity: str = "" 37 | """Weights and Biases的实体(团队)""" 38 | capture_video: bool = False 39 | """是否捕获代理的表现视频(请查看`videos`文件夹)""" 40 | save_model: bool = True 41 | """是否保存模型到`runs/{run_name}`文件夹""" 42 | upload_model: bool = False 43 | """是否将保存的模型上传到Hugging Face""" 44 | hf_entity: str = "" 45 | """来自Hugging Face Hub的模型仓库的用户或组织名称""" 46 | model_test_path: str = "" 47 | """模型测试的参数地址""" 48 | 49 | # 算法特定的参数 50 | mode: str = "train" 51 | """"算法模式""" 52 | env_id: str = "CFLP" 53 | """环境的ID""" 54 | total_timesteps: int = 20480 55 | """实验的总步数""" 56 | learning_rate: float = 2.5e-4 57 | """优化器的学习率""" 58 | num_envs: int = 2048 59 | """并行游戏环境的数量""" 60 | num_steps: int = 1 61 | """每个策略回合在每个环境中运行的步数""" 62 | anneal_lr: bool = True 63 | """是否对策略和值网络进行学习率退火""" 64 | gamma: float = 0.99 65 | """折扣因子 gamma""" 66 | gae_lambda: float = 0.95 67 | """用于广义优势估计的 lambda 值""" 68 | num_minibatches: int = 16 69 | """mini-batch 的数量""" 70 | update_epochs: int = 10 71 | """更新策略的 K 个epochs""" 72 | norm_adv: bool = True 73 | """是否进行优势归一化""" 74 | clip_coef: float = 0.20 75 | """策略梯度裁剪系数""" 76 | clip_vloss: bool = True 77 | """是否对值函数使用裁剪损失,根据论文""" 78 | ent_coef: float = 0.0 79 | """熵的系数""" 80 | vf_coef: float = 0.5 81 | """值函数的系数""" 82 | max_grad_norm: float = 0.5 83 | """梯度裁剪的最大范数""" 84 | target_kl: float = None 85 | """目标KL散度阈值""" 86 | 87 | # 在运行时填充 88 | batch_size: int = 0 89 | """批量大小(在运行时计算)""" 90 | minibatch_size: int = 0 91 | """mini-batch 大小(在运行时计算)""" 92 | num_iterations: int = 0 93 | """迭代次数(在运行时计算)""" 94 | 95 | # 读取参数 96 | def load_param(parser, device, mode = "train"): 97 | args = parser.parse_args() 98 | all_kwargs = json.load(open(args.config_file, 'r')) 99 | data_param = all_kwargs['TrainData'] 100 | #load train param 101 | policy_param = all_kwargs['Policy'] 102 | train_param = all_kwargs['train'] 103 | if mode == "train": 104 | data = torch.load(data_param["save_path"]) 105 | train_cls = data_param['cls_path'] 106 | n_scenarios = train_param["sel_num"] 107 | bs = [] 108 | clusters = [] 109 | # 从文件中读取列表 110 | with open(train_cls, 'rb') as f: 111 | cls_path = pickle.load(f) 112 | 113 | for i in range(len(cls_path)): 114 | cls_loc = os.path.join(data_param['pkl_folder'], cls_path[i]) 115 | with open(cls_loc, 'rb') as f: 116 | cls = pickle.load(f) 117 | clusters.append(cls) 118 | 119 | file_path = f"result_of_{cls_path[i][10:-4]}.pkl" 120 | file_path = os.path.join(data_param['result_folder'], file_path) 121 | with open(file_path, "rb") as f: 122 | result = pickle.load(f) 123 | ans = [] 124 | for key in result['X'].keys(): 125 | ans.append(float(result['X'][key])) 126 | ans.append(result['primal']) 127 | bs.append(ans) 128 | 129 | return policy_param, train_param, data, bs, n_scenarios, clusters 130 | elif mode == "test": 131 | return policy_param, train_param 132 | else: 133 | raise ValueError("mode should be train or test") 134 | 135 | # 测试用函数 136 | def test_model(test_cls_path, action, test_ins_num, test_pararm): 137 | mean_bs = 0 138 | mean_agent = 0 139 | mean_time = 0 140 | delta = 0 141 | np_bs, np_agent, np_time, np_delta = [],[],[],[] 142 | file_name = [] 143 | for i in range(test_ins_num): 144 | cls_loc = os.path.join(test_pararm['pkl_folder'], test_cls_path[i]) 145 | file_name.append(cls_loc) 146 | with open(cls_loc, 'rb') as f: 147 | cls = pickle.load(f) 148 | 149 | file_path = f"result_of_{test_cls_path[i][10:-4]}.pkl" 150 | file_path = os.path.join(test_pararm['result_folder'], file_path) 151 | bs_x = [] 152 | with open(file_path, "rb") as f: 153 | results = pickle.load(f) 154 | bs = results['primal'] 155 | for key in results['X'].keys(): 156 | bs_x.append(results['X'][key]) 157 | mean_bs += bs 158 | np_bs.append(bs) 159 | bs_x = torch.from_numpy(np.array(bs_x)) 160 | args = (cls, action[i].cpu(), True) 161 | test_ = solve_cflp_softmax_new(args).squeeze() 162 | cost = torch.sum((bs_x == test_[:-2]), dim=0)/(test_.shape[-1]-2) 163 | test_results = {} 164 | test_results['primal'] = test_[-1].item() 165 | test_results['time'] = test_[-2].item() 166 | if abs(cost - 1.0) < 1e-5: 167 | now_delta = 0.0 168 | else : 169 | now_delta = (test_results['primal'] - bs)/ bs *100 170 | print(f"Test {i} {test_cls_path[i]}: {test_results['primal']} , {test_results['time']} , bs: {bs} , gap: {now_delta} %") 171 | 172 | mean_agent += test_results['primal'] 173 | np_agent.append(test_results['primal']) 174 | mean_time += test_results['time'] 175 | np_time.append(test_results['time']) 176 | delta += ((test_results['primal'] - bs)/ bs *100) 177 | np_delta.append(((test_results['primal'] - bs)/ bs *100)) 178 | mean_agent = mean_agent / test_ins_num 179 | mean_bs = mean_bs / test_ins_num 180 | mean_time = mean_time / test_ins_num 181 | delta /= test_ins_num 182 | print(f"Test Averge: agent:{mean_agent} bs:{mean_bs} time:{mean_time} gap:{delta}%") 183 | return file_name,np_agent, np_bs, np_time, np_delta 184 | 185 | def test(parser, mode, model_test_path, test_ins_num, device, nums=1, seed=16, clip=0.2, alpha=0.001): 186 | '''num: 测试的次数,多次试验,避免机器、随机性的影响''' 187 | mean_agent, mean_bs, mean_time, delta = [],[],[],[] 188 | policy_param, train_param = load_param(parser, device, mode = mode) 189 | agent = Agent(policy_param, train_param, device).to(device) 190 | print("Test "+model_test_path+" ....") 191 | param = torch.load(model_test_path, map_location=device) 192 | agent.load_state_dict(param) 193 | console_args = parser.parse_args() 194 | all_kwargs = json.load(open(console_args.config_file, 'r')) 195 | test_pararm = all_kwargs['TestData'] 196 | test_data = torch.load(test_pararm['save_path']) 197 | test_ins_num = min(test_ins_num, len(test_data)) 198 | 199 | test_decoder = all_kwargs['test']['decode_type'] 200 | sel_num = all_kwargs['test']['sel_num'] 201 | print("Select numbers:",sel_num) 202 | test_data = [test_data[i] for i in range(test_ins_num)] 203 | file_name_all = [] 204 | with open(test_pararm['cls_path'], 'rb') as f: 205 | test_cls_path = pickle.load(f) 206 | idxs, ag_data, bs_data, ti_data, da_data = [],[],[],[],[] 207 | for num in range(nums): 208 | with torch.no_grad(): 209 | start = time.time() 210 | action, log_p= agent.get_action_and_value(test_data, decode_type=test_decoder, cluster_k=sel_num, mode = mode) 211 | print("Model_time:", time.time() - start) 212 | file_name, np_agent, np_bs, np_time, np_delta = test_model(test_cls_path, action, test_ins_num, test_pararm) 213 | idx = [num]*len(np_agent) 214 | ag,bs,ti,de = np.mean(np_agent),np.mean(np_bs),np.mean(np_time),np.mean(np_delta) 215 | file_name_all.extend(file_name) 216 | ag_data.extend(np_agent) 217 | bs_data.extend(np_bs) 218 | ti_data.extend(np_time), 219 | da_data.extend(np_delta) 220 | idxs.extend(idx) 221 | mean_agent.append(ag) 222 | mean_bs.append(bs) 223 | mean_time.append(ti) 224 | delta.append(de) 225 | results_df = pd.DataFrame({ 226 | 'idx': idxs, 227 | 'file_name': file_name_all, 228 | 'real_results': bs_data, 229 | 'model_result': ag_data, 230 | 'model_time': ti_data, 231 | 'gap': da_data, 232 | 'error':da_data 233 | }) 234 | # print(results_df) 235 | csv_file_path = f'./test_csv/ppo_test_results_cflp_10_20_{sel_num}_clip_{clip}_alpha_{alpha}.csv' # 修改为您希望保存文件的路径 236 | results_df.to_csv(csv_file_path, index=False) 237 | print("results_df:", results_df) 238 | # 输出保存成功的消息 239 | print(f"Results have been saved to {csv_file_path}") 240 | 241 | print('test done for '+model_test_path +' with '+str(nums)+' times: ') 242 | print('mean_agent: ',np.mean(mean_agent),' mean_bs: ',np.mean(mean_bs), 243 | ' mean_time: ',np.mean(mean_time), ' delta: ',np.mean(delta)) 244 | 245 | 246 | if __name__ == "__main__": 247 | current_dir = os.getcwd() 248 | print("current_dir:",current_dir) 249 | # 参数配置:固定参数json 文件;调试参数命令行 250 | parser = argparse.ArgumentParser(description="Gnn_Transformer for two_stage") 251 | parser.add_argument('--config_file', type=str, default='./configs/cflp_config.json', help="base config json dir") 252 | 253 | args = tyro.cli(Args) 254 | args.batch_size = int(args.num_envs * args.num_steps) 255 | args.minibatch_size = int(args.batch_size // args.num_minibatches) 256 | args.num_iterations = args.total_timesteps // args.batch_size 257 | run_name = f"{args.env_id}__{args.exp_name}__{args.seed}__{int(time.time())}" 258 | if args.track and args.mode == "train": 259 | 260 | 261 | wandb.init( 262 | project=args.wandb_project_name, 263 | entity=args.wandb_entity, 264 | sync_tensorboard=True, 265 | config=vars(args), 266 | name=run_name, 267 | monitor_gym=True, 268 | save_code=True, 269 | ) 270 | 271 | # TRY NOT TO MODIFY: seeding 272 | random.seed(args.seed) 273 | np.random.seed(args.seed) 274 | torch.manual_seed(args.seed) 275 | torch.backends.cudnn.deterministic = args.torch_deterministic 276 | 277 | if args.device_id is not None: 278 | torch.cuda.set_device(args.device_id) 279 | device = torch.device("cuda" if torch.cuda.is_available() and args.cuda else "cpu") 280 | 281 | if args.mode == "train": 282 | policy_param, train_param, data, bs, n_scenarios, clusters = load_param(parser, device) 283 | # trainer setup 284 | trainer = PPOTrainer(args, policy_param, train_param, data, bs, clusters, run_name, device) 285 | trainer.train() 286 | elif args.mode == "test": 287 | test(parser, args.mode, args.model_test_path, 100, device, nums=1, seed = args.seed, clip = args.clip_coef, alpha = 0.0001) 288 | 289 | -------------------------------------------------------------------------------- /sample.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | 4 | class Sampler: 5 | def __init__(self, envs, agent, num_steps, device): 6 | self.envs = envs 7 | self.agent = agent 8 | self.num_steps = num_steps 9 | self.device = device 10 | self.reset_buffer() 11 | 12 | def reset_buffer(self): 13 | self.obs = [] 14 | self.actions = torch.zeros((self.num_steps, self.envs.batch_size, self.envs.k), device=self.device) 15 | self.logprobs = torch.zeros((self.num_steps, self.envs.batch_size), device=self.device) 16 | self.rewards = torch.zeros((self.num_steps, self.envs.batch_size), device=self.device) 17 | self.values = torch.zeros((self.num_steps, self.envs.batch_size), device=self.device) 18 | self.next_done = torch.zeros(self.envs.batch_size, device=self.device) 19 | 20 | def collect_trajectories(self, next_obs): 21 | for step in range(self.num_steps): 22 | self.obs.append(next_obs) 23 | with torch.no_grad(): 24 | action, logprob, _, value = self.agent.get_action_and_value(next_obs) 25 | next_obs, reward, terminations, truncations, _ = self.envs.step(action.cpu().numpy(), step) 26 | next_done = torch.Tensor(np.logical_or(terminations, truncations)).to(self.device) 27 | 28 | # 存储数据 29 | self.actions[step] = action 30 | self.logprobs[step] = logprob 31 | self.rewards[step] = torch.tensor(reward).to(self.device).view(-1) 32 | self.values[step] = value.flatten() 33 | self.next_done = next_done 34 | return next_obs, self.next_done 35 | 36 | def compute_advantages_and_returns(self, args): 37 | with torch.no_grad(): 38 | advantages = torch.zeros_like(self.rewards).to(self.device) 39 | lastgaelam = 0 40 | for t in reversed(range(args.num_steps)): 41 | if t == args.num_steps - 1: 42 | nextnonterminal = 1.0 - self.next_done 43 | delta = self.rewards[t] - self.values[t] 44 | advantages[t] = lastgaelam = delta + args.gamma * args.gae_lambda * nextnonterminal * lastgaelam 45 | returns = advantages + self.values 46 | return advantages, returns 47 | 48 | def get_batch_data(self, advantages, returns): 49 | b_obs = [element for sublist in self.obs for element in sublist] 50 | b_actions = self.actions.reshape((-1, self.envs.k)) 51 | b_logprobs = self.logprobs.reshape(-1) 52 | b_advantages = advantages.reshape(-1) 53 | b_returns = returns.reshape(-1) 54 | b_values = self.values.reshape(-1) 55 | return b_obs, b_actions, b_logprobs, b_advantages, b_returns, b_values -------------------------------------------------------------------------------- /test_results/result_of_0.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_0.pkl -------------------------------------------------------------------------------- /test_results/result_of_1.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_1.pkl -------------------------------------------------------------------------------- /test_results/result_of_10.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_10.pkl -------------------------------------------------------------------------------- /test_results/result_of_100.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_100.pkl -------------------------------------------------------------------------------- /test_results/result_of_101.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_101.pkl -------------------------------------------------------------------------------- /test_results/result_of_102.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_102.pkl -------------------------------------------------------------------------------- /test_results/result_of_103.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_103.pkl -------------------------------------------------------------------------------- /test_results/result_of_104.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_104.pkl -------------------------------------------------------------------------------- /test_results/result_of_105.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_105.pkl -------------------------------------------------------------------------------- /test_results/result_of_106.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_106.pkl -------------------------------------------------------------------------------- /test_results/result_of_107.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_107.pkl -------------------------------------------------------------------------------- /test_results/result_of_108.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_108.pkl -------------------------------------------------------------------------------- /test_results/result_of_109.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_109.pkl -------------------------------------------------------------------------------- /test_results/result_of_11.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_11.pkl -------------------------------------------------------------------------------- /test_results/result_of_110.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_110.pkl -------------------------------------------------------------------------------- /test_results/result_of_111.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_111.pkl -------------------------------------------------------------------------------- /test_results/result_of_112.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_112.pkl -------------------------------------------------------------------------------- /test_results/result_of_113.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_113.pkl -------------------------------------------------------------------------------- /test_results/result_of_114.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_114.pkl -------------------------------------------------------------------------------- /test_results/result_of_115.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_115.pkl -------------------------------------------------------------------------------- /test_results/result_of_116.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_116.pkl -------------------------------------------------------------------------------- /test_results/result_of_117.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_117.pkl -------------------------------------------------------------------------------- /test_results/result_of_118.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_118.pkl -------------------------------------------------------------------------------- /test_results/result_of_119.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_119.pkl -------------------------------------------------------------------------------- /test_results/result_of_12.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_12.pkl -------------------------------------------------------------------------------- /test_results/result_of_120.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_120.pkl -------------------------------------------------------------------------------- /test_results/result_of_121.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_121.pkl -------------------------------------------------------------------------------- /test_results/result_of_122.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_122.pkl -------------------------------------------------------------------------------- /test_results/result_of_123.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_123.pkl -------------------------------------------------------------------------------- /test_results/result_of_124.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_124.pkl -------------------------------------------------------------------------------- /test_results/result_of_125.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_125.pkl -------------------------------------------------------------------------------- /test_results/result_of_126.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_126.pkl -------------------------------------------------------------------------------- /test_results/result_of_127.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_127.pkl -------------------------------------------------------------------------------- /test_results/result_of_128.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_128.pkl -------------------------------------------------------------------------------- /test_results/result_of_129.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_129.pkl -------------------------------------------------------------------------------- /test_results/result_of_130.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_130.pkl -------------------------------------------------------------------------------- /test_results/result_of_131.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_131.pkl -------------------------------------------------------------------------------- /test_results/result_of_132.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_132.pkl -------------------------------------------------------------------------------- /test_results/result_of_133.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_133.pkl -------------------------------------------------------------------------------- /test_results/result_of_134.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_134.pkl -------------------------------------------------------------------------------- /test_results/result_of_135.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_135.pkl -------------------------------------------------------------------------------- /test_results/result_of_136.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_136.pkl -------------------------------------------------------------------------------- /test_results/result_of_137.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_137.pkl -------------------------------------------------------------------------------- /test_results/result_of_138.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_138.pkl -------------------------------------------------------------------------------- /test_results/result_of_139.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_139.pkl -------------------------------------------------------------------------------- /test_results/result_of_140.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_140.pkl -------------------------------------------------------------------------------- /test_results/result_of_141.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_141.pkl -------------------------------------------------------------------------------- /test_results/result_of_142.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_142.pkl -------------------------------------------------------------------------------- /test_results/result_of_144.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_144.pkl -------------------------------------------------------------------------------- /test_results/result_of_145.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_145.pkl -------------------------------------------------------------------------------- /test_results/result_of_146.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_146.pkl -------------------------------------------------------------------------------- /test_results/result_of_148.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_148.pkl -------------------------------------------------------------------------------- /test_results/result_of_149.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_149.pkl -------------------------------------------------------------------------------- /test_results/result_of_15.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_15.pkl -------------------------------------------------------------------------------- /test_results/result_of_150.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_150.pkl -------------------------------------------------------------------------------- /test_results/result_of_152.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_152.pkl -------------------------------------------------------------------------------- /test_results/result_of_153.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_153.pkl -------------------------------------------------------------------------------- /test_results/result_of_154.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_154.pkl -------------------------------------------------------------------------------- /test_results/result_of_156.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_156.pkl -------------------------------------------------------------------------------- /test_results/result_of_157.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_157.pkl -------------------------------------------------------------------------------- /test_results/result_of_158.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_158.pkl -------------------------------------------------------------------------------- /test_results/result_of_16.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_16.pkl -------------------------------------------------------------------------------- /test_results/result_of_160.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_160.pkl -------------------------------------------------------------------------------- /test_results/result_of_161.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_161.pkl -------------------------------------------------------------------------------- /test_results/result_of_162.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_162.pkl -------------------------------------------------------------------------------- /test_results/result_of_164.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_164.pkl -------------------------------------------------------------------------------- /test_results/result_of_165.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_165.pkl -------------------------------------------------------------------------------- /test_results/result_of_166.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_166.pkl -------------------------------------------------------------------------------- /test_results/result_of_168.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_168.pkl -------------------------------------------------------------------------------- /test_results/result_of_169.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_169.pkl -------------------------------------------------------------------------------- /test_results/result_of_17.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_17.pkl -------------------------------------------------------------------------------- /test_results/result_of_170.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_170.pkl -------------------------------------------------------------------------------- /test_results/result_of_172.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_172.pkl -------------------------------------------------------------------------------- /test_results/result_of_173.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_173.pkl -------------------------------------------------------------------------------- /test_results/result_of_174.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_174.pkl -------------------------------------------------------------------------------- /test_results/result_of_176.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_176.pkl -------------------------------------------------------------------------------- /test_results/result_of_177.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_177.pkl -------------------------------------------------------------------------------- /test_results/result_of_178.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_178.pkl -------------------------------------------------------------------------------- /test_results/result_of_180.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_180.pkl -------------------------------------------------------------------------------- /test_results/result_of_181.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_181.pkl -------------------------------------------------------------------------------- /test_results/result_of_182.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_182.pkl -------------------------------------------------------------------------------- /test_results/result_of_184.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_184.pkl -------------------------------------------------------------------------------- /test_results/result_of_185.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_185.pkl -------------------------------------------------------------------------------- /test_results/result_of_186.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_186.pkl -------------------------------------------------------------------------------- /test_results/result_of_187.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_187.pkl -------------------------------------------------------------------------------- /test_results/result_of_188.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_188.pkl -------------------------------------------------------------------------------- /test_results/result_of_189.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_189.pkl -------------------------------------------------------------------------------- /test_results/result_of_190.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_190.pkl -------------------------------------------------------------------------------- /test_results/result_of_192.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_192.pkl -------------------------------------------------------------------------------- /test_results/result_of_193.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_193.pkl -------------------------------------------------------------------------------- /test_results/result_of_194.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_194.pkl -------------------------------------------------------------------------------- /test_results/result_of_196.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_196.pkl -------------------------------------------------------------------------------- /test_results/result_of_197.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_197.pkl -------------------------------------------------------------------------------- /test_results/result_of_198.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_198.pkl -------------------------------------------------------------------------------- /test_results/result_of_2.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_2.pkl -------------------------------------------------------------------------------- /test_results/result_of_40.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_40.pkl -------------------------------------------------------------------------------- /test_results/result_of_41.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_41.pkl -------------------------------------------------------------------------------- /test_results/result_of_42.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_42.pkl -------------------------------------------------------------------------------- /test_results/result_of_43.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_43.pkl -------------------------------------------------------------------------------- /test_results/result_of_44.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_44.pkl -------------------------------------------------------------------------------- /test_results/result_of_5.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_5.pkl -------------------------------------------------------------------------------- /test_results/result_of_6.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_6.pkl -------------------------------------------------------------------------------- /test_results/result_of_7.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_results/result_of_7.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_0.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_0.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_1.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_1.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_10.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_10.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_100.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_100.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_101.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_101.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_102.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_102.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_103.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_103.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_104.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_104.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_105.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_105.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_106.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_106.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_107.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_107.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_108.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_108.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_109.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_109.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_11.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_11.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_110.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_110.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_111.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_111.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_112.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_112.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_113.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_113.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_114.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_114.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_115.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_115.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_116.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_116.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_117.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_117.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_118.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_118.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_119.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_119.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_12.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_12.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_120.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_120.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_121.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_121.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_122.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_122.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_123.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_123.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_124.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_124.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_125.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_125.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_126.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_126.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_127.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_127.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_128.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_128.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_129.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_129.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_130.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_130.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_131.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_131.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_132.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_132.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_133.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_133.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_134.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_134.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_135.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_135.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_136.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_136.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_137.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_137.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_138.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_138.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_139.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_139.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_140.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_140.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_141.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_141.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_142.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_142.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_144.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_144.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_145.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_145.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_146.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_146.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_148.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_148.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_149.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_149.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_15.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_15.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_150.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_150.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_152.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_152.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_153.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_153.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_154.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_154.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_156.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_156.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_157.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_157.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_158.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_158.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_16.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_16.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_160.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_160.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_161.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_161.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_162.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_162.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_164.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_164.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_165.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_165.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_166.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_166.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_168.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_168.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_169.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_169.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_17.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_17.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_170.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_170.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_172.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_172.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_173.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_173.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_174.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_174.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_176.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_176.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_177.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_177.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_178.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_178.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_180.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_180.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_181.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_181.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_182.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_182.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_184.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_184.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_185.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_185.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_186.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_186.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_187.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_187.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_188.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_188.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_189.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_189.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_190.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_190.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_192.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_192.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_193.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_193.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_194.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_194.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_196.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_196.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_197.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_197.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_198.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_198.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_2.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_2.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_40.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_40.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_41.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_41.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_42.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_42.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_43.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_43.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_44.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_44.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_5.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_5.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_6.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_6.pkl -------------------------------------------------------------------------------- /test_scenarios/scene_200_7.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samwu-learn/HGCN2SP/e123c9aa048c95e3184da58189ddc427ad8f6ad2/test_scenarios/scene_200_7.pkl -------------------------------------------------------------------------------- /trainer.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import torch 4 | import numpy as np 5 | import wandb 6 | import pickle 7 | import torch.nn as nn 8 | from agent import Agent 9 | from env import CFLPEnv 10 | from sample import Sampler 11 | from utils import solve_cflp_softmax 12 | 13 | class PPOTrainer: 14 | def __init__(self, args, policy_param, train_param, data, bs, clusters, run_name, device): 15 | self.args = args 16 | self.train_param = train_param 17 | self.run_name = run_name 18 | self.device = device 19 | self.envs = CFLPEnv(data, bs, clusters, train_param['sel_num'], args.num_envs, device=self.device) 20 | self.agent = Agent(policy_param, train_param, self.device).to(self.device) 21 | self.optimizer = torch.optim.Adam(self.agent.parameters(), lr=args.learning_rate, eps=1e-5) 22 | self.sampler = Sampler(self.envs, self.agent, args.num_steps, self.device) 23 | self.best_eval_delta = 100.0 24 | self.eval_epoch = 0 25 | self.use_wandb = args.track and hasattr(wandb, 'run') and wandb.run is not None 26 | 27 | def train(self): 28 | next_obs, _ = self.envs.reset(seed=self.args.seed) 29 | next_done = torch.zeros(self.envs.batch_size, device=self.device) 30 | 31 | for iteration in range(1, self.args.num_iterations + 1): 32 | if self.args.anneal_lr: 33 | self._anneal_learning_rate(iteration) 34 | 35 | # 数据采集 36 | next_obs, next_done = self.sampler.collect_trajectories(next_obs) 37 | 38 | # 计算优势与回报 39 | advantages, returns = self.sampler.compute_advantages_and_returns(self.args) 40 | 41 | # 获取批数据 42 | b_obs, b_actions, b_logprobs, b_advantages, b_returns, b_values = self.sampler.get_batch_data(advantages, returns) 43 | 44 | # 策略优化 45 | self._update_policy(b_obs, b_actions, b_logprobs, b_advantages, b_returns, b_values) 46 | 47 | # 评估与保存模型 48 | if iteration % self.train_param['eval_epoch'] == 0: 49 | self._evaluate_and_save(iteration) 50 | 51 | # 训练完成后保存模型 52 | if self.args.save_model: 53 | model_path = f"runs/{self.run_name}/{self.args.exp_name}.pt" 54 | # 提取文件夹路径 55 | folder_path = os.path.dirname(model_path) 56 | # 检查文件夹是否存在,如果不存在则创建 57 | if not os.path.exists(folder_path): 58 | os.makedirs(folder_path) 59 | torch.save(self.agent.state_dict(), model_path) 60 | print(f"model saved to {model_path}") 61 | self.envs.close() 62 | 63 | def _update_policy(self, b_obs, b_actions, b_logprobs, b_advantages, b_returns, b_values): 64 | # Optimizing the policy and value network 65 | b_inds = np.arange(self.args.batch_size) 66 | clipfracs = [] 67 | for epoch in range(self.args.update_epochs): 68 | np.random.shuffle(b_inds) 69 | for start in range(0, self.args.batch_size, self.args.minibatch_size): 70 | end = start + self.args.minibatch_size 71 | mb_inds = b_inds[start:end] 72 | 73 | b_obs_m = [b_obs[i] for i in mb_inds] 74 | 75 | _, newlogprob, entropy, newvalue = self.agent.get_action_and_value(b_obs_m, b_actions[mb_inds]) 76 | logratio = newlogprob - b_logprobs[mb_inds] 77 | ratio = logratio.exp() 78 | 79 | with torch.no_grad(): 80 | # calculate approx_kl http://joschu.net/blog/kl-approx.html 81 | old_approx_kl = (-logratio).mean() 82 | approx_kl = ((ratio - 1) - logratio).mean() 83 | clipfracs += [((ratio - 1.0).abs() > self.args.clip_coef).float().mean().item()] 84 | 85 | mb_advantages = b_advantages[mb_inds] 86 | if self.args.norm_adv: 87 | mb_advantages = (mb_advantages - mb_advantages.mean()) / (mb_advantages.std() + 1e-8) 88 | 89 | # Policy loss 90 | pg_loss1 = -mb_advantages * ratio 91 | pg_loss2 = -mb_advantages * torch.clamp(ratio, 1 - self.args.clip_coef, 1 + self.args.clip_coef) 92 | pg_loss = torch.max(pg_loss1, pg_loss2).mean() 93 | 94 | # Value loss 95 | newvalue = newvalue.view(-1) 96 | if self.args.clip_vloss: 97 | v_loss_unclipped = (newvalue - b_returns[mb_inds]) ** 2 98 | v_clipped = b_values[mb_inds] + torch.clamp( 99 | newvalue - b_values[mb_inds], 100 | -self.args.clip_coef, 101 | self.args.clip_coef, 102 | ) 103 | v_loss_clipped = (v_clipped - b_returns[mb_inds]) ** 2 104 | v_loss_max = torch.max(v_loss_unclipped, v_loss_clipped) 105 | v_loss = 0.5 * v_loss_max.mean() 106 | else: 107 | v_loss = 0.5 * ((newvalue - b_returns[mb_inds]) ** 2).mean() 108 | 109 | entropy_loss = entropy.mean() 110 | loss = pg_loss - self.args.ent_coef * entropy_loss + v_loss * self.args.vf_coef 111 | 112 | print("loss:", loss.item()) 113 | 114 | if self.use_wandb: 115 | wandb.log({'epoch': epoch, 'loss': loss.item()}) 116 | 117 | self.optimizer.zero_grad() 118 | loss.backward() 119 | nn.utils.clip_grad_norm_(self.agent.parameters(), self.args.max_grad_norm) 120 | self.optimizer.step() 121 | 122 | if self.args.target_kl is not None and approx_kl > self.args.target_kl: 123 | break 124 | 125 | def _anneal_learning_rate(self, iteration): 126 | frac = 1.0 - (iteration - 1.0) / self.args.num_iterations 127 | self.optimizer.param_groups[0]["lr"] = frac * self.args.learning_rate 128 | 129 | def eval_model(self, eval_cls_path, action, train_param): 130 | mean_bs = 0 131 | mean_agent = 0 132 | mean_time = 0 133 | delta = 0 134 | eval_num = min(100, len(eval_cls_path)) 135 | for i in range(eval_num): 136 | cls_loc = os.path.join(train_param["eval_cls_loc"], eval_cls_path[i]) 137 | with open(cls_loc, 'rb') as f: 138 | cls = pickle.load(f) 139 | file_path = f"result_of_{eval_cls_path[i][10:-4]}.pkl" 140 | file_path = os.path.join(train_param["eval_result"], file_path) 141 | with open(file_path, "rb") as f: 142 | results = pickle.load(f) 143 | bs = results['primal'] 144 | mean_bs += bs 145 | args = (cls, action[i].cpu(), True) 146 | eval_results = solve_cflp_softmax(args).squeeze() 147 | print(eval_results, bs, (eval_results[0].item() - bs)/ bs *100) 148 | mean_agent += eval_results[0].item() 149 | mean_time += eval_results[1].item() 150 | delta += ((eval_results[0].item() - bs)/ bs *100) 151 | 152 | mean_agent = mean_agent / eval_num 153 | mean_bs = mean_bs / eval_num 154 | mean_time = mean_time / eval_num 155 | delta /= eval_num 156 | if (delta) < self.best_eval_delta: 157 | print("Saving models...") 158 | self.best_eval_delta = (delta) 159 | model_path = f"./model_path/{self.run_name}_eval_{self.eval_epoch}_{round(self.best_eval_delta, 2)}.pt" 160 | torch.save(self.agent.state_dict(), model_path) 161 | self.eval_epoch += 1 162 | print(f"Eval Averge: agent:{mean_agent} bs:{mean_bs} time:{mean_time} delta:{delta}%") 163 | 164 | if self.use_wandb: 165 | wandb.log({"mean_agent": mean_agent, "Averge bs": mean_bs, "time": mean_time, "delta": delta}) 166 | 167 | def _evaluate_and_save(self, iteration): 168 | train_param = self.train_param 169 | # Evaluate 自行修改存储位置 170 | torch.save(self.agent.state_dict(), f"./model_path/{self.run_name}_seed_{self.args.seed}_{iteration}.pt") 171 | print("Eval...") 172 | eval_data = torch.load(os.path.join(train_param['eval_path'], train_param['eval_pt'])) 173 | for i in range(len(eval_data)): 174 | eval_data[i] = eval_data[i].to(self.device) 175 | with open(os.path.join(train_param['eval_path'], train_param['eval_cls']), 'rb') as f: 176 | eval_cls_path = pickle.load(f) 177 | with torch.no_grad(): 178 | action, _, _, _ = self.agent.get_action_and_value(eval_data, decode_type="greedy") 179 | self.eval_model(eval_cls_path, action, train_param) -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .solver_return_x import solve_cflp_scenarios, solve_cflp_softmax_new, solve_cflp_softmax -------------------------------------------------------------------------------- /utils/cflpdata.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import Dataset, DataLoader 2 | 3 | class CustomDataset(Dataset): 4 | def __init__(self, data_list): 5 | self.data_list = data_list 6 | 7 | def __len__(self): 8 | return len(self.data_list) 9 | 10 | def __getitem__(self, index): 11 | # 在这里实现你的数据加载逻辑,只返回数据 12 | sample = self.data_list[index] 13 | # 假设数据是一个元组 14 | return sample -------------------------------------------------------------------------------- /utils/processer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pickle as pkl 3 | import networkx as nx 4 | import scipy.sparse as sp 5 | from scipy.sparse.linalg import eigsh 6 | import sys 7 | import torch 8 | import torch.nn as nn 9 | 10 | def parse_skipgram(fname): 11 | with open(fname) as f: 12 | toks = list(f.read().split()) 13 | nb_nodes = int(toks[0]) 14 | nb_features = int(toks[1]) 15 | ret = np.empty((nb_nodes, nb_features)) 16 | it = 2 17 | for i in range(nb_nodes): 18 | cur_nd = int(toks[it]) - 1 19 | it += 1 20 | for j in range(nb_features): 21 | cur_ft = float(toks[it]) 22 | ret[cur_nd][j] = cur_ft 23 | it += 1 24 | return ret 25 | 26 | # Process a (subset of) a TU dataset into standard form 27 | def process_tu(data, nb_nodes): 28 | nb_graphs = len(data) 29 | ft_size = data.num_features 30 | 31 | features = np.zeros((nb_graphs, nb_nodes, ft_size)) 32 | adjacency = np.zeros((nb_graphs, nb_nodes, nb_nodes)) 33 | labels = np.zeros(nb_graphs) 34 | sizes = np.zeros(nb_graphs, dtype=np.int32) 35 | masks = np.zeros((nb_graphs, nb_nodes)) 36 | 37 | for g in range(nb_graphs): 38 | sizes[g] = data[g].x.shape[0] 39 | features[g, :sizes[g]] = data[g].x 40 | labels[g] = data[g].y[0] 41 | masks[g, :sizes[g]] = 1.0 42 | e_ind = data[g].edge_index 43 | coo = sp.coo_matrix((np.ones(e_ind.shape[1]), (e_ind[0, :], e_ind[1, :])), shape=(nb_nodes, nb_nodes)) 44 | adjacency[g] = coo.todense() 45 | 46 | return features, adjacency, labels, sizes, masks 47 | 48 | def micro_f1(logits, labels): 49 | # Compute predictions 50 | preds = torch.round(nn.Sigmoid()(logits)) 51 | 52 | # Cast to avoid trouble 53 | preds = preds.long() 54 | labels = labels.long() 55 | 56 | # Count true positives, true negatives, false positives, false negatives 57 | tp = torch.nonzero(preds * labels).shape[0] * 1.0 58 | tn = torch.nonzero((preds - 1) * (labels - 1)).shape[0] * 1.0 59 | fp = torch.nonzero(preds * (labels - 1)).shape[0] * 1.0 60 | fn = torch.nonzero((preds - 1) * labels).shape[0] * 1.0 61 | 62 | # Compute micro-f1 score 63 | prec = tp / (tp + fp) 64 | rec = tp / (tp + fn) 65 | f1 = (2 * prec * rec) / (prec + rec) 66 | return f1 67 | 68 | """ 69 | Prepare adjacency matrix by expanding up to a given neighbourhood. 70 | This will insert loops on every node. 71 | Finally, the matrix is converted to bias vectors. 72 | Expected shape: [graph, nodes, nodes] 73 | """ 74 | def adj_to_bias(adj, sizes, nhood=1): 75 | nb_graphs = adj.shape[0] 76 | mt = np.empty(adj.shape) 77 | for g in range(nb_graphs): 78 | mt[g] = np.eye(adj.shape[1]) 79 | for _ in range(nhood): 80 | mt[g] = np.matmul(mt[g], (adj[g] + np.eye(adj.shape[1]))) 81 | for i in range(sizes[g]): 82 | for j in range(sizes[g]): 83 | if mt[g][i][j] > 0.0: 84 | mt[g][i][j] = 1.0 85 | return -1e9 * (1.0 - mt) 86 | 87 | 88 | ############################################### 89 | # This section of code adapted from tkipf/gcn # 90 | ############################################### 91 | 92 | def parse_index_file(filename): 93 | """Parse index file.""" 94 | index = [] 95 | for line in open(filename): 96 | index.append(int(line.strip())) 97 | return index 98 | 99 | def sample_mask(idx, l): 100 | """Create mask.""" 101 | mask = np.zeros(l) 102 | mask[idx] = 1 103 | return np.array(mask, dtype=np.bool) 104 | 105 | def load_data(dataset_str): # {'pubmed', 'citeseer', 'cora'} 106 | """Load data.""" 107 | names = ['x', 'y', 'tx', 'ty', 'allx', 'ally', 'graph'] 108 | objects = [] 109 | for i in range(len(names)): 110 | with open("data/ind.{}.{}".format(dataset_str, names[i]), 'rb') as f: 111 | if sys.version_info > (3, 0): 112 | objects.append(pkl.load(f, encoding='latin1')) 113 | else: 114 | objects.append(pkl.load(f)) 115 | 116 | x, y, tx, ty, allx, ally, graph = tuple(objects) 117 | test_idx_reorder = parse_index_file("data/ind.{}.test.index".format(dataset_str)) #得到测试集的索引分布 118 | test_idx_range = np.sort(test_idx_reorder) 119 | 120 | if dataset_str == 'citeseer': 121 | # Fix citeseer dataset (there are some isolated nodes in the graph) 122 | # Find isolated nodes, add them as zero-vecs into the right position 123 | test_idx_range_full = range(min(test_idx_reorder), max(test_idx_reorder)+1) 124 | tx_extended = sp.lil_matrix((len(test_idx_range_full), x.shape[1])) 125 | tx_extended[test_idx_range-min(test_idx_range), :] = tx 126 | tx = tx_extended 127 | ty_extended = np.zeros((len(test_idx_range_full), y.shape[1])) 128 | ty_extended[test_idx_range-min(test_idx_range), :] = ty 129 | ty = ty_extended 130 | 131 | features = sp.vstack((allx, tx)).tolil() #堆叠allx和tx,所有节点特征 132 | features[test_idx_reorder, :] = features[test_idx_range, :] 133 | adj = nx.adjacency_matrix(nx.from_dict_of_lists(graph)) #处理得到邻接矩阵 134 | 135 | labels = np.vstack((ally, ty)) 136 | labels[test_idx_reorder, :] = labels[test_idx_range, :] #处理标签 类同与节点特征的处理 137 | 138 | idx_test = test_idx_range.tolist() 139 | idx_train = range(len(y)) 140 | idx_val = range(len(y), len(y)+500) 141 | 142 | return adj, features, labels, idx_train, idx_val, idx_test 143 | 144 | def sparse_to_tuple(sparse_mx, insert_batch=False): 145 | """Convert sparse matrix to tuple representation.""" 146 | """Set insert_batch=True if you want to insert a batch dimension.""" 147 | def to_tuple(mx): 148 | if not sp.isspmatrix_coo(mx): 149 | mx = mx.tocoo() 150 | if insert_batch: 151 | coords = np.vstack((np.zeros(mx.row.shape[0]), mx.row, mx.col)).transpose() 152 | values = mx.data 153 | shape = (1,) + mx.shape 154 | else: 155 | coords = np.vstack((mx.row, mx.col)).transpose() 156 | values = mx.data 157 | shape = mx.shape 158 | return coords, values, shape 159 | 160 | if isinstance(sparse_mx, list): 161 | for i in range(len(sparse_mx)): 162 | sparse_mx[i] = to_tuple(sparse_mx[i]) 163 | else: 164 | sparse_mx = to_tuple(sparse_mx) 165 | 166 | return sparse_mx 167 | 168 | def standardize_data(f, train_mask): 169 | """Standardize feature matrix and convert to tuple representation""" 170 | # standardize data 171 | f = f.todense() 172 | mu = f[train_mask == True, :].mean(axis=0) 173 | sigma = f[train_mask == True, :].std(axis=0) 174 | f = f[:, np.squeeze(np.array(sigma > 0))] 175 | mu = f[train_mask == True, :].mean(axis=0) 176 | sigma = f[train_mask == True, :].std(axis=0) 177 | f = (f - mu) / sigma 178 | return f 179 | 180 | def preprocess_features(features): 181 | """Row-normalize feature matrix and convert to tuple representation""" 182 | rowsum = np.array(features.sum(1)) 183 | r_inv = np.power(rowsum, -1).flatten() 184 | r_inv[np.isinf(r_inv)] = 0. 185 | r_mat_inv = sp.diags(r_inv) 186 | features = r_mat_inv.dot(features) 187 | return features.todense(), sparse_to_tuple(features) 188 | 189 | def normalize_adj(adj): 190 | """Symmetrically normalize adjacency matrix.""" 191 | adj = sp.coo_matrix(adj) 192 | rowsum = np.abs(np.array(adj.sum(1))) #绝对值,以免负数报错 193 | rowsum[rowsum == 0] = 1 194 | d_inv_sqrt = np.power(rowsum, -0.5).flatten() 195 | d_inv_sqrt[np.isinf(d_inv_sqrt)] = 0. 196 | d_mat_inv_sqrt = sp.diags(d_inv_sqrt) 197 | return adj.dot(d_mat_inv_sqrt).transpose().dot(d_mat_inv_sqrt).tocoo() 198 | 199 | 200 | def preprocess_adj(adj): 201 | """Preprocessing of adjacency matrix for simple GCN model and conversion to tuple representation.""" 202 | adj_normalized = normalize_adj(adj + sp.eye(adj.shape[0])) 203 | return sparse_to_tuple(adj_normalized) 204 | 205 | def sparse_mx_to_torch_sparse_tensor(sparse_mx): 206 | """Convert a scipy sparse matrix to a torch sparse tensor.""" 207 | sparse_mx = sparse_mx.tocoo().astype(np.float32) 208 | indices = torch.from_numpy( 209 | np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)) 210 | values = torch.from_numpy(sparse_mx.data) 211 | shape = torch.Size(sparse_mx.shape) 212 | return torch.sparse.FloatTensor(indices, values, shape) 213 | -------------------------------------------------------------------------------- /utils/solver_return_x.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | from multiprocessing import Manager, Pool 3 | 4 | from gurobipy import GRB 5 | import gurobipy as gp 6 | import numpy as np 7 | import torch 8 | 9 | def solve_cflp_scenarios(cluster, scenarios = None, weights = None, first_precision = None, flag=False, mip_gap=0, large = False): 10 | 11 | constraint = cluster['first_stage']['constraint'] 12 | M = cluster['second_stage']['M'] 13 | model = gp.Model() 14 | var_dict = {} 15 | 16 | n_facilities = cluster['n_facilities'] 17 | n_customers = cluster['n_customers'] 18 | if scenarios is not None: 19 | index = scenarios 20 | else: 21 | index = list(range(cluster['n_scenarios'])) 22 | if weights is None: 23 | prob = 1.0 / len(index) 24 | weights = [prob for i in range(len(index))] 25 | 26 | # 目标函数 27 | # 每个设施的二进制变量 第一阶段 28 | for i in range(n_facilities): 29 | var_name = f"x_{i}" 30 | if first_precision is None: 31 | var_dict[var_name] = model.addVar( 32 | lb=0.0, 33 | ub=1.0, 34 | obj=cluster["first_stage"]["facilities_cost"][i], 35 | vtype="B", 36 | name=var_name, 37 | ) 38 | else : 39 | var_dict[var_name] = model.addVar( #固定第一阶段决策变量 40 | lb=first_precision[f"x_{i}"], 41 | ub=first_precision[f"x_{i}"], 42 | obj=cluster["first_stage"]["facilities_cost"][i], 43 | vtype="B", 44 | name=var_name, 45 | ) 46 | #第一阶段约束 设施数不大于v 47 | cons = 0 48 | for i in range(n_facilities): 49 | cons += var_dict[f"x_{i}"] 50 | model.addConstr(cons<=constraint, name = f"v") 51 | 52 | loc = 0 53 | for s in index: 54 | # 第二阶段 55 | for i in range(n_customers): 56 | for j in range(n_facilities): 57 | var_name = f"y_{i}_{j}_{s}" 58 | var_dict[var_name] = model.addVar( 59 | lb=0.0, 60 | ub=1.0, 61 | obj=weights[loc] * cluster["second_stage"]["trans_cost"][i][j], 62 | vtype="B", 63 | name=var_name, 64 | ) 65 | for j in range(n_facilities): 66 | var_name = f"z_{j}_{s}" 67 | var_dict[var_name] = model.addVar( 68 | lb=0.0, 69 | obj=weights[loc] * cluster["second_stage"]["recourse_costs"], 70 | vtype="C", 71 | name=var_name, 72 | ) 73 | loc = loc + 1 74 | 75 | # 约束条件 76 | #约束1 77 | for j in range(n_facilities): 78 | cons = (-1.0)*cluster['second_stage']["qx"][j] * var_dict[f"x_{j}"] - var_dict[f"z_{j}_{s}"]*cluster['second_stage']['z_coeff'] 79 | for i in range(n_customers): 80 | cons+= cluster['second_stage']["q_c_f"][s][i][j]*var_dict[f"y_{i}_{j}_{s}"] 81 | model.addConstr(cons<=0, name = f"c_{j}_{s}") 82 | #约束2 83 | for j in range(n_facilities): 84 | cons = var_dict[f"z_{j}_{s}"] - cluster['second_stage']['M'] * var_dict[f"x_{j}"] 85 | model.addConstr(cons<=0, name = f"d_{j}_{s}") 86 | #约束3 87 | for i in range(n_customers): 88 | cons = (-1)*cluster['second_stage']["h"][s][i] 89 | for j in range(n_facilities): 90 | cons+=var_dict[f"y_{i}_{j}_{s}"] 91 | model.addConstr(cons==0, name = f"t_{i}_{s}") 92 | 93 | model.update() 94 | 95 | #set param 96 | if flag == True: 97 | model.setParam('outputFlag',1) 98 | else: 99 | model.setParam('OutputFlag', 0) 100 | 101 | if large: 102 | model.setParam("MIPGap", 0.05) 103 | else: 104 | model.setParam("MIPGap", mip_gap) 105 | model.setParam("TimeLimit", 10800) 106 | # 设置线程数 107 | model.setParam('Threads', 16) 108 | 109 | model.optimize() 110 | 111 | solving_results = {} 112 | 113 | if model.status == GRB.OPTIMAL: 114 | # 获取第一阶段变量的取值 115 | if first_precision == None: 116 | variable_values = {var.varName: var.x for var in model.getVars() if 'x' in var.varName} 117 | else : 118 | variable_values = first_precision 119 | solving_results["primal"] = model.objVal 120 | solving_results["time"] = model.Runtime 121 | solving_results['X'] = variable_values 122 | 123 | elif model.status == GRB.INFEASIBLE or model.status == GRB.UNBOUNDED: 124 | solving_results["primal"] = 1 125 | solving_results["time"] = 100 126 | solving_results['X'] = first_precision 127 | 128 | else : 129 | if first_precision == None: 130 | variable_values = {var.varName: var.x for var in model.getVars() if 'x' in var.varName} 131 | else : 132 | variable_values = first_precision 133 | solving_results["primal"] = model.objVal 134 | solving_results["time"] = model.Runtime 135 | solving_results['X'] = variable_values 136 | 137 | return solving_results 138 | 139 | def solve_cflp_softmax(args): 140 | """ 141 | args: (dict, list, bool) 142 | """ 143 | 144 | cluster_dict, index, is_train = args 145 | """Formulates two stage extensive form and solves""" 146 | if is_train: 147 | index = torch.squeeze(index).numpy() 148 | 149 | train_results = solve_cflp_scenarios(cluster_dict, index) 150 | train_results = solve_cflp_scenarios(cluster_dict, first_precision=train_results['X']) 151 | results = [train_results['primal'], train_results['time']] 152 | results = torch.tensor(results).unsqueeze(0) 153 | return results 154 | n_customers = cluster_dict["n_customers"] 155 | n_facilities = cluster_dict["n_facilities"] 156 | 157 | n_scenarios = index 158 | 159 | prob = 1.0/len(n_scenarios) 160 | model = gp.Model() 161 | var_dict = {} 162 | 163 | # 目标函数 164 | # 每个设施的二进制变量 第一阶段 165 | for i in range(n_facilities): 166 | var_name = f"x_{i}" 167 | var_dict[var_name] = model.addVar( 168 | lb=0.0, 169 | ub=1.0, 170 | obj=cluster_dict["first_stage"]["facilities_cost"][i], 171 | vtype="B", 172 | name=var_name, 173 | ) 174 | #第一阶段约束 设施数不大于v 175 | cons = 0 176 | for i in range(n_facilities): 177 | cons += var_dict[f"x_{i}"] 178 | model.addConstr(cons<=cluster_dict['first_stage']['constraint'], name = f"v") 179 | 180 | for s in n_scenarios: 181 | # 第二阶段 182 | for i in range(n_customers): 183 | for j in range(n_facilities): 184 | var_name = f"y_{i}_{j}_{s}" 185 | var_dict[var_name] = model.addVar( 186 | lb=0.0, 187 | ub=1.0, 188 | obj=prob * cluster_dict["second_stage"]["trans_cost"][i][j], 189 | vtype="B", 190 | name=var_name, 191 | ) 192 | for j in range(n_facilities): 193 | var_name = f"z_{j}_{s}" 194 | var_dict[var_name] = model.addVar( 195 | lb=0.0, 196 | obj=prob * cluster_dict["second_stage"]["recourse_costs"], 197 | vtype="C", 198 | name=var_name, 199 | ) 200 | 201 | # 约束条件 202 | #约束1 203 | for j in range(n_facilities): 204 | cons = (-1.0)*cluster_dict['second_stage']["qx"][j] * var_dict[f"x_{j}"] - var_dict[f"z_{j}_{s}"]*cluster_dict['second_stage']['z_coeff'] 205 | for i in range(n_customers): 206 | cons+= cluster_dict['second_stage']["q_c_f"][s][i][j]*var_dict[f"y_{i}_{j}_{s}"] 207 | model.addConstr(cons<=0, name = f"c_{j}_{s}") 208 | #约束2 209 | for j in range(n_facilities): 210 | cons = var_dict[f"z_{j}_{s}"] - cluster_dict['second_stage']['M'] * var_dict[f"x_{j}"] 211 | model.addConstr(cons<=0, name = f"d_{j}_{s}") 212 | #约束3 213 | for i in range(n_customers): 214 | cons = (-1)*cluster_dict['second_stage']["h"][s][i] 215 | for j in range(n_facilities): 216 | cons+=var_dict[f"y_{i}_{j}_{s}"] 217 | model.addConstr(cons==0, name = f"t_{i}_{s}") 218 | 219 | model.update() 220 | 221 | model.setParam('OutputFlag', 0) 222 | model.setParam("MIPGap", 0.001) 223 | model.setParam("TimeLimit", 600) 224 | 225 | # 设置线程数 226 | model.setParam('Threads', 16) 227 | 228 | model.optimize() 229 | 230 | solving_results = {} 231 | 232 | solving_results["primal"] = model.objVal 233 | solving_results["time"] = model.Runtime 234 | 235 | return solving_results 236 | 237 | def solve_cflp_softmax_new(args): 238 | """ 239 | args: (dict, list, bool) 240 | """ 241 | if len(args) ==3: 242 | cluster_dict, index, is_train = args 243 | is_large = False 244 | else: 245 | cluster_dict, index, is_train, is_large = args 246 | """Formulates two stage extensive form and solves""" 247 | if is_train: 248 | index = torch.squeeze(index).numpy() 249 | #print("index:",index) 250 | if len(index) < 20 : 251 | mip_gap = 0 252 | else: 253 | mip_gap = 0.005 254 | train_results = solve_cflp_scenarios(cluster_dict, index, flag=False, mip_gap=mip_gap,large=is_large) 255 | x = [] 256 | X = train_results['X'] 257 | for key in X.keys(): 258 | x.append(X[key]) 259 | x.append(train_results['time']) 260 | train_results = solve_cflp_scenarios(cluster_dict, first_precision=train_results['X']) 261 | x.append(train_results['primal']) 262 | results = torch.tensor(x) 263 | return results 264 | n_customers = cluster_dict["n_customers"] 265 | n_facilities = cluster_dict["n_facilities"] 266 | 267 | n_scenarios = index 268 | 269 | prob = 1.0/len(n_scenarios) 270 | model = gp.Model() 271 | var_dict = {} 272 | 273 | # 目标函数 274 | # 每个设施的二进制变量 第一阶段 275 | for i in range(n_facilities): 276 | var_name = f"x_{i}" 277 | var_dict[var_name] = model.addVar( 278 | lb=0.0, 279 | ub=1.0, 280 | obj=cluster_dict["first_stage"]["facilities_cost"][i], 281 | vtype="B", 282 | name=var_name, 283 | ) 284 | #第一阶段约束 设施数不大于v 285 | cons = 0 286 | for i in range(n_facilities): 287 | cons += var_dict[f"x_{i}"] 288 | model.addConstr(cons<=cluster_dict['first_stage']['constraint'], name = f"v") 289 | 290 | for s in n_scenarios: 291 | # 第二阶段 292 | for i in range(n_customers): 293 | for j in range(n_facilities): 294 | var_name = f"y_{i}_{j}_{s}" 295 | var_dict[var_name] = model.addVar( 296 | lb=0.0, 297 | ub=1.0, 298 | obj=prob * cluster_dict["second_stage"]["trans_cost"][i][j], 299 | vtype="B", 300 | name=var_name, 301 | ) 302 | for j in range(n_facilities): 303 | var_name = f"z_{j}_{s}" 304 | var_dict[var_name] = model.addVar( 305 | lb=0.0, 306 | obj=prob * cluster_dict["second_stage"]["recourse_costs"], 307 | vtype="C", 308 | name=var_name, 309 | ) 310 | 311 | # 约束条件 312 | #约束1 313 | for j in range(n_facilities): 314 | cons = (-1.0)*cluster_dict['second_stage']["qx"][j] * var_dict[f"x_{j}"] - var_dict[f"z_{j}_{s}"]*cluster_dict['second_stage']['z_coeff'] 315 | for i in range(n_customers): 316 | cons+= cluster_dict['second_stage']["q_c_f"][s][i][j]*var_dict[f"y_{i}_{j}_{s}"] 317 | model.addConstr(cons<=0, name = f"c_{j}_{s}") 318 | #约束2 319 | for j in range(n_facilities): 320 | cons = var_dict[f"z_{j}_{s}"] - cluster_dict['second_stage']['M'] * var_dict[f"x_{j}"] 321 | model.addConstr(cons<=0, name = f"d_{j}_{s}") 322 | #约束3 323 | for i in range(n_customers): 324 | cons = (-1)*cluster_dict['second_stage']["h"][s][i] 325 | for j in range(n_facilities): 326 | cons+=var_dict[f"y_{i}_{j}_{s}"] 327 | model.addConstr(cons==0, name = f"t_{i}_{s}") 328 | 329 | model.update() 330 | 331 | model.setParam('OutputFlag', 0) 332 | model.setParam("MIPGap", 0.001) 333 | model.setParam("TimeLimit", 600) 334 | 335 | # 设置线程数 336 | model.setParam('Threads', 4) 337 | 338 | model.optimize() 339 | 340 | solving_results = {} 341 | 342 | solving_results["primal"] = model.objVal 343 | solving_results["time"] = model.Runtime 344 | 345 | return solving_results 346 | 347 | 348 | --------------------------------------------------------------------------------