FRAMES NO FRAMES

Table Constraints
PREVIOUS NEXT
External data as constraints
Improving efficiency: a table constraint for a subproblem

Table constraints are constraints that are used frequently in constraint applications. There are two broad categories of use:

External data as constraints

In many constraint applications, it is necessary to process a huge quantity of data. For instance, the features of some products can be described as a relation in a database or in text files.

Consider as an example a bicycle factory that can produce thousands of different models. For each model of bicycle, a relation associates the features of that bicycle such as size, weight, color, price. This information can be used in a constraint programming application that allows a customer to find the bicycle that most closely fits a specification. This application benefits from a table constraint: this constraint takes a relation (a set of k-ary tuples) and an array of k variables and guarantees that the values of the variables correspond to a tuple of the relation.

In the bicycle example, you first define the relation as an IloIntTupleSet:

IloIntTupleSet bicycleTable(env, 5);
while (thereIsTupleToBeRead()) {
  IloIntArray aTuple(env,5);
  aTuple = myReadTupleFunction();
  // aTuple[0]= the id of a type of bicycle
  // aTuple[1]= its size
  // aTuple[2]= its weight
  // aTuple[3]= its color
  // aTuple[4]= its price
  bicycleTable.add(aTuple);
}

Then define an array of integer variables x, and assume x[0] represents the id of the bicycle, x[1] its size, x[2] its weight, x[3] its color, and x[4] its price:

IloIntVarArray x(env, 5);

Finally, add a table constraint on x that forces the values of x to be one of the combinations defined in the tuple set:

model.add(IloTableConstraint(env, x, bicycleTable, IloTrue);

If you are looking for two bicycles of size 2 and 4 with the same color, add another array of integer variables y to represent the second bicycle along with another table constraint (notice that the tuple set is shared between the two table constraints):

IloIntVarArray y(env, 5);
model.add(IloTableConstraint(env, y, bicycleTable, IloTrue);
model.add(x[1]== 2);
model.add(y[1]== 4);
model.add(x[3]==y[3]);

There are several ways to express a table constraint:

  • The tuple set may indicate the combinations of values that satisfy the constraint, as in the above example.
  • The tuple set may also indicate the combinations of values that do no satisfy the constraint.
  • The combinations of values may be expressed by a predicate.
  • The combinations of values may be expressed by an array whose index corresponds to one variable and values to a second variable.

See IloTableConstraint for the complete description of the different table constraints.

Improving efficiency: a table constraint for a subproblem

A modeling trick that may sometimes dramatically reduce the CPU time needed to solve a problem consists in identifying a difficult subproblem, computing all the solutions of the subproblem, and storing them in a table constraint. This approach is not restricted to constraint programming, it is a general approach: facing a difficult problem, it is often easier to solve it by:

  1. decomposing the problem into subproblems,
  2. solving the different subproblems, and
  3. connecting the solutions of the subproblems to produce a solution to the whole problem.

A table constraint forces the values of the variables of the subproblem to be one of the solutions of the subproblem. Thus the connection of the solution of the subproblem with the remainder of the problem is automatically handled. The advantage of this approach is that when searching for a solution of the whole problem, instead of always retrieving the solutions of the subproblem in the search, the table constraint forces values to one of these solutions. In other terms, the work of solving the subproblem is factorized and done only once, before the search, and not several times during the search (which is potentially a huge number of times).

This approach also has a drawback: the solutions of the subproblem must be found first so this must be practical (the solutions should not be too numerous). Tables with several hundreds of thousands of tuples can be handled, but subproblems with billions of solutions cannot be handled in this way. Nevertheless, note that it is possible to set a bound on the number of solutions of the subproblem to precompute and store in the table. In this case, the problem solved is a restriction of the initial problem, but this may be useful in practice.

An example of such an approach is available in the file dinner.cpp in the examples/src directory.

PREVIOUS NEXT