Program Description

The main program starts by declaring the environment and terminates by calling method end() for the environment. The code in between is encapsulated in a try block that catches all Concert Technology exceptions and prints them to the C++ error stream cerr. All other exceptions are caught as well, and a simple error message is issued. The first action of the program is to evaluate command line parameters and call function usage in cases of misuse.

Using Arrays for Input/Output

If all goes well, the input file is opened in the file ifstream. After that, the arrays for storing the problem data are created by declaring the appropriate variables. Then the arrays are filled by using the input operator with the data file. The data is checked for consistency and, if it fails, the program is aborted, again by throwing an exception.

After the problem data has been read and verified, we are ready to build the model. To do so we construct the model object with the declaration

  IloModel mod(env); 

The array Buy is created to store the modeling variables. Since the environment is not passed to the constructor of Buy, an empty handle is constructed. So at this point the variable Buy cannot be used.

Depending on the command line function, either buildMethodByRow or buildMethodByColumn is called. Both create the dietary model from the input data and return an array of modeling variables as an instance of the class IloNumVarArray. At that point, Buy is assigned to an initialized handle containing all the modeling variables and can be used afterwards.

Building the Model by Row

The model is created by rows using the function buildModelByRow. It first gets the environment from the model object passed to it. Then the modeling variables Buy are created. Instead of calling the constructor for the variables individually for each variable, we create the full array of variables, with the array of lower and upper bounds and the variable type as parameter. In this array, variable Buy[i] is created such that it has lower bound foodMin[i], upper bound foodMax[i], and type type.

The statement:

  mod.add(IloMinimize(env, IloScalProd(Buy, foodCost))); 

creates the objective function and adds it to the model. The IloScalProd function creates the expression j (Buy[j] * foodCost[j]) which is then passed to the function IloMinimize. That function creates and returns the actual IloObjective object, which is added to the model with the call mod.add().

The following loop creates the constraints of the problem one by one and adds them to the model. First the expression j (Buy[j] * nutrPer[i][j]) is created by building a Concert Technology expression. An expression variable expr of type IloExpr is created, and linear terms are added to it by using operator+= in a loop. The expression is used with the overloaded operator<= to construct a range constraint (an IloRange object) which is added to the model:

  mod.add(nutrMin[i] <= expr <= nutrMax[i]); 

After an expression has been used for creating a constraint, it is deleted by calling expr.end().

Finally, the array of modeling variables Buy is returned.

Building the Model by Column

The function buildModelByColumn()implements the creation of the model by columns. It begins by creating the array of modeling variables Buy of size 0. This is later populated when the columns of the problem are created and eventually returned.

The statement:

  IloObjective cost = IloAdd(mod, IloMinimize(env)); 

creates a minimization objective function object with 0 expressions and adds it to the model. The objective object is created with the function IloMinimize. The template function IloAdd is used to add the objective object to the model and to return an objective object with the same type, so that we can store the objective in variable cost. The method IloModel::add() returns the modeling object as an IloExtractable, which cannot be assigned to a variable of a derived class such as IloObjective. Similarly an array of range constraints with 0 expressions is created, added to the model, and stored in array range.

In the following loop, the variables of the model are created one by one in columns thus, the new variables are immediately installed in the model. An IloNumColumn object col is created and initialized to describe how each new variable will be appended to the existing objective and constraints.

The IloNumColumn object col is initialized to contain the objective coefficient for the new variable. This is created with cost(foodCost[j]), that is using the overloaded operator() for IloObjective. Next, an IloNumColumn object is created for every constraint, representing the coefficient the new variable has in that constraint. Again these IloNumColumn objects are created with the overloaded operator(), this time of IloRange. The IloNumColumn objects are merged together to an aggregate IloNumColumn object using operator +=. The coefficient for row i is created with range[i](nutrPer[i][j]), which calls the overloaded operator() for IloRange objects.

When a column is completely constructed, a new variable is created for it and added to the array of modeling variables Buy. The construction of the variable is performed by the constructor:

  IloNumVar(col, foodMin[j], foodMax[j], type) 

which creates the new variable with lower bound foodMin[j], upper bound foodMax[j] and type type, and adds it to the existing objective and ranges with the coefficients specified in column col. After creating the variable for this column, the IloColumn object is deleted by calling col.end().


Previous Page: Example: Dietary Optimization  Return to Top Next Page: Solving the Model with IloCplex