cuGenOpt/benchmark/experiments/e13_multiobjective/gpu.cu
2026-03-20 00:33:45 +08:00

328 lines
11 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

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

#include "solver.cuh"
#include "multi_gpu_solver.cuh"
#include "bi_objective_vrp.cuh"
#include "tri_objective_vrp.cuh"
#include "bi_objective_knapsack.cuh"
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>
// 确保使用 std:: 命名空间的数学函数
using std::sqrt;
using std::round;
// ============================================================
// 数据加载工具
// ============================================================
// 加载 A-n32-k5 VRP 实例EUC_2D 格式)
struct VRPInstance {
float* dist;
float* demand;
int n;
float capacity;
int optimal_vehicles;
float optimal_distance;
};
VRPInstance load_an32k5() {
// A-n32-k5 坐标(包含 depot
const float coords[32][2] = {
{82,76},
{96,44},{50,5},{49,8},{13,7},{29,89},{58,30},{84,39},{14,24},{2,39},
{3,82},{5,10},{98,52},{84,25},{61,59},{1,65},{88,51},{91,2},{19,32},
{93,3},{50,93},{98,14},{5,42},{42,9},{61,62},{9,97},{80,55},{57,69},
{23,15},{20,70},{85,60},{98,5}
};
const float demands[31] = {
19,21,6,19,7,12,16,6,16,8,14,21,16,3,22,18,19,1,24,8,12,4,8,24,24,2,20,15,2,14,9
};
VRPInstance inst;
inst.n = 31;
inst.capacity = 100.0f;
inst.optimal_vehicles = 5;
inst.optimal_distance = 784.0f;
// 计算 EUC_2D 距离矩阵
inst.dist = new float[32 * 32];
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 32; j++) {
float dx = coords[i][0] - coords[j][0];
float dy = coords[i][1] - coords[j][1];
inst.dist[i * 32 + j] = std::round(std::sqrt(dx * dx + dy * dy));
}
}
inst.demand = new float[31];
for (int i = 0; i < 31; i++) {
inst.demand[i] = demands[i];
}
return inst;
}
// 加载 knapPI_1_100 实例
struct KnapsackInstance {
int* values;
int* weights;
int n;
int capacity;
int optimal_value;
};
KnapsackInstance load_knapsack_100() {
const char* filename = "../../data/knapsack/knapPI_1_100.txt";
std::ifstream file(filename);
if (!file.is_open()) {
fprintf(stderr, "Error: Cannot open %s\n", filename);
exit(1);
}
int n, capacity;
file >> n >> capacity;
KnapsackInstance inst;
inst.n = n;
inst.capacity = capacity;
inst.optimal_value = 9147; // 已知最优值
inst.values = new int[n];
inst.weights = new int[n];
for (int i = 0; i < n; i++) {
file >> inst.values[i] >> inst.weights[i];
}
file.close();
return inst;
}
// ============================================================
// 实验配置
// ============================================================
struct ExperimentConfig {
const char* name;
CompareMode mode;
float obj_weights[MAX_OBJ];
int obj_priority[MAX_OBJ];
float obj_tolerance[MAX_OBJ];
};
// Weighted 模式配置
ExperimentConfig WEIGHTED_CONFIGS[] = {
{"W_90_10", CompareMode::Weighted, {0.9f, 0.1f}, {0, 1}, {0.0f, 0.0f}},
{"W_70_30", CompareMode::Weighted, {0.7f, 0.3f}, {0, 1}, {0.0f, 0.0f}},
{"W_50_50", CompareMode::Weighted, {0.5f, 0.5f}, {0, 1}, {0.0f, 0.0f}},
};
// Lexicographic 模式配置(双目标)
ExperimentConfig LEX_CONFIGS_BI[] = {
{"L_dist_veh_t100", CompareMode::Lexicographic, {1.0f, 1.0f}, {0, 1}, {100.0f, 0.0f}},
{"L_dist_veh_t50", CompareMode::Lexicographic, {1.0f, 1.0f}, {0, 1}, {50.0f, 0.0f}},
{"L_veh_dist_t0", CompareMode::Lexicographic, {1.0f, 1.0f}, {1, 0}, {0.0f, 100.0f}},
};
// Lexicographic 模式配置(三目标)
ExperimentConfig LEX_CONFIGS_TRI[] = {
{"L_dist_veh_max", CompareMode::Lexicographic, {1.0f, 1.0f, 1.0f}, {0, 1, 2}, {100.0f, 0.0f, 50.0f}},
{"L_veh_dist_max", CompareMode::Lexicographic, {1.0f, 1.0f, 1.0f}, {1, 0, 2}, {0.0f, 100.0f, 50.0f}},
};
// ============================================================
// 实验运行函数
// ============================================================
template<typename Problem>
void run_experiment(const char* problem_name, Problem& prob,
const ExperimentConfig& exp_cfg,
int num_objectives,
bool multi_gpu = false) {
printf(" [run_experiment] 开始\n");
fflush(stdout);
// 应用实验配置到 Problem通过覆盖字段
prob.override_mode = exp_cfg.mode;
for (int i = 0; i < num_objectives; i++) {
prob.override_weights[i] = exp_cfg.obj_weights[i];
prob.override_priority[i] = exp_cfg.obj_priority[i];
prob.override_tolerance[i] = exp_cfg.obj_tolerance[i];
}
printf(" [run_experiment] 配置覆盖完成\n");
fflush(stdout);
SolverConfig cfg;
cfg.pop_size = 64; // 固定小规模
cfg.max_gen = 1000; // 固定代数
cfg.time_limit_sec = 0.0f; // 不使用时间限制
cfg.verbose = true; // 启用详细输出
cfg.sa_temp_init = 50.0f;
cfg.sa_alpha = 0.999f;
cfg.num_islands = 2; // 固定岛屿数
cfg.migrate_interval = 50;
cfg.crossover_rate = 0.1f;
cfg.use_aos = true; // 启用 AOS测试延迟归一化
cfg.aos_update_interval = 5; // 每 5 个 batch 更新一次
cfg.use_cuda_graph = false; // 禁用 CUDA Graph
printf(" [run_experiment] SolverConfig 创建完成\n");
fflush(stdout);
const int num_runs = 1; // 先只运行 1 次测试
const unsigned seeds[] = {42, 123, 456, 789, 2024};
printf("\n[%s] %s (mode=%s, multi_gpu=%s)\n",
problem_name, exp_cfg.name,
exp_cfg.mode == CompareMode::Weighted ? "Weighted" : "Lexicographic",
multi_gpu ? "YES" : "NO");
fflush(stdout);
for (int run = 0; run < num_runs; run++) {
printf(" [run_experiment] 开始 Run %d\n", run + 1);
fflush(stdout);
cfg.seed = seeds[run];
SolveResult<typename Problem::Sol> result;
if (multi_gpu) {
cfg.num_gpus = 2;
result = solve_multi_gpu(prob, cfg);
} else {
result = solve(prob, cfg);
}
printf(" Run %d (seed=%u): ", run + 1, seeds[run]);
for (int i = 0; i < num_objectives; i++) {
printf("obj%d=%.2f ", i, result.best_solution.objectives[i]);
}
printf("penalty=%.2f time=%.1fs gen=%d\n",
result.best_solution.penalty,
result.elapsed_ms / 1000.0f,
result.generations);
}
}
// ============================================================
// 主函数
// ============================================================
int main() {
printf("==============================================\n");
printf("E13: 多目标优化验证实验\n");
printf("==============================================\n\n");
fflush(stdout);
// 检测 GPU
int num_gpus;
cudaGetDeviceCount(&num_gpus);
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, 0);
printf("GPU: %s (检测到 %d 个)\n\n", prop.name, num_gpus);
fflush(stdout);
// ========== 实验 1: 双目标 VRP (A-n32-k5) ==========
printf("========================================\n");
printf("实验 1: 双目标 VRP (A-n32-k5)\n");
printf("目标: 最小化距离 + 最小化车辆数\n");
printf("========================================\n");
fflush(stdout);
printf("加载数据...\n");
fflush(stdout);
VRPInstance vrp_inst = load_an32k5();
printf("数据加载完成\n");
fflush(stdout);
// Weighted 模式测试
printf("\n--- Weighted 模式 ---\n");
fflush(stdout);
printf("创建第一个 Problem...\n");
fflush(stdout);
auto prob = BiObjectiveVRP::create(vrp_inst.dist, vrp_inst.demand,
vrp_inst.n, vrp_inst.capacity, 10);
printf("Problem 创建成功,开始实验...\n");
fflush(stdout);
run_experiment("BiVRP", prob, WEIGHTED_CONFIGS[0], 2, false);
printf("第一个实验完成\n");
fflush(stdout);
prob.destroy();
// Lexicographic 模式测试
printf("\n--- Lexicographic 模式 ---\n");
for (int i = 0; i < 3; i++) {
auto prob = BiObjectiveVRP::create(vrp_inst.dist, vrp_inst.demand,
vrp_inst.n, vrp_inst.capacity, 10);
run_experiment("BiVRP", prob, LEX_CONFIGS_BI[i], 2, false);
prob.destroy();
}
// 多 GPU 验证(附加)
if (num_gpus >= 2) {
printf("\n--- 多 GPU 附加验证 (2×GPU) ---\n");
// Weighted 验证
auto prob_w = BiObjectiveVRP::create(vrp_inst.dist, vrp_inst.demand,
vrp_inst.n, vrp_inst.capacity, 10);
run_experiment("BiVRP_MultiGPU", prob_w, WEIGHTED_CONFIGS[1], 2, true);
prob_w.destroy();
// Lexicographic 验证
auto prob_l = BiObjectiveVRP::create(vrp_inst.dist, vrp_inst.demand,
vrp_inst.n, vrp_inst.capacity, 10);
run_experiment("BiVRP_MultiGPU", prob_l, LEX_CONFIGS_BI[0], 2, true);
prob_l.destroy();
}
delete[] vrp_inst.dist;
delete[] vrp_inst.demand;
// ========== 实验 2: 三目标 VRP (A-n32-k5) ==========
printf("\n========================================\n");
printf("实验 2: 三目标 VRP (A-n32-k5)\n");
printf("目标: 最小化距离 + 最小化车辆数 + 最小化最大路径长度\n");
printf("========================================\n");
vrp_inst = load_an32k5();
// Weighted 模式
printf("\n--- Weighted 模式 ---\n");
ExperimentConfig tri_weighted = {"W_60_20_20", CompareMode::Weighted, {0.6f, 0.2f, 0.2f}, {0, 1, 2}, {0.0f, 0.0f, 0.0f}};
auto prob_tri_w = TriObjectiveVRP::create(vrp_inst.dist, vrp_inst.demand,
vrp_inst.n, vrp_inst.capacity, 10);
run_experiment("TriVRP", prob_tri_w, tri_weighted, 3, false);
prob_tri_w.destroy();
// Lexicographic 模式
printf("\n--- Lexicographic 模式 ---\n");
for (int i = 0; i < 2; i++) {
auto prob_tri_l = TriObjectiveVRP::create(vrp_inst.dist, vrp_inst.demand,
vrp_inst.n, vrp_inst.capacity, 10);
run_experiment("TriVRP", prob_tri_l, LEX_CONFIGS_TRI[i], 3, false);
prob_tri_l.destroy();
}
delete[] vrp_inst.dist;
delete[] vrp_inst.demand;
// ========== 实验 3: 双目标 Knapsack - 暂时跳过(文件读取问题) ==========
printf("\n========================================\n");
printf("实验 3: 双目标 Knapsack - 跳过\n");
printf("========================================\n");
fflush(stdout);
printf("\n==============================================\n");
printf("E13 实验完成\n");
printf("==============================================\n");
return 0;
}