> Languages and APIs > ILOG Concert Technology for C++ Users > Example: Optimizing the Diet Problem in C++ > Application Description

The main part of the application starts by declaring the environment and terminates by calling the method end for that 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 options and call the function usage in cases of misuse.

Note
In such cases, an exception is thrown. This practice makes sure that env.end is called before the program is terminated.

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, it is time to build the model. To do so, construct the model object with this 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 option, either buildMethodByRow or buildMethodByColumn is called. Both create the model of the diet problem 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, 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 indicated by 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 a call to 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 as an object to the model and to return an objective object with the same type, so that the objective can be stored in the 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 (zero) expressions is created, added to the model, and stored in the 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 define 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.