首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用SCIP实现MIP LP弛豫的最佳方法

利用SCIP实现MIP LP弛豫的最佳方法
EN

Stack Overflow用户
提问于 2022-01-04 19:09:43
回答 1查看 300关注 0票数 0

我有一个C++应用程序,可以使用不明显的CPLEX硬币,现在我想添加SCIP作为选择。作为功能的一部分,它需要运行MIP问题的LP松弛。在CPLEX或硬币(这很简单)中,我只需创建问题,然后使用以下方法解决LP:

  • CPLEXint const rval = CPXXlpopt(m_env, m_lp);
  • 金币:m_modelIP.solver()->getModelPtr().initialSolve(m_lpOptions);

这个LP的解决方案在同一个地方--常规MIP的解决方案是,没有“特殊的”或“单独的”解决方案对象,我需要查看的只是普通的解决方案。

但是,我还无法用SCIP来找出相应的值。到目前为止,我已经看到了实现这一目标的两个可能的解决方案:

代码语言:javascript
复制
    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");
    }
  • 方法2:使用SCIP的LP接口。
代码语言:javascript
复制
    /* 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()是一种更好的方法,但我还没有找到任何关于这方面的示例。

非常感谢你的帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-04 21:07:25

如果您可以在SCIP插件中执行代码,那么这将是最有效/最优雅的方法。(例如,可以添加一个事件处理程序,该处理程序在第一个LP解决方案之后执行,并只获得LP解决方案)。这也是您可以使用潜水模式改变问题的某些方面,只需解决(改变) LP,然后恢复解决原来的问题。您不能不使用插件,因为您需要在解决阶段,以执行潜水mdoe。方法2有相同的问题,只有当您已经处于解决模式时,LPI才会有正确的信息。当然,您可以创建一个新的LPI结构并基本上复制整个问题,但是如果您要解决大型问题,这可能太低了。

如果您需要您的代码结构与它是相同的(调用LP解题,处理信息,继续求解),那么现在您只能选择选项1(变量类型的改变并不是性能问题,但是在更改变量类型之后,基本上会重新启动解决方案)。

不幸的是,SCIP目前不具备只解决放松问题,然后停止的功能,可以选择继续整个MIP解决方案。

我希望这有帮助,如果你用我的答案不清楚的话,请告诉我。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70583885

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档