1 | | % (c) 2009-2019 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(b_interpreter_check,[imply_test_boolean_expression/7, |
6 | | equiv_test_boolean_expression/7, |
7 | | equiv_bidrectional_test_boolean_expression/7, |
8 | | get_priority_of_boolean_expression/2, get_priority_of_boolean_expression2/2, |
9 | | b_check_boolean_expression/5,b_check_boolean_expression/7, |
10 | | |
11 | | /* some lower-level propagation predicates */ |
12 | | imply_true/2, |
13 | | b_check_forall_wf/8, b_check_exists_wf/7, |
14 | | |
15 | | reify_closure_with_small_cardinality/5, |
16 | | |
17 | | register_predicate/6, |
18 | | |
19 | | conjoin/6, disjoin/6 |
20 | | ]). |
21 | | |
22 | | /* A version for checking the truth value of boolean-expressions, |
23 | | the result is instantiated with pred_true/pred_false as soon as the result is known */ |
24 | | /* Warning: does not cover all expressions */ |
25 | | /* It provides SMT-like performance, for predicates involving arithmetic comparisons (<,...), |
26 | | equality, disequality and membership/not_membership |
27 | | It is not restricted to CNF |
28 | | */ |
29 | | |
30 | | :- use_module(debug). |
31 | | :- use_module(self_check). |
32 | | :- use_module(error_manager). |
33 | | :- use_module(b_interpreter,[b_compute_expression/5, b_not_test_boolean_expression/6, b_test_boolean_expression/6, b_test_boolean_expression/4]). |
34 | | :- use_module(kernel_waitflags). |
35 | | |
36 | | |
37 | | :- use_module(kernel_objects,[less_than_direct/2, less_than_equal_direct/2]). |
38 | | |
39 | | :- use_module(kernel_equality). |
40 | | |
41 | | :- use_module(tools). |
42 | | |
43 | | :- use_module(module_information,[module_info/2]). |
44 | | :- module_info(group,interpreter). |
45 | | :- module_info(description,'This module provides a reified interpreter for certain predicates.'). |
46 | | |
47 | | |
48 | | |
49 | | :- meta_predicate wd_delay(0,-,-,-). |
50 | | :- meta_predicate wd_delay_block(0,-,-,-,-,-). |
51 | | :- meta_predicate wd_delay_until_needed(-,0). |
52 | | :- meta_predicate wd_delay_until_needed_block(-,-,0,0). |
53 | | |
54 | | :- block imply_test_boolean_expression(-, ?,?,?,?,?,?). % TO DO: pass at least Ai to it |
55 | | imply_test_boolean_expression(PredRes1,PredRes2, RHS,LocalState,State,WF,Ai) :- |
56 | ? | (PredRes1=PredRes2 |
57 | | -> % print('enforcing RHS '),print(PredRes), print(' : '), translate:print_bexpr(RHS),nl, %% |
58 | | % print(LocalState),nl, |
59 | ? | b_test_boolean_expression(RHS,LocalState,State,WF,Ai,_) |
60 | | ; true %,print(not_checking_rhs(_PRes)), print(' : '), print_bexpr(_RHS),nl, print(_State),nl |
61 | | ). |
62 | | |
63 | | :- block equiv_test_boolean_expression(-, ?,?,?,?,?,?). |
64 | | equiv_test_boolean_expression(PredRes,PredRes, RHS,LocalState,State,WF,Ai) :- !, |
65 | | %print('enforcing RHS '),print(PredRes), print(' : '), print_bexpr(RHS),nl, |
66 | | b_test_boolean_expression(RHS,LocalState,State,WF,Ai,_). |
67 | | equiv_test_boolean_expression(_PredRes,_, RHS,LocalState,State,WF,Ai) :- |
68 | | %print('enforcing negation of RHS '),print(_PredRes), print(' : '), print_bexpr(RHS),nl, |
69 | | b_not_test_boolean_expression(RHS,LocalState,State,WF,Ai,_). |
70 | | |
71 | | equiv_bidrectional_test_boolean_expression(PredResLHS,PredResRHS, _LHS,_RHS,_LocalState,_State,WF) :- |
72 | | PredResLHS=PredResRHS, |
73 | | (var(PredResLHS) |
74 | | -> % create a choice point to enumerate two possible solutions |
75 | | % important, e.g., for not((y > 0 & y * y > 20) <=> (y * y > 25 & y > 0)) |
76 | | get_last_wait_flag(equivalence,WF,LWF), |
77 | | enum_bool(PredResLHS,LWF) |
78 | | ; true). |
79 | | :- block enum_bool(-,-). |
80 | | enum_bool(pred_true,_). |
81 | | enum_bool(pred_false,_). |
82 | | /* |
83 | | :- block equiv_bidrectional_test_boolean_expression(-,-, ?,?,?,?,?). |
84 | | equiv_bidrectional_test_boolean_expression(PredResLHS,PredResRHS, LHS,RHS,LocalState,State,WF) :- |
85 | | ( PredResLHS == pred_true -> b_test_boolean_expression(RHS,LocalState,State,WF) |
86 | | ; PredResLHS == pred_false -> b_not_test_boolean_expression(RHS,LocalState,State,WF) |
87 | | ; PredResRHS == pred_true -> b_test_boolean_expression(LHS,LocalState,State,WF) |
88 | | ; PredResRHS == pred_false -> b_not_test_boolean_expression(LHS,LocalState,State,WF) |
89 | | ; add_error_fail(equiv,'Illegal values: ',equiv_bidrectional_test_boolean_expression(PredResLHS,PredResRHS)) |
90 | | ). |
91 | | */ |
92 | | |
93 | | % return starting priority for binary choice points; should be power of 2 |
94 | | get_priority_of_boolean_expression(priority(P),Prio) :- !, |
95 | | % case generated for disjoin by contains_fd_element, and not_in_difference_set_wf,not_in_intersection_set_wf,in_union_set_wf |
96 | | Prio=P. |
97 | | get_priority_of_boolean_expression(b(Expr,_,_Infos),Prio) :- !, |
98 | | % try to estimate a priority for performing a case split upon a predicate |
99 | | % i.e., forcing a predicate Expr to be true/false |
100 | | get_priority_of_boolean_expression2(Expr,Prio). |
101 | | get_priority_of_boolean_expression(E,Prio) :- |
102 | | add_internal_error('Boolean expression not properly wrapped: ',get_priority_of_boolean_expression(E,Prio)), |
103 | | get_priority_of_boolean_expression2(E,Prio). |
104 | | |
105 | | :- use_module(bsyntaxtree). |
106 | | get_priority_of_boolean_expression2(truth,0) :- !. %, nl,nl,print('TRUTH in disjunct/conjunct'),nl. |
107 | | get_priority_of_boolean_expression2(falsity,0) :- !. %, nl,nl,print('FALSITY in disjunct/conjunct'),nl. |
108 | | get_priority_of_boolean_expression2(_,R) :- |
109 | | preferences:preference(data_validation_mode,true), % in data validation mode we want to drive enumeration from data values only |
110 | | !, R=4096. |
111 | | get_priority_of_boolean_expression2(_,R) :- !, R=4. % force SMT style case-splitting; was 3 before using get_binary_choice_wait_flag_exp_backoff; raising this to 4 makes test 1358, 49 behave better (baload_R07 recognised possible) |
112 | | |
113 | | |
114 | | |
115 | | |
116 | | count_number_of_conjuncts(b(Expr,_,_Infos),Prio) :- !, |
117 | | count_number_of_conjuncts2(Expr,Prio). |
118 | | count_number_of_conjuncts(priority(_),Prio) :- !, Prio=1. |
119 | | count_number_of_conjuncts(B,Prio) :- |
120 | | add_internal_error('Expression not wrapped: ',count_number_of_conjuncts(B,Prio)),Prio=1. |
121 | | count_number_of_conjuncts2(conjunct(A,B),Nr) :- !, count_number_of_conjuncts(A,NA), |
122 | | count_number_of_conjuncts(B,NB), Nr is NA+NB. |
123 | | count_number_of_conjuncts2(norm_conjunct(_,RHS),Res) :- length(RHS,Len),!, |
124 | | Res is Len+1. |
125 | | count_number_of_conjuncts2(negation(A),Nr) :- !, count_number_of_disjuncts(A,Nr). |
126 | | count_number_of_conjuncts2(_,1). |
127 | | |
128 | | :- public count_number_of_disjuncts/2. %currently commented out above |
129 | | count_number_of_disjuncts(b(Expr,_,_Infos),Prio) :- !, |
130 | | count_number_of_disjuncts2(Expr,Prio). |
131 | | count_number_of_disjuncts(priority(_),Prio) :- !, Prio=1. |
132 | | count_number_of_disjuncts(B,Prio) :- |
133 | | add_internal_error('Expression not wrapped: ',count_number_of_disjuncts(B,Prio)),Prio=1. |
134 | | count_number_of_disjuncts2(disjunct(A,B),Nr) :- !, count_number_of_disjuncts(A,NA), |
135 | | count_number_of_disjuncts(B,NB), Nr is NA+NB. |
136 | | count_number_of_disjuncts2(norm_disjunct(_,RHS),Res) :- length(RHS,Len),!, |
137 | | Res is Len+1. |
138 | | count_number_of_disjuncts2(negation(A),Nr) :- !, count_number_of_conjuncts(A,Nr). |
139 | | count_number_of_disjuncts2(_,1). |
140 | | |
141 | | |
142 | | |
143 | | % we need to ensure that b_check_boolean_expression does not create a choice point on its own |
144 | | |
145 | | b_check_boolean_expression(b(Expr,_,Infos),LS,S,WF,Res) :- |
146 | | (composed(Expr) -> empty_avl(Ai) |
147 | | ; Ai = no_avl), % simple expression: no sharing is possible: no need to register expressions |
148 | | b_check_boolean_expression2(Expr,Infos,LS,S,wfwd(WF,pred_true,pred_true),Res,Ai,_). |
149 | | |
150 | | composed(negation(_)). |
151 | | composed(conjunct(_,_)). |
152 | | composed(disjunct(_,_)). |
153 | | composed(implication(_,_)). |
154 | | composed(equivalence(_,_)). |
155 | | composed(let_predicate(_,_,_)). |
156 | | composed(lazy_let_pred(_,_,_)). |
157 | | |
158 | | b_check_boolean_expression(E,LS,S,WF,Res,Ai,Ao) :- |
159 | | % add information about WD context: wfwd(WF_store, ExpectedVal, Val) |
160 | | % when Val becomes nonvar: if Val==ExpectedVal we need the value of E, otherwise it should be discarded |
161 | | b_check_boolean_expression1(E,LS,S,wfwd(WF,pred_true,pred_true),Res,Ai,Ao). |
162 | | |
163 | | b_check_boolean_expression0(WDE,WDV,Expr,LS,S,WF,Res,Ai,Ao) :- |
164 | | b_check_boolean_expression1(Expr,LS,S,wfwd(WF,WDE,WDV),Res,Ai,Ao). |
165 | | % ((nonvar(WDV),WDE \= WDV) -> Ai=Ao, Res=pred_false |
166 | | % ; b_check_boolean_expression1(Expr,LS,S,wfwd(WF,WDE,WDV),Res,Ai,Ao)). |
167 | | |
168 | | b_check_boolean_expression1(b(Expr,_,Infos),LS,S,WFD,Res,Ai,Ao) :- WFD=wfwd(_WF,WDE,WDV),!, |
169 | | % print('check : '), translate:print_bexpr(b(Expr,pred,Infos)),nl, |
170 | | %when(nonvar(Res), (print(Res), print(' <--> '),translate:print_bexpr(b(Expr,pred,Infos)),nl)), |
171 | | (nonvar(WDV),WDE \= WDV |
172 | | -> Ai=Ao, |
173 | | (var(Res) -> Res=pred_false ; true) |
174 | | ; b_check_boolean_expression2(Expr,Infos,LS,S,WFD,Res,Ai,Ao)). |
175 | | b_check_boolean_expression1(b(Expr,T,Infos),LS,S,WFD,Res,Ai,Ao) :- !, |
176 | | add_internal_error('Illegal WFWD info: ',b_check_boolean_expression1(b(Expr,T,Infos),LS,S,WFD,Res,Ai,Ao)), |
177 | | b_check_boolean_expression2(Expr,Infos,LS,S,wfwd(WFD,pred_true,pred_true),Res,Ai,Ao). |
178 | | b_check_boolean_expression1(E,LS,S,WFD,Res,Ai,Ao) :- |
179 | | add_internal_error('Boolean expression not properly wrapped: ',b_check_boolean_expression1(E,LS,S,WFD,Res,Ai,Ao)), |
180 | | b_check_boolean_expression2(E,[],LS,S,WFD,Res,Ai,Ao). |
181 | | |
182 | | % normalise conjunction into flat list of conjuncts |
183 | | normalise_conjunct(b(E,_,Info)) --> normalise_conjunct2(E,Info). |
184 | | normalise_conjunct2(conjunct(A,B),_) --> !,normalise_conjunct(A),normalise_conjunct(B). |
185 | | normalise_conjunct2(F,Info) --> [b(F,pred,Info)]. |
186 | | |
187 | | construct_norm_conjunct(A,b(B,pred,Info)) :- construct_norm_conjunct2(A,B,Info). |
188 | | construct_norm_conjunct2([],truth,[]). |
189 | | construct_norm_conjunct2([H|T],Res,Info) :- |
190 | | (T==[] -> H=b(Res,pred,Info) ; Res=norm_conjunct(H,T),Info=[]). |
191 | | % TO DO: build up member(contains_wd_condition,Infos) |
192 | | |
193 | | |
194 | | % normalise disjunction into flat list of disjuncts |
195 | | normalise_disjunct(b(E,_,Info)) --> normalise_disjunct2(E,Info). |
196 | | normalise_disjunct2(disjunct(A,B),_) --> !,normalise_disjunct(A),normalise_disjunct(B). |
197 | | normalise_disjunct2(F,Info) --> [b(F,pred,Info)]. |
198 | | |
199 | | construct_norm_disjunct(A,b(B,pred,Info)) :- construct_norm_disjunct2(A,B,Info). |
200 | | construct_norm_disjunct2([],falsity,[]). |
201 | | construct_norm_disjunct2([H|T],Res,Info) :- |
202 | | (T==[] -> H=b(Res,pred,Info) ; Res=norm_disjunct(H,T),Info=[]). |
203 | | |
204 | | can_negate_expression(b(Expr,pred,I),b(NExpr,pred,I)) :- can_negate2(Expr,NExpr). |
205 | | can_negate2(equal(A,B),not_equal(A,B)). |
206 | | can_negate2(not_equal(A,B),equal(A,B)). |
207 | | can_negate2(member(A,B),not_member(A,B)). |
208 | | can_negate2(not_member(A,B),member(A,B)). |
209 | | can_negate2(subset(A,B),not_subset(A,B)). |
210 | | can_negate2(not_subset(A,B),subset(A,B)). |
211 | | can_negate2(subset_strict(A,B),not_subset_strict(A,B)). |
212 | | can_negate2(not_subset_strict(A,B),subset_strict(A,B)). |
213 | | can_negate2(greater_equal(A,B),less(A,B)). |
214 | | can_negate2(less(A,B),greater_equal(A,B)). |
215 | | can_negate2(less_equal(A,B),greater(A,B)). |
216 | | can_negate2(greater(A,B),less_equal(A,B)). |
217 | | |
218 | | b_check_boolean_expression2(truth,_,_,_,_WFD,Res,Ai,Ao) :- !,Res=pred_true, Ai=Ao. |
219 | | b_check_boolean_expression2(falsity,_,_,_,_WFD,Res,Ai,Ao) :- !,Res=pred_false, Ai=Ao. |
220 | | b_check_boolean_expression2(negation(BExpr),_,LocalState,State,WFD,Res,Ai,Ao) :- !, |
221 | | (can_negate_expression(BExpr,NBExpr) |
222 | | -> /* avoid introducing negate propagator; maybe not necessary */ |
223 | | b_check_boolean_expression1(NBExpr,LocalState,State,WFD,Res,Ai,Ao) |
224 | | ; negate(NR,Res), |
225 | | b_check_boolean_expression1(BExpr,LocalState,State,WFD,NR,Ai,Ao)). |
226 | | b_check_boolean_expression2(conjunct(LHS,RHS),CInfo,LocalState,State,WFD,Res,Ai,Ao) :- !, |
227 | | normalise_conjunct2(conjunct(LHS,RHS),CInfo,NormRes,[]), |
228 | | construct_norm_conjunct2(NormRes,NC,Info), % print(normalised(NC)),nl, |
229 | | b_check_boolean_expression2(NC,Info,LocalState,State,WFD,Res,Ai,Ao). |
230 | | b_check_boolean_expression2(norm_conjunct(LHS,RHS),_,LocalState,State,wfwd(WF,WDE,WDV),Res,Ai,Ao) :- !, |
231 | | construct_norm_conjunct(RHS,NC), |
232 | | conjoin(LR,RR,Res,LHS,NC,WF), |
233 | | b_check_boolean_expression1(LHS,LocalState,State,wfwd(WF,WDE,WDV),LR,Ai,Aii), |
234 | | % when(nonvar(LR),(print(LR), print(' && : '), translate:print_bexpr(LHS),nl)), |
235 | | propagagate_wfwd(WDE,WDV,GuardFlag,LR,pred_false), % if WDE/=WDV then set GuardFlag to pred_false; indicating to RHS that it is not needed also |
236 | | b_check_boolean_expression0(pred_true,GuardFlag,NC,LocalState,State,WF,RR,Aii,Ao). |
237 | | b_check_boolean_expression2(implication(LHS,RHS),_,LocalState,State,wfwd(WF,WDE,WDV),Res,Ai,Ao) :- !, impl(LR,RR,Res), |
238 | | b_check_boolean_expression1(LHS,LocalState,State,wfwd(WF,WDE,WDV),LR,Ai,Aii), |
239 | | % when(nonvar(LR),(LR=pred_true -> print(' => : '), translate:print_bexpr(RHS),nl ; true)), |
240 | | propagagate_wfwd(WDE,WDV,GuardFlag,LR,pred_false), |
241 | | b_check_boolean_expression0(pred_true,GuardFlag,RHS,LocalState,State,WF,RR,Aii,Ao). |
242 | | b_check_boolean_expression2(equivalence(LHS,RHS),_,LocalState,State,WFD,Res,Ai,Ao) :- !, equiv(LR,RR,Res), |
243 | | b_check_boolean_expression1(LHS,LocalState,State,WFD,LR,Ai,Aii), |
244 | | b_check_boolean_expression1(RHS,LocalState,State,WFD,RR,Aii,Ao). |
245 | | b_check_boolean_expression2(disjunct(LHS,RHS),CInfo,LocalState,State,WFD,Res,Ai,Ao) :- !, |
246 | | normalise_disjunct2(disjunct(LHS,RHS),CInfo,NormRes,[]), |
247 | | construct_norm_disjunct2(NormRes,NC,Info), % print(normalised_disj(NC)),nl, |
248 | | b_check_boolean_expression2(NC,Info,LocalState,State,WFD,Res,Ai,Ao). |
249 | | b_check_boolean_expression2(norm_disjunct(LHS,RHS),_,LocalState,State,wfwd(WF,WDE,WDV),Res,Ai,Ao) :- !, |
250 | | construct_norm_disjunct(RHS,NC), |
251 | | disjoin(LR,RR,Res,LHS,NC,WF), |
252 | | %print(disjoin(WDE,WDV)), translate:print_bexpr(LHS),nl, |
253 | | b_check_boolean_expression1(LHS,LocalState,State,wfwd(WF,WDE,WDV),LR,Ai,Aii), |
254 | | propagagate_wfwd(WDE,WDV,GuardFlag,LR,pred_true), |
255 | | b_check_boolean_expression0(pred_false,GuardFlag,NC,LocalState,State,WF,RR,Aii,Ao). |
256 | | b_check_boolean_expression2(let_predicate(Ids,AssignmentExprs,Pred),_Info,LocalState,State,WFD,Res,Ai,Ao) :- |
257 | | % nl,print(check_let_predicate(Ids)),nl, translate:print_bexpr(Pred),nl, |
258 | | !, |
259 | | wd_set_up_localstate_for_let(Ids,AssignmentExprs,LocalState,State,LetState,WFD), |
260 | | b_check_boolean_expression1(Pred,LetState,State,WFD,Res,Ai,Ao). |
261 | | b_check_boolean_expression2(lazy_let_pred(Id,AssignmentExpr,Pred),_I,LocalState,State,wfwd(WF,WDE,WDV),Res,Ai,Ao) :- !, |
262 | | store:set_up_localstate([Id],[(Trigger,IdValue)],LocalState,LetState), |
263 | | % print(setting_up_lazy_let_pred(Id)),nl, |
264 | | b_interpreter:lazy_compute_expression(Trigger,AssignmentExpr,LocalState,State,IdValue,WF,Ai), |
265 | | b_check_boolean_expression1(Pred,LetState,State,wfwd(WF,WDE,WDV),Res,Ai,Ao). |
266 | | b_check_boolean_expression2(lazy_lookup_pred(Id),Info,LocalState,_State,WFD,Res,Ai,Ao) :- !, Ai=Ao, |
267 | | % print(lazy_lookup_pred_check(Id,Info)),nl, |
268 | | store:lookup_value_for_existing_id(Id,LocalState,(Trigger,Value)), % should normally only occur in LocalState; value introduced by lazy_let |
269 | | %(Trigger,Value) = (pred_true,Res). % ,print(res(Res)),nl. % force evaluation |
270 | | wd_delay(((Trigger,Value) = (pred_true,Res)), |
271 | | Res,b(lazy_lookup_pred(Id),pred,Info),WFD). |
272 | | b_check_boolean_expression2(value(V),_Info,_LocalState,_State,_WFD,Res,Ai,Ao) :- !, % this can occur when lazy_lookup_pred gets compiled by b_compiler |
273 | | Res=V,Ai=Ao. |
274 | | b_check_boolean_expression2(not_equal(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
275 | | (negate_equal_false(LHS,RHS,LHS1,RHS1) |
276 | | -> /* X/=FALSE equivalent to X=TRUE */ |
277 | | b_check_boolean_expression3_pos(equal(LHS1,RHS1),Info,LocalState,State,WFD,Res,Ai,Ao) |
278 | | ; b_check_boolean_expression3_neg(equal(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) |
279 | | ). |
280 | | b_check_boolean_expression2(equal(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
281 | | (negate_equal_false(LHS,RHS,LHS1,RHS1) |
282 | | -> RHS1=b(boolean_true,boolean,[]), /* X/=FALSE equivalent to X=TRUE */ |
283 | | b_check_boolean_expression3_neg(equal(LHS1,RHS1),Info,LocalState,State,WFD,Res,Ai,Ao) |
284 | | ; b_check_boolean_expression3_pos(equal(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) |
285 | | ). |
286 | | b_check_boolean_expression2(not_member(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
287 | | b_check_boolean_expression3_neg(member(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao). |
288 | | b_check_boolean_expression2(not_subset(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
289 | | b_check_boolean_expression3_neg(subset(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao). |
290 | | b_check_boolean_expression2(not_subset_strict(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
291 | | b_check_boolean_expression3_neg(subset_strict(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao). |
292 | | b_check_boolean_expression2(greater(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
293 | | b_check_boolean_expression3_pos(less(RHS,LHS),Info,LocalState,State,WFD,Res,Ai,Ao). |
294 | | b_check_boolean_expression2(greater_equal(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
295 | | b_check_boolean_expression3_neg(less(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao). |
296 | | b_check_boolean_expression2(less_equal(LHS,RHS),Info,LocalState,State,WFD,Res,Ai,Ao) :- !, |
297 | | b_check_boolean_expression3_neg(less(RHS,LHS),Info,LocalState,State,WFD,Res,Ai,Ao). |
298 | | b_check_boolean_expression2(Pred,Infos,LocalState,State,WFD,Res,Ai,Ao) :- |
299 | | b_check_boolean_expression3_pos(Pred,Infos,LocalState,State,WFD,Res,Ai,Ao). |
300 | | |
301 | | |
302 | | % check whether one of the two arguments is FALSE |
303 | | % translate X/=FALSE -> X=TRUE for normalisation purposes |
304 | | negate_equal_false(b(boolean_false,boolean,_),E,E,b(boolean_true,boolean,[])). |
305 | | negate_equal_false(E,b(boolean_false,boolean,_),E,b(boolean_true,boolean,[])). |
306 | | |
307 | | b_check_boolean_expression3_pos(Pred,Infos,LocalState,State,WFD,Res,Ai,Ao) :- |
308 | | %print(register_predicate(WFD,Infos,Pred)),nl,portray_avl(Ai),nl, |
309 | | register_predicate_wfd(WFD,Pred,Infos,Res,Reused,Ai,Ao), |
310 | | (Reused=true |
311 | | -> true % , print(reused_pred(WFD,Infos)),nl, translate:print_bexpr(Pred),nl |
312 | | ; b_check_boolean_expression4(Pred,Infos,LocalState,State,WFD,Res) |
313 | | ). |
314 | | |
315 | | b_check_boolean_expression3_neg(Pred,Infos,LocalState,State,WFD,NegRes,Ai,Ao) :- |
316 | | %print(register_neg_predicate(WFD,Infos,Pred)),nl, |
317 | | register_predicate_wfd(WFD,Pred,Infos,Res,Reused,Ai,Ao), negate(Res,NegRes), |
318 | | (Reused=true |
319 | | -> true |
320 | | ; b_check_boolean_expression4(Pred,Infos,LocalState,State,WFD,Res) |
321 | | ). |
322 | | |
323 | | % Register a new predicate in the AVL tree if either forced or non-WD condition inside |
324 | | register_predicate_wfd(_,_,_,_,false,Ai,Ao) :- Ai = no_avl,!, Ai=Ao. |
325 | | register_predicate_wfd(_,_Pred,_Infos,_,false,Ai,Ao) :- |
326 | | preferences:preference(use_common_subexpression_elimination,true), |
327 | | preferences:preference(use_common_subexpression_also_for_predicates,true), |
328 | | preferences:preference(disprover_mode,false), % there are still a few things detected here that CSE does not detect (=FALSE,=TRUE,...) |
329 | | !, % CSE already statically detects these ( all of the time !?) |
330 | | Ai=Ao. |
331 | | register_predicate_wfd(wfwd(_,A,B),Pred,Infos,PredTruthVar,Reused,Ai,Ao) :- |
332 | | (A==B -> register_predicate_aux(Pred,PredTruthVar,Reused,Ai,Ao) % it will be evaluated; we can share it |
333 | | ; nonmember(contains_wd_condition,Infos) -> register_predicate_aux(Pred,PredTruthVar,Reused,Ai,Ao) |
334 | | ; Ai=Ao, Reused=false % not guaranteed to be evaluated: WD-condition + not in forced WFD context |
335 | | % ,print('NOT REGISTERING: '), translate:print_bexpr(Pred),nl |
336 | | ). |
337 | | |
338 | | % Register a new predicate in the AVL tree (for outside callers like b_interpreter.pl) |
339 | | register_predicate(Pred,_Infos,NegPredTruthVar,Reused,Ai,Ao) :- negate_pred(Pred,NegPred),!, |
340 | | %print(negating),nl, |
341 | | negate(PredTruthVar,NegPredTruthVar), |
342 | | register_predicate_aux(NegPred,PredTruthVar,Reused,Ai,Ao). |
343 | | register_predicate(Pred,_Infos,PredTruthVar,Reused,Ai,Ao) :- |
344 | | register_predicate_aux(Pred,PredTruthVar,Reused,Ai,Ao). |
345 | | |
346 | | negate_pred(equal(A,B),not_equal(AA,TRUE)) :- negate_equal_false(A,B,AA,TRUE). |
347 | | negate_pred(not_equal(A,B),equal(A,B)). % TO DO: we should check negate_equal_false |
348 | | negate_pred(not_member(A,B),member(A,B)). |
349 | | negate_pred(not_subset(A,B),subset(A,B)). |
350 | | negate_pred(not_subset_strict(A,B),subset_strict(A,B)). |
351 | | negate_pred(greater_equal(A,B),less(A,B)). |
352 | | negate_pred(less_equal(A,B),less(B,A)). |
353 | | |
354 | | register_predicate_aux(Pred,_PredTruthVar,Reused,Ai,Ao) :- do_not_store_pred(Pred),!, |
355 | | Ai=Ao, Reused=false. |
356 | | register_predicate_aux(Pred,PredTruthVar,Reused,Ai,Ao) :- check_pred_truth_var(PredTruthVar), |
357 | | norm_pred_check(Pred,NPred), % We could store this information in the info field computed by ast_cleanup ? |
358 | | (%too_simple(NPred) -> Reused=false, Ao=Ai ; %% even for simple equalities it actually pays off ! |
359 | | reuse_predicate(NPred,Var,Ai) |
360 | | -> % nl,print(reusing(NPred,Var)),nl, %% |
361 | | PredTruthVar=Var,Ao=Ai, Reused=true |
362 | | ; add_predicate(NPred,PredTruthVar,Ai,Ao), Reused=false |
363 | | %,nl,print(not_reusing(NPred)),nl |
364 | | ). |
365 | | |
366 | | check_pred_truth_var(X) :- var(X),!. |
367 | | check_pred_truth_var(pred_true) :- !. |
368 | | check_pred_truth_var(pred_false) :- !. |
369 | | check_pred_truth_var(X) :- add_internal_error('Illegal Predicate Truth Value: ',check_pred_truth_var(X)). |
370 | | |
371 | | :- use_module(kernel_tools,[ground_bexpr/1]). |
372 | | %do_not_store_pred(b(P,_,_)) :- do_not_store_pred_aux(P),!. |
373 | | do_not_store_pred(external_pred_call(_P,_)) :- !. % expcept maybe LESS, CHOOSE,... we could check performs_io |
374 | | do_not_store_pred(B) :- |
375 | | (ground_bexpr(b(B,pred,[])) |
376 | | % TO DO: improve performance: marking bexpr with potential non-ground value(.) terms inside |
377 | | -> fail |
378 | | ; true %print('-> Not storing: '),translate:print_bexpr(b(B,pred,[])),nl |
379 | | ). |
380 | | do_not_store_pred_aux(external_pred_call(_P,_)). % expcept maybe LESS, CHOOSE,... we could check performs_io |
381 | | |
382 | | |
383 | | % Quantifier Expansion |
384 | | |
385 | | b_check_forall_wf(Parameters,LHS,RHS,Info,LocalState,State,WF,PredRes) :- |
386 | | WFD=wfwd(WF,pred_true,pred_true), % we expect it to be in a context where the value will be needed |
387 | | b_check_forall_wfwd(Parameters,LHS,RHS,Info,LocalState,State,WFD,PredRes). |
388 | | b_check_forall_wfwd(_Parameters,LHS,RHS,_Info,_LocalState,_State,_WFD,PredRes) :- |
389 | | (is_falsity(LHS) ; is_truth(RHS)),!, % quantifier always true |
390 | | PredRes = pred_true. |
391 | | b_check_forall_wfwd(Parameters,LHS,RHS,Info,LocalState,State,WFD,PredRes) :- |
392 | | small_quantifier_cardinality(Parameters,LHS,LHS1,LHSRest), |
393 | | %print(expand(forall(Parameters))),nl, |
394 | | expand_quantifier(Parameters,LHS1,List), %print(List),nl, |
395 | | Body = b(implication(LHSRest,RHS),pred,Info),% translate:print_bexpr(Body),nl, |
396 | | WFD=wfwd(WF,_,_), |
397 | | check_expanded_forall_quantifier(List,Body, LocalState, State,WF,WFD,PredRes). |
398 | | % TO DO: if not small_quantifier_cardinality: b_check_boolean_expression4_delay |
399 | | |
400 | | |
401 | | b_check_exists_wf(Parameters,Body,Info,LocalState,State,WF,PredRes) :- |
402 | | WFD=wfwd(WF,pred_true,pred_true), % we expect it to be in a context where the value will be needed |
403 | | b_check_exists_wfwd(Parameters,Body,Info,LocalState,State,WFD,PredRes). |
404 | | b_check_exists_wfwd(Parameters,Body,_Info,LocalState,State,WFD,PredRes) :- |
405 | | % could be generalised to take into consideration domain as restricted by Body |
406 | | small_quantifier_cardinality(Parameters,Body,LHS,RHS), |
407 | | % print(expanding_check_exists(_Card,Parameters)),nl, % portray_waitflags(WF), |
408 | | expand_quantifier(Parameters,LHS,List), |
409 | | % print(List),nl, translate:print_bexpr(Body),nl,nl, |
410 | | % now compute a priority for the disjunction based on the number of case splits |
411 | | % relevant for tests 1358, 1746 |
412 | | length(List,Len), % Note: if Len=1: the body must be true; no disjoin will be set up |
413 | | get_pow2_binary_choice_priority(Len,Prio), |
414 | | % if Len=2 -> we actually have just two possibilities T,_ and F,T; but we want Prio to start at 4 ? |
415 | | % if Len=3 -> we have T,_,_ ; F,T,_ ; F,F,T less possibilites if disjoin enumerated from left-to-right; TO DO: should we lower the priority taking this into account ? |
416 | | % TO DO: maybe we could directly set up an n-ary disjoin predicate ? if one disjunct true; remove case-splits on other disjuncts |
417 | | WFD=wfwd(WF,_,_), |
418 | | check_expanded_exists_quantifier(List,Prio,RHS, LocalState, State,WF,WFD,PredRes). |
419 | | % TO DO: if not small_quantifier_cardinality: b_check_boolean_expression4_delay |
420 | | |
421 | | |
422 | | :- use_module(b_enumerate, [b_tighter_enumerate_values/2]). |
423 | | expand_quantifier(Parameters,Pred,ListOfNewLocalStates) :- |
424 | | % at the moment LS,State not really needed; only necessary if non-compiled Pred can be used |
425 | | % also: feeding in any non-bound variables in LocalState or State would cause problems in findall ! |
426 | | findall(ParLocalState, |
427 | | (b_interpreter:set_up_typed_localstate(Parameters,_ParaValues,ParamTypedVals,[],ParLocalState,all_solutions), |
428 | | kernel_waitflags:init_wait_flags(WF), |
429 | | b_test_boolean_expression(Pred,[],ParLocalState,WF), |
430 | | b_tighter_enumerate_values(ParamTypedVals,WF), |
431 | | kernel_waitflags:ground_wait_flags(WF)), |
432 | | ListOfNewLocalStates). |
433 | | |
434 | | check_expanded_forall_quantifier([], _Body, _LS, _State,_WF,_WFD,Res) :- |
435 | | Res=pred_true. |
436 | | check_expanded_forall_quantifier([LS1|TLS], Body, LS, State,WF,WFD,Res) :- |
437 | | conjoin(Res1,TRes,Res,Body,Body,WF), |
438 | | empty_avl(InnerAi), % TO DO: maybe use no_avl ? |
439 | | append(LS1,LS,InnerLS), |
440 | | % Note: we do not need to guard against wd-definition from other instances inside a quantified expression |
441 | | % either all conjuncts can be evaluated or none |
442 | | % print(expand_forall(WFD)), translate:print_bexpr(Body),nl, |
443 | | b_check_boolean_expression1(Body,InnerLS,State,WFD,Res1,InnerAi,_Aii), |
444 | | %instantiate_wfwd_result(WDE,WDV,Res1), |
445 | | check_expanded_forall_quantifier(TLS,Body,LS,State,WF,WFD,TRes). |
446 | | |
447 | | /* |
448 | | :- block instantiate_wfwd_result(?,-,-). |
449 | | % instantiate a boolean variable in case it is no longer needed and not set by something else |
450 | | instantiate_wfwd_result(WDE,WDV,Res) :- |
451 | | (nonvar(Res) -> true |
452 | | ; WDE==WDV -> true |
453 | | ; Res = pred_false). */ |
454 | | |
455 | | check_expanded_exists_quantifier([], _, _Body, _LS, _State,_WF,_WFD,Res) :- |
456 | | Res=pred_false. |
457 | | check_expanded_exists_quantifier([LS1|TLS], Priority, Body, LS, State,WF,WFD,Res) :- |
458 | | (TLS = [] -> Res=Res1 |
459 | | ; disjoin(Res1,TRes,Res,priority(Priority),priority(Priority),WF)), % was using Body instead of priority(Priority) |
460 | | empty_avl(InnerAi), % TO DO: maybe use no_avl ? |
461 | | append(LS1,LS,InnerLS), |
462 | | b_check_boolean_expression1(Body,InnerLS,State,WFD,Res1,InnerAi,_Aii), |
463 | | % Note: we do not need to guard against wd-definition from other instances inside a quantified expression |
464 | | check_expanded_exists_quantifier(TLS,Priority,Body,LS,State,WF,WFD,TRes). |
465 | | |
466 | | |
467 | | :- use_module(library(lists),[maplist/4]). |
468 | | % try and convert a closure into a list of 0/1 variables for each potential element |
469 | | reify_closure_with_small_cardinality(P,T,Body, WF,ReifiedList) :- %print(try(P)),nl, |
470 | | maplist(create_typed_id,P,T,Parameters), |
471 | | small_quantifier_cardinality(Parameters,Body,LHS,RHS,350,25000), % TO DO: how to choose these parameters ? |
472 | | % for card({x|x:1..n & x mod 3=0})=c & n=24000 -> 340 ms with reification; 320 ms without; n=74000 : 1020 ms without, 1160 with reification |
473 | | % but there is a big difference for card({x|x:1..n & x mod 3=0 & x<10}) with n=74000 : 0 ms without reification, 1580 with; n=500: 20 ms with reification; n=250: 10 ms with reification |
474 | | %print(clos_card(Card,LHS,RHS)),nl, |
475 | | expand_quantifier(Parameters,LHS,List), |
476 | | % print(list_of_local_states(List)),nl, |
477 | | WFD=wfwd(WF,pred_true,pred_true), % is this ok ?? |
478 | | reifiy_list(List,RHS,WFD,ReifiedList). |
479 | | |
480 | | reifiy_list([], _Body,_WFD,[]). |
481 | | reifiy_list([LS1|TLS], Body,WFD,[Res_01|TRes]) :- |
482 | | empty_avl(InnerAi), |
483 | | b_check_boolean_expression1(Body,LS1,[],WFD,Res1_pred,InnerAi,_Aii), |
484 | | %print(reified(Res1_pred,LS1)),nl, |
485 | | prop_pred_01(Res1_pred,Res_01), |
486 | | % Note: we do not need to guard against wd-definition from other instances inside a quantified expression |
487 | | reifiy_list(TLS,Body,WFD,TRes). |
488 | | |
489 | | |
490 | | |
491 | | :- use_module(library(lists),[select/3]). |
492 | | |
493 | | % check if Body produces a small cardinality for the paramters Par |
494 | | % if yes: the predicates constraining Par are put into LHS, the rest into RHS |
495 | | % also: LHS must ensure that ground values are produced for Par and that we can enumerate with a separate WF (in expand_quantifier) |
496 | | small_quantifier_cardinality(Par,Body,LHS,RHS) :- |
497 | | %preferences:preference(solver_strength,SS), NL is 10+SS, SMTL is 40+SS, |
498 | | NL=10,SMTL=40, |
499 | | small_quantifier_cardinality(Par,Body,LHS,RHS,NL,SMTL). % was 10,35; raising it to 10,41 makes tests 1441, 1442 fail due to expansion of exists; raising it to 16,50 makes test 1112 fail; TO DO: investigate |
500 | | small_quantifier_cardinality(Par,Body,LHS,RHS,NormalLimit,SMTLimit) :- |
501 | | conjunction_to_list(Body,BodyList), |
502 | | def_get_texpr_ids(Par,AllParas), |
503 | | small_quantifier_cardinality_aux(Par,AllParas,BodyList,_UpBoundOnSize,LLHS,LRHS,NormalLimit,SMTLimit), |
504 | | conjunct_predicates(LLHS,LHS), |
505 | | conjunct_predicates(LRHS,RHS). |
506 | | |
507 | | is_membership(b(P,pred,_),TLHS,RHS) :- is_mem_aux(P,TLHS,RHS). |
508 | | is_mem_aux(member(TLHS,b(RHS,_,_)),TLHS,RHS). |
509 | | is_mem_aux(equal(TLHS,b(value(V),_,_)),TLHS,value([V])). % x = V is the same as x:{V} |
510 | | |
511 | | % do not rely on size for anything: it is just an upper bound on the size; the actual size could be smaller |
512 | | small_quantifier_cardinality_aux([],_,Body,Size,LHS,RHS,_,_) :- !, |
513 | | LHS=[],RHS=Body,Size=1. |
514 | | small_quantifier_cardinality_aux(Parameters,AllParas,[LHS|TBody],FullSize,FullLHS,FullRHS,NormalLimit,SMTLimit) :- |
515 | | %LHS = b(member(SID,b(MemRHS,_,_)),pred,_), |
516 | | is_membership(LHS,SID,MemRHS), |
517 | | %print(try_small(SID,MemRHS)),nl, |
518 | ? | constrains_ID(SID,AllParas,Parameters,RestParameters,SkelVal,SkelToUnify,BindList), % we could check RestParameters /= Parameters |
519 | | % TO DO: we could also allow parameter to be constrained twice x: 1..100 & x: {...} ? |
520 | | %print(check_is_small(MemRHS,SkelToUnify,BindList)),nl, |
521 | | (is_small_set(MemRHS,Size,NormalLimit,SMTLimit) % we have a small set of ground values: we can evaluate LHS to expand the quantifier/set_comprehension for the parameters occuring in LHS |
522 | | -> FullLHS = [LHS|RestLHS],FullRHS = RestRHS |
523 | | ; infer_ground_membership(MemRHS,SID,SkelVal,SkelToUnify,BindList,NormalLimit,SMTLimit, Size,InferredLHS) -> |
524 | | % we have inferred a superset InferredLHS of MemRHS which is small and known |
525 | | FullLHS = [InferredLHS|RestLHS], % we have added an inferred membership constraint |
526 | | FullRHS = [LHS|RestRHS]), % the original membership LHS still needs to be checked later, after expansion of the quantifier |
527 | | !, |
528 | | % we select LHS to be included in FullLHS and mark parameter ID as constrained |
529 | | small_quantifier_cardinality_aux(RestParameters,AllParas,TBody,RestSize,RestLHS,RestRHS,NormalLimit,SMTLimit), |
530 | | FullSize is Size*RestSize, |
531 | | is_small_size(FullSize,NormalLimit,SMTLimit, Parameters). |
532 | | small_quantifier_cardinality_aux(Parameters,AllParas,[H|Rest],FullSize,RestLHS,[H|RestRHS],NormalLimit,SMTLimit) :- !, |
533 | | % skip the conjunct H |
534 | | small_quantifier_cardinality_aux(Parameters,AllParas,Rest,FullSize,RestLHS,RestRHS,NormalLimit,SMTLimit). |
535 | | small_quantifier_cardinality_aux(Parameters,_AllParas,Body,ParCard,[],Body,NormalLimit,SMTLimit) :- |
536 | | % if the remaining parameter type cardinality is small: just use "truth" as body; will instantiate parameters |
537 | | b_interpreter:parameter_list_cardinality(Parameters,ParCard), |
538 | | is_small_size(ParCard,NormalLimit,SMTLimit, Parameters). |
539 | | |
540 | | % try and extract a ground superset (InferredLHS) of the RHS (ID:RHS) which constrains ID |
541 | | infer_ground_membership(value(List),_,SkelVal,SkelToUnify,BindList,NormalLimit,SMTLimit, Size,InferredLHS) :- |
542 | | !, |
543 | | % the List is probably not ground; let's try and see if we can extract ground matches for the parameters at least; see test 1627 (s=1..20 & x: s-->BOOL & card({t|t|->TRUE:x}):18..19) |
544 | | extract_bind_list(BindList,LHSTerm,RHSValue), |
545 | | has_bounded_ground_matches(List,SkelVal,SkelToUnify,RHSValue,MatchedValues,1,NrMatches), % TO DO: provide SMTLimit as upper limit |
546 | | NrMatches = Size, |
547 | | is_small_size(Size,NormalLimit,SMTLimit, unknown), |
548 | | get_texpr_type(LHSTerm,LHSTermType), |
549 | | InferredLHS = b(member(LHSTerm,b(value(MatchedValues),set(LHSTermType),[])),pred,[generated]). |
550 | | %print(matches(NrMatches,MatchedValues)),nl, translate:print_bexpr(InferredLHS),nl, |
551 | | infer_ground_membership(Set,SID,SkelVal,SkelToUnify,BindList,NormalLimit,SMTLimit,Size,InferredLHS) :- |
552 | | superset(Set,SuperSet), |
553 | | % e.g., if ID: {1} /\ x -> InferredLHS = {1} and we will add ID : {1} to the LHS of the quantifier and keep ID : {1} /\ x as the RHS |
554 | | infer_ground_mem_aux(SuperSet,SID,SkelVal,SkelToUnify,BindList,NormalLimit,SMTLimit,Size,InferredLHS). |
555 | | |
556 | | |
557 | | superset(intersection(A,B),Set) :- (Set=A ; Set=B). % Set /\ X <: Set |
558 | | superset(set_subtraction(Set,_),Set). % Set \ X <: Set |
559 | | superset(domain_restriction(_,Set),Set). % X <| Set <: Set |
560 | | superset(domain_subtraction(_,Set),Set). % X <<| Set <: Set |
561 | | superset(range_subtraction(Set,_),Set). % Set |> X <: Set |
562 | | superset(range_restriction(Set,_),Set). % Set |>> X <: Set |
563 | | |
564 | | infer_ground_mem_aux(b(Set,T,I),SID,SkelVal,SkelToUnify,BindList,NormalLimit,SMTLimit, Size,InferredLHS) :- |
565 | | (is_small_set(Set,Size,NormalLimit,SMTLimit) -> InferredLHS = b(member(SID,b(Set,T,I)),pred,[generated]) |
566 | | ; infer_ground_membership(Set,SID,SkelVal,SkelToUnify,BindList,NormalLimit,SMTLimit, Size,InferredLHS)). |
567 | | |
568 | | :- use_module(bsyntaxtree, [create_couple/3]). |
569 | | % extract result of constrains_ID BindList into an Expression-Tuple for new membership constraint and a value that will be put into a value(List) |
570 | | extract_bind_list([TID/Val],TID,Val) :- !. |
571 | | extract_bind_list([TID/Val|BList],Couple,(Val,RestVal)) :- |
572 | | create_couple(TID,RestExpr,Couple), |
573 | | extract_bind_list(BList,RestExpr,RestVal). |
574 | | |
575 | | :- use_module(kernel_tools,[can_match/2]). |
576 | | % check if we can find a bounded / fixed number of ground matches for Skeleton Value in List |
577 | | has_bounded_ground_matches(Var,_,_,_, _,_,_) :- var(Var),!. |
578 | | has_bounded_ground_matches([],_SkelVal,_SkelToUnify,_,[],LenAcc,LenAcc). |
579 | | has_bounded_ground_matches([H|T],SkelVal,SkelToUnify,ValueToStore,Matches,LenAcc,LenRes) :- |
580 | | (can_match(H,SkelVal) -> copy_term((SkelToUnify,ValueToStore),(H,HValueToStore)), |
581 | | ground_value(HValueToStore), |
582 | | Matches = [HValueToStore|MT], |
583 | | A1 is LenAcc+1 ; Matches=MT,A1=LenAcc), |
584 | | has_bounded_ground_matches(T,SkelVal,SkelToUnify,ValueToStore,MT,A1,LenRes). |
585 | | |
586 | | % check if the Expr contains ID, i.e., matching Expr with an element of a set will also instantiate and determine TID |
587 | | % TO DO: also accept other patterns: records, sets?,.... |
588 | | |
589 | | % SkeletonToUnify: a skeleton that can be used to unify with any value and extracts value in BindList |
590 | | constrains_ID(b(E,_,_),AllParas,Parameters,RestParameters,SkeletonValue,SkeletonToUnify,BindList) :- |
591 | ? | constrains_ID_aux(E,AllParas,Parameters,RestParameters,SkeletonValue,SkeletonToUnify,BindList). |
592 | | constrains_ID_aux(couple(A,B),AllParas,Parameters,RestParameters,(V1,V2),(Skel1,Skel2),Bind) :- |
593 | ? | constrains_ID(A,AllParas,Parameters,Rest1,V1,Skel1,Bind1), |
594 | ? | constrains_ID(B,AllParas,Rest1,RestParameters,V2,Skel2,Bind2), |
595 | | append(Bind1,Bind2,Bind). % TO DO: use DCGs |
596 | | constrains_ID_aux(rec(F),AllParas,Parameters,RestParameters,record(SkelV),record(SkelU),Bind) :- |
597 | | constrains_ID_fields(F,AllParas,Parameters,RestParameters,SkelV,SkelU,Bind). |
598 | | constrains_ID_aux(identifier(ID),AllParas,Parameters,RestParameters,_SkelV,SkelU,Bind) :- |
599 | | % TO DO: allow same id to appear multiple times in expression + allow to re-use parameters in another conjunct |
600 | ? | (select(TID,Parameters,RestParameters), get_texpr_id(TID,ID) |
601 | | -> Bind = [TID/SkelU] |
602 | ? | ; member(ID,AllParas), % we have already used/bound ID; we will use first occurence for skeleton/bind; this one is simply ignored |
603 | | % TO DO: we could try and see whether using the second occurence gives a better result |
604 | | % print(double_match(ID)),nl, |
605 | | RestParameters=Parameters, Bind=[] |
606 | | ). |
607 | | constrains_ID_aux(value(V),_AllParas,P,P,V,_,[]) :- ground_value(V).% if not ground value we may not be able to compute all possible values for ID |
608 | | constrains_ID_aux(boolean_true,_AllParas,P,P,pred_true,pred_true,[]). % needed ?? everything is compiled anway ? |
609 | | constrains_ID_aux(boolean_false,_AllParas,P,P,pred_false,pred_false,[]). % needed ?? everything is compiled anway ? |
610 | | % Below: allow any other expression as long as it only uses AllParas |
611 | | % e.g. x+1 in : s: 1..20 --> (BOOL*(1..20)) & card({x|x|->(TRUE|->x):s})=10 & card({x|x|->(FALSE|->x+1):s})=10 |
612 | | constrains_ID_aux(add(A,B),AllParas,P,P,_,_,[]) :- % basically allow other Parameters or ground values |
613 | | constrains_ID(A,AllParas,[],[],_,_,_), constrains_ID(B,AllParas,[],[],_,_,_). |
614 | | constrains_ID_aux(minus(A,B),AllParas,P,P,_,_,[]) :- % TO DO: allow other binary/unary operators ? |
615 | | constrains_ID(A,AllParas,[],[],_,_,_), constrains_ID(B,AllParas,[],[],_,_,_). |
616 | | %constrains_ID_aux(Other,All,P,P,_,_,[]) :- print(other(Other)),nl,fail. |
617 | | |
618 | | constrains_ID_fields([],_AllParas,P,P,[],[],[]). |
619 | | constrains_ID_fields([field(Field,Val)|TF],AllParas,Parameters,RestParameters, |
620 | | [field(Field,SkelVal)|TSkelV],[field(Field,SkelUnify)|TSkelU],Bind) :- |
621 | | constrains_ID(Val,AllParas,Parameters,Rest1,SkelVal,SkelUnify,Bind1), |
622 | | constrains_ID_fields(TF,AllParas,Rest1,RestParameters,TSkelV,TSkelU,Bind2), |
623 | | append(Bind1,Bind2,Bind). % TO DO: use DCGs |
624 | | |
625 | | :- use_module(custom_explicit_sets,[efficient_card_for_set/3]). |
626 | | |
627 | | %is_small_set(S,_,LocalState,State) :- print(is_small_set(S,LocalState,State)),nl,fail. |
628 | | |
629 | | is_small_set(Val,Size,NormalLimit,SMTLimit) :- |
630 | | get_small_set_size(Val,Size), |
631 | | is_small_size(Size,NormalLimit,SMTLimit,unknown). |
632 | | |
633 | | :- use_module(kernel_tools,[ground_value/1]). |
634 | | get_small_set_size(value(S),Size) :- !, |
635 | | ground_value(S), % otherwise we could have S=[X] and expand_quantifier will erroneously create multiple solutions for parameter=X |
636 | | efficient_card_for_set(S,Size,C), |
637 | | call(C). |
638 | | get_small_set_size(interval(From,To),Size) :- !, |
639 | | custom_explicit_sets:is_interval_with_integer_bounds(interval(From,To),Low,Up), |
640 | | number(Low), number(Up), |
641 | | (Low > Up -> Size = 1 ; Size is 1+Up-Low). |
642 | | % we provide dom/ran here explicitly as this is often used {i|i:dom(f) ...} |
643 | | get_small_set_size(bool_set,Size) :- !, Size=2. |
644 | | get_small_set_size(domain(b(Val,_,_)),Size) :- !, get_small_domain_set_size(Val,Size). % this is only an upper bound on the size !! |
645 | | get_small_set_size(range(b(Val,_,_)),Size) :- !, get_small_set_size(Val,Size). % this is only an upper bound on the size !! |
646 | | get_small_set_size(cartesian_product(b(A,_,_),b(B,_,_)),Size) :- !, |
647 | | get_small_set_size(A,SizeA), number(SizeA), |
648 | | get_small_set_size(B,SizeB), number(SizeB), |
649 | | kernel_objects:safe_mul(SizeA,SizeB,Size), number(Size). |
650 | | |
651 | | %get_small_set_size(set_extension(L),Size,_,_,_) :- !, length(L,Size), is_small_size(Size). what if elements itself notknown ?? probably the case as otherwise this would have been compiled into a value |
652 | | %get_small_set_size(sequence_extension(L),Size,_,_,_) :- !, length(L,Size), is_small_size(Size). ditto |
653 | | %get_small_set_size(interval... |
654 | | %get_small_set_size(domain(value([....]))... |
655 | | % for this to work efficiently one should call b_compiler:compile on the predicates before sending them |
656 | | % to b_interpreter_check; otherwise the sets will not yet be in value(_) form |
657 | | |
658 | | % TO DO: the same for range or find more principled solution |
659 | | %get_small_domain_set_size(value(S),Size) :- var(S), frozen(S,Frozen), print(var_value(S,Frozen)),nl,fail. |
660 | | get_small_domain_set_size(value(Val),Size) :- nonvar(Val), Val=[H|T],!, |
661 | | efficient_card_for_set([H|T],Size,C), |
662 | | ground_domain([H|T]), % rather than requiring ground of entire list; we only require ground for domain (see test 1272) |
663 | | call(C). |
664 | | get_small_domain_set_size(Val,Size) :- get_small_set_size(Val,Size). |
665 | | ground_domain(V) :- var(V),!,fail. |
666 | | ground_domain([]). |
667 | | ground_domain([H|T]) :- nonvar(H), H=(D,_), ground_value(D), ground_domain(T). |
668 | | |
669 | | % maybe in other cases try b_compiler:compile ? |
670 | | %is_small_set(EXPR,Size,Parameters,LocalState,State) :- |
671 | | % print('check is_small_set: '),translate:print_bexpr(EXPR),nl, |
672 | | % def_get_texpr_ids(Parameters,PN), |
673 | | % print(parameters(PN)),nl, |
674 | | % b_compiler:b_compile(b(EXPR,pred,[]),PN,LocalState,State,CLHS,WF), |
675 | | % print('compiled: '), print(CLHS),nl, |
676 | | % CLHS = value(S),efficient_card_for_set(S,Size,C),call(C), is_small_size(Size). |
677 | | |
678 | | :- use_module(performance_messages). |
679 | | is_small_size(Size,NormalLimit,SMTLimit,SrcLocation) :- Size \= inf, |
680 | | (Size < NormalLimit -> true |
681 | | ; Size < SMTLimit |
682 | | -> (preferences:preference(use_smt_mode,true) -> true |
683 | | ; perfmessage(not_reifiying_size_too_large_try_SMT_mode(Size,limits(NormalLimit,SMTLimit)),SrcLocation),fail) |
684 | | ; perfmessage(not_reifiying_size_too_large(Size,limits(NormalLimit,SMTLimit)),SrcLocation),fail). |
685 | | |
686 | | % ------------------------------------- |
687 | | % EXPRESSIONS |
688 | | |
689 | | :- use_module(store,[set_up_localstate/4]). |
690 | | |
691 | | wd_set_up_localstate_for_let(Ids,Exprs,LocalState,State,LetState,WFD) :- |
692 | | set_up_localstate(Ids,Vars,LocalState,LetState), |
693 | | wd_compute_let_expressions(Exprs,Vars,LetState,State,WFD). |
694 | | wd_compute_let_expressions([],[],_,_,_). |
695 | | wd_compute_let_expressions([Expr|RestExprs],[Var|RestVars],LocalState,State,WFD) :- |
696 | | b_wd_compute_expression(Expr,LocalState,State,Value,WFD), |
697 | | kernel_objects:equal_object_optimized(Var,Value,compute_let_expressions), |
698 | | wd_compute_let_expressions(RestExprs,RestVars,LocalState,State,WFD). |
699 | | |
700 | | |
701 | | b_wd_compute_expressions([], _, _, [],_WFD). |
702 | | b_wd_compute_expressions([EXPRsHd|EXPRsTl],LocalState,State,[ValHd|ValTl],WFD) :- |
703 | | b_wd_compute_expression(EXPRsHd,LocalState,State,ValHd,WFD), |
704 | | b_wd_compute_expressions(EXPRsTl,LocalState,State,ValTl,WFD). |
705 | | |
706 | | % we have to avoid trying to compute certain expressions: evaluation can fail if not well-defined ! |
707 | | b_wd_compute_expression(Expr,LocalState,State,Value,wfwd(WF,WDE,WDV)) :- |
708 | | (nonvar(WDV) |
709 | | -> (WDE==WDV |
710 | | -> %print('REQUIRED: '), translate:print_bexpr(Expr),nl, |
711 | | if(b_compute_expression(Expr,LocalState,State,Value,WF), % TO DO: we could use fresh variable for Value |
712 | | true, |
713 | | (kernel_objects:unbound_value(Value), % we have a WD error, if nonvar it could be because we expect a wrong value |
714 | | translate:translate_bexpression_with_limit(Expr,TS), |
715 | | add_wd_error_span('Well-definedness error evaluating expression: ',TS,span_predicate(Expr,LocalState,State),WF) |
716 | | %Value = term(undefined), |
717 | | ) |
718 | | ) |
719 | | ; instantiate_to_any_value(Value,Expr,WF)) |
720 | | ; always_well_defined(Expr) % should we use always_well_defined_or_disprover_mode ?; probably not because of failure of the entire computation! |
721 | | -> % print('ALWAYS WD: '), translate:print_bexpr(Expr),nl, % |
722 | | b_compute_expression(Expr,LocalState,State,Value,WF) |
723 | | % ; \+ preferences:preference(use_smt_mode,_____false) %,\+ may_instantiate(Expr) |
724 | | % -> |
725 | | % % Necessary for tests 323, 324 : but dangerous inside set comprehensions ,... !! |
726 | | % print('NOT DELAYING WD in SMT MODE: '), translate:print_bexpr(Expr),nl, |
727 | | % b_compute_expression(Expr,LocalState,State,Value,WF) |
728 | | ; % print('DELAYING DUE TO WD: '), translate:print_bexpr(Expr),nl, %% |
729 | | b_compute_expression_delay(WDE,WDV, Expr,LocalState,State,Value,WF) |
730 | | % TO DO: allow further partial instantiation |
731 | | ). |
732 | | |
733 | | /* |
734 | | % what if function is used inside Expr ?? |
735 | | may_instantiate(b(E,_,_Infos)) :- !,may_instantiate_aux(E). |
736 | | % Warning: function application can force a variable to be bound to non-empty set ! |
737 | | may_instantiate_aux(function(_,_)). |
738 | | */ |
739 | | |
740 | | :- block b_compute_expression_delay(?,-, ?,?,?,?,?). |
741 | | b_compute_expression_delay(WDE,WDV,Expr,LocalState,State,Value,WF) :- |
742 | ? | (WDE==WDV |
743 | | -> % print('WD Evaluation: '), print(WDE),print(' =?= '), print(WDV), print(' '),translate:print_bexpr(Expr),nl, |
744 | ? | b_compute_expression(Expr,LocalState,State,Value,WF) |
745 | | % ,print(' Value: '), print(Value),nl |
746 | | ; %print(instantiate_to_any_value(Value,Expr)),nl, |
747 | | instantiate_to_any_value(Value,Expr,WF) % does not matter anyway; but there can be pending co-routines :-( |
748 | | ). |
749 | | |
750 | | % WARNING: the variable could be used in another context, where it is relevant ! |
751 | | |
752 | | |
753 | | wd_delay(WDCall,Res, Expr,wfwd(WF,WDExpected,WDV)) :- %print(wd_delay(WDExpected,WDV)),nl, |
754 | | (WDExpected==WDV -> call(WDCall) % WDV truth value on left is ok: we can evaluate |
755 | | ; nonvar(WDV) -> instantiate_to_any_value(Res,Expr,WF) % truth value not ok; we do not need the value |
756 | | ; always_well_defined(Expr) -> call(WDCall) |
757 | | ; wd_delay_block(WDCall,Res,Expr,WDExpected,WDV,WF)). |
758 | | :- block wd_delay_block(?,?,?,?,-,?). |
759 | | wd_delay_block(WDCall,Res,Expr,WDExpected,WDV,WF) :- |
760 | | (WDExpected==WDV -> call(WDCall) |
761 | | ; instantiate_to_any_value(Res,Expr,WF)). |
762 | | |
763 | | |
764 | | :- use_module(typing_tools,[any_value_for_type/2]). |
765 | | %instantiate_to_any_value(V,_) :- print(inst(V)),nl,nonvar(V),!. |
766 | | instantiate_to_any_value(V,_,_) :- ground_value(V),!. |
767 | | instantiate_to_any_value(V,b(_B,TYPE,_I),WF) :- |
768 | | get_enumeration_finished_wait_flag(WF,EWF), |
769 | | % TO DO: use ground value check |
770 | | when((nonvar(EWF);ground(V)),any_value_for_type(TYPE,V)). % , print(inst2(TYPE,V)),translate:print_bexpr(b(_B,TYPE,_I)),nl. |
771 | | |
772 | | |
773 | | :- block propagagate_wfwd(-,?,?,-,?), propagagate_wfwd(?,-,?,-,?). |
774 | | % propagate expected and actual value guarding left with actual predicate value obtained for left |
775 | | propagagate_wfwd(WDE,WDV,Res,F1,F2) :- |
776 | ? | (F1==F2 -> Res=F1 % then value of WDE does not matter at all; Res always the same |
777 | ? | ; propagagate_wfwd2(WDE,WDV,Res,F1,F2)). |
778 | | |
779 | | :- block propagagate_wfwd2(-,?,?,?,?), propagagate_wfwd2(?,-,?,?,?). |
780 | ? | propagagate_wfwd2(WDE,WDV,Res,F1,F2) :- (WDE==WDV -> Res=F1 ; Res=F2). |
781 | | |
782 | | :- use_module(external_functions,[external_fun_has_wd_condition/1]). |
783 | | :- use_module(preferences). |
784 | | b_check_boolean_expression4(equal(LHS,RHS),_,LocalState,State,WFD,EqRes) :- !, |
785 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
786 | | b_wd_compute_expression(RHS,LocalState,State,RHValue,WFD), |
787 | | get_texpr_type(LHS,Type), |
788 | | %translate:translate_bexpression(b(equal(LHS,RHS),pred,[]),SSS),preq(EqRes,SSS), |
789 | | % was translate_eq(Eq,Res), |
790 | | %when(nonvar(EqRes),(print(EqRes),print(' : '),translate:print_bexpr(b(equal(LHS,RHS),pred,[])),nl)), |
791 | | %print(equality(Type,LHValue,RHValue,WFD)), translate:print_bexpr(b(equal(LHS,RHS),pred,[])),nl, |
792 | | equality_objects_with_type(Type,LHValue,RHValue,EqRes). |
793 | | %:- block preq(-,?). |
794 | | %preq(Res,Expr) :- print('Equality determined '), print(Res), print(' '),print(Expr),nl. |
795 | | % we may need to improve not_member for closure to invert symbolic operators |
796 | | % we may want to add things like partial_function_check, subset_check, ... |
797 | | b_check_boolean_expression4(member(LHS,RHS),Info,LocalState,State,WFD,Res) :- |
798 | | %member_check_should_be_reified(LHS,RHS), % no longer need this: symbolic operators will be kept as closures if large ?! |
799 | | !, |
800 | | get_texpr_expr(RHS,ERHS), |
801 | | b_check_member_expression(ERHS,RHS,LHS,Info,LocalState,State,WFD,Res). |
802 | | % TO DO: add member(,pow_subset, fin_subset) --> subset_test |
803 | | % TO DO: compile forall, exists + setup choice point if expansion fails + remove compile calls in b_interpreter |
804 | | b_check_boolean_expression4(forall(Parameters,LHS,RHS),Info,LocalState,State,WFD,Res) :- !, |
805 | | if(b_check_forall_wfwd(Parameters,LHS,RHS,Info,LocalState,State,WFD,Res),true, |
806 | | (perfmessagecall(cannot_reify_forall(Parameters),translate:print_bexpr(LHS),LHS),fail)). |
807 | | b_check_boolean_expression4(exists(Parameters,Body),Info,LocalState,State,WFD,Res) :- !, |
808 | | if(b_check_exists_wfwd(Parameters,Body,Info,LocalState,State,WFD,Res),true, |
809 | | (perfmessagecall(cannot_reify_exists(Parameters),translate:print_bexpr(Body),Body),fail)). |
810 | | b_check_boolean_expression4(subset(LHS,RHS),_,LocalState,State,WFD,Res) :- !, WFD=wfwd(WF,_,_), |
811 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
812 | | b_wd_compute_expression(RHS,LocalState,State,RHValue,WFD), |
813 | | % print(subset_check),print(' '),translate:print_bexpr(b(subset(LHS,RHS),pred,[])),nl, %% |
814 | | subset_test(LHValue,RHValue,Res,WF). |
815 | | b_check_boolean_expression4(subset_strict(LHS,RHS),_,LocalState,State,WFD,Res) :- !, WFD=wfwd(WF,_,_), |
816 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
817 | | b_wd_compute_expression(RHS,LocalState,State,RHValue,WFD), |
818 | | % print(subset_strict_check),print(' '),translate:print_bexpr(b(subset_strict(LHS,RHS),pred,[])),nl, %% |
819 | | subset_strict_test(LHValue,RHValue,Res,WF). |
820 | | b_check_boolean_expression4(external_pred_call(FunName,Args),Info,LocalState,State,WFD,Res) :- |
821 | | !, |
822 | | (external_fun_has_wd_condition(FunName) |
823 | | -> wd_delay_until_needed(WFD,b_check_external_pred_call(FunName,Args,Info,LocalState,State,WFD,Res)) |
824 | | ; b_check_external_pred_call(FunName,Args,Info,LocalState,State,WFD,Res)). |
825 | | b_check_boolean_expression4(freetype_case(FT,IsCase,Expr),_Infos,LocalState,State,WFD,Res) :- !, |
826 | | b_wd_compute_expression(Expr,LocalState,State,freeval(FT,ActualCase,_A),WFD), |
827 | | %print(eq_atomic(IsCase,ActualCase,FT,_A,Res,WFD)),nl,translate:print_bexpr(Expr),nl, |
828 | | eq_atomic(IsCase,ActualCase,freeval_case,Res). |
829 | | b_check_boolean_expression4(finite(Expr),_Infos,LocalState,State,WFD,Res) :- !, WFD=wfwd(WF,_,_), |
830 | | b_wd_compute_expression(Expr,LocalState,State,ExprVal,WFD), |
831 | | % print(test_finite),nl,translate:print_bexpr(Expr),nl, |
832 | | kernel_objects:test_finite_set_wf(ExprVal,Res,WF). |
833 | | b_check_boolean_expression4(Pred,_,LocalState,State,WFD,Res) :- |
834 | | arithmetic_op(Pred,Op,LHS,RHS),!, |
835 | | % print('checking arith: '), print(op(Op,Res)),nl,translate:print_bexpr(Pred),nl, % |
836 | | b_wd_compute_expression(LHS,LocalState,State,int(LHValue),WFD), |
837 | | % kernel_objects:basic_type2(integer,int(LHValue)), % |
838 | | b_wd_compute_expression(RHS,LocalState,State,int(RHValue),WFD), |
839 | | % kernel_objects:basic_type2(integer,int(RHValue)), % |
840 | | check_arithmetic_operator(Op,LHValue,RHValue,Res). % |
841 | | % TO DO ???: use idea of b_artihmetic_expression to avoid intermediate CLPFD variables |
842 | | % TO DO: add other operators, ... |
843 | | /* use_smt_mode = full is never set; at some point we should enable the following clause by default |
844 | | b_check_boolean_expression4(Pred,Infos,LocalState,State,wfwd(WF,WDE,WDV),Res) :- |
845 | | preferences:preference(use_smt_mode,full), %% comment out to enable check testing of complicated predicates inside; |
846 | | % causes slowdowns of cbtc/actions_cbtc.mch; TO DO: investigate why |
847 | | b_check_boolean_expression4_delay(WDE,WDV,Pred,Infos,LocalState,State,WF,Res). |
848 | | */ |
849 | | |
850 | | :- use_module(library(lists),[maplist/3]). |
851 | | % TO DO: add member(,pow_subset, fin_subset) --> subset_test |
852 | | % we could distribute RHS=union -> disjunction, LHS=intersection -> conjunction ,... ? |
853 | | %b_check_member_expression(EHRS,_RHS,_LHS,_,_LocalState,_State,_WFD,_Res) :- |
854 | | % print('member : '), print(EHRS),nl,fail. |
855 | | %b_check_member_expression(union(A,B),LHS,_,LocalState,State,WFD,Res) :- |
856 | | b_check_member_expression(pow_subset(RHS),_,LHS,_Info,LocalState,State,WFD,Res) :- !, |
857 | | b_check_boolean_expression4(subset(LHS,RHS),[],LocalState,State,WFD,Res). |
858 | | %b_check_member_expression(NotContainingEmptySet,_TRHS,LHS,LocalState,State,WFD,Res) :- |
859 | | % non_empty_set_version_of(NotContainingEmptySet,RHS_With_EmptySet), |
860 | | % % translate x:seq1(RHS) -> x /= {} & x:seq(RHS), ... |
861 | | % % this improves propagation, in particular in light of WD issues |
862 | | % % TO DO: avoid computing LHS twice ! |
863 | | % !, |
864 | | % get_texpr_type(LHS,LType), |
865 | | % EMPTYVERSION = b(member(LHS,b(RHS_With_EmptySet,set(LType),[])),pred,[]), |
866 | | % NOTEMPTYPRED = b(not_equal(LHS,b(empty_set,LType,[])),pred,[]), |
867 | | % print('Translating : '), translate:print_bexpr(EMPTYVERSION), print(' & '), translate:print_bexpr(NOTEMPTYPRED),nl, |
868 | | % empty_avl(Ai), Infos=[], % Infos not important for conjunction |
869 | | % b_check_boolean_expression2(conjunct(EMPTYVERSION,NOTEMPTYPRED),Infos,LocalState,State,WFD,Res,Ai,_). |
870 | | b_check_member_expression(interval(Low,Up),_,LHS,_Info,LocalState,State,WFD,Res) :- !, WFD=wfwd(WF,_,_), |
871 | | % to do: should we also match interval value closure |
872 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
873 | | b_wd_compute_expression(Low,LocalState,State,LowValue,WFD), |
874 | | b_wd_compute_expression(Up,LocalState,State,UpValue,WFD), |
875 | | % print(mem_check_in_interval),print(' '),translate:print_bexpr(b(interval(Low,Up),set(integer),[])),nl, |
876 | | kernel_objects:test_in_nat_range_wf(LHValue,LowValue,UpValue,Res,WF). |
877 | | b_check_member_expression(set_extension(SetExt),_RHS,LHS,Info,LocalState,State,WFD,Res) :- !, WFD=wfwd(WF,_,_), |
878 | | % rewrite x:{a,b,c} into x=a or x=b or x=c (is the opposite of rewrite_disjunct_to_member) |
879 | | % The rewrite_disjunct_to_member is good when we know a membership to be true; the disjunct is better for reification |
880 | | % Note: the problem is in particular when the result of the membership is not needed and an uninstantiated |
881 | | % variable is used in the set extension, example y:dom(f) => (x:{f(y),0} or f(y)=0) |
882 | | % print(mem_check_set_extension),print(' '),translate:print_bexpr(b(member(LHS,_RHS),pred,[])),nl, |
883 | | b_wd_compute_expressions(SetExt,LocalState,State,SetExtValues,WFD), |
884 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
885 | | get_texpr_type(LHS,Type), |
886 | | NewLHS = b(value(LHValue),Type,[]), |
887 | | (ground(SetExtValues) |
888 | | -> % better to use normal treatment, we can compute the entire set and translate it into an AVL tree |
889 | | maplist(construct_value(Type),SetExtValues,Vals), |
890 | | b_wd_compute_expression(b(set_extension(Vals),set(Type),[]),LocalState,State,RHValue,WFD), |
891 | | %print(rhval(RHValue)),nl, |
892 | | membership_test_wf(RHValue,LHValue,Res,WF), |
893 | | force_membership_test(Res,LHValue,RHValue,WF) |
894 | | ; maplist(construct_equality(NewLHS,Type),SetExtValues,Disjuncts), |
895 | | construct_norm_disjunct2(Disjuncts,NC,Info), % print(normalised_disj(NC)),nl, |
896 | | empty_avl(Ai), |
897 | | b_check_boolean_expression2(NC,Info,LocalState,State,WFD,Res,Ai,_) |
898 | | ). |
899 | | b_check_member_expression(closure(Relation),_RHS,LHS,_Info,LocalState,State,WFD,Res) :- !, WFD=wfwd(WF,_,_), |
900 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
901 | | b_wd_compute_expression(Relation,LocalState,State,RelValue,WFD), |
902 | | %print(reify_in_closure(LHValue,RelValue)),nl, |
903 | | bsets_clp:in_closure1_membership_test_wf(LHValue,RelValue,Res,WF). |
904 | | b_check_member_expression(_,RHS,LHS,_Info,LocalState,State,WFD,Res) :- WFD=wfwd(WF,_,_), |
905 | | b_wd_compute_expression(LHS,LocalState,State,LHValue,WFD), |
906 | | b_wd_compute_expression(RHS,LocalState,State,RHValue,WFD), |
907 | | % print(mem_check),print(' '),translate:print_bexpr(b(member(LHS,RHS),pred,[])),nl, |
908 | | % print(mem_test(RHValue,LHValue,Res)),nl, trace, |
909 | | membership_test_wf(RHValue,LHValue,Res,WF), |
910 | | force_membership_test(Res,LHValue,RHValue,WF). |
911 | | |
912 | | construct_value(Type,Val,b(value(Val),Type,[])). |
913 | | |
914 | | :- use_module(bsyntaxtree, [safe_create_texpr/3]). |
915 | | construct_equality(NewLHS,Type,ElementV,Equality) :- |
916 | | Element = b(value(ElementV),Type,[]), |
917 | | safe_create_texpr(equal(NewLHS,Element),pred,Equality). %, translate:print_bexpr(Equality),nl. |
918 | | |
919 | | %non_empty_set_version_of(seq1(RHS),seq(RHS)). |
920 | | %non_empty_set_version_of(iseq1(RHS),iseq(RHS)). |
921 | | %non_empty_set_version_of(fin1_subset(RHS),fin_subset(RHS)). |
922 | | %non_empty_set_version_of(pow1_subset(RHS),pow_subset(RHS)). |
923 | | |
924 | | /* |
925 | | :- block b_check_boolean_expression4_delay(?,-,?,?,?,?,?,?). |
926 | | b_check_boolean_expression4_delay(WDE,WDV,_,_,_,_,_,Res) :- WDE \= WDV,!, |
927 | | Res=pred_false. % does not matter |
928 | | b_check_boolean_expression4_delay(_WDE,_WDV,Pred,Infos,LocalState,State,WF,Res) :- |
929 | | % we currently have not yet implemented a way to check the Pred; wait until Result is known |
930 | | (preferences:preference(use_smt_mode,false) |
931 | | -> |
932 | | get_last_wait_flag(b_check_test_boolean_expression,WF,WF2) |
933 | | %Prio=10000,get_wait_flag(Prio,b_check_test_boolean_expression,WF,WF2) |
934 | | ; get_binary_choice_wait_flag(b_check_test_boolean_expression,WF,WF2) |
935 | | ), |
936 | | (debug:debug_mode(on) -> print(' Check Testing: '),translate:print_bexpr(Pred),nl ; true), |
937 | | b_check_test_boolean_expression(Res,WF2,b(Pred,pred,Infos),LocalState,State,WF). |
938 | | |
939 | | :- block b_check_test_boolean_expression(-,-,?,?,?,?). |
940 | | b_check_test_boolean_expression(pred_true,_,Pred,LocalState,State,WF) :- |
941 | | b_test_boolean_expression(Pred,LocalState,State,WF). |
942 | | b_check_test_boolean_expression(pred_false,_,Pred,LocalState,State,WF) :- |
943 | | b_not_test_boolean_expression(Pred,LocalState,State,WF). |
944 | | */ |
945 | | |
946 | | /* |
947 | | :- use_module(kernel_mappings). |
948 | | member_check_should_be_reified(_,b(RHS,_,_)) :- functor(RHS,BOP,Arity), print(check(BOP,Arity)),nl,!. |
949 | | member_check_should_be_reified(_,_) :- \+ preferences:preference(use_smt_mode,false),!. |
950 | | member_check_should_be_reified(_LHS,b(RHS,_,_)) :- functor(RHS,BOP,Arity), |
951 | | % check if we have optimized treatments available, for which we do not yet have reified versions |
952 | | (Arity=1 -> \+ kernel_mappings:unary_in_boolean_type(BOP,_) |
953 | | ; Arity=2 -> \+ kernel_mappings:binary_in_boolean_type(BOP,_) |
954 | | ; Arity=0 -> \+ kernel_mappings:cst_in_boolean_type(BOP,_) |
955 | | ; true). |
956 | | */ |
957 | | |
958 | | |
959 | | :- block force_membership_test(-,?,?,?). |
960 | | % currently required for ensuring that following fails: |
961 | | % kernel_objects:union(closure(['_zzzz_unit_tests'],[integer],b(member(b(identifier('_zzzz_unit_tests'),integer,[generated]),b(value([int(3),int(4)]),set(integer),[])),pred,[])),closure(['_zzzz_unit_tests'],[integer],b(member(b(identifier('_zzzz_unit_tests'),integer,[generated]),b(value([int(2),int(1)]),set(integer),[])),pred,[])),[int(1),int(3),int(2)]) |
962 | | % Reason: membership_test does not on its own enumerate |
963 | | force_membership_test(pred_true,X,Set,WF) :- % print(forcing_element_true(X,Set)),nl,% |
964 | | Set \= [], |
965 | | (ground_value(X) -> true |
966 | | ; (nonvar(Set),no_use_forcing(Set)) -> true % no use in forcing membership, will call same element_of_avl_set_wf |
967 | | %, tools_printing:print_term_summary(not_forcing(X,Set)),nl |
968 | | ; kernel_objects:check_element_of_wf(X,Set,WF) |
969 | | ) |
970 | | %, tools:bt_trace(force_membership) |
971 | | %, print(forced(X)),nl |
972 | | . |
973 | | force_membership_test(pred_false,_X,_Set,_WF). |
974 | | |
975 | | % forcing is sometimes useful because we can transmit a WF, currently some of the reification predicates |
976 | | % do not have a WF-Store and can thus do limited enumeration ! in particular true for CLPFD = FALSE mode |
977 | | no_use_forcing(avl_set(_)) :- preferences:preference(use_clpfd_solver,true). |
978 | | no_use_forcing(global_set(_)). |
979 | | %no_use_forcing(closure(_,_,B)) :- preferences:preference(use_clpfd_solver,true). |
980 | | |
981 | | |
982 | | |
983 | | :- use_module(external_functions,[call_external_predicate/8, do_not_evaluate_args/1]). |
984 | | b_check_external_pred_call(FunName,Args,Info,LocalState,State,WFD,Res) :- |
985 | | WFD=wfwd(WF,_,_), |
986 | | (do_not_evaluate_args(FunName) -> EvaluatedArgs=[] |
987 | | ; b_wd_compute_expressions(Args, LocalState,State, EvaluatedArgs, WFD)), |
988 | | %% print(external_pred_check),print(FunName),nl,%% |
989 | | call_external_predicate(FunName,Args,EvaluatedArgs,LocalState,State,Res,Info,WF). |
990 | | |
991 | | wd_delay_until_needed(wfwd(_,WDExpected,WDV),Call) :- !, |
992 | | wd_delay_until_needed_block(WDExpected,WDV,Call,true). |
993 | | wd_delay_until_needed(WFD,Call) :- add_internal_error('Illegal WFWD info:',wd_delay_until_needed(WFD,Call)), |
994 | | call(Call). |
995 | | :- block wd_delay_until_needed_block(-,?,?,?), wd_delay_until_needed_block(?,-,?,?). |
996 | | wd_delay_until_needed_block(WDExpected,WDV,Call,_) :- WDExpected==WDV,!, |
997 | | call(Call). |
998 | | wd_delay_until_needed_block(_,_,_,Call) :- call(Call). % first call not needed |
999 | | |
1000 | | |
1001 | | :- use_module(library(avl)). |
1002 | | reuse_predicate(_,_,no_avl) :- !,fail. |
1003 | | reuse_predicate(Pred,Var,AVL) :- avl_fetch(Pred,AVL,Var). %pred_var(Var)). |
1004 | | add_predicate(_Pred,_Var,no_avl,NewAVL) :- !, NewAVL=no_avl. |
1005 | | add_predicate(Pred,Var,AVL,NewAVL) :- (avl_store(Pred,AVL,Var,NewAVL) -> true ; NewAVL=no_avl). %pred_var(Var),NewAVL). |
1006 | | |
1007 | | |
1008 | | :- use_module(translate,[print_bexpr/1]). |
1009 | | % normalises a typed predicate by removing position information and ordering commutative operators in a canonical way |
1010 | | norm_pred_check(B,Res) :- |
1011 | | (norm_pred(B,Res) -> true |
1012 | | ; bget_functor(B,F,N),print(norm_pred_failed(F/N)),nl, print_bexpr(B),nl, % print(B),nl, |
1013 | | Res=B). |
1014 | | bget_functor(b(B,_,_),F,N) :- functor(B,F,N). |
1015 | | bget_functor(B,F,N) :- functor(B,F,N). |
1016 | | |
1017 | | norm_pred(X,Res) :- var(X),!,Res=X. |
1018 | | norm_pred(b(B,_,_),Res) :- !, norm_pred(B,Res). |
1019 | | norm_pred(conjunct(A,B),Res) :- !, norm_pred(A,AA), norm_pred(B,BB), |
1020 | | (BB @< AA -> Res = conjunct(AA,BB) ; Res= conjunct(BB,AA)). |
1021 | | norm_pred(disjunct(A,B),Res) :- !, norm_pred(A,AA), norm_pred(B,BB), |
1022 | | (BB @< AA -> Res = disjunct(AA,BB) ; Res= disjunct(BB,AA)). |
1023 | | norm_pred(equal(A,B),Res) :- !,norm_expr(A,AA),norm_expr(B,BB), |
1024 | | (BB @< AA -> Res = equal(AA,BB) ; Res= equal(BB,AA)). |
1025 | | norm_pred(equivalence(A,B),Res) :- !, norm_pred(A,AA), norm_pred(B,BB), |
1026 | | (BB @< AA -> Res = equivalence(AA,BB) ; Res= equivalence(BB,AA)). |
1027 | | norm_pred(exists(A,B),Res) :- !, Res=exists(AA,BB),l_norm_expr(A,AA), norm_pred(B,BB). |
1028 | | norm_pred(forall(A,B,C),Res) :- !, Res=forall(AA,BB,CC),l_norm_expr(A,AA), norm_pred(B,BB), norm_pred(C,CC). |
1029 | | norm_pred(greater(A,B),less(BB,AA)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1030 | | norm_pred(greater_equal(A,B),less_equal(BB,AA)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1031 | | norm_pred(implication(A,B),Res) :- !, Res=implication(AA,BB),norm_pred(A,AA), norm_pred(B,BB). |
1032 | | norm_pred(less(A,B),less(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1033 | | norm_pred(less_equal(A,B),less_equal(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1034 | | norm_pred(let_predicate(A,B,C),Res) :- !, |
1035 | | Res=let_predicate(AA,BB,CC), |
1036 | | l_norm_expr(A,AA), l_norm_expr(B,BB),norm_pred(C,CC). |
1037 | | norm_pred(lazy_let_pred(A,B,C),Res) :- !, |
1038 | | Res = lazy_let_pred(AA,BB,CC), |
1039 | | norm_expr(A,AA), |
1040 | | norm_pred_or_expr(B,BB),norm_pred(C,CC). |
1041 | | norm_pred(lazy_lookup_pred(A),Res) :- !, Res = lazy_lookup_pred(A). |
1042 | | norm_pred(member(A,B),member(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1043 | | norm_pred(negation(A),Res) :- !, Res=negation(AA), norm_pred(A,AA). |
1044 | | norm_pred(not_equal(A,B),Res) :- !,norm_expr(A,AA),norm_expr(B,BB), |
1045 | | (BB @< AA -> Res = not_equal(AA,BB) ; Res= not_equal(BB,AA)). |
1046 | | norm_pred(not_member(A,B),not_member(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1047 | | norm_pred(not_subset(A,B),not_subset(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1048 | | norm_pred(not_subset_strict(A,B),not_subset_strict(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1049 | | norm_pred(subset(A,B),subset(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1050 | | norm_pred(subset_strict(A,B),subset_strict(AA,BB)) :- !,norm_expr(A,AA),norm_expr(B,BB). |
1051 | | norm_pred(freetype_case(Type,Case,A),freetype_case(Type,Case,AA)) :- !,norm_expr(A,AA). |
1052 | | norm_pred(X,X). % :- print(norm_pred(X)),nl. |
1053 | | |
1054 | | norm_pred_or_expr(b(B,pred,_),Res) :- norm_pred(B,Res). |
1055 | | norm_pred_or_expr(B,Res) :- norm_expr(B,Res). |
1056 | | |
1057 | | :- public norm_expr_check/2. |
1058 | | norm_expr_check(X,Res) :- var(X),!,Res=X. |
1059 | | norm_expr_check(b(B,_,_),Res) :- !, norm_expr_check2(B,Res). |
1060 | | norm_expr_check(X,X). |
1061 | | |
1062 | | norm_expr_check2(B,Res) :- |
1063 | | (norm_expr2(B,Res) -> true |
1064 | | ; functor(B,F,N),print(norm_expr2_failed(F/N)),nl, |
1065 | | Res=B). |
1066 | | |
1067 | | norm_expr(X,Res) :- var(X),!,Res=X. |
1068 | | norm_expr(b(B,_,_),Res) :- !, norm_expr2(B,Res). |
1069 | | %norm_expr_check2(B,Res). %% comment in to obtain details about failed normalisation for expressions |
1070 | | norm_expr(X,X). |
1071 | | |
1072 | | norm_expr2(assertion_expression(Cond,E,Expr),assertion_expression(AA,E,BB)) :- norm_pred(Cond,AA),norm_expr(Expr,BB). |
1073 | | norm_expr2(add(A,B),Res) :- norm_expr(A,AA), norm_expr(B,BB), (BB @< AA -> Res = add(AA,BB) ; Res= add(BB,AA)). |
1074 | | norm_expr2(bag_items(A),bag_items(AA)) :- norm_expr(A,AA). |
1075 | | norm_expr2(boolean_false,boolean_false). |
1076 | | norm_expr2(boolean_true,boolean_true). |
1077 | | norm_expr2(bool_set,bool_set). |
1078 | | norm_expr2(card(A),card(AA)) :- norm_expr(A,AA). |
1079 | | norm_expr2(cartesian_product(A,B),cartesian_product(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1080 | | norm_expr2(closure(A),closure(AA)) :- norm_expr(A,AA). % this is closure1 |
1081 | | norm_expr2(compaction(A),compaction(AA)) :- norm_expr(A,AA). |
1082 | | norm_expr2(composition(A,B),composition(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1083 | | norm_expr2(comprehension_set(A,B),comprehension_set(AA,BB)) :- norm_expr(A,AA), norm_pred(B,BB). |
1084 | | norm_expr2(concat(A,B),concat(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1085 | | norm_expr2(convert_bool(A),convert_bool(AA)) :- norm_pred_check(A,AA). |
1086 | | norm_expr2(couple(A,B),couple(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1087 | | norm_expr2(direct_product(A,B),direct_product(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1088 | | norm_expr2(div(A,B),div(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1089 | | norm_expr2(floored_div(A,B),floored_div(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1090 | | norm_expr2(domain_restriction(A,B),domain_restriction(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1091 | | norm_expr2(domain_subtraction(A,B),domain_subtraction(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1092 | | norm_expr2(domain(A),domain(AA)) :- norm_expr(A,AA). |
1093 | | norm_expr2(empty_sequence,empty_sequence). |
1094 | | norm_expr2(empty_set,empty_set). |
1095 | | norm_expr2(event_b_identity,event_b_identity). |
1096 | | norm_expr2(external_function_call(A,B),external_function_call(A,BB)) :- l_norm_expr(B,BB). |
1097 | | norm_expr2(fin_subset(A),fin_subset(AA)) :- norm_expr(A,AA). |
1098 | | norm_expr2(fin1_subset(A),fin1_subset(AA)) :- norm_expr(A,AA). |
1099 | | norm_expr2(first(A),first(AA)) :- norm_expr(A,AA). |
1100 | | norm_expr2(first_of_pair(A),first_of_pair(AA)) :- norm_expr(A,AA). |
1101 | | norm_expr2(front(A),front(AA)) :- norm_expr(A,AA). |
1102 | | norm_expr2(function(A,B),function(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1103 | | norm_expr2(general_concat(A),general_concat(AA)) :- norm_expr(A,AA). |
1104 | | norm_expr2(general_intersection(A),general_intersection(AA)) :- norm_expr(A,AA). |
1105 | | norm_expr2(general_product(A,B,C),Res) :- !, Res=general_sum(AA,BB,CC),l_norm_expr(A,AA), norm_pred(B,BB), norm_expr(C,CC). |
1106 | | norm_expr2(general_sum(A,B,C),Res) :- !, Res=general_sum(AA,BB,CC),l_norm_expr(A,AA), norm_pred(B,BB), norm_expr(C,CC). |
1107 | | norm_expr2(general_union(A),general_union(AA)) :- norm_expr(A,AA). |
1108 | | norm_expr2(identifier(A),'$'(A)). % need wrapper to avoid confusion with other terms ! |
1109 | | norm_expr2(identity(A),identity(AA)) :- norm_expr(A,AA). |
1110 | | norm_expr2(if_then_else(P,A,B),if_then_else(PP,AA,BB)) :- norm_pred(P,PP),norm_expr(A,AA), norm_expr(B,BB). |
1111 | | norm_expr2(image(A,B),image(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1112 | | norm_expr2(insert_front(A,B),insert_front(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1113 | | norm_expr2(insert_tail(A,B),insert_tail(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1114 | | norm_expr2(integer_set(A),A). |
1115 | | norm_expr2(integer(A),A). |
1116 | | norm_expr2(intersection(A,B),Res) :- norm_expr(A,AA), norm_expr(B,BB), |
1117 | | (BB @< AA -> Res = intersection(AA,BB) ; Res= intersection(BB,AA)). |
1118 | | norm_expr2(interval(A,B),interval(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1119 | | norm_expr2(iseq(A),iseq(AA)) :- norm_expr(A,AA). |
1120 | | norm_expr2(iseq1(A),iseq1(AA)) :- norm_expr(A,AA). |
1121 | | norm_expr2(iteration(A,B),iteration(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1122 | | norm_expr2(last(A),last(AA)) :- norm_expr(A,AA). |
1123 | | norm_expr2(lazy_let_expr(A,B,C),lazy_let_expr(AA,BB,CC)) :- |
1124 | | norm_expr(A,AA),norm_pred_or_expr(B,BB),norm_expr(C,CC). |
1125 | | norm_expr2(lazy_lookup_expr(A),lazy_lookup_expr(A)) :- !. |
1126 | | norm_expr2(let_expression(A,B,C),let_expression(AA,BB,CC)) :- l_norm_expr(A,AA), l_norm_expr(B,BB),norm_pred(C,CC). |
1127 | | norm_expr2(let_expression_global(A,B,C),let_expression_global(AA,BB,CC)) :- l_norm_expr(A,AA), l_norm_expr(B,BB),norm_pred(C,CC). |
1128 | | norm_expr2(max(A),max(AA)) :- norm_expr(A,AA). |
1129 | | norm_expr2(max_int,max_int). |
1130 | | norm_expr2(min(A),min(AA)) :- norm_expr(A,AA). |
1131 | | norm_expr2(min_int,min_int). |
1132 | | norm_expr2(minus(A,B),minus(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1133 | | norm_expr2(modulo(A,B),modulo(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1134 | | norm_expr2(mu(A),mu(AA)) :- norm_expr(A,AA). |
1135 | | norm_expr2(multiplication(A,B),Res) :- norm_expr(A,AA), norm_expr(B,BB), (BB @< AA -> Res = multiplication(AA,BB) ; Res= multiplication(BB,AA)). |
1136 | | norm_expr2(operation_call_in_expr(A,B),overwrite(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1137 | | norm_expr2(overwrite(A,B),overwrite(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1138 | | norm_expr2(parallel_product(A,B),parallel_product(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1139 | | norm_expr2(partial_bijection(A,B),partial_bijection(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1140 | | norm_expr2(partial_function(A,B),partial_function(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1141 | | norm_expr2(partial_injection(A,B),partial_injection(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1142 | | norm_expr2(partial_surjection(A,B),partial_surjection(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1143 | | norm_expr2(perm(A),perm(AA)) :- norm_expr(A,AA). |
1144 | | norm_expr2(power_of(A,B),power_of(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1145 | | norm_expr2(pow_subset(A),pow_subset(AA)) :- norm_expr(A,AA). |
1146 | | norm_expr2(pow1_subset(A),pow1_subset(AA)) :- norm_expr(A,AA). |
1147 | | norm_expr2(range_restriction(A,B),range_restriction(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1148 | | norm_expr2(range_subtraction(A,B),range_subtraction(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1149 | | norm_expr2(range(A),range(AA)) :- norm_expr(A,AA). |
1150 | | norm_expr2(rec(A),rec(A)). % should we do norm_fields here ? |
1151 | | norm_expr2(record_field(A,B),record_field(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1152 | | norm_expr2(relations(A,B),relations(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1153 | | norm_expr2(restrict_front(A,B),restrict_front(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1154 | | norm_expr2(restrict_tail(A,B),restrict_tail(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1155 | | norm_expr2(reflexive_closure(A),reflexive_closure(AA)) :- norm_expr(A,AA). % this is rewritten in ast_cleanup |
1156 | | norm_expr2(rev(A),rev(AA)) :- norm_expr(A,AA). |
1157 | | norm_expr2(reverse(A),reverse(AA)) :- norm_expr(A,AA). |
1158 | | norm_expr2(second_of_pair(A),second_of_pair(AA)) :- norm_expr(A,AA). |
1159 | | norm_expr2(seq(A),seq(AA)) :- norm_expr(A,AA). |
1160 | | norm_expr2(seq1(A),seq1(AA)) :- norm_expr(A,AA). |
1161 | | norm_expr2(sequence_extension(L),sequence_extension(NL)) :- l_norm_expr(L,NL). |
1162 | | norm_expr2(set_extension(L),set_extension(NL)) :- l_norm_expr(L,NL). |
1163 | | norm_expr2(set_subtraction(A,B),set_subtraction(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1164 | | norm_expr2(size(A),size(AA)) :- norm_expr(A,AA). |
1165 | | norm_expr2(string(A),string(A)). % need wrapper to avoid confusion with other terms ! |
1166 | | norm_expr2(string_set,string_set). |
1167 | | norm_expr2(struct(A),struct(A)). % should we do norm_fields here ? |
1168 | | norm_expr2(surjection_relation(A,B),surjection_relation(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1169 | | norm_expr2(tail(A),tail(AA)) :- norm_expr(A,AA). |
1170 | | norm_expr2(total_bijection(A,B),total_bijection(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1171 | | norm_expr2(total_function(A,B),total_function(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1172 | | norm_expr2(total_injection(A,B),total_injection(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1173 | | norm_expr2(total_relation(A,B),total_relation(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1174 | | norm_expr2(total_surjection(A,B),total_surjection(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1175 | | norm_expr2(total_surjection_relation(A,B),total_surjection_relation(AA,BB)) :- norm_expr(A,AA), norm_expr(B,BB). |
1176 | | |
1177 | | norm_expr2(unary_minus(A),unary_minus(AA)) :- norm_expr(A,AA). |
1178 | | norm_expr2(union(A,B),Res) :- norm_expr(A,AA), norm_expr(B,BB), (BB @< AA -> Res = union(AA,BB) ; Res= union(BB,AA)). |
1179 | | norm_expr2(value(A),value(NA)) :- norm_value(A,NA). |
1180 | | |
1181 | | norm_expr2(freetype_set(T),freetype_set(T)). |
1182 | | norm_expr2(freetype_constructor(FT,Case,A), freetype_constructor(FT,Case,AA)) :- norm_expr(A,AA). |
1183 | | norm_expr2(freetype_destructor(FT,Case,A),freetype_destructor(FT,Case,AA)) :- norm_expr(A,AA). |
1184 | | norm_expr2(recursive_let(A,B),recursive_let(AA,BB)) :- norm_expr(A,AA),norm_expr(B,BB). |
1185 | | |
1186 | | l_norm_expr([],[]). |
1187 | | l_norm_expr([H|T],[NH|NT]) :- norm_expr(H,NH), l_norm_expr(T,NT). |
1188 | | |
1189 | | norm_value(V,R) :- var(V),!,R=V. |
1190 | | norm_value(closure(P,T,B),R) :- norm_pred(B,NB), |
1191 | | !, % normalising relevant for test 1544 with position info aded by construct_member_closure |
1192 | | R=closure(P,T,NB). |
1193 | | norm_value(V,V). % we could normalise AVL |
1194 | | |
1195 | | arithmetic_op(less(LHS,RHS),'<',LHS,RHS). |
1196 | | arithmetic_op(less_equal(LHS,RHS),'<=',LHS,RHS). |
1197 | | arithmetic_op(greater(LHS,RHS),'<',RHS,LHS). |
1198 | | arithmetic_op(greater_equal(LHS,RHS),'<=',RHS,LHS). |
1199 | | |
1200 | | :- use_module(clpfd_interface). |
1201 | | check_arithmetic_operator('<',X,Y,Res) :- check_less(X,Y,Res), |
1202 | | (nonvar(Res) -> true |
1203 | | ; clpfd_interface:try_post_constraint(clpfd:'#<=>'((X#<Y) , R01)), prop_pred_01(Res,R01)). |
1204 | | check_arithmetic_operator('<=',X,Y,Res) :- check_less_than_equal(X,Y,Res), |
1205 | | (nonvar(Res) -> true |
1206 | | ; clpfd_interface:try_post_constraint(clpfd:'#<=>'( (X#=<Y) , R01)), prop_pred_01(Res,R01)). |
1207 | | |
1208 | | :- block prop_pred_01(-,-). |
1209 | | % prop_pred_01(A,B) :- print(prop(A,B)),nl,fail. |
1210 | | prop_pred_01(A,B) :- B==1,!,A=pred_true. % cut ok: either pred_true or 1 set |
1211 | | prop_pred_01(pred_true,1). |
1212 | | prop_pred_01(pred_false,0). |
1213 | | |
1214 | | :- block check_less(-,?,-), check_less(?,-,-). |
1215 | | check_less(X,Y,Res) :- nonvar(Res),!, /* truth value known: enforce it */ |
1216 | | %% print(forcing_less(X,Y,Res)),nl, %% |
1217 | | (Res=pred_true -> less_than_direct(X,Y) ; less_than_equal_direct(Y,X)). |
1218 | | check_less(X,Y,Res) :- % print(check_less(X,Y)),nl,%% |
1219 | | X < Y,!,/* we could call safe_less_than(X,Y), */ |
1220 | | Res=pred_true. |
1221 | | check_less(_,_,pred_false). |
1222 | | :- block check_less_than_equal(-,?,-), check_less_than_equal(?,-,-). |
1223 | | check_less_than_equal(X,Y,Res) :- nonvar(Res),!, /* truth value known: enforce it */ |
1224 | | %% print(forcing_less_than_equal(X,Y,Res)),nl,%% |
1225 | | (Res=pred_true -> less_than_equal_direct(X,Y) ; less_than_direct(Y,X)). |
1226 | | check_less_than_equal(X,Y,Res) :- X =< Y,!,Res=pred_true. |
1227 | | check_less_than_equal(_,_,pred_false). |
1228 | | |
1229 | | |
1230 | | |
1231 | | :- use_module(bool_pred). |
1232 | | |
1233 | | :- use_module(kernel_objects,[exhaustive_kernel_check_wf/2, |
1234 | | exhaustive_kernel_check/1, exhaustive_kernel_check/2, exhaustive_kernel_fail_check/1]). |
1235 | | |
1236 | | :- assert_must_succeed(exhaustive_kernel_check_wf(b_interpreter_check:conjoin(pred_false,pred_false,pred_false,b(truth,pred,[]),b(truth,pred,[]),WF),WF)). |
1237 | | :- assert_must_succeed(exhaustive_kernel_check_wf(b_interpreter_check:conjoin(pred_false,pred_true,pred_false,b(truth,pred,[]),b(truth,pred,[]),WF),WF)). |
1238 | | :- assert_must_succeed(exhaustive_kernel_check_wf(b_interpreter_check:conjoin(pred_true,pred_false,pred_false,b(truth,pred,[]),b(truth,pred,[]),WF),WF)). |
1239 | | :- assert_must_succeed(exhaustive_kernel_check_wf(b_interpreter_check:conjoin(pred_true,pred_true,pred_true,b(truth,pred,[]),b(truth,pred,[]),WF),WF)). |
1240 | | :- assert_must_fail(b_interpreter_check:conjoin(pred_true,pred_false,pred_true,b(truth,pred,[]),b(truth,pred,[]),_WF)). |
1241 | | :- assert_must_fail(b_interpreter_check:conjoin(pred_true,pred_true,pred_false,b(truth,pred,[]),b(truth,pred,[]),_WF)). |
1242 | | |
1243 | | |
1244 | | % same as and_equality/3 but for pred_false/pred_true rather than eq_obj/pred_false |
1245 | | :- block conjoin(-,-,-,?,?,?). |
1246 | | conjoin(X,Y,Res,LHS,RHS,WF) :- % print(conjoin(X,Y,Res)),nl, translate:print_bexpr(LHS),nl,% |
1247 | ? | ( Res==pred_true -> X=pred_true,Y=pred_true |
1248 | | ; X==pred_true -> Res=Y |
1249 | | ; X==pred_false -> Res=pred_false |
1250 | | ; Y==pred_true -> Res=X |
1251 | | ; Y==pred_false -> Res=pred_false |
1252 | | ; Res==pred_false -> conjoin_false0(X,Y,LHS,RHS,WF) |
1253 | | ; add_error_fail(conjoin,'Illegal values: ', conjoin(X,Y,Res,LHS,RHS,WF)) |
1254 | | ). |
1255 | | conjoin_false0(X,Y,_LHS,_RHS,_WF) :- X==Y,!, |
1256 | | %print(conjoin_false_eqeq(X,Y)),nl, translate:print_bexpr(_LHS),nl, |
1257 | | X=pred_false. |
1258 | | conjoin_false0(X,Y,_LHS,_RHS,_WF) :- % X & not(X) -> always false |
1259 | | bool_negate_check(X,Y),! |
1260 | | . %,print(conjoin_false_neqeq(X,Y)),nl,translate:print_bexpr(_LHS),nl. |
1261 | | conjoin_false0(X,Y,LHS,RHS,WF) :- |
1262 | | %%Prio=1, %% |
1263 | | %%(preferences:preference(use_smt_mode,full) -> FullPrio=1.5 ; |
1264 | | get_priority_of_boolean_expression(LHS,Prio), |
1265 | | (preferences:preference(use_clpfd_solver,true) -> |
1266 | | % relevant for tests 349, 362: |
1267 | | count_number_of_conjuncts(RHS,NrC), |
1268 | | FullPrio is Prio+(NrC-1)/10, |
1269 | | get_wait_flag(FullPrio,conjoin,WF,LWF) %% |
1270 | | ; % in non-clpfd mode: much less propagation going on, avoid explosion of choice points |
1271 | | % tests 349, 362 fail with the following for CLPFD: TO DO investigate and use this also in CLPFD mode |
1272 | | get_binary_choice_wait_flag_exp_backoff(Prio,not_conjunct,WF,LWF) |
1273 | | ), |
1274 | | % print('SETUP conjoin_false: '), print(FullPrio), print(' '), print(NrC), print(' '), translate:print_bexpr(LHS),nl, % kernel_waitflags:portray_waitflags(WF), |
1275 | | conjoin_false(X,Y,LHS,RHS,LWF). |
1276 | | % missing rule: if X==Y -> X=pred_true |
1277 | | :- block conjoin_false(-,-,?,?,-). |
1278 | | conjoin_false(X,Y,LHS,_RHS,_LWF) :- % print(conjoin_false(X,Y)),nl, translate:print_bexpr(LHS),nl,% |
1279 | ? | ( X==pred_true -> % print('TRUE: '), translate:print_bexpr(LHS),nl, |
1280 | | % print(' FORCING FALSE: '), translate:print_bexpr(_RHS),nl, |
1281 | | pred_false=Y |
1282 | ? | ; X==pred_false -> true % , print('FALSE: '), translate:print_bexpr(LHS),nl |
1283 | ? | ; Y==pred_true -> pred_false=X |
1284 | ? | ; Y==pred_false -> true %, print('FALSE: '), translate:print_bexpr(_RHS),nl |
1285 | ? | ; useless_to_force(LHS) -> |
1286 | | ( % print(forcing_conjoin_rhs_false(X,Y,_LWF)), translate:print_bexpr(_RHS), print(' == FALSE '),nl, |
1287 | | Y=pred_false |
1288 | | ; |
1289 | | (Y,X)=(pred_true,pred_false) |
1290 | | ) |
1291 | | ; ( % print(forcing_conjoin_lhs_false(X,Y,_LWF)), translate:print_bexpr(LHS), print(' == FALSE '),nl, |
1292 | ? | X=pred_false |
1293 | | ; % print(forcing_conjoin_rhs_false(X,Y,_LWF)), translate:print_bexpr(LHS), print(' == TRUE ; '), nl, |
1294 | | (X,Y)=(pred_true,pred_false) |
1295 | | ) |
1296 | | ). |
1297 | | |
1298 | | % determine when forcing a predicate to true/false does not really help; better choose something else |
1299 | | useless_to_force(b(B,T,I)) :- useless_to_force3(B,T,I). |
1300 | | useless_to_force3(finite(_),_,_). % forcing finite to be false usually not a good idea; we cannot propagate this |
1301 | | % what are other predicates useless to force: some foralls/exists ? some external_pred_call |
1302 | | % in principle a conjunction of useless predicates is also useless: but could be more expensive to check |
1303 | | |
1304 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:disjoin(pred_false,pred_false,pred_false,_,_,_WF))). |
1305 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],b_interpreter_check:disjoin(pred_false,pred_true,pred_true,_,_,_WF))). |
1306 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:disjoin(pred_true,pred_true,pred_true,_,_,_WF))). |
1307 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:disjoin(pred_true,pred_true,pred_false,_,_,_WF))). |
1308 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:disjoin(pred_true,pred_false,pred_false,_,_,_WF))). |
1309 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:disjoin(pred_false,pred_true,pred_false,_,_,_WF))). |
1310 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:disjoin(pred_false,pred_false,pred_true,_,_,_WF))). |
1311 | | |
1312 | | :- block disjoin(-,-,-,?,?,?). |
1313 | | disjoin(X,Y,Res,LHS,RHS,WF) :- %print(disjoin(X,Y,Res,WF)),nl, %% translate:print_bexpr(LHS),print(' or '),translate:print_bexpr(RHS),nl,%% |
1314 | ? | ( Res==pred_false -> X=pred_false,Y=pred_false |
1315 | | ; X==pred_true -> Res=pred_true |
1316 | | ; X==pred_false -> Res=Y |
1317 | | ; Y==pred_true -> Res=pred_true |
1318 | | ; Y==pred_false -> Res=X |
1319 | | ; Res==pred_true -> disjoin_true0(X,Y,LHS,RHS,WF) |
1320 | | ; add_error_fail(disjoin,'Illegal values: ',disjoin(X,Y,Res,LHS,RHS,WF)) |
1321 | | ). |
1322 | | disjoin_true0(X,Y,_LHS,_RHS,_WF) :- X==Y,!, |
1323 | | %print(disjoin_true_eqeq(X,Y)),nl, translate:print_bexpr(_LHS),nl, |
1324 | | X=pred_true. |
1325 | | %disjoin_true0(X,Y,LHS,_,WF) :- !, disjoin_true(X,Y,_). |
1326 | | disjoin_true0(X,Y,_LHS,_RHS,_WF) :- % X or not(X) -> always true |
1327 | | bool_negate_check(X,Y),!. |
1328 | | %,print(disjoin_true_neqeq(X,Y)),nl,translate:print_bexpr(_LHS),nl. |
1329 | | |
1330 | | disjoin_true0(X,Y,LHS,_RHS,WF) :- %% print('disjoin_true0 '), translate:print_bexpr(LHS), print(' OR '), translate:print_bexpr(_RHS),nl, %% |
1331 | | %%(preferences:preference(use_smt_mode,full) -> FullPrio=2.5 ; |
1332 | | % poses problem for test 1096: |
1333 | | % count_number_of_disjuncts(RHS,NrC), |
1334 | | %FullPrio is Prio+(NrC-1)/10, % print(disj_prio(Prio,NrC,RHS,FullPrio)),nl, |
1335 | | %print(prio(FullPrio,NrC)),nl, |
1336 | | %get_wait_flag(FullPrio,disjoin,WF,LWF), %% |
1337 | | get_priority_of_boolean_expression(LHS,StartPrio), |
1338 | | get_binary_choice_wait_flag_exp_backoff(StartPrio,disjunct,WF,LWF), |
1339 | | % TO DO: extract FD information from LHS and RHS and assert, e.g. x:1..2 or x:4..5 |
1340 | | disjoin_true(X,Y,LHS,LWF). |
1341 | | % missing rule: if X==Y -> X=pred_true ; if X==~Y -> no need to setup choice point |
1342 | | :- block disjoin_true(-,-,?,-). |
1343 | | disjoin_true(X,Y,LHS,_LWF) :- %% print(disjoin_true(X,Y,_LWF)),nl, %% |
1344 | ? | ( X==pred_true -> true |
1345 | ? | ; X==pred_false -> pred_true=Y |
1346 | ? | ; Y==pred_true -> true |
1347 | ? | ; Y==pred_false -> pred_true=X |
1348 | ? | ; useless_to_force(LHS) -> |
1349 | | ( %% print(forcing_disjoin_true(X,Y,_LWF)),nl, %% |
1350 | | Y=pred_true |
1351 | | ; |
1352 | | %%print(forcing_disjoin_false(X,Y,_LWF)),nl, |
1353 | | (Y,X) = (pred_false,pred_true) % these two unifications will happen atomically ! |
1354 | | ) |
1355 | | ; ( %% print(forcing_disjoin_true(X,Y,_LWF)),nl, %% |
1356 | ? | X=pred_true |
1357 | | ; |
1358 | | %%print(forcing_disjoin_false(X,Y,_LWF)),nl, |
1359 | ? | (X,Y) = (pred_false,pred_true) % these two unifications will happen atomically ! |
1360 | | ) |
1361 | | %add_error_fail(disjoin_true,'Illegal values: ',disjoin_true(X,Y)) |
1362 | | ). |
1363 | | |
1364 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:impl(pred_false,pred_false,pred_true))). |
1365 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:impl(pred_false,pred_true,pred_true))). |
1366 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:impl(pred_true,pred_false,pred_false))). |
1367 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:impl(pred_true,pred_true,pred_true))). |
1368 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:impl(pred_false,pred_false,pred_false))). |
1369 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:impl(pred_false,pred_true,pred_false))). |
1370 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:impl(pred_true,pred_false,pred_true))). |
1371 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:impl(pred_true,pred_true,pred_false))). |
1372 | | |
1373 | | impl(X,Y,Res) :- % print(impl(X,Y,Res)),nl, |
1374 | | (var(X),var(Y),var(Res) -> bool_equality(X,Y,EqXY) ; true /* impl4 will not block anyway */), |
1375 | | impl4(X,Y,EqXY,Res). |
1376 | | :- block impl4(-,-,-,-). |
1377 | | impl4(X,Y,EqXY,Res) :- |
1378 | | ( Res==pred_false -> X=pred_true,Y=pred_false |
1379 | | ; Res==pred_true -> imply_true(X,Y,EqXY) |
1380 | | ; X==pred_false -> Res=pred_true |
1381 | | ; X==pred_true -> Res=Y |
1382 | | ; Y==pred_true -> Res=pred_true |
1383 | | ; Y==pred_false -> negate(X,Res) |
1384 | | ; EqXY==pred_true -> Res=pred_true % X => X is always true |
1385 | | ; EqXY==pred_false -> Y=Res % not(Y) => Y is true iff Y is true |
1386 | | ; add_error_fail(impl,'Illegal values: ',impl(X,Y,EqXY,Res)) |
1387 | | ). |
1388 | | imply_true(X,Y) :- %print(imply_true(X,Y)),nl, |
1389 | | (var(X),var(Y) -> bool_equality(X,Y,EqXY) ; true /* imply_true will not block anyway */), |
1390 | | imply_true(X,Y,EqXY). |
1391 | | :- block imply_true(-,-,-). |
1392 | | imply_true(X,Y,EqXY) :- %print(imply_true(X,Y,EqXY)),nl, |
1393 | | ( X==pred_false -> true |
1394 | | ; X==pred_true -> Y=pred_true |
1395 | | ; Y==pred_true -> true |
1396 | | ; Y==pred_false -> X=pred_false |
1397 | | ; EqXY==pred_true -> true |
1398 | | ; EqXY==pred_false -> X=pred_false % X => not(X) ===> X=pred_false |
1399 | | ; add_error_fail(imply_true,'Illegal values: ',imply_true(X,Y,EqXY)) |
1400 | | ). |
1401 | | |
1402 | | |
1403 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:equiv(pred_false,pred_false,pred_true))). |
1404 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:equiv(pred_false,pred_true,pred_false))). |
1405 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:equiv(pred_true,pred_false,pred_false))). |
1406 | | :- assert_must_succeed(exhaustive_kernel_check(b_interpreter_check:equiv(pred_true,pred_true,pred_true))). |
1407 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:equiv(pred_false,pred_false,pred_false))). |
1408 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:equiv(pred_false,pred_true,pred_true))). |
1409 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:equiv(pred_true,pred_false,pred_true))). |
1410 | | :- assert_must_succeed(exhaustive_kernel_fail_check(b_interpreter_check:equiv(pred_true,pred_true,pred_false))). |
1411 | | |
1412 | | % b_interpreter_check:equiv(X,Y,Res),X=Y, Res==pred_true |
1413 | | equiv(X,Y,Res) :- %print(equiv(X,Y,Res)),nl, |
1414 | | bool_equality(X,Y,Res). |
1415 | | |
1416 | | |