Overview | Group | Tree | Graph | Index |
Arrays |
Assert and NDEBUG |
Column-Wise Modeling |
Exceptions, Errors |
Extraction |
Handle Class |
Lazy Copy |
Normalization: Reducing Linear Terms |
Notification |
Deletion of Extractables |
Obsolete Functions & Classes |
For most basic classes (such as IloNumVar
or IloConstraint
)
in Concert Technology, there is also a corresponding class of arrays where the elements
of the array are instances of that basic class. For example, elements of an instance of
IloConstraintArray
are instances of the class
IloConstraint
.
Concert Technology arrays are extensible. That is, you can add elements to the array dynamically. You add
elements by means of the add
member function of the array class.
You can also remove elements from an array by means of its remove
member function.
References to an array change whenever an element is added to or removed from the array.
Like other Concert Technology objects, arrays are implemented by means of two classes: a handle class corresponding to an implementation class. An object of the handle class contains a data member (the handle pointer) that points to an object (its implementation object) of the corresponding implementation class. As a Concert Technology user, you will be working primarily with handles.
Many handles may point to the same implementation object. This principle holds true for arrays as well as other handle classes in Concert Technology. When you want to create more than one handle for the same implementation object, you should use either the copy constructor or the assignment operator of the array class. For example,
IloNumArray array(env); // creates a handle pointing to new impl IloNumArray array1(array); // creates a handle pointing to same impl IloNumArray array2; // creates an empty handle array2 = array; // sets impl of handle array2 to impl of array
If your application only reads an array (that is, if your function does not modify an element of the
array), then we recommend that you pass the array to your function as a const
parameter.
This practice forces Concert Technology to access the const
conversion of the index operator
(that is, operator[]
), which is faster.
Most member functions of classes in Concert Technology are inline functions that contain
an assert
statement. This statement asserts that the invoking object and the
member function parameters are consistent; in some member functions, the assert
statement checks that the handle pointer is non-null. These statements can be suppressed by
the macro NDEBUG
. This option usually reduces execution time. The price you pay
for this choice is that attempts to access through null pointers are not trapped and usually
result in memory faults.
Compilation with assert
statements will not prevent core dumps by incorrect
code. Instead, compilation with assert
statements moves the execution of the
incorrect code (the core dump, for example) to a place where you can see what is causing the
problem in a source code debugger. Correctly written code will never cause one of these
Concert Technology assert
statements to fail.
Concert Technology supports column-wise modeling, a technique widely used in the math
programming and operations research communities to build a model column by column. In
Concert Technology, creating a new column is comparable to creating a new variable and
adding it to a set of constraints. You use an instance of
IloNumColumn
to do so. An instance of
IloNumColumn
allows you to specify to which
constraints or other extractable objects Concert Technology should add the new variable
along with its data. For example, in a linear programming problem (an LP), if the new
variable will appear in some linear constraints as ranges (instances of
IloRange
), you need to specify the list of such
constraints along with the non zero coefficients (a value of IloNum
) for
each of them.
You then create a new column in your model when you create a new variable with an
instance of IloNumColumn
as its parameter. When
you create the new variable, Concert Technology will add it along with appropriate
parameters to all the extractable objects you have specified in the instance of
IloNumColumn
.
Instead of building an instance of IloNumColumn
,
as an alternative, you can use a column expression directly in the constructor of the
variable. You can also use instances of IloNumColumn
within column expressions.
The following undocumented classes provide the underlying mechanism for column-wise modeling:
IloAddValueToObj
IloAddValueToRange
The following operators are useful in column-wise modeling:
IloRange
, IloAddValueToRange operator() (IloNum value);
IloObjective
, IloAddValueToObj operator () (IloNum value);
That is, the operator ()
in extractable classes, such as
IloRange
or
IloObjective
, creates descriptors of how Concert
Technology should add the new, yet-to-be-created variable to the invoking extractable
object.
You can use the operator +
to link together the objects returned by
operator ()
to form a column. You can then use an instance of
IloNumColumn
to build up column expressions within
a programming loop and thus save them for later use or to pass them to functions.
Here is how to use an instance of IloNumColumn
with operators from IloRange
and
IloObjective
to create a column with a coefficient
of 2 in the objective, with 10 in range1
, and with 3 in range2
.
The example then uses that column when it creates the new variable newvar1
,
and it uses column expressions when it creates newvar2
and
newvar3
.
IloNumColumn col = obj(2) + range1(10) + range2(3); IloNumVar newvar1(col); IloNumVar newvar2(col + range3(17)); IloNumVar newvar3(range1(1) + range3(3));
In other words, given an instance obj
of IloObjective
and
the instances range1
, range2
, and range3
of
IloRange
, those lines create the new variables newvar1
,
newvar2
, and newvar3
and add them as linear terms to
obj
, range1
, and range3
in the following way:
obj: + 2*newvar1 + 2*newvar2 range1: +10*newvar1 + 10*newvar2 + 1*newvar3 range2: + 3*newvar1 + 3*newvar2 range3: + 17*newvar2 +3*newvar3
For more information, refer to the documentation of IloNumColumn
,IloObjective
, and IloRange
.
An exception is thrown; it is not allocated in a Concert Technology environment; it is not allocated on the C++ heap. It is not necessary for you as a programmer to delete an exception explicitly. Instead, the system calls the constructor of the exception to create it, and the system calls the destructor of the exception to delete it.
When exceptions are enabled on a platform that supports C++ exceptions, an instance of a class of Concert Technology is able to throw an exception in case of error. On platforms that do not support C++ exceptions, it is possible for Concert Technology to exit in case of error.
Programming Hint: Throwing and Catching Exceptions
Exceptions are thrown by value. They are not allocated on the C++ heap, nor in a Concert
Technology environment. The correct way to catch an exception is to catch a reference to the
error (indicated by the ampersand &
), like this:
catch(IloException& oops);
Concert Technology offers classes for you to design a model of your problem.
You can then invoke an algorithm to extract information from your model to solve the
problem. In this context, an algorithm is an instance of a class such as
IloCplex
, documented in the ILOG CPLEX Reference Manual, or
IloSolver
, documented in the ILOG Solver Reference Manual.
For details about what each algorithm extracts from a model, see the reference manual
documenting that algorithm. For example, the ILOG CPLEX Reference Manual lists
precisely which classes of Concert Technology are extracted by an instance of
IloCplex
. In general terms, an instance of IloCplex
extracts a
model as rows and columns, where the columns indicate decision variables of the model.
Also in general terms, an instance of IloSolver
extracts an instance of a
class whose name begins Ilo
to a corresponding instance of a class whose name
begins Ilc
. For example, an instance of IloAllDiff
is extracted
by IloSolver
as an instance of IlcAllDiff
.
Most Concert Technology entities are implemented by means of two classes: a handle class and an implementation class, where an object of the handle class contains a data member (the handle pointer) that points to an object (its implementation object) of the corresponding implementation class. As a Concert Technology user, you will be working primarily with handles.
As handles, these objects should be passed in either of these ways:
const
by value (when no change is involved);They should be created as automatic objects, where "automatic" has the usual C++ meaning.
Member functions of a handle class correspond to member functions of the same name in the implementation class.
Concert Technology makes a lazy copy when you use any of the following objects inside a predefined Concert Technology object:
IloExpr
or one
of its subclasses), IloNumArray
),IloNumColumn
),IloIntSet
). That is, a physical copy of those objects is created only when needed.
In Concert Technology, expressions, arrays, columns, and sets are implemented by handle
classes and corresponding implementation classes. One or more handles may point to the same
implementation object. For example, many instances of the handle class
IloNumVarArray
may point to the same implementation object.
A handle may be empty; that is, it may point to 0 (zero). You can test whether a handle
is empty by means of the member function handle.getImpl
. If that member
function returns 0, the handle points to a null implementation.
When you modify an expression, an array, a column, or a set that has been used in a Concert Technology object, Concert Technology considers whether the handle you are modifying is the sole reference to the corresponding implementation object. If so, Concert Technology simply makes the modification.
In contrast, if the handle you are modifying points to an implementation object that is used by other objects predefined in Concert Technology, Concert Technology first copies the implementation object for the handle you are modifying and then makes the modification. The other handles pointing to the original implementation object remain unchanged and your modification has no impact on them.
Examples:
Here is an example illustrating lazy copy of variables:
IloNumVar a1(env, 0, 10); IloNumVar a2(env, 0, 10); IloNumVar a3(env, 0, 0); IloNumVarArray A(env, 2, a1, a2); IloConstraint ct = IloAllDiff(env, A); A.add (a3);
Because of the lazy copy, even though a3
was added to A
,
ct
uses only a1
and a2
.
Normalizing is sometimes known as reducing the terms of a linear expression.
Linear expressions consist of terms made up of constants and variables related by arithmetic operations; for example, x + 3y is a linear expression of two terms consisting of two variables. In some expressions, a given variable may appear in more than one term, for example, x + 3y +2x. Concert Technology has more than one way of dealing with linear expressions in this respect, and you control which way Concert Technology treats expressions from your application.
In one mode, Concert Technology analyzes linear expressions that your application
passes it and attempts to reduce them so that a given variable appears in only one term
in the linear expression. This is the default mode. You set this mode with the member
function IloEnv::setNormalizer(IloTrue)
.
In the other mode, Concert Technology assumes that no variable appears in more than
one term in any of the linear expressions that your application passes to Concert
Technology. We call this mode assume normalized linear expressions. You set this mode
with the member function IloEnv::setNormalizer(IloFalse)
.
In classes such as IloExpr
or
IloRange
, there are member functions that check the
setting of the member function IloEnv::setNormalizer
in the environment and
behave accordingly. The documentation of those member functions indicates how they behave
with respect to normalization.
When you set IloEnv::setNormalizer(IloFalse)
,
those member functions assume that no variable appears in more than one term in a linear
expression. This mode may save time during computation, but it entails the risk that a
linear expression may contain one or more variables, each of which appears in one or more
terms. Such a case may cause certain assertions in member functions of a class to fail if
you do not compile with the flag -DNDEBUG
.
By default, those member functions attempt to reduce expressions. This mode may require more time during preliminary computation, but it avoids of the possibility of a failed assertion in case of duplicates.
For more information, refer to the documentation of IloEnv
,IloExpr
, and IloRange
.
You may modify the elements of a model in Concert Technology. For example, you may add or remove constraints, change the objective, add or remove columns, add or remove rows, and so forth.
In order to maintain consistency between a model and the algorithms that may use it, Concert Technology notifies algorithms about changes in the objects that the algorithms have extracted. In this manual, member functions that are part of this notification system are indicated like this:
As a modeling layer, Concert allows the creation and destruction of extractables.
This is accessible through the method
IloExtractable::end()
and
IloExtractableArray::endElements()
method. The
goal of these methods is to reclaim memory associated with the deleted objects while
maintaining the safest possible Concert environment. In this context, a safe Concert
environment is defined by the property that no object points to a deleted object; this
is referred to as a dangling pointer in C++.
There exist two paradigms to ensure the safeness of the delete operation. The first, linear mode, comes from math programming and is possible only on extractables and objects used in linear programming. The second, safe generic mode, is more strict and is valid on all Concert extractables.
You can access both paradigms by calling
IloEnv::setDeleter(IloDeleterMode mode)
, where mode may be
IloLinearDeleterMode
or IloSafeDeleterMode
.
Linear Mode
To use linear mode, you must either
IloEnv::setDeleter(IloLinearDeleterMode)
, orIloEnv::setDeleter()
, as it is the default mode.In linear mode, the following behavior is implemented:
0
in the ranges,
expressions, and objectives where it appears. The variable is removed from the
SOS1
, SOS2
, and IloConversion
where it appears.Example
This example tests the linear mode deletion of a variable x
.
void TestLinearDeleter() { IloEnv env; env.out() << "TestLinearDeleter" << endl; try { IloModel model(env); IloNumVar x(env, 0, 10, "x"); IloNumVar y(env, 0, 10, "y"); IloConstraint con = (x + y <= 0); IloConstraint con2 = y >= 6; IloNumVarArray ar(env, 2, x, y); IloSOS1 sos(env, ar, "sos"); model.add(con); model.add(con2); model.add(sos); env.out() << "Before Delete" << endl; env.out() << model << endl; x.end(); con2.end(); env.out() << "After Delete" << endl; env.out() << model << endl; } catch (IloException& e) { cout << "Error : " << e << endl; } env.end(); }
The example produces the following output:
TestLinearDeleter Before Delete IloModel model0 = { IloRange rng3( 1 * x + 1 * y ) <= 0 IloRange rng46 <=( 1 * y ) IloSOS1I (sos) _varArray [x(F)[0..10], y(F)[0..10]] _valArray [] } After Delete IloModel model0 = { IloRange rng3( 1 * y ) <= 0 IloSOS1I (sos) _varArray [y(F)[0..10]] _valArray [] }
Safe Generic Mode
To use safe generic mode, you must:
IloEnv::setDeleter(IloSafeDeleterMode)
, and#include <ilconcert/ilodeleter.h>
to your
program.In this mode, the environment builds a dependency graph between all extractables. This graph contains all extractables created
IloEnv::setDeleter(IloSafeDeleterMode)
and IloEnv::unsetDeleter()
.Objects not managed by this dependency graph are referred to here as "nondeletable". An attempt to delete a nondeletable object will throw an exception.
We recommended that you create this graph just after the creation of the environment
and that you refrain from using IloEnv::unsetDeleter
. We make these
recommendations because building an incomplete dependency graph is very error prone and
should only be attempted by advanced users. A good example of this incomplete graph is
the separation of a model between a nondeletable base model and deletable extensions of
this base model.
Calling IloExtractable::end()
on extractable xi
will succeed
only if no other extractable uses extractable xi
. If this is not the case,
a call to IloExtractable::end()
will throw an exception
IloDeleter::RequiresAnotherDeletionException
indicating which extractable
uses the extractable that you want to delete.
Example
This example shows an attempt to delete one extractable that is used by another.
void TestSafeDeleter() { IloEnv env; env.out() << "TestSafeDeleter" << endl; env.setDeleter(IloSafeDeleterMode); try { IloModel model(env); IloNumVar x(env, 0, 10); IloNumVar y(env, 0, 10); IloConstraint con = (x + y <= 0); try { x.end(); } catch (IloDeleter::RequiresAnotherDeletionException &e) { cout << "Caught " << e << endl; e.getUsers()[0].end(); e.end(); } x.end(); } catch (IloException& e) { cout << "Error : " << e << endl; } env.unsetDeleter(); env.end(); }
The example produces the following output:
TestSafeDeleter Caught You cannot end x1(F)[0..10] before IloRange rng3( 1 * x1 + 1 * x2 ) <= 0
To address this, you should use the IloExtractableArray::endElements()
method. With this method,
all extractables appearing in the array are deleted one after another. Thus, if an
extractable is used by another extractable and this other extractable is deleted before the
first one, the system will not complain and will not throw an exception.
Example
This example illustrates the use of the endElements()
method
void TestSafeDeleterWithArray() { IloEnv env; env.out() << "TestSafeDeleterWithArray" << endl; env.setDeleter(IloSafeDeleterMode); try { IloModel model(env); IloNumVar x(env, 0, 10); IloNumVar y(env, 0, 10); IloConstraint con = (x + y <= 0); IloExtractableArray ar(env, 2, con, x); ar.endElements(); } catch (IloException& e) { cout << "Error : " << e << endl; } env.unsetDeleter(); env.end(); }
The example will not throw an exception.
con
must appear
before the variable x
as it will be deleted before the variable
x
.Obsolete Function or Class | Replaced By |
---|---|
IloNumSet | IloIntSet |
IloNumSetVar | IloIntSetVar |
IloNumSetVarArray | IloIntSetVarArray |
IloExprBase | IloNumExprArg and
IloIntExprArg |
IloExprNode | IloNumExprArg and
IloIntExprArg |
IloExprArg | IloNumExprArg and
IloIntExprArg |
IloExprI | IloNumLinTermI (undocumented) |