CPLEX+JAVA:在启发式回调中检索解决方案行为异常
CPLEX+JAVA: Retrieving Solution inside Heuristic Callback behaves weirdly
我遇到以下问题:我使用与启发式组件集成的 CPLEX 来解决具有许多同步约束的大型 VRP,以改进现任者。一般算法如下:如果在 CPLEX 中找到新的现任者,或者如果达到时间限制,我将转向启发式,并尝试改进当前的现任者。前者使用 Incumbent Callback 完成,后者使用 Heuristic Callback。虽然我能够查询现任回调中的所有变量,但我在启发式回调中遇到了一些奇怪的行为:
当我查询
this.getStatus().toString()
this returns "Optimal",虽然解决方案还不是最优的(有一个在位的,但仍然有相当大的完整性差距)。我通过查看 objective 值和当前完整性差距确保模型实际查询了正确的 cplex 对象,它们与日志匹配。那么,
this.getIncumbentValue(v[n][i][j]);
失败(如果我使用 this.getIncumbentValues(v[n][i]);
查询值,它也会失败)。
当我检入模型时(使用 cplex.exportModel(String filename)
,所有变量都存在。
我在想这可能与我使用CPLEX作为单例有关,但是当我第一次使用单例时状态已经"optimal"(但是在第一次迭代中,所有变量都可以查询,这个问题只存在于第二次迭代)。
我这样创建单例:
public static IloCplex getCplex() {
if (cplex == null) {
try {
cplex = new IloCplex();
} catch (IloException e) {
e.printStackTrace();
}
} else {
try {
cplex.clearModel();
cplex.setDefaults();
} catch (IloException e) {
e.printStackTrace();
}
}
return cplex;
}
我是不是做错了什么?
编辑:包括回溯在内的确切错误信息是:
ilog.cplex.IloCplex$UnknownObjectException: CPLEX Error: object is unknown to IloCplex
at ilog.cplex.CpxNumVar.getVarIndexValue(CpxNumVar.java:295)
at ilog.cplex.IloCplex$MIPInfoCallback.getIndex(IloCplex.java:13648)
at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13807)
at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13785)
at SolverHybridCRP$InsertSolution.getV(SolverHybridCRP.java:2091)
at SolverHybridCRP$InsertSolution.improveIncumbent(SolverHybridCRP.java:2054)
at SolverHybridCRP$InsertSolution.main(SolverHybridCRP.java:2024)
at ilog.cplex.CpxCallback.callmain(CpxCallback.java:160)
at ilog.cplex.CpxHeuristicCallbackFunction.callIt(CpxHeuristicCallbackFunction.java:48)
at ilog.cplex.Cplex.CPXmipopt(Native Method)
at ilog.cplex.CplexI$SolveHandle.start(CplexI.java:2837)
at ilog.cplex.CplexI.solve(CplexI.java:2963)
at ilog.cplex.IloCplex.solve(IloCplex.java:10254)
at SolverHybridCRP.solveModel(SolverHybridCRP.java:1525)
at AppHelp.runtimeTest4(AppHelp.java:1218)
at AppHelp.main(AppHelp.java:61)
它在我查询任何变量时发生,但仅在我第二次查询 cplex 对象之后发生。 (所以:我启动程序,它迭代了很多实例,第一个实例很好,所有启发式回调都有效,在所有进一步的迭代中,我最终进入 catch 块并获得上述异常跟踪。)
这就是为什么我假设单例可能无法完全按预期工作,并且并非所有内容都从第一次迭代中删除。
查看 reference documentation 您可以看到 IloCplex.HeuristicCallback.getStatus()
Returns the solution status for the current node.
This method returns the status of the solution found by the instance
of IloCplex at the current node during the last call to the method
IloCplex.HeuristicCallback.solve (which may have been called directly
in the callback or by IloCplex when processing the node just before
the callback is called).
换句话说,该函数不是 return 全局状态,而是节点本地状态。预计调用回调时节点当前已求解至最优。
关于回调中的异常:您正在尝试访问不在正在求解的模型中的变量对象。发生这种情况的典型案例是:
- 您创建了变量,但它没有出现在任何约束或 objective 中,即它没有在任何地方使用。您可以通过使用变量作为参数显式调用
cplex.add()
来强制使用它。
- 变量是在上一次迭代中创建的,在当前迭代中不再是模型的一部分。调试它的一个好方法是为每个变量分配一个名称,并让该名称包含迭代索引。然后在异常处理程序中打印有问题的变量的名称。这应该很好地提示出了什么问题。
我遇到以下问题:我使用与启发式组件集成的 CPLEX 来解决具有许多同步约束的大型 VRP,以改进现任者。一般算法如下:如果在 CPLEX 中找到新的现任者,或者如果达到时间限制,我将转向启发式,并尝试改进当前的现任者。前者使用 Incumbent Callback 完成,后者使用 Heuristic Callback。虽然我能够查询现任回调中的所有变量,但我在启发式回调中遇到了一些奇怪的行为: 当我查询
this.getStatus().toString()
this returns "Optimal",虽然解决方案还不是最优的(有一个在位的,但仍然有相当大的完整性差距)。我通过查看 objective 值和当前完整性差距确保模型实际查询了正确的 cplex 对象,它们与日志匹配。那么,
this.getIncumbentValue(v[n][i][j]);
失败(如果我使用 this.getIncumbentValues(v[n][i]);
查询值,它也会失败)。
当我检入模型时(使用 cplex.exportModel(String filename)
,所有变量都存在。
我在想这可能与我使用CPLEX作为单例有关,但是当我第一次使用单例时状态已经"optimal"(但是在第一次迭代中,所有变量都可以查询,这个问题只存在于第二次迭代)。
我这样创建单例:
public static IloCplex getCplex() {
if (cplex == null) {
try {
cplex = new IloCplex();
} catch (IloException e) {
e.printStackTrace();
}
} else {
try {
cplex.clearModel();
cplex.setDefaults();
} catch (IloException e) {
e.printStackTrace();
}
}
return cplex;
}
我是不是做错了什么?
编辑:包括回溯在内的确切错误信息是:
ilog.cplex.IloCplex$UnknownObjectException: CPLEX Error: object is unknown to IloCplex
at ilog.cplex.CpxNumVar.getVarIndexValue(CpxNumVar.java:295)
at ilog.cplex.IloCplex$MIPInfoCallback.getIndex(IloCplex.java:13648)
at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13807)
at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13785)
at SolverHybridCRP$InsertSolution.getV(SolverHybridCRP.java:2091)
at SolverHybridCRP$InsertSolution.improveIncumbent(SolverHybridCRP.java:2054)
at SolverHybridCRP$InsertSolution.main(SolverHybridCRP.java:2024)
at ilog.cplex.CpxCallback.callmain(CpxCallback.java:160)
at ilog.cplex.CpxHeuristicCallbackFunction.callIt(CpxHeuristicCallbackFunction.java:48)
at ilog.cplex.Cplex.CPXmipopt(Native Method)
at ilog.cplex.CplexI$SolveHandle.start(CplexI.java:2837)
at ilog.cplex.CplexI.solve(CplexI.java:2963)
at ilog.cplex.IloCplex.solve(IloCplex.java:10254)
at SolverHybridCRP.solveModel(SolverHybridCRP.java:1525)
at AppHelp.runtimeTest4(AppHelp.java:1218)
at AppHelp.main(AppHelp.java:61)
它在我查询任何变量时发生,但仅在我第二次查询 cplex 对象之后发生。 (所以:我启动程序,它迭代了很多实例,第一个实例很好,所有启发式回调都有效,在所有进一步的迭代中,我最终进入 catch 块并获得上述异常跟踪。) 这就是为什么我假设单例可能无法完全按预期工作,并且并非所有内容都从第一次迭代中删除。
查看 reference documentation 您可以看到 IloCplex.HeuristicCallback.getStatus()
Returns the solution status for the current node.
This method returns the status of the solution found by the instance of IloCplex at the current node during the last call to the method IloCplex.HeuristicCallback.solve (which may have been called directly in the callback or by IloCplex when processing the node just before the callback is called).
换句话说,该函数不是 return 全局状态,而是节点本地状态。预计调用回调时节点当前已求解至最优。
关于回调中的异常:您正在尝试访问不在正在求解的模型中的变量对象。发生这种情况的典型案例是:
- 您创建了变量,但它没有出现在任何约束或 objective 中,即它没有在任何地方使用。您可以通过使用变量作为参数显式调用
cplex.add()
来强制使用它。 - 变量是在上一次迭代中创建的,在当前迭代中不再是模型的一部分。调试它的一个好方法是为每个变量分配一个名称,并让该名称包含迭代索引。然后在异常处理程序中打印有问题的变量的名称。这应该很好地提示出了什么问题。