Residual constraints with reification in clpfd - prolog

I defined reified variants of the
clpfd constraints (#<)/2, (#=<)/2, (#>=)/2 and (#>)/2:
:- use_module(library(clpfd)).
ltA(X,Y,Truth) :- X #< Y #<==> B, bool01_truth(B,Truth).
ltB(X,Y, true) :- X #< Y.
ltB(X,Y,false) :- X #>= Y.
lteA(X,Y,Truth) :- X #=< Y #<==> B, bool01_truth(B,Truth).
lteB(X,Y, true) :- X #=< Y.
lteB(X,Y,false) :- X #> Y.
gteA(X,Y,Truth) :- X #>= Y #<==> B, bool01_truth(B,Truth).
gteB(X,Y, true) :- X #>= Y.
gteB(X,Y,false) :- X #< Y.
gtA(X,Y,Truth) :- X #> Y #<==> B, bool01_truth(B,Truth).
gtB(X,Y, true) :- X #> Y.
gtB(X,Y,false) :- X #=< Y.
Of course, ltA/3 and ltB/3 are logically equivalent, as are
lteA/3 and lteB/3, gteA/3 and gteB/3, and gtA/3 and gtB/3.
The answers I get using these predicates, however, differ regarding size and readability. I ran the following queries with SWI-Prolog 7.1.37:
Good news, first!
?- lteA(X,Y,Truth).
Truth = false, Y#=<X+ -1 ;
Truth = true, Y#>=X.
?- lteB(X,Y,Truth).
Truth = true, Y#>=X ;
Truth = false, Y#=<X+ -1.
?- gteA(X,Y,Truth).
Truth = false, X#=<Y+ -1 ;
Truth = true, X#>=Y.
?- gteB(X,Y,Truth).
Truth = true, X#>=Y ;
Truth = false, X#=<Y+ -1.
Ok! But what about the other two?
?- ltA(X,Y,Truth).
Truth = false, X+1#=_G968, Y#=<_G968+ -1 ;
Truth = true, X+1#=_G912, Y#>=_G912.
?- ltB(X,Y,Truth).
Truth = true, X#=<Y+ -1 ;
Truth = false, X#>=Y.
?- gtA(X,Y,Truth).
Truth = false, X#=<_G1301+ -1, Y+1#=_G1301 ;
Truth = true, X#>=_G1243, Y+1#=_G1243.
?- gtB(X,Y,Truth).
Truth = true, Y#=<X+ -1 ;
Truth = false, Y#>=X.
Not quite!
How do I get compact answers with ltA/3 and gtA/3---just like with lteA/3 and gteA/3?

It runs counter the basic idea of CLP(FD) to have compact
answers. Since CLP(FD) usually doesn't do gauss elimination and
similar things. Its not like a Computer Algebra System (CAS).
In CLP(FD), you basically model your problem by entering
inequations, and the system is allowed to do nothing with this
inequations as long as you don't call labeling.
Some CLP(FD) realizations already check consistency to some
degree when entering inequations and/or already do simplifications
and propagations. But this isnt mandatory.
In your example you have E #= X where E is an expression and
X is a variable. There is no guarantee that occurences
of X are replaced by E when entering a model.
Usually this is not done in CLP(FD), since it would blow
up the entered model. You can directly test that this
is not simplified:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.4)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
?- use_module(library(clpfd)).
true.
?- A#=X+1, Y#=<A+ -1.
Y#=<A+ -1,
X+1#=A.
The same also happens in Jekejeke Prolog. The CLP(FD) of
Jekejeke Prolog is open source here. Refification itself
is planned but not yet implemented:
Jekejeke Prolog, Runtime Library 1.0.7
(c) 1985-2015, XLOG Technologies GmbH, Switzerland
?- use_module(library(finite/clpfd)).
% 11 consults and 0 unloads in 513 ms.
Yes
?- A#=X+1, Y#=<A+ -1.
A #= 1+X,
-1+A #>= Y
Typicall an equation E #= X only leads to substitutions when
E is also a variable or constant. This might explain why your
examples look different from case to case.
Here you see SWI-Prolog simplifying A #= X. I just modified
the above example slightly so that E is a variable:
?- A#=X, Y#=<A+ -1.
A = X,
Y#=<X+ -1.
And here you see Jekejeke Prolog doing it (Todo bug fix: I
guess I need to reorder the rules a little bit, so that it
gives A = X and not X = A as here):
?- A#=X, Y#=<A+ -1.
X = A,
-1+A #>= Y
The case of E #= X where E is a constant and where this
value is propagated is called forward checking. This is the
minimum requirement a CLP(FD) must be able to do, otherwise
labeling would not work.
But already the case of E #= X where E is a variable a
propagation isn't mandatory. But the testing above shows
that many CLP(FD) do it. Propagating variables leads to
union find algorithms and the like.
Bye

