From 282633c877fe1cf9fa39a900c33e4fb05922f43b Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 10 Oct 2023 19:42:42 +0200 Subject: [PATCH 1/4] ENHANCED: Queue morphed propagators to give them a chance for propagation. This addresses #2096: ?- B in -2..0, 0#<==>0#=0/(B*B),labeling([],[B]). B = 0. ?- A#<==>A#=A/A^2,A=0. A = 0. --- src/lib/clpz.pl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index ff7cfe4f..77bd7ba6 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -2657,6 +2657,12 @@ morphing_propagator(P0, P, Target) :- ), P =.. [F|Args]. +morph_into_propagator(MState, Vs, Propagator, Morph) --> + kill(MState), + { make_propagator(Propagator, Morph) }, + init_propagator_(Vs, Morph), + trigger_prop(Morph). + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ?- use_module(library(lists)), use_module(library(format)), @@ -4834,9 +4840,7 @@ run_propagator(pplus(X,Y,Z,Morph), MState) --> ) ) ; ( X == Y -> - kill(MState), - { make_propagator(ptimes(2,X,Z,_), Morph) }, - init_propagator_([X,Z], Morph) + morph_into_propagator(MState, [X,Z], ptimes(2,X,Z,_), Morph) ; X == Z -> kill(MState), Y = 0 ; Y == Z -> kill(MState), X = 0 ; { fd_get(X, XD, XL, XU, XPs), @@ -4909,9 +4913,7 @@ run_propagator(ptimes(X,Y,Z,Morph), MState) --> ) ) ; ( X == Y -> - kill(MState), - { make_propagator(pexp(X,2,Z,_), Morph) }, - init_propagator_([X,Z], Morph) + morph_into_propagator(MState, [X,Z], pexp(X,2,Z,_), Morph) ; { fd_get(X, XD, XL, XU, XPs), fd_get(Y, _, YL, YU, _), fd_get(Z, ZD, ZL, ZU, _) }, @@ -5440,10 +5442,8 @@ run_propagator(pmin(X,Y,Z), MState) --> run_propagator(pexp(X,Y,Z,Morph), MState) --> ( X == 1 -> kill(MState), Z = 1 ; X == 0 -> - kill(MState), queue_goal((Z in 0..1, Y #>= 0)), - { make_propagator(reified_eq(1,Y,1,0,[],Z), Morph) }, - init_propagator_([Y,Z], Morph) + morph_into_propagator(MState, [Y,Z], reified_eq(1,Y,1,0,[],Z), Morph) ; Y == 0 -> kill(MState), Z = 1 ; Y == 1 -> kill(MState), Z = X ; nonvar(X) -> From 32af04792592aa2292676ee9ee4770856c08b317 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 10 Oct 2023 19:49:48 +0200 Subject: [PATCH 2/4] remove definition and calls of do_queue/0, which has become a NOP --- src/lib/clpz.pl | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index 77bd7ba6..76dee8bb 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -1957,7 +1957,6 @@ choice_order_variable(step, Order, Var, Vars, Vars0, Selection, Consistency) :- ( Var = Next, label(Vars, Selection, Order, step, Consistency) ; neq_num(Var, Next), - do_queue, label(Vars0, Selection, Order, step, Consistency) ). choice_order_variable(enum, Order, Var, Vars, _, Selection, Consistency) :- @@ -2753,14 +2752,12 @@ geq(A, B) :- ) ; ( AI cis_geq n(B) -> true ; domain_remove_smaller_than(AD, B, AD1), - fd_put(A, AD1, APs), - do_queue + fd_put(A, AD1, APs) ) ) ; fd_get(B, BD, BPs) -> domain_remove_greater_than(BD, A, BD1), - fd_put(B, BD1, BPs), - do_queue + fd_put(B, BD1, BPs) ; A >= B ). @@ -3316,7 +3313,7 @@ integer_kroot_leq(L, U, N, K, R) :- % When reasoning over integers, replace (=\=)/2 by (#\=)/2 to obtain more % general relations. -X #\= Y :- clpz_neq(X, Y), do_queue. +X #\= Y :- clpz_neq(X, Y). % X #\= Y + Z @@ -3379,7 +3376,7 @@ X #< Y :- Y #> X. % X in inf.. -4\/1..9\/81..sup. % ``` -#\ Q :- reify(Q, 0), do_queue. +#\ Q :- reify(Q, 0). %% #<==>(?P, ?Q) % @@ -3417,7 +3414,7 @@ X #< Y :- Y #> X. % Z = 2. % ``` -L #<==> R :- reify(L, B), reify(R, B), do_queue. +L #<==> R :- reify(L, B), reify(R, B). %% #==>(?P, ?Q) % @@ -3452,7 +3449,7 @@ L #<== R :- R #==> L. % % P and Q hold. -L #/\ R :- reify(L, 1), reify(R, 1), do_queue. +L #/\ R :- reify(L, 1), reify(R, 1). conjunctive_neqs_var_drep(Eqs, Var, Drep) :- conjunctive_neqs_var(Eqs, Var), @@ -3906,7 +3903,6 @@ domain(V, Dom) :- domains_intersection(Dom, Dom0, Dom1), %format("intersected\n: ~w\n ~w\n==> ~w\n\n", [Dom,Dom0,Dom1]), fd_put(V, Dom1, VPs), - do_queue, reinforce(V) ; domain_contains(Dom, V) ). @@ -4221,7 +4217,6 @@ activate_propagator(propagator(P,State)) --> enable_queue :- true. % NOP disable_queue :- true. % NOP -do_queue. % NOP %do_queue --> print_queue, { false }. do_queue --> @@ -6446,8 +6441,7 @@ num_infinite(Var, N0, N) :- weak_arc_all_distinct(Ls) :- must_be(list, Ls), Orig = original_goal(_, weak_arc_all_distinct(Ls)), - all_distinct(Ls, [], Orig), - do_queue. + all_distinct(Ls, [], Orig). all_distinct([], _, _). all_distinct([X|Right], Left, Orig) :- @@ -6760,8 +6754,10 @@ gcc_pairs([Key-Num0|KNs], Vs, [Key-Num|Rest]) :- gcc_global(Vs, KNs) :- gcc_check(KNs), - % reach fix-point: all elements of clpz_gcc_vs must be variables - do_queue, + % previously: call do_queue/0 (now a NOP) here to reach a + % fix-point: all elements of clpz_gcc_vs must be variables. We + % must ensure this holds if gcc_check/1 is later rewritten to + % actually disable the queue. with_local_attributes(Vs, (gcc_arcs(KNs, S, Vals), variables_with_num_occurrences(Vs, VNs), From 26fdf83a483ac98eae92aa56f13326d1af335093 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 10 Oct 2023 19:53:26 +0200 Subject: [PATCH 3/4] update comment to reflect the used propagators --- src/lib/clpz.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index 76dee8bb..2432d6b1 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -3545,9 +3545,9 @@ L #\ R :- (L #\/ R) #/\ #\ (L #/\ R). undefined, created auxiliary constraints are killed, and the "clpz" attribute is removed from auxiliary variables. - For mod/2, div/2, rem/2 etc. we create a skeleton propagator and - remember it as an auxiliary constraint. The pskeleton propagator - can use the skeleton when the constraint is defined. + For (//)/2, (mod)/2 and (rem)/2, we create a skeleton propagator + and remember it as an auxiliary constraint. The pskeleton + propagator can use the skeleton when the constraint is defined. We cannot use a skeleton propagator for (/)/2, since (/)/2 can fail in cases such as 0 #==> X #= 1/2, where we expect success. From 8de3498e07cfb155dac28bd85e9e88dd2147078b Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 10 Oct 2023 19:54:12 +0200 Subject: [PATCH 4/4] use round brackets around operators to form valid Prolog terms --- src/lib/clpz.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index 2432d6b1..faad7c0f 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -3537,9 +3537,9 @@ L #\ R :- (L #\/ R) #/\ #\ (L #/\ R). d(D) that states D is 1 iff all subexpressions are defined. a(V) means that V is an auxiliary variable that was introduced while parsing a compound expression. a(X,V) means V is auxiliary unless - it is ==/2 X, and a(X,Y,V) means V is auxiliary unless it is ==/2 X - or Y. l(L) means the literal L occurs in the described list, - and ls(Ls) means the literals Ls occur in the described list. + it is (==)/2 X, and a(X,Y,V) means V is auxiliary unless it is + (==)/2 X or Y. l(L) means the literal L occurs in the described + list, and ls(Ls) means the literals Ls occur in the described list. When a constraint becomes entailed or subexpressions become undefined, created auxiliary constraints are killed, and the