IBM ILOG Solver User's Manual > Extending the Library > Writing a Constraint: Allocating Frequencies > Writing your own metaconstraint |
Writing your own metaconstraint |
INDEX
![]() |
If you want to define a new metaconstraint, that is, a constraint on constraints, you'll need to define additional virtual functions (besides those you just defined for a new constraint: propagate
and post
). Those additional virtual functions are isViolated
, makeOpposite
and metaPostDemon
. This section shows you how to define makeOpposite
and metaPostDemon
.
Let's assume that you want to express the idea that the variable x
is different from some other variable, y
, or that y
is different from z
. You can write that very simply by using the logical or operator provided by Solver.
solver.add(IlcDiff(x, y) || IlcDiff(y, z)); |
Once one of those two constraints proves false, Solver makes the other one true. To do so, Solver obviously needs to know the truth value of these constraints. In fact, Solver needs only to know when one of these constraints is violated. To detect it, this disjunctive constraint has to be posted on the variables that are involved. This is the task of the metaPostDemon
member function.
void IlcDiffConstraint::metaPostDemon(IlcDemonI* ct){ _x.whenValue(ct); _y.whenValue(ct); } |
Now, if you write:
solver.add(IlcDiff(x, y) || IlcDiff(y, z)); |
metaPostDemon
is called with the disjunctive constraint as its argument. Thus, you get the effect that once one of the two constraints proves false (that is, isViolated
returns IlcTrue
), Solver invokes the propagate
function of the other one, insuring that the disjunctive constraint is taken into account.
There's still one more point to consider. Let's assume now that you want to affirm that the constraint IlcDiff(x, y)
is false; in other words, that x == y
is true. You can use the negation operator to write this:
solver.add(!IlcDiff(x, y)); |
But if you do so, how will Solver know that you want to impose the negation of a specific constraint? You have to tell Solver explicitly what the opposite constraint is, and that is the work of the member function makeOpposite
.
In our example, the opposite constraint of x != y
is obviously x == y
. Remember that x == y
is a handle. Indeed, it's an instance of the class IlcConstraint
. With Solver, you get the object implementation from the getImpl()
member function of the handle class. For example, (x == y).getImpl()
returns the pointer to the implementation of x == y
.
Thus, the code is:
IlcConstraintI* IlcDiffConstraint::makeOpposite() const { return (_x == _y).getImpl(); } |
Finally, here's the code of the metaconstraint IlcDiff
. (First, you'll see the definitions of the appropriate class and its member functions; then IlcDiff
itself near the end.)
class IlcDiffConstraint :public IlcConstraintI { IlcIntExp _x, _y; public: IlcDiffConstraint(IloSolver solver, IlcIntExp x, IlcIntExp y); ~IlcDiffConstraint(){}; // empty destructor virtual void propagate (); virtual void post(); virtual IlcBool isViolated() const; virtual IlcConstraintI* makeOpposite() const; virtual void metaPostDemon(IlcDemonI* expr); }; IlcDiffConstraint::IlcDiffConstraint(IloSolver solver, IlcIntExp x, IlcIntExp y) : IlcConstraintI(solver), _x(x), _y(y) {} void IlcDiffConstraint::propagate () { if (_x.isBound()) _y.removeValue(_x.getValue()); if (_y.isBound()) _x.removeValue(_y.getValue()); } void IlcDiffConstraint::post(){ _x.whenValue(this); _y.whenValue(this); } IlcBool IlcDiffConstraint::isViolated() const { return (_x.isBound() && _y.isBound() && _x.getValue()==_y.getValue()); } IlcConstraint IlcDiff(IlcIntExp x, IlcIntExp y){ IloSolver solver=x.getSolver(); return new (solver.getHeap()) IlcDiffConstraint(solver, x, y); } void IlcDiffConstraint::metaPostDemon(IlcDemonI* ct){ _x.whenValue(ct); _y.whenValue(ct); } IlcConstraintI* IlcDiffConstraint::makeOpposite() const { return (_x == _y).getImpl(); }
All the predefined constraints of Solver are defined like this, as metaconstraints.
As you saw in "Writing your own constraint", defining an ordinary new constraint yourself is not as difficult as defining a metaconstraint. Only because you want to exploit IlcDiff
as a metaconstraint were you obliged to redefine the virtual functions isViolated
, metaPostDemon
and makeOpposite
.
© Copyright IBM Corp. 1987, 2009. Legal terms. | PREVIOUS NEXT |