clpz
clpz copied to clipboard
min could settle if one input and the other's upper bound are known
I'm wondering if we could we unify B=A here:
A in 0..100, B #= min(100, A).
returns:
clpz:(B#=min(100,A)),
clpz:(A#>=B),
clpz:(A in 0..100),
clpz:(B in 0..100) ?
yes
Especially if A can definitely not be less than 100:
| ?- [A, B] ins 0..100, B #= min(100, A), B#\=A, labeling([], [A,B]).
no
it's possible to make the constraint stronger:
propagator for `min`
% Z=min(X, Y)
% min(X, Y) = min(Y, X), X =< Y <=> X = min(X, Y)
%
% X =< Y => Z = X
% Z = X => Z =< Y
% Z < X => Z = Y
run_propagator(pmin(X,Y,Z), MState) -->
( nonvar(X), nonvar(Y), nonvar(Z)
-> Z =:= min(X, Y)
; X == Y
-> kill(MState),
queue_goal(Z = X)
; run_propagator(pmin2(X,Y,Z), MState),
run_propagator(pmin2(Y,X,Z), MState),
run_propagator(pmin1(X,Y,Z), MState),
run_propagator(pmin1(Y,X,Z), MState),
run_propagator(pmin0(X,Y,Z), MState),
run_propagator(pmin0(Y,X,Z), MState)
).
run_propagator(pmin2(X,Y,Z), MState) -->
( nonvar(X), nonvar(Y), nonvar(Z)
-> true
; ( nonvar(X), nonvar(Y), X =< Y
-> kill(MState),
queue_goal(Z = X)
; true
),
( nonvar(Z), nonvar(X)
-> ( Z = X
-> kill(MState),
% queue_goal(#Z #=< #Y)
{ fd_get(Y, YD0, YPs0),
domain_remove_smaller_than(YD0, Z, YD1) },
fd_put(Y, YD1, YPs0)
; Z < X
-> kill(MState),
queue_goal(Z = Y)
; false % Z > X
)
; true
)
).
run_propagator(pmin1(X,Y,Z), MState) -->
( nonvar(X), nonvar(Y)
-> true
; nonvar(Y), nonvar(Z)
-> true
; nonvar(Z), nonvar(X)
-> true
; ( { nonvar(X), fd_get(Y, _, n(YL), _, _), X =< YL }
-> kill(MState),
queue_goal(Z = X)
; { fd_get(X, _, _, n(XU), _), nonvar(Y), XU =< Y }
-> kill(MState),
queue_goal(Z = X)
; true
),
( Z == X, nonvar(Y)
-> kill(MState),
% queue_goal(#Z #=< #Y)
{ fd_get(Z, ZD0, ZPs0),
domain_remove_greater_than(ZD0, Y, ZD1) },
fd_put(Z, ZD1, ZPs0)
; { nonvar(Z), fd_get(X, _, n(XL), _, _), Z < XL }
-> kill(MState),
queue_goal(Z = Y)
; { fd_get(Z, _, _, n(ZU), _), nonvar(X), ZU < X }
-> kill(MState),
queue_goal(Z = Y)
% ; nonvar(Z)
% -> true % queue_goal((#Z #=< #X, #Z #=< #Y))
; true
),
( { fd_get(X, _, n(XL), _, _), nonvar(Y), XL =< Y }
-> % queue_goal(#Z #>= #XL)
{ fd_get(Z, ZD2, ZPs1),
domain_remove_smaller_than(ZD2, XL, ZD3) },
fd_put(Z, ZD3, ZPs1)
; true
)
).
run_propagator(pmin0(X,Y,Z), MState) -->
( nonvar(X)
-> true
; nonvar(Y)
-> true
; nonvar(Z)
-> true
; ( { fd_get(X, _, _, n(XU), _), fd_get(Y, _, n(YL), _, _), XU =< YL }
-> kill(MState),
queue_goal(Z = X)
; true
),
( Z == X
-> kill(MState),
queue_goal(#Z #=< #Y)
; { fd_get(Z, _, _, n(ZU), _), fd_get(X, _, n(XL), _, _), ZU < XL }
-> kill(MState),
queue_goal(Z = Y)
; true
),
( { fd_get(X, _, n(XL), _, _), fd_get(Y, _, n(YL), _, _), XL =< YL }
-> % queue_goal(#Z #>= #XL)
{ fd_get(Z, ZD2, ZPs1),
domain_remove_smaller_than(ZD2, XL, ZD3) },
fd_put(Z, ZD3, ZPs1)
; true
)
).
This version is not too efficient. It still needs some testing. This version of min could land on Scryer Prolog. The maximum would also have a stronger version.