Example: deriving the simplex callback ilolpex4.cpp

Illustrates derivation of a simplex callback in the C++ API.

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 methods getNiterations, isFeasible, getObjValue, and getInfeasibility are methods provided in the base class of the callback, IloCplex::ContinuousCallbackI (IloCplex.ContinuousCallback or Cplex.ContinuousCallback). See the Reference Manual of the C++ API 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::SimplexCallbackI {
void main();
  IloCplex::CallbackI* duplicateCallback() const {
    return (new (getEnv()) MyCallbackI(*this));
  }
}; 
IloCplex::Callback MyCallback(IloEnv env) {
  return (IloCplex::Callback(new (env) MyCallbackI()));
}

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++

  • cplex.use(new MyCallback()); in Java

  • cplex.Use(new MyCallback()); in .NET

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

If your application defines more than one simplex callback object (possibly with different subclasses), only the last one passed to CPLEX with the use method is actually used during simplex. On the other hand, IloCplex can manage 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).