Creating a model: IloModel
CPLEX C++ offers modeling objects for an application.
After creating the environment, a Concert application is ready to create one or more optimization models. Doing so consists of creating a set of modeling objects to define each optimization model.
Modeling objects, like IloEnv objects, are handles to implementation objects.
Though you will be dealing only with the handle objects, it is the
implementation objects that contain the data that specifies the optimization
model. If you need to remove an implementation object from memory,
you need to call the end method for one
of its handle objects.
Modeling objects are also known as extractables because it is the individual
modeling objects that are extracted one by one when you extract an
optimization model to IloCplex . So, extractables are characterized by the possibility
of being extracted to algorithms such as IloCplex .
In fact, they all are inherited from the class IloExtractable .
In other words, IloExtractable is the base
class of all classes of extractables or modeling objects.
The most fundamental extractable class is IloModel .
Objects of this class are used to define a complete optimization model
that can later be extracted to an
IloCplex object.
You create a model by constructing an object of type
IloModel.
For example, to construct a modeling object named model,
within an existing environment named env,
you write the following line:
IloModel model(env);
At this point, it is important to note that the environment
is passed as an argument to the constructor. There is also a constructor
that does not use the environment argument, but this constructor creates
an empty handle, the handle corresponding to a NULL pointer.
Empty handles cannot be used for anything but for assigning other
handles to them. Unfortunately, it is a common mistake to try to use
empty handles for other things.
After an IloModel object has been constructed, it is populated with the extractables that define the optimization model. The most important classes here are:
| Modeling classes | Description |
|---|---|
| IloNumVar | representing modeling variables; |
| IloRange | defining constraints of the form l <= expr <= u, where expr is a linear expression; and |
| IloObjective | representing an objective function. |
You create objects of these classes for each variable, constraint, and objective function of your optimization problem. Then you add the objects to the model by calling
model.add(object);
for each extractable object .
There is no need to explicitly add the variable objects to a model,
as they are implicitly added when they are used in the range constraints
(instances of IloRange ) or the objective.
At most one objective can be used in a model with IloCplex .
Modeling variables are constructed as objects of class IloNumVar ,
by defining variables of type IloNumVar .
Concert Technology provides several constructors for doing this; the
most flexible form is:
IloNumVar x1(env, 0.0, 40.0, ILOFLOAT);
This definition creates the modeling variable x1 with
lower bound 0.0, upper bound 40.0 and type ILOFLOAT ,
which indicates the variable is continuous. Other possible variable
types include ILOINT for integer variables
and ILOBOOL for Boolean variables.
For each variable in the optimization model a corresponding
object of class IloNumVar must be created.
Concert Technology provides a wealth of ways to help you construct
all the IloNumVar objects.
After all the modeling variables have been constructed,
they can be used to build expressions, which in turn are used to define
objects of class IloObjective and IloRange .
For example,
IloObjective obj = IloMinimize(env, x1 + 2*x2 + 3*x3);
This creates the extractable obj of
type IloObjective which represents the
objective function of the example presented in Introducing CPLEX.
Consider in more detail what this line does. The function IloMinimize takes
the environment and an expression as arguments, and constructs a new IloObjective object
from it that defines the objective function to minimize the expression.
This new object is returned and assigned to the new handle obj .
After an objective extractable is created, it must be added to the model. As noted earlier this
is done with the add method of IloModel . If this is all that the
variable obj is needed for, it can be written more compactly, like this:
model.add(IloMinimize(env, x1 + 2*x2 + 3*x3));
This way there is no need for the program variable obj and
the program is shorter. If in contrast, the objective function is
needed later, for example, to change it and re-optimize the model
when doing scenario analysis, the variable obj must
be created in order to refer to the objective function. (From the
standpoint of algorithmic efficiency, the two approaches are comparable.)
Creating constraints and adding them to the model can be done just as easily with the following statement:
model.add(-x1 + x2 + x3 <= 20);
The part -x1 + x2 + x3 <= 20 creates
an object of class IloRange that is immediately
added to the model by passing it to the method IloModel::add .
Again, if a reference to the IloRange object
is needed later, an IloRange handle object
must be stored for it. Concert Technology provides flexible array
classes for storing data, such as these IloRange objects.
As with variables, Concert Technology provides a variety of constructors
that help create range constraints.
While those examples use expressions with modeling variables
directly for modeling, it should be pointed out that such expressions
are themselves represented by yet another Concert Technology class, IloExpr .
Like most Concert Technology objects, IloExpr objects
are handles. Consequently, the method end must
be called when the object is no longer needed. The only exceptions
are implicit expressions, where the user does not create an IloExpr object,
such as when writing (for example) x1 + 2*x2 .
For such implicit expressions, the method end should
not be called. The importance of the class IloExpr becomes
clear when expressions can no longer be fully spelled out in the source
code but need instead to be built up in a loop. Operators like += provide
an efficient way to do this.