Decision Optimization

Decision Optimization

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


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
  • 1.  Getting the objective of the root node

    Posted 05/02/13 10:18 AM

    Originally posted by: JorisK


    Dear,

    I have implemented a Mixed integer model using the java interface of cplex 12.5.0.1. In order to obtain the LP relaxation and the corresponding variable values, i.e. the solution of the root node *after* all cuts have been added, I have added a simple branch callback:

     

    private class BranchCallbackImpl extends BranchCallback{
          @Override
          protected void main() throws IloException {
         
         IloIntVar[] flowVarArray=mipData.flowVars.values().toArray(new IloIntVar[mipData.flowVars.size()]);
         flowValues=this.getValues(flowVarArray);
         
         IloIntVar[] complVarArray=mipData.complVars.values().toArray(new IloIntVar[mipData.complVars.size()]);
         complValues=this.getValues(complVarArray);
         
         IloIntVar[] fulfVarArray=mipData.fulfVars.values().toArray(new IloIntVar[mipData.fulfVars.size()]);
         fulfValues=this.getValues(fulfVarArray);
         
         objectiveValue=this.getBestObjValue();
         this.abort();
          }
    }

     

    I ran my code both on cplex 12.4 and cplex 12.5.0.1. The lp relaxation of the model using cplex 12.4 results in an objective of 135, whereas cplex 12.5.0.1 produces a solution with objective 150. Since its a minimization problem, cplex 12.4 produces a stronger LP relaxation than cplex 12.5.0.1. Apparently, cplex 12.5.0.1 uses different cuts than 12.4?

    When I remove the above callback and in fact solve (using 12.5.0.1) the integer problem, I get the following output:

    ====================================

     

            Nodes                                         Cuts/
       Node  Left     Objective  IInf  Best Integer    Best Bound    ItCnt     Gap
     
    *     0+    0                           85.0000      150.0000      116   76.47%
          0     0      150.0000    28       85.0000      150.0000      116   76.47%
          0     0      150.0000    31       85.0000      Cuts: 12      168   76.47%
          0     0      150.0000    28       85.0000     Covers: 1      192   76.47%
          0     0      150.0000    37       85.0000      Cuts: 32      247   76.47%
          0     0        cutoff             85.0000       85.0000      247    0.00%
    Elapsed time = 0.07 sec. (22.61 ticks, tree = 0.00 MB, solutions = 1)
     
    Cover cuts applied:  1
    Implied bound cuts applied:  3
    Zero-half cuts applied:  4
    Gomory fractional cuts applied:  3
     
    Root node processing (before b&c):
      Real time             =    0.05 sec. (19.32 ticks)
    Parallel b&c, 8 threads:
      Real time             =    0.00 sec. (0.00 ticks)
      Sync time (average)   =    0.00 sec.
      Wait time (average)   =    0.00 sec.
                              ------------
    Total (root+branch&cut) =    0.05 sec. (19.32 ticks)

    ======================================

    Judging from the output (MipInterval=1), it seems that cplex does not branch, i.e. that the optimal solution is found at the root node? So I'm wondering:

    1. why did cplex invoke the BranchCallBack in the first place, as it apparently finds the optimal solution at the root node?

    2. why does my BranchCallBack produce an objective of 150, whereas in the above output, the optimal solution found at the root node has an objective of 85?


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Getting the objective of the root node

    Posted 05/03/13 10:57 AM

    Originally posted by: JorisK


    An additional question:

    I have a simple maximization objective:

     

    ===============

    IloLinearIntExpr obj=cplex.linearIntExpr();
    for(Customer c: rmcp.customers){
       obj.addTerm(c.demand, fulfVars.get(c));
    }
    cplex.addMaximize(obj);

    ===============

    As mentioned in the topic start, I query the LP relaxation via a branch callback. At the end of the callback, I have added the following verification code:

    ===============

     

    objectiveValue=this.getBestObjValue();
    double realObjective=0;
    for(Customer c : rmcp.customers)
       realObjective+=c.demand*this.getValue(fulfVars.get(c));
    if(Math.abs(objectiveValue-realObjective)>Constants.EPSILON)
       throw new RuntimeException("Deviation in objective! Real: "+realObjective+" expected: "+objectiveValue+" instance: "+rmcp.fileName);

    ===============

    In short, I do the following:

    1. ask cplex to provide the objective of the LP relaxation via the getBestObjValue() function.
    2. ask cplex for the values of the variables, and recompute the objective manually.

    Finally, I compare the results of (1) and (2), which obviously should be the same. However, I get the following exception:

    Exception in thread "main" java.lang.RuntimeException: Deviation in objective! Real: 437.48031496063913 expected: 439.9999999999999 instance: A_2_45_4.rmc

    So, there is a significant deviation between what cplex gives me as the objective of the LP relaxation, and the actual objective I get when using the variable values. Is this a bug, or is there an obvious explanation? It only seems to happen occasionally; usually the callback ends gracefully without a runtime exception. Note that the the demand of a customer, i.e c.demand is an integer value between 120 and 480 for this instance, so no big numbers. Consequently, I don't think this is a rounding issue?


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Getting the objective of the root node

    Posted 05/06/13 03:07 AM

    The issue may still be numerics. Could you attach a SAV file for a model that exhibits this strange behavior?


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Getting the objective of the root node

    Posted 05/06/13 06:49 AM

    Originally posted by: JorisK


     

    Dear Daniel Junglas,
     
    I conducted some additional testing. With cplex 12.4, my application throws the following exception:
    -Exception in thread "main" java.lang.RuntimeException: Deviation in objective! Real: 435.71428571429425 expected: 439.9999999999892 instance: A_2_45_4.rmc
    With cplex 12.5.01, I get the following exception:
    -Exception in thread "main" java.lang.RuntimeException: Deviation in objective! Real: 431.77631578949126 expected: 442.50000000000006 instance: A_2_45_4.rmc
    Note that the difference between the 'real' and 'expected' objectives is significantly larger for cplex 12.5.01!
     
    Attached files: 2 SAV files (created resp. by cplex 12.4 and 12.5.01), a small Java test class, and the log files of the original model.
    The SAV files are generated by exporting the model right before the exception is thrown, i.e:
    ==========
    if(Math.abs(objectiveValue-realObjective)>Constants.EPSILON){
       cplex.exportModel("lp_bug.sav");
       throw new RuntimeException("Deviation in objective! Real: "+realObjective+" expected: "+objectiveValue+" instance: "+rmcp.fileName);
    }
    ==========
    The attached Java class (Test.java) does the following:
    -read the model from the SAV file
    -add a branch callback to calculate the objective of the root node.
    -the branch callback also has some verification code to check the correctness of the reported objective
    Note: I consistently run Test.java with cplex 12.4 for the SAV file produced by cplex 12.4, and cplex 12.5.01 for the SAV file produced by cplex 12.5.01.
     
    Observations:
    1. Test.java throws an exception when solving the SAV file from cplex 12.4:
    -Exception in thread "main" java.lang.RuntimeException: Deviation in objective! Real: 435.71428571429425 expected: 439.9999999999892
    This exception is identical to the one reported above!
    2. Test.java does *NOT* throw an exception when solving the SAV file from cplex 12.5.01! Hence, using the cplex 12.5.01 SAV file, I am *NOT* able to reproduce this strange behavior. However, as reported above, the strange behavior does occur in my java implementation of the model. For some reason, the exported model in the cplex 12.5.01 SAV file behaves correct, whereas the original model does not. If needed, I can e-mail you my code which produces the strange behavior with cplex 12.5.01.
     
     
    > If I understand correctly then you run your program twice: once with branch callback and once without branch callback. That the run without branch
    > callback terminates at the root node does not mean the run with the branch callback will terminate at the root node as well. Could you also
    > attach a log for the run with the branch callback?
    See the attached log 'rootnode.log' (produced with cplex 12.5.01).
     
    Kind regards,
     
    Joris

    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: Getting the objective of the root node

    Posted 05/14/13 01:19 AM

    Sorry, I missed the real problem in your original post. This statement is wrong:

    double objectiveValue=this.getBestObjValue();

    you should instead use

    double objectiveValue=this.getObjValue();

    Function getBestObjValue() returns the global dual bound (which in your case is the maximum of the dual bounds for all open nodes) while getObjValue() returns the objective function value for the current node. See also the reference documentation of the IloCplex.BranchCallback class.


    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: Getting the objective of the root node

    Posted 05/22/13 10:40 AM

    Originally posted by: JorisK


    Dear Daniel Junglas,

    Thank you again for your help. Your answer resolved the problem. Just to clarify things:

    -If the branch callback has not been invoked, i.e. an integer solution is obtained at the root node, then you can query the LP relaxation using getBestObjValue();

    -Inside the branch callback invoked immediately after the root node has been solved, you have to use the getObjValue() function to obtain the LP relaxation of the root node.

    You mentioned that getBestObjValue() returns the global dual bound, i.e. the best dual bound over all open nodes. But the problem I mentioned occurred at the root node, so there are no other open nodes right?


    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: Getting the objective of the root node

    Posted 05/29/13 03:41 AM

    Right, at the root node there are no other open nodes. At the root node one would expect getObjValue() and getBestObjValue() to return the same value.


    #CPLEXOptimizers
    #DecisionOptimization


  • 8.  Re: Getting the objective of the root node

    Posted 05/06/13 03:06 AM

    It is entirely possible that CPLEX 12.4 uses different cuts than 12.5. That is expected behavior.

    If I understand correctly then you run your program twice: once with branch callback and once without branch callback. That the run without branch callback terminates at the root node does not mean the run with the branch callback will terminate at the root node as well. Could you also attach a log for the run with the branch callback?


    #CPLEXOptimizers
    #DecisionOptimization