Как написать формулировку проблемы (CPXwriteprob) после того, как пользовательский вырез добавлен в обратный вызов (CPXcutcallbackadd)? - PullRequest
0 голосов
/ 29 января 2019

Я пытаюсь добавить пользовательские сокращения в функцию обратного вызова cplex.Чтобы проверить эти срезы, я пишу lp-файл после добавления среза.Тем не менее, в lp-файле не отображаются сокращения пользователя.

Согласно этой теме форума (url: 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;
}

1 Ответ

0 голосов
/ 04 февраля 2019

Когда вы пишете LP, похоже, что вы используете исходный объект модели (т. Е. masterproblem):

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

Вместо этого вам нужно будет использовать узел LP, например, так:

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

Как упоминалось в сообщении на форуме, на которое вы ссылались:

функции CPXcutcallbackadd () не принимают аргументов для предоставления имен.В файле cback.lp добавленные срезы будут иметь имя, начинающееся с «u», за которым следует число.Таким образом, вы можете найти, какие строки являются вырезками, которые были добавлены вами, но вы не можете легко сопоставить их с вещами в вашем коде

Еще один незначительный момент, о котором стоит упомянуть (и уточнить, что я упомянул в комментариях)в том, что, вне обратного вызова , ваши сокращения будут не обнаруживаться при использовании CPXwriteprob (то есть любые сокращения, которые были добавлены динамически во время поиска по дереву в обратном вызове, не будутвывозимый).Однако, если вы добавите пользовательские сокращения до оптимизации с использованием CPXaddusercuts , тогда они будут.

Еще один похожий на ваш вопрос можно найти на форуме developerWorks здесь.

...