In eplex, constraints added to a problem are removed on backtracking. However, it is sometimes possible to discover constraints that are valid for the whole problem, which the user wish to apply even after backtracking – such constraints are referred to as ‘global cuts’.

In addition, the user may want to remove some constraints from the problem being solved, because they do not help to constrain the problem, but they slow down the solving of the problem.

To support this, eplex allow constraints to be added to a cutpool associated with a problem, instead of directly to the problem. The main differences from the normal problem constraints are:

- they are not removed on backtracking. Once added to a cutpool, a constraint exists until the problem itself is destroyed.
- they are handled differently during solving, and the user has more control on how the external solver takes the constraints into account.

Logically, cutpool constraints are always valid for the problem, and so should be considered when the problem is solved. Unlike normal constraints, cutpool constraints are not necessarily added to the solver’s problem matrix, and if they are added, they are added only for the solving, and removed from the problem matrix after the solving.

When the external solver solves the problem, eplex ensures that the cutpool constraints are consistent with the problem, i.e. none of the constraints are violated. The cutpool constraints can either be added to the problem matrix immediately, or they can be checked for violation after the solver solves the problem. Any violated constraints are then added to the problem, and the problem resolved. This is repeated until either a fix-point is reached, where no constraints are violated, or if the external solver is unable to solve the problem.

If the external solver does not produce a solution, then:

- if the problem is unbounded, any outstanding cutpool constraints are added to the problem matrix without checking for violation, and the external solver is invoked for one more time. This is because the extra constraints may make the problem bounded.
- if the problem is infeasible, then failure occurs as normal (with the default infeasible handler behaviour).

This multiple invocation of the solver occurs within an eplex’s call to the external solver to solve a problem, and so the process should be transparent to the user, except that the setting of the timeout applies to each solver invocation, rather than to the whole solving process.

The user can specify how the cutpool constraints are treated: they can be either added to the problem matrix before invoking the solver, or only added if violated. In addition, cutpool constraints can be made inactive, in which case they are not considered for adding to the problem matrix at all (and are not checked for violations). This is provided for efficiency reason – if the user knows for certain constraints would not be violated by the solution, they can be made inactive. It is the user’s responsibility to ensure the correctness in this case.

Unlike normal problem constraints, cutpool constraints cannot add new variables to the problem, i.e. the constraint must only involve problem variables that are present in the problem during solver set up. This is because cutpool constraints are globally valid, and so cannot involve variables that may not exist after backtracking. Variables can be added to a problem before solver set up by posting constraints involving them, including reals/1, which simply declares variables as problem variables.

Additionally, each cutpool constraint belongs to a named group, specified when the constraint is added. This allows the user to classify the cutpool constraints into different groups, and then manipulate a groups of constraints as a whole, e.g. making them all inactive. A default group is predefined, to which cutpool constraints belongs unless specified otherwise. To add cutpool constraints to other groups, the group name must first be created with the cutpool_group option of lp_get/3.

Constraints are added to the cutpool using:

Add the constraints to the cut-pool associated with the problem specified by the handle. By default, the constraints belong to the default group, and are active and have the ‘add initially’ status set. These can be over-ridden by the Options argument. The predicate returns a list of indices for these constraints in Idxs.

Information on cutpool constraints can be obtained using the cutpool_info option of lp_get/3. The status of a cutpool constraint, such as its active status, can be set using the cutpool_option option of lp_set/3 – the change is non-logical, i.e. it is not undone on backtracking.

Using lp_get/3 and lp_set/3, the user can program their own algorithms to control how the cutpool constraints are treated when the problem is solved. For example, the user may want to make a whole group of constraints inactive because they seem to slow the solver down but do not produce better solutions. In this case, the user can use lp_get/3 to obtain all the current constraints in the group, and then use lp_set/3 to set these constraints to inactive.

As cutpool constraints are not added directly to the problem matrix, this affects the library predicates that deals with the problem state:

- row-wise solution states like dual and slack values include only the cutpool constraints that are actually added to the problem. These are added after the normal constraints, and their order in the matrix can be obtained using the cutpool_info(last_added, index) option of lp_get/3.
- the constraints and constraints_norm options of lp_get/3 returns only the normal constraints. Other options that returns information about the problem (e.g. num_rows) also do not include the cutpool constraints.
- eplex_write/2 and lp_write/3 will dump all the active cutpool constraints with the problem. This may be different from the actual problem solved by the external solver because not all active cutpool constraints need be added to the problem, and the order of these constraints could be different. To dump the exact problem solved by the external solver, use the write_before_solve option of the solver instead.