Overview | Group | Tree | Graph | Index | Concepts |
A constraint is an object in Solver. Like other Solver entities, a
constraint is implemented by means of two classes: a handle class and an
implementation class. In other words, an instance of the class
IlcConstraint
(a handle) contains a data member (the handle
pointer) that points to an instance of the class IlcConstraintI
(its implementation object).
Two member functions in this class actually implement the semantics of a
constraint: isViolated
and propagate
. When you are
defining a new class of constraint, you must define the member function
propagate
. That member function defines how the domain of a
constrained variable must be reduced by the constraint. (Defining
isViolated
is not usually mandatory. Its definition is
mandatory if you want to use the new class of constraint as a
metaconstraint, for example in a Boolean formula.)
A constraint must be stored when it is posted so that it can be used by
the propagation algorithm later. The member function post
must
be defined for that purpose. In other words, if you are defining a new class
of constraint, when you define the implementation class for it, you must
define this post
member function as well.
A constraint can be used in a Boolean formula. In other words, you can
combine constraints by means of the usual Boolean operators to produce other
constraints. In order to use a constraint in that way, if you are defining a
new class of constraints, then you must define the member functions
metaPost
, makeOpposite
, and
isViolated
.
For more information, see the concepts Propagation and Propagation Events.
See Also:
IlcConstraint, ILCCTDEMON0, IlcDemonI, IlcGoalI
Constructor and Destructor Summary | |
---|---|
public | IlcConstraintI(IloSolver solver) |
Method Summary | |
---|---|
public virtual void | display(ostream & str) const |
public void | fail(IlcAny label=0) |
public IlcConstraintI * | getCopy(IlcManagerI *=0) |
public IlcDemonI * | getParentDemonI() const |
public virtual IlcBool | isAConstraint() const |
public virtual IlcBool | isViolated() const |
protected virtual IlcConstraintI * | makeCopy(IlcManagerI *) const |
public virtual IlcConstraintI * | makeOpposite() const |
public virtual void | metaPostDemon(IlcDemonI * metaconstraint) |
public virtual void | post() |
public virtual void | propagate() |
public void | push() |
public void | push(IlcInt priority) |
Inherited Methods from IlcDemonI |
---|
getConstraintI, getSolver, getSolverI, isAConstraint, propagate |
Constructor and Destructor Detail |
---|
This constructor creates a constraint implementation. This constructor should not be called directly because this is an abstract class. This constructor is called automatically in the constructors of its subclasses.
Method Detail |
---|
By default, this virtual member function puts the name of the invoking constraint (if it has
a name) on the output stream indicated by its argument; if the invoking constraint has no name, this
virtual member function puts the string IlcConstraintI
on that stream. When you define
a new class of constraint, of course, you can redefine this behavior.
This member function causes the invoking constraint to fail at the choice point
indicated by label
.
This member function returns a pointer to a copy of the invoking implementation object.
If the invoking constraint is defined at the top level (that is, it is not nested; it is inside another constraint), then this member function returns the constraint itself. If the invoking constraint is inside another constraint or inside a demon, then this member function returns that other constraint or demon.
This member function returns IlcTrue
if the invoking constraint
derives from IlcConstraintI
; it returns IlcFalse
otherwise.
If this member function returns IlcTrue
, the invoking constraint cannot be satisfied.
This member function may return IlcFalse
even if the constraint can not be satisfied.
However, it should never return IlcTrue
if there is a possibility of satisfying the
constraint. This provision is made for cases where it can be computationally expensive to determine whether
the constraint can be satisfied or not; in such a case, the function should return IlcFalse
.
Consistent with this remark, the default behavior defined in the class IlcConstraintI
for this
member function is to return IlcFalse
.
Since this virtual member function implements part of the semantics of an invoking constraint, it is not
mandatory to redefine it in all cases when you define a new class of constraint. It is mandatory if you want
to use instances of the new class in Boolean expressions, as explained about logical Boolean operators for the
class IlcConstraint
.
The negation of a constraint must also be a constraint. Semantically, this virtual member function expresses that principle. It is called to create the negation of the invoking constraint. This member function is called only once by Solver. Solver stores its results in order to avoid unnecessary computations.
This virtual member function must be defined when you define a new class of constraint if you
want to use instances of the constraint in Boolean expressions, as explained about logical Boolean
operators for the class IlcConstraint
.
When a Boolean expression is posted on constraints, the expression has to be examined whenever the truth
value of one of the constraints appearing in it changes. That is, a constraint is posted on the constraints
appearing in the expression. Since it is a constraint on constraints, we call it a metaconstraint.
The virtual member function metaPostDemon
must be defined when you are defining a new class of
constraints if you plan to use instances of the new class in Boolean expressions, as explained about logical
Boolean operators for the class IlcConstraint
.
This virtual member function is called to post its argument, a metaconstraint, on the invoking constraint.
The metaconstraint should be associated with all the propagation events of the expressions appearing in the
invoking constraint that may result in the unsatisfiability of the invoking constraint. Normally, these
propagation events are the same events that are used in the post
member function.
Thus the implementation of metaPostDemon
is very similar to the implementation of
post
. The main difference is that metaPostDemon
associates propagation events with
the demon passed as an argument, whereas post
associates propagation events with the
invoking constraint.
A constraint must be stored when it is posted so that it can be used by the propagation algorithm later. This member function must be defined for that purpose. In other words, if you are defining a new class of constraint, when you define the implementation class for it, you must define this pure virtual member function. It is called to attach the invoking constraint to the constrained expressions that the constraint involves.
This member function must associate the invoking constraint with propagation events triggered
by the expressions it is constraining. This association is carried out by the member functions
whenValue
, whenDomain
, whenRange
(member functions of the
classes IlcIntExp
, IlcAnyExp
, IlcFloatExp
, IlcIntSetVar
,
IlcAnySetVar
, etc.).
We strongly recommend that you do not modify variables in the scope of this member function.
In other words, you should not call a modifier on a constrained variable within your definition
of this virtual member function. Instead, you should make such changes (if they are necessary in your
application) in your definition of the propagate
member function.
This pure virtual member function must be redefined when you define a new class of constraints. It defines how the domains of constrained variables must be reduced by the invoking constraint. It is called by the constraint propagation algorithm in order to execute the propagation of the invoking constraint. This member function should reduce the domains of the constrained expressions involved in the invoking constraint by removing the values that cannot satisfy the invoking constraint.
While there is an active demon, you must not start another search in the same
solver (the instance of IloSolver
in which the invoking
constraint exists). In practice, this rule means that you should not call
IloSolver::solve
from inside the member function
IlcConstraintI::propagate
.
This member function pushes the invoking constraint onto the constraint priority queue. Solver will use the default priority in the queue.
This member function pushes the invoking constraint onto the constraint priority queue. The
argument priority
indicates its priority in the queue.
This virtual member function returns a pointer to a copy of the invoking implementation object and
associates that copy with solver
. When you derive a new class of constraints, you must, of course,
define this virtual member function appropriately. In particular, you must insure that the copy of the
constraint is built with a copy of each constrained variable involved in the constraint. In other words,
makeCopy
should copy the subobjects of the constraint; to do so, it should use the
member function getCopy
.
For example, if we define an equality constraint between two constrained integer variables
_x
and _y
, we should implement makeCopy
for that constraint
like this:
IlcConstraintI* MyEqCt::makeCopy(IloSolverI* solver) const { return new (solver) MyEqCt(_x,getCopy(solver), _y.getCopy(solver)); }