Related

Pure Prolog Peano Number Apartness

Lets assume there is pure_2 Prolog with dif/2 and pure_1 Prolog without dif/2. Can we realize
Peano apartness for values, i.e. Peano numbers, without using dif/2? Thus lets assume we have Peano apartness like this in pure_2 Prolog:
/* pure_2 Prolog */
neq(X, Y) :- dif(X, Y).
Can we replace neq(X,Y) by a more pure definition, namely from pure_1 Prolog that doesn't use dif/2? So that we have a terminating neq/2 predicate that can decide inequality for Peano numbers? So what would be its definition?
/* pure_1 Prolog */
neq(X, Y) :- ??
Using less from this comment:
less(0, s(_)).
less(s(X), s(Y)) :- less(X, Y).
neq(X, Y) :- less(X, Y); less(Y, X).
I had something else in mind, which is derived from two of the Peano Axioms, which is also part of Robinson Arithmetic. The first axiom is already a Horn clause talking about apartness:
∀x(0 ≠ S(x))
∀x∀y(S(x) = S(y) ⇒ x = y)
Applying contraposition to the second axiom gives.
The axiom is now a Horn clause talking about apartness:
∀x∀y(x ≠ y ⇒ S(x) ≠ S(y))
Now we have everything to write some Prolog code.
Adding some symmetry we get:
neq(0, s(_)).
neq(s(_), 0).
neq(s(X), s(Y)) :- neq(X, Y).
Here are some example queries. Whether the predicate leaves a choice
point depends on the Prolog system. I get:
SWI-Prolog 8.3.15 (some choice point):
?- neq(s(s(0)), s(s(0))).
false.
?- neq(s(s(0)), s(0)).
true ;
false.
Jekejeke Prolog 1.4.6 (no choice point):
?- neq(s(s(0)), s(s(0))).
No
?- neq(s(s(0)), s(0)).
Yes
Just removing the unwanted choicepoint (in swi-prolog) from user502187's answer:
neq(0, s(_)).
neq(s(N), M) :-
% Switch args, to use first-arg indexing
neq_(M, s(N)).
neq_(0, s(_)).
neq_(s(N), s(M)) :-
% Switch args back, to fix choicepoint
neq(M, N).
Results in swi-prolog:
?- neq(s(s(0)), s(0)).
true.
?- neq(s(0), s(s(0))).
true.
?- neq(N, M).
N = 0,
M = s(_) ;
N = s(_),
M = 0 ;
N = s(s(_)),
M = s(0) ;
N = s(0),
M = s(s(_)) ;
N = s(s(0)),
M = s(s(s(_))) ;
N = s(s(s(_))),
M = s(s(0)) ;

Evaluating expressions with indexicals in SICStus Prolog

