Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
  • 1.  UserCutCallback memory leak

    Posted 01/12/19 10:49 AM

    Originally posted by: GP_Song


    I wrote a usercutcallback to separate cuts for a MIP model. There is some memory leak in the callback procedure, which I could not identify. This issue is reflected when repetitively calling the MIP model to solve many instances, where memory usage just piles up! The separation in the callback is done only locally by another library to solve a min cut model, so it should be Ok. I also have a nodecallback to get the depth (int cplex_node_depth) of the current node in order to separate cuts only for nodes on certain depths. I've listed the callback macros down below. Can anyone help me to check where it went wrong. Many thanks in advance!

     

    [code]

    ILONODECALLBACK0(NodeDepthCallback){
    IloInt64 nextNode = 0;
    cplex_node_depth = getDepth(nextNode);
    //cout << cplex_node_depth << endl;
    }

     

    ILOUSERCUTCALLBACK6(BoundingCutsCallback, NumVarMatrix, arc, NumVarMatrix, y, IloNumArray, job_release_time_ilo, IloNumArray, job_frac_UB_ilo, IloNumArray, job_frac_LB_ilo, int, node_depth_choice)
    {
    assert(MAP_VEC.size() == y.getSize());
     
    // Skip the separation if not at the end of the cut loop
    if (!isAfterCutLoop())
    return;
     
    if (cplex_node_depth < 3 || cplex_node_depth % node_depth_choice == 0)
    {
    // get the master env and numbers
    IloEnv env = getEnv();
    //get num of jobs and planning horizon
    int num_job = y.getSize();
    int time_horizon = y[0].getSize();
     
    // get the solution of the first stage
    // the values of y variables 
    NumMatrix ySol(env, num_job);
    for (int j = 0; j < num_job; j++)
    {
    ySol[j] = IloNumArray(env);
    getValues(ySol[j], y[j]);
    //cout << ySol[j] << endl;
    }
     
    // the solution of arc variables
    NumMatrix arcSol(env, num_job);
    for (int j = 0; j < num_job; j++)
    {
    arcSol[j] = IloNumArray(env);
    getValues(arcSol[j], arc[j]);
    }
     
    vector<bool> cut_flag(num_job, false);
    ////array of cut lefthand sides and bool indicators
    //IloExprArray cut_expr(env, num_job);
     
    //for (int j = 0; j < num_job; j++)
    //{
    // cut_expr[j] = IloExpr(env);
    //}
     
    ////separation
    ////if (separate_bound_y(arc, arcSol, y, ySol, job_release_time_ilo, job_frac_UB_ilo, job_frac_LB_ilo, cut_flag, cut_expr))//separation with local graphs
    //if (separate_bound_y_pointer(arc, arcSol, y, ySol, job_release_time_ilo, job_frac_UB_ilo, job_frac_LB_ilo, cut_flag, cut_expr))//separation with the global pointer
    //{
    // for (int j = 0; j < num_job; j++)
    // {
    // if (cut_flag[j] == true)
    // {
    // add(cut_expr[j] >= 0).end();
    // //vio_cuts.add(cut_expr[j] >= 0);
    // CUT_NUM++;
    // }
    // }
    //}
     
    //expr containing the cut lefthand side
    for (int j = 0; j < num_job; j++)
    {
    IloExpr cut_expr(env);
    if (separate_bound_y_pointer_j(arc, arcSol, y, ySol, job_release_time_ilo, job_frac_UB_ilo, job_frac_LB_ilo, cut_flag, cut_expr, j))
    {
    add(cut_expr >= 0).end();
    // //vio_cuts.add(cut_expr[j] >= 0);
    CUT_NUM++;
    }
    cut_expr.end();
    }
     
    //release the memory
    for (int j = 0; j < num_job; j++)
    {
    ySol[j].end();
    arcSol[j].end();
    //cut_expr[j].end();
    }
    ySol.end();
    arcSol.end();
    //cut_expr.endElements();
    //release the vector
    cut_flag.clear();
    cut_flag.shrink_to_fit();
    vector<bool>().swap(cut_flag);
     
    return;
    }
    else
    {
    return;
    }
     
    }

    [/code]


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: UserCutCallback memory leak

    Posted 01/13/19 04:37 PM

    As far as I can tell you are missing end()ing the IloRange instance that is created as cut. If you look at the examples shipped with CPLEX you can see that cuts are usually added like this:

    add(lhs <= rhs).end();

    Can you first check whether adding that fixes the leak.


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: UserCutCallback memory leak

    Posted 01/14/19 04:12 AM

    Originally posted by: GP_Song


    Hi Daniel, thanks for you reply. If you check the code I posted, I did already put an end to the IloRange instance as well as for all other stuff created in the callback macro.

    One difference compared to the example is, for the IloExpr instance that contains the cut info, I have to pass it to the separation routine with reference, otherwise it doesn't work (outside the separation scope, the IloExpr instance comes back to 0). However, I don't think that should cause the memory issue. 


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: UserCutCallback memory leak

    Posted 01/14/19 06:05 AM

    Sorry, I mixed that up with one of the lines that are commented out (when posting in a forum is a good idea to remove commented code that is irrelevant and to properly format the code, that makes things easier to read).

    That being said, I don't see an obvious mistake in your code. How do you know the leak is in your callback? Couldn't the leak be in another part of your iterative process?


    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: UserCutCallback memory leak

    Posted 01/14/19 06:55 AM

    Originally posted by: GP_Song


    Thanks, Daniel, for checking the code and your suggestions.

    So far, I have tried two things, running the the plain MIP model without callback, and creating one separation instance to run only the separation routine many times. Both cases are fine without memory issue. So I am guessing the problem should be in the Callback, or the connection between the callback and the separation routine?

    I am using VS2013 with CPLEX 12.6.3, by the way, am I supposed to pass the IloExpr instance to the separation routine by reference (no reference in the shipped example, but that doesn't work for me)? Passing arguments by reference should not cause the issue, I assume.


    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: UserCutCallback memory leak

    Posted 01/15/19 04:20 AM

    Ok, that clearly points at the callback.

    Can you repeat the same experiment with the callback enabled but without calling separate_bound_y_pointer_j() (and then obviously not ever adding a cut)? Does that leak as well?

    As far as I can tell, passing the IloExpr by reference should be fine. How exactly do you update the IloExpr in your separation function. Can you show that function? Or the relevant parts of it?


    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: UserCutCallback memory leak

    Posted 01/15/19 06:35 AM

    Originally posted by: GP_Song


    Hi Daniel, it should be exactly in the callback, even more specifically, because of IloExpr.

    I profiled the heap usage after solving one instance, where I can see a lot IloExpr instances stay in the memory. Then I just noticed that there is only "+=" operator instead of "+" defined for IloExpr. Now the issue is kind of resolved. Again, many thanks for your help.


    #CPLEXOptimizers
    #DecisionOptimization


  • 8.  Re: UserCutCallback memory leak

    Posted 01/16/19 07:39 AM

    "operator+" should be defined for IloExpr. But indeed carries the risk of memory leaks. It also is highly inefficient. Writing something like A = B + C with A, B, C being instances of IloExpr will create a new IloExpr instance for A and will leave B and C untouched. Writing B += C will instead modify B in place without creating a new object. This is faster, less memory intensive and less prone to leaks.

    Whenever possible you should use computes assignment (+=, -=, /=, *=) for operations on IloExpr.


    #CPLEXOptimizers
    #DecisionOptimization


  • 9.  Re: UserCutCallback memory leak

    Posted 01/16/19 09:25 AM

    Originally posted by: GP_Song


    Lesson learned! If it wasn't for this case, I wouldn't notice the difference, since I have been mixed-using both operators. Thanks for your help and the suggestions!


    #CPLEXOptimizers
    #DecisionOptimization