ILOG CPLEX 11.0 User's Manual > Advanced Programming Techniques > Using Optimization Callbacks > Example: Deriving the Simplex Callback ilolpex4.cpp

Example ilolpex4.cpp demonstrates the use of the simplex callback to print logging information at each iteration. It is a modification of example ilolpex1.cpp, so this discussion concentrates on the differences. The following code:

ILOSIMPLEXCALLBACK0(MyCallback) {
  cout << "Iteration " << getNiterations() << ": ";
  if ( isFeasible() ) {
    cout << "Objective = " << getObjValue() << endl;
  } 
  else {
    cout << "Infeasibility measure = " << getInfeasibility() << endl;
  } 
}

defines the callback MyCallback without arguments with the code enclosed in the outer {}. In Java, the same callback is defined like this:

static class MyCallback extends IloCplex.ContinuousCallback {
   public void main() throws IloException {
      System.out.print("Iteration " + getNiterations() + ": ");
      if ( isFeasible() )
         System.out.println("Objective = " + getObjValue());
      else
         System.out.println("Infeasibility measure = " 
                             + getInfeasibility());
   }
}

The callback prints the iteration number. Then, depending on whether the current solution is feasible or not, it prints the objective value or infeasibility measure. The functions getNiterations, isFeasible, getObjValue, and getInfeasibility are methods provided in the base class of the callback, IloCplex::ContinuousCallbackI (IloCplex.ContinuousCallback). See the ILOG CPLEX Reference Manual for the complete list of methods provided for each callback class.

Here is the previous sample of code, with the macro ILOSIMPLEXCALLBACK0 expanded:

class MyCallbackI : public IloCplex::PrimalSimplexCallbackI {
public:
  IloCplex::CallbackI* duplicateCallback() const {
    return (new (getEnv()) MyCallbackI(*this));
  } 
  MyCallbackI(IloEnv env) : IloCplex::PrimalSimplexCallbackI(env) {}
  void main();
};
IloCplex::Callback MyCallback(IloEnv env) {
  return (IloCplex::Callback(new (env) MyCallbackI(env)));
}

void MyCallbackI::main() {
  cout << "Iteration " << getNiterations() << ": ";
  if ( isFeasible() ) {
    cout << "Objective = " << getObjValue() << endl;
  }
  else {
    cout << "Infeasibility measure = " << getInfeasibility() << endl;
  }
}

The 0 (zero) in the macro indicates that no arguments are passed to the constructor of the callback. For callbacks requiring up to 7 arguments, similar macros are defined where the 0 is replaced by the number of arguments, ranging from 1 through 7. For an example using the cut callback, see Example: Controlling Cuts iloadmipex5.cpp. If you need more than 7 arguments, you will need to derive your callback class yourself without the help of a macro.

After the callback MyCallback is defined, it can be used with the line:

cplex.use(MyCallback(env));

in C++ or

cplex.use(new MyCallback());

in Java, or in .NET

cplex.Use(new MyCallback());

In the case of C++, function MyCallback creates an instance of the implementation class MyCallbackI. A handle to this implementation object is passed to cplex method use.

If your application defines more than one simplex callback object (possibly with different subclasses), only the last one passed to ILOG CPLEX with the use method is actually used during simplex. On the other hand, IloCplex can handle one callback for each callback class at the same time. For example, a simplex callback and a MIP callback can be used at the same time.

The complete program, ilolpex4.cpp, appears online in the standard distribution at yourCPLEXinstallation/examples/src. In the same location, there are also samples in Java (LPex4.java) and in the .NET API (LPex4.cs and LPex4.vb).