Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

min could settle if one input and the other's upper bound are known #39

Open
jeshan opened this issue Jan 18, 2025 · 1 comment
Open

Comments

@jeshan
Copy link

jeshan commented Jan 18, 2025

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
@notoria
Copy link

notoria commented Feb 3, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants