1 % (c) 2009-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(kernel_dif,[frozen_dif/2, fd_frozen_dif/2,
6 syntactic_equality_test/3
7 %, post_dif/2
8 ]).
9
10
11 :- use_module(module_information,[module_info/2]).
12 :- module_info(group,kernel).
13 :- module_info(description,'This module provides a dif which works with reified equality.').
14
15 :- use_module(clpfd_interface,[clpfd_can_intersect/2]).
16 % a version of frozen_dif which uses FD information to avoid calling frozen_dif if possible
17 % see ../prob_examples/examples/B/ClearSy/alloc_large.mch where frozen_dif is a bottleneck
18 fd_frozen_dif(X,Y) :-
19 ( clpfd_can_intersect(X,Y)
20 -> var(X),var(Y), % CLP(FD) at least on SICStus can propagate X#\=Nr : X #\= 5. --> X in(inf..4)\/(6..sup) ?
21 % so there cannot be a frozen dif constraint (if a corresponding CLP #\= was posted)
22 frozen_dif(X,Y)
23 ; true % X and Y must be different
24 ).
25
26 :- use_module(preferences).
27 % check if a frozen dif co-routine is pending and stating that the variables are different
28 % cf testcase 1175
29 %frozen_dif(X,Y) :- preferences:preference(use_smt_mode,false),!,fail.
30 frozen_dif(X,Y) :-
31 % print(check_frozen(X,Y)),nl, translate:l_print_frozen_info([X,Y]),nl,
32 var(X),
33 !,
34 X \== Y, % avoid calling frozen when both variables identical
35 frozen(X,Goal), %print(frozen(X,Y)),nl,portray_clause((check_frozen_dif(X,Y) :- Goal)),nl,
36 %terms:term_size(Goal,Sz), (Sz>200 -> print(large_frozen(X,Y,Sz)),nl,print(Goal),nl ; true),
37 preferences:preference(solver_strength,Strength),
38 Limit is 5+2*Strength,
39 frozen_dif_aux(Goal,Limit,X,Y). % increase required from 5 to 6 for SlotTool_04092017 issue
40 frozen_dif(X,Y) :- var(Y), frozen(Y,Goal), % do we need this in clpfd mode ? should we use solver_strength?
41 preferences:preference(solver_strength,Strength),
42 Limit is 2+Strength, % with TRACE_INFO or in SWI we may have additional goals and limit may be reached
43 frozen_dif_aux(Goal,Limit,Y,X).
44 frozen_dif_aux(kernel_objects:int_plus4(Nr,A,B),_,X,Y) :- !,
45 integer(Nr), % should always be the case, TO DO: maybe use CHR for this
46 Nr \= 0, % should normally also always be true, as int_plus4 would not have been called
47 (A==X -> B==Y % TO DO: maybe check if Y is variable and has int_plus attached wrt B to detect that z+1 is different from z+2
48 ; B==X -> A==Y % ditto
49 ).
50 frozen_dif_aux(prolog:dif(A,B),_,X,Y) :- !,
51 (A==X,B==Y ; A==Y,B==X). % , print(frozen_dif(X,Y)),nl.
52 frozen_dif_aux(dif(A,B),_,X,Y) :- !,
53 (A==X,B==Y ; A==Y,B==X). % , print(frozen_dif(X,Y)),nl.
54 % Nr: put an upper bound on checks; avoid slow-down when frozen goal very large; see e.g. alloc_large in test 1222
55 % TO DO: use attribute and get more efficient lookup
56 frozen_dif_aux((A,B),Nr,X,Y) :-
57 Nr>1, %(Nr>1 -> true ; print(frozen_dif_limit_reached(X,Y,(A,B))),nl,fail),
58 N1 is Nr-1,
59 ? (frozen_dif_aux(A,N1,X,Y) -> true ; frozen_dif_aux(B,N1,X,Y)).
60
61
62
63 % a reified version for syntactic equality ==
64
65 % trigger Res to pred_true when two variables become identical (as CLPFD does not do this)
66 % it is supposed to be used in conjunction with ((X#=Y) #<=> R01)
67 %syntactic_equality_test(X,Y,Res) :- Res==pred_true, !, print(useless_syntactic_test(X,Y,Res)),nl.
68 syntactic_equality_test(X,Y,Res) :-
69 % TO DO: attach attribute/co-routine so that dif will trigger Res to be pred_false ?
70 % e.g., (X=Y <=> r=TRUE) & X:1..100 & Y /= X does not deterministically set r to FALSE (but does if Y/=X moved to the left)
71 %reify(X,Y,Res), % a way to attach information for frozen_eqeq check
72 %when(?=(X,Y),(X==Y -> Res=pred_true ; true)). % CLPFD does not detect variable equality
73 when((?=(X,Y) ; nonvar(Res)),syntactic_eq_prop(Res,X,Y)). % CLPFD does not detect variable equality
74
75 syntactic_eq_prop(Res,X,Y) :- var(Res), !,
76 (X==Y
77 -> Res=pred_true
78 ; Res=pred_false). % syntactically not equal, as ?=(X,Y) triggered they must be different FD values
79 syntactic_eq_prop(pred_true,X,Y) :-
80 (var(X),var(Y) -> X=Y ; true). % CLPFD reification does not unify ! required for test 1525
81 syntactic_eq_prop(pred_false,X,Y) :-
82 (var(X),var(Y)
83 -> dif(X,Y)
84 ; true). % CLPFD can handle X #= Nr without dif; see NinePrisoners performance when dif is unnecessarily posted
85
86
87 /*
88 % currently not used:
89
90 :- block reify(-,-,-).
91 reify(_,_,_).
92
93 post_dif(X,Y) :- dif(X,Y),
94 (frozen_eqeq(X,Y,Res) -> print(frz(X,Y,Res)),nl, Res=pred_false ; true).
95
96 %kernel_dif:syntactic_equality_test(X,Y,R), kernel_dif:post_dif(X,Y), -> R==pred_false
97
98 frozen_eqeq(X,Y,R) :-
99 % print(check_frozen(X,Y)),nl, translate:l_print_frozen_info([X,Y]),nl,
100 var(X),!,frozen(X,Goal),
101 frozen_eqeq_aux(Goal,5,X,Y,R).
102 frozen_eqeq(X,Y,R) :- var(Y), frozen(Y,Goal), % do we need this in clpfd mode ?
103 frozen_eqeq_aux(Goal,2,Y,X,R).
104 frozen_eqeq_aux(kernel_dif:reify(A,B,R),_,X,Y,R) :-
105 (A==X,B==Y ; A==Y,B==X),
106 !. % , print(frozen_dif(X,Y)),nl.
107 % Nr: put an upper bound on checks; avoid slow-down when frozen goal very large; see e.g. alloc_large in test 1220
108 % TO DO: use attribute and get more efficient lookup
109 frozen_eqeq_aux((A,B),Nr,X,Y,R) :- Nr>1, N1 is Nr-1,
110 (frozen_eqeq_aux(A,N1,X,Y,R) -> true ; frozen_eqeq_aux(B,N1,X,Y,R)).
111 */