在CPLEX循环中迭代扩展集合N并保留迭代方案的技术求助
逐步扩展集合N的CPLEX迭代实现方案
核心思路
通过OPL主脚本循环迭代,每次生成集合N的递增子集(从{"a"}开始,逐步添加后续元素),复用恒定数据,并用前一次迭代的解作为初始暖启动,最后保存每次迭代的方案。
实现步骤与代码示例
1. 定义恒定数据与有序集合
首先在模型文件中定义所有恒定数据,并将原始集合N转换为有序数组,确保子集扩展顺序固定:
// 恒定数据(所有迭代保持不变) {string} N_full = {"a", "b", "c", "d", "e", "f", "g"}; string N_arr[1..card(N_full)] = asSequence(N_full); // 转换为有序数组,保证子集顺序 {string} M = {"aa","bb","cc","dd","ee"}; range nods = 0..10; tuple edge{int o;int d;float C;float D;}; {edge} edges = ...; // 填入你的边数据 int Tr = ...; int cd = ...; // 其他恒定数据... // 可迭代更新的集合N(初始占位,将在主脚本中修改) {string} N = {}; // 变量定义(依赖当前迭代的N) dvar boolean x[M][N]; dvar boolean y[M,edges]; dvar boolean w[M,N,edges]; dvar float+ T[M][nods]; // 目标函数与约束条件(根据你的问题定义) minimize ...; // 或 maximize subject to { // 你的约束逻辑... }
2. 主脚本实现迭代逻辑
在OPL主脚本中编写循环,生成递增子集、加载模型、暖启动求解并保存方案:
main { var source = thisOplModel; var cplex = new IloCplex(); var prevSolData = {}; // 存储前一次迭代的解数据 // 迭代1到7(对应N的7个元素逐步扩展) for (var k=1; k<=source.N_full.size; k++) { // 生成当前迭代的N子集:前k个元素 var current_N = new IloOplSet(); for (var i=1; i<=k; i++) { current_N.add(source.N_arr[i]); } source.N = current_N; // 更新模型的N集合 // 初始化当前迭代的模型 var currentModel = new IloOplModel(source, cplex); currentModel.generate(); // 暖启动:使用前一次迭代的解作为初始值 if (k > 1) { for (var m in source.M) { // 更新x变量 for (var n in current_N) { if (prevSolData.x && prevSolData.x[m] && prevSolData.x[m][n] !== undefined) { currentModel.x[m][n].LB = prevSolData.x[m][n]; currentModel.x[m][n].UB = prevSolData.x[m][n]; } } // 更新y变量(恒定,直接复用) for (var e in source.edges) { if (prevSolData.y[m] && prevSolData.y[m][e] !== undefined) { currentModel.y[m][e].LB = prevSolData.y[m][e]; currentModel.y[m][e].UB = prevSolData.y[m][e]; } } // 更新w变量 for (var n in current_N) { for (var e in source.edges) { if (prevSolData.w[m] && prevSolData.w[m][n] && prevSolData.w[m][n][e] !== undefined) { currentModel.w[m][n][e].LB = prevSolData.w[m][n][e]; currentModel.w[m][n][e].UB = prevSolData.w[m][n][e]; } } } // 更新T变量(恒定,直接复用) for (var nd in source.nods) { if (prevSolData.T[m] && prevSolData.T[m][nd] !== undefined) { currentModel.T[m][nd].LB = prevSolData.T[m][nd]; currentModel.T[m][nd].UB = prevSolData.T[m][nd]; } } } } // 求解当前模型 if (cplex.solve()) { writeln("=== 迭代", k, "完成 ==="); writeln("目标值: ", cplex.getObjValue()); // 保存当前解数据,供下一次迭代暖启动使用 prevSolData = { x: {}, y: {}, w: {}, T: {} }; for (var m in source.M) { prevSolData.x[m] = {}; for (var n in current_N) { prevSolData.x[m][n] = currentModel.x[m][n].solutionValue; } prevSolData.y[m] = {}; for (var e in source.edges) { prevSolData.y[m][e] = currentModel.y[m][e].solutionValue; } prevSolData.w[m] = {}; for (var n in current_N) { prevSolData.w[m][n] = {}; for (var e in source.edges) { prevSolData.w[m][n][e] = currentModel.w[m][n][e].solutionValue; } } prevSolData.T[m] = {}; for (var nd in source.nods) { prevSolData.T[m][nd] = currentModel.T[m][nd].solutionValue; } } // 将当前解写入文件(可选,用于后续分析) var solFile = new IloOplOutputFile("iteration_" + k + "_solution.dat"); solFile.writeln("// 迭代", k, "解数据"); solFile.writeln("Current N subset: ", current_N); solFile.writeln("Objective value: ", cplex.getObjValue()); solFile.writeln("// x变量值"); for (var m in source.M) { for (var n in current_N) { solFile.writeln("x[\"", m, "\"][\"", n, "\"] = ", prevSolData.x[m][n], ";"); } } // 可继续写入y、w、T变量值... solFile.close(); } else { writeln("迭代", k, "求解失败,终止循环"); break; } // 清理当前模型资源 currentModel.end(); } // 释放CPLEX资源 cplex.end(); }
关键说明
- 有序子集生成:通过
asSequence将无序集合N转换为有序数组,确保每次迭代按a→b→c...的顺序扩展子集。 - 暖启动优化:将前一次迭代的解赋值给当前模型变量的上下界,让CPLEX从已有解开始搜索,大幅提升求解速度。
- 解保存:通过字典存储每次迭代的变量值,既用于下一次暖启动,也可写入文件留存。
内容的提问来源于stack exchange,提问作者yalan
相关产品推荐
相关产品推荐

