我有一个C++应用程序,可以使用不明显的CPLEX或硬币,现在我想添加SCIP作为选择。作为功能的一部分,它需要运行MIP问题的LP松弛。在CPLEX或硬币(这很简单)中,我只需创建问题,然后使用以下方法解决LP:
int const rval = CPXXlpopt(m_env, m_lp);m_modelIP.solver()->getModelPtr().initialSolve(m_lpOptions);这个LP的解决方案在同一个地方--常规MIP的解决方案是,没有“特殊的”或“单独的”解决方案对象,我需要查看的只是普通的解决方案。
但是,我还无法用SCIP来找出相应的值。到目前为止,我已经看到了实现这一目标的两个可能的解决方案:
int nVars = SCIPgetNVars(m_scip);
std::vector<SCIP_VARTYPE> varTypes(nVars, SCIP_VARTYPE_CONTINUOUS);
SCIP_VAR **pVars = SCIPgetVars(m_scip);
/* Move all binary and integral variables to continuous */
for (size_t i = 0; i < static_cast<size_t>(nVars); i++)
{
SCIP_VARTYPE const varType = SCIPvarGetType(pVars[i]);
if (varType == SCIP_VARTYPE_CONTINUOUS)
continue;
varTypes[i] = varType;
SCIP_Bool infeasible;
if (SCIPchgVarType(m_scip, pVars[i], SCIP_VARTYPE_CONTINUOUS, &infeasible) != SCIP_OKAY)
throw std::runtime_error("Error changing integrality type to SCIP variable " + std::to_string(i) + " to continuos to solve LP relaxation");
}
/* Store parameters current value */
SCIP_Longint oldNodes;
if (SCIPgetLongintParam(m_scip, "limits/nodes", &oldNodes) != SCIP_OKAY)
throw std::runtime_error("Couldn't get limits/nodes parameter in SCIP");
int oldMaxRounds;
if (SCIPgetIntParam(m_scip, "presolving/maxrounds", &oldMaxRounds) != SCIP_OKAY)
throw std::runtime_error("Couldn't get presolving/maxrounds parameter in SCIP");
/* Change parameters to create the "LP-like" scenario */
if (SCIPsetLongintParam(m_scip, "limits/nodes", 1) != SCIP_OKAY)
throw std::runtime_error("Couldn't set limits/nodes parameter in SCIP");
if (SCIPsetIntParam(m_scip, "presolving/maxrounds", 0) != SCIP_OKAY)
throw std::runtime_error("Couldn't set presolving/maxrounds parameter in SCIP");
/* Solve the supposedly now LP problem */
if (SCIPsolve(m_scip) != SCIP_OKAY)
throw std::runtime_error("Couldn't solve LP problem in SCIP");
/* Restore the original state of the parameters */
if (SCIPsetLongintParam(m_scip, "limits/nodes", oldNodes) != SCIP_OKAY)
throw std::runtime_error("Couldn't restore limits/nodes parameter in SCIP");
if (SCIPsetIntParam(m_scip, "presolving/maxrounds", oldMaxRounds) != SCIP_OKAY)
throw std::runtime_error("Couldn't restore presolving/maxrounds parameter in SCIP");
/* Restore the original state of the variables */
for (size_t i = 0; i < static_cast<size_t>(nVars); i++)
{
SCIP_VARTYPE const varType = varTypes[i];
if (varType == SCIP_VARTYPE_CONTINUOUS)
continue;
SCIP_Bool infeasible;
if (SCIPchgVarType(m_scip, pVars[i], varType, &infeasible) != SCIP_OKAY)
throw std::runtime_error("Error restoring integrality type to SCIP variable " + std::to_string(i) + " from continuos after solving LP relaxation");
} /* Presolve the original MIP problem. Without this step, the following SCIPgetLPI() call throws a SIGSEGV */
if (SCIPpresolve(m_scip) != SCIP_OKAY)
throw std::runtime_error("Couldn't presolve SCIP");
/* Access the LP interface of SCIP */
SCIP_LPI *pLpi = nullptr;
if (SCIPgetLPI(m_scip, &pLpi) != SCIP_OKAY)
throw std::runtime_error("Couldn't obtain access to LP interface of SCIP");
/* And solve it */
if (SCIPlpiSolvePrimal(pLpi) != SCIP_OKAY)
throw std::runtime_error("Couldn't solve LP interface of SCIP");虽然方法1似乎有效,但我(未经证实)认为方法2更正确。但是,我不确定用于解决问题(SCIPlpiSolvePrimal())的方法是否确实是正确的,或者如果该方法提供的解决方案位于这样一个位置,我可以使用SCIPgetBestSol()检索它(我的库没有单独的方法来获得IP或LP解决方案,因为CPLEX和硬币都不需要它)。
所以我的主要问题是:我的方法#1正确吗?或者它太慢/不是最批准的,而#2是应该使用的吗?如果是这样的话,SCIPlpiSolvePrimal()提供的解决方案是否可以从常规的MIP接口访问?或者如果没有,有什么办法让它变成那样吗?
或者还有第三种方法来处理这个案子?我读过这里,也许使用SCIP*Dive()是一种更好的方法,但我还没有找到任何关于这方面的示例。
非常感谢你的帮助。
发布于 2022-01-04 21:07:25
如果您可以在SCIP插件中执行代码,那么这将是最有效/最优雅的方法。(例如,可以添加一个事件处理程序,该处理程序在第一个LP解决方案之后执行,并只获得LP解决方案)。这也是您可以使用潜水模式改变问题的某些方面,只需解决(改变) LP,然后恢复解决原来的问题。您不能不使用插件,因为您需要在解决阶段,以执行潜水mdoe。方法2有相同的问题,只有当您已经处于解决模式时,LPI才会有正确的信息。当然,您可以创建一个新的LPI结构并基本上复制整个问题,但是如果您要解决大型问题,这可能太低了。
如果您需要您的代码结构与它是相同的(调用LP解题,处理信息,继续求解),那么现在您只能选择选项1(变量类型的改变并不是性能问题,但是在更改变量类型之后,基本上会重新启动解决方案)。
不幸的是,SCIP目前不具备只解决放松问题,然后停止的功能,可以选择继续整个MIP解决方案。
我希望这有帮助,如果你用我的答案不清楚的话,请告诉我。
https://stackoverflow.com/questions/70583885
复制相似问题