*本文主要記錄和分享學習到的知識,算不上原創html
*參考文獻見連接node
這篇文章主要記錄一些Cplex的Callback的使用方法,採用Java語言。es6
什麼是Callbackapp
第一種:Informational Callbackless
第二種:Query Callbackide
第三種:Control Callback學習
Callbacks allow you to monitor closely and to guide the behavior of CPLEX optimizers. In particular, callbacks (either optimization or tuning callbacks) allow user code to be executed regularly during an optimization or during a tuning session. To use callbacks with CPLEX, you must first write the callback function, and then pass it to CPLEX.ui
This essay concentrates on optimization callbacks.this
There are three types of optimization callbacks:
informational callbacks,
query callbacks,
control callbacks
An informational callback is a user-written routine that enables your application to access information about the current mixed integer programming (MIP) optimization without sacrificing performance and without interfering in the search of the solution space. The algorithms call an informational callback when the algorithm finds it appropriate; for some algorithms, an informational callback is called at every node; for other algorithms, an informational callback is called at convenient points in the progress of the algorithm.
An informational callback can also enable your application to abort (that is, to terminate) optimization.
In the Java API, an informational callback is an instance of MIPInfoCallback or one of these derived subclasses:
IloCplex.DisjunctiveCutInfoCallback IloCplex.FlowMIRCutInfoCallback IloCplex.FractionalCutInfoCallback IloCplex.ProbingInfoCallback
An informational callback is installed in a Java application by the method IloCplex.use().
(1)informational callback 01: Spend at least timeLimit seconds on optimization, but once this limit is reached, quit as soon as the solution is acceptable.
1 public class MIPex4 { 2 static void usage() { 3 System.out.println("usage: MIPex4 <filename> <option>"); 4 System.out.println(" t to use the time-limit-gap callback"); 5 System.out.println(" l to use the logging callback"); 6 System.out.println(" a to use the aborter"); 7 } 8 9 public static void main(String[] args) throws IloException { 10 if ( args.length != 2 ) { 11 usage(); 12 return; 13 } 14 IloCplex cplex=new IloCplex(); 15 /* 16 * Aborter terminates the solve and tuning methods of CPLEX 17 */ 18 Aborter aborter=new Aborter(); 19 boolean useLoggingCallback = false; 20 boolean useTimeLimitCallback = false; 21 boolean useAborter = false; 22 switch ( args[1].charAt(0) ) { 23 case 't': 24 useTimeLimitCallback = true; 25 break; 26 case 'l': 27 useLoggingCallback = true; 28 break; 29 case 'a': 30 useAborter = true; 31 break; 32 default: 33 usage(); 34 return; 35 } 36 cplex.importModel(args[0]); 37 IloLPMatrix lp=(IloLPMatrix)cplex.LPMatrixIterator().next(); 38 /* 39 * cplex.getObjective(): returns the IObjective object of the active model, 40 * or null if no IObjective object is currently in the active model 41 */ 42 IloObjective obj=cplex.getObjective();// 43 if(useTimeLimitCallback){ 44 cplex.use(new TimeLimitCallback(false, cplex.getCplexTime(), 1.0, 0.1)); 45 }else if(useLoggingCallback){ 46 cplex.setParam(IloCplex.Param.MIP.Limits.Nodes, 5000); 47 /* 48 * IloObjectiveSense: 49 * Maximize 50 * Minimize 51 */ 52 double lastObjVal = (obj.getSense() == IloObjectiveSense.Minimize ) ? 53 Double.MAX_VALUE : -Double.MAX_VALUE; 54 cplex.use(new LogCallback(lp.getNumVars(), 0, lastObjVal)); 55 cplex.setParam(IloCplex.Param.MIP.Display, 0);//turn off logging 56 }else if(useAborter){ 57 cplex.use(aborter); 58 } 59 if(cplex.solve()){ 60 System.out.println("Solution status = " + cplex.getStatus()); 61 System.out.println("CPLEX status = " + cplex.getCplexStatus()); 62 } 63 cplex.end(); 64 } 65 66 /* 67 * informational callback 01: 68 * Spend at least timeLimit seconds on optimization, but once this limit is reached, 69 * quit as soon as the solution is acceptable 70 */ 71 static class TimeLimitCallback extends MIPInfoCallback{ 72 boolean aborted; 73 double timeLimit; 74 double timeStart; 75 double acceptableGap; 76 public TimeLimitCallback(boolean aborted,double timeStart,double timeLimit,double acceptableGap) { 77 // TODO Auto-generated constructor stub 78 this.aborted=aborted; 79 this.timeLimit=timeLimit; 80 this.timeStart=timeStart; 81 this.acceptableGap=acceptableGap; 82 } 83 @Override 84 protected void main() throws IloException { 85 // TODO Auto-generated method stub 86 /* 87 * hasIncumbent(): returns true if an incumbent solution has been found when the callback is called. 88 */ 89 if(! aborted && hasIncumbent()){ 90 double gap=getMIPRelativeGap(); 91 double timeUsed=getCplexTime()-timeStart; 92 if(timeUsed>timeLimit && gap<acceptableGap){ 93 System.out.println("Good enough solution at " 94 + timeUsed + " sec., gap = " 95 + gap + "%, quitting."); 96 aborted=true; 97 abort();//terminate 98 } 99 } 100 } 101 } 102 }
(2)informational callback 02: Log new incumbents if they are at better than the old by a relative tolerance of 1e-5; also log progress info every 100 nodes.
1 public class MIPex4 { 2 static void usage() { 3 System.out.println("usage: MIPex4 <filename> <option>"); 4 System.out.println(" t to use the time-limit-gap callback"); 5 System.out.println(" l to use the logging callback"); 6 System.out.println(" a to use the aborter"); 7 } 8 9 public static void main(String[] args) throws IloException { 10 if ( args.length != 2 ) { 11 usage(); 12 return; 13 } 14 IloCplex cplex=new IloCplex(); 15 /* 16 * Aborter terminates the solve and tuning methods of CPLEX 17 */ 18 Aborter aborter=new Aborter(); 19 boolean useLoggingCallback = false; 20 boolean useTimeLimitCallback = false; 21 boolean useAborter = false; 22 switch ( args[1].charAt(0) ) { 23 case 't': 24 useTimeLimitCallback = true; 25 break; 26 case 'l': 27 useLoggingCallback = true; 28 break; 29 case 'a': 30 useAborter = true; 31 break; 32 default: 33 usage(); 34 return; 35 } 36 cplex.importModel(args[0]); 37 IloLPMatrix lp=(IloLPMatrix)cplex.LPMatrixIterator().next(); 38 /* 39 * cplex.getObjective(): returns the IObjective object of the active model, 40 * or null if no IObjective object is currently in the active model 41 */ 42 IloObjective obj=cplex.getObjective();// 43 if(useTimeLimitCallback){ 44 cplex.use(new TimeLimitCallback(false, cplex.getCplexTime(), 1.0, 0.1)); 45 }else if(useLoggingCallback){ 46 cplex.setParam(IloCplex.Param.MIP.Limits.Nodes, 5000); 47 /* 48 * IloObjectiveSense: 49 * Maximize 50 * Minimize 51 */ 52 double lastObjVal = (obj.getSense() == IloObjectiveSense.Minimize ) ? 53 Double.MAX_VALUE : -Double.MAX_VALUE; 54 cplex.use(new LogCallback(lp.getNumVars(), 0, lastObjVal)); 55 cplex.setParam(IloCplex.Param.MIP.Display, 0);//turn off logging 56 }else if(useAborter){ 57 cplex.use(aborter); 58 } 59 if(cplex.solve()){ 60 System.out.println("Solution status = " + cplex.getStatus()); 61 System.out.println("CPLEX status = " + cplex.getCplexStatus()); 62 } 63 cplex.end(); 64 } 65 66 static class LogCallback extends MIPInfoCallback{ 67 IloNumVar[] var; 68 long lastLog; 69 double lastIncumbent; 70 public LogCallback(IloNumVar[] var, int lastLog, double lastIncumbent) { 71 // TODO Auto-generated constructor stub 72 this.var=var; 73 this.lastLog=lastLog; 74 this.lastIncumbent=lastIncumbent; 75 } 76 @Override 77 protected void main() throws IloException { 78 // TODO Auto-generated method stub 79 boolean newIncumbent=false; 80 /* 81 * getNnodes64(): returns the number of nodes processed so far in the active branch-and-cut search 82 */ 83 long nodes=getNnodes64(); 84 if(hasIncumbent() && 85 //integer value: Math.abs(lastIncumbent-getIncumbentObjValue())>1e-5*(1+Math.abs(getIncumbentObjValue())) 86 //numeric value: Math.abs(lastIncumbent-getIncumbentObjValue())>1e-5*(1e-10+Math.abs(getIncumbentObjValue())) 87 Math.abs(lastIncumbent-getIncumbentObjValue())>1e-5*(1+Math.abs(getIncumbentObjValue()))){ 88 lastIncumbent=getIncumbentObjValue(); 89 newIncumbent=true; 90 } 91 if(nodes >=lastLog+100 || newIncumbent){ 92 if(!newIncumbent){ 93 lastLog=nodes; 94 /* 95 * getBestObjValue() returns a bound on the optimal solution value of the active problem at the moment the callback is called. 96 */ 97 System.out.println("Nodes = " + nodes 98 + "(" + getNremainingNodes64() + ")" 99 + " Best objective = " + getBestObjValue()); 100 } 101 if ( hasIncumbent() ) { 102 System.out.println (" Incumbent objective = " + 103 getIncumbentObjValue()); 104 }else { 105 System.out.println(""); 106 } 107 if ( newIncumbent ) { 108 System.out.println("New incumbent values: "); 109 int n = var.length; 110 double[] x = getIncumbentValues(var, 0, n); 111 for (int i = 0; i < n; i++) { 112 System.out.println("x[" + i + "] = " + x[i]); 113 } 114 } 115 } 116 } 117 118 } 119 }
Query or diagnostic callbacks allow you to monitor an ongoing optimization, and optionally to abort it (that is, to terminate it). Query callbacks access more detailed information about the current optimization than do informational callbacks. As a side effect, query or diagnostic callbacks may slow progress.
Furthermore, query or diagnostic callbacks make assumptions about the traversal of a conventional branch & cut tree; those assumptions about a mixed integer program (MIP) may be incorrect during dynamic search or during deterministic search in parallel optimization.
Query or diagnostic callbacks are distinguished by the place where they are called during an optimization. There are nine such places where CPLEX calls a query or diagnostic callback:
The presolve query callback is called regularly during presolve. IloCplex.PresolveCallback in the Java API The crossover query callback is called regularly during crossover from a barrier solution to a simplex basis. IloCplex.CrossoverCallback in the Java API The network query callback is called regularly during the network simplex algorithm. IloCplex.NetworkCallback in the Java API The barrier query callback is called at each iteration during the barrier algorithm. IloCplex.BarrierCallback or IloCplex.ContinuousCallback in the Java API The simplex query callback is called at each iteration during the simplex algorithm. IloCplex.SimplexCallback or IloCplex.ContinuousCallback in the Java API The MIP query callback is called regularly during the branch and cut search. IloCplex.MIPCallback in the Java API The probing query callback is called regularly during probing. IloCplex.ProbingCallback in the Java API The fractional cut query callback is called regularly during the generation of fractional cuts. IloCplex.FractionalCutCallback in the Java API
The disjunctive cut query callback is called regularly during the generation of disjunctive cuts. IloCplex.DisjunctiveCutCallback in the Java API The flow and mixed integer rounding (MIR) cut query callback is called regularly during the generation of flow and MIR cuts. IloCplex.FlowMIRCutCallback in the Java API
In the Java API, a query callback is installed by the method IloCplex.use().
Control callbacks allow you to control the branch & cut search during the optimization of MIP problems. Because control callbacks intervene in the search, the presence of a control callback in an application will cause CPLEX to turn off dynamic search.
As the reader is no doubt familiar, the process of solving a mixed integer programming problem involves exploring a tree of linear programming relaxations. CPLEX repeatedly selects a node from the tree, solves the LP relaxation at that node, attempts to generate cutting planes to cut off the current solution, invokes a heuristic to try to find an integer feasible solution 「close」 to the current relaxation solution, selects a branching variable (an integer variable whose value in the current relaxation is fractional), and finally places the two nodes that result from branching up or down on the branching variable back into the tree.
The user should be aware that the branch & cut process works with the presolved problem.
These callbacks allow sophisticated users to control the details of the branch & cut process. Specifically, users can choose the next node to explore, choose the branching variable, add their own cutting planes, place additional restrictions on integer solutions, or insert their own heuristic solutions.
(1)選擇想要實現的Callback類,寫一個子類;
(2)重寫子類中的main()方法;
(3)而後用IloCplex.use()調用。
If you determine that your application needs to seize control, intervene in the search, and redirect the optimizer, then the following control callbacks are available to do so.
The node callback allows you to query and optionally overwrite the next node CPLEX will process during a branch & cut search. IloCplex.NodeCallback in the Java API
The solve callback allows you to specify and configure the optimizer option to be used for solving the LP at each individual node. IloCplex.SolveCallback in the Java API
The user cut callback allows you to add problem-specific user-defined cuts at each node. IloCplex.UserCutCallback in the Java API
The lazy constraint callback allows you to add lazy constraints; that is, constraints that are not evaluated unless they are violated. IloCplex.LazyConstraintCallback in the Java API
The heuristic callback allows you to implement a heuristic that tries to generate a new incumbent from the solution of the LP relaxation at each node. IloCplex.HeuristicCallback in the Java API
The branch callback allows you to query and optionally overwrite the way CPLEX will branch at each node. IloCplex.BranchCallback in the Java API
The incumbent callback allows you to check and optionally reject incumbents found by CPLEX during the search. IloCplex.IncumbentCallback in the Java API
In Java, there is no way of removing individual callbacks from yourIloCplexorCplexobject. Instead, you remove all callbacks by calling the methodIloCplex.clearCallbacksorCplexClearCallbacks.