Decision Optimization

Decision Optimization

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


#Analytics
#DecisionOptimization
#DecisionOptimization
 View Only
  • 1.  Gracefully handling a time limit while generating a cut

    Posted 09/03/13 12:17 AM

    Originally posted by: JorisK


    Dear,
     
    I've a branch-and-cut procedure where the cuts are generated using a LazyCutCallback (cplex 12.5.1+java interface). What I would like to do is to put a time limit on the total solution procedure, say 5 minutes. I can put a time limit on the solution procedure of cplex, but, since my cutting procedures in the LazyCutCallback are handled separately, I also need to limit the time allowed to calculate a single cut. This however poses a problem: what do you do if the time limit is reached while calculating a cut? In such a case, it is not certain whether the solution violates some constraints, so its unclear whether a cut should be generated or not. Is there a way to communicate this to cplex? 
    How would you handle such a case? If I would simply generate a cut, I might wrongly cut-off a feasible solution. Alternatively, if I would not generate a cut, I might wrongly allow a infeasible solution. I hope that my point is more or less clear. So basically, if a time limit occurs during the cutting procedure, cplex must return to the state it was in right before the callback was invoked, as the callback could not be completed in time.
     
    br,
     
    Joris

    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Gracefully handling a time limit while generating a cut

    Posted 09/03/13 09:53 AM

    Wow, this is really difficult. Note that CPLEX will not interrupt your separation routine. So unless you interrupt the routine yourself you can just run it to completion (unless of course it is too time consuming).

    One thing you could do is to just run your separation routine on the solution that IloCplex.getValues() returns after solve() returns. This should tell you if you missed a cut in the callback or not. If you plan to continue optimization after the timeout then this will not work. In that case the only solution I currently see is this sequence of callbacks:
    1. If the separation in the lazy constraint callback times out without separating a cut then mark the node as "problematic" (using node user data).
    2. Add an incumbent callback. Whenever this callback is presented with a feasible solution at a node that is marked "problematic" then it rejects that incumbent. Rejecting incumbents on integral nodes requires you to add a
    3. branchcallback. Usually this callback does nothing. If it is invoked on a node that is marked "problematic" then it just creates a single new node without additional constraints (or just dummy constraints). This eventually will result in the problematic being processed again.


    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Gracefully handling a time limit while generating a cut

    Posted 09/03/13 02:39 PM

    Originally posted by: JorisK


    Dear Daniel,

    Thanks for your answer. I think I get the idea of what you are suggesting. However, it is beyond my cplex knowledge to implement this without some help. Here is what I think I should have. Can you check whether this makes sense or whether I'm missing something?

    Code: http://pastebin.com/Hg0iSbAE
     

    Btw, how do I paste code in this forum such that syntax highlighting and indentation is preserved? 

    With respect to the above code, I'm especially uncertain about the BranchCallback implementation. 

    3. branchcallback. Usually this callback does nothing. If it is invoked on a node that is marked "problematic" then it just creates a single new node without additional constraints (or just dummy constraints). This eventually will result in the problematic being processed again.

    How should I do this? 


    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Gracefully handling a time limit while generating a cut

    Posted 09/03/13 05:20 PM

    Your code looks almost correct. But as of version 12.5 the handling of user node data has been improved. There is no longer a need to always set this in the branch callback. You can directly set it in other callbacks. So this should do the trick (untested code)

    // Empty class to mark problematic nodes.
    // We just use the presence of a node data object to indicate that a node is problematic.
    public class Mark implements IloCplex.MIPCallback.NodeData { public void delete() {} }

    public class LazyCutCallbackImpl2 extends LazyConstraintCallback{
        @Override
        protected void main() throws IloException {
            //Get the values
            double values[]=...
            //Try to create a cut:
            try{
                this.generateCut(values); //Try to calculate the cut
            }catch(TimeOutException e){ //If a timeout occurs, mark the node as problematic
                setNodeData(new Mark());
            }
        }
    }
        
    public class IncumbentCallbackImpl extends IncumbentCallback{
        @Override
        protected void main() throws IloException {
            if ( this.getNodeData() != null )
               // problematic node, so reject the incumbent
               reject();
        }   
    }

    public class BranchCallbackImpl extends BranchCallback{
        @Override
        protected void main() throws IloException {
            if ( getNodeData() != null ) {
               // problematic node, create a new node that has the same bounds
               // so that the node is evaluated again.
               makeBranch(new IloNumVar[0], new double[0], new IloCplex.BranchDirection[0], getObjValue());
            }
            // for non-problematic nodes we don't do anything so that CPLEX uses
            // its default branches
        }
    }

    As for pasting code in a nice way: There is no way to do that :-( They took this away from us when they moved to the new Forum software a while ago. See also the known issues https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/Improvements%20in%20developerWorks%20Community.

    A completely different option that just came to my mind: Each callback has an abort() method that is supposed to immediately stop the optimization. Do you have an easy way to test whether this indeed would result in re-evaluation of the node? In the meantime I will check CPLEX source code to figure out whether just calling abort() in case of a TimeoutException is enough.


    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: Gracefully handling a time limit while generating a cut

    Posted 09/03/13 11:51 PM

    Sorry for the confusion. I just checked the CPLEX source code and found that calling abort() from the callback is exactly what you want. This will stop the optimization immediately. In case you restart optimization the node will be evaluated again.


    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: Gracefully handling a time limit while generating a cut

    Posted 09/03/13 05:11 PM

    Assuming that your intention is to terminate the solver if you reach the time limit while generating a cut, you could just record the most recent valid incumbent in the lazy constraint callback and take that add your (probably suboptimal) solution. That's really no different from what would happen if you hit the time limit just before entering the callback.

     


    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: Gracefully handling a time limit while generating a cut

    Posted 09/06/13 12:08 AM

    Originally posted by: JorisK


    @DanielJunglas:

    Thank you for your suggestion. The abort() works great. I've performed some tests and indeed, after invoking an abort(), the solve procedure terminates immediately. After aborting the search, it's possible to continue the search by re-invoking the solve() function. Cplex then correctly continues solving the node it was solving when the abort() was called.

    @PaulRubin: You are indeed correct that you can store the most recent valid incumbent, and simply query that solution when terminating the solver. But I think the solution proposed by Daniel is much cleaner as it enables you to continue the search without much effort.

    Would it be possible to update the java documentation of the abort() function? It currently states: "Instructs CPLEX to stop the current optimization after the user-written callback finishes.". This information is very limited and certainly does not reflect the fact that the search can be continued, thereby continuing from the aborted node?


    #CPLEXOptimizers
    #DecisionOptimization


  • 8.  Re: Gracefully handling a time limit while generating a cut

    Posted 10/04/13 12:26 PM

    I forwarded your request to the people who write the reference documentation. Not sure when/if the updates will appear there.


    #CPLEXOptimizers
    #DecisionOptimization