Originally posted by: EdKlotz
I don't think lazy constraints are the best way to accomplish this. First of all, telling CPLEX to enumerate all possible solutions in the model disables a lot of CPLEX's node pruning features and will slow performance. In that case, CPLEX can only prune a node when enough branches have made it infeasible. No pruning based on the primary objective is possible. Now, you could restrict the solution pool to enumerating just the optimal solutions, applying a lazy constraint callback as you described to optimize the secondary goal. But, this seems more complicated than just minimizing the first objective, adding a constraint that the first objective equals the optimal value you just obtained, then minimizing the second objective. I think that would be easier and also probably run faster. Is there some reason you don't want to take that approach (e.g. you may want to generalize the priorities on the two objective from the pure lexicographic approach you mention above to something involving Pareto optimality)?
Nonetheless, if you want to take this approach, have a look at the BendersATSP.java example that comes with the CPLEX distribution to see how to use the IloCplex.LazyConstraintCallback method to add lazy constraints dynamically during the course of the optimization like you describe. However, this example assumes a regular MIP optimization, not the 2-phase optimization associated with the solution pool. The Populate.java example shows how to use the solution pool feature to accumulate solutions within 10% of optimal. So, essentially you could modify that example to have the solution pool find solutions that are optimal, then merge some of the code in the BendersATSP.java example that uses the LazyConstraint callback. You would need to replace the code in BendersATSP.java that generates subtour elimination constraints for a TSP problem as lazy constraints with your lazy constraints involving the secondary objective. You should also have a look at the documentation on the solution pool in the user manual. If you are going to use callbacks with the solution pool, you need to be clear on how the solution pool operates. Namely, it is a two phase approach. In the first phase, CPLEX solves the MIP to optimality (or whatever stopping criterion you specify), but it retains nodes it would normally prune if they have potential to yield sub optimal solutions that are still of interest based on the solution pool parameters you have specified (e.g. solutions within 10% of optimal as in Populate.java). In the second phase, after it knows the optimal objective value,
CPLEX processes the remaining nodes, branching as needed to find additional solutions. For some slides with additional info on this, try
http://www.stanford.edu/dept/ICME/docs/seminars/Danna-2008-01-30.pdf
and if you need to dig even deeper, have a look at
Emilie Danna, Mary Fenelon, Roland Wunderling,
Zonghao Gu. Generating multiple solutions for mixed
integer programming models. Proceedings of IPCO
2007. LNCS 4513, pages 280-294.
Another approach to consider if you may want to generalize your prioritization of the two (or more) objective involves using a branch callback function. You probably would not need to change CPLEX's branching selection (although you could if you thought that would help performance). Rather, you would use the makeBranch(int i,java.lang.Object data)
method branch as CPLEX would do, but you would call the prune() method of IloCplex.BranchCallback to prune certain nodes based on the two (or more) objectives rather than the single objective criterion CPLEX uses.
#CPLEXOptimizers#DecisionOptimization