I\'m playing around with constraints in (swi) prolog using the clpfd library.
I\'m trying to identify when one set of constraints encapsulates or subsumes the other,
Subsumption of general arithmetic constraints over the integers is undecidable in general, so all correct solvers have inherent limits beyond which they have to delay their answers until more is known. If you know your domains to be finite, you can post the domains and then try to find counterexamples that would make the implication invalid, using the constraint solver's labeling/2 predicate. Consider also that linear inequalities over Q are decidable, and that SWI-Prolog's library(clpq) is complete for them. You can thus try your constraints in CLP(Q) with:
?- use_module(library(clpq)).
true.
?- { X < 4, X >= 7 }.
false.
and see that no such counterexample exists in Q (hence also not in Z), and thus the implication holds.
It seems you are dealing with CLP(FD). These solvers distinguish the setup phase and the labeling phase of solving a constraint problem.
A CLP(FD) solver does not completely reduce a problem during the setup phase. Since it has the chance to reduce variable ranges during the labeling phase. Thus it could be that during setup a problem is posed which could be reduced by other solvers to "No", but it will not with a CLP(FD) solver. Only during labeling a "No" will be detected.
How much reduction is done during the setup phase highly depends on the given CLP(FD) system. Some CLP(FD) systems do more reduction during the setup phase, while other do less. GNU Prolog for example uses some indexical propagation, whereas SWI Prolog does not. So we find for example, not your example:
SWI-Prolog:
?- X #< Y, Y #< Z, Z #< X.
Z#=<X+ -1,
X#=<Y+ -1,
Y#=<Z+ -1.
GNU Prolog:
?- X #< Y, Y #< Z, Z #< X.
(7842 ms) no
Further since you are using reified constraints it also depends a little bit how clever the reification is done. But I guess in the present case its only a matter of propagation. We find now for your example:
SWI-Prolog:
?- X #< 4 #==> X #< 7.
X+1#=_G1330,
X+1#=_G1342,
7#>=_G1330#<==>_G1354,
_G1354 in 0..1,
_G1377#==>_G1354,
_G1377 in 0..1,
4#>=_G1342#<==>_G1377.
GNU Prolog:
?- X #< 4 #==> X #< 7.
X = _#22(0..268435455)
There is a tradeoff between doing more reduction in the setup phase and leaving more work to the labeling phase. And the whole matter also depends on the given example. But when you have also labeling beside setup, you will not see any difference in terms of outcome:
SWI-Prolog:
?- X in 0..9, X #< 4 #==> X #< 7, label([X]).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
X = 6 ;
X = 7 ;
X = 8 ;
X = 9.
GNU Prolog:
?- fd_domain(X,0,9), X #< 4 #==> X #< 7, fd_labeling([X]).
X = 0 ? ;
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 4 ? ;
X = 5 ? ;
X = 6 ? ;
X = 7 ? ;
X = 8 ? ;
X = 9
I didn't test with SICStus Prolog or B-Prolog. But I guess they will behave somewhere in the vincinity of SWI-Prolog and GNU Prolog.
CLP(Q) is no real alternative if your domain is really FD, since it will miss some "No" reductions, which CLP(FD) would not miss. For example the following is unsatisfiable in CLP(FD), but satisfiable in CLP(Q):
X = Y + 1, Y < Z, Z < X.
Bye