Decision Optimization

Decision Optimization

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


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
  • 1.  Difference in CPLEX root node cuts leading to different values

    Posted 12/27/19 10:23 PM

    Originally posted by: UserCplex


    Hello,

    I have an MIP -- problemIP.lp. This is a minimization problem.

    When I read this problem in and solve it using the executable built out of 1.cpp, it indicates the optimal solution of 5466 obtained in the root node itself. When this file is read in using the interactive optimizer and solved using default cplex parameters, one can also verify that the optimal solution of 5466 is obtained at the root node itself without the need for any branching.

    When I read this problem in and solve it using the executable built out of 2.cpp, it outputs the linear program associated with the root node. This LP, file, (nodelp_0.lp) however, has an optimal objective function of only 5138.54.

    I was expecting that nodelp_0.lp would be the file containing all cuts that helped CPLEX raise the lower bound upto 5466.

    Would it be possible to know why 2.cpp does not provide an output file, nodelp_0.lp containing all CPLEX cuts as I would have expected?

    Thanks.

     

     


    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Difference in CPLEX root node cuts leading to different values

    Posted 12/30/19 08:33 PM

    Originally posted by: EdKlotz


    First of all, to save any other readers time, the difference between 1.cpp and 2.cpp (which actually use the C API) is that 1.cpp is basically the mipex2.c example that reads in a model in an LP, MPS or SAV file and solves it.    2.cpp does the same thing, but has a solve callback that writes out node LPs; it is essentially the wrtnode.c program that can be found here:

    https://www.ibm.com/support/pages/sample-c-program-retrieve-cuts-added-cplex-during-mip-optimization

     

    Regarding

    > I was expecting that nodelp_0.lp would be the file containing all cuts that helped CPLEX raise the lower bound upto 5466.

    Be careful about your definition of the root node LP.   The root node LP includes the initial LP relaxation solve, which involves no cuts at all (other than any simple cuts obtained during presolve that are bound changes that result in removal of variables).   The nodelp_0.lp in your program is this initial LP relaxation solve, and it never involves cuts.   Furthermore, for this model, it has a sub optimal objective, as can be seen by running interactive CPLEX on the problemIP file.   Here we see that the root node consists not only of the initial LP relaxation solve, but subsequently LP relaxation solves associated with the root node cut loop:

     


            Nodes                                         Cuts/
       Node  Left     Objective  IInf  Best Integer    Best Bound    ItCnt     Gap

    *     0+    0                         6152.0000        0.0000           100.00%
          0     0     3752.0000     9     6152.0000     3752.0000       18   39.01%             // this is the initial root node LP relaxation value
    *     0+    0                         6099.0000     3752.0000            38.48%
          0     0     4812.2656     7     6099.0000      Cuts: 52       51   21.10%
    *     0+    0                         5482.0000     4812.2656            12.22%
          0     0     5056.2801     8     5482.0000      Cuts: 62       79    7.77%
          0     0     5072.5000     4     5482.0000      Cuts: 26       83    7.47%
          0     0     5080.2254     8     5482.0000    MIRcuts: 3       92    7.33%
          0     0     5110.5010     9     5482.0000       Cuts: 7      109    6.78%
          0     0     5121.6906     8     5482.0000      Cuts: 12      121    6.57%
    *     0+    0                         5466.0000     5121.6906             6.30%
          0     0        cutoff           5466.0000     5466.0000      121    0.00%

     

    So yes, this model solves at the root node, but only after several cut passes, so you want to look at the final node LP exported by your 2.cpp program, not the first one, if you want to examine the cuts CPLEX generated.  However, the final node LP still may not match the optimal objective value.   The node log above indicates that the penultimate node LP has an objective of 5121.6906, but that the final node LP has no objective because the last node LP solve was determined to exceed the cutoff value and terminated early.   Still, the final exported node LP will have all the cuts CPLEX generated.

     

    Also, while I don't think it really matters for your particular question here, note that by adding a solve callback you disable dynamic search and restrict the optimization to a single thread, which could lead to other differences in the optimization for your 2.cpp program relative to the 1.cpp program which will run dynamic search and use multiple threads.    So that can lead to other differences in the optimization performed by your 2 programs, e.g. the 1.cpp program may use heuristics more effectively and, if the solve goes part the root node, benefit more from dynamic search.


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Difference in CPLEX root node cuts leading to different values

    Posted 12/30/19 10:24 PM

    Originally posted by: UserCplex


    Ed,

    Thanks. 

     

    In the wrtnode.c program, (if I understand you correctly), the final root node LP is the file obtained via

    sprintf (filename, "nodelp%d_%d", count, nodecount);
    

    where count is the maximum amongst all all such files where nodecount is 0. Is that right?

     


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Difference in CPLEX root node cuts leading to different values

    Posted 12/30/19 10:57 PM

    Originally posted by: UserCplex


    Ed,

    You state:

    " The nodelp_0.lp in your program is this initial LP relaxation solve, and it never involves cuts."

    I am not quite sure about that. Following are the labels of the cuts cuts that CPLEX has added -- they can be seen in the nodelp_0.lp file itself: m0 through till F139

     

    Note that the way 2.cpp is (it is modified from wrtnode.c) the usersolve callback function is exactly the same as wrtnode.c, except that I have 

     

    sprintf(filename, "nodelp_%d", nodecount);
    strcat(filename, ".lp");

     

    That is, the count information is lost in 2.cpp while it is there in wrtnode.c

    So, assuming that in wrtnode.c, count will be incremented sequentially as further runds of cutloop passes happen at the same nodecount node, nodelp_0.lp file is precisely the final LP file at the root node. Further, as stated above, it indeed does have CPLEX cuts. Its LP relaxation objective function value is 5138.54 and not 3752.


    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: Difference in CPLEX root node cuts leading to different values

    Posted 12/30/19 11:43 PM

    Originally posted by: EdKlotz


    OK, I think I didn't fully understand how 2.cpp works.   Based on your latest  comments, it basically rewrites a file called nodelp_0.lp for each cut loop pass at the root node LP, during which time the nodecount value queried by CPXcallbackinfo in your solve callback remains at 0.   So your program does write out a nodelp_0.lp without any cuts, but it subsequently overwrites that file during each subsequent cut pass, so the final LP file corresponds to the final LP solve in the root node cut loop pass.   That would explain why you have an objective such as 5138.54.

     

    Getting back to your original question about why the final LP doesn't have all the cuts, let's look at the final few passes through the root node.  

     

    0     0     5110.5010     9     5482.0000       Cuts: 7      109    6.78%
          0     0     5121.6906     8     5482.0000      Cuts: 12      121    6.57%
    *     0+    0                         5466.0000     5121.6906             6.30%
          0     0        cutoff           5466.0000     5466.0000     121    0.00%

     

    A CPLEX heuristic finds the optimal solution with objective 5466.   Once it has that, it can do all sorts of things with that information, such as reduced cost fixiing, additional probing, and various other operations that can fix variables and prevent the need for an additional node LP solve.   Note that the cumulative simplex iteration count  stays at 121 in the last line of the node log, suggesting that CPLEX did not solve an additional node LP to get that final best node value of 5466.   You can verify that by either setting a print statement in the callback the reveals each time it writes out a node LP, or similarly just setting a breakpoint in the callback in debug mode.    Rather, CPLEX probably tightened some additional variable bounds and recognized that the root node LP was infeasible and hence didn't bother solving another LP.  So you probably got all the cuts CPLEX generated, although that depends on interpretation in the sense that one can interpret bound tightenings by reduced cost fixing, probing or strong branching as cuts as well.

     

     

     

     


    #CPLEXOptimizers
    #DecisionOptimization