1 % (c) 2009-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(kernel_objects,[basic_type/2,
6 enumerate_basic_type/2, enumerate_basic_type_wf/3, enumerate_basic_type_wf/4,
7 all_objects_of_type/2,
8 max_cardinality/2,
9 enumerate_type/3, % last argument basic or tight
10 enumerate_basic_type/3, enumerate_type/4, % last argument false/true disables/enables enum warning
11 enumerate_tight_type/2, enumerate_tight_type/3,
12 enumerate_int/3,
13 enum_warning/5,
14 all_strings/1, is_string/2, is_not_string/1,
15
16 top_level_dif/2,
17 equal_object_optimized/2, equal_object_optimized/3, equal_object_optimized_wf/4,
18 equal_object/2, equal_object/3, equal_object_wf/3, equal_object_wf/4,
19 not_equal_object/2, not_equal_object_wf/3,
20 equal_cons/3, equal_cons_wf/4, equal_cons_lwf/5,
21 get_next_element/3,
22 is_marked_to_be_computed/1, mark_as_to_be_computed/1,
23
24 %equality_objects/3,
25 membership_test/3, membership_test_wf/4,
26
27 %is_a_set/1,
28 empty_set/1, empty_set_wf/2,
29 not_empty_set/1, not_empty_set_wf/2,
30 exact_element_of/2,
31 check_element_of/2, check_element_of_wf/3,
32 not_element_of/2, not_element_of_wf/3,
33
34 add_element/3, add_element/4, add_element_wf/4, add_element_wf/5,
35 add_new_element_wf/4,
36 delete_element_wf/4,
37 remove_element/3, remove_element_wf/4,remove_element_wf/5,remove_element_wf_if_not_infinite_or_closure/6,
38 remove_exact_first_element/3,
39
40 partition_wf/3, not_partition_wf/3,
41 %all_different/2,
42 disjoint_sets/3, not_disjoint_sets/3,
43
44 union/3, union_wf/4, union_generalized/2, union_generalized_wf/3,
45 intersection/3, intersection_generalized_wf/4,
46 difference_set/3, difference_set_wf/4,
47 in_difference_set_wf/4, not_in_difference_set_wf/4,
48 in_union_set_wf/4, not_in_union_set_wf/4,
49 in_intersection_set_wf/4, not_in_intersection_set_wf/4,
50
51 strict_subset_of/2, strict_subset_of_wf/3,
52 check_subset_of/2, check_subset_of_wf/3, check_finite_subset_of_wf/3,
53 check_non_empty_subset_of_wf/3, check_finite_non_empty_subset_of_wf/3,
54 not_subset_of/2, not_subset_of_wf/3, not_both_subset_of/5,
55 not_finite_subset_of_wf/3,
56 not_strict_subset_of/2, not_strict_subset_of_wf/3,
57 not_non_empty_subset_of_wf/3, not_non_empty_finite_subset_of_wf/3,
58 both_global_sets/4,check_subset_of_global_sets/2, check_not_subset_of_global_sets/2,
59
60 first_of_pair/2, second_of_pair/2,
61 minimum_of_set_extension_list/4,
62 maximum_of_set_extension_list/4,
63 minimum_of_set/4, maximum_of_set/4,
64 is_finite_set_wf/2, is_infinite_set_wf/2, test_finite_set_wf/3,
65 finite_cardinality_as_int/3, cardinality_as_int_for_wf/2,
66 cardinality_as_int_wf/3,
67 cardinality_as_int/2, cardinality_peano_wf/3, card_convert_int_to_peano/2,
68 % card_geq/2,
69 cardinality_greater/5, cardinality_greater_equal/5,
70 cardinality_of_set_extension_list/3,
71
72 cartesian_product/3, % removed
73 is_cartesian_pair_wf/4, not_is_cartesian_pair/4,
74
75 power_set/2, non_empty_power_set/2,
76
77 % is_boolean/1, %is_not_boolean/1,
78 is_integer/2, is_not_integer/1,
79 is_natural/2, is_natural1/2,
80 is_implementable_int/2,is_implementable_nat/2, is_implementable_nat1/2,
81 is_not_natural/1, is_not_natural1/1,
82 is_not_implementable_int/1,is_not_implementable_nat/1, is_not_implementable_nat1/1,
83
84 less_than/2, less_than_equal/2,
85 less_than_direct/2, less_than_equal_direct/2,
86 safe_less_than_equal/2, safe_less_than_equal/3,
87 safe_pow2/2, safe_mul/3, safe_add/3, safe_pown/3,
88 greater_than/2, greater_than_equal/2,
89 int_plus/3,
90 division/5, floored_division/5,
91 modulo/5,
92 int_minus/3, unary_minus_wf/3,
93 % nat_range/3, % removed
94 in_nat_range_wf/4, not_in_nat_range/3, not_in_nat_range_wf/4, test_in_nat_range_wf/5,
95 in_nat_range/3, % version without enumeration
96 times/3, square/3,
97 int_power/5,
98 % pred/2, succ/2, removed
99 integer_global_set/1,
100
101 element_of_global_set/2,element_of_global_set_wf/3,not_element_of_global_set/2,
102
103 exhaustive_kernel_check/1, exhaustive_kernel_check_wf/2, exhaustive_kernel_check_wf/3,
104 exhaustive_kernel_check_wfdet/2,
105 exhaustive_kernel_succeed_check/1, exhaustive_kernel_fail_check/1,
106 exhaustive_kernel_fail_check_wf/2, exhaustive_kernel_fail_check_wfdet/2,
107 exhaustive_kernel_check/2, exhaustive_kernel_succeed_check/2, exhaustive_kernel_fail_check/2,
108
109 singleton_set_element/4,
110 infer_value_type/2
111 ]).
112
113
114 %:- use_module('../extensions/profiler/profiler.pl').
115 %:- use_module('../extensions/profiler/profiler_te.pl').
116 %:- enable_profiling(enumerate_basic_type/3).
117 %:- enable_profiling(enumerate_type/3).
118 %:- enable_profiling(enumerate_tight_type/2).
119
120 %:- print(loading_kernel_objects),nl.
121
122 %portray_message(informational, _).
123 :- use_module(library(terms)).
124 :- use_module(self_check).
125
126 :- use_module(debug).
127 :- use_module(tools_printing,[print_term_summary/1]).
128 :- use_module(tools).
129
130 :- use_module(module_information,[module_info/2]).
131 :- module_info(group,kernel).
132 :- module_info(description,'This module provides operations for the basic datatypes of ProB (equal, not_equal, enumeration).').
133
134 :- use_module(typechecker).
135 :- use_module(error_manager).
136
137 :- use_module(b_global_sets). %,[global_type/2, b_global_set_cardinality/2, b_empty_global_set/1]).
138
139 :- use_module(kernel_waitflags).
140 :- use_module(library(lists)).
141 :- use_module(library(avl),[avl_min/2, avl_max/2]).
142
143 %:- use_module(library(clpfd)).
144 %:- use_module(fd_utils).
145 :- use_module(fd_utils_clpfd).
146
147 :- use_module(kernel_freetypes).
148
149 :- use_module(custom_explicit_sets).
150
151
152 :- use_module(typechecker).
153
154 %:- use_module(clpfd_off_interface). %
155 % on a 32 bit system: use clpfd_off_interface; on 64 bit system clpfd_interface should be ok (integer overflows)
156 :- use_module(clpfd_interface). %
157
158
159 :- type atomic_type +--> (term(integer,[]) ; term(string,[]) ; constant(list(atomic)) ; abort ; boolean ; global(atomic)).
160 :- type atomic_any_type +--> (type(atomic_type) ; term(any,[]) ).
161 :- type basic_type_descriptor +--> (type(atomic_any_type) ; set(basic_type_descriptor) ;
162 seq(basic_type_descriptor) ;
163 couple(basic_type_descriptor,basic_type_descriptor) ;
164 record(list(type(field_type))) ;
165 freetype(atomic)).
166
167 :- type inferred_basic_type_descriptor +--> (var ; type(atomic_type) ; set(inferred_basic_type_descriptor) ;
168 seq(inferred_basic_type_descriptor) ;
169 couple(inferred_basic_type_descriptor,inferred_basic_type_descriptor)).
170
171 :- type fd_index +--> (integer ; var).
172 :- type fd_set +--> (atomic ; var).
173 :- type fd_term +--> fd(fd_index,fd_set).
174 :- type bsets_integer +--> int((integer ; var)).
175 :- type bsets_string +--> string((atomic ; var)).
176 :- type bsets_bool +--> (pred_false /* bool_false */ ; pred_true /* bool_true */).
177 :- type field_type +--> field(atomic,basic_type_descriptor).
178
179 %:- type bsets_sequence +--> (nil_seq ; cons(type(bsets_object),type(bsets_sequence))).
180 %:- type bsets_set +--> vlist(type(bsets_object)).
181 :- type bsets_set +--> (term([],[]) ; var ; term('.',[type(bsets_object),type(bsets_set)]) ;
182 avl_set( ground ) ;
183 closure(list(type(variable_id)),
184 list(type(basic_type_descriptor)),type(boolean_expression))
185 ; closure_x(list(type(variable_id)),
186 list(type(basic_type_descriptor)),type(boolean_expression),any)).
187 :- type bsets_couple +--> term(',',[type(bsets_object),type(bsets_object)]).
188 :- type bsets_global +--> global_set((atomic ; var)).
189 :- type bsets_field +--> field(atomic,type(bsets_object)).
190 :- type bsets_record +--> rec((var ; list(bsets_field))).
191 :- type bsets_freetype +--> freeval(atomic,(atomic ; var),type(bsets_object)).
192
193 :- type bsets_object +--> (fd_term ; bsets_integer ; bsets_bool ; term(term,[any]) ; bsets_set ;
194 % abort(any) ; % deprecated
195 bsets_couple ; bsets_string ; bsets_global ; var;
196 bsets_record ; bsets_freetype).
197
198
199 :- assert_must_succeed(kernel_waitflags:set_silent(true)). % disable waitflag store not init msgs
200
201
202
203
204 % a predicate to exhaustively check a kernel predicate with all possible modes
205
206 :- use_module(tools_timeout,[time_out_call/1]).
207 exhaustive_kernel_check_opt(C,Cond) :- (Cond -> exhaustive_kernel_check(C) ; true).
208 exhaustive_kernel_check(C) :- exhaustive_kernel_check4([],C,true,true).
209 exhaustive_kernel_check(Opts,C) :- exhaustive_kernel_check4(Opts,C,true,true).
210 exhaustive_kernel_check_wf(C,WF) :- exhaustive_kernel_check_wf([],C,WF).
211 exhaustive_kernel_check_wf(Opts,C,WF) :-
212 exhaustive_kernel_check4(Opts,C,kernel_waitflags:init_wait_flags(WF),
213 kernel_waitflags:ground_wait_flags(WF)).
214 exhaustive_kernel_check_wfdet(C,WF) :-
215 exhaustive_kernel_check4([],C,kernel_waitflags:init_wait_flags(WF),
216 kernel_waitflags:ground_det_wait_flag(WF)).
217
218 exhaustive_kernel_check4(Opts,Call,Pre,Post) :- enumerate_kernel_call(Call,Opts,ECall,Code),
219 debug_println(9,exhaustive_kernel_check(ECall,Code)),
220 flatten_call((Pre,ECall,Code,Post),FullCall), %print(FullCall),nl,
221 time_out_call(must_succeed_without_residue(FullCall)),debug_println(9,ok),
222 fail.
223 exhaustive_kernel_check4(_,_,_,_).
224
225 flatten_call((A,B),Res) :- !,flatten_call(A,FA), flatten_call(B,FB), conjoin_call(FA,FB,Res).
226 flatten_call(Module:Call,Res) :- !, flatten_call(Call,F), Res=Module:F.
227 flatten_call(X,X).
228
229 conjoin_call(true,X,R) :- !,R=X.
230 conjoin_call(X,true,R) :- !, R=X.
231 conjoin_call(X,Y,(X,Y)).
232
233 exhaustive_kernel_succeed_check(C) :- exhaustive_kernel_succeed_check([],C).
234 exhaustive_kernel_succeed_check(Opts,Call) :- enumerate_kernel_call(Call,Opts,ECall,Code),
235 debug_println(9,exhaustive_kernel_succeed_check(ECall,Code)),
236 flatten_call((ECall,Code),FullCall),
237 time_out_call(must_succeed(FullCall)),debug_println(9,ok),
238 fail.
239 exhaustive_kernel_succeed_check(_,_).
240
241 exhaustive_kernel_fail_check_opt(C,Cond) :- (Cond -> exhaustive_kernel_fail_check(C) ; true).
242 exhaustive_kernel_fail_check(C) :- exhaustive_kernel_fail_check4([],C,true,true).
243 exhaustive_kernel_fail_check(Opts,C) :- exhaustive_kernel_fail_check4(Opts,C,true,true).
244 exhaustive_kernel_fail_check_wf(C,WF) :-
245 exhaustive_kernel_fail_check4([],C,kernel_waitflags:init_wait_flags(WF),
246 kernel_waitflags:ground_wait_flags(WF)).
247 exhaustive_kernel_fail_check_wfdet(C,WF) :-
248 exhaustive_kernel_fail_check4([],C,kernel_waitflags:init_wait_flags(WF),
249 kernel_waitflags:ground_det_wait_flag(WF)).
250 exhaustive_kernel_fail_check4(Opts,Call,Pre,Post) :- enumerate_kernel_call(Call,Opts,ECall,Code),
251 debug_println(9,exhaustive_kernel_fail_check(ECall,Code)),
252 flatten_call((Pre,ECall,Code,Post),FullCall),
253 time_out_call(must_fail(FullCall)),debug_println(9,ok),
254 fail.
255 exhaustive_kernel_fail_check4(_,_,_,_).
256
257 % enumerate_kernel_call(Call, OptionList, NewCall, CodeAfter)
258 enumerate_kernel_call((A,B),Opts,(EA,EB),(CA,CB)) :- !,
259 enumerate_kernel_call(A,Opts,EA,CA), enumerate_kernel_call(B,Opts,EB,CB).
260 enumerate_kernel_call(Module:Call,Opts,Module:ECall,Code) :- !, enumerate_kernel_call(Call,Opts,ECall,Code).
261 enumerate_kernel_call(Call,Opts,ECall,Code) :- Call=..[KernelPred|CArgs],
262 (member(commutative,Opts)
263 -> (Args=CArgs ; CArgs=[A1,A2|T], Args=[A2,A1|T])
264 ; Args=CArgs
265 ),
266 l_enumerate_kernel_args(Args,EArgs,Code,KernelPred,1), ECall=..[KernelPred|EArgs].
267 l_enumerate_kernel_args([],[],true,_,_).
268 l_enumerate_kernel_args([H|T],[EH|ET],Code,KernelPred,Nr) :-
269 enumerate_kernel_args(H,EH,C1,KernelPred/Nr),
270 N1 is Nr+1,
271 l_enumerate_kernel_args(T,ET,C2,KernelPred,N1),
272 permute_code((C1,C2),Code).
273
274 permute_code((true,C),R) :- !,R=C.
275 permute_code((C,true),R) :- !, R=C.
276 permute_code((C1,C2),(C1,C2)).
277 permute_code((C1,C2),(C2,C1)).
278
279 enumerate_kernel_args(Var,Res,Code,_) :- var(Var),!, Res=Var, Code=true.
280 enumerate_kernel_args(X,Res,Code,KP_Nr) :- do_not_delay(X,KP_Nr),!, Res=X, Code=true.
281 enumerate_kernel_args(Arg,Arg,true,_). % just keep the argument
282 enumerate_kernel_args(Arg,NewArg,Code,_) :- % delay the argument fully
283 (term_is_of_type(Arg,bsets_object,no)
284 -> Code = equal_object(NewArg,Arg,enumerate_kernel_args)
285 ; Code = '='(NewArg,Arg)).
286 enumerate_kernel_args(int(X),int(XX),Code,_) :- nonvar(X), Code = '='(X,XX). % delay setting number content
287 enumerate_kernel_args(string(X),string(XX),Code,_) :- nonvar(X), Code = '='(X,XX). % delay setting string content
288 enumerate_kernel_args((A,B),(AA,BB),(CodeA,CodeB),KP_Nr) :-
289 enumerate_kernel_args(A,AA,CodeA,KP_Nr),enumerate_kernel_args(B,BB,CodeB,KP_Nr),
290 (AA,BB) \== (A,B). % avoid re-generating case 3 above (just keep argument)
291 enumerate_kernel_args(freeval(ID,Case,A),freeval(ID,Case,AA),CodeA,KP_Nr) :-
292 enumerate_kernel_args(A,AA,CodeA,KP_Nr),
293 AA \== A. % avoid re-generating case 3 above (just keep argument)
294 enumerate_kernel_args([H|T],[H|NewT],Code,_) :- Code = equal_object(NewT,T).
295 enumerate_kernel_args([H|T],Res,Code,KP_Nr) :- try_expand_and_convert_to_avl([H|T],AVL),
296 AVL \= [H|T], enumerate_kernel_args(AVL,Res,Code,KP_Nr).
297 enumerate_kernel_args([H|T],Res,Code,KP_Nr) :- ground([H|T]),generate_member_closure([H|T],Closure),
298 enumerate_kernel_args(Closure,Res,Code,KP_Nr).
299
300 do_not_delay(b(_,_,_),_). % do not delay B predicates and expressions
301 do_not_delay(global_set(G),KP/ArgNr) :- custom_explicit_sets:is_infinite_global_set(G,_),
302 %print(inf_nr(KP,ArgNr)),nl,
303 do_not_delay_arg(KP,ArgNr).
304 % these arguments cause difficulty if infinite sets are delayed
305 do_not_delay_arg(partial_function_wf,2).
306 do_not_delay_arg(partial_function_wf,3).
307 do_not_delay_arg(subset_test,2).
308 do_not_delay_arg(subset_strict_test,2).
309
310 generate_member_closure(ExplicitSet,closure(['_zzzz_unit_tests'],[Type],Pred)) :-
311 infer_type(ExplicitSet,set(Type)),
312 Pred =
313 b(member(b(identifier('_zzzz_unit_tests'),Type,[generated]),
314 b(value(ExplicitSet),set(Type),[])),pred,[]).
315
316 infer_type(Value,Type) :- (infer_value_type(Value,Type)
317 -> true %,print(inferred(Type,Value)),nl
318 ; print('### Could not infer type: '), print(Value),nl,fail).
319
320 :- use_module(btypechecker,[couplise_list/2]).
321 infer_value_type([],set(any)).
322 infer_value_type([H|T],set(ResType)) :- infer_value_type(H,Type),
323 ((contains_any(Type),T=[H2|_], % try H2; maybe we can infer a better type here
324 infer_value_type(H2,Type2), \+ contains_any(Type2))
325 -> ResType = Type2
326 ; ResType = Type).
327 infer_value_type(avl_set(node(H,_True,_,_,_)),set(Type)) :- infer_value_type(H,Type).
328 infer_value_type(int(_),integer).
329 infer_value_type(string(_),string).
330 infer_value_type((A,B),couple(TA,TB)) :- infer_value_type(A,TA), infer_value_type(B,TB).
331 infer_value_type(fd(_,T),global(T)).
332 infer_value_type(pred_true /* bool_true */,boolean).
333 infer_value_type(pred_false /* bool_false */,boolean).
334 infer_value_type(rec(Fields),record(FieldTypes)) :- infer_field_types(Fields,FieldTypes).
335 infer_value_type(freeval(Id,_Case,_Val),freetype(Id)).
336 infer_value_type(closure(_,Types,_),set(Res)) :- couplise_list(Types,Res).
337 infer_value_type(global_set('STRING'),R) :- !, R=set(string). % what if Event-B/TLA have a deferred set of that name
338 infer_value_type(global_set(X),R) :- b_integer_set(X),!,R=set(integer).
339 infer_value_type(global_set(Name),set(global(Name))) :- b_global_set(Name).
340
341 infer_field_types([],[]).
342 infer_field_types([field(Name1,Val)|T],[field(Name1,VT)|TT]) :-
343 infer_value_type(Val,VT),
344 infer_field_types(T,TT).
345
346 contains_any(any).
347 contains_any(couple(A,B)) :- (contains_any(A) -> true ; contains_any(B)).
348 contains_any(set(A)) :- contains_any(A).
349 % to do: fields
350
351 :- assert_pre(kernel_objects:basic_type(Obj,Type), (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))).
352 :- assert_post(kernel_objects:basic_type(Obj,_), type_check(Obj,bsets_object)).
353
354 %:- block basic_type(-,-).
355
356 basic_type(FD,global(T)) :- !, global_type(FD,T). % will set up CLP(FD) domain for X
357 % TO DO: Also: what about global(T) inside other structures (pairs) ?
358 basic_type(Rec,record(FieldTypes)) :- !, Rec=rec(Fields), %print(basic_field(FieldTypes)),nl,
359 basic_field_types(Fields,FieldTypes).
360 %basic_type(Set,set(Type)) :- !, basic_type_set(Type,Set,inf).
361 basic_type(_X,_TY). %basic_type2(TY,X) %basic_symbreak(TY,X)
362 %print(ignore_basic_type(X,Y)),nl %, basic_type2(TY,X) %%STILL REQUIRED ?????
363
364 basic_field_types([],[]).
365 basic_field_types([field(Name1,Val)|T],[field(Name2,VT)|TT]) :-
366 basic_field_types2(Name1,Val,T,Name2,VT,TT).
367
368 basic_field_types2(Name,Val,T,Name,VT,TT) :-
369 basic_type(Val,VT),basic_field_types(T,TT).
370
371
372
373 /* ------------------------- */
374 /* enumerate_basic_type/2 */
375 /* ------------------------- */
376 /* a version of basic_type that enumerates */
377
378 :- assert_must_succeed(enumerate_basic_type([],set(couple(integer,integer)) )).
379 :- assert_must_succeed(enumerate_basic_type([([],int(2)), ([int(3)],int(4))],
380 set(couple(set(integer),integer)) )).
381 :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))],
382 set(couple(integer,integer)) )).
383 :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))],
384 seq(integer) )).
385 :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))],
386 seq(integer) )).
387 :- assert_must_succeed((enumerate_basic_type(X,global('Name')),
388 equal_object(X,fd(1,'Name')) )).
389 :- assert_must_succeed((enumerate_basic_type(X,global('Name')),
390 equal_object(X,fd(2,'Name')) )).
391 :- assert_must_succeed((enumerate_basic_type(X,global('Name')),
392 X==fd(2,'Name')) ).
393 :- assert_must_succeed((enumerate_basic_type(X,record([field(a,global('Name'))])),
394 equal_object(X,rec([field(a,fd(1,'Name'))])) )).
395 :- assert_must_succeed((enumerate_basic_type(X,record([field(a,integer),field(b,global('Name'))])),
396 equal_object(X,rec([field(a,int(1)),field(b,fd(1,'Name'))])) )).
397 :- assert_must_succeed((kernel_freetypes:add_freetype(selfc1,[case(a,constant([a])),case(b,integer)]),
398 kernel_freetypes:set_freetype_depth(2),
399 enumerate_basic_type(X,freetype(selfc1)),equal_object(X,freeval(selfc1,a,term(a))),
400 kernel_freetypes:reset_freetypes)).
401 :- assert_must_succeed((kernel_freetypes:add_freetype(selfc5,[case(a,constant([a])),case(b,integer)]),
402 kernel_freetypes:set_freetype_depth(2),
403 enumerate_basic_type(X,freetype(selfc5)),equal_object(X,freeval(selfc5,b,int(1))),
404 kernel_freetypes:reset_freetypes)).
405 :- assert_must_succeed((kernel_freetypes:add_freetype(selfc7,[case(nil,constant([nil])),case(node,couple(freetype(selfc7),freetype(selfc7)))]),
406 kernel_freetypes:set_freetype_depth(3),
407 findall(X,enumerate_basic_type(X,freetype(selfc7)),Solutions),
408 length(Solutions,5),
409 kernel_freetypes:reset_freetypes)).
410 :- assert_must_succeed((kernel_freetypes:add_freetype(selfc2,[case(a,constant([a])),case(b,freetype(selfc3))]),
411 kernel_freetypes:add_freetype(selfc3,[case(c,constant([c])),case(d,freetype(selfc2))]),
412 kernel_freetypes:set_freetype_depth(4),
413 enumerate_basic_type(X,freetype(selfc2)),
414 equal_object(X,freeval(selfc2,b,freeval(selfc3,d,freeval(selfc2,b,freeval(selfc3,c,term(c)))))),
415 kernel_freetypes:reset_freetypes)).
416 :- assert_must_succeed((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ),
417 equal_object(X,[(fd(1,'Name'),fd(1,'Code'))])) ).
418 :- assert_must_succeed((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ),
419 equal_object(X,[(fd(2,'Name'),fd(1,'Code')), (fd(1,'Name'),fd(2,'Code'))])) ).
420 :- assert_must_succeed((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ),
421 equal_object(X,[(fd(1,'Name'),fd(2,'Code')), (fd(2,'Name'),fd(1,'Code'))])) ).
422 :- assert_must_succeed_any((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ),
423 equal_object(X,[(fd(1,'Name'),fd(2,'Code')), (fd(2,'Name'),fd(1,'Code'))])) ).
424 :- assert_must_succeed(enumerate_basic_type([(int(2),(int(1),int(2))),
425 (int(1),(int(3),int(4)))],
426 set(couple(integer,couple(integer,integer))) )).
427 :- assert_must_succeed(enumerate_basic_type([(int(2),(int(1),int(2))),
428 (int(55),(int(3),int(4)))],
429 set(couple(integer,couple(integer,integer))) )).
430 :- assert_must_succeed(enumerate_basic_type([term('err')],set(constant([err])))).
431 :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))],
432 set(couple(integer,integer)))).
433
434 :- assert_must_succeed_multiple(enumerate_basic_type([(int(2),fd(_A,'Name')),(int(3),fd(_B,'Name')),
435 (int(4),fd(_C,'Name')),(int(5),fd(_D,'Name')),(int(6),fd(_E,'Name')),(int(7),fd(_F,'Name')),
436 (int(8),fd(_G,'Name')),(int(9),fd(_H,'Name')),(int(10),fd(_I,'Name')),
437 (int(11),fd(_,'Name')),(int(12),fd(_,'Name')),(int(13),fd(_,'Name')),
438 (int(14),fd(_,'Name'))],set(couple(integer,global('Name'))))).
439
440 :- assert_must_fail(( findall(XX,enumerate_basic_type(XX, set(set(global('Code')))) ,S), member(X,S), remove(S,X,R), member(X2,R), equal_object(X,X2) )).
441
442 :- assert_must_succeed(( enumerate_basic_type(global_set('Code'),
443 set(global('Code'))) )).
444
445 :- assert_must_succeed(exhaustive_kernel_succeed_check(enumerate_basic_type([(fd(1,'Name'),fd(2,'Code')), (fd(2,'Name'),fd(1,'Code'))],set(couple(global('Name'),global('Code')))))).
446 :- assert_must_succeed(exhaustive_kernel_succeed_check(enumerate_basic_type([(fd(1,'Name'),pred_true), (fd(2,'Name'),pred_false), (fd(2,'Name'),pred_true)],set(couple(global('Name'),boolean))))).
447 :- assert_must_succeed(exhaustive_kernel_succeed_check(enumerate_basic_type([pred_true,pred_false],set(boolean)))).
448 :- assert_must_succeed(exhaustive_kernel_succeed_check(enumerate_basic_type([[],[pred_true,pred_false]],set(set(boolean))))).
449
450 :- assert_pre(kernel_objects:enumerate_basic_type(Obj,Type),
451 (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))).
452 :- assert_post(kernel_objects:enumerate_basic_type(Obj,_), (type_check(Obj,bsets_object),ground_check(Obj))).
453
454 enumerate_basic_type_wf(Obj,Type,WF) :-
455 enumerate_basic_type_wf(Obj,Type,enumerate_basic_type,WF).
456 :- block enumerate_basic_type_wf(?,-,?,?).
457 enumerate_basic_type_wf(Obj,Type,EnumWarning,WF) :-
458 enumerate_basic_type4(Type,Obj,basic,trigger_true(enum_wf_context(WF,EnumWarning))). % add WF context info
459
460 :- block enumerate_basic_type(?,-).
461 enumerate_basic_type(Obj,Type) :- %print_message(call_enumerate_basic_type(Obj,Type)),
462 %enumerate_basic_type2(Obj,Type).
463 enumerate_basic_type4(Type,Obj,basic,trigger_true(enumerate_basic_type)).
464 %(ground(Obj) -> true ; enumerate_basic_type3(Type,Obj,basic)).
465
466 :- block enumerate_basic_type(?,-,-).
467 enumerate_basic_type(Obj,Type,EnumWarning) :-
468 enumerate_basic_type4(Type,Obj,basic,EnumWarning).
469
470
471 :- block enumerate_type(?,-,?). % last argument: basic or tight
472 enumerate_type(Obj,Type,Tight) :- %print_message(call_enumerate_basic_type(Obj,Type)),
473 %enumerate_basic_type2(Obj,Type).
474 enumerate_basic_type4(Type,Obj,Tight,trigger_true(enumerate_type_3)).
475
476 :- block enumerate_type(?,-,?,-).
477 enumerate_type(Obj,Type,Tight,EnumWarning) :-
478 ? enumerate_basic_type4(Type,Obj,Tight,EnumWarning).
479
480 %enumerate_basic_type2(X,Type) :-
481 % (ground(X) -> (basic_type(X,Type) -> true
482 % ; add_internal_error('Type error: ',enumerate_basic_type2(X,Type)))
483 % ; enumerate_basic_type3(Type,X)).
484
485 enumerate_basic_type4(global(T),R,_Tight,EnumWarning) :-
486 ? enumerate_global_type_with_enum_warning(R,T,EnumWarning).
487 enumerate_basic_type4(set(X),Set,Tight,EnumWarning) :-
488 enumerate_basic_type_set(Set,X,Tight,EnumWarning).
489 enumerate_basic_type4(seq(SeqRanType),Seq,Tight,EnumWarning) :-
490 (Tight = tight -> enumerate_seq_type(Seq,SeqRanType,EnumWarning) % might trigger warning. push flag.
491 ; enumerate_basic_type4(set(couple(integer,SeqRanType)),Seq,basic,EnumWarning)).
492 enumerate_basic_type4(couple(XT,YT),(X,Y),Tight,EnumWarning) :-
493 ? enumerate_type(X,XT,Tight,EnumWarning),enumerate_type(Y,YT,Tight,EnumWarning).
494 ?enumerate_basic_type4(boolean,B,_Tight,_EnumWarning) :- enumerate_bool(B).
495 ?enumerate_basic_type4(string,string(S),_Tight,EnumWarning) :- enumerate_string(S,EnumWarning).
496 enumerate_basic_type4(constant([V]),term(V),_Tight,_EnumWarning).
497 enumerate_basic_type4(record(FT),rec(F),Tight,EnumWarning) :- %print(enum_rec(FT,F)),nl,
498 enumerate_basic_field_types(F,FT,Tight,EnumWarning). %, print(rec(F)),nl.
499 enumerate_basic_type4(freetype(Id),freeval(Id,C,Value),Tight,_EnumWarning) :-
500 enumerate_freetype(Tight,freeval(Id,C,Value),freetype(Id)).
501 enumerate_basic_type4(freetype(Id,Depth),freeval(Id,C,Value),Tight,_EnumWarning) :-
502 enumerate_freetype(Tight,freeval(Id,C,Value),freetype(Id,Depth)).
503 enumerate_basic_type4(integer,int(N),Tight,EnumWarning) :-
504 ? (nonvar(N)
505 -> (number(N) -> true ; add_internal_error('Illegal value: ',enumerate_basic_type4(integer,int(N),Tight,EnumWarning)))
506 ? ; enumerate_int_with_span(N,EnumWarning,unknown)).
507 enumerate_basic_type4(abort,V,Tight,EnumWarning) :-
508 add_internal_error(deprecated_abort_type,enumerate_basic_type4(abort,V,Tight,EnumWarning)).
509 enumerate_basic_type4(constant,V,Tight,EnumWarning) :-
510 add_internal_error(deprecated_abort_type,enumerate_basic_type4(constant,V,Tight,EnumWarning)).
511 enumerate_basic_type4(any,Obj,_Tight,EnumWarning) :- enumerate_any(Obj,EnumWarning).
512
513 :- use_module(library(random),[random/3]).
514 enumerate_bool(X) :- preferences:preference(randomise_enumeration_order,true),
515 random(1,3,1),!,
516 (X=pred_false ; X=pred_true).
517 enumerate_bool(pred_true). /* was bool_true */
518 enumerate_bool(pred_false).
519
520 max_cardinality_string(inf). % was 2
521 all_strings(AS) :- findall(string(S),enumerate_string(S,trigger_throw(all_strings)),AS).
522 :- use_module(btypechecker,[machine_string/1]).
523 enumerate_string(S,_EnumWarning) :- atomic(S),!.
524 enumerate_string(S,EnumWarning) :- %print('### WARNING, Enumerating STRING'),nl,
525 % frozen(S,Goal), print(enum(S,Goal)),nl,
526 % MAYBE TO DO: we could check if prolog:dif(S,'"STR1"') are in frozen Goal and then enumerate more?
527 % if we do this we need to adapt dont_expand(global('STRING')) :- ... further below
528 ? enum_warning('STRING',inf,'"STRING1","STRING2",...',EnumWarning,unknown),
529 ? (S = 'STRING1', \+ btypechecker:machine_string(S) % used to be '"STR1"'
530 ; S = 'STRING2', \+ btypechecker:machine_string(S) % used to be '"STR2"'
531 ; btypechecker:machine_string(S)).
532
533 is_string(string(_),_WF).
534 is_not_string(X) :- top_level_dif(X,string).
535
536 :- block enumerate_any(-,?).
537 enumerate_any(fd(X,T),EnumWarning) :- !,
538 when(nonvar(T),enumerate_global_type_with_enum_warning(fd(X,T),T,EnumWarning)).
539 enumerate_any(int(N),EnumWarning) :- !,enumerate_basic_type4(integer,int(N),basic,EnumWarning).
540 enumerate_any(term(X),_EnumWarning) :- !, print_message(could_not_enumerate_term(X)).
541 enumerate_any(string(S),EnumWarning) :- !, enumerate_string(S,EnumWarning).
542 enumerate_any(pred_true /* bool_true */,_EnumWarning) :- !.
543 enumerate_any(pred_false /* bool_false */,_EnumWarning) :- !.
544 enumerate_any([],_EnumWarning) :- !.
545 enumerate_any([H|T],EnumWarning) :- !, enumerate_any(H,EnumWarning), enumerate_any(T,EnumWarning).
546 enumerate_any(avl_set(_),_EnumWarning) :- !.
547 enumerate_any(global_set(_),_EnumWarning) :- !.
548 enumerate_any((H,T),EnumWarning) :- !, enumerate_any(H,EnumWarning), enumerate_any(T,EnumWarning).
549 enumerate_any(rec(Fields),EnumWarning) :- !, enumerate_any(Fields,EnumWarning).
550 enumerate_any(field(_,V),EnumWarning) :- !, enumerate_any(V,EnumWarning).
551 % we could support: closure values...
552 enumerate_any(T,_EnumWarning) :- add_message(enumerate_any,'Could_not_enumerate value: ',T).
553
554
555 :- use_module(preferences,[preference/2]).
556 :- use_module(library(clpfd),[labeling/2]). %, indomain/1]).
557 % enumerate an INTEGER variable
558 enumerate_int_with_span(N,EnumWarning,Span) :-
559 ? clpfd_domain(N,FDLow,FDUp), % print(enum(N,FDLow,FDUp)),nl,
560 ? (finite_domain(FDLow,FDUp)
561 ? -> label(N,FDLow,FDUp)
562 ? ; enum_unbounded(FDLow,FDUp,N,EnumWarning,Span)
563 ).
564 label(N,FDLow,FDUp) :-
565 ? gen_enum_warning_if_large(N,FDLow,FDUp),
566 ? clpfd_interface:clpfd_randomised_labeling([],[N]).
567 % Note: CLP(FD) labeling does not necessarily try all values in range (disjunctive domains)
568
569 % when in CLP(FD) mode; try and do a case-split and see if that narrows down the possible ranges
570 ?enum_unbounded(X,Y,N,EnumWarning,Span) :- preferences:preference(use_clpfd_solver,true),!,
571 ? enum_unbounded_clp(X,Y,N,EnumWarning,Span).
572 enum_unbounded(X,Y,N,EnumWarning,Span) :- %frozen(N,G), print(frozen(N,G,X,Y,EnumWarning)),nl,
573 clpfd_off_domain(N,X,Y,NX,NY),
574 (finite_domain(NX,NY) -> enumerate_int1(N,NX,NY)
575 ; enum_unbounded_clpfd_off(NX,NY,N,EnumWarning,Span)).
576 enum_unbounded_clpfd_off(_FDLow,_FDUp,N,_EnumWarning,_) :- is_wdguarded_result_variable(N),!.
577 enum_unbounded_clpfd_off(FDLow,FDUp,N,EnumWarning,Span) :-
578 make_domain_finite(FDLow,FDUp,Min,Max),
579 enum_warning('INTEGER',FDLow:FDUp,Min:Max,EnumWarning,Span),
580 enumerate_int1(N,Min,Max). % will also do a case split, but without posting constraints
581
582 % try to determine integer variable bounds from pending co-routines for CLPFD off mode
583 clpfd_off_domain(Var,Low,Up,NewLow,NewUp) :-
584 frozen(Var,Goal), narrow_down_interval(Goal,Var,Low,Up,NewLow,NewUp).
585 % ((Lowx,Up)==(NewLow,NewUp) -> true ; print(narrowed_down(Var,Low,Up,NewLow,NewUp)),nl).
586 narrow_down_interval((A,B),Var,Low,Up,NewLow,NewUp) :- !,
587 narrow_down_interval(A,Var,Low,Up,Low1,Up1),
588 narrow_down_interval(B,Var,Low1,Up1,NewLow,NewUp).
589 narrow_down_interval(kernel_objects:safe_less_than_equal(_,V1,V2),Var,Low,Up,NewLow,NewUp) :- !,
590 (V1==Var,number(V2) -> NewLow=Low,fd_min(Up,V2,NewUp)
591 ; V2==Var,number(V1) -> fd_max(Low,V1,NewLow),NewUp=Up
592 ; NewLow=Low,NewUp=Up).
593 narrow_down_interval(kernel_objects:safe_less_than(V1,V2),Var,Low,Up,NewLow,NewUp) :- !,
594 (V1==Var,number(V2) -> NewLow=Low,V2m1 is V2-1, fd_min(Up,V2m1,NewUp)
595 ; V2==Var,number(V1) -> V1p1 is V1+1, fd_max(Low,V1p1,NewLow),NewUp=Up
596 ; NewLow=Low,NewUp=Up).
597 narrow_down_interval(_,_,L,U,L,U).
598
599 % check if this variable is marked as being assigned to by currently not-well-defined construct such as min,max,...:
600 is_wdguarded_result_variable(N) :-
601 frozen(N,FrozenGoal), %print(frozen(N,FrozenGoal)),nl,
602 is_wdguarded_result_variable_aux(FrozenGoal,N). %, print(not_enumerating(N)),nl.
603 is_wdguarded_result_variable_aux(kernel_waitflags:is_wd_guarded_result(V),N) :- !, N==V.
604 is_wdguarded_result_variable_aux((A,B),N) :-
605 is_wdguarded_result_variable_aux(A,N) ; is_wdguarded_result_variable_aux(B,N).
606
607 % enumerate unbounded integer variable N in a CLP(FD) fashion:
608 ?enum_unbounded_clp(0,Y,N,EnumWarning,Span) :- (Y=sup ; Y>0),
609 % we span 0 and positive numbers
610 ? !,
611 %print(case_split_0(0,Y,N)),nl,
612 ? (N=0
613 % for division/modulo... 0 is often a special case
614 ; try_post_constraint(N #>0), force_enumerate_int_wo_case_split(N,'INTEGER',EnumWarning,Span)
615 ).
616 enum_unbounded_clp(X,Y,N,EnumWarning,Span) :-
617 ? (X=inf -> true ; X<0), (Y=sup ; Y>0),
618 % we span both negative and positive numbers
619 ? !,
620 % do a case split
621 %print(case_split(X,Y,N)),nl,
622 ? (N=0
623 % Instead of doing a case-split on 0; we could try and detect other relevant values (e.g., what if we have x / (y-1)
624 ? ; try_post_constraint(N #>0), % TO DO: use clpfd_lt_expr(0,N), ?and in other calls; this is an area where time-outs are more likely, but we cannot do anything about them anyway
625 ? force_enumerate_int_wo_case_split(N,'INTEGER',EnumWarning,Span)
626 ; try_post_constraint(N #<0), force_enumerate_int_wo_case_split(N,'INTEGER',EnumWarning,Span)
627 ).
628 enum_unbounded_clp(FDLow,FDUp,N,EnumWarning,Span) :-
629 % we cover only negative or only positive numbers
630 ? force_enumerate_with_warning(N,FDLow,FDUp,'INTEGER',EnumWarning,Span).
631
632 % force enumeration without case split:
633 force_enumerate_int_wo_case_split(N,Msg,EnumWarning,Span) :-
634 ? clpfd_domain(N,FDLow,FDUp), % print(enum(N,FDLow,FDUp)),nl,
635 ? (finite_domain(FDLow,FDUp)
636 -> label(N,FDLow,FDUp)
637 ; %print(force_enumerate_int_wo_case_split(FDLow,FDUp)),nl,
638 ? force_enumerate_with_warning(N,FDLow,FDUp,Msg,EnumWarning,Span)
639 ).
640
641 force_enumerate_with_warning(N,_FDLow,_FDUp,_Msg,_EnumWarning,_Span) :- % check if we should enumerate at all
642 is_wdguarded_result_variable(N),!.
643 force_enumerate_with_warning(N,FDLow,FDUp,Msg,EnumWarning,Span) :-
644 ? make_domain_finite(FDLow,FDUp,Min,Max),
645 ? enum_warning(Msg,FDLow:FDUp,Min:Max,EnumWarning,Span),
646 %try_post_constraint(N in Min..Max), % I am not sure whether this is useful or not
647 %print(posted_in(N,Min,Max)),nl,trace,
648 ? enumerate_int2(N,Min,Max).
649
650 %enum_warning3(TYPE,RANGE,RESTRICTED_RANGE) :- enum_warning(TYPE,RANGE,RESTRICTED_RANGE,trigger_true(unknown)).
651
652 enum_warning(TYPE,RANGE,RESTRICTED_RANGE,Trigger,Span) :-
653 Warning = enumeration_warning(enumerating(Info),TYPE,RANGE,RESTRICTED_RANGE,critical),
654 ( get_trigger_info(Trigger,Info)
655 -> true
656 ; Info=unknown),
657 (add_new_event_in_error_scope(Warning,print_enum_warning(Trigger,TYPE,RANGE,RESTRICTED_RANGE,Span)) % may also throw(Warning)
658 ->
659 (preference(allow_enumeration_of_infinite_types,false)
660 -> print('### VIRTUAL TIME-OUT generated because ENUMERATE_INFINITE_TYPES=false'),nl, % trace,
661 % print_pending_abort_error(Info),
662 print_span(Span),nl,
663 throw(Warning)
664 ; Trigger = trigger_throw(Source)
665 -> print('### VIRTUAL TIME-OUT generated for '),print(Source), % trace,
666 print(' '),print_span(Span),nl,
667 throw(Warning)
668 ; true)
669 ; true).
670
671 get_trigger_info(trigger_false(I),Info) :- get_trigger_info2(I,Info). % was non_critical ; TO DO: simplify !
672 get_trigger_info(trigger_true(I),Info) :- get_trigger_info2(I,Info).
673 get_trigger_info(trigger_throw(I),Info) :- get_trigger_info2(I,Info).
674 get_trigger_info2(enum_wf_context(_,Info),Res) :- !,Res=Info.
675 get_trigger_info2(Info,Info).
676
677 get_trigger_info_wf_context(enum_wf_context(WF,_),WF).
678
679 % TO DO: pass WF explicitly rather than extracting it from enumeration warning terms
680 :- use_module(translate,[translate_span/2, translate_error_term/2]).
681 print_pending_abort_error(Info) :-
682 get_pending_abort_error(Info,Span,Msg,ErrTerm),
683 !, % just print one error
684 translate:translate_span(Span,TSpan), translate:translate_error_term(ErrTerm,TT),
685 format(' (could be due to WD-Error ~w: ~w ~w)~n',[TSpan,Msg,TT]).
686 print_pending_abort_error(_).
687
688 get_pending_abort_error(Info,Span,Msg,ErrTerm) :-
689 get_trigger_info_wf_context(Info,WF),
690 pending_abort_error(WF,Msg,ErrTerm,Span).
691
692 % try and get get_pending_abort_error_for_trigger
693 get_pending_abort_error_for_info(Info,Span,FullMsg,ErrTerm) :-
694 get_pending_abort_error(Info,Span,Msg,ErrTerm),
695 ajoin(['Enumeration warning occured, probably caused by WD-Error: ',Msg],FullMsg).
696
697 :- use_module(translate,[print_span/1]).
698 % THROWING,OuterSpan added by add_new_event_in_error_scope
699 print_enum_warning(Trigger,TYPE,RANGE,RESTRICTED_RANGE,LocalSpan,THROWING,OuterThrowSpan) :-
700 print('### Warning: unbounded enumeration of '), % error_manager:trace_if_user_wants_it,
701 print_trigger_var(Trigger,Info),
702 format('~w : ~w ---> ~w ',[TYPE,RANGE,RESTRICTED_RANGE]),
703 print_span(LocalSpan),nl,
704 (THROWING=throwing -> print_pending_abort_error(Info)
705 ; true), % trace,
706 print_throwing(THROWING,Info,OuterThrowSpan).
707
708 :- use_module(tools_printing,[format_with_colour/4]).
709 print_throwing(THROWING,Span) :- print_throwing(THROWING,unknown_info,Span).
710 print_throwing(THROWING,Info,ThrowSpan) :-
711 (preference(strict_raise_enum_warnings,true)
712 -> (get_pending_abort_error_for_info(Info,Span,Msg,ErrTerm)
713 -> add_error(strict_raise_enum_warnings,Msg,ErrTerm,Span)
714 ; add_error(strict_raise_enum_warnings,'Enumeration warning occured','',ThrowSpan)
715 )
716 ; (THROWING=throwing -> print_pending_abort_error(Info) ; true)
717 ),
718 (THROWING=throwing ->
719 format_with_colour(user_output,[bold],'Generating VIRTUAL TIME-OUT for enumeration warning!~n',[]),
720 (extract_span_description(ThrowSpan,PosMsg) -> format_with_colour(user_output,[bold],' ~w~n',[PosMsg]) ; true)
721 ; true).
722
723 print_trigger_var(trigger_true(Info),Info) :- !, print_trigger_var_aux(Info), print(' : ').
724 print_trigger_var(trigger_throw(Info),Info) :- !, print_trigger_var_aux(Info), print(' : (all_solutions) : ').
725 print_trigger_var(trigger_false(Info),Info) :- !, print_trigger_var_aux(Info), print(' (not critical [unless failure]) : ').
726 print_trigger_var(X,X) :- print(' UNKNOWN TRIGGER: '),print(X), print(' : ').
727
728 :- use_module(translate,[print_bexpr/1]).
729 print_trigger_var_aux(enum_wf_context(_WF,VarID)) :- !, print_trigger_var_aux(VarID).
730 print_trigger_var_aux(b(E,T,I)) :- !, print_bexpr(b(E,T,I)), print_span(I).
731 print_trigger_var_aux(VarID) :- print(VarID).
732
733
734 % generate a warning if a large range is enumerated
735 gen_enum_warning_if_large(Var,FDLow,FDUp) :-
736 (FDUp>FDLow+8388608 /* 2**23 ; {x|x:1..2**23 & x mod 2 = x mod 1001} takes about 2 minutes */
737 % however the domain itself could be very small, we also check clpfd_size instead
738 -> clpfd:fd_size(Var,Size), % no need to call clpfd_size; we know we are in CLP(FD) mode
739 (Size =< 8388608 -> true
740 ; enum_warning_large(Var,'INTEGER',FDLow:FDUp)
741 )
742 ; true).
743 enum_warning_large(_Var,TYPE,RANGE) :-
744 Warning = enumeration_warning(enumerating,TYPE,RANGE,RANGE,non_critical),
745 (add_new_event_in_error_scope(Warning,print_enum_warning_large(TYPE,RANGE))
746 -> %(b_enumerate:get_prolog_variable_name(_Var,Name,_Type) -> print(' : Identifier = '), print(Name) ; true),
747 %nl,frozen(_Var,G), print(frozen(G)), % comment in to get info about variable
748 %% trace,
749 (preference(allow_enumeration_of_infinite_types,true) -> true
750 ; debug_println(9,'### THROWING EXCEPTION'), %trace,
751 throw(Warning))
752 ; true).
753 print_enum_warning_large(TYPE,RANGE,THROWING,Span) :-
754 print('### Warning: enumerating large range '),
755 print(TYPE), print(' : '),
756 print(RANGE),nl,
757 print_throwing(THROWING,Span).
758
759 :- block finite_warning(-,?,?,?,?).
760 finite_warning(_,Par,Types,Body,Source) :-
761 add_new_event_in_error_scope(enumeration_warning(checking_finite_closure,Par,Types,finite,critical),
762 print_finite_warning(Par,Types,Body,Source) ),
763 fail. % WITH NEW SEMANTICS OF ENUMERATION WARNING WE SHOULD PROBABLY ALWAYS FAIL HERE !
764 print_finite_warning(Par,Types,Body,Source,THROWING,Span) :-
765 print('### Warning: could not determine set comprehension to be finite: '),
766 translate:print_bvalue(closure(Par,Types,Body)),nl,
767 print('### Source: '), print(Source),nl,
768 print_throwing(THROWING,Span).
769
770 :- block enumerate_natural(-,?,-,?).
771 ?enumerate_natural(N,From,_,Span) :- nonvar(N) -> true ; enumerate_natural(N,From,Span).
772 ?enumerate_natural(N,From,Span) :- clpfd_domain(N,FDLow,FDUp), % print(enumerate_nat(N,From,FDLow,FDUp)),nl,trace,
773 ? fd_max(FDLow,From,Low),
774 ? (finite_domain(Low,FDUp)
775 -> label(N,Low,FDUp)
776 ? ; preference(use_clpfd_solver,true) -> enumerate_natural_unbounded(N,Low,FDUp,Span)
777 ; clpfd_off_domain(N,Low,FDUp,NewLow,NewUp), % try narrow down domain using co-routines
778 (finite_domain(NewLow,NewUp) -> enumerate_int1(N,NewLow,NewUp)
779 ; enumerate_natural_unbounded(N,NewLow,NewUp,Span)
780 )
781 ).
782 enumerate_natural_unbounded(N,FDLow1,FDUp,Span) :-
783 ? (FDLow1=0
784 ? -> (N=0 ; /* do a case split */
785 try_post_constraint(N #>0), % this can sometimes make the domain finite
786 force_enumerate_int_wo_case_split(N,'NATURAL',trigger_true('NATURAL'),Span)
787 )
788 ; force_enumerate_with_warning(N,FDLow1,FDUp,'NATURAL(1)',trigger_true('NATURAL(1)'),Span)
789 ).
790
791
792 % assumes one of FDLow and FDUp is not a number
793 make_domain_finite(FDLow,_FDUp,Min,Max) :- number(FDLow),!,Min=FDLow,
794 preferences:preference(maxint,MaxInt),
795 (MaxInt>=FDLow -> Max=MaxInt ; Max=FDLow). % ensure that we try at least one number
796 make_domain_finite(_FDLow,FDUp,Min,Max) :- number(FDUp),!,Max=FDUp,
797 preferences:preference(minint,MinInt),
798 (MinInt=<FDUp -> Min=MinInt ; Min=FDUp).
799 make_domain_finite(_FDLow,_FDUp,Min,Max) :-
800 ((preferences:preference(maxint,Max),
801 preferences:get_preference(minint,Min))->true). % ensure that we try at least one number
802
803 enumerate_int1(N,Min,Max) :-
804 (Min<0 /* enumerate positive numbers first; many specs only use NAT/NATURAL */
805 -> (enumerate_int2(N,0,Max) ; enumerate_int2(N,Min,-1))
806 ; enumerate_int2(N,Min,Max)
807 ).
808 ?enumerate_int(X,Low,Up) :- get_int_domain(X,Low,Up,RL,RU),
809 %% print(enumerate_int(X,Low,Up, RL,RU)),nl, %%
810 ? enumerate_int2(X,RL,RU).
811
812 get_int_domain(X,Low,Up,RL,RU) :- clpfd_domain(X,FDLow,FDUp),
813 fd_max(FDLow,Low,RL),fd_min(FDUp,Up,RU).
814
815 finite_domain(Low,Up) :- \+ infinite_domain(Low,Up).
816 infinite_domain(inf,_) :- !.
817 infinite_domain(_,sup).
818
819 % second arg should always be a number
820 fd_max(inf,L,R) :- !,R=L.
821 fd_max(FDX,Y,R) :- (nonvar(FDX),nonvar(Y),FDX>Y -> R=FDX ; R=Y).
822 fd_min(sup,L,R) :- !,R=L.
823 fd_min(FDX,Y,R) :- (nonvar(FDX),nonvar(Y),FDX<Y -> R=FDX ; R=Y).
824
825 :- use_module(extension('random_permutations/random_permutations')).
826 :- use_module(library(random),[random/1]).
827 enumerate_int2(N,X,Y) :-
828 ? preferences:get_preference(randomise_enumeration_order,true)
829 ? -> enumerate_int_random(N,X,Y) ; enumerate_int2_linear(N,X,Y).
830
831 ?enumerate_int2_linear(N,X,Y) :- X=<Y,
832 ? (N=X ; X1 is X+1, enumerate_int2_linear(N,X1,Y)).
833
834 enumerate_int_random(N,X,Y) :-
835 init_random_permutations,
836 %format('enumerate_int2: Enumerating ~w from ~w to ~w~n',[N,X,Y]),
837 IntervalLength is Y - X + 1,
838 get_num_bits(IntervalLength,MaxIdx,NumBits),
839 get_masks(NumBits,LeftMask,RightMask),
840 % the seed relies on the random predicate, not on now/1, thus prob can be made deterministic by setting a central random seed
841 random(TempSeed),
842 Seed is floor(TempSeed * 10000),
843 enumerate_int_random_aux(N,0,MaxIdx,X,Y,Seed,NumBits,LeftMask,RightMask).
844
845 enumerate_int_random_aux(N,CurIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask) :-
846 random_permutation_element(CurIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask,Drawn,NextIdx),
847 %format('enumerate_int2: Setting variable ~w to ~w~n',[N,Drawn]),
848 ( N=Drawn
849 ; enumerate_int_random_aux(N,NextIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask)).
850
851 enumerate_basic_type_set(X,Type,Tight,EnumWarning) :- var(X),!,
852 max_cardinality_with_check(Type,Card),
853 enumerate_basic_type_set2(X,[],Card,Type,none,Tight,EnumWarning).
854 enumerate_basic_type_set([],_,_,_EnumWarning) :- !.
855 enumerate_basic_type_set(avl_set(_),_,_,_EnumWarning) :- !.
856 enumerate_basic_type_set(freetype(_),_,_,_EnumWarning) :- !.
857 enumerate_basic_type_set(global_set(GS),Type,_Tight,_EnumWarning) :- !,
858 (Type = global(GT)
859 -> (GS = GT -> true
860 ; nonvar(GS), add_error_and_fail(enumerate_basic_type_set,'Type error in global set: ',GS:GT))
861 ; Type = integer,integer_global_set(GS)
862 ; Type = string, string_global_set(GS)
863 ).
864 enumerate_basic_type_set(closure(Parameters, _ParameterTypes, Body),_Type,_Tight,_EnumWarning) :- !,
865 (ground(Body) -> true
866 ; format('### Enumerating non-ground closure-body ~w: ',[Parameters]), %print_term_summary(Body),
867 %translate:print_bexpr_with_limit(Body,250),
868 nl, error_manager:print_error_span(Body,message),
869 %term_variables(Body,Vars), print('### Variables: '), print(Vars),nl,
870 %add_message(enumerate_basic_type_set,'### Enumerating non-ground closure-body: ',Body,Body),
871 %print('### EnumWarning Info: '), print(EnumWarning),nl,
872 enumerate_values_inside_expression(Body)
873 ).
874 enumerate_basic_type_set([H|T],Type,Tight,EnumWarning) :- !,
875 % collect bound elements; avoid enumerating initial elements with elements that already appear later
876 collect_bound_elements([H|T], SoFar,Unbound,Closed),
877 (Closed=false -> max_cardinality_with_check(Type,Card)
878 ; Card = Closed),
879 % print(enum(Card,Unbound,SoFar,[H|T],Closed)),nl,
880 enumerate_basic_type_set2(Unbound,SoFar,Card,Type,none,Tight,EnumWarning).
881 %enumerate_basic_type_set([H|T],Type,Tight) :- !,
882 % (is_list_skeleton([H|T],Card) -> true
883 % ; max_cardinality_with_check(Type,Card)
884 % ),
885 % enumerate_basic_type_set2([H|T],[],Card,Type,none,Tight).
886 enumerate_basic_type_set(S,Type,Tight,EnumWarning) :-
887 add_internal_error('Illegal set: ',enumerate_basic_type_set(S,Type,Tight,EnumWarning)).
888
889 enumerate_basic_type_set2(HT,ElementsSoFar,_Card,_Type,_Last,_Tight,_EnumWarning) :- nonvar(HT),
890 is_custom_explicit_set(HT,enumerate_basic_type),!,
891 disjoint_sets(HT,ElementsSoFar). % I am not sure this is necessary; probably other constraints already ensure this holds
892 enumerate_basic_type_set2(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning) :- var(HT),
893 preferences:preference(randomise_enumeration_order,true),!,
894 (random(1,3,1)
895 -> (enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning)
896 ; HT = [])
897 ; (HT = [] ;
898 enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning))
899 ).
900 enumerate_basic_type_set2([],_,_,_,_,_Tight,_EnumWarning).
901 enumerate_basic_type_set2(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning) :-
902 enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning).
903
904 enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning) :- positive_card(Card),
905 %debug:trace_point(enum(HT,ElementsSoFar,Card,Type,Last,Tight)),
906 (var(HT) -> HT=[H|T], NewLast=NormH /* the enumerator has completely determined H */
907 % Note: HT=[H|T] may wake up co-routines and then attach infos to H; but these should hold indpendently for all elements
908 ; HT=[H|T],
909 (unbound_value(H) -> NewLast=NormH /* the enumerator has completely determined H */
910 ; NewLast=Last) /* H was not freely chosen by the enumerator */
911 ),
912 not_element_of(H,ElementsSoFar), % this is only needed for elements generated by the enumerator itself
913 enumerate_type(H,Type,Tight,EnumWarning),
914 % TO DO: extract normal form from add_new_element
915 val_greater_than(H,NormH,Last),
916 %(val_greater_than(H,NormH,Last) -> print(ok(H)),nl ; print(pruned(H,NormH,Last)),nl,fail),
917 %(ground(NormH) -> true ; print(not_ground(NormH)),nl),
918 C1 is Card-1,
919 add_new_element(NormH,ElementsSoFar,SoFar2), % we could use avl_store(NormH,A,true,A2) if ElementsSoFar=avl_set(A)
920 %debug:trace_point(add_new_element(NormH,ElementsSoFar,SoFar2)),
921 enumerate_basic_type_set2(T,SoFar2,C1,Type,NewLast,Tight,EnumWarning).
922
923 :- assert_must_succeed((collect_bound_elements([int(1),int(2),int(4),X,int(5)|T],_,U,C),U==[X|T],C==false)).
924 :- assert_must_succeed((collect_bound_elements([int(1),int(2),int(4),X,int(5)],_,U,C),U==[X],C==1)).
925 :- assert_must_succeed(exhaustive_kernel_succeed_check(collect_bound_elements([int(1),int(2),int(4),int(5)],_,_,_))).
926
927 % collect the bound and unbound elements in a list; also return if the list is closed (then return length) or return false
928 collect_bound_elements(T, SoFar,Unbound,Closed) :- var(T),!, SoFar=[],Unbound=T,Closed=false.
929 collect_bound_elements([],[],[],0).
930 collect_bound_elements(avl_set(A),avl_set(A),[],0).
931 collect_bound_elements(global_set(GS),SoFar,Unbound,Closed) :- expand_custom_set(global_set(GS),ES),
932 collect_bound_elements(ES,SoFar,Unbound,Closed).
933 collect_bound_elements(freetype(FS),SoFar,Unbound,Closed) :- expand_custom_set(freetype(FS),ES),
934 collect_bound_elements(ES,SoFar,Unbound,Closed).
935 collect_bound_elements(closure(P,T,B),SoFar,Unbound,Closed) :- expand_custom_set(closure(P,T,B),ES),
936 collect_bound_elements(ES,SoFar,Unbound,Closed).
937 collect_bound_elements([H|T],SoFar,Unbound,Closed) :-
938 collect_bound_elements(T,TSoFar,TUnbound,TClosed),
939 (ground(H) -> add_new_element(H,TSoFar,SoFar), Unbound=TUnbound, TClosed=Closed
940 ; SoFar = TSoFar, Unbound = [H|TUnbound],
941 (TClosed=false -> Closed=false ; Closed is TClosed+1)
942 ).
943
944 % use_module(kernel_objects),findall(A,enumerate_tight_type(A,set(set(boolean))),B),length(B,C).
945 % use_module(kernel_objects),findall(A,enumerate_tight_type(A,set(set(global('Name')))),B),length(B,C).
946 % use_module(kernel_objects),findall(A,enumerate_tight_type(A,set(global('Name'))),B),length(B,C).
947
948 % perform order checking on terms, normalising them first
949 % val_greater_than(A,NormA,NormB)
950 val_greater_than(A,NormA,NormB) :- !,
951 (nonvar(A),custom_explicit_sets:convert_to_avl_inside_set(A,NormA)
952 -> (NormB==none -> true ; NormA @> NormB)
953 ; add_internal_error('Call failed: ',custom_explicit_sets:convert_to_avl_inside_set(A,NormA)),
954 NormA = A).
955
956 positive_card(inf) :- !, print('$').
957 positive_card(C) :- (number(C) -> C>0
958 ; add_internal_error('Not number: ',positive_card(C)),fail).
959
960
961
962 :- block enumerate_basic_field_types(?,-,?,-).
963 enumerate_basic_field_types([],[],_Tight,_EnumWarning).
964 enumerate_basic_field_types(Fields,[field(Name,VT)|TT],Tight,EnumWarning) :-
965 enumerate_basic_field_types2(Fields,Name,VT,TT,Tight,EnumWarning).
966
967 :- block enumerate_basic_field_types2(?,-,?,?,?,?).
968 enumerate_basic_field_types2([field(Name,V)|T], Name,VT,TT,Tight,EnumWarning) :-
969 enumerate_type(V,VT,Tight,EnumWarning),
970 enumerate_basic_field_types(T,TT,Tight,EnumWarning).
971
972
973 :- block all_objects_of_type(-,?).
974 all_objects_of_type(Type,Res) :-
975 findall(O,enumerate_basic_type(O,Type),Res).
976
977 list_length(X,L,Type,MaxIndex) :- var(X),!,L=0, Type=open, MaxIndex=0.
978 list_length([],0,closed,0).
979 list_length([H|T],C1,Type,MaxIndex1) :- list_length(T,C,Type,MaxIndex),
980 C1 is C+1,
981 ((nonvar(H),H=(I,_),nonvar(I),I=int(Idx),number(Idx),Idx>MaxIndex)
982 -> MaxIndex1 = Idx ; MaxIndex1 = MaxIndex).
983
984
985 :- assert_must_succeed((max_cardinality(set(couple(global('Name'),global('Code'))),64))).
986 :- assert_must_succeed((max_cardinality(set(set(set(couple(global('Name'),global('Code'))))),_))).
987 :- assert_must_succeed((kernel_freetypes:add_freetype(selfc4,[case(a,boolean),case(b,couple(boolean,boolean))]),
988 max_cardinality(freetype(selfc4),6),
989 kernel_freetypes:reset_freetypes)).
990 :- assert_must_succeed((kernel_freetypes:add_freetype(selfc6,[case(a,boolean),case(b,freetype(selfc6)),case(c,constant([c]))]),
991 kernel_freetypes:set_freetype_depth(3),
992 findall(X,enumerate_tight_type(X,freetype(selfc6)),Solutions),
993 length(Solutions,NumberOfSolutions),
994 max_cardinality(freetype(selfc6),NumberOfSolutions),
995 kernel_freetypes:reset_freetypes)).
996
997 :- use_module(tools_printing,[print_error/1]).
998 max_cardinality_with_check(Set,CCard) :-
999 (max_cardinality(Set,Card) ->
1000 (Card=inf
1001 -> debug_println(9,very_large_cardinality(Set,Card)),
1002 CCard = 20000000
1003 ; CCard=Card,
1004 (Card>100 -> debug_println(9,large_cardinality(Set,Card)) ; true)
1005 )
1006 ; print_error(failed(max_cardinality(Set,CCard))), CCard = 10
1007 ).
1008 max_cardinality(global(T),Card) :- b_global_set_cardinality(T,Card).
1009 max_cardinality(boolean,2).
1010 max_cardinality(constant([_V]),1).
1011 max_cardinality(any,inf) :- print_message(dont_know_card_of_any). /* what should we do here ? */
1012 max_cardinality(string,MC) :- max_cardinality_string(MC). % is inf now
1013 %max_cardinality(abort,1).
1014 max_cardinality(integer,Card) :- Card=inf. %b_global_set_cardinality('INTEGER',Card).
1015 max_cardinality(seq(X),Card) :- % Card=inf, unless a freetype can be of cardinality 0
1016 max_cardinality(set(couple(integer,X)),Card).
1017 max_cardinality(couple(X,Y),Card) :-
1018 max_cardinality(X,CX), max_cardinality(Y,CY), safe_mul(CX,CY,Card).
1019 max_cardinality(record([]),1).
1020 max_cardinality(record([field(_,T1)|RF]),Card) :-
1021 max_cardinality(record(RF),RC),
1022 max_cardinality(T1,C1),
1023 safe_mul(C1,RC,Card).
1024 max_cardinality(set(X),Card) :- max_cardinality(X,CX),
1025 safe_pow2(CX,Card).
1026 % RealCard is 2**CX, (RealCard is inf -> Card is inf ; Card is integer(RealCard)).
1027 max_cardinality(freetype(Id),Card) :- max_cardinality_freetype(freetype(Id),Card).
1028 max_cardinality(freetype(Id,Depth),Card) :- max_cardinality_freetype(freetype(Id,Depth),Card).
1029
1030 :- assert_must_succeed((safe_pow2(3,R),R==8)).
1031 :- assert_must_succeed((safe_pow2(inf,R),R==inf)).
1032 :- assert_must_succeed((safe_pow2(3072,R),R==inf)).
1033 :- assert_must_succeed((safe_pow2(18446744073709551616,R),R==inf)).
1034 :- assert_must_succeed((safe_pow2(500,X), safe_pow2(501,X2), X2 is 2*X)).
1035 % :- assert_must_succeed((kernel_objects:safe_pow2(1022,X), kernel_objects:safe_pow2(1023,X2), X2 is 2*X)).
1036
1037 safe_pow2(Exp,Res) :- (Exp==inf -> Res=inf
1038 ; Exp>1023 -> Res=inf /* the limit where SICStus 4.2.1 reported inf; 4.2.3 goes further but uses a huge amount of memory */
1039 ; Res is 2^Exp % ^ integer exponentiation operator new in SICStus 4.3
1040 ).
1041 % this seems to be either precise or give inf (at 1023 on 64 bit system)
1042
1043 :- assert_must_succeed((safe_pown(3,2,R),R==9)).
1044 :- assert_must_succeed((safe_pown(2,3072,R),R==inf)).
1045 :- assert_must_succeed((safe_pown(3,647,R),R==inf)).
1046 :- assert_must_succeed((safe_pown(2,500,X), safe_pown(2,501,X2), X2 is 2*X)).
1047 :- assert_must_succeed((safe_pown(2,500,X), safe_pow2(500,X))).
1048 :- assert_must_succeed((kernel_objects:safe_pown(2,1022,X), kernel_objects:safe_pown(2,1023,X2), X2 is 2*X)).
1049 :- assert_must_succeed((kernel_objects:safe_pown(3,500,X), kernel_objects:safe_pown(3,501,X3), X3 is 3*X)).
1050 safe_pown(Base,Exp,Res) :-
1051 (Base=inf -> (Exp=0 -> Res=1 ; Res=inf)
1052 ; Exp=inf -> (Base=0 -> Res=0 ; Base=1 -> Res=1 ; Res=inf)
1053 ; infinite_pown(Base,Exp) -> Res=inf /* SICStus 4.2.1 reported inf; 4.2.3 goes further but uses a huge amount of memory */
1054 ; Res is Base ^ Exp % ^ integer exponentiation operator new in SICStus 4.3
1055 ).
1056
1057 /* SICStus 4.2.1 reported inf; 4.2.3 goes further but uses a huge amount of memory */
1058 infinite_pown(Base,Exp) :- Exp > 1023, !, Base >= 2.
1059 infinite_pown(Base,Exp) :- Exp > 646, !, Base >= 3. % was not really necessary when using overflow_float_pown
1060 infinite_pown(Base,Exp) :- Exp > 511, !, Base >= 4.
1061 infinite_pown(Base,Exp) :- Exp > 441, !, Base >= 5.
1062
1063 :- assert_must_succeed((safe_mul(3,2,R),R==6)).
1064 :- assert_must_succeed((safe_mul(inf,2,R),R==inf)).
1065 :- assert_must_succeed((safe_mul(2,inf,R),R==inf)).
1066 :- assert_must_succeed((safe_mul(0,inf,R),R==0)).
1067 :- assert_must_succeed((safe_mul(inf,0,R),R==0)).
1068 % safe_multiplication for positive numbers
1069 safe_mul(0,_,R) :- !, R=0. % true for cartesian product: card({}*INTEGER)=0
1070 safe_mul(_,0,R) :- !, R=0. % ditto
1071 safe_mul(inf,_,R) :- !, R=inf.
1072 safe_mul(_,inf,R) :- !, R=inf.
1073 safe_mul(X,Y,R) :- is_overflowcheck(R,X*Y).
1074
1075 safe_add(inf,_,R) :- !, R=inf.
1076 safe_add(_,inf,R) :- !, R=inf.
1077 safe_add(X,Y,R) :- is_overflowcheck(R,X+Y).
1078
1079
1080 /* is with overflow check */
1081 is_overflowcheck(Var,Expr) :- %print(is_with_overflow(Var,Expr)),nl,
1082 (Expr=inf -> Var=inf
1083 ; on_exception(error(_,_), Var is Expr, Var=inf)).
1084
1085 %overflow_float_pown(Base,Exp,Res) :-
1086 % on_exception(error(_,_),
1087 % (R1 is Base**Exp, /* separate into two steps; SICStus 4.2.3 otherwise seems to use integer exponentation */
1088 % Res is integer(R1)), Res=inf).
1089
1090 /*
1091 % this code below would sometimes fail in spld generated code:
1092 is_overflowcheck_old(Var,Expr) :- print(is_with_overflow(Var,Expr)),nl,
1093 (Expr=inf -> Var=inf
1094 ; on_exception(error(type_error(evaluable,inf/0),_),
1095 on_exception(error(evaluation_error(float_overflow),_),
1096 Var is Expr,
1097 (print(float_overflow),nl,Var = inf)),
1098 (print(evaluable_inf),nl,Var=inf))).
1099 % catches any exception (e.g. also representation_error when converting inf to integer)
1100 % could be unsafe with timeout !!
1101 is_errc(Var,Expr) :-
1102 (Expr=inf -> Var=inf
1103 ; safe_on_exception(_E, Var is Expr, Var = inf)).
1104 */
1105
1106 /* ---------------------------- */
1107
1108
1109 /* use a cleverer, better enumeration than enumerate_basic_type */
1110 /* can only be used in certain circumstances: operation preconditions,
1111 properties,... but not for VARIABLES as there is no guarantee that
1112 something declared as a sequence will actually turn out to be a sequence */
1113
1114 :- assert_pre(kernel_objects:enumerate_tight_type(Obj,Type),
1115 (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))).
1116 :- assert_post(kernel_objects:enumerate_tight_type(Obj,_), (type_check(Obj,bsets_object),ground_check(Obj))).
1117 :- assert_pre(kernel_objects:enumerate_tight_type(Obj,Type,_),
1118 (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))).
1119 :- assert_post(kernel_objects:enumerate_tight_type(Obj,_,_), (type_check(Obj,bsets_object),ground_check(Obj))).
1120
1121 :- assert_must_succeed(enumerate_tight_type([(int(1),int(2)),(int(2),int(4))],
1122 seq(integer) )).
1123 :- assert_must_succeed(enumerate_tight_type([(int(1),int(2))],seq(integer) )).
1124 :- assert_must_succeed(enumerate_tight_type([],seq(integer) )).
1125 :- assert_must_succeed((enumerate_tight_type(X,record([field(a,integer),field(b,global('Name'))])),
1126 equal_object(X,rec([field(a,int(1)),field(b,fd(1,'Name'))])) )).
1127 :- assert_must_fail(enumerate_tight_type([(int(1),int(2)),(int(3),int(_))],
1128 seq(integer) )).
1129 :- assert_must_fail(enumerate_tight_type([(int(3),int(_))],seq(integer) )).
1130 :- assert_must_succeed((bsets_clp:is_sequence(X,global_set('Name')),
1131 enumerate_tight_type(X,seq(global('Name')) ),
1132 X = [(int(1),fd(2,'Name'))] )).
1133 :- assert_must_succeed(( enumerate_tight_type(XX, record([field(balance,integer),field(name,global('Name'))])) ,
1134 XX = rec([field(balance,int(1)),field(name,fd(3,'Name'))]) )).
1135 :- assert_must_succeed(( enumerate_tight_type(XX, set(record([field(balance,global('Name')),field(name,global('Name'))]))) , /* STILL TAKES VERY LONG !! */
1136 XX = [rec([field(balance,fd(3,'Name')),field(name,fd(3,'Name'))])] )).
1137 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(balance,global('Name')),field(name,global('Name'))]))) ,S),
1138 length(S,Len), Len = 512 )).
1139 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(name,global('Code'))]))) ,S),
1140 length(S,Len), Len = 4 )).
1141 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(fname,global('Code')),field(name,global('Code'))]))) ,S),
1142 length(S,Len), Len = 16 )).
1143 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(fname,global('Code')),field(name,global('Name'))]))) ,S),
1144 length(S,Len), Len = 64 )).
1145 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(global('Name'))) ,S),
1146 length(S,Len), Len = 8 )).
1147 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(boolean))) ,S),
1148 length(S,Len), Len = 16 )).
1149 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(global('Name')))) ,S),
1150 length(S,Len), Len = 256 )).
1151 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(global('Code')))) ,S),
1152 length(S,Len), Len = 16 )).
1153 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(boolean))) ,S),
1154 length(S,Len), Len = 16 )).
1155 :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(couple(global('Code'),global('Name')))) ,S),
1156 length(S,Len), Len = 64 )).
1157 %:- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(couple(global('Code'),integer))) ,S),
1158 % length(S,Len), Len = 64 )).
1159 :- assert_must_succeed(( enumerate_tight_type(XX, set(record([field(balance,integer)]))) ,
1160 XX = [rec([field(balance,int(1))])] )).
1161 :- assert_must_succeed(( enumerate_tight_type(global_set('Code'),set(global('Code'))) )).
1162
1163 :- block enumerate_tight_type(?,-).
1164 enumerate_tight_type(Obj,Type) :- %enumerate_tight_type2(Type,Obj).
1165 %%print_message(call_enumerate_tight_type(Obj,Type)),
1166 (ground_value(Obj) -> true ; % print(enumerate_tight_type(Obj,Type)),nl,
1167 enumerate_basic_type4(Type,Obj,tight,trigger_true(enumerate_tight_type))
1168 ).
1169
1170 :- block enumerate_tight_type(?,-,-).
1171 enumerate_tight_type(Obj,Type,EnumWarning) :- %enumerate_tight_type2(Type,Obj).
1172 %%print_message(call_enumerate_tight_type(Obj,Type)),
1173 ? (ground_value(Obj) -> true ; % print(enumerate_tight_type(Obj,Type)),nl,
1174 ? enumerate_basic_type4(Type,Obj,tight,EnumWarning)
1175 ).
1176
1177
1178 /* TO DO: provide tight enumerators for nat, functions, ... ?? */
1179
1180
1181
1182 :- assert_must_succeed((X=[(int(I1),pred_true /* bool_true */),Y], dif(I1,1),
1183 kernel_objects:enumerate_seq_type(X,boolean,true),I1==2,Y=(int(1),pred_false /* bool_false */))).
1184
1185 enumerate_seq_type(X,Type,EnumWarning) :-
1186 list_length(X,Len,ListType,MaxIndex), % ListType can be open or closed
1187 (ListType=closed
1188 -> MaxIndexForEnum=Len, EW = no_enum_warning,
1189 MaxIndex =< Len % otherwise this is obviously not a sequence
1190 ; (MaxIndex>Len -> Card = MaxIndex ; Card=Len), % in case we already have an explicit index which is higher than the length we use that as index
1191 b_global_set_cardinality('NAT1',NatCard),
1192 (NatCard<Card -> Max1=Card ; Max1=NatCard),
1193 (Max1<1 -> MaxIndexForEnum = 1 ; MaxIndexForEnum=Max1), % ensure that we generate enumeration warning
1194 EW = EnumWarning
1195 ),
1196 enumerate_seq(X,range(1,MaxIndexForEnum),MaxIndexForEnum,Type,EW).
1197
1198 enumerate_seq([],_,_,_,_).
1199 enumerate_seq(Seq,Indexes,Card,Type,EnumWarning) :-
1200 (unbound_variable_for_cons(Seq)
1201 -> positive_card(Card),
1202 Seq = [(int(Index),Element)|TSeq], VarEl=true
1203 ; Seq = [El|TSeq],
1204 (unbound_variable(El) -> VarEl=true ; VarEl=false),
1205 El = (int(Index),Element)
1206 ),
1207 (VarEl=true -> get_next_index(Indexes,Index,RemIndexes)
1208 ; number(Index) -> remove_index_ground(Indexes,Index,RemIndexes) % this can fail if Index > MaxIndex found above ! but not first time around, i.e., we will generate enum warning anyway
1209 ; remove_index(Indexes,Index,RemIndexes)),
1210 (EnumWarning==no_enum_warning -> true
1211 ; enum_warning('seq (length)',inf,Card,EnumWarning,unknown)), % delay enum_warning until we have made the first case-split (sometimes instantiating the sequence to at least one element will trigger an inconsistency)
1212 enumerate_tight_type(Element,Type),
1213 C1 is Card-1,
1214 enumerate_seq(TSeq,RemIndexes,C1,Type,no_enum_warning).
1215
1216 get_next_index([Index1|RestIndexes],Index1,RestIndexes).
1217 get_next_index(range(I1,I2),I1,Res) :-
1218 I11 is I1+1, (I11>I2 -> Res=[] ; Res=range(I11,I2)).
1219
1220 remove_index_ground(Indexes,X,Res) :- get_next_index(Indexes,H,T),
1221 (X=H -> Res=T ; Res=[H|R2], remove_index_ground(T,X,R2)).
1222
1223 remove_index(Indexes,X,Res) :- get_next_index(Indexes,H,T),
1224 (X=H,Res=T ; X\==H, Res=[H|R2], remove_index(T,X,R2)).
1225
1226
1227
1228 /* a few more unit tests: */
1229
1230 :- assert_must_succeed(( findall(X,enumerate_type(X,set(couple(boolean,boolean)),tight) ,L), length(L,16) )).
1231 :- assert_must_succeed(( findall(X,enumerate_type(X,set(couple(boolean,boolean)),basic) ,L), length(L,16) )).
1232
1233 :- assert_must_succeed(( enumerate_tight_type(
1234 [rec([field(balance,int(0)),field(name,fd(2,'Name'))])],[
1235 rec([field(balance,int(1)),field(name,fd(3,'Name'))]),
1236 rec([field(balance,int(1)),field(name,fd(2,'Name'))]),
1237 rec([field(balance,int(0)),field(name,fd(1,'Name'))]),
1238 rec([field(balance,int(-1)),field(name,fd(1,'Name'))])],
1239 set(record([field(balance,integer),field(name,global('Name'))]))) )).
1240 :- assert_must_succeed(( enumerate_tight_type([
1241 rec([field(balance,int(1)),field(name,fd(2,'Name'))]),
1242 rec([field(balance,int(1)),field(name,fd(1,'Name'))]),
1243 rec([field(balance,int(0)),field(name,fd(1,'Name'))]),
1244 rec([field(balance,int(-1)),field(name,fd(1,'Name'))])|X],
1245 set(record([field(balance,integer),field(name,global('Name'))]))) ,
1246 X = [rec([field(balance,int(1)),field(name,fd(3,'Name'))])] )).
1247
1248 :- assert_must_succeed((not_element_of(X,[(pred_true /* bool_true */,pred_true /* bool_true */),
1249 (pred_true /* bool_true */,pred_false /* bool_false */),(pred_false /* bool_false */,pred_false /* bool_false */)]),
1250 enumerate_tight_type(X,couple(boolean,boolean)))).
1251
1252 :- assert_must_succeed(( not_equal_object(X,(pred_true /* bool_true */,pred_false /* bool_false */)),
1253 not_equal_object(X,(pred_false /* bool_false */,pred_false /* bool_false */)),
1254 not_equal_object(X,(pred_true /* bool_true */,pred_true /* bool_true */)),
1255 enumerate_tight_type(X,couple(boolean,boolean)))).
1256
1257 :- assert_must_succeed(( X = [fd(3,'Name')|T],enumerate_tight_type(X,set(global('Name'))),
1258 T == [fd(1,'Name'),fd(2,'Name')] )).
1259
1260
1261
1262 unbound_value(V) :-
1263 (var(V) -> unbound_variable(V)
1264 ; V = (V1,W1),unbound_value(V1), unbound_value(W1)).
1265
1266 :- use_module(bsyntaxtree,[syntaxtraversion/6]).
1267 enumerate_values_inside_expression(TExpr) :-
1268 syntaxtraversion(TExpr,Expr,Type,_Infos,Subs,_),
1269 nonvar(Expr),!,
1270 enumerate_expr(Expr,Type,Subs).
1271 enumerate_values_inside_expression(X) :-
1272 add_internal_error('Unexpected B expression: ',enumerate_values_inside_expression(X)).
1273
1274 %:- block enumerate_expr(-,?,?).
1275 enumerate_expr(value(X),Type,Subs) :- !,
1276 (ground(Type) -> enumerate_value(X,Type)
1277 ; add_internal_error('Value type not ground: ',enumerate_expr(value(X),Type,Subs))).
1278 enumerate_expr(_,_,Subs) :- l_enumerate_values_inside_expression(Subs).
1279
1280 :- use_module(bsyntaxtree,[is_set_type/2]).
1281 % catch a few type errors:
1282 enumerate_value(X,Type) :- X==[], !,
1283 (is_set_type(Type,_) -> true ; add_internal_error('Illegal type: ',enumerate_value(X,Type))).
1284 enumerate_value(X,Type) :- enumerate_basic_type(X,Type).
1285
1286 :- block l_enumerate_values_inside_expression(-).
1287 l_enumerate_values_inside_expression([]).
1288 l_enumerate_values_inside_expression([H|T]) :-
1289 enumerate_values_inside_expression(H),
1290 l_enumerate_values_inside_expression(T).
1291
1292
1293 /* --------------- */
1294 /* top_level_dif/2 */
1295 /* --------------- */
1296 /* checks whether two terms have a different top-level functor */
1297
1298 :- assert_must_succeed(top_level_dif(a,b)).
1299 :- assert_must_succeed(top_level_dif(f(_X),g(_Z))).
1300 :- assert_must_fail(top_level_dif(f(a),f(_Z))).
1301 :- assert_must_fail(top_level_dif(f(a),f(b))).
1302
1303 :- block top_level_dif(-,?),top_level_dif(?,-).
1304 top_level_dif(X,Y) :-
1305 functor(X,FX,_),functor(Y,FY,_), FX\=FY. /* check arities ? */
1306
1307
1308 /* ------------------------------------------------------------------- */
1309 /* EQUAL OBJECT */
1310 /* ------------------------------------------------------------------- */
1311
1312 sample_closure(C) :-
1313 construct_closure([xx],[integer],Body,C),
1314 Body = b(conjunct(b(conjunct(
1315 b(member(b(identifier(xx),integer,[]),b(integer_set('NAT'),set(identifier(xx)),[])),pred,[]),
1316 b(greater(b(identifier(xx),integer,[]),b(integer(0),integer,[])),pred,[])),pred,[]),
1317 b(less(b(identifier(xx),integer,[]),b(integer(3),integer,[])),pred,[])),pred,[]).
1318
1319 :- assert_must_succeed(equal_object([int(3),int(1)],
1320 closure([zz],[integer],b(member(b(identifier(zz),integer,[]),b(value([int(1),int(3)]),set(integer),[])),pred,[])))).
1321 :- assert_must_succeed(( equal_object( (fd(1,'Name'),fd(1,'Name')) , (fd(1,'Name'),fd(1,'Name')) ) )).
1322 :- assert_must_succeed(( equal_object( (X,Y) , (fd(2,'Name'),fd(2,'Name')) ) , X = fd(2,'Name'), Y=fd(2,'Name') )).
1323 :- assert_must_fail(equal_object(term(a),term(b))).
1324 :- assert_must_fail(equal_object(int(1),int(2))).
1325 :- assert_must_fail(equal_object([term(a),term(b)],[term(a),term(c)])).
1326 :- assert_must_fail((equal_object([(int(1),[Y])],[(int(X),[Z])]),
1327 Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[int(2)])).
1328 :- assert_must_fail(equal_object(rec([field(a,int(1))]),rec([field(a,int(2))]))).
1329 :- assert_must_fail(equal_object(rec([field(a,int(2)),field(b,int(3))]),
1330 rec([field(a,int(2)),field(b,int(4))]))).
1331 :- assert_must_succeed(equal_object(rec([field(a,int(2))]),rec([field(a,int(2))]))).
1332 :- assert_must_succeed(equal_object(rec([field(a,int(2)),field(b,[int(3),int(2)])]),
1333 rec([field(a,int(2)),field(b,[int(2),int(3)])]) )).
1334 :- assert_must_succeed(equal_object([(term(a),[])],[(term(a),[])])).
1335 :- assert_must_succeed(equal_object(_X,[int(1),int(2)])).
1336 :- assert_must_succeed(equal_object([int(1),int(2)],_X)).
1337 :- assert_must_succeed((equal_object([(int(1),[Y])],[(int(X),[Z])]),
1338 Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[])).
1339 :- assert_must_succeed(equal_object([int(1),int(2)],[int(2),int(1)])).
1340 :- assert_must_succeed(equal_object(global_set('Name'),[fd(2,'Name'),fd(3,'Name'),fd(1,'Name')])).
1341 :- assert_must_succeed(equal_object(global_set('Name'),[fd(1,'Name'),fd(3,'Name'),fd(2,'Name')])).
1342 :- assert_must_succeed((equal_object([fd(3,'Name'),fd(2,'Name'),fd(1,'Name')],global_set('Name')))).
1343 %:- assert_must_succeed((equal_object([fd(3,'Name'),fd(2,'Name'),fd(1,'Name')],X),X=global_set('Name'))).
1344 :- assert_must_succeed((equal_object(Y,X),X=global_set('Name'),equal_object(Y,[fd(3,'Name'),fd(2,'Name'),fd(1,'Name')]))).
1345 :- assert_must_succeed((equal_object(X,X),X=global_set('Name'))).
1346 :- assert_must_succeed((equal_object(_,X),X=global_set('Name'))).
1347 :- assert_must_succeed((equal_object(X,global_set('Name')),X=global_set('Name'))).
1348 :- assert_must_succeed((equal_object([_A,_B],[int(2),int(1)]))).
1349 :- assert_must_fail((equal_object(X,global_set('Code')),X=global_set('Name'))).
1350 :- assert_must_fail((equal_object(Y,global_set('Name')),Y=[fd(3,'Name'),fd(1,'Name')])).
1351 :- assert_must_fail((equal_object(Y,global_set('Name')),Y=[_,_])).
1352 :- assert_must_succeed((equal_object(X,closure([xx],[integer],b(truth,pred,[]))),X==closure([xx],[integer],b(truth,pred,[])))).
1353 :- assert_must_succeed((sample_closure(C), equal_object([int(1),int(2)],C))).
1354 :- assert_must_succeed((sample_closure(C), equal_object(C,[int(1),int(2)]))).
1355 :- assert_must_fail((sample_closure(C), equal_object(C,[int(1),int(0)]))).
1356 :- assert_must_fail((sample_closure(C), equal_object(C,global_set('NAT')))).
1357 :- assert_must_succeed((equal_object(freeval(selfcx,a,int(5)),freeval(selfcx,a,int(5))))).
1358 :- assert_must_fail((equal_object([int(1),int(2),int(3)],global_set('NATURAL1')))).
1359 :- assert_must_fail((equal_object(X,global_set('NATURAL1')),equal_object(X,[int(1),int(2),int(3)]))).
1360 :- assert_must_fail((equal_object(X,[int(1),int(2),int(3)]),equal_object(X,global_set('NATURAL1')))).
1361 :- assert_must_fail((equal_object(X,global_set('NATURAL')),equal_object(X,global_set('NATURAL1')))).
1362 :- assert_must_succeed((equal_object(X,global_set('NATURAL')),equal_object(X,global_set('NATURAL')))).
1363 % :- assert_must_fail((equal_object(freeval(selfcx,a,int(5)),freeval(selfcy,a,int(5))))). % is a type error
1364 :- assert_must_fail((equal_object(freeval(selfcx,b,int(5)),freeval(selfcx,a,int(5))))).
1365 :- assert_must_fail((equal_object(freeval(selfcx,a,int(5)),freeval(selfcx,a,int(6))))).
1366 :- assert_must_succeed((equal_object(
1367 [[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')],
1368 [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(3,'Name'),fd(2,'Name')]]
1369 ,[[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')],
1370 [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(2,'Name'),fd(3,'Name')]])
1371 )).
1372 :- assert_must_succeed(exhaustive_kernel_check( (equal_object([int(3),int(2),int(1)],[int(2)|T]),
1373 equal_object(T,[int(1),int(3)])))).
1374 :- assert_must_succeed(exhaustive_kernel_check([commutative],equal_object([int(3),int(1)],[int(1),int(3)]))).
1375 :- assert_must_succeed(exhaustive_kernel_check([commutative],equal_object([int(3),int(4),int(1)],[int(4),int(1),int(3)]))).
1376
1377 %:- assert_must_succeed(exhaustive_kernel_fail_check([commutative],equal_object([int(1),int(2),int(3)],global_set('NATURAL1')))).
1378 :- assert_must_succeed(( equal_object([int(0),int(5)|T],avl_set(node(int(1),true,1,node(int(0),true,0,empty,empty),node(int(3),true,1,empty,node(int(5),true,0,empty,empty))))), nonvar(T),equal_object(T,[int(_A),int(_B)]) )).
1379 % NOTE: had multiple solutions; after solving Ticket #227 it no longer has :-)
1380 :- assert_must_succeed(( equal_object([int(0),int(5)|T],avl_set(node(int(1),true,1,node(int(0),true,0,empty,empty),node(int(3),true,1,empty,node(int(5),true,0,empty,empty))))), nonvar(T),equal_object(T,[_A,_B]) )).
1381
1382 :- assert_must_succeed((equal_object([_X,_Y],[int(1),int(2)]))).
1383 :- assert_must_succeed((equal_object([(int(1),X),(int(2),Y),(int(3),Z),(int(4),A),(int(5),B),(int(6),C),(int(7),D),(int(8),E),(int(9),F),(int(10),G)],avl_set(node((int(5),int(25)),true,0,node((int(2),int(4)),true,1,node((int(1),int(1)),true,0,empty,empty),node((int(3),int(9)),true,1,empty,node((int(4),int(16)),true,0,empty,empty))),node((int(8),int(64)),true,0,node((int(6),int(36)),true,1,empty,node((int(7),int(49)),true,0,empty,empty)),node((int(9),int(81)),true,1,empty,node((int(10),int(100)),true,0,empty,empty)))))),
1384 A == int(16), B == int(25),C == int(36),D == int(49),E == int(64),F == int(81),G == int(100),X == int(1),Y == int(4), Z == int(9))).
1385
1386 :- use_module(bool_pred).
1387
1388 ?equal_object(V1,V2) :- equal_object_wf(V1,V2,no_wf_available).
1389 ?equal_object(V1,V2,Origin) :- equal_object_wf(V1,V2,Origin,no_wf_available).
1390 equal_object_optimized(V1,V2,Origin) :- equal_object_optimized_wf(V1,V2,Origin,no_wf_available).
1391 equal_object_optimized(V1,V2) :- equal_object_optimized(V1,V2,unknown).
1392
1393 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
1394 :- if(environ(prob_safe_mode,true)).
1395 /* a version of equal_object which will convert lists to avl if possible */
1396 equal_object_optimized_wf(V1,V2,Origin,WF) :-
1397 ( var(V1) -> (var(V2) -> V1=V2 ; equal_object_opt3(V2,V1,WF))
1398 ; equal_object_opt3(V1,V2,WF)),
1399 check_value(V1,Origin), check_value(V2,Origin).
1400 equal_object_wf(V1,V2,Origin,WF) :- ( (var(V1);var(V2)) -> V1=V2
1401 ; nonvar(V1) -> equal_object3(V1,V2,WF)
1402 ; equal_object3(V2,V1,WF)),
1403 check_value(V1,val1(Origin)), check_value(V2,val2(Origin)).
1404 equal_object_wf(V1,V2,WF) :- ( (var(V1);var(V2)) -> V1=V2
1405 ; nonvar(V1) -> equal_object3(V1,V2,WF)
1406 ; equal_object3(V2,V1,WF)),
1407 check_value(V1,equal_object1), check_value(V2,equal_object2).
1408 check_value(X,Origin) :- nonvar(X) -> check_value_aux(X,Origin) ; true.
1409 check_value_aux((A,B),Origin) :- !, check_value(A,pair1(Origin)), check_value(B,pair2(Origin)).
1410 check_value_aux([H|T],Origin) :- !, check_value(H,head(Origin)), check_value(T,tail(Origin)).
1411 check_value_aux(avl_set(X),Origin) :- !,
1412 (var(X) -> add_warning(Origin,'Variable avl_set')
1413 ; X=empty -> add_warning(Origin,'Empty avl_set') ; true).
1414 check_value_aux(closure(P,T,B),Origin) :- !,
1415 (ground(P),ground(T),nonvar(B) -> true
1416 ; add_warning(Origin,illegal_closure(P,T,B))).
1417 check_value_aux(_,_Origin).
1418 :- else.
1419 /* a version of equal_object which will convert lists to avl if possible */
1420 equal_object_optimized_wf(V1,V2,_Origin,WF) :-
1421 ? ( var(V1) -> (var(V2) -> V1=V2 ; equal_object_opt3(V2,V1,WF))
1422 ? ; equal_object_opt3(V1,V2,WF)).
1423
1424 ?equal_object_wf(V1,V2,_Origin,WF) :- ( (var(V1);var(V2)) -> V1=V2
1425 ? ; nonvar(V1) -> equal_object3(V1,V2,WF)
1426 ; equal_object3(V2,V1,WF)).
1427 ?equal_object_wf(V1,V2,WF) :- ( (var(V1);var(V2)) -> V1=V2
1428 ? ; nonvar(V1) -> equal_object3(V1,V2,WF)
1429 ; equal_object3(V2,V1,WF)).
1430 :- endif.
1431
1432
1433 equal_object_opt3(int(X),Y,_WF) :- !, Y=int(X).
1434 equal_object_opt3(fd(X,T),Y,_WF) :- !, Y=fd(X,T).
1435 equal_object_opt3(string(X),Y,_WF) :- !, Y=string(X).
1436 equal_object_opt3(pred_false,Y,_WF) :- !, Y=pred_false.
1437 equal_object_opt3(pred_true,Y,_WF) :- !, Y=pred_true.
1438 equal_object_opt3(X,S2,_WF) :- var(S2), %unbound_variable(S2), % is it ok to assing an AVL set in one go ?!
1439 should_be_converted_to_avl_from_lists(X), !, % does a ground(X) check
1440 construct_avl_from_lists(X,S2).
1441 %equal_object_opt3([H|T],S2) :- var(S2),ground(H),ground(T), !, construct_avl_from_lists([H|T],S2).
1442 ?equal_object_opt3(X,Y,WF) :- equal_object3(X,Y,WF).
1443
1444
1445 %%equal_object3c(X,Y) :- if(equal_object3(X,Y),true,
1446 %% (print_message(equal_object3_failed(X,Y)),equal_object3(X,Y),fail)). %%
1447 :- if(environ(prob_safe_mode,true)).
1448 equal_object3(X,Y,_WF) :- (nonvar(Y) -> type_error(X,Y) ; illegal_value(X)),
1449 add_internal_error('Internal Typing Error (please report as bug !) : ',equal_object(X,Y)),fail.
1450 :- endif.
1451 %%equal_object3(X,Y,_WF) :- print(eq(X,Y)),nl,trace,fail.
1452 equal_object3(closure(Par,ParTypes,Clo),Y,WF) :- var(Y),!,
1453 ( closure_occurs_check(Y,Par,ParTypes,Clo)
1454 -> print(occurs_check(Y,Par)),nl,
1455 expand_custom_set(closure(Par,ParTypes,Clo),Expansion),
1456 equal_object_optimized_wf(Y,Expansion,equal_object3,WF)
1457 ; Y = closure(Par,ParTypes,Clo)).
1458 equal_object3(closure(Parameters,PT,Cond),Y,WF) :-
1459 equal_object_custom_explicit_set(closure(Parameters,PT,Cond),Y,WF).
1460 %equal_object3(Obj,Y) :- is_custom_explicit_set(Obj,equal_object3_Obj),
1461 % equal_object_custom_explicit_set(Obj,Y,WF). % inlined below for performance
1462 equal_object3(global_set(X),Y,WF) :- equal_object_custom_explicit_set(global_set(X),Y,WF).
1463 equal_object3(freetype(X),Y,WF) :- equal_object_custom_explicit_set(freetype(X),Y,WF).
1464 ?equal_object3(avl_set(X),Y,WF) :- equal_object_custom_explicit_set(avl_set(X),Y,WF).
1465 equal_object3(pred_true /* bool_true */,pred_true /* bool_true */,_WF).
1466 equal_object3(pred_false /* bool_false */,pred_false /* bool_false */,_WF).
1467 equal_object3(term(X),term(X),_WF).
1468 equal_object3(string(X),string(X),_WF).
1469 equal_object3(rec(F1),rec(F2),_WF) :- equal_fields(F1,F2).
1470 equal_object3(freeval(Id,C,F1),freeval(Id,C,F2),WF) :- equal_object_wf(F1,F2,WF).
1471 equal_object3(int(X),int(X),_WF).
1472 ?equal_object3(fd(X,Type),fd(Y,Type),_WF) :- eq_fd(X,Y).
1473 equal_object3((X,Y),(X2,Y2),WF) :-
1474 ? equal_object_wf(X,X2,WF), equal_object_wf(Y,Y2,WF). % initially order was reversed; but this can lead to issues in e.g. g(f("f2")), for f = {"f0"|->0, "f2"|->2} where g gets called for 0 before "f2"="f0" fails
1475 equal_object3([],X,WF) :- empty_set_wf(X,WF).
1476 ?equal_object3([H|T],S2,WF) :- nonvar(S2), is_custom_explicit_set_nonvar(S2),!,
1477 ? equal_custom_explicit_set_cons_wf(S2,H,T,WF).
1478 %equal_object3([H|T],S2,WF) :- equal_cons_wf(S2,H,T,WF). % leads to time-out for test 1270 : TODO investigate
1479 ?equal_object3([H|T],S2,_WF) :- equal_cons(S2,H,T).
1480
1481
1482 equal_object_custom_explicit_set(Obj,Y,WF) :- % print(eq(Obj,Y)),nl,
1483 ? (var(Y) -> Y = Obj
1484 ? ; (is_custom_explicit_set_nonvar(Y) -> equal_explicit_sets_wf(Obj,Y,WF)
1485 ? ; (Y=[] -> is_empty_explicit_set_wf(Obj,WF)
1486 ? ; Y=[H|T] -> equal_custom_explicit_set_cons_wf(Obj,H,T,WF)
1487 ; add_internal_error('Illegal set: ',equal_object_custom_explicit_set(Obj,Y,WF)),fail
1488 )
1489 )).
1490
1491 equal_custom_explicit_set_cons_wf(CS,H,T,_WF) :- CS \= avl_set(_),
1492 var(H),var(T), % TO DO: should we move this treatment below ? to equal_cons_lwf
1493 % YES, I THINK WE CAN DELETE THIS NOW for avl_sets; but not yet for global_set,...
1494 % print_term_summary(equal_custom_explicit_set_cons(CS,H,T)),nl, (debug_mode(on) -> trace ; true),
1495 unbound_variable(H),
1496 unbound_variable_for_cons(T),
1497 !,
1498 remove_minimum_element_custom_set(CS,Min,NewCS),
1499 %print_term_summary(remove_min(CS,Min,H,T)),nl,
1500 (H,T) = (Min,NewCS).
1501 equal_custom_explicit_set_cons_wf(avl_set(AVL),H,T,_WF) :- var(H),
1502 %frozen(H,VH), print_term_summary(check_unbound(H,VH,T)),nl,
1503 ? is_unbound_ordered_list_skeleton(H,T),!, % TO DO: provide this also for global_set(_)
1504 remove_minimal_elements([H|T],avl_set(AVL),SkeletonToUnify),
1505 %print_term_summary(remove_min(H,T,SkeletonToUnify)),nl,
1506 [H|T] = SkeletonToUnify.
1507 equal_custom_explicit_set_cons_wf(Obj,H,T,WF) :-
1508 %print_term_summary(equal_custom_explicit_set_cons_wf(Obj,H,T)),nl,
1509 %(ground(H) -> true ; H=(H1,_),ground(H1) -> true ; print(unbound(H,T)),nl),
1510 ? equal_cons_lwf(Obj,H,T,2,WF). % equal_cons_wf causes issues to tests 799, 1751, 1642, 1708
1511 %equal_cons(Obj,H,T).
1512 %print_term_summary(after_equal_custom_explicit_set_cons_wf(Obj,H,T)),nl.
1513
1514 :- block equal_fields(-,-).
1515 equal_fields([],[]).
1516 equal_fields([field(Name,V1)|T1],[field(Name,V2)|T2]) :-
1517 equal_object(V1,V2,field),
1518 equal_fields(T1,T2).
1519
1520
1521 % is just like equal_cons, but H and T are guaranteed by the caller to be free
1522 % this just gives one next element of the set; can be used to iterate over sets.
1523 get_next_element(R,H,T) :- var(R),!,R=[H|T].
1524 get_next_element([H1|T1],H,T) :- !,(H1,T1)=(H,T).
1525 get_next_element(R,H,T) :- equal_cons(R,H,T).
1526
1527
1528 equal_cons_wf(R,H,T,WF) :- WF == no_wf_available,!, equal_cons_lwf(R,H,T,2,WF).
1529 equal_cons_wf(R,H,T,WF) :-
1530 %get_cardinality_wait_flag(R,equal_cons_wf,WF,LWF),
1531 %get_binary_choice_wait_flag(equal_cons_wf,WF,LWF), %old version
1532 ? LWF = lwf_card(R,equal_cons_wf,WF), % will be instantiated by instantiate_lwf
1533 ? equal_cons_lwf(R,H,T,LWF,WF).
1534
1535 % a deterministic version; will never instantiate non-deterministically:
1536 % probably better to use equal_cons_wf if possible
1537 %equal_cons_det(R,H,T) :- equal_cons_lwf(R,H,T,_).
1538
1539 equal_cons(R,H,T) :- %print(eq_cons(R,H,T)),nl,
1540 ? equal_cons_lwf(R,H,T,2,no_wf_available). %lwf_first(2)).
1541
1542 :- block blocking_equal_cons_lwf(-,?,?,?,?).
1543 blocking_equal_cons_lwf(E,H,T,LWF,WF) :- equal_cons_lwf(E,H,T,LWF,WF).
1544
1545 equal_cons_lwf(R,H,T,LWF) :- equal_cons_lwf(R,H,T,LWF,no_wf_available).
1546
1547 ?equal_cons_lwf(R,H,T,_,_) :- var(R),!,add_new_el(T,H,R).
1548 equal_cons_lwf([HR|TR],H,T,_,_) :- ground_value(H), delete_exact_member([HR|TR],H,Rest),!,
1549 equal_object(Rest,T,equal_cons_lwf_1).
1550 ?equal_cons_lwf([HR|TR],H,T,LWF,WF) :- !, equal_cons_cons(HR,TR,H,T,LWF,WF).
1551 ?equal_cons_lwf(avl_set(AVL),H,T,LWF,WF) :- !,
1552 ? (is_one_element_custom_set(avl_set(AVL),El)
1553 ? -> empty_set(T), % was T=[], but T could be an empty closure !
1554 ? equal_object(El,H,equal_cons_lwf_2)
1555 ? ; T==[] -> fail % we have a one element set and AVL is not
1556 ? ; element_can_be_added_or_removed_to_avl(H) ->
1557 remove_element_from_explicit_set(avl_set(AVL),H,AR), %print(removed(H)),nl,
1558 equal_object(AR,T,equal_cons_lwf_3)
1559 ? ; nonvar(T),T=[H2|T2],element_can_be_added_or_removed_to_avl(H2) -> %print(removed_next(H2)),nl,
1560 remove_element_from_explicit_set(avl_set(AVL),H2,AR),
1561 equal_object(AR,[H|T2],equal_cons_lwf_4)
1562 % TO DO: move all such H2 to the front ??
1563 % Common pattern for function application patterns f(a) = 1 & f(b) = 2 & f = AVL
1564 % We have f = [(a,1),(b,2)|_] to be unified with an avl_set
1565 % ; at_most_one_match_possible(H,AVL,Pairs) -> Pairs=[H2], % unification could fail if no match found
1566 % % this optimisation is redundant wrt definitely_not_in_list optimisation below; check test 1716
1567 % equal_object_wf(H,H2,WF),
1568 % remove_element_from_explicit_set(avl_set(AVL),H2,AR), print(removed_from_avl_by_equal_cons(H)),nl,
1569 % equal_object(AR,T,equal_cons_lwf_3)
1570 ? ; expand_custom_set(avl_set(AVL),ES), % length(ES,LenES),print(expanded(LenES,T)),nl,
1571 % before attempting unification quickly look if lengths are compatible:
1572 ? quick_check_length_compatible(ES,[H|T]), % not really sure this is worth it: we have propagate_card in equal_cons_cons below
1573 %we could do the following: (nonvar(LWF),LWF=lwf_card(_,_,WF) -> quick_propagation_element_information(avl_set(AVL),H,WF,NS) ; true) % we could also do it for T, but both H/T can cause issues with free_var detection
1574 ? equal_cons_lwf(ES,H,T,LWF,WF) ).
1575 equal_cons_lwf(C,H,T,LWF,WF) :-
1576 is_interval_closure_or_integerset(C,Low,Up),
1577 (T==[] -> true ; finite_bound(Low), finite_bound(Up)),
1578 !, %%print(eq_interval(C,Low,Up)),nl,
1579 equal_cons_interval(H,T,Low,Up,LWF,WF).
1580 equal_cons_lwf(closure(P,Ty,B),H,T,LWF,WF) :- !,
1581 equal_cons_closure(P,Ty,B,H,T,LWF,WF).
1582 equal_cons_lwf(freetype(ID),H,T,LWF,WF) :- !, expand_custom_set(freetype(ID),ES),
1583 blocking_equal_cons_lwf(ES,H,T,LWF,WF).
1584 equal_cons_lwf(global_set(G),H,T,LWF,WF) :- equal_cons_global_set(G,H,T,LWF,WF).
1585
1586 equal_cons_closure(P,Ty,B,_H,T,_LWF,_WF) :-
1587 is_infinite_closure(P,Ty,B),
1588 is_definitely_finite(T),
1589 !,
1590 fail. % an infinite set cannot be equal to a finite one.
1591 equal_cons_closure(P,Ty,B,H,T,LWF,WF) :-
1592 expand_custom_set_wf(closure(P,Ty,B),ES,equal_cons_closure,WF),
1593 blocking_equal_cons_lwf(ES,H,T,LWF,WF).
1594
1595 is_definitely_finite(Var) :- var(Var),!,fail.
1596 is_definitely_finite([]).
1597 is_definitely_finite([_|T]) :- is_definitely_finite(T).
1598 is_definitely_finite(avl_set(_)).
1599
1600 %get_wf_from_lwf(LWF,WF) :- % TO DO: a cleaner, less hacky version; passing WF around if possible
1601 % (nonvar(LWF),LWF=lwf_card(_,_,WF1) -> WF=WF1 ; WF = no_wf_available).
1602
1603 finite_bound(I) :- (var(I) -> true /* inf would be created straightaway */ ; number(I)).
1604
1605 % Purpose: treat some specific closures better; e.g., interval closures and constraint a..b = {1,y,5,x,4} or a..b = {x} & x:100..1002
1606 equal_cons_interval(H,T,Low,Up,_LWF,_WF) :- T==[],!, % Low..Up = {H} -> Low=H & Up=H
1607 % unification will fail if Low or Up are not numbers (inf)
1608 (int(Low),int(Up)) = (H,H).
1609 %equal_cons_interval(_H,_T,Low,Up,_LWF) :- (nonvar(Low),\+ number(Low) ; nonvar(Up),\+ number(Up)),!,
1610 % enum_warning('OPEN INTERVAL',Low:Up,'cannot expand',trigger_throw(equal_cons_interval)),
1611 % % we could try and instantiate T to an infinite closure
1612 % fail.
1613 equal_cons_interval(H,T,Low,Up,LWF,WF) :- % print(equal_cons_interval(H,T,Low,Up)),nl,
1614 (number(Low),number(Up) -> true % we can expand interval fully
1615 ; %print(prop1(H,Low,Up)),nl,trace,
1616 propagate_in_interval([H|T],int(Low),int(Up),0)),
1617 expand_interval_closure_to_avl(Low,Up,ES),
1618 blocking_equal_cons_lwf(ES,H,T,LWF,WF).
1619
1620 :- block propagate_in_interval(-,?,?,?).
1621 propagate_in_interval([],Low,Up,Sze) :- %print(interval_size(Sze,Low,Up)),nl,
1622 (Sze > 0 -> S1 is Sze-1, int_plus(Low,int(S1),Up) ; true). % Test should always be true
1623 propagate_in_interval([H|T],Low,Up,Sze) :- %print(prop(H,Low,Up,tail(T))),nl,trace,
1624 in_nat_range(H,Low,Up), % without enumeration
1625 S1 is Sze+1,
1626 propagate_in_interval(T,Low,Up,S1).
1627 propagate_in_interval(avl_set(_A),_Low,_Up,_). % TO DO: propagate if Low/Up not instantiated
1628 propagate_in_interval(closure(_,_,_),_,_,_).
1629 propagate_in_interval(global_set(_),_,_,_).
1630
1631 quick_check_length_compatible([],R) :- !,
1632 (var(R) -> R=[] % can we force R=[] here ??
1633 ; R \= [_|_]). %(R \= [_|_] -> true ; print(incompatible(R)),fail).
1634 quick_check_length_compatible([_|T],R) :-
1635 (var(R) -> true
1636 ; R = [] -> fail %print(incompatible),nl,fail
1637 ; R = [_|RT] -> quick_check_length_compatible(T,RT)
1638 ; true).
1639
1640 :- block equal_cons_global_set(-,?,?,?,?).
1641 equal_cons_global_set(G,H,T,LWF,WF) :- is_infinite_global_set(G,_),!,
1642 % for maximal sets we could complement_set([H],global(G),Res),
1643 /* should normally fail, unless T is not a list but contains closure or global set */
1644 test_finite_set_wf(T,Finite,WF), dif(Finite,pred_true),
1645 when((nonvar(Finite);nonvar(LWF)),equal_cons_global_set_warning(LWF,G,H,T)).
1646 % used to be : expand_custom_set(global_set(G),ES), equal_cons_lwf(ES,H,T,LWF))).
1647 equal_cons_global_set(G,H,T,LWF,WF) :-
1648 %(is_infinite_global_set(G,_) -> test_finite_set_wf(T,Finite,WF), Finite \== pred_true ; true),
1649 expand_custom_set(global_set(G),ES), equal_cons_lwf(ES,H,T,LWF,WF).
1650
1651
1652 :- block equal_cons_global_set_warning(-,?,?,?).
1653 equal_cons_global_set_warning(_,G,H,T) :-
1654 add_new_event_in_error_scope(enumeration_warning(enumerating(G),G,'{}',finite,critical),
1655 print_equal_cons_warning(G,H,T)),
1656 fail. % WITH NEW SEMANTICS OF ENUMERATION WARNING WE SHOULD PROBABLY ALWAYS FAIL HERE !
1657
1658 print_equal_cons_warning(G,H,T,THROWING,Span) :-
1659 print('### Enumeration Warning: trying to deconstruct infinite set: '),
1660 translate:print_bvalue(global_set(G)),nl,
1661 print('### Source: '), print(equal_cons_global_set(G,H,T)),nl,
1662 print_throwing(THROWING,Span).
1663
1664 add_new_el(T,H,R) :- var(T),!,R=[H|T].
1665 add_new_el(T,H,R) :- nonvar(T), is_custom_explicit_set_nonvar(T),
1666 add_element_to_explicit_set(T,H,Res), % will fail for closure/3
1667 !,
1668 Res=R.
1669 add_new_el([HT|TT],H,R) :- !,R=[H,HT|TT].
1670 ?add_new_el([],H,R) :- !, R=[H].
1671 add_new_el(Set,H,R) :- expand_custom_set_to_list(Set,ESet,_,add_new_el),
1672 add_new_el(ESet,H,R).
1673
1674 delete_exact_member(V,_,_) :- var(V),!,fail.
1675 delete_exact_member([H|T],El,Res) :-
1676 (H==El -> Res=T
1677 ; Res=[H|TR], delete_exact_member(T,El,TR)).
1678
1679
1680 %var_list(V) :- var(V),!,unbound_variable(V).
1681 %var_list([]).
1682 %var_list([H|T]) :- unbound_variable(H),var_list(T).
1683
1684 %unbound_variable(V) :- !, unbound_variable_check(V).
1685 ?unbound_variable(V) :- free_var(V), frozen(V,Residue),
1686 ? unbound_residue(Residue,V).
1687 %(unbound_residue(Residue,V) -> true ; print(bound_var(V,Residue)),nl,trace,unbound_residue(Residue,V),fail).
1688 unbound_residue(external_functions:to_string_aux(GrV,_Val,Str),V) :- !, %GrV checks for groundness of _Val
1689 V==GrV,unbound_variable(Str).
1690 unbound_residue(external_functions:format_to_string_aux(GrV,_Format,_Val,Str),V) :- !, %GrV checks for groundness of _Val
1691 V==GrV,unbound_variable(Str).
1692 % TO DO: we need to detect other functions (e.g., B function application,...) which result in values which are not used
1693 ?unbound_residue(kernel_tools:ground_value_check(V1,V2),V) :- !, V1==V, unbound_variable(V2).
1694 ?unbound_residue((A,B),V) :- !,unbound_residue(A,V), unbound_residue(B,V).
1695 ?unbound_residue(Residue,_) :- unbound_residue(Residue).
1696
1697 unbound_residue(true).
1698 unbound_residue(kernel_objects:mark_as_to_be_computed(_)).
1699 ?unbound_residue(kernel_tools:ground_value_check_aux(_,_,V)) :- unbound_variable(V).
1700 unbound_residue(custom_explicit_sets:block_copy_waitflag_store(_,_,_,_,_)). % this stems from checking the domain predicate of function application check_element_of_function_closure
1701 %unbound_residue(kernel_objects:ordered_value(V,_)). % <-- TO DO: treat this and then assign minimal value !
1702 %unbound_residue(kernel_ordering:ordered_value2(V,_)).
1703 %unbound_residue(U) :- print(unbound(U)),nl,fail.
1704
1705 % check if we have an unbound list_skeleton with optionally just ordering constraints
1706 % check if it is safe to assign H minimal value
1707 % TO DO: also accept if all elements have the same co-routines constraints attached (e.g., because of +-> check)
1708 is_unbound_ordered_list_skeleton(H,T) :-
1709 ? is_unbound_ordered_list_skeleton3(H,T,[allow_ordered_values]).
1710 is_unbound_list_skeleton(H,T) :-
1711 is_unbound_ordered_list_skeleton3(H,T,[]).
1712
1713 is_unbound_ordered_list_skeleton(H,T,Ordered) :-
1714 is_unbound_ordered_list_skeleton3(H,T,List),
1715 % if List gets instantiated it will become [allow_ordered_values|_]
1716 (var(List) -> Ordered=unordered ; Ordered=ordered).
1717
1718 is_unbound_ordered_list_skeleton3(H,T,Options) :- % print(chk_is_unbound_ordered_list_skeleton(H,T)),nl,
1719 ? free_var(H),
1720 ? (var(T) -> unbound_variable(H),
1721 unbound_ordered_tail(T,Options) % or ? unbound_variable_for_cons(T)
1722 ? ; T = [H2|T2],
1723 ? unbound_variable_or_ordered(H,'$$',H2,T,Options),
1724 ? is_unbound_ordered_list_skeleton5(H,H2,T2,[H|T],Options)).
1725 is_unbound_ordered_list_skeleton5(Prev,H,T,All,Options) :-
1726 ? free_var(H),
1727 ? (var(T) -> unbound_variable_or_ordered(H,Prev,'$$',All,Options),
1728 unbound_ordered_tail(T,Options)
1729 ? ; T==[] -> unbound_variable_or_ordered(H,Prev,'$$',All,Options)
1730 ? ; T = [H2|T2],
1731 ? unbound_variable_or_ordered(H,Prev,H2,All,Options),
1732 ? is_unbound_ordered_list_skeleton5(H,H2,T2,All,Options)).
1733
1734 % utility: if is_unbound_ordered_list_skeleton is true, extract for every element in the list one minimal element from CS
1735 remove_minimal_elements(T,CS,Res) :- var(T),!,Res=CS.
1736 remove_minimal_elements([],CS,Res) :- !, empty_set(CS),Res=[].
1737 remove_minimal_elements([_H|T],CS,[Min|Rest]) :-
1738 remove_minimum_element_custom_set(CS,Min,NewCS), % _H will be unified in one go with Min later
1739 remove_minimal_elements(T,NewCS,Rest).
1740
1741 % it is unbound or can be assigned the minimal value of a set
1742 % TO DO: merge with var_list_just_card_constraints
1743 unbound_variable_or_ordered(V,Prev,Nxt,All,Options) :-
1744 ? free_var(V), frozen(V,Residue), %print(residue(Residue,Prev,Nxt)),nl,
1745 ? unbound_ord_residue_aux(Residue,Prev,V,Nxt,All,Options).% , print(ok),nl.
1746 unbound_ord_residue_aux(true,_Prev,_,_Nxt,_All,_Options).
1747 unbound_ord_residue_aux(kernel_objects:mark_as_to_be_computed(_),_,_,_,_,_).
1748 ?unbound_ord_residue_aux(kernel_tools:ground_value_check(_,V),_,_,_,_,_) :- unbound_variable(V).
1749 unbound_ord_residue_aux(kernel_tools:ground_value_check_aux(_,_,V),_,_,_,_,_) :- unbound_variable(V).
1750 unbound_ord_residue_aux(bsets_clp:check_index(V2,_),_,V,_,_,_) :- V2==V. % assumes all index elements in the sequence are being checked; this is the case
1751 unbound_ord_residue_aux(kernel_objects:ordered_value(A,B),Prev,V,Nxt,_,Options) :- % there is also a bsets_clp version
1752 ((A,B)==(Prev,V) ; (A,B)==(V,Nxt)),
1753 (member(allow_ordered_values,Options) -> true).
1754 unbound_ord_residue_aux(kernel_objects:not_equal_object_wf(A,B,_),_,V,_,All,_) :-
1755 (A==V -> exact_member_in_skel(B,All) ; B==V, exact_member_in_skel(A,All)). % all diff constraint; e.g., set up by not_element_of_wf(H,SoFar,WF) in cardinality_as_int2; anyway: all elements in a list must be different
1756 unbound_ord_residue_aux(kernel_objects:not_element_of_wf1(Set,Val,_),_,V,_,All,_) :- Val==V,
1757 open_tail(All,Tail), Tail==Set. % ditto, again just stating that Values are distinct in the list
1758 ?unbound_ord_residue_aux((A,B),Prev,V,Nxt,All,Options) :- !,
1759 ? unbound_ord_residue_aux(A,Prev,V,Nxt,All,Options),
1760 ? unbound_ord_residue_aux(B,Prev,V,Nxt,All,Options).
1761 %unbound_ord_residue_aux(A,Prev,V,Nxt,All) :-
1762 % print(unbound_ord_residue_aux(A,Prev,V,Nxt,All)),nl,fail.
1763
1764 % get tail of an open list:
1765 open_tail(X,Res) :- var(X),!,Res=X.
1766 open_tail([_|T],Res) :- open_tail(T,Res).
1767 % exact member in a possibly open list:
1768 exact_member_in_skel(X,List) :- nonvar(List), List=[Y|T],
1769 (X==Y -> true ; exact_member_in_skel(X,T)).
1770
1771
1772 unbound_ordered_tail(T,Options) :- free_var(T), frozen(T,Residue),
1773 unbound_ordered_tail_aux(Residue,T,Options).
1774 unbound_ordered_tail_aux(true,_,_).
1775 unbound_ordered_tail_aux(kernel_objects:propagate_card(A,B,_Eq),V,_) :-
1776 (V==A ; V==B). % just specifies A and B have same cardinality
1777 unbound_ordered_tail_aux(prolog:dif(X,Y),V,_) :- (V==X,Y==[] ; V==Y,X==[]).
1778 unbound_ordered_tail_aux(kernel_objects:lazy_ordered_value(W,_),T,Options) :-
1779 W==T, %% difference with just_cardinality_constraints
1780 (member(allow_ordered_values,Options)->true).
1781 unbound_ordered_tail_aux(bsets_clp:propagate_empty_set(_,_),_,_).
1782 unbound_ordered_tail_aux(kernel_objects:prop_non_empty(_,W,_),T,_) :- W==T.
1783 unbound_ordered_tail_aux(kernel_objects:cardinality_as_int2(W,_,_,_,_,_),T,_) :- W==T.
1784 unbound_ordered_tail_aux(kernel_objects:cardinality3(W,_,_),Var,_) :- W==Var.
1785 unbound_ordered_tail_aux((A,B),T,Options) :-
1786 (unbound_ordered_tail_aux(A,T,Options) -> true ; unbound_ordered_tail_aux(B,T,Options)).
1787
1788 % co-routine used to mark certain values as to be computed; avoid instantiating them
1789 :- block mark_as_to_be_computed(-).
1790 mark_as_to_be_computed(_).
1791
1792 is_marked_to_be_computed(X) :- var(X),frozen(X,G), %nl,print(check_frozen(X,G)),nl,
1793 marked_aux(G,X).
1794 marked_aux((A,B),V) :- (marked_aux(A,V) -> true ; marked_aux(B,V)).
1795 marked_aux(kernel_objects:mark_as_to_be_computed(M),V) :- V==M.
1796
1797 :- public unbound_variable_check/1.
1798 % currently not used; but can be useful for debugging
1799 unbound_variable_check(V) :- free_var(V), % check no bool_pred attributes
1800 (frozen(V,Goal), Goal\=true
1801 -> nl,print('### WARNING: goal attached to unbound variable expression'),nl,print(V:Goal),nl, %trace,
1802 fail
1803 ; true).
1804
1805 % check if a variable is unbound or only dif(_,[]) attached; we do not need to check for bool_pred attributes as we have a set
1806 unbound_variable_for_cons(Set) :- var(Set),frozen(Set,F), % print(f(Set,F)),nl,
1807 \+ contains_problematic_coroutine_for_cons(F,Set). % for equal cons we can allow more co-routines than when we want to freely determine a value in enumeration; the head of the list is unbound
1808
1809 % prolog:dif(X,Y) with Y == [] is ok
1810 contains_problematic_coroutine_for_cons(custom_explicit_sets:element_of_avl_set_wf3(Var,_,_,_,_),V) :- V==Var. % occurs in test 1270
1811 contains_problematic_coroutine_for_cons(kernel_objects:non_free(_),_). % has been marked as non-free
1812 contains_problematic_coroutine_for_cons(kernel_objects:mark_as_to_be_computed(_),_). % has been marked to be computed by closure expansion
1813 contains_problematic_coroutine_for_cons((A,B),Var) :-
1814 ? (contains_problematic_coroutine_for_cons(A,Var) -> true
1815 ; contains_problematic_coroutine_for_cons(B,Var)).
1816
1817
1818 unbound_variable_for_card(Set) :- % when do we allow card to instantiate a list skeleton
1819 preference(data_validation_mode,true),
1820 !,
1821 unbound_variable(Set).
1822 unbound_variable_for_card(Set) :- unbound_variable_for_cons(Set).
1823
1824 unbound_variable_for_element_of(Set) :- unbound_variable_for_cons(Set).
1825
1826
1827 % handling equal_object for [HR|TR] = [H|T]
1828
1829 equal_cons_cons(HR,TR,H,T,_LWF,WF) :- TR==[],!,
1830 empty_set_wf(T,WF), % was T=[], but T could be an empty closure
1831 equal_object_wf(HR,H,equal_cons_cons_1,WF).
1832 equal_cons_cons(HR,TR,H,T,_LWF,WF) :- T==[],!,
1833 empty_set_wf(TR,WF), % was TR=[], but TR could be an empty closure
1834 equal_object_wf(HR,H,equal_cons_cons_2,WF).
1835 equal_cons_cons(HR,TR,H,T,_LWF,WF) :-
1836 %(is_unbound_list_skeleton(H,T) -> true ; is_unbound_list_skeleton(HR,TR)),
1837 (is_unbound_ordered_list_skeleton(H,T,Ordered)
1838 -> %print(ord(Ordered)),nl,
1839 (Ordered = unordered -> true
1840 ; is_unbound_ordered_list_skeleton(HR,TR))
1841 ; is_unbound_list_skeleton(HR,TR)),
1842 % if both are ordered: then the first elements must be equal,
1843 % if one or both are not ordered: the unification HR=H is only ok if the other is unbound
1844 % beware of tests 1078 and 1101 when allowing ordered lists
1845 !, % print(eq_var_cons(HR,TR,H,T)),nl,
1846 % HR is variable: no constraints/co-routines attached to it; no other element in TR is constrained either
1847 %(HR,TR)=(H,T). %fails, e.g., if TR=[] and T= empty closure !
1848 %print((HR,H,TR,T)),nl,
1849 % at the moment : unbound_check does not allow ordered set skeletons
1850 HR=H, equal_object_wf(TR,T,equal_cons_cons3,WF).
1851 equal_cons_cons(HR,TR,H,T,LWF,WF) :-
1852 % here we use LWF for the first time
1853 %(number(LWF) -> LWF2=LWF ; true),
1854 % print(equality_objects_lwf(HR,H,EqRes,LWF2)),nl,
1855 ? equality_objects_lwf(HR,H,EqRes,LWF2),
1856 % print(equal_cons2(EqRes,HR,TR,H,T,LWF2)),nl,
1857 ? (var(EqRes),
1858 ? ( definitely_not_in_list(TR,H) % maybe we should also check
1859 ; definitely_not_in_list(T,HR) )
1860 -> %print(notin(TR,H,or,T,HR)),nl,
1861 ? EqRes=pred_true % H cannot appear in TR; it must match HR
1862 ; true),
1863 ? instantiate_lwf(LWF,LWF2), % instantiate later to ensure var(EqRes) can hold if LWF already bound
1864 ? equal_cons2(EqRes,HR,TR,H,T,LWF2,WF),
1865 propagate_card(TR,T,EqRes). % prevents tail recursion; move earlier/remove if EqRes nonvar?
1866 %,instantiate_lwf(LWF,LWF2) % we could instantiate LWF2 later here to give propagate_card a chance to figure out value of EqRes first ? this slows down examples/B/Alstom/CompilatonProject/Regles/Rule_DB_Route_0001ori.his
1867
1868
1869 % this will instantiate LWF if it has not yet been computed
1870 % (Idea: get_cardinality_wait_flag can be expensive; only do it if we really need the wait_flag)
1871 instantiate_lwf(LWF,R) :- var(LWF),!,R=LWF.
1872 instantiate_lwf(lwf_card(Set,Info,WF),LWF) :- !, % TO DO: in prob_data_validation_mode: increase or get_last_waitflag
1873 get_cardinality_wait_flag(Set,Info,WF,LWF).
1874 %% get_cardinality_powset_wait_flag(Set,Info,WF,_,LWF).
1875 %instantiate_lwf(lwf_first(X),R) :- !, R=X.
1876 instantiate_lwf(LWF,LWF).
1877
1878 :- block equal_cons2(-,?,?,?,?,?,?).
1879 ?equal_cons2(pred_true,_HR,TR,_H,T,_,WF) :- equal_object_wf(TR,T,equal_cons2,WF).
1880 equal_cons2(pred_false,HR,TR, H,T,LWF,WF) :- % print(eq_cons2_neq(HR,TR,H,T)),nl,
1881 % print(equal_cons_lwf(T,HR,TR2,LWF)),nl,
1882 ? equal_cons_lwf(T,HR,TR2,LWF,WF), % look for HR inside T
1883 % print(res(T,HR,TR2,LWF)),nl,
1884 ? T2=TR2,
1885 ? equal_cons_lwf(TR,H,T2,LWF,WF). %, was instead of T2=TR2: equal_object(TR2,T2).
1886
1887 :- use_module(kernel_tools,[cannot_match/2]).
1888 % TO DO: investigate whether we should not use kernel_equality or at least a blocking version
1889 definitely_not_in_list(V,_) :- var(V),!,fail.
1890 definitely_not_in_list([],_).
1891 definitely_not_in_list([H|T],X) :- cannot_match(H,X), definitely_not_in_list(T,X).
1892
1893
1894 :- block propagate_card(-,-,-).
1895 propagate_card(X,Y,EqRes) :-
1896 (nonvar(EqRes) -> true % we no longer need to propagate; equal_cons will traverse
1897 ; nonvar(X) -> propagate_card2(X,Y,EqRes)
1898 ; propagate_card2(Y,X,EqRes)).
1899 propagate_card2([],Y,_) :- !,empty_set(Y).
1900 propagate_card2([_|TX],Y,EqRes) :- !,
1901 (var(Y) -> Y= [_|TY], propagate_card(TX,TY,EqRes)
1902 ; Y=[] -> fail
1903 ; Y=[_|TY] -> propagate_card(TX,TY,EqRes)
1904 ; true
1905 ). % TO DO: add more propagation
1906 propagate_card2(_,_,_).
1907
1908 %same_card_and_expand(A,B,ExpA,ExpB) :- .... + reorder ??
1909
1910 :- if(environ(prob_safe_mode,true)).
1911 % CODE FOR CHECKING FOR TYPE ERRORS AT RUNTIME
1912 :- assert_must_succeed(type_error([],int(1))).
1913 :- assert_must_succeed(type_error((int(1),int(2)),[pred_true])).
1914 :- assert_must_succeed(type_error(string('Name'),global_set('Name'))).
1915 :- assert_must_fail((type_error([],[_]))).
1916 type_error([],Y) :- no_set_type_error(Y).
1917 type_error([_|_],Y) :- no_set_type_error(Y).
1918 %type_error(X,Y) :- is_custom_explicit_set(X,type_error1), no_set_type_error(Y).
1919 type_error(avl_set(A),Y) :- illegal_avl_set(A) -> true ; no_set_type_error(Y).
1920 type_error(global_set(_),Y) :- no_set_type_error(Y).
1921 type_error(freetype(_),Y) :- no_set_type_error(Y).
1922 type_error(closure(P,_,B),Y) :-
1923 (var(P) -> true ; var(B) -> true ; P=[] -> true ; P=[P1|_], var(P1) -> true ; no_set_type_error(Y)).
1924 type_error((_,_),Y) :- Y \= (_,_).
1925 type_error(fd(_,T1),Y) :- (Y= fd(_,T2) -> nonvar(T1),nonvar(T2),T1 \=T2 ; true).
1926 type_error(int(_),Y) :- Y\= int(_).
1927 type_error(term(_),Y) :- Y\= term(_).
1928 type_error(rec(_),Y) :- Y \= rec(_).
1929 type_error(freeval(ID,_,_),Y) :- Y \= freeval(ID,_,_).
1930 type_error(string(_),Y) :- Y \= string(_).
1931 % Should raise type error: kernel_objects:union([int(1)],[[]],R).
1932
1933 illegal_value(X) :- var(X),!,fail.
1934 illegal_value(avl_set(A)) :- illegal_avl_set(A).
1935 illegal_value([H|T]) :- illegal_value(H) -> true ; illegal_value(T).
1936 illegal_value(global_set(G)) :- \+ ground(G).
1937 illegal_value(N) :- number(N).
1938 illegal_value((A,B)) :- illegal_value(A) -> true ; illegal_value(B).
1939 % TO DO: complete this
1940
1941 illegal_avl_set(X) :- var(X),!.
1942 illegal_avl_set(empty).
1943 illegal_avl_set(X) :- (X=node(_,_,_,_,_) -> \+ ground(X) ; true).
1944
1945 no_set_type_error(int(_)).
1946 no_set_type_error(fd(_,_)).
1947 no_set_type_error((_,_)).
1948 no_set_type_error(rec(_)).
1949 no_set_type_error(pred_true /* bool_true */).
1950 no_set_type_error(pred_false /* bool_false */).
1951 no_set_type_error(term(_)).
1952 no_set_type_error(string(_)).
1953 no_set_type_error(freeval(_,_,_)).
1954 no_set_type_error(avl_set(A)) :- illegal_avl_set(A).
1955 %% END OF CHECKING CODE
1956 :- endif.
1957
1958
1959 :- assert_must_succeed(not_equal_object(term(a),term(b))).
1960 :- assert_must_succeed(not_equal_object(string('a'),string('b'))).
1961 :- assert_must_succeed(not_equal_object(int(1),int(2))).
1962 :- assert_must_succeed(not_equal_object(rec([field(a,int(1))]),rec([field(a,int(2))]))).
1963 :- assert_must_succeed(not_equal_object(rec([field(a,int(1)),field(b,int(2))]),
1964 rec([field(a,int(1)),field(b,int(3))]))).
1965 :- assert_must_fail(not_equal_object(rec([field(a,int(1))]),rec([field(a,int(1))]))).
1966 :- assert_must_fail(not_equal_object(rec([field(a,int(1)),field(b,int(2))]),
1967 rec([field(a,int(1)),field(b,int(2))]))).
1968 :- assert_must_fail(not_equal_object(term(msg),int(2))).
1969 :- assert_must_fail(not_equal_object(fd(1,a),term(msg))).
1970 :- assert_must_succeed(not_equal_object(global_set(a),global_set(b))).
1971 :- assert_must_succeed(not_equal_object([term(a),term(b)],[term(a),term(c)])).
1972 :- assert_must_succeed((not_equal_object([(int(1),[Y])],[(int(X),[Z])]),
1973 Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[int(2)])).
1974 :- assert_must_succeed(not_equal_object((int(1),int(2)),(int(3),int(4)))).
1975 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_equal_object((int(1),int(2)),(int(1),int(4))))).
1976 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_equal_object((int(1),int(4)),(int(3),int(4))))).
1977 :- assert_must_fail(not_equal_object((int(1),int(4)),(int(1),int(4)))).
1978 :- assert_must_succeed(not_equal_object((int(1),string('a')),(int(1),string('b')))).
1979 :- assert_must_fail(not_equal_object((int(1),string('b')),(int(1),string('b')))).
1980 :- assert_must_fail(not_equal_object([(term(a),[])],[(term(a),[])])).
1981 :- assert_must_fail((not_equal_object([(int(1),[Y])],[(int(X),[Z])]),
1982 Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[])).
1983 :- assert_must_fail(not_equal_object([int(1),int(2)],[int(2),int(1)])).
1984 :- assert_must_succeed(not_equal_object(term(msg),term(another_msg))).
1985 :- assert_must_succeed(not_equal_object([int(1),int(2)],[int(0),int(4)])).
1986 :- assert_must_fail((sample_closure(C),
1987 not_equal_object(C,[int(1),int(2)]))).
1988 :- assert_must_succeed((sample_closure(C),
1989 not_equal_object(C,[int(1),int(0)]))).
1990 :- assert_must_succeed((sample_closure(C),
1991 not_equal_object(C,global_set('NAT')))).
1992 :- assert_must_fail((not_equal_object(
1993 [[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')],
1994 [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(3,'Name'),fd(2,'Name')]]
1995 ,[[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')],
1996 [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(2,'Name'),fd(3,'Name')]])
1997 )).
1998 :- assert_must_fail((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,a,int(2))))).
1999 :- assert_must_succeed((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,a,int(3))))).
2000 :- assert_must_succeed((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,b,int(2))))).
2001 :- assert_must_succeed((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,a,int(3))))).
2002
2003 :- assert_must_succeed((not_equal_object(pred_true /* bool_true */,X), X==pred_false /* bool_false */)).
2004 :- assert_must_succeed((not_equal_object([],X),X=[_|_])).
2005 %:- assert_must_succeed((not_equal_object([],X), nonvar(X),X=[_|_])).
2006 :- assert_must_succeed((not_equal_object(X,[]), X=[_|_])).
2007 :- assert_must_succeed((not_equal_object(X,pred_false /* bool_false */), X==pred_true /* bool_true */)).
2008
2009 :- assert_must_succeed(not_equal_object([_X],[int(1),int(3)])). % Inefficiency example of setlog
2010 :- assert_must_succeed_any(not_equal_object([_X],[int(1)])). % Inefficiency example of setlog
2011 :- assert_must_succeed((not_equal_object([X],[pred_true /* bool_true */]),X==pred_false /* bool_false */)).
2012 :- assert_must_succeed((not_equal_object([pred_true /* bool_true */],[X]),X==pred_false /* bool_false */)).
2013 :- assert_must_succeed((not_equal_object([[X]],[[pred_true /* bool_true */]]),X==pred_false /* bool_false */)).
2014 :- assert_must_succeed((not_equal_object([[pred_true /* bool_true */]],[[X]]),X==pred_false /* bool_false */)).
2015 :- assert_must_succeed((custom_explicit_sets:construct_one_element_custom_set(pred_true /* bool_true */, A), kernel_objects:not_equal_object(A,[X]), X==pred_false /* bool_false */)).
2016 :- assert_must_succeed((custom_explicit_sets:construct_one_element_custom_set(pred_true /* bool_true */,A), kernel_objects:not_equal_object([X],A), X==pred_false /* bool_false */)).
2017 :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([],[int(3333)]))).
2018 :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([],[int(2),int(1),int(3)]))).
2019 :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([int(3)],[int(2),int(1),int(3)]))).
2020 :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([int(3),int(1),int(4)],[int(2),int(1),int(3)]))).
2021 :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([int(2),int(1),int(3),int(5)],[int(2),int(1),int(3)]))).
2022 % X in 3..4, kernel_objects:not_equal_object([int(2),int(3)],[int(2),int(X)]), X==4. in clpfd Mode
2023
2024
2025
2026 :- block not_equal_object_wf(-,-,?).
2027 /* TO DO: implement a better _wf version ; use bool_dif if possible */
2028 % block is relevant for tests 1374, 1737
2029 ?not_equal_object_wf(X,Y,WF) :- X\==Y, (var(X) -> not_equal_object_wf1(Y,X,WF)
2030 ? ; not_equal_object_wf1(X,Y,WF)).
2031
2032 not_equal_object_wf1([],R,WF) :- !, not_empty_set_wf(R,WF).
2033 not_equal_object_wf1(R,E,WF) :- E==[],!, not_empty_set_wf(R,WF).
2034 ?not_equal_object_wf1(X,Y,_) :- not_equal_object2(X,Y).
2035
2036 not_equal_object(X,Y) :-
2037 (nonvar(X) -> not_equal_object2(X,Y)
2038 ; nonvar(Y) -> not_equal_object2(Y,X)
2039 ; X\==Y, when((?=(X,Y);nonvar(X);nonvar(Y)), not_equal_object0(X,Y))).
2040
2041 not_equal_object0(X,Y) :- X\==Y,(var(X) -> not_equal_object2(Y,X)
2042 ; not_equal_object2(X,Y)).
2043
2044 %not_equal_object2(X,Y) :- print(not_equal_object2(X,Y)),nl,fail.
2045 not_equal_object2(pred_true /* bool_true */,R) :- !, R=pred_false /* bool_false */.
2046 not_equal_object2(pred_false /* bool_false */,R) :- !, R=pred_true /* bool_true */.
2047 not_equal_object2(fd(X,Type),R) :- !, get_global_type_value(R,Type,Y), % also sets up FD range for Y if R was var
2048 neq_fd(X,Y,Type).
2049 ?not_equal_object2(int(X),R) :- !, R=int(Y), integer_dif(X,Y).
2050 not_equal_object2(string(X),R) :- !, R=string(Y), dif(X,Y).
2051 not_equal_object2(term(X),R) :- !, R=term(Y), dif(X,Y).
2052 not_equal_object2(rec(F1),R) :- !, R=rec(F2),
2053 not_equal_fields(F1,F2).
2054 %not_equal_object2([],R) :- var(R),!, print(not_empty(R)),nl,R=[_|_]. % Dangerous for equal_object: we generate a non-enumerated variable !
2055 not_equal_object2((X1,X2),R) :- !, R=(Y1,Y2),
2056 not_equal_couple(X1,Y1,X2,Y2).
2057 not_equal_object2(X,Y) :- is_custom_explicit_set(X,not_equal_object2),!,
2058 % print(not_equal_object2(X,Y)),nl, % uncovered case; for efficiency better explicitly written above
2059 not_equal_explicit_set(X,Y).
2060 not_equal_object2(X,Y) :- not_equal_object3(X,Y).
2061
2062
2063 :- block not_equal_explicit_set(?,-).
2064 not_equal_explicit_set(X,Y) :-
2065 is_custom_explicit_set_nonvar(Y),!,
2066 % print(not_equal_explicit_sets(X,Y)),nl,
2067 not_equal_explicit_sets(X,Y).
2068 not_equal_explicit_set(X,[]) :- !, %print(check_non_empty(X)),nl,
2069 is_non_empty_explicit_set(X).
2070 not_equal_explicit_set(X,Y) :- % print_term_summary(expanding(X)),
2071 expand_custom_set(X,EX), not_equal_object3_block(EX,Y).
2072
2073 :- block not_equal_object3_block(-,?).
2074 not_equal_object3_block(EX,Y) :- not_equal_object3(EX,Y).
2075
2076 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
2077 :- block not_equal_object3(?,-).
2078 :- if(environ(prob_safe_mode,true)).
2079 not_equal_object3(X,Y) :- nonvar(X),type_error(X,Y),
2080 add_internal_error('Internal Typing Error (please report as bug !) : ',not_equal_object(X,Y)),
2081 fail.
2082 :- endif.
2083 not_equal_object3(freeval(ID,Case1,Value1),freeval(ID,Case2,Value2)) :-
2084 when(?=(Case1,Case2), % we first have to be able to decide the case; if cases are different types of values may be different
2085 not_equal_freeval(Case1,Value1,Case2,Value2)).
2086 not_equal_object3([],X) :- not_empty_set(X).
2087 not_equal_object3([H|T],Set2) :-
2088 (Set2=[] -> true
2089 ; cardinality_peano_wf([H|T],N1,no_wf_available),
2090 cardinality_peano_wf(Set2,N2,no_wf_available),
2091 when(?=(N1,N2), % when we trigger code below, = can be decided:
2092 (N1=N2 -> neq_cons(Set2,H,T) ; true))).
2093 % (dif(N1,N2) ; (N1=N2, neq_cons(Set2,H,T)))). %not_equal_object_sets(Set1,Set2) )) ).
2094
2095 not_equal_freeval(Case1,Value1,Case2,Value2) :-
2096 (Case1=Case2 -> not_equal_object(Value1,Value2) ; true).
2097
2098 :- block not_equal_object_sets(-,?), not_equal_object_sets(?,-).
2099 not_equal_object_sets([H|T],Set2) :- !,
2100 ( Set2=[H2|_T2]
2101 -> not_equal_object_sets2(H,T,H2,Set2)
2102 ; Set2=[] -> true
2103 ; not_equal_object2(Set2,[H|T]) % avl_set probably
2104 ).
2105 not_equal_object_sets(Set1,Set2) :- % Note : if Set1 =[] then we can fail, as both sets have same length
2106 % we could have empty set or avl_set can sometimes creep into end of lists
2107 not_equal_object2(Set1,Set2).
2108
2109 :- block not_equal_object_sets2(-,?,?,?), not_equal_object_sets2(?,?,-,?).
2110 not_equal_object_sets2(H,_T,_H2,Set2) :-
2111 % TO DO: should we not use kernel_equality:membership_test_wf here ??
2112 not_element_of(H,Set2).
2113 not_equal_object_sets2(H,T,_H2,Set2) :-
2114 remove_element(H,Set2,Del2), %print_message(rem(H,Set2,Del2)),
2115 not_equal_object(T,Del2).
2116
2117
2118 :- block neq_cons(-,?,?).
2119 %neq_cons(X,Y,Z) :- print(neq_cons(X,Y,Z)),nl,fail.
2120 neq_cons([],_,_) :- !.
2121 neq_cons([H2|T2],H1,T1) :- !,
2122 (T2==[],T1==[]
2123 -> not_equal_object(H1,H2)
2124 ; check_and_remove([H2|T2],H1,NewSet2,RemoveSuccesful),
2125 % print(removed(H1,H2,T2,NewSet2,RemoveSuccesful)),
2126 neq_cons2(RemoveSuccesful,T1,NewSet2)
2127 ).
2128 neq_cons(avl_set(A),H1,T1) :- element_can_be_added_or_removed_to_avl(H1),!,
2129 %print(removing(H1)),nl,
2130 (remove_element_from_explicit_set(avl_set(A),H1,RA)
2131 -> not_equal_object(T1,RA)
2132 ; true ).
2133 neq_cons(ES,H1,T1) :- is_custom_explicit_set(ES,neq_cons),expand_custom_set(ES,ExpSet),
2134 neq_cons(ExpSet,H1,T1).
2135
2136 :- block neq_cons2(-,?,?).
2137 neq_cons2(not_successful,_T1,_NewSet2). % one element could not be removed: the sets are different
2138 neq_cons2(successful,T1,NewSet2) :- not_equal_object_sets(T1,NewSet2).
2139
2140 % kernel_objects:not_equal_couple(int(1),int(Y),B,pred_true).
2141 :- assert_must_succeed(( kernel_objects:not_equal_couple(int(1),int(Y),B,pred_true),Y=1, B==pred_false)).
2142 :- assert_must_succeed(( kernel_objects:not_equal_couple(int(Y),int(1),B,pred_true),Y=1, B==pred_false)).
2143 :- assert_must_succeed(( kernel_objects:not_equal_couple(int(Y),int(1),B,pred_false),Y=1, B==pred_true)).
2144 :- assert_must_succeed(( kernel_objects:not_equal_couple(int(Y),int(1),pred_false,B),Y=1, B==pred_true)).
2145 :- assert_must_succeed(( kernel_objects:not_equal_couple(int(Y),int(1),B,pred_true),Y=2, var(B))).
2146 :- assert_must_succeed(( kernel_objects:not_equal_couple(B,pred_true,int(Y),int(1)),Y=1, B==pred_false)).
2147 :- assert_must_succeed(( kernel_objects:not_equal_couple(B,fd(C,'Code'),fd(Y,'Name'),F),F=fd(1,'Name'),Y=1,B=fd(1,'Code'),C=2 )).
2148 :- assert_must_succeed(( kernel_objects:not_equal_couple(B,pred_true,fd(Y,'Name'),F),F=fd(1,'Name'),Y=1, B==pred_false)).
2149 :- block not_equal_couple(-,?,-,?),not_equal_couple(?,-,?,-).
2150 % (X1,X2) /= (Y1,Y2)
2151
2152 % using CLPFD results in less propagation it seems
2153 % e.g. post_constraint((A1 #\= A2 #\/ B1 #\= B2), dif((A1,B1),(A2,B2))) will not propagate if A1=A2 or B1=B2
2154 % we could do something like
2155 % post_constraint((N*A1 + B1 #\= N*A2 + B2), dif((A1,B1),(A2,B2))). ; but we need to know good value for N
2156 % TO DO: pass typing information when available ?? or not needed because type info extracted ?
2157
2158
2159 not_equal_couple(X1,Y1,X2,Y2) :-
2160 equality_objects(X1,Y1,EqRes1),
2161 (var(EqRes1)
2162 -> equality_objects(X2,Y2,EqRes2),
2163 % print(call_not_equal_couple4(EqRes1,X1,Y1,EqRes2,X2,Y2)),nl,
2164 not_equal_couple4(EqRes1,X1,Y1,EqRes2,X2,Y2)
2165 ; EqRes1=pred_true -> not_equal_object(X2,Y2)
2166 ; true).
2167
2168 :- block not_equal_couple4(-,?,?,-,?,?).
2169 not_equal_couple4(EqRes1,X1,Y1,EqRes2,X2,Y2) :-
2170 %print(unblock_not_equal_couple4(EqRes1,X1,Y1,EqRes2,X2,Y2)),nl,
2171 (var(EqRes1)
2172 -> not_equal_couple5(EqRes2,X1,Y1,EqRes1)
2173 ; not_equal_couple5(EqRes1,X2,Y2,EqRes2)).
2174
2175 not_equal_couple5(pred_true,_X2,_Y2,EqResOther) :- EqResOther=pred_false.
2176 not_equal_couple5(pred_false,_,_,_).
2177
2178
2179 /* To do: provide special support for things like
2180 couple of fd's [done], list of fd's, set of fd's */
2181
2182 :- block not_equal_fields(-,-).
2183 not_equal_fields([field(ID1,V1)|T1],[field(ID2,V2)|T2]) :-
2184 % should we wait for ID1 or ID2 to become nonvar?
2185 check_field_name_compatibility(ID1,ID2),
2186 (T1==[]
2187 -> T2=[],not_equal_object(V1,V2)
2188 ; not_equal_couple(V1,V2,rec(T1),rec(T2)) % would be slightly more efficient to have a custom version of not_equal_couple
2189 ).
2190
2191 check_field_name_compatibility(Name1,Name2) :-
2192 nonvar(Name1), nonvar(Name2), Name1 \= Name2, !,
2193 add_internal_error('Incompatible fields: ',check_field_name_compatibility(Name1,Name2)).
2194 check_field_name_compatibility(_,_).
2195
2196
2197 /* ------------------------------------------- */
2198 /* equality_objects/3 function */
2199 /* ------------------------------------------- */
2200
2201 %% :- ensure_loaded(kernel_equality).
2202
2203 % ----------------------------------------------------------
2204 % ----------------------------------------------------------
2205
2206
2207
2208 :- use_module(kernel_equality).
2209
2210 % ----------------------------------------------------------
2211 % ----------------------------------------------------------
2212
2213 /* ---------------> */
2214 /* This should probably be more systematically applied before every kernel call
2215 + expanded for other symbolic representations !! */
2216
2217
2218
2219 /* underlying assumption: if G is a global set: we get back the
2220 global_set tag immediately: no need to use when to wait;
2221 better: ensure that b_compute_expression always returns a nonvar term */
2222
2223 integer_global_set('NAT').
2224 integer_global_set('NATURAL').
2225 integer_global_set('NAT1').
2226 integer_global_set('NATURAL1').
2227 integer_global_set('INT').
2228 integer_global_set('INTEGER').
2229
2230 string_global_set('STRING'). % TODO : check what happens when we have STRING in Event-B as a set
2231
2232
2233 :- assert_must_succeed(( kernel_objects:element_of_global_set(int(0),'NATURAL'))).
2234 :- assert_must_fail(( kernel_objects:element_of_global_set(int(0),'NATURAL1'))).
2235 :- assert_must_fail(( kernel_objects:element_of_global_set(int(-1),'NATURAL'))).
2236 :- assert_must_succeed(( kernel_objects:element_of_global_set(int(-1),'INTEGER'))).
2237 :- assert_must_succeed(( kernel_objects:element_of_global_set(int(0),'NAT'))).
2238 :- assert_must_fail(( kernel_objects:element_of_global_set(int(0),'NAT1'))).
2239 :- assert_must_succeed(( kernel_objects:element_of_global_set(X,'NAT'),X=int(1))).
2240 :- assert_must_succeed(( kernel_objects:element_of_global_set(X,'NATURAL'),X=int(1))).
2241
2242 element_of_global_set(X,GS) :-
2243 init_wait_flags(WF),element_of_global_set_wf(X,GS,WF),ground_wait_flags(WF).
2244
2245 element_of_global_set_wf(El,Set,WF) :- element_of_global_set_wf(El,Set,WF,unknown).
2246
2247 :- block element_of_global_set_wf(?,-,?,?).
2248 ?element_of_global_set_wf(El,Set,WF,_) :- b_global_set(Set),!,
2249 global_type_wf(El,Set,WF).
2250 element_of_global_set_wf(X,'STRING',_WF,_) :- !, X=string(_).
2251 element_of_global_set_wf(int(X),GS,WF,Span) :-
2252 element_of_global_integer_set_wf(GS,X,WF,Span).
2253
2254 /* what about BOOL ?? */
2255 element_of_global_integer_set_wf('NAT',X,WF,_) :-
2256 preferences:get_preference(maxint,MAXINT),
2257 in_nat_range_wf(int(X),int(0),int(MAXINT),WF).
2258 element_of_global_integer_set_wf('NATURAL',X,WF,Span) :-
2259 (ground(X) -> X>=0
2260 ; is_natural(int(X),WF),
2261 %get_last_wait_flag(element_of_global_set(int(X),'NATURAL'),WF,LWF),
2262 get_integer_enumeration_wait_flag(X,'NATURAL',WF,LWF),
2263 enumerate_natural(X,0,LWF,Span)
2264 ).
2265 element_of_global_integer_set_wf('NAT1',X,WF,_) :-
2266 preferences:get_preference(maxint,MAXINT),
2267 in_nat_range_wf(int(X),int(1),int(MAXINT),WF).
2268 element_of_global_integer_set_wf('NATURAL1',X,WF,Span) :-
2269 (ground(X) -> X>=1
2270 ; is_natural1(int(X),WF),
2271 %get_last_wait_flag(element_of_global_set_wf(int(X),'NATURAL1'),WF,LWF),
2272 get_integer_enumeration_wait_flag(X,'NATURAL1',WF,LWF),
2273 enumerate_natural(X,1,LWF,Span)
2274 ).
2275 element_of_global_integer_set_wf('INT',X,WF,_) :-
2276 preferences:get_preference(minint,MININT),
2277 preferences:get_preference(maxint,MAXINT),
2278 in_nat_range_wf(int(X),int(MININT),int(MAXINT),WF).
2279 element_of_global_integer_set_wf('INTEGER',X,WF,Span) :-
2280 (ground(X) -> true
2281 ; %get_last_wait_flag(element_of_global_set_wf(int(X),'INTEGER'),WF,LWF),
2282 get_integer_enumeration_wait_flag(X,'INTEGER',WF,LWF),
2283 enumerate_int_wf(X,LWF,element_of_global_integer_set_wf,Span) %when((nonvar(LWF);nonvar(X)),(ground(X)->true;enumerate_int(X)))
2284 ).
2285
2286
2287 get_integer_enumeration_wait_flag(X,SET,WF,LWF) :-
2288 clpfd_domain(X,FDLow,FDUp), finite_domain(FDLow,FDUp),!,
2289 Size is 1+FDUp-FDLow,
2290 get_wait_flag(Size,element_of_global_set_wf(int(X),SET),WF,LWF).
2291 get_integer_enumeration_wait_flag(X,SET,WF,LWF) :-
2292 get_integer_enumeration_wait_flag(element_of_global_set_wf(int(X),SET),WF,LWF).
2293 % important for e.g., solving r = /*@symbolic*/ {u|#x.(x : NATURAL & u : {x |-> x * x,x |-> x + x})} & 10|->20 : r
2294 % see test 1933, the code was: get_enumeration_starting_wait_flag(element_of_global_set_wf(int(X),SET),WF,LWF), which is a lower number
2295
2296 :- assert_must_succeed((kernel_objects:enumerate_int_wf(X,4,self_check,unknown),X==2)).
2297 :- block enumerate_int_wf(-,-,?,?).
2298 enumerate_int_wf(X,_LWF,Source,Span) :- %print(enum_int(X)),nl,
2299 ? (ground(X) -> true ; enumerate_int_with_span(X,trigger_true(Source),Span)).
2300
2301 :- assert_must_succeed(not_element_of_global_set(int(-1),'NAT')).
2302 :- assert_must_succeed(not_element_of_global_set(int(-1),'NATURAL')).
2303 :- assert_must_succeed(not_element_of_global_set(int(0),'NAT1')).
2304 :- assert_must_succeed(not_element_of_global_set(int(0),'NATURAL1')).
2305 not_element_of_global_set(int(X),GS) :-
2306 (var(GS) -> add_error(kernel_objects,var_not_element_of_global_set,(int(X),GS)) ; true),
2307 not_element_of_global_set2(GS,X).
2308 not_element_of_global_set2('NAT',X) :-
2309 preferences:get_preference(maxint,MAXINT),
2310 clpfd_not_in_non_empty_range(X,0,MAXINT). %when(nonvar(X), (X<0 ; X>MAXINT)).
2311 not_element_of_global_set2('NATURAL',X) :- is_not_natural(int(X)).
2312 not_element_of_global_set2('NAT1',X) :-
2313 preferences:get_preference(maxint,MAXINT),
2314 clpfd_not_in_non_empty_range(X,1,MAXINT). %when(nonvar(X),(X<1 ; X>MAXINT)).
2315 not_element_of_global_set2('NATURAL1',X) :- is_not_natural1(int(X)).
2316 not_element_of_global_set2('INT',X) :-
2317 preferences:get_preference(minint,MININT),
2318 preferences:get_preference(maxint,MAXINT),
2319 clpfd_not_in_non_empty_range(X,MININT,MAXINT). %when(nonvar(X), (X < MININT ; X > MAXINT)).
2320 %not_element_of_global_set(string(_X),'STRING') :- fail.
2321 %not_element_of_global_set(int(_X),'INTEGER') :- fail.
2322 %not_element_of_global_set(_El,Set) :- b_global_set(Set), fail.
2323
2324
2325
2326 /* ---- */
2327 /* SETS */
2328 /* ---- */
2329
2330 %:- block is_a_set(-).
2331 %is_a_set(X) :- is_a_set2(X).
2332 %is_a_set2([]) :- !.
2333 %is_a_set2([_|_]) :- !.
2334 %is_a_set2(X) :- is_custom_explicit_set(X,is_a_set2).
2335
2336
2337
2338
2339 :- assert_must_succeed(exhaustive_kernel_fail_check(empty_set([int(4),int(3)]))).
2340 :- assert_must_fail((empty_set([int(2),int(1)]))).
2341 :- assert_must_fail((empty_set([int(1)]))).
2342 :- assert_must_fail((empty_set([[]]))).
2343 :- assert_must_fail((empty_set(global_set('Name')))).
2344 :- assert_must_fail((empty_set(X),X=[int(1)])).
2345 :- assert_must_succeed((empty_set([]))).
2346 empty_set(X) :- (var(X) -> X=[]
2347 ; X=[] -> true
2348 % ; X=[_|_] -> fail
2349 ; is_custom_explicit_set_nonvar(X),is_empty_explicit_set(X)).
2350 empty_set_wf(X,WF) :- (var(X) -> X=[]
2351 ; X=[] -> true
2352 % ; X=[_|_] -> fail
2353 ; is_custom_explicit_set_nonvar(X),is_empty_explicit_set_wf(X,WF)).
2354
2355
2356 :- assert_must_succeed(exhaustive_kernel_check(not_empty_set([int(4),int(3)]))).
2357 :- assert_must_succeed((kernel_objects:not_empty_set([int(2),int(1)]))).
2358 :- assert_must_succeed((kernel_objects:not_empty_set([int(1)]))).
2359 :- assert_must_succeed((kernel_objects:not_empty_set([[]]))).
2360 :- assert_must_succeed((kernel_objects:not_empty_set(global_set('Name')))).
2361 :- assert_must_succeed((kernel_objects:not_empty_set_lwf(X,1),nonvar(X),X=[_|_])).
2362 :- assert_must_succeed((kernel_objects:not_empty_set_lwf([int(1)],_))).
2363 :- assert_must_fail((kernel_objects:not_empty_set([]))).
2364
2365 not_empty_set_wf(S,WF) :- WF==no_wf_available,!, not_empty_set(S).
2366 not_empty_set_wf(S,WF) :- var(S), !,
2367 (preferences:preference(use_smt_mode,true) -> S=[_|_]
2368 % ; WF=no_wf_available -> not_empty_set(S)
2369 ; get_large_finite_wait_flag(not_empty_set_wf,WF,LWF),
2370 not_empty_set_lwf(S,LWF)).
2371 not_empty_set_wf(closure(P,T,B),WF) :- !, is_non_empty_explicit_set_wf(closure(P,T,B),WF).
2372 not_empty_set_wf(S,_WF) :- not_empty_set(S).
2373
2374 :- block not_empty_set_lwf(-,-).
2375 % the instantiation with a list skeleton can easily cause multiple solutions for the same
2376 % set to be found: hence we guard it by a wait flag
2377 not_empty_set_lwf(S,_LWF) :- var(S),!, %print(setting_not_empty(S)),nl,
2378 S=[_|_].
2379 not_empty_set_lwf(S,_) :- not_empty_set(S).
2380
2381 :- use_module(error_manager,[add_warning/2]).
2382 :- block not_empty_set(-).
2383 %not_empty_set(S) :- var(S),!, print(setting_not_empty(S)),nl,S=[_|_].
2384 % not_empty_set(X) :- not_equal_object([],X).
2385 not_empty_set([_|_]).
2386 not_empty_set(avl_set(A)) :- (A==empty -> add_warning(not_empty_set,'Empty avl_set'),fail ; true).
2387 not_empty_set(closure(P,T,B)) :- is_non_empty_explicit_set(closure(P,T,B)). % TO DO: also use WF
2388 not_empty_set(global_set(Type)) :- b_non_empty_global_set(Type).
2389 not_empty_set(freetype(ID)) :- kernel_freetypes:is_non_empty_freetype(ID).
2390
2391 % there also exists: eq_empty_set , a reified version, i.e., test_empty_set
2392
2393
2394 :- assert_must_succeed((exact_element_of(int(1),[int(2),int(1)]))).
2395 :- assert_must_succeed((exact_element_of(int(1),[int(2),int(3),int(4),int(1)]))).
2396 :- assert_must_succeed((exact_element_of(int(4),[int(2),int(3),int(4),int(1)]))).
2397 :- assert_must_succeed((exact_element_of(int(1),[int(2),int(3)|T]), T=[int(4),int(1)])).
2398 :- assert_must_fail((exact_element_of(int(5),[int(2),int(3)|T]), T=[int(4),int(1)])).
2399 :- assert_must_succeed((exact_element_of(fd(1,'Name'),global_set('Name')))).
2400 :- assert_must_succeed((exact_element_of([int(2),int(1)],[[],[int(2),int(1)]]))).
2401 :- assert_must_fail((exact_element_of([int(1),int(2)],[[],[int(2),int(1)]]))).
2402 %:- assert_must_succeed((exact_element_of([(int(1),fd(2,'Name'))],
2403 % closure([zzzz],[set(couple(integer,global('Name')))], 'In'('ListExpression'(['Identifier'(zzzz)]),
2404 % 'Seq'(value([fd(1,'Name'),fd(2,'Name')]))))) )).
2405 %:- assert_must_succeed((exact_element_of(XX,
2406 % closure([zzzz],[set(couple(integer,global('Name')))], 'In'('ListExpression'(['Identifier'(zzzz)]),
2407 % 'Seq'(value([fd(1,'Name'),fd(2,'Name')]))))),
2408 % equal_object(XX,[(int(1),fd(1,'Name'))]) )).
2409 %:- assert_must_succeed((
2410 %exact_element_of(XX,closure([zzzz],[set(couple(integer,global('Name')))],
2411 % 'In'('ListExpression'(['Identifier'(zzzz)]),
2412 % 'Perm'(value([fd(1,'Name'),fd(2,'Name')]))))),
2413 % equal_object(XX,[(int(1),fd(2,'Name')),(int(2),fd(1,'Name'))]) )).
2414
2415 %:- assert_must_succeed(( exact_element_of(X,
2416 % closure([zzzz],[set(record([field(balance,integer),field(name,global('Code'))]))],
2417 % 'In'('ListExpression'(['Identifier'(zzzz)]),
2418 % 'PowerSet'(value(closure([zzzz],
2419 % [record([field(balance,integer),field(name,global('Code'))])],'In'('ListExpression'(['Identifier'(zzzz)]),
2420 % 'SetOfRecords'(value(cons_expr(field(balance,global_set('NAT')),
2421 % cons_expr(field(name,global_set('Code')),nil_expr))))))))))),
2422 % X=[rec([field(balance,int(0)),field(name,fd(2,'Code'))])] )).
2423 %:- assert_must_fail(( exact_element_of(X,
2424 % closure([zzzz],[set(record([field(balance,integer),field(name,global('Code'))]))],
2425 % 'In'('ListExpression'(['Identifier'(zzzz)]),
2426 % 'PowerSet'(value(closure([zzzz],
2427 % [record([field(balance,integer),field(name,global('Code'))])],'In'('ListExpression'(['Identifier'(zzzz)]),
2428 % 'SetOfRecords'(value(cons_expr(field(balance,global_set('NAT')),
2429 % cons_expr(field(name,global_set('Code')),nil_expr))))))))))),
2430 % X=[rec([field(balance,int(-1)),field(name,fd(2,'Code'))])] )).
2431
2432
2433 /* use this to compute elements */
2434 exact_element_of(X,Set) :- %print_message(exact_element_of(X,Set)),
2435 dif(Set,[]),
2436 exact_element_of2(Set,X).
2437 :- block exact_element_of2(-,?).
2438 exact_element_of2([H|_],H).
2439 exact_element_of2([_|T],E) :- exact_element_of3(T,E).
2440 exact_element_of2(X,E) :- is_custom_explicit_set_nonvar(X), check_element_of(E,X).
2441 :- block exact_element_of3(-,?).
2442 exact_element_of3([H|_],H).
2443 exact_element_of3([_|T],E) :- exact_element_of3(T,E).
2444
2445
2446 :- assert_must_succeed(exhaustive_kernel_check(check_element_of(int(1),[int(2),int(1)]))).
2447 :- assert_must_succeed(exhaustive_kernel_fail_check(check_element_of(int(3),[int(2),int(1)]))).
2448 :- assert_must_succeed(exhaustive_kernel_fail_check(check_element_of(int(1),[]))).
2449
2450 /* uses equal_object instead of unification */
2451 :- assert_must_succeed((check_element_of(X,
2452 [(int(1),(int(1),(int(1),int(1)))),(int(2),(int(1),(int(1),int(1)))),
2453 (int(1),(int(1),(int(1),int(2)))),(int(2),(int(1),(int(1),int(2))))]),
2454 equal_object(X, (int(2),(int(1),(int(1),int(2))))) )).
2455 :- assert_must_succeed((check_element_of(X,
2456 [ (((int(1),int(1)),int(1)),int(1)), (((int(1),int(1)),int(1)),int(2)),
2457 (((int(1),int(1)),int(1)),int(3)), (((int(1),int(1)),int(1)),int(4)),
2458 (((int(1),int(1)),int(2)),int(1)), (((int(1),int(1)),int(2)),int(2))
2459 ]), equal_object(X, (((int(1),int(1)),int(2)),int(1)))
2460 )).
2461 :- assert_must_succeed((check_element_of(fd(1,'Name'),global_set('Name')))).
2462 %:- assert_must_succeed_multiple(check_element_of(X,[[fd(1,'Name')],[]])).
2463 :- assert_must_succeed((check_element_of((int(1),int(2)),[(int(1),int(2))]))).
2464 :- assert_must_succeed((check_element_of((_X,_Y),[(fd(2,'Code'),fd(2,'Code'))]))).
2465 :- assert_must_succeed((init_wait_flags(WF),
2466 check_element_of_wf((X,Y),[(fd(2,'Code'),fd(2,'Code'))],WF),
2467 ground_det_wait_flag(WF), X= fd(2,'Code'), Y= fd(2,'Code'),
2468 kernel_waitflags:ground_wait_flags(WF) )).
2469 :- assert_must_succeed((init_wait_flags(WF),
2470 check_element_of_wf((Y,X),[(fd(2,'Code'),fd(2,'Code'))],WF),
2471 ground_det_wait_flag(WF), X= fd(2,'Code'), Y= fd(2,'Code'),
2472 kernel_waitflags:ground_wait_flags(WF) )).
2473 :- assert_must_succeed((check_element_of([int(1),int(2)],[[int(2),int(1)]]))).
2474
2475 :- assert_must_succeed((check_element_of([int(1),int(2)],[[],[int(2),int(1)]]))).
2476 :- assert_must_succeed((check_element_of(X,[[],[int(2),int(1)]]), X==[] )).
2477 :- assert_must_succeed((check_element_of_wf(X,[[],[int(2),int(1)]],_WF),
2478 equal_object(X,[int(1),int(2)]) )).
2479 :- assert_must_succeed((check_element_of_wf(XX,global_set('Name'),WF),kernel_waitflags:ground_wait_flags(WF), XX==fd(3,'Name') )).
2480 :- assert_must_fail(check_element_of([fd(2,'Name')],[[fd(1,'Name')],[]])).
2481 :- assert_must_fail((check_element_of([int(2)],[[],[int(2),int(1)]]))).
2482 :- assert_must_succeed((check_element_of(int(1),_X))).
2483 :- assert_must_succeed((check_element_of((int(2),_X),[(int(1),[(int(1),int(22))]),(int(2),[(int(1),int(55))])]))).
2484
2485 check_element_of(X,Set) :- init_wait_flags(WF),
2486 check_element_of_wf(X,Set,WF),
2487 ground_wait_flags(WF).
2488
2489 % new test: check_element_of(int(1),X).
2490 % new test: check_element_of(int(1),[int(2)|X]).
2491
2492 check_element_of_wf(X,Set,WF) :- %%print_message(check_element_of_wf(X,Set)),
2493 ? dif(Set,[]),
2494 ? check_element_of1(X,Set,WF).
2495
2496 %check_element_of1(X,Set,WF) :- var(X),var(Set),unbound_variable_check(Set),!,
2497 % Set=[_|_], check_element_of2(Set,X,WF).
2498 %:- block check_element_of1(-,-,?). %%
2499 :- if(environ(prob_data_validation_mode,true)).
2500 % avoid instantiating Sets to lists early on: can disturb enumeration and efficient computation of large sets
2501 check_element_of1(X,Set,WF) :- nonvar(Set),!, check_element_of2(Set,X,WF).
2502 check_element_of1(X,Set,WF) :- get_wait_flag(3000,check_element_of1(X,Set),WF,WF2),
2503 check_element_of1b(X,Set,WF,WF2).
2504
2505 :- block check_element_of1b(?,-,?,-).
2506 check_element_of1b(X,Set,WF,_) :- % print_term_summary(check_element_of1(X,Set,WF)),
2507 (unbound_variable_for_element_of(Set)
2508 -> mark_as_non_free(X),
2509 Set=[X|_] % Note: X needs to be nonvar so that other code knows X is not free anymore
2510 % TO DO: normalise X ?
2511 % TO DO: do this using CHR/attributes rather than by instantiation
2512 ; check_element_of2(Set,X,WF)
2513 ).
2514 :- else.
2515 check_element_of1(X,Set,WF) :- % print_term_summary(check_element_of1(X,Set,WF)), trace,
2516 ? (unbound_variable_for_element_of(Set)
2517 -> mark_as_non_free(X),
2518 Set=[X|_] % Note: X needs to be nonvar so that other code knows X is not free anymore
2519 % TO DO: normalise X ?
2520 % TO DO: do this using CHR/attributes rather than by instantiation
2521 ? ; check_element_of2(Set,X,WF)
2522 ).
2523 :- endif.
2524
2525
2526 % attach co-routine to mark a given term as not a real variable
2527 mark_as_non_free(X) :- var(X) -> non_free(X) ; true.
2528 :- block non_free(-).
2529 non_free([H|T]) :- !, mark_as_non_free(H), mark_as_non_free(T).
2530 non_free((A,B)) :- !, mark_as_non_free(A), mark_as_non_free(B).
2531 non_free(rec(Fields)) :- !, mark_as_non_free_fields(Fields).
2532 non_free(_).
2533 :- block mark_as_non_free_fields(-).
2534 mark_as_non_free_fields([]).
2535 mark_as_non_free_fields([field(_,Val)|T]) :- mark_as_non_free(Val),mark_as_non_free_fields(T).
2536
2537 :- use_module(clpfd_lists,[lazy_fd_value_check/4]).
2538
2539 :- block check_element_of2(-,?,?).
2540 check_element_of2(CS,El,WF) :-
2541 ? is_custom_explicit_set_nonvar(CS),!, element_of_custom_set_wf(El,CS,WF).
2542 check_element_of2([],_,_) :- !,fail.
2543 %check_element_of2([H|T],El,WF) :- try_expand_and_convert_to_avl([H|T],AVL),AVL=avl_set(_),!, % much better support exists for AVL trees; should we enable this conversion ?? %nl,print(converted_list_to_AVL([H|T])),nl,nl,
2544 % element_of_custom_set_wf(El,AVL,WF).
2545 check_element_of2([H|T],E,WF) :- !, % print(check_element_of4w(E,H,T,WF)),nl,
2546 % try and transform E : Set into clpfd:element(_,FDVals,EFD) check:
2547 clpfd_lists:lazy_fd_value_check([H|T],E,WF,FullyChecked),
2548 %get_partial_set_priority([H|T],WF,LWF), %%
2549 %get_wait_flag(2,check_element_of2([H|T],E),WF,LWF), %%
2550 (FullyChecked==true,ground(E) -> true % no need to check
2551 ; get_cardinality_wait_flag([H|T],check_element_of2,WF,LWF),
2552 check_element_of4w(E,H,T,WF,LWF) % this call is somewhat redundant if FullyChecked=true; but otherwise in_fd_value_list will not enumerate on its own (e.g., self-checks for relation_over will fail)
2553 ).
2554 check_element_of2(freetype(Id),E,WF) :- !, is_a_freetype_wf(E,Id,WF).
2555 check_element_of2(Set,E,WF) :-
2556 add_internal_error('Illegal argument: ',check_element_of2(Set,E,WF)),fail.
2557
2558
2559 % call if you already have an explicit waitflag (LWF) setup for the cardinality of the set
2560 :- block check_element_of_wf_lwf(?,-,?,?).
2561 check_element_of_wf_lwf(El,CS,WF,_LWF) :-
2562 is_custom_explicit_set_nonvar(CS),!, element_of_custom_set_wf(El,CS,WF).
2563 check_element_of_wf_lwf(E,[H|T],WF,LWF) :- check_element_of4w(E,H,T,WF,LWF).
2564 check_element_of_wf_lwf(E,freetype(Id),WF,_) :- !, is_a_freetype_wf(E,Id,WF).
2565
2566 :- block check_element_of4w(-,?,-,?,-).
2567 % check_element_of4w(E,H,T,_WF,_LWF) :- print(check_element_of4w(E,H,T,_WF,_LWF)),nl,fail.
2568 check_element_of4w(E,H,T,_WF,_LWF) :- T==[],!,equal_object(E,H,check_element_of4w).
2569 check_element_of4w(E,H,_T,_WF,_LWF) :- E==H ,!. %,print(eq(E,H)),nl. % added by mal, 17.10 2007
2570 ?check_element_of4w(E,H,T,WF,LWF) :- T\==[],
2571 ? equality_objects_lwf(E,H,Res,LWF),
2572 ? check_element_of4(Res,E,T,WF,LWF).
2573
2574 :- block check_element_of4(-,?,?,?,-).
2575 check_element_of4(pred_true,_E,_,_WF,_LWF).
2576 check_element_of4(pred_false,E,T,WF,LWF) :-
2577 ? (var(T) -> T = [E|_] ; check_element_of5(E,T,WF,LWF)).
2578
2579 :- block check_element_of5(?,-,?,?).
2580 check_element_of5(E,R,WF,LWF) :- %print(equal_cons(R,H,T,for(E))),nl,
2581 ? get_next_element(R,H,T),
2582 ? check_element_of4w(E,H,T,WF,LWF).
2583
2584
2585
2586 :- assert_must_succeed(exhaustive_kernel_check(not_element_of(int(3),[int(2),int(1)]))).
2587 :- assert_must_succeed(exhaustive_kernel_check(not_element_of(int(3),[int(2),int(1),int(4)]))).
2588 :- assert_must_succeed(exhaustive_kernel_fail_check(not_element_of(int(1),[int(2),int(1)]))).
2589 :- assert_must_succeed((kernel_objects:not_element_of(int(3),[int(2),int(1)]))).
2590 :- assert_must_succeed((kernel_objects:not_element_of(fd(1,'Name'),[]))).
2591 :- assert_must_fail((kernel_objects:not_element_of(fd(1,'Name'),global_set('Name')))).
2592 :- assert_must_succeed((kernel_objects:not_element_of(X,[fd(1,'Name')]),X = fd(2,'Name'))).
2593 :- assert_must_fail((kernel_objects:not_element_of(X,[fd(1,'Name')]),X = fd(1,'Name'))).
2594 :- assert_must_succeed(kernel_objects:not_element_of(term(a),[])).
2595 :- assert_must_fail((kernel_objects:not_element_of(int(1),[int(2),int(1)]))).
2596 :- assert_must_succeed((kernel_objects:not_element_of([int(1),int(2)],
2597 [[int(1)],[int(0),int(4)],[int(0),int(3)],[int(0),int(1)],[int(0)],[]]))).
2598 :- assert_must_fail((kernel_objects:not_element_of(term(3),[int(2),int(1)]))).
2599
2600
2601 not_element_of(X,Set) :- init_wait_flags(WF),
2602 not_element_of_wf(X,Set,WF),
2603 ground_wait_flags(WF).
2604
2605 :- use_module(b_global_sets,[b_get_fd_type_bounds/3]).
2606 :- block not_element_of_wf(-,-,?).
2607 not_element_of_wf(_,Set,_) :- Set==[],!.
2608 not_element_of_wf(El,Set,WF) :- nonvar(El),El=fd(X,GS),b_get_fd_type_bounds(GS,N,N),!,
2609 % we have a global set with a single element; Set must be empty
2610 % print(not_el_of(El,Set)),nl,
2611 X=N,empty_set_wf(Set,WF).
2612 not_element_of_wf(El,Set,WF) :- not_element_of_wf1(Set,El,WF).
2613
2614 :- block not_element_of_wf1(-,?,?).
2615 %not_element_of_wf1(E,S,WF) :- print(not_el_of(E,S,WF)),nl,fail.
2616 not_element_of_wf1(X,E,WF) :- is_custom_explicit_set_nonvar(X),!,
2617 %print(check_not_el(E,X,WF)),nl,
2618 not_element_of_custom_set_wf(E,X,WF). % , print(ok(E,X,WF)),nl.
2619 not_element_of_wf1([],_E,_WF).
2620 not_element_of_wf1([H|T],E,WF) :- /* print(call(not_element_of_wf1([H|T],E))),nl, */
2621 not_equal_object_wf(E,H,WF),
2622 not_element_of_wf1(T,E,WF).
2623
2624
2625 :- assert_must_succeed(exhaustive_kernel_check(add_element(int(3),[int(2),int(1)],[int(1),int(3),int(2)]))).
2626 :- assert_must_succeed(exhaustive_kernel_fail_check(add_element(int(2),[int(2),int(1)],[int(1),int(3),int(2)]))).
2627 :- assert_must_succeed(exhaustive_kernel_fail_check(add_element(int(4),[int(2),int(1)],[int(1),int(3),int(2)]))).
2628 :- assert_must_succeed((kernel_objects:add_element(int(3),[int(2),int(1)],R),
2629 kernel_objects:equal_object(R,[int(1),int(2),int(3)]))).
2630 :- assert_must_succeed((kernel_objects:add_element([int(2)],[[int(2),int(1)],[]],R),
2631 kernel_objects:equal_object(R,[[],[int(1),int(2)],[int(2)]]))).
2632 :- assert_must_succeed((kernel_objects:add_element([int(1),int(2)],[[int(2),int(1)],[]],R),
2633 kernel_objects:equal_object(R,[[],[int(1),int(2)]]))).
2634 :- assert_must_succeed((kernel_objects:add_element(X,[int(2),int(1)],R),
2635 kernel_objects:equal_object(R,[int(1),int(2)]), X = int(1))).
2636 :- assert_must_succeed((kernel_objects:add_element([int(1),int(2)],
2637 [[int(1)],[int(0),int(4)],[int(0),int(3)],[int(0),int(1)],[int(0)],[]], _R))).
2638
2639 :- assert_must_succeed((kernel_objects:add_element(int(3),[int(X),int(1)],R,D),
2640 var(D), X=3, R==[int(3),int(1)], D==done)).
2641
2642 :- assert_must_fail((kernel_objects:add_element(term(msg),[int(2),int(1)],_R))).
2643 :- assert_must_succeed((kernel_objects:add_element(int(3),[int(2),int(X)],R),
2644 nonvar(R), R =[H|T], H==int(2), nonvar(T),T=[_HH|TT],var(TT),
2645 X=4, T==[int(4),int(3)])).
2646 :- assert_must_succeed((kernel_objects:add_element(int(3),[int(2),int(X)],R),
2647 nonvar(R), R =[H|T], H==int(2), nonvar(T),T=[_HH|TT],var(TT),
2648 X=3, T==[int(3)])).
2649 :- assert_must_succeed((kernel_objects:add_element(int(3),X,[int(2),int(3)]),
2650 kernel_objects:equal_object(X,[int(2)]) )).
2651 :- assert_must_succeed((kernel_objects:add_element(int(3),X,[int(3)]),
2652 kernel_objects:equal_object(X,[]) )).
2653 :- assert_must_succeed((add_element(X,[int(1)],[int(1)]),X==int(1))).
2654 :- assert_must_succeed((add_element(X,[],[int(1)]),X==int(1))).
2655 % kernel_objects:add_element(E,[H],R,Done), H = int(X), E=int(Y), X in 1..10, Y in 11..20.
2656
2657
2658 add_element(E,Set,NewSet) :- add_element(E,Set,NewSet,_).
2659 add_element(Element,Set,NewSet,Done) :- add_element_wf(Element,Set,NewSet,Done,no_wf_available).
2660 add_element_wf(E,Set,NewSet,WF) :- add_element_wf(E,Set,NewSet,_,WF).
2661
2662 :- block add_element_wf(?,-,?,?,?).
2663 add_element_wf(Element,Set,NewSet,Done,_WF) :- Set==[],!,
2664 % try and convert to AVL if possible:
2665 equal_object_optimized(NewSet,[Element]), % we could call equal_object_opt3 directly
2666 Done=done.
2667 ?add_element_wf(E,Set,NewSet,Done,WF) :- add_element1_wf(E,Set,NewSet,Done,WF).
2668
2669 :- block %add_element1(-,?,-,?),
2670 add_element1_wf(?,-,?,?,?).
2671 add_element1_wf(E,Set,NewSet,Done,WF) :- var(E),!, add_element_var(Set,NewSet,E,Done,WF).
2672 add_element1_wf(E,[H|T],NewSet,Done,WF) :- E==H,!, % avoid running [H|T] through expand_custom_set_to_list, in case T is a variable this will create a pending co-routine
2673 equal_object_wf(NewSet,[H|T],add_element1_1,WF),Done=done.
2674 add_element1_wf(E,Set,NewSet,Done,WF) :- %print(add_el(E,Set,NewSet)),nl,
2675 ? nonvar(Set), is_custom_explicit_set_nonvar(Set),
2676 ? add_element_to_explicit_set(Set,E,R),!,
2677 % print(add_to_explicit_set(E)),nl,
2678 ? equal_object_wf(R,NewSet,add_element1_2,WF),Done=done.
2679 add_element1_wf(E,Set,NewSet,Done,WF) :-
2680 expand_custom_set_to_list_wf(Set,ESet,_,add_element1,WF), % we could avoid this expansion by treating avl_set,... below in add_element3
2681 add_element2_wf(ESet,E,NewSet,Done,WF).
2682
2683
2684 add_element_var([],Res,Element,Done,WF) :- !, % print(add_elvarempty(Element,[],Res)),nl,
2685 equal_cons_wf(Res,Element,[],WF),Done=done.
2686 add_element_var(Set,Res,Element,Done,WF) :- Set \= [], Set \= closure(_,_,_),
2687 is_one_element_set(Res,ResEl), !,
2688 % the result is a one element set; hence Element *must* be the element in that set
2689 %% print(add_elvar(Element,Set,Res,ResEl)),nl,
2690 equal_object_wf(Element,ResEl,add_element_var_1,WF),
2691 equal_object_wf(Set,Res,add_element_var_2,WF), Done=done.
2692 add_element_var(Set,Res,Element,Done,WF) :- %when(nonvar(Element), add_element(Element,Set,Res,Done)).
2693 expand_custom_set_to_list_wf(Set,ESet,_,add_element_var,WF),
2694 add_element2_wf(ESet,Element,Res,Done,WF).
2695
2696 is_one_element_set(S,_) :- var(S),!,fail.
2697 is_one_element_set([H|T],H) :- T==[].
2698 is_one_element_set(avl_set(S),El) :- is_one_element_custom_set(avl_set(S),El).
2699
2700 :- block add_element2_wf(-,?,?,?,?).
2701 % add_element2_wf(E,S,R,_) :- print_message(add_el2(E,S,R)),fail.
2702 add_element2_wf([],E,Res,Done,_WF) :- var(Res),should_be_converted_to_avl(E),
2703 construct_avl_from_lists([E],R),!,
2704 (R,Done)=(Res,done).
2705 add_element2_wf(S,E,Res,Done,WF) :- copy_list_skeleton(S,Res,WF),
2706 add_element3_wf(S,E,Res,Done,WF).
2707
2708 % TO DO: use something else, like subset to propagate info that Set1 <: Set1 \/ {New}
2709 :- block copy_list_skeleton(-,?,?).
2710 copy_list_skeleton([],_,_WF) :- !.
2711 copy_list_skeleton([H|T],R,WF) :- !, % H must be in R, but not all elements of R are in [H|T] !; it could be the added element
2712 ? ((ground(H) ; unbound_variable_for_cons(R) ;
2713 custom_explicit_sets:singleton_set(R,_) % if R is a singleton set {EL} then H must be EL and T=[]
2714 ) -> equal_cons_wf(R,H,RR,WF), copy_list_skeleton(T,RR,WF)
2715 ; %nl,print(not_copying([H|T],R)),nl,
2716 true % otherwise equal_cons_wf can backpropagate elements from R into H !! see {x,y| x = {1,2} & x \/ y = {1,2,3} & 1:y } test 1535
2717 ).
2718 copy_list_skeleton(Set,R,WF) :- !,is_custom_explicit_set(Set,copy_list_skeleton),
2719 expand_custom_set_to_list_wf(Set,ESet,_,copy_list_skeleton,WF), copy_list_skeleton(ESet,R,WF).
2720 copy_list_skeleton(Skel,R,WF) :- add_internal_error('Argument not a set: ',copy_list_skeleton(Skel,R,WF)).
2721
2722 :- block add_element3_wf(-,?,?,?,?).
2723 add_element3_wf([],E,Res,Done,WF) :- % Res must be {E}
2724 ? equal_cons_wf(Res,E,[],WF),
2725 Done=done.
2726 add_element3_wf([H|T],E,Res,Done,WF) :-
2727 equality_objects_wf(H,E,EqRes,WF),
2728 equal_cons_wf(Res,H,TailRes,WF), % was: equal_object([H|TailRes],Res), % use WF?
2729 (var(EqRes)
2730 -> has_not_to_be_added([H|T],Res,EqRes,0)
2731 ; true),
2732 %(when(nonvar(EqRes),(print(nv(EqRes,H,T,WF)),nl))),
2733 add_element4_wf(EqRes,T,E,TailRes,Done,WF).
2734
2735
2736 % check if an element has not to be added to arg1 to obtain arg2
2737 :- block has_not_to_be_added(?,-,?,?),has_not_to_be_added(-,?,?,?).
2738 %has_not_to_be_added(A,B,R,Sz) :- print(has_not_to_be_added(A,B,R,Sz)),nl,fail.
2739 has_not_to_be_added([],[],R,Sz) :- !,(Sz=1 -> R=pred_true % we have 1 element: force equality with first element
2740 ; true).
2741 has_not_to_be_added([],[_H|T],R,_Sz) :- !, %(var(R) -> print(add_f([],[_H|T],R,_Sz)),nl ; true),
2742 empty_set(T),R=pred_false. % R=pred_false means with add an element
2743 has_not_to_be_added([_|_],[],_,_) :- !,fail. % we can either add or not; in both cases we do not obtain []
2744 has_not_to_be_added([_|T1],[_|T2],R,Sz) :- !, S1 is Sz+1, has_not_to_be_added(T1,T2,R,S1).
2745 has_not_to_be_added(_,_,_,_). % to do: support custom explicit sets
2746
2747 :- block add_element4_wf(-,?,?,?,?,?).
2748 ?add_element4_wf(pred_true, T,_E,TRes,Done,WF) :- equal_object_wf(T,TRes,add_element4_wf,WF), Done=done.
2749 ?add_element4_wf(pred_false,T, E,TRes,Done,WF) :- add_element3_wf(T,E,TRes,Done,WF).
2750
2751
2752 :- assert_must_succeed((kernel_objects:add_new_element(int(3),[int(2),int(1)],R),
2753 kernel_objects:equal_object(R,[int(1),int(2),int(3)]))).
2754 :- assert_must_succeed((kernel_objects:add_new_element([int(2)],[[int(2),int(1)],[]],R),
2755 kernel_objects:equal_object(R,[[],[int(1),int(2)],[int(2)]]))).
2756
2757 % TO DO : get rid of need for non-WF version in enumeration basic type:
2758 add_new_element(E,Set,NewSet) :- init_wait_flags(WF),
2759 add_new_element_wf(E,Set,NewSet,WF), ground_wait_flags(WF).
2760
2761 % use when you are sure the element to add is not in the set
2762 % to be used for adding elements to an accumulator
2763 :- block add_new_element_wf(?,-,?,?).
2764 %%add_new_element(E,Set,NewSet) :- add_element(E,Set,NewSet). % TO DO : Improve
2765 add_new_element_wf(E,Set,NewSet,WF) :-
2766 is_custom_explicit_set(Set,add_element), add_element_to_explicit_set(Set,E,R),!,
2767 %% print(add_new_to_explicit_set(E)),nl, %%
2768 equal_object_wf(R,NewSet,add_new_element_wf,WF).
2769 add_new_element_wf(E,Set,NewSet,WF) :- expand_custom_set_to_list_wf(Set,ESet,_,add_new_element_wf,WF),
2770 add_new_element2(ESet,E,NewSet,WF).
2771
2772 :- block add_new_element2(-,?,?,?).
2773 add_new_element2([],E,Res,WF) :- var(Res),should_be_converted_to_avl(E),
2774 construct_avl_from_lists([E],R),!,equal_object_wf(R,Res,add_new_element2,WF).
2775 add_new_element2(S,E,Res,WF) :- equal_cons_wf(Res,E,S,WF).
2776
2777 %:- assert_must_succeed(exhaustive_kernel_check(remove_element(int(3),[int(2),int(1),int(3)],[int(1),int(2)]))).
2778 :- assert_must_succeed((kernel_objects:remove_element(fd(1,'Name'),X,[fd(2,'Name'),fd(3,'Name')]),
2779 kernel_objects:equal_object(X,global_set('Name')))).
2780 :- assert_must_succeed((kernel_objects:remove_element(X,global_set('Name'),[fd(2,'Name'),fd(3,'Name')]),
2781 X = fd(1,'Name'))).
2782 :- assert_must_succeed((kernel_objects:remove_element(int(1),X,[int(2)]),
2783 kernel_objects:equal_object(X,[int(2),int(1)]))).
2784 :- assert_must_succeed((kernel_objects:remove_element([int(1),int(2)],X,[]),
2785 kernel_objects:equal_object([[int(2),int(1)]],X))).
2786 :- assert_must_fail((kernel_objects:remove_element(int(3),X,_),
2787 (X = [int(2),int(1)] ; X=[], X = [int(2)]))).
2788 :- assert_must_fail((kernel_objects:remove_element(int(1),X,Res),
2789 X = [int(2),int(1)], (Res=[] ; Res = [_,_|_] ; Res = [int(1)]))).
2790
2791 /* remove element is currenlty only used in not_equal_sets */
2792
2793 % remove element X from Set, yielding Res
2794 remove_element(X,Set,Res) :- equal_cons(Set,X,Res).
2795
2796
2797
2798 :- assert_must_succeed(exhaustive_kernel_check(remove_element_wf(int(3),[int(3),int(1)],
2799 [int(1)],_WF))).
2800 :- assert_must_succeed(exhaustive_kernel_check(remove_element_wf(int(1),[int(3),int(1)],
2801 [int(3)],_WF))).
2802 :- assert_must_succeed(exhaustive_kernel_fail_check(remove_element_wf(int(1),[int(3),int(1)],
2803 [int(1)],_WF))).
2804 :- assert_must_succeed(exhaustive_kernel_fail_check(remove_element_wf(int(11),[int(1)],
2805 [int(1)],_WF))).
2806 :- assert_must_succeed(exhaustive_kernel_fail_check(remove_element_wf(int(1),[int(3),int(1)],
2807 [],_WF))).
2808 :- assert_must_succeed((kernel_objects:remove_element_wf(fd(1,'Name'),X,[fd(2,'Name'),fd(3,'Name')],_WF),
2809 kernel_objects:equal_object(X,global_set('Name')))).
2810 :- assert_must_succeed((kernel_objects:remove_element_wf(int(1),X,[int(2)],_WF),
2811 kernel_objects:equal_object(X,[int(2),int(1)]))).
2812 :- assert_must_succeed(( kernel_objects:remove_element_wf(int(1),[int(X),int(2)],R,WF), kernel_waitflags:ground_wait_flags(WF),X==1,R==[int(2)] )).
2813 :- assert_must_succeed(( kernel_objects:remove_element_wf(X,[int(1),int(2)],R,WF), kernel_waitflags:ground_wait_flags(WF),X==int(2),R==[int(1)] )).
2814 :- assert_must_succeed(( kernel_objects:remove_element_wf(X,[pred_true /* bool_true */,pred_false /* bool_false */],R,WF), kernel_waitflags:ground_wait_flags(WF),X==pred_false /* bool_false */,R==[pred_true /* bool_true */] )).
2815
2816 remove_element_wf(X,Set,Res,WF) :- remove_element_wf(X,Set,Res,WF,_DONE).
2817
2818 :- block remove_element_wf(?,-, -,?,?).
2819 remove_element_wf(X,Set,Res,WF,_DONE) :- Res==[],!, % we know that X must be the only element in Set
2820 equal_object_wf(Set,[X],remove_element_wf,WF).
2821 remove_element_wf(X,Set,Res,WF,DONE) :-
2822 remove_element_wf1(X,Set,Res,WF,DONE).
2823
2824 :- block remove_element_wf1(?,-, ?,?,?).
2825 remove_element_wf1(X,avl_set(A),Res,WF,DONE) :- element_can_be_added_or_removed_to_avl(X),!,
2826 /* TO DO: try and move the check about whether X can be added to later; when either X is known
2827 or LWF is instantiated */
2828 remove_element_from_explicit_set(avl_set(A),X,AR),
2829 equal_object_wf(AR,Res,remove_element_wf1,WF), DONE=done.
2830 remove_element_wf1(X,Set,Res,WF,DONE) :- /* DONE is ground when element actually removed */
2831 expand_custom_set_to_list_wf(Set,ESet,_,remove_element_wf1,WF),
2832 %% nl,print(remove_element_wf1(X,Set,ESet,Res,WF,DONE)),nl,nl, %%
2833 remove_element_wf2(X,ESet,Res,LWF,DONE),
2834 %when(nonvar(DONE), print_bt_message(removed(X,ESet,Res,LWF))),
2835 (DONE==done -> true
2836 ; same_card_prop(ESet,[X|Res]), % in case result is instantiated: check compatible with inputs
2837 get_cardinality_wait_flag(ESet,remove_element_wf1(X,ESet,Res),WF,LWF),
2838 quick_propagation_element_information(Set,X,WF,_) % use Set rather than ESet; better if still closure or AVL
2839 ).
2840
2841 :- block same_card_prop(-,?), same_card_prop(?,-).
2842 same_card_prop([],[_|_]) :- !, fail.
2843 same_card_prop([_|T],R) :- !,
2844 (R=[] -> fail
2845 ; R=[_|RT] -> same_card_prop(T,RT)
2846 ; true). % just ignore
2847 same_card_prop(_,_).
2848
2849 :- block remove_element_wf2(?,-,?,?,?).
2850 remove_element_wf2(H1,[H2|T],Res,LWF,DONE) :- Res==[],!,
2851 equal_object(H1,H2,remove_element_wf2),
2852 remove_element_wf3(pred_true,H1,H2,T,Res,LWF,DONE).
2853 remove_element_wf2(H1,[H2|T],Res,LWF,DONE) :-
2854 ? prop_empty_set(T,EqRes),
2855 ? equality_objects_lwf(H1,H2,EqRes,LWF),
2856 %% print(rem(H1,H2,EqRes,T,Res)),nl,trace, %%
2857 %%((var(EqRes),var(LWF)) -> print(block_remove_element_wf3(EqRes,H1,H2,T,Res)),nl ; true),
2858 remove_element_wf3(EqRes,H1,H2,T,Res,LWF,DONE).
2859 /* important for total_bijection that this has higher priority than other expansions */
2860
2861 :- block prop_empty_set(-,?).
2862 % force second argument to pred_true if first arg is empty set
2863 prop_empty_set([],R) :- !, R=pred_true.
2864 prop_empty_set(_,_).
2865
2866 :- block remove_element_wf3(-,?,?,?,?,-,?).
2867 % remove_element_wf3(EqRes,H1,H2,T,Res,LWF,DONE) :- print(remove_element_wf3(EqRes,H1,H2,T,Res,LWF,DONE)),nl,fail.
2868 remove_element_wf3(pred_true,_H1,_H2,T,Res,_LWF,DONE) :-
2869 equal_object(T,Res,remove_element_wf3_1),DONE=done.
2870 remove_element_wf3(pred_false,E,H,T,Res,LWF,DONE) :-
2871 ? equal_object([H|RT],Res,remove_element_wf3_2),
2872 ? remove_element_wf2(E,T,RT,LWF,DONE).
2873
2874 /* the same as above: but do not remove if infinite or closure */
2875
2876 :- block remove_element_wf_if_not_infinite_or_closure(?,-,?,?,?,?).
2877 remove_element_wf_if_not_infinite_or_closure(X,Set, Res,WF,LWF,Done) :-
2878 (dont_expand(Set)
2879 -> check_element_of_wf(X,Set,WF),
2880 equal_object_wf(Res,Set,remove_element_wf_if_not_infinite_or_closure,WF),
2881 Done=true % or should we wait until X known ?
2882 %(var(Res)->Res=Set ; equal_object(Res,Set))
2883 ; expand_custom_set_to_list_wf(Set,ESet,_,remove_element_wf_if_not_infinite_or_closure,WF),
2884 remove_element_wf2(X,ESet,Res,LWF,Done)
2885 ).
2886
2887 %:- use_module(bmachine_construction,[external_procedure_used/1]).
2888 %dont_expand(global_set('STRING')) :- !. % s: STRING +-> ... will generate new strings !
2889 %(external_procedure_used(_) -> true). % we could check if there is a STRING generating procedure involved
2890 % unless we use external functions, there is *no* way that new strings can be generated from a B machine !
2891 % Hence: we can expand STRING safely and thus avoid infinite enumeration of partial functions, ...
2892 % example: procs : STRING +-> {"waiting"} & card( dom(procs) ) = 6 thus fails quickly
2893 dont_expand(avl_set(_)) :- !,fail.
2894 dont_expand(Set) :- is_non_expanded_closure(Set).
2895 dont_expand(Set) :- is_infinite_or_very_large_explicit_set(Set). % should we use a smaller bound than 20000 ? see test 1609
2896
2897
2898
2899
2900 :- assert_must_succeed((kernel_objects:remove_exact_first_element([int(1),int(2)],X,[[]]),
2901 X = [[int(1),int(2)],[]])).
2902 :- assert_must_succeed((kernel_objects:remove_exact_first_element(X,global_set('Name'),T),
2903 X==fd(1,'Name'),T==[fd(2,'Name'),fd(3,'Name')])).
2904 :- assert_must_fail((kernel_objects:remove_exact_first_element([[]],X,_),
2905 X = [[int(1),int(2)],[]])).
2906
2907 :- assert_must_succeed((kernel_objects:remove_exact_first_element(X,C,R),
2908 kernel_objects:gen_test_interval_closure(1,2,C),
2909 X == int(1), R == [int(2)] )).
2910
2911 gen_test_interval_closure(From,To,CL) :-
2912 CL=closure(['_zzzz_unary'],[integer],b(member( b(identifier('_zzzz_unary'),integer,[]),
2913 b(interval(b(value(int(From)),integer,[]),
2914 b(value(int(To)),integer,[])),set(integer),[])),pred,[])).
2915
2916 :- block remove_exact_first_element(?,-,?).
2917 remove_exact_first_element(X,Set,Res) :- remove_exact_first_element1(Set,X,Res).
2918
2919 remove_exact_first_element1([],_,_) :- fail.
2920 remove_exact_first_element1([H|T],H,T).
2921 remove_exact_first_element1(avl_set(A),H,T) :- remove_minimum_element_custom_set(avl_set(A),H,T).
2922 remove_exact_first_element1(global_set(GS),H,T) :-
2923 remove_minimum_element_custom_set(global_set(GS),H,T).
2924 remove_exact_first_element1(freetype(GS),H,T) :-
2925 remove_minimum_element_custom_set(freetype(GS),H,T).
2926 remove_exact_first_element1(closure(P,Types,B),H,T) :-
2927 remove_minimum_element_custom_set(closure(P,Types,B),H,T).
2928
2929
2930 :- assert_must_succeed((kernel_objects:delete_element_wf(fd(1,'Name'),X,[fd(2,'Name'),fd(3,'Name')],_WF),
2931 X = global_set('Name'))).
2932 :- assert_must_succeed((kernel_objects:delete_element_wf(int(1),X,[int(2)],_WF),
2933 X = [int(2),int(1)])).
2934 :- assert_must_succeed((kernel_objects:delete_element_wf([int(1),int(2)],X,[],_WF),
2935 X = [[int(2),int(1)]])).
2936 :- assert_must_succeed((kernel_objects:delete_element_wf(int(3),X,[int(2),int(1)],_WF),
2937 X = [int(2),int(1)])).
2938 :- assert_must_succeed((kernel_objects:delete_element_wf(int(1),X,X,_WF),
2939 X = [])).
2940 :- assert_must_fail((kernel_objects:delete_element_wf(int(X),[int(1)],[int(1)],_WF),
2941 X = 1)).
2942
2943 /* WARNING: only use when R is not instantiated by something else;
2944 (except for R=[]) */
2945
2946
2947 :- block delete_element_wf(?,-,?,?).
2948 delete_element_wf(X,Set,Res,WF) :-
2949 ground(X),
2950 try_expand_and_convert_to_avl_with_check(Set,ESet,delete_element_wf),!,
2951 delete_element0(X,ESet,Res,WF).
2952 delete_element_wf(X,Set,Res,WF) :- delete_element1(X,Set,Res,WF).
2953
2954 :- block delete_element0(?,-,?,?).
2955 delete_element0(X,ESet,Res,WF) :-
2956 ( is_custom_explicit_set(ESet,delete_element),
2957 delete_element_from_explicit_set(ESet,X,DS)
2958 -> equal_object_wf(DS,Res,delete_element0,WF)
2959 ; delete_element1(X,ESet,Res,WF)
2960 ).
2961
2962 delete_element1(X,Set,Res,WF) :- expand_custom_set_to_list_wf(Set,ESet,_,delete_element1,WF),
2963 %check_is_expanded_set(ESet,delete_element2),
2964 delete_element2(ESet,X,Res,WF).
2965
2966 :- block delete_element2(-,?,?,?).
2967 delete_element2([],_,[],_). /* same as above, but allow element to be absent */
2968 delete_element2([H2|T],E,R,WF) :-
2969 equality_objects_wf(H2,E,EqRes,WF),
2970 delete_element3(EqRes,H2,T,E,R,WF).
2971 %when_sufficiently_instantiated(E,H2,delete_element3(H1,[H2|T],R)). /* added by Michael Leuschel, 16/3/06 */
2972
2973 :- block delete_element3(-,?,?,?,?,?).
2974 delete_element3(pred_true,_H2,T,_,R,WF) :- equal_object_wf(R,T,delete_element3,WF).
2975 delete_element3(pred_false,H2,T,E,Res,WF) :- equal_cons_wf(Res,H2,RT,WF),delete_element2(T,E,RT,WF).
2976
2977
2978
2979
2980 :- assert_must_succeed(kernel_objects:check_is_expanded_set([int(1)],test)).
2981
2982 :- public check_is_expanded_set/2.
2983 check_is_expanded_set(X,Source) :-
2984 (nonvar(X),(X=[] ; X= [_|_]) -> true
2985 ; add_internal_error('Is not expanded set: ',check_is_expanded_set(X,Source))
2986 ).
2987
2988
2989 /* union/3 */
2990
2991 :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(3)],[int(2),int(1),int(3)],[int(1),int(3),int(2)]))).
2992 :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(1)],[int(1),int(2)],[int(1),int(2)]))).
2993 :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(3)],[int(2),int(1)],[int(1),int(3),int(2)]))).
2994 :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(3),int(2)],[int(2),int(1)],[int(1),int(3),int(2)]))).
2995 :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],union([int(3),int(4)],[int(2),int(1)],[int(1),int(3),int(2)]))).
2996 :- assert_must_succeed((kernel_objects:union([int(1)],[int(2)],Res),kernel_objects:equal_object(Res,[_,_]))).
2997 :- assert_must_succeed((kernel_objects:union([],[int(2)],Res),
2998 kernel_objects:equal_object(Res,[int(2)]))).
2999 :- assert_must_succeed((kernel_objects:union([int(2)],[],Res),
3000 kernel_objects:equal_object(Res,[int(2)]))).
3001 :- assert_must_succeed((kernel_objects:union([int(2)],[int(2)],Res),
3002 kernel_objects:equal_object(Res,[int(2)]))).
3003 :- assert_must_succeed((kernel_objects:union([int(1)],Res,[int(1),int(2)]),
3004 kernel_objects:equal_object(Res,[int(2)]))).
3005 :- assert_must_succeed((kernel_objects:union([fd(1,'Name')],X,Res),X=global_set('Name'),
3006 kernel_objects:equal_object(Res,X))).
3007 :- assert_must_succeed((kernel_objects:union(X,global_set('Name'),Res),X=[fd(2,'Name'),fd(1,'Name')],
3008 kernel_objects:equal_object(Res,global_set('Name')))).
3009 :- assert_must_succeed((kernel_objects:union([fd(1,'Name')],[fd(3,'Name'),fd(2,'Name')],Res),
3010 kernel_objects:equal_object(Res,global_set('Name')))).
3011 %:- assert_must_succeed((kernel_objects:union([fd(1,'Name')],[fd(3,'Name'),fd(2,'Name')],Res),
3012 % kernel_objects:equal_object(Res,X),X=global_set('Name'))).
3013 :- assert_must_fail((kernel_objects:union([int(1)],[int(2)],Res),
3014 (kernel_objects:equal_object(Res,[_]);kernel_objects:equal_object(Res,[_,_,_|_])))).
3015 :- assert_must_fail((kernel_objects:union([int(1)],[int(1)],Res),(Res=[];kernel_objects:equal_object(Res,[_,_|_])))).
3016 :- assert_must_fail((kernel_objects:union([fd(1,'Name')],[fd(2,'Name')],Res),
3017 kernel_objects:equal_object(Res,global_set('Name')))).
3018 % kernel_objects:union([int(1),int(2)],X,[int(1),int(2),int(3)])
3019
3020 union(S1,S2,Res) :- init_wait_flags(WF), union_wf(S1,S2,Res,WF), ground_wait_flags(WF).
3021
3022 :- block union_wf(-,-,-,?).
3023 %union_wf(Set1,Set2,Res,_WF) :- print(union_wf(Set1,Set2,Res)),nl,fail.
3024 ?union_wf(Set1,Set2,Res,WF) :- Set1==[],!,equal_object_wf(Set2,Res,union_wf_1,WF).
3025 union_wf(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,union_wf_2,WF).
3026 union_wf(Set1,Set2,Res,WF) :- Res==[],!,empty_set_wf(Set1,WF), empty_set_wf(Set2,WF).
3027 union_wf(Set1,Set2,Res,WF) :- union0(Set1,Set2,Res,WF).
3028
3029 :- block union0(-,-,?,?), union0(-,?,-,?), union0(?,-,-,?). % require two arguments to be known
3030 %union0(Set1,Set2,Res,_WF) :- print(union0(Set1,Set2,Res)),nl,fail.
3031 union0(Set1,Set2,Res,WF) :- Set1==[],!,equal_object_wf(Set2,Res,union0_1,WF).
3032 union0(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,union0_2,WF).
3033 union0(Set1,Set2,Res,WF) :- Res==[],!,empty_set_wf(Set1,WF), empty_set_wf(Set2,WF).
3034 union0(Set1,Set2,Res,WF) :- nonvar(Res), singleton_set(Res,X),!,
3035 %print(union0_to_singleton_set(Set2,Set1,X,WF)),nl,
3036 (var(Set1) -> union0_to_singleton_set(Set2,Set1,X,WF) ; union0_to_singleton_set(Set1,Set2,X,WF)).
3037 union0(Set1,Set2,Res,WF) :- (var(Set1) -> union1(Set2,Set1,Res,WF) ; union1(Set1,Set2,Res,WF)).
3038
3039 % optimized version for Set1 \/ Set2 = {X}
3040 % TO DO: is not triggered when Set1 and Set2 are instantiated first (before result)
3041 % >>> z:11..12 & {x,y} \/ {v} = {z} does not work
3042 union0_to_singleton_set([],Set2,X,WF) :- !, equal_object_wf(Set2,[X],union0_3,WF). % cannot be reached, due to checks above
3043 union0_to_singleton_set([H|T],Set2,X,WF) :- !, empty_set_wf(T,WF), equal_object_wf(H,X,WF),
3044 check_subset_of_wf(Set2,[X],WF).
3045 union0_to_singleton_set(avl_set(A),Set2,X,WF) :- !, singleton_set(avl_set(A),AEl),
3046 equal_object_wf(AEl,X,WF),
3047 check_subset_of_wf(Set2,[X],WF).
3048 union0_to_singleton_set(Set1,Set2,X,WF) :- % closure or global_set; revert to normal treatment
3049 union1(Set1,Set2,[X],WF).
3050
3051 union1(Set1,Set2,Res,WF) :-
3052 %print_term_summary(union1(Set1,Set2,Res,WF)),nl,
3053 try_expand_and_convert_to_avl_unless_large_or_closure(Set1,ESet1),
3054 try_expand_and_convert_to_avl_unless_large_or_closure(Set2,ESet2),
3055 union1e(ESet1,ESet2,Res,WF). %, print(union1e(ESet1,ESet2,Res,WF)),nl.
3056
3057 ?try_expand_and_convert_to_avl_unless_large_or_closure(Set,ESet) :- (var(Set);Set=closure(_,_,_)),!,ESet=Set.
3058 try_expand_and_convert_to_avl_unless_large_or_closure(Set,ESet) :-
3059 try_expand_and_convert_to_avl_unless_large(Set,ESet).
3060
3061 union1e(Set1,Set2,Res,WF) :- % print_term_summary(union1e(Set1,Set2,Res)),
3062 is_custom_explicit_set(Set1,union1e), %print(try_union(Set1,Set2)),nl,
3063 union_of_explicit_set(Set1,Set2,Union), !,
3064 %print_term_summary(explicit_set_union(Union)),
3065 equal_object_wf(Union,Res,union1e,WF).
3066 union1e(Set2,Set1,Res,WF) :- % Set2=avl_set(_), nonvar(Set1), Set1 \= avl_set(_),
3067 nonvar(Set1), Set1=avl_set(_), Set2 \= avl_set(_), \+ ground(Set2),
3068 !, % avoid expanding Set2
3069 % print_term_summary(union_invert_arguments(Set2,Set1,Res)),
3070 expand_custom_set_to_list_wf(Set1,ESet1,_,union1e_1,WF),
3071 union2(ESet1,Set2,Res,WF), lazy_check_subset_of(Set2,Res,WF).
3072 union1e(Set1,Set2,Res,WF) :-
3073 expand_custom_set_to_list_wf(Set1,ESet1,_,union1e_2,WF), % we could avoid this expansion by treating avl_set,... below in union2
3074 union2(ESet1,Set2,Res,WF),
3075 lazy_check_subset_of(Set1,Res,WF), % ADDED to solve {x,y| { x \/ y } <: {{1} \/ {2}}}
3076 lazy_check_subset_of(Set2,Res,WF) % could perform additional constraint checking
3077 %%,nl, print(union2_result(ESet1,Set2,Res)),nl,nl
3078 % ,try_prop_card_leq(ESet1,Res), try_prop_card_leq(Set2,Res). %%% seems to slow down ProB: investigate
3079 .
3080
3081 :- block lazy_try_check_element_of(?,-,?).
3082 lazy_try_check_element_of(_H,V,_) :- %print(lazy(_H,V)),nl,
3083 var(V),!.
3084 lazy_try_check_element_of(H,Set,WF) :- lazy_check_element_of_aux(Set,H,WF).
3085
3086 lazy_check_element_of_aux(closure(P,T,B),H,WF) :- !, check_element_of_wf(H,closure(P,T,B),WF).
3087 lazy_check_element_of_aux(avl_set(A),H,WF) :- !, check_element_of_wf(H,avl_set(A),WF).
3088 lazy_check_element_of_aux([X|T],H,WF) :- !, lazy_check_element_of_list(T,X,H,WF).
3089 lazy_check_element_of_aux(_,_,_).
3090
3091 :- block lazy_check_element_of_list(-,?,?,?).
3092 lazy_check_element_of_list([],X,H,WF) :- !, equal_object_wf(X,H,WF).
3093 lazy_check_element_of_list([Y|T],X,H,WF) :- !, %% print(quick_lst(H,[X,Y|T])),nl,
3094 quick_propagation_element_information([X,Y|T],H,WF,_). % TO DO: check that we loose no performance due to this
3095 lazy_check_element_of_list(_,_,_,_).
3096
3097 % an incomplete subset check without enumeration
3098 :- block lazy_check_subset_of(-,?,?), lazy_check_subset_of(?,-,?).
3099 % lazy_check_subset_of(A,B,_) :- print(lazy_check_subset(A,B)),nl,fail.
3100 lazy_check_subset_of(Set1,Set2,WF) :- nonvar(Set2),
3101 (Set2=closure(_,_,_) ; Set2=avl_set(_)),!, lazy_check_subset_of2(Set1,Set2,WF).
3102 lazy_check_subset_of(_,_,_). % ignore other set representations
3103 :- block lazy_check_subset_of2(-,?,?).
3104 lazy_check_subset_of2([],_,_WF) :- !.
3105 lazy_check_subset_of2([H|T],Set,WF) :- !, check_element_of_wf(H,Set,WF), lazy_check_subset_of2(T,Set,WF).
3106 lazy_check_subset_of2(_,_,_). % ignore other set representations
3107
3108 :- block union2(-,?,?,?).
3109 %union2(A,B,R,_) :- print(union2(A,B,R)),nl,fail.
3110 ?union2([],S,Res,WF) :- equal_object_optimized_wf(S,Res,union2,WF).
3111 union2([H|T],Set2,Res,WF) :-
3112 ? (T\==[],nonvar(Set2), Set2=[H2|T2], T2==[] % minor optimisation for improved propagation; e.g., for x:S & S<:1..13 & S \/ {x} = S2 & x/: S2
3113 % the constraint is not yet detected straight away: x:S & S<:1..12 & S \/ {x} /= S
3114 -> union3(H2,T2,[H|T],Res,WF)
3115 ? ; union3(H,T,Set2,Res,WF)
3116 ).
3117 union3(H,T,Set2,Res,WF) :-
3118 ? add_element_wf(H,Set2,R,Done,WF), %print(add_element(H,Set2,R,Done)),nl,
3119 ? lazy_try_check_element_of(H,Res,WF), % TO DO: propagate constraint that H is in Res
3120 ? (T==[] -> union2(T,R,Res,WF) ; union4(Done,T,R,Res,WF)).
3121 :- block union4(-,?,?,?,?).
3122 ?union4(_Done,T,R,Res,WF) :- union2(T,R,Res,WF). % if WF not set to 2 there maybe equality_objects pending from add_element_wf ! TO DO: investigate; see test 293
3123
3124
3125 :- assert_must_succeed(exhaustive_kernel_check(union_generalized([[int(3)],[int(2),int(1),int(3)]],[int(1),int(3),int(2)]))).
3126 :- assert_must_succeed(exhaustive_kernel_check(union_generalized([[int(3),int(2)],[],[int(2),int(1),int(3)]],[int(1),int(3),int(2)]))).
3127 :- assert_must_succeed(exhaustive_kernel_fail_check(union_generalized([[int(3)],[int(3),int(4)],[int(2),int(1),int(3)]],[int(1),int(3),int(2)]))).
3128 :- assert_must_succeed((kernel_objects:union_generalized([[]],Res),Res=[])).
3129 :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2)]],Res),
3130 kernel_objects:equal_object(Res,[_,_]))).
3131 :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2),int(1)]],Res),
3132 kernel_objects:equal_object(Res,[_,_]))).
3133 :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2),int(1)],[],[int(2)]],Res),
3134 kernel_objects:equal_object(Res,[_,_]))).
3135 :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2)],X],Res),
3136 kernel_objects:equal_object(X,Res), X = [int(2),int(1),int(3)])).
3137 :- assert_must_succeed((kernel_objects:union_generalized([global_set('Name'),X,X,X],Res),
3138 kernel_objects:equal_object(global_set('Name'),Res), X = [fd(2,'Name'),fd(1,'Name')])).
3139 :- assert_must_succeed((kernel_objects:union_generalized([X,global_set('Name')],Res),
3140 kernel_objects:equal_object(global_set('Name'),Res), X = [fd(2,'Name'),fd(1,'Name')])).
3141 :- assert_must_fail((kernel_objects:union_generalized([[int(1)],[int(2)]],Res),(Res=[_];
3142 kernel_objects:equal_object(Res,[_,_,_|_])))).
3143 :- assert_must_fail((kernel_objects:union_generalized([[int(1)],[int(1)]],Res),(Res=[];
3144 kernel_objects:equal_object(Res,[_,_|_])))).
3145
3146 % treates the general_union AST node (union(.) in B syntax)
3147 union_generalized(S,Res) :- init_wait_flags(WF), union_generalized_wf(S,Res,WF), ground_wait_flags(WF).
3148
3149 :- block union_generalized_wf(-,-,?).
3150 union_generalized_wf(SetsOfSets,Res,WF) :- var(SetsOfSets), Res==[],!,
3151 expand_custom_set_to_list(SetsOfSets,ESetsOfSets,_,union_generalized_wf),
3152 %print(check_all_empty(SetsOfSets)),nl, when(nonvar(SetsOfSets),(print(check_all_emptynv(SetsOfSets)),nl)),
3153 all_empty_sets_wf(ESetsOfSets,WF).
3154 union_generalized_wf(SetsOfSets,Res,WF) :-
3155 union_generalized_wf2(SetsOfSets,Res,WF).
3156
3157 :- block union_generalized_wf2(-,?,?).
3158 union_generalized_wf2(SetsOfSets,Res,WF) :-
3159 custom_explicit_sets:union_generalized_explicit_set(SetsOfSets,ARes,WF),!,
3160 %print_term_summary(union_generalized_explicit_set(SetsOfSets,ARes,Res,WF)),nl,
3161 equal_object_optimized_wf(ARes,Res,union_generalized_avl_set,WF).
3162 union_generalized_wf2(SetsOfSets,Res,WF) :-
3163 expand_custom_set_to_list(SetsOfSets,ESetsOfSets,_,union_generalized_wf2),
3164 union_generalized2(ESetsOfSets,[],Res,WF). %, print(res(Res)),nl.
3165
3166 :- block union_generalized2(-,?,?,?).
3167 union_generalized2([],S,Res,WF) :- equal_object_optimized_wf(S,Res,union_generalized2,WF).
3168 union_generalized2([H|T],UnionSoFar,Res,WF) :- Res==[],!, %print(empty(H,T,UnionSoFar)),nl,
3169 empty_set_wf(H,WF), empty_set_wf(UnionSoFar,WF), all_empty_sets_wf(T,WF).
3170 union_generalized2([H|T],UnionSoFar,Res,WF) :- union_wf(H,UnionSoFar,UnionSoFar2,WF),
3171 %print_message(called_union(H,UnionSoFar,UnionSoFar2,res(Res))), %%
3172 (((var(T);var(UnionSoFar2)),
3173 nonvar(Res),is_custom_explicit_set(Res,union_generalized2) % check important for Schneider2_Trees/NewSolver_v3_complex.mch and query CHOOSE_MODULES("bk-phi-H-2013", solution) (0.1 vs 0.9 secs)
3174 )
3175 -> check_subset_of_wf(H,Res,WF)
3176 % this is only a very weak propagation; example, for union(v) = {4444} & v={{x},{y},{z}} we will instantiate v={{4444},...} and z=4444; see also test 1216
3177 ; true),
3178 union_generalized2(T,UnionSoFar2,Res,WF).
3179
3180 :- block all_empty_sets_wf(-,?).
3181 all_empty_sets_wf([],_).
3182 all_empty_sets_wf([H|T],WF) :- empty_set_wf(H,WF), all_empty_sets_wf(T,WF).
3183
3184 :- assert_must_succeed(exhaustive_kernel_check([commutative],intersection([int(3)],[int(2),int(1),int(3)],[int(3)]))).
3185 :- assert_must_succeed(exhaustive_kernel_check([commutative],intersection([int(4),int(3),int(2)],[int(2),int(1),int(3)],[int(2),int(3)]))).
3186 :- assert_must_succeed(exhaustive_kernel_check([commutative],intersection([int(4),int(3),int(2)],[],[]))).
3187 :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],intersection([int(1),int(3)],[int(4),int(3),int(2)],[]))).
3188 :- assert_must_succeed((kernel_objects:intersection(Y,X,Res),X=global_set('Name'),
3189 kernel_objects:equal_object(Res,Y), Y =[fd(1,'Name')])).
3190 :- assert_must_succeed((kernel_objects:intersection([int(1)],[int(2)],Res),Res=[])).
3191 :- assert_must_succeed((kernel_objects:intersection([int(1)],[int(2)],[]))).
3192 :- assert_must_fail((kernel_objects:intersection([int(1),int(4),int(3)],[int(2),int(3)],[]))).
3193 :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(1)],_))).
3194 :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(1)],[int(2),int(1)]))).
3195 :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(1)],[int(1),int(2)]))).
3196 :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(3)],Res),
3197 kernel_objects:equal_object(Res,[int(2)]))).
3198 :- assert_must_succeed((kernel_objects:intersection([int(2)],[int(2)],Res),
3199 kernel_objects:equal_object(Res,[int(2)]))).
3200 :- assert_must_succeed((kernel_objects:intersection([int(2),int(3)],[int(3),int(4),int(2)],Res),
3201 kernel_objects:equal_object(Res,[int(2),int(3)]))).
3202 :- assert_must_fail((kernel_objects:intersection([int(1)],[int(2)],Res),(
3203 kernel_objects:equal_object(Res,[_|_])))).
3204 :- assert_must_fail((kernel_objects:intersection([int(1)],[int(1)],Res),(Res=[];
3205 kernel_objects:equal_object(Res,[_,_|_])))).
3206 :- assert_must_fail((kernel_objects:intersection([fd(1,'Name')],X,Res),X=global_set('Name'),
3207 kernel_objects:equal_object(Res,X))).
3208
3209
3210 intersection(S1,S2,Res) :- init_wait_flags(WF), intersection(S1,S2,Res,WF), ground_wait_flags(WF).
3211
3212 :- block intersection(-,-,-,?).
3213 intersection(Set1,Set2,Res,WF) :- (Set1==[] ; Set2==[]),!, empty_set_wf(Res,WF).
3214 intersection(Set1,Set2,Res,WF) :- quick_same_value(Set1,Set2),!, % print_term_summary(inter_eq_eq(Set1)),nl,
3215 equal_object_wf(Res,Set1,inter0_equal,WF).
3216 intersection(Set1,Set2,Res,WF) :- Res==[],!,
3217 disjoint_sets(Set1,Set2,WF).
3218 intersection(Set1,Set2,Res,WF) :- % now we need to know at least a bit about both Set1 and Set2; at least given the current code below; TO DO: infer that {x} /\ s = {x} => x:s
3219 %print(intersection0(Set1,Set2,Res,WF)),nl,
3220 intersection0(Set1,Set2,Res,WF),
3221 propagate_intersection(Set1,Set2,Res,WF).
3222
3223 :- block propagate_intersection(?,?,-,?). % propagate constraint that result elements must be in both sets
3224 %propagate_intersection(Set1,Set2,Set3,WF) :- print(inter(Set1,Set2,WF)),nl,print(res(Set3)),nl,fail.
3225 propagate_intersection(Set1,Set2,[H|T],WF) :- !,
3226 propagate_intersection_aux(Set1,Set2,H,T,WF).
3227 propagate_intersection(Set1,Set2,avl_set(A),WF) :- !,
3228 ((unknown_set(Set1) ; unknown_set(Set2)) % otherwise intersection0 has already triggered below
3229 -> custom_explicit_sets:avl_approximate_size(A,Size),
3230 %print(prop_inter(Size)),nl,
3231 (Size<20
3232 -> expand_custom_set_to_list(avl_set(A),ESet,_,propagate_intersection)
3233 ; avl_min(A,Min), avl_max(A,Max), ESet=[Min,Max]
3234 ),
3235 propagate_intersection(Set1,Set2,ESet,WF)
3236 ; true).
3237 % other cases: Set1,2,3 could be interval closure with unknown bounds,...
3238 propagate_intersection(_,_,_,_).
3239
3240 :- block propagate_intersection_aux(-,-,-,?,?).
3241 propagate_intersection_aux(Set1,Set2,H,T,WF) :-
3242 ((unknown_set(Set1) ; unknown_set(Set2)) % otherwise intersection0 has already triggered below
3243 -> % print(prop(H,T,Set1,Set2)),nl,
3244 check_element_of_wf(H,Set1,WF),
3245 check_element_of_wf(H,Set2,WF),
3246 propagate_intersection(Set1,Set2,T,WF)
3247 ; true).
3248
3249 unknown_set(Set) :- var(Set),!.
3250 unknown_set([H|T]) :- (unknown_val(H) -> true ; unknown_set(T)).
3251 unknown_val(Val) :- var(Val),!.
3252 unknown_val(int(X)) :- var(X).
3253 unknown_val(string(X)) :- var(X).
3254 unknown_val(fd(X,_)) :- var(X).
3255 unknown_val((A,B)) :- (unknown_val(A) -> true ; unknown_val(B)).
3256 unknown_val([H|T]) :- (unknown_val(H) -> true ; unknown_set(T)).
3257 :- block intersection0(-,?,?,?), intersection0(?,-,?,?).
3258 intersection0(Set1,Set2,Res,WF) :- (Set1==[] ; Set2==[]),!, empty_set_wf(Res,WF).
3259 intersection0(Set1,Set2,Res,WF) :- quick_same_value(Set1,Set2),!, % print_term_summary(inter0_eq_eq(Set1)),nl,
3260 equal_object_wf(Res,Set1,inter0_equal,WF).
3261 intersection0(Set1,Set2,Res,WF) :- Res==[],!,
3262 disjoint_sets(Set1,Set2,WF).
3263 intersection0(Set1,Set2,Res,WF) :-
3264 ? intersection_with_interval_closure(Set1,Set2,Inter),!, % avoid expanding intervals at all
3265 %print_term_summary(inter0(Set1,Set2,Inter)),nl,
3266 equal_object_wf(Inter,Res,intersection0,WF).
3267 intersection0(Set1,Set2,Res,WF) :-
3268 try_expand_and_convert_to_avl_unless_large(Set1,ESet1),
3269 try_expand_and_convert_to_avl_unless_large(Set2,ESet2),
3270 intersection1(ESet1,ESet2,Res,WF).
3271
3272 intersection1(Set1,Set2,Res,WF) :- nonvar(Set1),is_custom_explicit_set(Set1,intersection),
3273 %% print_term_summary(try_inter(Set1,Set2,Res)),nl, %%
3274 intersection_of_explicit_set_wf(Set1,Set2,Inter,WF), !,
3275 %print_term_summary(explicit_set_inter(Set1,Set2,Inter)), %%
3276 equal_object_wf(Inter,Res,intersection1,WF).
3277 intersection1(Set1,Set2,Res,WF) :-
3278 %% print_term_summary(intersection(Set1,Set2,Res) ), %%
3279 (Res==[] -> % print_term_summary(disjoint(Set1,Set2)),
3280 disjoint_sets(Set1,Set2,WF)
3281 ;
3282 (swap_set(Set1,Set2) -> intersection2(Set2,Set1,Res,WF)
3283 ; intersection2(Set1,Set2,Res,WF))
3284 ).
3285
3286 swap_set(Set1,_Set2) :- var(Set1),!.
3287 swap_set(_Set1,Set2) :- var(Set2),!,fail.
3288 %swap_set(_Set1,Set2) :- is_infinite_explicit_set(Set2),!,fail.
3289 swap_set(avl_set(_),Set2) :- \+ functor(Set2,avl_set,2), %Set2 \= avl_set(_),
3290 Set2 \= [],
3291 \+ functor(Set2,closure,3), %Set2 \= closure(_,_,_),
3292 \+ functor(Set2,global_set,1). %Set2 \= global_set(_). % if it was a small closure, intersection_of_explicit_set should have triggered
3293 swap_set(closure(_P,_T,_B),Set2) :- ok_to_swap(Set2). % TO DO: for two closures: we could try and use the smallest one as first argument to intersection2
3294 swap_set(global_set(_GS),Set2) :- ok_to_swap(Set2).
3295
3296 ok_to_swap(global_set(GS)) :- !, \+ is_infinite_or_very_large_explicit_set(global_set(GS),1000000).
3297 ok_to_swap(closure(P,T,B)) :- !,\+ is_infinite_or_very_large_explicit_set(closure(P,T,B),1000000).
3298 ok_to_swap(_).
3299 % maybe also use is_efficient_custom_set as below ??
3300 % what about freetype ?
3301
3302
3303 intersection2(Set1,Set2,Res,WF) :- % print_term_summary(expand_inter1(Set1,Set2,Res,WF)),
3304 expand_custom_set_to_list(Set1,ESet1,_,intersection2),
3305 % print_term_summary(expanded_inter1(Set1)),
3306 intersection3(ESet1,Set2,Res,WF).
3307 :- block intersection3(-,?,?,?).
3308 intersection3([],_,Res,WF) :- empty_set_wf(Res,WF).
3309 intersection3([H|T],Set,Res,WF) :-
3310 (Res==[] -> %print(inter_res_empty(H,T,Set)),nl,
3311 not_element_of_wf(H,Set,WF),intersection3(T,Set,Res,WF)
3312 ; membership_test_wf(Set,H,MemRes,WF),
3313 %print(mem_test(H,MemRes)),nl, %
3314 intersection4(MemRes,H,T,Set,Res,WF)
3315 ).
3316
3317 :- block intersection4(-,?,?, ?,?,?).
3318 intersection4(pred_true,H,T,Set,Result,WF) :- %print(inter4_mem_obj(H)),nl,
3319 %check_element_of(H,Set),
3320 equal_object_wf([H|Res],Result,intersection4,WF),
3321 intersection3(T,Set,Res,WF).
3322 intersection4(pred_false,_H,T,Set,Res,WF) :- %not_element_of(H,Set),
3323 intersection3(T,Set,Res,WF).
3324
3325
3326 :- assert_must_succeed(exhaustive_kernel_check_wfdet(disjoint_sets([int(5)],[int(2),int(1),int(3)],WF),WF)).
3327 :- assert_must_succeed(exhaustive_kernel_check_wfdet(disjoint_sets([int(5)],[],WF),WF)).
3328 :- assert_must_succeed(exhaustive_kernel_check_wfdet(disjoint_sets([int(5),int(2)],[int(6),int(1),int(3)],WF),WF)).
3329
3330 disjoint_sets(S1,S2) :- init_wait_flags(WF),
3331 disjoint_sets(S1,S2,WF),
3332 ground_wait_flags(WF).
3333
3334 :- block disjoint_sets(-,?,?), disjoint_sets(?,-,?).
3335 disjoint_sets(S1,S2,WF) :-
3336 % print_term_summary(disjoint_sets(S1,S2)),
3337 % TO DO: we could provide faster code for two avl sets or intervals; but probably caught in intersection code above?
3338 ((S1==[];S2==[]) -> true
3339 ; is_efficient_custom_set(S2) -> expand_custom_set_to_list(S1,ESet1,_,disjoint_sets_1),
3340 disjoint_sets2(ESet1,S2,WF)
3341 ; is_efficient_custom_set(S1) -> expand_custom_set_to_list(S2,ESet2,_,disjoint_sets_2),
3342 disjoint_sets2(ESet2,S1,WF)
3343 ; expand_custom_set_to_list(S1,ESet1,_,disjoint_sets_3),
3344 %expand_custom_set_to_list(S2,ESet2,_,disjoint_sets_4),
3345 disjoint_sets2(ESet1,S2,WF)
3346 ).
3347
3348 % TO DO: we could infer some constraints on the possible max sizes of the sets
3349 % for finite types (sum of size must be <= size of type)
3350 :- block disjoint_sets2(-,?,?).
3351 disjoint_sets2([],_,_WF).
3352 disjoint_sets2([H|T],S2,WF) :- not_element_of_wf(H,S2,WF), disjoint_sets2(T,S2,WF).
3353
3354 % NOT YET USED: not_disjoint_sets could be used for S /\ R /= {}
3355 :- assert_must_succeed(exhaustive_kernel_check_wfdet(not_disjoint_sets([int(3)],[int(2),int(1),int(3)],WF),WF)).
3356 :- block not_disjoint_sets(-,?,?), not_disjoint_sets(?,-,?).
3357 not_disjoint_sets(S1,S2,WF) :-
3358 ((S1==[];S2==[]) -> fail
3359 ; is_efficient_custom_set(S2) -> expand_custom_set_to_list(S1,ESet1,_,disjoint_sets_1),
3360 not_disjoint_sets2(ESet1,S2,WF)
3361 ; is_efficient_custom_set(S1) -> expand_custom_set_to_list(S2,ESet2,_,disjoint_sets_2),
3362 not_disjoint_sets2(ESet2,S1,WF)
3363 ; expand_custom_set_to_list(S1,ESet1,_,disjoint_sets_3),
3364 %expand_custom_set_to_list(S2,ESet2,_,disjoint_sets_4),
3365 not_disjoint_sets2(ESet1,S2,WF)
3366 ).
3367
3368 :- block not_disjoint_sets2(-,?,?).
3369 not_disjoint_sets2([],_,_WF).
3370 not_disjoint_sets2([H|T],S2,WF) :- membership_test_wf(S2,H,MemRes,WF), not_disjoint3(MemRes,T,S2,WF).
3371
3372 :- block not_disjoint3(-,?,?,?).
3373 not_disjoint3(pred_true,_,_,_).
3374 not_disjoint3(pred_false,T,S2,WF) :- not_disjoint_sets2(T,S2,WF).
3375
3376 :- assert_must_succeed(exhaustive_kernel_check_wfdet(intersection_generalized_wf([[int(3)],[int(2),int(1),int(3)]],[int(3)],unknown,WF),WF)).
3377 :- assert_must_succeed(exhaustive_kernel_check_wfdet(intersection_generalized_wf([[int(3),int(2)],[int(2),int(1),int(3)],[int(4),int(3)]],[int(3)],unknown,WF),WF)).
3378 :- assert_must_succeed((kernel_objects:intersection_generalized_wf(avl_set(node(avl_set(node(fd(1,'Name'),true,1,empty,node(fd(2,'Name'),true,0,empty,empty))),
3379 true,1,empty,node(avl_set(node(fd(2,'Name'),true,1,empty,node(fd(3,'Name'),true,0,empty,empty))),true,0,empty,empty))),
3380 avl_set(node(fd(2,'Name'),true,0,empty,empty)),unknown,_WF))).
3381 :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(1)],[int(2)]],Res,unknown,_WF),Res=[])).
3382 :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(1)],[int(2),int(1)]],Res,unknown,_WF),
3383 kernel_objects:equal_object(Res,[int(1)]))).
3384 :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(1)],X,[int(2),int(3),int(1)]],Res,unknown,_WF),
3385 X = [int(2),int(1)],
3386 kernel_objects:equal_object(Res,[int(1)]))).
3387 :- assert_must_succeed((kernel_objects:intersection_generalized_wf([X,X,[int(2),int(3),int(1)]],Res,unknown,_WF),
3388 X = [int(2),int(1)], kernel_objects:equal_object(Res,[int(1),int(2)]))).
3389 :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(2),int(1),int(3)],X,[int(1),int(2)],X],Res,unknown,_WF),
3390 kernel_objects:equal_object(X,Res), X = [int(2),int(1)])).
3391 :- assert_must_succeed((kernel_objects:intersection_generalized_wf([global_set('Name'),X],Res,unknown,_WF),
3392 kernel_objects:equal_object(X,Res), X = [fd(2,'Name'),fd(1,'Name')])).
3393 :- assert_must_fail((kernel_objects:intersection_generalized_wf([[int(1)],[int(2)]],Res,unknown,_WF),(
3394 kernel_objects:equal_object(Res,[_|_])))).
3395 :- assert_must_fail((kernel_objects:intersection_generalized_wf([[int(1)],[int(1)]],Res,unknown,_WF),(Res=[];
3396 kernel_objects:equal_object(Res,[_,_|_])))).
3397 :- assert_must_abort_wf(kernel_objects:intersection_generalized_wf([],_R,unknown,WF),WF).
3398
3399 % code for general_intersection
3400 :- block intersection_generalized_wf(-,?,?,?).
3401 intersection_generalized_wf(SetsOfSets,Res,Span,WF) :-
3402 expand_custom_set_to_list(SetsOfSets,ESetsOfSets,_,intersection_generalized_wf),
3403 intersection_generalized2(ESetsOfSets,Res,Span,WF).
3404
3405 intersection_generalized2([],Res,Span,WF) :- /* Atelier-B manual requires argument to inter to be non-empty */
3406 add_wd_error_set_result('inter applied to empty set','',Res,[],Span,WF).
3407 intersection_generalized2([H|T],Res,_Span,WF) :- intersection_generalized3(T,H,Res,WF).
3408 :- block intersection_generalized3(-,?,?,?).
3409 intersection_generalized3([],SoFar,Res,WF) :- equal_object_optimized_wf(SoFar,Res,intersection_generalized3,WF).
3410 intersection_generalized3([H|T],InterSoFar,Res,WF) :-
3411 intersection(H,InterSoFar,InterSoFar2,WF),
3412 intersection_generalized3(T,InterSoFar2,Res,WF).
3413
3414 :- assert_must_succeed(exhaustive_kernel_check(difference_set([int(3),int(2)],[int(2),int(1),int(3)],[]))).
3415 :- assert_must_succeed(exhaustive_kernel_check(difference_set([int(3),int(2)],[int(2),int(1),int(4)],[int(3)]))).
3416 :- assert_must_succeed((kernel_objects:difference_set(SSS,[[int(1),int(2)]],[]),
3417 kernel_objects:equal_object(SSS,[[int(2),int(1)]]))).
3418 :- assert_must_succeed((kernel_objects:difference_set(SSS,[[int(1),int(2)]],R), kernel_objects:equal_object(R,[]),
3419 kernel_objects:equal_object(SSS,[[int(2),int(1)]]))).
3420 :- assert_must_succeed((kernel_objects:difference_set(SSS,[[fd(1,'Name'),fd(2,'Name')]],R),
3421 kernel_objects:equal_object(R,[]),
3422 kernel_objects:equal_object(SSS,[[fd(2,'Name'),fd(1,'Name')]]))).
3423 :- assert_must_succeed((kernel_objects:difference_set(SSS,[[int(1),int(2)]],[]),
3424 kernel_objects:equal_object(SSS,[[int(1),int(2)]]))).
3425 :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[int(1)],_))).
3426 :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[int(2)],_))).
3427 :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[int(2)],[int(1)]))).
3428 :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[],[int(2),int(1)]))).
3429 :- assert_must_succeed((kernel_objects:difference_set([],[int(1),int(2)],[]))).
3430 :- assert_must_succeed((kernel_objects:difference_set(Y,X,Res),X=global_set('Name'),
3431 kernel_objects:equal_object(Res,[]), Y =[fd(1,'Name')])).
3432 :- assert_must_succeed((kernel_objects:difference_set(X,Y,Res),X=global_set('Name'),
3433 kernel_objects:equal_object(Res,[fd(3,'Name'),fd(1,'Name')]), Y =[fd(2,'Name')])).
3434 :- assert_must_fail((kernel_objects:difference_set(X,Y,Res),X=global_set('Name'),
3435 kernel_objects:equal_object(Res,[]), Y =[fd(1,'Name'),fd(2,'Name')])).
3436 :- assert_must_fail((kernel_objects:difference_set(Y,X,Res),X=global_set('Name'),
3437 kernel_objects:equal_object(Res,Y), Y =[fd(1,'Name')])).
3438
3439 difference_set(Set1,Set2,Res) :- init_wait_flags(WF),
3440 difference_set_wf(Set1,Set2,Res,WF),
3441 ground_wait_flags(WF).
3442
3443 :- block difference_set_wf(-,-,?,?).
3444 difference_set_wf(Set1,_,Res,WF) :- Set1==[],!,empty_set_wf(Res,WF).
3445 difference_set_wf(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,difference_set_wf,WF).
3446 difference_set_wf(Set1,Set2,Res,WF) :- difference_set1(Set1,Set2,Res,WF).
3447
3448
3449 :- block difference_set1(?,-,-,?), difference_set1(-,?,-,?).
3450 difference_set1(Set1,Set2,Res,WF) :-
3451 ? nonvar(Set1),is_custom_explicit_set(Set1,difference_set),
3452 ? difference_of_explicit_set_wf(Set1,Set2,Diff,WF), !,
3453 %print_term_summary(explicit_set_diff(Set1,Set2,Diff)),%
3454 ? equal_object_wf(Diff,Res,difference_set1_1,WF).
3455 difference_set1(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,difference_set1_2,WF).
3456 difference_set1(Set1,Set2,Res,WF) :- Res==[],!, check_subset_of_wf(Set1,Set2,WF).
3457 difference_set1(Set1,Set2,Res,WF) :- %print(diff(Set1,Set2,Res)),nl,%
3458 expand_custom_set_to_list(Set1,ESet1,_,difference_set1), %print_term_summary(expanded(Set1,ESet1)),
3459 compute_diff(ESet1,Set2,Res,WF),
3460 %print_term_summary(computed_diff(ESet1,Set2,Res)),nl,%
3461 propagate_into2(Res,ESet1,Set2,WF). %print(propagated(ESet1,Set2)),nl.
3462
3463 :- block compute_diff(-,?,?,?).
3464 compute_diff([],_Set2,Res,WF) :- empty_set_wf(Res,WF).
3465 compute_diff([H|T],Set2,Res,WF) :-
3466 ? membership_test_wf(Set2,H,MemRes,WF),compute_diff2(MemRes,H,T,Set2,Res,WF).
3467
3468 :- block compute_diff2(-,?,?,?,?,?).
3469 compute_diff2(pred_true,_H,T,Set2,Res,WF) :- compute_diff(T,Set2,Res,WF).
3470 ?compute_diff2(pred_false,H,T,Set2,Res,WF) :- equal_object_wf([H|R2],Res,compute_diff2,WF),
3471 ? compute_diff(T,Set2,R2,WF).
3472
3473 % propagate all elements from one set into another one; do not use for computation; may skip elements ...
3474 /* this version not used at the moment:
3475 :- block propagate_into(-,?,?).
3476 propagate_into(_,Set2,_WF) :- nonvar(Set2),
3477 is_custom_explicit_set(Set2,propagate_into),!. % second set already fully known
3478 propagate_into([],_,_WF) :- !.
3479 propagate_into([H|T],Set,WF) :- !,check_element_of_wf(H,Set,WF), propagate_into(T,Set,WF).
3480 propagate_into(Set1,Set2,WF) :- is_custom_explicit_set(Set1,propagate_into),!,
3481 (is_infinite_explicit_set(Set1) -> true ;
3482 expand_custom_set_to_list(Set1,ESet1), propagate_into(ESet1,Set2,WF)). */
3483
3484 :- block propagate_into2(-,?,?,?).
3485 propagate_into2(_,Set2,_NegSet,_WF) :- nonvar(Set2),
3486 is_custom_explicit_set(Set2,propagate_into),!. % second set already fully known
3487 propagate_into2([],_,_,_WF) :- !.
3488 propagate_into2([H|T],PosSet,NegSet,WF) :- !,
3489 check_element_of_wf(H,PosSet,WF),
3490 not_element_of_wf(H,NegSet,WF),propagate_into2(T,PosSet,NegSet,WF).
3491 propagate_into2(Set1,PosSet,NegSet,WF) :- is_custom_explicit_set(Set1,propagate_into),!,
3492 (is_infinite_explicit_set(Set1) -> true ;
3493 expand_custom_set_to_list(Set1,ESet1,_,propagate_into2), propagate_into2(ESet1,PosSet,NegSet,WF)).
3494
3495 :- assert_must_succeed(exhaustive_kernel_check_wf(in_difference_set_wf(int(33),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3496 :- block in_difference_set_wf(-,-,-,?).
3497 in_difference_set_wf(A,X,Y,WF) :-
3498 ? (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)),
3499 % symbolic treatment would also make sense when A is nonvar and X var to force A to be in X ?!
3500 % print_term_summary(symbolic_treatment_in_difference_set_wf(A,X,Y,WF)),
3501 !,
3502 check_element_of_wf(A,X,WF), not_element_of_wf(A,Y,WF).
3503 in_difference_set_wf(A,X,Y,WF) :-
3504 difference_set_wf(X,Y,Diff,WF),
3505 check_element_of_wf(A,Diff,WF).
3506
3507 treat_arg_symbolically(X) :- var(X),!.
3508 treat_arg_symbolically(global_set(_)).
3509 treat_arg_symbolically(freetype(_)).
3510 treat_arg_symbolically(closure(P,T,B)) :- \+ small_interval(P,T,B).
3511
3512 small_interval(P,T,B) :- is_interval_closure(P,T,B,Low,Up),
3513 number(Low),number(Up),
3514 Up-Low < 500. % Magic Constant; TO DO: determine good value
3515
3516
3517 :- assert_must_succeed(exhaustive_kernel_check_wf(not_in_difference_set_wf(int(2),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3518 :- assert_must_succeed(exhaustive_kernel_check_wf(not_in_difference_set_wf(int(111),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3519 :- assert_must_succeed(exhaustive_kernel_check_wf(not_in_difference_set_wf(int(1),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3520
3521 :- block not_in_difference_set_wf(-,-,-,?).
3522 not_in_difference_set_wf(A,X,Y,WF) :-
3523 (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)),
3524 !, %print(not_in_diff(A,X,Y,WF)),nl,
3525 % A : (X-Y) <=> A:X & not(A:Y)
3526 % A /: (X-Y) <=> A/: X or A:Y
3527 membership_test_wf(X,A,AX_Res,WF),
3528 (AX_Res==pred_false -> true
3529 ; bool_pred:negate(AX_Res,NotAX_Res),
3530 b_interpreter_check:disjoin(NotAX_Res,AY_Res,pred_true,priority(16384),priority(16384),WF), % better: uese a version that does not do a case split ?! or use last wait flag ?
3531 membership_test_wf(Y,A,AY_Res,WF)
3532 ).
3533 not_in_difference_set_wf(A,X,Y,WF) :-
3534 difference_set_wf(X,Y,Diff,WF),
3535 not_element_of_wf(A,Diff,WF).
3536
3537
3538 :- assert_must_succeed(exhaustive_kernel_check_wf(in_intersection_set_wf(int(2),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3539
3540 :- block in_intersection_set_wf(-,-,-,?).
3541 in_intersection_set_wf(A,X,Y,WF) :-
3542 ? (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)),
3543 % print_term_summary(symbolic_treatment_in_difference_set_wf(A,X,Y,WF)),
3544 !,
3545 Y \== [], % avoid setting up check_element_of for X then
3546 check_element_of_wf(A,X,WF), check_element_of_wf(A,Y,WF).
3547 in_intersection_set_wf(A,X,Y,WF) :-
3548 intersection(X,Y,Inter,WF),
3549 check_element_of_wf(A,Inter,WF).
3550
3551 :- assert_must_succeed(exhaustive_kernel_check_wf(not_in_intersection_set_wf(int(3),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3552 :- block not_in_intersection_set_wf(-,-,-,?).
3553 not_in_intersection_set_wf(_A,_X,Y,_WF) :- Y == [], !. % intersection will be empty; avoid analysing X
3554 not_in_intersection_set_wf(A,X,Y,WF) :-
3555 (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)),
3556 !, %print(not_in_intersection(A,X,Y,WF)),nl,
3557 % A : (X /\ Y) <=> A:X & A:Y
3558 % A /: (X /\ Y) <=> A/:X or A/:Y
3559 membership_test_wf(X,A,AX_Res,WF),
3560 (AX_Res==pred_false -> true
3561 ; bool_pred:negate(AX_Res,NotAX_Res), bool_pred:negate(AY_Res,NotAY_Res),
3562 b_interpreter_check:disjoin(NotAX_Res,NotAY_Res,pred_true,priority(16384),priority(16384),WF), % better: uese a version that does not do a case split ?! or use last wait flag ?
3563 membership_test_wf(Y,A,AY_Res,WF)
3564 ).
3565 not_in_intersection_set_wf(A,X,Y,WF) :-
3566 intersection(X,Y,Inter,WF),
3567 not_element_of_wf(A,Inter,WF).
3568
3569 :- assert_must_succeed(exhaustive_kernel_check_wf(in_union_set_wf(int(2),[int(33),int(2)],[int(2),int(1),int(3)],WF),WF)).
3570 :- assert_must_succeed(exhaustive_kernel_check_wf(in_union_set_wf(int(33),[int(32),int(2)],[int(2),int(1),int(33)],WF),WF)).
3571
3572 :- block in_union_set_wf(-,-,-,?).
3573 in_union_set_wf(A,X,Y,WF) :-
3574 (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)),
3575 % symbolic treatment would also make sense when A is nonvar and X var to force A to be in X ?!
3576 % print_term_summary(symbolic_treatment_in_difference_set_wf(A,X,Y,WF)),
3577 !,
3578 %print(in_union(A,X,Y)),nl,
3579 membership_test_wf(X,A,AX_Res,WF),
3580 (AX_Res==pred_true -> true
3581 ; b_interpreter_check:disjoin(AX_Res,AY_Res,pred_true,priority(16384),priority(16384),WF), % better: use a version that does not do a case split ?! or use last wait flag ?
3582 membership_test_wf(Y,A,AY_Res,WF)
3583 ).
3584 in_union_set_wf(A,X,Y,WF) :-
3585 union_wf(X,Y,Union,WF),
3586 check_element_of_wf(A,Union,WF).
3587
3588 :- assert_must_succeed(exhaustive_kernel_check_wf(not_in_union_set_wf(int(3),[int(32),int(2)],[int(2),int(1),int(33)],WF),WF)).
3589
3590 :- block not_in_union_set_wf(-,-,-,?).
3591 not_in_union_set_wf(A,X,Y,WF) :- % print(not_in_union(A,X,Y)),nl,
3592 not_element_of_wf(A,X,WF),
3593 not_element_of_wf(A,Y,WF).
3594
3595 % ---------------------
3596
3597
3598 strict_subset_of(X,Y) :-
3599 init_wait_flags(WF),
3600 strict_subset_of_wf(X,Y,WF),
3601 ground_wait_flags(WF).
3602
3603 :- assert_must_succeed(exhaustive_kernel_check(strict_subset_of_wf([int(3),int(2)],[int(2),int(1),int(3)],_))).
3604 :- assert_must_succeed(exhaustive_kernel_check(strict_subset_of_wf([],[int(2),int(1),int(3)],_))).
3605 :- assert_must_succeed(exhaustive_kernel_check(strict_subset_of_wf([],[ [] ],_))).
3606 :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([int(3),int(2),int(1)],[int(2),int(1),int(3)],_))).
3607 :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([int(1),int(4)],[int(2),int(1),int(3)],_))).
3608 :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([[]],[],_))).
3609 :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([],[],_))).
3610 :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [int(1)], X=[int(2),int(1)])).
3611 :- assert_must_succeed((kernel_objects:strict_subset_of(Y,X), Y = [int(1)], X=[int(2),int(1)])).
3612 :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [], X=[int(2),int(1)])).
3613 :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [[int(1),int(2)]], X=[[int(2)],[int(2),int(1)]])).
3614 :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [fd(1,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3615 :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [fd(3,'Name'),fd(2,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3616 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))).
3617 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [fd(1,'Name'),fd(3,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3618 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(1)], X=[int(2),int(1)])).
3619 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(1),int(2)], X=[int(2),int(1)])).
3620 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(2)], X=[int(2)])).
3621 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(2)], X=[int(1)])).
3622 :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [], X=[int(1)])).
3623
3624
3625 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
3626 :- if(\+ environ(disable_chr, true)).
3627 :- use_module(chrsrc(chr_set_membership)).
3628 :- else.
3629 chr_subset_strict(_,_).
3630 :- endif.
3631
3632 strict_subset_of_wf(Set1,Set2,WF) :-
3633 (preference(use_chr_solver,true) -> chr_subset_strict(Set1,Set2)
3634 ; Set1 \== Set2), % relevant for test 1326
3635 strict_subset_of_wf_aux(Set1,Set2,WF).
3636
3637 %:- block strict_subset_of_wf(-,-,?).
3638 strict_subset_of_wf_aux(Set1,Set2,WF) :- Set1==[],!,not_empty_set_wf(Set2,WF).
3639 %strict_subset_of_wf_aux(Set1,Set2,WF) :- var(Set2),nonvar(Set1), print(subs(Set1,Set2)),nl,fail.
3640 strict_subset_of_wf_aux(Set1,Set2,WF) :- nonvar(Set2), singleton_set(Set2,_),!, empty_set_wf(Set1,WF).
3641 strict_subset_of_wf_aux(Set1,Set2,WF) :- %print_quoted(check_subset_of(Set1,Set2)),nl,
3642 not_empty_set_wf(Set2,WF),
3643 get_cardinality_powset_wait_flag(Set2,strict_subset_of_wf,WF,_,LWF),
3644 % we could subtract 1 from priority !? (get_cardinality_pow1set_wait_flag)
3645 when(((nonvar(LWF),(nonvar(Set1);ground(Set2))) ; (nonvar(Set1),nonvar(Set2)) ),
3646 strict_subset_of_aux_block(Set1,Set2,WF,LWF)).
3647
3648 strict_subset_of_aux_block(Set1,_Set2,_WF,_LWF) :-
3649 Set1==[],
3650 !. % we have already checked that Set2 is not empty
3651 strict_subset_of_aux_block(Set1,Set2,WF,_LWF) :-
3652 nonvar(Set2), is_definitely_maximal_set(Set2),
3653 !,
3654 not_equal_object_wf(Set1,Set2,WF).
3655 strict_subset_of_aux_block(Set1,Set2,WF,_LWF) :- nonvar(Set2), singleton_set(Set2,_),!, empty_set_wf(Set1,WF).
3656 strict_subset_of_aux_block(Set1,Set2,_WF,_LWF) :-
3657 both_global_sets(Set1,Set2,G1,G2),
3658 !, %(print(check_strict_subset_of_global_sets(G1,G2)),nl,
3659 check_strict_subset_of_global_sets(G1,G2).
3660 strict_subset_of_aux_block(Set1,Set2,WF,_LWF) :-
3661 var(Set1),ground(Set2),
3662 !, % DO WE STILL NEED THIS VERSION ????
3663 %non_free(Set1), % as we used to force order, now we use equal_object_wf and no longer need non_free marking ?
3664 expand_custom_set_to_list(Set2,ESet2,_,strict_subset_of_wf), %print(gen_strict_subsets(ESet2)),nl,
3665 gen_strict_subsets(Set1,ESet2,WF).
3666 strict_subset_of_aux_block(Set1,Set2,WF,LWF) :-
3667 strict_subset_of0(Set1,Set2,WF,LWF).
3668
3669 % TO DO (26.10.2014): test 1270 now passes thanks to maximal set check above
3670 % but we should need a better way of ensuring that something like {ssu|ssu<<:POW(elements)} is efficiently computed
3671 % (which it no longer is once the unbound_variable check had been fixed)
3672 % we could also just generally use Set1 <: Set2 & Set1 /= Set2
3673
3674
3675 %:- block strict_subset_of0(-,?,?,?). % required to wait: we know Set2 must be non-empty, but Set1 could be an avl-tree or closure
3676 % TO DO: deal with infinite Set1
3677 strict_subset_of0(Set1,Set2,WF,LWF) :-
3678 expand_custom_set_to_list(Set1,ESet1,_,strict_subset_of0),
3679 (ESet1==[] -> true %not_empty_set(Set2) already checked above
3680 ; is_infinite_explicit_set(Set2) -> %print(inf(Set2)),nl,
3681 % Set1 is expanded to a list ESet1 and thus finite: it is sufficient to check subset relation
3682 check_subset_of_wf(ESet1,Set2,WF)
3683 ; try_expand_custom_set_wf(Set2,ESet2,strict_subset_of0,WF),
3684 %%try_prop_card_lt(ESet1,ESet2), try_prop_card_gt(ESet2,ESet1),
3685 strict_subset_of2(ESet1,[],ESet2,WF,LWF)
3686 ).
3687
3688 :- block strict_subset_of2(-,?,?,?,-).
3689 %strict_subset_of2(S,SoFar,Set2,WF) :- print(strict_subset_of2(S,SoFar,Set2,WF)),nl,fail.
3690 strict_subset_of2([],_,RemS,WF,_LWF) :- not_empty_set_wf(RemS,WF). /* we know it must be explicit set */
3691 strict_subset_of2([H|T],SoFar,Set2,WF,LWF) :- var(Set2),!,
3692 Set2 = [H|Set2R],
3693 add_new_element_wf(H,SoFar,SoFar2,WF), %was SoFar2 = [H|SoFar],
3694 strict_subset_of2(T,SoFar2,Set2R,WF,LWF).
3695 strict_subset_of2([H|T],SoFar,Set2,WF,LWF) :-
3696 % when_sufficiently_for_member(H,Set2,WF,
3697 remove_element_wf(H,Set2,RS2,WF), not_empty_set_wf(RS2,WF),
3698 not_element_of_wf(H,SoFar,WF), /* consistent((H,SoFar)), necessary? */
3699 when((nonvar(T) ; (ground(LWF),ground(RS2))),
3700 (add_new_element_wf(H,SoFar,SoFar2,WF), %SoFar2 = [H|SoFar],
3701 strict_subset_of2(T,SoFar2,RS2,WF,LWF) )).
3702
3703
3704
3705
3706 :- assert_must_succeed(exhaustive_kernel_check(partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ],_))).
3707 :- assert_must_succeed(exhaustive_kernel_check(partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)] ],_))).
3708 :- assert_must_succeed(exhaustive_kernel_check(partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5)],[int(1)] ],_))).
3709 :- assert_must_succeed(exhaustive_kernel_fail_check(partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)], [int(3)] ],_))).
3710 :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ], _))).
3711 :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2)],[ [int(2)], [int(1)], [] ], _))).
3712 :- assert_must_fail((kernel_objects:partition_wf([int(1),int(2)],[ [int(2)], [int(1),int(2)] ], _))).
3713 :- assert_must_fail((kernel_objects:partition_wf([int(1),int(3)],[ [int(1)], [int(2)] ], _))).
3714 :- assert_must_fail((kernel_objects:partition_wf([int(1),int(2),int(3)],[ [int(1)], [int(2)] ], _))).
3715 :- assert_must_succeed((kernel_objects:partition_wf([int(1)],[S1,S2],_WF), S1=[H|T], S2==[],T==[],H==int(1))).
3716 :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2)],[S1,S2],_WF), S1=[H|T], S2=[int(1)],(preferences:preference(use_clpfd_solver,true) -> T==[],H==int(2) ; T=[],H=int(2)))).
3717 :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2),int(3)],[S1,S2,S3],_WF), S1=[H2|T], S3=[int(3)],T=[H1|TT],H2=int(2),TT==[],S2==[],H1==int(1))).
3718 :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2),int(3)],[[int(1)],X,[int(2)]],_WF),
3719 X==[int(3)])).
3720
3721 :- use_module(bsets_clp,[disjoint_union_generalized_wf/3]).
3722 :- use_module(kernel_tools,[ground_value/1]).
3723 :- block partition_wf(?,-,?).
3724 partition_wf(Set,ListOfSets,WF) :- % print_term_summary(partition_wf(Set,ListOfSets,_WF)),nl, %
3725 (ground_value(Set),find_non_ground_set(ListOfSets,NGS,Rest) ->
3726 % we have: partition(Set, GroundSet1,...,GroundSetk, NGS)
3727 % print(backwards_computation_of_partition(NGS)),nl, %
3728 bsets_clp:disjoint_union_generalized_wf(Rest,RestSet,WF),
3729 check_subset_of_wf(RestSet,Set,WF), % otherwise this is not a partition of Set
3730 difference_set(Set,RestSet,NGS)
3731 ; bsets_clp:disjoint_union_generalized_wf(ListOfSets,Set,WF)
3732 ),
3733 all_disjoint(ListOfSets,WF).
3734
3735 :- assert_must_succeed((kernel_objects:find_non_ground_set([int(1),int(2),A,int(5)],B,C), B==A,C==[int(1),int(2),int(5)])).
3736 find_non_ground_set([H|T],NG,Rest) :-
3737 (ground_value(H) -> Rest=[H|TR], find_non_ground_set(T,NG,TR)
3738 ; ground_value(T),NG=H, Rest=T).
3739
3740 :- block all_disjoint(-,?).
3741 all_disjoint(closure(P,T,B),WF) :-
3742 expand_custom_set(closure(P,T,B),ExpandedSet), all_disjoint(ExpandedSet,WF).
3743 all_disjoint(avl_set(AVL),WF) :-
3744 expand_custom_set(avl_set(AVL),ExpandedSet), all_disjoint(ExpandedSet,WF).
3745 % no case for global_set: cannot be a set of sets
3746 all_disjoint([],_WF).
3747 all_disjoint([H|T],WF) :- all_disjoint_with(T,H,WF),
3748 all_disjoint(T,WF).
3749
3750 :- block all_disjoint_with(-,?,?).
3751 all_disjoint_with([],_,_WF).
3752 all_disjoint_with([H|T],Set1,WF) :- disjoint_sets(Set1,H,WF), all_disjoint_with(T,Set1,WF).
3753
3754
3755
3756
3757 :- assert_must_succeed(exhaustive_kernel_fail_check(not_partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ],_))).
3758 :- assert_must_succeed(exhaustive_kernel_fail_check(not_partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)] ],_))).
3759 :- assert_must_succeed(exhaustive_kernel_fail_check(not_partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5)],[int(1)] ],_))).
3760 :- assert_must_succeed(exhaustive_kernel_check(not_partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)], [int(3)] ],_))).
3761 :- assert_must_fail((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ], _))).
3762 :- assert_must_fail((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(2)], [int(1)], [] ], _))).
3763 :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(2)], [int(1),int(2)] ], _))).
3764 :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(3)],[ [int(1)], [int(2)] ], _))).
3765 :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(2),int(3)],[ [int(1)], [int(2)] ], _))).
3766
3767 :- block not_partition_wf(?,-,?).
3768 not_partition_wf(FullSet,ListOfSets,WF) :-
3769 expand_custom_set_to_list(ListOfSets,EListOfSets,_,not_partition_wf), % necessary ? ListOfSets is actually list
3770 not_partition_wf2(EListOfSets,[],FullSet,WF).
3771
3772 :- block not_partition_wf2(-,?,?,?).
3773 %not_partition_wf2(Sets,SoFar,_) :- print(not_part2(Sets,SoFar)),nl,fail.
3774 not_partition_wf2([],ElementsSoFar,FullSet,WF) :- not_equal_object_wf(ElementsSoFar,FullSet,WF).
3775 not_partition_wf2([Set1|Rest],ElementsSoFar,FullSet,WF) :-
3776 expand_custom_set_to_list(Set1,ESet1,_,not_partition_wf2), not_partition_wf3(ESet1,ElementsSoFar,Rest,FullSet,WF).
3777
3778 :- block not_partition_wf3(-,?,?,?,?).
3779 not_partition_wf3([],S,OtherSets,FullSet,WF) :-
3780 not_partition_wf2(OtherSets,S,FullSet,WF). % finished treating this set
3781 not_partition_wf3([H|T],ElementsSoFar,OtherSets,FullSet,WF) :-
3782 membership_test_wf(ElementsSoFar,H,MemRes,WF),
3783 not_partition_wf4(MemRes,H,T,ElementsSoFar,OtherSets,FullSet,WF).
3784
3785 :- block not_partition_wf4(-,?,?,?,?,?,?).
3786 not_partition_wf4(pred_true,_,_,_,_,_,_). % Not disjoint
3787 not_partition_wf4(pred_false,H,T,ElementsSoFar,OtherSets,FullSet,WF) :-
3788 add_element_wf(H,ElementsSoFar,ElementsSoFar2,WF), % we could also already check whether H in FullSet or not
3789 not_partition_wf3(T,ElementsSoFar2,OtherSets,FullSet,WF).
3790
3791 :- assert_must_succeed(exhaustive_kernel_succeed_check(check_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1),int(3)]))).
3792 :- assert_must_succeed(exhaustive_kernel_succeed_check(check_subset_of([int(1),int(2),int(5)],[int(2),int(5),int(1)]))).
3793 :- assert_must_succeed(exhaustive_kernel_fail_check(check_subset_of([int(1),int(3),int(5)],[int(2),int(5),int(1)]))).
3794 :- assert_must_succeed((kernel_objects:power_set(global_set('Name'),PS),kernel_objects:check_subset_of(X,PS),
3795 kernel_objects:equal_object(X,[[fd(2,'Name'),fd(1,'Name')]]))).
3796 :- assert_must_succeed(findall(X,kernel_objects:check_subset_of(X,[[int(1),int(2)],[]]),[_1,_2,_3,_4])).
3797 :- assert_must_succeed((kernel_objects:check_subset_of(X,[[int(1),int(2)],[]]),
3798 nonvar(X),
3799 kernel_objects:equal_object(X,[[int(2),int(1)]]))).
3800 :- assert_must_succeed((kernel_objects:check_subset_of_wf(Y,X,_WF), Y = [fd(1,'Name')],
3801 nonvar(X),X=[H|T], var(T), H==fd(1,'Name'), X=Y)).
3802 :- assert_must_succeed((kernel_objects:check_subset_of(Y,X), Y = [fd(1,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3803 :- assert_must_succeed((kernel_objects:check_subset_of(Y,X), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3804 :- assert_must_succeed((kernel_objects:check_subset_of(X,Y), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3805 :- assert_must_succeed((kernel_objects:sample_closure(C),kernel_objects:check_subset_of(C,global_set('NAT')))).
3806 :- assert_must_succeed((kernel_objects:check_subset_of(global_set('NAT'),global_set('NAT')))).
3807 :- assert_must_succeed((kernel_objects:check_subset_of(global_set('NAT'),global_set('NATURAL')))).
3808 :- assert_must_fail((kernel_objects:check_subset_of(global_set('NAT'),global_set('NATURAL1')))).
3809 :- assert_must_fail((kernel_objects:check_subset_of(global_set('NAT'),global_set('NAT1')))).
3810 :- assert_must_fail((kernel_objects:check_subset_of(X,Y), Y = [fd(1,'Name')], kernel_objects:equal_object(X,global_set('Name')))).
3811 /* TO DO: add special treatment for closures and type checks !! */
3812
3813 check_subset_of(Set1,Set2) :- init_wait_flags(WF),
3814 check_subset_of_wf(Set1,Set2,WF),
3815 ground_wait_flags(WF).
3816
3817 check_finite_subset_of_wf(Set1,Set2,WF) :-
3818 check_subset_of_wf(Set1,Set2,WF),
3819 is_finite_set_wf(Set1,WF).
3820
3821 :- block check_subset_of_wf(-,-,?).
3822 check_subset_of_wf(Set1,Set2,WF) :- % print_term_summary(check_subset_of(Set1,Set2)),nl,
3823 (both_global_sets(Set1,Set2,G1,G2)
3824 -> ( %print(check_subset_of_global_sets(G1,G2)),nl,
3825 check_subset_of_global_sets(G1,G2))
3826 ; check_subset_of0(Set1,Set2,WF)
3827 ).
3828
3829 both_global_sets(S1,S2,G1,G2) :- nonvar(S1),nonvar(S2),
3830 is_global_set(S1,G1), is_global_set(S2,G2).
3831
3832 % check if we have a global set or interval
3833 % is_global_set([],R) :- !, R=interval(0,-1). % useful ???
3834 is_global_set(global_set(G1),R) :- !,
3835 (custom_explicit_sets:get_integer_set_interval(G1,Low,Up) -> R=interval(Low,Up) ; R=G1).
3836 is_global_set(Closure,R) :-
3837 custom_explicit_sets:is_interval_closure_or_integerset(Closure,Low,Up),!,
3838 R=interval(Low,Up).
3839
3840
3841 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(0,0),interval(minus_inf,inf))).
3842 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(-200,1000),interval(minus_inf,inf))).
3843 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(10,1000),interval(0,inf))).
3844 :- assert_must_fail(kernel_objects:check_subset_of_global_sets(interval(-10,1000),interval(0,inf))).
3845 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(0,inf),interval(0,inf))).
3846 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(0,inf),interval(minus_inf,inf))).
3847 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(1,inf),interval(0,inf))).
3848 :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(1,inf),interval(minus_inf,inf))).
3849
3850 % to do: also extend to allow intervals with inf/minus_inf
3851 check_subset_of_global_sets(X,Y) :- (var(X) ; var(Y)),
3852 add_internal_error('Illegal call: ',check_subset_of_global_sets(X,Y)),fail.
3853 check_subset_of_global_sets(interval(Low1,Up1),interval(Low2,Up2)) :- !,
3854 interval_subset(Low1,Up1,Low2,Up2).
3855 check_subset_of_global_sets(X,X) :- !. % both args must be atomic and ground (global set names)
3856 % BUT WE COULD HAVE {x|x>0} <: NATURAL1 ? interval(0,inf) <: NATURAL1
3857 check_subset_of_global_sets(X,Y) :- check_strict_subset_of_global_sets(X,Y).
3858
3859 % To do: perform some treatment of inf, minus_inf values here <----
3860 interval_subset(Low1,Up1,Low2,Up2) :- % print(interval_subset(Low1,Up1,Low2,Up2)),nl,
3861 ? (var(Low1) ; var(Up1)), % otherwise we can use code below
3862 finite_interval(Low1,Up1), finite_interval(Low2,Up2), % inf can appear as term; but only directly not later
3863 !,
3864 %print(posting),nl,
3865 % Maybe to do: try to avoid CLPFD overflows if possible; pass WF to force case distinction between empty/non-empty intervals
3866 clpfd_in_interval(Low1,Up1,Low2,Up2).
3867 interval_subset(Low1,Up1,Low2,Up2) :-
3868 interval_subset_aux(Low1,Up1,Low2,Up2).
3869
3870 % check if we have a finite interval (fails for inf/minus_inf terms)
3871 finite_interval(Low1,Up1) :- (var(Low1) -> true ; number(Low1)), (var(Up1) -> true ; number(Up1)).
3872
3873
3874 % assert Low1..Up1 <: Low2..Up2
3875 clpfd_in_interval(Low1,Up1,Low2,Up2) :-
3876 (preferences:preference(use_chr_solver,true)
3877 -> chr_integer_inequality:chr_in_interval(Low1,Up1,Low2,Up2) ; true),
3878 % TO DO: improve detection of Low1 #=< Up1; maybe outside of CHR ?; we could also add a choice point here
3879 % example: p..q <: 0..25 & p<q -> should constrain p,q to p:0..24 & q:1..25
3880 clpfd_interface:post_constraint2((Low1 #=< Up1) #=> ((Low2 #=< Low1) #/\ (Up1 #=< Up2)),Posted),
3881 (Posted==true -> true ; interval_subset_aux(Low1,Up1,Low2,Up2)).
3882
3883 :- block interval_subset_aux(-,?,?,?), interval_subset_aux(?,-,?,?).
3884 interval_subset_aux(Low1,Up1,_,_) :- safe_less_than_with_inf(Up1,Low1). %Set 1 is empty.
3885 interval_subset_aux(Low1,Up1,Low2,Up2) :- %print(s1(Low1,Up1)),nl,
3886 safe_less_than_equal_with_inf(Low1,Up1), % Set 1 is not empty
3887 safe_less_than_equal_with_inf_clpfd(Low2,Low1), safe_less_than_equal_with_inf_clpfd(Up1,Up2). % may call CLPFD
3888
3889 % a version of safe_less_than which allows minus_inf and inf, but only if those terms appear straightaway at the first call
3890 % assumes any variable will only be bound to a number
3891 ?safe_less_than_with_inf(X,Y) :- (X==Y ; X==inf ; Y==minus_inf), !,fail.
3892 safe_less_than_with_inf(X,Y) :- (X==minus_inf ; Y==inf), !.
3893 safe_less_than_with_inf(X,Y) :- safe_less_than(X,Y).
3894
3895 safe_less_than_with_inf_clpfd(X,Y) :- (X==Y ; X==inf ; Y==minus_inf), !,fail.
3896 safe_less_than_with_inf_clpfd(X,Y) :- (X==minus_inf ; Y==inf), !.
3897 safe_less_than_with_inf_clpfd(X,Y) :- less_than_direct(X,Y). % this can also call CLPFD
3898
3899 % a version of safe_less_than_equal which allows minus_inf and inf, but only if those terms appear straightaway at the first call
3900 safe_less_than_equal_with_inf(X,Y) :- X==Y,!.
3901 safe_less_than_equal_with_inf(X,Y) :- (X==inf ; Y==minus_inf), !,fail.
3902 safe_less_than_equal_with_inf(X,Y) :- (X==minus_inf ; Y==inf), !.
3903 safe_less_than_equal_with_inf(X,Y) :- safe_less_than_equal(X,Y).
3904
3905 safe_less_than_equal_with_inf_clpfd(X,Y) :- X==Y,!.
3906 safe_less_than_equal_with_inf_clpfd(X,Y) :- (X==inf ; Y==minus_inf), !,fail.
3907 ?safe_less_than_equal_with_inf_clpfd(X,Y) :- (X==minus_inf ; Y==inf), !.
3908 safe_less_than_equal_with_inf_clpfd(X,Y) :- less_than_equal_direct(X,Y). % this can also call CLPFD
3909
3910 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,2),interval(1,3))).
3911 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,1),interval(1,2))).
3912 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,1),interval(0,1))).
3913 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(2,1),interval(33,34))).
3914 :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(3,1),interval(4,2))).
3915 :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(3,1),interval(2,1))).
3916 :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(1,2),interval(1,2))).
3917 :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(1,2),interval(2,3))).
3918 :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(2,3),interval(1,2))).
3919 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(0,1000),interval(0,inf))).
3920 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,1000),interval(1,inf))).
3921 :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(-200,1000),interval(minus_inf,inf))).
3922 % for any other term we have global enumerated or deferred sets: they cannot be a strict subset of each other
3923 check_strict_subset_of_global_sets(interval(Low1,Up1),interval(Low2,Up2)) :-
3924 check_strict_subset_intervals(Low1,Up1,Low2,Up2).
3925
3926 check_strict_subset_intervals(Low1,Up1,Low2,Up2) :-
3927 safe_less_than_equal_with_inf_clpfd(Low2,Up2), % Low2..Up2 not empty
3928 check_strict_subset_intervals1(Low1,Up1,Low2,Up2).
3929
3930 check_strict_subset_intervals1(Low1,Up1,Low2,Up2) :- % we cannot have inf as term (yet) here
3931 %preferences:preference(use_clpfd_solver,true),
3932 (var(Low1) ; var(Up1)),
3933 finite_interval(Low1,Up1), finite_interval(Low2,Up2),
3934 %print(posting(Low1,Up1,Low2,Up2)),nl,
3935 !,
3936 clpfd_interface:post_constraint2((Low1 #=< Up1) #=> ((Low2 #=< Low1) #/\ (Up1 #=< Up2) #/\ (Low1 #\= Low2 #\/ Up1 #\= Up2)),Posted),
3937 (Posted==true -> true ; check_strict_subset_intervals2(Low1,Up1,Low2,Up2)).
3938 check_strict_subset_intervals1(Low1,Up1,Low2,Up2) :- check_strict_subset_intervals2(Low1,Up1,Low2,Up2).
3939
3940 :- block check_strict_subset_intervals2(-,?,?,?),check_strict_subset_intervals2(?,-,?,?),
3941 check_strict_subset_intervals2(?,?,-,?).
3942 check_strict_subset_intervals2(Low1,Up1,_,_) :- safe_less_than_with_inf(Up1,Low1). % interval 1 empty
3943 check_strict_subset_intervals2(Low1,Up1,Low2,Up2) :-
3944 safe_less_than_equal_with_inf(Low1,Up1), % interval 1 not empty
3945 ( safe_less_than_with_inf(Low2,Low1), safe_less_than_equal_with_inf_clpfd(Up1,Up2)
3946 ;
3947 Low1=Low2,safe_less_than_with_inf_clpfd(Up1,Up2)
3948 ).
3949
3950 :- use_module(custom_explicit_sets,[is_definitely_maximal_set/1,singleton_set/2]).
3951 :- use_module(kernel_tools,[ground_value_check/2, quick_same_value/2]).
3952
3953 check_subset_of0(Set1,_Set2,_WF) :- Set1==[],!.
3954 check_subset_of0(Set1,Set2,WF) :- Set2==[],
3955 %nonvar(Set2),Set2=[], %var(Set1),
3956 !,% print(checking_empty_set(Set1)),nl,
3957 empty_set_wf(Set1,WF). % ,print(empty),nl.
3958 check_subset_of0(_Set1,Set2,_WF) :-
3959 ? nonvar(Set2),is_definitely_maximal_set(Set2),!. % , print(subset_maximal(_Set1,Set2)),nl.
3960 %singleton
3961 check_subset_of0(Set1,Set2,_) :-
3962 quick_same_value(Set1,Set2), % important for e.g. test 1948 for closures with different info fields
3963 !.
3964 check_subset_of0(Set1,Set2,WF) :- custom_explicit_sets:singleton_set(Set1,El),!,
3965 check_element_of_wf(El,Set2,WF).
3966 check_subset_of0(Set1,Set2,WF) :- % Note: two intervals are treated in check_subset_of_global_sets
3967 subset_of_explicit_set(Set1,Set2,Code,WF),!,
3968 % print(subset_explicit(Set1,Set2,Code)),nl,
3969 call(Code).
3970 check_subset_of0(Set1,Set2,WF) :- nonvar(Set1),!,
3971 get_cardinality_powset_wait_flag(Set2,check_subset_of0,WF,_,LWF),
3972 expand_custom_set_to_list(Set1,ESet1,_,check_subset_of1),
3973 try_expand_and_convert_to_avl_unless_large(Set2,ESet2),
3974 % print(check_subset(ESet1,Set2,WF,LWF)),nl,
3975 % b_interpreter_components:observe_instantiation(ESet1,'ESet1',ESet1),
3976 check_subset_of2(ESet1,[],ESet2,WF,LWF,none).
3977 check_subset_of0(Set1,Set2,WF) :-
3978 is_wait_flag_info(WF,wfx_no_enumeration),!,
3979 %print(no_enum(Set1)),nl,
3980 check_subset_of0_lwf(Set1,Set2,WF,_LWF,_).
3981 check_subset_of0(Set1,Set2,WF) :-
3982 % DO we need LWF if Set1=avl_set(_) ??
3983 get_cardinality_powset_wait_flag(Set2,check_subset_of0,WF,_Card,LWF),
3984 ground_value_check(Set2,GS2),
3985 % print_term_summary(check_subset_of0(Set1,Set2,WF,LWF,GS2)),nl, portray_waitflags(WF),nl,
3986 %print(subset_card(Card,Set2,WF)),nl, (Card==inf -> trace ; true),
3987 check_subset_of0_lwf(Set1,Set2,WF,LWF,GS2).
3988
3989 :- use_module(custom_explicit_sets,[is_infinite_or_very_large_explicit_set/2]).
3990
3991 :- block check_subset_of0_lwf(-,?,?,-,?),check_subset_of0_lwf(-,?,?,?,-).
3992 check_subset_of0_lwf(Set1,_Set2,_WF,_LWF,_GS2) :- Set1==[],!.
3993 %check_subset_of0_lwf(Set1,Set2,WF,_LWF) :- Set2==[],!, % can never trigger as Set2 was already nonvar
3994 % empty_set_wf(Set1,WF).
3995 check_subset_of0_lwf(Set1,Set2,WF,_LWF,_GS2) :- custom_explicit_sets:singleton_set(Set1,El),!,
3996 check_element_of_wf(El,Set2,WF).
3997 check_subset_of0_lwf(Set1,Set2,_WF,_,_) :-
3998 both_global_sets(Set1,Set2,G1,G2),!, % may now succeed compared to same check above, as Set1/Set2 now instantiated
3999 %print(check_subset_of_global_sets(G1,G2)),
4000 check_subset_of_global_sets(G1,G2).
4001 check_subset_of0_lwf(Set1,Set2,WF,_LWF,_GS2) :- % Note: two intervals are treated in check_subset_of_global_sets
4002 nonvar(Set1), % otherwise we have already checked this code above
4003 subset_of_explicit_set(Set1,Set2,Code,WF),!,
4004 % print(subset_explicit(Set1,Set2,Code)),nl,
4005 call(Code).
4006 check_subset_of0_lwf(Set1,Set2,WF,LWF,_GS2) :-
4007 (nonvar(Set1) ; nonvar(Set2),dont_expand_this_explicit_set(Set2)),
4008 !,
4009 expand_custom_set_to_list(Set1,ESet1,_,check_subset_of1),
4010 try_expand_and_convert_to_avl_unless_large(Set2,ESet2),
4011 % print(check_subset(ESet1,Set2,WF,LWF)),nl,
4012 % b_interpreter_components:observe_instantiation(ESet1,'ESet1',ESet1),
4013 check_subset_of2(ESet1,[],ESet2,WF,LWF,none).
4014 check_subset_of0_lwf(Set1,Set2,WF,_LWF,_GS2) :-
4015 expand_custom_set_to_list(Set2,ESet2,_,check_subset_of0_lwf), % Set2 is ground
4016 % THIS WILL ENUMERATE, for something like dom(f) <: SET this is problematic, as information cannot be used
4017 % hence we use wfx_no_enumeration above
4018 %non_free(Set1), % we used to enumerate Set1 in a specific order ESet2; now we use equal_object_wf and we no longer need to mark Set1 as non-free ?
4019 %print_term_summary(gen_subsets(Set1,ESet2,WF,_LWF)),nl, portray_waitflags(WF),nl,
4020 gen_subsets(Set1,ESet2,WF).
4021
4022 :- block check_subset_of2(-,?,?,?,-, ?).
4023 check_subset_of2([],_SoFar,_Set2,_WF,_LWF,_Last).
4024 % :- print_tabs, print('SOLUTION '), hashing:my_term_hash((_SoFar,_Set2),Hash), print(Hash),nl, (Hash = 30707821301826039 -> trace ; true).
4025 check_subset_of2(HT,SoFar,Set2,WF,LWF,Last) :- %print(chk(H,Set2,Last)),nl,
4026 (var(HT),Set2 = avl_set(AVL)
4027 -> % the value is chosen by the enumerator
4028 %trace_point(check_subset_of2(HT,SoFar,Set2,WF,LWF,Last)),
4029 %print_tabs,print(' --> enum '), translate:print_bvalue(SoFar),nl,
4030 custom_explicit_sets:safe_avl_member(H,AVL),
4031 % this forces H to be ground; if Last /= none then it will be ground
4032 (Last==none -> true ; Last @< H),
4033 % TO DO: we could write a safe_avl_member_greater_than(H,Last,AVL)
4034 %print_tabs,translate:print_bvalue(H),nl, %(H==avl_set(node([],true,0,empty,empty)) -> trace ; true),
4035 not_element_of_wf(H,SoFar,WF),
4036 NewLast=H,
4037 HT = [H|T]
4038 ; % the value may have been chosen by somebody else or will not be enumerated in order below
4039 %trace_point(normal_checksubset(HT,SoFar,Set2,WF,LWF,Last)),
4040 HT = [H|T],
4041 not_element_of_wf(H,SoFar,WF),
4042 check_element_of_wf_lwf(H,Set2,WF,LWF),
4043 %check_element_of_wf(H,Set2,WF),
4044
4045 NewLast = Last
4046 ),
4047 %print(check(H,Set2,WF,LWF,Last)),nl,
4048 check_subset_of3(H,T,SoFar,Set2,WF,LWF,NewLast).
4049
4050 % TO DO: write specific subsets code for avl_set(Set2) + try expand when becomes ground; merge with enumerate_tight_set ,...
4051 % TO DO: ensure that it also works with global_set(T) instead of avl_set(_) or with interval closures
4052
4053
4054 :- block check_subset_of3(?,-,-,?,?,-,?), check_subset_of3(?,-,?,-,?,-,?), check_subset_of3(?,-,-,-,?,?,?).
4055 check_subset_of3(_,T,_,_Set2,_WF,_LWF,_) :- T==[],!.
4056 check_subset_of3(H,T,SoFar,Set2,WF,LWF,Last) :- var(T),!,
4057 % Sofar, Set2 and LWF must be set
4058 when((nonvar(T);(ground(Set2),ground(H),ground(SoFar))),
4059 (T==[] -> true
4060 ; add_new_element_wf(H,SoFar,SoFar2,WF), %SoFar2 = [H|SoFar],
4061 check_subset_of2(T,SoFar2,Set2,WF,LWF,Last))).
4062 check_subset_of3(H,T,SoFar,Set2,WF,LWF,Last) :-
4063 % T must be set and not equal to []
4064 T = [H2|T2],
4065 add_new_element_wf(H,SoFar,SoFar2,WF), %SoFar2 = [H|SoFar],
4066 %check_subset_of2(T,SoFar2,Set2,WF,LWF))),
4067 check_element_of_wf(H2,Set2,WF),
4068 not_element_of_wf(H2,SoFar2,WF),
4069 check_subset_of3(H2,T2,SoFar2,Set2,WF,LWF,Last).
4070
4071
4072 :- block gen_subsets(?,-,?).
4073 gen_subsets([],_,_).
4074 gen_subsets(SubSet,Set,WF) :-
4075 ordered_delete(DH,Set,NewSet),
4076 equal_object_wf([DH|T],SubSet,gen_subsets,WF),
4077 gen_subsets(T,NewSet,WF).
4078
4079 % old version:
4080 %gen_subsets(SubSet,Set,WF) :- %print(gen_subsets(H,T,Set)),nl,
4081 % non_free(H), % is redundant, but just instantiating SubSet to [H|T] can trigger co-routines before non-free gets propagated !
4082 % SubSet = [H|T],
4083 % ordered_delete(DH,Set,NewSet),
4084 % equal_object(DH,H,gen_subsets), % it is important that [H|T] remains uninstantiated, hence we should mark arg1 as non_free before calling gen_subsets
4085 % gen_subsets(T,NewSet,WF).
4086
4087 ordered_delete(H,[H|T],T).
4088 ordered_delete(H,[_|T],R) :- ordered_delete(H,T,R).
4089
4090 gen_strict_subsets(T,[_H2|T2],WF) :- gen_subsets(T,T2,WF).
4091 gen_strict_subsets(SubSet,[H2|T2],WF) :-
4092 equal_object_wf([H2|T],SubSet,gen_strict_subsets,WF),
4093 gen_strict_subsets(T,T2,WF).
4094 %old version which required non_free:
4095 %gen_strict_subsets([H|T],[H2|T2],WF) :-
4096 % equal_object_wf(H,H2,gen_strict_subsets,WF),
4097 % gen_strict_subsets(T,T2,WF).
4098
4099 :- assert_must_succeed(exhaustive_kernel_check_wf(check_finite_non_empty_subset_of_wf([int(1),int(5)], [int(2),int(5),int(1),int(3)],WF),WF)).
4100 :- assert_must_succeed(exhaustive_kernel_check_wf(check_finite_non_empty_subset_of_wf([int(1),int(5)], [int(5),int(1)],WF),WF)).
4101 check_finite_non_empty_subset_of_wf(Set1,Set2,WF) :-
4102 check_non_empty_subset_of_wf(Set1,Set2,WF),
4103 is_finite_set_wf(Set1,WF).
4104
4105 :- assert_must_succeed(exhaustive_kernel_check_wf(check_non_empty_subset_of_wf([int(1),int(5)], [int(2),int(5),int(1),int(3)],WF),WF)).
4106 :- assert_must_succeed(exhaustive_kernel_fail_check_wfdet(check_non_empty_subset_of_wf([int(2)], [int(5),int(1)],WF),WF)).
4107 :- assert_must_succeed(exhaustive_kernel_fail_check_wfdet(check_non_empty_subset_of_wf([], [int(1)],WF),WF)).
4108
4109 check_non_empty_subset_of_wf(S1,S2,WF) :- not_empty_set_wf(S1,WF),
4110 check_subset_of_wf(S1,S2,WF).
4111
4112 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_subset_of([int(1),int(2),int(5)], [int(2),int(4),int(1),int(3)]))).
4113 :- assert_must_succeed(exhaustive_kernel_fail_check(not_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1),int(3)]))).
4114 :- assert_must_succeed((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name')], X=global_set('Name'))).
4115 :- assert_must_succeed((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name')], X=[fd(2,'Name')])).
4116 :- assert_must_succeed((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name')], X=[fd(1,'Name'),fd(2,'Name')])).
4117 :- assert_must_fail((kernel_objects:not_subset_of(Y,X), Y = [fd(1,'Name'),fd(3,'Name')], X=global_set('Name'))).
4118 :- assert_must_fail((kernel_objects:not_subset_of(Y,X), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))).
4119 :- assert_must_fail((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))).
4120 :- assert_must_fail((kernel_objects:not_subset_of(global_set('NAT'),global_set('NAT')))).
4121 :- assert_must_succeed((kernel_objects:not_subset_of(global_set('NAT'),global_set('NAT1')))).
4122
4123
4124 not_subset_of(Set1,Set2) :- init_wait_flags(WF),
4125 not_subset_of_wf(Set1,Set2,WF),
4126 ground_wait_flags(WF).
4127
4128 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf([int(1),int(2),int(5)], [int(2),int(4),int(1),int(3)],_WF))).
4129 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf(global_set('NATURAL'), global_set('INTEGER'),_WF))).
4130 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf(global_set('INTEGER'), global_set('INTEGER'),_WF))).
4131 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf([int(1)], [],_WF))).
4132
4133 :- block not_finite_subset_of_wf(-,?,?).
4134 not_finite_subset_of_wf(Set1,Set2,WF) :- test_finite_set_wf(Set1,Finite,WF),
4135 not_finite_subset_of_wf_aux(Finite,Set1,Set2,WF).
4136 :- block not_finite_subset_of_wf_aux(-,?,?,?).
4137 not_finite_subset_of_wf_aux(pred_false,_Set1,_Set2,_WF).
4138 not_finite_subset_of_wf_aux(pred_true,Set1,Set2,WF) :- not_subset_of_wf(Set1,Set2,WF).
4139
4140 :- block not_subset_of_wf(-,?,?).
4141 not_subset_of_wf([],_,_WF) :- !, fail.
4142 not_subset_of_wf(Set1,Set2,WF) :- Set2==[],!, not_empty_set_wf(Set1,WF).
4143 not_subset_of_wf(Set1,Set2,WF) :- % print_quoted(not_subset_of_wf(Set1,Set2)),nl,trace,
4144 (both_global_sets(Set1,Set2,G1,G2) % also catches intervals
4145 -> check_not_subset_of_global_sets(G1,G2)
4146 ; not_subset_of_wf1(Set1,Set2,WF)
4147 ).
4148 not_subset_of_wf1(_Set1,Set2,_WF) :-
4149 nonvar(Set2), is_definitely_maximal_set(Set2),!,fail.
4150 not_subset_of_wf1(Set1,Set2,_WF) :- quick_same_value(Set1,Set2),
4151 !, fail.
4152 not_subset_of_wf1(Set1,Set2,WF) :- custom_explicit_sets:singleton_set(Set1,El),!,
4153 not_element_of_wf(El,Set2,WF).
4154 ?not_subset_of_wf1(Set1,Set2,WF) :- not_subset_of_explicit_set(Set1,Set2,Code,WF),!,
4155 call(Code).
4156 not_subset_of_wf1(Set1,Set2,WF) :-
4157 expand_custom_set_to_list(Set1,ESet1,_,not_subset_of_wf1),
4158 % print_quoted(not_subset_of2(ESet1,Set2,WF)),nl,
4159 not_subset_of2(ESet1,Set2,WF).
4160
4161
4162 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(0,2),interval(1,3))).
4163 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(1,2),interval(0,-1))).
4164 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(1,2),interval(4,3))).
4165 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(1,3))).
4166 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(1,9000),interval(2,9999))).
4167 :- assert_must_succeed((kernel_objects:check_not_subset_of_global_sets(interval(X2,X4),interval(1,3)),
4168 X2=2, X4=4)).
4169 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(1,4))).
4170 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(2,4))).
4171 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(0,10))).
4172 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(0,2),interval(1,inf))).
4173 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(-1,2),interval(0,inf))).
4174 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,2),interval(1,inf))).
4175 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(0,2),interval(0,inf))).
4176 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(-1,2),interval(minus_inf,inf))).
4177 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(0,inf),interval(1,inf))).
4178 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(minus_inf,inf),interval(1,inf))).
4179 :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(minus_inf,inf),interval(0,inf))).
4180 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,inf),interval(minus_inf,inf))).
4181 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,inf),interval(1,inf))).
4182 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,inf),interval(0,inf))).
4183 :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(0,inf),interval(0,inf))).
4184
4185 :- block check_not_subset_of_global_sets(-,?), check_not_subset_of_global_sets(?,-).
4186 check_not_subset_of_global_sets(interval(Low1,Up1),G2) :- !,
4187 safe_less_than_equal_with_inf_clpfd(Low1,Up1), % Set 1 is not empty; otherwise it will always be a subset
4188 not_subset_interval_gs_aux(G2,Low1,Up1).
4189 check_not_subset_of_global_sets(G1,G2) :-
4190 \+ check_subset_of_global_sets(G1,G2).
4191
4192 :- use_module(library(clpfd)).
4193 not_subset_interval_gs_aux(interval(Low2,Up2),Low1,Up1) :-
4194 finite_interval(Low1,Up1), finite_interval(Low2,Up2),
4195 !,
4196 % post_constraint2((Low1 #<Low2 #\/ Up1 #> Up2 #\/ Up2 #< Low1),Posted), %% X #<100 #\/ X#<0. does not constraint X ! but X #<max(100,0) does
4197 post_constraint2((Low1 #<Low2 #\/ Up2 #< max(Up1,Low1)),Posted),
4198 (Posted==true -> true ; not_interval_subset(Low1,Up1,Low2,Up2)).
4199 not_subset_interval_gs_aux(interval(Low2,Up2),Low1,Up1) :- !, not_interval_subset(Low1,Up1,Low2,Up2).
4200 not_subset_interval_gs_aux(GS2,Low1,Up1) :-
4201 when((nonvar(Low1),nonvar(Up1)), \+ check_subset_of_global_sets(interval(Low1,Up1),GS2)).
4202
4203 not_interval_subset(Val1,Up1,Low2,Up2) :- var(Val1), Val1==Up1, %print(not_in(Val1,Up1,Low2,Up2)),nl,
4204 !, % better propagation for singleton set
4205 (Up2==inf -> Low2\==minus_inf, less_than_direct(Val1,Low2)
4206 ; Low2=minus_inf -> less_than_direct(Low2,Val1)
4207 ; not_in_nat_range(int(Val1),int(Low2),int(Up2))).
4208 not_interval_subset(Low1,Up1,Low2,Up2) :- not_interval_subset_block(Low1,Up1,Low2,Up2).
4209 :- block not_interval_subset_block(-,?,?,?), not_interval_subset_block(?,-,?,?),
4210 not_interval_subset_block(?,?,-,?), not_interval_subset_block(?,?,?,-).
4211 not_interval_subset_block(Low1,Up1,Low2,Up2) :- % this could be decided earlier, e.g. 1..n /<: 1..inf is false
4212 \+ interval_subset(Low1,Up1,Low2,Up2).
4213
4214
4215 :- block not_subset_of2(-,?,?).
4216 %not_subset_of2([],_,_WF) :- fail.
4217 not_subset_of2([H|T],Set2,WF) :-
4218 membership_test_wf(Set2,H,MemRes,WF),
4219 not_subset_of3(MemRes,T,Set2,WF).
4220
4221 :- block not_subset_of3(-,?,?,?).
4222 not_subset_of3(pred_false,_T,_Set2,_WF).
4223 not_subset_of3(pred_true,T,Set2,WF) :- not_subset_of2(T,Set2,WF).
4224
4225
4226
4227 :- assert_must_succeed(exhaustive_kernel_check_wf(not_both_subset_of([int(1),int(2),int(5)], []
4228 ,[int(2),int(4),int(1),int(3)],[],WF),WF)).
4229 :- assert_must_succeed(exhaustive_kernel_check_wf(not_both_subset_of([int(1),int(2),int(5)], [int(3)],
4230 [int(2),int(5),int(1),int(3)],[int(1),int(4)],WF),WF)).
4231
4232 not_both_subset_of(Set1A,Set1B, Set2A,Set2B, WF) :-
4233 kernel_equality:subset_test(Set1A,Set2A,Result,WF), % not yet implemented ! % TODO ! -> sub_set,equal,super_set
4234 not_both_subset_of_aux(Result,Set1B,Set2B,WF).
4235
4236 :- block not_both_subset_of_aux(-,?,?,?).
4237 not_both_subset_of_aux(pred_false,_Set1B,_Set2B,_WF).
4238 not_both_subset_of_aux(pred_true,Set1B,Set2B,WF) :-
4239 not_subset_of_wf(Set1B,Set2B,WF).
4240
4241 /***********************************/
4242 /* not_strict_subset_of(Set1,Set2) */
4243 /* Set1 /<<: Set2 */
4244 /**********************************/
4245
4246
4247 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_strict_subset_of([int(1),int(2),int(5)], [int(2),int(4),int(1),int(3)]))).
4248 :- assert_must_succeed(exhaustive_kernel_succeed_check(not_strict_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1)]))).
4249 :- assert_must_succeed(exhaustive_kernel_fail_check(not_strict_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1),int(3)]))).
4250 :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [int(1)], X=[int(2),int(1)])).
4251 :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [], X=[int(2),int(1)])).
4252 :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [[int(1),int(2)]], X=[[int(2)],[int(2),int(1)]])).
4253 :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [fd(1,'Name')], X=global_set('Name'))).
4254 :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))).
4255 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))).
4256 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [fd(1,'Name'),fd(3,'Name')], X=global_set('Name'))).
4257 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(1)], X=[int(2),int(1)])).
4258 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(1),int(2)], X=[int(2),int(1)])).
4259 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(2)], X=[int(2)])).
4260 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(2)], X=[int(1)])).
4261 :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [], X=[int(1)])).
4262
4263 not_strict_subset_of(Set1,Set2) :-
4264 chr_not_subset_strict(Set1,Set2),
4265 init_wait_flags(WF),
4266 not_strict_subset_of_wf(Set1,Set2,WF),
4267 ground_wait_flags(WF).
4268
4269 :- block not_strict_subset_of_wf(-,?,?),not_strict_subset_of_wf(?,-,?).
4270 not_strict_subset_of_wf(Set1,Set2,WF) :- %print_quoted(check_subset_of(Set1,Set2)),nl,
4271 (both_global_sets(Set1,Set2,G1,G2)
4272 -> %print(check_not_strict_subset_of_global_sets(G1,G2)),nl,
4273 not_strict_subset_of_global_sets(G1,G2)
4274 ; not_strict_subset_of_wf1(Set1,Set2,WF)
4275 ).
4276 not_strict_subset_of_wf1(Set1,Set2,WF) :- not_subset_of_explicit_set(Set1,Set2,Code,WF),!,
4277 equality_objects_wf(Set1,Set2,EqRes,WF),
4278 not_strict_eq_check(EqRes,Code).
4279 not_strict_subset_of_wf1(Set1,Set2,WF) :-
4280 % OLD VERSION: not_subset_of(Set1,Set2) ; check_equal_object(Set1,Set2).
4281 expand_custom_set_to_list(Set1,ESet1,_,not_strict_subset_of_wf1),
4282 (nonvar(Set2),is_infinite_explicit_set(Set2) -> Inf=infinite ; Inf=unknown),
4283 not_strict_subset_of2(ESet1,Set2,Inf,WF).
4284
4285 :- block not_strict_eq_check(-,?).
4286 not_strict_eq_check(pred_true,_). % if equal then not strict subset is true
4287 not_strict_eq_check(pred_false,Code) :- call(Code). % check if not subset
4288
4289 :- block not_strict_subset_of2(-,?,?,?).
4290 not_strict_subset_of2([],R,_,WF) :- empty_set_wf(R,WF).
4291 not_strict_subset_of2([H|T],Set2,Inf,WF) :-
4292 membership_test_wf(Set2,H,MemRes,WF),
4293 not_strict_subset_of3(MemRes,H,T,Set2,Inf,WF).
4294
4295 :- block not_strict_subset_of3(-,?,?,?,?,?).
4296 not_strict_subset_of3(pred_false,_H,_T,_Set2,_,_WF).
4297 not_strict_subset_of3(pred_true,H,T,Set2,Inf,WF) :-
4298 (Inf=infinite
4299 -> RS2=Set2 % Set1 is finite; we just have to check that all elements are in Set2 and we have a strict subset
4300 ; remove_element_wf(H,Set2,RS2,WF)),
4301 not_strict_subset_of2(T,RS2,Inf,WF).
4302
4303
4304 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,2),interval(1,3))).
4305 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,2),interval(0,-1))).
4306 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,2),interval(4,3))).
4307 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(1,3))).
4308 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,9000),interval(2,9999))).
4309 :- assert_must_succeed((kernel_objects:not_strict_subset_of_global_sets(interval(X2,X4),interval(1,3)),
4310 X2=2, X4=4)).
4311 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(1,4))).
4312 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(2,4))).
4313 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(0,10))).
4314 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,2),interval(1,inf))).
4315 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(-1,2),interval(0,inf))).
4316 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(1,2),interval(1,inf))).
4317 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(0,2),interval(0,inf))).
4318 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(-1,2),interval(minus_inf,inf))).
4319 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,inf),interval(1,inf))).
4320 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(minus_inf,inf),interval(1,inf))).
4321 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(minus_inf,inf),interval(0,inf))).
4322 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(1,inf),interval(minus_inf,inf))).
4323 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,inf),interval(1,inf))).
4324 :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(1,inf),interval(0,inf))).
4325 :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,inf),interval(0,inf))).
4326
4327 :- block not_strict_subset_of_global_sets(-,?), not_strict_subset_of_global_sets(?,-).
4328 not_strict_subset_of_global_sets(interval(Low1,Up1),interval(Low2,Up2)) :- !,
4329 % Note: if Low2>Up2 then nothing is a strict subset of the empty set, i.e., everything is not a strict subset
4330 (finite_interval(Low1,Up1), finite_interval(Low2,Up2)
4331 -> clpfd_interface:post_constraint2(((Low2 #=< Up2) #=> (Low1 #=< Up1 #/\ ((Low2 #> Low1) #\/ (Up1 #> Up2) #\/ ((Low1 #= Low2 #/\ Up1 #= Up2))))),Posted)
4332 ; Posted=false),
4333 (Posted==true -> true ; not_strict_subset_intervals(Low1,Up1,Low2,Up2)).
4334 not_strict_subset_of_global_sets(G1,G2) :-
4335 when((ground(G1),ground(G2)), \+check_strict_subset_of_global_sets(G1,G2)).
4336
4337 :- block not_strict_subset_intervals(?,?,-,?), not_strict_subset_intervals(?,?,?,-).
4338 % Instead of blocking on Low2,Up2 we could post bigger constraint (Low2 <= Up2 => (Low1 <= Up1 /\ ....
4339 not_strict_subset_intervals(_Low1,_Up1,Low2,Up2) :- safe_less_than_with_inf(Up2,Low2),!.
4340 not_strict_subset_intervals(Low1,Up1,Low2,Up2) :-
4341 safe_less_than_equal_with_inf_clpfd(Low1,Up1), % if Low1..Up1 is empty then it would be a strict subset
4342 not_check_strict_subset_intervals2(Low1,Up1,Low2,Up2).
4343 :- block not_check_strict_subset_intervals2(-,?,?,?),not_check_strict_subset_intervals2(?,-,?,?),
4344 not_check_strict_subset_intervals2(?,?,-,?).
4345 not_check_strict_subset_intervals2(Low1,Up1,Low2,Up2) :- \+ check_strict_subset_intervals2(Low1,Up1,Low2,Up2).
4346
4347
4348 /* Set1 /: FIN1(Set2) */
4349 :- assert_must_succeed((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(2)])).
4350 :- assert_must_succeed((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X=[int(1)], Y=[int(1),int(2)])).
4351 :- assert_must_succeed((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[])).
4352 :- assert_must_fail((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(1)])).
4353
4354 :- block not_non_empty_finite_subset_of_wf(-,?,?).
4355 not_non_empty_finite_subset_of_wf(Set1,Set2,WF) :- test_finite_set_wf(Set1,Finite,WF),
4356 not_non_empty_finite_subset_of_aux(Finite,Set1,Set2,WF).
4357 :- block not_non_empty_finite_subset_of_aux(-,?,?,?).
4358 not_non_empty_finite_subset_of_aux(pred_false,_Set1,_Set2,_WF).
4359 not_non_empty_finite_subset_of_aux(pred_true,Set1,Set2,WF) :- not_non_empty_subset_of_wf(Set1,Set2,WF).
4360
4361 /* Set1 /: POW1(Set2) */
4362 :- assert_must_succeed(exhaustive_kernel_check_wf(not_non_empty_subset_of_wf([int(1)], [int(2),int(3)],WF),WF)).
4363 :- assert_must_succeed(exhaustive_kernel_fail_check_wf(not_non_empty_subset_of_wf([int(2)], [int(2),int(3)],WF),WF)).
4364 :- assert_must_succeed((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(2)])).
4365 :- assert_must_succeed((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X=[int(1)], Y=[int(1),int(2)])).
4366 :- assert_must_succeed((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[])).
4367 :- assert_must_fail((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(1)])).
4368
4369 % Set1 /: POW1(Set2)
4370 :- block not_non_empty_subset_of_wf(-,?,?).
4371 not_non_empty_subset_of_wf(Set1,_,_WF) :- Set1==[],!.
4372 not_non_empty_subset_of_wf(Set1,Set2,WF) :- % Maybe introduce binary choice point ?
4373 empty_set_wf(Set1,WF) ;
4374 not_subset_of_wf(Set1,Set2,WF).
4375
4376
4377 /* min, max */
4378
4379 :- assert_must_succeed(exhaustive_kernel_check(minimum_of_set([int(1)],int(1),unknown,_WF))).
4380 :- assert_must_succeed(exhaustive_kernel_check(minimum_of_set([int(2),int(3),int(1)],int(1),unknown,_WF))).
4381 :- assert_must_succeed(exhaustive_kernel_fail_check(minimum_of_set([int(2),int(3),int(1)],int(2),unknown,_WF))).
4382 :- assert_must_succeed((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(1)])).
4383 :- assert_must_succeed((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(2),int(1)])).
4384 :- assert_must_succeed((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(1),int(2),int(1),int(3)])).
4385 :- assert_must_fail((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(2), Y=[int(1),int(2),int(1),int(3)])).
4386 :- assert_must_abort_wf(kernel_objects:minimum_of_set([],_R,unknown,WF),WF).
4387 %:- must_succeed(kernel_waitflags:assert_must_abort2_wf(kernel_objects:minimum_of_set([],_R,WF),WF)).
4388
4389 :- block minimum_of_set_extension_list(-,?,?,?).
4390 minimum_of_set_extension_list(ListOfValues,int(Min),Span,WF) :-
4391 minimum_of_set2(ListOfValues,Min,Span,WF).
4392
4393 :- block minimum_of_set(-,?,?,?).
4394 minimum_of_set(Set1,Res,_Span,WF) :- is_custom_explicit_set(Set1,minimum_of_set),
4395 min_of_explicit_set(Set1,Min), !,
4396 %%print_term_summary(explicit_set_min(Set1,Min)), %%
4397 equal_object_wf(Min,Res,minimum_of_set,WF).
4398 minimum_of_set(Set1,int(Min),Span,WF) :- expand_custom_set_to_list(Set1,ESet1,_,minimum_of_set),
4399 minimum_of_set2(ESet1,Min,Span,WF).
4400 :- block minimum_of_set2(-,?,?,?).
4401 minimum_of_set2([],Res,Span,WF) :-
4402 add_wd_error_set_result('min applied to empty set','',Res,int(0),Span,WF).
4403 minimum_of_set2([int(N)|T],Min,_,_) :- clpfd_geq2(N,Min,_),minimum_of_set3(T,N,Min,[N]).
4404
4405 :- if((current_prolog_flag(version_data,sicstus(4,X,Y,_,_)),(X>2;X=2,Y>0))). % we are 4.2.1 or later
4406 :- block minimum_of_set3(-,?,?,?). % with CLPFD: makes sense to also unfold if Min Variable; hence no longer block on : minimum_of_set3(?,-,-).
4407 minimum_of_set3([],MinSoFar,MinSoFar,ListOfValues) :-
4408 (var(MinSoFar) -> clpfd_minimum(MinSoFar,ListOfValues) ; true). % THIS CRASHES SICSTUS 4.2.0
4409 :- else.
4410 :- block minimum_of_set3(-,?,?,?).
4411 minimum_of_set3([],MinSoFar,MinSoFar,_ListOfValues).
4412 :- endif.
4413 minimum_of_set3([int(M)|T],MinSoFar,Min,ListOfValues) :- clpfd_geq2(M,Min,_),
4414 minimum(M,MinSoFar,NewMinSoFar),
4415 minimum_of_set3(T,NewMinSoFar,Min,[M|ListOfValues]).
4416
4417
4418 :- block minimum(-,?,?), minimum(?,-,?).
4419 minimum(M1,M2,Min) :- M1<M2 -> Min=M1 ; Min=M2.
4420
4421 :- assert_must_succeed(exhaustive_kernel_check(maximum_of_set([int(1)],int(1),unknown,_WF))).
4422 :- assert_must_succeed(exhaustive_kernel_check(maximum_of_set([int(2),int(3),int(1)],int(3),unknown,_WF))).
4423 :- assert_must_succeed(exhaustive_kernel_fail_check(maximum_of_set([int(2),int(3),int(1)],int(2),unknown,_WF))).
4424 :- assert_must_succeed((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(1)])).
4425 :- assert_must_succeed((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(2), Y=[int(2),int(1)])).
4426 :- assert_must_succeed((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(3), Y=[int(1),int(2),int(1),int(3)])).
4427 :- assert_must_fail((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(2), Y=[int(1),int(2),int(1),int(3)])).
4428 :- assert_must_fail((preferences:preference(use_clpfd_solver,true),
4429 kernel_objects:maximum_of_set([int(X),int(_Y)],int(3),unknown,_WF), X = 4)). % in CLPFD modus
4430 :- assert_must_fail((preferences:preference(use_clpfd_solver,true),
4431 kernel_objects:maximum_of_set([int(_),int(X)],int(3),unknown,_WF), X = 4)).% in CLPFD modus
4432 :- assert_must_abort_wf(kernel_objects:maximum_of_set([],_R,unknown,WF),WF).
4433
4434 :- block maximum_of_set_extension_list(-,?,?,?).
4435 maximum_of_set_extension_list(ListOfValues,int(Max),Span,WF) :-
4436 maximum_of_set2(ListOfValues,Max,Span,WF).
4437
4438 :- block maximum_of_set(-,?,?,?).
4439 maximum_of_set(Set1,Res,_Span,WF) :- %print(max(Set1,Res)),nl,
4440 ? is_custom_explicit_set(Set1,maximum_of_set),
4441 ? max_of_explicit_set(Set1,Max), !,
4442 % print_term_summary(explicit_set_max(Set1,Max)), %%
4443 ? equal_object_wf(Max,Res,maximum_of_set,WF).
4444 maximum_of_set(Set1,int(Max),Span,WF) :-
4445 expand_custom_set_to_list(Set1,ESet1,_,maximum_of_set),
4446 maximum_of_set2(ESet1,Max,Span,WF).
4447 :- block maximum_of_set2(-,?,?,?).
4448 maximum_of_set2([],Res,Span,WF) :-
4449 add_wd_error_set_result('max applied to empty set','',Res,int(0),Span,WF). %preferences:get_preference(maxint,R))). %R=abort(maximum_of_empty_set))).
4450 maximum_of_set2([int(N)|T],Max,_Span,_) :- clpfd_geq2(Max,N,_),
4451 maximum_of_set3(T,N,Max,[N]).
4452
4453 :- if((current_prolog_flag(version_data,sicstus(4,X,Y,_,_)),(X>2;X=2,Y>0))). % we are 4.2.1 or later
4454 :- block maximum_of_set3(-,?,?,?). % with CLPFD: makes sense to also unfold if Max Variable; hence no longer block on : maximum_of_set3(?,-,-).
4455 maximum_of_set3([],MaxSoFar,MaxSoFar,ListOfValues) :-
4456 (var(MaxSoFar) -> clpfd_maximum(MaxSoFar,ListOfValues) ; true). % THIS CRASHES SICSTUS 4.2.0
4457 :- else.
4458 :- block maximum_of_set3(-,?,?,?).
4459 maximum_of_set3([],MaxSoFar,MaxSoFar,_ListOfValues).
4460 :- endif.
4461 maximum_of_set3([int(M)|T],MaxSoFar,Max,ListOfValues) :- clpfd_geq2(Max,M,_),
4462 maximum(M,MaxSoFar,NewMaxSoFar),
4463 maximum_of_set3(T,NewMaxSoFar,Max,[M|ListOfValues]).
4464
4465 :- block maximum(-,?,?), maximum(?,-,?).
4466 maximum(M1,M2,Max) :- M1>M2 -> Max=M1 ; Max=M2.
4467
4468
4469 :- assert_must_succeed((cardinality_of_set_extension_list([fd(1,'Name')],R,_WF), R = int(1))).
4470 :- assert_must_succeed((cardinality_of_set_extension_list([int(X),int(Y)],int(1),_WF), X=22, Y==22)).
4471
4472 cardinality_of_set_extension_list(List,int(Card),WF) :-
4473 length(List,MaxCard), less_than_equal_direct(Card,MaxCard),
4474 cardinality_of_set_extension_list2(List,[],0,MaxCard,Card,WF).
4475
4476 :- block cardinality_of_set_extension_list2(-,?,?,?,?,?).
4477 cardinality_of_set_extension_list2([],_,AccSz,_MaxCard,Res,_WF) :- Res=AccSz.
4478 cardinality_of_set_extension_list2([H|T],Acc,AccSz,MaxCard,Res,WF) :-
4479 % print(card_set_ext([H|T],Acc,AccSz,MaxCard,Res)),nl,
4480 membership_test_wf(Acc,H,MemRes,WF),
4481 (MaxCard==Res -> /* only solution is for H to be not in Acc */ MemRes=pred_false
4482 ; AccSz==Res -> /* only solution is for H to be in Acc */ MemRes=pred_true
4483 ; (var(Res),var(MemRes)) -> kernel_equality:equality_int(MaxCard,Res,EqMaxC),prop_if_pred_true(EqMaxC,MemRes,pred_false),
4484 kernel_equality:equality_int(AccSz,Res,EqAccSz),prop_if_pred_true(EqAccSz,MemRes,pred_true)
4485 ; true),
4486 cardinality_of_set_extension_list3(MemRes,H,T,Acc,AccSz,MaxCard,Res,WF).
4487
4488 :- block prop_if_pred_true(-,?,?).
4489 prop_if_pred_true(pred_true,X,X).
4490 prop_if_pred_true(pred_false,_,_).
4491
4492 :- block cardinality_of_set_extension_list3(-,?,?,?,?,?,?,?).
4493 cardinality_of_set_extension_list3(pred_true,_,T,Acc,AccSz,MaxCard,Res,WF) :-
4494 % H is a member of Acc, do not increase Acc nor AccSz; however MaxCard now decreases
4495 less_than_direct(Res,MaxCard), M1 is MaxCard-1,
4496 cardinality_of_set_extension_list2(T,Acc,AccSz,M1,Res,WF).
4497 cardinality_of_set_extension_list3(pred_false,H,T,Acc,AccSz,MaxCard,Res,WF) :-
4498 A1 is AccSz+1, less_than_equal_direct(A1,Res),
4499 cardinality_of_set_extension_list2(T,[H|Acc],A1,MaxCard,Res,WF).
4500
4501 :- assert_must_succeed(exhaustive_kernel_check(is_finite_set_wf([fd(1,'Name'),fd(2,'Name')],_WF))).
4502 :- assert_must_succeed((is_finite_set_wf(Y,_WF), Y = [])).
4503 :- assert_must_succeed((is_finite_set_wf(Y,_WF), Y = [int(1),int(2)])).
4504 :- use_module(typing_tools,[contains_infinite_type/1]).
4505 :- use_module(custom_explicit_sets,[card_for_specific_custom_set/3]).
4506
4507 is_finite_set_wf(Set,WF) :- test_finite_set_wf(Set,pred_true,WF).
4508
4509 :- assert_must_succeed(exhaustive_kernel_fail_check(is_infinite_set_wf([fd(1,'Name'),fd(2,'Name')],_WF))).
4510 :- assert_must_fail((is_infinite_set_wf(Y,_WF), Y = [int(1),int(2)])).
4511
4512 is_infinite_set_wf(Set,WF) :- test_finite_set_wf(Set,pred_false,WF).
4513
4514 :- block test_finite_set_wf(-,?,?).
4515 %test_finite_set_wf(A,B,C) :- print(test_finite_set_wf(A,B,C)),nl,fail.
4516 test_finite_set_wf([],X,_WF) :- !, X=pred_true.
4517 test_finite_set_wf([_|T],X,WF) :- !, test_finite_set_wf(T,X,WF). % what if Tail contains closure ??
4518 test_finite_set_wf(avl_set(_),X,_WF) :- !, X=pred_true.
4519 test_finite_set_wf(closure(_P,T,_B),X,_WF) :- \+ contains_infinite_type(T), !, X=pred_true.
4520 test_finite_set_wf(closure(P,T,B),X,WF) :- !, test_finite_closure(P,T,B,X,WF).
4521 test_finite_set_wf(Set,X,WF) :- /* also deals with global_set(_) */
4522 /* explicit_set_cardinality may trigger an enum warning */
4523 explicit_set_cardinality_wf(Set,Card,WF), set_finite_result(Card,Set,X).
4524
4525 :- use_module(bsyntaxtree,[is_a_disjunct/3]).
4526 % we already check that contains_infinite_type above
4527 test_finite_closure(P,T,B,X,WF) :- is_a_disjunct(B,D1,D2),!,
4528 test_finite_closure(P,T,D1,X1,WF),
4529 (X1=pred_true -> test_finite_closure(P,T,D2,X,WF)
4530 ; X = pred_false).
4531 % TO DO: add is_closure1_value_closure
4532 test_finite_closure(P,T,B,X,WF) :- when(ground(B), test_finite_closure_ground(P,T,B,X,WF)).
4533
4534 % first: we need to check all constructors such as POW, FIN, ... which card_for_specific_custom_set supports
4535 % problem: if card becomes very large it is replaced by inf, which may give wrong results here (for card(.) we just get a spurious WD warning, here we may get wrong results)
4536 test_finite_closure_ground(P,T,B,X,WF) :-
4537 is_powerset_closure(closure(P,T,B),_Type,Subset),
4538 % note: whether Type is fin, fin1, pow, or pow1 does not matter
4539 !,
4540 test_finite_set_wf(Subset,X,WF).
4541 test_finite_closure_ground(P,T,B,X,WF) :-
4542 custom_explicit_sets:is_lambda_value_domain_closure(P,T,B, Subset,_Expr), !,
4543 %print(lambda(Subset)),nl,
4544 test_finite_set_wf(Subset,X,WF).
4545 test_finite_closure_ground(P,T,B,X,WF) :-
4546 custom_explicit_sets:is_cartesian_product_closure(closure(P,T,B), A1,B2), !,
4547 test_finite_set_wf(A1,AX,WF),
4548 test_finite_set_wf(B2,BX,WF),
4549 %print(result_cart(AX,BX)),nl,
4550 test_finite_cartesian_product(AX,BX,A1,B2,X).
4551 test_finite_closure_ground(Par,Typ,Body, X,_WF) :- %print(try(Par,Typ,Body)),nl,
4552 custom_explicit_sets:is_geq_leq_interval_closure(Par,Typ,Body,Low,Up), !,
4553 % print(geq_leq(Par,Low,Up,Body)),nl,
4554 custom_explicit_sets:card_of_interval_inf(Low,Up,Card), %print(Card),nl,
4555 set_finite_result_no_warn(Card,X).
4556 test_finite_closure_ground(P,T,B,X,WF) :-
4557 custom_explicit_sets:is_member_closure(P,T,B,_,SET), nonvar(SET),
4558 unary_member_closure_for_finite(SET,Check,SET1),
4559 !,
4560 (Check==finite -> test_finite_set_wf(SET1,X,WF) ; kernel_equality:eq_empty_set(SET1,X)).
4561 % TO DO: catch other special cases : relations, struct,...
4562 test_finite_closure_ground(P,T,B,X,_WF) :-
4563 card_for_specific_custom_set(closure(P,T,B),Card,Code),!,
4564 call(Code), % TO DO: catch if we convert large integer due to overflow to inf !
4565 % maybe we can set / transmit a flag for is_overflowcheck ? overflow_float_pown ? factorial ?
4566 set_finite_result(Card,closure(P,T,B),X).
4567 test_finite_closure_ground(P,T,B,X,WF) :- %print(try_expand2(P)),nl,
4568 on_enumeration_warning(expand_only_custom_closure_global(closure(P,T,B),Result,check,WF),fail),
4569 !,
4570 %print(expanded2(P,Result)),nl,
4571 test_finite_set_wf(Result,X,WF).
4572 test_finite_closure_ground(P,T,B,X,WF) :- X==pred_true, !,
4573 get_enumeration_finished_wait_flag(WF,AWF), % only add warning if indeed we find a solution
4574 finite_warning(AWF,P,T,B,is_finite_set_closure(P)).
4575 test_finite_closure_ground(P,T,B,_X,_WF) :- !,
4576 finite_warning(now,P,T,B,test_finite_closure(P)),
4577 fail. % now we fail; used to be X=pred_true. % we assume set to be finite, but print a warning
4578 % we could set up the closure and do a deterministic phase: if it fails or all variables become bounded, then it is finite
4579
4580 unary_member_closure_for_finite(seq(b(value(SET1),_,_)),empty,SET1). % finite if SET1 is empty
4581 unary_member_closure_for_finite(seq1(b(value(SET1),_,_)),empty,SET1).
4582 unary_member_closure_for_finite(perm(b(value(SET1),_,_)),finite,SET1). % finite if SET1 is finite
4583 unary_member_closure_for_finite(iseq(b(value(SET1),_,_)),finite,SET1).
4584 unary_member_closure_for_finite(iseq1(b(value(SET1),_,_)),finite,SET1).
4585 unary_member_closure_for_finite(identity(b(value(SET1),_,_)),finite,SET1).
4586 % we could deal with POW/POW1... here
4587
4588 :- block test_finite_cartesian_product(-,?,?,?,?), test_finite_cartesian_product(?,-,?,?,?).
4589 test_finite_cartesian_product(pred_true, pred_true, _,_,X) :- !, X=pred_true. % both finite
4590 test_finite_cartesian_product(pred_false,pred_false,_,_,X) :- !, X=pred_false. % both infinite
4591 test_finite_cartesian_product(pred_false,pred_true, _,B,X) :- !,
4592 kernel_equality:eq_empty_set(B,X). % only finite if B empty
4593 test_finite_cartesian_product(pred_true, pred_false,A,_,X) :- !,
4594 kernel_equality:eq_empty_set(A,X). % only finite if B empty
4595
4596
4597 :- block set_finite_result_no_warn(-,?).
4598 set_finite_result_no_warn(inf,X) :- !, X=pred_false.
4599 set_finite_result_no_warn(_,pred_true).
4600
4601 :- block set_finite_result(-,?,?).
4602 set_finite_result(inf,Set,X) :- !,
4603 (Set=closure(P,T,B) %,preferences:preference(disprover_mode,_true))
4604 -> finite_warning(now,P,T,B,test_finite_closure(P)) % we sometimes return inf for very large sets % TO DO: fix
4605 ; true),
4606 X=pred_false.
4607 set_finite_result(_,_,pred_true).
4608
4609
4610 :- assert_must_succeed((finite_cardinality_as_int(Y,int(X),_WF), Y = [fd(1,'Name'),fd(2,'Name')],X==2)).
4611 :- assert_must_succeed(exhaustive_kernel_check(cardinality_as_int([int(2),int(4),int(1)],int(3)))).
4612 :- assert_must_succeed((cardinality_as_int(Y,int(2)), Y = [fd(1,'Name'),fd(2,'Name')])).
4613 :- assert_must_succeed((cardinality_as_int(Y,int(2)),
4614 nonvar(Y), Y = [H1|YY], nonvar(YY), YY=[H2], H1=int(0), H2=int(3) )).
4615 :- assert_must_succeed((cardinality_as_int([A|Y],int(3)),
4616 nonvar(Y), Y = [B|YY], nonvar(YY), YY=[C], A=int(1),B=int(3),C=int(2) )).
4617 :- assert_must_succeed((cardinality_as_int(Y,int(1)), Y = [fd(1,'Name')])).
4618 :- assert_must_succeed((cardinality_as_int(Y,int(0)), Y = [])).
4619 :- assert_must_succeed((cardinality_as_int(X,int(3)), equal_object(X,global_set('Name')))).
4620 :- assert_must_fail((cardinality_as_int(Y,int(X)), Y = [fd(1,'Name'),fd(2,'Name')],dif(X,2))).
4621 :- assert_must_succeed_any((preferences:preference(use_clpfd_solver,false) ;
4622 cardinality_as_int(S,int(C)), clpfd_interface:try_post_constraint('#>='(C,2)), nonvar(S),S=[_|T],nonvar(T))).
4623 :- assert_must_succeed((cardinality_as_int([int(1)|avl_set(node(int(3),true,0,empty,empty))],int(2)))).
4624 :- assert_must_succeed((cardinality_as_int([int(1)|avl_set(node(int(3),true,0,empty,empty))],X),X==int(2))).
4625 % check that we deal with repeated elements, in case no other predicate sets up a list !
4626 :- assert_must_fail((cardinality_as_int([int(1),int(1)],int(2)))).
4627 :- assert_must_fail((cardinality_as_int([int(1),int(1)],_))).
4628 :- assert_must_fail((cardinality_as_int(X,int(2)),X=[int(1),int(1)])).
4629 :- assert_must_fail((cardinality_as_int([int(3)|avl_set(node(int(3),true,0,empty,empty))],_))).
4630 :- assert_must_fail((cardinality_as_int([X|avl_set(node(int(3),true,0,empty,empty))],int(2)),X=int(3))).
4631
4632 % :- use_module(probsrc(kernel_cardinality)).
4633 %finite_cardinality_as_int(Set,C,WF) :- preference(use_clpfd_solver,true), !, kernel_cardinality:finite_int_cardinality(Set,C,WF). % see also test 34 where this helps
4634 finite_cardinality_as_int(Set,int(Card),WF) :- % print(card(Set)),nl,trace,
4635 % if Card is already known we could give it to cardinality_as_int1 straightaway; but we would not detect certain WD-problems
4636 %(number(Card) -> CardValue=Card ; true),
4637 cardinality_as_int1(Set,Card,CardValue,WF), % print(card_value(CardValue,Card)),nl,
4638 % clpfd_domain(CardValue,Low,Up), print(card(CardValue,Low,Up,Set)),nl,trace,
4639 (clpfd_max_bounded(CardValue)
4640 -> Card=CardValue % we cannot have an infinite return value for CardValue
4641 ; (nonvar(Set),is_interval_closure(Set,_,_)) -> % we must have a finite interval; no need to guard against inf
4642 Card=CardValue % TO DO: let cardinality_as_int1 return a flag whether set can be infinite
4643 % example i=2..x & card(i):10..2122110 & x > 2121000; see test 1625
4644 ; check_finite_card(CardValue,Card,Set,WF) % check that we have obtained a finite value; only propagate then
4645 % TO DO: maybe detect a few more cases where infinite return values are not possible; e.g., based on type
4646 % indeed: check_finite_card prevents propagation of CLPFD information
4647 ).
4648
4649 :- block check_finite_card(-,-,?,?).
4650 % check before assigning that the result is not "inf" (otherwise we may trigger arithmetic co-routines before generating the error)
4651 check_finite_card(CardValue,C,Set,WF) :- % print(check_finite_card(CardValue,C)),nl,
4652 (CardValue==inf -> add_wd_error('card applied to infinite (or very large) set: ',b(value(Set),any,[]),WF)
4653 % if CardValue not yet instantiated we may want to delay the unification below for stronger wd-checking:
4654 % i.e., if find_abort_values preference is true
4655 ; C=CardValue).
4656
4657
4658 cardinality_as_int(S,I) :- cardinality_as_int_wf(S,I,no_wf_available). % TO DO: remove this predicate ?
4659 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
4660 :- if(environ(prob_data_validation_mode,true)).
4661 :- block cardinality_as_int_wf(-,?,?). % avoid instantiating list skeletons; cause backtracking in unifications,...
4662 :- else.
4663 :- block cardinality_as_int_wf(-,-,?).
4664 :- endif.
4665 % can return inf !
4666 cardinality_as_int_wf(Set,int(Card),WF) :-
4667 cardinality_as_int1(Set,Card,Card,WF).
4668
4669 cardinality_as_int1(Set,Card,ResCard,WF) :-
4670 %print(card1(Set,Card,ResCard)), tools_printing:print_var_integer(Card),
4671 (number(Card) -> cardinality_as_int1b(Set,Card,ResCard,WF) ;
4672 cardinality_as_int1b(Set,Card,ResCard,WF),
4673 (var(Set) ->
4674 (clpfd_domain(Card,Low,_Up), number(Low), Low>1,
4675 unbound_variable_for_card(Set)
4676 % TO DO: also use this optimization later in cardinality_as_int2
4677 -> setup_ordered_list_skeleton(Low,Skel,open,WF), %print(open_skel_low(Low,Up,Skel)),nl,
4678 Skel=Set
4679 ; get_wait_flag(1,force_non_empty(Set,Card),WF,LWF),
4680 force_non_empty(Set,0,Card,LWF) % we could consider using guarding this with a waitflag with priority 1.1
4681 )
4682 ; true)
4683 ).
4684 % tests 1418, 1419, 1628, 1776 require that cardinality_as_int1b be triggered quickly
4685 :- block cardinality_as_int1b(-,-,?,?). % with this the self-check with post_constraint('#>='(C,2) fails
4686 % cardinality_as_int1(Set, CardValue, ComputedCardValue) : CardValue should be unified with ComputedCardValue afterwards
4687 cardinality_as_int1b(Set,Card,ResCard,WF) :- % print(card1b(Card)),nl,
4688 %portray_waitflags(WF),nl,
4689 number(Card), unbound_variable_for_card(Set),
4690 !, % we know the cardinality and the set is not yet bound; this improvement is tested in tests 1417, 1418
4691 %frozen(Set,F), print(frozen(Set,F)),nl,
4692 setup_ordered_list_skeleton(Card,Skel,closed,WF),
4693 %% print(skel(Card,Skel)),nl, %%
4694 (Card,Set) = (ResCard,Skel). % bypass equal_object: assign variable in one-go
4695 cardinality_as_int1b(Set,Card,ResCard,WF) :- nonvar(Set),!,
4696 cardinality_as_int2(Set,0,Card,ResCard,[],WF).
4697 cardinality_as_int1b(Set,Card,ResCard,WF) :- %print(card2_prio(Card,ResCard,WF)),nl,
4698 % Set is a variable but not unbound_variable_for_cons
4699 % Unifications can be very expensive when we set up long lists
4700 % Idea: multiply Card by a factor and delay instantiating; maybe we get a avl_set; see test 456
4701 Prio is Card*100,
4702 get_wait_flag(Prio,cardinality_as_int1(Set,Card),WF,LWF2),
4703 when((nonvar(Set) ; nonvar(LWF2)),
4704 cardinality_as_int2(Set,0,Card,ResCard,[],WF)).
4705 %force_non_empty(Set,0,Card,1). % we could consider using guarding this with a waitflag with priority 1.1
4706
4707 :- if(environ(prob_data_validation_mode,true)).
4708 :- block cardinality_as_int2(-,?,?,?,?,?). % avoid instantiating list skeletons; cause backtracking in unifications,...
4709 :- else.
4710 :- block cardinality_as_int2(-,?,-,?,?,?).
4711 :- endif.
4712 cardinality_as_int2(X,C,Res,ResultValue,_,WF) :- % print(card2(X,C,Res,ResultValue)),nl,
4713 C==Res,!,empty_set_wf(X,WF),ResultValue=Res. % avoid choice point below
4714 cardinality_as_int2(X,C,Res,ResultValue,SoFar,WF) :- nonvar(X), X \= [], X\= [_|_],!,
4715 (is_custom_explicit_set(X)
4716 -> %print(explicit_set_card(X,C,ResultValue)),nl,
4717 explicit_set_cardinality_wf(X,ESC,WF), add_card(C,ESC,ResultValue),
4718 disjoint_sets(X,SoFar,WF)
4719 ; add_error_fail(cardinality_as_int2,'First argument not set: ',cardinality_as_int2(X,C,Res))
4720 ).
4721 cardinality_as_int2([],C,Res,ResultValue,_,_WF) :- C=ResultValue, Res=ResultValue.
4722 cardinality_as_int2([H|T],C,Res,ResultValue,SoFar,WF) :-
4723 C1 is C+1,
4724 % print(card(_H,T,C,Res)),nl,
4725 not_element_of_wf(H,SoFar,WF), % do we always need to check this ? relevant for test 1828
4726 add_new_element_wf(H,SoFar,SoFar2,WF),
4727 (ground(Res) -> safe_less_than_equal(cardinality_as_int2,C1,Res)
4728 /* check consistency so far if cardinality provided */
4729 ; clpfd_geq(Res,C1,_) %,(ground(Res)->print(forced(Res)),nl;true)
4730 ),
4731 force_non_empty(T,C1,Res,1), % Use WF ?
4732 cardinality_as_int2(T,C1,Res,ResultValue,[H|SoFar2],WF).
4733
4734 % setup an list skeleton with ordering constraints to avoid duplicate solutions
4735 setup_ordered_list_skeleton(0,R,Closed,_WF) :- !, (Closed=closed -> R=[] ; true).
4736 setup_ordered_list_skeleton(N,[H|T],Closed,WF) :-
4737 all_different_wf([H|T],WF),
4738 N1 is N-1, setup_list_skel_aux(N1,H,T,Closed).
4739
4740
4741 :- use_module(kernel_ordering,[ordered_value/2]).
4742 %setup_list_skel_aux(0,_,R,Closed) :- !, (Closed=closed -> R=[] ; true). % if open: TO DO: impose ordering on rest using lazy_ordered_value ? done in next clause below
4743 setup_list_skel_aux(0,Prev,R,Closed) :- !, (Closed=closed -> R=[] ; lazy_ordered_value(R,Prev)).
4744 setup_list_skel_aux(N,Prev,[H|T],Closed) :- ordered_value(Prev,H),
4745 N>0, N1 is N-1, setup_list_skel_aux(N1,H,T,Closed).
4746
4747 :- block lazy_ordered_value(-,?).
4748 lazy_ordered_value([H|T],Prev) :- !, ordered_value(Prev,H), lazy_ordered_value(T,H).
4749 lazy_ordered_value(_,_).
4750
4751
4752 % TO DO: use clpfd all_different for integers !?
4753 % get_integer_list(Set,IntList), clpfd_alldifferent(IntList).
4754 % ensure we have all different constraint in case ordered_value does not succeed in enforcing order!
4755 all_different_wf(ListOfValues,WF) :-
4756 all_different2(ListOfValues,[],WF).
4757 :- block all_different2(-,?,?).
4758 all_different2([],_,_) :- !.
4759 all_different2([H|T],SoFar,WF) :- !, all_different3(SoFar,H,WF), all_different2(T,[H|SoFar],WF).
4760 all_different2(CS,SoFar,WF) :- is_custom_explicit_set(CS),
4761 disjoint_sets(CS,SoFar,WF). % already done above by cardinality_as_int2 ?
4762 all_different3([],_,_).
4763 all_different3([H|T],X,WF) :- not_equal_object_wf(H,X,WF), all_different3(T,X,WF).
4764
4765
4766
4767 force_non_empty(Set,CSoFar,TotalCard,LWF) :-
4768 var(Set), var(TotalCard),
4769 preference(data_validation_mode,false),!,
4770 % print(force_non_empty(CSoFar)),nl,
4771 clpfd_interface:try_post_constraint(clpfd:'#<=>'( (TotalCard#=CSoFar) , EmptyR01)),
4772 prop_non_empty(EmptyR01,Set,LWF).
4773 force_non_empty(_,_,_,_).
4774 :- block prop_non_empty(-,-,?).
4775 prop_non_empty(_,X,_) :- nonvar(X),!. % do nothing; cardinality_as_int2 will be called anyway
4776 prop_non_empty(0,X,LWF) :- /* X is var; first arg nonvar */ !, not_empty_set_lwf(X,LWF).
4777 %prop_non_empty(1,X,_). % empty_set not really required: TotalCard is now instantiated; cardinality_as_int2 will get called
4778 prop_non_empty(_,_,_).
4779
4780
4781
4782 :- assert_must_succeed(exhaustive_kernel_check(cardinality_as_int_for_wf(global_set('NATURAL'),inf))).
4783 :- assert_must_succeed(exhaustive_kernel_check(cardinality_as_int_for_wf([],0))).
4784 :- assert_must_succeed(exhaustive_kernel_check_opt(cardinality_as_int_for_wf([int(2)],1),
4785 preferences:get_preference(convert_comprehension_sets_into_closures,false))). % in this case inf returned for closures
4786 :- assert_must_succeed(exhaustive_kernel_check_opt(cardinality_as_int_for_wf([int(3),int(1),int(-1),int(100)],4),
4787 preferences:get_preference(convert_comprehension_sets_into_closures,false))).
4788 :- assert_must_succeed(exhaustive_kernel_fail_check_opt(cardinality_as_int_for_wf([int(3),int(1),int(-1),int(100)],1000),
4789 preferences:get_preference(convert_comprehension_sets_into_closures,false))).
4790 :- assert_must_succeed(exhaustive_kernel_fail_check_opt(cardinality_as_int_for_wf(global_set('NATURAL'),1000),
4791 preferences:get_preference(convert_comprehension_sets_into_closures,false))).
4792 % a simpler version without propagation to result; for waitflag priority computation or similar
4793 % it may return inf for closures marked as symbolic !
4794 cardinality_as_int_for_wf(Set,Card) :- cardinality_as_int_for_wf0(Set,0,Card).
4795 :- block cardinality_as_int_for_wf0(-,?,-).
4796 cardinality_as_int_for_wf0(X,C,Res) :-
4797 (nonvar(X) -> cardinality_as_int_for_wf1(X,C,Res)
4798 ; Res==inf -> cardinality_as_int_for_inf(X,C)
4799 ; cardinality_as_int_for_wf2(X,C,Res)).
4800
4801 :- block cardinality_as_int_for_inf(-,?).
4802 cardinality_as_int_for_inf(X,C) :- cardinality_as_int_for_wf1(X,C,inf).
4803
4804 cardinality_as_int_for_wf1([],C,Res) :- !,C=Res.
4805 cardinality_as_int_for_wf1([_H|T],C,Res) :- !,C1 is C+1,
4806 cardinality_as_int_for_wf0(T,C1,Res).
4807 cardinality_as_int_for_wf1(X,C,Res) :- is_custom_explicit_set(X),!,
4808 explicit_set_cardinality_for_wf(X,ESC), add_card(C,ESC,Res).
4809 cardinality_as_int_for_wf1(term(T),C,Res) :- nonvar(T), T=no_value_for(ID),
4810 format_with_colour(user_error,[bold,red],'~nNo value for ~w for cardinality_as_int_for_wf1!~n',[ID]), % can happen with partial_setup_constants
4811 !, C=Res.
4812 cardinality_as_int_for_wf1(X,C,Res) :-
4813 add_internal_error('First arg is not a set: ',cardinality_as_int_for_wf1(X,C,Res)),fail.
4814
4815 % first argument was var, third argument not inf hence third arg must be set
4816 %cardinality_as_int_for_wf2([],C,C).
4817 cardinality_as_int_for_wf2([],C,Res) :- (C==Res -> ! ; C=Res).
4818 cardinality_as_int_for_wf2([_H|T],C,Res) :- C<Res, C1 is C+1,
4819 (var(T) -> cardinality_as_int_for_wf2(T,C1,Res) ; cardinality_as_int_for_wf1(T,C1,Res)).
4820
4821 % add two cardinalities together: can be number or inf
4822 :- block add_card(-,-,?).
4823 add_card(X,Y,R) :- X==0,!,R=Y.
4824 add_card(X,Y,R) :- Y==0,!,R=X.
4825 add_card(X,_,R) :- X==inf,!,R=inf.
4826 add_card(_,Y,R) :- Y==inf,!,R=inf.
4827 add_card(X,Y,R) :- add_card2(X,Y,R).
4828
4829 :- block add_card2(-,?,?), add_card2(?,-,?).
4830 add_card2(inf,_,R) :- !,R=inf.
4831 add_card2(_,inf,R) :- !,R=inf.
4832 add_card2(X,Y,R) :- R is X+Y.
4833
4834 :- assert_must_succeed(exhaustive_kernel_check(cardinality_peano_wf([],0,no_wf_available))).
4835 :- assert_must_succeed(exhaustive_kernel_check(cardinality_peano_wf([int(11)],s(0),no_wf_available))).
4836 :- assert_must_succeed(exhaustive_kernel_check(cardinality_peano_wf([int(11),int(22)],s(s(0)),no_wf_available))).
4837 % cardinality as peano number
4838 :- block cardinality_peano_wf(-,-,?).
4839 cardinality_peano_wf(Set,PCard,WF) :-
4840 (nonvar(Set),is_custom_explicit_set(Set,cardinality)
4841 -> explicit_set_cardinality_wf(Set,Card,WF), % print(explicit_cardinality(Set,Card)),nl,
4842 card_convert_int_to_peano(Card,PCard)
4843 ; cardinality3(Set,PCard,WF)
4844 ).
4845
4846 :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(3,s(s(s(0)))))).
4847 :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(2,S),S==s(s(0)))).
4848 :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(X,s(s(s(0)))),X==3)).
4849 :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(X,s(s(s(Y)))),X=4,Y==s(0))).
4850 :- assert_must_fail((kernel_objects:card_convert_int_to_peano(X,s(s(s(_Y)))),X=2)).
4851
4852 :- block card_convert_int_to_peano(-,-).
4853 card_convert_int_to_peano(X,S0) :- var(X), !,
4854 peel_s(S0,SX,RemS), %% print(peel_s(S0,SX,RemS)),nl, %%
4855 (RemS==0 -> X=SX
4856 ; int_plus(int(X1),int(SX),int(X)),
4857 greater_than_equal(int(X1),int(0)),
4858 card_convert_int_to_peano(X1,RemS)).
4859 card_convert_int_to_peano(inf,X) :- !,
4860 add_message(cardinality,'*** WARNING: Large or infinite Cardinality.'),
4861 infinite_peano(X).
4862 %convert_int_to_peano(100,X). % used to limit to 100
4863 card_convert_int_to_peano(X,P) :- convert_int_to_peano(X,P).
4864
4865 :- block infinite_peano(-).
4866 infinite_peano(0) :- fail.
4867 infinite_peano(s(X)) :- infinite_peano(X).
4868
4869 peel_s(0,0,0).
4870 peel_s(s(X),Res,SX) :- (var(X) -> Res=1, SX=X ; peel_s(X,RX,SX), Res is RX+1).
4871
4872 :- block cardinality3(-,?,?). % avoids instantiating set; to do: use kernel_cardinality instead
4873 % relevant, e.g., for "BK-ANT-N-2013" for SlotSolver_v7; but makes 'axm2/WD' fail for test 1448; TO DO: hopefully fixed with kernel_cardinality
4874 % :- block cardinality3(-,-,?).
4875 cardinality3(Set,SC,WF) :- var(Set),!,
4876 (SC=0 -> Set=[] ; SC=s(C),Set=[_|T],cardinality3(T,C,WF)).
4877 cardinality3([],0,_).
4878 cardinality3([_|T],s(C),WF) :- cardinality3(T,C,WF).
4879 cardinality3(avl_set(AVL),Res,WF) :- cardinality_peano_wf(avl_set(AVL),Res,WF).
4880 cardinality3(closure(P,T,B),Res,WF) :- cardinality_peano_wf(closure(P,T,B),Res,WF).
4881
4882
4883
4884
4885
4886
4887 :- assert_must_succeed(exhaustive_kernel_check(card_geq([int(2),int(4),int(1)],s(s(s(0)))))).
4888 :- assert_must_succeed((kernel_objects:card_geq(global_set('Name'),s(s(s(0)))))).
4889 :- assert_must_succeed((kernel_objects:card_geq([int(1),int(2)],s(s(0))))).
4890 :- assert_must_succeed((kernel_objects:card_geq([int(1),int(2)],s(0)))).
4891 :- assert_must_fail((kernel_objects:card_geq(global_set('Name'),s(s(s(s(0))))))).
4892 :- assert_must_fail((kernel_objects:card_geq([int(1),int(2)],s(s(s(0)))))).
4893 :- block card_geq(-,-).
4894 card_geq(Set,Card) :-
4895 (nonvar(Set),is_custom_explicit_set(Set,card_geq)
4896 -> explicit_set_cardinality(Set,CCard), geq_int_peano(CCard,Card)
4897 ; card_geq2(Set,Card) ).
4898 % should we call setup_ordered_list_skeleton(Card,Set,open)
4899 :- block card_geq2(?,-).
4900 card_geq2(_,C) :- C==0,!.
4901 card_geq2(S,C) :- S==[],!,C=0.
4902 card_geq2(S,s(C)) :- var(S),!,S=[_|T],card_geq2(T,C).
4903 card_geq2([_|T],s(C)) :- card_geq2(T,C).
4904 card_geq2(avl_set(A),s(C)) :- card_geq(avl_set(A),s(C)).
4905 card_geq2(closure(P,T,B),s(C)) :- card_geq(closure(P,T,B),s(C)).
4906 card_geq2(global_set(G),s(C)) :- card_geq(global_set(G),s(C)).
4907
4908 :- block geq_int_peano(-,-).
4909 geq_int_peano(_,0).
4910 geq_int_peano(X,s(C)) :- geq_int_peano1(X,C).
4911 :- block geq_int_peano1(-,?).
4912 geq_int_peano1(inf,_) :- !.
4913 geq_int_peano1(X,C) :- X>0, X1 is X-1, geq_int_peano(X1,C).
4914
4915 :- block convert_int_to_peano(-,?).
4916 convert_int_to_peano(X,Y) :- convert_int_to_peano2(X,Y).
4917 convert_int_to_peano2(inf,_).
4918 convert_int_to_peano2(X,R) :- number(X),
4919 (X>100000
4920 -> print('*** Warning: converting large integer to peano: '),print(X),nl,
4921 (X>1000000000 -> print('*** treat like inf'),nl % no hope of ever finishing, do not instantiate just like inf
4922 ; convert_int_to_peano3(X,R))
4923 ; convert_int_to_peano3(X,R)
4924 ).
4925 convert_int_to_peano3(0,R) :- !, R=0.
4926 convert_int_to_peano3(X,s(P)) :-
4927 (X>0 -> X1 is X-1, convert_int_to_peano3(X1,P)
4928 ; X<0 -> add_error_and_fail(convert_int_to_peano,'Negative nr cannot be converted to peano: ',X)
4929 ).
4930
4931 % not used:
4932 %:- block convert_peano_to_int(-,?).
4933 %convert_peano_to_int(0,0).
4934 %convert_peano_to_int(s(P),X) :- convert_peano_to_int(P,X1), X is X1+1.
4935
4936 :- assert_must_succeed((kernel_objects:cardinality_greater_equal(Set,set(integer),int(X),integer,_WF), X=3,
4937 nonvar(Set),Set=[_|S2],nonvar(S2),S2=[_|S3],nonvar(S3),S3=[_|S4],var(S4), Set=[int(1),int(2),int(3)] )).
4938 :- assert_must_succeed((kernel_objects:cardinality_greater(Set,set(integer),int(X),integer,_WF), X=2,
4939 nonvar(Set),Set=[_|S2],nonvar(S2),S2=[_|S3],nonvar(S3),S3=[_|S4],var(S4), Set=[int(1),int(2),int(3)] )).
4940 /* special predicates called for e.g. card(Set)>X */
4941 cardinality_greater(Set,TypeSet,int(X),_,WF) :-
4942 kernel_objects:max_cardinality(TypeSet,MaxCard),
4943 %print(check_less(X,MaxCard)),nl,
4944 (number(MaxCard) -> less_than(int(X),int(MaxCard)) ; true),
4945 card_greater2(Set,X,WF).
4946 :- block card_greater2(?,-,?).
4947 card_greater2(Set,X,WF) :- X1 is X+1, card_greater_equal2(Set,X1,WF).
4948
4949 cardinality_greater_equal(Set,TypeSet,int(X),_,WF) :-
4950 kernel_objects:max_cardinality(TypeSet,MaxCard),
4951 %print(check_less_equal(X,MaxCard)),nl,
4952 (number(MaxCard) -> less_than_equal(int(X),int(MaxCard)) ; true),
4953 card_greater_equal2(Set,X,WF).
4954 :- block card_greater_equal2(?,-,?).
4955 card_greater_equal2(Set,X,WF) :-
4956 (X<1 -> true % potential WD issue, hence this predicates should only be called when no wd issue
4957 ; X=1 -> not_empty_set(Set) % ditto: Set could be infinite
4958 ; var(Set) -> setup_ordered_list_skeleton(X,Set,open,WF)
4959 ; convert_int_to_peano(X,Peano),
4960 card_geq(Set,Peano)).
4961
4962
4963
4964 %is_cartesian_pair_or_times(P,X,Y) :- is_cartesian_pair(P,X,Y).
4965 %is_cartesian_pair_or_times(int(Z),int(X),int(Y)) :- times(int(X),int(Y),int(Z)).
4966
4967 is_cartesian_pair_wf((X,Y),XType,YType,WF) :-
4968 check_element_of_wf(X,XType,WF), check_element_of_wf(Y,YType,WF).
4969
4970 :- assert_must_succeed(exhaustive_kernel_check_wf(kernel_objects:not_is_cartesian_pair((int(1),int(1)),
4971 [int(1),int(2)],[int(2),int(3)],WF),WF)).
4972 :- assert_must_succeed(exhaustive_kernel_check_wf(kernel_objects:not_is_cartesian_pair((int(3),int(2)),
4973 [int(1),int(2)],[int(2),int(3)],WF),WF)).
4974 :- assert_must_succeed((kernel_objects:not_is_cartesian_pair((int(1),int(1)),
4975 [int(1),int(2)],[int(2),int(3)],_WF))).
4976 :- assert_must_succeed((kernel_objects:not_is_cartesian_pair((int(3),int(1)),
4977 [int(1),int(2)],[int(2),int(3)],_WF))).
4978 :- assert_must_fail((kernel_objects:not_is_cartesian_pair((int(1),int(3)),
4979 [int(1),int(2)],[int(2),int(3)],_WF))).
4980 :- assert_must_succeed((kernel_objects:not_is_cartesian_pair((X,int(3)),
4981 [int(1),int(2)],[int(2),int(3)],_WF),X=int(4))).
4982
4983
4984 not_is_cartesian_pair((X,Y),XType,YType,WF) :-
4985 not_is_cartesian_pair0(X,Y,XType,YType,WF).
4986
4987 :- block not_is_cartesian_pair0(-,-,?,?,?).
4988 not_is_cartesian_pair0(X,Y,XType,YType,WF) :-
4989 (nonvar(X) -> not_is_cartesian_pair1(X,Y,XType,YType,WF)
4990 ; not_is_cartesian_pair1(Y,X,YType,XType,WF)).
4991
4992 not_is_cartesian_pair1(X,Y,XType,YType,WF) :-
4993 %print(member_ship_test(XType,X,MemResX)),nl,
4994 membership_test_wf(XType,X,MemResX,WF),
4995 (var(MemResX) -> membership_test_wf(YType,Y,MemResY,WF) ; true),
4996 not_is_cartesian_pair3(MemResX,X,XType,MemResY,Y,YType,WF).
4997
4998 :- block not_is_cartesian_pair3(-,?,?, -,?,?, ?).
4999 not_is_cartesian_pair3(MemResX,X,XType, MemResY,Y,YType, WF) :-
5000 (MemResX==pred_false -> true
5001 ; MemResY==pred_false -> true
5002 ; MemResX==pred_true -> not_element_of_wf(Y,YType,WF)
5003 ; not_element_of_wf(X,XType,WF)
5004 ).
5005
5006
5007
5008 /***************************/
5009 /* power_set(Set,TypeSet) */
5010 /* Set : POW(TypeSet) */
5011 /***************************/
5012
5013 :- assert_must_succeed(exhaustive_kernel_check(power_set([int(2),int(4)],[[int(2)],
5014 [int(4)],[],[int(4),int(2)]]))).
5015 :- assert_must_succeed(power_set([int(1)],[[int(1)],[]])).
5016 :- assert_must_succeed((power_set([int(1),int(2)],R),
5017 equal_object(R,[[],[int(1)],[int(2)],[int(1),int(2)]]))).
5018 :- assert_must_succeed(power_set([],[[]])).
5019
5020 :- block power_set(-,?).
5021 power_set(S,Res) :- %print_message(power_set(S,PowerS)),
5022 cardinality_peano_wf(S,Card,no_wf_available),
5023 when(ground(Card), /* when all elements are known */
5024 (try_expand_custom_set(S,SE),
5025 findall(Subset, generate_subsets(SE,Subset), PowerS), %print(powerS(PowerS)),nl,
5026 equal_object_optimized(PowerS,Res,power_set)
5027 )).
5028
5029
5030 generate_subsets([],[]).
5031 generate_subsets([H|T],R) :- (R=[H|GT]; R=GT), generate_subsets(T,GT).
5032
5033
5034 :- assert_must_succeed(exhaustive_kernel_check(non_empty_power_set([int(2),int(4)],[[int(2)],
5035 [int(4)],[int(4),int(2)]]))).
5036 :- assert_must_succeed(non_empty_power_set([int(1)],[[int(1)]])).
5037 :- assert_must_succeed((non_empty_power_set([int(1),int(2)],R),
5038 equal_object(R,[[int(1)],[int(2)],[int(1),int(2)]]))).
5039 :- assert_must_succeed(non_empty_power_set([],[])).
5040
5041 :- block non_empty_power_set(-,?).
5042 non_empty_power_set(S,Res) :-
5043 cardinality_peano_wf(S,Card,no_wf_available),
5044 when(ground(Card), /* when all elements are known */
5045 (try_expand_custom_set(S,SE),findall(Subset, (generate_subsets(SE,Subset),not_empty_set(Subset)), PowerS),
5046 equal_object_optimized(PowerS,Res,non_empty_power_set)) ).
5047
5048
5049
5050 /* ------- */
5051 /* BOOLEAN */
5052 /* ------- */
5053
5054 % following predicates are not used:
5055 %is_boolean(pred_true /* bool_true */).
5056 %is_boolean(pred_false /* bool_false */).
5057 %is_not_boolean(X) :- dif(X,pred_true /* bool_true */), dif(X,pred_false /* bool_false */).
5058
5059 /* ------- */
5060 /* NUMBERS */
5061 /* ------- */
5062
5063
5064 is_integer(int(X),_WF) :- when(ground(X),integer(X)).
5065 :- block is_not_integer(-).
5066 is_not_integer(X) :- X \= int(_), % will be called for x /: INTEGER; should always fail.
5067 add_internal_error('Wrong type argument: ',is_not_integer(X)),fail.
5068
5069 is_natural(int(X),_WF) :- clpfd_geq2(X,0,Posted), (Posted==true -> true ; number_geq(X,0)).
5070 is_natural1(int(X),_WF) :- clpfd_geq2(X,1,Posted), (Posted==true -> true ; number_geq(X,1)).
5071 :- block number_geq(-,?).
5072 number_geq(X,N) :- X>=N.
5073 :- block number_leq(-,?).
5074 number_leq(X,N) :- X=<N.
5075
5076 :- assert_must_succeed(is_implementable_int(int(0),_WF)).
5077 :- assert_must_fail(is_not_implementable_int(int(0))).
5078
5079
5080 is_implementable_int(int(X),WF) :- element_of_global_integer_set_wf('INT',X,WF,unkmown).
5081 is_implementable_nat(int(X),WF) :- element_of_global_integer_set_wf('NAT',X,WF,unknown).
5082 is_implementable_nat1(int(X),WF) :- element_of_global_integer_set_wf('NAT1',X,WF,unknown).
5083 is_not_implementable_int(X) :- not_element_of_global_set(X,'INT').
5084 is_not_implementable_nat(X) :- not_element_of_global_set(X,'NAT').
5085 is_not_implementable_nat1(X) :- not_element_of_global_set(X,'NAT1').
5086
5087 is_not_natural(int(X)) :- clpfd_geq2(-1,X,Posted), (Posted=true -> true ; number_leq(X,-1)).
5088 is_not_natural1(int(X)) :- clpfd_geq2(0,X,Posted), (Posted==true -> true ; number_leq(X,0)).
5089
5090 :- assert_must_succeed(exhaustive_kernel_check(less_than(int(2),int(3)))).
5091 :- assert_must_succeed(( safe_less_than(A,B),A=3,B=5 )).
5092 :- assert_must_succeed(( safe_less_than(A,B),B=5,A=3 )).
5093 :- assert_must_fail(( safe_less_than(A,B),A=5,B=3 )).
5094 :- assert_must_fail(( safe_less_than(A,B),B=3,A=5 )).
5095 :- assert_must_fail(( safe_less_than(A,B),A=5,B=5 )).
5096 :- assert_must_fail(( safe_less_than(A,B),B=5,A=5 )).
5097
5098 less_than(int(X),int(Y)) :-
5099 (number(X),number(Y) -> X < Y
5100 ; clpfd_lt(X,Y,Posted),
5101 (Posted=true -> true ; safe_less_than(X,Y))).
5102 less_than_direct(X,Y) :-
5103 (number(X),number(Y) -> X < Y
5104 ; clpfd_lt(X,Y,Posted),
5105 (Posted=true -> true ; safe_less_than(X,Y))).
5106 :- block safe_less_than(-,?), safe_less_than(?,-).
5107 safe_less_than(X,Y) :-
5108 (number(X),number(Y) -> X<Y
5109 ; add_internal_error('Arguments not numbers: ',safe_less_than(X,Y))).
5110
5111 :- assert_must_succeed(exhaustive_kernel_check(less_than_equal(int(33),int(33)))).
5112 less_than_equal(int(X),int(Y)) :-
5113 (number(X),number(Y) -> X =< Y
5114 ; clpfd_leq(X,Y,Posted),
5115 (Posted=true -> true ; safe_less_than_equal(less_than_equal,X,Y))).
5116 less_than_equal_direct(X,Y) :-
5117 (number(X),number(Y) -> X =< Y
5118 ; clpfd_leq(X,Y,Posted),
5119 (Posted=true -> true ; safe_less_than_equal(less_than_equal_direct,X,Y))).
5120
5121 safe_less_than_equal(X,Y) :-
5122 safe_less_than_equal(safe_less_than_equal,X,Y).
5123 :- block safe_less_than_equal(?,-,?), safe_less_than_equal(?,?,-).
5124 safe_less_than_equal(PP,X,Y) :- %print(slte(PP,X,Y)),nl,
5125 (number(X),number(Y) -> X=<Y
5126 ; add_internal_error('Arguments not numbers: ',safe_less_than_equal(PP,X,Y))).
5127
5128 :- assert_must_succeed(exhaustive_kernel_check(greater_than(int(2),int(1)))).
5129 :- assert_must_succeed(exhaustive_kernel_fail_check(greater_than(int(2),int(2)))).
5130 greater_than(int(X),int(Y)) :- less_than_direct(Y,X).
5131 :- assert_must_succeed(exhaustive_kernel_check(greater_than(int(2),int(1)))).
5132 :- assert_must_succeed(exhaustive_kernel_check(greater_than_equal(int(2),int(2)))).
5133 :- assert_must_succeed(exhaustive_kernel_fail_check(greater_than_equal(int(1),int(2)))).
5134 greater_than_equal(int(X),int(Y)) :- less_than_equal_direct(Y,X).
5135
5136
5137
5138
5139
5140 :- assert_must_succeed(exhaustive_kernel_check([commutative],int_plus(int(2),int(3),int(5)))).
5141 :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],int_plus(int(2),int(3),int(6)))).
5142
5143 :- assert_must_succeed(int_plus(int(1),int(2),int(3))).
5144 :- assert_must_succeed(( int_plus2(A,B,C),A=3,B=2,C==5 )).
5145 :- assert_must_succeed(( int_plus2(A,B,C),A=3,C=5,B==2 )).
5146 :- assert_must_succeed(( int_plus2(A,B,C),B=2,A=3,C==5 )).
5147 :- assert_must_succeed(( int_plus2(A,B,C),B=2,C=5,A==3 )).
5148 :- assert_must_succeed(( int_plus2(A,B,C),C=5,A=3,B==2 )).
5149 :- assert_must_succeed(( int_plus2(A,B,C),C=5,B=2,A==3 )).
5150 :- assert_must_succeed(( int_plus2(A,B,C),A=0,B==C )).
5151 :- assert_must_succeed(( int_plus2(A,B,C),B=0,A==C )).
5152
5153 int_plus(int(X),int(Y),int(Plus)) :- %print(int_plus(X,Y,Plus)),nl,
5154 ? (two_vars_or_more(X,Y,Plus)
5155 -> clpfd_eq(Plus,X+Y) % can have performance problems
5156 ; true % otherwise we can compute the value directly below; we could skip the block declaration
5157 ),
5158 int_plus2(X,Y,Plus).
5159 ?two_vars_or_more(X,Y,Z) :- var(X),!, (var(Y) ; var(Z)).
5160 two_vars_or_more(_X,Y,Z) :- var(Y) , var(Z).
5161
5162 :- block int_plus2(-,-,-).
5163 int_plus2(X,Y,Plus) :- %print(int_plus2(X,Y,Plus)),nl,
5164 ( ground(X) -> int_plus3(X,Y,Plus)
5165 ; ground(Y) -> int_plus3(Y,X,Plus)
5166 ; int_minus3(Plus,X,Y)).
5167
5168 % int_plus3/3: the first argument must be ground when called
5169 int_plus3(0,Y,Plus) :- !, Y=Plus. % not inferred by CLP(FD): Z #= Y+X, X=0. does not infer Y==Z
5170 int_plus3(X,Y,Plus) :- % print(dif(Y,Plus)),nl, integer_dif(Y,Plus), % this generates overflows for test 1353, 1014
5171 int_plus4(X,Y,Plus).
5172
5173 % int_plus4/3: the first argument must be ground when called
5174 :- block int_plus4(?,-,-).
5175 int_plus4(X,Y,Plus) :-
5176 ? ( var(Plus) -> Plus is X+Y
5177 ; Y is Plus-X).
5178
5179 :- assert_must_succeed(exhaustive_kernel_check(int_minus(int(2),int(3),int(-1)))).
5180 :- assert_must_succeed(exhaustive_kernel_fail_check(int_minus(int(2),int(3),int(1)))).
5181 :- assert_must_succeed(int_minus(int(3),int(1),int(2))).
5182 :- assert_must_succeed(( int_minus2(A,B,C),A=3,B=2,C==1 )).
5183 :- assert_must_succeed(( int_minus2(A,B,C),A=3,C=1,B==2 )).
5184 :- assert_must_succeed(( int_minus2(A,B,C),B=2,A=3,C==1 )).
5185 :- assert_must_succeed(( int_minus2(A,B,C),B=2,C=1,A==3 )).
5186 :- assert_must_succeed(( int_minus2(A,B,C),C=1,A=3,B==2 )).
5187 :- assert_must_succeed(( int_minus2(A,B,C),C=1,B=2,A==3 )).
5188 :- assert_must_succeed(( int_minus2(A,B,C),B=0,A==C )).
5189 :- assert_must_succeed(( int_minus2(A,B,C),B=0,C=5,A==5 )).
5190 :- assert_must_succeed(( int_minus2(A,B,5),B=0,A==5 )).
5191
5192 int_minus(int(X),int(Y),int(Minus)) :- %print(int_minus(X,Y,Minus)),nl,
5193 int_minus2(X,Y,Minus),
5194 ? (two_vars_or_more(X,Y,Minus) -> clpfd_eq(Minus,X-Y) % can have performance problems.
5195 % we could also set Minus to 0 if X==Y; this is done in CHR (chr_integer_inequality)
5196 ; true). % we can compute the value directly anyway
5197 :- block int_minus2(-,-,-).
5198 int_minus2(X,Y,Minus) :- %print(int_minus2(X,Y,Minus)),nl,
5199 ( ground(Y) ->
5200 ( Y=0 -> X=Minus
5201 ; Y2 is -Y, int_plus3(Y2,X,Minus))
5202 ; ground(X) ->
5203 int_minus3(X,Y,Minus)
5204 ; int_plus3(Minus,Y,X) % will infer that Y=X if Minus=0
5205 ).
5206
5207 % int_minus3/3: the first argument must be ground when called
5208 :- block int_minus3(?,-,-).
5209 int_minus3(X,Y,Minus) :-
5210 ? ( var(Minus) -> Minus is X-Y
5211 ; Y is X-Minus).
5212
5213 :- assert_must_succeed(exhaustive_kernel_check(division(int(2),int(3),int(0),unknown,_WF))).
5214 :- assert_must_succeed(exhaustive_kernel_check(division(int(7),int(2),int(3),unknown,_WF))).
5215 :- assert_must_succeed(exhaustive_kernel_check(division(int(8),int(2),int(4),unknown,_WF))).
5216 :- assert_must_succeed(exhaustive_kernel_check(division(int(9),int(2),int(4),unknown,_WF))).
5217 :- assert_must_succeed(exhaustive_kernel_check(division(int(2),int(-1),int(-2),unknown,_WF))).
5218 :- assert_must_succeed(exhaustive_kernel_check(division(int(9),int(-2),int(-4),unknown,_WF))).
5219 :- assert_must_succeed(exhaustive_kernel_check(division(int(-9),int(-3),int(3),unknown,_WF))).
5220 :- assert_must_succeed(exhaustive_kernel_check(division(int(-1),int(4),int(0),unknown,_WF))).
5221 :- assert_must_succeed((platform_is_64_bit
5222 -> exhaustive_kernel_check(division(int(4294967296),int(2),int(2147483648),unknown,_WF))
5223 ; exhaustive_kernel_check(division(int(134217728),int(2),int(67108864),unknown,_WF)))).
5224 :- assert_must_succeed((platform_is_64_bit
5225 -> exhaustive_kernel_check(division(int(4294967296),int(2147483648),int(2),unknown,_WF))
5226 ; exhaustive_kernel_check(division(int(134217728),int(67108864),int(2),unknown,_WF)))).
5227 :- assert_must_succeed(exhaustive_kernel_fail_check(division(int(2),int(3),int(1),unknown,_WF))).
5228 :- assert_must_succeed(( division3(A,B,C,unknown,_),A=15,B=4,C==3 )).
5229 :- assert_must_succeed(( division3(A,B,C,unknown,_),B=4,A=15,C==3 )).
5230
5231 ?division(int(X),int(Y),int(XDY),Span,WF) :- var(Y), (var(X) ; var(XDY)),
5232 preferences:preference(use_clpfd_solver,true),!,
5233 (preferences:preference(disprover_mode,true)
5234 -> clpfd_eq_div(XDY,X,Y) /* we can assume well-definedness */
5235 ; clpfd_eq_guarded_div(XDY,X,Y),
5236 % TO DO: we could set up a choice point just before enumeration of infinite types for Y=0 & Y/=0;
5237 % same for modulo
5238 check_nonzero(X,Y,XDY,Span,WF)
5239 ).
5240 division(int(X),int(Y),int(XDY),Span,WF) :-
5241 %% clpfd_eq_expr(XDY,X/Y), % can have performance problems; could hide division by 0 !
5242 division3(X,Y,XDY,Span,WF).
5243
5244 :- block check_nonzero(?,-,?,?,?).
5245 check_nonzero(X,Y,XDY,Span,WF) :-
5246 (Y=0 -> add_wd_error_set_result('division by zero','/'(X,Y),XDY,0,Span,WF)
5247 ; true).
5248
5249 :- block division3(?,-,?,?,?).
5250 division3(X,Y,XDY,Span,WF) :-
5251 ( Y==0 -> add_wd_error_set_result('division by zero','/'(X,Y),XDY,0,Span,WF)
5252 ; nonvar(X) -> XDY is X // Y
5253 ; Y == 1 -> X=XDY
5254 ; Y == -1,nonvar(XDY) -> X is -XDY
5255 ; clpfd_eq_div(XDY,X,Y)). % we could setup constraint before Y is known; could hide division by 0 ?
5256
5257
5258
5259 :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(2),int(3),int(0),unknown,_WF))).
5260 :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(7),int(2),int(3),unknown,_WF))).
5261 :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(-1),int(4),int(-1),unknown,_WF))).
5262 :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(-9),int(-3),int(3),unknown,_WF))).
5263 floored_division(int(X),int(Y),int(XDY),Span,WF) :- var(Y), (var(X) ; var(XDY)),
5264 preferences:preference(use_clpfd_solver,true),!,
5265 (preferences:preference(disprover_mode,true)
5266 -> clpfd_eq_fdiv(XDY,X,Y) /* we can assume well-definedness */
5267 ; clpfd_eq_guarded_fdiv(XDY,X,Y),
5268 check_nonzero(X,Y,XDY,Span,WF)
5269 ).
5270 floored_division(int(X),int(Y),int(XDY),Span,WF) :-
5271 %% clpfd_eq_expr(XDY,X/Y), % can have performance problems; could hide division by 0 !
5272 floored_division3(X,Y,XDY,Span,WF).
5273 :- block floored_division3(?,-,?,?,?).
5274 floored_division3(X,Y,XDY,Span,WF) :-
5275 ( Y==0 -> add_wd_error_set_result('division by zero','/'(X,Y),XDY,0,Span,WF)
5276 ; nonvar(X) -> XDY is X div Y
5277 ; Y == 1 -> X=XDY
5278 ; (Y == -1,nonvar(XDY)) -> X is -XDY
5279 ; clpfd_eq_guarded_fdiv(XDY,X,Y)). % we could setup constraint before Y is known; could hide division by 0 ?
5280
5281 :- assert_must_succeed(exhaustive_kernel_check(modulo(int(2),int(3),int(2),unknown,_WF))).
5282 :- assert_must_succeed(exhaustive_kernel_check(modulo(int(7),int(2),int(1),unknown,_WF))).
5283 :- assert_must_succeed(exhaustive_kernel_check(modulo(int(8),int(2),int(0),unknown,_WF))).
5284 :- assert_must_succeed(exhaustive_kernel_check(modulo(int(9),int(2),int(1),unknown,_WF))).
5285 :- assert_must_succeed((platform_is_64_bit
5286 -> exhaustive_kernel_check(modulo(int(4294967296),int(2147483648),int(0),unknown,_WF))
5287 ; exhaustive_kernel_check(modulo(int(134217728),int(67108864),int(0),unknown,_WF)))).
5288 :- assert_must_succeed((platform_is_64_bit
5289 -> exhaustive_kernel_check(modulo(int(4294967299),int(2147483648),int(3),unknown,_WF))
5290 ; exhaustive_kernel_check(modulo(int(134217731),int(67108864),int(3),unknown,_WF)))).
5291 :- assert_must_succeed(( modulo2(A,B,C,unknown,_),A=7,B=5,C==2 )).
5292 :- assert_must_fail(( modulo2(A,B,C,unknown,_),A=7,B=5,C==3 )).
5293
5294 modulo(int(X),int(Y),int(Modulo),Span,WF) :-
5295 %% clpfd_eq(Modulo,X mod Y), % can have performance problems; could hide division by 0 !
5296 %clpfd_modulo(X,Y,Modulo,WF), % maybe only call in non-CLPFD mode ?
5297 modulo2(X,Y,Modulo,Span,WF),
5298 % assert that Modulo<Y, Modulo>=0
5299 (nonvar(X),nonvar(Y) -> true % we already have computed Modulo using modulo2
5300 ; nonvar(Modulo), Modulo < 0 -> true % we will generate well-definedness error; see comment next line
5301 ; number(Y),Y =< 0 -> true % in this case we will generate a well-definedness error; it would be more efficient from a constraint solving perspective to assume that there are no well-definedness errors and remove this case !!
5302 ; clpfd_modulo_prop(X,Y,Modulo,WF)
5303 ).
5304 :- use_module(specfile,[z_or_tla_minor_mode/0]).
5305 :- block modulo2(-,?,?,?,?), modulo2(?,-,?,?,?).
5306 modulo2(X,Y,Modulo,Span,WF) :-
5307 ( Y>0 -> (X<0 -> (z_or_tla_minor_mode -> Modulo is X mod Y
5308 ; add_wd_error_set_result('mod not defined for negative numbers in B:',mod(X,Y),Modulo,0,Span,WF))
5309 ; Modulo is X mod Y)
5310 ; Y==0 -> add_wd_error_set_result('mod by zero:',mod(X,Y),Modulo,0,Span,WF)
5311 ; Y<0 -> add_wd_error_set_result('mod not defined for negative numbers:',mod(X,Y),Modulo,0,Span,WF)). % there seems to be a definition in Z ? at least for Z Live ?
5312
5313 % propagate information about Modulo result if part of the information known
5314 clpfd_modulo_prop(X,Y,Modulo,WF) :- %preferences:preference(use_clpfd_solver,true),!,
5315 % in CLP(FD) this is sufficient; for non-CLPFD mode it is better to call in_nat_range to restrict enumeration
5316 less_than_direct(Modulo,Y),
5317 less_than_equal_direct(0,Modulo), % 0 <= Modulo < Y -> by transitivity this forces Y>0 and we no longer detect wd-errors
5318 %less_than_equal_direct(Modulo,X). % by transitivity this imposes X >= 0 and we will never find WD problems with negative X
5319 clpfd_modulo_prop2(X,Y,Modulo,WF).
5320
5321
5322 clpfd_modulo_prop2(X,Y,Modulo,_WF) :-
5323 number(Modulo), % this test is required for test 1009, 417 : TO DO : investigate cause
5324 var(X), % or should this be var(X) ; var(Y) ??
5325 preferences:preference(use_clpfd_solver,true),
5326 clpfd:fd_min(Y,MinY), number(MinY), MinY>0,
5327 clpfd:fd_min(X,MinX), number(MinX), MinX>=0,
5328 !,
5329 %print(modulo_prop(X,MinX,Y,MinY,Modulo)),nl,
5330 clpfd_interface:clpfd_leq_expr(Modulo,X),
5331 clpfd_interface:try_post_constraint(Modulo #= X mod Y).
5332 clpfd_modulo_prop2(X,_Y,Modulo,_WF) :-
5333 clpfd_interface:try_post_constraint(X#>=0 #=> X#>=Modulo). % this would be faster (e.g., {y|y:100000..200000 & y mod 2 = 0}), but would not catch some WD errors: clpfd_interface:try_post_constraint(X#>=Modulo).
5334 % we could reify: Y>0 => Modulo <Y ? Is it worth it ?
5335 % we could also use the CLP(FD) modulo operator X in 3..100, 1 #= X mod 20 infers X in 21..81
5336 % try_post_constraint((X#>=0 #/\ Y#>0) #=> Modulo #= X mod Y)
5337 % what is still missing is that if Y < Modulo => X=Y (CLP(FD) does this X in 0..100 , Y in 2..20 , X #= Y mod 30.)
5338 /* clpfd_modulo_prop(X,Y,Modulo,WF) :- clpfd_modulo_noclp(X,Y,Modulo,WF).
5339 :- block clpfd_modulo_noclp(-,-,-,?).
5340 clpfd_modulo_noclp(X,Y,Modulo,WF) :- print(mod(X,Y,Modulo,WF)),nl,
5341 var(X),var(Modulo),number(Y),!,
5342 Y1 is Y-1,
5343 in_nat_range_wf(int(Modulo),int(0),int(Y1),WF). % problem: could enumerate lambda return variables !!
5344 clpfd_modulo_noclp(_X,_Y,_Modulo,_WF).
5345 */
5346
5347
5348 :- assert_must_succeed(exhaustive_kernel_check(unary_minus_wf(int(2),int(-2),_WF))).
5349 :- assert_must_succeed(exhaustive_kernel_fail_check(unary_minus_wf(int(2),int(2),_WF))).
5350 :- assert_must_succeed(( unary_minus2(A,B),A=7,B== -7 )).
5351 :- assert_must_succeed(( unary_minus2(A,B),A= -7,B==7 )).
5352 :- assert_must_succeed(( unary_minus2(B,A),A=7,B== -7 )).
5353 :- assert_must_succeed(( unary_minus2(B,A),A= -7,B==7 )).
5354 :- assert_must_fail(( unary_minus2(B,A),A= -7,B=6 )).
5355 :- assert_must_fail(( unary_minus2(A,B),A= -7,B=6 )).
5356
5357 unary_minus_wf(int(X),int(MX),_WF) :-
5358 unary_minus2(X,MX),
5359 (var(X),var(MX) -> clpfd_eq(MX,0 - X) % can have performance problems
5360 ; true % we can compute the value without CLPFD
5361 ).
5362 :- block unary_minus2(-,-).
5363 unary_minus2(X,MX) :-
5364 ( ground(X) -> MX is -X
5365 ; X is -MX).
5366
5367 :- assert_must_succeed(first_of_pair((int(1),int(2)),int(1))).
5368 :- assert_must_succeed(second_of_pair((int(1),int(2)),int(2))).
5369
5370 first_of_pair((A,_B),R) :- equal_object(R,A,first_of_pair).
5371 second_of_pair((_A,B),R) :- equal_object(R,B,second_of_pair).
5372
5373
5374 :- assert_must_succeed(exhaustive_kernel_check(cartesian_product([int(2),int(4)],[int(3),int(1)],
5375 [(int(2),int(1)),(int(2),int(3)),(int(4),int(3)),(int(4),int(1))]))).
5376 :- assert_must_succeed(exhaustive_kernel_check(cartesian_product([],[int(3),int(1)],[]))).
5377 :- assert_must_succeed(exhaustive_kernel_check(cartesian_product([int(3)],[],[]))).
5378 :- assert_must_succeed(exhaustive_kernel_fail_check(cartesian_product([int(3)],[int(2)],[]))).
5379 :- assert_must_succeed((cartesian_product(global_set('NAT'),[int(2)],_Res))).
5380 :- assert_must_succeed((cartesian_product([int(1)],[int(2)],Res),
5381 equal_object(Res,[(int(1),int(2))]))).
5382 :- assert_must_succeed((cartesian_product([int(1)],[int(2)],[(int(1),int(2))]))).
5383 :- assert_must_succeed((cartesian_product([],[int(1),int(2)],Res),
5384 equal_object(Res,[]))).
5385 :- assert_must_succeed((cartesian_product([int(1),int(2)],[],Res),
5386 equal_object(Res,[]))).
5387 :- assert_must_succeed((cartesian_product([int(1),int(2)],[int(2),int(3)],Res),
5388 equal_object(Res,[(int(1),int(2)),(int(1),int(3)),(int(2),int(2)),(int(2),int(3))]))).
5389 :- assert_must_succeed((cartesian_product([int(1)|T],[int(2)|T2],Res),
5390 T = [int(2)], T2 = [int(3)],
5391 equal_object(Res,[(int(1),int(2)),(int(1),int(3)),(int(2),int(2)),(int(2),int(3))]))).
5392 :- assert_must_fail((cartesian_product([int(1)],[int(2),int(3)],Res),(Res=[_];
5393 equal_object(Res,[_,_,_|_])))).
5394
5395
5396 :- block cartesian_product(-,?,?), cartesian_product(?,-,?).
5397 cartesian_product(Set1,Set2,Res) :-
5398 expand_custom_set_to_list(Set1,ESet1,_,cartesian_product1),
5399 (ESet1==[] -> empty_set(Res)
5400 ; expand_custom_set_to_list(Set2,ESet2,_,cartesian_product2),
5401 (var(Res) -> cartesian_product2(ESet1,ESet2,CRes), kernel_objects:equal_object_optimized(CRes,Res,cart_product)
5402 ; cartesian_product2(ESet1,ESet2,Res))
5403 ).
5404
5405 :- block cartesian_product2(-,?,?).
5406 cartesian_product2([],_,Res) :- empty_set(Res).
5407 cartesian_product2([H|T],Set2,Res) :-
5408 cartesian_el_product(Set2,H,Res,InnerRes),
5409 cartesian_product2(T,Set2,InnerRes).
5410
5411 :- block cartesian_el_product(-,?,?,?).
5412 cartesian_el_product([],_El,Res,InnerRes) :- equal_object_optimized(Res,InnerRes,cartesian_el_product_1).
5413 cartesian_el_product([H|T],El,ResSoFar,InnerRes) :-
5414 equal_object(ResSoFar,[(El,H)|NewResSoFar],cartesian_el_product_2),
5415 cartesian_el_product(T,El,NewResSoFar,InnerRes).
5416
5417
5418
5419 :- assert_must_succeed(exhaustive_kernel_check(in_nat_range(int(2),int(2),int(3)))).
5420 :- assert_must_succeed(exhaustive_kernel_check(in_nat_range_wf(int(2),int(2),int(3),_WF))).
5421 :- assert_must_succeed(exhaustive_kernel_fail_check(in_nat_range_wf(int(2),int(3),int(2),_WF))).
5422 :- assert_must_succeed((in_nat_range_wf(X,int(11),int(12),WF),
5423 kernel_waitflags:ground_wait_flags(WF), X==int(12) )).
5424 :- assert_must_fail((in_nat_range_wf(X,int(11),int(12),_WF), X=int(10) )).
5425 :- assert_must_fail((in_nat_range_wf(X,int(11),int(12),_WF), X=int(13) )).
5426 :- assert_must_succeed((in_nat_range_wf(X,int(11),int(12),_WF), X=int(11) )).
5427 :- assert_must_fail((in_nat_range_wf(X,int(11),int(10),_WF), X=int(11) )).
5428 :- assert_must_fail((in_nat_range_wf(X,int(11),int(10),_WF), X=int(10) )).
5429 :- assert_must_fail((in_nat_range_wf(X,int(11),int(10),_WF), X=int(12) )).
5430
5431 in_nat_range(int(X),int(Y),int(Z)) :- % does not enumerate, in contrast to in_nat_range_wf
5432 clpfd_inrange(X,Y,Z,Posted), % better to call inrange rather than leq twice, avoids unecessary propagation
5433 (Posted==true -> true
5434 ; safe_less_than_equal(in_nat_range,Y,X),
5435 safe_less_than_equal(in_nat_range,X,Z)
5436 ).
5437 in_nat_range_wf(int(X),int(Y),int(Z),WF) :- %print(in_nat_range_wf(X,Y,Z)),nl,
5438 clpfd_inrange(X,Y,Z,Posted), % better to call inrange rather than leq twice, avoids unecessary propagation
5439 (Posted==true ->
5440 /* if the constraint was posted: we do not need to add safe_less_than_equal,...: if overflow happes whole computation will fail anyway */
5441 add_nat_range_fd_variable_for_labeling(X,Y,Z,WF) % do we really need to do this ? maybe add just before enumeration finished ?
5442 %,print(delay_adding(X,Y,Z)),nl %, portray_waitflags(WF),nl,nl
5443 ; safe_less_than_equal(in_nat_range_wf,Y,X),
5444 safe_less_than_equal(in_nat_range_wf,X,Z),
5445 (ground(X) -> true
5446 ; get_int_domain(X,Y,Z,RL,RU),get_nat_range_prio(X,RL,RU,WF,LWF),
5447 % print(register_enumerate_int(X,RL,RU,WF,LWF)),nl, %% portray_waitflags(WF),nl, %%
5448 call_enumerate_int(X,RL,RU,LWF))
5449 ).
5450 % when((ground(X);nonvar(LWF)),(ground(X) -> true ; enumerate_int(X,RL,RU))).
5451
5452 add_nat_range_fd_variable_for_labeling(X,_Low,_Up,_WF) :- nonvar(X),!.
5453 % TO DO: avoid adding useless choice points; not adding makes test 328 fail
5454 %add_nat_range_fd_variable_for_labeling(X,Low,Up,WF) :- !,Size is 100*(Up+1-Low),
5455 % get_wait_flag(Size,add_nat_range_fd(X,Low,Up),WF,LWF), when(nonvar(LWF),add_fd_variable_for_labeling(X,WF)).
5456 add_nat_range_fd_variable_for_labeling(X,_Low,_Up,WF) :- !,add_fd_variable_for_labeling(X,WF).
5457
5458
5459 :- block get_nat_range_prio(?,-,?,?,?), get_nat_range_prio(?,?,-,?,?).
5460 get_nat_range_prio(_Variable,Y,Z,WF,LWF) :- Size is Z+1-Y, %print(get_natrange_prio(Size,Y,Z,WF)),nl,
5461 (Size>1 ->
5462 % we do not use add_fd_variable_for_labeling(Variable,Size,WF,LWF) % will use CLP(FD) labeling
5463 % either clpfd is off or we had a time-out or overflow; so labeling may generate instantiation error
5464 get_wait_flag(Size,get_nat_range_prio(Y,Z),WF,LWF)
5465 ; LWF=Size /* Size=0 or 1 -> we can either fail or determine variable */).
5466
5467 :- assert_must_succeed((kernel_objects:call_enumerate_int(X,1,2,g), X==2)).
5468 :- block call_enumerate_int(-,?,?,-).
5469 call_enumerate_int(X,RL,RU,_LWF) :- % print(enum(X,RL,RU,_LWF)),nl,%
5470 ? (ground(X) -> true
5471 ; % print(enum_int(X,RL,RU)),nl, %%
5472 % get_int_domain(X,RL,RU,RLL,RUU) : if clp(fd) active then CLP(FD) labeling is used anyway
5473 ? enumerate_int(X,RL,RU)).
5474
5475
5476
5477
5478 :- assert_must_succeed(exhaustive_kernel_check(not_in_nat_range(int(2),int(3),int(2)))).
5479 :- assert_must_succeed(exhaustive_kernel_fail_check(not_in_nat_range(int(2),int(2),int(3)))).
5480 :- assert_must_succeed((not_in_nat_range(X,int(11),int(12)), X=int(10) )).
5481 :- assert_must_succeed((not_in_nat_range(X,int(11),int(12)), X=int(13) )).
5482 :- assert_must_fail((not_in_nat_range(X,int(11),int(12)), X=int(11) )).
5483 :- assert_must_succeed((not_in_nat_range(X,int(11),int(10)), X=int(11) )).
5484 :- assert_must_succeed((not_in_nat_range(X,int(11),int(10)), X=int(10) )).
5485 :- assert_must_succeed((not_in_nat_range(X,int(11),int(10)), X=int(12) )).
5486
5487 ?not_in_nat_range_wf(X,Y,Z,_WF) :- not_in_nat_range(X,Y,Z).
5488 not_in_nat_range(int(X),int(Y),int(Z)) :-
5489 ? (number(Y),number(Z)
5490 ? -> (Z>=Y -> clpfd_not_in_non_empty_range(X,Y,Z) ; true /* interval empty */)
5491 ; clpfd_not_inrange(X,Y,Z)
5492 ).
5493
5494
5495 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(1),int(0),int(10),pred_true,WF),WF)).
5496 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(10),int(10),int(10),pred_true,WF),WF)).
5497 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(1),int(1),int(10),pred_true,WF),WF)).
5498 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(10),int(0),int(10),pred_true,WF),WF)).
5499 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(11),int(10),int(9),pred_false,WF),WF)).
5500 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(11),int(13),int(12),pred_false,WF),WF)).
5501 :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(11),int(13),int(15),pred_false,WF),WF)).
5502
5503 % reified version
5504 :- block test_in_nat_range_wf(-,-,?,-,?), test_in_nat_range_wf(-,?,-,-,?), test_in_nat_range_wf(?,-,-,-,?).
5505 test_in_nat_range_wf(X,Y,Z,PredRes,WF) :- PredRes==pred_true,!,
5506 in_nat_range_wf(X,Y,Z,WF).
5507 test_in_nat_range_wf(X,Y,Z,PredRes,WF) :- PredRes==pred_false,!,
5508 not_in_nat_range_wf(X,Y,Z,WF).
5509 test_in_nat_range_wf(int(X),int(Low),int(Up),PredRes,WF) :-
5510 %print(post(X,Low,Up)),nl,
5511 clpfd_interface:post_constraint2(C1 #<=> (X #>= Low #/\ X #=< Up #/\ Low #=< Up),Posted1),
5512 %print(p(Posted1,C1)),nl,
5513 (Posted1 == true -> prop_01(C1,PredRes) ; test_in_nat_range_no_clpfd(X,Low,Up,PredRes,WF)).
5514
5515 % Note: A #<=> (X #>= Low #/\ X#=< Up #/\ Low #=< Up), Low in 11..15, Up in 7..8. -> CLPFD infers A=0
5516 % without the redundant Low #=< Up it does not infer it !
5517 :- block prop_01(-,-).
5518 prop_01(0,pred_false).
5519 prop_01(1,pred_true).
5520
5521 :- block test_in_nat_range_no_clpfd(-,?,?,-,?), test_in_nat_range_no_clpfd(?,-,?,-,?),
5522 test_in_nat_range_no_clpfd(?,?,-,-,?).
5523 test_in_nat_range_no_clpfd(X,Y,Z,PredRes,WF) :- PredRes==pred_true,!,
5524 in_nat_range_wf(int(X),int(Y),int(Z),WF).
5525 test_in_nat_range_no_clpfd(X,Y,Z,PredRes,WF) :- PredRes==pred_false,!,
5526 not_in_nat_range_wf(int(X),int(Y),int(Z),WF).
5527 test_in_nat_range_no_clpfd(X,Y,Z,PredRes,_WF) :- % X,Y,Z must be ground integers
5528 (X >= Y, X =< Z, Y =< Z -> PredRes=pred_true ; PredRes=pred_false).
5529
5530 :- assert_must_succeed(exhaustive_kernel_check_wf(square(int(3),int(9),WF),WF)).
5531 % is now only called when CLPFD is FALSE
5532 square(int(X),int(Sqr),WF) :- % print(sqr(X,Sqr)),nl,
5533 int_square(X,Sqr,WF),
5534 (var(X) -> clpfd_eq(Sqr,X * X)
5535 ; true). % we can compute the value directly
5536
5537 :- block int_square(-,-,?).
5538 int_square(X,Sqr,_) :- ground(X),!, Sqr is X*X.
5539 int_square(X,Sqr,WF) :- get_binary_choice_wait_flag(int_square,WF,WF2), int_square2(X,Sqr,WF2).
5540 :- block int_square2(-,?,-).
5541 int_square2(X,Sqr,_) :- ground(X),!, Sqr is X*X.
5542 int_square2(X,Sqr,_WF2) :-
5543 integer_square_root(Sqr,X).
5544
5545 :- assert_must_succeed(( kernel_objects:integer_square_root(0,X),X==0 )).
5546 :- assert_must_succeed(( kernel_objects:integer_square_root(1,X),X==1 )).
5547 :- assert_must_succeed(( kernel_objects:integer_square_root(4,X),X==2 )).
5548 :- assert_must_succeed(( kernel_objects:integer_square_root(49,X),X==7 )).
5549 :- assert_must_succeed(( kernel_objects:integer_square_root(49,X),X==(-7) )).
5550 :- assert_must_fail(( kernel_objects:integer_square_root(5,_) )).
5551 :- assert_must_succeed(( X= 123456789, Y is X*X, kernel_objects:integer_square_root(Y,Z),Z==X)).
5552 :- assert_must_fail(( X= 123456789, Y is 1+X*X, kernel_objects:integer_square_root(Y,_Z))).
5553 :- assert_must_succeed(( X= 12345678900, Y is X*X, kernel_objects:integer_square_root(Y,Z),Z==X)).
5554
5555 integer_square_root(0,Root) :- !, Root = 0.
5556 integer_square_root(Sqr,PMRoot) :- %print(sqrt(Sqr)),nl,
5557 Sqr>0, Root is truncate(sqrt(Sqr)), Sqr is Root*Root, %print(root(Root)),nl,
5558 (PMRoot = Root ; PMRoot is -(Root)).
5559
5560 times(int(X),int(Y),int(Times)) :-
5561 int_times2(X,Y,Times),
5562 ? (two_vars_or_more(X,Y,Times) -> clpfd_eq(Times,X * Y) % can have performance problems.
5563 ; true). % we can compute the value directly
5564
5565 :- assert_must_succeed(exhaustive_kernel_check([commutative],times(int(2),int(3),int(6)))).
5566 :- assert_must_succeed(exhaustive_kernel_check([commutative],times(int(2),int(1),int(2)))).
5567 :- assert_must_succeed(exhaustive_kernel_check([commutative],times(int(2),int(0),int(0)))).
5568 :- assert_must_succeed(exhaustive_kernel_check(times(int(0),int(1),int(0)))).
5569 :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],times(int(2),int(3),int(5)))).
5570 :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],times(int(1),int(3),int(2)))).
5571 :- assert_must_succeed(( int_times2(A,B,C),A=3,B=2,C==6 )).
5572 :- assert_must_succeed(( int_times2(A,B,C),A=3,C=6,B==2 )).
5573 :- assert_must_succeed(( int_times2(A,B,C),B=2,A=3,C==6 )).
5574 :- assert_must_succeed(( int_times2(A,B,C),B=2,C=6,A==3 )).
5575 :- assert_must_succeed(( int_times2(A,B,C),C=6,A=3,B==2 )).
5576 :- assert_must_succeed(( int_times2(A,B,C),C=6,B=2,A==3 )).
5577 :- assert_must_succeed(( int_times2(A,_,C),A=0,C==0 )).
5578 :- assert_must_succeed(( int_times2(_,B,C),B=0,C==0 )).
5579 :- assert_must_succeed(( int_times2(A,B,C),A=1,B==C )).
5580 :- assert_must_succeed(( int_times2(A,B,C),B=1,A==C )).
5581 :- assert_must_succeed(( int_times2(A,1,C),A=2,C==2 )).
5582 :- assert_must_succeed(( int_times2(_A,0,C),C==0 )).
5583 :- assert_must_succeed(( int_times2(A,_,C),C=0,A=0 )).
5584 :- assert_must_succeed(( int_times2(_,B,C),C=0,B=0 )).
5585 :- assert_must_succeed(( int_times2(A,B,0),A=0,B=2 )).
5586 :- assert_must_succeed(( int_times2(A,B,0),B=2,A=0 )).
5587 :- assert_must_succeed(( int_times2(B,A,0),A=0,B=2 )).
5588 :- assert_must_succeed(( int_times2(B,A,0),B=2,A=0 )).
5589 :- assert_must_fail(( int_times2(A,_,C),A=3,C=7 )).
5590 :- assert_must_fail(( int_times2(A,_,C),C=7,A=3 )).
5591 :- assert_must_fail(( int_times2(_,B,C),B=2,C=7 )).
5592 :- assert_must_fail(( int_times2(_,B,C),C=7,B=2 )).
5593 :- assert_must_fail(( int_times2(A,_,C),C=7,A=0 )).
5594 :- assert_must_fail(( int_times2(_,B,C),C=7,B=0 )).
5595 :- assert_must_fail(( int_times2(B,A,0),B=2,A=1 )).
5596
5597 :- block int_times2(-,-,-).
5598 int_times2(X,Y,Times) :-
5599 ( ground(X) ->
5600 ( X==1 -> Y=Times
5601 ; X==0 -> Times=0
5602 ; int_times3(X,Y,Times))
5603 ; ground(Y) ->
5604 ( Y==1 -> X=Times
5605 ; Y==0 -> Times=0
5606 ; int_times3(Y,X,Times))
5607 ; int_times4(X,Y,Times)).
5608 % int_times3/3: First argument must be ground when called and non-zero
5609 :- block int_times3(?,-,-).
5610 int_times3(X,Y,Times) :-
5611 ? ( ground(Y) -> Times is X*Y
5612 ; Y is Times // X, Times is X*Y).
5613 % int_times4/3: Third argument must be ground when called
5614 :- block int_times4(-,-,?).
5615 int_times4(X,Y,Times) :- %print(int_times4(X,Y,Times)),nl,
5616 ( Times==0 ->
5617 ( ground(X) -> (X==0 -> true; Y=0 )
5618 ; /* ground(Y) -> */ (Y==0 -> true; X=0 ))
5619 ; /* Times /== 0 */
5620 ( ground(X) -> X\==0, Y is Times // X, Times is X*Y
5621 ; /* ground(Y) -> */ Y\==0, X is Times // Y, Times is X*Y)).
5622
5623
5624 :- assert_must_succeed(exhaustive_kernel_check(int_power(int(2),int(3),int(8),unknown,_))).
5625 :- assert_must_succeed(exhaustive_kernel_check(int_power(int(2),int(1),int(2),unknown,_))).
5626 :- assert_must_succeed(exhaustive_kernel_check(int_power(int(3),int(0),int(1),unknown,_))).
5627 :- assert_must_succeed(exhaustive_kernel_check(int_power(int(1),int(3),int(1),unknown,_))).
5628 :- assert_must_succeed(exhaustive_kernel_check(int_power(int(0),int(3),int(0),unknown,_))).
5629 :- assert_must_succeed(exhaustive_kernel_fail_check(int_power(int(2),int(3),int(6),unknown,_))).
5630 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=2,B=5,C==32 )).
5631 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A= -2,B=5,C== -32 )).
5632 %:- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=1,B= -5,C==1 )). % now aborts !
5633 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=1,C=1, B= -5 )).
5634 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=1,C= 1,B = -5 )).
5635 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=2,C=32,B==5 )).
5636 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=10,C=1000,B==3 )).
5637 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A= -2,C= -32,B==5 )).
5638 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A= -2,C= 16,B==4 )).
5639 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=2,C=1,B==0 )).
5640 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,B=2,C==0 )).
5641 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,C=0,B=2 )).
5642 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,B=0,C==1 )).
5643 :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,C=1,B==0 )).
5644 :- assert_must_succeed(( int_power2(17,13,C,unknown,_),C==9904578032905937 )).
5645 :- assert_must_succeed((platform_is_64_bit
5646 -> int_power2(A,13,C,unknown,_),C=9904578032905937,A=17
5647 ; int_power2(A,9,C,unknown,_),C=134217728,A=8 )).
5648 :- assert_must_fail((platform_is_64_bit
5649 -> int_power2(A,13,C,unknown,_),C=9904578032905936,A=17
5650 ; int_power2(A,9,C,unknown,_),C=134217727,A=8 )).
5651 :- assert_must_succeed((platform_is_64_bit
5652 -> int_power2(A,10,C,unknown,_),C=576650390625,A=15
5653 ; true)).
5654 :- assert_must_fail((platform_is_64_bit
5655 -> int_power2(A,10,C,unknown,_),C=576650390626,A=15
5656 ; false)).
5657 :- assert_must_succeed(( int_power2(A,100,C,unknown,_),A=2,C==1267650600228229401496703205376 )).
5658 :- assert_must_fail(( int_power2(A,100,C,unknown,_),C=1267650600228229401496703205375,A=2 )).
5659 :- assert_must_fail(( int_power2(A,100,C,unknown,_),C=1267650600228229401496703205377,A=2 )).
5660
5661 :- assert_must_fail(( int_power2(A,B,C,unknown,_),A=2,B=5,C=33 )).
5662 :- assert_must_abort_wf(( int_power2(A,B,_,unknown,WF),A=2,B= -5 ),WF).
5663 :- assert_must_fail(( int_power2(A,_,C,unknown,_),A= -2,C=32 )).
5664 :- assert_must_fail(( int_power2(A,_,C,unknown,_),A= -2,C= -16 )).
5665
5666 % TODO: calculate X from Y und Pow (i.e., Yth root of Pow); in CLPFD mode this is more or less done
5667 int_power(int(X),int(Y),int(Pow),Span,WF) :-
5668 ( preferences:preference(use_clpfd_solver,true)
5669 -> int_power2(X,Y,Pow,Span,WF), int_power_clpfd_propagation(X,Y,Pow)
5670 ; int_power1(X,Y,Pow,Span,WF)).
5671 % TO DO ?: if all are variables we can still infer some knowledge
5672 % e.g. if X is positive then Pow must be positive; but it is probably quite rare that we have models with unknown exponent ?
5673 :- block int_power1(-,?,?,?,?). % ensure that Base X is known
5674 int_power1(X,Y,Pow,Span,WF) :-
5675 int_power2(X,Y,Pow,Span,WF).
5676 :- block int_power2(-,-,?,?,?), int_power2(?,-,-,?,?).
5677 int_power2(X,Y,Pow,Span,WF) :- %print(int_power2(X,Y,Pow,WF)),nl,
5678 ( ground(Y) ->
5679 ( Y>=0 -> safe_int_power0(X,Y,Pow)
5680 ; otherwise -> add_wd_error_set_result('power with negative exponent','**'(X,Y),Pow,1,Span,WF))
5681 ; otherwise -> /* X & POW are ground */
5682 ( X==1 -> Pow==1 /* 1**Y = 1 */
5683 ; X==0, Pow==1 -> Y=0
5684 ; X==0 -> Pow==0
5685 ; X>0, Pow>0 ->
5686 checked_log(X,Y,Pow)
5687 ; X<0, Pow<0 ->
5688 PosPow is -(Pow),
5689 NegX is -(X),
5690 checked_log(NegX,Y,PosPow),
5691 odd(Y)
5692 ; X<0, Pow>0 ->
5693 NegX is -(X),
5694 checked_log(NegX,Y,Pow),
5695 even(Y))).
5696
5697 % TO DO for checked_log: we should take pre-cautions with try_find_abort
5698 % 2**x + y = 1024 & y:0..100 -> will give x=10, y=0 but not give rise to possible WD error
5699 checked_log(1,Exp,Pow) :- !, % the SICStus Prolog log function does not work for Base=1
5700 Pow=1, less_than_equal_direct(0,Exp).
5701 checked_log(Base,Exp,Pow) :-
5702 Try is integer(log(Base,Pow)),
5703 % the calculation might have a rounding error
5704 ( safe_int_power(Base,Try,Pow) -> Exp=Try
5705 ; otherwise -> Exp is Try+1, safe_int_power(Base,Exp,Pow)).
5706
5707 :- block even(-).
5708 even(X) :- 0 is X mod 2.
5709 :- block odd(-).
5710 odd(X) :- 1 is X mod 2.
5711
5712 % propagation rules if only one of the args known
5713 :- block int_power_clpfd_propagation(-,-,-).
5714 int_power_clpfd_propagation(Base,Exp,Pow) :- Exp==0, var(Base),var(Pow),!, % B**0 = 1
5715 Pow = 1.
5716 int_power_clpfd_propagation(Base,Exp,Pow) :- Exp==1, var(Base),var(Pow),!, % B**1 = B
5717 Pow = Base.
5718 int_power_clpfd_propagation(Base,Exp,Pow) :- Base==1, var(Exp),var(Pow),!, % 1**E = 1
5719 Pow = Base.
5720 %int_power_clpfd_propagation(Base,Exp,Pow) :- number(Base), Base>0,var(Exp),var(Pow),!,
5721 % clpfd_leq(1,Pow,_). % causes problem with test 305
5722 int_power_clpfd_propagation(X,Y,Pow) :-% print_term_summary(int_power1(X,Y,Pow)),
5723 clpfd:fd_min(X,MinX), number(MinX), MinX>0,
5724 clpfd:fd_min(Y,MinY), number(MinY), MinY>0, % ensures no WD problem possible
5725 MinPow is MinX^MinY,
5726 \+ integer_too_large_for_clpfd(MinPow),
5727 %print(min(MinX,MinY,MinPow)),nl,
5728 clpfd:fd_max(X,MaxX), number(MaxX),
5729 clpfd:fd_max(Y,MaxY), number(MaxY),
5730 MaxPow is MaxX^MaxY,
5731 \+ integer_too_large_for_clpfd(MaxPow),
5732 % only do propagation if we are sure not to produce a CLPFD overflow
5733 !,
5734 %print(max(MaxX,MaxY,MaxPow)),nl,
5735 clpfd_inrange(Pow,MinPow,MaxPow),
5736 (number(X), clpfd:fd_max(Pow,MaxPow2), number(MaxPow2), get_new_upper_bound(X,MaxPow2,NewMaxExp,NewMaxPow)
5737 -> %print(new_max_power(X,MaxPow2,NewMaxPow)),nl,
5738 clpfd_leq(Pow,NewMaxPow,_),
5739 clpfd_leq(Y,NewMaxExp,_)
5740 ; true),
5741 (number(X), clpfd:fd_min(Pow,MinPow2), number(MinPow2), get_new_lower_bound(X,MinPow2,NewMinExp,NewMinPow)
5742 -> %print(new_min_power(X,MinPow2,NewMinPow)),nl,
5743 clpfd_leq(NewMinPow,Pow,_),
5744 clpfd_leq(NewMinExp,Y,_)
5745 ; true),
5746 true. %print_term_summary(int_power1_after_propagation(X,Y,Pow)),nl.
5747 %result of this propagation: x = 3**y & y:3..5 & x /= 27 & x /= 243 -> deterministically forces x=81, y=4
5748 int_power_clpfd_propagation(_,_,_).
5749 % TO DO: maybe implement custom CLPFD propagators; above does not trigger for x>0 & y:0..500 & 2**x + y = 1500 or x>0 & x<20 & y:0..500 & 2**x + y = 1500
5750
5751 :- assert_must_succeed((kernel_objects:get_new_lower_bound(2,3,E,P),E==2,P==4)).
5752 :- assert_must_succeed((kernel_objects:get_new_lower_bound(2,11,E,P),E==4,P==16)).
5753 :- assert_must_fail((kernel_objects:get_new_lower_bound(2,16,_,_))).
5754 % given Base and Power, determine if Power is a proper power of Exp, if not determine the next possible power of Base
5755 get_new_lower_bound(Base,Power,MinExp,MinPower) :- Base > 1, Power> 0,
5756 Exp is integer(log(Base,Power)),
5757 BE is Base^Exp,
5758 BE < Power,
5759 MinPower is Base*BE,
5760 MinPower>Power,
5761 MinPower < 1125899906842624, % 2^50 \+ integer_too_large_for_clpfd(MinPower),
5762 MinExp is Exp+1.
5763 :- assert_must_succeed((kernel_objects:get_new_upper_bound(2,3,E,P),E==1,P==2)).
5764 :- assert_must_succeed((kernel_objects:get_new_upper_bound(2,11,E,P),E==3,P==8)).
5765 :- assert_must_fail((kernel_objects:get_new_upper_bound(2,16,_,_))).
5766 get_new_upper_bound(Base,Power,MaxExp,MaxPower) :- Base > 1, Power> 0,
5767 MaxExp is integer(log(Base,Power)),
5768 MaxPower is Base^MaxExp,
5769 MaxPower < Power,
5770 \+ integer_too_large_for_clpfd(MaxPower),
5771 MaxPower*Base > Power.
5772
5773 % safe exponentiation using the squaring algorithm (CLPFD does not support exponentiation yet)
5774 % Note: in TLA mode 0^0 is undefined according to TLC; for B/Rodin it is 1
5775 safe_int_power0(Base,Exp,Result) :- var(Base),
5776 Exp>30,!, % Exp>59 % 2**59 no overflow; but everything above that is guaranteed to generate an overflow unless Base is 0 or 1 or -1
5777 % 3**38 generates overflow; 4**30 generates overflow on 64-bit systems
5778 % To do: examine whether we should already delay with a smaller or larger exponent
5779 when(nonvar(Base),safe_int_power(Base,Exp,Result)). % wait until Base is known to avoid CLPFD overflow
5780 safe_int_power0(Base,Exp,Result) :- safe_int_power(Base,Exp,Result).
5781
5782 safe_int_power(_Base,0,Result) :- !, Result = 1.
5783 safe_int_power(Base,Exp,Result) :- ground(Base),!,
5784 Result is Base^Exp. % new integer exponentiation operator in SICStus 4.3
5785 safe_int_power(Base,Exp,Result) :-
5786 Msb is msb(Exp), % most significant bit
5787 ExpMask is 1<<Msb,
5788 safe_int_power_clpfd2(ExpMask,Exp,Base,1,Result).
5789
5790 :- use_module(clpfd_interface,[clpfd_eq_expr/2]).
5791 safe_int_power_clpfd2(0,_,_,Prev,Result) :- !, Prev=Result.
5792 safe_int_power_clpfd2(Mask,Exp,Base,Prev,Result) :-
5793 P is Exp /\ Mask, % P is Exp's highest bit
5794 Mask2 is Mask>>1,
5795 clpfd_eq_expr(Quad,Prev*Prev),
5796 ( P==0 -> Next = Quad
5797 ; otherwise -> clpfd_eq_expr(Next,Quad*Base) ),
5798 safe_int_power_clpfd2(Mask2,Exp,Base,Next,Result).
5799 %% -------------------------------------------------------
5800
5801 :- assert_must_succeed(( singleton_set_element([int(1)],E,unknown,_WF), E==int(1) )).
5802 :- assert_must_fail(singleton_set_element([int(1)],int(2),unknown,_WF) ).
5803 :- assert_must_abort_wf(kernel_objects:singleton_set_element([int(1),int(2)],_E,unknown,WF),WF).
5804 % This predicate computes the effect of the MU operator.
5805 % Set should be a singleton set and Elem its only element.
5806 % In case Set is empty or has more than one element, an error
5807 % message is generated.
5808 % The waitflag store WFStore is needed to obtain a waitflag for the
5809 % decision when to force whether Set is a singleton or not and
5810 % to save the error if necessary.
5811 singleton_set_element(Set,Elem,Span,WFStore) :-
5812 cardinality_as_int_wf(Set,Card,WFStore),
5813 get_enumeration_finished_wait_flag(WFStore,LWF),
5814 equality_objects_lwf(Card,int(1),IsSingleton,LWF),
5815 singleton_set_element2(IsSingleton,Set,Elem,Card,Span,WFStore).
5816 :- block singleton_set_element2(-,?,?,?,?,?).
5817 singleton_set_element2(pred_true,Set,Elem,_Card,_Span,_WFStore) :-
5818 exact_element_of(Elem,Set).
5819 singleton_set_element2(pred_false,_Set,_Elem,Card,Span,WFStore) :-
5820 ( Card=int(C) -> true ; C = 'unknown'),
5821 add_wd_error_span('argument of MU expression must have cardinality 1, but has ', C, Span,WFStore).
5822
5823
5824 %:- print(finished_loading_kernel_objects),nl.