1 % (c) 2009-2024 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
6 :- module(custom_explicit_sets,[is_set_value/2,
7 is_custom_explicit_set/1, is_custom_explicit_set/2, is_custom_explicit_set_nonvar/1,
8 %equal_explicit_sets/2,
9 equal_explicit_sets_wf/3,
10 not_equal_explicit_sets_wf/3,
11 equality_explicit_sets_wf/4, same_texpr_body/2, same_closure/2,
12 is_empty_explicit_set/1, is_empty_explicit_set_wf/2, is_empty_closure_wf/4,
13 is_non_empty_explicit_set/1, is_non_empty_explicit_set_wf/2,
14 is_non_empty_closure_wf/4,
15 test_empty_explicit_set_wf/3, test_empty_closure_wf/5,
16 is_definitely_maximal_set/1,
17 explicit_set_cardinality/2, explicit_set_cardinality_wf/3,
18 explicit_set_cardinality_for_wf/2,
19 card_for_specific_custom_set/3, % only succeeds if we can compute it efficiently
20 card_for_specific_closure/4,
21 efficient_card_for_set/3, % same, but also for lists
22 quick_custom_explicit_set_approximate_size/2,
23 avl_approximate_size/2, avl_approximate_size/3,
24 is_infinite_explicit_set/1, is_infinite_closure/3,
25 is_infinite_global_set/2, is_simple_infinite_set/1,
26 dont_expand_this_explicit_set/1, dont_expand_this_explicit_set/2,
27 dont_expand_symbolic_explicit_set/1,
28 definitely_expand_this_explicit_set/1,
29 is_infinite_or_very_large_explicit_set/1,
30 is_infinite_or_very_large_explicit_set/2,
31 is_cartesian_product_closure/3,
32 expand_custom_set/2, expand_custom_set_wf/4,
33 try_expand_custom_set/2, try_expand_custom_set_with_catch/3,
34 try_expand_custom_set_wf/4,
35 expand_custom_set_to_list/2, expand_custom_set_to_list/4,
36 expand_custom_set_to_list_wf/5,
37 expand_custom_set_to_list_no_dups_wf/5,
38 expand_custom_set_to_list_gg/4,
39 try_expand_custom_set_to_list/4,
40 expand_interval_closure_to_avl/3,
41 expand_custom_set_to_list_now/2,
42 expand_closure_to_avl_or_list/6,
43 expand_only_custom_closure_global/4, %try_expand_only_custom_closure_global/2,
44 expand_and_convert_to_avl_set/4,
45 ord_list_to_avlset_direct/3, sorted_ground_normalised_list_to_avlset/3,
46 try_expand_and_convert_to_avl/2, convert_to_avl/2,
47 should_be_converted_to_avl_from_lists/1, should_be_converted_to_avl/1,
48 try_expand_and_convert_to_avl_with_check/3,
49 try_expand_and_convert_to_avl_with_check/4,
50 try_expand_and_convert_to_avl_unless_large_wf/3,
51 %try_expand_and_convert_to_avl_unless_large_wf/3,
52 try_expand_and_convert_to_avl_if_smaller_than/3,
53 is_small_specific_custom_set/2,
54 quick_propagation_element_information/4,
55 element_of_custom_set/2, element_of_custom_set_wf/3,
56 element_of_closure/5,
57 check_element_of_function_closure/6,
58 not_element_of_custom_set_wf/3,
59 membership_custom_set/3, membership_custom_set_wf/4, membership_avl_set_wf/4,
60 quick_test_avl_membership/3,
61
62 is_efficient_custom_set/1,
63 remove_minimum_element_custom_set/3,
64
65 is_maximal_global_set/1, quick_is_definitely_maximal_set/1,
66 quick_definitely_maximal_set_avl/1,
67 is_one_element_custom_set/2, singleton_set/2,
68 is_one_element_avl/2,
69 construct_one_element_custom_set/2,
70 avl_is_interval/3,
71
72 %closure0_for_explicit_set/2,
73 closure1_for_explicit_set/2, closure1_for_explicit_set_from/3,
74 check_in_domain_of_avlset/2, check_unique_in_domain_of_avlset/2,
75 domain_of_explicit_set_wf/3, range_of_explicit_set_wf/3,
76 is_avl_partial_function/1, is_not_avl_partial_function/2,
77 is_avl_total_function_over_domain/2,
78 quick_definitely_maximal_total_function_avl/1,
79 is_avl_relation/1,
80 is_avl_relation_over_domain/3,
81 is_avl_relation_over_range/3,
82 is_not_avl_relation_over_domain_range/4, is_not_avl_relation_over_range/3,
83 is_avl_sequence/1,
84 get_avl_sequence/2,
85 is_injective_avl_relation/2,
86 invert_explicit_set/2, union_of_explicit_set/3,
87 union_generalized_explicit_set/3,
88 difference_of_explicit_set_wf/4,
89 intersection_of_explicit_set_wf/4, intersection_with_interval_closure/3,
90 disjoint_intervals_with_inf/4,
91 image_for_id_closure/3, image_for_explicit_set/4,
92 rel_composition_for_explicit_set/3,
93 element_can_be_added_or_removed_to_avl/1,
94 add_element_to_explicit_set_wf/4, remove_element_from_explicit_set/3,
95 delete_element_from_explicit_set/3,
96 at_most_one_match_possible/3,
97 apply_to_avl_set/5, try_apply_to_avl_set/3,
98 min_of_explicit_set_wf/3, max_of_explicit_set_wf/3,
99 sum_or_mul_of_explicit_set/3,
100 %sum_of_range_custom_explicit_set/2, mul_of_range_custom_explicit_set/2,
101 domain_restriction_explicit_set_wf/4,
102 range_restriction_explicit_set_wf/4,
103 domain_subtraction_explicit_set_wf/4,
104 range_subtraction_explicit_set_wf/4,
105 override_pair_explicit_set/4,
106 direct_product_explicit_set/3,
107 override_custom_explicit_set_wf/4,
108 symbolic_functionality_check_closure/2, symbolic_injectivity_check_closure/2,
109
110 subset_of_explicit_set/4, not_subset_of_explicit_set/4,
111 test_subset_of_explicit_set/5,
112
113 conc_custom_explicit_set/2,
114 prefix_of_custom_explicit_set/4, suffix_of_custom_explicit_set/4,
115 concat_custom_explicit_set/4, prepend_custom_explicit_set/3,
116 append_custom_explicit_set/4,
117 tail_sequence_custom_explicit_set/5,
118 last_sequence_explicit_set/2, %first_sequence_explicit_set/2,
119 front_sequence_custom_explicit_set/3,
120 reverse_custom_explicit_set/2,
121 size_of_custom_explicit_set/3,
122
123 get_first_avl_elements/4,
124 construct_avl_from_lists/2, construct_avl_from_lists_wf/3,
125 equal_avl_tree/2,
126 check_avl_in_interval/3, check_interval_in_custom_set/4,
127 check_avl_subset/2,
128 construct_closure/4, is_closure/4, % from closures
129 construct_member_closure/5, % from closures
130
131 construct_interval_closure/3,
132 is_interval_closure/3, % checks if we have a finite interval closure Low..Up (but bounds can be variables)
133 is_interval_closure/5,
134 is_interval_closure_or_integerset/3,
135 is_interval_with_integer_bounds/3, % checks that bounds are known
136
137 is_powerset_closure/3,
138
139 dom_range_for_specific_closure/5,
140 dom_for_specific_closure/4,
141 dom_for_lambda_closure/2,
142 portray_custom_explicit_set/1,
143 closure_occurs_check/4
144 ]).
145
146 :- meta_predicate call_card_for_relations(-,-,0).
147
148 :- use_module(error_manager).
149 :- use_module(self_check).
150 :- use_module(library(avl)).
151 :- use_module(kernel_waitflags).
152 :- use_module(kernel_tools).
153 :- use_module(delay).
154 :- use_module(tools).
155 :- use_module(avl_tools).
156 :- use_module(library(clpfd)).
157
158 :- use_module(module_information,[module_info/2]).
159 :- module_info(group,kernel).
160 :- module_info(description,'This module provides customised operations for the custom explicit set representations of ProB (closures, avl_sets and global_sets).').
161
162 :- use_module(tools_printing,[print_term_summary/1, print_error/1]).
163 :- use_module(preferences,[preference/2]).
164 :- use_module(kernel_objects,[equal_object/2, equal_object/3]).
165 :- use_module(kernel_freetypes,[enumerate_freetype_wf/4,freetype_cardinality/2,
166 is_infinite_freetype/1, is_empty_freetype/1,
167 is_non_empty_freetype/1, test_empty_freetype/2]).
168
169 :- use_module(clpfd_interface,[try_post_constraint/1, clpfd_reify_inlist/4]).
170 :- use_module(closures).
171 :- use_module(b_compiler).
172
173 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
174
175 /* These meta_predicate declarations do not seem to have the right effect;
176 the predicates below return code, they do not get passed code
177 :- meta_predicate card_for_specific_custom_set(*,*,0).
178 :- meta_predicate card_for_specific_closure(*,*,0).
179 :- meta_predicate is_a_relation(*,*,*,*,*,*,0).
180 :- meta_predicate subset_of_explicit_set(*,*,0,*).
181 :- meta_predicate not_subset_of_explicit_set(*,*,0,*).
182 */
183
184 construct_avl_from_lists(S,Res) :-
185 (convert_to_avl(S,CS) -> true ; print(convert_to_avl_failed(S,CS)),nl,CS=S),
186 Res = CS.
187
188 % version with WF to see call stack in case of virtual time-outs due to expansions
189 construct_avl_from_lists_wf(S,Res,WF) :-
190 (convert_to_avl_wf(S,CS,WF) -> true ; print(convert_to_avl_wf_failed(S,CS)),nl,CS=S),
191 Res = CS.
192
193 :- use_module(tools,[safe_sort/3]).
194 :- block normalised_list_to_avl_when_ground(-,?).
195 normalised_list_to_avl_when_ground(S,R) :- % call if you are not sure that S will be ground; e.g. after closure expansion
196 ground_value_check(S,GS),
197 blocking_normalised_list_to_avl(GS,S,R).
198 :- block blocking_normalised_list_to_avl(-,?,?).
199 blocking_normalised_list_to_avl(_,S,R) :- normalised_list_to_avl(S,R).
200
201 normalised_list_to_avl(S,R) :- safe_sort(normalised_list_to_avl,S,SS),
202 ord_list_to_avlset_direct(SS,AVL,normalised_list_to_avl),
203 equal_object(AVL,R). % due to co-routine, R can now be instantiated
204
205 %set_to_avl(List,R) :- empty_avl(A), add_to_avl(List,A,AR), R=avl_set(AR).
206 add_to_avl([],R,R).
207 add_to_avl([H|T],AVL,AVLOUT) :- avl_store(H,AVL,true,AVL1),
208 add_to_avl(T,AVL1,AVLOUT).
209
210
211 % get only the first x elements of an AVL tree
212 get_first_avl_elements(empty,_,R,all) :- !,R=[].
213 get_first_avl_elements(AVL,X,FirstXEls,CutOff) :-
214 avl_min(AVL,Min), get_first_els(X,Min,AVL,FirstXEls,CutOff).
215
216 get_first_els(X,_,_AVL,R,CutOff) :- X<1,!,R=[], CutOff=not_all.
217 get_first_els(X,Cur,AVL,[Cur|T],CutOff) :-
218 (avl_next(Cur,AVL,Nxt) -> X1 is X-1,get_first_els(X1,Nxt,AVL,T,CutOff)
219 ; T=[],CutOff=all).
220
221 %expand_and_try_convert_to_avl(C,R) :- is_closure(C,_,_,_), expand_custom_set(C,EC), expand_and_convert_to_avl
222 %expand_and_convert_to_avl(C,R) :- convert_to_avl(C,R).
223
224 /* convert all list data-values (with all-sub-values) into avl-form */
225 /* assumption: the value is ground when convert_to_avl is called */
226
227 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
228 :- if(environ(prob_safe_mode,true)).
229 convert_to_avl(X,R) :- \+ ground_value(X), !, add_error(convert_to_avl,'Non-ground argument: ',convert_to_avl(X,R)), R=X.
230 :- endif.
231 convert_to_avl(X,R) :- var(X), !, add_error(convert_to_avl,'Variable argument: ',convert_to_avl(X,R)), R=X.
232 ?convert_to_avl(Term,R) :- no_conversion_necessary(Term),!,
233 R=Term.
234 convert_to_avl(closure(P,T,B),R) :- !,
235 R=closure(P,T,B).
236 convert_to_avl(avl_set(A),R) :- !,(A==empty -> add_warning(convert_to_avl,'Emtpy avl_set'), R=[]
237 ; R=avl_set(A)).
238 convert_to_avl((A,B),(CA,CB)) :- !,convert_to_avl(A,CA), convert_to_avl(B,CB).
239 convert_to_avl(freetype(X),R) :- !, R=freetype(X).
240 convert_to_avl(freeval(ID,Case,Value),R) :- !, R=freeval(ID,Case,CValue),convert_to_avl(Value,CValue).
241 convert_to_avl(rec(Fields),R) :- !, convert_fields(Fields,CFields), R=rec(CFields).
242 convert_to_avl(global_set(GS),R) :- !, R=global_set(GS).
243 convert_to_avl([H|T],R) :- !, convert_cons_to_avl_inside_set_wf(H,T,R,no_wf_available).
244 %convert_to_avl(abort(X),_R) :- print(deprecetated_convert_to_avl(abort(X))),nl,!, fail.
245 convert_to_avl(X,R) :- add_internal_error('Unknown term: ',convert_to_avl(X,R)), R=X.
246
247 % pass WF for call stack in case of expansions TODO: complete
248 convert_to_avl_wf((A,B),(CA,CB),WF) :- !,convert_to_avl_wf(A,CA,WF), convert_to_avl_wf(B,CB,WF).
249 convert_to_avl_wf([H|T],R,WF) :- !, convert_cons_to_avl_inside_set_wf(H,T,R,WF).
250 convert_to_avl_wf(X,R,_) :- convert_to_avl(X,R).
251
252 convert_fields(Var,R) :- var(Var),!,
253 add_internal_error('Var arg: ',convert_fields(Var,R)),fail.
254 convert_fields([],[]).
255 convert_fields([field(FieldName,Value)|T],[field(FieldName,CValue)|CT]) :-
256 convert_to_avl_inside_set(Value,CValue),
257 convert_fields(T,CT).
258
259 l_convert_to_avl_wf(Var,_,WF) :- var(Var),!,
260 add_warning_wf(l_convert_to_avl_wf,'Cannot expand variable to avl: ',Var,unknown,WF),
261 fail.
262 l_convert_to_avl_wf([],[],_).
263 l_convert_to_avl_wf(avl_set(A),R,WF) :-
264 expand_custom_set_wf(avl_set(A),ES,l_convert_to_avl,WF),
265 l_convert_to_avl_wf(ES,R,WF).
266 l_convert_to_avl_wf(closure(P,T,B),R,WF) :-
267 expand_custom_set_wf(closure(P,T,B),ES,l_convert_to_avl,WF),
268 l_convert_to_avl_wf(ES,R,WF).
269 l_convert_to_avl_wf([H|T],[CH-true|CT],WF) :-
270 convert_to_avl_inside_set_wf(H,CH,WF), l_convert_to_avl_wf(T,CT,WF).
271
272 :- assert_must_succeed((X=(fd(1,'Name'),fd(2,'Name')),
273 custom_explicit_sets:convert_to_avl_inside_set(X,R), R==X)).
274
275 convert_to_avl_inside_set(Var,R) :- var(Var),!,
276 add_internal_error('Var arg: ',convert_to_avl_inside_set(Var,R)),fail.
277 :- if(environ(prob_safe_mode,true)).
278 convert_to_avl_inside_set(fd(A,T),R) :- var(A),!,
279 add_error(convert_to_avl,'Non-ground FD-Term: ',convert_to_avl_inside_set(fd(A,T),R)), R=fd(A,T).
280 convert_to_avl_inside_set(int(X),R) :- var(X),!,
281 add_error(convert_to_avl,'Non-ground integer: ',convert_to_avl_inside_set(int(X),R)), R=int(X).
282 convert_to_avl_inside_set(string(X),R) :- var(X),!,
283 add_error(convert_to_avl,'Non-ground string: ',convert_to_avl_inside_set(string(X),R)), R=string(X).
284 convert_to_avl_inside_set(term(X),R) :- (var(X) ; X=floating(F), var(F)), !,
285 add_error(convert_to_avl,'Non-ground term: ',convert_to_avl_inside_set(term(X),R)), R=term(X).
286 :- endif.
287 ?convert_to_avl_inside_set(Term,R) :- no_conversion_necessary(Term),!,R=Term.
288 convert_to_avl_inside_set(closure(P,T,B),R) :- !,
289 % inside a set, closures need to be expanded to check against other elements
290 expand_closure_to_avl_wf(P,T,B,R,no_wf_available).
291 %convert_to_avl_inside_set(closure_x(_P,_T,_B,E),R) :- !, convert_to_avl_inside_set(E,R).
292 convert_to_avl_inside_set(avl_set(A),R) :- !, normalise_avl_set(A,R). %AVL's inside other AVL's need to be normalised !
293 convert_to_avl_inside_set((A,B),(CA,CB)) :- !,convert_to_avl_inside_set(A,CA), convert_to_avl_inside_set(B,CB).
294 convert_to_avl_inside_set(freetype(X),R) :- !,
295 expand_custom_set(freetype(X),EC,check), convert_to_avl_inside_set(EC,R).
296 convert_to_avl_inside_set(freeval(ID,Case,Value),R) :- !,
297 R=freeval(ID,Case,CValue),convert_to_avl_inside_set(Value,CValue).
298 convert_to_avl_inside_set(rec(Fields),R) :- !, convert_fields(Fields,CFields), R=rec(CFields).
299 convert_to_avl_inside_set(global_set(GS),R) :- !,
300 % first check if GS infinite integer set: in this case do not expand; there can be no confusion with finite avl_sets
301 (is_infinite_global_set(GS,_) -> R = global_set(GS)
302 ; expand_only_custom_closure_global(global_set(GS),EC,check,no_wf_available), convert_to_avl_inside_set(EC,R)).
303 convert_to_avl_inside_set([H|T],R) :- !,convert_cons_to_avl_inside_set_wf(H,T,R,no_wf_available).
304 convert_to_avl_inside_set(X,R) :-
305 add_internal_error('Unknown or non-ground argument: ',convert_to_avl_inside_set(X,R)),
306 fail.
307
308 ?convert_to_avl_inside_set_wf(Term,R,_WF) :- no_conversion_necessary(Term),!,R=Term.
309 convert_to_avl_inside_set_wf(closure(P,T,B),R,WF) :- !,
310 expand_closure_to_avl_wf(P,T,B,R,WF). % inside a set, closures need to be expanded to check against other elements
311 convert_to_avl_inside_set_wf((A,B),(CA,CB),WF) :- !,
312 convert_to_avl_inside_set_wf(A,CA,WF), convert_to_avl_inside_set_wf(B,CB,WF).
313 convert_to_avl_inside_set_wf([H|T],R,WF) :- !,convert_cons_to_avl_inside_set_wf(H,T,R,WF).
314 convert_to_avl_inside_set_wf(V,CV,_WF) :- % use version without WF; TO DO: adapt fully
315 convert_to_avl_inside_set(V,CV).
316
317 % true when we have a simple value that does not need to be converted for use within an avl_set:
318 no_conversion_necessary([]).
319 no_conversion_necessary(pred_false). /* bool_false */
320 no_conversion_necessary(pred_true). /* bool_true */
321 no_conversion_necessary(fd(FD,_)) :- nonvar(FD).
322 no_conversion_necessary(int(I)) :- nonvar(I).
323 no_conversion_necessary(string(S)) :- nonvar(S).
324 ?no_conversion_necessary(term(T)) :- nonvar(T), no_conversion_nec_term(T).
325
326 no_conversion_nec_term(floating(T)) :- nonvar(T).
327 no_conversion_nec_term(T) :- atom(T).
328
329 normalise_avl_set(A,R) :- A=node(_,_,0,empty,empty), !,R=avl_set(A).
330 normalise_avl_set(A,R) :-
331 avl_to_list(A,L),
332 ord_list_to_avlset_direct(L,R,convert_to_avl_inside_set). %AVL's inside other AVL's need to be normalised !
333
334 convert_cons_to_avl_inside_set_wf(H,T,R,WF) :- T==[], !,
335 convert_to_avl_inside_set_wf(H,CH,WF),
336 R = avl_set(node(CH,true,0,empty,empty)).
337 convert_cons_to_avl_inside_set_wf(H,T,R,WF) :- l_convert_to_avl_wf([H|T],S,WF),
338 sort(S,SS),
339 ord_list_to_avlset_direct(SS,R,convert_to_avl_inside_set).
340
341
342
343
344 is_set_value(X,Origin) :- var(X), !,print(is_set_value(Origin)),nl,fail.
345 is_set_value([],_) :- !.
346 is_set_value([_|_],_) :- !.
347 is_set_value(X,_) :- is_custom_explicit_set(X).
348
349 is_custom_explicit_set(X,Origin) :- var(X), !,print(var_is_custom_explicit_set(Origin)),nl,fail.
350 is_custom_explicit_set(X,_) :- is_custom_explicit_set(X).
351
352 is_custom_explicit_set(X) :- var(X), !,print(var_is_custom_explicit_set),nl,fail.
353 is_custom_explicit_set(global_set(_)).
354 is_custom_explicit_set(freetype(_)).
355 %is_custom_explicit_set(integer_global_set(_)).
356 is_custom_explicit_set(avl_set(_)).
357 is_custom_explicit_set(closure(_Parameters,_PT,_Cond)).
358
359 % use if you know the argument to be nonvar
360 is_custom_explicit_set_nonvar(global_set(_)).
361 is_custom_explicit_set_nonvar(freetype(_)).
362 is_custom_explicit_set_nonvar(avl_set(_)).
363 is_custom_explicit_set_nonvar(closure(_Parameters,_PT,_Cond)).
364
365 %:- assert_must_succeed(( custom_explicit_sets:portray_custom_explicit_set(avl_set(empty)) )). % now generates error
366 :- use_module(translate,[translate_bvalue/2]).
367 portray_custom_explicit_set(S) :- translate_bvalue(S,A), format(A,[]),nl.
368
369 /* a predicate to check equality of two custom explicit sets */
370
371 %equal_explicit_sets(A,B) :- equal_explicit_sets_wf(A,B,no_wf_available).
372
373 %equal_explicit_sets(X,Y) :- print_term_summary(equal_explicit_sets(X,Y)),fail.
374 :- block equal_explicit_sets_wf(-,?,?), equal_explicit_sets_wf(?,-,?).
375 ?equal_explicit_sets_wf(A,B,WF) :- equal_explicit_sets4(A,B,allow_expansion,WF).
376
377 equal_explicit_sets4(global_set(X),global_set(Y),_,_WF) :- !,X=Y.
378 equal_explicit_sets4(global_set(B),avl_set(A),E,WF) :- !,equal_explicit_sets4(avl_set(A),global_set(B),E,WF).
379 equal_explicit_sets4(freetype(X),freetype(Y),_,_WF) :- !,X=Y.
380 equal_explicit_sets4(avl_set(A),avl_set(B),_,_WF) :- !,
381 equal_avl_tree(A,B). % alternatively, we could normalise avl_trees and only store normalised versions
382 equal_explicit_sets4(avl_set(A),I2,_,_WF) :-
383 is_interval_closure_or_integerset(I2,L2,U2),!, % also covers I2=global_set(...)
384 avl_equal_to_interval(A,L2,U2).
385 equal_explicit_sets4(avl_set(A),global_set(B),_,WF) :- \+ b_global_sets:b_integer_set(B), !, % integersets dealt with above
386 explicit_set_cardinality_wf(global_set(B),Card,WF),
387 Card \= inf, %as avl_set must be finite
388 explicit_set_cardinality_wf(avl_set(A),Card,WF). /* the sets must be identical as global_set contains all values */
389 equal_explicit_sets4(avl_set(A),CPB,_,WF) :-
390 is_cartesian_product_closure(CPB,B1,B2),!,
391 decompose_avl_set_into_cartesian_product_wf(A,A1,A2,WF),
392 kernel_objects:equal_object_wf(A1,B1,equal_explicit_sets4,WF),
393 kernel_objects:equal_object_wf(A2,B2,equal_explicit_sets4,WF).
394 ?equal_explicit_sets4(closure(P,T,B),avl_set(A),E,WF) :- !, equal_explicit_sets4(avl_set(A),closure(P,T,B),E,WF).
395 equal_explicit_sets4(I1,I2,_,_WF) :- is_interval_closure_or_integerset(I1,L1,U1),
396 is_interval_closure_or_integerset(I2,L2,U2), !,
397 L1=L2, U1=U2.
398 equal_explicit_sets4(CPA,CPB,_,WF) :-
399 ? is_cartesian_product_closure(CPA,A1,A2),
400 is_cartesian_product_closure(CPB,B1,B2),!,
401 equal_cartesian_product_wf(A1,A2,B1,B2,WF).
402 % what if both subset or relations or functions ... closure: TO DO: add support
403 equal_explicit_sets4(S1,S2,_,WF) :-
404 is_not_member_value_closure_or_integerset(S1,TYPE,MS1),
405 is_not_member_value_closure_or_integerset(S2,TYPE,MS2),
406 !,
407 kernel_objects:equal_object_wf(MS1,MS2,equal_explicit_sets4,WF).
408 equal_explicit_sets4(closure(P1,T1,B1),closure(P2,T2,B2),_,_WF) :-
409 same_closure_body(P1,T1,B1,P2,T2,B2),!.
410 %equal_explicit_sets4(X,Y) :- X==Y,!.
411 equal_explicit_sets4(Set1,Set2,allow_expansion,WF) :-
412 %kernel_objects:test_finite_set_wf(Set1,F1,WF), kernel_objects:test_finite_set_wf(Set2,F2,WF), equal_expansions(F1,F2,Set1,Set2)
413 card_for_specific_custom_set(Set1,Card1,Code1), % TO DO: do not throw info away if Set2 cannot be determined
414 card_for_specific_custom_set(Set2,Card2,Code2),
415 !,
416 ? call(Code1), call(Code2),
417 % TO DO: if one of the two sets is infinite, then it would be enough to know that the other is not infinite for failure without expansion
418 equal_expansions(Card1,Card2,Set1,Set2,WF).
419 equal_explicit_sets4(Set1,Set2,allow_expansion,WF) :- equal_expansions(0,0,Set1,Set2,WF).
420
421
422 :- use_module(btypechecker, [unify_types_strict/2]).
423 % detect e.g. when one closure has seq(Type) and the other one set(integer,Type)
424 same_types([],[]).
425 same_types([H1|T1],[H2|T2]) :- unify_types_strict(H1,H2), same_types(T1,T2).
426
427 :- block equal_expansions(-,?,?,?,?).
428 equal_expansions(F1,F2,Set1,Set2,WF) :- (number(F1);number(F2)),!,
429 % NOTE: sometimes we get inf for finite but very large sets
430 F1=F2, % unify; can propagate info back to closure; e.g. prj2(BOOL,NAT) = prj2(BOOL,0..n)
431 equal_expansions2(F1,F2,Set1,Set2,WF).
432 equal_expansions(F1,F2,Set1,Set2,WF) :-
433 equal_expansions2(F1,F2,Set1,Set2,WF).
434
435 :- block equal_expansions2(-,?,?,?,?), equal_expansions2(?,-,?,?,?).
436 %equal_expansions(0,0,avl_set(A),closure(P,T,B)) :- check_subset ?? in both directions ?
437 %equal_expansions2(inf,inf,Set1,Set2,WF) :- WF \= no_wf_available, !, % symbolic treatment
438 equal_expansions2(F,F,Set1,Set2,WF) :-
439 % only expand if both sets have same cardinality
440 % print_term_summary(equal_expansions3(F,Set1,Set2)),nl,
441 equal_expansions3(F,Set1,Set2,WF).
442
443 % TO DO: check if this brings something:
444 %equal_expansions3(avl_set(A),closure(P,T,B),_WF) :- !,
445 % expand_closure_to_avl_or_list(P,T,B,E2,check), % in case E2 is avl_set; we can use equal_avl_tree
446 % ((nonvar(E2),E2=avl_set(B2))
447 % -> print(eql_avl),nl, print_term_summary(equal_avl_tree(A,B2)),nl, equal_avl_tree(A,B2)
448 % ; print(eql_non_avl),nl,equal_object(avl_set(A),E2,equal_expansions3)
449 % ).
450 %:- use_module(library(lists),[perm2/4]).
451 %equal_expansions3(F,Set1,Set2,_WF) :- number(F), F>100, % test with: {{},{TRUE},{FALSE},{TRUE,FALSE}} = /*@symbolic */ {x|x<:BOOL} or
452 % {x|x<:POW(BOOL*BOOL) & (x={} or card(x)>0)} = /*@symbolic */ {x|x<:POW(BOOL*BOOL)} 26 sec -> 14 sec
453 % case does not seem to appear very often
454 % perm2(Set1,Set2,avl_set(_),Set),
455 % is_definitely_maximal_set(Set),
456 %Set2 is maximal and has the same cardinality as F, hence Set1 must be identical to Set2
457 % !,
458 % debug_println(9,equal_to_maximal_closure(F)).
459 equal_expansions3(F,Set1,Set2,WF) :-
460 ? get_identity_as_equivalence(F,Set1,Set2,EQUIV),
461 !,
462 b_test_boolean_expression(EQUIV,[],[],WF).
463 % Alternative could be, if difference were to be fully treated symbolically:
464 % difference_of_explicit_set_wf(Set1,Set2,R12,WF), difference_of_explicit_set_wf(Set2,Set1,R21,WF),
465 % kernel_objects:empty_set_wf(R12,WF), kernel_objects:empty_set_wf(R21,WF).
466 equal_expansions3(_,Set1,Set2,WF) :-
467 expand_custom_set_wf(Set1,E1,equal_expansions1,WF),
468 expand_custom_set_wf(Set2,E2,equal_expansions2,WF),
469 E1=E2. /* ensure that ordering and normalization is same for all representations ! */
470
471
472 get_identity_as_equivalence(F,Set1,Set2,EQUIV) :-
473 (F=inf %; is_infinite_explicit_set(Set1) ; is_infinite_explicit_set(Set2)
474 ; Set1 \= avl_set(_),Set2 \= avl_set(_), % if one of the two sets is an AVL Set: better compute the other set explicitly instead of using this symbolic treatment
475 ? (dont_expand_this_explicit_set(Set1,100000) ;
476 ? dont_expand_this_explicit_set(Set2,100000)
477 )
478 % avl_test check for test 1081; TO DO: instead of test try to expand set and if this leads to enum warning use symbolic check
479 ),
480 get_identity_as_equivalence_aux(Set1,Set2,EQUIV).
481 get_identity_as_equivalence_aux(Set1,Set2,EQUIV) :-
482 kernel_objects:infer_value_type(Set1,SType),
483 is_set_type(SType,Type),
484 % Construct: !x.(x:Set1 <=> x:Set2) ??
485 get_pos_infos_for_explicit_set(Set1,I1),
486 get_pos_infos_for_explicit_set(Set2,I2),
487 I12 = I1, % we could merge position_info; but two sets could be very far apart
488 TID = b(identifier('_equality_sets_'),Type,[]),
489 EQUIV = b(forall([TID],b(truth,pred,[used_ids([])]),
490 b(equivalence(
491 b(member(TID,b(value(Set1),SType,I1)),pred,I1),
492 b(member(TID,b(value(Set2),SType,I2)),pred,I2)
493 ) ,pred,I12)
494 ),pred,[used_ids([]),I12]).
495
496 :- use_module(bsyntaxtree, [get_texpr_pos/2]).
497 get_pos_infos_for_explicit_set(closure(_,_,Body),[Pos]) :- get_texpr_pos(Body,Pos),!.
498 get_pos_infos_for_explicit_set(_,[]).
499
500 :- use_module(kernel_equality,[eq_atomic/4, equality_objects/3,
501 equality_objects_wf_no_enum/4, equality_objects_with_type_wf/5]).
502 /* maybe rewrite equal_explicit_sets and not_... to use this to avoid maintaining multiple versions */
503 equality_explicit_sets_wf(global_set(X),global_set(Y),R,_WF) :- !, eq_atomic(X,Y,set,R).
504 equality_explicit_sets_wf(global_set(B),avl_set(A),R,WF) :- !,equality_explicit_sets_wf(avl_set(A),global_set(B),R,WF).
505 equality_explicit_sets_wf(freetype(X),freetype(Y),R,_) :- !, eq_atomic(X,Y,set,R).
506 equality_explicit_sets_wf(avl_set(A),avl_set(B),R,_) :- !,
507 (equal_avl_tree(A,B) -> R=pred_true ; R=pred_false). % alternatively, we could normalise avl_trees and only store normalised versions
508 equality_explicit_sets_wf(avl_set(A),I2,R,WF) :- is_interval_closure_or_integerset(I2,L2,U2),!, % also covers I2=global_set(...)
509 avl_equality_to_interval(A,L2,U2,R,WF).
510 equality_explicit_sets_wf(avl_set(A),global_set(B),R,WF) :- \+ b_global_sets:b_integer_set(B), !,
511 explicit_set_cardinality_wf(global_set(B),Card,WF),
512 (Card \= inf, %as avl_set must be finite
513 explicit_set_cardinality_wf(avl_set(A),Card,WF)
514 -> R=pred_true /* the sets must be identical as global_set contains all values */
515 ; R=pred_false).
516 equality_explicit_sets_wf(avl_set(A),CPB,R,WF) :-
517 is_cartesian_product_closure(CPB,B1,B2),!,
518 if(decompose_avl_set_into_cartesian_product_wf(A,A1,A2,WF), % should not produce pending co-routines
519 equality_cartesian_product_wf(A1,A2,B1,B2,R,WF),
520 R=pred_false % no cartesian product can be equal to this avl_set
521 ).
522 equality_explicit_sets_wf(closure(P,T,B),avl_set(A),R,WF) :- !,
523 equality_explicit_sets_wf(avl_set(A),closure(P,T,B),R,WF).
524 equality_explicit_sets_wf(I1,I2,R,WF) :- is_interval_closure_or_integerset(I1,L1,U1),
525 is_interval_closure_or_integerset(I2,L2,U2), !,
526 equality_objects_wf_no_enum((int(L1),int(U1)),(int(L2),int(U2)),R,WF).
527 equality_explicit_sets_wf(CPA,CPB,R,WF) :-
528 is_cartesian_product_closure(CPA,A1,A2), is_cartesian_product_closure(CPB,B1,B2),!,
529 equality_cartesian_product_wf(A1,A2,B1,B2,R,WF).
530 equality_explicit_sets_wf(S1,S2,R,WF) :-
531 is_not_member_value_closure_or_integerset(S1,TYPE,MS1),
532 is_not_member_value_closure_or_integerset(S2,TYPE,MS2),!,
533 equality_objects_with_type_wf(TYPE,MS1,MS2,R,WF).
534 equality_explicit_sets_wf(closure(P,T,B),closure(P,T,B2),R,_) :-
535 same_texpr_body(B,B2),!,R=pred_true.
536 % TO DO: add complement sets
537
538 /* Cartesian Product Comparison */
539 :- use_module(kernel_equality,[empty_cartesian_product_wf/4]).
540 % A1*A2 = B1*B2 <=> (((A1={} or A2={}) & (B1={} or B2={})) or (A1=B1 & A2=B2))
541 equal_cartesian_product_wf(A1,A2,B1,B2,WF) :-
542 equality_cartesian_product_wf(A1,A2,B1,B2,pred_true,WF).
543 not_equal_cartesian_product_wf(A1,A2,B1,B2,WF) :-
544 equality_cartesian_product_wf(A1,A2,B1,B2,pred_false,WF).
545
546 equality_cartesian_product_wf(A1,A2,B1,B2,R,_WF) :-
547 nonvar(A1), A1=closure(P,T,BdyA1),
548 nonvar(B1), B1=closure(P,T,BdyB1),
549 nonvar(A2), A2=closure(P2,T2,BdyA2),
550 nonvar(B2), B2=closure(P2,T2,BdyB2),
551 % they have the same names; probably we are comparing identical values (e.g., in bvisual2)
552 same_texpr_body(BdyA1,BdyB1),
553 % note: we cannot simply call equality of A2 and B2 as cartesian products can be empty, see test 2072
554 same_texpr_body(BdyA2,BdyB2),
555 !,
556 R=pred_true.
557 equality_cartesian_product_wf(A1,A2,B1,B2,R,WF) :-
558 empty_cartesian_product_wf(A1,A2,EmptyA,WF),
559 equality_cart_product2(EmptyA,A1,A2,B1,B2,R,WF).
560 :- block equality_cart_product2(-, ?,?,?,?,?,?).
561 equality_cart_product2(pred_true,_,_,B1,B2,R,WF) :- empty_cartesian_product_wf(B1,B2,R,WF).
562 equality_cart_product2(pred_false,A1,A2,B1,B2,R,WF) :- equality_objects_wf_no_enum((A1,A2),(B1,B2),R,WF).
563
564 /* COMPARING AVL-SET with INTERVAL */
565
566 % check if an avl tree is equal to an interval range
567 avl_equal_to_interval(_A,L2,U2) :-
568 infinite_interval(L2,U2),!,fail. % otherwise infinite & avl_set is finite
569 % we can now assume L2, U2 are numbers (but could not yet be instantiated)
570 avl_equal_to_interval(A,L2,U2) :-
571 avl_min(A,int(L2)), avl_max(A,int(U2)),
572 Card is 1+U2-L2,
573 explicit_set_cardinality(avl_set(A),Card). % sets are equal: same size + same lower & upper bound
574
575 avl_not_equal_to_interval(A,L2,U2,WF) :- avl_equality_to_interval(A,L2,U2,pred_false,WF).
576
577 avl_equality_to_interval(_A,L2,U2,R,_WF) :-
578 infinite_interval(L2,U2),!,R=pred_false. % interval infinite & avl_set is finite
579 % we can now assume L2, U2 are numbers (but could not yet be instantiated)
580 avl_equality_to_interval(A,L2,U2,R,WF) :-
581 avl_min(A,int(AL)), avl_max(A,int(AU)),
582 Card is 1+AU-AL,
583 explicit_set_cardinality_wf(avl_set(A),ACard,WF),
584 equality_objects_wf_no_enum((int(ACard),(int(AL),int(AU))),
585 (int(Card),(int(L2),int(U2))),R,WF).
586 % sets are equal if same size + same lower & upper bound
587
588 /* COMPARING TWO CLOSURES */
589
590 % a variation of equal_explicit_sets which tries not expand and just compares two closures
591
592 same_closure(I1,I2) :-
593 is_interval_closure_or_integerset(I1,L1,U1),
594 is_interval_closure_or_integerset(I2,L2,U2), !,
595 L1=L2, U1=U2.
596 same_closure(CPA,CPB) :-
597 is_cartesian_product_closure(CPA,A1,A2),
598 is_cartesian_product_closure(CPB,B1,B2),!,
599 equal_cartesian_product_wf(A1,A2,B1,B2,no_wf_available). % could be expensive
600 same_closure(S1,S2) :-
601 is_not_member_value_closure_or_integerset(S1,TYPE,MS1),
602 is_not_member_value_closure_or_integerset(S2,TYPE,MS2),
603 !,
604 kernel_objects:equal_object(MS1,MS2,same_closure). % could be expensive
605 same_closure(closure(P1,T1,B1),closure(P2,T2,B2)) :- same_closure_body_with_parameter_renaming(P1,T1,B1,P2,T2,B2).
606
607 same_closure_body(P,T1, B1, P,T2,B2) :-
608 same_types(T1,T2),
609 same_texpr_body(B1,B2).
610
611 % a version of same_closure_body which allows renaming of the parameters
612 same_closure_body_with_parameter_renaming(P1,T1, B1, P2,T2,B2) :-
613 same_types(T1,T2),
614 create_renaming(P1,P2,Renaming),
615 % TO DO: pass Renaming in AVL tree and rename on the fly
616 rename_bt(B2,Renaming,RenamedB2),
617 same_texpr_body(B1,RenamedB2).
618
619 create_renaming([],[],[]).
620 create_renaming([ID|T1],[ID|T2],TR) :- !, create_renaming(T1,T2,TR).
621 create_renaming([ID1|T1],[ID2|T2],[rename(ID2,ID1)|TR]) :-
622 create_renaming(T1,T2,TR).
623
624
625 % check if two wrapped expressions are equal (modulo associated Info, e.g. source loc info)
626 % and checking inserted values for equality (sometimes storing a closure will convert small inner closures into AVL sets)
627 same_texpr_body(E1,E2) :- empty_avl(E),same_texpr_body(E1,E,E2).
628 same_texpr_body(b(E1,Type1,_),AVL,b(E2,Type2,_)) :-
629 unify_types_strict(Type1,Type2), % check in principle redundant
630 same_texpr2(E1,AVL,E2).
631
632 :- use_module(bsyntaxtree,[safe_syntaxelement_det/5, is_set_type/2,get_texpr_ids/2,
633 get_texpr_expr/2, get_negated_operator_expr/2]).
634 same_texpr2(value(V1),AVL,RHS) :- !,same_texpr_value2(RHS,AVL,V1).
635 same_texpr2(LHS,AVL,value(V2)) :- !,same_texpr_value2(LHS,AVL,V2).
636 same_texpr2(lazy_let_expr(ID,LHS,RHS),AVL,lazy_let_expr(ID2,LHS2,RHS2)) :- !,
637 same_texpr_body(LHS,AVL,LHS2),
638 avl_store(ID,AVL,ID2,NewAVL),
639 same_texpr_body(RHS,NewAVL,RHS2).
640 same_texpr2(lazy_let_pred(ID,LHS,RHS),AVL,lazy_let_pred(ID2,LHS2,RHS2)) :- !,
641 same_texpr_body(LHS,AVL,LHS2),
642 avl_store(ID,AVL,ID2,NewAVL),
643 same_texpr_body(RHS,NewAVL,RHS2).
644 same_texpr2(lazy_lookup(ID1), AVL,lazy_lookup(ID2)) :- !, avl_fetch(ID1,AVL,ID2).
645 same_texpr2(E1,AVL,E2) :- % Should we only enable this for same_closure_body_with_parameter_renaming?
646 quantifier_construct(E1,Functor,TParas1,Body1),
647 quantifier_construct(E2,Functor,TParas2,Body2),
648 !,
649 same_quantified_expression(TParas1,Body1,AVL,TParas2,Body2).
650 same_texpr2(E1,AVL,E2) :-
651 functor(E1,F,Arity),
652 functor(E2,F,Arity),!,
653 safe_syntaxelement_det(E1,Subs1,_Names1,_List1,Constant1),
654 safe_syntaxelement_det(E2,Subs2,_Names2,_List2,Constant2),
655 Constant2==Constant1,
656 same_sub_expressions(Subs1,AVL,Subs2).
657 same_texpr2(E1,AVL,E2) :- same_texpr_with_rewrite(E1,AVL,E2),!.
658 same_texpr2(E1,AVL,E2) :- same_texpr_with_rewrite(E2,AVL,E1).
659 %same_texpr2(E1,_,E2) :-
660 % functor(E1,F1,Arity1),
661 % functor(E2,F2,Arity2), print(not_eq(F1,Arity1,F2,Arity2)),nl, print(E1),nl, print(E2),nl,nl,fail.
662 % some differences: assertion_expression/3 and function/2, ...
663
664 % some rewrite rules from ast_cleanup; but we cannot replicate all rules here
665 same_texpr_with_rewrite(negation(TE1),AVL,E2) :-
666 get_negated_operator_expr(b(E2,pred,[]),NegE2),!,
667 get_texpr_expr(TE1,E1),
668 same_texpr2(E1,AVL,NegE2).
669 same_texpr_with_rewrite(member(X1,b(value(Set1),_,_)),AVL,equal(X2,b(El2,_,_))) :-
670 singleton_set(Set1,El1), !,
671 % X : {El} <===> X = El ; required for JSON trace replay of test 1491
672 same_texpr_body(X1,X2),
673 same_texpr_value2(El2,AVL,El1).
674 same_texpr_with_rewrite(not_member(X1,b(value(Set1),_,_)),AVL,not_equal(X2,b(El2,_,_))) :-
675 singleton_set(Set1,El1), !,
676 % X /: {El} <===> X /= El ; required for JSON trace replay of test 1491
677 same_texpr_body(X1,X2),
678 same_texpr_value2(El2,AVL,El1).
679
680 % constructs with local quantified parameters:
681 quantifier_construct(comprehension_set(TParas,Body),comprehension_set,TParas,Body).
682 quantifier_construct(exists(TParas,Body),exists,TParas,Body).
683 quantifier_construct(forall(TParas,LHS,RHS),forall,TParas,Body) :-
684 Body = b(implication(LHS,RHS),pred,[]).
685 % TODO?: SIGMA, PI, UNION, INTER
686
687 :- use_module(bsyntaxtree,[split_names_and_types/3]).
688 same_quantified_expression(TParas1,Body1,AVL,TParas2,Body2) :-
689 split_names_and_types(TParas1,P1,T1),
690 split_names_and_types(TParas2,P2,T2),
691 same_types(T1,T2),
692 create_renaming(P1,P2,Renaming),
693 rename_bt(Body2,Renaming,RenamedB2), % TODO: store renaming in AVL and lookup on the fly
694 same_texpr_body(Body1,AVL,RenamedB2).
695
696 same_texpr_value2(E2,_,V2) :- var(V2),!,V2==E2.
697 same_texpr_value2(interval(Min,Max),_,avl_set(A)) :- !, % occurs in JSON trace replay for test 268
698 avl_equal_to_interval(A,Min,Max). % TODO: also compare the other way around above; only apply if Card not too large?
699 same_texpr_value2(value(V2),_,V1) :- !,
700 same_value_inside_closure(V1,V2).
701 %(same_value_inside_closure(V1,V2) -> true ; print(not_eq_vals(V1,V2)),nl,fail).
702 same_texpr_value2(comprehension_set(Paras,B2),AVL,closure(P,_,B1)) :- !,
703 get_texpr_ids(Paras,P),!,
704 same_texpr_body(B1,AVL,B2).
705 same_texpr_value2(cartesian_product(TB1,TB2),AVL,V1) :-
706 decompose_value_into_cartesian_product(V1,A1,A2), !,
707 %print(cart(A1,A2)),nl,
708 get_texpr_expr(TB1,B1),
709 same_texpr_value2(B1,AVL,A1),
710 get_texpr_expr(TB2,B2),
711 same_texpr_value2(B2,AVL,A2).
712 same_texpr_value2(StaticExpr,_,int(Nr)) :- number(Nr),
713 b_ast_cleanup:pre_compute_static_int_expression(StaticExpr,Nr),!.
714 % TO DO: maybe also check if both sides can be evaluated
715 % TO DO: move pre_compute_static_int_expression to another module
716 same_texpr_value2(E2,AVL,V1) :- rewrite_value(V1,E2,NewE1),!,
717 same_texpr2(NewE1,AVL,E2).
718 %same_texpr_value2(E1,_,E2) :-
719 % functor(E1,F1,Arity1),
720 % functor(E2,F2,Arity2), print(not_eq_val(F1,Arity1,F2,Arity2)),nl, fail,print(E1),nl, print(E2),nl,nl,fail.
721
722 decompose_value_into_cartesian_product(avl_set(A),A1,A2) :- !,
723 decompose_avl_set_into_cartesian_product_wf(A,A1,A2,no_wf_available).
724 decompose_value_into_cartesian_product(Closure,A1,A2) :- is_cartesian_product_closure(Closure,A1,A2).
725
726
727 % rewrite values back to AST nodes
728 rewrite_value(value(V),OtherVal,New) :- nonvar(V),
729 rewrite_value_aux(V,OtherVal,New).
730 %rewrite_value(function(Lambda,Argument),assertion_expression(_,_,_),assertion_expression(Cond,Msg,Expr)) :- b_ast_cleanup:rewrite_function_application(Lambda,Argument,[],assertion_expression(Cond,Msg,Expr)).
731 rewrite_value_aux(closure(P,T,B),_,Set) :-
732 is_member_closure(P,T,B,_,Set). % TO DO: ensure that ast_cleanup does not generate useless member closures ?
733 rewrite_value_aux(global_set(GS),_,AST) :-
734 rewrite_glob_set(GS,AST).
735 rewrite_value_aux(avl_set(A),interval(_,_),interval(TLow,TUp)) :-
736 avl_equal_to_interval(A,Low,Up),
737 TLow = b(integer(Low),integer,[]), TUp = b(integer(Up),integer,[]).
738 rewrite_value_aux(int(A),integer(_),integer(A)) :- number(A).
739 rewrite_value_aux(pred_true,_,boolean_true).
740 rewrite_value_aux(pred_false,_,boolean_false).
741 rewrite_value_aux(string(A),integer(_),string(A)) :- % value(string(A)) rewritten to AST node string(A)
742 atom(A).
743
744
745 rewrite_glob_set('REAL',real_set).
746 rewrite_glob_set('FLOAT',float_set).
747 rewrite_glob_set('STRING',string_set).
748 rewrite_glob_set(I,integer_set(I)) :-
749 kernel_objects:integer_global_set(I).
750
751 allow_expansion(avl_set(_),closure(P,T,B)) :-
752 is_small_specific_custom_set(closure(P,T,B),100).
753 allow_expansion(closure(P,T,B),avl_set(_)) :-
754 is_small_specific_custom_set(closure(P,T,B),100).
755
756 same_sub_expressions([],_,[]).
757 same_sub_expressions([H1|T1],AVL,[H2|T2]) :-
758 same_texpr_body(H1,AVL,H2),
759 same_sub_expressions(T1,AVL,T2).
760
761 same_value_inside_closure(V1,V2) :- var(V1),!, V1==V2.
762 same_value_inside_closure(_,V2) :- var(V2),!,fail.
763 same_value_inside_closure(rec(Fields1),rec(Fields2)) :- !,
764 % sets of records come in this form: struct(b(value(rec(FIELDS)),record(_),_))
765 same_fields_inside_closure(Fields1,Fields2).
766 same_value_inside_closure(V1,V2) :-
767 % we could attempt this only if the outer closure was large/infinite ??
768 is_custom_explicit_set(V1), is_custom_explicit_set(V2),
769 !,
770 (allow_expansion(V1,V2) -> EXP=allow_expansion ; EXP = no_expansion),
771 equal_explicit_sets4(V1,V2,EXP,no_wf_available). % usually only sets compiled differently inside closures
772 same_value_inside_closure([H1|T1],avl_set(A2)) :- !, % relevant for JSON trace replay for test 1263
773 try_convert_to_avl([H1|T1],V1), V1=avl_set(A1),
774 equal_avl_tree(A1,A2).
775 same_value_inside_closure(avl_set(A2),[H1|T1]) :- !,
776 try_convert_to_avl([H1|T1],V1), V1=avl_set(A1),
777 equal_avl_tree(A1,A2).
778 same_value_inside_closure(V1,V2) :- V1==V2.
779
780 same_fields_inside_closure(V1,V2) :- var(V1),!, V1==V2.
781 same_fields_inside_closure(_,V2) :- var(V2),!,fail.
782 same_fields_inside_closure([],[]).
783 same_fields_inside_closure([field(Name,V1)|T1],[field(Name,V2)|T2]) :-
784 same_value_inside_closure(V1,V2),
785 same_fields_inside_closure(T1,T2).
786
787 /*
788 same_texpr_body_debug(H1,H2) :-
789 (same_texpr_body(H1,H2) -> true
790 ; print('FAIL: '),nl,
791 translate:print_bexpr(H1),nl, translate:print_bexpr(H2),nl, print(H1),nl, print(H2),nl, fail). */
792
793 %test(Y2,Z2) :- empty_avl(X), avl_store(1,X,2,Y), avl_store(2,X,3,Z),
794 % avl_store(2,Y,3,Y2), avl_store(1,Z,2,Z2), equal_avl_tree(Y2,Z2).
795
796 %equal_avl_tree(A,B) :- avl_min(A,Min), avl_min(B,Min), cmp(Min,A,B).
797 %cmp(El,A,B) :-
798 % (avl_next(El,A,Nxt) -> (avl_next(El,B,Nxt), cmp(Nxt,A,B))
799 % ; \+ avl_next(El,B,Nxt) ).
800
801 % The following is faster than using avl_next
802 equal_avl_tree(A,B) :-
803 % statistics(walltime,[WT1,_]),if(equal_avl_tree2(A,B),true,(statistics(walltime,[_,W]),print(wall(W)),nl)).
804 %equal_avl_tree2(A,B) :-
805 avl_min(A,Min),
806 !,
807 avl_min(B,Min),
808 avl_max(A,Max), avl_max(B,Max),
809 % maybe also check avl_height +/- factor of 1.4405 (page 460, Knuth 3) ? but it seems this would trigger only extremely rarely
810 %avl_height(A,H1), avl_height(A,H2), log(check(Min,Max,H1,H2)),
811 avl_domain(A,L), avl_domain(B,L).
812 equal_avl_tree(empty,_) :- !, format(user_error,'*** Warning: empty AVL tree in equal_avl_tree~n',[]).
813 equal_avl_tree(A,B) :- add_internal_error('Illegal AVL tree: ',equal_avl_tree(A,B)),fail.
814
815 /* a predicate to check equality of two custom explicit sets */
816
817 % TO DO: deal with second set being a variable with kernel_cardinality_attr attribute
818 :- block not_equal_explicit_sets_wf(-,?,?), not_equal_explicit_sets_wf(?,-,?).
819 not_equal_explicit_sets_wf(global_set(X),global_set(Y),_) :- !,dif(X,Y).
820 not_equal_explicit_sets_wf(global_set(B),avl_set(A),WF) :- !,
821 \+ equal_explicit_sets4(avl_set(A),global_set(B),allow_expansion,WF).
822 not_equal_explicit_sets_wf(freetype(X),freetype(Y),_) :- !,dif(X,Y).
823 not_equal_explicit_sets_wf(avl_set(A),avl_set(B),_) :- !,
824 \+ equal_avl_tree(A,B).
825 %not_equal_explicit_sets_wf(X,Y,_) :- X==Y,!,fail.
826 not_equal_explicit_sets_wf(avl_set(A),I2,WF) :- is_interval_closure_or_integerset(I2,L2,U2),!, % also covers I2=global_set(...)
827 avl_not_equal_to_interval(A,L2,U2,WF).
828 not_equal_explicit_sets_wf(avl_set(A),global_set(B),WF) :- !,
829 \+ equal_explicit_sets4(avl_set(A),global_set(B),allow_expansion,WF).
830 not_equal_explicit_sets_wf(avl_set(A),CPB,WF) :-
831 is_cartesian_product_closure(CPB,B1,B2),!,
832 if(decompose_avl_set_into_cartesian_product_wf(A,A1,A2,WF), % should not produce pending co-routines, but better safe
833 kernel_objects:not_equal_object_wf((A1,A2),(B1,B2),WF),
834 true % no cartesian product can be equal to this avl_set
835 ).
836 not_equal_explicit_sets_wf(closure(P,T,B),avl_set(A),WF) :- !,
837 not_equal_explicit_sets_wf(avl_set(A),closure(P,T,B),WF).
838 not_equal_explicit_sets_wf(I1,I2,_) :- is_interval_closure_or_integerset(I1,L1,U1),
839 is_interval_closure_or_integerset(I2,L2,U2), !,
840 dif((L1,U1),(L2,U2)). % maybe we should call not_equal_objects on integers (not on inf values)?
841 not_equal_explicit_sets_wf(CPA,CPB,WF) :-
842 is_cartesian_product_closure(CPA,A1,A2), is_cartesian_product_closure(CPB,B1,B2),!,
843 not_equal_cartesian_product_wf(A1,A2,B1,B2,WF).
844 not_equal_explicit_sets_wf(S1,S2,WF) :-
845 is_not_member_value_closure_or_integerset(S1,TYPE,MS1),
846 is_not_member_value_closure_or_integerset(S2,TYPE,MS2),!,
847 kernel_objects:not_equal_object_wf(MS1,MS2,WF).
848 not_equal_explicit_sets_wf(closure(P,T,B),closure(P,T,B2),_) :-
849 same_texpr_body(B,B2),!,fail.
850 % TO DO: maybe support interval & avl_set comparison
851 not_equal_explicit_sets_wf(Set1,Set2,WF) :-
852 card_for_specific_custom_set(Set1,Card1,Code1), card_for_specific_custom_set(Set2,Card2,Code2),
853 call(Code1), call(Code2),!,
854 not_equal_expansions(Card1,Card2,Set1,Set2,WF).
855 not_equal_explicit_sets_wf(Set1,Set2,WF) :- not_equal_expansions(0,0,Set1,Set2,WF).
856
857
858 :- block not_equal_expansions(-,?,?,?,?), not_equal_expansions(?,-,?,?,?).
859 not_equal_expansions(F1,F2,_,_,_) :- F1 \= F2,!. % sets guaranteed to be different
860 not_equal_expansions(F,F,Set1,Set2,WF) :-
861 ? get_identity_as_equivalence(F,Set1,Set2,EQUIV),
862 !,
863 b_not_test_boolean_expression(EQUIV,[],[],WF).
864 not_equal_expansions(F,F,Set1,Set2,WF) :-
865 % only expand if both sets have same cardinality
866 expand_custom_set_wf(Set1,E1,not_equal_expansions1,WF),
867 expand_custom_set_wf(Set2,E2,not_equal_expansions2,WF),
868 dif(E1,E2). /* TO DO: ensure that ordering and normalization is same for all representations ! */
869
870
871
872
873 :- use_module(b_global_sets,[b_empty_global_set/1, b_non_empty_global_set/1, b_global_set_cardinality/2]).
874 is_empty_explicit_set_wf(closure(P,T,B),WF) :- !,
875 is_empty_closure_wf(P,T,B,WF).
876 is_empty_explicit_set_wf(S,_WF) :- is_empty_explicit_set(S).
877
878 % with WF we can delay computing Card; see test 1272 / card({x|x:1..10 & x*x<i}) = 0 & i>1
879 % TO DO: ideally we could just write this: is_empty_closure_wf(P,T,B,WF) :- closure_cardinality(P,T,B,0,WF). ; but empty_set / not_exists optimisation not triggered in closure_cardinality (yet); would avoid duplicate code
880 is_empty_closure_wf(P,T,B,WF) :-
881 is_lambda_value_domain_closure(P,T,B, DomainValue,_Expr),!,
882 kernel_objects:empty_set_wf(DomainValue,WF).
883 is_empty_closure_wf(P,T,B,WF) :- is_cartesian_product_closure_aux(P,T,B,A1,A2),!,
884 very_approximate_cardinality(A1,C1,WF),
885 very_approximate_cardinality(A2,C2,WF),
886 blocking_safe_mul(C1,C2,0).
887 is_empty_closure_wf(P,T,B,_WF) :-
888 card_for_specific_closure2(P,T,B,CC,Code),
889 !,
890 call(Code),CC=0.
891 is_empty_closure_wf(P,T,Body,WF) :-
892 WF \== no_wf_available, % only do this if we have a WF store; see comments for closure_cardinality ; code relevant for test 1272; card({x|x:1..10 & x*x<i}) = 0 & i>1
893 \+ ground_bexpr(Body), % otherwise better to use not_test_exists below (e.g., Bosch v6 Codespeed benchmark)
894 b_interpreter_check:reify_closure_with_small_cardinality(P,T,Body, WF, ReifiedList),
895 !,
896 domain(ReifiedList,0,1),
897 sum(ReifiedList,'#=',0).
898 is_empty_closure_wf(P,T,B,WF) :-
899 get_recursive_identifier_of_closure_body(B,TRID),!,
900 def_get_texpr_id(TRID,RID),
901 gen_typed_ids(P,T,TypedParas),
902 % now add Recursive ID's value to local state:
903 b_interpreter:b_not_test_exists(TypedParas,B,[used_ids([RID])],[bind(RID,closure(P,T,B))],[],no_compile,WF).
904 is_empty_closure_wf(P,T,B,WF) :- !, % try and check that not(#(P).(B)); i.e., there is no solution for the Body B; solves tests 1542, detecting that {x|x>100 & x mod 102 = 2} = {} is false
905 gen_typed_ids(P,T,TypedParas),
906 b_interpreter:b_not_test_exists(TypedParas,B,[used_ids([])],[],[],no_compile,WF). % used_ids are empty, as all variables already compiled into values
907
908 % very_approximate_cardinality: only required to return 0 for empty set, and number or inf for non-empty set, tested in 1893
909 :- block very_approximate_cardinality(-,?,?).
910 very_approximate_cardinality(avl_set(A),C,_) :- !, (A=empty -> print(empty_avl),nl,C=0 ; C=1).
911 very_approximate_cardinality([],C,_) :- !, C=0.
912 very_approximate_cardinality([_|_],C,_) :- !, C=1.
913 very_approximate_cardinality(Set,C,WF) :- kernel_objects:cardinality_as_int_wf(Set,int(C),WF).
914 % TO DO: maybe call is_empty_closure or similar for closures
915
916 gen_typed_ids([],[],R) :- !, R=[].
917 gen_typed_ids([ID|IT],[Type|TT],[b(identifier(ID),Type,[])|TTT]) :- !,
918 % TO DO: add Info field from outer set comprehension
919 gen_typed_ids(IT,TT,TTT).
920 gen_typed_ids(I,T,TI) :- add_internal_error('Call failed: ',gen_typed_ids(I,T,TI)),fail.
921
922 % version with WF can also deal with closures via exists !
923 is_empty_explicit_set(global_set(GS)) :- !, b_empty_global_set(GS).
924 is_empty_explicit_set(freetype(ID)) :- !, is_empty_freetype(ID).
925 is_empty_explicit_set(avl_set(A)) :- !,
926 (var(A) -> add_warning(is_empty_explicit_set,'Variable avl_set')
927 ; empty_avl(A), add_warning(is_empty_explicit_set,'Empty avl_set')
928 ).
929 is_empty_explicit_set(C) :- card_for_specific_closure(C,CC,Code),!,call(Code),CC=0.
930 is_empty_explicit_set(ES) :- expand_custom_set(ES,[],is_empty_explicit_set).
931
932
933 is_non_empty_explicit_set(CS) :- is_non_empty_explicit_set_wf(CS,no_wf_available).
934
935 is_non_empty_explicit_set_wf(global_set(GS),_WF) :- !, b_non_empty_global_set(GS).
936 is_non_empty_explicit_set_wf(freetype(ID),_WF) :- !, is_non_empty_freetype(ID).
937 is_non_empty_explicit_set_wf(avl_set(A),_WF) :- !,
938 (empty_avl(A) -> print('### Warning: empty avl_set (2)'),nl,fail
939 ; true).
940 is_non_empty_explicit_set_wf(closure(P,T,B),WF) :- !, is_non_empty_closure_wf(P,T,B,WF).
941 %is_non_empty_explicit_set_wf(ES,_WF) :- expand_custom_set(ES,[_|_],is_non_empty_explicit_set).
942
943
944 % TO DO: this code is a bit redundant with is_empty_closure_wf
945 is_non_empty_closure_wf(P,T,B,WF) :-
946 is_lambda_value_domain_closure(P,T,B, DomainValue,_Expr),!,
947 kernel_objects:not_empty_set_wf(DomainValue,WF).
948 is_non_empty_closure_wf(P,T,B,WF) :- is_cartesian_product_closure_aux(P,T,B,A1,A2),!,
949 very_approximate_cardinality(A1,C1,WF),
950 very_approximate_cardinality(A2,C2,WF),
951 blocking_safe_mul(C1,C2,CC),gt0(CC).
952 is_non_empty_closure_wf(P,T,B,_WF) :-
953 card_for_specific_closure2(P,T,B,CC,Code),!,call(Code),gt0(CC).
954 % TO DO: reify_closure_with_small_cardinality
955 is_non_empty_closure_wf(P,T,B,WF) :- WF \== no_wf_available,
956 ? get_recursive_identifier_of_closure_body(B,TRID),!,
957 def_get_texpr_id(TRID,RID),
958 gen_typed_ids(P,T,TypedParas),
959 % now add Recursive ID's value to local state:
960 b_interpreter:b_test_exists(TypedParas,B,[used_ids([RID])],[bind(RID,closure(P,T,B))],[],WF).
961 is_non_empty_closure_wf(P,T,B,WF) :- WF \== no_wf_available,
962 % otherwise enumeration of test_exists will behave strangely; leading to enumeration warnings,... [TO DO: ensure we always have a WF or fix this below ?]
963 % try and check that not(#(P).(B)); i.e., there is no solution for the Body B; solves tests 1542; test 1146 also triggers this code
964 (debug_mode(off) -> true ; print(non_empty_closure_test(P)),nl, translate:print_bexpr(B),nl),
965 gen_typed_ids(P,T,TypedParas),
966 !,
967 b_interpreter:b_test_exists(TypedParas,B,[used_ids([])],[],[],WF). % used_ids are empty, as all variables already compiled into values
968 % some rules for set_subtraction, ... closures ?? if left part infinite and right part finite it must be infinite
969 is_non_empty_closure_wf(P,T,B,WF) :-
970 expand_custom_set_wf(closure(P,T,B),[_|_],is_non_empty_closure_wf,WF).
971
972
973 % TO DO: expand cart / reify and use for pf_test
974 test_empty_closure_wf(P,T,B,Res,WF) :-
975 is_lambda_value_domain_closure(P,T,B, DomainValue,_Expr),!,
976 kernel_equality:empty_set_test_wf(DomainValue,Res,WF).
977 %test_empty_closure_wf(P,T,B,WF) :- is_cartesian_product_closure_aux(P,T,B,A1,A2),!,
978 test_empty_closure_wf(P,T,B,Res,_WF) :-
979 card_for_specific_closure2(P,T,B,CC,Code),!,call(Code),leq0(CC,Res).
980 test_empty_closure_wf(P,T,B,Res,WF) :-
981 \+ is_memoization_closure(P,T,B,_MemoID),
982 preferences:preference(use_closure_expansion_memoization,false),
983 !,
984 bexpr_variables(B,ClosureWaitVars),
985 % this does not perform a few optimisations of expand_normal closure:
986 % memoization, stored_memo_expansion, is_closure1_value_closure, is_lambda_closure
987 % print(test_empty_closure_wf),nl, translate:print_bexpr(B),nl,
988 when((ground(ClosureWaitVars) ; nonvar(Res)),
989 test_empty_closure_wf2(P,T,B,Res,WF)).
990 test_empty_closure_wf(P,T,B,Res,WF) :- % print(expand_test(P)),nl,
991 % was expand_custom_set_wf(closure(P,T,B),ExpES,test_empty_closure_wf,WF), in turn calls expand_closure_to_list
992 expand_normal_closure(P,T,B,ExpES,_CDone,check(test_empty_closure_wf),WF),
993 kernel_equality:empty_set_test_wf(ExpES,Res,WF).
994 % /*@symbolic */ {x|x:1..100000000 & x mod 22=1} = x & (x={} <=> B=TRUE)
995
996 test_empty_closure_wf2(P,T,B,Res,WF) :-
997 Res == pred_true,!,
998 is_empty_closure_wf(P,T,B,WF).
999 test_empty_closure_wf2(P,T,B,Res,WF) :- Res == pred_false,!,
1000 is_non_empty_closure_wf(P,T,B,WF).
1001 test_empty_closure_wf2(P,T,B,Res,WF) :-
1002 (is_empty_closure_now(P,T,B,WF) % we need to force expansion here to be able to use local cut ->
1003 % expand_normal_closure would now also expand the closure;
1004 -> Res=pred_true
1005 ; Res=pred_false).
1006
1007 % check if closure now; ground everything except WFE
1008 is_empty_closure_now(P,T,B,OuterWF) :-
1009 create_inner_wait_flags(OuterWF,is_empty_closure_now,WF),
1010 debug_opt_push_wait_flag_call_stack_info(WF,
1011 external_call('Check if empty set',[closure(P,T,B)],unknown),WF2),
1012 is_empty_closure_wf(P,T,B,WF2),
1013 ground_inner_wait_flags(WF2). % does not ground WFE in case WD errors are pending
1014
1015 :- block leq0(-,?).
1016 leq0(inf,Res) :- !, Res=pred_false.
1017 leq0(CC,Res) :- (CC>0 -> Res=pred_false ; Res=pred_true).
1018
1019 test_empty_explicit_set_wf(V,Res,_) :- var(V),!,
1020 add_internal_error('Illegal call: ',test_empty_explicit_set(V,Res,_)),fail.
1021 test_empty_explicit_set_wf(global_set(GS),Res,_WF) :- !,
1022 (b_empty_global_set(GS) -> Res=pred_true ; Res=pred_false).
1023 test_empty_explicit_set_wf(freetype(ID),Res,_WF) :- !, test_empty_freetype(ID,Res).
1024 test_empty_explicit_set_wf(avl_set(A),Res,_WF) :- !,
1025 (var(A) -> add_warning(test_empty_explicit_set_wf,'Variable avl_set'), Res=pred_true
1026 ; empty_avl(A), add_warning(test_empty_explicit_set_wf,'Empty avl_set'), Res = pred_true
1027 ; Res=pred_false).
1028 test_empty_explicit_set_wf(closure(P,T,B),Res,WF) :- !,
1029 test_empty_closure_wf(P,T,B,Res,WF).
1030 test_empty_explicit_set_wf(ES,Res,WF) :-
1031 expand_custom_set(ES,ExpES,test_empty_explicit_set),
1032 kernel_equality:empty_set_test_wf(ExpES,Res,WF).
1033
1034 :- block gt0(-).
1035 gt0(CC) :- (CC=inf -> true ; CC>0).
1036
1037 % a version to compute cardinality for
1038 explicit_set_cardinality_for_wf(closure(P,T,B),Card) :-
1039 (is_symbolic_closure_or_symbolic_mode(P,T,B) ; \+ ground_bexpr(B)),
1040 !,
1041 Card = inf. % assume card is infinite for WF computation; it may be finite!
1042 %explicit_set_cardinality_for_wf(avl_set(AVL),Size) :- !, quick_avl_approximate_size(AVL,Size).
1043 explicit_set_cardinality_for_wf(CS,Card) :- card_for_specific_custom_set(CS,Card,Code),!,
1044 on_enumeration_warning(call(Code),Card=inf). % see test 1519 for relevance
1045 explicit_set_cardinality_for_wf(_,inf). % assume card is infinite for WF computation; it may be finite!
1046 % TO DO: maybe never expand closures here !? -> closure_cardinality can expand closure !!!!!!
1047 %explicit_set_cardinality_for_wf(CS,Card) :-
1048 % on_enumeration_warning(
1049 % explicit_set_cardinality(CS,Card),
1050 % (debug_println(assuming_inf_card_for_wf), % see test 1519 for relevance
1051 % Card = inf)). % assume card is infinite for WF computation; it may be finite!
1052
1053 explicit_set_cardinality(CS,Card) :-
1054 % init_wait_flags(WF,[explicit_set_cardinality]), % there are a few checks for no_wf_available below
1055 explicit_set_cardinality_wf(CS,Card,no_wf_available).
1056 % ground_wait_flags(WF).
1057
1058 explicit_set_cardinality_wf(global_set(GS),Card,_) :- !,b_global_set_cardinality(GS,Card).
1059 explicit_set_cardinality_wf(freetype(GS),Card,_WF) :- !, freetype_cardinality(GS,Card).
1060 explicit_set_cardinality_wf(avl_set(S),Card,_WF) :- !,avl_size(S,Card).
1061 ?explicit_set_cardinality_wf(closure(P,T,B),Card,WF) :- closure_cardinality(P,T,B,Card,WF).
1062
1063 :- use_module(performance_messages).
1064 closure_cardinality(P,T,B,Card,WF) :-
1065 is_lambda_value_domain_closure(P,T,B, DomainValue,_Expr),!,
1066 kernel_objects:cardinality_as_int_wf(DomainValue,int(Card),WF). % always compute it; card_for_specific_closure will only compute it if it can be done efficiently
1067 closure_cardinality(P,T,B,Card,WF) :- is_cartesian_product_closure_aux(P,T,B,A1,A2),!,
1068 kernel_objects:cardinality_as_int_wf(A1,int(C1),WF),
1069 kernel_objects:cardinality_as_int_wf(A2,int(C2),WF),
1070 blocking_safe_mul(C1,C2,Card).
1071 % TO DO: card_for_specific_closure2 calls is_lambda_value_domain_closure and is_cartesian_product_closure_aux again !
1072 closure_cardinality(P,T,B,Card,_WF) :-
1073 card_for_specific_closure2(P,T,B,CC,Code),
1074 !,
1075 call(Code),Card=CC.
1076 closure_cardinality(P,T,Body,Card,WF) :-
1077 (WF == no_wf_available -> CBody=Body
1078 ? ; b_compiler:b_compile(Body,P,[],[],CBody)
1079 ),
1080 % reify will work better if we used b_compiler:compile so that more sets can be detected as small
1081 closure_cardinality2(P,T,CBody,Card,WF).
1082 closure_cardinality2(P,T,Body,Card,WF) :-
1083 WF \== no_wf_available, % only do this if we have a WF store
1084 ? if(b_interpreter_check:reify_closure_with_small_cardinality(P,T,Body, WF, ReifiedList),
1085 true,
1086 (perfmessagecall(reify,reification_of_closure_for_card_failed(P),translate:print_bexpr(Body),Body),fail)),
1087 !,
1088 domain(ReifiedList,0,1),
1089 sum(ReifiedList,'#=',Card),
1090 % in this case we know card to be finite ! TO DO: ensure that check_finite propagates Card variable
1091 debug_println(9,reified_cardinality_sum(ReifiedList,Card)). % fd_dom(Card,Dom),print(dom(Card,Dom)),nl.
1092 % should we add a special check if Card=0 ? usually Card not instantiated at this point !
1093 %closure_cardinality(P,T,B,Card,WF) :- Card==0, %is_symbolic_closure(P,T,B),
1094 % !, is_empty_closure_wf(P,T,B,WF).
1095 closure_cardinality2(P,T,B,Card,WF) :-
1096 % TO DO: bexpr_variables(ClosureBody,ClosureWaitVars) and wait until those are bound; if Card = 0 -> empty_set; we can try to reifiy again
1097 expand_custom_set_wf(closure(P,T,B),Expansion,closure_cardinality,WF),
1098 my_length(Expansion,0,Card).
1099
1100 :- block my_length(-,?,?).
1101 my_length([],A,A).
1102 my_length([_|T],A,R) :- A1 is A+1, my_length(T,A1,R).
1103
1104 % compute domain and range for specific relations;
1105 % not the closure is total over the domain and surjective over the range
1106 % WARNING: this should never enumerate on its own, it is often called with
1107 % a cut straight after it; if some enumeration happens then only first solution
1108 % will be pursued (e.g., cond_assign_eq_obj)
1109 dom_range_for_specific_closure([],[],[],function(bijection),_WF).
1110 dom_range_for_specific_closure(closure(P,T,Pred),Domain,Range,Functionality,WF) :-
1111 dom_range_for_specific_closure2(P,T,Pred, Domain,Range,Functionality,WF).
1112
1113 dom_range_for_specific_closure2(Par,Typ,Body, Domain,Range,Functionality,_WF) :-
1114 is_member_closure(Par,Typ,Body,TYPE,SET),
1115 dom_range_for_member_closure(SET,TYPE,Domain,Range,Functionality),!.
1116 dom_range_for_specific_closure2(Par,Typ,Body, DOMAIN,RANGE,Functionality,WF) :-
1117 is_cartesian_product_closure_aux(Par,Typ,Body,SET1,SET2),!,
1118 (singleton_set(SET2,_) % checks nonvar
1119 -> Functionality = function(total) % function if card(SET2)=1
1120 ; Functionality=relation),
1121 kernel_equality:empty_set_test_wf(SET1,EqRes1,WF),
1122 cond_assign_eq_obj_wf(EqRes1,RANGE,[],SET2,WF), % if SET1=[] then Range=[]
1123 kernel_equality:empty_set_test_wf(SET2,EqRes2,WF),
1124 cond_assign_eq_obj_wf(EqRes2,DOMAIN,[],SET1,WF). %if SET2=[] then Domain=[]
1125 dom_range_for_specific_closure2(Par,Typ,Body, DomainRange,DomainRange,function(bijection),_WF) :-
1126 is_id_closure_over(Par,Typ,Body,DomainRange,_).
1127
1128
1129 dom_range_for_member_closure(identity(b(value(SET1),ST1,_)),_SEQT,SET1,SET1,function(bijection)) :-
1130 is_set_type(ST1,_). /* _SEQT=id(T1) */
1131 % not sure if we need this: memoized functions are infinite usually and range can never be computed anyway
1132 %dom_range_for_member_closure(Expr,_,Domain,Range,Func) :-
1133 % expand_memoize_stored_function_reference(Expr,ExpandedValue),
1134 % dom_range_for_specific_closure(ExpandedValue,Domain,Range,Func,no_wf_available).
1135
1136 :- block cond_assign_eq_obj_wf(-,?,?,?,?).
1137 %cond_assign_eq_obj_wf(PTF,R,A,B,_) :- var(PTF), add_error(cond_assign_eq_obj,'block declaration bug warning: ',cond_assign_eq_obj(PTF,R,A,B)),fail. % comment in to detect if affected by block declaration bug
1138 cond_assign_eq_obj_wf(pred_true,Res,A,_,WF) :- equal_object_wf(Res,A,cond_assign_eq_obj_wf_1,WF).
1139 cond_assign_eq_obj_wf(pred_false,Res,_,B,WF) :- equal_object_wf(Res,B,cond_assign_eq_obj_wf_2,WF).
1140
1141 is_cartesian_product_closure(closure(Par,Typ,Body),SET1,SET2) :-
1142 ? is_cartesian_product_closure_aux(Par,Typ,Body,SET1,SET2).
1143 is_cartesian_product_closure_aux(Par,Types,b(truth,pred,Info),SET1,SET2) :- Par=[_,_|_],!,
1144 append(LPar,[RParID],Par), append(LTypes,[RType],Types),
1145 construct_closure_if_necessary(LPar,LTypes,b(truth,pred,Info),SET1),
1146 construct_closure_if_necessary([RParID],[RType],b(truth,pred,Info),SET2).
1147 is_cartesian_product_closure_aux(Par,Types,Body,SET1,SET2) :- Par=[_,_|_],!,
1148 append(LPar,[RParID],Par), append(LTypes,[RType],Types),!,
1149 split_conjunct(Body,[RParID], RConjL, LPar, LConjL),
1150 bsyntaxtree:conjunct_predicates(RConjL,RConj), bsyntaxtree:conjunct_predicates(LConjL,LConj),
1151 construct_closure_if_necessary(LPar,LTypes,LConj,SET1),
1152 construct_closure_if_necessary([RParID],[RType],RConj,SET2).
1153 is_cartesian_product_closure_aux(Par,Typ,Body,SET1,SET2) :-
1154 SET = cartesian_product(b(value(SET1),ST1,_), b(value(SET2),ST2,_)),
1155 is_member_closure(Par,Typ,Body,couple(T1m,T2m),SET),
1156 is_set_type(ST1,T1),unify_types_strict(T1,T1m),
1157 is_set_type(ST2,T2),unify_types_strict(T2,T2m),!.
1158 %is_cartesian_product_closure_aux([ID1,ID2],[T1,T2],FBody,SET1,SET2) :- % is this not redundant wrt split ??
1159 % % a closure of the form {ID1,ID2|ID1 : SET1 & ID2 : SET2} ;
1160 % % can get generated when computing domain symbolically of lambda abstraction
1161 % FBody = b(Body,pred,_),
1162 % is_cartesian_product_body(Body,ID1,ID2,T1,T2,SET1,SET2). % ,print(cart_res(SET1,SET2)),nl.
1163
1164 % try and split conjunct into two disjoint parts (for detecting cartesian products)
1165 % on the specified variables
1166 % fails if it cannot be done
1167 split_conjunct(b(PRED,pred,Info),Vars1,C1,Vars2,C2) :-
1168 split_conjunct_aux(PRED,Info,Vars1,C1,Vars2,C2).
1169 split_conjunct_aux(truth,_Info,_Vars1,C1,_Vars2,C2) :- !,C1=[],C2=[].
1170 split_conjunct_aux(conjunct(A,B),_Info,Vars1,C1,Vars2,C2) :- !, % TO DO: use DCG
1171 split_conjunct(B,Vars1,CB1,Vars2,CB2), !, % Note: conjunct_predicates will create inner conjunct in A and atomic Expression in B
1172 split_conjunct(A,Vars1,CA1,Vars2,CA2),!,
1173 append(CA1,CB1,C1), append(CA2,CB2,C2).
1174 split_conjunct_aux(E,Info,Vars1,C1,_Vars2,C2) :- unique_id_comparison(E,ID),!,
1175 (member(ID,Vars1) -> C1=[b(E,pred,Info)], C2=[] ; C1=[], C2=[b(E,pred,Info)]).
1176
1177 unique_id_comparison(less(b(L,_,_),b(R,_,_)), ID) :- unique_id_comparison_aux(L,R,ID).
1178 unique_id_comparison(less_equal(b(L,_,_),b(R,_,_)), ID) :- unique_id_comparison_aux(L,R,ID).
1179 unique_id_comparison(greater(b(L,_,_),b(R,_,_)), ID) :- unique_id_comparison_aux(L,R,ID).
1180 unique_id_comparison(greater_equal(b(L,_,_),b(R,_,_)), ID) :- unique_id_comparison_aux(L,R,ID).
1181 unique_id_comparison(member(b(identifier(ID),_,_),b(V,_,_)), ID) :- explicit_value(V).
1182 unique_id_comparison(subset(b(identifier(ID),_,_),b(V,_,_)), ID) :- explicit_value(V).
1183 unique_id_comparison(equal(b(L,_,_),b(R,_,_)), ID) :- unique_id_comparison_aux(L,R,ID). % means we also detect something like %x.(x : INTEGER|0) as cartesian product
1184 % what about not_equal
1185
1186 unique_id_comparison_aux(identifier(ID),V,ID) :- !,explicit_value(V).
1187 unique_id_comparison_aux(V,identifier(ID),ID) :- explicit_value(V).
1188
1189 explicit_value(value(_)) :- !.
1190 explicit_value(integer(_)) :- !.
1191 explicit_value(unary_minus(TV)) :- !, explicit_tvalue(TV).
1192 explicit_value(interval(TV1,TV2)) :- !,
1193 explicit_tvalue(TV1), explicit_tvalue(TV2).
1194 %explicit_value(seq(B)) :- !, explicit_tvalue(B). % are encoded as values by b_compile
1195 %explicit_value(seq1(B)) :- !, explicit_tvalue(B).
1196 %explicit_value(iseq(B)) :- !, explicit_tvalue(B).
1197 %explicit_value(iseq1(B)) :- !, explicit_tvalue(B).
1198 %explicit_value(struct(B)) :- !, explicit_tvalue(B).
1199 %explicit_value(rec(Fields)) :- !, explicit_tfields(Fields).
1200 explicit_value(total_bijection(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B). % see test 1897 for cases below
1201 explicit_value(total_injection(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1202 explicit_value(total_function(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1203 explicit_value(total_surjection(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1204 explicit_value(partial_function(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1205 explicit_value(partial_injection(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1206 explicit_value(partial_surjection(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1207 explicit_value(relations(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1208 explicit_value(total_relation(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1209 explicit_value(surjection_relation(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1210 explicit_value(total_surjection_relation(A,B)) :- !, explicit_tvalue(A),explicit_tvalue(B).
1211 explicit_value(real_set) :- !.
1212 explicit_value(string_set) :- !.
1213
1214 explicit_tvalue(b(B,_,_)) :- !, explicit_value(B).
1215
1216 %explicit_tfields(V) :- var(V),!,fail.
1217 %explicit_tfields([]).
1218 %explicit_tfields([field(N,V)|T]) :- ground(N),explicit_tvalue(V),explicit_tfields(T).
1219
1220 % conjunct_predicates([CA1,CB1],C1),
1221 % conjunct_predicates([CA2,CB2],C2).
1222
1223 /* *********
1224 is_cartesian_product_body(conjunct(A,B),ID1,ID2,_T1,_T2,SET1,SET2) :- !,
1225 member_pred_value(A,CID1,CSET1),
1226 member_pred_value(B,CID2,CSET2),
1227 (ID1=CID1,ID2=CID2,SET1=CSET1,SET2=CSET2 ; ID1=CID2,ID2=CID1,SET1=CSET2,SET2=CSET1).
1228 is_cartesian_product_body(A,ID1,ID2,T1,T2,SET1,SET2) :-
1229 member_pred_value2(A,AID,ASET),
1230 ( AID=ID1 -> SET1=ASET, construct_closure_if_necessary([ID2],[T2],b(truth,pred,[]),SET2)
1231 ; AID=ID2 -> SET2=ASET, construct_closure_if_necessary([ID1],[T1],b(truth,pred,[]),SET1)).
1232
1233 member_pred_value(b(B,pred,_), ID,VAL) :- print(member_pred_value2(B,ID,VAL)),nl,
1234 member_pred_value2(B,ID,VAL).
1235 member_pred_value2(member(b(identifier(ID),_CT1,_),b(value(VAL),_SCT1,_)), ID,VAL). %_SCT1 = set(CT1)
1236 */
1237
1238 % check if we have POW(SET1) or SET1<->SET2 (equiv. to POW(SET1*SET2))
1239 is_full_powerset_or_relations_or_struct_closure(closure(Par,Typ,Body),SUBSETS) :-
1240 %TYPE = set(T),
1241 is_member_closure(Par,Typ,Body,TYPE,SET),
1242 is_full_powset_aux(SET,TYPE,SUBSETS).
1243
1244 :- use_module(library(lists),[maplist/3, maplist/4]).
1245 is_full_powset_aux(pow_subset(b(value(SET1),set(T1),_)),set(T1),[SET1]).
1246 is_full_powset_aux(relations(S1,S2),set(couple(T1,T2)),[SET1,SET2]) :-
1247 S1 = b(value(SET1),set(T1),_), S2 = b(value(SET2),set(T2),_).
1248 is_full_powset_aux(struct(b(value(rec(FIELDS)),record(_),_)),record(_),FieldValueSets) :-
1249 maplist(get_field_val,FIELDS,FieldValueSets).
1250
1251 get_field_val(field(_,Val),Val).
1252
1253 %[field(duration,global_set('INTEGER')),field(rhythm,global_set('INTEGER')),field(slot,avl_set(...))]
1254
1255 is_powerset_closure(closure(Par,Typ,Body),PType,Subset) :-
1256 ? is_set_type(TYPE,T),
1257 is_member_closure(Par,Typ,Body,TYPE,SET),
1258 nonvar(SET),
1259 is_powset_aux(SET,PType,b(VS,set(T),_)) ,
1260 nonvar(VS), VS = value(Subset). %,print(powerset(Subset)),nl.
1261 is_powset_aux(pow_subset(A),pow,A).
1262 is_powset_aux(pow1_subset(A),pow1,A).
1263 is_powset_aux(fin_subset(A),fin,A).
1264 is_powset_aux(fin1_subset(A),fin1,A).
1265
1266 % group together closures which can be treated like cartesian products in the sense that:
1267 % Closure is empty if either Set1 or Set2 (could also be empty in other conditions though)
1268 % Closure is subset of other Closure if same Constructor and both sets are subsets
1269 /* is_cartesian_product_like_closure(Closure,Constructor,Set1,Set2) :-
1270 is_cartesian_product_closure(Closure,S11,S12),!,
1271 Constructor = cartesian_product,Set1=S11,Set2=S12.
1272 is_cartesian_product_like_closure(closure(Par,Typ,Body),Constructor,Set1,Set2) :-
1273 is_member_closure(Par,Typ,Body,TYPE,SET),
1274 is_cart_like_relation(SET,Constructor,b(value(Set1),set(_T1),_), b(value(Set1),set(_T2),_)).
1275 is_cart_like_relation(relations(A,B),relations,A,B).
1276 is_cart_like_relation(partial_function(A,B),partial_function,A,B).
1277 is_cart_like_relation(partial_injection(A,B),partial_injection,A,B). */
1278
1279 % (closure([_zzzz_unary],[set(couple(integer,string))],b(member(b(identifier(_zzzz_unary),set(couple(integer,string)),[]),b(relations(b(value(global_set(INTEGER)),set(integer),[]),b(value(global_set(STRING)),set(string),[])),set(set(couple(integer,string))),[])),pred,[])))
1280 % 1 1 Fail: custom_explicit_sets:is_powset_aux(relations(b(value(global_set('INTEGER')),set(integer),[]),b(value(global_set('STRING')),set(string),[])),couple(integer,string),_19584) ?
1281
1282 % card_for_specific_custom_set(+Set,-Cardinality,-CodeToComputeCardinality)
1283 % succeeds if card can be computed efficiently
1284 card_for_specific_custom_set(CS,C,Cd) :- var(CS),!,
1285 add_internal_error('Internal error: var ',card_for_specific_custom_set(CS,C,Cd)),fail.
1286 card_for_specific_custom_set(global_set(GS),Card,true) :- !, b_global_set_cardinality(GS,Card).
1287 card_for_specific_custom_set(avl_set(S),Card,true) :- !,avl_size(S,Card).
1288 card_for_specific_custom_set(closure(P,T,B),Card,CodeToComputeCard) :-
1289 card_for_specific_closure3(_,P,T,B,Card,CodeToComputeCard).
1290
1291 card_for_specific_closure(closure(P,T,Pred),Card,CodeToComputeCard) :-
1292 card_for_specific_closure3(_ClosureKind,P,T,Pred,Card,CodeToComputeCard).
1293 card_for_specific_closure(closure(P,T,Pred),ClosureKind,Card,CodeToComputeCard) :-
1294 card_for_specific_closure3(ClosureKind,P,T,Pred,Card,CodeToComputeCard).
1295
1296 :- use_module(btypechecker,[couplise_list/2]).
1297 :- use_module(bsyntaxtree,[is_truth/1]).
1298 card_for_specific_closure2(Par,Typ,Body, Card,Code) :-
1299 card_for_specific_closure3(_ClosureKind,Par,Typ,Body, Card,Code).
1300
1301 % first argument for debugging purposes or filtering
1302 card_for_specific_closure3(special_closure,Par,Typ,Body, Card,Code) :-
1303 is_special_infinite_closure(Par,Typ,Body),!,Card=inf, Code=true.
1304 card_for_specific_closure3(truth_closure,_,Types,Body,Card,Code) :- is_truth(Body),!,
1305 % TO DO: also treat multiple parameters
1306 couplise_list(Types,Type),
1307 Code=kernel_objects:max_cardinality(Type,Card).
1308 card_for_specific_closure3(interval_closure,Par,Typ,Body, Card,Code) :-
1309 ? is_geq_leq_interval_closure(Par,Typ,Body,Low,Up), !,
1310 card_of_interval_inf(Low,Up,Card),
1311 Code=true. % should we return card_of_interval_inf as code ?
1312 % TO DO: deal with non-infinite not_member_closures, prj1, prj2, id, ...
1313 card_for_specific_closure3(lambda_closure,Par,Typ,Body, Card,Code) :-
1314 is_lambda_value_domain_closure(Par,Typ,Body, DomainValue,_Expr),!, nonvar(DomainValue),
1315 efficient_card_for_set(DomainValue,Card,Code).
1316 card_for_specific_closure3(cartesian_product,Par,Typ,Body, Card,Code) :-
1317 is_cartesian_product_closure_aux(Par,Typ,Body,A1,A2),!, nonvar(A1), nonvar(A2),
1318 efficient_card_for_set(A1,Card1,Code1),
1319 efficient_card_for_set(A2,Card2,Code2),
1320 Code = (Code1,Code2, custom_explicit_sets:blocking_safe_mul(Card1,Card2,Card)).
1321 card_for_specific_closure3(member_closure,Par,Typ,Body, Card,Code) :-
1322 is_member_closure(Par,Typ,Body,TYPE,SET),
1323 nonvar(SET),!,
1324 card_for_member_closure(SET,TYPE,Card,Code).
1325 % Note: _ExprInfo could have: contains_wd_condition,
1326 % but if lambda is well-defined we compute the correct card ; if not then card is not well-defined anyway
1327 % maybe we should check contains_wd_condition produce a warning msg ?
1328
1329 % inner values can sometimes be a list, e.g., [pred_true,pred_false] for BOOL
1330 efficient_card_for_set(VAR,_,_) :- var(VAR),!,fail.
1331 efficient_card_for_set([],Card,Code) :- !, Card=0,Code=true.
1332 efficient_card_for_set([_|T],Card,Code) :- known_length(T,1,C), !, Card = C, Code=true.
1333 efficient_card_for_set(CS,Card,Code) :- card_for_specific_custom_set(CS,Card,Code).
1334 known_length(X,_,_) :- var(X),!,fail.
1335 known_length([],A,A).
1336 known_length([_|T],A,R) :- A1 is A+1, known_length(T,A1,R).
1337 known_length(avl_set(S),Acc,Res) :- avl_size(S,Card),
1338 Res is Acc+Card.
1339 % TO DO: also support closures
1340
1341 card_for_member_closure(parallel_product(b(value(A1),ST1,_),b(value(A2),ST1,_)),_T,Card,CodeToComputeCard) :- !,
1342 nonvar(A1), nonvar(A2),
1343 efficient_card_for_set(A1,Card1,Code1),
1344 CodeToComputeCard = (Code1,Code2, custom_explicit_sets:blocking_safe_mul(Card1,Card2,Card)),
1345 % cardinality computed like for cartesian_product.
1346 efficient_card_for_set(A2,Card2,Code2).
1347 card_for_member_closure(seq(b(value(SET1),ST1,_)),_SEQT,Card,CodeToComputeCard) :- !, /* _SEQT=seq(T1) */
1348 is_set_type(ST1,_T1),
1349 CodeToComputeCard = custom_explicit_sets:seq_card(SET1,Card).
1350 card_for_member_closure(seq1(b(value(SET1),ST1,_)),_SEQT,Card,CodeToComputeCard) :- !, /* _SEQT=seq1(T1) */
1351 is_set_type(ST1,_T1),
1352 CodeToComputeCard = custom_explicit_sets:seq1_card(SET1,Card).
1353 card_for_member_closure(perm(b(value(SET1),ST1,_)),_SEQT,Card,CodeToComputeCard) :- !, /* _SEQT=perm(T1) */
1354 is_set_type(ST1,_T1),
1355 CodeToComputeCard = (kernel_objects:cardinality_as_int(SET1,int(SCard)),
1356 custom_explicit_sets:blocking_factorial(SCard,Card)).
1357 card_for_member_closure(iseq(b(value(SET1),ST1,_)),_SEQT,Card,CodeToComputeCard) :- !, /* _SEQT=iseq(T1) */
1358 is_set_type(ST1,_T1),
1359 CodeToComputeCard = (kernel_objects:cardinality_as_int(SET1,int(SCard)),
1360 custom_explicit_sets:blocking_nr_iseq(SCard,Card)).
1361 card_for_member_closure(iseq1(b(value(SET1),ST1,_)),_SEQT,Card,CodeToComputeCard) :- !, /* _SEQT=iseq1(T1) */
1362 is_set_type(ST1,_T1),
1363 CodeToComputeCard = (kernel_objects:cardinality_as_int(SET1,int(SCard)),
1364 custom_explicit_sets:blocking_nr_iseq1(SCard,Card)).
1365 card_for_member_closure(identity(b(value(SET1),ST1,_)),_SEQT,Card,CodeToComputeCard) :- !, /* _SEQT=id(T1) */
1366 is_set_type(ST1,_T1),
1367 CodeToComputeCard =
1368 kernel_objects:cardinality_as_int(SET1,int(Card)).
1369 card_for_member_closure(struct(b(RecVal,record(_FieldSetTypes),_)), record(_FieldTypes), % set of records
1370 Card,CodeToComputeCard) :-
1371 !,
1372 (RecVal=value(RECF), nonvar(RECF), RECF=rec(FIELDS) % value has been computed:
1373 -> CodeToComputeCard = custom_explicit_sets:get_field_cardinality(FIELDS,Card)
1374 ; RecVal = rec(TypedFields), % we still have a typed AST
1375 maplist(get_field_val_type,TypedFields,Exprs,Types),
1376 l_card_for_member_closure(Exprs,Types,Card, CodeToComputeCard)
1377 ).
1378 % now dealt with separately above: card_for_member_closure(cartesian_product(b(value(SET1),set(T1),_), b(value(SET2),set(T2),_)),
1379 % couple(T1,T2), Card,CodeToComputeCard) :- !,
1380 % CodeToComputeCard =
1381 % (kernel_objects:cardinality_as_int(SET1,int(SCard1)),
1382 % kernel_objects:cardinality_as_int(SET2,int(SCard2)),
1383 % custom_explicit_sets:blocking_safe_mul(SCard1,SCard2,Card) ).
1384 card_for_member_closure(POW,TYPE, Card,CodeToComputeCard) :-
1385 (POW = pow_subset(b(value(SET),TYPE,_)) ;
1386 POW = fin_subset(b(value(SET),TYPE,_))),!,
1387 CodeToComputeCard =
1388 (kernel_objects:cardinality_as_int(SET,int(SCard)),
1389 custom_explicit_sets:blocking_safe_pow2(SCard,Card)
1390 ).
1391 card_for_member_closure(POW,TYPE, Card,CodeToComputeCard) :-
1392 (POW = pow1_subset(b(value(SET),TYPE,_)) ;
1393 POW = fin1_subset(b(value(SET),TYPE,_))),!,
1394 CodeToComputeCard =
1395 (kernel_objects:cardinality_as_int(SET,int(SCard)),
1396 custom_explicit_sets:blocking_safe_pow2(SCard,C1),
1397 custom_explicit_sets:safe_dec(C1,Card)
1398 ).
1399 card_for_member_closure(RELEXPR,SType, Card,CodeToComputeCard) :-
1400 is_set_type(SType,couple(T1,T2)),
1401 is_a_relation(RELEXPR, b(value(DOM),set(T1),_),
1402 b(value(RAN),set(T2),_), DCard,RCard,Card,RELCODE),!,
1403 CodeToComputeCard =
1404 (
1405 kernel_objects:cardinality_as_int(DOM,int(DCard)),
1406 kernel_objects:cardinality_as_int(RAN,int(RCard)),
1407 custom_explicit_sets:call_card_for_relations(DCard,RCard,RELCODE)
1408 ).
1409 card_for_member_closure(BODY, integer, Card,CodeToComputeCard) :-
1410 is_interval_with_integer_bounds(BODY,Low,Up),!,
1411 CodeToComputeCard = custom_explicit_sets:card_of_interval_inf(Low,Up,Card).
1412 card_for_member_closure(value(Value), _Type, Card,CodeToComputeCard) :-
1413 % we have a closure of the type {x|x:S}; equivalent to S
1414 (nonvar(Value),
1415 Value=closure(P,T,B)
1416 -> % cardinality_as_int may expand it ! is bad if e.g. we called this code to check if a closure is infinite
1417 card_for_specific_closure2(P,T,B,Card,CodeToComputeCard) % will not expand, but fail if cannot be computed
1418 % TO DO: provide an argument: precise_or_efficient
1419 ; CodeToComputeCard = kernel_objects:cardinality_as_int(Value,int(Card))
1420 ).
1421 %card_for_member_closure(BODY, Type, Card,CodeToComputeCard) :- print(try_card(BODY,Type)),nl,fail.
1422 % TO DO: add maybe other common closures ? simple value closure
1423 % also: what if subexpressions are not of value() type ?
1424
1425 :- public call_card_for_relations/3.
1426 :- block call_card_for_relations(-,?,?), call_card_for_relations(?,-,?).
1427 call_card_for_relations(_,_,RELCODE) :- call(RELCODE).
1428
1429 get_field_val_type(field(_F1,b(Expr1,Type1,_)),Expr1,Type1).
1430
1431 l_card_for_member_closure([Expr1],[Type1],Card,CodeToComputeCard) :- !,
1432 card_for_member_closure(Expr1,Type1,Card, CodeToComputeCard).
1433 l_card_for_member_closure([Expr1|ET],[Type1|TT],Card,CodeToComputeCard) :-
1434 CodeToComputeCard = (Code1,Code2, custom_explicit_sets:blocking_safe_mul(Card1,Card2,Card)),
1435 card_for_member_closure(Expr1,Type1,Card1, Code1),
1436 l_card_for_member_closure(ET,TT,Card2,Code2).
1437
1438 :- public safe_dec/2. % used in card_for_member_closure
1439 :- block safe_dec(-,?).
1440 safe_dec(inf,R) :- !, R=inf.
1441 safe_dec(X,R) :- R is X-1.
1442
1443 :- use_module(kernel_equality,[empty_set_test/2]).
1444 :- public seq_card/2. % used in card_for_member_closure
1445 :- block seq_card(-,?).
1446 seq_card([],R) :- !,R=1.
1447 seq_card([_|_],R) :- !,R=inf.
1448 seq_card(X,Res) :- empty_set_test(X,EqRes),
1449 set_card(EqRes,1,Res).
1450
1451 :- block set_card(-,?,?).
1452 set_card(pred_true,Nr,Nr).
1453 set_card(pred_false,_,inf).
1454 % card(seq({n|n>10 & (n mod 20=3 & n mod 20 = 4) }))
1455
1456 :- public seq1_card/2. % used in card_for_member_closure
1457 :- block seq1_card(-,?).
1458 seq1_card([],R) :- !,R=0.
1459 seq1_card([_|_],R) :- !,R=inf.
1460 seq1_card(X,Res) :- empty_set_test(X,EqRes), set_card(EqRes,0,Res).
1461
1462 :- public get_field_cardinality/2. % used in card_for_member_closure
1463 get_field_cardinality([],1).
1464 get_field_cardinality([field(_Name,Value)|T],ResCard) :-
1465 kernel_objects:cardinality_as_int(Value,int(SCard1)),
1466 get_field_cardinality(T,RestCard), blocking_safe_mul(SCard1,RestCard,ResCard).
1467
1468 :- block blocking_safe_mul(-,-,?).
1469 blocking_safe_mul(A,B,R) :-
1470 ( A==0 -> R=0
1471 ; B==0 -> R=0
1472 ; A==1 -> R=B
1473 ; B==1 -> R=A
1474 ; blocking_safe_mul2(A,B,R) ).
1475
1476 :- block blocking_safe_mul2(-,?,?), blocking_safe_mul2(?,-,?).
1477 blocking_safe_mul2(A,B,Res) :-
1478 (safe_mul(A,B,AB) -> Res=AB
1479 ; add_warning(blocking_safe_mul2,'Call failed: ',blocking_safe_mul2(A,B,Res)),
1480 % could happen for something like prj2(BOOL,NAT) = prj2(BOOL,0..n)
1481 fail).
1482
1483 :- public blocking_safe_pow2/2. % used in card_for_member_closure above
1484 :- block blocking_safe_pow2(-,?).
1485 blocking_safe_pow2(A,Res) :-
1486 (safe_pow2(A,A2) -> Res=A2
1487 ; add_warning(blocking_safe_pow2,'Call failed: ',safe_pow2(A,Res)),fail).
1488
1489 :- assert_must_succeed((blocking_factorial(5,R),R==120)).
1490 :- assert_must_succeed((blocking_factorial(0,R),R==1)).
1491 :- assert_must_succeed((blocking_factorial(1,R),R==1)).
1492 :- assert_must_succeed((blocking_factorial(3,R),R==6)).
1493 :- assert_must_succeed((blocking_factorial(inf,R),R==inf)).
1494 :- block blocking_factorial(-,?).
1495 blocking_factorial(inf,R) :- !, R=inf.
1496 blocking_factorial(X,R) :- X<0,!, add_error(blocking_factorial,'Negative arg: ',blocking_factorial(X,R)),R=0.
1497 blocking_factorial(X,R) :- X>1000,!,
1498 % here we overapproximate: throw finite warning in Disprover mode ? or when checking for finite
1499 R=inf.
1500 % Note: blocking_safe_pow2(X,R) reports inf for X>1023; for X=171 blocking_factorial gives a result
1501 % which is greater than 2**1024 :
1502 % X=171,custom_explicit_sets:blocking_factorial(X,R),custom_explicit_sets:blocking_safe_pow2(1023,R2), R>2*R2.
1503 % debug:time(custom_explicit_sets:fact(10000,1,_)) --> 170 ms
1504 % debug:time(custom_explicit_sets:fact(1000,1,_)) --> 0 ms
1505 blocking_factorial(A,Res) :- fact(A,1,Res).
1506
1507 fact(0,Acc,Res) :- !,Res=Acc.
1508 fact(N,Acc,Res) :- (Acc=inf -> Res=inf
1509 ; safe_mul(N,Acc,NAcc), N1 is N-1, fact(N1,NAcc,Res)).
1510
1511
1512 :- assert_must_succeed((custom_explicit_sets:blocking_factorial_k(5,5,R),R==120)).
1513 :- assert_must_succeed((blocking_factorial_k(5,2,R),R==20)).
1514 :- assert_must_succeed((blocking_factorial_k(5,1,R),R==5)).
1515 :- assert_must_succeed((blocking_factorial_k(5,0,R),R==1)).
1516 :- assert_must_succeed((blocking_factorial_k(5,3,R),R==60)).
1517 :- assert_must_succeed((blocking_factorial_k(5,4,R),R==120)).
1518 :- assert_must_succeed((blocking_factorial_k(5,6,R),R==0)).
1519 :- assert_must_succeed((blocking_factorial_k(0,0,R),R==1)).
1520 :- assert_must_succeed((blocking_factorial_k(0,1,R),R==0)).
1521 :- assert_must_succeed((blocking_factorial_k(1,1,R),R==1)).
1522 :- assert_must_succeed((blocking_factorial_k(2,1,R),R==2)).
1523 :- assert_must_succeed((blocking_factorial_k(2,2,R),R==2)).
1524 :- assert_must_succeed((blocking_factorial_k(3,3,R),R==6)).
1525 :- assert_must_succeed((blocking_factorial_k(inf,1,R),R==inf)).
1526 :- assert_must_succeed((blocking_factorial_k(inf,0,R),R==1)).
1527 :- assert_must_succeed((blocking_factorial_k(inf,inf,R),R==inf)).
1528 :- assert_must_succeed((blocking_factorial_k(2,inf,R),R==0)).
1529 % blocking_factorial_k(N,K,Res) :: Res = N*(N-1)*...*(N-K+1)
1530 % Number of ways to choose sequences of K different objects amongst a pool of N objects
1531 :- block blocking_factorial_k(-,?,?),blocking_factorial_k(?,-,?).
1532 blocking_factorial_k(_X,0,R) :- !, R=1.
1533 blocking_factorial_k(inf,_,R) :- !, R=inf.
1534 blocking_factorial_k(_N,K,R) :- K=inf,!, R=0.
1535 blocking_factorial_k(N,K,R) :- K>N,!, R=0.
1536 blocking_factorial_k(A,K,Res) :- fact_k(A,K,1,Res).
1537
1538 fact_k(0,_,Acc,Res) :- !, Res=Acc.
1539 fact_k(_,K,Acc,Res) :- K<1,!,Res=Acc.
1540 fact_k(N,K,Acc,Res) :- (Acc=inf -> Res=inf
1541 ; safe_mul(N,Acc,NAcc), N1 is N-1, K1 is K-1, fact_k(N1,K1,NAcc,Res)).
1542
1543
1544 :- assert_must_succeed((choose_nk(3,3,R),R==1)).
1545 :- assert_must_succeed((choose_nk(3,2,R),R==3)).
1546 :- assert_must_succeed((choose_nk(3,1,R),R==3)).
1547 :- assert_must_succeed((choose_nk(3,0,R),R==1)).
1548 :- block choose_nk(-,?,?), choose_nk(?,-,?).
1549 choose_nk(N,K,Res) :- (K=0;K=N),!,Res=1.
1550 choose_nk(N,K,Res) :- K > N/2,!, KN is N-K, choose_nk2(N,KN,Res).
1551 choose_nk(N,K,Res) :- choose_nk2(N,K,Res).
1552 choose_nk2(N,K,Res) :- blocking_factorial_k(N,K,NK), blocking_factorial(K,KF),
1553 safe_div(NK,KF,Res).
1554
1555 :- assert_must_succeed((safe_div(inf,10,R),R==inf)).
1556 :- assert_must_succeed((safe_div(10,inf,R),R==0)).
1557 :- assert_must_succeed((safe_div(10,5,R),R==2)).
1558 :- assert_must_succeed((safe_div(10,6,R),R==1)).
1559 :- block safe_div(-,?,?), safe_div(?,-,?).
1560 safe_div(X,0,R) :- print(div_by_zero(X,0,R)),nl, !, R=inf.
1561 safe_div(inf,K,R) :-
1562 (number(K) -> true ; print(safe_div(inf,K,R)),nl), !, R=inf.
1563 safe_div(_N,inf,R) :- !, R=0.
1564 safe_div(X,Y,Z) :- Z is X//Y.
1565
1566 :- assert_must_succeed((safe_minus(506,501,R),R==5)).
1567 :- assert_must_succeed((safe_minus(inf,10,R),R==inf)).
1568 :- assert_must_succeed((safe_minus(10,inf,R),R==0)).
1569 :- block safe_minus(-,?,?), safe_minus(?,-,?).
1570 safe_minus(_,inf,R) :- !, print('### Warning: cannot compute X - inf'),nl, R=0.
1571 safe_minus(inf,_,R) :- !, R=inf.
1572 safe_minus(X,Y,R) :- R is X-Y.
1573
1574 :- assert_must_succeed((blocking_nr_iseq(2,R),R==5)).
1575 :- assert_must_succeed((blocking_nr_iseq(0,R),R==1)).
1576 :- assert_must_succeed((blocking_nr_iseq(1,R),R==2)).
1577 :- assert_must_succeed((blocking_nr_iseq(3,R),R==16)).
1578 :- assert_must_succeed((blocking_nr_iseq(inf,R),R==inf)).
1579 :- block blocking_nr_iseq(-,?).
1580 blocking_nr_iseq(inf,R) :- !, R=inf.
1581 blocking_nr_iseq(X,R) :- X<0,!, add_error(blocking_nr_iseq,'Negative arg: ',blocking_nr_iseq(X,R)),R=0.
1582 blocking_nr_iseq(X,R) :- X>500,!, R=inf.
1583 % Note: blocking_safe_pow2(X,R) reports inf for X>1023; for X=171 blocking_nr_iseq gives a result
1584 % which is greater than 2**1024 :
1585 % X=171,custom_explicit_sets:blocking_nr_iseq(X,R),custom_explicit_sets:blocking_safe_pow2(1023,R2), R>2*R2.
1586 % debug:time(custom_explicit_sets:nr_iseq(10000,_)) --> 250 ms
1587 % debug:time(custom_explicit_sets:nr_iseq(1000,_)) --> 10 ms
1588 % debug:time(custom_explicit_sets:nr_iseq(500,_)) --> 0 ms
1589 blocking_nr_iseq(A,Res) :- nr_iseq(A,Res). % , print(nr_iseq(A,Res)),nl.
1590 % number of injective sequences: f(N) = 1+N*(f(N-1))
1591 nr_iseq(0,Res) :- !,Res=1.
1592 nr_iseq(N,Res) :- N1 is N-1, nr_iseq(N1,N1Res),
1593 safe_mul(N,N1Res,NAcc), safe_add(NAcc,1,Res).
1594 :- public blocking_nr_iseq1/2. % used in card_for_member_closure above
1595 :- block blocking_nr_iseq1(-,?).
1596 blocking_nr_iseq1(inf,R) :- !, R=inf.
1597 blocking_nr_iseq1(A,Res1) :- blocking_nr_iseq(A,Res) , safe_add(Res,-1,Res1). %, print(nr_iseq1(A,Res1)),nl.
1598
1599 :- assert_must_succeed((custom_explicit_sets:card_for_specific_closure2(['_zzzz_binary'],[integer],
1600 b(member(b(identifier('_zzzz_binary'),integer,[generated]),
1601 b(interval(b(value(int(1)),integer,[]),b(value(int(10)),integer,[])),set(integer),[])),pred,[]),R,C),
1602 call(C),
1603 R=10)).
1604
1605 %! is_interval_closure_or_integerset(+I,-L,-U)
1606 is_interval_closure_or_integerset(Var,_,_) :- var(Var),!,fail.
1607 is_interval_closure_or_integerset(global_set(X),Low,Up) :- !, get_integer_set_interval(X,Low,Up).
1608 is_interval_closure_or_integerset(Set,El,El) :- singleton_set(Set,ELX),
1609 nonvar(ELX), ELX=int(El),!. % new, useful??
1610 is_interval_closure_or_integerset(closure(P,T,B),Low,Up) :-
1611 ? (is_geq_leq_interval_closure(P,T,B,Low,Up) -> true ; is_interval_closure(P,T,B,Low,Up)).
1612
1613
1614 get_integer_set_interval('NAT',0,MAXINT) :- (preferences:preference(maxint,MAXINT)->true).
1615 get_integer_set_interval('NAT1',1,MAXINT) :- (preferences:preference(maxint,MAXINT)->true).
1616 get_integer_set_interval('INT',MININT,MAXINT) :-
1617 ((preferences:preference(maxint,MAXINT),preferences:preference(minint,MININT))->true).
1618 get_integer_set_interval('NATURAL',0,inf).
1619 get_integer_set_interval('NATURAL1',1,inf).
1620 get_integer_set_interval('INTEGER',minus_inf,inf).
1621 % TO DO: add minus_inf to kernel_objects !
1622
1623 :- block geq_inf(-,?), geq_inf(?,-).
1624 geq_inf(inf,_) :- !.
1625 geq_inf(minus_inf,B) :- !, B=minus_inf.
1626 geq_inf(_,minus_inf) :- !.
1627 geq_inf(A,inf) :- !, A=inf.
1628 geq_inf(A,B) :- A >= B.
1629
1630 :- block minimum_with_inf(-,-,?).
1631 % in the first three cases we can determine outcome without knowing both args
1632 minimum_with_inf(A,B,R) :- (A==minus_inf ; B==minus_inf),!,R=minus_inf.
1633 minimum_with_inf(A,B,R) :- A==inf,!,R=B.
1634 minimum_with_inf(A,B,R) :- B==inf,!,R=A.
1635 minimum_with_inf(A,B,R) :- minimum_with_inf1(A,B,R), geq_inf(A,R), geq_inf(B,R).
1636 :- block minimum_with_inf1(-,?,?), minimum_with_inf1(?,-,?).
1637 minimum_with_inf1(minus_inf,_,R) :- !, R=minus_inf.
1638 minimum_with_inf1(_,minus_inf,R) :- !, R=minus_inf.
1639 minimum_with_inf1(inf,B,R) :- !, R=B.
1640 minimum_with_inf1(A,inf,R) :- !, R=A.
1641 minimum_with_inf1(A,B,R) :- (A<B -> R=A ; R=B).
1642
1643 :- block maximum_with_inf(-,-,?).
1644 % in the first three cases we can determine outcome without knowing both args
1645 maximum_with_inf(A,B,R) :- (A==inf ; B==inf),!,R=inf.
1646 maximum_with_inf(A,B,R) :- A==minus_inf,!,R=B.
1647 maximum_with_inf(A,B,R) :- B==minus_inf,!,R=A.
1648 maximum_with_inf(A,B,R) :- maximum_with_inf1(A,B,R), geq_inf(R,A), geq_inf(R,B).
1649 :- block maximum_with_inf1(-,?,?), maximum_with_inf1(?,-,?).
1650 maximum_with_inf1(inf,_,R) :- !, R=inf.
1651 maximum_with_inf1(_,inf,R) :- !, R=inf.
1652 maximum_with_inf1(minus_inf,B,R) :- !, R=B.
1653 maximum_with_inf1(A,minus_inf,R) :- !, R=A.
1654 maximum_with_inf1(A,B,R) :- (A>B -> R=A ; R=B).
1655
1656 /* utilities for detecting interval closures */
1657 construct_interval_closure(Low,Up,Res) :- (Low==inf;Up==minus_inf),!,Res=[].
1658 construct_interval_closure(Low,Up,Res) :- number(Low),number(Up), Low>Up,!,Res=[].
1659 construct_interval_closure(Low,Up,Res) :- Up==inf,!,
1660 ( Low==0 -> Res = global_set('NATURAL')
1661 ; Low==1 -> Res = global_set('NATURAL1')
1662 ; Low==minus_inf -> Res = global_set('INTEGER')
1663 ; Low==inf -> Res = []
1664 ; construct_greater_equal_closure(Low,Res)
1665 ).
1666 construct_interval_closure(Low,Up,Res) :- Low==minus_inf,!,
1667 construct_less_equal_closure(Up,Res).
1668 construct_interval_closure(Low,Up,Res) :- Low==Up,!,
1669 (number(Low) -> construct_one_element_custom_set(int(Low),Res)
1670 ; Res = [int(Low)]).
1671 construct_interval_closure(Low,Up,Res) :-
1672 construct_interval_set(Low,Up,Set),
1673 construct_member_closure('_zzzz_unary',integer,[],Set,Res).
1674
1675 transform_global_sets_into_closure(closure(P,T,B),closure(P,T,B)).
1676 transform_global_sets_into_closure(global_set(X),Res) :-
1677 transform_global_set_into_closure_aux(X,Res).
1678 transform_global_set_into_closure_aux('NATURAL',Res) :-
1679 construct_greater_equal_closure(0,Res).
1680 transform_global_set_into_closure_aux('NATURAL1',Res) :-
1681 construct_greater_equal_closure(1,Res).
1682 % TO DO: add INTEGER
1683
1684
1685
1686 is_geq_leq_interval_closure([Par],[integer],b(Body,pred,Span),Low,Up) :-
1687 (var(Par)
1688 -> add_internal_error('Non-ground closure: ',closure([Par],[integer],b(Body,pred,Span))),fail
1689 ? ; get_geq_leq_bounds(Body,Par,Low,Up)).
1690
1691 infinite_interval(Low,Up) :- (Low==minus_inf -> true ; Up==inf).
1692
1693 :- assert_must_succeed((card_of_interval_inf(1,10,10))).
1694 :- assert_must_succeed((card_of_interval_inf(1,inf,R),R==inf)).
1695 :- assert_must_succeed((card_of_interval_inf(minus_inf,0,R),R==inf)).
1696 :- assert_must_succeed((card_of_interval_inf(2,2,R), R==1)).
1697 :- assert_must_succeed((card_of_interval_inf(12,2,R), R==0)).
1698 :- assert_must_succeed((card_of_interval_inf(2,B,10), B==11)).
1699 :- assert_must_succeed((card_of_interval_inf(A,12,10), A==3)).
1700 :- assert_must_succeed((card_of_interval_inf(A,12,0), A=222)).
1701 :- assert_must_succeed((card_of_interval_inf(12,B,0), B=11)).
1702 :- assert_must_fail((card_of_interval_inf(A,12,0), A=12)).
1703 % compute cardinality of interval; allow bounds to be inf and minus_inf (but if so, they must be bound straightaway)
1704 card_of_interval_inf(A,B,Card) :-
1705 ? at_least_two_vars(A,B,Card), % initially this will usually be true, if only one variable we can compute result
1706 preferences:preference(use_clpfd_solver,true),
1707 !,
1708 clpfd_interface:post_constraint(Card #= max(0,1+B-A),custom_explicit_sets:block_card_of_interval_inf(A,B,Card)).
1709 card_of_interval_inf(A,B,Card) :- block_card_of_interval_inf(A,B,Card).
1710
1711 ?at_least_two_vars(A,B,C) :- var(A),!,(var(B) -> not_infinite_bound(C) ; number(B),var(C)).
1712 at_least_two_vars(A,B,C) :- number(A), var(B),var(C).
1713 not_infinite_bound(A) :- (var(A) ; number(A)). % inf can only appear immediately, not for variables
1714
1715 :- block block_card_of_interval_inf(-,?,-),block_card_of_interval_inf(?,-,-).
1716 block_card_of_interval_inf(A,_,Card) :- A==minus_inf,!, Card=inf.
1717 block_card_of_interval_inf(_,B,Card) :- B==inf,!, Card=inf.
1718 block_card_of_interval_inf(From,To,Card) :- number(From),number(To),!,
1719 (From>To -> Card=0 ; Card is (To-From)+1).
1720 block_card_of_interval_inf(A,B,C) :- number(C),!, number_card_of_interval_inf_aux(C,A,B).
1721 block_card_of_interval_inf(A,B,C) :- C==inf,!,
1722 % probably this should systematically fail; if A and B are not inf/minus_inf now they will never be
1723 print(infinite_interval_requested(A,B,C)),nl,
1724 when((nonvar(A),nonvar(B)), block_card_of_interval_inf(A,B,C)).
1725 block_card_of_interval_inf(A,B,C) :- add_internal_error('Illegal call: ',card_of_interval_inf(A,B,C)).
1726 :- use_module(inf_arith,[block_inf_greater/2]).
1727 number_card_of_interval_inf_aux(0,A,B) :- !, % empty interval
1728 % if A and B are variables then they will not become inf later ??
1729 % inf can only be set directly for sets such as {x|x>4} or NATURAL1
1730 (((var(A);number(A)),(var(B);number(B)))
1731 % hence we can use ordinary comparison (with CLPFD) here
1732 -> kernel_objects:less_than_direct(B,A)
1733 % TO DO: we could do this even if both A and B are variables !! ex : {n,m|n..m = {} & m..100={} & 103..n={}}
1734 ; block_inf_greater(A,B)).
1735 %number_card_of_interval_inf_aux(Card,From,B) :- number(From),!, B is (From+Card)-1.
1736 %number_card_of_interval_inf_aux(Card,A,To) :- number(To),!, A is 1+To-Card.
1737 number_card_of_interval_inf_aux(Card,A,B) :-
1738 Card>0, C1 is Card-1,
1739 kernel_objects:int_minus(int(B),int(A),int(C1)).
1740
1741
1742 get_geq_leq_bounds(conjunct(b(LEFT,pred,_),b(RIGHT,pred,_)), Par,Low,Up) :-
1743 ? get_geq_leq_bounds(LEFT,Par,From1,To1),
1744 ? get_geq_leq_bounds(RIGHT,Par,From2,To2),
1745 intersect_intervals_with_inf(From1,To1,From2,To2,Low,Up).
1746 get_geq_leq_bounds(member(b(identifier(Par),integer,_),
1747 b(Value,set(integer),_)),Par,Low,Up) :-
1748 get_value_bounds(Value,Low,Up).
1749 ?get_geq_leq_bounds(greater_equal(b(A,_,_),b(B,_,_)),Par,Low,Up) :- get_bounds2(greater_equal,A,B,Par,Low,Up).
1750 ?get_geq_leq_bounds( less_equal(b(A,_,_),b(B,_,_)),Par,Low,Up) :- get_bounds2(less_equal,A,B,Par,Low,Up).
1751 ?get_geq_leq_bounds( greater(b(A,_,_),b(B,_,_)),Par,Low,Up) :- get_bounds2(greater,A,B,Par,Low,Up).
1752 get_geq_leq_bounds( less(b(A,_,_),b(B,_,_)),Par,Low,Up) :- get_bounds2(less,A,B,Par,Low,Up).
1753
1754 get_value_bounds(value(GS),Low,Up) :- is_interval_closure_or_integerset(GS,Low,Up). % recursive call
1755 % nonvar(GS), GS=global_set(ISET), get_integer_set_interval(ISET,Low,Up).
1756 get_value_bounds(interval(b(TLow,_,_),b(TUp,_,_)),Low,Up) :-
1757 integer_value(TLow,Low),
1758 integer_value(TUp,Up).
1759
1760 get_bounds2(greater_equal,identifier(Par),V,Par,X,inf) :- integer_value(V,X).
1761 get_bounds2(greater_equal,V,identifier(Par),Par,minus_inf,X) :- integer_value(V,X).
1762 get_bounds2(less_equal,identifier(Par),V,Par,minus_inf,X) :- integer_value(V,X).
1763 get_bounds2(less_equal,V,identifier(Par),Par,X,inf) :- integer_value(V,X).
1764 get_bounds2(greater,identifier(Par),V,Par,X1,inf) :- integer_value(V,X), kernel_objects:int_plus(int(X),int(1),int(X1)). %, X1 is X+1.
1765 get_bounds2(greater,V,identifier(Par),Par,minus_inf,X1) :- integer_value(V,X), kernel_objects:int_minus(int(X),int(1),int(X1)). %X1 is X-1.
1766 get_bounds2(less,V,identifier(Par),Par,X1,inf) :- integer_value(V,X), kernel_objects:int_plus(int(X),int(1),int(X1)). %X1 is X+1.
1767 get_bounds2(less,identifier(Par),V,Par,minus_inf,X1) :- integer_value(V,X),
1768 kernel_objects:int_minus(int(X),int(1),int(X1)). %X1 is X-1.
1769 % to do: add negation thereof ??
1770
1771 integer_value(V,_) :- var(V),!, print(var_integer_value(V)),nl,fail.
1772 integer_value(integer(X),R) :- !, R=X.
1773 integer_value(unary_minus(b(X,_,_)),R) :- !, integer_value(X,RM),
1774 number(RM), % if RM is not a number we could setup CLPFD constraint ?!
1775 R is -(RM).
1776 integer_value(minus(b(X,_,_),b(Y,_,_)),R) :- !, % some AST compilation rules generate X-1, X+1 ...
1777 integer_value(X,RMX),
1778 integer_value(Y,RMY),
1779 kernel_objects:int_minus(int(RMX),int(RMY),int(R)).
1780 integer_value(plus(b(X,_,_),b(Y,_,_)),R) :- !, % some AST compilation rules generate X-1, X+1 ...
1781 integer_value(X,RMX),
1782 integer_value(Y,RMY),
1783 kernel_objects:int_plus(int(RMX),int(RMY),int(R)).
1784 integer_value(value(V),R) :- !, V=int(R).
1785
1786 is_interval_closure(closure(Par,[integer],Pred),Low,Up) :-
1787 is_interval_closure_aux(Par,Pred,Low,Up).
1788 is_interval_closure(Par,[integer],Pred,Low,Up) :-
1789 is_interval_closure_aux(Par,Pred,Low,Up).
1790 is_interval_closure_aux(Par,Pred,Low,Up) :-
1791 is_member_closure(Par,[integer],Pred,integer,Set),
1792 is_interval_with_integer_bounds(Set,Low,Up).
1793 %is_interval_closure(closure_x(Par,[integer],Pred,_),Low,Up) :-
1794 % is_interval_closure(closure(Par,[integer],Pred),Low,Up).
1795
1796 is_interval_closure_body(Body,ID,Low,Up) :-
1797 is_member_closure([ID],[integer],Body,integer,Set),!,
1798 is_interval_with_integer_bounds(Set,Low,Up).
1799 is_interval_closure_body(Body,ID,Low,Up) :-
1800 ? is_geq_leq_interval_closure([ID],[integer],Body,Low,Up),
1801 number(Low), number(Up).
1802
1803 :- use_module(bsyntaxtree,[get_texpr_info/2,get_texpr_id/2]).
1804 % do a single check if we have interval, member or not-member closure, avoiding redundant checking
1805 % TO DO: move this and related predicates to closures module ?
1806 is_special_closure(_Ids,_Types,Pred,Result) :-
1807 get_texpr_info(Pred,Info),memberchk(prob_annotation(recursive(RId)),Info),!,
1808 Result = recursive_special_closure(RId).
1809 is_special_closure(Ids,Types,Pred,Result) :-
1810 ? is_memoization_closure(Ids,Types,Pred,MemoID),!,
1811 Result = memoization_closure(MemoID).
1812 is_special_closure([ID],[TYPE],b(PRED,_,_), Result) :-
1813 ( closures:is_member_closure_aux(PRED, ID,TYPE,SET) ->
1814 ( (TYPE=integer, is_interval_with_integer_bounds(SET,Low,Up)) ->
1815 Result = interval(Low,Up)
1816 ; Result = member_closure(ID,TYPE,SET))
1817 ; closures:is_not_member_closure_aux(PRED,ID,TYPE,SET) ->
1818 Result = not_member_closure(ID,TYPE,SET)
1819 ? ; (TYPE=integer,get_geq_leq_bounds(PRED,ID,Low,Up),number(Low), number(Up)) ->
1820 Result = interval(Low,Up)
1821 ).
1822
1823
1824 construct_interval_set(Low,Up,Res) :-
1825 Res = interval(b(value(int(Low)),integer,[]),
1826 b(value(int(Up)), integer,[])).
1827 is_interval_with_integer_bounds(X,L,U) :- var(X),!,
1828 add_internal_error('var arg: ',is_interval_with_integer_bounds(X,L,U)),fail.
1829 is_interval_with_integer_bounds(interval(b(TLOW,integer,_),b(TUP, integer,_)),Low,Up) :-
1830 integer_value(TLOW,Low), integer_value(TUP,Up).
1831
1832 :- use_module(kernel_objects,[safe_mul/3, safe_add/3, safe_pow2/2, safe_pown/3]).
1833
1834 is_a_relation(relations(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '<->'
1835 Code = (kernel_objects:safe_mul(DCard,RCard,Exp), kernel_objects:safe_pow2(Exp,Card)).
1836 is_a_relation(partial_function(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '+->'
1837 Code = (kernel_objects:safe_add(RCard,1,R1),kernel_objects:safe_pown(R1,DCard,Card)).
1838 is_a_relation(total_function(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '-->'
1839 Code = (kernel_objects:safe_pown(RCard,DCard,Card)).
1840 is_a_relation(partial_bijection(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '>+>>'
1841 Code = (custom_explicit_sets:partial_bijection_card(DCard,RCard,Card)).
1842 is_a_relation(total_bijection(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '>->>'
1843 Code = (custom_explicit_sets:total_bijection_card(DCard,RCard,Card)).
1844 is_a_relation(total_injection(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '>->'
1845 Code = (custom_explicit_sets:blocking_factorial_k(RCard,DCard,Card)).
1846 is_a_relation(partial_injection(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '>+>'
1847 Code = (custom_explicit_sets:partial_injection_card(DCard,RCard,Card)).
1848 is_a_relation(total_surjection(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '-->>'
1849 Code = (custom_explicit_sets:total_surjection_card(DCard,RCard,Card)).
1850 is_a_relation(partial_surjection(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '+->>'
1851 Code = (custom_explicit_sets:partial_surjection_card(DCard,RCard,Card)).
1852 is_a_relation(total_relation(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '<<->'
1853 Code = (custom_explicit_sets:total_relation_card(DCard,RCard,Card)).
1854 is_a_relation(surjection_relation(Domain,Range),Domain,Range,DCard,RCard,Card,Code) :- %% '<->>'
1855 % just swap args: card(A<->>B) = card(B<<->A)
1856 Code = (custom_explicit_sets:total_relation_card(RCard,DCard,Card)).
1857 % TO DO: total_surjection_relation <<->>
1858
1859
1860 :- assert_must_succeed((custom_explicit_sets:total_relation_card(0,inf,R),R==1)).
1861 :- assert_must_succeed((custom_explicit_sets:total_relation_card(2,inf,R),R==inf)).
1862 :- assert_must_succeed((custom_explicit_sets:total_relation_card(inf,0,R),R==0)).
1863 :- assert_must_succeed((custom_explicit_sets:total_relation_card(inf,1,R),R==1)).
1864 :- assert_must_succeed((custom_explicit_sets:total_relation_card(inf,2,R),R==inf)).
1865 :- assert_must_succeed((custom_explicit_sets:total_relation_card(inf,inf,R),R==inf)).
1866 :- assert_must_succeed((custom_explicit_sets:total_relation_card(2,2,R),R==9)).
1867 :- assert_must_succeed((custom_explicit_sets:total_relation_card(2,3,R),R==49)).
1868
1869 :- block total_relation_card(-,?,?), total_relation_card(?,-,?).
1870 total_relation_card(0,_RanC,Card) :- !, Card=1. % empty set is a solution
1871 total_relation_card(_DomC,0,Card) :- !, Card=0. % no element to choose from in the range
1872 total_relation_card(inf,RanC,Card) :- !, (RanC=1 -> Card=1 ; Card=inf).
1873 total_relation_card(_,inf,Card) :- !, Card=inf.
1874 total_relation_card(DomC,RanC,Card) :- safe_pow2(RanC,SubRan),
1875 safe_minus(SubRan,1,S1), % as we have a total relation we cannot choose empty set
1876 safe_pown(S1,DomC,Card).
1877
1878 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(2,inf,R),R==0)).
1879 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(inf,2,R),R==inf)).
1880 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(inf,inf,R),R==inf)).
1881 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(3,2,R),R==6)).
1882 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(2,2,R),R==2)).
1883 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(1,2,R),R==0)).
1884 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(2,1,R),R==2)).
1885 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(5,3,R),R==60)).
1886 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(6,4,R),R==360)).
1887 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(10,1,R),R==10)).
1888 :- assert_must_succeed((custom_explicit_sets:partial_bijection_card(10,2,R),R==90)).
1889
1890 :- block partial_bijection_card(-,?,?), partial_bijection_card(?,-,?).
1891 partial_bijection_card(_X,0,R) :- !, R=1. % the empty set is a solution
1892 partial_bijection_card(inf,X,R) :- !,
1893 print_inf_warning(X,'>+>>'), % we could have : INTEGER >+>> POW(INTEGER); TO DO: use omega(inf) for POW ?
1894 R=inf. % we know _X>0
1895 partial_bijection_card(_X,inf,R) :- !, R=0. % _X<inf -> no way to cover all elements in range
1896 partial_bijection_card(DomCard,RanCard,Res) :- DomCard<RanCard,!,Res=0.
1897 partial_bijection_card(DomCard,RanCard,XCard) :-
1898 choose_nk(DomCard,RanCard,CNK), % ways to choose domain of size RanCard
1899 blocking_factorial(RanCard,Card),
1900 safe_mul(CNK,Card,XCard).
1901
1902 print_inf_warning(inf,FUN) :- print('### WARNING: Assuming '),
1903 print(FUN), print(' exists for two infinite sets'),nl.
1904 print_inf_warning(_,_).
1905
1906 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(0,2,R),R==0)).
1907 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(0,0,R),R==1)).
1908 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(2,0,R),R==1)).
1909 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(1,1,R),R==1)).
1910 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(inf,2,R),R==inf)).
1911 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(2,inf,R),R==0)).
1912 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(inf,inf,R),R==inf)).
1913 :- assert_must_succeed((custom_explicit_sets:partial_surjection_card(3,2,R),R==12)).
1914 :- block partial_surjection_card(-,?,?), partial_surjection_card(?,-,?).
1915 partial_surjection_card(_X,0,R) :- !, R=1. % the empty set is a solution
1916 partial_surjection_card(inf,X,R) :- !,print_inf_warning(X,'+->>'),R=inf. % we know _X>0
1917 partial_surjection_card(_X,inf,R) :- !, R=0. % _X<inf -> no way to cover all elements in range
1918 partial_surjection_card(A,B,Res) :- tsurjcard(A,1,B,Res). % 1 because we can choose to leave the function undefined
1919
1920 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(0,2,R),R==0)).
1921 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(0,0,R),R==1)).
1922 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(2,0,R),R==0)).
1923 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(inf,0,R),R==0)).
1924 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(inf,1,R),R==1)).
1925 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(inf,2,R),R==inf)).
1926 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(2,inf,R),R==0)).
1927 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(0,inf,R),R==0)).
1928 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(inf,inf,R),R==inf)).
1929 :- assert_must_succeed((custom_explicit_sets:total_surjection_card(3,2,R),R==6)).
1930 :- block total_surjection_card(-,?,?), total_surjection_card(?,-,?).
1931 total_surjection_card(0,Range,R) :- !,(Range=0 -> R=1 % the empty set is a solution
1932 ; R=0). % no solution
1933 total_surjection_card(_X,0,R) :- !, R=0. % as _X>0 there is no way to construct a total function
1934 total_surjection_card(_X,1,R) :- !, R=1. % we only have one choice for every element of _X
1935 total_surjection_card(inf,X,R) :- !,print_inf_warning(X,'-->>'),R=inf. % we know _X>0
1936 total_surjection_card(_X,inf,R) :- !, R=0. % _X<inf -> no way to cover all elements in range
1937 total_surjection_card(A,B,Res) :- tsurjcard(A,0,B,Res).
1938
1939 tsurjcard(Rem,_AlreadyUsed,StillToBeUsed,Res) :- Rem<StillToBeUsed,!,Res=0. % no solution
1940 tsurjcard(0,_AlreadyUsed,_StillToBeUsed,Res) :- !, Res=1. % we have finished
1941 tsurjcard(Rem,AlreadyUsed,StillToBeUsed,Res) :-
1942 R1 is Rem-1, A1 is AlreadyUsed+1, S1 is StillToBeUsed-1,
1943 (AlreadyUsed=0 -> ResA=0 ; tsurjcard(R1,AlreadyUsed,StillToBeUsed,ResA)),
1944 (StillToBeUsed=0 -> ResB =0 ; tsurjcard(R1,A1,S1,ResB)),
1945 Res is AlreadyUsed*ResA+StillToBeUsed*ResB.
1946
1947
1948
1949 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(1,1,R),R==2)).
1950 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(1,2,R),R==3)).
1951 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(1,100,R),R==101)).
1952 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(0,100,R),R==1)).
1953 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(1,inf,R),R==inf)).
1954 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(0,inf,R),R==1)).
1955 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(5,0,R),R==1)).
1956 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(inf,0,R),R==1)).
1957 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(inf,1,R),R==inf)).
1958 :- assert_must_succeed((custom_explicit_sets:partial_injection_card(5,1,R),R==6)).
1959
1960 :- block partial_injection_card(-,?,?), partial_injection_card(?,-,?).
1961 partial_injection_card(Dom,Ran,R) :- (Dom=0;Ran=0),!, R=1. % only one solution: empty function
1962 partial_injection_card(Dom,1,R) :- !, (Dom=inf -> R=inf ; R is Dom+1). % empty function + for every domain element one function
1963 partial_injection_card(inf,inf,Card) :- !, print_inf_warning(inf,'>+>'), Card=inf.
1964 partial_injection_card(Dom,Ran,R) :- (Dom=inf;Ran=inf),!, R=inf.
1965 partial_injection_card(Dom,Ran,R) :- Dom>1000,Ran>1000,!, R=inf. % TO DO: refine this
1966 % would give a result larger than blocking_factorial(1000)
1967 partial_injection_card(DCard,RCard,Card) :-
1968 pinj_card(1,DCard,RCard,1,Card).
1969
1970 % TO DO: can we compute this directly rather than using recursion ?
1971 pinj_card(I,M,N,Acc,Res) :- (I>M ; I>N ; Acc=inf),!, Res=Acc.
1972 pinj_card(I,M,N,Acc,Res) :-
1973 choose_nk(M,I,MI), % ways to choose domain of size I
1974 blocking_factorial_k(N,I,NI), % ways to map the domain of size I to N
1975 safe_mul(MI,NI,MINI), safe_add(MINI,Acc,NewAcc),
1976 I1 is I+1, pinj_card(I1,M,N,NewAcc,Res).
1977
1978 :- public total_bijection_card/3. % exported in is_a_relation above
1979 :- block total_bijection_card(-,?,?), total_bijection_card(?,-,?).
1980 total_bijection_card(inf,inf,Card) :- !, print_inf_warning(inf,'>->>'), Card=inf.
1981 total_bijection_card(DCard,RCard,Card) :- DCard \= RCard,!,Card=0.
1982 total_bijection_card(RCard,RCard,Card) :- blocking_factorial(RCard,Card).
1983
1984
1985
1986 :- use_module(b_global_sets,[infinite_global_set/1]).
1987
1988 :- block is_infinite_global_set(-,?).
1989 is_infinite_global_set('NATURAL',integer).
1990 is_infinite_global_set('NATURAL1',integer).
1991 is_infinite_global_set('INTEGER',integer).
1992 is_infinite_global_set('FLOAT',real).
1993 is_infinite_global_set('REAL',real).
1994 is_infinite_global_set('STRING',string).
1995 is_infinite_global_set(G,global(G)) :- infinite_global_set(G).
1996
1997 %is_finite_integer_global_set('NAT').
1998 %is_finite_integer_global_set('NAT1').
1999 %is_finite_integer_global_set('INT').
2000
2001 % detects (certain) infinite explict sets
2002 is_infinite_explicit_set(X) :- var(X),!, add_internal_error(is_infinite_explicit_set,var(X)),fail.
2003 ?is_infinite_explicit_set(global_set(X)) :- is_infinite_global_set(X,_).
2004 is_infinite_explicit_set(freetype(X)) :- is_infinite_freetype(X).
2005 is_infinite_explicit_set(closure(Par,T,Body)) :- is_infinite_closure(Par,T,Body).
2006
2007 % detect some closure that we should definitely expand; even in SYMBOLIC mode or for ABSTRACT_CONSTANTS
2008 definitely_expand_this_explicit_set(Var) :- var(Var),!,fail.
2009 definitely_expand_this_explicit_set(closure(P,_T,B)) :-
2010 B = b(Body,_,_), definitely_expand(Body,P).
2011 % some lambda functions have small domain, but are very complicated to compute (test 1078, 1376)
2012 % hence the following is not sufficient:
2013 % ;is_small_specific_custom_set(closure(P,T,B),100), print(exp(T)),nl,translate:print_bexpr(B),nl,fail).
2014
2015 definitely_expand(Body,_) :- avl_mem_construct(Body,_).
2016 definitely_expand(exists(TEIDS,Body),P) :- P = [ID], TEIDS = [TEID], % TO DO: detect multiple ids
2017 % detect {res|#y.(y:AVL & res=Expr(y))} % test 1101
2018 Body = b(conjunct(b(Mem,pred,_),Eq),pred,_),
2019 Eq = b(equal(EqA,EqB),pred,_),
2020 avl_mem_construct(Mem,LHS), get_texpr_id(LHS,EID), get_texpr_id(TEID,EID),
2021 (get_texpr_id(EqA,ID) -> true ; get_texpr_id(EqB,ID)).
2022
2023 avl_mem_construct(member(LHS,RHS),LHS) :- RHS = b(value(V),_,_), nonvar(V), V=avl_set(_).
2024
2025 dont_expand_this_explicit_set(closure(P,T,B)) :- !,
2026 ? dont_expand_this_closure(P,T,B).
2027 dont_expand_this_explicit_set(S) :-
2028 is_infinite_or_very_large_explicit_set(S).
2029
2030 % true if we have a closure / global_set that should not be expanded
2031 % TO DO: we could detect finite (is_lambda_value_domain_closure) closures which contain infinite elements such as %p.(p : BOOL|%t.(t : NATURAL|t .. t + 7))
2032 dont_expand_symbolic_explicit_set(closure(P,T,B)) :- !,
2033 dont_expand_this_closure(P,T,B).
2034 dont_expand_symbolic_explicit_set(avl_set(_)) :- !,
2035 fail. % already expanded
2036 dont_expand_symbolic_explicit_set(S) :-
2037 is_infinite_or_very_large_explicit_set(S).
2038
2039
2040 ?dont_expand_this_explicit_set(closure(P,T,B),Limit) :- !, dont_expand_this_closure(P,T,B,Limit).
2041 dont_expand_this_explicit_set(S,_) :- is_infinite_or_very_large_explicit_set(S).
2042
2043 ?dont_expand_this_closure(P,T,B) :- dont_expand_this_closure(P,T,B,20000).
2044
2045 dont_expand_this_closure(P,T,B,_Limit) :-
2046 is_interval_closure_or_integerset(closure(P,T,B),Low,Up), !,
2047 % interval closures are quite efficient for certain manipulations
2048 (number(Low), number(Up)
2049 -> Size is Up+1-Low, Size>100 % another magic constant ; which value to choose ??
2050 ; true % we have a closure with inf/minus_inf or variables as bounds; in both cases keep the closure
2051 ).
2052 dont_expand_this_closure(_P,_T,b(_,_,INFO),_Limit) :-
2053 ? member(prob_annotation('SYMBOLIC'),INFO). % cf is_symbolic_closure in closures
2054 dont_expand_this_closure(P,T,B,Limit) :-
2055 is_infinite_or_very_large_closure(P,T,B,Limit).
2056 %% TODO: also prevent expansion of things like ff = %x.(x:STRING & REGEX_MATCH(x,"[a-z]+")=TRUE|TRUE)
2057
2058 is_converted_lambda_closure(_P,_T,b(_,_,INFO)) :-
2059 ? member(prob_annotation('LAMBDA'),INFO).
2060
2061 is_symbolic_closure_or_symbolic_mode(P,T,B) :-
2062 ? (is_symbolic_closure(P,T,B) -> true
2063 ; preference(convert_comprehension_sets_into_closures,true)
2064 % by default suppose closures should be dealt with symbolically
2065 ).
2066 /*
2067 % check both LAMBDA + not RECURSIVE
2068 is_converted_non_recursive_lambda_closure(_,_,b(_,_,INFO)) :- is_conv_lambda_nonrec(INFO).
2069 is_conv_lambda_nonrec([prob_annotation(A)|T]) :- !,
2070 (A='LAMBDA' -> \+ memberchk(prob_annotation('RECURSIVE'),T)
2071 ; A\='RECURSIVE' -> is_conv_lambda_nonrec(T)).
2072 is_conv_lambda_nonrec([_|T]) :- is_conv_lambda_nonrec(T). */
2073
2074
2075
2076 % a set that is so large that expanding it would probably cause problems
2077 is_infinite_or_very_large_explicit_set(S) :- is_infinite_or_very_large_explicit_set(S,20000).
2078
2079 is_infinite_or_very_large_explicit_set(X,_) :- var(X),!,print(var_is_infinite_check(X)),nl,fail.
2080 is_infinite_or_very_large_explicit_set(closure(P,T,B),Limit) :- !,
2081 % treat closure separately here; some special rules
2082 is_infinite_or_very_large_closure(P,T,B,Limit).
2083 is_infinite_or_very_large_explicit_set(avl_set(A),Limit) :- !, % we could compute log and use avl_height_less_than
2084 quick_avl_approximate_size(A,Size), Size >= Limit.
2085 is_infinite_or_very_large_explicit_set(X,Limit) :- % closures are checked above
2086 explicit_set_cardinality(X,Card),
2087 card_gt_limit(Card,Limit).
2088
2089
2090 is_very_large_or_symbolic_closure(P,T,B,Limit) :-
2091 ? (is_symbolic_closure(P,T,B) -> true ; is_infinite_or_very_large_closure(P,T,B,Limit)).
2092 :- use_module(bsyntaxtree,[is_a_disjunct/3]).
2093 is_infinite_or_very_large_closure(P,T,B,Limit) :-
2094 is_a_disjunct(B,D1,D2), % Assumption: there is no card_for_specific_closure code for disjuncts
2095 !,
2096 (is_infinite_or_very_large_closure(P,T,D1,Limit) -> true
2097 ; is_infinite_or_very_large_closure(P,T,D2,Limit)).
2098 is_infinite_or_very_large_closure(Par,T,Body,Limit) :-
2099 is_closure1_value_closure(Par,T,Body,VAL),!,
2100 nonvar(VAL), % it could still be large or infinite
2101 (Limit>1 -> NLimit is Limit/2 ; NLimit = Limit), % reduce limit as closure1 usually blows up
2102 is_infinite_or_very_large_explicit_set(VAL,NLimit).
2103 is_infinite_or_very_large_closure(P,T,B,Limit) :-
2104 card_for_specific_closure3(Kind,P,T,B,Card,Code),
2105 ? on_enumeration_warning(call(Code),
2106 (debug_println(cannot_expand_specific_closure_for_card(Kind,Limit)),
2107 % see test 1519 for relevance
2108 Card=inf)),
2109 !,
2110 card_gt_limit(Card,Limit).
2111
2112 card_gt_limit(Card,Limit) :- (Card==inf -> true ; number(Card),Card>Limit).
2113
2114 is_infinite_or_symbolic_closure(P,T,B) :-
2115 ? (is_symbolic_closure(P,T,B) -> true ; is_infinite_closure(P,T,B)).
2116 is_infinite_closure(P,T,B) :-
2117 is_a_disjunct(B,D1,D2), % Assumption: there is no card_for_specific_closure code for disjuncts
2118 !,
2119 (is_infinite_closure(P,T,D1) -> true ; is_infinite_closure(P,T,D2)).
2120 is_infinite_closure(Par,T,Body) :-
2121 is_closure1_value_closure(Par,T,Body,VAL),!, % TO DO: also check if closure1 is large this way
2122 nonvar(VAL), % if var: it could still be infinite !! TO DO fix
2123 is_infinite_explicit_set(VAL).
2124 is_infinite_closure(Par,T,Body) :-
2125 card_for_specific_closure(closure(Par,T,Body),Card,Code),
2126 ? call(Code), % TO DO: catch enumeration exceptions (see is_infinite_or_very_large_closure above)
2127 ground(Card), Card == inf.
2128
2129
2130 :- use_module(memoization,[compute_memo_hash/2, get_stored_memo_expansion/3, store_memo_expansion/3]).
2131 /* transitive closure */
2132 closure1_for_explicit_set(avl_set(A),Res) :-
2133 preferences:preference(use_closure_expansion_memoization,true),!,
2134 compute_memo_hash(closure1_for_explicit_set(A),Hash),
2135 (get_stored_memo_expansion(Hash,closure1_for_explicit_set(A),StoredResult)
2136 -> Res = StoredResult
2137 ; closure1_for_explicit_set_direct(avl_set(A),Result),
2138 store_memo_expansion(Hash,closure1_for_explicit_set(A),Result),
2139 Res = Result
2140 ).
2141 closure1_for_explicit_set(avl_set(A),Res) :- closure1_for_explicit_set_direct(avl_set(A),Res).
2142
2143 % sometimes faster, but can also be considerably slower:
2144 %:- use_module(extrasrc(avl_ugraphs),[avl_transitive_closure/2]).
2145 %closure1_for_explicit_set_direct(avl_set(A),Res) :-
2146 % avl_transitive_closure(A,TC),
2147 % construct_avl_set(TC,Res).
2148 closure1_for_explicit_set_direct(avl_set(A),Res) :-
2149 avl_domain(A,AList),
2150 iterate_closure(AList,A,A,IterationRes),
2151 construct_avl_set(IterationRes,Res).
2152
2153 /* transitive closure starting from some initial set */
2154 /* not sure if we should do this:
2155 closure1_for_explicit_set_from(avl_set(A),StartFrom,Res) :-
2156 preferences:preference(use_closure_expansion_memoization,true),
2157 compute_memo_hash(closure1_for_explicit_set(A),Hash),
2158 stored_expansion(Hash,closure1_for_explicit_set(A),StoredResult),!,
2159 domain_restriction_explicit_set(StartFrom,StoredResult,Res). */
2160 % StartFrom can be avl_set(empty)
2161 closure1_for_explicit_set_from(avl_set(A),StartFrom,Res) :-
2162 avl_domain(A,AList),
2163 filter_start_relation(AList,StartFrom,FAList),
2164 (FAList = [] -> Res=[]
2165 ; convert_to_avl(FAList,avl_set(Start)),
2166 iterate_closure(FAList,A,Start,IterationRes),
2167 construct_avl_set(IterationRes,Res)).
2168 filter_start_relation([],_,[]).
2169 filter_start_relation([(X,Y)|T],StartSet,Res) :-
2170 (element_of_custom_set(X,StartSet) -> Res = [(X,Y)|RT] ; Res=RT),
2171 filter_start_relation(T,StartSet,RT).
2172
2173 iterate_closure([],_,Res,Res).
2174 iterate_closure([(X,Y)|T],InitialRelation,Relation,Res) :-
2175 %(Key = (X,Y) -> true ; add_error_and_fail(iterate_closure,'Not a relation element: ',Key)),
2176 add_tuples(X,Y,InitialRelation,Relation,NewRelation,AddedTuples),
2177 % better: do added tuples straight away ?
2178 iterate_closure(T,InitialRelation,NewRelation,NewRelation2),
2179 iterate_closure(AddedTuples,InitialRelation,NewRelation2,Res).
2180
2181 add_tuples(X,Y,AVL,AVLClosureSoFar,Res,NewTuples) :-
2182 findall((X,Z), (avl_fetch_pair(Y,AVL,Z), %ok instead of safe_avl_member((Y,Z),AVL),; Y in AVL form, Z var
2183 %Y \= Z, % self-loops are already in initial AVLClosure, this will never add a new pair
2184 % if we use AVLClosureSoFar instead of AVL: considerably slower
2185 \+ avl_fetch((X,Z),AVLClosureSoFar)), NewTuples),
2186 add_to_avl(NewTuples,AVLClosureSoFar,Res).
2187
2188 :- use_module(bsyntaxtree,[create_negation/2]).
2189 % SUBSET_OF <:
2190 % subset_of_explicit_set: returns code to be executed if this subset check can be done in an optimized way
2191 % TO DO: add strict_subset <<: + more cases, e.g., interval & avl_set, ...
2192 % interval & interval already handled in check_subset_of_global_sets
2193 subset_of_explicit_set(AVL,Closure,Code,_WF) :- nonvar(AVL),AVL=avl_set(A),
2194 is_interval_closure_or_integerset(Closure,Low,Up),!,
2195 Code=custom_explicit_sets:check_avl_in_interval(A,Low,Up).
2196 subset_of_explicit_set(Closure,CS,Code,WF) :- nonvar(CS), is_custom_explicit_set(CS),
2197 is_interval_closure_or_integerset(Closure,Low,Up),!,
2198 Code=custom_explicit_sets:check_interval_in_custom_set(Low,Up,CS,WF).
2199 subset_of_explicit_set(AVL1,AVL2,Code,_WF) :-
2200 nonvar(AVL1),AVL1=avl_set(A1), nonvar(AVL2),AVL2=avl_set(A2),!,
2201 Code = custom_explicit_sets:check_avl_subset(A1,A2).
2202 subset_of_explicit_set(C1,AVL2,Code,_WF) :- nonvar(C1),
2203 simple_finite_set(AVL2),
2204 is_simple_infinite_set(C1),!, % infinite set cannot be subset of finite one
2205 Code = fail.
2206 subset_of_explicit_set(C1,C2,Code,WF) :- nonvar(C1),
2207 is_cartesian_product_closure(C1,S11,S12),!,
2208 ((S11==[] ; S12==[]) -> Code=true /* we always have a subset */
2209 ; is_definitely_not_empty(S11),
2210 is_definitely_not_empty(S12), % only use optimisation if we know S11, S12 to be non-empty
2211 nonvar(C2), is_cartesian_product_closure(C2,S21,S22),
2212 Code = (kernel_objects:check_subset_of_wf(S11,S21,WF),
2213 kernel_objects:check_subset_of_wf(S12,S22,WF) )
2214 ).
2215 subset_of_explicit_set(Set1,Set2,Code,WF) :-
2216 nonvar(Set2),is_cartesian_product_closure(Set2,S21,S22),!,
2217 % TO DO: maybe don't do this if Set1 is avl_set ??
2218 debug_println(9,'Applying C <: S21*S22 <=> C : S21 <-> S22'),
2219 Code = bsets_clp:relation_over_wf(Set1,S21,S22,WF).
2220 subset_of_explicit_set(C1,C2,Code,WF) :- nonvar(C1), nonvar(C2),
2221 ? is_powerset_closure(C1,Constructor1,Set1),
2222 ? is_powerset_closure(C2,Constructor2,Set2),
2223 subset_constructor(Constructor1,Constructor2,R),
2224 !,
2225 Code = (R=pred_true, kernel_objects:check_subset_of_wf(Set1,Set2,WF)).
2226 subset_of_explicit_set(Set1,Set2,Code,WF) :- %print_term_summary(subset(Set1,Set2)),nl,
2227 get_subset_counter_example_closure(Set1,Set2,NewP,NewT,NewB,DefResult), % {x|P1} <: {x|P2} <=> {x|P1 & not(P2)}={}
2228 !,
2229 (DefResult==definitely_non_empty -> Code = fail
2230 ; Code = custom_explicit_sets:is_empty_closure_wf(NewP,NewT,NewB,WF)).
2231
2232 % get closure representing the counter examples to Set1 <: Set2: i.e. elements in Set1 and not in Set2
2233 % used for symbolic treatment of subset, not_subset and test_subset
2234 % note: in case this fails subset_test1 will expand Set1
2235 % DefiniteResultFlag may return the information that the generated closure is definitely not empty
2236 get_subset_counter_example_closure(Set1,Set2,NewP,NewT,NewB,DefiniteResultFlag) :-
2237 get_closure(Set1,P1,T1,B1),
2238 get_subset_counter_aux(P1,T1,B1,Set2,NewP,NewT,NewB,DefiniteResultFlag).
2239
2240 get_subset_counter_aux(P1,T1,B1,Set2,NewP,NewT,NewB,DefRes) :-
2241 nonvar(Set2), is_definitely_finite(Set2), !,
2242 create_couple_term(P1,T1,P1Couple), % can currently still fail for more than 2 args
2243 ? (is_symbolic_closure(P1,T1,B1) -> DefRes=unknown
2244 ; is_infinite_closure(P1,T1,B1) -> DefRes=definitely_non_empty
2245 % return a flag that tells that there are definitely counter examples as Set2 is finite
2246 ),
2247 NewP=P1, NewT=T1,
2248 % {x|P1} <: {a1,...} <=> {x|P1 & x /: {a1,...}}={}
2249 get_texpr_type(P1Couple,CoupleType1),
2250 VSet2 = b(value(Set2),set(CoupleType1),[]),
2251 create_texpr(not_member(P1Couple,VSet2),pred,[],NegPred2),
2252 conjunct_predicates([B1,NegPred2],NewB).
2253 get_subset_counter_aux(P1,T1,B1,Set2,NewP,NewT,NewB,unknown) :-
2254 get_closure(Set2,P2,T2,B2),
2255 (is_infinite_or_symbolic_closure(P1,T1,B1) -> true
2256 ), % should we also allow ?? ; is_symbolic_closure(P2,T2,B2)),
2257 % not necessary maybe as subset_test1 only expands Set1
2258 % {x|P1} <: {x|P2} <=> {x|P1 & not(P2)}={}
2259 unify_closure_predicates(P1,T1,B1, P2,T2,B2 , NewP,NewT, NewB1,NewB2),
2260 create_negation(NewB2,NegNewB2),
2261 bsyntaxtree:conjunct_predicates([NewB1,NegNewB2],NewB).
2262
2263
2264 % get_closure or infinite global set:
2265 get_closure(V,_,_,_) :- var(V),!,fail.
2266 get_closure(closure(P,T,B),P,T,B).
2267 get_closure(global_set(G),P,T,B) :- is_infinite_global_set(G,Type),!,
2268 ID = '_zzzz_unary',
2269 TID = b(identifier(ID),Type,[]),
2270 TSet = b(value(global_set(G)),set(Type),[]),
2271 P = [ID], T=[Type], B= b(member(TID,TSet),pred,[prob_annotation('SYMBOLIC')]).
2272
2273
2274 subset_constructor(X,X,R) :- !,R=pred_true.
2275 subset_constructor(fin1,_,R) :- !,R=pred_true.
2276 subset_constructor(fin,pow,R) :- !,R=pred_true.
2277 subset_constructor(X,Y,R) :- strict_subset_constructor(X,Y),!,R=pred_true.
2278 subset_constructor(X,Y,R) :- strict_subset_constructor(Y,X),!,R=pred_false.
2279 % pow1,fin1 ; pow,fin ; and pow1,fin only ok if type infinite
2280 strict_subset_constructor(pow1,pow).
2281 strict_subset_constructor(fin1,fin).
2282
2283 % more rules for <->, +->, ...
2284 % what if same closure: then we also know it is a subset
2285
2286 % to be completed:
2287 % code that instantiates R to subset or not_subset, may have to delay
2288 test_subset_of_explicit_set(Set1,_,_,_,_) :- var(Set1),!,fail.
2289 test_subset_of_explicit_set(avl_set(A),Closure,R,WF,Code) :-
2290 is_interval_closure_or_integerset(Closure,Low,Up),!,
2291 Code=custom_explicit_sets:test_avl_in_interval(A,Low,Up,R,WF).
2292 test_subset_of_explicit_set(_,Set2,_,_,_) :- var(Set2),!,fail.
2293 test_subset_of_explicit_set(avl_set(A1),avl_set(A2),R,_WF,Code) :-
2294 Code = (custom_explicit_sets:check_avl_subset(A1,A2) -> R=pred_true ; R=pred_false).
2295 test_subset_of_explicit_set(global_set(G),Set2,R,_WF,Code) :-
2296 ? is_infinite_global_set(G,_), % TODO: we could extend this to other infinite sets
2297 is_definitely_finite(Set2), !,
2298 Code =(R=pred_false).
2299 test_subset_of_explicit_set(Set1,Set2,Res,WF,Code) :-
2300 get_subset_counter_example_closure(Set1,Set2,NewP,NewT,NewB,DefResult), % {x|P1} <: {x|P2} <=> {x|P1 & not(P2)}={}
2301 !,
2302 (DefResult==definitely_non_empty -> Code = (Res=pred_false)
2303 ; Code = custom_explicit_sets:test_empty_closure_wf(NewP,NewT,NewB,Res,WF)
2304 ).
2305 % TO DO: add is_cartesian_product_closure case
2306 is_definitely_finite([]).
2307 is_definitely_finite(avl_set(_)).
2308
2309 :- use_module(kernel_equality,[test_interval_subset_wf/6]).
2310
2311 :- public test_avl_in_interval/5. % used in test_subset_of_explicit_set
2312 % see also check_avl_in_interval(A,Low,Up), check_avl_not_in_interval(A,Low,Up).
2313 test_avl_in_interval(A,Low2,Up2,Res,WF) :-
2314 avl_min(A,int(Min)), % not needed if Low2==minus_inf
2315 avl_max(A,int(Max)), % not needed if Up2==inf
2316 test_interval_subset_wf(Min,Max,Low2,Up2,Res,WF).
2317
2318 % ----------------------
2319
2320 is_definitely_not_empty(X) :- nonvar(X),
2321 (X=[_|_] -> true
2322 ; is_custom_explicit_set(X), is_non_empty_explicit_set(X)).
2323
2324 % check if defnitely not empty and provide a witness
2325 is_definitely_not_empty_with_witness(X,El) :- nonvar(X),
2326 get_witness_element(X,El).
2327 get_witness_element([H|_],H).
2328 get_witness_element(avl_set(node(H,_True,_,_,_)),H).
2329 % TO DO: add global_set(GS),...
2330
2331 check_avl_subset(A1,A2) :- avl_max(A1,Max1), avl_max(A2,Max2),
2332 Max1@>Max2,!, % then A1 cannot be subset of A2
2333 fail.
2334 check_avl_subset(A1,A2) :-
2335 avl_min(A1,Cur1), avl_min(A2,Cur2),
2336 check_avl_subset_loop(Cur1,A1,Cur2,A2).
2337 check_avl_subset_loop(Cur1,AVL1,Cur2,AVL2) :-
2338 (Cur1 @> Cur2 -> avl_next(Cur2,AVL2,NC2), check_avl_subset_loop(Cur1,AVL1,NC2,AVL2)
2339 ; Cur1=Cur2 -> (avl_next(Cur1,AVL1,NC1)
2340 -> avl_next(Cur2,AVL2,NC2),
2341 check_avl_subset_loop(NC1,AVL1,NC2,AVL2)
2342 ; true /* all objects of AVL1 inspected */)
2343 ).
2344
2345 % check A <: Low..Up
2346 check_avl_in_interval(A,Low,Up) :- % does not have to delay: if we have minus_inf & inf they will be known straightaway
2347 (Low==minus_inf -> true
2348 ; avl_min(A,Min), kernel_objects:less_than_equal(int(Low),Min)),
2349 (Up==inf -> true
2350 ; avl_max(A,Max), kernel_objects:less_than_equal(Max,int(Up))).
2351
2352 % some experiments:
2353 % 1..x <: {1,2,3,5} & x>1 & !y.(y>x & y<10 => 1..y /<: {1,2,3,5})
2354 % {ss | ss <: 0..0 & ss /= {} & ss=0..max(ss)}
2355 % {ss | ss <: 0..0 & ss /= {} & ss=min(ss)..max(ss)} // does not work yet
2356 % x..x+1 <: {0,2,3,5}
2357 % x..x+2 <: {0,2,3,5} // does not work yet
2358 % r = {x|x:1..400 & x mod 3/=0} & res={v|v:0..1300 & v..v+1 <: r}
2359 % check Low..Up <: Avl
2360
2361 check_interval_in_custom_set(Low,Up,CS,WF) :-
2362 Low \== minus_inf,
2363 Up \== inf,
2364 b_interpreter_check:check_arithmetic_operator('<=',Low,Up,LeqRes),
2365 (var(LeqRes) -> get_binary_choice_wait_flag_exp_backoff(16,check_interval_in_custom_set,WF,WF2) ; true),
2366 check_interval_in_custom_set_aux(LeqRes,Low,Up,CS,WF2).
2367
2368 :- block check_interval_in_custom_set_aux(-,?,?,?,-).
2369 check_interval_in_custom_set_aux(pred_true,Low,Up,CS,_WF2) :-
2370 element_of_custom_set_wf(int(Low),CS,WF),
2371 element_of_custom_set_wf(int(Up),CS,WF),
2372 interval_in_avl_block(Low,Up,CS,WF).
2373 check_interval_in_custom_set_aux(pred_false,_Low,_Up,_CS,_WF2). % Interval is empty; but infinitely many solutions for Low and Up exist in principle
2374
2375 :- block interval_in_avl_block(-,?,?,?), interval_in_avl_block(?,-,?,?).
2376 interval_in_avl_block(Low,Up,CS,WF) :-
2377 Low1 is Low+1, interval_in_avl_loop(Low1,Up,CS,WF).
2378 interval_in_avl_loop(Low,Up,_CS,_WF) :- Low>=Up,!. % Lower bound and upper bound already checked
2379 interval_in_avl_loop(Low,Up,CS,WF) :-
2380 element_of_custom_set_wf(int(Low),CS,WF), L1 is Low+1,
2381 interval_in_avl_loop(L1,Up,CS,WF).
2382
2383
2384 :- public not_check_avl_subset/2. % used in not_subset_of_explicit_set_aux
2385 not_check_avl_subset(A1,A2) :- \+ check_avl_subset(A1,A2).
2386
2387 not_subset_of_explicit_set(S1,S2,Code,WF) :- nonvar(S1),
2388 ? not_subset_of_explicit_set_aux(S1,S2,Code,WF).
2389 not_subset_of_explicit_set_aux(avl_set(A),Closure,Code,_WF) :-
2390 is_interval_closure_or_integerset(Closure,Low,Up),!,
2391 Code=custom_explicit_sets:check_avl_not_in_interval(A,Low,Up).
2392 not_subset_of_explicit_set_aux(avl_set(A1),AVL2,Code,_WF) :-
2393 nonvar(AVL2),AVL2=avl_set(A2),
2394 Code = custom_explicit_sets:not_check_avl_subset(A1,A2).
2395 not_subset_of_explicit_set_aux(CS,AVL,Code,_WF) :-
2396 ? is_simple_infinite_set(CS),
2397 % TO DO: provide code for interval/NAT/INT /<: AVL
2398 simple_finite_set(AVL),
2399 !,
2400 Code = true. % G cannot be subset of finite set
2401 not_subset_of_explicit_set_aux(C1,C2,Code,WF) :- is_cartesian_product_closure(C1,S11,S12),
2402 ((S11==[] ; S12==[]) -> Code=fail /* we always have a subset */
2403 ; is_definitely_not_empty(S11),
2404 is_definitely_not_empty(S12), % only use optimisation if we know S11, S12 to be non-empty
2405 nonvar(C2), is_cartesian_product_closure(C2,S21,S22),
2406 Code = (kernel_objects:not_both_subset_of(S11,S12, S21,S22, WF))
2407 ), !.
2408 not_subset_of_explicit_set_aux(C1,C2,Code,WF) :- nonvar(C2),
2409 ? is_powerset_closure(C1,Constructor1,Set1),
2410 ? is_powerset_closure(C2,Constructor2,Set2),
2411 subset_constructor(Constructor1,Constructor2,R),!,
2412 Code = (R=pred_false -> true ; kernel_objects:not_subset_of_wf(Set1,Set2,WF)).
2413 not_subset_of_explicit_set_aux(Set1,Set2,Code,WF) :-
2414 get_subset_counter_example_closure(Set1,Set2,NewP,NewT,NewB,DefResult), % {x|P1} <: {x|P2} <=> {x|P1 & not(P2)}={}
2415 !,
2416 (DefResult==definitely_non_empty -> Code = true
2417 ; Code = custom_explicit_sets:is_non_empty_closure_wf(NewP,NewT,NewB,WF)
2418 ).
2419
2420
2421 :- public check_avl_not_in_interval/3. % used in not_subset_of_explicit_set_aux
2422 :- block check_avl_not_in_interval(?,-,?). % TO DO: use non-blocking version, minus_inf, and inf set directly
2423 check_avl_not_in_interval(A,Low,Up) :- avl_min(A,int(Min)),
2424 check_avl_not_in_interval4(Low,Up,A,Min).
2425
2426 check_avl_not_in_interval4(Low,_Up,_A,Min) :- Low \== minus_inf, Min < Low,!.
2427 check_avl_not_in_interval4(_Low,Up,A,_Min) :-
2428 Up \== inf, avl_max(A,Max),
2429 kernel_objects:less_than(int(Up),Max). % Up could still be a variable
2430
2431
2432 % checks for simple infinite sets, without Cartesian Product, ... decomposition
2433 ?is_simple_infinite_set(global_set(X)) :- !, is_infinite_global_set(X,_).
2434 is_simple_infinite_set(CS) :- is_interval_closure_or_integerset(CS,Low,Up), infinite_interval(Low,Up).
2435
2436 simple_finite_set(AVL) :- nonvar(AVL), (AVL=avl_set(_) -> true ; AVL = []).
2437
2438 % IMAGE [.]
2439 image_for_id_closure(closure(Par,Types,Body),Set,Res) :-
2440 is_full_id_closure(Par,Types,Body),!,
2441 Res=Set.
2442
2443 image_for_explicit_set(closure(Par,Types,Body),Set,Res,WF) :-
2444 image_for_closure(Par,Types,Body,Set,Res,WF).
2445 image_for_explicit_set(avl_set(A),Set,Res,WF) :- nonvar(Set),
2446 image_for_explicit_avl_set(A,Set,Res,WF).
2447
2448
2449 image_for_closure(Par,Types,Body,Set,Res,_WF) :-
2450 is_id_closure_over(Par,Types,Body,ID_Domain,Full),!,
2451 (Full=true -> Res=Set ; kernel_objects:intersection(ID_Domain,Set,Res)).
2452 % infinite function case dealt with in image1 in bsets_clp
2453 % TO DO: other closure(); Maybe special case if Set is an interval ?
2454 image_for_closure(Par,Types,Body,Set,Res,WF) :-
2455 is_closure1_value_closure(Par,Types,Body,VAL), % TODO: also detect reflexive closure, iteration (iterate(rel,k))
2456 % compute closure1(VAL)[Set]
2457 bsets_clp:image_for_closure1_wf(VAL,Set,Res,WF).
2458
2459 is_closure1_value_closure(Par,Types,Body,VAL) :-
2460 is_member_closure(Par,Types,Body,couple(A,A),MemSET), nonvar(MemSET),
2461 MemSET = closure(V), % this is the closure1 B operator !
2462 nonvar(V), V=b(value(VAL),_,_).
2463
2464 image_for_explicit_avl_set(A,Set,Res,_WF) :- % Set is nonvar
2465 is_interval_closure_or_integerset(Set,From1,To1),!,
2466 % Note: if From1, To1 not yet known we will block and not revert to other image calculation code
2467 % Important e.g. for performance of San Juan (AdaptedBModelPropCheck/acs_as_env_cfg_ipart.mch)
2468 %we used to check for: ground(From1),ground(To1),
2469 interval_image_for_explicit_avl_set(From1,To1,A,Set,Res).
2470 image_for_explicit_avl_set(A,Set,Res,WF) :-
2471 \+ bsets_clp:keep_symbolic(Set), % in this case we fall back to treatment in bsets_clp (image1)
2472 expand_custom_set_to_list_gg(Set,ESet,GG,image_for_explicit_avl_set),
2473 empty_avl(Empty),
2474 (GG=guaranteed_ground -> image_explicit_ground(ESet,A,Empty,Res,WF)
2475 ; image_explicit(ESet,A,Empty,Res,WF)).
2476
2477 :- block interval_image_for_explicit_avl_set(-,?,?,?,?),
2478 interval_image_for_explicit_avl_set(?,-,?,?,?).
2479 interval_image_for_explicit_avl_set(From1,To1,_A,_Set,Res) :-
2480 number(From1), number(To1), From1>To1,!,
2481 kernel_objects:empty_set(Res).
2482 interval_image_for_explicit_avl_set(From1,To1,A,_Set,Res) :-
2483 findall(Image-true, avl_image_interval(From1,To1, A,Image),ImageList),
2484 normalised_list_to_avl(ImageList,ImageAvl),
2485 ? equal_object(ImageAvl,Res).
2486
2487
2488 %! singleton_set(+Set,-Element).
2489 singleton_set(X,_) :- var(X),!,fail.
2490 singleton_set([H|T],R) :- T==[], R=H.
2491 singleton_set(avl_set(node(Y,_,_,empty,empty)),Y). % same as is_one_element_custom_set
2492
2493 is_one_element_custom_set(avl_set(node(Y,_,_,empty,empty)),Y).
2494 is_one_element_avl(node(Y,_,_,empty,empty),Y).
2495
2496 % requires El to be ground
2497 construct_one_element_custom_set(El,avl_set(AVL)) :-
2498 empty_avl(E),avl_store(El,E,true,AVL).
2499
2500 construct_avl_set(Avl,Res) :- empty_avl(Avl) -> Res = [] ; Res = avl_set(Avl).
2501
2502 :- block image_explicit(-,?,?,?,?).
2503 image_explicit([],_,Acc,Res,WF) :- !,
2504 construct_avl_set(Acc,AVLS),
2505 ? kernel_objects:equal_object_wf(Res,AVLS,image_explicit,WF).
2506 image_explicit([D1|T],AVLRelation,In,Out,WF) :- !,
2507 ground_value_check(D1,G1),
2508 ((var(T);T==[]) % TO DO: see below, make propagation also interesting in other circumstances
2509 -> must_be_in_domain_check(G1,D1,T,AVLRelation,In,Out,WF)
2510 ; true),
2511 image_explicit_aux(G1,D1,AVLRelation,T,In,Out,WF).
2512 image_explicit(Set,_,_,_,_) :- add_error_and_fail(image_explicit,'Unknown set: ',Set).
2513
2514 % a version of image_explicit where the list is guaranteed to be ground
2515 image_explicit_ground([],_,Acc,Res,WF) :- !,
2516 construct_avl_set(Acc,AVLS),
2517 kernel_objects:equal_object_wf(Res,AVLS,image_explicit,WF).
2518 image_explicit_ground([D1|T],AVLRelation,In,Out,WF) :- !,
2519 image_explicit_aux_ground(D1,AVLRelation,T,In,Out,WF).
2520 image_explicit_ground(Set,_,_,_,_) :- add_error_and_fail(image_explicit_ground,'Unknown set: ',Set).
2521
2522 :- block must_be_in_domain_check(-,?,?,?,?,-,?),
2523 must_be_in_domain_check(-,?,-,?,?,?,?).
2524 % if result requires at least one more element, then D must be in domain of Relation
2525 % ensures that we get a domain for j in x = {1|->2,2|->4, 4|->8} & x[{j}]={8}
2526 % we could even propagate using inverse of AVLRelation ?!
2527 must_be_in_domain_check(GroundD,D,T,AVLRelation,In,Out,WF) :-
2528 T==[], % apart from D, there are no more elements to be added
2529 var(GroundD), % otherwise we already have a value for D
2530 delta_witness(In,Out,Witness), % obtain at least one value that D must map to
2531 !,
2532 quick_propagation_element_information(avl_set(AVLRelation),(D,Witness),WF,_). % Witness avoids pending co-routines
2533 % TO DO: we could check that *all* elements of Out have this value
2534 % TO DO: below we could check that In is a subset of Out; e.g., for x = %i.(i:1..10|i+i) & x[{5,j,k}]={16,11}; we could also check that Out is subset of range of relation
2535 must_be_in_domain_check(_,_D,_T,_,_In,_Out,_). % :- print(must_be(D,T,In,Out)),nl.
2536
2537 % provide, if possible, a witness element in Out not in In
2538 delta_witness(In,Out,_Witness) :- (var(In) ; var(Out)),!,fail.
2539 %delta_witness(empty,Out,Witness) :- is_definitely_not_empty_with_witness(Out,Witness).
2540 delta_witness(In,Out,Witness) :-
2541 is_custom_explicit_set(Out,delta_witness),
2542 difference_of_explicit_set(Out,avl_set(In),Diff), % could be expensive to compute !? delay ? print(delta(Diff)),nl,
2543 is_definitely_not_empty_with_witness(Diff,Witness).
2544
2545
2546 :- block image_explicit_aux(-,?,?, ?,?,?,?). % we know that D1 is ground
2547 image_explicit_aux(_,D1,AVLRelation,T,In,Out,WF) :-
2548 all_images(D1,AVLRelation,NewImages), % compute AVLRelation[{D1}]
2549 add_to_avl(NewImages,In,In2),
2550 ? image_explicit(T,AVLRelation,In2,Out,WF).
2551 image_explicit_aux_ground(D1,AVLRelation,T,In,Out,WF) :-
2552 all_images(D1,AVLRelation,NewImages), % compute AVLRelation[{D1}]
2553 add_to_avl(NewImages,In,In2),
2554 image_explicit_ground(T,AVLRelation,In2,Out,WF).
2555
2556 all_images(From,AVLRelation,Images) :-
2557 findall(AY,avl_member_pair_arg1_ground(From,AY,AVLRelation),Images). % we know From ground and AY free variable
2558 % findall(AY,safe_avl_member_pair(From,AY,AVLRelation),Images). %
2559
2560 % compute relational composition ( ; ) if second arg is an AVL set
2561 % TO DO: add support for infinite closures; avoid expanding them [currently handled by symbolic composition in bsets_clp]
2562 rel_composition_for_explicit_set(Rel1,Rel2,Comp) :- nonvar(Rel2),
2563 Rel2=avl_set(A2), % TO DO: see if we can maybe convert Rel2 to AVL ?
2564 % \+ bsets_clp:keep_symbolic(Rel1), check already done in bsets
2565 expand_custom_set_to_list_gg(Rel1,Relation1,GG,rel_composition_for_explicit_set),
2566 empty_avl(In),
2567 (GG=guaranteed_ground
2568 -> rel_avl_compose2_ground(Relation1,A2,In,Comp)
2569 ; rel_avl_compose2(Relation1,A2,In,Comp)).
2570
2571 :- block rel_avl_compose2(-,?,?,?).
2572 rel_avl_compose2([],_,In,Res) :- construct_avl_set(In,A),
2573 equal_object(Res,A,rel_avl_compose2). % as we delay; we need to use equal_object at the end
2574 rel_avl_compose2([(X,Y)|T],A2,In,Out) :-
2575 when((ground(X),ground(Y)),
2576 (all_image_pairs_ground(X,Y,A2,ImagePairs),
2577 add_to_avl(ImagePairs,In,In2),
2578 rel_avl_compose2(T,A2,In2,Out))).
2579
2580 % a version where argument is guaranteed to be ground; no when-ground checks
2581 rel_avl_compose2_ground([],_,In,Res) :- construct_avl_set(In,A),
2582 equal_object(Res,A,rel_avl_compose2). % as we delay; we need to use equal_object at the end
2583 rel_avl_compose2_ground([(X,Y)|T],A2,In,Out) :-
2584 all_image_pairs_ground(X,Y,A2,ImagePairs),
2585 add_to_avl(ImagePairs,In,In2),
2586 rel_avl_compose2_ground(T,A2,In2,Out).
2587
2588 %all_image_pairs(From,To,AVLRelation,ImagePairs) :-
2589 % findall((From,AY),safe_avl_member_pair(To,AY,AVLRelation),ImagePairs).
2590 all_image_pairs_ground(From,To,AVLRelation,ImagePairs) :-
2591 findall((From,AY),avl_member_pair_arg1_ground(To,AY,AVLRelation),ImagePairs).
2592 % To: already in AVL format; AY is variable -> we could use avl_fetch_pair directly : findall((From,AY),avl_fetch_pair(To,AVLRelation,AY),ImagePairs).
2593
2594 /* succeeds if it can compute domain by some clever way */
2595 domain_of_explicit_set_wf(global_set(GS),_R,_) :- !,
2596 add_error_and_fail(domain_of_explicit_set_wf,'Cannot compute domain of global set: ',GS).
2597 domain_of_explicit_set_wf(freetype(GS),_R,_) :- !,
2598 add_error_and_fail(domain_of_explicit_set_wf,'Cannot compute domain of freetype: ',GS).
2599 domain_of_explicit_set_wf(avl_set(A),Res,_) :- !,
2600 domain_of_avl_set(A,Res).
2601 domain_of_explicit_set_wf(C,R,WF) :- dom_for_specific_closure(C,Dom,_,WF),!,
2602 Dom=R.
2603 domain_of_explicit_set_wf(C,R,_) :-
2604 ? dom_symbolic(C,CC),!,
2605 R=CC.
2606 domain_of_explicit_set_wf(closure(P,T,B),Res,WF) :-
2607 % does not seem to be reached, as dom_symbolic now seems to cover all cases
2608 expand_custom_set_wf(closure(P,T,B),EC,domain_of_explicit_set,WF),
2609 domain_of_list_blocking(EC,R),
2610 normalised_list_to_avl_when_ground(R,Res).
2611
2612 % avl tree is a relation with an integer domain
2613 %avl_integer_domain(node((int(_From),_KeyTo),_True,_,_L,_R)).
2614
2615 % the first clause is in principle faster
2616 % but we don't gain time compared to treatment in second clause; we just avoid building up the domain list
2617 %domain_of_avl_set(A,Res) :- avl_integer_domain(A),
2618 % \+ avl_tools:avl_height_less_than(A,10), % try and detect interval if height >= 10
2619 % avl_is_pf_with_interval_domain(A,First,Last),!,
2620 % construct_interval_closure(First,Last,Res).
2621 domain_of_avl_set(A,Res) :-
2622 avl_domain(A,EC), % -> expand_custom_set(avl_set(A),EC),
2623 domain_of_sorted_list(EC,SizeRes,R), % size of list can be smaller than A if we have a relation
2624 (SizeRes=size_res(Size,int(Last)), R=[int(First)-true|_],
2625 Size>1000,
2626 Size is Last+1-First % we have an interval; quite common that we have functions with intervals as domain
2627 -> debug_println(19,constructing_interval_for_domain(First,Last)),
2628 construct_interval_closure(First,Last,Res)
2629 ; ord_list_to_avlset(R,Res,domain)
2630 ).
2631
2632 % check if an AVL tree represents a function with an interval domain
2633 %avl_is_pf_with_interval_domain(AVL,Min,Max) :-
2634 % avl_min(AVL,(int(Min),_)),avl_max(AVL,(int(Max),_)),
2635 % Size is 1+Max-Min, avl_size_possible(AVL,Size),
2636 % is_avl_partial_function(AVL),
2637 % % now check real size
2638 % avl_size(AVL,Size).
2639
2640 % check if an avl represents a set of integers:
2641 avl_integer_set(node(int(_TOP),_True,_,_L,_R)).
2642
2643 % check if an avl set is an interval:
2644 avl_is_interval(AVL,Min,Max) :-
2645 avl_integer_set(AVL),
2646 avl_min(AVL,int(Min)),avl_max(AVL,int(Max)),
2647 Size is 1+Max-Min,
2648 avl_size_possible(AVL,Size),
2649 avl_size(AVL,Size).
2650
2651
2652
2653 :- use_module(bsyntaxtree,[create_typed_id/3]).
2654 dom_symbolic(closure(Paras,Types,Pred), Res) :-
2655 expand_pair_closure(Paras,Types,Pred,[X,Y],[TX,TY],NewPred),
2656 !, % single argument which is a pair
2657 % simply call code for range ; inverting arguments
2658 bsyntaxtree:check_used_ids_in_ast(Pred),
2659 bsyntaxtree:check_used_ids_in_ast(NewPred),
2660 ran_symbolic_closure(Y,[X],TY,[TX],NewPred,Res).
2661 dom_symbolic(closure(Paras,Types,Pred), Res) :-
2662 append(Xs,[Y],Paras), Xs \= [],
2663 append(TXs,[TY],Types),
2664 % simply call code for range ; inverting arguments
2665 ran_symbolic_closure(Y,Xs,TY,TXs,Pred,Res).
2666 % TO DO: allow computation if Paras is a single argument and more than pair
2667
2668 % just computes domain: it can also be successful for lambda closures
2669 dom_for_specific_closure(closure(P,T,Pred),Domain,Functionality,WF) :-
2670 dom_for_specific_closure_aux(P,T,Pred,Domain,Functionality,WF).
2671 dom_for_specific_closure_aux(P,T,Pred,Domain,Functionality,_WF) :-
2672 is_lambda_value_domain_closure(P,T,Pred, DomainValue,Expr),
2673 (preference(find_abort_values,full) -> bsyntaxtree:always_well_defined_or_disprover_mode(Expr)
2674 ; true),
2675 % Warning: this will lead to dom(%x.(x:1..3|1/0)) = 1..3 to be true; discarding WD condition
2676 % this is not as bad as {1|->2}(0) = 3 to be silently failing though; hence only done if TRY_FIND_ABORT = full
2677 !,
2678 Domain=DomainValue,
2679 Functionality=function(total).
2680 dom_for_specific_closure_aux(P,T,Pred,Domain,Functionality,WF) :-
2681 dom_range_for_specific_closure2(P,T,Pred, Domain,_Range,Functionality,WF).
2682 %TO DO treat overwrite closure dom(F1<+F2) = dom(F1) \/ dom(F2)
2683
2684 dom_for_lambda_closure(closure(P,T,Pred),Domain) :-
2685 is_lambda_value_domain_closure(P,T,Pred, DomainValue,_Expr),
2686 Domain=DomainValue.
2687
2688 % TO DO: add total functions
2689 %dom_for_specific_closure2([F],[T],
2690 % b(member(b(identifier(F),T,_), b(total_function(value(A),B),set(couple(DOM,RAN)),_)), pred,_) ,
2691 % A).
2692
2693 :- block domain_of_list_blocking(-,?).
2694 % the list will be sorted according to the term ordering for (_,_); hence it will
2695 % already be sorted for the projection onto the first element
2696 % maybe the speed difference is not worth it ??
2697 domain_of_list_blocking([],[]).
2698 domain_of_list_blocking([(A,_B)|T],[A-true|DT]) :- domain_blocking_aux(T,A,DT).
2699 :- block domain_blocking_aux(-,?,?).
2700 domain_blocking_aux([],_,[]).
2701 domain_blocking_aux([(A,_B)|T],Prev,Res) :-
2702 compare(Comp,A,Prev),
2703 (Comp = '='
2704 -> domain_blocking_aux(T,Prev,Res)
2705 ; Res = [A-true|DT],
2706 (Comp = '<' -> add_error_fail(custom_explicit_sets,'Domain list not_sorted: ',(A,Prev)) ; true),
2707 domain_blocking_aux(T,A,DT) ).
2708
2709 % and now a non-blocking version:
2710 domain_of_sorted_list([],size_res(0,'$none'),[]).
2711 domain_of_sorted_list([(A,_B)|T],Size,[A-true|DT]) :- domain_aux(T,A,DT,1,Size).
2712
2713 % TO DO: count length and determine when we have an interval
2714 domain_aux([],Prev,[],Acc,size_res(Acc,Prev)).
2715 domain_aux([(A,_B)|T],Prev,Res,SizeAcc,Size) :- SA1 is SizeAcc+1,
2716 compare(Comp,A,Prev),
2717 (Comp = '='
2718 -> domain_aux(T,Prev,Res,SA1,Size)
2719 ; Res = [A-true|DT],
2720 (Comp = '<' -> add_error_fail(custom_explicit_sets,'Domain list not_sorted: ',(A,Prev)) ; true),
2721 domain_aux(T,A,DT,SA1,Size) ).
2722
2723 /* succeeds if it can compute domain by some clever way */
2724 range_of_explicit_set_wf(global_set(GS),_R,_) :- !,
2725 add_error_and_fail(range_of_explicit_set_wf,'Cannot compute domain of global set: ',GS).
2726 range_of_explicit_set_wf(freetype(GS),_R,_) :- !,
2727 add_error_and_fail(range_of_explicit_set_wf,'Cannot compute domain of freetype: ',GS).
2728 range_of_explicit_set_wf(avl_set(A),Res,_) :- !,
2729 avl_domain(A,EC), % -> expand_custom_set(avl_set(A),EC),
2730 range(EC,R),
2731 normalised_list_to_avl(R,Res).
2732 range_of_explicit_set_wf(C,R,WF) :-
2733 ran_for_specific_closure(C,Ran,WF),!,
2734 Ran=R.
2735 range_of_explicit_set_wf(C,R,_) :-
2736 ran_symbolic(C,CC),!,
2737 R=CC.
2738 range_of_explicit_set_wf(closure(P,T,B),Res,WF) :-
2739 expand_custom_set_wf(closure(P,T,B),EC,range_of_explicit_set_wf,WF),
2740 % TO DO: it would be more useful here to directly just expand the projection onto the last component of P
2741 range_blocking(EC,R),
2742 normalised_list_to_avl_when_ground(R,Res).
2743
2744 % TO DO: in future it is maybe better to add an in_range_wf kernel predicate
2745 ran_symbolic(closure(Paras,Types,Pred), Res) :-
2746 ? (is_memoization_closure(Paras,Types,Pred,_)
2747 -> !,fail % memoization closures can never be dealt with symbolically; we need expansion
2748 ; true),
2749 expand_pair_closure(Paras,Types,Pred,[Y,X],[TY,TX],NewPred),!,
2750 % following test (1541) works with this: 2 : ran({y|#(x).(y = x |-> x + 2 & x : NATURAL)})
2751 ran_symbolic_closure(Y,[X],TY,[TX],NewPred,Res). %, print('res: '),translate:print_bvalue(Res),nl.
2752 ran_symbolic(closure([Y,X],[TY,TX],Pred), Res) :-
2753 ran_symbolic_closure(Y,[X],TY,[TX],Pred,Res).
2754 % TO DO: treat closures with more arguments: we need to quantify Y1,...Yn [Y1,...,Yn,X]
2755
2756 % Replace single Identifier YX of type pair by pair (Y,X) where Y,X are (fresh) variables not occuring in Pred
2757 % example: {y| #(x).(y = x |-> x + 2 & x : NATURAL)} --> {y__1,y__2|#(x).(y__1 |-> y__2 = x |-> x + 2 & x : NATURAL)}
2758 expand_pair_closure([YX],[TYX],Pred,[Y,X],[TY,TX],NewPred) :- TYX = couple(TY,TX),
2759 % Replace single ID YX of type pair by pair (Y,X) where Y,X are (fresh) variables not occuring in Pred
2760 % example: {y| #(x).(y = x |-> x + 2 & x : NATURAL)} --> {y__1,y__2|#(x).(y__1 |-> y__2 = x |-> x + 2 & x : NATURAL)}
2761 % following test (1541) works with this: 2 : ran({y|#(x).(y = x |-> x + 2 & x : NATURAL)})
2762 gensym:gensym(YX,Y),gensym:gensym(YX,X),
2763 create_typed_id(Y,TY,YTID), create_typed_id(X,TX,XTID),
2764 Pair = b(couple(YTID,XTID),TYX,[]),
2765 bsyntaxtree:replace_id_by_expr(Pred,YX,Pair,NewPred).
2766
2767 :- use_module(bsyntaxtree,[create_exists_opt_liftable/3]).
2768 %:- use_module(bsyntaxtree,[add_texpr_info_if_new/3]).
2769 ran_symbolic_closure(Y,Xs,TY,TXs,Pred,Res) :-
2770 % create closure for {Xs | #Y.(Pred)} where Pred uses Y|->Xs
2771 rename_ran_ids(Xs,Pred,[],XIDs,Pred2),
2772 create_typed_id(Y,TY,YTID),
2773 create_exists_opt_liftable([YTID],Pred2,Exists), % Y is liftable as the source is a closure with all ids
2774 %bsyntaxtree:check_used_ids_in_ast(Exists),
2775 %bsyntaxtree:create_exists_opt([YTID],[Pred2],Exists), %or
2776 %b_interpreter_components:create_and_simplify_exists([YTID],Pred2,Exists),
2777 %bsyntaxtree:add_texpr_info_if_new(Exists,allow_to_lift_exists,Exists2), % leads to pending co-routines in self_checks for bsets for apply_to;
2778 % Reason: the tests ground only det WF; without lifting the exists is fully evaluated (and its waitflags with prio 2 and higher grounded) as the wait arguments are ground; with lifting only the det WF is grounded leading to pending coroutines
2779 Res = closure(XIDs,TXs,Exists).
2780
2781
2782
2783 :- use_module(library(lists),[select/3]).
2784
2785 % rename lambda_results :
2786 rename_ran_ids([],Pred,_,[],Pred).
2787 rename_ran_ids([X|TX],Pred,Acc,[XID|TTX],Pred2) :-
2788 % in case X is _lambda_result_ we need to rename it as it then would not get enumerated !
2789 (X == '_lambda_result_'
2790 -> get_fresh_id('_was_lambda_result_',TX,Acc,XID),
2791 % we could remove lambda_result info field, but it will no longer match new id anyway
2792 rename_bt(Pred,[rename(X,XID)],Pred2),
2793 TTX=TX
2794 % TODO: maybe we should also remove the prob_annotation('LAMBDA-EQUALITY') info inside Pred for the ids and equality !?
2795 ; XID = X, rename_ran_ids(TX,Pred,[X|Acc],TTX,Pred2)
2796 ).
2797
2798 :- use_module(b_ast_cleanup,[get_unique_id/2]).
2799 get_fresh_id(ID,List1,List2,Res) :- nonmember(ID,List1), nonmember(ID,List2),!, Res=ID.
2800 get_fresh_id(ID,_,_,FRESHID) :- nl,print('*** VARIABLE_CLASH PREVENTED: '), print(ID),nl,
2801 get_unique_id(ID,FRESHID).
2802
2803 :- block range_blocking(-,?).
2804 range_blocking([],[]).
2805 range_blocking([(_A,B)|T],[B-true|DT]) :- range_blocking(T,DT).
2806 % and a non-blocking version:
2807 range([],[]).
2808 range([(_A,B)|T],[B-true|DT]) :- range(T,DT).
2809
2810 ran_for_specific_closure(closure(P,T,Pred),Range,WF) :-
2811 dom_range_for_specific_closure2(P,T,Pred, _Domain,Range,_Functionality,WF).
2812 %ran_for_specific_closure(closure_x(P,T,Pred,_Exp),Card,_) :- ran_for_specific_closure2(P,T,Pred,Card).
2813
2814 :- use_module(bsyntaxtree,[conjunct_predicates/2, disjunct_predicates/2, create_typed_id/3, get_texpr_type/2]).
2815 override_custom_explicit_set_wf(R,S,Res,WF) :- /* R <+ S */
2816 nonvar(R),override_custom_explicit_set_aux(R,S,Res,WF).
2817 override_custom_explicit_set_aux(CL,Rel2,Res,_WF) :-
2818 CL=closure(P0,T,B0),
2819 % TO DO: maybe call keep_symbolic in bsets_clp ??
2820 ( preferences:get_preference(convert_comprehension_sets_into_closures,true),
2821 (var(Rel2) -> true ; Rel2 \= avl_set(_)) % if Rel2 is avl_set then maybe better to compute explicitly; unless infinite
2822 ; quick_size_check_larger_than(Rel2,Size2,133) ->
2823 % if we have a large AVL set anyway; then allow expansion up to a larger limit; cf machine 670_002.mch
2824 % a lot of machines use A*B*C <+ {....} to more compactly define large explicit sets
2825 (Size2=inf -> Limit = 200000
2826 ; Limit is min(200000,Size2*150)), dont_expand_this_closure(P0,T,B0,Limit)
2827 ? ; dont_expand_this_closure(P0,T,B0) % use default limit
2828 ),
2829 !,
2830 rename_ran_ids(P0,B0,[],P,B), % any '_lambda_result_' id is no longer guaranteed to be assigned a value in all cases
2831 NewClosure=closure(P,T,NewBody),
2832 % B <+ Rel2 ---> NewBody = P:Rel2 or (prj1(P) /: dom(Rel2) & B)
2833 % TODO better? : %x.(x:Domain|IF x:dom(SFF) THEN SFF(x) ELSE DEFAULT)?
2834 generate_typed_id_pairs(P,T,NestedPairs),
2835 get_texpr_type(NestedPairs,PairsType),
2836 RelPairsType = set(PairsType),
2837 ValS = b(value(Rel2),RelPairsType,[]),
2838 MemS = b(member(NestedPairs,ValS),pred,[]), % P:Rel2
2839 get_prj1(NestedPairs,DomExpr),
2840 get_texpr_type(DomExpr,DomType),
2841 Domain = b(domain(ValS),set(DomType),[]), % TO DO: perform some optimisations like dom(%x.(P|E)) --> {x|P}
2842 %bsets_clp:domain_wf(Rel2,DomainOfRel2,WF), Domain = b(value(DomainOfRel2),DomType,[]), % this DOES NOT work for 1619, 1706 where override is used for infinite functions
2843 NotMemDomS = b(not_member(DomExpr,Domain),pred,[]), % prj1(P) /: dom(Rel2)
2844 conjunct_predicates([NotMemDomS,B],RHS),
2845 disjunct_predicates([MemS,RHS],NewBody),
2846 %print(override),nl, bsyntaxtree:check_used_ids_in_ast(NewBody),
2847 mark_closure_as_symbolic(NewClosure,Res).
2848 % TO DO: add a case where for second set we have: dont_expand_this_closure
2849 override_custom_explicit_set_aux(R,S,Res,WF) :-
2850 is_custom_explicit_set(R,override_custom_explicit_set),
2851 nonvar(S), is_custom_explicit_set(S,override_custom_explicit_set),
2852 %% hit_profiler:add_profile_hit(override(R,S),3), %%
2853 override_custom_explicit_set2(R,S,Res,WF).
2854
2855 override_custom_explicit_set2(R,S,Res,_WF) :- is_one_element_custom_set(S,(X,Y)),
2856 override_pair_explicit_set(R,X,Y,NewR),!,
2857 Res=NewR.
2858 % TO DO: if R is very large and S relatively small : iterate by calling override_pair_explicit_set
2859 override_custom_explicit_set2(R,S,Res,WF) :-
2860 expand_custom_set_wf(R,ER,override_custom_explicit_set_aux1,WF),
2861 expand_custom_set_wf(S,ES,override_custom_explicit_set_aux2,WF),
2862 override_list(ER,ES,LRes,Done),
2863 finish_restriction(Done,LRes,Res).
2864
2865 quick_size_check_larger_than(Set,Size,Limit) :-
2866 quick_custom_explicit_set_approximate_size(Set,Size),
2867 (Size == inf -> true ; Size > Limit).
2868 get_prj1(b(couple(DomExpr,_),_,_),Prj1) :- !, Prj1 = DomExpr.
2869 get_prj1(BE,b(first_of_pair(BE),DT,[])) :- % some closures have a single identifier; we need to apply prj1
2870 BE = b(_E,couple(DT,_RT),_I).
2871
2872 % translate a parameter name and type list into a nested-pair value
2873 generate_typed_id_pairs([ID|IT],[Type|TT],Res) :- create_typed_id(ID,Type,TypedID),
2874 conv2(IT,TT,TypedID,Res).
2875 conv2([],[],X,X).
2876 conv2([ID|IT],[Type|TT],Acc,Res) :- create_typed_id(ID,Type,TypedID),
2877 get_texpr_type(Acc,AccType),
2878 Couple = b(couple(Acc,TypedID),couple(AccType,Type),[]),
2879 conv2(IT,TT,Couple,Res).
2880
2881 :- block override_list(-,?,?,?), override_list(?,-,?,?).
2882 override_list([],S,Res,Done) :- !, copy_to_true_list(S,Res,Done).
2883 override_list(R,[],Res,Done) :- !, copy_to_true_list(R,Res,Done).
2884 override_list([(From1,To1)|T1],[(From2,To2)|T2],Res,Done) :-
2885 (From1 @< From2
2886 -> Res = [(From1,To1)-true|TR], override_list(T1,[(From2,To2)|T2],TR,Done)
2887 ; From2 @< From1
2888 -> Res = [(From2,To2)-true|TR], override_list([(From1,To1)|T1],T2,TR,Done)
2889 ; override_list(T1,[(From2,To2)|T2],Res,Done)).
2890
2891 :- block copy_to_true_list(-,?,?).
2892 % add -true to get lists that can be converted to avl
2893 copy_to_true_list([],[],true).
2894 copy_to_true_list([H|T],[H-true|CT],Done) :- copy_to_true_list(T,CT,Done).
2895
2896 :- use_module(closures,[get_domain_range_for_closure_types/3]).
2897 % compute a closure with the functionality violations of a closure
2898 symbolic_functionality_check_closure(closure(P,T,B),closure([DID,ID1,ID2],[DomType,RanType,RanType],Body)) :-
2899 % construct {d,z_,z__| (d,z_):R & (d,z__):R & z_\= z__}
2900 generate_typed_id_pairs(P,T,NestedPairs),
2901 get_texpr_type(NestedPairs,PairsType),
2902 RelPairsType = set(PairsType),
2903 TRel = b(value(closure(P,T,B)),RelPairsType,[]),
2904 DID = '_domain', ID1 = '_zzzz_unary', ID2 = '_zzzz_binary',
2905 TDID = b(identifier(DID),DomType,[]),
2906 TID1 = b(identifier(ID1),RanType,[]),
2907 TID2 = b(identifier(ID2),RanType,[]),
2908 Mem1 = b(member( b(couple(TDID,TID1),PairsType,[]),TRel),pred,[]),
2909 Mem2 = b(member( b(couple(TDID,TID2),PairsType,[]),TRel),pred,[]),
2910 get_domain_range_for_closure_types(T,DomType,RanType),
2911 NeqRan = b(not_equal(TID1,TID2), pred, []),
2912 conjunct_predicates([Mem1,Mem2,NeqRan],Body),
2913 bsyntaxtree:check_used_ids_in_ast(Body).
2914 %bsyntaxtree:check_ast(Body).
2915
2916 % compute a closure with the injectivity violations of a closure
2917 symbolic_injectivity_check_closure(closure(P,T,B),closure([RID,ID1,ID2],[RanType,DomType,DomType],Body)) :-
2918 % construct {r,z_,z__| (z_,r):R & (z__,r):R & z_\= z__}
2919 generate_typed_id_pairs(P,T,NestedPairs),
2920 get_texpr_type(NestedPairs,PairsType),
2921 RelPairsType = set(PairsType),
2922 TRel = b(value(closure(P,T,B)),RelPairsType,[]), % what if closure body B has WD condition?
2923 RID = '_range', ID1 = '_zzzz_unary', ID2 = '_zzzz_binary',
2924 TRID = b(identifier(RID),RanType,[]),
2925 TID1 = b(identifier(ID1),DomType,[]),
2926 TID2 = b(identifier(ID2),DomType,[]),
2927 Mem1 = b(member( b(couple(TID1,TRID),PairsType,[]),TRel),pred,[]),
2928 Mem2 = b(member( b(couple(TID2,TRID),PairsType,[]),TRel),pred,[]),
2929 get_domain_range_for_closure_types(T,DomType,RanType),
2930 NeqRan = b(not_equal(TID1,TID2), pred, []),
2931 conjunct_predicates([Mem1,Mem2,NeqRan],Body),
2932 bsyntaxtree:check_used_ids_in_ast(Body).
2933 %bsyntaxtree:check_ast(Body).
2934
2935 % -------------------------
2936
2937
2938 % check whether we have a partial function
2939 is_avl_partial_function(empty) :- !.
2940 is_avl_partial_function(node((KeyFrom,_KeyTo),_True,_,L,R)) :- !,
2941 is_avl_partial_function2(L,'$$MIN$$',KeyFrom),
2942 is_avl_partial_function2(R,KeyFrom,'$$MAX$$').
2943 is_avl_partial_function(X) :- add_internal_error('Not avl_set or relation: ',is_avl_partial_function(X)),fail.
2944
2945 % we traverse the tree from top to bottom, keeping track of possible upper- and lower-bounds
2946 % if any value matches the upper or lower bound, the we do not have a partial function
2947 is_avl_partial_function2(empty,_,_).
2948 is_avl_partial_function2(node((KeyFrom,_KeyTo),_True,_,L,R),ParentFrom,ParentTo) :-
2949 KeyFrom \= ParentFrom, KeyFrom \= ParentTo,
2950 is_avl_partial_function2(L,ParentFrom,KeyFrom),
2951 is_avl_partial_function2(R,KeyFrom,ParentTo).
2952
2953 % the dual of the above, returning a counter example
2954 is_not_avl_partial_function(node((KeyFrom,_KeyTo),_True,_,L,R),DuplicateKey) :- !,
2955 (is_not_avl_partial_function2(L,'$$MIN$$',KeyFrom,DuplicateKey) -> true
2956 ; is_not_avl_partial_function2(R,KeyFrom,'$$MAX$$',DuplicateKey)).
2957 is_not_avl_partial_function2(node((KeyFrom,_KeyTo),_True,_,L,R),ParentFrom,ParentTo,DuplicateKey) :-
2958 ( KeyFrom = ParentFrom -> DuplicateKey=KeyFrom
2959 ; KeyFrom = ParentTo -> DuplicateKey=KeyFrom
2960 ; is_not_avl_partial_function2(L,ParentFrom,KeyFrom,DuplicateKey) -> true
2961 ; is_not_avl_partial_function2(R,KeyFrom,ParentTo,DuplicateKey) -> true).
2962
2963
2964 % check whether we have a function which is total over a given domain; both as AVL sets
2965 is_avl_total_function_over_domain(empty,empty) :- !.
2966 is_avl_total_function_over_domain(AVLFun,AVLDom) :-
2967 avl_domain(AVLFun,FunList),
2968 avl_domain(AVLDom,DomList),
2969 is_avl_total_fun2(FunList,DomList).
2970
2971 is_avl_total_fun2([],[]).
2972 is_avl_total_fun2([(From,_To)|FT],[From|DomT]) :- is_avl_total_fun2(FT,DomT).
2973
2974
2975 %not_is_avl_partial_function(AVLF) :- \+ is_avl_partial_function(AVLF).
2976
2977 :- use_module(kernel_equality,[membership_test_wf/4]).
2978 % check whether an AVL Relation is not over a specific domain & range
2979 is_not_avl_relation_over_domain_range(AVLRel,Domain,Range,WF) :- AVLRel \= empty,
2980 avl_min_pair(AVLRel,RFrom,RTo),
2981 membership_test_wf(Domain,RFrom,MemRes,WF),
2982 is_not_avl_rel_dom1(MemRes,RFrom,RTo,AVLRel,Domain,Range,WF).
2983
2984 :- block is_not_avl_rel_dom1(-, ?,?,?,?,?,?).
2985 is_not_avl_rel_dom1(pred_false,_,_,_,_,_,_WF).
2986 is_not_avl_rel_dom1(pred_true,RFrom,RTo,AVLRel,Domain,Range,WF) :-
2987 membership_test_wf(Range,RTo,MemRes,WF),
2988 is_not_avl_rel_dom2(MemRes,RFrom,RTo,AVLRel,Domain,Range,WF).
2989
2990 :- block is_not_avl_rel_dom2(-, ?,?,?,?,?,?).
2991 is_not_avl_rel_dom2(pred_false,_,_,_,_,_,_WF).
2992 is_not_avl_rel_dom2(pred_true,RFrom,RTo,AVLRel,Domain,Range,WF) :-
2993 avl_next((RFrom,RTo),AVLRel,(RFrom2,RTo2)),
2994 membership_test_wf(Domain,RFrom2,MemRes,WF),
2995 is_not_avl_rel_dom1(MemRes,RFrom2,RTo2,AVLRel,Domain,Range,WF).
2996
2997 % check whether an AVL Relation is not over a specific range
2998 is_not_avl_relation_over_range(AVLRel,Range,WF) :- AVLRel \= empty,
2999 avl_min_pair(AVLRel,RFrom,RTo),
3000 membership_test_wf(Range,RTo,MemRes,WF),
3001 is_not_avl_rel_ran2(MemRes,RFrom,RTo,AVLRel,Range,WF).
3002
3003 :- block is_not_avl_rel_ran2(-, ?,?,?,?,?).
3004 is_not_avl_rel_ran2(pred_false,_,_,_,_,_WF).
3005 is_not_avl_rel_ran2(pred_true,RFrom,RTo,AVLRel,Range,WF) :-
3006 avl_next((RFrom,RTo),AVLRel,(RFrom2,RTo2)),
3007 kernel_equality:membership_test_wf(Range,RTo2,MemRes,WF),
3008 is_not_avl_rel_ran2(MemRes,RFrom2,RTo2,AVLRel,Range,WF).
3009
3010 % check whether we have a relation
3011 is_avl_relation(node((_KeyFrom,_KeyTo),_True,_,_,_)).
3012
3013 % check whether a Relation has all its range elments in a certain Range (not necessarily AVL)
3014 % TO DO: if Domain is an interval: we could take avl_min and avl_max and rely on lexicographic ordering
3015 is_avl_relation_over_domain(AVL,IntervalClosure,_WF) :-
3016 is_interval_closure_or_integerset(IntervalClosure,Low,Up),!,
3017 ((avl_min(AVL,(int(ALow),_)), avl_max(AVL,(int(AUp),_)))
3018 -> cs_greater_than_equal(ALow,Low), cs_greater_than_equal(Up,AUp) %,print(ok),nl
3019 ; (AVL=empty -> true ; add_error_and_fail(is_avl_relation_over_domain,'Not a relation with integer domain: ',AVL))).
3020 is_avl_relation_over_domain(_,Domain,_) :-
3021 quick_is_definitely_maximal_set(Domain),!.
3022 %is_definitely_maximal_set(Domain),!.
3023 is_avl_relation_over_domain(AVL,Domain,WF) :- is_avl_relation_over_domain2(AVL,Domain,WF).
3024 is_avl_relation_over_domain2(empty,_,_).
3025 is_avl_relation_over_domain2(node((KeyFrom,_KeyTo),_,_,L,R), Domain,WF) :-
3026 is_avl_relation_over_domain2(L, Domain,WF),
3027 is_avl_relation_over_domain2(R, Domain,WF),
3028 kernel_objects:check_element_of_wf(KeyFrom,Domain,WF).
3029
3030 % : faster to check than is_definitely_maximal_set
3031 quick_is_definitely_maximal_set(X) :- nonvar(X),
3032 quick_is_definitely_maximal_set_aux(X).
3033 quick_is_definitely_maximal_set_aux(global_set(GS)) :-
3034 nonvar(GS),is_maximal_global_set(GS).
3035 quick_is_definitely_maximal_set_aux(avl_set(AVL)) :-
3036 quick_definitely_maximal_set_avl(AVL).
3037
3038 % check whether a Relation has all its range elments in a certain Range (not necessarily AVL)
3039
3040
3041
3042 is_avl_relation_over_range(empty,_,_) :- !.
3043 is_avl_relation_over_range(_,Range,_) :-
3044 %quick_is_definitely_maximal_set(Range),
3045 is_definitely_maximal_set(Range),
3046 !.
3047 is_avl_relation_over_range(AVL,Range,WF) :- is_avl_relation_over_range2(AVL,Range,WF).
3048
3049 is_avl_relation_over_range2(empty,_,_).
3050 is_avl_relation_over_range2(node((_KeyFrom,KeyTo),_,_,L,R), Range,WF) :-
3051 is_avl_relation_over_range(L, Range,WF),
3052 kernel_objects:check_element_of_wf(KeyTo,Range,WF),
3053 is_avl_relation_over_range2(R, Range,WF).
3054
3055
3056 is_avl_sequence(empty) :- !.
3057 is_avl_sequence(node((int(KeyFrom),_KeyTo),_True,_,L,R)) :- !,
3058 is_avl_sequence2(L,0,KeyFrom),
3059 is_avl_sequence2(R,KeyFrom,'$$MAX$$').
3060 is_avl_sequence(X) :- add_error_and_fail(is_avl_sequence,'Not avl_set or sequence: ',X).
3061
3062 % we traverse the tree from top to bottom, keeping track of possible upper- and lower-bounds
3063 % if any value matches the upper or lower bound, the we do not have a partial function
3064 is_avl_sequence2(empty,X,Y) :-
3065 (Y=='$$MAX$$' -> true ; Y is X+1). % otherwise there is a gap in the sequence
3066 is_avl_sequence2(node((int(KeyFrom),_KeyTo),_,_,L,R),ParentFrom,ParentTo) :-
3067 KeyFrom > ParentFrom, KeyFrom \= ParentTo,
3068 is_avl_sequence2(L,ParentFrom,KeyFrom),
3069 is_avl_sequence2(R,KeyFrom,ParentTo).
3070
3071 % for performance: it is not worthwhile to make a version that checks that
3072 % we have a sequence over a range using a single traversal
3073
3074
3075 % get avl_sequence elements as sorted list (without indices)
3076 % used by external function REPLACE
3077 get_avl_sequence(AVL,SeqList) :-
3078 get_avl_sequence_dcg(AVL,SeqList,[]).
3079
3080 get_avl_sequence_dcg(empty) --> [].
3081 get_avl_sequence_dcg(node((int(_),SeqEl),_True,_,L,R)) -->
3082 get_avl_sequence_dcg(L),
3083 [SeqEl],
3084 get_avl_sequence_dcg(R).
3085
3086
3087 % ---------------------------
3088 prefix_of_custom_explicit_set(avl_set(A),MinIndex,Result,WF) :-
3089 size_of_avl_sequence(A,Size,WF),
3090 (MinIndex > Size
3091 -> add_wd_error('index larger than size of sequence in prefix_sequence (/|\\)! ', '>'(MinIndex,Size),WF)
3092 % ; MinIndex = 0 -> Result = [] % case already treated in bsets_clp
3093 ; MinIndex = Size -> Result=avl_set(A)
3094 ; prefix_of_custom_explicit_set2(A,MinIndex,OrdList,[]),
3095 ord_list_to_avlset(OrdList,Result,prefix_of_custom_explicit_set)
3096 ).
3097 prefix_of_custom_explicit_set2(empty,_MaxIndex) --> {true}.
3098 prefix_of_custom_explicit_set2(node((int(KeyFrom),KeyTo),_True,_,L,R),MaxIndex) -->
3099 ({KeyFrom = MaxIndex}
3100 -> prefix_of_custom_explicit_set2(L,MaxIndex), [((int(KeyFrom),KeyTo)-true)]
3101 ; {KeyFrom > MaxIndex} -> prefix_of_custom_explicit_set2(L,MaxIndex)
3102 ; prefix_of_custom_explicit_set2(L,MaxIndex), [((int(KeyFrom),KeyTo)-true)],
3103 prefix_of_custom_explicit_set2(R,MaxIndex)
3104 ).
3105
3106 % size is only well-defined for sequences:
3107 size_of_custom_explicit_set(avl_set(AVL),int(Size),WF) :- size_of_avl_sequence(AVL,Size,WF).
3108 size_of_custom_explicit_set(closure(P,T,B),Res,WF) :-
3109 is_lambda_value_domain_closure(P,T,B, DomainValue,_Expr),
3110 kernel_cardinality_attr:finite_cardinality_as_int_wf(DomainValue,Res,WF).
3111 size_of_avl_sequence(AVL,Size,WF) :-
3112 preference(find_abort_values,true),
3113 \+ is_avl_sequence(AVL),!,
3114 avl_max_pair(AVL,int(Sz),_),
3115 add_wd_error('Applying size to a value which is not a sequence',b(value(avl_set(AVL)),seq(any),[]),WF),
3116 Size=Sz. % other calls to size_of_avl_sequence currently expect a value
3117 size_of_avl_sequence(AVL,Size,WF) :-
3118 % TO DO: checking minimum is 1?
3119 avl_max_pair(AVL,int(Sz),_),
3120 avl_height(AVL,H), % we cannot compute the height together with max; we need the longest path!
3121 get_min_max_card(H,MinSize,MaxSize),
3122 %avl_size(AVL,Real),format('AVL SeqSize: ~w, height: ~w, real size:~w, min: ~w, max: ~w~n',[Sz,H,Real,MinSize,MaxSize]),
3123 (Sz > MaxSize
3124 -> add_wd_error('Applying size to a value which is not a sequence (maximum index too large)',b(value(avl_set(AVL)),seq(any),[]),WF),
3125 avl_size(AVL,Size)
3126 % triggered by e.g. size({0|->1,0|->2,1|->3}) or size({0|->1,1|->2,3|->3,1|->22,1|->23,1|->24,1|->25,1|->26})
3127 ; Sz < MinSize
3128 -> add_wd_error('Applying size to a value which is not a sequence (maximum index too small)',b(value(avl_set(AVL)),seq(any),[]),WF),
3129 avl_size(AVL,Size)
3130 % triggered by e.g. size([0,2,2,2] |> {2})
3131 ; Size=Sz).
3132
3133 get_min_max_card(Height,MinCard,MaxCard) :-
3134 % page 460, Knuth 3: The height of a balanced tree with N internal nodes always lies between lg(N+1) and 1.4405 lg(N+2) - 0.3277
3135 MaxCard is 2^Height - 1,
3136 % 1.618034 is golden ration phi 0.5(1+sqrt(5)) , 2.236068 is sqrt(5)
3137 % proof in Knuth uses fact: N > phi^(h+2)/sqrt(5) - 2
3138 MinCard is ceiling((1.61803398875**(Height+2)) / 2.2360679775 - 2).
3139
3140 % check if a candidate size is possible given height:
3141 avl_size_possible(AVL,SizeCandidate) :-
3142 avl_height(AVL,Height), % TO DO: restrict to something like log2 of Height
3143 get_min_max_card(Height,MinCard,MaxCard),
3144 MinCard =< SizeCandidate,
3145 SizeCandidate =< MaxCard.
3146
3147
3148 suffix_of_custom_explicit_set(avl_set(A),MinIndex,Result,WF) :-
3149 size_of_avl_sequence(A,Size,WF),
3150 (MinIndex > Size
3151 -> add_wd_error('index larger than size of sequence in suffix_sequence (\\|/)! ', '>'(MinIndex,Size),WF)
3152 % ; MinIndex = 0 -> Result = avl_set(A) % case already treated in bsets_clp
3153 ; MinIndex = Size -> Result=[]
3154 ; suffix_of_custom_explicit_set2(A,MinIndex,OrdList,[]),
3155 ord_list_to_avlset(OrdList,Result,suffix_of_custom_explicit_set)
3156 ).
3157 suffix_of_custom_explicit_set2(empty,_MinIndex) --> {true}.
3158 suffix_of_custom_explicit_set2(node((int(KeyFrom),KeyTo),_True,_,L,R),MinIndex) -->
3159 ({KeyFrom =< MinIndex} -> suffix_of_custom_explicit_set2(R,MinIndex)
3160 ; {ShiftedKeyFrom is KeyFrom-MinIndex},
3161 ({KeyFrom =:= MinIndex+1}
3162 -> {true} ; suffix_of_custom_explicit_set2(L,MinIndex)),
3163 [((int(ShiftedKeyFrom),KeyTo)-true)],
3164 suffix_of_custom_explicit_set2(R,MinIndex)
3165 ).
3166
3167 shift_avl_sequence_to_ord_list(AVL,Offset,ShiftedOrdList) :-
3168 avl_to_list(AVL,List),shift_seq(List,Offset,ShiftedOrdList).
3169 % it does not seem to be worth to use avl_to_list_dcg_offset or a variation thereof
3170 % it is not really slower to do two traversals (avl_to_list and shift_seq)
3171
3172 shift_seq([],_,[]).
3173 shift_seq([(int(I),Val)-true|T],Offset,[(int(NI),Val)-true|ST]) :- NI is I+Offset,
3174 shift_seq(T,Offset,ST).
3175
3176 :- use_module(debug).
3177 concat_custom_explicit_set(avl_set(S1),Seq2,Res,WF) :- nonvar(Seq2), Seq2=avl_set(S2),
3178 size_of_avl_sequence(S1,Size1,WF),
3179 shift_avl_sequence_to_ord_list(S2,Size1,OL2),
3180 % if OL2 is small we could use avl_store like in append_custom_explicit_set
3181 %avl_to_list(S1,OL1),
3182 avl_to_list_dcg(S1,NewOrdList,OL2), % use OL2 rather than [] as tail
3183 %append(OL1,OL2,NewOrdList), % we could avoid traversing OL1 again by doing a custom avl_to_list/3 which specifies tail
3184 ord_list_to_avlset(NewOrdList,Res,concat). % , print_term_summary(res_concat(Res)).
3185
3186 % a DCG version of avl_to_list; allows to call it with something else than [] as tail
3187 avl_to_list_dcg(empty) --> [].
3188 avl_to_list_dcg(node(Key,Val,_,L,R)) -->
3189 avl_to_list_dcg(L), [(Key-Val)],
3190 avl_to_list_dcg(R).
3191
3192 /* conc: concatenation of sequence of sequences (general_concat) */
3193 conc_custom_explicit_set(avl_set(AVL),Res) :-
3194 avl_min_pair(AVL,int(ONE),First),
3195 conc2_cs(First,ONE,AVL,0,NewOrdList),
3196 ord_list_to_avlset(NewOrdList,Res,conc).
3197
3198 conc2_cs(Seq,NrSeq,AVL,Offset,OrdList) :-
3199 add_seq(Seq,Offset,OrdList,NewOffset,TailOrd),
3200 (avl_next((int(NrSeq),Seq),AVL,(int(N2),Seq2))
3201 -> conc2_cs(Seq2,N2,AVL,NewOffset,TailOrd)
3202 ; TailOrd=[]).
3203
3204 add_seq([],Offset,OrdRes,NewOffset,TailOrdRes) :- NewOffset=Offset, TailOrdRes=OrdRes.
3205 add_seq(avl_set(ASeq),Offset,OrdRes,NewOffset,TailOrd) :-
3206 avl_to_list_dcg_offset(ASeq,Offset,NrEls,OrdRes,TailOrd), NewOffset is Offset+NrEls.
3207
3208 % a version of avl_to_list for sequences which autmatically adds an offset
3209 avl_to_list_dcg_offset(empty,_,0) --> [].
3210 avl_to_list_dcg_offset(node((int(Idx),El),Val,_,L,R),Offset,NrEls) -->
3211 {NIdx is Idx+Offset},
3212 avl_to_list_dcg_offset(L,Offset,N1),
3213 [((int(NIdx),El)-Val)],
3214 avl_to_list_dcg_offset(R,Offset,N2), {NrEls is N1+N2+1}.
3215
3216 prepend_custom_explicit_set(avl_set(S1),ObjectToPrepend,Res) :-
3217 %hit_profiler:add_profile_hit(prepend_custom_explicit_set(avl_set(S1),ObjectToPrepend,Res)),
3218 element_can_be_added_or_removed_to_avl(ObjectToPrepend),
3219 shift_avl_sequence_to_ord_list(S1,1,OL1),
3220 ord_list_to_avlset([(int(1),ObjectToPrepend)-true|OL1],Res).
3221
3222 append_custom_explicit_set(avl_set(S1),ObjectToAppend,Res,WF) :-
3223 element_can_be_added_or_removed_to_avl(ObjectToAppend), % implies that ObjectToAppend is ground
3224 size_of_avl_sequence(S1,Size1,WF), NewSize is Size1+1,
3225 add_ground_element_to_explicit_set_wf(avl_set(S1),(int(NewSize),ObjectToAppend),Res,WF).
3226
3227 % compute tail of a sequence and also return first element
3228 tail_sequence_custom_explicit_set(avl_set(S1),First,Res,Span,WF) :-
3229 shift_avl_sequence_to_ord_list(S1,-1,NewOrdList),
3230 (NewOrdList = [(int(0),First)-true|TailOL] -> ord_list_to_avlset(TailOL,Res)
3231 ; add_wd_error_span('tail argument is not a sequence!', avl_set(S1),Span,WF)
3232 % add_error_fail(tail_sequence,'tail applied to ', NewOrdList))
3233 ).
3234 last_sequence_explicit_set(avl_set(AVL),Last) :-
3235 avl_max_pair(AVL,int(_Sz),Last).
3236 % TO DO: we could compute height of the path to max H, then check that Sz is in 2**(H-1)+1 .. 2**(H+1)-1 ?
3237 %first_sequence_explicit_set(avl_set(AVL),First) :- % not used anymore; apply_to used instead
3238 % avl_min_pair(AVL,int(_One),First).
3239
3240 % compute front and return last element at the same time
3241 front_sequence_custom_explicit_set(avl_set(AVL),Last,Res) :-
3242 avl_max_pair(AVL,int(Size),Last),
3243 direct_remove_element_from_avl(AVL, (int(Size),Last), Res). % we know Last is already in AVL-converted format
3244
3245
3246 reverse_custom_explicit_set(avl_set(AVL),Res) :-
3247 avl_to_list_dcg_offset(AVL,0,Size,List,[]),
3248 S1 is Size+1,
3249 reverse_list(List,S1,[],RevList),
3250 ord_list_to_avl(RevList,RevAVL),
3251 Res=avl_set(RevAVL).
3252
3253 reverse_list([],_,Acc,Acc).
3254 reverse_list([(int(Idx),El)-V|T],S1,Acc,Res) :-
3255 NewIdx is S1 - Idx,
3256 reverse_list(T,S1,[(int(NewIdx),El)-V|Acc],Res).
3257
3258 % check if a relation is injective ; compute range at the same time; note AVL can be empty
3259 is_injective_avl_relation(AVL,RangeRes) :-
3260 avl_domain(AVL,ElList),
3261 empty_avl(EmptyAcc),
3262 is_avl_inj_list(ElList,EmptyAcc,Range),
3263 construct_avl_set(Range,RangeRes).
3264
3265 is_avl_inj_list([],Range,Range).
3266 is_avl_inj_list([(_From,To)|T],InRange,OutRange) :-
3267 (avl_fetch(To,InRange) -> fail /* this is not an injection; a range element is repeated */
3268 ; avl_store(To,InRange,true,InRange1),
3269 is_avl_inj_list(T,InRange1,OutRange)
3270 ).
3271
3272 % Example predicates that work with code below:
3273 % card(id((1..1000)*(1..1000))~)=1000*1000
3274 % card(((1..1000)*(1..1000))~)=1000*1000
3275 invert_explicit_set(global_set(GS),_R) :- !,
3276 add_error_and_fail(invert_explicit_set,'Cannot compute inverse of global set: ',GS).
3277 invert_explicit_set(freetype(GS),_R) :- !,
3278 add_error_and_fail(invert_explicit_set,'Cannot compute inverse of freetype: ',GS).
3279 invert_explicit_set(closure([P1,P2],[T1,T2],Clo),R) :- !,
3280 % TODO: also invert closures with single argument or more arguments
3281 % e.g., {a,b,c|a=1 & b=1 &c:1..10}~ = {c,ab|ab=(1,1) & c:1..10}
3282 R = closure([P2,P1],[T2,T1],Clo).
3283 invert_explicit_set(closure([P1],[T1],Clo),R) :-
3284 is_member_closure_with_info([P1],[T1],Clo,_Type,Info,MEM),
3285 invert_member_predicate(MEM,T1,InvMEM,InvT1),!,
3286 construct_member_closure(P1,InvT1,Info,InvMEM,R).
3287 invert_explicit_set(C,AVL) :- expand_custom_set(C,EC,invert_explicit_set), %% convert to AVL ?
3288 inv_and_norm(EC,AVL).
3289
3290 invert_member_predicate(cartesian_product(A,B),couple(TA,TB),
3291 cartesian_product(B,A),couple(TB,TA)).
3292 invert_member_predicate(identity(A),TA,identity(A),TA).
3293
3294
3295 :- block inv_and_norm(-,?).
3296 inv_and_norm(EC,AVL) :- inv(EC,R,Done), norm(Done,R,AVL).
3297
3298 :- block norm(-,?,?).
3299 norm(_,R,AVL) :- normalised_list_to_avl(R,AVL).
3300
3301 :- block inv(-,?,?).
3302 inv([],[],done).
3303 inv([(A,B)|T],[(B,A)-true|DT],Done) :- inv(T,DT,Done).
3304
3305
3306
3307 % checks whether a ground value is in the domain of an AVL relation
3308 check_in_domain_of_avlset(X,AVL) :- convert_to_avl_inside_set(X,AX),!,
3309 ? (avl_fetch_pair(AX,AVL,_) -> true ; fail).
3310 check_in_domain_of_avlset(X,AVL) :-
3311 print('### could not convert arg for check_in_domain_of_avlset'),nl,
3312 print(X),nl,
3313 safe_avl_member_pair(X,_,AVL).
3314
3315 % checks whether a ground value is in the domain of an AVL relation and has only one solution
3316 check_unique_in_domain_of_avlset(X,AVL) :- convert_to_avl_inside_set(X,AX),!,
3317 avl_fetch_pair(AX,AVL,AY1),!,
3318 (avl_fetch_pair(AX,AVL,AY2), AY1 \= AY2 -> fail
3319 ; true).
3320
3321
3322 % utility to check if for a value there is at most one matching element in an AVL set
3323 % optimized for function application
3324 at_most_one_match_possible(Element,AVL,Matches) :- nonvar(Element),
3325 Element=(Index,_Rest), % Function Application; TO DO: does this cover all func. appl ?
3326 element_can_be_added_or_removed_to_avl(Index),
3327 convert_to_avl_inside_set(Index,AX), % is ground and normalised ?
3328 % TO DO: check AVL size ? Check other patterns ?
3329 findall((AX,Match),avl_tools:avl_fetch_pair(AX,AVL,Match),Matches),
3330 Matches \= [_,_|_].
3331
3332
3333
3334 apply_to_avl_set(A,X,Y,Span,WF) :-
3335 ground_value_check(X,GroundX),
3336 apply_to_avl_set_aux(A,X,Y,GroundX,Span,WF).
3337
3338 apply_to_avl_set_aux(A,X,Y,GroundX,Span,WF) :- nonvar(GroundX),!,
3339 apply_check_tuple(X,Y,A,Span,WF). % we could call apply_check_tuple_ground to avoid one ground test
3340 % We know that A is a function: we can deterministically apply if X is ground;
3341 % if Y is ground this is only the cases for injective functions
3342 apply_to_avl_set_aux(A,X,Y,GroundX,Span,WF) :-
3343 %(preference(data_validation_mode,true); % we now reduce priority of backpropagation below
3344 preference(find_abort_values,true),
3345 % do not try inverse propagation onto argument X of function application A(X) = Y
3346 !,
3347 avl_approximate_size(A,3,ApproxSizeA),
3348 apply_check_tuple_delay(X,Y,A,ApproxSizeA,Span,WF,GroundX,_,_).
3349 apply_to_avl_set_aux(A,X,Y,GroundX,Span,WF) :-
3350 ground_value_check(Y,GroundY),
3351 avl_approximate_size(A,3,ApproxSizeA), % exact size for height <= 3; approximate size above
3352 (ApproxSizeA < 4 -> SPrio=ApproxSizeA ; SPrio is ApproxSizeA * 10), % magic number; ideally we want X or Y to be known beforehand; if none are known we may miss WD errors and may enumerate useless intermediate variables
3353 get_bounded_wait_flag(SPrio,apply_to_explicit(X,Y),WF,WF1), % this only makes sense if X is a domain variable to be enumerated
3354 %propagate_avl_element_information((X,Y),A,ApproxSizeA,WF), % could be done; but would prevent WD problems from being detected
3355 % this waitflag is used when neither X nor Y are ground;
3356 % quite often not much is gained by enumerating possible values; unless X or Y are constrained or trigger other computations
3357 % WSz is 10*ApproxSizeA, % magic value
3358 %(ApproxSizeA > 100 -> InversePrioSize = 4
3359 % ; avl_range_size_and_propagate_element_info(A,X,Y,RSize), InversePrioSize is ApproxSizeA // RSize), % we could probably compute the exact worst case with the same complexity
3360 % delay_get_wait_flag(GroundY,GroundX,WF1,InversePrioSize,apply_to_explicit_inverse(X,Y),WF,WF2),
3361 %(ApproxSizeA<4000 -> propagate_apply(X,Y,A,ApproxSizeA,WF,GroundX,GroundY) ; true),
3362 apply_check_tuple_delay(X,Y,A,ApproxSizeA,Span,WF,GroundX,WF1,GroundY),
3363 (preference(use_clpfd_solver,false) -> true
3364 % should we also check: preference(find_abort_values,true)?
3365 ; get_wait_flag0(WF,WF0),
3366 propagate_apply(X,Y,A,ApproxSizeA,WF,WF0,GroundX,WF1,GroundY)).
3367
3368 :- block propagate_apply(?,?,?,?,?,-,?,?,?).
3369 propagate_apply(X,Y,AVL,ApproxSizeA,WF,_,GroundX,WF1,GroundY) :-
3370 var(GroundX), var(WF1), var(GroundY),
3371 (preference(disprover_mode,true)
3372 -> XX=X % this will also instantiate X and prevent finding WD errors
3373 ; (ApproxSizeA<128 -> true
3374 ; preference(solver_strength,SS), ApproxSizeA < 128+SS*100), % up until 4000 it may make sense to constrain Y
3375 preference(data_validation_mode,false), % note: this can slow down ProB, e.g., test 1105; hence allow disabling it
3376 preference(find_abort_values,false), % TO DO: v = %x.(x:1..20|x+x) & {y,z|y<4 & z=v(y) & (y:{-1,2})} =res: no WD ERROR found
3377 propagate_value(X,XX) % only instantiate X, propagation only makes sense for propagate_avl_element_information_small, as otherwise only X will be bounded
3378 ),
3379 !,
3380 propagate_avl_element_information_direct((XX,Y),AVL,ApproxSizeA,WF).
3381 propagate_apply(_,_,_,_,_,_,_,_,_).
3382
3383 % only propagate in one direction to allow to find WD errors but also prevent pending co-routines/constraints
3384 :- block propagate_value(-,?).
3385 propagate_value(int(X),R) :- !,
3386 (
3387 %%integer(X) -> R=int(X) ; % relevant for SWI 8.5.10 and older where fd_set fails for integers, see test 788; should be fixed in next release
3388 propagate_fd_dom(X,RX), R=int(RX), propagate_atomic_value(X,RX)
3389 ).
3390 propagate_value(fd(X,T),R) :- !,
3391 (
3392 %%integer(X) -> R=fd(X,T) ; % for SWI 8.5.10 and older, see above
3393 propagate_fd_dom(X,RX), R=fd(RX,T), propagate_atomic_value(X,RX)
3394 ).
3395 propagate_value((X1,X2),R) :- !, R=(RX1,RX2), propagate_value(X1,RX1), propagate_value(X2,RX2).
3396 propagate_value(pred_true,R) :- !, if(R=pred_true,true,debug_println(9,function_arg_outside_domain(pred_true))).
3397 propagate_value(pred_false,R) :- !, if(R=pred_false,true,debug_println(9,function_arg_outside_domain(pred_false))).
3398 propagate_value(string(X),R) :- !, R=string(RX),propagate_atomic_value(X,RX).
3399 propagate_value(X,RX) :- equal_object(X,RX). % TO DO: get rid of this: this propagates and prevents finding WD errors
3400 :- block propagate_atomic_value(-,?).
3401 propagate_atomic_value(X,Y) :-
3402 if(X=Y,true,debug_println(9,function_arg_outside_domain(X))).
3403
3404 %propagate_fd_dom(X,RX) :- integer(X),!,RX=X. % relevant for SWI 8.5.10 and older where fd_set fails for integers
3405 propagate_fd_dom(X,RX) :- fd_set(X,Dom),in_set(RX,Dom).
3406
3407
3408 /*
3409 :- block propagate_apply(-,?,?,?,?,-,-).
3410 % call propagate as soon as we know something about the function argument and we do not propgagate completely using GroundX/Y anyway
3411 propagate_apply(X,Y,AVL,Size,WF,GroundX,GroundY) :- print(prop_apply(Size,GroundX,GroundY,X,Y)),nl,
3412 (nonvar(GroundX) -> true ; nonvar(GroundY) -> true
3413 ; propagate_avl_element_information((X,Y),AVL,Size,WF)).
3414
3415 % get the waitflag when first WF set and other two not
3416 :- block delay_get_wait_flag(-,-,-,?,?,?,?).
3417 delay_get_wait_flag(_,WF1,WF2, _,_,_,_) :- (nonvar(WF1);nonvar(WF2)),!. % DO NOTHING
3418 delay_get_wait_flag(_,_,_,Prio,Info,WF,WF2) :- get_wait_flag(Prio,Info,WF,WF2).
3419 */
3420
3421 :- block apply_check_tuple_delay(?,?,?, ?,?,?, -,-,-).
3422 apply_check_tuple_delay(X,Y,AVL,_ApproxSizeA,Span,WF,GroundX,WF1,_) :-
3423 (nonvar(GroundX);nonvar(WF1)),!,
3424 apply_check_tuple(X,Y,AVL,Span,WF).
3425 apply_check_tuple_delay(X,Y,AVL,ApproxSizeA,Span,WF,_GroundX,_WF1,_GroundY) :-
3426 % Y is ground; try to do an inverse function lookup
3427 inverse_apply_ok(Y,X,AVL,ApproxSizeA),
3428 !,
3429 % print(inverse_apply(Y,X,ApproxSizeA,_GroundX)),nl,
3430 inverse_get_possible_values(X,Y,AVL,Res),
3431 Res=avl_set(InvAVL), % if empty set : we fail
3432 (preference(data_validation_mode,true),
3433 avl_approximate_size(InvAVL,10,ApproxSize),
3434 ApproxSize>1
3435 -> A2 is (ApproxSize*15*ApproxSize)//ApproxSizeA, % used to be A2 is ApproxSize*100,
3436 A22 is max(A2,ApproxSize),
3437 (get_inversion_penalty(Span)
3438 -> A23 is A22 * 100 %, add_message(f,'Inversion Penalty: ',Y:A22,Span)
3439 ; A23=A22),
3440 % give lower priority for backwards propagation, upto 15 times if no reduction from backwards propagation
3441 % but also take into account how much we reduce the size by inverting
3442 % relevant for, e.g., Machines_perf_0111/Thales_All/rule_OPS_SDS_3940.mch
3443 % or rule_OPS_SDS_6496 -> 15 instead of 150 improves performance
3444 get_bounded_wait_flag(A23,element_of_avl_inverse_apply_ok(X),WF,WF2),
3445 % does not call propagate_avl_element_information(X,InvAVL,ApproxSize,WF) or avl_to_table
3446 element_of_avl_set_wf3(X,InvAVL,ApproxSize,WF2,WF) % TODO: pass GroundX
3447 %apply_check_tuple_delay(X,Y,AVL,ApproxSizeA,Span,WF,GroundX,WF1,_) % now wait on WF1 or GroundX
3448 ; element_of_avl_set_wf(InvAVL,X,WF)
3449 ).
3450 apply_check_tuple_delay(X,Y,AVL,ApproxSizeA,Span,WF,GroundX,WF1,_GroundY) :-
3451 apply_check_tuple_delay(X,Y,AVL,ApproxSizeA,Span,WF,GroundX,WF1,_). % now wait on WF1 or GroundX
3452
3453 % check if the function call was annotated as not suitable for backwards inverse function lookup propagation
3454 get_inversion_penalty(span_predicate(b(_Function,_,Info),_LS,_S)) :- !,
3455 get_inversion_penalty(Info).
3456 get_inversion_penalty(Info) :-
3457 member(prob_annotation('INVERSION_PENALTY'),Info).
3458
3459 inverse_get_possible_values(X,Y,AVL,Res) :-
3460 get_template(X,XX,_),
3461 copy_term(XX,XX_Copy), % avoid that findall instantiates X
3462 % TODO: copy_value_term similar to ground_value to avoid traversing avl_sets; but usually X is not a set
3463 findall(XX_Copy, safe_avl_member_default((XX_Copy,Y),AVL), PossibleValues),
3464 PossibleValues \= [], % fail straightaway
3465 sort(PossibleValues,SPV),
3466 % length(SPV,Len),print(inverse_image(Y,Len)),nl, print_term_summary(apply_check_tuple_delay(X,Y,AVL)),nl,
3467 convert_to_avl(SPV,Res).
3468
3469 % is it ok to compute inverse ? only makes sense if AVL tree not too big and quite functional
3470 inverse_apply_ok(pred_true,_,_AVL,ApproxSizeA) :- !, % only two values possible, probably half of AVL will be returned
3471 ApproxSizeA < 1023. % corresponds to avl_height < 10
3472 inverse_apply_ok(pred_false,_,_AVL,ApproxSizeA) :- !,ApproxSizeA < 1023.
3473 % TO DO: other small types, such as fd(_,_)
3474 inverse_apply_ok(_,_,_AVL,ApproxSizeA) :- ApproxSizeA < 255,!.
3475 inverse_apply_ok(_,X,_AVL,ApproxSizeA) :- ApproxSizeA < 65535, % corresponds Height < 16
3476 (preference(data_validation_mode,true) ->
3477 (preference(solver_strength,SS), ApproxSizeA < 16383+SS -> true
3478 ; perfmessage(inverse,function_call_not_inverted(ApproxSizeA)),fail
3479 )
3480 ; true),
3481 quick_non_ground_check(X).
3482 %inverse_apply_ok(_,_,_,_).
3483
3484 % sometimes the ground_value_check co-routine hasn't grounded GroundX yet ! so do a quick check
3485 quick_non_ground_check(X) :- var(X),!.
3486 quick_non_ground_check([]) :- !,fail.
3487 quick_non_ground_check(avl_set(_)) :- !,fail.
3488 quick_non_ground_check(pred_true) :- !,fail.
3489 quick_non_ground_check(pred_false) :- !,fail.
3490 quick_non_ground_check(int(X)) :- !,var(X).
3491 quick_non_ground_check(string(X)) :- !,var(X).
3492 quick_non_ground_check(fd(X,T)) :- !,(var(X) ; var(T)).
3493 quick_non_ground_check((A,B)) :- !, (quick_non_ground_check(A) -> true ; quick_non_ground_check(B)).
3494 quick_non_ground_check(_). % assume it is non ground
3495
3496
3497
3498 % apply_check_tuple is allowed to enumerate: either X is ground or Y is ground
3499 apply_check_tuple(X,Y,A,Span,WF) :-
3500 ground_value(X),
3501 convert_to_avl_inside_set_wf(X,AX,WF),!, % we can do optimized lookup + checking in one go (but avl_apply only does partial check)
3502 avl_apply(AX,A,XY,Span,WF),
3503 kernel_objects:equal_object_wf(XY,Y,apply_check_tuple,WF).
3504 :- if(environ(no_wd_checking, true)).
3505 apply_check_tuple(X,Y,A,_Span,WF) :- safe_avl_member_default_wf((X,Y),A,WF).
3506 :- else.
3507 apply_check_tuple(X,Y,A,_Span,WF) :- preferences:preference(find_abort_values,false), !,
3508 safe_avl_member_default_wf((X,Y),A,WF).
3509 apply_check_tuple(X,Y,A,Span,WF) :- !,
3510 if(safe_avl_member_default_wf((X,XY),A,WF), % does not detect abort errors if X unbound
3511 kernel_objects:equal_object_wf(XY,Y,apply_check_tuple_avl,WF),
3512 add_wd_error_span('function applied outside of domain (#4): ','@fun'(X,avl_set(A)),Span,WF)).
3513 :- endif.
3514
3515
3516 % ------------------------------------------
3517
3518
3519 :- use_module(b_global_sets,[b_type2_set/2]).
3520 :- use_module(bsyntaxtree,[rename_bt/3]).
3521 union_of_explicit_set(global_set(GS),_,R) :- is_maximal_global_set(GS), !,
3522 R= global_set(GS). /* global_set is already maximal */
3523 union_of_explicit_set(freetype(GS),_,R) :- !, R= freetype(GS). /* freetype is already maximal */
3524 union_of_explicit_set(closure(P,T,B),_,R) :- is_definitely_maximal_closure(P,T,B), !,
3525 R= closure(P,T,B). /* global_set is already maximal */
3526 union_of_explicit_set(_,S2,R) :- is_definitely_maximal_set(S2),!, % will also look at AVL set
3527 R=S2.
3528 union_of_explicit_set(S1,S2,R) :- nonvar(S2), S2 = [], !, R=S1.
3529 union_of_explicit_set(S1,S2,_) :- (var(S1);var(S2)),!,fail. % then we cannot compute it here
3530 union_of_explicit_set(S2,S1,R) :-
3531 is_not_member_value_closure(S1,TYPE,MS1), nonvar(MS1), is_efficient_custom_set(MS1),
3532 % also works if S2 is complement closure
3533 difference_of_explicit_set(MS1,S2,Diff),!,
3534 construct_complement_closure_if_necessary(Diff,TYPE,R).
3535 union_of_explicit_set(avl_set(A1),S2,R) :- !, union_of_avl_set(S2,A1,R).
3536 union_of_explicit_set(S1,S2,R) :-
3537 is_not_member_value_closure(S1,TYPE,MS1), nonvar(MS1), is_efficient_custom_set(MS1),
3538 difference_of_explicit_set(MS1,S2,Diff),!,
3539 construct_complement_closure_if_necessary(Diff,TYPE,R).
3540 union_of_explicit_set(S1,avl_set(A2),R) :- !, union_of_avl_set(S1,A2,R).
3541 union_of_explicit_set(I1,I2,R) :- is_interval_closure_or_integerset(I1,From1,To1), ground(From1), ground(To1),
3542 is_interval_closure_or_integerset(I2,From2,To2), ground(From2), ground(To2),
3543 !,
3544 (union_of_interval(From1,To1,From2,To2,FromRes,ToRes)
3545 -> construct_interval_closure(FromRes,ToRes,R)
3546 ; small_enough_for_expansion(From1,To1),small_enough_for_expansion(From2,To2) ->
3547 % do not attempt union_of_closure below
3548 expand_interval_closure_to_avl(From1,To1,R1), R1=avl_set(A1), % empty interval already dealt with above !?
3549 expand_interval_closure_to_avl(From2,To2,R2), R2=avl_set(A2), % Note: unification after call as expand_interval calls equal_object (which gets confused by partially instantiated avl_set(_))
3550 union_of_avl(A1,A2,ARes),R=avl_set(ARes) /* AVL not normalised */
3551 ; transform_global_sets_into_closure(I1,closure(Par,T,Body)),
3552 union_of_closure(I2,Par,T,Body,R)
3553 ).
3554 union_of_explicit_set(closure(P,T,B),C2,Res) :-
3555 union_of_closure(C2,P,T,B,Res).
3556
3557 small_enough_for_expansion(From1,To1) :- number(To1), number(From1), To1-From1<250.
3558
3559 :- use_module(bsyntaxtree,[extract_info/2, extract_info_wo_used_ids/2, extract_info/3, rename_bt/3, replace_id_by_expr/4]).
3560
3561 union_of_closure(global_set(X),P,T,B,Res) :- !, transform_global_sets_into_closure(global_set(X),C),
3562 union_of_closure(C,P,T,B,Res).
3563 union_of_closure(closure(P2,T2,B2),P,T,B,Res) :- !,
3564 % T2 should be equal to T, module seq(_) <-> set(couple(integer,_))
3565 unify_closure_predicates(P,T,B, P2,T2,B2 , NewP,NewT, NewB1,NewB2),
3566 debug:debug_println(9,union_of_two_closures(P,P2,NewP,NewT)),
3567 extract_info(B,B2,NewInfo),
3568 construct_disjunct(NewB1,NewB2,Disj),
3569 Res = closure(NewP,NewT,b(Disj,pred,NewInfo)).
3570
3571 % rename predicates of two closures so that they work on common closure parameter ids
3572 % and can then be either joined by conjunction or disjunction
3573 unify_closure_predicates(P,T,B, P2,T2,B2 , NewP,NewT, NewB1,NewB2) :-
3574 length(P,Len1), length(P2,Len2),
3575 (Len1=Len2
3576 -> generate_renaming_list(P,P2,RL),
3577 rename_bt(B2,RL,NewB2),
3578 NewP=P, NewT=T, NewB1 = B
3579 ; Len1 < Len2 -> unify_clos_lt(P,T,B, P2,T2,B2 , NewP,NewT, NewB1,NewB2)
3580 ; unify_clos_lt(P2,T2,B2, P,T,B , NewP,NewT, NewB2,NewB1) % inverted the predicate
3581 ).
3582
3583 % TO DO: generalize: currently only works for single identifier on left
3584 % but works for id(NATURAL) \/ %x.(x<0|-x) or abs = id(NATURAL) \/ %x.(x<0|-x) & abs(2)=a2 & abs(-2)=am2
3585 unify_clos_lt([ID1],[couple(_,_)],B, P2,T2,B2 , NewP,NewT, NewB1,NewB2) :-
3586 rename_lambda_result_id(P2,B2,P3,B3),
3587 create_couple_term(P3,T2,Pair),
3588 replace_id_by_expr(B,ID1,Pair,NewB1),
3589 NewP=P3, NewT=T2, NewB2=B3.
3590
3591 % _lambda_result_ id is not enumerated, hence we have to avoid inserting such ids into NewB1 as part of the pPair
3592 rename_lambda_result_id(['_lambda_result_',ID2],B2,[FRESHID,ID2],B3) :- !,get_unique_id('_RANGE_',FRESHID),
3593 rename_bt(B2,[rename('_lambda_result_',FRESHID)],B3).
3594 rename_lambda_result_id([ID1,'_lambda_result_'],B2,[ID1,FRESHID],B3) :- !,get_unique_id('_RANGE_',FRESHID),
3595 rename_bt(B2,[rename('_lambda_result_',FRESHID)],B3).
3596 rename_lambda_result_id(P2,B2,P2,B2).
3597
3598 % translate a list of atomic ids and a list of types into a couple-term
3599 create_couple_term([ID1],[T1],Res) :- !,
3600 create_texpr(identifier(ID1),T1,[],Res).
3601 create_couple_term([ID1,ID2],[T1,T2],Res) :-
3602 bsyntaxtree:create_couple(b(identifier(ID1),T1,[]),b(identifier(ID2),T2,[]),Res).
3603 % TODO: extend for more than two args
3604
3605 generate_renaming_list([],[],[]).
3606 generate_renaming_list([ID|T],[ID2|T2],RL) :-
3607 (ID==ID2 -> generate_renaming_list(T,T2,RL)
3608 ; RL = [rename(ID2,ID)|RL2],
3609 generate_renaming_list(T,T2,RL2)).
3610
3611
3612 % a more clever way of constructing a disjunct; factor out common prefixes
3613 % (A & B1) or (A1 & B2) <=> A1 & (B1 or B2)
3614 % TO DO: we should try and get the leftmost basic conjunct !
3615 /* construct_disjunct(b(conjunct(A1,A2),pred,IA), b(conjunct(B1,B2),pred,_IB), Res) :-
3616
3617 print('TRY DISJUNCT FACTOR: '), translate:print_bexpr(A1),nl,
3618 translate:print_bexpr(B1),nl,
3619 same_texpr_body(A1,B1),!,
3620 print('DISJUNCT FACTOR: '), translate:print_bexpr(A1),nl,
3621 Res = conjunct(A1,b(Disj,pred,IA)),
3622 construct_disjunct(A2,B2,Disj).
3623 */
3624 construct_disjunct(A,B,disjunct(A,B)).
3625
3626 :- use_module(btypechecker,[couplise_list/2]).
3627 % TO DO: quick_check if AVL A1 is maximal ?
3628 union_of_avl_set(avl_set(A2),A1,R) :- !, union_of_avl(A1,A2,ARes), R=avl_set(ARes). /* AVL not normalised */
3629 union_of_avl_set(I2,A1,R) :- is_interval_closure_or_integerset(I2,From2,To2), !,
3630 ground(From2), ground(To2), % we can only compute it if bounds known
3631 (avl_min(A1,int(Min)), low_border(From2,Min,FromRes), avl_max(A1,int(Max)), up_border(To2,Max,ToRes)
3632 -> /* AVL contained (almost) in Interval */
3633 construct_interval_closure(FromRes,ToRes,R)
3634 ; \+ small_interval(From2,To2) ->
3635 transform_global_sets_into_closure(I2,closure(Par,T,Body)), % we may have something like NATURAL1,...
3636 union_of_avl_set_with_closure(Par,T,Body,A1,R)
3637 ; expand_and_convert_to_avl_set(I2,A2,union_of_avl_set,'? \\/ ARG'), % can generate ARel=empty; will fail if not possible to convert
3638 union_of_avl(A1,A2,ARes), R=avl_set(ARes)
3639 ).
3640 union_of_avl_set(closure(Par,T,Body),A1,Res) :- is_infinite_or_symbolic_closure(Par,T,Body),!,
3641 % TO DO: what if we are in SYMBOLIC mode and the type of T is infinite; maybe we should also keep the union symbolic ?? (cf Ticket/Georghe1)
3642 union_of_avl_set_with_closure(Par,T,Body,A1,Res).
3643 union_of_avl_set(S2,A1,Res) :-
3644 S2 \= freetype(_),
3645 ground_value(S2), % could be a closure
3646 !,
3647 (try_expand_and_convert_to_avl_set(S2,A2,union)
3648 -> union_of_avl(A1,A2,ARes), Res=avl_set(ARes) /* AVL not normalised */
3649 ; S2=closure(Par,T,Body),
3650 union_of_avl_set_with_closure(Par,T,Body,A1,Res)).
3651
3652 try_expand_and_convert_to_avl_set(S2,A2,Source) :-
3653 % false: do not add enumeration warning events as errors
3654 catch_enumeration_warning_exceptions(expand_and_convert_to_avl_set(S2,A2,Source,''),fail,false,ignore(Source)).
3655
3656 % try expanding to list, but catch enumeration warnings and fail if they do occur
3657 % used by override(...)
3658 %try_expand_custom_set_to_list(CS,_,_,_) :- nonvar(CS),CS=global_set(GS),is_infinite_global_set(GS,_),
3659 % !,
3660 % fail.
3661 try_expand_custom_set_to_list(CS,_,_,_) :- nonvar(CS),
3662 (is_symbolic_closure(CS) ; is_infinite_explicit_set(CS)),
3663 !, % we could also check is_symbolic_closure
3664 fail.
3665 try_expand_custom_set_to_list(CS,List,Done,Source) :-
3666 % false: do not add enumeration warning events as errors
3667 catch_enumeration_warning_exceptions(expand_custom_set_to_list(CS,List,Done,Source),fail,false,ignore(Source)).
3668
3669
3670 small_interval(From,To) :- number(From), number(To), To-From < 10000.
3671
3672 union_of_avl_set_with_closure(Par,T,Body,A1,Res) :-
3673 Body = b(_,BodyT,_),
3674 setup_typed_ids(Par,T,TypedPar),
3675 btypechecker:couplise_list(TypedPar,TypedCPar),
3676 generate_couple_types(TypedCPar,ParExpr,ParType),
3677 debug:debug_println(9,union_of_avl_and_infinite_closure(Par,T,BodyT)),
3678 BodyAvl = b(member(ParExpr,b(value(avl_set(A1)),set(ParType),[])),pred,[]),
3679 extract_info_wo_used_ids(Body,NewInfo),
3680 Res = closure(Par,T,b(disjunct(BodyAvl,Body),pred,NewInfo)).
3681 % mark_closure_as_symbolic(closure(Par,T,b(disjunct(BodyAvl,Body),pred,NewInfo)),Res).
3682
3683 low_border(Low,AVLMin,R) :- geq_inf(AVLMin,Low),!,R=Low.
3684 low_border(Low,AVLMin,R) :- number(Low),AVLMin is Low-1,R=AVLMin. % extend lower border by one
3685 up_border(Up,AVLMax,R) :- geq_inf(Up,AVLMax),!,R=Up.
3686 up_border(Up,AVLMax,R) :- number(Up),AVLMax is Up+1,R=AVLMax. % extend upper border by one
3687
3688
3689 setup_typed_ids([],[],[]).
3690 setup_typed_ids([ID|TI],[Type|TT],[b(identifier(ID),Type,[])|BT]) :- setup_typed_ids(TI,TT,BT).
3691
3692 generate_couple_types(couple(A,B),b(couple(TA,TB),Type,[]),Type) :- !, Type = couple(TTA,TTB),
3693 generate_couple_types(A,TA,TTA),
3694 generate_couple_types(B,TB,TTB).
3695 generate_couple_types(b(X,T,I),b(X,T,I),T).
3696
3697
3698 % try to see if two intervals can be unioned into a new interval
3699 union_of_interval(F1,T1,F2,T2,FR,TR) :-
3700 geq_inf(F2,F1), geq_inf(T1,T2),!,FR=F1,TR=T1. % interval [F2,T2] contained in [F1,T1]
3701 union_of_interval(F2,T2,F1,T1,FR,TR) :- geq_inf(F2,F1), geq_inf(T1,T2),!,FR=F1,TR=T1. % see above
3702 union_of_interval(F1,T1,F2,T2,FR,TR) :- number(F2),
3703 geq_inf(F2,F1), number(T1),T11 is T1+1,geq_inf(T11,F2), geq_inf(T2,F2),!,FR=F1,TR=T2. % intervals can be joined
3704 union_of_interval(F2,T2,F1,T1,FR,TR) :- number(F2),
3705 geq_inf(F2,F1), number(T1),T11 is T1+1,geq_inf(T11,F2), geq_inf(T2,F2),!,FR=F1,TR=T2. % see above
3706
3707 :- use_module(library(ordsets),[ord_union/3]).
3708 union_of_avl(A1,A2,ARes) :-
3709 avl_height(A2,Sz2),
3710 (Sz2 < 2 % we have something like Set := Set \/ {x}; no need to compute height of A1
3711 -> union_of_avl1(A1,99999,A2,Sz2,ARes)
3712 ; avl_height(A1,Sz1), % TODO: we could call avl_height_less_than or avl_height_compare
3713 (Sz1<Sz2 -> union_of_avl1(A2,Sz2,A1,Sz1,ARes) ; union_of_avl1(A1,Sz1,A2,Sz2,ARes))
3714 ).
3715 union_of_avl1(A1,Sz1,A2,Sz2,ARes) :- Sz2>2, Sz1 =< Sz2+3, % difference not too big; Sz2 at least a certain size
3716 !,
3717 avl_to_list(A2,List2), % get all members
3718 avl_to_list(A1,List1),
3719 ord_union(List1,List2,L12),
3720 ord_list_to_avl(L12,ARes).
3721 union_of_avl1(A1,_Sz1,A2,_Sz2,ARes) :- % this version is better when A2 is small compared to A1
3722 avl_domain(A2,List2), % get all members
3723 add_to_avl(List2,A1,ARes).
3724
3725 :- use_module(library(lists),[reverse/2]).
3726 % a custom version for union(A) where A is AVL set; avoid converting/expanding accumulators and computing avl_height
3727 % runtime of e.g., UNION(x).(x:1000..1514|0..x) 0.65 sec or UNION(n).(n:10000..10010|UNION(x).(x:n..n+1000|n..x)) 4.8 sec is considerably smaller with this version
3728 union_generalized_explicit_set(avl_set(SetsOfSets),Res,WF) :-
3729 expand_custom_set_to_list_wf(avl_set(SetsOfSets),ESetsOfSets,_,union_generalized_wf,WF),
3730 % length(ESetsOfSets,Len),print(union_gen(Len)),nl,
3731 (ESetsOfSets=[OneSet]
3732 -> Res=OneSet % avoid converting to list and back to Avl
3733 ; reverse(ESetsOfSets,RESetsOfSets), % be sure to insert larger values first, so that ord_union has less work to do below; useful if you have many small singleton sets, for example union(ran(%x.(x : 1 .. 10000|{x * x}))) 2.37 secs --> 0.15 secs
3734 % note: dom({r,x|x:1..50000 & r:{x*x}}) is still 3 times faster
3735 union_of_avls(RESetsOfSets,[],Res)).
3736
3737 % take the union of a list of avl_sets
3738 union_of_avls([],Acc,Res) :- ord_list_to_avl(Acc,ARes), construct_avl_set(ARes,Res).
3739 union_of_avls([H|T],Acc,Res) :-
3740 union_of_avl_with_acc(H,Acc,NewAcc),
3741 union_of_avls(T,NewAcc,Res).
3742
3743 union_of_avl_with_acc(avl_set(H),Acc,NewAcc) :- !,
3744 avl_to_list(H,HList),
3745 ord_union(Acc,HList,NewAcc).
3746 union_of_avl_with_acc([],Acc,Res) :- !,Res=Acc.
3747 % other custom sets should normally not appear, we obtain the list as elements stored in an avl_set
3748 union_of_avl_with_acc(G,_,_) :- add_internal_error('Uncovered element: ',union_of_avl_with_acc(G,_,_)),fail.
3749
3750
3751
3752 % TO DO: there are no rules for is_not_member_value_closure for intersection below
3753 intersection_of_explicit_set_wf(global_set(GS),S2,R,_WF) :- is_maximal_global_set(GS), !, R=S2.
3754 intersection_of_explicit_set_wf(freetype(_GS),S2,R,_WF) :- !, R=S2.
3755 intersection_of_explicit_set_wf(_,S2,_,_WF) :- var(S2),!,fail. % code below may instantiate S2
3756 intersection_of_explicit_set_wf(S1,S2,R,_WF) :- is_definitely_maximal_set(S2), !, R=S1.
3757 intersection_of_explicit_set_wf(_S1,[],R,_WF) :-!, R=[].
3758 intersection_of_explicit_set_wf(avl_set(A1),I2,R,_WF) :-
3759 is_interval_closure_or_integerset(I2,From1,To1),
3760 !,
3761 intersect_avl_interval(A1,From1,To1,R).
3762 intersection_of_explicit_set_wf(I1,I2,R,_WF) :-
3763 intersection_with_interval_closure(I1,I2,R),!.
3764 intersection_of_explicit_set_wf(S1,S2,R,_WF) :-
3765 get_avl_sets(S1,S2,A1,A2),
3766 !, % if too large: better to apply normal intersection code ?
3767 % if one of the args is an interval this is already caught in kernel_objects calling intersection_with_interval_closure; see SetIntersectionBig.mch
3768 avl_domain(A1,ES), % A1 has the smaller height; important for e.g. SetIntersectionBig2.mch
3769 inter2(ES,A2,IRes),
3770 ord_list_to_avlset(IRes,R,intersection). % we have generated the elements in the right order already
3771 intersection_of_explicit_set_wf(Set1,Set2,R,WF) :-
3772 transform_global_sets_into_closure(Set1,closure(P1,T1,B1)),
3773 transform_global_sets_into_closure(Set2,closure(P2,T2,B2)),
3774 % gets called, e.g., for {x|x /: NATURAL1} /\ NATURAL1
3775 unify_closure_predicates(P1,T1,B1, P2,T2,B2 , NewP,NewT, NewB1,NewB2),
3776 debug:debug_println(9,intersection_of_two_closures(P1,P2,NewP,NewT)),
3777 conjunct_predicates([NewB1,NewB2],BI),
3778 % create a conjunction: can be much more efficient than seperately expanding;
3779 % also works well if one of the closures is infinite
3780 C = closure(NewP,NewT,BI),
3781 expand_custom_set_wf(C,R,intersection_of_explicit_set_wf,WF). % we could keep it symbolic; maybe use SYMBOLIC pref
3782 % to do: also use above for closure and AVL set with member(P,value(avl_set(A)))
3783 % we could also apply the same principle to difference_of_explicit_set
3784 % currently we enable intersection to be treated symbolically (not_symbolic_binary(intersection) commented out)
3785 % This means the above clause for intersection_of_explicit_set_wf is less useful
3786 % a special case; just for interval closures
3787 intersection_with_interval_closure(I1,I2,R) :-
3788 is_interval_closure_or_integerset(I1,From1,To1), nonvar(I2),
3789 intersection_with_interval_closure_aux(I2,From1,To1,R).
3790 intersection_with_interval_closure(avl_set(A1),I2,R) :-
3791 is_interval_closure_or_integerset(I2,From1,To1),
3792 !,
3793 intersect_avl_interval(A1,From1,To1,R).
3794
3795 % try and get AVL sets from two args; first AVL set is smaller one according to height
3796 get_avl_sets(avl_set(A1),S2,AA1,AA2) :- nonvar(S2), S2=avl_set(A2),
3797 ? (avl_height_compare(A1,A2,R), R=lt
3798 -> (AA1,AA2)=(A1,A2)
3799 ; (AA1,AA2)=(A2,A1)).
3800 %get_avl_sets(S1,S2,AA1,AA2) :- nonvar(S2),S2=avl_set(A2), get_avl_set_arg(S1,A1),
3801 % (avl_height_compare(A1,A2,R),R=gt -> (AA1,AA2)=(A2,A1) ; (AA1,AA2)=(A1,A2)).
3802
3803
3804 %intersection_with_interval_closure_aux(avl_set(A),...
3805 intersection_with_interval_closure_aux(I2,From1,To1,R) :-
3806 is_interval_closure_or_integerset(I2,From2,To2),!,
3807 intersect_intervals_with_inf(From1,To1,From2,To2,FromRes,ToRes),
3808 construct_interval_closure(FromRes,ToRes,R).
3809 % (is_interval_closure_or_integerset(R,F,T) -> print(ok(F,T)),nl ; print(ko),nl).
3810 intersection_with_interval_closure_aux(avl_set(A2),From1,To1,R) :-
3811 intersect_avl_interval(A2,From1,To1,R).
3812
3813 % intersect avl with interval
3814 % TO DO: expand interval if small (or small intersection with AVL) and use avl intersection
3815 intersect_avl_interval(_,From2,To2,_) :- (var(From2) ; var(To2)),!,fail.
3816 intersect_avl_interval(A1,From2,To2,R) :- avl_min(A1,int(Min)),
3817 geq_inf(Min,From2),
3818 geq_inf(To2,Min), avl_max(A1,int(Max)),
3819 geq_inf(To2,Max),
3820 % AVL fully contained in interval; no need to expand to list and back again
3821 !,
3822 construct_avl_set(A1,R).
3823 intersect_avl_interval(A1,From2,To2,R) :-
3824 avl_domain(A1,ES),
3825 inter_interval(ES,From2,To2,IRes),
3826 ord_list_to_avlset(IRes,R,intersect_avl_interval).
3827
3828 inter_interval([],_,_, []).
3829 inter_interval([IH|T],From2,To2, Res) :- IH = int(H),
3830 (geq_inf(To2,H) ->
3831 (geq_inf(H,From2) -> Res = [IH-true|Res2] ; Res = Res2),
3832 inter_interval(T,From2,To2,Res2)
3833 ; Res = [] % we have exceeded the upper limit of the interval
3834 ).
3835
3836 intersect_intervals_with_inf(From1,To1,From2,To2,FromRes,ToRes) :-
3837 minimum_with_inf(To1,To2,ToRes),
3838 maximum_with_inf(From1,From2,FromRes).
3839
3840 % check if two intervals are disjoint
3841 disjoint_intervals_with_inf(From1,To1,From2,To2) :-
3842 intersect_intervals_with_inf(From1,To1,From2,To2,Low,Up),
3843 number(Up), number(Low), Low > Up.
3844
3845 inter2([],_, []).
3846 inter2([H|T],A1, Res) :-
3847 (avl_fetch(H,A1) -> Res = [H-true|Res2] ; Res = Res2), inter2(T,A1,Res2).
3848
3849 ord_list_to_avlset(OL,R) :- ord_list_to_avlset(OL,R,unknown).
3850 ord_list_to_avlset(OrdList,Res,Origin) :-
3851 % assumes that we have generated the elements in the right order already
3852 (OrdList=[] -> Res=[]
3853 ; check_sorted(OrdList,Origin),
3854 ord_list_to_avl(OrdList,ARes), Res=avl_set(ARes)).
3855
3856 % a version which accepts a list of values without -true
3857 % values have to be ground and already converted for use in avl_set
3858 sorted_ground_normalised_list_to_avlset(List,Res,PP) :-
3859 add_true_to_list(List,LT),
3860 ord_list_to_avlset_direct(LT,Res,PP).
3861
3862 add_true_to_list([],[]).
3863 add_true_to_list([H|T],[H-true|TT]) :- add_true_to_list(T,TT).
3864
3865 % the same, but without checking sorted (only use if you are really sure the list is sorted)
3866 ord_list_to_avlset_direct([],[],_).
3867 ord_list_to_avlset_direct([H|T],Res,_):-
3868 (T==[] -> H=Key-Val, Res = avl_set(node(Key,Val,0,empty,empty)) % slightly faster than calling ord_list_to_avl
3869 ; ord_list_to_avl([H|T],ARes), Res = avl_set(ARes)).
3870
3871 check_sorted([],_) :- !.
3872 check_sorted([H-_|T],Origin) :- !, check_sorted2(T,H,Origin).
3873 check_sorted(X,Origin) :- add_error_and_fail(ord_list_to_avlset,'Not a list of -/2 pairs: ',Origin:X).
3874
3875 check_sorted2([],_,_) :- !.
3876 check_sorted2([H-_|T],PH,Origin) :- PH @< H,!, check_sorted2(T,H,Origin).
3877 check_sorted2(X,Prev,Origin) :-
3878 add_error_and_fail(ord_list_to_avlset,'Not a sorted list of -/2 pairs: ',Origin:(X,Prev)).
3879
3880 % ------------------
3881
3882 :- use_module(kernel_freetypes,[is_maximal_freetype/1]).
3883 is_definitely_maximal_set(S) :- nonvar(S),
3884 is_definitely_maximal_set2(S).
3885 is_definitely_maximal_set2(freetype(ID)) :- is_maximal_freetype(ID).
3886 is_definitely_maximal_set2(global_set(GS)) :- is_maximal_global_set(GS).
3887 is_definitely_maximal_set2(closure(P,T,B)) :- is_definitely_maximal_closure(P,T,B).
3888 is_definitely_maximal_set2(avl_set(S)) :- quick_definitely_maximal_set_avl(S).
3889 is_definitely_maximal_set2([H|T]) :- nonvar(H), is_definitely_maximal_list(H,T). %, nl,print(maximal(H,T)),nl,nl.
3890 %H==pred_true, T == [pred_false]. % for some reason BOOL is sometimes presented this way
3891 is_definitely_maximal_set2(empty) :- % detect unwrapped AVL sets
3892 add_internal_error('Not a set: ',is_definitely_maximal_set2(empty)),fail.
3893 is_definitely_maximal_set2(node(A,B,C,D,E)) :-
3894 add_internal_error('Not a set: ',is_definitely_maximal_set2(node(A,B,C,D,E))),fail.
3895
3896 is_definitely_maximal_list(pred_true,T) :- nonvar(T), T=[_|_]. %
3897 is_definitely_maximal_list(pred_false,T) :- nonvar(T), T=[_|_].%
3898 is_definitely_maximal_list(fd(_,Type),T) :- nonvar(T),b_global_set_cardinality(Type,Card),
3899 % check if we have the same number of elements as the type: then the set must me maximal
3900 length_at_least(T,Card).
3901 % We could try and and also treat pairs
3902
3903 length_at_least(1,_) :- !. % we have already removed 1 element; T can be nil
3904 length_at_least(N,T) :- nonvar(T), T=[_|TT], N1 is N-1, length_at_least(N1,TT).
3905
3906 is_definitely_maximal_closure(_,_,b(truth,_Pred,_)) :- !.
3907 is_definitely_maximal_closure(P,T,B) :- is_cartesian_product_closure_aux(P,T,B,S1,S2),!,
3908 is_definitely_maximal_set(S1),is_definitely_maximal_set(S2).
3909 is_definitely_maximal_closure(P,T,B) :-
3910 is_full_powerset_or_relations_or_struct_closure(closure(P,T,B),Sets),
3911 l_is_definitely_maximal_set(Sets).
3912
3913 l_is_definitely_maximal_set([]).
3914 l_is_definitely_maximal_set([H|T]) :- is_definitely_maximal_set(H), l_is_definitely_maximal_set(T).
3915
3916 % check if we have an AVL tree covering all elements of the underlying type
3917 quick_definitely_maximal_set_avl(AVL) :-
3918 AVL=node(El,_True,_,_Left,_Right),
3919 quick_definitely_maximal_set_avl_aux(El,AVL).
3920 quick_definitely_maximal_set_avl_aux(El,AVL) :-
3921 try_get_finite_max_card_from_ground_value(El,Card), % this could fail if El contains empty sets !
3922 (Card < 1000 -> true
3923 ; preferences:preference(solver_strength,SS), Card < 1000+SS*100
3924 ), % otherwise too expensive a check avl_size
3925 quick_avl_approximate_size(AVL,MaxSize),
3926 MaxSize >= Card, % otherwise no sense in computing avl_size, which is linear in size of AVL
3927 avl_size(AVL,Size),
3928 %(MaxSize>=Size -> print(ok(Size,all(Card))),nl ; print('**** ERROR: '), print(Size),nl,trace),
3929 Size=Card.
3930
3931 % check if we have an AVL function with domain covering all elements of the underlying type
3932 quick_definitely_maximal_total_function_avl(AVL) :-
3933 AVL=node(El,_True,_,_Left,_Right),
3934 El=(DomEl,_),
3935 quick_definitely_maximal_set_avl_aux(DomEl,AVL), % the size is exactly the size of the domain
3936 is_avl_partial_function(AVL).
3937
3938 % ----------------------
3939 % set_subtraction /
3940 difference_of_explicit_set(S1,S2,R) :-
3941 difference_of_explicit_set_wf(S1,S2,R,no_wf_available).
3942 % this is called with first argument nonvar (for set_subtraction operator):
3943 difference_of_explicit_set_wf(_S1,S2,R,_) :-
3944 is_definitely_maximal_set(S2), !, R=[].
3945 difference_of_explicit_set_wf(S1,S2,R,_) :- nonvar(S2), S2=[],!, R=S1.
3946 difference_of_explicit_set_wf(S1,S2,R,_) :-
3947 %nonvar(S1),
3948 ? is_very_large_maximal_global_set(S1,Type), !, % TO DO: also for freetype ? cartesian products,...
3949 /* we have a complement-set */
3950 complement_set(S2,Type,R).
3951 difference_of_explicit_set_wf(S1,S2,Result,_) :-
3952 is_not_member_value_closure(S1,Type,MS1),
3953 nonvar(MS1), is_custom_explicit_set(MS1,difference_of_explicit_set_wf),!,
3954 union_complement_set(MS1,S2,Type,Result).
3955 difference_of_explicit_set_wf(_,S2,_,_) :- var(S2), !, fail. % then we cannot do anything below
3956 difference_of_explicit_set_wf(S1,S2,R,WF) :-
3957 is_not_member_value_closure(S2,_Type,MS2), nonvar(MS2),
3958 intersection_of_explicit_set_wf(MS2,S1,R,WF),!.
3959 difference_of_explicit_set_wf(I1,I2,R,_) :-
3960 is_interval_closure_or_integerset(I1,From1,To1),
3961 is_interval_closure_or_integerset(I2,From2,To2),
3962 difference_interval(From1,To1,From2,To2,FromRes,ToRes),
3963 % TO DO: also treat case when difference yields two disjoint intervals
3964 % i.e., do not fail and forget info about interval bounds in case we cannot compute difference as a an interval, e.g., INT - {0}
3965 !,
3966 construct_interval_closure(FromRes,ToRes,R).
3967 difference_of_explicit_set_wf(avl_set(A1),S2,R,WF) :-
3968 (S2=avl_set(A2) ;
3969 ground_value(S2), expand_and_convert_to_avl_set_unless_very_large(S2,A2,WF)),!,
3970 avl_height(A2,H2),
3971 %avl_min(A1,Min1),avl_max(A1,Max1), avl_min(A2,Min2),avl_max(A2,Max2), avl_height(A1,H1),nl,print(diff(avl(H1,Min1,Max1),avl(H2,Min2,Max2))),nl,
3972 avl_height(A1,H1),
3973 ((H2<2 -> true ; H1 > H2+1) % then it is more efficient to expand A2 and remove the A2 elements from A1;
3974 % note that difference_of_explicit_set2 now also sometimes expands both:
3975 % exact threshold when it is beneficial: difference_of_explicit_set2/3
3976 % for {x|x:1..200000 & x mod 2 = 0} - {y|y:2500..29010 & y mod 2 = 0} -> 150 ms vs 80 ms avl(17,int(2),int(200000)),avl(14,int(2500),int(29010)
3977 % {x|x:1..200000 & x mod 2 = 0} - {y|y:2500..59010 & y mod 2 = 0} -> 180 ms vs 80 ms avl(17,int(2),int(200000)),avl(15,int(2500),int(59010))
3978 % {x|x:1..200000 & x mod 2 = 0} - {y|y:500..159010 & y mod 2 = 0} -> 180 ms vs 250 ms avl(17,int(2),int(200000)),avl(17,int(500),int(159010))
3979 -> expand_custom_set_to_sorted_list(S2,ES,_,difference_of_explicit_set1,WF),
3980 difference_of_explicit_set3(ES,A1,R)
3981 ; expand_custom_set_to_sorted_list(avl_set(A1),ES,Done,difference_of_explicit_set2,WF),
3982 difference_of_explicit_set2(ES,H1,A2,H2,R,Done)).
3983 difference_of_explicit_set_wf(S1,S2,R,WF) :-
3984 (S2=avl_set(A2) ;
3985 ground_value(S2), expand_and_convert_to_avl_set_unless_very_large(S2,A2,WF)),!,
3986 avl_height(A2,A2Height),
3987 difference_with_avl(S1,A2,A2Height,R,WF).
3988 % to do: we could detect same_texpr_body for two closures and return R=[]
3989
3990 :- use_module(avl_tools,[avl_approximate_size_from_height/2]).
3991 :- use_module(bsyntaxtree,[create_texpr/4, conjunct_predicates/2, mark_bexpr_as_symbolic/2]).
3992 difference_with_avl(S1,A2,A2Height,R,_) :-
3993 is_closure_or_integer_set(S1,[ID],[T],B),
3994 % check if the first argument is infinite; then do the difference set symbolically
3995 % this could supersed the complement set construction and be generalised to other sets apart from avl_sets as A2
3996 avl_approximate_size_from_height(A2Height,A2Size),
3997 Limit is max(A2Size*10,1000000), % if A2 is more than 10% size of S1, probably better to compute difference explicitly
3998 is_very_large_or_symbolic_closure([ID],[T],B,Limit),
3999 !, % TO DO: also allow multiple identifiers
4000 create_texpr(identifier(ID),T,[],TID),
4001 create_texpr(value(avl_set(A2)),set(T),[],A2Value),
4002 create_texpr(not_member(TID,A2Value),pred,[],NotMemA2),
4003 conjunct_predicates([B,NotMemA2],NewBody),
4004 mark_bexpr_as_symbolic(NewBody,NewBodyS),
4005 R = closure([ID],[T],NewBodyS).
4006 difference_with_avl(S1,A2,A2Height,R,WF) :-
4007 (nonvar(S1),S1=avl_set(A1) -> avl_height(A1,H1) ; H1=unknown),
4008 expand_custom_set_to_sorted_list(S1,ES,Done,difference_of_explicit_set3,WF),
4009 difference_of_explicit_set2(ES,H1,A2,A2Height,R,Done).
4010
4011
4012 % construct complement of a set
4013 union_complement_set(S1,S2,Type,Result) :-
4014 ground_value_check(S2,G2),
4015 when(nonvar(G2),union_complement_set2(S1,S2,Type,Result)).
4016 union_complement_set2(S1,S2,Type,Result) :-
4017 union_of_explicit_set(S1,S2,S12),
4018 construct_complement_closure_if_necessary(S12,Type,R),
4019 kernel_objects:equal_object(R,Result,union_complement_set2).
4020
4021 % construct complement of a set
4022 complement_set(S2,Type,Result) :-
4023 ground_value_check(S2,G2),
4024 when(nonvar(G2),complement_set2(S2,Type,Result)).
4025 complement_set2(S2,Type,Result) :-
4026 is_not_member_value_closure(S2,Type,MS2),!, % complement of complement
4027 kernel_objects:equal_object(MS2,Result,complement_set2).
4028 complement_set2(S2,Type,Result) :-
4029 try_expand_and_convert_to_avl_with_check(S2,ExpandedS2,difference_complement_set),
4030 construct_complement_closure_if_necessary(ExpandedS2,Type,R),
4031 kernel_objects:equal_object(R,Result,complement_set2).
4032
4033 :- block construct_complement_closure_if_necessary(-,?,?).
4034 construct_complement_closure_if_necessary(Set,TYPE,R) :-
4035 (Set=[] -> b_type2_set(TYPE,R)
4036 ; is_not_member_value_closure(Set,TYPE,MS) -> R=MS % complement of complement
4037 ; construct_complement_closure(Set,TYPE,R)).
4038
4039 % succeeds if difference of two intervals is also a interval
4040 difference_interval(SourceLow,SourceUp,DiffLow,DiffUp,ResLow,ResUp) :-
4041 (ground(SourceLow),ground(DiffLow),geq_inf(SourceLow,DiffLow)
4042 -> inc(DiffUp,D1),maximum_with_inf(D1,SourceLow,ResLow), ResUp=SourceUp
4043 ; ground(DiffUp),ground(SourceUp),geq_inf(DiffUp,SourceUp)
4044 -> ResLow=SourceLow, dec(DiffLow,D1),minimum_with_inf(SourceUp,D1,ResUp)).
4045
4046 inc(N,R) :- N==inf,!,R=inf.
4047 inc(N,N1) :- N1 is N+1.
4048 dec(N,R) :- N==inf,!,R=inf.
4049 dec(N,N1) :- N1 is N-1.
4050
4051 :- use_module(library(ordsets), [ord_subtract/3]).
4052 :- block difference_of_explicit_set2(?,?,?,?,?,-).
4053 difference_of_explicit_set2(ES,A1Height,A2,A2Height,R,_) :-
4054 (number(A1Height), A1Height+4 >= A2Height -> true
4055 ; A2Height < 5
4056 ; Limit is 2**(A2Height-4),
4057 length_larger_than(ES,Limit)
4058 % TO DO: we could try and pass sizes from specific closures to this predicate
4059 ),
4060 % A1 is not much larger than A2, then it is probably faster to use ord_subtract on expanded A2
4061 % {x|x mod 2 =0 & x:1..10000} - {y|y mod 3 =0 & y : 1..200000} : still more efficient with ord_subtract
4062 !,
4063 avl_domain(A2,A2Expanded),
4064 ord_subtract(ES,A2Expanded,OrdRes),
4065 sorted_ground_normalised_list_to_avlset(OrdRes,AVL,difference_of_explicit_set2),
4066 equal_object(AVL,R).
4067 difference_of_explicit_set2(ES,_A1Height,A2,_A2Height,R,_) :-
4068 avl_min(A2,Min),
4069 diff1(ES,Min,A2,IRes),
4070 ord_list_to_avlset(IRes,AVL,difference), % we have generated the elements in the right order already
4071 equal_object(AVL,R). % due to delays in expansion the result could be instantiated
4072
4073
4074 length_larger_than([_|T],Limit) :-
4075 (Limit<1 -> true
4076 ; L1 is Limit-1, length_larger_than(T,L1)).
4077
4078 diff1([],_, _,[]).
4079 diff1([H|T],Min,A1, Res) :-
4080 (H @< Min -> Res = [H-true|Res2],diff1(T,Min,A1,Res2)
4081 ; diff2([H|T],A1,Res)).% TO DO: compute avl_max
4082
4083 diff2([],_, []).
4084 diff2([H|T],A1, Res) :-
4085 (avl_fetch(H,A1) -> Res = Res2 ; Res = [H-true|Res2]), diff2(T,A1,Res2).
4086
4087 % another version to be used when second set small in comparison to first set
4088 difference_of_explicit_set3([],A1,Res) :- construct_avl_set(A1,AVL),
4089 equal_object(AVL,Res). % due to delay in expansion, Res could now be instantiated
4090 difference_of_explicit_set3([H|T],A1,ARes) :-
4091 (avl_delete(H,A1,_True,A2) -> true ; A2=A1),
4092 difference_of_explicit_set3(T,A2,ARes).
4093
4094 % -------------------------
4095
4096 % a version of add_element_to_explicit_set where we have already done the groundness check
4097 add_ground_element_to_explicit_set_wf(avl_set(A),Element,R,WF) :- !,
4098 convert_to_avl_inside_set_wf(Element,AEl,WF),
4099 avl_store(AEl,A,true,A2),!,R=avl_set(A2).
4100 add_ground_element_to_explicit_set_wf(Set,Element,R,WF) :-
4101 add_element_to_explicit_set_wf(Set,Element,R,WF).
4102
4103 add_element_to_explicit_set_wf(global_set(GS),_,R,_) :- is_maximal_global_set(GS), !, R=global_set(GS).
4104 add_element_to_explicit_set_wf(freetype(ID),_,R,_) :- is_maximal_freetype(ID),!, R=freetype(ID).
4105 add_element_to_explicit_set_wf(avl_set(A),Element,R,WF) :-
4106 ground_value(Element), %% was element_can_be_added_or_removed_to_avl(Element),
4107 convert_to_avl_inside_set_wf(Element,AEl,WF),
4108 avl_store(AEl,A,true,A2),!,R=avl_set(A2). /* AVL not normalised */
4109 /* do we need to add support for (special) closures ??
4110 add_element_to_explicit_set_wf(Clos,Element,R,_) :- nonvar(Element),Element=int(X), nonvar(X),
4111 is_interval_closure_or_integerset(Clos,Low,Up), ground(Low), ground(Up),
4112 union_of_interval(X,X,Low,Up,FromRes,ToRes),
4113 !,
4114 construct_interval_closure(FromRes,ToRes,R).
4115 % not-member closure not dealt with here
4116 */
4117
4118 element_can_be_added_or_removed_to_avl(Element) :-
4119 ground_value(Element),
4120 does_not_contain_closure(Element).
4121 ground_element_can_be_added_or_removed_to_avl(Element) :- /* use if you know the element to be ground */
4122 does_not_contain_closure(Element).
4123
4124 % does not contain closure or infinite other sets
4125 does_not_contain_closure([]).
4126 does_not_contain_closure([H|T]) :-
4127 (simple_value(H) -> true /* TO DO: check if we could have a closure at the end ?? */
4128 ; does_not_contain_closure(H),list_does_not_contain_closure(T)).
4129 does_not_contain_closure(fd(_,_)).
4130 does_not_contain_closure(pred_true /* bool_true */).
4131 does_not_contain_closure(pred_false /* bool_false */).
4132 does_not_contain_closure(int(_)).
4133 does_not_contain_closure(string(_)).
4134 does_not_contain_closure(term(_)). % real/floating number
4135 does_not_contain_closure((X,Y)) :- does_not_contain_closure(X), does_not_contain_closure(Y).
4136 does_not_contain_closure(avl_set(_)).
4137 does_not_contain_closure(global_set(G)) :- \+ is_infinite_global_set(G,_).
4138 %does_not_contain_closure(freetype(_)).
4139 does_not_contain_closure(freeval(_,_,Value)) :- does_not_contain_closure(Value).
4140 does_not_contain_closure(rec(Fields)) :- does_not_contain_closure_fields(Fields).
4141
4142 does_not_contain_closure_fields([]).
4143 does_not_contain_closure_fields([field(_,Val)|T]) :- does_not_contain_closure(Val),
4144 does_not_contain_closure_fields(T).
4145
4146 list_does_not_contain_closure([]).
4147 list_does_not_contain_closure([H|T]) :-
4148 does_not_contain_closure(H),list_does_not_contain_closure(T).
4149 list_does_not_contain_closure(avl_set(_)).
4150 list_does_not_contain_closure(global_set(G)) :- \+ is_infinite_global_set(G,_).
4151
4152 simple_value(fd(_,_)).
4153 simple_value(pred_true /* bool_true */).
4154 simple_value(pred_false /* bool_false */).
4155 simple_value(int(_)).
4156 simple_value((A,B)) :- simple_value(A), simple_value(B).
4157 simple_value(string(_)).
4158
4159
4160 % a version of the above which throws error if element cannot be added
4161 % assumes element_can_be_added_or_removed_to_avl has been checked
4162 remove_element_from_explicit_set(avl_set(A),Element,R) :-
4163 element_can_be_added_or_removed_to_avl(Element), % remove check?
4164 convert_to_avl_inside_set(Element,AEl), !,
4165 direct_remove_element_from_avl(A,AEl,R).
4166 remove_element_from_explicit_set(ES,Element,R) :-
4167 add_internal_error('Cannot remove element from explicit set:',remove_element_from_explicit_set(ES,Element,R)).
4168
4169 direct_remove_element_from_avl(A,AEl,R) :-
4170 avl_delete(AEl,A,_True,A2),
4171 construct_avl_set(A2,R). /* AVL not normalised */
4172
4173 /* same as remove but element can be absent */
4174 delete_element_from_explicit_set(avl_set(A),Element,R) :-
4175 element_can_be_added_or_removed_to_avl(Element),
4176 convert_to_avl_inside_set(Element,AEl), !,
4177 (avl_delete(AEl,A,_True,A2)
4178 -> construct_avl_set(A2,R)
4179 ; R = avl_set(A)
4180 ). /* AVL not normalised */
4181
4182 is_maximal_global_set(GS) :- is_maximal_global_set(GS,_Type).
4183 is_maximal_global_set(GS,_) :- var(GS),!,fail.
4184 is_maximal_global_set('INTEGER',Type) :- !, Type=integer.
4185 is_maximal_global_set('REAL',Type) :- !, Type=real.
4186 is_maximal_global_set('FLOAT',_) :- !, fail.
4187 is_maximal_global_set('STRING',Type) :- !, Type=string.
4188 is_maximal_global_set(GS,global(GS)) :-
4189 \+ kernel_objects:integer_global_set(GS).
4190
4191 % To do: maybe get rid of all complement set code; add in_difference_set as symbolic binary operator
4192 %is_very_large_maximal_global_set(X,_) :- print(very(X)),nl,fail.
4193 is_very_large_maximal_global_set(closure(P,T,B),Type) :- is_definitely_maximal_closure(P,T,B),
4194 couplise_list(T,Type).
4195 is_very_large_maximal_global_set(global_set('INTEGER'),integer).
4196 is_very_large_maximal_global_set(global_set('STRING'),string).
4197 is_very_large_maximal_global_set(global_set('REAL'),string).
4198 is_very_large_maximal_global_set(freetype(ID),freetype(ID)) :- is_infinite_freetype(ID).
4199
4200
4201
4202 remove_minimum_element_custom_set(avl_set(S),X,RES) :- !,
4203 avl_del_min(S,X,_True,Res0),
4204 (empty_avl(Res0) -> RES=[] ; RES = avl_set(Res0)).
4205 %remove_minimum_element_custom_set(closure(P,T,B),X,RES) :-
4206 % is_interval_closure_or_integerset(Clos,Low,Up),!,
4207 % X = Low, TO DO: construct new interval closure
4208 remove_minimum_element_custom_set(CS,X,RES) :-
4209 expand_custom_set_to_list(CS,ECS,Done,remove_minimum_element_custom_set),
4210 remove_minimum_element_custom_set2(ECS,X,RES,Done).
4211
4212 :- block remove_minimum_element_custom_set2(?,?,?,-).
4213 % wait until Done: otherwise the Tail of the list could be instantiated by somebody else; interfering with expand_custom_set_to_list
4214 remove_minimum_element_custom_set2([H|T],X,RES,_) :- equal_object((H,T),(X,RES)).
4215
4216
4217 min_of_explicit_set_wf(avl_set(S),Min,_) :- !, avl_min(S,Min).
4218 min_of_explicit_set_wf(Clos,Min,WF) :-
4219 is_interval_closure_or_integerset(Clos,Low,Up),
4220 (Low == minus_inf
4221 -> add_wd_error('minimum of unbounded infinite set not defined:',Clos,WF)
4222 ; cs_greater_than_equal(Up,Low),
4223 Min=int(Low)).
4224
4225 cs_greater_than_equal(X,Y) :-
4226 ((X==inf;Y==minus_inf) -> true ; kernel_objects:less_than_equal_direct(Y,X)).
4227
4228
4229 max_of_explicit_set_wf(avl_set(S),Max,_) :- !,avl_max(S,Max).
4230 max_of_explicit_set_wf(Clos,Max,WF) :-
4231 is_interval_closure_or_integerset(Clos,Low,Up),
4232 (Up==inf
4233 -> add_wd_error('maximum of unbounded infinite set not defined:',Clos,WF)
4234 ; cs_greater_than_equal(Up,Low),
4235 Max=int(Up)).
4236
4237 % ------------- SIGMA/PI --------------
4238
4239 % compute sum or product of an integer set:
4240 sum_or_mul_of_explicit_set(avl_set(S),SUMorMUL,Result) :-
4241 avl_domain(S,Dom),
4242 (SUMorMUL=sum -> simple_sum_list(Dom,0,R) ; simple_mul_list(Dom,1,R)),
4243 Result = int(R).
4244 sum_or_mul_of_explicit_set(CS,SUMorMUL,Result) :- SUMorMUL == sum,
4245 is_interval_closure(CS,Low,Up),
4246 sum_interval(Low,Up,Result),
4247 sum_interval_clpfd_prop(Low,Up,Result).
4248
4249 :- block sum_interval(-,?,?), sum_interval(?,-,?).
4250 sum_interval(Low,Up,_) :- (\+ number(Low) ; \+ number(Up)),!,
4251 add_error(sum_interval,'Cannot compute sum of interval: ',Low:Up),fail.
4252 sum_interval(Low,Up,Result) :- Low>Up,!, Result=int(0).
4253 sum_interval(Low,Up,Result) :-
4254 R is ((1+Up-Low)*(Low+Up)) // 2, % generalisation of Gauss formula k*(k+1)//2
4255 Result = int(R).
4256
4257 sum_interval_clpfd_prop(Low,Up,Result) :-
4258 preferences:preference(use_clpfd_solver,true), Result=int(R),
4259 var(R), % we haven't computed the result yet; the bounds are not known; set up constraint propagation rules
4260 !,
4261 try_post_constraint((Low #>= 0) #=> (R #> 0)), % we could provide better bounds here for negative numbers
4262 try_post_constraint(((Low #=< Up) #\/ (R #\= 0)) #=> (R #= ((1+Up-Low)*(Low+Up))//2)),
4263 try_post_constraint((Low #> Up) #=> (R #= 0)).
4264 % not working yet: x = SIGMA(i).(i:-3..n|i) & x=0 & n< -1
4265 sum_interval_clpfd_prop(_,_,_).
4266
4267 simple_sum_list([],A,A).
4268 simple_sum_list([int(H)|T],Acc,R) :- NA is Acc+H, simple_sum_list(T,NA,R).
4269 simple_mul_list([],A,A).
4270 simple_mul_list([int(H)|T],Acc,R) :- NA is Acc*H, simple_mul_list(T,NA,R).
4271
4272
4273 /*
4274 direct_product_symbolic(S,R,Res) :- % NOT YET FINISHED
4275 nonvar(S), S=closure(PS,[T1,TS2],RS),
4276 nonvar(R), R=closure(PR,[T1,TR1],RR),
4277 is_lambda_value_domain_closure(PS,TS,RS, SDomainValue,SExpr),
4278 is_lambda_value_domain_closure(PR,TR,RR, RDomainValue,RExpr),
4279 construct_closure(['zzz','_lambda_result_'],[T1,couple(TR1,TR2)],
4280 member(zzz,SDomainValue) , member(zzz,RDomainValue), eq(lambda,pair(SExpr,RExpr))).
4281 */
4282
4283 % we assume that try_expand_and_convert_to_avl_unless_very_large already called on arguments
4284 direct_product_explicit_set(S,R,Res) :-
4285 nonvar(R), %is_custom_explicit_set(R,direct_product),
4286 nonvar(S), %is_custom_explicit_set(S,direct_product),
4287 direct_product_explicit_set_aux(S,R,Res).
4288 %direct_product_explicit_set_aux(S,R,Res) :- (S = closure(_,_,_) ; R = closure(_,_,_)),
4289 % print_term_summary(direct_product_explicit_set_aux(S,R,Res)),nl,
4290 % % TO DO: generate closure
4291 % fail.
4292 direct_product_explicit_set_aux(avl_set(AS),avl_set(AR),Res) :-
4293 % the expansion guarantees that we have the lists ES and ER then in sorted order
4294 avl_domain(AS,ES), % -> expand_custom_set(avl_set(AS),ES),
4295 avl_domain(AR,ER), % -> expand_custom_set(avl_set(AR),ER),
4296 direct_product3(ES,ER,DPList),
4297 ord_list_to_avlset(DPList,DPAVL,direct_product), % is it really ordered ? findall must also return things ordered!
4298 equal_object(DPAVL,Res,direct_product_explicit_set).
4299
4300 direct_product3([],_Rel2,[]).
4301 direct_product3([(From,To1)|T1],Rel2,Res) :-
4302 get_next_mapped_to_eq(T1,From,TTo,Tail1), ToList1 = [To1|TTo],
4303 get_next_mapped_to(Rel2,From,ToList2,Tail2),
4304 calc_direct_product(ToList1,From,ToList2,Res,Rest),
4305 (Tail2=[] -> Rest=[] ; direct_product3(Tail1,Tail2,Rest)).
4306
4307 % get all elements which map to From, supposing that the list is sorted & we have already had a match
4308 get_next_mapped_to_eq([],_,[],[]).
4309 get_next_mapped_to_eq([(From2,To2)|T],From,Result,Tail) :-
4310 (From=From2 -> Result = [To2|RR], get_next_mapped_to_eq(T,From,RR,Tail)
4311 ; Result = [], Tail = [(From2,To2)|T]
4312 ).
4313
4314 % get all elements which map to From, supposing the list is sorted
4315 get_next_mapped_to([],_,[],[]).
4316 get_next_mapped_to([(From2,To2)|T],From,Result,Tail) :-
4317 (From=From2 -> Result = [To2|RR], get_next_mapped_to_eq(T,From,RR,Tail)
4318 ; From2 @> From -> Result = [], Tail = [(From2,To2)|T]
4319 ; get_next_mapped_to(T,From,Result,Tail)
4320 ).
4321
4322 calc_direct_product([],_From,_,Tail,Tail).
4323 calc_direct_product([To1|T1],From,To2List,Result,Tail) :-
4324 findall((From,(To1,To2))-true,member(To2,To2List),Result,ResResult),
4325 calc_direct_product(T1,From,To2List,ResResult,Tail).
4326
4327 % TO DO: maybe also add a special rule for infinite R such as event_b_identity ?
4328 domain_restriction_explicit_set_wf(S,R,Res,WF) :- /* S <| R */
4329 nonvar(R),
4330 (nonvar(S),is_one_element_custom_set(S,El),R \= closure(_,_,_) ->
4331 domain_restrict_singleton_element(El,R,Res)
4332 ; restriction_explicit_set_wf(S,R,Res,domain,pred_true,WF)).
4333 domain_subtraction_explicit_set_wf(S,R,Res,WF) :- /* S <<| R */
4334 (nonvar(S),is_one_element_custom_set(S,El), nonvar(R), R=avl_set(AVL) ->
4335 avl_domain_subtraction_singleton(AVL,El,ARes),
4336 construct_avl_set(ARes,Res) % TO DO: use this also when S is small and R large
4337 ; restriction_explicit_set_wf(S,R,Res,domain,pred_false,WF)).
4338 range_restriction_explicit_set_wf(R,S,Res,WF) :- /* R |> S */
4339 restriction_explicit_set_wf(S,R,Res,range,pred_true,WF).
4340 range_subtraction_explicit_set_wf(R,S,Res,WF) :- /* R |>> S */
4341 restriction_explicit_set_wf(S,R,Res,range,pred_false,WF).
4342
4343
4344 domain_restrict_singleton_element(El,R,Res) :- /* {El} <| R ; TO DO maybe apply this technique for "small" sets as well */
4345 nonvar(R), is_custom_explicit_set(R,domain_restrict_singleton_element),
4346 expand_and_convert_to_avl_set(R,AR,domain_restrict_singleton_element,''), % can generate ARel=empty; will fail if not possible to convert
4347 findall((El,Z)-true, avl_fetch_pair(El,AR,Z), RTuples),
4348 ord_list_to_avlset(RTuples,Res,domain_restrict_singleton_element).
4349
4350 restriction_explicit_set_wf(Set,Rel,Res,_RanOrDom,AddWhen,WF) :- Set==[],!,
4351 (AddWhen=pred_false
4352 -> equal_object_wf(Rel,Res,restriction_explicit_set_wf,WF) % {} <<| Rel = Rel |>> {} = Rel
4353 ; kernel_objects:empty_set_wf(Res,WF)
4354 ).
4355 restriction_explicit_set_wf(Set,Rel,Res,_RanOrDom,AddWhen,WF) :- is_definitely_maximal_set(Set),!,
4356 (AddWhen=pred_true
4357 -> equal_object_wf(Rel,Res,restriction_explicit_set_wf,WF) % TYPE <| Rel = Rel |> TYPE = Rel
4358 ; kernel_objects:empty_set_wf(Res,WF)
4359 ).
4360 restriction_explicit_set_wf(_,Rel,_,_,_,_) :- var(Rel),!,fail.
4361 restriction_explicit_set_wf(Set,closure(Paras,Types,Body),Res,RanOrDom,AddWhen,WF) :-
4362 % perform symbolic treatment by adding restriction predicate to Body
4363 !,
4364 (RanOrDom=domain
4365 -> get_domain_id_or_expr(Paras,Types,TID,TT)
4366 ; get_range_id_or_expr(Paras,Types,TID,TT)
4367 ),
4368 TSet=b(value(Set),set(TT),[]),
4369 (AddWhen = pred_true
4370 -> PRED = member(TID,TSet)
4371 ; PRED = not_member(TID,TSet) ),
4372 conjunct_predicates([b(PRED,pred,[]),Body],NewBody),
4373 % translate:print_bexpr(NewBody),nl,
4374 try_expand_and_convert_to_avl_with_catch_wf(closure(Paras,Types,NewBody),Res,restriction_explicit_set_wf,WF).
4375 restriction_explicit_set_wf(Set,Rel,Res,RanOrDom,AddWhen,WF) :-
4376 is_custom_explicit_set(Rel,restriction_explicit_set_wf),
4377 expand_and_convert_to_avl_set(Rel,ARel,restriction_explicit_set_wf,''), % can generate ARel=empty; will fail if not possible to convert
4378 avl_domain(ARel,ERel), % -> expand_custom_set(avl_set(ARel),ERel),
4379 %try_expand_and_convert_to_avl_unless_large_wf(Set,ES,WF),
4380 (nonvar(Set),Set=avl_set(AVLS)
4381 -> restrict2_avl(ERel,AVLS,DRes,RanOrDom,AddWhen,Done)
4382 ; restrict2(ERel,Set,DRes,RanOrDom,AddWhen,Done,WF)
4383 ),
4384 finish_restriction(Done,DRes,Res).
4385
4386 % extract domain expression for domain restriction/subtraction predicate:
4387 get_domain_id_or_expr([DR],[couple(TD,TR)], PRJ1, TD) :- !, % special case: just one parameter in closure
4388 TID = b(identifier(DR),couple(TD,TR),[]),
4389 PRJ1 = b(first_of_pair(TID),TD,[]).
4390 get_domain_id_or_expr([D1|Paras],[TD1|Types],Expr,Type) :-
4391 get_dom_couple_aux(Paras,Types, b(identifier(D1),TD1,[]), TD1, Expr,Type).
4392
4393 get_dom_couple_aux([_RangeID],[_], AccExpr, AccType, Expr, Type) :- !, Expr=AccExpr, Type=AccType.
4394 get_dom_couple_aux([D2|TParas],[TD2|Types], AccExpr, AccType, Expr, Type) :-
4395 TID2 = b(identifier(D2),TD2,[]),
4396 NewAccType = couple(AccType,TD2),
4397 NewAcc = b(couple(AccExpr,TID2),NewAccType,[]),
4398 get_dom_couple_aux(TParas,Types,NewAcc,NewAccType,Expr,Type).
4399
4400 :- use_module(library(lists),[last/2]).
4401 % extract range expression for range restriction/subtraction predicate:
4402 get_range_id_or_expr( [DR],[CType], PRJ2, TR) :- !, % special case: just one parameter in closure
4403 CType = couple(TD,TR),
4404 TID = b(identifier(DR),CType,[]),
4405 PRJ2 = b(second_of_pair(TID),TD,[]).
4406 get_range_id_or_expr( [_|Paras],[_|Types], b(identifier(R),TR,[]), TR) :-
4407 last(Paras,R), last(Types,TR).
4408
4409 :- block finish_restriction(-,?,?).
4410 finish_restriction(_,DRes,Res) :-
4411 ord_list_to_avlset(DRes,Restriction,restriction),
4412 equal_object(Restriction,Res,finish_restriction). % as we may block below: we need to use equal_object
4413
4414 restrict2([],_,[],_,_,done,_WF).
4415 restrict2([(From,To)|T],S,Res,RanOrDom,AddWhen,Done,WF) :-
4416 (RanOrDom==domain -> El=From ; El=To),
4417 kernel_equality:membership_test_wf(S,El,MemRes,WF), % TO DO: WF Version !!
4418 /* this only makes sense once we have the full result as argument:
4419 (nonvar(MemRes) -> true % it is already decided
4420 ; AddWhen=pred_true -> kernel_equality:membership_test_wf(Res,(From,To),MemRes,WF)
4421 ; kernel_equality:membership_test_wf(Res,(From,To),InResult,WF), bool_pred:negate(InResult,MemRes)
4422 ), */
4423 restrict3(MemRes,From,To,T,S,Res,RanOrDom,AddWhen,Done,WF).
4424 :- block restrict3(-, ?,?, ?,?,?, ?,?,?,?).
4425 restrict3(MemRes, From,To, T,S,Res, RanOrDom,AddWhen,Done,WF) :-
4426 (AddWhen=MemRes -> Res = [(From,To)-true|TRes]
4427 ; Res=TRes),
4428 restrict2(T,S,TRes,RanOrDom,AddWhen,Done,WF).
4429
4430 % optimised version when second set is also an AVL tree: less blocking,...
4431 restrict2_avl([],_,[],_,_,done).
4432 restrict2_avl([(From,To)|T],AVLS,Res,RanOrDom,AddWhen,Done) :-
4433 fetch(RanOrDom,From,To,AVLS,MemRes),
4434 (AddWhen=MemRes -> Res = [(From,To)-true|TRes]
4435 ; Res=TRes),
4436 restrict2_avl(T,AVLS,TRes,RanOrDom,AddWhen,Done).
4437
4438 fetch(domain,El,_,AVLS,MemRes) :- (avl_fetch(El,AVLS) -> MemRes=pred_true ; MemRes = pred_false).
4439 fetch(range,_,El,AVLS,MemRes) :- (avl_fetch(El,AVLS) -> MemRes=pred_true ; MemRes = pred_false).
4440
4441 % override R(X) := Y
4442 override_pair_explicit_set(avl_set(S),X,Y,avl_set(NewAVL)) :- element_can_be_added_or_removed_to_avl(X),
4443 element_can_be_added_or_removed_to_avl(Y),
4444 convert_to_avl_inside_set(X,AX),
4445 convert_to_avl_inside_set(Y,AY),
4446 avl_domain_subtraction_singleton(S,AX,AVL2),
4447 avl_store((AX,AY), AVL2, true, NewAVL).
4448
4449 avl_domain_subtraction_singleton(AVL,AX,NewAVL) :-
4450 avl_delete_pair(AX,AVL,_True,AVL2),
4451 !, % recurse, in case we have multiple entries
4452 % this recursion could be avoided if we know AVL to be a function
4453 avl_domain_subtraction_singleton(AVL2,AX,NewAVL).
4454 avl_domain_subtraction_singleton(AVL,_,AVL).
4455
4456 % try and decompose an AVL set into a cartesian product
4457 % AVL = Set1 * Set2
4458 % much faster e.g. for let xx = ((1..10)*(3..1000)\/ {0}*(3..1000)) and then xx = AA*BB
4459 % should not produce pending co-routines
4460 decompose_avl_set_into_cartesian_product_wf(AVL,DomainSet,RangeSet,WF) :-
4461 avl_domain(AVL,Expansion),
4462 decompose_cart(Expansion,'$none',DomainList,[],RangeList),
4463 construct_avl_from_lists_wf(DomainList,DomainSet,WF),
4464 construct_avl_from_lists_wf(RangeList,RangeSet,WF).
4465
4466 decompose_cart([],_,[],[],_).
4467 decompose_cart([(A,B)|T],Prev,Domain,Range,FullRange) :-
4468 (A=Prev
4469 -> Range = [B|TRange],
4470 decompose_cart(T,Prev,Domain,TRange,FullRange)
4471 ; Domain = [A|TDom], Range=[],
4472 FullRange = [B|TRange],
4473 decompose_cart(T,A,TDom,TRange,FullRange)
4474 ).
4475
4476 /* --------- */
4477 /* EXPANSION */
4478 /* --------- */
4479
4480 :- use_module(b_global_sets,[all_elements_of_type_wf/3, all_elements_of_type_rand_wf/3]).
4481
4482 expand_custom_set(X,R) :- expand_custom_set_wf(X,R,expand_custom_set,no_wf_available).
4483 expand_custom_set(X,R,Src) :- expand_custom_set_wf(X,R,Src,no_wf_available).
4484 expand_custom_set_wf(X,R,Source,WF) :- var(X), !,
4485 add_error_and_fail(expand_custom_set_wf, 'Variable as argument: ',expand_custom_set_wf(X,R,Source,WF)).
4486 expand_custom_set_wf(global_set(GS),ExpandedSet,_,WF) :- !,all_elements_of_type_wf(GS,ExpandedSet,WF).
4487 expand_custom_set_wf(freetype(GS),R,_,WF) :- !,
4488 expand_freetype(GS,ValueList,WF), convert_to_avl(ValueList,R).
4489 expand_custom_set_wf(avl_set(AVL),ExpandedSet,_,_) :- !,
4490 avl_domain(AVL,ExpandedSet).
4491 expand_custom_set_wf(closure(Parameters,PTypes,Cond),Res,Source,WF) :- !,
4492 expand_closure_to_list(Parameters,PTypes,Cond,Res,_Done,Source,WF).
4493 %wait_try_expand_custom_set(Res1,Res). % could be in AVL form; no longer the case !
4494 expand_custom_set_wf(Set,_,Source,_) :-
4495 add_error_and_fail(expand_custom_set(Source),'Cannot expand custom set: ',Set).
4496
4497
4498
4499 %try_expand_only_custom_closure_global(X,Y) :-
4500 % (var(X) -> X=Y ; expand_only_custom_closure_global(X,Y,check)).
4501
4502 expand_only_custom_closure_global(X,R,C,_WF) :- var(X), !,
4503 add_error_and_fail(expand_only_custom_closure_global, 'Variable as argument: ',expand_only_custom_closure_global(X,R,C)).
4504 expand_only_custom_closure_global(global_set(GS),ExpandedSet,_,WF) :- !,all_elements_of_type_wf(GS,ExpandedSet,WF).
4505 expand_only_custom_closure_global(freetype(GS),ExpandedSet,_,_WF) :- !,ExpandedSet=freetype(GS).
4506 expand_only_custom_closure_global(avl_set(AVL),ExpandedSet,_,_WF) :- !, ExpandedSet=avl_set(AVL).
4507 expand_only_custom_closure_global(closure(Parameters,PTypes,Cond),Res,CheckTimeOuts,WF) :- !,
4508 (Res==[] -> is_empty_explicit_set(closure(Parameters,PTypes,Cond)) % TO DO: think about other special cases
4509 ; expand_closure_to_avl_or_list(Parameters,PTypes,Cond,Res,CheckTimeOuts,WF)).
4510 expand_only_custom_closure_global(Set,Set,_CheckTimeOuts,_WF).
4511 %:- add_error_and_fail(expand_only_custom_closure_global,'Cannot expand custom set: ',Set).
4512
4513
4514 try_expand_custom_set_with_catch(CS,Expansion,PP) :-
4515 on_enumeration_warning(try_expand_custom_set_wf(CS,Expansion,PP,no_wf_available),
4516 Expansion=CS).
4517
4518 try_expand_custom_set(CS,Expansion) :-
4519 try_expand_custom_set_wf(CS,Expansion,try_expand_custom_set,no_wf_available).
4520
4521
4522 try_expand_custom_set_wf(CS,Res,_,_) :- var(CS),!,Res=CS.
4523 try_expand_custom_set_wf([],Res,_,_) :- !, Res=[].
4524 try_expand_custom_set_wf([H|T],Res,_,_) :- !, Res=[H|T].
4525 try_expand_custom_set_wf(CS,Res,Src,WF) :-
4526 expand_custom_set_wf(CS,Res,Src,WF). % will generate error message for illegal sets
4527
4528
4529 :- assert_must_succeed((expand_custom_set_to_list(closure(['_zzzz_unit_tests'],
4530 [couple(integer,integer)],
4531 b(member(b(identifier('_zzzz_unit_tests'),couple(integer,integer),[generated]),
4532 b(value([(int(1),int(22))]),set(couple(integer,integer)),[])),pred,[])),R),R==[(int(1),int(22))])).
4533
4534 expand_custom_set_to_list(CS,List) :- expand_custom_set_to_list(CS,List,_Done,unknown).
4535
4536 % a version of expansion which returns guaranteed_ground if the List is guaranteed to be ground
4537 expand_custom_set_to_list_gg(CS,List,GuaranteedGround,_PP) :-
4538 nonvar(CS), CS=avl_set(AVL), var(List),
4539 !,
4540 GuaranteedGround = guaranteed_ground,
4541 avl_domain(AVL,List).
4542 expand_custom_set_to_list_gg(CS,List,not_guaranteed_ground,PP) :-
4543 expand_custom_set_to_list(CS,List,_Done,PP).
4544
4545 % a version where the expansion should happen straightaway and should not block:
4546 expand_custom_set_to_list_now(CS,List) :- expand_custom_set_to_list(CS,List,Done,unknown),
4547 (Done==true -> true ; print_error(expand_custom_set_to_list_not_done(CS,List))).
4548
4549 :- block expand_custom_set_to_sorted_list(-,-,?,?,?).
4550 % sorts the resulting list if needed
4551 % due to random enumeration
4552 expand_custom_set_to_sorted_list(From,To,Done,Source,WF) :-
4553 expand_custom_set_to_list(From,UnsortedTo,Done,Source),
4554 (preferences:get_preference(randomise_enumeration_order,true)
4555 -> sort_when_done(Done,UnsortedTo,To,WF) ; UnsortedTo = To).
4556
4557 :- block sort_when_done(-,?,?,?).
4558 sort_when_done(_,Unsorted,Res,WF) :- sort(Unsorted,Sorted),
4559 equal_object_wf(Sorted,Res,sort_when_done,WF).
4560
4561 expand_custom_set_to_list(From,To,Done,Source) :-
4562 expand_custom_set_to_list_wf(From,To,Done,Source,no_wf_available).
4563
4564 :- use_module(kernel_objects,[equal_object_wf/4]).
4565
4566 expand_custom_set_to_list_wf(From,To,Done,Source,WF) :-
4567 expand_custom_set_to_list_k_wf(From,To,Done,_Kind,Source,WF).
4568
4569 % a variation of expand_custom_set_to_list which also checks that there are no duplicates in the list
4570 expand_custom_set_to_list_no_dups_wf(From,To,Done,Source,WF) :-
4571 expand_custom_set_to_list_k_wf(From,To,Done,Kind,Source,WF),
4572 check_dups(Kind,To,WF).
4573
4574 :- block check_dups(-,?,?).
4575 check_dups(unsorted_list,List,WF) :- !,
4576 kernel_objects:check_no_duplicates_in_list(List,[],WF).
4577 check_dups(_,_,_).
4578
4579 % warn if duplicates in list; to do: use in prob_safe mode
4580 %:- block warn_dups(-,?,?,?).
4581 %warn_dups(unsorted_list,List,Src,WF) :- !,
4582 % kernel_objects:warn_if_duplicates_in_list(List,Src,WF).
4583 %warn_dups(_,_,_,_).
4584
4585
4586
4587 :- block expand_custom_set_to_list_k_wf(-,-,?,?,?,?).
4588 % ensures that the output is a pure list; the list skeleton should not be instantiated by anybody else
4589 expand_custom_set_to_list_k_wf(From,To,Done,Kind,Source,WF) :-
4590 (var(From) ->
4591 (is_list_skeleton(To)
4592 -> equal_object_wf(To,From,Source,WF), Done=true, Kind=unsorted_list
4593 ? ; expand_custom_set_to_list2(To,From,Done,Kind,Source,WF))
4594 ; var(To),is_list_skeleton(From)
4595 -> To=From, Done=true, Kind=unsorted_list % equal_object_wf will also to a Prolog unification
4596 ; expand_custom_set_to_list2(From,To,Done,Kind,Source,WF)).
4597
4598 expand_custom_set_to_list2([],ExpandedSet,Done,Kind,_Source,WF) :- !,
4599 ? equal_object_wf([],ExpandedSet,expand_custom_set_to_list2,WF),Done=true,Kind=empty_set.
4600 expand_custom_set_to_list2([H|T],ExpandedSet,Done,Kind,Source,WF) :- !, Kind=unsorted_list,
4601 ? equal_object_wf([H|ET],ExpandedSet,expand_custom_set_to_list2,WF),
4602 ? expand_custom_set_to_list3(T,ET,Done,Source,WF).
4603 expand_custom_set_to_list2(global_set(GS),ExpandedSet,Done,Kind,_Source,WF) :- !,
4604 all_elements_of_type_rand_wf(GS,R,WF),
4605 check_list(R,expand_custom_set_to_list2),
4606 equal_object_wf(R,ExpandedSet,expand_custom_set_to_list2,WF),Done=true,Kind=sorted_list.
4607 expand_custom_set_to_list2(avl_set(AVL),ExpandedSet,Done,Kind,_Source,WF) :- !,
4608 avl_domain(AVL,R),
4609 ? equal_object_wf(R,ExpandedSet,expand_custom_set_to_list2,WF), Done=true,Kind=sorted_list.
4610 expand_custom_set_to_list2(closure(Parameters,PTypes,Cond),ExpandedSet,Done,Kind,Source,WF) :- !,
4611 expand_closure_to_list(Parameters,PTypes,Cond,ExpandedSet,Done,Source,WF),
4612 Kind=sorted_list.
4613 %assign_expand_result(CDone,Res,ExpandedSet,Done).
4614 expand_custom_set_to_list2(freetype(ID),ExpandedSet,Done,Kind,_Source,WF) :- !,
4615 expand_freetype(ID,R,WF),
4616 equal_object_wf(R,ExpandedSet,expand_custom_set_to_list2,WF),
4617 Done=true,Kind=sorted_list.
4618 % missing avl_set wrapper:
4619 expand_custom_set_to_list2(node(A,B,C,D,E),ExpandedSet,Done,Kind,Source,WF) :- !,
4620 add_internal_error('Illegal argument: ',expand_custom_set_to_list2(node(A,B,C,D,E),ExpandedSet,Done,Source)),
4621 expand_custom_set_to_list2(avl_set(node(A,B,C,D,E)),ExpandedSet,Done,Kind,Source,WF).
4622 expand_custom_set_to_list2(E,ES,Done,Kind,Source,WF) :-
4623 add_internal_error('Illegal argument: ',expand_custom_set_to_list2(E,ES,Done,Kind,Source,WF)),fail.
4624
4625 :- block expand_custom_set_to_list3(-,-,?,?,?). % we are no longer sure which was From and which is To
4626 expand_custom_set_to_list3(From,To,Done,Source,WF) :-
4627 ? (var(From) -> expand_custom_set_to_list2(To,From,Done,_,Source,WF) ;
4628 ? expand_custom_set_to_list2(From,To,Done,_,Source,WF)).
4629
4630 expand_freetype(ID,Elements,WF) :- var(ID), !,
4631 add_internal_error('Uninstantiated freetype ID: ',expand_freetype(ID,Elements,WF)), fail.
4632 expand_freetype(ID,Elements,WF) :-
4633 findall(FV, enumerate_freetype_wf(basic,FV,freetype(ID),WF), Elements).
4634
4635 is_list_skeleton(X) :- var(X),!,fail.
4636 is_list_skeleton([]).
4637 is_list_skeleton([_|T]) :- is_list_skeleton(T).
4638
4639 % true if it is more efficient to keep this, rather than expand into list
4640 is_efficient_custom_set(avl_set(_)).
4641 is_efficient_custom_set(closure(P,T,B)) :-
4642 (is_interval_closure(closure(P,T,B),_,_) -> true ; is_infinite_or_symbolic_closure(P,T,B)).
4643 is_efficient_custom_set(global_set(X)) :- is_infinite_global_set(X,_).
4644 is_efficient_custom_set(freetype(_)).
4645
4646 % tries to expand & convert to avl_set; fails if not possible: NOTE: also generates empty AVL
4647 expand_and_convert_to_avl_set(R,AER,Origin,Source) :-
4648 try_expand_and_convert_to_avl(R,ER,Origin,Source),
4649 nonvar(ER),(ER==[] -> AER=empty ; ER=avl_set(AER)).
4650
4651
4652 expand_and_convert_to_avl_set_unless_very_large(R,AER,WF) :-
4653 try_expand_and_convert_to_avl_unless_very_large_wf(R,ER,WF),
4654 nonvar(ER),(ER==[] -> AER=empty ; ER=avl_set(AER)).
4655
4656
4657 % similar to unless_large version, but will only expand if it is guaranteed to be small
4658
4659 try_expand_and_convert_to_avl_if_smaller_than(freetype(GS),Res,_) :- !, Res = freetype(GS).
4660 try_expand_and_convert_to_avl_if_smaller_than([H|T],Res,_) :- !, try_expand_and_convert_to_avl([H|T],Res).
4661 try_expand_and_convert_to_avl_if_smaller_than(avl_set(A),Res,_) :- !, Res=avl_set(A).
4662 try_expand_and_convert_to_avl_if_smaller_than(CS,Res,Limit) :-
4663 (is_small_specific_custom_set(CS,Limit)
4664 -> try_expand_and_convert_to_avl(CS,Res,try_expand_and_convert_to_avl_if_smaller_than,'')
4665 ; Res = CS % TO DO: maybe look at cardinality of types and determine max. cardinality
4666 ).
4667 is_small_specific_custom_set(CS,Limit) :- card_for_specific_custom_set(CS,Card,Code),
4668 call(Code), ground(Card),Card \= inf, number(Card),Card<Limit.
4669 get_card_for_specific_custom_set(CS,Card) :-
4670 card_for_specific_custom_set(CS,Card,Code),
4671 ? call(Code), ground(Card).
4672
4673 try_expand_and_convert_to_avl_unless_very_large_wf(CS,Res,WF) :-
4674 try_expand_and_convert_to_avl_unless_large_wf(CS,Res,10000,WF).
4675
4676 try_expand_and_convert_to_avl_unless_large_wf(CS,Res,WF) :-
4677 try_expand_and_convert_to_avl_unless_large_wf(CS,Res,2000,WF).
4678
4679 try_expand_and_convert_to_avl_unless_large_wf(CS,Res,_,_WF) :- var(CS), !, CS=Res.
4680 try_expand_and_convert_to_avl_unless_large_wf(global_set(GS),Res,_,_WF) :- !, Res = global_set(GS).
4681 try_expand_and_convert_to_avl_unless_large_wf(freetype(GS),Res,_,_WF) :- !, Res = freetype(GS).
4682 %try_expand_and_convert_to_avl_unless_large_wf(CS,Res,_WF) :- is_interval_closure(CS,Low,Up),!,
4683 % ((ground(Low),ground(Up),Size is 1+Up-Low, Size<2000)
4684 %% -> try_expand_and_convert_to_avl(CS,Res)
4685 % ; Res = CS
4686 % ).
4687 try_expand_and_convert_to_avl_unless_large_wf(closure(P,T,B),Res,Limit,_WF) :-
4688 is_very_large_or_symbolic_closure(P,T,B,Limit),!, % is explicitly marked as SYMBOLIC
4689 Res=closure(P,T,B).
4690 try_expand_and_convert_to_avl_unless_large_wf(CS,Res,_Limit,WF) :-
4691 % TO DO: check if maybe we cannot determine card explicitly, but have a large lower-bound
4692 try_expand_and_convert_to_avl_wf(CS,Res,try_expand_and_convert_to_avl_unless_large,'',WF).
4693
4694
4695
4696 % calls try_expand_and_convert_to_avl and returns original value if enumeration warning occured
4697 try_expand_and_convert_to_avl_with_catch_wf(CS,Res,Origin,WF) :-
4698 on_enumeration_warning(try_expand_and_convert_to_avl_wf(CS,Res,Origin,'',WF),
4699 Res=CS).
4700
4701 /* tries to generate an avl-structure, if possible */
4702 try_expand_and_convert_to_avl(CS,Res) :-
4703 try_expand_and_convert_to_avl_wf(CS,Res,try_expand_and_convert_to_avl,'',no_wf_available).
4704
4705 try_expand_and_convert_to_avl(CS,Res,Origin,Source) :-
4706 try_expand_and_convert_to_avl_wf(CS,Res,Origin,Source,no_wf_available).
4707
4708 try_expand_and_convert_to_avl_wf(CS,Res,_,_,_WF) :- var(CS), !, CS=Res.
4709 try_expand_and_convert_to_avl_wf(avl_set(A),R,_,_,_WF) :- !, R=avl_set(A).
4710 try_expand_and_convert_to_avl_wf([],R,_,_,_WF) :- !, R=[].
4711 try_expand_and_convert_to_avl_wf([H|T],R,_,_,WF) :- !, try_convert_to_avl_wf([H|T],R,WF).
4712 try_expand_and_convert_to_avl_wf(closure(P,T,B),Res,Origin,_Source,WF) :- !,
4713 debug_opt_push_wait_flag_call_stack_info(WF,
4714 external_call('TRY EXPANDING',[closure(P,T,B)],unknown),WF2),
4715 expand_only_custom_closure_global(closure(P,T,B),Expansion,check(Origin),WF2),
4716 try_convert_to_avl_wf(Expansion,Res,WF).
4717 try_expand_and_convert_to_avl_wf(CS,Res,Origin,_Source,WF) :-
4718 (\+ is_custom_explicit_set(CS,try_expand_and_convert_to_avl_wf)
4719 -> Expansion = CS
4720 ; expand_only_custom_closure_global(CS,Expansion,check(Origin),WF)
4721 ),
4722 try_convert_to_avl_wf(Expansion,Res,WF).
4723
4724 try_convert_to_avl(Expansion,Res) :-
4725 (should_be_converted_to_avl_from_lists(Expansion) -> construct_avl_from_lists(Expansion,Res) ; Res=Expansion).
4726 try_convert_to_avl_wf(Expansion,Res,WF) :-
4727 (should_be_converted_to_avl_from_lists(Expansion) -> construct_avl_from_lists_wf(Expansion,Res,WF) ; Res=Expansion).
4728
4729 should_be_converted_to_avl_from_lists(Value) :- var(Value),!,fail.
4730 should_be_converted_to_avl_from_lists(Value) :-
4731 \+ is_custom_explicit_set(Value,should_be_converted_to_avl_from_lists), % already avl_set, global_set or closure
4732 \+ do_not_convert_aux(Value),
4733 ground_value(Value).
4734
4735 do_not_convert_aux(V) :- var(V),!.
4736 do_not_convert_aux((A,B)) :- !,
4737 (do_not_convert_aux(A) -> true ; do_not_convert_aux(B)).
4738 do_not_convert_aux([H|T]) :- !, % do not convert a set containing a symbolic closure
4739 (var(T) -> true ; do_not_convert_aux(H)).
4740 do_not_convert_aux(rec(Fields)) :- !,
4741 (var(Fields) -> true
4742 ? ; member(field(_,V),Fields), do_not_convert_aux(V) -> true).
4743 do_not_convert_aux(H) :-
4744 is_symbolic_closure(H).
4745
4746 should_be_converted_to_avl(Value) :- %preference(use_avl_trees_for_sets,true),
4747 ground_value(Value).
4748
4749 try_expand_and_convert_to_avl_with_check(CS,Res,Origin) :-
4750 try_expand_and_convert_to_avl_with_check(CS,Res,do_not_keep_intervals,Origin).
4751
4752 try_expand_and_convert_to_avl_with_check(CS,Res,_,_Origin) :- var(CS),!, Res = CS.
4753 try_expand_and_convert_to_avl_with_check([],Res,_,_Origin) :- !, Res=[].
4754 try_expand_and_convert_to_avl_with_check(avl_set(A),Res,_,_Origin) :- !, Res=avl_set(A).
4755 try_expand_and_convert_to_avl_with_check([H|T],Res,_,Origin) :- !, try_expand_and_convert_to_avl([H|T],Res,Origin,'').
4756 %try_expand_and_convert_to_avl_with_check(CS,Res,_Origin) :-
4757 % \+ is_custom_explicit_set(CS,try_expand_and_convert_to_avl),!, Res = CS.
4758 try_expand_and_convert_to_avl_with_check(CS,Res,KeepIntervals,_Origin) :-
4759 is_interval_closure(CS,Low,Up),
4760 (var(Low) -> true ; var(Up) -> true % better keep this symbolic as we may be able to do constraint propagation
4761 ; KeepIntervals=keep_intervals(Size) -> Up-Low >= Size
4762 ),
4763 !, % TO DO: see if we should do this check in try_expand_and_convert_to_avl above instead
4764 Res=CS.
4765 try_expand_and_convert_to_avl_with_check(CS,Res,_,Origin) :-
4766 ? get_card_for_specific_custom_set(CS,Size), % TO DO: avoid checking for special closures twice (below in try_expand_and_convert_to_avl ?)
4767 !,
4768 try_expconv_to_avl_with_size(Size,CS,Res,Origin).
4769 try_expand_and_convert_to_avl_with_check(CS,Res,_,Origin) :-
4770 try_expand_and_convert_to_avl(CS,Res,Origin,'').
4771
4772 try_expconv_to_avl_with_size(inf,CS,Res,Origin) :- !,
4773 debug_format(9,'### Not expanding infinite or very large set~n### ORIGIN: ~w~n',[Origin]),
4774 Res=CS.
4775 try_expconv_to_avl_with_size(Size,CS,Res,Origin) :- Size>=10000000, !,
4776 /* will probably never terminate */
4777 debug_format(9,'### Not expanding very large set with cardinality ~w~n### ORIGIN: ~w~n',[Size,Origin]),
4778 Res=CS.
4779 try_expconv_to_avl_with_size(Size,CS,Res,Origin) :- Size>=50000, !,
4780 print('### WARNING: expanding very large comprehension set, size = '), print(Size),nl,
4781 print('### ORIGIN: '), print(Origin),nl,
4782 try_expand_and_convert_to_avl(CS,Res,Origin,'').
4783 try_expconv_to_avl_with_size(_Size,CS,Res,Origin) :-
4784 try_expand_and_convert_to_avl(CS,Res,Origin,'').
4785
4786 /* underlying assumption for var case: if G is a global set: we get back the
4787 global_set tag immediately: no need to use when to wait;
4788 better: ensure that b_compute_expression always returns a nonvar term */
4789
4790
4791 :- assert_must_succeed((custom_explicit_sets:try_expand_custom_set(closure([xx],[integer],b(falsity,pred,[])),R),R = [])).
4792 :- assert_must_succeed((custom_explicit_sets:test_closure(X),custom_explicit_sets:expand_custom_set(X,EX),
4793 EX = [(fd(1,'Name'),_),(fd(3,'Name'),_)])).
4794
4795 test_closure(X) :- X = closure(['_zzzz_binary'],[couple(global('Name'),set(global('Name')))],
4796 b(member(b(identifier('_zzzz_binary'),couple(global('Name'),set(global('Name'))),[generated]),
4797 b(cartesian_product(b(value([fd(1,'Name'),fd(3,'Name')]),set(global('Name')),[]),
4798 b(value([[fd(2,'Name'),fd(3,'Name')]]),set(set(global('Name'))),[])),
4799 set(couple(global('Name'),set(global('Name')))),[])),pred,[])).
4800
4801
4802 /* --------- */
4803 /* ELEMENT_OF */
4804 /* --------- */
4805
4806
4807 /* A function that instantiates last argument when membership test can be decided */
4808
4809 membership_custom_set(CS,X,R) :- print(warning_deprecated_non_wf_version(CS,X,R)),nl,
4810 membership_custom_set_wf(CS,X,R,_WF).
4811
4812 membership_custom_set_wf(avl_set(A),X,R,WF) :- !, membership_avl_set_wf(A,X,R,WF).
4813 membership_custom_set_wf(freetype(_GS),_X,R,_WF) :- !, R=pred_true. % should be covered by clause above
4814 membership_custom_set_wf(CS,X,R,WF) :- R==pred_true,!, element_of_custom_set_wf(X,CS,WF).
4815 membership_custom_set_wf(CS,X,R,WF) :- R==pred_false,!, not_element_of_custom_set_wf(X,CS,WF).
4816 membership_custom_set_wf(CS,_X,R,_WF) :-
4817 is_definitely_maximal_set(CS),!,
4818 R=pred_true.
4819 membership_custom_set_wf(closure(Par,Types,Body),X,R,WF) :- !,
4820 closure_membership_wf(X,Par,Types,Body,R,WF).
4821 %membership_custom_set_wf(CS,X,R,WF) :- is_one_element_custom_set(CS,Y),!, % only succeeds for AVL
4822 % kernel_equality:equality_objects_wf_no_enumr(X,Y,R,WF).
4823 membership_custom_set_wf(global_set(GS),X,R,WF) :- !,
4824 membership_global_set(GS,X,R,WF).
4825 membership_custom_set_wf(CS,X,R,WF) :-
4826 add_internal_error('Illegal custom set: ',membership_custom_set_wf(CS,X,R,WF)),fail.
4827
4828 membership_avl_set_wf(A,X,R,WF) :- R==pred_true,!, element_of_avl_set_wf(A,X,WF).
4829 membership_avl_set_wf(A,X,R,WF) :- R==pred_false,!, not_element_of_custom_set_wf(X,avl_set(A),WF).
4830 membership_avl_set_wf(A,X,R,WF) :- is_one_element_avl(A,Y),!,
4831 kernel_equality:equality_objects_wf_no_enum(X,Y,R,WF).
4832 membership_avl_set_wf(A,_X,R,_WF) :-
4833 quick_definitely_maximal_set_avl(A),!,
4834 R=pred_true.
4835 membership_avl_set_wf(A,X,R,WF) :- reify_avl_membership(A,X,R,FullReification),
4836 (FullReification==true
4837 -> true %print_term_summary(full_reification(A,X,R)),nl,nl %% did slow down e.g. Bosch Deadlock v9, seems no longer the case
4838 ; when((ground(X);nonvar(R)),membership_avl_set_wf2(A,X,R,WF))).
4839
4840 ?membership_avl_set_wf2(A,X,R,WF) :- R==pred_true,!, element_of_avl_set_wf(A,X,WF).
4841 membership_avl_set_wf2(A,X,R,WF) :- R==pred_false,!, not_element_of_custom_set_wf(X,avl_set(A),WF).
4842 membership_avl_set_wf2(AVL,X,R,_WF) :-
4843 ground_element_can_be_added_or_removed_to_avl(X), !,
4844 (safe_avl_member(X,AVL) %safe_avl_member_ground(X,AVL)
4845 -> R=pred_true ; R=pred_false).
4846 membership_avl_set_wf2(AVL,X,Res,WF) :- % X is ground but cannot be added
4847 (Res \== pred_false, element_of_avl_set_wf(AVL,X,WF), Res=pred_true
4848 ;
4849 Res \== pred_true, not_element_of_custom_set_wf(X,avl_set(AVL),WF), Res=pred_false).
4850
4851 membership_global_set(GS,_X,R,_WF) :- is_maximal_global_set(GS),!,
4852 R=pred_true.
4853 membership_global_set(GS,X,R,WF) :- ground(X),!,
4854 (element_of_global_set_wf(X,GS,WF) -> R=pred_true ; R=pred_false).
4855 membership_global_set(GS,X,R,_WF) :- get_integer_set_interval(GS,Low,Up),!,
4856 membership_interval(X,Low,Up,R).
4857 membership_global_set(GS,X,R,WF) :- % this case should probably never apply
4858 (GS=='FLOAT' -> true % currently it actually is also treated like REAL
4859 ; print(uncovered_membership(GS,X,R,WF)),nl),
4860 when(ground(X), (element_of_global_set_wf(X,GS,WF) -> R=pred_true ; R=pred_false)).
4861
4862 membership_interval(X,Low,Up,Res) :- nonvar(Up),Up=inf,!,X=int(IX),
4863 b_interpreter_check:check_arithmetic_operator('<=',Low,IX,Res).
4864 membership_interval(X,Low,Up,Res) :- kernel_equality:in_nat_range_test(X,int(Low),int(Up),Res).
4865
4866 :- use_module(bool_pred).
4867 closure_membership_wf(X,[ZZZZ],[integer],CondClosure,Res,_WF) :-
4868 ? is_interval_closure_body(CondClosure,ZZZZ,LOW,UP),!,
4869 kernel_equality:in_nat_range_test(X,int(LOW),int(UP),Res).
4870 % TO DO: deal with open intervals 0..inf ...
4871 closure_membership_wf(X,Par,Types,Body,Res,WF) :-
4872 is_member_closure(Par,Types,Body,_Type,VAL),
4873 (VAL=value(_) ; VAL = cartesian_product(b(value(A),_,_),b(value(B),_,_))),!,
4874 (VAL=value(Set)
4875 -> kernel_objects:membership_test_wf(Set,X,Res,WF)
4876 ; kernel_equality:cartesian_pair_test_wf(X,A,B,Res,WF)).
4877 closure_membership_wf(X,Par,Typ,Body,Res,WF) :-
4878 is_not_member_closure(Par,Typ,Body,_Type,value(Set)),!,
4879 bool_pred:negate(ResXSet,Res), % was kernel_equality:inv_mem_obj(ResXSet,Res),
4880 kernel_objects:membership_test_wf(Set,X,ResXSet,WF).
4881 % TO DO: if closure = POW closure -> translate into subset_test pow_subset
4882 % TO DO: support a few other closures related to symbolic unary/binary operators: closure1, POW(..), ... ?
4883 % TO DO: expand if set is small
4884 closure_membership_wf(X,Par,Types,Body,Res,WF) :- ground_value(X),!,
4885 closure_membership_ground_wf(X,closure(Par,Types,Body),Res,WF).
4886 closure_membership_wf(X,Par,Types,Body,Res,WF) :-
4887 CS = closure(Par,Types,Body),
4888 is_small_specific_custom_set(CS,100),
4889 try_expand_and_convert_to_avl_wf(CS,Expanded,closure_membership_wf,'',WF),
4890 nonvar(Expanded), Expanded=avl_set(_),
4891 !,
4892 membership_custom_set_wf(Expanded,X,Res,WF).
4893 closure_membership_wf(X,Par,Types,Body,Res,WF) :-
4894 Body \= b(member(_,_),_,_), % otherwise we may have an infinite loop; b_check_boolean_expression will generate a closure which will call closure_membership_wf again; TO DO: refine to allow certain memberships to go through
4895 get_texpr_info(Body,BodyInfo),
4896 \+ member(prob_annotation(recursive(_RID)),BodyInfo), % otherwise we can get errors as recursive identifier _RID needs to be added to local state ! (test 1151 fails otherwise)
4897 % TO DO: add recursive parameter below in set_up_typed_localstate2; + in which other circumstances do we need to set up recursion identifier !
4898 % Try reifiyng the body
4899 NegationContext=positive,
4900 copy_wf_start(WF,closure_membership_wf,CWF),
4901 b_interpreter:set_up_typed_localstate2(Par,Types,BodyInfo,ParValues,TypedVals,[],State,NegationContext),
4902 %couplise_list(Types,XType),
4903 convert_list_into_pairs(ParValues,SingleParValue),
4904 kernel_objects:equal_object(X,SingleParValue,closure_membership_wf),
4905 b_interpreter_check:b_check_boolean_expression(Body,[],State,CWF,PredRes),
4906 !,
4907 (debug_mode(on) -> print('REIFICATION of closure: '), translate:print_bexpr(Body),nl, print(pred_res(X,PredRes)),nl ; true),
4908 b_enumerate:b_tighter_enumerate_all_values(TypedVals,WF), % not necessary ?? as X should get enumerated
4909 Res=PredRes,
4910 copy_wf_finish(WF,CWF).
4911 closure_membership_wf(X,Par,Types,Body,Res,WF) :-
4912 when( (ground(X);nonvar(Res)), %%
4913 % used to be ground(X), % with (ground(X);nonvar(Res)), test 292 failed {x,t|t : BOOL & (x : POW(1024 .. 1025) & bool(x : POW(NATURAL1)) = t)} = {{} |-> TRUE,{1024} |-> TRUE,{1024,1025} |-> TRUE,{1025} |-> TRUE} and test 1088 failed
4914 closure_membership_ground_wf(X,closure(Par,Types,Body),Res,WF)).
4915
4916 closure_membership_ground_wf(X,CS,Res,WF) :- nonvar(Res),!,
4917 % this optimization is checked in test 1452
4918 ? (Res==pred_true -> element_of_custom_set_wf(X,CS,WF) ; not_element_of_custom_set_wf(X,CS,WF)).
4919 closure_membership_ground_wf(X,CS,Res,WF) :-
4920 % to ensure that we leave no choice point behind we have to force full evaluation of element/not_element calls:
4921 % hence we do not call element_of_custom_set_wf or not_element_of_custom_set_wf below !!
4922 kernel_waitflags:get_idle_wait_flag(closure_membership_ground_wf,WF,LWF), % enable other triggered co-routines to fire first; some maybe much more efficient to deal with than closure expansion; important for test 1146
4923 %term_variables(CS,Vars),print(closure_membership_ground_wf_aux(LWF,vars(Vars),CS)),nl,
4924 ground_value_check(CS,CSGr),
4925 %when((nonvar(LWF),(nonvar(CSGr);nonvar(Res))),closure_membership_ground_wf_aux(X,CS,Res)).
4926 block_closure_membership_ground_wf_aux(X,CS,Res,CSGr,LWF). % Note: wrong block in commit 332cb17487017d819e9140427b1017a3045b3685 caused problem for test 1162
4927
4928 :- block block_closure_membership_ground_wf_aux(?,?,?,?,-),
4929 block_closure_membership_ground_wf_aux(?,?,-,-,?).
4930 block_closure_membership_ground_wf_aux(X,CS,Res, _,_) :-
4931 ? closure_membership_ground_wf_aux(X,CS,Res).
4932
4933 % X & CS are ground or Res is known
4934 closure_membership_ground_wf_aux(X,CS,Res) :- Res==pred_true,!,
4935 element_of_custom_set(X,CS).
4936 closure_membership_ground_wf_aux(X,CS,Res) :- Res==pred_false,!,
4937 ? not_element_of_custom_set(X,CS).
4938 closure_membership_ground_wf_aux(X,CS,Res) :-
4939 % we know that X is a ground value and CS is ground: we can determine completely whether X is element of CS or not
4940 if(element_of_custom_set(X,CS),Res=pred_true, Res=pred_false).
4941 /* used to be: (Res \== pred_false, element_of_custom_set(X,CS), Res=pred_true
4942 ; Res \== pred_true, not_element_of_custom_set(X,CS), Res=pred_false)).
4943 */
4944
4945
4946
4947 :- use_module(kernel_objects,[element_of_global_set/2,element_of_global_set_wf/3]).
4948 element_of_custom_set_wf(X,CS,WF) :-
4949 ? element_of_custom_set_wf2(CS,X,WF). %, print(check_ok(X)),nl.
4950
4951 element_of_custom_set_wf2(node(A,B,C,D,E),X,WF) :-
4952 add_internal_error('Unwrapped avl_set: ',element_of_custom_set_wf2(node(A,B,C,D,E),X,WF)),fail.
4953 element_of_custom_set_wf2(global_set(GS),X,WF) :- element_of_global_set_wf(X,GS,WF).
4954 element_of_custom_set_wf2(freetype(ID),X,WF) :-
4955 (is_maximal_freetype(ID) -> true
4956 ; add_internal_error('Uncovered case: ',element_of_custom_set_wf2(freetype(ID),X,WF))
4957 ). % we assume freetypes to be maximal !
4958 ?element_of_custom_set_wf2(avl_set(AVL),X,WF) :- element_of_avl_set_wf(AVL,X,WF).
4959 element_of_custom_set_wf2(closure(Parameters,PT,Cond),X,WF) :-
4960 ? element_of_closure(X,Parameters,PT,Cond,WF).
4961
4962 element_of_avl_set_wf(node(Y,_,_,empty,empty),X,WF) :- !,
4963 ? kernel_objects:equal_object_wf(X,Y,element_of_custom_set_wf2,WF).
4964 element_of_avl_set_wf(AVL,X,_WF) :- ground_value(X),!, safe_avl_member(X,AVL). %safe_avl_member_ground(X,AVL).
4965 element_of_avl_set_wf(AVL,X,WF) :-
4966 avl_approximate_size(AVL,10,ApproxSize),
4967 ? element_of_avl_set_wf(AVL,ApproxSize,X,WF).
4968
4969 :- use_module(clpfd_tables).
4970
4971 element_of_avl_set_wf(AVL,ApproxSize,X,WF) :-
4972 % first check if worthwhile to attempt table treatment
4973 % after fixing table/2 bug runtimes have slowed down and test 1753 became much slower
4974 % for test 1753 a threshold of < 63 would be ideal; but test 1716 requires size 91
4975 % TODO: re-evaluate when SICStus 4.8 available
4976 preferences:preference(use_clpfd_solver,true),
4977 preferences:preference(solver_strength,SS),
4978 ApproxSize < 100+SS,
4979 (var(X) -> true
4980 ; X = (X1,_X2) -> (ground_value(X1) -> ApproxSize < 10+SS ; true)
4981 ; X=rec(_) -> true
4982 %; X=int(_) -> true ; X=fd(_,_) -> true % for scalar values we already use in_fd_value_list_wf via avl_fd_value_check
4983 ),
4984 can_translate_avl_to_table(AVL,SkeletonType),
4985 !,
4986 ? check_element_of_avl_with_table(X,SkeletonType,AVL,WF).
4987 element_of_avl_set_wf(AVL,ApproxSize,X,WF) :-
4988 ? propagate_avl_element_information(X,AVL,ApproxSize,WF), %translate:translate_bvalue(avl_set(AVL),SS),
4989 get_bounded_wait_flag(ApproxSize,element_of_avl(X),WF,WF1),
4990 element_of_avl_set_wf3(X,AVL,ApproxSize,WF1,WF).
4991
4992
4993 % compute an approximate size (small sets are computed exactly)
4994 avl_approximate_size(AVL,Size) :- avl_approximate_size(AVL,10,Size).
4995
4996 avl_approximate_size(AVL,HeightBound,Size) :- var(AVL),!,
4997 add_internal_error('AVL Set is variable: ', avl_approximate_size(AVL,HeightBound,Size)),
4998 Size=1000000.
4999 avl_approximate_size(AVL,HeightBound,Size) :- % when the AVL gets too large; not so important that we have a precise estimation anyway
5000 % so: save some time and just compute height
5001 avl_height(AVL,Height),
5002 (Height>HeightBound
5003 -> Size is floor(2**Height-1)
5004 ; avl_size(AVL,Size)).
5005
5006 :- block element_of_avl_set_wf3(-,?,?,-,?).
5007 ?element_of_avl_set_wf3(X,AVL,_ApproxSize,_WF1,_WF) :- var(X), !, safe_avl_member(X,AVL).
5008 % TO DO: if randomise_enumeration_order is true then choose elements in random order
5009 :- if(environ(prob_data_validation_mode,xxxtrue)). % currently disabled due to bug related to 14082013/435_002.mch TO DO: investigate
5010 element_of_avl_set_wf3((X,Y),AVL,ApproxSize,WF1,WF) :- !,
5011 %% ((var(WF1), \+ ground(X)) -> print(avl_relation_check(X,Y)),nl, %%
5012 %% copy_term((X,Y),Copy), findall(Copy,safe_avl_member(Copy,AVL),Cs), print(Cs),nl, Cs \=[] %% check that at least one element exists
5013 %% ; true),
5014 couple_element_of_avl_set_wf(X,Y,AVL,ApproxSize,WF1,WF).
5015 :- else.
5016 element_of_avl_set_wf3((X,Y),AVL,ApproxSize,WF1,WF) :- !,
5017 ground_value_check(X,GrX),
5018 block_couple_element_of_avl_set_grX_wf1(X,Y,AVL,ApproxSize,GrX,WF1,WF).
5019 %when((nonvar(WF1) ; ground(X)), couple_element_of_avl_set(X,Y,AVL,GrX,WF1,WF)).
5020 :- endif.
5021 element_of_avl_set_wf3(X,AVL,_ApproxSize,WF1,_WF) :-
5022 ground_value_check(X,GrX),
5023 safe_avl_member_block(X,AVL,GrX,WF1).
5024
5025 :- block safe_avl_member_block(?,?,-,-).
5026 safe_avl_member_block(X,AVL,_,_) :-
5027 ? safe_avl_member(X,AVL).
5028
5029 :- if(environ(prob_data_validation_mode,true)).
5030 :- public couple_element_of_avl_set_wf/6. % used in conditional if above
5031 :- block couple_element_of_avl_set_wf(-,?,?,?,-,?).
5032 couple_element_of_avl_set_wf(X,Y,AVL,ApproxSize,WF1,WF) :-
5033 ground_value_check(X,GrX),
5034 ((nonvar(WF1);nonvar(GrX)) -> couple_element_of_avl_set(X,Y,AVL,GrX,WF1,WF)
5035 %; true -> when((nonvar(WF1) ; ground(X)), couple_element_of_avl_set(X,Y,AVL,WF1,WF))
5036 ; nonvar(X),X=(X1,X2),ground(X1) -> triple_element_of_avl_set(X1,X2,Y,AVL,WF)
5037 ; nonvar(X),X=(X1,X2) ->
5038 avl_member_blocking((X,Y),AVL),
5039 (ground(Y),ground(X1) -> safe_avl_member_pair_wf(X,Y,AVL,WF)
5040 ; when(ground(X1),(\+ ground(X2) -> triple_element_of_avl_set(X1,X2,Y,AVL,WF) ; true % avl_member_blocking will have done its work
5041 )),
5042 block_couple_element_of_avl_set(X,Y,AVL,WF1,WF)
5043 )
5044 ; %when((nonvar(WF1) ; ground(X)), couple_element_of_avl_set(X,Y,AVL,WF1,WF))
5045 block_couple_element_of_avl_set_grX_wf1(X,Y,AVL,ApproxSize,GrX,WF1,WF)
5046 /* ; (simple_avl_type(AVL)
5047 -> avl_member_blocking((X,Y),AVL) % TO DO: don't call couple_element_of_avl_set ! avoid double traversal !!
5048 ; true),
5049 block_couple_element_of_avl_set_grX_wf1(X,Y,AVL,GrX,WF1,WF) */
5050 ).
5051
5052 :- block block_couple_element_of_avl_set(?,?,?,-,?).
5053 block_couple_element_of_avl_set(X,Y,_AVL,_WF1,_WF) :- ground(X),ground(Y),!.
5054 block_couple_element_of_avl_set(X,Y,AVL,_WF1,WF) :- safe_avl_member_pair_wf(X,Y,AVL,WF).
5055
5056 triple_element_of_avl_set(X1,X2,Y,AVLRelation,WF) :- % X1 must be ground
5057 copy_term((X2,Y),(CX2,CY)),
5058 findall((CX2,CY),safe_avl_member_pair((X1,CX2),CY,AVLRelation),Images),
5059 % we pass no WF to safe_avl_member_pair; we need to fully evaluate all unifications due to findall
5060 Images \= [],
5061 construct_avl_from_lists_wf(Images,AVL,WF),
5062 element_of_custom_set_wf2(AVL,(X2,Y),WF). % will set up waitflag if necessary
5063 :- endif.
5064
5065 % ---------------------------------------------------
5066
5067 test_avl_set(node(((int(2),int(3)),int(6)),true,0,node(((int(1),int(2)),int(2)),true,0,empty,empty),node(((int(3),int(4)),int(12)),true,0,empty,empty))).
5068
5069 %simple_avl_type(node(K,_,_,_,_)) :- simple_value(K). % we can index directly on AVL, without having to normalise inner values
5070 % in particular, we can apply avl_member_blocking
5071
5072 :- assert_must_succeed(( custom_explicit_sets:test_avl_set(A), custom_explicit_sets:avl_member_blocking(((X,Y),Z),A), X=int(2), Y==int(3),Z==int(6) )).
5073 :- assert_must_succeed(( custom_explicit_sets:test_avl_set(A), custom_explicit_sets:avl_member_blocking(((X,Y),Z),A), X=int(3), Y==int(4),Z==int(12) )).
5074 :- assert_must_succeed(( custom_explicit_sets:test_avl_set(A), custom_explicit_sets:avl_member_blocking(((X,Y),Z),A), X=int(1), Y==int(2),Z==int(2) )).
5075 :- assert_must_fail(( custom_explicit_sets:test_avl_set(A), custom_explicit_sets:avl_member_blocking(((X,_Y),_Z),A), X=int(5) )).
5076 % a blocking version of avl_member; will not instantiate the element; just prune
5077
5078 avl_member_blocking(Key, AVL) :- AVL=node(K,_,_,L,R),
5079 %avl_height(AVL,Height),
5080 avl_member_blocking4(Key,K,L,R).
5081
5082 avl_member_blocking4(Key,Kavl,L,R) :- L=empty,R=empty,!,
5083 Key=Kavl. % we could do equal_object
5084 avl_member_blocking4(Key,Kavl,L,R) :-
5085 match_possible(Key,Kavl,MatchPossible), % check if in principle a match could occur
5086 (Kavl=(_,_) ->
5087 (avl_min(R,Knext) -> true ; dif(O,>), Knext=no_match,
5088 force_comp(MatchPossible,O,'<')),
5089 (avl_max(L,Kprev) -> true ; dif(O,<), Kprev=no_match,
5090 force_comp(MatchPossible,O,'>'))
5091 ; Knext = no_match, Kprev = no_match
5092 ),
5093 (nonvar(O) -> true
5094 /* ; (MatchPossible==pred_false, avl_height(L,Height), Height < 8,
5095 copy_term(Key,CKey), \+ safe_avl_member(CKey,L), \+ safe_avl_member(CKey,R))
5096 -> print(cannot_match(Key)),nl,fail */
5097 ; compare_blocking(O, Key, Kavl, Kprev,Knext)),
5098 avl_member_blocking_aux(O, Key, Kavl, L, R).
5099
5100 %force_comp(V,_,_) :- var(V),!.
5101 :- block force_comp(-,?,?).
5102 force_comp(pred_true,_,_).
5103 force_comp(pred_false,R,R).
5104
5105 :- block avl_member_blocking_aux(-,?,?,?,?).
5106 avl_member_blocking_aux(<, Key, _K, AVL, _) :- avl_member_blocking(Key, AVL).
5107 avl_member_blocking_aux(=, Key, Key, _L, _R). % we could use equal_object
5108 avl_member_blocking_aux(>, Key, _K, _, AVL) :- avl_member_blocking(Key, AVL).
5109
5110 % a blocking version of compare
5111 compare_blocking(Res,A,Kavl, Kprev, Knext) :- block_compare(A,Kavl,Res, Kprev, Knext).
5112
5113 :- block block_compare(-,?,?,?,?), block_compare(?,-,?,?,?).
5114 block_compare((A,B),Kavl,Res, Kprev, Knext) :- !,
5115 (Kavl=(RA,RB) ->
5116 match_key(Kprev,RA,PA,PB),
5117 match_key(Knext,RA,NA,NB),
5118 block_compare(A,RA,ACRes,PA,NA),
5119 block_compare_aux(ACRes,B,RB,Res,PB,NB)
5120 ; add_internal_error('Illegal type: ',block_compare((A,B),Kavl,Res, Kprev, Knext)),fail).
5121 % TO DO: same for records; but currently not used anyway
5122 block_compare(int(A),int(B),Res,_,_) :- !, block_compare_atomic(A,B,Res).
5123 block_compare(pred_false,B,Res,_,_) :- !, block_compare_atomic(pred_false,B,Res).
5124 block_compare(pred_true,B,Res,_,_) :- !, block_compare_atomic(pred_true,B,Res).
5125 block_compare(string(A),string(B),Res,_,_) :- !, block_compare_atomic(A,B,Res).
5126 block_compare(fd(A,T),fd(B,T),Res,_,_) :- !, block_compare_atomic(A,B,Res).
5127 block_compare(avl_set(A),Kavl,Res,_,_) :- !,
5128 convert_to_avl_inside_set(avl_set(A),ConvertedA),compare(Res,ConvertedA,Kavl).
5129 block_compare([],[],Res,_,_) :- !, Res = '='.
5130 block_compare([],_,Res,_,_) :- !, Res = '<'.
5131 block_compare(A,Kavl,Res,_,_) :-
5132 % does deal with various representations of sets !! closure/global_set/...
5133 when(ground(A),
5134 (convert_to_avl_inside_set(A,ConvertedA),compare(Res,ConvertedA,Kavl))).
5135
5136 match_key((KeyA,KeyB),Key,ResA,ResB) :- !, ResA=KeyA,
5137 (Key==KeyA -> ResB=KeyB ; ResB = no_match).
5138 match_key(_,_,no_match,no_match).
5139
5140 :- block block_compare_atomic(-,?,?), block_compare_atomic(?,-,?).
5141 block_compare_atomic(A,B,Res) :- compare(Res,A,B).
5142
5143 :- block block_compare_aux(-,?,?,?, ?,?).
5144 block_compare_aux(ACRes,B,D,Res, Kprev,Knext) :-
5145 (ACRes='<' -> Res = '<'
5146 ; ACRes = '>' -> Res = '>'
5147 ; Kprev=no_match, Knext=no_match ->
5148 Res = '=' % we cannot match neither previous nor next key: force match
5149 ; block_compare(B,D,Res,Kprev,Knext)). % TO DO: check with prev & next value: if no match possible force Res='='
5150
5151 % check if a match is possible between two terms
5152 :- block match_possible(-,?,?), match_possible(?,-,?).
5153 match_possible([],[],Possible) :- !, Possible=pred_true.
5154 match_possible([],avl_set(_),Possible) :- !, Possible=pred_false.
5155 match_possible(avl_set(_),[],Possible) :- !, Possible=pred_false.
5156 match_possible(int(A),int(B),Possible) :- !, match_possible_atomic(A,B,Possible).
5157 match_possible(fd(A,T),fd(B,T),Possible) :- !, match_possible_atomic(A,B,Possible).
5158 match_possible(string(A),string(B),Possible) :- !, match_possible_atomic(A,B,Possible).
5159 match_possible((A1,A2),(B1,B2),Possible) :- !, match_possible(A1,B1,P1),
5160 match_possible(A2,B2,P2), kernel_equality:conjoin_test(P1,P2,Possible,_WF). %% WF <--- TO DO
5161 match_possible(_,_,pred_true).
5162
5163 :- block match_possible_atomic(-,?,?), match_possible_atomic(?,-,?).
5164 match_possible_atomic(A,B,Res) :- (A==B -> Res=pred_true ; Res=pred_false).
5165
5166 % --------------------------------------------
5167
5168 :- block block_couple_element_of_avl_set_grX_wf1(?, - ,?,?,-,-,?).
5169 block_couple_element_of_avl_set_grX_wf1(X,Y,AVL,ApproxSize,GrX,WF1,WF) :-
5170 var(GrX), var(WF1),
5171 !,
5172 % we know the result Y but not yet fully the input value X
5173 (ApproxSize < 129 % TO DO: improve this; unify with inverse_apply_ok(Y,X,AVL,ApproxSize) ?
5174 -> ground_value_check(Y,GrY) % wait until Y is fully known
5175 ; (preference(solver_strength,SS), ApproxSize < 129+SS)
5176 -> ground_value_check(Y,GrY)
5177 % TO DO: we could look at avl_min and avl_max and estimate spread of range keys
5178 ; cond_perfmessage([data_validation_mode/false],no_inverse_avl_lookup(ApproxSize,Y)) % do not bind GrY; we wait until GrX or WF1 is bound
5179 ),
5180 block_couple_element_of_avl_set_grX_grY_wf1(X,Y,AVL,ApproxSize,GrX,GrY,WF1,WF).
5181 block_couple_element_of_avl_set_grX_wf1(X,Y,AVL,_ApproxSize,GrX,WF1,WF) :-
5182 ? couple_element_of_avl_set(X,Y,AVL,GrX,WF1,WF).
5183
5184 :- block block_couple_element_of_avl_set_grX_grY_wf1(?,?,?,?, -,-,-,?).
5185 block_couple_element_of_avl_set_grX_grY_wf1(X,Y,AVL,_ApproxSize, GrX,_GrY,WF1,WF) :-
5186 var(GrX), var(WF1), % i.e., Y is known
5187 % we know the result Y but not yet fully the input value X
5188 %inverse_apply_ok(Y,X,AVL,ApproxSize),
5189 !,
5190 inverse_get_possible_values(X,Y,AVL,Res),
5191 Res = avl_set(InvAVL),
5192 element_of_avl_set_wf(InvAVL,X,WF).
5193 %couple_element_of_avl_set(X,Y,AVL,GrX,1,WF).
5194 block_couple_element_of_avl_set_grX_grY_wf1(X,Y,AVL,_ApproxSize,GrX,_GrY,WF1,WF) :-
5195 ? couple_element_of_avl_set(X,Y,AVL,GrX,WF1,WF).
5196
5197
5198 % special treatment for relations: if the first component is known: then we can check how many images there are
5199 couple_element_of_avl_set(X,Y,AVL,GrX,WF1,WF) :-
5200 nonvar(WF1), var(GrX), %\+ground(X),
5201 !,
5202 ? safe_avl_member_default_wf((X,Y),AVL,WF).
5203 couple_element_of_avl_set(X,Y,AVLRelation,_GrX,_,WF) :- % X must be ground
5204 get_template(Y,TY,_ToUnifyAfter), % was copy_term(Y,CY) but could cause issues with closures with variables
5205 copy_term(TY,CY), % avoid that we instantiate Y and trigger co-routines
5206 findall(CY,avl_member_pair_arg1_ground(X,CY,AVLRelation),Images), % should we use Y instead of CY
5207 Images \= [],
5208 construct_avl_from_lists_wf(Images,AVL,WF),
5209 element_of_custom_set_wf2(AVL,Y,WF). % will set up waitflag if necessary
5210
5211
5212 % set Res -> pred_true or pred_false if membership can be decided early
5213 % interval closures already dealt with by closure_membership
5214 % maximal sets are also already dealt with by membership_custom_set
5215 reify_avl_membership(AVL,Element,Res,FullReification) :-
5216 is_avl_simple_set(AVL,Type),
5217 preferences:preference(use_clpfd_solver,true), % to do: require maybe only for integer type !?
5218 \+ ground_value(Element),
5219 !,
5220 reify_avl_mem2(Type,Element,AVL,Res,FullReification).
5221 reify_avl_membership(_,_,_,false).
5222
5223
5224 is_avl_simple_set(node(El,_True,_,_,_),Type) :- simple_type(El,Type).
5225 simple_type(int(_),integer).
5226 simple_type(fd(_,GS),global(GS)).
5227
5228
5229 reify_avl_mem2(integer,int(El),AVL,Res,FullReification) :-
5230 avl_min(AVL,int(Min)), avl_max(AVL,int(Max)),
5231 (reify_integer_avl_mem(AVL,Min,Max) % reify if AVL small enough
5232 -> avl_domain(AVL,R),project_avl_domain_on_fd(R,FDList),
5233 clpfd_reify_inlist(El,FDList,FDRes,Posted),
5234 propagate_fd_membership(FDRes,Res,inlist(El,FDList)),
5235 FullReification=Posted
5236 ; clpfd_interface:try_post_constraint((El in Min..Max) #<=> FDRes),
5237 propagate_not_membership(FDRes,Res,int(El,Min,Max)),
5238 FullReification=false
5239 ).
5240 % this could also be enabled with CLPFD = FALSE ?? no overflows are possible
5241 reify_avl_mem2(global(GS),fd(El,GS),AVL,Res,FullReification) :-
5242 avl_domain(AVL,R),project_avl_domain_on_fd(R,FDList),
5243 b_global_sets:b_get_fd_type_bounds(GS,Low,Up),
5244 (is_full_fdlist(FDList,Low,Up)
5245 -> Res=pred_true, % all the values are in the list; it must be a member
5246 % normally this should also be detected by clpfd_reify_inlist, unless no constraint was set up for El
5247 % it seems to have an effect for test 426: probcli examples/EventBPrologPackages/SSF/Bepi_Soton/M1_mch.eventb -cbc all -strict -p CLPFD TRUE -p SMT TRUE -strict -p STRICT_RAISE_WARNINGS TRUE
5248 FullReification=true
5249 ; clpfd_reify_inlist(El,FDList,FDRes,Posted),
5250 propagate_fd_membership(FDRes,Res,inlist(El,FDList)),
5251 FullReification=Posted
5252 ).
5253 %reify_avl_mem2(global(GS),fd(El,GS),AVL,Res) :-
5254 % avl_min(AVL,fd(Min,GS)), avl_max(AVL,fd(Max,GS)),
5255 % clpfd_interface:try_post_constraint((El in Min..Max) #<=> FDRes),
5256 % propagate_not_membership(FDRes,Res,fd(El,GS,Min,Max)).
5257
5258 % assumes list is sorted
5259 is_full_fdlist(List,Low,Up) :- integer(Up), is_full_fdlist2(List,Low,Up).
5260 is_full_fdlist2([],Low,Up) :- Low>Up.
5261 is_full_fdlist2([Low|T],Low,Up) :- L1 is Low+1, is_full_fdlist2(T,L1,Up).
5262
5263 % check if avl small enough to call clpfd_reify_inlist
5264 reify_integer_avl_mem(_AVL,Min,Max) :- MaxSizeM1 is Max-Min, MaxSizeM1 =< 20,!.
5265 reify_integer_avl_mem(AVL,_Min,_Max) :- avl_height_less_than(AVL,5).
5266
5267
5268
5269 project_avl_domain_on_fd([],[]).
5270 project_avl_domain_on_fd([H|T],[PH|PT]) :- project_avl_domain(H,PH), project_avl_domain_on_fd(T,PT).
5271 project_avl_domain(int(X),X).
5272 project_avl_domain(fd(X,_),X).
5273
5274
5275 :- block propagate_fd_membership(-,-,?).
5276 % if we make it propagate_fd_membership(-,-?) Bosch examples becomes much slower ?
5277 % Indeed: membership_custom_set will already force membership or non-membership !
5278 %propagate_fd_membership(X,M,Info) :- var(X),!, print(propagate_fd(X,M,Info)),nl, (M=pred_true ->X=1 ; X=0).
5279 propagate_fd_membership(1,pred_true,_Info).
5280 propagate_fd_membership(0,pred_false,_Info).
5281
5282 :- block propagate_not_membership(-,?,?).
5283 propagate_not_membership(1,_,_). % there could be elements in the interval which are not in the set
5284 propagate_not_membership(0,Res,_Info) :-
5285 Res=pred_false.
5286
5287 % -----------------
5288
5289 % fails if not possible to quickly compute approximate size
5290 quick_custom_explicit_set_approximate_size(V,_) :- var(V),!,fail.
5291 quick_custom_explicit_set_approximate_size(avl_set(AVL),Size) :- !,
5292 quick_avl_approximate_size(AVL,Size).
5293 quick_custom_explicit_set_approximate_size(CS,Size) :-
5294 card_for_specific_custom_set(CS,Size,Code),
5295 on_enumeration_warning(call(Code),fail),
5296 atomic(Size). % inf or number; sometimes card_for_specific_custom_set can return a variable
5297
5298 :- use_module(clpfd_lists,[try_get_fd_value_list/4, get_fd_value/3, in_fd_value_list_wf/4]).
5299 % a membership propagation, but only done if it can be done quickly
5300
5301
5302 % quick_propagation_element_information(Set, Element, WF, PossiblyCompiledSet)
5303 % use last element for next iteration if you call quick_propagation_element_information in a loop
5304 :- block quick_propagation_element_information(-,?,?,?).
5305 quick_propagation_element_information(Set,_El,_,R) :-
5306 preferences:preference(use_clpfd_solver,false),
5307 !, R=Set.
5308 quick_propagation_element_information(avl_set(AVL),Element,WF,NewSet) :- !,
5309 quick_avl_approximate_size(AVL,Size),
5310 NewSet=avl_set_with_size(AVL,Size),
5311 propagate_avl_element_information_direct(Element,AVL,Size,WF).
5312 quick_propagation_element_information(avl_set_with_size(AVL,Size),Element,WF,NewSet) :- !,
5313 NewSet = avl_set_with_size(AVL,Size),
5314 propagate_avl_element_information_direct(Element,AVL,Size,WF).
5315 quick_propagation_element_information(closure(P,T,B),Element,WF,NewSet) :- !,
5316 NewSet = closure(P,T,B),
5317 element_of_closure(Element,P,T,B,WF).
5318 quick_propagation_element_information(fd_value_list(FDList,GroundList,Type),El,WF,NewSet) :- !,
5319 NewSet = fd_value_list(FDList,GroundList,Type),
5320 get_fd_value(Type,El,ElFD),
5321 in_fd_value_list_wf(GroundList,ElFD,FDList,WF).
5322 quick_propagation_element_information(Set,El,WF,NewSet) :-
5323 ? try_get_fd_value_list(Set,Type,FDList,GroundList),!,
5324 FDList \= [], % if list is empty membership fails
5325 NewSet = fd_value_list(FDList,GroundList,Type),
5326 % clpfd_inlist requires list of integers as second argument
5327 ? get_fd_value(Type,El,ElFD),
5328 % We could apply filter_non_matching_elements here
5329 in_fd_value_list_wf(GroundList,ElFD,FDList,WF).
5330 quick_propagation_element_information(Set,_,_,Set).
5331
5332 % -----------------
5333
5334 % infer information about an element of an AVL set
5335 propagate_avl_element_information(Element,AVL,Size,WF) :-
5336 (preferences:preference(use_clpfd_solver,true)
5337 ? -> propagate_avl_element_information_direct(Element,AVL,Size,WF)
5338 ; true).
5339
5340 propagate_avl_element_information_direct(Element,AVL,Size,WF) :-
5341 (Size<100 -> %30 which magic constant to use here; use larger value in SMT mode ?
5342 ? propagate_avl_element_information_small(Element,AVL,WF)
5343 ; is_avl_fd_index_set(AVL,Type) ->
5344 propagate_avl_element_information_large(Type,Element,AVL),
5345 (Size < 4000, nonvar(Element), Element = (_,_) % another magic constant
5346 -> Prio is Size // 60,
5347 get_wait_flag(Prio,propagate_avl_element_information(Element),WF,LWF),
5348 propagate_avl_el_large_block(Element,AVL,WF,LWF) % will do precise propagation
5349 ; true)
5350 ; true).
5351 % TO DO: we could call in_nat_range_wf; this way it would also work in non-CLPFD mode
5352
5353 :- block propagate_avl_el_large_block(?,?,?,-).
5354 propagate_avl_el_large_block((A,B),_,_,_) :-
5355 (ground(A); ground_value(B)), % in first: case we will apply AVL set ; in second case probably no benefit as propagate_avl_element_information_large already propagated first element
5356 !.
5357 propagate_avl_el_large_block(Element,AVL,WF,_LWF) :-
5358 % TO DO: maybe look if we should not use clpfd_list, but only upper & lower bound
5359 propagate_avl_element_information_small(Element,AVL,WF). % will do precise propagation.
5360
5361 :- use_module(clpfd_lists,[avl_fd_value_check/4]).
5362 :- use_module(clpfd_interface,[catch_and_ignore_clpfd_overflow/2]).
5363 propagate_avl_element_information_small(Element,AVL,WF) :-
5364 ? catch_and_ignore_clpfd_overflow(propagate_avl_element_information_small, % relevant test e.g. 1708 (with used_ids_defined_by_equality)
5365 avl_fd_value_check(AVL,Element,WF,_FullyChecked)).
5366
5367 propagate_avl_element_information_large(Type,El,AVL) :-
5368 avl_min(AVL,Min), avl_max(AVL,Max),
5369 % if Size small enough and smaller than Max-Min we call clpfd_inlist on domain
5370 % Note: overflows should be caught below; we could check that Min/Max are within CLPFD range
5371 couple_prj1_in_range(Type,El,Min,Max).
5372
5373 couple_prj1_in_range(integer,int(El),int(Min),int(Max)) :- clpfd_interface:clpfd_inrange(El,Min,Max).
5374 couple_prj1_in_range(global(GS),fd(El,GS),fd(Min,GS),fd(Max,GS)) :- clpfd_interface:clpfd_inrange(El,Min,Max).
5375 couple_prj1_in_range(couple_prj1(T),(El,_),(Min,_),(Max,_)) :- couple_prj1_in_range(T,El,Min,Max).
5376 couple_prj1_in_range(rec_first_field(Name,T),rec([field(Name,El)|TF]),
5377 rec([field(Name,Min)|TMin]),rec([field(Name,Max)|_])) :-
5378 (var(TF)
5379 -> copy_field_names(TMin,TF) % if Fields not yet instantiated: copy over all fields
5380 ; true),
5381 couple_prj1_in_range(T,El,Min,Max).
5382
5383 copy_field_names([],[]).
5384 copy_field_names([field(N,_)|T],[field(N,_)|CT]) :- copy_field_names(T,CT).
5385
5386 % check if the first component of the AVL elements of a type such that we can propagate FD information
5387 is_avl_fd_index_set(node(El,_True,_,_,_),Type) :-
5388 simple_index_type(El,Type).
5389 simple_index_type((El,_),couple_prj1(T)) :- simple_index_type(El,T).
5390 simple_index_type(int(_),integer).
5391 simple_index_type(fd(_,GS),global(GS)).
5392 simple_index_type(rec(Fields),rec_first_field(Name,T)) :- nonvar(Fields),
5393 Fields = [field(Name,El)|_],
5394 simple_index_type(El,T).
5395 %simple_index_type((int(_),_),couple_integer).
5396 %simple_index_type(((int(_),_),_),couple_couple_integer).
5397 %simple_index_type((fd(_,GS),_),couple_global(GS)).
5398
5399
5400 /* avoid instantiating non-normalised with normalised values leading to failure */
5401 :- assert_must_succeed((X=(fd(1,'Name'),fd(2,'Name')), A=node(X,true,0,empty,empty),
5402 custom_explicit_sets:safe_avl_member(X,A) )).
5403
5404 ?safe_avl_member(X,AVL) :- var(X), !, my_avl_member(X,AVL).
5405 %safe_avl_member((X,Y),AVL) :- !, safe_avl_member_pair(X,Y,AVL).
5406 safe_avl_member(Value,AVL) :- decompose_index(Value,Key,RestVal), !,
5407 ? avl_fetch_indexed(Value,Key,RestVal,AVL).
5408 safe_avl_member(X,AVL) :- ground_value(X), convert_to_avl_inside_set(X,AX), !, avl_fetch(AX,AVL).
5409 ?safe_avl_member(X,AVL) :- safe_avl_member_default_wf(X,AVL,no_wf_available).
5410
5411
5412 % this is a generalisation of safe_avl_member_pair
5413 % check if a value can be decomposed into an index and the rest of a value and the key is ground
5414 % it also works for records indexing on first field
5415 avl_fetch_indexed(Value,Key,RestVal,AVL) :-
5416 ground_value_or_field(Key),
5417 convert_value_or_field(Key,NormKey),
5418 !,
5419 (ground_value_or_field(RestVal),
5420 convert_to_avl_inside_set(Value,NormValue)
5421 -> avl_fetch(NormValue,AVL)
5422 ? ; avl_fetch_with_index(NormKey,AVL,RestValLookup),
5423 kernel_objects:equal_object(RestValLookup,RestVal,avl_fetch_indexed)
5424 ).
5425 avl_fetch_indexed(Value,_,_,AVL) :-
5426 ? safe_avl_member_default_wf(Value,AVL,no_wf_available).
5427
5428 convert_value_or_field(field(Name,Val),field(Name,NVal)) :- !,
5429 convert_to_avl_inside_set(Val,NVal).
5430 convert_value_or_field(Key,NormKey) :-
5431 convert_to_avl_inside_set(Key,NormKey).
5432
5433 % a version of safe_avl_member where the first argument is guaranteed to be ground
5434 % somehow using this seems to slow-down evaluation for vesg_Dec12; Caching ??
5435 %safe_avl_member_ground(X,AVL) :-
5436 % convert_to_avl_inside_set(X,AX), !, avl_fetch(AX,AVL).
5437 %safe_avl_member_ground((X,Y),AVL) :- !, avl_member_pair_arg1_ground(X,Y,AVL).
5438 %safe_avl_member_ground(X,AVL) :- safe_avl_member_default_wf(X,AVL,no_wf_available).
5439
5440
5441 safe_avl_member_pair(X,Y,AVL) :- safe_avl_member_pair_wf(X,Y,AVL,no_wf_available).
5442
5443 safe_avl_member_pair_wf(X,Y,AVL,_WF) :- ground_value(X),!,
5444 ( ground_value(Y),
5445 convert_to_avl_inside_set((X,Y),AX)
5446 -> avl_fetch(AX,AVL)
5447 ; avl_member_pair_arg1_ground(X,Y,AVL)). % TODO: pass WF
5448 safe_avl_member_pair_wf(X,Y,AVL,WF) :- safe_avl_member_default_wf((X,Y),AVL,WF).
5449
5450 % can be used to try and lookup a function value without creating WD errors, ...
5451 % used in b_compiler to compile function applications
5452 try_apply_to_avl_set(X,Y,AVL) :- ground_value(X),
5453 ? avl_member_pair_arg1_ground(X,Y,AVL).
5454
5455 %safe_avl_member_pair_ground(X,Y,AVL) :- convert_to_avl_inside_set((X,Y),AX),!, avl_fetch(AX,AVL).
5456 %safe_avl_member_pair_ground(X,Y,AVL) :- avl_member_pair_arg1_ground(X,Y,AVL).
5457
5458 avl_member_pair_arg1_ground(X,Y,AVL) :- convert_to_avl_inside_set(X,AX), !,
5459 get_template(Y,RY,ToUnifyAfter),
5460 ? avl_fetch_pair(AX,AVL,RY),
5461 unify_after_wf(ToUnifyAfter,no_wf_available). %kernel_objects:equal_object(RY,Y).
5462 avl_member_pair_arg1_ground(X,Y,AVL) :-
5463 safe_avl_member_default((X,Y),AVL).
5464
5465 ?safe_avl_member_default(X,AVL) :- safe_avl_member_default_wf(X,AVL,no_wf_available).
5466 %safe_avl_member_default(PP,X,AVL) :-
5467 % debug:timer_call(safe_avl_member_default(PP),custom_explicit_sets:safe_avl_member_default1(X,AVL)).
5468 safe_avl_member_default_wf(X,AVL,WF) :- %statistics(runtime,_),
5469 get_template(X,Template,ToUnifyAfter),
5470 ? my_avl_member(Template,AVL),
5471 % statistics(runtime,[_,T2]), print(avl_member(Template,T2)),nl,
5472 unify_after_wf(ToUnifyAfter,WF). % kernel_objects:equal_object(Template,X)).
5473
5474 unify_after_wf([],_).
5475 unify_after_wf([A/B|T],WF) :- kernel_objects:equal_object_wf(A,B,unify_after,WF),
5476 unify_after_wf(T,WF).
5477
5478
5479
5480 get_template(A,R,ToUnifyAfter) :-
5481 (var(A) -> ToUnifyAfter=[A/R]
5482 ; get_template2(A,R,ToUnifyAfter) -> true
5483 ; add_internal_error('Could_not_get_template: ',get_template(A,R,_))).
5484
5485 get_template2((A,B),(TA,TB),ToUnifyAfter) :- get_template(A,TA,ToUnifyAfter1), get_template(B,TB,ToUnifyAfter2),
5486 append(ToUnifyAfter1,ToUnifyAfter2,ToUnifyAfter). % TO DO: use DifferenceLists / DCG
5487 get_template2(int(X),int(X),[]).
5488 get_template2(fd(A,B),fd(A,B),[]).
5489 get_template2([],[],[]).
5490 get_template2(pred_false /* bool_false */,pred_false /* bool_false */,[]).
5491 get_template2(pred_true /* bool_true */,pred_true /* bool_true */,[]).
5492 get_template2([H|T],R,ToUnifyAfter) :-
5493 (ground_value(H),ground_value(T)
5494 -> convert_to_avl_inside_set([H|T],R),ToUnifyAfter=[]
5495 ; ToUnifyAfter=[[H|T]/R]).
5496 % ; R=avl_set(A), ToUnifyAfter=[[H|T]/avl_set(A)]).
5497 get_template2(closure(P,T,B),R,[]) :- ground_value(closure(P,T,B)),
5498 expand_closure_to_avl_wf(P,T,B,R,no_wf_available),!.
5499 get_template2(closure(P,T,B),AVL_OR_EMPTY_OR_GS,[closure(P,T,B)/AVL_OR_EMPTY_OR_GS]). % closure could be empty or an infinite global set ?
5500 %get_template2(closure_x(_,_,_),_AVL_OR_EMPTY).
5501 get_template2(avl_set(A),avl_set(NA),[]) :- convert_to_avl_inside_set(avl_set(A),avl_set(NA)). % do we need to normalise here ??
5502 get_template2(string(X),string(X),[]).
5503 get_template2(term(X),term(X),[]).
5504 get_template2(freetype(X),R,[]) :- convert_to_avl_inside_set(freetype(X),R).
5505 get_template2(rec(Fields),rec(TFields),ToUnifyAfter) :- get_fields_template(Fields,TFields,ToUnifyAfter).
5506 get_template2(freeval(ID,Case,Value),freeval(ID,Case,TValue),ToUnifyAfter) :- get_template(Value,TValue,ToUnifyAfter).
5507 get_template2(global_set(GS),R,[]) :- convert_to_avl_inside_set(global_set(GS),R).
5508
5509
5510 get_fields_template(A,R,[rec(A)/rec(R)]) :- var(A),!.
5511 get_fields_template([],[],ToUnifyAfter) :- !, ToUnifyAfter=[].
5512 get_fields_template([field(Name,Val)|T],[field(Name,TVal)|TT],ToUnifyAfter) :- nonvar(Name),!,
5513 get_template(Val,TVal,ToUnifyAfter1),
5514 get_fields_template(T,TT,ToUnifyAfter2), append(ToUnifyAfter1,ToUnifyAfter2,ToUnifyAfter).
5515 get_fields_template(A,R,[rec(A)/rec(R)]).
5516
5517
5518 % succeed if we can decide membership of an avl_set on the spot
5519 quick_test_avl_membership(AVL,X,Res) :-
5520 element_can_be_added_or_removed_to_avl(X),
5521 convert_to_avl_inside_set(X,AX),
5522 (avl_fetch(AX,AVL) -> Res=pred_true ; Res=pred_false).
5523
5524 % ---------------------
5525
5526 % a dispatch predicate
5527 my_avl_member(Key,AVL) :-
5528 (preferences:preference(randomise_enumeration_order,true)
5529 ? -> random_avl_member(Key,AVL) ; avl_member_opt(Key,AVL)).
5530 :- use_module(library(random),[random/3]).
5531 ?random_avl_member(Key,AVL) :- avl_height(AVL,Height), H1 is Height+1, random_avl_member(Key,H1,AVL).
5532 % TO DO: make more intelligent; this is not really a very uniform way of randomly enumerating an AVL set (e.g., Key never occurs between L and R)
5533 random_avl_member(Key, H, node(K,_,_,L,R)) :-
5534 random(1,H,1), !, H1 is H-1,
5535 ? (Key=K ; random_avl_member(Key,H1,L) ; random_avl_member(Key,H1,R)).
5536 random_avl_member(Key, H, node(K,_,_,L,R)) :- random(1,3,1), !, H1 is H-1,
5537 ? (random_avl_member(Key,H1,L) ; random_avl_member(Key,H1,R) ; Key=K).
5538 random_avl_member(Key, H, node(K,_,_,L,R)) :- H1 is H-1,
5539 ? (random_avl_member(Key,H1,R) ; random_avl_member(Key,H1,L) ; Key=K).
5540
5541 % a variation of avl_member from library(avl) which tries to avoid leaving choice points behind
5542 avl_member_opt(Key, node(K,_,_,L,R)) :-
5543 ? ( avl_member_opt(Key, L)
5544 ; R=empty -> Key = K % avoid trailing choice_point
5545 ? ; (Key=K ; avl_member_opt(Key, R))
5546 ).
5547
5548 % ---------------------
5549
5550 :- use_module(kernel_objects,[check_element_of_wf/3,not_element_of_wf/3]).
5551 :- use_module(memoization,[element_of_memoization_closure/6]).
5552 element_of_special_closure(interval(LOW,UP),X,WF,_,_,_) :- !,
5553 %hit_profiler:add_profile_hit(in_nat_range(X,LOW,UP,CondClosure)),
5554 ? kernel_objects:in_nat_range_wf(X,int(LOW),int(UP),WF).
5555 element_of_special_closure(member_closure(_ID,_Type,VAL),X,WF,_,_,_) :-
5556 (VAL=value(_) ; VAL = cartesian_product(b(value(A),_,_),b(value(B),_,_))),!,
5557 %hit_profiler:add_profile_hit(in_member_closure(X,Par,Typ,Body)),
5558 (VAL=value(Set) -> check_element_of_wf(X,Set,WF)
5559 ; X=(XA,XB),
5560 ? kernel_objects:check_element_of_wf(XA,A,WF),
5561 ? kernel_objects:check_element_of_wf(XB,B,WF)).
5562 element_of_special_closure(not_member_closure(_ID,_Type,value(Set)),X,WF,_,_,_) :- !,
5563 %hit_profiler:add_profile_hit(in_not_member_closure(X,Par,Typ,Set)),
5564 not_element_of_wf(X,Set,WF).
5565 % we used to have to add enumerator, as not_element_of does not instantiate; e.g. relevant when doing X :: GS - {y}
5566 % This is no longer required
5567 % see test 6 (../prob_examples/public_examples/B/FeatureChecks/NotMemberCheck.mch)
5568 element_of_special_closure(recursive_special_closure(RId),X,WF,Parameters,PT,CondClosure) :- !,
5569 add_recursive_parameter(Parameters,PT,X,RId,CondClosure,NewParameters,NewPT,Value,WF),
5570 element_of_normal_closure(Value,NewParameters,NewPT,CondClosure,WF).
5571 element_of_special_closure(memoization_closure(MemoID),X,WF,P,T,B) :- !,
5572 element_of_memoization_closure(MemoID,X,WF,P,T,B).
5573 element_of_special_closure(_,X,WF,Parameters,PT,CondClosure) :-
5574 % none of the special cases above apply after all
5575 ? element_of_normal_closure(X,Parameters,PT,CondClosure,WF).
5576
5577 :- block element_of_closure(?,-,?,?,?), element_of_closure(?,?,?,-,?).
5578 % element_of_closure(X,Para,T,Body,_WF): check if X is a member of closure(Para,T,Body)
5579 element_of_closure(X,Parameters,PT,CondClosure,WF) :-
5580 is_special_closure(Parameters,PT,CondClosure, SpecialClosure),!,
5581 %print_term_summary(element_of_special_closure(SpecialClosure,X,WF,Parameters,PT,CondClosure)), trace_in_debug_mode,
5582 ? element_of_special_closure(SpecialClosure,X,WF,Parameters,PT,CondClosure).
5583 element_of_closure(X,Parameters,PT,CondClosure,WF) :-
5584 %print_term_summary(element_of_normal_closure(X,Parameters,PT,CondClosure,WF)), trace_in_debug_mode,
5585 ? element_of_normal_closure(X,Parameters,PT,CondClosure,WF).
5586 element_of_normal_closure(X,Parameters,PT,CondClosure,WF) :-
5587 %hit_profiler:add_profile_hit(element_of_closure(X,Parameters,PT,CondClosure)),
5588 same_length(Parameters,ParValues),
5589 convert_list_into_pairs(ParValues,X),
5590 ? b_test_closure_wo_enum(Parameters,PT,CondClosure,ParValues,WF).
5591
5592 :- use_module(store,[set_up_localstate/4]).
5593 :- block b_test_closure_wo_enum(?,?,-,?,?).
5594 b_test_closure_wo_enum(Parameters,ParameterTypes,ClosurePred,ParValues,WF) :-
5595 % same_length(Parameters,ParValues), % not necessary
5596 set_up_localstate(Parameters,ParValues,[],LocalState),
5597 ? b_enumerate:b_type_values_in_store(Parameters,ParameterTypes,LocalState),
5598 copy_wf_start(WF,b_test_closure_wo_enum(Parameters),InnerWF),
5599 % avoid that WF0 actions triggered before we have had a chance to traverse the expression
5600 b_test_boolean_expression(ClosurePred,LocalState,[],InnerWF),
5601 ? copy_wf_finish(WF,InnerWF).
5602
5603 % recursive identifier to list of parameters with body as value
5604 % NewValue is the Value that should be checked for membership in the adapted closure; it has one argument more
5605 add_recursive_parameter(Parameters,Types,Value,TId,CondClosure,NewParameters,NewTypes,NewValue,WF) :-
5606 TId = b(identifier(RId),SetType,_), % unification replaces: get_texpr_id(TId,RId), get_texpr_type(TId,SetType),
5607 append(Parameters,[RId],NewParameters),
5608 append(Types,[SetType],NewTypes),
5609 %tools_printing:print_term_summary(recursion(Value)),nl,
5610 % TO DO check some variant decreases
5611 (kernel_waitflags:pending_abort_error(WF)
5612 -> NewValue = (_,_) % prevent further expansion of recursion, in case WD error in recursive function
5613 % TO DO: detect whether WD error occurs within recursive function,
5614 % indeed, the expansion of the recursive function could be unrelated to WD error and be important to detect inconsistency which prevents WD error: e.g., 1/x=res & recfun(x) \= 0
5615 ,debug_println(19,stopping_recursion_due_to_wd_error)
5616 ; NewValue = (Value,closure(Parameters,Types,CondClosure))
5617 ).
5618
5619
5620 % same as above, but without a waitflag
5621 element_of_custom_set(X,CS) :- element_of_custom_set2(CS,X).
5622
5623 element_of_custom_set2(global_set(GS),X) :- !,element_of_global_set(X,GS).
5624 element_of_custom_set2(freetype(ID),_) :- is_maximal_freetype(ID),!. % freetypes are always maximal at the moment
5625 element_of_custom_set2(avl_set(AVL),X) :- !,
5626 safe_avl_member(X,AVL).
5627 element_of_custom_set2(CS,X) :- init_wait_flags(WF,[element_of_custom_set2]),
5628 element_of_custom_set_wf2(CS,X,WF),
5629 ground_wait_flags(WF).
5630
5631 % ---------------
5632
5633 % function application for closure
5634
5635 % same as check_element_of_wf but does not wait on Y:
5636 % should also work for relation ??
5637
5638 check_element_of_function_closure(X,Y,Parameters,PT,CondClosure,WF) :-
5639 is_special_closure(Parameters,PT,CondClosure, SpecialClosure),!, % this covers recursive closures
5640 element_of_special_closure(SpecialClosure,(X,Y),WF,Parameters,PT,CondClosure).
5641 check_element_of_function_closure(X,Y, P,T,ClosureBody, WF) :-
5642 % affects test 1312, unless we add s:seq(0..9) before calling num
5643 % a special rule which tries and avoid enumerating solutions to arguments of function application
5644 % usually a function application will either be given all arguments or maybe be used in inverse
5645 ? is_converted_lambda_closure(P,T,ClosureBody), %is_converted_non_recursive_lambda_closure(P,T,ClosureBody),
5646 % TO DO: also make this work for recursive closures by adding recursive args (see e.g. test 1302)
5647 is_lambda_closure(P,T,ClosureBody, OtherIDs, OtherTypes, DomainPred, EXPR),
5648 (debug:debug_level_active_for(4) ->
5649 print('Apply Fun : '), translate:print_bexpr(DomainPred), print(' | '), translate:print_bexpr(EXPR),nl,
5650 get_texpr_info(ClosureBody,I), print(info(I,WF)),nl,
5651 print_term_summary((X,Y)),nl %,trace
5652 ; true),
5653 !,
5654 % alternative: annotate X,Y as inner variable ?
5655 get_texpr_info(ClosureBody,BInfo),
5656 b_interpreter:set_up_typed_localstate2(OtherIDs,OtherTypes,BInfo,ParValues,_TypedVals,[],LocalState,positive),
5657 convert_list_into_pairs(ParValues,SingleParValue),
5658 kernel_objects:equal_object_wf(X,SingleParValue,check_element_of_function_closure,WF),
5659 (is_truth(DomainPred) -> true
5660 ; init_wait_flags(InnerWF,[check_element_of_function_closure]),
5661 %copy_wf01e_wait_flags(WF,InnerWF), % we could delay copying WF0 until after test_boolean_expression of DomainPred ?
5662 b_test_boolean_expression(DomainPred,LocalState,[],InnerWF),
5663 get_wait_flag0(WF,WF0), get_wait_flag0(InnerWF,WF0), % was: ground_wait_flag0(InnerWF), but this can result in inner WF0 being set when outer is not yet set; see test 1948
5664 ground_value_check(X,GrX),
5665 (nonvar(GrX) -> copy_waitflag_store(InnerWF,WF) % block would trigger already
5666 ; ground_value_check(Y,GrY),
5667 (nonvar(GrY) -> copy_waitflag_store(InnerWF,WF) % block would trigger already
5668 ; get_last_wait_flag(check_element_of_function_closure(OtherIDs),WF,LastWF),
5669 block_copy_waitflag_store(InnerWF,WF,GrX,GrY,LastWF)
5670 )
5671 )
5672 ),
5673 b_interpreter:b_compute_expression(EXPR,LocalState,[],Y,WF).
5674 check_element_of_function_closure(X,Y, P,T,ClosureBody, WF) :-
5675 element_of_normal_closure((X,Y),P,T,ClosureBody,WF).
5676 % we could memoize on X here if /*@symbolic-memo */ pragma used and closure has special ID associated with it
5677
5678 :- block block_copy_waitflag_store(?,?,-,-,-).
5679 block_copy_waitflag_store(InnerWF,WF,_GrX,_GrY,_LWF) :-
5680 % copy waitflags from InnerWF store to WF
5681 copy_waitflag_store(InnerWF,WF).
5682
5683 /* -------------- */
5684 /* NOT_ELEMENT_OF */
5685 /* -------------- */
5686
5687 :- use_module(kernel_objects,[not_element_of_global_set/2]).
5688
5689 not_element_of_custom_set(X,CS) :- init_wait_flags(WF,[not_element_of_custom_set]),
5690 not_element_of_custom_set_wf(X,CS,WF),
5691 ? ground_wait_flags(WF).
5692 not_element_of_custom_set_wf(X,CS,WF) :-
5693 ? not_element_of_custom_set_wf2(CS,X,WF).
5694
5695 not_element_of_custom_set_wf2(global_set(GS),X,_WF) :- not_element_of_global_set(X,GS).
5696 not_element_of_custom_set_wf2(freetype(_),_,_) :- !,fail. % TO DO: what if we have List(1..3) ? can that occur ??
5697 not_element_of_custom_set_wf2(avl_set(node(Y,_,_,empty,empty)),X,WF) :- !,
5698 % X /: {Y} <=> X /= Y
5699 ? kernel_objects:not_equal_object_wf(X,Y,WF). % improve if X is ground
5700 not_element_of_custom_set_wf2(avl_set(AVL),X,_WF) :- !,
5701 ground_value_check(X,GrX),
5702 ? propagate_avl_not_element_information(X,GrX,AVL),
5703 not_element_of_avl_set_block(GrX,X,AVL).
5704 not_element_of_custom_set_wf2(closure(Parameters,PT,Cond),X,WF) :-
5705 ? closure_not_member(X,Parameters,PT,Cond,WF).
5706
5707 :- block not_element_of_avl_set_block(-,?,?).
5708 not_element_of_avl_set_block(_,X,AVL) :-
5709 convert_to_avl_inside_set(X,CX),
5710 \+ avl_fetch(CX,AVL). %% IMPROVE ??
5711
5712 propagate_avl_not_element_information(_,GrEl,_) :- nonvar(GrEl),!.
5713 propagate_avl_not_element_information(Element,_,AVL) :- preferences:preference(use_clpfd_solver,true),
5714 is_avl_simple_set(AVL,Type), % \+ground(Element) ,
5715 (Type=integer -> avl_height_less_than(AVL,6) % 16-31 elements - was: avl_size(AVL,Size), Size<20
5716 ; true),
5717 !,
5718 ? propagate_avl_not_element_information3(Type,Element,AVL).
5719 propagate_avl_not_element_information(_Element,_,AVL) :-
5720 quick_definitely_maximal_set_avl(AVL),
5721 !, % we require something not to be an element of the full set; impossible
5722 % to do: check if all but one element is in set
5723 fail.
5724 propagate_avl_not_element_information(_,_,_).
5725
5726
5727 % try and compute a small finite cardinality for a ground value; fail if not possible
5728 try_get_finite_max_card_from_ground_value(pred_true,2).
5729 try_get_finite_max_card_from_ground_value(pred_false,2).
5730 try_get_finite_max_card_from_ground_value(fd(_,Type),Card) :-
5731 b_global_sets:b_fd_card(Type,Card), integer(Card).
5732 try_get_finite_max_card_from_ground_value((A,B),Card) :-
5733 try_get_finite_max_card_from_ground_value(A,CA),
5734 try_get_finite_max_card_from_ground_value(B,CB),
5735 Card is CA*CB,
5736 Card < 20000.
5737 % TO DO: add records
5738 try_get_finite_max_card_from_ground_value(avl_set(node(El,_True,_,_,_)),Card) :-
5739 try_get_finite_max_card_from_ground_value(El,CEl),
5740 CEl < 16,
5741 safe_pow2(CEl,Card).
5742
5743
5744 :- use_module(b_global_sets,[get_global_type_value/3]).
5745 propagate_avl_not_element_information3(integer,int(El),AVL) :-
5746 avl_domain(AVL,R),project_avl_domain_on_fd(R,FDList),
5747 clpfd_interface:clpfd_not_inlist(El,FDList).
5748 propagate_avl_not_element_information3(global(GS),FD,AVL) :-
5749 get_global_type_value(FD,GS,El), % sets up the FD constraint if var; maybe we can detect inconsistency straightaway below
5750 avl_domain(AVL,R),project_avl_domain_on_fd(R,FDList), % maybe we can compute directly the complement ?
5751 ? clpfd_interface:clpfd_not_inlist(El,FDList).
5752
5753
5754 :- block closure_not_member(?,-,?,?,?).
5755 %, closure_not_member(-,?,?,?,?). /* El is unlikely to be instantiated by not_element_of test , but test 6 requires commenting out block declaration */
5756
5757 closure_not_member(X,Parameters,Types,Body,WF) :-
5758 is_special_closure(Parameters,Types,Body,SpecialClosure),!,
5759 ? not_element_of_special_closure(SpecialClosure,X,WF,Parameters,Types,Body).
5760 closure_not_member(El,Parameters,PT,Cond,WF) :-
5761 normal_closure_not_member(El,Parameters,PT,Cond,WF).
5762
5763 :- use_module(memoization,[not_element_of_memoization_closure/6]).
5764 not_element_of_special_closure(interval(LOW,UP),X,_WF,_Parameters,_Types,_Body) :-
5765 ? !,kernel_objects:not_in_nat_range(X,int(LOW),int(UP)).
5766 not_element_of_special_closure(member_closure(_ID,_Type,VAL),X,WF,_Parameters,_Types,_Body) :-
5767 ( VAL = value(_)
5768 ; VAL = cartesian_product(b(value(A),_,_),b(value(B),_,_))),!,
5769 %hit_profiler:add_profile_hit(member(X,Par,Typ,Body)),
5770 ( VAL=value(Set) -> kernel_objects:not_element_of_wf(X,Set,WF)
5771 ? ; kernel_objects:not_is_cartesian_pair(X,A,B,WF)).
5772 not_element_of_special_closure(not_member_closure(_ID,_Type,value(Set)),X,WF,_Parameters,_Types,_Body) :-
5773 !,kernel_objects:check_element_of_wf(X,Set,WF).
5774 not_element_of_special_closure(memoization_closure(MemoID),X,WF,P,T,B) :- !,
5775 ? not_element_of_memoization_closure(MemoID,X,WF,P,T,B).
5776 not_element_of_special_closure(recursive_special_closure(RId),X,WF,Parameters,Types,Body) :-
5777 !,
5778 add_recursive_parameter(Parameters,Types,X,RId,Body,NewParameters,NewPT,Value,WF),
5779 normal_closure_not_member(Value,NewParameters,NewPT,Body,WF).
5780
5781 not_element_of_special_closure(SC,_X,_WF,Parameters,Types,Body) :-
5782 SC \= interval(_,_),
5783 SC \= not_member_closure(_,_,_),
5784 is_definitely_maximal_closure(Parameters,Types,Body),
5785 !,
5786 fail.
5787 not_element_of_special_closure(_,X,WF,Parameters,Types,Body) :-
5788 % falling back to normal test
5789 ? normal_closure_not_member(X,Parameters,Types,Body,WF).
5790
5791 :- use_module(library(lists),[same_length/2]).
5792
5793 normal_closure_not_member(El,Parameters,PT,Cond,WF) :-
5794 %hit_profiler:add_profile_hit(closure_not_member(El,Parameters,PT,Cond,WF)),
5795 same_length(Parameters,ParValues),
5796 convert_list_into_pairs(ParValues,El),
5797 ? b_not_test_closure_wf(Parameters,PT,Cond,ParValues,WF).
5798
5799
5800
5801
5802 /* -------------------------- */
5803 /* VARIOUS CLOSURE PREDICATES */
5804 /* -------------------------- */
5805
5806
5807 :- use_module(tools,[convert_list_into_pairs/2]).
5808 :- use_module(b_interpreter,[b_test_boolean_expression/4, b_not_test_boolean_expression/4]).
5809 :- use_module(b_enumerate).
5810
5811 :- assert_pre(custom_explicit_sets:expand_closure_to_list(_,_,ClosureBody,_Result,_Done,_,_WF),
5812 (nonvar(ClosureBody),
5813 bsyntaxtree:check_if_typed_predicate(ClosureBody))).
5814 :- assert_post(custom_explicit_sets:expand_closure_to_list(_,_,_,Result,_Done,_,_WF),
5815 b_interpreter:value_type(Result)).
5816
5817 :- block expand_interval_closure_to_avl(-,?,?), expand_interval_closure_to_avl(?,-,?).
5818 expand_interval_closure_to_avl(Low,Up,Result) :-
5819 Delta is Up-Low,
5820 (Delta>9999 -> perfmessage(expanding_interval(Low,Up)) ; true),
5821 construct_interval_ord_list(Low,Up,OL),
5822 ord_list_to_avlset_direct(OL,ARes,expand_interval),
5823 equal_object(ARes,Result,expand_interval_closure_to_avl).
5824 construct_interval_ord_list(Low,Up,Res) :-
5825 (Low>Up -> Res = []
5826 ; Res = [int(Low)-true|T], L1 is Low+1, construct_interval_ord_list(L1,Up,T)
5827 ).
5828
5829 :- block expand_interval_closure_to_list(-,?,?,?), expand_interval_closure_to_list(?,-,?,?).
5830 expand_interval_closure_to_list(Low,Up,Result,Done) :-
5831 construct_interval_list(Low,Up,OL),
5832 equal_object(OL,Result,expand_interval_closure_to_list),
5833 Done=true.
5834 construct_interval_list(Low,Up,Res) :-
5835 (Low>Up -> Res = []
5836 ; Res = [int(Low)|T], L1 is Low+1, construct_interval_list(L1,Up,T)
5837 ).
5838
5839 expand_closure_to_list([X],[integer],Body,Result,Done,_,_) :-
5840 ? is_interval_closure_body(Body,X,Low,Up),!,
5841 expand_interval_closure_to_list(Low,Up,Result,Done).
5842 expand_closure_to_list(Par,Types,Body,Result,Done,Source,WF) :-
5843 expand_normal_closure(Par,Types,Body,CResult,CDone,expand_closure_to_list(Source),WF),
5844 expand_if_avl(CResult,Result,CDone,Done,Source),
5845 (WF==no_wf_available -> true ;
5846 lazy_check_elements(Result,CDone, Par,Types,Body,WF)).
5847
5848 % Note: does slow down test 1306
5849 % check that if result variable bound by the outside, before closure expanded, we check that the predicate holds for its elements
5850 :- block lazy_check_elements(-,-, ?,?,?,?).
5851 lazy_check_elements(Result,CDone, _Par,_Types,_Body,_WF) :- (var(Result) ; nonvar(CDone)),!.
5852 lazy_check_elements([H|T],CDone, Par,Types,Body,WF) :- !,
5853 ? element_of_closure(H,Par,Types,Body,WF),
5854 ? lazy_check_elements(T,CDone, Par,Types,Body,WF).
5855 lazy_check_elements(avl_set(A),_CDone, Par,Types,Body,WF) :- !,
5856 avl_max(A,X),
5857 element_of_closure(X,Par,Types,Body,WF).
5858 % TO DO: also check avl_min or even all elements ?
5859 lazy_check_elements(_,_,_,_,_,_).
5860
5861 %check_valid_avl(AVL,Origin) :-
5862 % (nonvar(AVL) -> true
5863 % ; add_internal_error('Var avl_set: ', check_valid_avl(AVL,Origin)),fail).
5864
5865 :- block expand_if_avl(?,?,-,?,?).
5866 expand_if_avl(avl_set(S),Result,_,Done,Source) :- !, % we could transmit a flag to expand_normal_closure so that transform_result_into_set does not expand to avl
5867 ? expand_custom_set_to_list2(avl_set(S),Result,Done,_,expand_if_avl(Source),no_wf_available).
5868 expand_if_avl(Res,Result,_,Done,Source) :- check_list(Res,expand_if_avl(Source)),
5869 equal_object(Res,Result), Done=true.
5870
5871 check_list(Res,_) :- nonvar(Res), is_list(Res),!.
5872 check_list(Res,Src) :- add_error(Src,'Could not expand to list: ',Res).
5873 is_list([]). is_list([_|_]).
5874
5875 expand_closure_to_avl_or_list([X],[integer],Body,Result,_CheckTimeouts,_WF) :-
5876 ? is_interval_closure_body(Body,X,Low,Up),!,
5877 expand_interval_closure_to_avl(Low,Up,Result).
5878 %expand_closure_to_avl_or_list(P,T,Body,Result,_WF) :- is_member_closure(P,T,Body,TS,Set),
5879 % print(expand_member_closure(P,T,Body,TS,Set)),nl,fail.
5880 expand_closure_to_avl_or_list(Par,Types,Body,Result,CheckTimeouts,WF) :-
5881 expand_normal_closure(Par,Types,Body,CResult,_Done,CheckTimeouts,WF),
5882 kernel_objects:equal_object(Result,CResult,expand_closure_to_avl_or_list). % may convert to AVL, should we wait for _Done?
5883
5884
5885 % use WF just for call stack messages; we should not delay creating result
5886 expand_closure_to_avl_wf([X],[integer],Body,Result,_WF) :-
5887 is_interval_closure_body(Body,X,Low,Up),!,
5888 expand_interval_closure_to_avl(Low,Up,Result). % we could pass WF
5889 expand_closure_to_avl_wf(Par,Types,Body,Result,WF) :-
5890 expand_normal_closure(Par,Types,Body,S,Done,check(expand_closure_to_avl),WF),
5891 (ground_value(S) % ground value is sufficient to proceed; we do not need to check Done
5892 -> convert_to_avl_inside_set(S,R),equal_object(R,Result,expand_closure_to_avl)
5893 ; print(cannot_convert_closure_value_to_avl(closure(Par,Types),done(Done))),nl,
5894 translate:print_bexpr(Body),nl,trace,
5895 fail).
5896
5897
5898 % possible values for CheckTimeouts: check, check_no_inf, no_check, ...
5899 % Note: we no longer check is_infinite_explicit_set(closure(Parameters,ParameterTypes,ClosureBody))
5900 % and no longer raise add_closure_warning(Source,Parameters,ParameterTypes,ClosureBody,'### WARNING: expanding infinite comprehension set: ')
5901 % and no longer use preference warn_when_expanding_infinite_closures
5902 % this is relevant for e.g., test 1291
5903 expand_normal_closure(Parameters,ParameterTypes,ClosureBody,Result,Done,CheckTimeouts,WF) :-
5904 expand_normal_closure_memo(CheckTimeouts,Parameters,ParameterTypes,ClosureBody,Result,Done,WF).
5905
5906 :- public add_closure_warning_wf/6.
5907 add_closure_warning_wf(Source,Parameters,_ParameterTypes,_ClosureBody,_MSG,_WF) :-
5908 preference(provide_trace_information,false),preference(strict_raise_warnings,false),!,
5909 format('### TIME-OUT raised during closure expansion (~w,~w).~n### set TRACE_INFO preference to TRUE for more details.~n',[Parameters,Source]).
5910 add_closure_warning_wf(Source,Parameters,ParameterTypes,ClosureBody,MSG,WF) :-
5911 (debug_mode(on) -> Limit = 2500, AvlLim=10 ; Limit = 500, AvlLim=5),
5912 preferences:temporary_set_preference(expand_avl_upto,AvlLim,CHNG),
5913 call_cleanup(translate:translate_bvalue_with_limit(closure(Parameters,ParameterTypes,ClosureBody),Limit,CT),
5914 preferences:reset_temporary_preference(expand_avl_upto,CHNG)),
5915 bsyntaxtree:get_texpr_info(ClosureBody,Infos),
5916 add_warning_wf(Source,MSG,CT,Infos,WF), debug_print(19,'! infos: '), debug_println(Infos). %,trace.
5917
5918
5919 :- use_module(memoization,[is_memoization_closure/4,get_complete_memoization_expansion/6]).
5920
5921 % a version of closure expansion which memoizes its results; stored_expansion needs to be cleared when new machine loaded
5922 expand_normal_closure_memo(CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF) :-
5923 ? is_memoization_closure(Parameters,ParameterTypes,ClosureBody,MemoID),
5924 !, Span=ClosureBody,
5925 % MemoID can be a variable
5926 (var(MemoID) -> perfmessage(CHECK,'Getting full value of a memoized function',ClosureBody) ; true),
5927 get_complete_memoization_expansion(MemoID,FullResult,Done,Span,expand_normal_closure_memo(CHECK),WF).
5928 expand_normal_closure_memo(CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF) :-
5929 preferences:preference(use_closure_expansion_memoization,false),!,
5930 expand_normal_closure2(CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF).
5931 expand_normal_closure_memo(CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF) :-
5932 % maybe we should only memo when ClosureWaitVars are ground ?
5933 MemoLookupTerm = closure(Parameters,ParameterTypes,ClosureBody),
5934 compute_memo_hash(MemoLookupTerm,Hash),
5935 % idea: maybe store expansion only on second hit ?
5936 (get_stored_memo_expansion(Hash,MemoLookupTerm,StoredResult)
5937 -> %print_term_summary(reusing_expansion(Hash,Parameters,ParameterTypes,ClosureBody,StoredResult)),nl,
5938 UPV=StoredResult, %state_packing:unpack_value(StoredResult,UPV),
5939 FullResult = UPV, Done=true
5940 ; %statistics(runtime,[T1,_]), %%
5941 expand_normal_closure2(CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF),
5942 %statistics(runtime,[T2,_]), Time is T2-T1, store_memo_computation_time(Hash,Time),
5943 (Done==true/* ,T2-T1>0*/
5944 -> PackedValue=FullResult, %state_packing:pack_value(FullResult,PackedValue),
5945 store_memo_expansion(Hash,MemoLookupTerm,PackedValue)
5946 ; true)
5947 ).
5948
5949
5950 expand_normal_closure2(_CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF) :-
5951 % TO DO: add more symbolic member closures who have expression computation code
5952 is_closure1_value_closure(Parameters,ParameterTypes,ClosureBody,VAL),!,
5953 bsets_clp:relational_trans_closure_wf(VAL,FullResult,WF),
5954 ground_value_check(FullResult,FRGr),
5955 when(nonvar(FRGr),Done=true).
5956 expand_normal_closure2(CHECK,Parameters,ParameterTypes,ClosureBody,FullResult,Done,WF) :-
5957 % special treatment for lambda closures: Advantage: we don't have to wait for variables in EXPR body of closure
5958 % Disadvantage: EXPR only gets evaluated after a solution has been found for args: can mean repeated computations !
5959 % (cf pas_as_env_inv_cv_sui, negated version of !(cv_i).(cv_i : t_cv_pas => closure(%cv_o2.((...|>> {cv_i} : t_cv_pas <-> t_cv_pas) ASSERTION
5960 % Advantage: it can solve constraints such as f = %x.(x:1..10|x+y) & f(5)=1005 (finding y without enumeration); see test 1168
5961 \+ preferences:preference(use_smt_mode,false),
5962 is_lambda_closure(Parameters,ParameterTypes,ClosureBody, OtherIDs,OtherTypes, DomainPred, EXPR),
5963 \+ ground_bexpr(EXPR), % if EXPR is ground, there is nothing to be gained by special treatment here
5964 WF \= no_wf_available, % otherwise we may have to enumerate EXPR result leading to choice points, e.g. in phase 0
5965 !,
5966 bexpr_variables(DomainPred,ClosureWaitVars),
5967 (CHECK=no_check -> TIMEOUTCODE = true ;
5968 TIMEOUTCODE = add_closure_warning_wf(CHECK,Parameters,ParameterTypes,ClosureBody,
5969 'TIME-OUT occurred while ProB was expanding: ',WF)),
5970 (CHECK=check_no_inf -> VIRTUALTIMEOUTCODE=true ; VIRTUALTIMEOUTCODE=TIMEOUTCODE),
5971 delay_setof_check_wf( ParTuple,
5972 (custom_explicit_sets:b_test_closure(OtherIDs,OtherTypes,DomainPred,OtherValues,all_solutions,WF),
5973 convert_list_into_pairs(OtherValues,ParTuple)
5974 % TO DO: compile EXPR when we start expanding the closure: to avoid repeated re-computation of expressions for every instance
5975 ),
5976 Result, ClosureWaitVars, __Done,
5977 TIMEOUTCODE,VIRTUALTIMEOUTCODE,WF,DomainPred),
5978 (WF = no_wf_available
5979 -> init_wait_flags(WF1,[expansion_context(lambda_function_result,Parameters)])
5980 ; WF1=WF
5981 ),
5982 evaluate_result_expr(Result,EXPR,OtherIDs,EvResult,EvDone,WF1),
5983 when(nonvar(EvDone),(
5984 (WF = no_wf_available -> ground_wait_flags(WF1) ; true),
5985 kernel_objects:equal_object_wf(EvResult,FullResult,expand_normal_closure2,WF),
5986 Done=true)).
5987 expand_normal_closure2(no_check,Parameters,ParameterTypes,ClosureBody,Result,Done,WF) :- !,
5988 expand_normal_closure_direct(Parameters,ParameterTypes,ClosureBody,Result,Done,WF).
5989 expand_normal_closure2(CHECK,Parameters,ParameterTypes,ClosureBody,Result,Done,WF) :-
5990 bexpr_variables(ClosureBody,ClosureWaitVars),
5991 TIMEOUTCODE = add_closure_warning_wf(CHECK,Parameters,ParameterTypes,ClosureBody,
5992 'TIME-OUT occurred while ProB was expanding: ',WF),
5993 (CHECK=check_no_inf -> VIRTUALTIMEOUTCODE=true ; VIRTUALTIMEOUTCODE=TIMEOUTCODE),
5994 % Note: delay_setof_check_wf will throw enumeration warning for virtual timeouts, after VIRTUALTIMEOUTCODE
5995 delay_setof_check_wf( ParTuple,
5996 custom_explicit_sets:test_closure_and_convert(Parameters,ParameterTypes,ClosureBody, ParTuple,WF),
5997 Result, ClosureWaitVars, Done, TIMEOUTCODE, VIRTUALTIMEOUTCODE,WF,ClosureBody),
5998 re_attach_pending_inner_abort_errors(all_solutions,WF).
5999
6000 expand_normal_closure_direct(Parameters,ParameterTypes,ClosureBody,Result,Done,WF) :-
6001 bexpr_variables(ClosureBody,ClosureWaitVars),
6002 Span = ClosureBody,
6003 delay_setof_wf( ParTuple,
6004 % TO DO: refresh waitflag in outer WF store to let pending code run to completion and avoid spurious WD errors ?
6005 custom_explicit_sets:test_closure_and_convert(Parameters,ParameterTypes,ClosureBody, ParTuple,WF),
6006 Result, ClosureWaitVars, Done,WF, Span),
6007 re_attach_pending_inner_abort_errors(all_solutions,WF).
6008
6009
6010
6011 :- block evaluate_result_expr(-,?,?,?,?,?).
6012 evaluate_result_expr(avl_set(AVL),EXPR,OtherIDs,Res,Done,WF) :-
6013 avl_domain(AVL,R),
6014 evaluate_result_expr(R,EXPR,OtherIDs,Res,Done,WF).
6015 evaluate_result_expr([],_EXPR,_OtherIDs,[],Done,_WF) :-
6016 %ground_wait_flags(WF),
6017 Done=true.
6018 evaluate_result_expr([ParTuple|T],EXPR,OtherIDs,[FullTuple|ET],Done,WF) :-
6019 % same_length(OtherIDs,ParValues), % not necessary
6020 set_up_localstate(OtherIDs,ParValues,[],LocalState),
6021 convert_list_into_pairs(ParValues,ParTuple), % bind values in ParTuple to LocalState
6022 b_interpreter:b_compute_expression(EXPR,LocalState,[],EXPRVALUE,WF),
6023 append(ParValues,[EXPRVALUE],FullValues),
6024 convert_list_into_pairs(FullValues,FullTuple),
6025 evaluate_result_expr(T,EXPR,OtherIDs,ET,Done,WF).
6026
6027 :- use_module(bsyntaxtree,[split_names_and_types/3]).
6028 :- use_module(probsrc(bsyntaxtree), [def_get_texpr_id/2]).
6029 %:- use_module(library(lists),[prefix_length/3, suffix_length/3]).
6030 % test a closure and convert into pairs; assume we want all solutions
6031 test_closure_and_convert(Parameters,ParameterTypes,ClosureBody, ParTuple, WF) :-
6032 is_recursive_closure(Parameters,ParameterTypes,ClosureBody),
6033 get_recursive_identifier_of_closure_body(ClosureBody,TRID),!,
6034 def_get_texpr_id(TRID,RID), get_texpr_type(TRID,RType),
6035 %print(test_recursion(RID)),nl, translate:nested_print_bexpr(ClosureBody),nl,
6036 RecVal = closure(Parameters,ParameterTypes,ClosureBody), % Recursive Value added to parameters
6037 same_length(Parameters,ParValues),
6038 reset_closure_solution_counter(Parameters),
6039 b_test_closure([RID|Parameters],[RType|ParameterTypes],ClosureBody,[RecVal|ParValues],all_solutions,WF),
6040 convert_sol_list_into_pairs(ParValues,Parameters,ParTuple). % convert tuple without recursive value to ParTuple
6041 test_closure_and_convert(Parameters,ParameterTypes,b(exists(EParAndTypes,ClosureBody),pred,OuterInfo), ParTuple, WF) :-
6042 % Motivation: enumerating Parameters can be quite inefficient
6043 % if for example we have something like {x|#y.(y:SmallSet & x=f(y))}
6044 % Problem: the existential quantifier will be delayed until the Parameters are instantiated !
6045 % relevant test: 1162
6046 % Note: this is duplicating to some extent the code in b_test_exists_wo_expansion
6047 % However, here we can also apply lambda_closure optimisation in b_test_closure below, this is
6048 % relevant for private_examples/2023/.../rule_FICHIER_MRGATKSAATPAR_RVF219_MRGA_DE.mch
6049 ? exists_should_be_lifted(Parameters,ParameterTypes,OuterInfo,ClosureBody),
6050 split_names_and_types(EParAndTypes,EPar,ETypes),
6051 !,
6052 % print(' Lifting existential quantifier (i.e., enumerating paras with closure paras): '), print(EPar),nl,
6053 % print(outer_paras(Parameters)),nl,
6054 % append Parameters at end; in case we have a lambda function
6055 append(EPar,Parameters,FullPar), length(Parameters,NrParas),
6056 append(ETypes,ParameterTypes,FullTypes),
6057 length(EPar,NrExistsParas),
6058 length(IrrelevantParas,NrExistsParas), length(Suffix,NrParas),
6059 append(IrrelevantParas,Suffix,FullParList),
6060 copy_identifier_infos(OuterInfo,ClosureBody,ClosureBody2),
6061 reset_closure_solution_counter(Parameters),
6062 % bsyntaxtree:check_used_ids_in_ast(ClosureBody2),
6063 ? b_test_closure(FullPar,FullTypes,ClosureBody2, FullParList,all_solutions,WF),
6064 convert_sol_list_into_pairs(Suffix,Parameters,ParTuple).
6065 test_closure_and_convert(Parameters,ParameterTypes,ClosureBody, ParTuple, WF) :-
6066 reset_closure_solution_counter(Parameters),
6067 % print(test),nl, translate:nested_print_bexpr(ClosureBody),nl,
6068 length(Parameters,Len), length(ParValues,Len),
6069 %(annotate_exists(Parameters,ParameterTypes,ClosureBody,Body2) -> true ; Body2=ClosureBody),
6070 ? b_test_closure(Parameters,ParameterTypes,ClosureBody,ParValues,all_solutions,WF),
6071 convert_sol_list_into_pairs(ParValues,Parameters,ParTuple). % ,print(solution(ParTuple)),nl,nl.
6072
6073 % Lifting existential quantifier was previously done here, but was duplicating code in b_test_exists_wo_expansion
6074 % we now simply generate the allow_to_lift_exists annotation here and let b_test_exists_wo_expansion do its job
6075 %annotate_exists(Parameters,ParameterTypes,
6076 % b(exists(EParAndTypes,ClosureBody),pred,OuterInfo),
6077 % b(exists(EParAndTypes,ClosureBody),pred,[allow_to_lift_exists|OuterInfo])) :-
6078 % exists_should_be_lifted(Parameters,ParameterTypes,OuterInfo,ClosureBody).
6079
6080 % check if a top-level exists with body ExistsClosureBody should be lifted
6081 % within a closure with paras Parameters of type ParameterTypes:
6082 exists_should_be_lifted(Parameters,ParameterTypes,OuterInfo,ExistsClosureBody) :-
6083 (Parameters == ['_was_lambda_result_'] % here we are quite sure that we gain by this optimisation
6084 ? ; member(allow_to_lift_exists,OuterInfo) % parameters were originally from a set comprehension,
6085 % see test 306: in this case existential quantifier is lifted in b_interpreter anyway;
6086 % Note we counter the rewrite ran({x1,...xn|P}) ---> {xn| #(x1,...).(P)} and similarly for dom({...})
6087 ; ExistsClosureBody = b(member(_,_),_,_) % we have a simple projection closure
6088 % TO DO: maybe support other ones as well
6089 ? ; basic_type_list_cardinality(ParameterTypes,Card),
6090 (Card=inf -> true ; Card>10000)
6091 % if here are only a few parameter values: do not lift existential quantified variables
6092 ).
6093
6094 % we need to copy important infos about the outer Parameters to ClosureBody
6095 copy_identifier_infos(Info,b(InnerPred,T,II),b(InnerPred,T,II2)) :-
6096 findall(I,identifier_info(I,Info),ToCopy),
6097 append(ToCopy,II,II2).
6098 identifier_info(I,Info) :- I=prob_annotation('DO_NOT_ENUMERATE'(ID)),
6099 ? member(I,Info), ID \= '$$NONE$$'.
6100
6101 convert_sol_list_into_pairs(ParaValues,Parameters,ParTuple) :-
6102 convert_list_into_pairs(ParaValues,ParTuple),
6103 update_closure_solution_counter(Parameters,ParTuple).
6104
6105 :- if(environ(prob_debug_flag,true)).
6106 :- dynamic closure_solution_counter/3.
6107 % debugging long expansions of comprehension_set / closures
6108 reset_closure_solution_counter(Parameters) :- retractall(closure_solution_counter(Parameters,_,_)).
6109
6110 update_closure_solution_counter(Parameters,ParTuple) :-
6111 retract(closure_solution_counter(Parameters,OldCount,OldTime)),!,
6112 statistics(walltime,[W2,_]), Delta is W2-OldTime,
6113 NewCount is OldCount+1,
6114 ((Delta > 5000 ; NewCount mod 1000 =:= 0)
6115 -> format('--> Solution ~w for expansion of closure ~w (delta ~w ms): ',[NewCount,Parameters,Delta]),
6116 translate:print_bvalue(ParTuple),nl,
6117 assert(closure_solution_counter(Parameters,NewCount,W2))
6118 ; assert(closure_solution_counter(Parameters,NewCount,OldTime))
6119 ).
6120 update_closure_solution_counter(Parameters,_ParTuple) :-
6121 statistics(walltime,[W2,_]),
6122 assert(closure_solution_counter(Parameters,1,W2)).
6123 :- else.
6124 reset_closure_solution_counter(_).
6125 update_closure_solution_counter(_,_).
6126 :- endif.
6127
6128
6129
6130 % compute cardinality of a list of basic types
6131 basic_type_list_cardinality([],1).
6132 basic_type_list_cardinality([BasicType|T],Res) :-
6133 basic_type_list_cardinality(T,TCard),
6134 (TCard=inf -> Res=inf
6135 ? ; kernel_objects:max_cardinality(BasicType,Card),
6136 kernel_objects:safe_mul(Card,TCard,Res)
6137 ).
6138
6139 % for lambda closures we can set up a second waitflag for the expression and only ground it when body enumeration finished
6140 % idea is to avoid perturbation of constraint solving of main closure predicate by lambda expression, see test 1737
6141 % something like %(x,y).(x:1..200 & y:1..100 & y+x<259 & y*x>10|(y+x*x+y) mod 100) is faster
6142 % this is slower : %(x,y).(x:1..200 & y:1..100 |(y+x*x+y))
6143 % currently this slows down test 1336
6144 :- block b_test_closure(?,?,-,?,?,?).
6145 b_test_closure(Parameters,ParameterTypes,ClosureBody, FullParValues, NegationContext, OuterWF) :-
6146 (preference(data_validation_mode,true)
6147 -> true % avoids ineraction between domain and range expression enumeration; see
6148 % private_examples/ClearSy/2019_May/perf_3264/rule_186.mch or
6149 % computation of 631 ic___DMI_MRGATKSAAT___Parametre_Identifiant_indices_function in rule_FICHIER_MRGATKSAATPAR_RVF219_MRGA_DE.mch
6150 % however, as b_optimize below does *not* evaluate nested set comprehensions, there can be a slowdown:
6151 % the nested set comprehension gets re-evaluated for every soluiton of the lambda parameters !
6152 % this was the case of private_examples/ClearSy/2019_Nov/rule_Regle_31C_0005/rule.mch before using SORT
6153 ; \+ preferences:preference(use_smt_mode,false)), % TO DO: enable in normal mode when performance of 1336 fixed
6154 % print(test_closure(Parameters,FullParValues)),nl,
6155 is_lambda_closure(Parameters,ParameterTypes,ClosureBody, OtherIDs,OtherTypes, DomainPred, EXPR),
6156 % TO DO: detect not only equalities at end, but any equality which is irrelevant for the rest
6157 % nl,print(lambda_closure(OtherIDs)),nl, translate:print_bexpr(EXPR),nl,
6158 append(ParValues,[LambdaResult],FullParValues),
6159 !,
6160 get_texpr_info(ClosureBody,BInfo),
6161 ? b_interpreter:set_up_typed_localstate2(OtherIDs,OtherTypes,BInfo,ParValues,TypedVals,[],LocalState,NegationContext),
6162 simplify_span(ClosureBody,BSpan), % sometimes BInfo no longer contains a position info, but first_sub_expr does
6163 init_quantifier_wait_flag(OuterWF,comprehension_set(NegationContext),OtherIDs,ParValues,BSpan,WF),
6164 b_test_boolean_expression(DomainPred,LocalState,[],WF),
6165 %print('PRED: '),translate:print_bexpr(ClosureBody),nl,
6166 b_tighter_enumerate_values_in_ctxt(TypedVals,DomainPred,WF), % also does: project_away_useless_enumeration_values
6167 init_quantifier_wait_flag(OuterWF,comprehension_set(NegationContext),OtherIDs,ParValues,BSpan,WF2),
6168 b_compiler:b_optimize(EXPR,[],LocalState,[],CEXPR,WF), % already pre-compile lookup, without constraint processing; is not sufficient for test 1336
6169 ? ground_wait_flags(WF), % TODO: also call ground inner WF in context
6170 b_interpreter:b_compute_expression(CEXPR,LocalState,[],LambdaResult,WF2),
6171 ground_inner_wait_flags_in_context(NegationContext,WF2).
6172 b_test_closure(Parameters,ParameterTypes,ClosureBody,ParValues,NegationContext, OuterWF) :-
6173 % tools:print_bt_message(b_test_closure_testing_closure(Parameters,ParValues)), %%
6174 get_texpr_info(ClosureBody,BInfo),
6175 ? b_interpreter:set_up_typed_localstate2(Parameters,ParameterTypes,BInfo,
6176 ParValues,TypedVals,[],LocalState,NegationContext),
6177 % print_message(b_interpreter:b_test_boolean_expression(ClosureBody,LocalState,[],WF)),
6178 simplify_span(ClosureBody,BSpan), % sometimes BInfo no longer contains a position info, but first_sub_expr does
6179 init_quantifier_wait_flag(OuterWF,comprehension_set(NegationContext),Parameters,ParValues,BSpan,WF),
6180 %external_functions:observe_parameters(Parameters,LocalState), %%
6181 ? b_test_boolean_expression(ClosureBody,LocalState,[],WF),
6182 % tools:print_bt_message(tested_bool_expr), translate:print_bexpr(ClosureBody),nl,
6183 b_enumerate:b_tighter_enumerate_values_in_ctxt(TypedVals,ClosureBody,WF), % also detects useless enumeration ids
6184 ? ground_inner_wait_flags_in_context(NegationContext,WF).
6185
6186
6187
6188 :- block b_not_test_closure_wf(?,?,?,-,?).
6189 b_not_test_closure_wf(Parameters,ParameterTypes,Closure,ParValues,WF) :-
6190 % same_length(Parameters,ParValues), % not necessary
6191 set_up_localstate(Parameters,ParValues,[],LocalState),
6192 b_enumerate:b_type_values_in_store(Parameters,ParameterTypes,LocalState),
6193 ? b_not_test_boolean_expression(Closure,LocalState,[],WF),
6194 get_last_wait_flag(b_not_test_closure_wf(Parameters),WF,WF2),
6195 get_texpr_info(Closure,Infos),
6196 b_not_test_closure_enum(Parameters,ParameterTypes,Infos,LocalState,WF,WF2).
6197
6198 :- block b_not_test_closure_enum(-,?,?,?,?,?).
6199 b_not_test_closure_enum(Parameters,ParameterTypes,Infos,LocalState,WF,WF2) :-
6200 b_enumerate:b_extract_typedvalc(Parameters,ParameterTypes,Infos,LocalState,TypedVals),
6201 (var(WF2) -> ground_typedvals_check(TypedVals,GrVals) ; true),
6202 b_not_test_closure_enum_aux(GrVals,WF2,TypedVals,WF).
6203
6204 :- block b_not_test_closure_enum_aux(-,-,?,?).
6205 b_not_test_closure_enum_aux(_,_,TypedVals,WF) :-
6206 b_enumerate:b_tighter_enumerate_all_values(TypedVals,WF).
6207 % , print(finished_enum(Parameters)),nl.
6208
6209
6210 :- use_module(library(terms)).
6211 % check whether a VARIABLE occurs inside a closure
6212 closure_occurs_check(VARIABLE,_Par,_ParTypes,ClosureBody) :- expression_contains_setvar(ClosureBody,VARIABLE).
6213 % /* occurs check; x = closure1(x) ; for other closures this cannot happen ???!!! TO DO: Check */
6214 % custom_explicit_sets:is_closure1_value_closure(Par,ParTypes,ClosureBody,Val),
6215 % contains_var(VARIABLE,Val).
6216
6217 expression_contains_setvar(b(E,_,_),Variable) :- !,
6218 expression_contains_setvar_aux(E,Variable).
6219 expression_contains_setvar(E,V) :- add_internal_error('Illegal Expression: ', expression_contains_setvar(E,V)),
6220 contains_var(V,E).
6221
6222 expression_contains_setvar_aux(value(Val),Variable) :- !,value_contains_setvar(Val,Variable).
6223 % a few very common cases for performance; currently this predicate is often called for recursive functions
6224 expression_contains_setvar_aux(identifier(_),_) :- !,fail.
6225 expression_contains_setvar_aux(equal(A,B),Variable) :- !,
6226 (expression_contains_setvar(A,Variable) -> true ; expression_contains_setvar(B,Variable)).
6227 expression_contains_setvar_aux(conjunct(A,B),Variable) :- !,
6228 (expression_contains_setvar(A,Variable) -> true ; expression_contains_setvar(B,Variable)).
6229 expression_contains_setvar_aux(function(A,B),Variable) :- !,
6230 (expression_contains_setvar(A,Variable) -> true ; expression_contains_setvar(B,Variable)).
6231 expression_contains_setvar_aux(union(A,B),Variable) :- !,
6232 (expression_contains_setvar(A,Variable) -> true ; expression_contains_setvar(B,Variable)).
6233 expression_contains_setvar_aux(couple(A,B),Variable) :- !,
6234 (expression_contains_setvar(A,Variable) -> true ; expression_contains_setvar(B,Variable)).
6235 % the rest via safe_syntaxelement:
6236 expression_contains_setvar_aux(Expr,V) :-
6237 safe_syntaxelement_det(Expr,Subs,_Names,_,_),!,
6238 ? member(Sub,Subs), expression_contains_setvar(Sub,V),!.
6239 expression_contains_setvar_aux(E,V) :- add_internal_error('Illegal Expression: ', expression_contains_setvar_aux(E,V)),
6240 contains_var(V,E).
6241
6242 value_contains_setvar(Val,V) :- var(Val),!,Val==V.
6243 value_contains_setvar(avl_set(_),_V) :- !, fail. % assume avl_set always properly grounded; avoid looking inside
6244 value_contains_setvar(closure(_,_,Body),V) :- !,
6245 expression_contains_setvar(Body,V).
6246 value_contains_setvar(int(_),_) :- !,fail. % we check for set variables
6247 value_contains_setvar(global_set(_),_) :- !,fail. % we check for set variables
6248 value_contains_setvar(freetype(_),_) :- !,fail. % we check for set variables
6249 value_contains_setvar(freeval(_ID,_Case,Val),V) :- !, value_contains_setvar(Val,V).
6250 value_contains_setvar(string(_),_) :- !,fail. % we check for set variables
6251 value_contains_setvar(fd(_,_),_) :- !,fail. % we check for set variables
6252 value_contains_setvar((A,B),V) :- !, (value_contains_setvar(A,V) ; value_contains_setvar(B,V)).
6253 value_contains_setvar([A|B],V) :- !, (value_contains_setvar(A,V) ; value_contains_setvar(B,V)).
6254 value_contains_setvar(Val,V) :-
6255 contains_var(V,Val).
6256
6257 % ------------------