ILOG CPLEX 11.0 User's Manual > Advanced Programming Techniques > Using Goals > Cuts and Goals

Goals can also be used to add global cuts. Whereas local cuts are respected only in a subtree, global cuts are added to the entire problem and are therefore respected at every node after they have been added.

Just as you can add local cuts by means of a local cut goal, as explained in Local Cut Goal, you can add a global cut by means of a global cut goal. A global cut goal is created with the method IloCplex::GoalI::GlobalCutGoal (IloCplex.globalCutGoal or Cplex.GlobalCutGoal). This method takes an instance of IloRange or IloRangeArray (IloRange[]) as its argument and returns a goal. When the goal executes, it adds the constraints as global cuts to the problem.

Example ilogoalex2.cpp shows the use of IloCplex::GoalI::GlobalCutGoal for solving the noswot MILP model. This is a relatively small model from the MIPLIB 3.0 test set, consisting of only 128 variables. Nonetheless, it is very hard to solve without adding special cuts.

Although it is now solvable directly, the computation time is in the order of several hours on state-of-the-art computers. However, cuts can be derived, and the addition of these cuts makes the problem solvable in a matter of minutes or seconds. These cuts are:

x21 - x22 <= 0
x22 - x23 <= 0
x23 - x24 <= 0
2.08*x11 + 2.98*x21 + 3.47*x31 + 2.24*x41 + 2.08*x51 +
0.25*w11 + 0.25*w21 + 0.25*w31 + 0.25*w41 + 0.25*w51 <= 20.25
2.08*x12 + 2.98*x22 + 3.47*x32 + 2.24*x42 + 2.08*x52 +
0.25*w12 + 0.25*w22 + 0.25*w32 + 0.25*w42 + 0.25*w52 <= 20.25
2.08*x13 + 2.98*x23 + 3.47*x33 + 2.24*x43 + 2.08*x53 +
0.25*w13 + 0.25*w23 + 0.25*w33 + 0.25*w43 + 0.25*w53 <= 20.25
2.08*x14 + 2.98*x24 + 3.47*x34 + 2.24*x44 + 2.08*x54 +
0.25*w14 + 0.25*w24 + 0.25*w34 + 0.25*w44 + 0.25*w54 <= 20.25
2.08*x15 + 2.98*x25 + 3.47*x35 + 2.24*x45 + 2.08*x55 +
0.25*w15 + 0.25*w25 + 0.25*w35 + 0.25*w45 + 0.25*w55 <= 16.25

These cuts have been derived after the problem has been interpreted as a resource allocation model on five machines with scheduling horizon constraints and transaction times. The first three cuts break symmetries among the machines, while the others capture minimum bounds on transaction costs.

Of course, the best way to solve the noswot model with these cuts is simply to add them to the model before calling the optimizer. However, for demonstration purposes here, the cuts are added by means of a goal. The source code of this example can be found in the examples/src directory of the ILOG CPLEX distribution. The equivalent Java implementation appears as GoalEx2.java in the same location. Likewise, there is also the C#.NET version in Goalex2.cs and the VB.NET version in Goalex2.vb.

The goal CutGoal in that example receives a list of "less than" constraints to use as global cuts and a tolerance value eps. The constraints are passed to the goal as an array of lhs expressions and an array of corresponding rhs values. Both are initialized in function makeCuts.

The goal CutGoal checks whether any of the constraints passed to it are violated by more than the tolerance value. It adds violated constraints as global cuts. Other than that, it follows the branching strategy ILOG CPLEX would use on its own.

The goal starts out by checking whether the solution of the continuous relaxation of the current node subproblem is integer feasible. This check is done by the method isIntegerFeasible. If the current solution is integer feasible, a candidate for a new incumbent has been found, and the goal returns the empty goal to instruct ILOG CPLEX to continue on its own.

Otherwise, the goal checks whether any of the constraints passed to it are violated. It computes the value of every lhs expression for current solution by calling getValue(lhs[i]). The result is compared against the corresponding righthand side value rhs[i]. If a violation of more than eps is detected, the constraint is added as a global cut and the rhs value will be set to IloInfinity to avoid checking it again unnecessarily.

The global cut goal for lhs[i] rhs[i] is created by the method GlobalCutGoal. It is then combined with the goal named goal by the method AndGoal, so that the new global cut goal will be executed first. The resulting goal is stored again in goal. Before adding any global cut goals, the goal is initialized as

IloCplex::Goal goal = AndGoal(BranchAsCplexGoal(getEnv()), this);

for C++, or for Java:

cplex.and(cplex.branchAsCplex(), this);

The method BranchAsCplexGoal(getEnv) ((cplex.branchAsCplex) creates a goal that branches in the same way as the built-in branch procedure. By adding this goal, the current goal will be executed for the entire subtree.

Thus the goal returned by CutGoal will add all currently violated constraints as global cuts one by one. Then it will branch in the way ILOG CPLEX would branch without any goals and execute the CutGoal again in the child nodes.