I'm trying to write a predicate in SICStus Prolog such that given an expression, I can evaluate it (possible several times). The following works as expected:
?- A is 1, H = A+2+2, C is H.
C = 5 ?
yes
And so does this more elaborate code:
testing(Variables, Updates, Values, Result):-
assert(temp(Variables, Updates)),
temp(Values, Result),
abolish(temp/2).
evaluate([],[]).
evaluate([Term|T1],[H|T2]):-
H is Term,
evaluate(T1,T2).
Now, if instead A is an indexical, say A in 1..3, it doesn't work anymore. Any ideas about how to fix it?
The longer code is supposed to be used as follows:
?- testing([A,B,C], [A+1,B+C,max(A,B)], [0,0,0], Result), evaluate(Result, R).
Result = [0+1,0+0,max(0,0)],
R = [1,0,0] ?
yes
But is suffers from the same problem as the small example: I can't provide ranges of values in this way:
?- Val1 in 1..2, Val2 in 3..10, testing([A,B], [A+1,B+A], [Val1,Val2], Result), evaluate(Result, R).
Any suggestions?
My current solution requires replacing is/2 with val_of/2. It works, but I still believe there should be a better/faster implementation.
testing(Variables, Updates, Values, Result):-
assert(temp(Variables, Updates)),
temp(Values, Result),
abolish(temp/2).
evaluate([],[]).
evaluate([Term|T1],[H|T2]):-
val_of(H,Term),
evaluate(T1,T2).
val_of(E,E):- number(E),!.
val_of(E,E):- var(E),!.
val_of(V,E1+E2):- !, val_of(V1,E1), val_of(V2,E2), V #= V1+V2.
val_of(V,E1-E2):- !, val_of(V1,E1), val_of(V2,E2), V #= V1-V2.
val_of(V,max(E1,E2)):- !, val_of(V1,E1), val_of(V2,E2), V #= max(V1,V2).
val_of(V,min(E1,E2)):- !, val_of(V1,E1), val_of(V2,E2), V #= min(V1,V2).
val_of(V,abs(E1,E2)):- !, val_of(V1,E1), val_of(V2,E2), V #= abs(V1,V2).
A test example:
| ?- X in 1..3, testing([A,B], [A+1,B], [X,0], R), evaluate(R,R1).
R = [X+1,0],
R1 = [_A,0],
X in 1..3,
_A in 2..4 ?
yes
I think that all you need is just
evaluate([],[]).
evaluate([Term|T1],[H|T2]):-
H #= Term,
evaluate(T1,T2).
but the temp/2 relation is unnecessary, so a real simplification could be:
testing(Variables, Updates, Values, Result):-
maplist(#=, Updates, Values), Result=Variables.
results in
?- testing([A,B,C], [A+1,B+C,max(A,B)], [0,0,0], Result).
A = -1,
B = C, C = 0,
Result = [-1, 0, 0].
(note: tested in SWI-Prolog, after ?- [library(clpfd)].)
My final solution is a modified version of my original code based on the useful answers and comments provided by #CapelliC and #false:
testing(Variables, Updates, Values, Result):-
copy_term(Variables-Updates, Values-Result).
evaluate([],[]).
evaluate([Term|T1],[H|T2]):-
call(H #= Term),
evaluate(T1,T2).
The main issue in my original code was the missing call/1 in evaluate/2.
A test example in SICStus Prolog looks like this:
?- A in 1..3, testing([C,D,R],[C+1,max(D,5),R],[A,0,0],Res), evaluate(Res,T).
Res = [A+1,max(0,5),0],
T = [_A,5,0],
A in 1..3,
_A in 2..4 ?
yes

SWI-Prolog CLPFD

I'm new to prolog for constraint programming. I have an issue with CLPFD not reducing a domain as I expect it to. This is probably really simple.
[A,B] ins 1..5,A*B#=5.
I expect it to reduce the domain of A and B to
1\/5
But it just gives
A in 1..5,
A*B#=5,
B in 1..5.
Any suggestions would be appreciated.
While this answer is tailored to clpfd as implemented in swi-prolog, the idea/method is portable.
:- use_module(library(clpfd)).
Here's how we can reduce domain sizes before starting full enumeration:
shave_zs(Zs) :-
maplist(flag_zs_shave_z(F,Zs), Zs),
once((var(F) ; ground(Zs) ; shave_zs(Zs))).
flag_zs_shave_z(Flag, Zs, Z) :-
( fd_size(Z, sup)
-> true % never shave the infinite
; fd_dom(Z, Z_dom),
phrase(dom_integers_(Z_dom), Z_vals),
maplist(flag_zs_z_val(Flag,Zs,Z), Z_vals)
).
flag_zs_z_val(Flag, Zs, Z, Z_val) :-
( \+ call_with_inference_limit((Z #= Z_val,labeling([],Zs)), 1000, _)
-> Z #\= Z_val,
Flag = true
; true
).
We use grammar dom_integers_//1, as defined on the SWI-Prolog clpfd manual page:
dom_integers_(I) --> { integer(I) }, [I].
dom_integers_(L..U) --> { numlist(L, U, Is) }, Is.
dom_integers_(D1\/D2) --> dom_integers_(D1), dom_integers_(D2).
Sample queries:
?- [A,B] ins 1..5, A*B #= 5, (Shaved = false ; Shaved = true, shave_zs([A,B])).
Shaved = false, A*B #= 5, A in 1..5, B in 1..5 ;
Shaved = true, A*B #= 5, A in 1\/5, B in 1\/5.
?- [A,B] ins 1..10, A*B #= 10, (Shaved = false ; Shaved = true, shave_zs([A,B])).
Shaved = false, A*B #= 10, A in 1..10 , B in 1..10 ;
Shaved = true, A*B #= 10, A in 1..2\/5\/10, B in 1..2\/5\/10.
You are right that 1\/5 would be optimal pruning in this case.
However, for efficiency reasons, CLP(FD) systems typically maintain only so-called bounds consistency for arithmetic constraints, and in general do not remove interior elements from domains even when some of them cannot participate in solutions.
Bounds consistency, in the finite case, means that there are solutions where the variable assumes the lower and upper boundary of the domain. In this case, there are solutions for A=1 and A=5.
Notice that these are the only solutions in this concrete case, but in general, there are also solutions with interior points in analogous larger instances, for example:
?- [A,B] ins 1..10, A*B#=10, label([A,B]).
A = 1,
B = 10 ;
A = 2,
B = 5 ;
A = 5,
B = 2 ;
A = 10,
B = 1.
The good news though is that the number of such solutions only grows logarithmically in the size of the domain:
?- length(_, Exp), N #= 2^Exp, [A,B] ins 1..N,A*B#=N,
findall(., label([A,B]), Ls), length(Ls, L),
writeln(Exp-L), false.
0-1
1-2
2-3
3-4
4-5
5-6
6-7
7-8
etc.
This is in contrast to other cases, like X mod 2 #= 0, where the number of solutions grows linearly in the size of the domain of X (and thus exponentially in the length of its decimal representation), and it is thus not feasible to explicitly prune the domain.
Thus, as a feasible workaround, you can use label/1 to obtain concrete solutions, and then use in/2 constraints to restrict the operands to their concretely admissible domains:
:- use_module(library(clpfd)).
stricter_domains(Vs) :-
findall(Vs, label(Vs), Sols0),
transpose(Sols0, Sols),
maplist(list_to_domain, Sols, Ds),
maplist(in, Vs, Ds).
list_to_domain([L|Ls], Dom) :- foldl(dom_disj, Ls, L, Dom).
dom_disj(D0, I, D0\/I).
Your example:
?- [A,B] ins 1..5, A*B#=5, stricter_domains([A,B]).
A in 1\/5,
A*B#=5,
B in 1\/5.

How can I define a new operator in Prolog?

I'm trying to define an operator =>> that checks if one of its operands is double of the other operand.
I tried so far:
:- op(200, xfy, =>>).
=>>(L, R) :- double(L, R); double(R, L).
double(L, R) :- L is R * 2.
But when used in RPEL, I got :
?- (-8) =>> (-4).
true ;
false.
%^^^^ note here
?- 7 =>> 3.
false.
?- 40 =>> 20.
true ;
false.
%^^^^ note here
?- 20 =>> 40.
true.
What is the problem? How can I fix it?
There are several issues. First, defining an operator for such a tiny task is a bit of an overkill. Always keep in mind the cost of declaring an operator: Every time you define an operator you change the language a bit which means that people who read that program text will have to learn that syntax as well.
So best would be to just stay with a simple predicate name. And if you really insist on it, try to use operators in a way, similar to existing operators. We have roughly the following three groups in ISO Prolog according to their priority:
1200-900: Rules, control constructs. Most notably conjunction is 1000.
700, xfx: Comparison related infix operators like: = \= == \== #< #=< #> #>= =.. is =:= =\= < =< > >=. Note that these are all non-associative, since nesting is not specific to their meaning.
500-200: Expressions.
Also note that all the symmetric relations have symmetric names — except for the negated ones: \= and \==.
:- op(700,xfx,=:*:=).
=:*:=(X, Y) :-
(X - 2*Y) * (Y - 2*X) =:= 0.
The following might be preferable since the intermediary results are smaller and thus multiplication is cheaper and never produces an overflow:
=:*:=(X, Y) :-
sign(X - 2*Y) * sign(Y - 2*X) =:= 0.
This is a determinism issue: There may be further solutions ((;)/2 can be read as "or"), and therefore Prolog backtracks (and finds no alternative).
There is an easy way to fix this: Use once/1 to commit to the first solution, if any:
L =>> R :- once((double(L, R) ; double(R, L))).
Notice also that you may want to use =:=/2, not is/2, in this case. Even better, if you are working over integers, simply use CLP(FD) constraints, and your predicate will be deterministic and much more general:
:- use_module(library(clpfd)).
L =>> R :- L #= R*2 #\/ R #= L*2.
Examples:
?- 40 =>> 20.
true.
?- 40 =>> X, X #< 80.
X = 20.
?- X =>> Y, X #= 2, Y #= 3.
false.

clpfd - constraint upper bond of domain the be the maximum of a list of elements

Given the following code:
solve(G,L) :-
G = [A0,B0,C0,D0],
L = [A1,B1,C1,D1,A2,B2,C2,D2,A3,B3,C3,D3,A4,B4,C4,D4],
G ins 0..4,
L ins 0..max(G).
I want to constraint L to not contain values that are higher than the maximum value contained in G, but I get a "domain error" when using this syntax. Is there another way to express this?
Essentially you were on the right track. But L ins 0..max(G) does not work, because the bounds that you pass to ins/2 need to be integers or inf or sup.
SWI-Prolog clpfd manual page supports max in
finite domain arithmetic expressions, so we first state that MaxG is the maximum of A0, B0, C0, and D0. Then we state that MaxG is greater than or equal to each item in list L.
Putting it all together:
:- use_module(library(clpfd)).
gte_than(X,Y) :-
X #>= Y.
solve(G,L) :-
G = [A0,B0,C0,D0],
L = [A1,B1,C1,D1,A2,B2,C2,D2,A3,B3,C3,D3,A4,B4,C4,D4],
G ins 0..4,
L ins 0..sup,
MaxG #= max(max(A0,B0),max(C0,D0)),
maplist(gte_than(MaxG),L).
Here are some queries:
?- solve([0,1,2,1], [0,1,2,1,1,2,1,2,1,0,1,2,1,1,1,2]).
true.
?- solve([0,1,2,1], [0,3,2,1,1,2,1,2,1,0,1,2,1,1,1,2]).
false.
?- solve([0,3,2,1], [0,3,2,1,1,2,1,2,1,0,1,2,1,1,1,2]).
true.
?- solve([0,3,2,1], [0,3,2,1,1,2,4,4,1,0,1,2,1,1,1,2]).
false.
?- solve([4,3,2,1], [0,3,2,1,1,2,4,4,1,0,1,2,1,1,1,2]).
true.
Side note: SICStus Prolog has a specialized arithmetic constraint named maximum/2 we could use here, but that constraint is not (yet) available in clpfd with SWI-Prolog.

Resources