IBM ILOG Solver User's Manual > Extending the Library > Writing a Constraint: Allocating Frequencies > Understanding constraints > Exp and var: More about modifiers and expressions |
Exp and var: More about modifiers and expressions |
INDEX
![]() |
Now that you have an idea about elementary modifiers and their effects on constrained integer variables, here's yet another way of understanding how elementary modifiers work. In this case, the point is illustrated by contrasting constrained expressions (where the domains are computed) with constrained variables (where the domains are stored), a contrast that mentioned briefly in the IBM ILOG Solver Reference Manual in the documentation for constrained integer variables and constrained enumerated variables.
This contrast between the computed domains of constrained expressions and the stored domains of constrained variables also highlights a major difference between modifiers (like setValue
) and constraints.
Consider this piece of code:
IlcIntVar x (solver, 0, 10); IlcIntVar y (solver, 0, 10); IlcIntExp z = x+y; z.setRange(0, 10); cout << z.getMax() << endl; |
It prints 20 as its result, not 10 as you might expect. This happens because Solver computes the domain of the expression when it prints z
; it does not store a domain for an expression. For that reason, the effect of an elementary modifier like setRange
is volatile.
Moreover, if you later bind x
to, say, 10, nothing happens to y
! To see that happen for yourself, consider this slightly different piece of code:
IlcIntVar x (solver, 0, 10); IlcIntVar y (solver, 0, 10); IlcIntExp z = x+y; z.setRange(0, 10); x.setValue(10); cout << y << endl; |
It prints [0 .. 10]
. Why? It does so because you used a modifier, setRange
, so 10, the maximum, is not stored in z
.
The correct code (correct in the sense of propagating values) must use a constraint (not a modifier), like this:
IlcIntVar x (solver, 0, 10); IlcIntVar y (solver, 0, 10); IlcIntExp z = x+y; solver.add(z <= 10); x.setValue(10); cout << y << endl; |
That piece of code stores the constraint (z <= 10)
and thus binds y
to 0.
So far, you've noticed that z
is a constrained integer expression. Another way of "correcting" this is to make z
a constrained integer variable. As mentioned in the IBM ILOG Solver Reference Manual, the domains of constrained expressions are not stored; they are computed. In contrast, the domains of constrained variables are stored.
Thus if z
is a constrained variable, y
is bound to 0, as in this piece of code:
IlcIntVar x (solver, 0, 10); IlcIntVar y (solver, 0, 10); IlcIntVar z = x+y; z.setRange(0, 10); x.setValue(10); cout << y << endl; |
However, the best way of writing (that is, the officially recommended way, supported by the Solver development team) is to use constrained variables and constraints, like this:
IlcIntVar x (solver, 0, 10); IlcIntVar y (solver, 0, 10); IlcIntVar z = x+y; solver.add(z <= 10); x.setValue(10); cout << y << endl; |
In that case, the constraint is created, though it is not stored because it is a unary constraint on a variable. This is the only case where constraints are not stored.
Let's summarize the conventions that Solver observes about constrained variables, constrained expressions, elementary modifiers, and constraints.
On the basis of those facts, here are a few recommendations to follow in your programming. Of course, there may be good and overriding reasons not to follow these practices in certain special cases, but in general these recommendations are sound.
propagate
;
© Copyright IBM Corp. 1987, 2009. Legal terms. | PREVIOUS NEXT |