It seems to me that the answer should be
Z in 1..99
How can you be so sure that you are right? This is one of the nice properties of constraints: You can verify this most easily:
?- X in 1..7, Y in -3..100, Y #> X, Z #\= 0, Z #= Y -X.
X in 1..7,
Z+X#=Y,
X#=<Y+ -1,
Z in -5.. -1\/1..99,
Y in 2..100.
?- X in 1..7, Y in -3..100, Y #> X, Z #\= 0, Z #= Y -X, Z #< 0.
false.
OK, now I believe what you said.
So you have discovered here an inconsistency which is present also in SICStus' native library(clpfd)
as well as library(clpz)
. First please note that the answer given was not incorrect! It said: Yes, there are solutions provided X in 1..7, Z+X#=Y, X#=<Y+ -1, Z in -5.. -1\/1..99, Y in 2..100.
is true. Helas, this is not true.
So that answer is a bit like the legalese in many insurance contracts where they say, yes we will pay, provided all that tiny unreadable print holds, but in reality you could replace that wall of microtext by a big fat false
.
In general, such inconsistencies are inevitable since CLP(FD)/CLP(Z) as defined in above systems permits to formulate undecidable problems. Thus, no matter how evolved your constraint solver is, we have the guarantee that there will be always cases that we cannot solve. That's a scientific, mathematical law, much more reliable than empirical laws like gravity or that speed limit.
The inconsistency here is effectively an engineering tradeoff. As long as nobody complains and doesn't have a convincing use case, the developers of such systems will not see a reason to improve. After all, such an improvement might slow down existing use cases.
- How, exactly (or failing that, approximately), does CLP propagate its constraints?
Actually, for any problem of realistic size, nobody knows. But this is not necessary either. In the case of CLP(FD), the fundamental element are the domains attached to the logical variables. You see them as (in)/2
goals like Z in -5.. -1\/1..99
. Connected between them are the actual constraints. In your case Y #> X
and Z #= Y-X
. These constraints now only see the domains of the variables and try to maintain consistency between them. As an even coarser approximation, the domains are seen as intervals thus Z in -5 .. 99
instead of above. What (most of them) do not see are the other constraints. In this case, there is no direct connection between Y #> X
and Z #= Y-X
. And thus the inconsistency. Such limited consistency checks are much easier to implement and also quite fast and often outperform more complete algorithms. With the discovery of better algorithms things evolve. A nice example is all_distinct/1
which maintains consistency between all variables using Regin's algorithm, whereas all_different/1
only maintains consistency between each pair of variables. But in any case: these things evolve and it is a bit of a surprise that this is an exam question.
- Is there any way to make CLP(FD) apply the constraint appropriately ...?
?- X in 1..7, Y in -3..100, Y #> X, Z #\= 0, Z #= Y -X, clpfd:contracting([X,Y,Z]).
X in 1..7,
Z+X#=Y,
X#=<Y+ -1,
Z in 1..99,
Y in 2..100.
But most will ignore this issue and just add labeling([],[X,Y])
- What is the domain of
Z
?
That is an ambiguous question. Give both as an answer.