Decision Optimization

Decision Optimization

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

 View Only
  • 1.  injecting heuristic solutions with HeuristicCallback

    Posted Mon June 18, 2012 12:34 PM

    Originally posted by: UteWW


    Hi all,

    I would be really glad if someone could give me a hint about the following problem:
    I want to solve a linear MIP and use HeuristicCallback to inject feasible solutions at each node. I manage to find solutions, that are better than the current one, but for some reasons, cplex does not seem to accept them, since the best found solution is not updated. Has somebody an idea, why? Are there some parameter settings I have to take into account?

    To be more precise, the output looks like this:
    (In the beginning I also provide a start solution with SetVectors...)
    ***************************************
    ....
    1 of 1 MIP starts provided solutions.
    MIP start 'm1' defined initial solution with objective 17.6294.
    Tried aggregator 20 times.
    MIP Presolve eliminated 16754 rows and 11157 columns.
    MIP Presolve modified 91868 coefficients.
    Aggregator did 4494 substitutions.
    Reduced MIP has 4756 rows, 3538 columns, and 15428 nonzeros.
    Reduced MIP has 918 binaries, 0 generals, 0 SOSs, and 0 indicators.
    Presolve time = 0.29 sec.
    Warning: Control callbacks may disable some MIP features.
    Clique table members: 128.
    MIP emphasis: balance optimality and feasibility.
    MIP search method: traditional branch-and-cut.
    Parallel mode: none, using 1 thread.
    Root relaxation solution time = 0.27 sec.

    Nodes Cuts/
    Node Left Objective IInf Best Integer Best Node ItCnt Gap Variable B NodeID Parent Depth

    • 0+ 0 17.6294 2013 ---
    0 0 20.5831 582 17.6294 20.5831 2013 16.75%
    primal heuristic, solution status = Optimal, objval=18.2641
    0 0 19.7229 444 17.6294 Cuts: 812 3834 11.88%
    primal heuristic, solution status = Optimal, objval=18.6294
    0 0 19.4783 424 17.6294 Cuts: 228 4745 10.49%
    primal heuristic, solution status = Optimal, objval=18.1144
    0 0 19.3322 391 17.6294 Cuts: 87 5202 9.66%
    primal heuristic, solution status = Optimal, objval=18.1561
    0 0 19.2853 410 17.6294 Cuts: 48 5449 9.39%
    ...
    ******************************************************
    The code looks like this:

    **********************************
    ILOHEURISTICCALLBACK2(...)
    {
    IloNumVarArray varsarray(env);
    IloNumArray valsarray(env);
    //computing values....

    setSolution(varsarray, valsarray, objval);
    varsarray.end();
    valsarray.end();
    env.out() << "primal heuristic, solution status = " << getStatus() << ",\tobjval=" << objval << endl;
    ....
    }
    ********************************

    I also stored the heuristical solutions in a file and used them as start solution in another run. And here, cplex accepts the solution and continues.

    How can I find out, why the heuristic solutions found in the callback are not used?

    Thanks a lot for your help

    Best regards
    Ute
    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Mon June 18, 2012 07:56 PM

    Originally posted by: SystemAdmin


    > UteWW wrote:
    > ILOHEURISTICCALLBACK2(...)
    > {
    > IloNumVarArray varsarray(env);
    > IloNumArray valsarray(env);
    > //computing values....
    >
    > setSolution(varsarray, valsarray, objval);
    > varsarray.end();
    > valsarray.end();
    > env.out() << "primal heuristic, solution status = " << getStatus() << ",\tobjval=" << objval << endl;
    >
    >
    > ....
    > }

    I'm not a C++ user, and you didn't specify your arguments to ILOHEURISTICCALLBACK2, but it looks suspicious to me that you're declaring varsarray inside ILOHEURISTICCALLBACK2. It should be passed in as an argument. Declaring valsarray and objval is fine, since they're computed within the callback. Are you sure you're not passing an empty variable list in setSolution?

    Paul

    Mathematicians are like Frenchmen: whenever you say something to them, they translate it into their own language, and at once it is something entirely different. (Goethe)
    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Tue June 19, 2012 12:31 AM

    Originally posted by: SystemAdmin


    Do you specify values for all variables in your model when you call setSolution()?
    One thing you could try for debugging is adding this code before calling setSolution():
    
    
    // Get feasibility status of variables. This is required to not call setBounds() on variables that have been presolved out ControlCallbackI::IntegerFeasibilityArray feas(getEnv()); getFeasibilities(feas, allVars); 
    
    for (IloInt i = 0; i < allVars.getSize(); ++i) 
    { 
    
    if (feas[i] != ImpliedFeasible) 
    { 
    
    if (
    /* Variable allVars[i] is in varsarray */) 
    { IloNum value = 
    // value for allVars[i] from valsarray setBounds(allVars[i], value, value); 
    } 
    } 
    }   
    
    if (solve()) 
    { env.out() << 
    "object value = " << getObjValue() << std::endl; 
    } 
    
    else 
    { env.out() << 
    "solve() failed" << std::endl; 
    } feas.end();
    

    Here I assume that 'allVars' is an instance of IloNumVarArray that contains all the variables in your model. In the first part of the code snippet all variables for which you have computed a value are fixed to that value (note that the bound changes applied via setBounds() are automatically undone by CPLEX when the callback returns). In the second part of the code snippet a solve with the fixed variables is performed. Does this solve() produce the same objective function value as you computed yourself?
    If it does, does it help to call setSolution() after a successful solve() like this:
    
    
    
    if (solve()) 
    { env.out() << 
    "object value = " << getObjValue() << std::endl; IloNumArray vals(getEnv()); getValues(vals, allVars); setSolution(allVars, vals); vals.end(); 
    }
    


    General comments:
    • Calling setSolution() with an objval argument is dangerous. You need to be extra sure that the value you provide is correct. CPLEX will not check it. I recommend calling the overload that does not use an objval argument.
    • Instead of 'varsarray(env)' you should use 'varsarray(getEnv())' (use callback-local environment). Same for 'valsarray'.

    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Fri June 22, 2012 04:07 AM

    Originally posted by: UteWW


    Hi Daniel.

    Thank you very much for this detailed answer :)
    It was helpful, but I still have some problems.
    In fact, I am trying to use the heuristic callback for two different MIPs.

    Now, one of them seems to work, but in a somewhat strange way. When I apply setBounds and solve, as you described, I get the confirmation, that the found solution is feasible and the Objective value is indeed the same, that I found myself. But still, the new incumbent is only used by cplex, when I use setSolution after the if-else-part, (and not inside it, as you proposed). And the most strange thing is, that it only works, if I use emtpy arrays of vals and vars as argument in SetSolution (so just initialised but without assigning values to it...)
    Well, but since it works like this, I am already happy with that.

    The heuristic callback of the second model is still not working. In order to continue I have some questions:

    1. Is it also possible that continuous variables are presolved out, or does this only happen to binaries?
    2. Is the function "getFeasibilities" also applicable for NumVarArrays? (I always get Error messages at this point.)
    Or how can I check, wether a continuous variable has been presovled out?
    3. I don't succeed with the setBounds and solve command this time. This means propably, that the values I want to use contradict to some constraints. Since they don't contradict to the original MIP, I suppose, that they violate constraints implied by cuts and branching rules that have been added later. Is it possible to switch of the cutting procedure?
    4. Last question: The MIP consists of several arrays of continuous and binary variables. The heuristic can only work probably, if the branching is only done on one special array of binary variables. I use the setPriority-routine for this. But I read, that it does not guarantee, that the branching is also done on another variable. Is there a way to totally prevent cplex from branching on certain variables?

    Thank you a lot for you help.
    Best wishes

    Ute
    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Fri June 22, 2012 01:43 PM

    Originally posted by: SystemAdmin


    > Now, one of them seems to work, but in a somewhat strange way. When I apply setBounds and solve, as you described, I get the confirmation, that the found solution is feasible and the Objective value is indeed the same, that I found myself. But still, the new incumbent is only used by cplex, when I use setSolution after the if-else-part, (and not inside it, as you proposed). And the most strange thing is, that it only works, if I use emtpy arrays of vals and vars as argument in SetSolution (so just initialised but without assigning values to it...)
    > Well, but since it works like this, I am already happy with that.
    >
    I think we should still try to figure out what goes wrong and why it does not work as expected. It is not completely clear to me how your code currently looks like. Could you post the relevant part of your callback here?

    > The heuristic callback of the second model is still not working. In order to continue I have some questions:
    >
    > 1. Is it also possible that continuous variables are presolved out, or does this only happen to binaries?
    >
    Any kind of variable may be presolved out. But usually you should not need to bother with continuous variables in a heuristic callback. After fixing the integral/binary variables a call to solve() will produce correct values for the continuous variables.

    > 2. Is the function "getFeasibilities" also applicable for NumVarArrays? (I always get Error messages at this point.)
    > Or how can I check, wether a continuous variable has been presovled out?
    >
    Yes, there is an overload of this function that takes an array of IloNumVar instances (see the reference documentation here).

    > 3. I don't succeed with the setBounds and solve command this time. This means propably, that the values I want to use contradict to some constraints. Since they don't contradict to the original MIP, I suppose, that they violate constraints implied by cuts and branching rules that have been added later. Is it possible to switch of the cutting procedure?
    >
    Yes, you can switch that off, for example by setting the PrePass parameter to -1. However, I don't think that cuts are your problem here. As long as the heuristic solution is feasible in the original model and better than the current incumbent, CPLEX is supposed to accept it. Could you describe in more detail what your problem is?

    > 4. Last question: The MIP consists of several arrays of continuous and binary variables. The heuristic can only work probably, if the branching is only done on one special array of binary variables. I use the setPriority-routine for this. But I read, that it does not guarantee, that the branching is also done on another variable. Is there a way to totally prevent cplex from branching on certain variables?
    >
    This can be done by jumping through some technical hoops (you would have to use branch callback and replace any branch that CPLEX intends to do on such a variable by another branch). But eventually CPLEX may have to branch on such a variable. As I said above, CPLEX should accept a solution if it is feasible for the original problem, no matter what cuts or branchings have been added.

    One common mistake with getFeasibilities() and setBounds() is: setBounds() invalidates the solution at the current node. That means that you can no longer call getFeasibilities() or getValues() before you call solve(). So if you want to check feasibility of several variables and also want to setBounds() of several variables then you have to first get the feasibility of all variables before you call setBounds() for any variable.
    Not sure whether you have run into that trap ...
    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Mon June 25, 2012 02:52 PM

    Originally posted by: UteWW


    Hi Daniel,

    sorry, that this entry is a bit lengthy. I summarized the structure of my code. But since I'm not sure, where the problem exactly is, I was not sure, what to skip and what to leave....

    *************************************************************************************
    CALLBACK1:
    > I think we should still try to figure out what goes wrong and why it does not work as expected.
    > It is not completely clear to me how your code currently looks like. Could you post the relevant
    > part of your callback here?
    The callback for the first MIP looks like this:

    ILOHEURISTICCALLBACK2(create_solution, TLModel*, model, Network<sLFRoad>*, net)
    {
    //TLModel is a class in which several NumVarArrays and BoolVarArrays, Constraints and Objective Function of the MIP is stored.
    // The only binary variables are given by IloArray<BoolVarArray> (I call i BoolVarMatrix) _A, _eta, _beta and IloArray<BoolVarMatrix> _kappa. Besides them many Matrices of NumVars a contained in model.
    //Network is a class containing some other parameters

    typedef IloArray<IntegerFeasibilityArray> FeasArray;
    typedef IloArray<FeasArray> FeasMatrix;
    IloEnv env = getEnv();
    try{

    int i,t,k;

    FeasArray feas(env,ne);
    FeasArray feasbeta(env,ne);
    FeasArray feaseta(env,ne);
    FeasMatrix feaskappa(env,ne);

    for(i=0; i<ne; i++)
    {
    feas[i] = FeasArray(env);
    feasbeta[i] = FeasArray(env);
    feaseta[i] = FeasArray(env);
    feaskappa[i] = FeasArray(env,nk[i]);
    }

    //in vals werden unter anderem die Lösungswerte für die Variablen aus "model" gespeichert
    TLValues* vals = new
    TLValues(env,ne,nt,&nk,net->_dx,net->_dt, net->_nS, &(net->_nnS), &(net->_S));
    for(i=0; i<ne;i++)
    {
    getValues(vals->_A[i], model->_A[i]);
    getFeasibilities(feas[i], model->_A[i]);
    getFeasibilities(feasbeta[i], model->_beta[i]);
    getFeasibilities(feaseta[i], model->_eta[i]);
    for(k=0; k<nk[i];k++)
    {
    feaskappa[i][k] = IntegerFeasibilityArray(env);
    }
    for(k=0; k<nk[i];k++)
    {
    getFeasibilities(feaskappa[i][k], model->_kappa[i][k]);
    }
    http://...
    }
    if(vals->create_tlsetting()==0) //create_tlsetting sets all entries of _A, which are not integer feasible, to a binary value.
    {
    //Now, the other values of the remaining variables are computed and stored in vals. Furthermore, the objective function value objval of the instance is computed.
    http://...
    //now comes the setBound-part to check the found solution
    for(i=0; i<ne; i++)
    {
    for(t=0; t<nt; t++)
    {
    if(feas[i][t]!=ImpliedFeasible)
    {
    setBounds(model->_A[i][t],vals->_A[i][t],vals->_A[i][t]);
    }
    }
    }
    feas.end();

    //The same is done for model->_beta, model->_eta and model->_kappa
    http://...

    IloNumVarArray varsarray(env);
    IloNumArray valsarray(env);

    //x for(i=0;i<ne;i++)
    //x {
    //x for(t=0;t<nt;t++)
    //x {
    //x varsarray.add(model->_A[i][t]);
    //x valsarray.add(vals->_A[i][t]);
    //x }
    //x }
    //x http://... //followed by all the other variables

    if(solve()){
    env.out() << "object value = " << getObjValue() << ", obvjal=" << objval << endl;
    //The following part is commented out because even though getObjValue() is equal to objval in the output, the if-clause is never entered
    //x if(getObjValue()==objval)
    //x {
    //x env.out() << "use heuristic solution1";
    //x setSolution(varsarray, valsarray, objval);
    //x }
    //x else
    //x {
    //x env.out() << "use heuristic solution2";
    //x setSolution(varsarray, valsarray);
    //x }
    //x env.out() << endl;

    }
    else{
    env.out() << "x";
    }

    setSolution(varsarray, valsarray);
    //setSolution only works, when it is used with empty arguments, like here. When I comment out that line and use the lines marked with //x, the solution is not used by cplex.

    varsarray.end();
    valsarray.end();

    }//end if _A is valid

    }
    catch (...) {
    throw;
    }

    }

    *******************************************************************
    CALLBACK2:

    > Could you describe in more detail what your problem is?

    I think, the best is, to describe the problem along with the code.
    The callback for the second MIP create an IP which itself is solved by cplex. Here, I use a different IloEnvironment for the inner IP. But I'm not too sure, if I do it in the correct way. At the moment, I have the feeling, that the problem might have to do with the inner IP.
    The structure of this callback looks like this:
    ILOHEURISTICCALLBACK2(create_solution2, TLModel*, model, Network<sLFRoad>*, net)
    {
    //the beginning is almost the same as in the first callback

    IloEnv env = getEnv();
    IloEnv env2; //second environment for the inner IP
    try{

    int i,t,k;

    FeasArray feas(env2,ne); //as well feasbeta, feaseta and feaskappa as in the first callback
    http://..

    for(i=0; i<ne; i++)
    {
    feas[i] = IntegerFeasibilityArray(env2);
    http://... //and the other feas...

    }

    TLValues* vals = new
    TLValues(env2,ne,nt,&nk,net->_dx,net->_dt, net->_nS, &(net->_nnS), &(net->_S));
    for(i=0; i<ne;i++)
    {
    getValues(vals->_A[i], model->_A[i]);
    getFeasibilities(feas[i], model->_A[i]);
    http://... //and the other feas...
    int s,l,j;

    //create IP

    IloModel model2(env2);
    IloArray<IloBoolVarArray> C(env2,_ne);
    for(i=0;i<_ne;i++)
    {
    C[i] = IloBoolVarArray (env2, _nt);
    for(t=0; t<_nt; t++)
    {
    C[i][t] = IloBoolVar(env2);
    }
    model2.add(C[i]);
    }

    //objective
    IloExpr so(env2);
    for(i=0;i<_ne;i++){
    for(t=0; t<_nt; t++){
    so += vals->_A[i][t]*C[i][t];
    }}
    model2.add(IloMaximize(env2, so));
    so.end();
    ´

    //constraints
    for(t=0; t<_nt; t++)
    {
    for(i=0;i<_ne;i++)
    {
    //Here I check, whether variable _A[i][t] has been fixed during the branch and bound and fix them also for the IP (is that correct?)
    int ub = getUB(model->_A[i][t]);
    int lb = getLB(model->_A[i][t]);
    if(vals->_If[i][t]==1 && ub==lb)
    {
    IloRange rg(env2,vals->_A[i][t],C[i][t],vals->_A[i][t],rgnm);
    model2.add(rg);
    }
    }
    }

    //also some other constraints follow
    http://...
    IloCplex cplex2(env2);
    cplex2.extract(model2);
    cplex2.setOut(env2.getNullStream());

    if(cplex2.solve()){
    cout << "inner IP solved" << endl;

    //according to the solution all values of variables are computed and stored in vals->_... and objval is computed
    http://...
    //then setBounds and SetSolution routines follows as in the upper version.

    }
    }
    } //end try
    catch (...) {
    throw;
    }
    }
    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Mon June 25, 2012 02:54 PM

    Originally posted by: UteWW


    oh... somehow by copying the text http:// ... transformed into http://....
    At these points I just wanted to indicate that Code is skipped.
    #CPLEXOptimizers
    #DecisionOptimization


  • 8.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Mon June 25, 2012 03:28 PM

    Originally posted by: SystemAdmin


    OK, lets start with your first callback. Things like
    
    getObjValue() == objvalue
    

    will not work as expected in most cases. The problem is numerical round-off. Due to numerical round-off the two values may differ by a very small amount, for example 1e-12. As a rule of thumb, you should never use '==' or '!=' to compare values of type 'double'.
    Moreover, you should not set 'valsarray' explicitly. Instead you should fetch the solution from CPLEX. I think the end of your callback should look something like this:
    
    
    // Do getFeasbilities() and setBounds(). ... 
    
    if ( solve() ) 
    { 
    // A feasible solution was found for the bound settings. env.out() << 
    "Feasible solution found (" << getObjValue() << 
    ")." << endl; 
    // Store _all_ variables in your model in varsarray. IloNumVarArray varsarry(env); 
    
    for (each variable v in the model) varsarray.add(v); 
    // Now fetch the solution values that CPLEX computed. IloNumArray valsarray(env); getValues(valsarray, varsarray);   
    // Compare objective values with tolerance. 
    // Actually, I think this is redundant and you should just always 
    // use the 'else' branch. 
    
    if ( fabs(getObjValue() - objvalue) < 1e-6 ) 
    { env.out() << 
    "Injecting solution with objective value" << endl; setSolution(varsarray, valsarray, getObjValue()); 
    } 
    
    else 
    { env.out() << 
    "Injecting solution without objective value" << endl; setSolution(varsarray, valsarray); 
    } valsarray.end(); varsarray.end(); 
    }
    

    Does this work any better than what you currently have?
    #CPLEXOptimizers
    #DecisionOptimization


  • 9.  Re: injecting heuristic solutions with HeuristicCallback

    Posted Mon July 23, 2012 04:35 AM

    Originally posted by: UteWW


    Hi,

    Was busy with other things, so it took me a while to apply the changes you proposed. Now I rearranged the code also for the second version of primal heuristic the way you proposed.
    Now it works =)

    Thanks a lot for you help and detailed answers.

    All the best
    Ute
    #CPLEXOptimizers
    #DecisionOptimization