c++ - 在回调(CPXcutcallbackadd)中添加用户切入后如何编写问题公式(CPXwriteprob)?

标签 c++ cplex

我正在尝试在 cplex 回调函数中添加用户剪切。为了检查这些切口,我在添加切口后写了一个 lp 文件。但是,lp 文件中没有出现用户剪辑。

根据 this forum thread (网址:www.ibm.com/developerworks/community/forums/html/topic?id=82b92bee-4ac7-41dd-b1fc-606eae3514f3),剪辑应该以“u”开头。

我的代码的相关部分(基于示例文件 bendersatsp.c):

int CPXPUBLIC benders_solver::benders_callback(CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle, int *useraction_p)
{
    int status = 0;
    int do_separate = 0;
    USER_CBHANDLE *user_cbhandle = (USER_CBHANDLE *)cbhandle;
    int purgeable;  
    *useraction_p = CPX_CALLBACK_DEFAULT;

    /* Decide if we want to separate cuts, depending on the parameter wherefrom */

    switch (wherefrom) {
    case CPX_CALLBACK_MIP_CUT_FEAS: // 115
    do_separate = 1;
    break;
    case CPX_CALLBACK_MIP_CUT_LAST: // 114: indicates that CPLEX is done adding cuts and the user has a last chance to add cuts
    do_separate = 1;
    break;
    case CPX_CALLBACK_MIP_CUT_LOOP: // 106: The callback was called from the cut loop CPLEX executes at each node.
    do_separate = 0;
    break;
    default:
    fprintf(stderr, "Unexpected value of wherefrom: %d\n", wherefrom);
    do_separate = 0;
    }

    if (!do_separate) goto TERMINATE;

    /* Get the current x solution */
    status = CPXgetcallbacknodex(env, cbdata, wherefrom, user_cbhandle->x, 0, user_cbhandle->num_x_cols - 1);
    if (status) {
        fprintf(stderr, "Error in CPXgetcallbacknodex: status = %d\n", status);
        goto TERMINATE;
    }

    CPXCLPptr lp_p;
    status = CPXgetcallbacklp(env, cbdata, wherefrom, &lp_p); // store master problem to lp_p

    changeSub_d(user_cbhandle, user_cbhandle->subenv, user_cbhandle->subproblem_d); 

    /* Solve the worker LP and look for a violated cut */
    CPXsetintparam(user_cbhandle->subenv, CPX_PARAM_PREIND, 0);

    int optstatus = CPXlpopt(user_cbhandle->subenv, user_cbhandle->subproblem_d);
    worker_lp_sol_stat = CPXgetstat(user_cbhandle->subenv, user_cbhandle->subproblem_d);

    /* Make cut */
    int matind[21000] = { 0 };              
    double matval[21000] = { 0 };
    double rhs[1];
    char sense[1];
    int nbnz{ 0 };      

    status = addBendersCut(user_cbhandle, worker_lp_sol_stat, env, lp_p, cbdata, wherefrom);

    int purgeable = CPX_USECUT_FORCE;
    status = CPXcutcallbackadd(env, cbdata, wherefrom, nbnz, rhs[0], sense[0], matind, matval, purgeable);
    status = CPXwriteprob(masterenv, masterproblem, "cback.lp", "LP");


    /* Tell CPLEX that cuts have been created */
    if (status)
        goto TERMINATE;

    *useraction_p = CPX_CALLBACK_SET;

    TERMINATE:

    /* If an error has been encountered, we fail */

    if (status) *useraction_p = CPX_CALLBACK_FAIL;

    return status;

} /* END benders_callback */



bool benders_solver::startSolve()
{
    loadGeneralData(sol);

    // Initialize the CPLEX environment 
    masterenv = CPXopenCPLEX(&status);
    subenv = CPXopenCPLEX(&status);

    loadMasterProblem(); 
    loadSubProblem(); 

    USER_CBHANDLE user_cbhandle;
    int separate_fractional_solutions = 1;

    /* Init the cut callback data structure */
    status = init_user_cbhandle(&user_cbhandle, separate_fractional_solutions);

    /* Let MIP callbacks work on the original model */
    status = CPXsetintparam(env, CPXPARAM_MIP_Strategy_CallbackReducedLP, CPX_OFF);
    status = CPXsetintparam(env, CPX_PARAM_PRELINEAR, 0);
    status = CPXsetintparam(env, CPX_PARAM_MIPCBREDLP, 0);
    status = CPXsetintparam(env, CPXPARAM_Threads, 1);  
    /* Turn on traditional search for use with control callbacks */
    status = CPXsetintparam(env, CPXPARAM_MIP_Strategy_Search,      CPX_MIPSEARCH_TRADITIONAL); 

    if (user_cbhandle->separate_fractional_solutions) {
        status = CPXsetusercutcallbackfunc(env, benders_callback, user_cbhandle);
    }

    /* Optimize the problem and obtain solution status */
    status = CPXsetintparam(masterenv, CPX_PARAM_PREIND, 0);
    status = CPXsetdblparam(masterenv, CPX_PARAM_TILIM, 300);
    status = CPXsetstrparam(masterenv, CPXPARAM_WorkDir, "c:/cplex/");
    status = CPXsetintparam(masterenv, CPXPARAM_MIP_Strategy_File, 2);
    status = CPXsetdblparam(masterenv, CPXPARAM_WorkMem, 6000);
    status = CPXsetintparam(masterenv, CPX_PARAM_MEMORYEMPHASIS, 1); 
    status = CPXmipopt(masterenv, masterproblem);

    status = CPXsetlogfile(masterenv, NULL);

    return true;
}

最佳答案

当您编写 LP 时,看起来您正在使用原始模型对象(即 masterproblem):

status = CPXwriteprob(masterenv, masterproblem, "cback.lp", "LP");

相反,您需要使用节点 LP,如下所示:

CPXLPptr _lp;
status = CPXgetcallbacknodelp(env, cbdata, wherefrom, &_lp);
CPXwriteprob(env, _lp, "cback.lp", "LP");

正如您链接到的论坛帖子中提到的:

the CPXcutcallbackadd() functions takes no arguments to provide names. In the cback.lp file, the cuts you added will have a name that starts with 'u', followed by a number. So you can find which rows are cuts that were added by you but you cannot easily map them back to things in your code

另一个值得一提的小问题(并澄清我在评论中提到的内容)是,在回调之外,您的削减将不会显示在使用 CPXwriteprob(即,不会导出在回调中的树搜索期间动态添加的任何剪切)。但是,如果您使用 CPXaddusercuts 在优化之前 添加用户削减,那么他们就会。

可以在 developerWorks 论坛上找到与您的问题类似的另一个问题 here .

关于c++ - 在回调(CPXcutcallbackadd)中添加用户切入后如何编写问题公式(CPXwriteprob)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54424166/

相关文章:

java - 使用 MATLAB 中的 CPLEX 和 Java 中的 CPLEX 求解模型是否可能得到不同的结果?

c++ - 仅在根节点上运行回调

c++ - C++ EXC_BAD_INSTRUCTION?

c++ - 如何在不降级为基类的情况下制作*对象的 vector

algorithm - 将旅行商表示为线性表达式

c - C 代码的 Makefile

c++ - std::string 在传递给库时会损坏/更改结构

c++ - 为什么不允许仅对一个 ref-qualifier 进行重载?

c++ - 为什么 VkKeyScanW 对 unicode 字符返回 -1?

python - windows下如何通过Pyomo读取cplex虚拟机配置文件?