X^2 + Y^2 =< C.
Assuming that X and Y are domain variables, we would like to define such a predicate that will be woken as soon as one or both variables' domains are updated in such a way that would require updating the other variable's domain, i.e. updates that would propagate via this constraint. For simplicity we assume that X and Y are nonnegative. We will define the predicate sq(X, Y, C) which will implement this constraint:
:- use_module(library(fd)).
% A*A + B*B <= C
sq(A, B, C) :-
dvar_domain(A, DomA),
dvar_domain(B, DomB),
dom_range(DomA, MinA, MaxA),
dom_range(DomB, MinB, MaxB),
MiA2 is MinA*MinA,
MaB2 is MaxB*MaxB,
(MiA2 + MaB2 > C ->
NewMaxB is fix(sqrt(C - MiA2)),
dvar_remove_greater(B, NewMaxB)
;
NewMaxB = MaxB
),
MaA2 is MaxA*MaxA,
MiB2 is MinB*MinB,
(MaA2 + MiB2 > C ->
NewMaxA is fix(sqrt(C - MiB2)),
dvar_remove_greater(A, NewMaxA)
;
NewMaxA = MaxA
),
(NewMaxA*NewMaxA + NewMaxB*NewMaxB =< C ->
true
;
suspend(sq(A, B, C), 3, (A, B)->min)
),
wake. % Trigger the propagation
The steps to be executed when this constraint becomes active, i.e. when the predicate sq/3 is called or woken are the following:
Here is what we get:
[eclipse 20]: [X,Y]::1..10, sq(X, Y, 50).
X = X{[1..7]}
Y = Y{[1..7]}
Delayed goals:
sq(X{[1..7]}, Y{[1..7]}, 50)
yes.
[eclipse 21]: [X,Y]::1..10, sq(X, Y, 50), X #> 5.
Y = Y{[1..3]}
X = X{[6, 7]}
Delayed goals:
sq(X{[6, 7]}, Y{[1..3]}, 50)
yes.
[eclipse 22]: [X,Y]::1..10, sq(X, Y, 50), X #> 5, Y #> 1.
X = 6
Y = Y{[2, 3]}
yes.
[eclipse 23]: [X,Y]::1..10, sq(X, Y, 50), X #> 5, Y #> 2.
X = 6
Y = 3
yes.