4

In SWI-Prolog, the following query gives this result:

?- X mod 2 #= 0, X mod 2 #= 0.
X mod 2#=0,
X mod 2#=0.

While correct, there is obviously no need for the second constraint

Similarly:

?- dif(X,0), dif(X,0).
dif(X, 0),
dif(X, 0).

Is there no way to avoid such duplicate constraints? (Obviously the most correct way would be to not write code that leads to that situation, but it is not always that easy).

false
  • 10,264
  • 13
  • 101
  • 209
Fatalize
  • 3,513
  • 15
  • 25

3 Answers3

3

You can either avoid posting redundant constraints, or remove them with a setof/3-like construct. Both are very implementation specific. The best interface for such purpose is offered by SICStus. Other implementations like YAP or SWI more or less copied that interface, by leaving out some essential parts. A recent attempt to overcome SWI's deficiencies was rejected.

Avoid posting constraints

In SICStus, you can use frozen/2 for this purpose:

| ?- dif(X,0), frozen(X,Goal).
Goal = prolog:dif(X,0),
prolog:dif(X,0) ? ;
no
| ?- X mod 2#=0, frozen(X, Goal).
Goal = clpfd:(X in inf..sup,X mod 2#=0),
X mod 2#=0,
X in inf..sup ? ;
no

Otherwise, copy_term/3 might be good enough, provided the constraints are not too much interconnected with each other.

Eliminate redundant constraints

Here, a setof-like construct together with call_residue_vars/1 and copy_term/3 is probably the best approach. Again, the original implementation is in SICStus....

Community
  • 1
  • 1
false
  • 10,264
  • 13
  • 101
  • 209
  • The attribute variable interface is not primary the problem with contraction. Even if you have this interface, as is the case in Jekejeke Minlog, you don't get contraction for free. You still need to do some extra work. –  Oct 14 '16 at 11:55
  • In my opinion it is only a problem of normalizing and duplicate removal, SWI-Prolog does neither always: ?- use_module(library(clpfd)). true. ?- Y+X*3 #= 2, 2-Y #= 3*X. 2#=Y+3*X, Y+3*X#=2. ?- X #< Y, Y-X #> 0. X#= –  Oct 14 '16 at 13:25
  • 1
    First, you need some clean interface for this. SICStus has it, SWI has it only partially. – false Oct 14 '16 at 14:53
3

For dif/2 alone, entailment can be tested without resorting to any internals:

difp(X,Y) :-
   (  X \= Y -> true
   ;  dif(X, Y)
   ).
false
  • 10,264
  • 13
  • 101
  • 209
2

Few constraint programming systems implement contraction also related to factoring in resolution theorem proving, since CLP labeling is not SMT. Contraction is a structural rule, and it reads as follows, assuming constraints are stored before the (|-)/2 in negated form.

G, A, A |- B
------------ (Left-Contraction)
  G, A |- B

We might also extend it to the case where the two A's are derivably equivalent. Mostlikely this is not implemented, since it is costly. For example Jekejeke Minlog already implements contraction for CLP(FD), i.e. finite domains. We find for queries similar to the first query from the OP:

?- use_module(library(finite/clpfd)).
% 19 consults and 0 unloads in 829 ms.
Yes

?- Y+X*3 #= 2, 2-Y #= 3*X.
3*X #= -Y+2

?- X #< Y, Y-X #> 0.
X #=< Y-1

Basically we normalize to A1*X1+..+An*Xn #= B respectively A1*X1+..+An*Xn #=< B where gcd(A1,..,An)=1 and X1,..,Xn are lexically ordered, and then we check whether there is already the same constraint in the constraint store. But for CLP(H), i.e. Herbrand domain terms, we have not yet implemented contraction. We are still deliberating an efficient algorithm:

?- use_module(library(term/herbrand)).
% 2 consults and 0 unloads in 35 ms.
Yes

?- neq(X,0), neq(X,0).
neq(X, 0),
neq(X, 0)

Contraction for dif/2 would mean to implement a kind of (==)/2 via the instantiation defined in the dif/2 constraint. i.e. we would need to apply a recursive test following the pairing of variables and terms defined in the dif/2 constraint against all other dif/2 constraints already in the constraint store. Testing subsumption instead of contraction would also make more sense.

It probably is only feasible to implement contraction or subsumption for dif/2 with the help of some appropriate indexing technique. In Jekejeke Minlog for example for CLP(FD) we index on X1, but we did not yet realize some indexing for CLP(H). What we first might need to figure out is a normal form for the dif/2 constraints, see also this problem here.

Community
  • 1
  • 1
  • In CLP(Q) such reasoning as a bit easier! – false Oct 14 '16 at 14:54
  • In CLP(Q) you don't need gcd(A1,..,An)=1 and you simply set A1=1 by dividing, but the variable ordering is still needed if you want to normalize. –  Oct 14 '16 at 15:46
  • In CLP(Q) you can do test entailment (for linear constraints, only). That's the cool thing compared to the situation in Z (which is what CLPFD is about). – false Oct 14 '16 at 16:34
  • 1
    If you can bound your search, even when infinite, you can also do something for CLP(FD), see here http://www.sciencedirect.com/science/article/pii/S0304397596001958 (Open Text) but I didn't try yet. Would need to adapt the algorithm from Z to N. –  Oct 14 '16 at 17:45
  • Corr.: from N to Z, in domain N we automatically have constraint X>=0 available. –  Oct 14 '16 at 22:51
  • Thanks for [the reference](http://www.sciencedirect.com/science/article/pii/S0304397596001958)! Seems noone is using this in concrete implementation (according to a fast check with scholar). in CLP(Q) no additional algorithms are needed for entailment checking! – false Oct 15 '16 at 15:00