The models

Presents the four different model files used in the vellino example.

In the distributed project, you can see that there are four different model files described in the following sections:

  • The model for common definitions: vellinocommon.mod contains the declaration of data common to all other models.

  • The generation model: vellinogenBin.mod is the model to generate the possible configurations for bins. This is a CP model.

  • The selection model: vellinochooseBin.mod selects a subset of configurations. This is a CPLEX model.

  • The flow control script: vellino.mod is only a flow control script that executes the two other models in the right order and transfers information from one to the other.

  • Selection of the bins to use: passing the generated bins to the selection model

The model for common definitions

The model vellinocommon.mod contains definitions that are common to all the models. For example, the tuple definition:

tuple Bin {
   key int id;
   string color;
   int n[Components];
};

is used to represent configurations that are passed between the different models.

The set of available configurations is given by:

{Bin} Bins = ...;

This model is included in other models that use these definitions as follows:


include "vellinocommon.mod";

The generation model

The generation model vellinogenBin.mod starts with the statement:


using CP;

which means that it is solved by the CP Optimizer engine.

The decision variables are:

dvar int color in RColors;
dvar int n[Components] in 0..maxCapacity;

The decision variable color indicates the color of the generated configuration. Colors are represented by integer values and each n[c] indicates how many components of type c are included in the bin configuration. Then, all the compatibility constraints are easily written:

subject to {  
   1 <= sum(c in Components) n[c];
   sum(c in Components) n[c] <= capacity_int_idx[color];
   color == ord(Colors, "red") =>
     n["plastic"] == 0 &&  n["steel"] == 0 && n["wood"] <= 1;
   color == ord(Colors, "blue") =>
      n["plastic"] == 0 && n["wood"] == 0;
   color == ord(Colors, "green") =>
     n["glass"] == 0 && n["steel"] == 0 && n["wood"] <= 2;
   n["wood"] >= 1 => n["plastic"] >= 1;
   n["glass"] == 0 || n["copper"] == 0;  
   n["copper"] == 0 || n["plastic"] == 0;
};

Some are just a direct expression of the problem description. For example, this constraint:

   n["wood"] >= 1 => n["plastic"] >= 1;

means that if there is at least one wood component, there needs to be at least one plastic component.

Others use intermediate structures. For example, this constraint:

   sum(c in Components) n[c] <= capacity_int_idx[color];

states that the total number of components must not exceed the capacity, depending on the color. For this, a preprocessed calculated structure has been created to go from the capacity indexed by strings to the capacity given by color indexes.

int capacity_int_idx[RColors] = [ord(Colors,c) : capacity[c] | c in Colors];

The selection model

The selection model vellinochooseBin.mod is also a very simple CPLEX model.

A variable is created for each available configuration given as input, by means of the tuple structure Bin and given in the tuple set Bins:

dvar int produce[Bins] in 0..maxDemand;

The objective is to minimize the number of bins produced.

minimize
   sum(b in Bins) produce[b];

The only constraint is to cover the demand in terms of number of components:

subject to {
   forall(c in Components)
     demandCt: sum(b in Bins) b.n[c] * produce[b] == demand[c];
 };

The flow control script

The flow control script defined in vellino.mod links the other models with each other.

It works as follows:

  1. It solves the generation model as many times as necessary to find all the possible solutions. This is easily done because the CP Optimizer engine can iterate on the feasible solutions.

  2. For each solution, a new Bin is created and added to the current list.

  3. The selection model is created and it uses the set of Bins just generated as input data.

Generation of all the configurations

Generating all the possible configurations consists in:

  1. creating an instance of the vellinogenBin.mod model using the common data

  2. using the following methods of theIloCP class to iterate on the feasible solutions:

    • startNewSearch

    • next

    • endSearch

At each solution, a new tuple is added to Bins from the current solution. You need to call the method postProcess on the generation model to be able to use postprocessing elements.

   var genBin = new IloOplRunConfiguration("vellinogenBin.mod");
   genBin.oplModel.addDataSource(data);
   genBin.oplModel.generate();
   genBin.cp.startNewSearch();
   while (genBin.cp.next()) {  
     genBin.oplModel.postProcess();
     data.Bins.add(genBin.oplModel.newId, 
                   genBin.oplModel.colorStringValue, 
                   genBin.oplModel.n.solutionValue);
   }
   genBin.cp.endSearch();
   genBin.end();

Selection of the bins to use

As the generated bin configurations have been added to the Bins data element, you can pass this data element object to the selection model.

   var chooseBin = new IloOplRunConfiguration("vellinochooseBin.mod");
   chooseBin.cplex = cplex;   
   chooseBin.oplModel.addDataSource(data);   
   chooseBin.oplModel.generate();
   if (chooseBin.cplex.solve()) {
     chooseBin.oplModel.postProcess();
   } 
   chooseBin.end();