在主流程控制循环中使用 opl.end() 时如何修复错误
How to fix errors when using opl.end() in main flow control loop
我在 main
流控制块内使用循环批处理 运行 数以万计的测试。循环的每个 运行 使用指定的 .dat
数据文件和 .mod
模型文件(与批处理 运行ner .mod
分开生成一个新的 OPL 模型仅包含 main
流控制块的文件)。
因为循环的每个 运行 都会创建一个新模型,所以内存使用会不断增加,直到我不使用 .end()
语句关闭时最终导致 IDE 崩溃为每个测试创建的所有数据结构。虽然大多数数据结构都可以很好地关闭,但我发现 opl.end();
会使测试仪崩溃。
如何在不使测试仪崩溃的情况下关闭 OPL 模型?
我已经在 macOS 和 Windows 上尝试了 oplide 应用程序和 oplrun
命令行界面(尽管我需要 运行 在 [=54= 上进行测试] 到底)。我正在使用 CPLEX Optimization Studio 12.9。
我使用以下方法创建对象:
// Create new model
var source = new IloOplModelSource("model-file.mod");
var def = new IloOplModelDefinition(source);
var cp = new IloCP();
var opl = new IloOplModel(def,cp);
// Set next test case as data source
var testCasePath = thisOplModel.TestCaseFilenames[testNumber];
var data = new IloOplDataSource(testCasePath);
opl.addDataSource(data);
// Generate model
opl.generate();
我尝试在完成后使用以下方法关闭它们:
data.end();
opl.end(); // Causes it to crash
cp.end();
def.end();
source.end();
编辑以添加更具体的信息:
我正在 运行解决 RCPSP 调度问题,使用我自己的模型,它是内置示例的修改版本。
这是我正在使用的代码的精简版。我创建了一个 运行 配置,只包含这批 运行ner .mod
文件,模型文件和它引用的数据文件存储在别处:
using CP;
// Import test case filename data
int NumberOfFiles = 3;
range FileIDs = 0..NumberOfFiles-1;
string TestCaseFilenames[FileIDs] = ["TestCase-01.dat", "TestCase-02.dat", "TestCase-03.dat"];
main {
var testCaseDirectory = "~/Desktop/TestCases/";
// Solve each test case in the list
for (var testNumber = 0; testNumber < thisOplModel.NumberOfFiles; testNumber++) {
// Create new model
var source = new IloOplModelSource("RCPSP.mod");
var def = new IloOplModelDefinition(source);
var cp = new IloCP();
var opl = new IloOplModel(def,cp);
// Set CP parameters
cp.param.TimeLimit = 5; // Number is in seconds
cp.param.Workers = 4; // Number of computer cores used
cp.param.TimeMode = "ElapsedTime"; // How to report time
cp.param.LogVerbosity = "Quiet"; // How much to write to the engine log
// Set next test case as data source
var testCaseFilename = thisOplModel.TestCaseFilenames[testNumber];
var testCasePath = testCaseDirectory + testCaseFilename;
var data = new IloOplDataSource(testCasePath);
opl.addDataSource(data);
// Generate model
opl.generate();
// Report test case name to script log for progress visibility
writeln(testNumber+1 + ") Solving " + opl.TestCaseFilename + "...");
// Solve model
if (cp.solve()) { // Successfully found solution
// Run solution validation code in model file's post-processing execute statement
// If a solution is invalid, the entire bath runner will fail with an error at that test and line
opl.postProcess();
// Report some solve-dependent results to oplide log for visibility
writeln(" - UB = " + cp.getObjValue() + ", LB = " + cp.getObjBound()); // Makespan
} else { // Failed to find solution
// Report no solution to oplide log for visibility
writeln(" - No solution found.")
writeln(" - Lower Bound = " + cp.getObjBound());
}
// Report some results to script log for visibility
writeln(" - Status = " + cp.status); // Solver status
writeln(" - Solve Time = " + cp.info.SolveTime + " sec"); // Time spent solving
// End processes to prevent memory leaks
data.end();
opl.end(); // Causes it to crash
cp.end();
def.end();
source.end();
}
// Confirm to user that tests are complete
writeln();
writeln("All done!");
}
输出应该是这样的(注释掉 opl.end()
行):
1) Solving TestCase-01.dat...
- UB = 48, LB = 48
- Status = 2
- Solve Time = 1.299999952 sec
2) Solving TestCase-02.dat...
- UB = 65, LB = 36
- Status = 1
- Solve Time = 5.019999981 sec
3) Solving TestCase-03.dat...
- No solution found.
- LB = 1
- Status = 0
- Solve Time = 5.010000229 sec
All done!
相反,它只记录此输出:
1) Solving TestCase-01.dat...
- UB = 48, LB = 48
- Status = 2
- Solve Time = 1.299999952 sec
然后弹出一个 window 错误信息:
Oplrun process is not responding, you must relaunch the Run Configuration.
我们通过电子邮件解决了这个问题。崩溃的原因是 OPL 中的错误。代码中有问题的部分是这样的:
tuple T {
key int id;
int intArray[0..0];
}
{T} tuples = ...;
T tupleById[1..1];
execute {
for (var t in tuples)
tupleById[t.id] = t;
}
问题是在脚本中分配包含数组或集合成员的元组。这会触发 OPL 中的错误,最终导致崩溃。解决方法是初始化 tupleById
而无需通过
编写脚本
T tupleById[id in 1..1] = first({ t | t in tuples : t.id == id});
这里的技巧是所有生成的集合都是单例,因为 id 是唯一的。然后我们使用 first() 函数从单例集中提取第一个元素以获得普通元组。
我在 main
流控制块内使用循环批处理 运行 数以万计的测试。循环的每个 运行 使用指定的 .dat
数据文件和 .mod
模型文件(与批处理 运行ner .mod
分开生成一个新的 OPL 模型仅包含 main
流控制块的文件)。
因为循环的每个 运行 都会创建一个新模型,所以内存使用会不断增加,直到我不使用 .end()
语句关闭时最终导致 IDE 崩溃为每个测试创建的所有数据结构。虽然大多数数据结构都可以很好地关闭,但我发现 opl.end();
会使测试仪崩溃。
如何在不使测试仪崩溃的情况下关闭 OPL 模型?
我已经在 macOS 和 Windows 上尝试了 oplide 应用程序和 oplrun
命令行界面(尽管我需要 运行 在 [=54= 上进行测试] 到底)。我正在使用 CPLEX Optimization Studio 12.9。
我使用以下方法创建对象:
// Create new model
var source = new IloOplModelSource("model-file.mod");
var def = new IloOplModelDefinition(source);
var cp = new IloCP();
var opl = new IloOplModel(def,cp);
// Set next test case as data source
var testCasePath = thisOplModel.TestCaseFilenames[testNumber];
var data = new IloOplDataSource(testCasePath);
opl.addDataSource(data);
// Generate model
opl.generate();
我尝试在完成后使用以下方法关闭它们:
data.end();
opl.end(); // Causes it to crash
cp.end();
def.end();
source.end();
编辑以添加更具体的信息: 我正在 运行解决 RCPSP 调度问题,使用我自己的模型,它是内置示例的修改版本。
这是我正在使用的代码的精简版。我创建了一个 运行 配置,只包含这批 运行ner .mod
文件,模型文件和它引用的数据文件存储在别处:
using CP;
// Import test case filename data
int NumberOfFiles = 3;
range FileIDs = 0..NumberOfFiles-1;
string TestCaseFilenames[FileIDs] = ["TestCase-01.dat", "TestCase-02.dat", "TestCase-03.dat"];
main {
var testCaseDirectory = "~/Desktop/TestCases/";
// Solve each test case in the list
for (var testNumber = 0; testNumber < thisOplModel.NumberOfFiles; testNumber++) {
// Create new model
var source = new IloOplModelSource("RCPSP.mod");
var def = new IloOplModelDefinition(source);
var cp = new IloCP();
var opl = new IloOplModel(def,cp);
// Set CP parameters
cp.param.TimeLimit = 5; // Number is in seconds
cp.param.Workers = 4; // Number of computer cores used
cp.param.TimeMode = "ElapsedTime"; // How to report time
cp.param.LogVerbosity = "Quiet"; // How much to write to the engine log
// Set next test case as data source
var testCaseFilename = thisOplModel.TestCaseFilenames[testNumber];
var testCasePath = testCaseDirectory + testCaseFilename;
var data = new IloOplDataSource(testCasePath);
opl.addDataSource(data);
// Generate model
opl.generate();
// Report test case name to script log for progress visibility
writeln(testNumber+1 + ") Solving " + opl.TestCaseFilename + "...");
// Solve model
if (cp.solve()) { // Successfully found solution
// Run solution validation code in model file's post-processing execute statement
// If a solution is invalid, the entire bath runner will fail with an error at that test and line
opl.postProcess();
// Report some solve-dependent results to oplide log for visibility
writeln(" - UB = " + cp.getObjValue() + ", LB = " + cp.getObjBound()); // Makespan
} else { // Failed to find solution
// Report no solution to oplide log for visibility
writeln(" - No solution found.")
writeln(" - Lower Bound = " + cp.getObjBound());
}
// Report some results to script log for visibility
writeln(" - Status = " + cp.status); // Solver status
writeln(" - Solve Time = " + cp.info.SolveTime + " sec"); // Time spent solving
// End processes to prevent memory leaks
data.end();
opl.end(); // Causes it to crash
cp.end();
def.end();
source.end();
}
// Confirm to user that tests are complete
writeln();
writeln("All done!");
}
输出应该是这样的(注释掉 opl.end()
行):
1) Solving TestCase-01.dat...
- UB = 48, LB = 48
- Status = 2
- Solve Time = 1.299999952 sec
2) Solving TestCase-02.dat...
- UB = 65, LB = 36
- Status = 1
- Solve Time = 5.019999981 sec
3) Solving TestCase-03.dat...
- No solution found.
- LB = 1
- Status = 0
- Solve Time = 5.010000229 sec
All done!
相反,它只记录此输出:
1) Solving TestCase-01.dat...
- UB = 48, LB = 48
- Status = 2
- Solve Time = 1.299999952 sec
然后弹出一个 window 错误信息:
Oplrun process is not responding, you must relaunch the Run Configuration.
我们通过电子邮件解决了这个问题。崩溃的原因是 OPL 中的错误。代码中有问题的部分是这样的:
tuple T {
key int id;
int intArray[0..0];
}
{T} tuples = ...;
T tupleById[1..1];
execute {
for (var t in tuples)
tupleById[t.id] = t;
}
问题是在脚本中分配包含数组或集合成员的元组。这会触发 OPL 中的错误,最终导致崩溃。解决方法是初始化 tupleById
而无需通过
T tupleById[id in 1..1] = first({ t | t in tuples : t.id == id});
这里的技巧是所有生成的集合都是单例,因为 id 是唯一的。然后我们使用 first() 函数从单例集中提取第一个元素以获得普通元组。