| 1 | | % (c) 2009-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
| 2 | | % Heinrich Heine Universitaet Duesseldorf |
| 3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
| 4 | | |
| 5 | | :- module(kernel_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_type_wf/4, |
| 11 | | enumerate_type/4, % last argument false/true disables/enables enum warning |
| 12 | | enumerate_basic_type/3, |
| 13 | | enumerate_tight_type/2, enumerate_tight_type/3, enumerate_tight_type_wf/4, |
| 14 | | enumerate_int/3, |
| 15 | | gen_enum_warning_wf/6, |
| 16 | | all_strings_wf/2, is_string/2, is_not_string/1, |
| 17 | | |
| 18 | | top_level_dif/2, |
| 19 | | equal_object_optimized/2, equal_object_optimized/3, equal_object_optimized_wf/4, |
| 20 | | equal_object/2, equal_object/3, equal_object_wf/3, equal_object_wf/4, |
| 21 | | not_equal_object/2, not_equal_object_wf/3, |
| 22 | | equal_cons/3, equal_cons_wf/4, equal_cons_lwf/5, |
| 23 | | get_next_element/3, |
| 24 | | is_marked_to_be_computed/1, mark_as_to_be_computed/1, |
| 25 | | |
| 26 | | %equality_objects/3, |
| 27 | | membership_test_wf/4, |
| 28 | | |
| 29 | | %is_a_set/1, |
| 30 | | empty_set/1, empty_set_wf/2, |
| 31 | | not_empty_set/1, not_empty_set_wf/2, |
| 32 | | exact_element_of/2, |
| 33 | | check_element_of/2, check_element_of_wf/3, |
| 34 | | not_element_of/2, not_element_of_wf/3, |
| 35 | | |
| 36 | | add_element/3, add_element/4, add_element_wf/4, add_element_wf/5, |
| 37 | | add_new_element_wf/4, |
| 38 | | delete_element_wf/4, |
| 39 | | %remove_element/3, |
| 40 | | remove_element_wf/4,remove_element_wf/5,remove_element_wf_if_not_infinite_or_closure/6, |
| 41 | | remove_exact_first_element/3, |
| 42 | | check_no_duplicates_in_list/3, |
| 43 | | |
| 44 | | partition_wf/3, not_partition_wf/3, test_partition_wf/4, |
| 45 | | %all_different/2, |
| 46 | | disjoint_sets/3, not_disjoint_sets/3, test_disjoint_wf/4, |
| 47 | | |
| 48 | | union/3, union_wf/4, union_generalized/2, union_generalized_wf/3, |
| 49 | | intersection/3, intersection_generalized_wf/4, |
| 50 | | difference_set/3, difference_set_wf/4, |
| 51 | | in_difference_set_wf/4, not_in_difference_set_wf/4, |
| 52 | | in_union_set_wf/4, not_in_union_set_wf/4, |
| 53 | | in_intersection_set_wf/4, not_in_intersection_set_wf/4, |
| 54 | | |
| 55 | | strict_subset_of/2, strict_subset_of_wf/3, |
| 56 | | check_subset_of/2, check_subset_of_wf/3, check_finite_subset_of_wf/3, |
| 57 | | check_non_empty_subset_of_wf/3, check_finite_non_empty_subset_of_wf/3, |
| 58 | | not_subset_of/2, not_subset_of_wf/3, not_both_subset_of/5, |
| 59 | | not_finite_subset_of_wf/3, |
| 60 | | not_strict_subset_of/2, not_strict_subset_of_wf/3, |
| 61 | | not_non_empty_subset_of_wf/3, not_non_empty_finite_subset_of_wf/3, |
| 62 | | both_global_sets/4,check_subset_of_global_sets/2, check_not_subset_of_global_sets/2, |
| 63 | | |
| 64 | | first_of_pair/2, second_of_pair/2, |
| 65 | | minimum_of_set_extension_list/4, |
| 66 | | maximum_of_set_extension_list/4, |
| 67 | | minimum_of_set/4, maximum_of_set/4, |
| 68 | | is_finite_set_wf/2, is_infinite_set_wf/2, test_finite_set_wf/3, |
| 69 | | %finite_cardinality_as_int/3, % now we use kernel_cardinality_attr |
| 70 | | cardinality_as_int_for_wf/2, |
| 71 | | cardinality_as_int_wf/3, |
| 72 | | cardinality_as_int/2, %cardinality_peano_wf/3, |
| 73 | | card_convert_int_to_peano/2, |
| 74 | | same_cardinality_wf/3, |
| 75 | | % card_geq/2, |
| 76 | | cardinality_greater/5, cardinality_greater_equal/5, |
| 77 | | cardinality_of_range/3, |
| 78 | | cardinality_of_set_extension_list/3, |
| 79 | | |
| 80 | | cartesian_product_wf/4, |
| 81 | | is_cartesian_pair_wf/4, not_is_cartesian_pair/4, |
| 82 | | |
| 83 | | power_set/2, non_empty_power_set/2, |
| 84 | | |
| 85 | | % is_boolean/1, %is_not_boolean/1, |
| 86 | | is_integer/2, is_not_integer/1, |
| 87 | | is_natural/2, is_natural1/2, |
| 88 | | is_implementable_int/2,is_implementable_nat/2, is_implementable_nat1/2, |
| 89 | | is_not_natural/1, is_not_natural1/1, |
| 90 | | is_not_implementable_int/1,is_not_implementable_nat/1, is_not_implementable_nat1/1, |
| 91 | | |
| 92 | | less_than/2, less_than_equal/2, |
| 93 | | less_than_direct/2, less_than_equal_direct/2, |
| 94 | | safe_less_than_equal/2, safe_less_than_equal/3, |
| 95 | | |
| 96 | | greater_than/2, greater_than_equal/2, |
| 97 | | int_plus/3, |
| 98 | | division/5, floored_division/5, |
| 99 | | modulo/5, |
| 100 | | int_minus/3, unary_minus_wf/3, |
| 101 | | % nat_range/3, % removed |
| 102 | | in_nat_range_wf/4, not_in_nat_range/3, not_in_nat_range_wf/4, test_in_nat_range_wf/5, |
| 103 | | in_nat_range/3, % version without enumeration |
| 104 | | times/3, square/3, |
| 105 | | int_power/5, |
| 106 | | % pred/2, succ/2, removed |
| 107 | | integer_global_set/1, |
| 108 | | |
| 109 | | element_of_global_set/2,element_of_global_set_wf/3,not_element_of_global_set/2, |
| 110 | | |
| 111 | | exhaustive_kernel_check/1, exhaustive_kernel_check_wf/2, exhaustive_kernel_check_wf/3, |
| 112 | | exhaustive_kernel_check_wfdet/2, exhaustive_kernel_check_wf_upto/3, |
| 113 | | exhaustive_kernel_succeed_check/1, exhaustive_kernel_fail_check/1, |
| 114 | | exhaustive_kernel_fail_check_wf/2, exhaustive_kernel_fail_check_wfdet/2, |
| 115 | | exhaustive_kernel_fail_check_wf_upto/3, |
| 116 | | exhaustive_kernel_fail_check_wfinit/2, |
| 117 | | exhaustive_kernel_check/2, exhaustive_kernel_succeed_check/2, exhaustive_kernel_fail_check/2, |
| 118 | | |
| 119 | | singleton_set_element/4, singleton_set_element_wd/4, |
| 120 | | infer_value_type/2, |
| 121 | | check_values_have_same_type/3, |
| 122 | | contains_any/1 |
| 123 | | ]). |
| 124 | | |
| 125 | | :- meta_predicate exhaustive_kernel_check_opt(-,0). |
| 126 | | :- meta_predicate exhaustive_kernel_fail_check_opt(-,0). |
| 127 | | :- meta_predicate not_strict_eq_check(-,0). |
| 128 | | |
| 129 | | %:- use_module('../extensions/profiler/profiler.pl'). |
| 130 | | %:- use_module('../extensions/profiler/profiler_te.pl'). |
| 131 | | %:- enable_profiling(enumerate_basic_type/3). |
| 132 | | %:- enable_profiling(enumerate_type/3). |
| 133 | | %:- enable_profiling(enumerate_tight_type/2). |
| 134 | | |
| 135 | | %:- print(loading_kernel_objects),nl. |
| 136 | | |
| 137 | | %:- multifile user:portray_message/2. |
| 138 | | %user:portray_message(informational, _). |
| 139 | | :- use_module(library(terms)). |
| 140 | | :- use_module(self_check). |
| 141 | | |
| 142 | | :- use_module(debug). |
| 143 | | :- use_module(tools_platform, [platform_is_64_bit/0]). |
| 144 | | :- use_module(tools_printing). |
| 145 | | :- use_module(tools). |
| 146 | | |
| 147 | | :- use_module(module_information,[module_info/2]). |
| 148 | | :- module_info(group,kernel). |
| 149 | | :- module_info(description,'This module provides operations for the basic datatypes of ProB (equal, not_equal, enumeration).'). |
| 150 | | |
| 151 | | :- use_module(typechecker). |
| 152 | | :- use_module(error_manager). |
| 153 | | :- use_module(b_global_sets). %,[global_type/2, b_global_set_cardinality/2, b_empty_global_set/1]). |
| 154 | | :- use_module(kernel_waitflags). |
| 155 | | :- use_module(library(lists)). |
| 156 | | :- use_module(library(avl),[avl_min/2, avl_max/2]). |
| 157 | | :- use_module(library(clpfd)). |
| 158 | | :- use_module(fd_utils_clpfd). |
| 159 | | :- use_module(kernel_freetypes). |
| 160 | | :- use_module(kernel_card_arithmetic). |
| 161 | | :- use_module(custom_explicit_sets). |
| 162 | | :- use_module(typechecker). |
| 163 | | %:- use_module(clpfd_off_interface). % |
| 164 | | % on a 32 bit system: use clpfd_off_interface; on 64 bit system clpfd_interface should be ok (integer overflows) |
| 165 | | :- use_module(clpfd_interface). % |
| 166 | | :- use_module(bsyntaxtree, [get_texpr_id/2, get_texpr_pos/2]). |
| 167 | | |
| 168 | | :- type atomic_type +--> (term(integer,[]) ; term(string,[]) ; constant(list(atomic)) ; abort ; boolean ; global(atomic)). |
| 169 | | :- type atomic_any_type +--> (type(atomic_type) ; term(any,[]) ). |
| 170 | | :- type basic_type_descriptor +--> (type(atomic_any_type) ; set(basic_type_descriptor) ; |
| 171 | | seq(basic_type_descriptor) ; |
| 172 | | couple(basic_type_descriptor,basic_type_descriptor) ; |
| 173 | | record(list(type(field_type))) ; |
| 174 | | freetype(atomic)). |
| 175 | | |
| 176 | | :- type inferred_basic_type_descriptor +--> (var ; type(atomic_type) ; set(inferred_basic_type_descriptor) ; |
| 177 | | seq(inferred_basic_type_descriptor) ; |
| 178 | | couple(inferred_basic_type_descriptor,inferred_basic_type_descriptor)). |
| 179 | | |
| 180 | | :- type fd_index +--> (integer ; var). |
| 181 | | :- type fd_set +--> (atomic ; var). |
| 182 | | :- type fd_term +--> fd(fd_index,fd_set). |
| 183 | | :- type bsets_integer +--> int((integer ; var)). |
| 184 | | :- type bsets_string +--> string((atomic ; var)). |
| 185 | | :- type bsets_bool +--> (pred_false /* bool_false */ ; pred_true /* bool_true */). |
| 186 | | :- type field_type +--> field(atomic,basic_type_descriptor). |
| 187 | | |
| 188 | | %:- type bsets_sequence +--> (nil_seq ; cons(type(bsets_object),type(bsets_sequence))). |
| 189 | | %:- type bsets_set +--> vlist(type(bsets_object)). |
| 190 | | :- functor([_|_],ListFunctor,_), |
| 191 | | (type bsets_set +--> (term([],[]) ; var ; term(ListFunctor,[type(bsets_object),type(bsets_set)]) ; |
| 192 | | avl_set( ground ) ; |
| 193 | | closure(list(type(variable_id)), |
| 194 | | list(type(basic_type_descriptor)),type(boolean_expression)) |
| 195 | | ; closure_x(list(type(variable_id)), |
| 196 | | list(type(basic_type_descriptor)),type(boolean_expression),any))). |
| 197 | | :- type bsets_couple +--> term(',',[type(bsets_object),type(bsets_object)]). |
| 198 | | :- type bsets_global +--> global_set((atomic ; var)). |
| 199 | | :- type bsets_field +--> field(atomic,type(bsets_object)). |
| 200 | | :- type bsets_record +--> rec((var ; list(bsets_field))). |
| 201 | | :- type bsets_freetype +--> freeval(atomic,(atomic ; var),type(bsets_object)). |
| 202 | | |
| 203 | | :- type bsets_object +--> (fd_term ; bsets_integer ; bsets_bool ; term(term,[any]) ; bsets_set ; |
| 204 | | % abort(any) ; % deprecated |
| 205 | | bsets_couple ; bsets_string ; bsets_global ; var; |
| 206 | | bsets_record ; bsets_freetype). |
| 207 | | |
| 208 | | |
| 209 | | :- assert_must_succeed(kernel_waitflags:set_silent(true)). % disable waitflag store not init msgs |
| 210 | | |
| 211 | | |
| 212 | | |
| 213 | | |
| 214 | | % a predicate to exhaustively check a kernel predicate with all possible modes |
| 215 | | |
| 216 | | :- use_module(tools_timeout,[time_out_call/1]). |
| 217 | | exhaustive_kernel_check_opt(C,Cond) :- (Cond -> exhaustive_kernel_check(C) ; true). |
| 218 | | exhaustive_kernel_check(C) :- exhaustive_kernel_check4([],C,true,true). |
| 219 | | exhaustive_kernel_check(Opts,C) :- exhaustive_kernel_check4(Opts,C,true,true). |
| 220 | | exhaustive_kernel_check_wf(C,WF) :- exhaustive_kernel_check_wf([],C,WF). |
| 221 | | exhaustive_kernel_check_wf(Opts,C,WF) :- |
| 222 | | exhaustive_kernel_check4(Opts,C,kernel_waitflags:init_wait_flags(WF), |
| 223 | | kernel_waitflags:ground_wait_flags(WF)). |
| 224 | | exhaustive_kernel_check_wfdet(C,WF) :- |
| 225 | | exhaustive_kernel_check4([],C,kernel_waitflags:init_wait_flags(WF), |
| 226 | | kernel_waitflags:ground_det_wait_flag(WF)). |
| 227 | | exhaustive_kernel_check_wf_upto(C,WF,Limit) :- |
| 228 | | exhaustive_kernel_check4([],C,kernel_waitflags:init_wait_flags(WF), |
| 229 | | (kernel_waitflags:ground_wait_flag_to(WF,Limit), |
| 230 | | kernel_waitflags:portray_waitflags(WF))). |
| 231 | | |
| 232 | ? | exhaustive_kernel_check4(Opts,Call,Pre,Post) :- enumerate_kernel_call(Call,Opts,ECall,Code), |
| 233 | | debug_println(9,exhaustive_kernel_check(ECall,Code)), |
| 234 | | flatten_call((Pre,ECall,Code,Post),FullCall), |
| 235 | ? | must_succeed_without_residue_and_time_out(FullCall), debug_println(9,ok), |
| 236 | | fail. |
| 237 | | exhaustive_kernel_check4(_,_,_,_). |
| 238 | | |
| 239 | | flatten_call((A,B),Res) :- !,flatten_call(A,FA), flatten_call(B,FB), conjoin_call(FA,FB,Res). |
| 240 | | flatten_call(Module:Call,Res) :- !, flatten_call(Call,F), Res=Module:F. |
| 241 | | flatten_call(X,X). |
| 242 | | |
| 243 | | conjoin_call(true,X,R) :- !,R=X. |
| 244 | | conjoin_call(X,true,R) :- !, R=X. |
| 245 | | conjoin_call(X,Y,(X,Y)). |
| 246 | | |
| 247 | | exhaustive_kernel_succeed_check(C) :- exhaustive_kernel_succeed_check([],C). |
| 248 | ? | exhaustive_kernel_succeed_check(Opts,Call) :- enumerate_kernel_call(Call,Opts,ECall,Code), |
| 249 | | debug_println(9,exhaustive_kernel_succeed_check(ECall,Code)), |
| 250 | | flatten_call((ECall,Code),FullCall), |
| 251 | | time_out_call(must_succeed(FullCall)),debug_println(9,ok), |
| 252 | | fail. |
| 253 | | exhaustive_kernel_succeed_check(_,_). |
| 254 | | |
| 255 | | exhaustive_kernel_fail_check_opt(C,Cond) :- (Cond -> exhaustive_kernel_fail_check(C) ; true). |
| 256 | | exhaustive_kernel_fail_check(C) :- exhaustive_kernel_fail_check4([],C,true,true). |
| 257 | | exhaustive_kernel_fail_check(Opts,C) :- exhaustive_kernel_fail_check4(Opts,C,true,true). |
| 258 | | exhaustive_kernel_fail_check_wf(C,WF) :- |
| 259 | | exhaustive_kernel_fail_check4([],C,kernel_waitflags:init_wait_flags(WF), |
| 260 | | kernel_waitflags:ground_wait_flags(WF)). |
| 261 | | exhaustive_kernel_fail_check_wfdet(C,WF) :- |
| 262 | | exhaustive_kernel_fail_check4([],C,kernel_waitflags:init_wait_flags(WF), |
| 263 | | kernel_waitflags:ground_det_wait_flag(WF)). |
| 264 | | exhaustive_kernel_fail_check_wf_upto(C,WF,Limit) :- |
| 265 | | exhaustive_kernel_fail_check4([],C,kernel_waitflags:init_wait_flags(WF), |
| 266 | | kernel_waitflags:ground_wait_flag_to(WF,Limit)). |
| 267 | | exhaustive_kernel_fail_check_wfinit(C,WF) :- |
| 268 | | exhaustive_kernel_fail_check4([],C,kernel_waitflags:init_wait_flags(WF), true). |
| 269 | | |
| 270 | ? | exhaustive_kernel_fail_check4(Opts,Call,Pre,Post) :- enumerate_kernel_call(Call,Opts,ECall,Code), |
| 271 | | debug_println(9,exhaustive_kernel_fail_check(ECall,Code)), |
| 272 | | flatten_call((Pre,ECall,Code,Post),FullCall), |
| 273 | | time_out_call(must_fail(FullCall)),debug_println(9,ok), |
| 274 | | fail. |
| 275 | | exhaustive_kernel_fail_check4(_,_,_,_). |
| 276 | | |
| 277 | | % enumerate_kernel_call(Call, OptionList, NewCall, CodeAfter) |
| 278 | | enumerate_kernel_call((A,B),Opts,(EA,EB),(CA,CB)) :- !, |
| 279 | ? | enumerate_kernel_call(A,Opts,EA,CA), enumerate_kernel_call(B,Opts,EB,CB). |
| 280 | ? | enumerate_kernel_call(Module:Call,Opts,Module:ECall,Code) :- !, enumerate_kernel_call(Call,Opts,ECall,Code). |
| 281 | | enumerate_kernel_call(Call,Opts,ECall,Code) :- Call=..[KernelPred|CArgs], |
| 282 | | (member(commutative,Opts) |
| 283 | | -> (Args=CArgs ; CArgs=[A1,A2|T], Args=[A2,A1|T]) |
| 284 | | ; Args=CArgs |
| 285 | | ), |
| 286 | ? | l_enumerate_kernel_args(Args,EArgs,Code,KernelPred,1), ECall=..[KernelPred|EArgs]. |
| 287 | | l_enumerate_kernel_args([],[],true,_,_). |
| 288 | | l_enumerate_kernel_args([H|T],[EH|ET],Code,KernelPred,Nr) :- |
| 289 | ? | enumerate_kernel_args(H,EH,C1,KernelPred/Nr), |
| 290 | | N1 is Nr+1, |
| 291 | ? | l_enumerate_kernel_args(T,ET,C2,KernelPred,N1), |
| 292 | ? | permute_code((C1,C2),Code). |
| 293 | | |
| 294 | | permute_code((true,C),R) :- !,R=C. |
| 295 | | permute_code((C,true),R) :- !, R=C. |
| 296 | | permute_code((C1,C2),(C1,C2)). |
| 297 | | permute_code((C1,C2),(C2,C1)). |
| 298 | | |
| 299 | | enumerate_kernel_args(Var,Res,Code,_) :- var(Var),!, Res=Var, Code=true. |
| 300 | ? | enumerate_kernel_args(X,Res,Code,KP_Nr) :- do_not_delay(X,KP_Nr),!, Res=X, Code=true. |
| 301 | | enumerate_kernel_args(Arg,Arg,true,_). % just keep the argument |
| 302 | | enumerate_kernel_args(Args,NewArg,Code,KP_Nr) :- arg_is_list(KP_Nr),!, |
| 303 | | % we have a list of B expressions (e.g., in partition_wf) |
| 304 | ? | (Code = '='(NewArg,Args) ; l_enumerate_kernel_args(Args,NewArg,Code,arg_is_list,1)). |
| 305 | | enumerate_kernel_args(Arg,NewArg,Code,_) :- % delay the argument fully |
| 306 | | (term_is_of_type(Arg,bsets_object,no) |
| 307 | | -> Code = equal_object(NewArg,Arg,enumerate_kernel_args) |
| 308 | | ; Code = '='(NewArg,Arg)). |
| 309 | | enumerate_kernel_args(int(X),int(XX),Code,_) :- nonvar(X), Code = '='(X,XX). % delay setting number content |
| 310 | | enumerate_kernel_args(string(X),string(XX),Code,_) :- nonvar(X), Code = '='(X,XX). % delay setting string content |
| 311 | | enumerate_kernel_args(term(floating(X)),term(floating(XX)),Code,_) :- nonvar(X), Code = '='(X,XX). % delay setting real number content |
| 312 | | enumerate_kernel_args((A,B),(AA,BB),(CodeA,CodeB),KP_Nr) :- |
| 313 | ? | enumerate_kernel_args(A,AA,CodeA,KP_Nr),enumerate_kernel_args(B,BB,CodeB,KP_Nr), |
| 314 | | (AA,BB) \== (A,B). % avoid re-generating case 3 above (just keep argument) |
| 315 | | enumerate_kernel_args(freeval(ID,Case,A),freeval(ID,Case,AA),CodeA,KP_Nr) :- |
| 316 | ? | enumerate_kernel_args(A,AA,CodeA,KP_Nr), |
| 317 | | AA \== A. % avoid re-generating case 3 above (just keep argument) |
| 318 | | enumerate_kernel_args([H|T],[H|NewT],Code,_) :- Code = equal_object(NewT,T). % delay tail |
| 319 | | enumerate_kernel_args([H|T],[(int(NewI),H2)|T],Code,_) :- nonvar(H), % make index (e.g. of sequence) nonvar first |
| 320 | ? | H = (II,H2), ground(II), II=int(I), \+ member((int(I),_),T), % the element is unique in domain |
| 321 | | Code = '='(NewI,I). |
| 322 | | enumerate_kernel_args([H|T],[(H1,NewH2)|T],Code,_) :- nonvar(H), |
| 323 | ? | H = (H1,H2), ground(H2), \+ member((_,H2),T), % the element is unique in ragne |
| 324 | | Code = equal_object(NewH2,H2). |
| 325 | | enumerate_kernel_args([H|T],Res,Code,KP_Nr) :- |
| 326 | | try_expand_and_convert_to_avl([H|T],AVL), |
| 327 | ? | AVL \= [H|T], enumerate_kernel_args(AVL,Res,Code,KP_Nr). |
| 328 | | enumerate_kernel_args([H|T],Res,Code,KP_Nr) :- ground([H|T]),generate_member_closure([H|T],Closure), |
| 329 | ? | enumerate_kernel_args(Closure,Res,Code,KP_Nr). |
| 330 | | |
| 331 | | % check if an argument is a list not a set. |
| 332 | | arg_is_list(KernelPred/Nr) :- argument_is_list_not_set(KernelPred,Nr). |
| 333 | | %arg_is_not_list(KernelPred/Nr) :- \+ argument_is_list_not_set(KernelPred,Nr). |
| 334 | | argument_is_list_not_set(partition_wf,2). |
| 335 | | argument_is_list_not_set(not_partition_wf,2). |
| 336 | | argument_is_list_not_set(test_partition_wf,2). |
| 337 | | argument_is_list_not_set(disjoint_union_generalized_wf,1). |
| 338 | | |
| 339 | | do_not_delay(b(_,_,_),_). % do not delay instantiation B predicates and expressions |
| 340 | ? | do_not_delay(global_set(G),KP/ArgNr) :- custom_explicit_sets:is_infinite_global_set(G,_), |
| 341 | ? | do_not_delay_arg(KP,ArgNr). |
| 342 | | do_not_delay(no_wf_available,_). % do not delay waitflag store arguments |
| 343 | | do_not_delay(wfx(_,_,_,_),_). % ditto |
| 344 | | % these arguments cause difficulty if infinite sets are delayed (i.e., instantiated later) |
| 345 | | do_not_delay_arg(partial_function_wf,2). |
| 346 | | do_not_delay_arg(partial_function_wf,3). |
| 347 | | do_not_delay_arg(subset_test,2). |
| 348 | | do_not_delay_arg(subset_strict_test,2). |
| 349 | | |
| 350 | | generate_member_closure(ExplicitSet,closure(['_zzzz_unit_tests'],[Type],Pred)) :- |
| 351 | | infer_type(ExplicitSet,set(Type)), |
| 352 | | Pred = |
| 353 | | b(member(b(identifier('_zzzz_unit_tests'),Type,[generated]), |
| 354 | | b(value(ExplicitSet),set(Type),[])),pred,[]). |
| 355 | | |
| 356 | | infer_type(Value,Type) :- (infer_value_type(Value,Type) |
| 357 | | -> true %,print(inferred(Type,Value)),nl |
| 358 | | ; print('### Could not infer type: '), print(Value),nl,fail). |
| 359 | | |
| 360 | | :- use_module(btypechecker,[couplise_list/2]). |
| 361 | | infer_value_type(Var,Type) :- var(Var),!,Type=any. |
| 362 | | infer_value_type([],set(any)). |
| 363 | | infer_value_type([H|T],set(ResType)) :- infer_value_type(H,Type), |
| 364 | | ((contains_any(Type),T=[H2|_], % try H2; maybe we can infer a better type here |
| 365 | | infer_value_type(H2,Type2), \+ contains_any(Type2)) |
| 366 | | -> ResType = Type2 |
| 367 | | ; ResType = Type). |
| 368 | | infer_value_type(avl_set(node(H,_True,_,_,_)),set(Type)) :- infer_value_type(H,Type). |
| 369 | | infer_value_type(int(_),integer). |
| 370 | | infer_value_type(string(_),string). |
| 371 | | infer_value_type((A,B),couple(TA,TB)) :- infer_value_type(A,TA), infer_value_type(B,TB). |
| 372 | | infer_value_type(fd(_,T),global(T)). |
| 373 | | infer_value_type(pred_true /* bool_true */,boolean). |
| 374 | | infer_value_type(pred_false /* bool_false */,boolean). |
| 375 | | infer_value_type(rec(Fields),record(FieldTypes)) :- infer_field_types(Fields,FieldTypes). |
| 376 | | infer_value_type(freeval(Id,_Case,_Val),freetype(Id)). |
| 377 | | infer_value_type(closure(_,Types,_),set(Res)) :- couplise_list(Types,Res). |
| 378 | | infer_value_type(global_set('STRING'),R) :- !, R=set(string). % what if Event-B/TLA have a deferred set of that name |
| 379 | | infer_value_type(global_set('FLOAT'),R) :- !, R=set(real). |
| 380 | | infer_value_type(global_set('REAL'),R) :- !, R=set(real). |
| 381 | | infer_value_type(global_set(X),R) :- b_integer_set(X),!,R=set(integer). |
| 382 | | infer_value_type(global_set(Name),set(global(Name))) :- b_global_set(Name). |
| 383 | | infer_value_type(term(floating(_)),real). % see kernel_reals:is_real(.) |
| 384 | | |
| 385 | | infer_field_types([],[]). |
| 386 | | infer_field_types([field(Name1,Val)|T],[field(Name1,VT)|TT]) :- |
| 387 | | infer_value_type(Val,VT), |
| 388 | | infer_field_types(T,TT). |
| 389 | | |
| 390 | | contains_any(any). |
| 391 | | contains_any(couple(A,B)) :- (contains_any(A) -> true ; contains_any(B)). |
| 392 | | contains_any(set(A)) :- contains_any(A). |
| 393 | | % to do: fields |
| 394 | | |
| 395 | | :- assert_pre(kernel_objects:basic_type(Obj,Type), (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))). |
| 396 | | :- assert_post(kernel_objects:basic_type(Obj,_), type_check(Obj,bsets_object)). |
| 397 | | |
| 398 | | %:- block basic_type(-,-). |
| 399 | | |
| 400 | | basic_type(FD,global(T)) :- !, global_type(FD,T). % will set up CLP(FD) domain for X |
| 401 | | % TO DO: Also: what about global(T) inside other structures (pairs) ? |
| 402 | | basic_type(Rec,record(FieldTypes)) :- !, Rec=rec(Fields), |
| 403 | ? | basic_field_types(Fields,FieldTypes). |
| 404 | | %basic_type(Set,set(Type)) :- !, basic_type_set(Type,Set,inf). |
| 405 | | basic_type(_X,_TY). %basic_type2(TY,X) %basic_symbreak(TY,X) |
| 406 | | %print(ignore_basic_type(X,Y)),nl %, basic_type2(TY,X) %%STILL REQUIRED ????? |
| 407 | | |
| 408 | | basic_field_types([],[]). |
| 409 | | basic_field_types([field(Name1,Val)|T],[field(Name2,VT)|TT]) :- |
| 410 | | check_field_name_compatibility(Name1,Name2,basic_field_types2), |
| 411 | ? | basic_type(Val,VT),basic_field_types(T,TT). |
| 412 | | |
| 413 | | |
| 414 | | |
| 415 | | /* ------------------------- */ |
| 416 | | /* enumerate_basic_type/2 */ |
| 417 | | /* ------------------------- */ |
| 418 | | /* a version of basic_type that enumerates */ |
| 419 | | |
| 420 | | :- assert_must_succeed(enumerate_basic_type([],set(couple(integer,integer)) )). |
| 421 | | :- assert_must_succeed(enumerate_basic_type([([],int(2)), ([int(3)],int(4))], |
| 422 | | set(couple(set(integer),integer)) )). |
| 423 | | :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))], |
| 424 | | set(couple(integer,integer)) )). |
| 425 | | :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))], |
| 426 | | seq(integer) )). |
| 427 | | :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))], |
| 428 | | seq(integer) )). |
| 429 | | :- assert_must_succeed((enumerate_basic_type(X,global('Name')), |
| 430 | | equal_object(X,fd(1,'Name')) )). |
| 431 | | :- assert_must_succeed((enumerate_basic_type(X,global('Name')), |
| 432 | | equal_object(X,fd(2,'Name')) )). |
| 433 | | :- assert_must_succeed((enumerate_basic_type(X,global('Name')), |
| 434 | | X==fd(2,'Name')) ). |
| 435 | | :- assert_must_succeed((enumerate_basic_type(X,record([field(a,global('Name'))])), |
| 436 | | equal_object(X,rec([field(a,fd(1,'Name'))])) )). |
| 437 | | :- assert_must_succeed((enumerate_basic_type(X,record([field(a,integer),field(b,global('Name'))])), |
| 438 | | equal_object(X,rec([field(a,int(1)),field(b,fd(1,'Name'))])) )). |
| 439 | | :- assert_must_succeed((kernel_freetypes:add_freetype(selfc1,[case(a,constant([a])),case(b,integer)]), |
| 440 | | kernel_freetypes:set_freetype_depth(2), |
| 441 | | enumerate_basic_type(X,freetype(selfc1)),equal_object(X,freeval(selfc1,a,term(a))), |
| 442 | | kernel_freetypes:reset_freetypes)). |
| 443 | | :- assert_must_succeed((kernel_freetypes:add_freetype(selfc5,[case(a,constant([a])),case(b,integer)]), |
| 444 | | kernel_freetypes:set_freetype_depth(2), |
| 445 | | enumerate_basic_type(X,freetype(selfc5)),equal_object(X,freeval(selfc5,b,int(1))), |
| 446 | | kernel_freetypes:reset_freetypes)). |
| 447 | | :- assert_must_succeed((kernel_freetypes:add_freetype(selfc7,[case(nil,constant([nil])),case(node,couple(freetype(selfc7),freetype(selfc7)))]), |
| 448 | | kernel_freetypes:set_freetype_depth(3), |
| 449 | | findall(X,enumerate_basic_type(X,freetype(selfc7)),Solutions), |
| 450 | | length(Solutions,5), |
| 451 | | kernel_freetypes:reset_freetypes)). |
| 452 | | :- assert_must_succeed((kernel_freetypes:add_freetype(selfc2,[case(a,constant([a])),case(b,freetype(selfc3))]), |
| 453 | | kernel_freetypes:add_freetype(selfc3,[case(c,constant([c])),case(d,freetype(selfc2))]), |
| 454 | | kernel_freetypes:set_freetype_depth(4), |
| 455 | | enumerate_basic_type(X,freetype(selfc2)), |
| 456 | | equal_object(X,freeval(selfc2,b,freeval(selfc3,d,freeval(selfc2,b,freeval(selfc3,c,term(c)))))), |
| 457 | | kernel_freetypes:reset_freetypes)). |
| 458 | | :- assert_must_succeed((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ), |
| 459 | | equal_object(X,[(fd(1,'Name'),fd(1,'Code'))])) ). |
| 460 | | :- assert_must_succeed((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ), |
| 461 | | equal_object(X,[(fd(2,'Name'),fd(1,'Code')), (fd(1,'Name'),fd(2,'Code'))])) ). |
| 462 | | :- assert_must_succeed((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ), |
| 463 | | equal_object(X,[(fd(1,'Name'),fd(2,'Code')), (fd(2,'Name'),fd(1,'Code'))])) ). |
| 464 | | :- assert_must_succeed_any((enumerate_basic_type(X,set(couple(global('Name'),global('Code'))) ), |
| 465 | | equal_object(X,[(fd(1,'Name'),fd(2,'Code')), (fd(2,'Name'),fd(1,'Code'))])) ). |
| 466 | | :- assert_must_succeed(enumerate_basic_type([(int(2),(int(1),int(2))), |
| 467 | | (int(1),(int(3),int(4)))], |
| 468 | | set(couple(integer,couple(integer,integer))) )). |
| 469 | | :- assert_must_succeed(enumerate_basic_type([(int(2),(int(1),int(2))), |
| 470 | | (int(55),(int(3),int(4)))], |
| 471 | | set(couple(integer,couple(integer,integer))) )). |
| 472 | | :- assert_must_succeed(enumerate_basic_type([term('err')],set(constant([err])))). |
| 473 | | :- assert_must_succeed(enumerate_basic_type([(int(1),int(2)),(int(3),int(4))], |
| 474 | | set(couple(integer,integer)))). |
| 475 | | |
| 476 | | :- assert_must_succeed_multiple(enumerate_basic_type([(int(2),fd(_A,'Name')),(int(3),fd(_B,'Name')), |
| 477 | | (int(4),fd(_C,'Name')),(int(5),fd(_D,'Name')),(int(6),fd(_E,'Name')),(int(7),fd(_F,'Name')), |
| 478 | | (int(8),fd(_G,'Name')),(int(9),fd(_H,'Name')),(int(10),fd(_I,'Name')), |
| 479 | | (int(11),fd(_,'Name')),(int(12),fd(_,'Name')),(int(13),fd(_,'Name')), |
| 480 | | (int(14),fd(_,'Name'))],set(couple(integer,global('Name'))))). |
| 481 | | |
| 482 | | :- 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) )). |
| 483 | | |
| 484 | | :- assert_must_succeed(( enumerate_basic_type(global_set('Code'), |
| 485 | | set(global('Code'))) )). |
| 486 | | |
| 487 | | :- 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')))))). |
| 488 | | :- 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))))). |
| 489 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(enumerate_basic_type([pred_true,pred_false],set(boolean)))). |
| 490 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(enumerate_basic_type([[],[pred_true,pred_false]],set(set(boolean))))). |
| 491 | | |
| 492 | | :- assert_pre(kernel_objects:enumerate_basic_type(Obj,Type), |
| 493 | | (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))). |
| 494 | | :- assert_post(kernel_objects:enumerate_basic_type(Obj,_), (type_check(Obj,bsets_object),ground_check(Obj))). |
| 495 | | |
| 496 | | enumerate_basic_type_wf(Obj,Type,WF) :- |
| 497 | | enumerate_basic_type_wf(Obj,Type,enumerate_basic_type,WF). |
| 498 | | :- block enumerate_basic_type_wf(?,-,?,?). |
| 499 | | enumerate_basic_type_wf(Obj,Type,EnumWarning,WF) :- |
| 500 | | enumerate_basic_type4(Type,Obj,basic,trigger_true(EnumWarning),WF). % add WF context info |
| 501 | | |
| 502 | | :- block enumerate_basic_type(?,-). |
| 503 | | enumerate_basic_type(Obj,Type) :- |
| 504 | | %enumerate_basic_type2(Obj,Type). |
| 505 | ? | enumerate_basic_type4(Type,Obj,basic,trigger_true(enumerate_basic_type),no_wf_available). |
| 506 | | %(ground(Obj) -> true ; enumerate_basic_type3(Type,Obj,basic)). |
| 507 | | |
| 508 | | :- block enumerate_basic_type(?,-,-). |
| 509 | | enumerate_basic_type(Obj,Type,EnumWarning) :- |
| 510 | | enumerate_basic_type4(Type,Obj,basic,EnumWarning,no_wf_available). |
| 511 | | |
| 512 | | |
| 513 | | :- block enumerate_type(?,-,?). % last argument: basic or tight |
| 514 | | enumerate_type(Obj,Type,Tight) :- |
| 515 | | %enumerate_basic_type2(Obj,Type). |
| 516 | ? | enumerate_basic_type4(Type,Obj,Tight,trigger_true(enumerate_type_3),no_wf_available). |
| 517 | | |
| 518 | | :- block enumerate_type(?,-,?,?), enumerate_type(?,?,?,-). |
| 519 | | enumerate_type(Obj,Type,Tight,EnumWarning) :- |
| 520 | | enumerate_basic_type4(Type,Obj,Tight,EnumWarning,no_wf_available). |
| 521 | | |
| 522 | | enumerate_type_wf(Obj,Type,Tight,WF) :- |
| 523 | ? | enumerate_type_wf(Obj,Type,Tight,trigger_true(enumerate_type_wf),WF). |
| 524 | | |
| 525 | | :- block enumerate_type_wf(?,-,?,?,?), enumerate_type_wf(?,?,?,-,?). |
| 526 | | enumerate_type_wf(Obj,Type,Tight,EnumWarning,WF) :- |
| 527 | ? | enumerate_basic_type4(Type,Obj,Tight,EnumWarning,WF). |
| 528 | | |
| 529 | | %enumerate_basic_type2(X,Type) :- |
| 530 | | % (ground(X) -> (basic_type(X,Type) -> true |
| 531 | | % ; add_internal_error('Type error: ',enumerate_basic_type2(X,Type))) |
| 532 | | % ; enumerate_basic_type3(Type,X)). |
| 533 | | |
| 534 | | enumerate_basic_type4(global(T),R,_Tight,EnumWarning,WF) :- |
| 535 | ? | enumerate_global_type_with_enum_warning(R,T,EnumWarning,WF). |
| 536 | | enumerate_basic_type4(set(X),Set,Tight,EnumWarning,WF) :- |
| 537 | ? | enumerate_basic_type_set(Set,X,Tight,EnumWarning,WF). |
| 538 | | enumerate_basic_type4(seq(SeqRanType),Seq,Tight,EnumWarning,WF) :- |
| 539 | ? | (Tight = tight -> enumerate_seq_type_wf(Seq,SeqRanType,EnumWarning,WF) % might trigger warning. push flag. |
| 540 | ? | ; enumerate_basic_type4(set(couple(integer,SeqRanType)),Seq,basic,EnumWarning,WF)). |
| 541 | | enumerate_basic_type4(couple(XT,YT),(X,Y),Tight,EnumWarning,WF) :- |
| 542 | ? | enumerate_type_wf(X,XT,Tight,EnumWarning,WF), |
| 543 | ? | enumerate_type_wf(Y,YT,Tight,EnumWarning,WF). |
| 544 | ? | enumerate_basic_type4(boolean,B,_Tight,_EnumWarning,_WF) :- enumerate_bool(B). |
| 545 | | enumerate_basic_type4(real,R,_Tight,EnumWarning,WF) :- enumerate_real_wf(R,EnumWarning,WF). |
| 546 | | enumerate_basic_type4(string,string(S),_Tight,EnumWarning,WF) :- enumerate_string_wf(S,EnumWarning,WF). |
| 547 | | enumerate_basic_type4(constant([V]),term(V),_Tight,_EnumWarning,_WF). |
| 548 | | enumerate_basic_type4(record(FT),rec(F),Tight,EnumWarning,WF) :- |
| 549 | ? | enumerate_basic_field_types(F,FT,Tight,EnumWarning,WF). |
| 550 | | enumerate_basic_type4(freetype(Id),freeval(Id2,C,Value),Tight,EnumWarning,WF) :- |
| 551 | | (Id=Id2 -> true |
| 552 | | ; add_internal_error('Freetypes do not match:',enumerate_basic_type4(freetype(Id),freeval(Id2,C,Value),Tight,_,_))), |
| 553 | | (ground_value(freeval(Id2,C,Value)) -> true |
| 554 | | ; (is_recursive_freetype(Id), |
| 555 | | max_freetype_enum_depth(Depth) |
| 556 | | -> gen_enum_warning_wf(Id,0:inf,0:Depth,EnumWarning,unknown,WF) |
| 557 | | ; true), |
| 558 | ? | enumerate_freetype_wf(Tight,freeval(Id,C,Value),freetype(Id),WF) |
| 559 | | ). |
| 560 | | enumerate_basic_type4(freetype_lim_depth(Id,Depth),freeval(Id2,C,Value),Tight,_EnumWarning,WF) :- |
| 561 | | (Id=Id2 -> true |
| 562 | | ; add_internal_error('Freetypes do not match:',enumerate_basic_type4(freetype_lim_depth(Id,Depth),freeval(Id2,C,Value),Tight,_,_))), |
| 563 | | % freetype_lim_depth is created artificially by enumerate_freetype |
| 564 | ? | enumerate_freetype_wf(Tight,freeval(Id,C,Value),freetype_lim_depth(Id,Depth),WF). |
| 565 | | enumerate_basic_type4(integer,int(N),Tight,EnumWarning,WF) :- |
| 566 | | (nonvar(N) |
| 567 | | -> (integer(N) -> true |
| 568 | | ; add_internal_error('Illegal value:',enumerate_basic_type4(integer,int(N),Tight,EnumWarning,WF)) |
| 569 | | ) |
| 570 | ? | ; enumerate_int_with_span(N,EnumWarning,unknown,WF)). |
| 571 | | enumerate_basic_type4(abort,V,Tight,EnumWarning,WF) :- |
| 572 | | add_internal_error(deprecated_abort_type,enumerate_basic_type4(abort,V,Tight,EnumWarning,WF)). |
| 573 | | enumerate_basic_type4(constant,V,Tight,EnumWarning,WF) :- |
| 574 | | add_internal_error(deprecated_abort_type,enumerate_basic_type4(constant,V,Tight,EnumWarning,WF)). |
| 575 | | enumerate_basic_type4(any,Obj,_Tight,EnumWarning,WF) :- enumerate_any_wf(Obj,EnumWarning,WF). |
| 576 | | |
| 577 | | :- use_module(library(random),[random/3]). |
| 578 | | enumerate_bool(X) :- preferences:preference(randomise_enumeration_order,true), |
| 579 | | random(1,3,1),!, |
| 580 | | (X=pred_false ; X=pred_true). |
| 581 | | enumerate_bool(pred_true). /* was bool_true */ |
| 582 | | enumerate_bool(pred_false). |
| 583 | | |
| 584 | | max_cardinality_string(inf). % was 2 |
| 585 | | all_strings_wf(AS,WF) :- findall(string(S),enumerate_string_wf(S,trigger_throw(all_strings),WF),AS). |
| 586 | | :- use_module(btypechecker,[machine_string/1]). |
| 587 | | enumerate_string_wf(S,_EnumWarning,_WF) :- atomic(S),!. |
| 588 | | enumerate_string_wf(S,EnumWarning,WF) :- %print('### WARNING, Enumerating STRING'),nl, |
| 589 | | % frozen(S,Goal), print(enum(S,Goal)),nl, |
| 590 | | % MAYBE TO DO: we could check if prolog:dif(S,'"STR1"') are in frozen Goal and then enumerate more? |
| 591 | | % if we do this we need to adapt dont_expand(global('STRING')) :- ... further below |
| 592 | | gen_enum_warning_wf('STRING',inf,'"STRING1","STRING2",...',EnumWarning,unknown,WF), |
| 593 | | (S = 'STRING1', \+ machine_string(S) % used to be '"STR1"' |
| 594 | | ; S = 'STRING2', \+ machine_string(S) % used to be '"STR2"' |
| 595 | | ; machine_string(S)). |
| 596 | | |
| 597 | | is_string(string(_),_WF). |
| 598 | | is_not_string(X) :- top_level_dif(X,string). |
| 599 | | |
| 600 | | |
| 601 | | :- use_module(library(random),[random/3]). |
| 602 | | :- use_module(kernel_reals,[is_ground_real/1, construct_real/2, is_real/2]). |
| 603 | | enumerate_real_wf(S,_EnumWarning,_) :- is_ground_real(S),!. |
| 604 | | enumerate_real_wf(S,EnumWarning,WF) :- |
| 605 | | gen_enum_warning_wf('REAL',inf,'"0.0","1.0",...',EnumWarning,unknown,WF), |
| 606 | | ( construct_real('0.0',S) |
| 607 | | ; construct_real('1.0',S) |
| 608 | | ; construct_real('-1.0',S) |
| 609 | | ; random(0.0,1.0,R), is_real(S,R) |
| 610 | | ; random(-1.0,0.0,R), is_real(S,R) |
| 611 | | ; preferences:preference(maxint,MaxInt), random(1.0,MaxInt,R), is_real(S,R) |
| 612 | | ; preferences:preference(minint,MinInt), random(MinInt,-1.0,R), is_real(S,R) |
| 613 | | ). |
| 614 | | |
| 615 | | |
| 616 | | :- block enumerate_any_wf(-,?,?). |
| 617 | | enumerate_any_wf(fd(X,T),EnumWarning,WF) :- !, |
| 618 | | when(nonvar(T),enumerate_global_type_with_enum_warning(fd(X,T),T,EnumWarning,WF)). |
| 619 | | enumerate_any_wf(int(N),EnumWarning,WF) :- !,enumerate_basic_type4(integer,int(N),basic,EnumWarning,WF). |
| 620 | | enumerate_any_wf(term(X),_EnumWarning,_WF) :- !, print_message(could_not_enumerate_term(X)). |
| 621 | | enumerate_any_wf(string(S),EnumWarning,WF) :- !, enumerate_string_wf(S,EnumWarning,WF). |
| 622 | | enumerate_any_wf(pred_true /* bool_true */,_EnumWarning,_WF) :- !. |
| 623 | | enumerate_any_wf(pred_false /* bool_false */,_EnumWarning,_WF) :- !. |
| 624 | | enumerate_any_wf([],_EnumWarning,_WF) :- !. |
| 625 | | enumerate_any_wf([H|T],EnumWarning,WF) :- !, enumerate_any_wf(H,EnumWarning,WF), enumerate_any_wf(T,EnumWarning,WF). |
| 626 | | enumerate_any_wf(avl_set(_),_EnumWarning,_WF) :- !. |
| 627 | | enumerate_any_wf(global_set(_),_EnumWarning,_WF) :- !. |
| 628 | | enumerate_any_wf((H,T),EnumWarning,WF) :- !, enumerate_any_wf(H,EnumWarning,WF), enumerate_any_wf(T,EnumWarning,WF). |
| 629 | | enumerate_any_wf(rec(Fields),EnumWarning,WF) :- !, enumerate_any_wf(Fields,EnumWarning,WF). |
| 630 | | enumerate_any_wf(field(_,V),EnumWarning,WF) :- !, enumerate_any_wf(V,EnumWarning,WF). |
| 631 | | % we could support: closure values... |
| 632 | | enumerate_any_wf(T,_EnumWarning,_WF) :- add_message(enumerate_any_wf,'Could_not_enumerate value: ',T). |
| 633 | | |
| 634 | | |
| 635 | | :- use_module(preferences,[preference/2]). |
| 636 | | |
| 637 | | % enumerate an INTEGER variable |
| 638 | | enumerate_int_with_span(N,EnumWarning,Span,WF) :- |
| 639 | | clpfd_domain(N,FDLow,FDUp), % print(enum(N,FDLow,FDUp)),nl, |
| 640 | | (finite_domain(FDLow,FDUp) |
| 641 | ? | -> label(N,FDLow,FDUp) |
| 642 | ? | ; enum_unbounded(FDLow,FDUp,N,EnumWarning,Span,WF) |
| 643 | | ). |
| 644 | | label(N,FDLow,FDUp) :- |
| 645 | | gen_enum_warning_if_large(N,FDLow,FDUp), |
| 646 | ? | clpfd_interface:clpfd_in_domain(N). |
| 647 | | |
| 648 | | % when in CLP(FD) mode; try and do a case-split and see if that narrows down the possible ranges |
| 649 | | enum_unbounded(X,Y,N,EnumWarning,Span,WF) :- preferences:preference(use_clpfd_solver,true),!, |
| 650 | ? | enum_unbounded_clp(X,Y,N,EnumWarning,Span,WF). |
| 651 | | enum_unbounded(X,Y,N,EnumWarning,Span,WF) :- %frozen(N,G), print(frozen(N,G,X,Y,EnumWarning)),nl, |
| 652 | | clpfd_off_domain(N,X,Y,NX,NY), |
| 653 | | (finite_domain(NX,NY) -> enumerate_int1(N,NX,NY) |
| 654 | ? | ; enum_unbounded_clpfd_off(NX,NY,N,EnumWarning,Span,WF)). |
| 655 | | |
| 656 | | enum_unbounded_clpfd_off(_FDLow,_FDUp,N,_EnumWarning,_,_WF) :- is_wd_guarded_result_variable(N),!. |
| 657 | | enum_unbounded_clpfd_off(FDLow,FDUp,N,EnumWarning,Span,WF) :- |
| 658 | | make_domain_finite(FDLow,FDUp,Min,Max), |
| 659 | | gen_enum_warning_wf('INTEGER',FDLow:FDUp,Min:Max,EnumWarning,Span,WF), |
| 660 | ? | enumerate_int1(N,Min,Max). % will also do a case split, but without posting constraints |
| 661 | | |
| 662 | | % try to determine integer variable bounds from pending co-routines for CLPFD off mode |
| 663 | | clpfd_off_domain(Var,Low,Up,NewLow,NewUp) :- |
| 664 | | frozen(Var,Goal), narrow_down_interval(Goal,Var,Low,Up,NewLow,NewUp). |
| 665 | | % ((Lowx,Up)==(NewLow,NewUp) -> true ; print(narrowed_down(Var,Low,Up,NewLow,NewUp)),nl). |
| 666 | | narrow_down_interval((A,B),Var,Low,Up,NewLow,NewUp) :- !, |
| 667 | | narrow_down_interval(A,Var,Low,Up,Low1,Up1), |
| 668 | | narrow_down_interval(B,Var,Low1,Up1,NewLow,NewUp). |
| 669 | | narrow_down_interval(kernel_objects:safe_less_than_equal(_,V1,V2),Var,Low,Up,NewLow,NewUp) :- !, |
| 670 | | (V1==Var,number(V2) -> NewLow=Low,fd_min(Up,V2,NewUp) |
| 671 | | ; V2==Var,number(V1) -> fd_max(Low,V1,NewLow),NewUp=Up |
| 672 | | ; NewLow=Low,NewUp=Up). |
| 673 | | narrow_down_interval(kernel_objects:safe_less_than(V1,V2),Var,Low,Up,NewLow,NewUp) :- !, |
| 674 | | (V1==Var,number(V2) -> NewLow=Low,V2m1 is V2-1, fd_min(Up,V2m1,NewUp) |
| 675 | | ; V2==Var,number(V1) -> V1p1 is V1+1, fd_max(Low,V1p1,NewLow),NewUp=Up |
| 676 | | ; NewLow=Low,NewUp=Up). |
| 677 | | narrow_down_interval(_,_,L,U,L,U). |
| 678 | | |
| 679 | | % check if this variable is marked as being assigned to by currently not-well-defined construct such as min,max,...: |
| 680 | | is_wd_guarded_result_variable(N) :- % write('-WDG-'), |
| 681 | | frozen(N,FrozenGoal), % TO DO: use attribute rather than frozen |
| 682 | | is_wd_guarded_result_variable_aux(FrozenGoal,N). |
| 683 | | is_wd_guarded_result_variable_aux(kernel_waitflags:is_wd_guarded_result(V),N) :- !, N==V. |
| 684 | | is_wd_guarded_result_variable_aux((A,B),N) :- |
| 685 | | is_wd_guarded_result_variable_aux(A,N) ; is_wd_guarded_result_variable_aux(B,N). |
| 686 | | |
| 687 | | % enumerate unbounded integer variable N in a CLP(FD) fashion: |
| 688 | | enum_unbounded_clp(0,Y,N,EnumWarning,Span,WF) :- (Y=sup ; Y>0), |
| 689 | | % we span 0 and positive numbers |
| 690 | | !, |
| 691 | | (N=0 |
| 692 | | % for division/modulo... 0 is often a special case |
| 693 | | ; try_post_constraint(N #>0), |
| 694 | | force_enumerate_int_wo_case_split(N,'INTEGER',EnumWarning,Span,WF) |
| 695 | | ). |
| 696 | | enum_unbounded_clp(X,Y,N,EnumWarning,Span,WF) :- |
| 697 | | (is_inf_or_overflow_card(X) -> true ; X<0), (Y=sup ; Y>0), |
| 698 | | % we span both negative and positive numbers |
| 699 | | !, |
| 700 | | % do a case split |
| 701 | | (N=0 |
| 702 | | % 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) |
| 703 | | ; 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 |
| 704 | ? | force_enumerate_int_wo_case_split(N,'INTEGER',EnumWarning,Span,WF) |
| 705 | | ; try_post_constraint(N #<0), |
| 706 | ? | force_enumerate_int_wo_case_split(N,'INTEGER',EnumWarning,Span,WF) |
| 707 | | ). |
| 708 | | enum_unbounded_clp(FDLow,FDUp,N,EnumWarning,Span,WF) :- |
| 709 | | % we cover only negative or only positive numbers |
| 710 | ? | force_enumerate_with_warning(N,FDLow,FDUp,'INTEGER',EnumWarning,Span,WF). |
| 711 | | |
| 712 | | % force enumeration without case split: |
| 713 | | force_enumerate_int_wo_case_split(N,Msg,EnumWarning,Span,WF) :- |
| 714 | | clpfd_domain(N,FDLow,FDUp), % print(enum(N,FDLow,FDUp)),nl, |
| 715 | | (finite_domain(FDLow,FDUp) |
| 716 | | -> label(N,FDLow,FDUp) |
| 717 | | ; %print(force_enumerate_int_wo_case_split(FDLow,FDUp)),nl, |
| 718 | ? | force_enumerate_with_warning(N,FDLow,FDUp,Msg,EnumWarning,Span,WF) |
| 719 | | ). |
| 720 | | |
| 721 | | force_enumerate_with_warning(N,_FDLow,_FDUp,_Msg,_EnumWarning,_Span,_WF) :- % check if we should enumerate at all |
| 722 | | is_wd_guarded_result_variable(N),!. % affects tests 1825, 2017 |
| 723 | | force_enumerate_with_warning(N,FDLow,FDUp,Msg,EnumWarning,Span,WF) :- |
| 724 | | make_domain_finite(FDLow,FDUp,Min,Max), |
| 725 | | gen_enum_warning_wf(Msg,FDLow:FDUp,Min:Max,EnumWarning,Span,WF), |
| 726 | | %try_post_constraint(N in Min..Max), % I am not sure whether this is useful or not |
| 727 | ? | enumerate_int2(N,Min,Max). |
| 728 | | |
| 729 | | |
| 730 | | % generate enumeration warning: |
| 731 | | gen_enum_warning_wf(TYPE,RANGE,RESTRICTED_RANGE,Trigger,Span,WF) :- |
| 732 | | Warning = enumeration_warning(enumerating(Info),TYPE,RANGE,RESTRICTED_RANGE,critical), |
| 733 | | (get_trigger_info(Trigger,Info) |
| 734 | | -> (Span=unknown,Info=b(_,_,_),get_texpr_pos(Info,Span2) -> true ; Span2=Span) |
| 735 | | ; Info=unknown, Span2=Span |
| 736 | | ), |
| 737 | | (add_new_event_in_error_scope(Warning, |
| 738 | | print_enum_warning(Trigger,TYPE,RANGE,RESTRICTED_RANGE,Span2,WF)) |
| 739 | | % may also throw(Warning) |
| 740 | | -> |
| 741 | | (preference(allow_enumeration_of_infinite_types,false) |
| 742 | | -> formatsilent('### VIRTUAL TIME-OUT generated because ENUMERATE_INFINITE_TYPES=false~n',[]), |
| 743 | | % print_pending_abort_error(WF), |
| 744 | | (silent_mode(on) -> true ; print_span_nl(Span2)), |
| 745 | | throw(Warning) |
| 746 | | ; Trigger = trigger_throw(Source) |
| 747 | | -> (silent_mode(on) -> true |
| 748 | | ; Source=b(identifier(ID),_,_) -> |
| 749 | | format('### VIRTUAL TIME-OUT generated for ~w ',[ID]), |
| 750 | | print_span_nl(Span2) |
| 751 | | ; format('### VIRTUAL TIME-OUT generated for ~w ',[Source]), |
| 752 | | print_span_nl(Span2) |
| 753 | | ), |
| 754 | | throw(Warning) |
| 755 | | ; true) |
| 756 | | ; true). |
| 757 | | |
| 758 | | %get_trigger_info(trigger_false(I),Info) :- get_trigger_info2(I,Info). % was non_critical ; no longer used |
| 759 | | get_trigger_info(trigger_true(I),Info) :- get_trigger_info2(I,Info). |
| 760 | | get_trigger_info(trigger_throw(I),Info) :- get_trigger_info2(I,Info). |
| 761 | | %get_trigger_info2(enum_wf_context(_,Info),Res) :- !,Res=Info. % no longer used; WF now passed |
| 762 | | get_trigger_info2(Info,Info). |
| 763 | | |
| 764 | | |
| 765 | | % TO DO: pass WF explicitly rather than extracting it from enumeration warning terms |
| 766 | | :- use_module(translate,[translate_span/2, translate_error_term/3]). |
| 767 | | print_pending_abort_error(WF) :- |
| 768 | | pending_abort_error(WF,Msg,ErrTerm,Span), |
| 769 | | !, % just print one error |
| 770 | | translate_span(Span,TSpan), |
| 771 | | translate_error_term(ErrTerm,Span,TT), |
| 772 | | (get_wait_flag_infos(WF,WFInfos), |
| 773 | | member(expect_explicit_value,WFInfos) |
| 774 | | -> ajoin(['Potential WD-Error: ',Msg],WDMsg), |
| 775 | | add_warning(eval_expr_command,WDMsg,TT,Span) |
| 776 | | ; format_with_colour(user_output,[bold],' (could be due to WD-Error ~w: ~w ~w)~n',[TSpan,Msg,TT])). |
| 777 | | print_pending_abort_error(_). |
| 778 | | |
| 779 | | % try and get get_pending_abort_error_for_trigger |
| 780 | | get_pending_abort_error_for_info(WF,Span,FullMsg,ErrTerm) :- |
| 781 | | pending_abort_error(WF,Msg,ErrTerm,Span), |
| 782 | | ajoin(['Enumeration warning occured, probably caused by WD-Error: ',Msg],FullMsg). |
| 783 | | |
| 784 | | :- use_module(translate,[print_span/1, print_span_nl/1]). |
| 785 | | % THROWING,OuterSpan added by add_new_event_in_error_scope |
| 786 | | print_enum_warning(_,_,_,_,_,_WF,THROWING,_) :- |
| 787 | | THROWING \= throwing, % maybe we should also be silent if THROWING=throwing; see test 1522 |
| 788 | | silent_mode(on), % we could also check: performance_monitoring_on, |
| 789 | | !. % do not print |
| 790 | | print_enum_warning(Trigger,_,_,_,_LocalSpan,WF,THROWING,OuterThrowSpan) :- |
| 791 | | will_throw_enum_warning(THROWING), |
| 792 | | debug_mode(off), |
| 793 | | !, % do not print detailed enumeration warning with reduced scopes; we print another message instead |
| 794 | | print_throwing_wf(THROWING,Trigger,OuterThrowSpan,WF). |
| 795 | | print_enum_warning(_,_,_,_,_,_WF,THROWING,_) :- THROWING \= throwing, |
| 796 | | inc_counter(non_critical_enum_warnings,Nr), Nr>50,!, % do not print anymore |
| 797 | | (Nr=51 -> write('### No longer printing non-critical enumeration warnings; limit exceeded.'),nl |
| 798 | | ; true). |
| 799 | | print_enum_warning(Trigger,TYPE,RANGE,RESTRICTED_RANGE,LocalSpan,WF,THROWING,OuterThrowSpan) :- |
| 800 | | write('### Unbounded enumeration of '), % error_manager:trace_if_user_wants_it, |
| 801 | | print_trigger_var(Trigger), |
| 802 | | format('~w : ~w ---> ~w ',[TYPE,RANGE,RESTRICTED_RANGE]), |
| 803 | | print_wf_context(WF), |
| 804 | | print_span(LocalSpan),nl, |
| 805 | | print_throwing_wf(THROWING,Trigger,OuterThrowSpan,WF). |
| 806 | | |
| 807 | | % just count number of enum warnings |
| 808 | | :- use_module(extension('counter/counter'), |
| 809 | | [counter_init/0, new_counter/1, inc_counter/2, reset_counter/1]). |
| 810 | | kernel_objects_startup :- % call once at startup to ensure all counters exist |
| 811 | | counter_init, |
| 812 | | new_counter(non_critical_enum_warnings). |
| 813 | | kernel_objects_reset :- reset_counter(non_critical_enum_warnings). |
| 814 | | |
| 815 | | :- use_module(probsrc(eventhandling),[register_event_listener/3]). |
| 816 | | :- register_event_listener(startup_prob,kernel_objects_startup, |
| 817 | | 'Initialise kernel_objects counters.'). |
| 818 | | :- register_event_listener(clear_specification,kernel_objects_reset, |
| 819 | | 'Reset kernel_objects counters.'). |
| 820 | | |
| 821 | | % ----------- |
| 822 | | |
| 823 | | will_throw_enum_warning(THROWING) :- |
| 824 | | (THROWING=throwing -> true ; preference(strict_raise_enum_warnings,true)). |
| 825 | | |
| 826 | | :- use_module(tools_printing,[format_with_colour/4]). |
| 827 | | print_throwing(THROWING,Span) :- print_throwing_wf(THROWING,unknown_info,Span,no_wf_available). |
| 828 | | print_throwing_wf(THROWING,TriggerInfo,ThrowSpan,WF) :- |
| 829 | | peel_trigger(TriggerInfo,Info), |
| 830 | | (preference(strict_raise_enum_warnings,true) |
| 831 | | -> (get_pending_abort_error_for_info(WF,Span,Msg,ErrTerm) |
| 832 | | -> add_error(strict_raise_enum_warnings,Msg,ErrTerm,Span) |
| 833 | | ; add_error(strict_raise_enum_warnings,'Enumeration warning occured','',ThrowSpan) |
| 834 | | ) |
| 835 | | ; true |
| 836 | | ), |
| 837 | | (THROWING=throwing -> |
| 838 | | (get_trigger_info_variable(Info,VarID) |
| 839 | | -> format_with_colour(user_output,[bold],'Generating VIRTUAL TIME-OUT for unbounded enumeration of ~w!~n',[VarID]) |
| 840 | | ; format_with_colour(user_output,[bold],'Generating VIRTUAL TIME-OUT for unbounded enumeration warning!~n',[]) |
| 841 | | ), |
| 842 | | print_pending_abort_error(WF), |
| 843 | | (get_wait_flags_context_msg(WF,Msg) % % get call stack or other context message from WF |
| 844 | | -> format_with_colour(user_output,[bold],' ~w~n',[Msg]) |
| 845 | | ; true), |
| 846 | | (extract_span_description(ThrowSpan,PosMsg) -> format_with_colour(user_output,[bold],' ~w~n',[PosMsg]) ; true) |
| 847 | | ; true). |
| 848 | | |
| 849 | | peel_trigger(trigger_true(Info),Info) :- !. |
| 850 | | peel_trigger(trigger_throw(Info),Info) :- !. |
| 851 | | peel_trigger(Info,Info). |
| 852 | | |
| 853 | | print_trigger_var(trigger_true(Info)) :- !, print_trigger_var_info(Info), write(' : '). |
| 854 | | print_trigger_var(trigger_throw(Info)) :- !, print_trigger_var_info(Info), write(' : (all_solutions) : '). |
| 855 | | %print_trigger_var(trigger_false(Info)) :- !, print_trigger_var_info(Info), print(' (not critical [unless failure]) : '). % no longer used |
| 856 | | print_trigger_var(X) :- write(' UNKNOWN TRIGGER: '), print(X), write(' : '). |
| 857 | | |
| 858 | | print_wf_context(WF) :- |
| 859 | | (get_wait_flags_context_msg(WF,Msg) |
| 860 | | -> format('~n### ~w~n ',[Msg]) %format(' : (~w)',[Msg]) |
| 861 | | ; true). |
| 862 | | :- use_module(translate,[print_bexpr/1]). |
| 863 | | print_trigger_var_info(b(E,T,I)) :- !, print_bexpr(b(E,T,I)), write(' '), print_span(I). |
| 864 | | print_trigger_var_info(VarID) :- print(VarID). |
| 865 | | |
| 866 | | % get variable name from trigger info field |
| 867 | | get_trigger_info_variable(b(identifier(ID),_,_),VarID) :- !, VarID=ID. |
| 868 | | get_trigger_info_variable(ID,VarID) :- atom(ID), VarID=ID. |
| 869 | | |
| 870 | | |
| 871 | | % generate a warning if a large range is enumerated |
| 872 | | gen_enum_warning_if_large(Var,FDLow,FDUp) :- |
| 873 | | (FDUp>FDLow+8388608 /* 2**23 ; {x|x:1..2**23 & x mod 2 = x mod 1001} takes about 2 minutes */ |
| 874 | | % however the domain itself could be very small, we also check clpfd_size instead |
| 875 | | -> fd_size(Var,Size), % no need to call clpfd_size; we know we are in CLP(FD) mode |
| 876 | | (Size =< 8388608 -> true |
| 877 | | ; enum_warning_large(Var,'INTEGER',FDLow:FDUp) |
| 878 | | ) |
| 879 | | ; true). |
| 880 | | enum_warning_large(_Var,TYPE,RANGE) :- |
| 881 | | Warning = enumeration_warning(enumerating,TYPE,RANGE,RANGE,non_critical), |
| 882 | | (add_new_event_in_error_scope(Warning,print_enum_warning_large(TYPE,RANGE)) |
| 883 | | -> true |
| 884 | | ; true). |
| 885 | | |
| 886 | | print_enum_warning_large(TYPE,RANGE,THROWING,Span) :- |
| 887 | | print('### Warning: enumerating large range '), |
| 888 | | print(TYPE), print(' : '), |
| 889 | | print(RANGE),nl, |
| 890 | | print_throwing(THROWING,Span). |
| 891 | | |
| 892 | | :- block finite_warning(-,?,?,?,?). |
| 893 | | finite_warning(_,Par,Types,Body,Source) :- |
| 894 | | add_new_event_in_error_scope(enumeration_warning(checking_finite_closure,Par,Types,finite,critical), |
| 895 | | print_finite_warning(Par,Types,Body,Source) ), |
| 896 | | fail. % WITH NEW SEMANTICS OF ENUMERATION WARNING WE SHOULD PROBABLY ALWAYS FAIL HERE ! |
| 897 | | print_finite_warning(Par,Types,Body,Source,THROWING,Span) :- |
| 898 | | print('### Warning: could not determine set comprehension to be finite: '), |
| 899 | | translate:print_bvalue(closure(Par,Types,Body)),nl, |
| 900 | | print('### Source: '), print(Source),nl, |
| 901 | | print_throwing(THROWING,Span). |
| 902 | | |
| 903 | | :- block enumerate_natural(-,?,-,?,?). |
| 904 | ? | enumerate_natural(N,From,_,Span,WF) :- nonvar(N) -> true ; enumerate_natural(N,From,Span,WF). |
| 905 | | enumerate_natural(N,From,Span,WF) :- preference(use_clpfd_solver,false),!, |
| 906 | | clpfd_off_domain(N,From,sup,NewLow,NewUp), % try narrow down domain using co-routines |
| 907 | | (finite_domain(NewLow,NewUp) -> enumerate_int1(N,NewLow,NewUp) |
| 908 | ? | ; force_enumerate_with_warning(N,NewLow,NewUp,'NATURAL(1)',trigger_true('NATURAL(1)'),Span,WF)). |
| 909 | | enumerate_natural(N,From,Span,WF) :- clpfd_domain(N,FDLow,FDUp), |
| 910 | | fd_max(FDLow,From,Low), |
| 911 | | (finite_domain(Low,FDUp) |
| 912 | | -> label(N,Low,FDUp) |
| 913 | ? | ; enumerate_natural_unbounded(N,Low,FDUp,Span,WF) |
| 914 | | ). |
| 915 | | enumerate_natural_unbounded(N,FDLow1,FDUp,Span,WF) :- |
| 916 | | (FDLow1=0 |
| 917 | | -> (N=0 ; /* do a case split */ |
| 918 | | try_post_constraint(N #>0), % this can sometimes make the domain finite |
| 919 | ? | force_enumerate_int_wo_case_split(N,'NATURAL',trigger_true('NATURAL'),Span,WF) |
| 920 | | ) |
| 921 | | ; force_enumerate_with_warning(N,FDLow1,FDUp,'NATURAL(1)',trigger_true('NATURAL(1)'),Span,WF) |
| 922 | | ). |
| 923 | | |
| 924 | | |
| 925 | | % assumes one of FDLow and FDUp is not a number |
| 926 | | make_domain_finite(FDLow,_FDUp,Min,Max) :- number(FDLow),!,Min=FDLow, |
| 927 | | preferences:preference(maxint,MaxInt), |
| 928 | | (MaxInt>=FDLow -> Max=MaxInt ; Max=FDLow). % ensure that we try at least one number |
| 929 | | make_domain_finite(_FDLow,FDUp,Min,Max) :- number(FDUp),!,Max=FDUp, |
| 930 | | preferences:preference(minint,MinInt), |
| 931 | | (MinInt=<FDUp -> Min=MinInt ; Min=FDUp). |
| 932 | | make_domain_finite(_FDLow,_FDUp,Min,Max) :- |
| 933 | | ((preferences:preference(maxint,Max), |
| 934 | | preferences:get_preference(minint,Min))->true). % ensure that we try at least one number |
| 935 | | |
| 936 | | enumerate_int1(N,Min,Max) :- |
| 937 | | (Min<0 /* enumerate positive numbers first; many specs only use NAT/NATURAL */ |
| 938 | ? | -> (enumerate_int2(N,0,Max) ; enumerate_int2(N,Min,-1)) |
| 939 | ? | ; enumerate_int2(N,Min,Max) |
| 940 | | ). |
| 941 | | enumerate_int(X,Low,Up) :- get_int_domain(X,Low,Up,RL,RU), |
| 942 | | %% print(enumerate_int(X,Low,Up, RL,RU)),nl, %% |
| 943 | ? | enumerate_int2(X,RL,RU). |
| 944 | | |
| 945 | | get_int_domain(X,Low,Up,RL,RU) :- clpfd_domain(X,FDLow,FDUp), |
| 946 | | fd_max(FDLow,Low,RL),fd_min(FDUp,Up,RU). |
| 947 | | |
| 948 | | finite_domain(Low,Up) :- \+ infinite_domain(Low,Up). |
| 949 | | infinite_domain(inf,_) :- !. |
| 950 | | infinite_domain(_,sup). |
| 951 | | |
| 952 | | % second arg should always be a number |
| 953 | | fd_max(inf,L,R) :- !,R=L. |
| 954 | | fd_max(FDX,Y,R) :- (nonvar(FDX),nonvar(Y),FDX>Y -> R=FDX ; R=Y). |
| 955 | | fd_min(sup,L,R) :- !,R=L. |
| 956 | | fd_min(FDX,Y,R) :- (nonvar(FDX),nonvar(Y),FDX<Y -> R=FDX ; R=Y). |
| 957 | | |
| 958 | | :- use_module(clpfd_interface,[clpfd_randomised_enum/3]). |
| 959 | | |
| 960 | | enumerate_int2(N,X,Y) :- % mainly called when CLPFD false |
| 961 | | (preferences:get_preference(randomise_enumeration_order,true) |
| 962 | ? | -> clpfd_randomised_enum(N,X,Y) ; enumerate_int2_linear(N,X,Y)). |
| 963 | | |
| 964 | | enumerate_int2_linear(N,X,Y) :- X=<Y, |
| 965 | ? | (N=X ; X1 is X+1, enumerate_int2_linear(N,X1,Y)). |
| 966 | | |
| 967 | | |
| 968 | | enumerate_basic_type_set(X,Type,Tight,EnumWarning,WF) :- var(X),!, |
| 969 | | max_cardinality_with_check(Type,Card), |
| 970 | ? | enumerate_basic_type_set2(X,[],Card,Type,none,Tight,EnumWarning,WF). |
| 971 | | enumerate_basic_type_set([],_,_,_EnumWarning,_WF) :- !. |
| 972 | | enumerate_basic_type_set(avl_set(_),_,_,_EnumWarning,_WF) :- !. |
| 973 | | enumerate_basic_type_set(freetype(_),_,_,_EnumWarning,_WF) :- !. |
| 974 | | enumerate_basic_type_set(global_set(GS),Type,_Tight,_EnumWarning,_WF) :- !, |
| 975 | | (Type = global(GT) |
| 976 | | -> (GS = GT -> true |
| 977 | | ; nonvar(GS), add_error_and_fail(enumerate_basic_type_set,'Type error in global set: ',GS:GT)) |
| 978 | | ; Type = integer,integer_global_set(GS) |
| 979 | | ; Type = string, string_global_set(GS) |
| 980 | | ; Type = real, real_global_set(GS) |
| 981 | | ). |
| 982 | | enumerate_basic_type_set(closure(Parameters, PT, Body),_Type,_Tight,_EnumWarning,WF) :- !, |
| 983 | | (ground(Body) -> true |
| 984 | | ; add_message_wf(kernel_objects,'Enumerating non-ground closure body: ',closure(Parameters, PT, Body),Body,WF), |
| 985 | | % this did happen for symbolic total function closures set up for f : NATURAL1 --> ..., see test 2022 |
| 986 | | %term_variables(Body,Vars), print('### Variables: '), print(Vars),nl, |
| 987 | | enumerate_values_inside_expression(Body,WF) |
| 988 | | ). |
| 989 | | enumerate_basic_type_set([H|T],Type,Tight,EnumWarning,WF) :- !, |
| 990 | | % collect bound elements; avoid enumerating initial elements with elements that already appear later |
| 991 | | collect_bound_elements([H|T], SoFar,Unbound,Closed), |
| 992 | | (Closed=false -> max_cardinality_with_check(Type,Card) |
| 993 | | ; Card = Closed), |
| 994 | | % print(enum(Card,Unbound,SoFar,[H|T],Closed)),nl, |
| 995 | ? | enumerate_basic_type_set2(Unbound,SoFar,Card,Type,none,Tight,EnumWarning,WF). |
| 996 | | %enumerate_basic_type_set([H|T],Type,Tight,WF) :- !, |
| 997 | | % (is_list_skeleton([H|T],Card) -> true |
| 998 | | % ; max_cardinality_with_check(Type,Card) |
| 999 | | % ), |
| 1000 | | % enumerate_basic_type_set2([H|T],[],Card,Type,none,Tight,WF). |
| 1001 | | enumerate_basic_type_set(S,Type,Tight,EnumWarning,WF) :- |
| 1002 | | add_internal_error('Illegal set: ',enumerate_basic_type_set(S,Type,Tight,EnumWarning,WF)). |
| 1003 | | |
| 1004 | | enumerate_basic_type_set2(HT,ElementsSoFar,_Card,_Type,_Last,_Tight,_EnumWarning,_WF) :- nonvar(HT), |
| 1005 | | is_custom_explicit_set(HT,enumerate_basic_type),!, |
| 1006 | | disjoint_sets(HT,ElementsSoFar). % I am not sure this is necessary; probably other constraints already ensure this holds |
| 1007 | | enumerate_basic_type_set2(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning,WF) :- var(HT), |
| 1008 | | preferences:preference(randomise_enumeration_order,true),!, |
| 1009 | | (random(1,3,1) |
| 1010 | | -> (enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning,WF) |
| 1011 | | ; HT = []) |
| 1012 | | ; (HT = [] ; |
| 1013 | | enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning,WF)) |
| 1014 | | ). |
| 1015 | | enumerate_basic_type_set2([],_,_,_,_,_Tight,_EnumWarning,_WF). |
| 1016 | | enumerate_basic_type_set2(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning,WF) :- |
| 1017 | ? | enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning,WF). |
| 1018 | | |
| 1019 | | enumerate_basic_type_set_cons(HT,ElementsSoFar,Card,Type,Last,Tight,EnumWarning,WF) :- positive_card(Card), |
| 1020 | | %debug:trace_point(enum(HT,ElementsSoFar,Card,Type,Last,Tight)), |
| 1021 | | (var(HT) -> HT=[H|T], NewLast=NormH /* the enumerator has completely determined H */ |
| 1022 | | % Note: HT=[H|T] may wake up co-routines and then attach infos to H; but these should hold indpendently for all elements |
| 1023 | | ; HT=[H|T], |
| 1024 | | (unbound_value(H) |
| 1025 | | -> NewLast=NormH /* the enumerator has completely determined H */ |
| 1026 | | ; NewLast=Last) /* H was not freely chosen by the enumerator */ |
| 1027 | | ), |
| 1028 | ? | not_element_of(H,ElementsSoFar), % this is only needed for elements generated by the enumerator itself |
| 1029 | | % if we pass WF to not_element_of then test 479 fails due to different enumeration order |
| 1030 | ? | enumerate_type_wf(H,Type,Tight,EnumWarning,WF), |
| 1031 | | % TO DO: extract normal form from add_new_element |
| 1032 | | % Note: if H is_wd_guarded_result_variable then H may not be ground !! |
| 1033 | | (ground_value(H) |
| 1034 | | -> val_greater_than(H,NormH,Last), |
| 1035 | | add_new_element(NormH,ElementsSoFar,SoFar2) % TODO : use add_new_element_wf ? |
| 1036 | | ; add_new_element(H,ElementsSoFar,SoFar2), |
| 1037 | | NormH=none |
| 1038 | | ), |
| 1039 | | C1 is Card-1, |
| 1040 | ? | enumerate_basic_type_set2(T,SoFar2,C1,Type,NewLast,Tight,EnumWarning,WF). |
| 1041 | | |
| 1042 | | :- assert_must_succeed((collect_bound_elements([int(1),int(2),int(4),X,int(5)|T],_,U,C),U==[X|T],C==false)). |
| 1043 | | :- assert_must_succeed((collect_bound_elements([int(1),int(2),int(4),X,int(5)],_,U,C),U==[X],C==1)). |
| 1044 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(collect_bound_elements([int(1),int(2),int(4),int(5)],_,_,_))). |
| 1045 | | |
| 1046 | | % collect the bound and unbound elements in a list; also return if the list is closed (then return length) or return false |
| 1047 | | collect_bound_elements(T, SoFar,Unbound,Closed) :- var(T),!, SoFar=[],Unbound=T,Closed=false. |
| 1048 | | collect_bound_elements([],[],[],0). |
| 1049 | | collect_bound_elements(avl_set(A),avl_set(A),[],0). |
| 1050 | | collect_bound_elements(global_set(GS),SoFar,Unbound,Closed) :- expand_custom_set(global_set(GS),ES), |
| 1051 | | collect_bound_elements(ES,SoFar,Unbound,Closed). |
| 1052 | | collect_bound_elements(freetype(FS),SoFar,Unbound,Closed) :- expand_custom_set(freetype(FS),ES), |
| 1053 | | collect_bound_elements(ES,SoFar,Unbound,Closed). |
| 1054 | | collect_bound_elements(closure(P,T,B),SoFar,Unbound,Closed) :- expand_custom_set(closure(P,T,B),ES), |
| 1055 | | collect_bound_elements(ES,SoFar,Unbound,Closed). |
| 1056 | | collect_bound_elements([H|T],SoFar,Unbound,Closed) :- |
| 1057 | | collect_bound_elements(T,TSoFar,TUnbound,TClosed), |
| 1058 | | (ground(H) -> add_new_element(H,TSoFar,SoFar), Unbound=TUnbound, TClosed=Closed |
| 1059 | | ; SoFar = TSoFar, Unbound = [H|TUnbound], |
| 1060 | | (TClosed=false -> Closed=false ; Closed is TClosed+1) |
| 1061 | | ). |
| 1062 | | |
| 1063 | | |
| 1064 | | % perform order checking on terms, normalising them first |
| 1065 | | % val_greater_than(A,NormA,NormB) |
| 1066 | | val_greater_than(A,NormA,NormB) :- !, |
| 1067 | | (nonvar(A),custom_explicit_sets:convert_to_avl_inside_set(A,NormA) |
| 1068 | | -> (NormB==none -> true ; NormA @> NormB) |
| 1069 | | ; add_internal_error('Call failed: ',custom_explicit_sets:convert_to_avl_inside_set(A,NormA)), |
| 1070 | | NormA = A). |
| 1071 | | |
| 1072 | | positive_card(inf) :- !, print('$'). |
| 1073 | | positive_card(C) :- (integer(C) -> C>0 |
| 1074 | | ; add_internal_error('Not an integer: ',positive_card(C)),fail). |
| 1075 | | |
| 1076 | | |
| 1077 | | |
| 1078 | | :- block enumerate_basic_field_types(?,-,?,-,?). |
| 1079 | | enumerate_basic_field_types([],[],_Tight,_EnumWarning,_). |
| 1080 | | enumerate_basic_field_types(Fields,[field(Name,VT)|TT],Tight,EnumWarning,WF) :- |
| 1081 | ? | enumerate_basic_field_types2(Fields,Name,VT,TT,Tight,EnumWarning,WF). |
| 1082 | | |
| 1083 | | :- block enumerate_basic_field_types2(?,-,?,?,?,?,?). |
| 1084 | | enumerate_basic_field_types2([field(Name1,V)|T], Name2,VT,TT,Tight,EnumWarning,WF) :- |
| 1085 | | check_field_name_compatibility(Name1,Name2,enumerate_basic_field_types2), |
| 1086 | ? | enumerate_type_wf(V,VT,Tight,EnumWarning,WF), |
| 1087 | ? | enumerate_basic_field_types(T,TT,Tight,EnumWarning,WF). |
| 1088 | | |
| 1089 | | |
| 1090 | | :- block all_objects_of_type(-,?). |
| 1091 | | all_objects_of_type(Type,Res) :- |
| 1092 | | findall(O,enumerate_basic_type(O,Type),Res). |
| 1093 | | |
| 1094 | | :- use_module(library(avl),[avl_size/2]). |
| 1095 | | :- use_module(kernel_cardinality_attr,[clpfd_card_domain_for_var/3]). |
| 1096 | | % obtain info for enumerating sequence lists: length of list skeleton and maximum index inferred to be in the list |
| 1097 | | % (MaxIndex is not the maximum index that can appear in the full sequence !) |
| 1098 | | list_length_info(X,LenSoFar,Len,Type,MaxIndex) :- var(X),!,Len=0, |
| 1099 | | clpfd_card_domain_for_var(X,MinCard,MaxCard), |
| 1100 | | ( number(MinCard) |
| 1101 | | -> MaxIndex is MinCard+LenSoFar % we know a valid list must be at least LenSoFar+MinCard long |
| 1102 | | ; MaxIndex=0), |
| 1103 | | ( number(MaxCard) -> Max1 is MaxCard+Len, Type = open_bounded(Max1) ; Type = open). |
| 1104 | | list_length_info([],_,0,closed,0). |
| 1105 | | list_length_info([H|T],LenSoFar,C1,Type,MaxIndex1) :- Len1 is LenSoFar+1, |
| 1106 | | list_length_info(T,Len1,C,Type,MaxIndex), |
| 1107 | | C1 is C+1, |
| 1108 | | (nonvar(H),H=(I,_),nonvar(I),I=int(Idx),number(Idx),Idx>MaxIndex |
| 1109 | | -> MaxIndex1 = Idx ; MaxIndex1 = MaxIndex). |
| 1110 | | list_length_info(avl_set(A),LenSoFar,Size,closed,0) :- % case arises e.g. in private_examples/ClearSy/2019_Dec/well_def |
| 1111 | | (LenSoFar=0 -> Size=1000000 % then length not used anyway |
| 1112 | | ; avl_size(A,Size)). % we could check that this is a sequence tail! |
| 1113 | | list_length_info(closure(_,_,_),_,0,open,0). |
| 1114 | | |
| 1115 | | :- assert_must_succeed((max_cardinality(set(couple(global('Name'),global('Code'))),64))). |
| 1116 | | :- assert_must_succeed((max_cardinality(set(set(set(couple(global('Name'),global('Code'))))),_))). |
| 1117 | | :- assert_must_succeed((kernel_freetypes:add_freetype(selfc4,[case(a,boolean),case(b,couple(boolean,boolean))]), |
| 1118 | | max_cardinality(freetype(selfc4),6), |
| 1119 | | kernel_freetypes:reset_freetypes)). |
| 1120 | | :- assert_must_succeed((kernel_freetypes:add_freetype(selfc6,[case(a,boolean),case(b,freetype(selfc6)),case(c,constant([c]))]), |
| 1121 | | kernel_freetypes:set_freetype_depth(3), |
| 1122 | | findall(X,enumerate_tight_type(X,freetype(selfc6)),Solutions), |
| 1123 | | length(Solutions,NumberOfSolutions), |
| 1124 | | max_cardinality(freetype(selfc6),NumberOfSolutions), |
| 1125 | | kernel_freetypes:reset_freetypes)). |
| 1126 | | |
| 1127 | | :- use_module(tools_printing,[print_error/1]). |
| 1128 | | max_cardinality_with_check(Set,CCard) :- |
| 1129 | ? | (max_cardinality(Set,Card) -> |
| 1130 | | (is_inf_or_overflow_card(Card) |
| 1131 | | -> debug_println(9,very_large_cardinality(Set,Card)), |
| 1132 | | CCard = 20000000 |
| 1133 | | ; CCard=Card, |
| 1134 | | (Card>100 -> debug_println(9,large_cardinality(Set,Card)) ; true) |
| 1135 | | ) |
| 1136 | | ; print_error(failed(max_cardinality(Set,CCard))), CCard = 10 |
| 1137 | | ). |
| 1138 | | max_cardinality(global(T),Card) :- b_global_set_cardinality(T,Card). |
| 1139 | | max_cardinality(boolean,2). |
| 1140 | | max_cardinality(constant([_V]),1). |
| 1141 | | max_cardinality(any,inf). % :- print_message(dont_know_card_of_any). /* TODO: what should we do here ? */ |
| 1142 | | max_cardinality(string,MC) :- max_cardinality_string(MC). % is inf now |
| 1143 | | %max_cardinality(abort,1). |
| 1144 | | max_cardinality(integer,Card) :- Card=inf. %b_global_set_cardinality('INTEGER',Card). |
| 1145 | | max_cardinality(real,Card) :- Card=inf. |
| 1146 | | max_cardinality(seq(X),Card) :- % Card=inf, unless a freetype can be of cardinality 0 |
| 1147 | | max_cardinality(set(couple(integer,X)),Card). |
| 1148 | | max_cardinality(couple(X,Y),Card) :- |
| 1149 | ? | max_cardinality(X,CX), max_cardinality(Y,CY), safe_mul(CX,CY,Card). |
| 1150 | | max_cardinality(record([]),1). |
| 1151 | | max_cardinality(record([field(_,T1)|RF]),Card) :- |
| 1152 | ? | max_cardinality(record(RF),RC), |
| 1153 | | max_cardinality(T1,C1), |
| 1154 | | safe_mul(C1,RC,Card). |
| 1155 | ? | max_cardinality(set(X),Card) :- max_cardinality(X,CX), |
| 1156 | | safe_pow2(CX,Card). |
| 1157 | | max_cardinality(freetype(Id),Card) :- max_cardinality_freetype(freetype(Id),Card). |
| 1158 | | max_cardinality(freetype_lim_depth(Id,Depth),Card) :- max_cardinality_freetype(freetype_lim_depth(Id,Depth),Card). |
| 1159 | | |
| 1160 | | |
| 1161 | | |
| 1162 | | /* ---------------------------- */ |
| 1163 | | |
| 1164 | | |
| 1165 | | /* use a cleverer, better enumeration than enumerate_basic_type */ |
| 1166 | | /* can only be used in certain circumstances: operation preconditions, |
| 1167 | | properties,... but not for VARIABLES as there is no guarantee that |
| 1168 | | something declared as a sequence will actually turn out to be a sequence */ |
| 1169 | | |
| 1170 | | :- assert_pre(kernel_objects:enumerate_tight_type(Obj,Type), |
| 1171 | | (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))). |
| 1172 | | :- assert_post(kernel_objects:enumerate_tight_type(Obj,_), (type_check(Obj,bsets_object),ground_check(Obj))). |
| 1173 | | :- assert_pre(kernel_objects:enumerate_tight_type(Obj,Type,_), |
| 1174 | | (type_check(Obj,bsets_object),type_check(Type,basic_type_descriptor))). |
| 1175 | | :- assert_post(kernel_objects:enumerate_tight_type(Obj,_,_), (type_check(Obj,bsets_object),ground_check(Obj))). |
| 1176 | | |
| 1177 | | :- assert_must_succeed(enumerate_tight_type([(int(1),int(2)),(int(2),int(4))], |
| 1178 | | seq(integer) )). |
| 1179 | | :- assert_must_succeed(enumerate_tight_type([(int(1),int(2))],seq(integer) )). |
| 1180 | | :- assert_must_succeed(enumerate_tight_type([],seq(integer) )). |
| 1181 | | :- assert_must_succeed((enumerate_tight_type(X,record([field(a,integer),field(b,global('Name'))])), |
| 1182 | | equal_object(X,rec([field(a,int(1)),field(b,fd(1,'Name'))])) )). |
| 1183 | | :- assert_must_fail(enumerate_tight_type([(int(1),int(2)),(int(3),int(_))], |
| 1184 | | seq(integer) )). |
| 1185 | | :- assert_must_fail(enumerate_tight_type([(int(3),int(_))],seq(integer) )). |
| 1186 | | :- assert_must_succeed((bsets_clp:is_sequence(X,global_set('Name')), |
| 1187 | | enumerate_tight_type(X,seq(global('Name')) ), |
| 1188 | | X = [(int(1),fd(2,'Name'))] )). |
| 1189 | | :- assert_must_succeed(( enumerate_tight_type(XX, record([field(balance,integer),field(name,global('Name'))])) , |
| 1190 | | XX = rec([field(balance,int(1)),field(name,fd(3,'Name'))]) )). |
| 1191 | | :- assert_must_succeed(( enumerate_tight_type(XX, set(record([field(balance,global('Name')),field(name,global('Name'))]))) , /* STILL TAKES VERY LONG !! */ |
| 1192 | | XX = [rec([field(balance,fd(3,'Name')),field(name,fd(3,'Name'))])] )). |
| 1193 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(balance,global('Name')),field(name,global('Name'))]))) ,S), |
| 1194 | | length(S,Len), Len = 512 )). |
| 1195 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(name,global('Code'))]))) ,S), |
| 1196 | | length(S,Len), Len = 4 )). |
| 1197 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(fname,global('Code')),field(name,global('Code'))]))) ,S), |
| 1198 | | length(S,Len), Len = 16 )). |
| 1199 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(record([field(fname,global('Code')),field(name,global('Name'))]))) ,S), |
| 1200 | | length(S,Len), Len = 64 )). |
| 1201 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(global('Name'))) ,S), |
| 1202 | | length(S,Len), Len = 8 )). |
| 1203 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(boolean))) ,S), |
| 1204 | | length(S,Len), Len = 16 )). |
| 1205 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(global('Name')))) ,S), |
| 1206 | | length(S,Len), Len = 256 )). |
| 1207 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(global('Code')))) ,S), |
| 1208 | | length(S,Len), Len = 16 )). |
| 1209 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(set(boolean))) ,S), |
| 1210 | | length(S,Len), Len = 16 )). |
| 1211 | | :- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(couple(global('Code'),global('Name')))) ,S), |
| 1212 | | length(S,Len), Len = 64 )). |
| 1213 | | %:- assert_must_succeed(( findall(XX,enumerate_tight_type(XX, set(couple(global('Code'),integer))) ,S), |
| 1214 | | % length(S,Len), Len = 64 )). |
| 1215 | | :- assert_must_succeed(( enumerate_tight_type(XX, set(record([field(balance,integer)]))) , |
| 1216 | | XX = [rec([field(balance,int(1))])] )). |
| 1217 | | :- assert_must_succeed(( enumerate_tight_type(global_set('Code'),set(global('Code'))) )). |
| 1218 | | |
| 1219 | | enumerate_tight_type(Obj,Type) :- |
| 1220 | ? | enumerate_tight_type_wf(Obj,Type,no_wf_available). |
| 1221 | | |
| 1222 | | enumerate_tight_type_wf(Obj,Type,WF) :- |
| 1223 | ? | enumerate_tight_type_wf(Obj,Type,trigger_true(enumerate_tight_type),WF). |
| 1224 | | |
| 1225 | | enumerate_tight_type(Obj,Type,EnumWarning) :- %enumerate_tight_type2(Type,Obj). |
| 1226 | | enumerate_tight_type_wf(Obj,Type,EnumWarning,no_wf_available). |
| 1227 | | |
| 1228 | | :- block enumerate_tight_type_wf(?,-,?,?), enumerate_tight_type_wf(?,?,-,?). |
| 1229 | | enumerate_tight_type_wf(Obj,Type,EnumWarning,WF) :- %enumerate_tight_type2(Type,Obj). |
| 1230 | | (ground_value(Obj) -> true ; % print(enumerate_tight_type(Obj,Type)),nl, |
| 1231 | ? | enumerate_basic_type4(Type,Obj,tight,EnumWarning,WF) |
| 1232 | | ). |
| 1233 | | |
| 1234 | | /* TO DO: provide tight enumerators for nat, functions, ... ?? */ |
| 1235 | | |
| 1236 | | |
| 1237 | | |
| 1238 | | :- assert_must_succeed((X=[(int(I1),pred_true /* bool_true */),Y], dif(I1,1), |
| 1239 | | kernel_objects:enumerate_seq_type(X,boolean,true),I1==2,Y=(int(1),pred_false /* bool_false */))). |
| 1240 | | |
| 1241 | ? | enumerate_seq_type(X,Type,EnumWarning) :- enumerate_seq_type_wf(X,Type,EnumWarning,no_wf_available). |
| 1242 | | |
| 1243 | | enumerate_seq_type_wf(X,Type,EnumWarning,WF) :- |
| 1244 | | list_length_info(X,0,Len,ListType,MaxIndex), % ListType can be open or closed |
| 1245 | | % determine MaxIndexForEnum: |
| 1246 | | (ListType=closed |
| 1247 | | -> MaxIndexForEnum=Len, EW = no_enum_warning, |
| 1248 | | MaxIndex =< Len % otherwise this is obviously not a sequence (Index in set which is larger than size) |
| 1249 | | ; ListType=open_bounded(MaxSize) |
| 1250 | | -> MaxIndexForEnum=MaxSize, EW = no_enum_warning, |
| 1251 | | MaxIndex =< MaxSize % otherwise cannot be a sequence |
| 1252 | | % TO DO: use MinSize? |
| 1253 | | ; (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 |
| 1254 | | b_global_set_cardinality('NAT1',NatCard), |
| 1255 | | (NatCard<Card -> Max1=Card ; Max1=NatCard), |
| 1256 | | (Max1<1 -> MaxIndexForEnum = 1 ; MaxIndexForEnum=Max1), % ensure that we generate enumeration warning |
| 1257 | | EW = EnumWarning |
| 1258 | | ), |
| 1259 | ? | enumerate_seq(X,range(1,MaxIndexForEnum),MaxIndexForEnum,Type,EW,WF). |
| 1260 | | |
| 1261 | | enumerate_seq([],_,_,_,_,_WF). |
| 1262 | | enumerate_seq(V,_,_,_,_,_WF) :- nonvar(V),V=avl_set(_),!. |
| 1263 | | enumerate_seq(V,_,_,Type,EnumWarning,WF) :- nonvar(V),V=closure(_,_,_),!, |
| 1264 | | enumerate_basic_type_set(V,Type,not_tight,EnumWarning,WF). |
| 1265 | | enumerate_seq(Seq,_,_,_,_,_WF) :- nonvar(Seq), |
| 1266 | | is_custom_explicit_set(Seq,enumerate_seq),!. |
| 1267 | | enumerate_seq(Seq,Indexes,Card,Type,EnumWarning,WF) :- |
| 1268 | | (unbound_variable_for_cons(Seq) |
| 1269 | | -> positive_card(Card), |
| 1270 | | get_next_index(Indexes,Index,RemIndexes), % force next index |
| 1271 | | Seq = [(int(Index),Element)|TSeq], VarEl=true |
| 1272 | | ; Seq = [El|TSeq], |
| 1273 | | (unbound_variable(El) |
| 1274 | | -> VarEl=true, get_next_index(Indexes,Index,RemIndexes) % force next index |
| 1275 | | ; VarEl=false), |
| 1276 | | El = (int(Index),Element) |
| 1277 | | ), |
| 1278 | | (VarEl=true |
| 1279 | | -> true % index already forced above |
| 1280 | | ; 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 |
| 1281 | ? | ; remove_index(Indexes,Index,RemIndexes) |
| 1282 | | ), |
| 1283 | | (EnumWarning==no_enum_warning -> true |
| 1284 | | ; gen_enum_warning_wf('seq (length)',inf,Card,EnumWarning,unknown,WF)), % delay enum_warning until we have made the first case-split (sometimes instantiating the sequence to at least one element will trigger an inconsistency) |
| 1285 | ? | enumerate_tight_type_wf(Element,Type,WF), |
| 1286 | | C1 is Card-1, |
| 1287 | ? | enumerate_seq(TSeq,RemIndexes,C1,Type,no_enum_warning,WF). |
| 1288 | | |
| 1289 | | get_next_index([Index1|RestIndexes],Index1,RestIndexes). |
| 1290 | | get_next_index(range(I1,I2),I1,Res) :- |
| 1291 | | I11 is I1+1, |
| 1292 | | (I11>I2 -> Res=[] ; Res=range(I11,I2)). |
| 1293 | | |
| 1294 | | remove_index_ground(Indexes,X,Res) :- get_next_index(Indexes,H,T), |
| 1295 | | (X=H -> Res=T ; Res=[H|R2], remove_index_ground(T,X,R2)). |
| 1296 | | |
| 1297 | | remove_index(Indexes,X,Res) :- get_next_index(Indexes,H,T), |
| 1298 | ? | (X=H,Res=T ; X\==H, Res=[H|R2], remove_index(T,X,R2)). |
| 1299 | | |
| 1300 | | |
| 1301 | | |
| 1302 | | /* a few more unit tests: */ |
| 1303 | | |
| 1304 | | :- assert_must_succeed(( findall(X,enumerate_type(X,set(couple(boolean,boolean)),tight) ,L), length(L,16) )). |
| 1305 | | :- assert_must_succeed(( findall(X,enumerate_type(X,set(couple(boolean,boolean)),basic) ,L), length(L,16) )). |
| 1306 | | |
| 1307 | | :- assert_must_succeed(( enumerate_tight_type( |
| 1308 | | [rec([field(balance,int(0)),field(name,fd(2,'Name'))])],[ |
| 1309 | | rec([field(balance,int(1)),field(name,fd(3,'Name'))]), |
| 1310 | | rec([field(balance,int(1)),field(name,fd(2,'Name'))]), |
| 1311 | | rec([field(balance,int(0)),field(name,fd(1,'Name'))]), |
| 1312 | | rec([field(balance,int(-1)),field(name,fd(1,'Name'))])], |
| 1313 | | set(record([field(balance,integer),field(name,global('Name'))]))) )). |
| 1314 | | :- assert_must_succeed(( enumerate_tight_type([ |
| 1315 | | rec([field(balance,int(1)),field(name,fd(2,'Name'))]), |
| 1316 | | rec([field(balance,int(1)),field(name,fd(1,'Name'))]), |
| 1317 | | rec([field(balance,int(0)),field(name,fd(1,'Name'))]), |
| 1318 | | rec([field(balance,int(-1)),field(name,fd(1,'Name'))])|X], |
| 1319 | | set(record([field(balance,integer),field(name,global('Name'))]))) , |
| 1320 | | X = [rec([field(balance,int(1)),field(name,fd(3,'Name'))])] )). |
| 1321 | | |
| 1322 | | :- assert_must_succeed((not_element_of(X,[(pred_true /* bool_true */,pred_true /* bool_true */), |
| 1323 | | (pred_true /* bool_true */,pred_false /* bool_false */),(pred_false /* bool_false */,pred_false /* bool_false */)]), |
| 1324 | | enumerate_tight_type(X,couple(boolean,boolean)))). |
| 1325 | | |
| 1326 | | :- assert_must_succeed(( not_equal_object(X,(pred_true /* bool_true */,pred_false /* bool_false */)), |
| 1327 | | not_equal_object(X,(pred_false /* bool_false */,pred_false /* bool_false */)), |
| 1328 | | not_equal_object(X,(pred_true /* bool_true */,pred_true /* bool_true */)), |
| 1329 | | enumerate_tight_type(X,couple(boolean,boolean)))). |
| 1330 | | |
| 1331 | | :- assert_must_succeed(( X = [fd(3,'Name')|T],enumerate_tight_type(X,set(global('Name'))), |
| 1332 | | T == [fd(1,'Name'),fd(2,'Name')] )). |
| 1333 | | |
| 1334 | | |
| 1335 | | |
| 1336 | | unbound_value(V) :- |
| 1337 | | (var(V) -> unbound_variable(V) |
| 1338 | | ; V = (V1,W1),unbound_value(V1), unbound_value(W1)). |
| 1339 | | |
| 1340 | | :- use_module(bsyntaxtree,[syntaxtraversion/6]). |
| 1341 | | enumerate_values_inside_expression(TExpr,WF) :- |
| 1342 | | syntaxtraversion(TExpr,Expr,Type,_Infos,Subs,_), |
| 1343 | | nonvar(Expr),!, |
| 1344 | | enumerate_expr(Expr,Type,Subs,WF). |
| 1345 | | enumerate_values_inside_expression(X,WF) :- |
| 1346 | | add_internal_error('Unexpected B expression: ',enumerate_values_inside_expression(X,WF)). |
| 1347 | | |
| 1348 | | %:- block enumerate_expr(-,?,?,?). |
| 1349 | | enumerate_expr(value(X),Type,Subs,WF) :- !, |
| 1350 | | (ground(Type) -> enumerate_value(X,Type,WF) |
| 1351 | | ; add_internal_error('Value type not ground: ',enumerate_expr(value(X),Type,Subs,WF))). |
| 1352 | | enumerate_expr(_,_,Subs,WF) :- l_enumerate_values_inside_expression(Subs,WF). |
| 1353 | | |
| 1354 | | :- use_module(bsyntaxtree,[is_set_type/2]). |
| 1355 | | % catch a few type errors: |
| 1356 | | enumerate_value(X,Type,_) :- X==[], !, |
| 1357 | | (is_set_type(Type,_) -> true ; add_internal_error('Illegal type: ',enumerate_value(X,Type,_))). |
| 1358 | | enumerate_value(X,Type,WF) :- enumerate_basic_type_wf(X,Type,WF). |
| 1359 | | |
| 1360 | | :- block l_enumerate_values_inside_expression(-,?). |
| 1361 | | l_enumerate_values_inside_expression([],_WF). |
| 1362 | | l_enumerate_values_inside_expression([H|T],WF) :- |
| 1363 | | enumerate_values_inside_expression(H,WF), |
| 1364 | | l_enumerate_values_inside_expression(T,WF). |
| 1365 | | |
| 1366 | | |
| 1367 | | /* --------------- */ |
| 1368 | | /* top_level_dif/2 */ |
| 1369 | | /* --------------- */ |
| 1370 | | /* checks whether two terms have a different top-level functor */ |
| 1371 | | |
| 1372 | | :- assert_must_succeed(top_level_dif(a,b)). |
| 1373 | | :- assert_must_succeed(top_level_dif(f(_X),g(_Z))). |
| 1374 | | :- assert_must_fail(top_level_dif(f(a),f(_Z))). |
| 1375 | | :- assert_must_fail(top_level_dif(f(a),f(b))). |
| 1376 | | |
| 1377 | | :- block top_level_dif(-,?),top_level_dif(?,-). |
| 1378 | | top_level_dif(X,Y) :- |
| 1379 | | functor(X,FX,_),functor(Y,FY,_), FX\=FY. /* check arities ? */ |
| 1380 | | |
| 1381 | | |
| 1382 | | /* ------------------------------------------------------------------- */ |
| 1383 | | /* EQUAL OBJECT */ |
| 1384 | | /* ------------------------------------------------------------------- */ |
| 1385 | | |
| 1386 | | sample_closure(C) :- |
| 1387 | | construct_closure([xx],[integer],Body,C), |
| 1388 | | Body = b(conjunct(b(conjunct( |
| 1389 | | b(member(b(identifier(xx),integer,[]),b(integer_set('NAT'),set(identifier(xx)),[])),pred,[]), |
| 1390 | | b(greater(b(identifier(xx),integer,[]),b(integer(0),integer,[])),pred,[])),pred,[]), |
| 1391 | | b(less(b(identifier(xx),integer,[]),b(integer(3),integer,[])),pred,[])),pred,[]). |
| 1392 | | |
| 1393 | | :- assert_must_succeed(equal_object([int(3),int(1)], |
| 1394 | | closure([zz],[integer],b(member(b(identifier(zz),integer,[]),b(value([int(1),int(3)]),set(integer),[])),pred,[])))). |
| 1395 | | :- assert_must_succeed(( equal_object( (fd(1,'Name'),fd(1,'Name')) , (fd(1,'Name'),fd(1,'Name')) ) )). |
| 1396 | | :- assert_must_succeed(( equal_object( (X,Y) , (fd(2,'Name'),fd(2,'Name')) ) , X = fd(2,'Name'), Y=fd(2,'Name') )). |
| 1397 | | :- assert_must_fail(equal_object(term(a),term(b))). |
| 1398 | | :- assert_must_fail(equal_object(int(1),int(2))). |
| 1399 | | :- assert_must_fail(equal_object([term(a),term(b)],[term(a),term(c)])). |
| 1400 | | :- assert_must_fail((equal_object([(int(1),[Y])],[(int(X),[Z])]), |
| 1401 | | Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[int(2)])). |
| 1402 | | :- assert_must_fail(equal_object(rec([field(a,int(1))]),rec([field(a,int(2))]))). |
| 1403 | | :- assert_must_fail(equal_object(rec([field(a,int(2)),field(b,int(3))]), |
| 1404 | | rec([field(a,int(2)),field(b,int(4))]))). |
| 1405 | | :- assert_must_succeed(equal_object(rec([field(a,int(2))]),rec([field(a,int(2))]))). |
| 1406 | | :- assert_must_succeed(equal_object(rec([field(a,int(2)),field(b,[int(3),int(2)])]), |
| 1407 | | rec([field(a,int(2)),field(b,[int(2),int(3)])]) )). |
| 1408 | | :- assert_must_succeed(equal_object([(term(a),[])],[(term(a),[])])). |
| 1409 | | :- assert_must_succeed(equal_object(_X,[int(1),int(2)])). |
| 1410 | | :- assert_must_succeed(equal_object([int(1),int(2)],_X)). |
| 1411 | | :- assert_must_succeed((equal_object([(int(1),[Y])],[(int(X),[Z])]), |
| 1412 | | Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[])). |
| 1413 | | :- assert_must_succeed(equal_object([int(1),int(2)],[int(2),int(1)])). |
| 1414 | | :- assert_must_succeed(equal_object(global_set('Name'),[fd(2,'Name'),fd(3,'Name'),fd(1,'Name')])). |
| 1415 | | :- assert_must_succeed(equal_object(global_set('Name'),[fd(1,'Name'),fd(3,'Name'),fd(2,'Name')])). |
| 1416 | | :- assert_must_succeed((equal_object([fd(3,'Name'),fd(2,'Name'),fd(1,'Name')],global_set('Name')))). |
| 1417 | | %:- assert_must_succeed((equal_object([fd(3,'Name'),fd(2,'Name'),fd(1,'Name')],X),X=global_set('Name'))). |
| 1418 | | :- assert_must_succeed((equal_object(Y,X),X=global_set('Name'),equal_object(Y,[fd(3,'Name'),fd(2,'Name'),fd(1,'Name')]))). |
| 1419 | | :- assert_must_succeed((equal_object(X,X),X=global_set('Name'))). |
| 1420 | | :- assert_must_succeed((equal_object(_,X),X=global_set('Name'))). |
| 1421 | | :- assert_must_succeed((equal_object(X,global_set('Name')),X=global_set('Name'))). |
| 1422 | | :- assert_must_succeed((equal_object([_A,_B],[int(2),int(1)]))). |
| 1423 | | :- assert_must_fail((equal_object(X,global_set('Code')),X=global_set('Name'))). |
| 1424 | | :- assert_must_fail((equal_object(Y,global_set('Name')),Y=[fd(3,'Name'),fd(1,'Name')])). |
| 1425 | | :- assert_must_fail((equal_object(Y,global_set('Name')),Y=[_,_])). |
| 1426 | | :- assert_must_succeed((equal_object(X,closure([xx],[integer],b(truth,pred,[]))),X==closure([xx],[integer],b(truth,pred,[])))). |
| 1427 | | :- assert_must_succeed((sample_closure(C), equal_object([int(1),int(2)],C))). |
| 1428 | | :- assert_must_succeed((sample_closure(C), equal_object(C,[int(1),int(2)]))). |
| 1429 | | :- assert_must_fail((sample_closure(C), equal_object(C,[int(1),int(0)]))). |
| 1430 | | :- assert_must_fail((sample_closure(C), equal_object(C,global_set('NAT')))). |
| 1431 | | :- assert_must_succeed((equal_object(freeval(selfcx,a,int(5)),freeval(selfcx,a,int(5))))). |
| 1432 | | :- assert_must_fail((equal_object([int(1),int(2),int(3)],global_set('NATURAL1')))). |
| 1433 | | :- assert_must_fail((equal_object(X,global_set('NATURAL1')),equal_object(X,[int(1),int(2),int(3)]))). |
| 1434 | | :- assert_must_fail((equal_object(X,[int(1),int(2),int(3)]),equal_object(X,global_set('NATURAL1')))). |
| 1435 | | :- assert_must_fail((equal_object(X,global_set('NATURAL')),equal_object(X,global_set('NATURAL1')))). |
| 1436 | | :- assert_must_succeed((equal_object(X,global_set('NATURAL')),equal_object(X,global_set('NATURAL')))). |
| 1437 | | % :- assert_must_fail((equal_object(freeval(selfcx,a,int(5)),freeval(selfcy,a,int(5))))). % is a type error |
| 1438 | | :- assert_must_fail((equal_object(freeval(selfcx,b,int(5)),freeval(selfcx,a,int(5))))). |
| 1439 | | :- assert_must_fail((equal_object(freeval(selfcx,a,int(5)),freeval(selfcx,a,int(6))))). |
| 1440 | | :- assert_must_succeed((equal_object( |
| 1441 | | [[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')], |
| 1442 | | [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(3,'Name'),fd(2,'Name')]] |
| 1443 | | ,[[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')], |
| 1444 | | [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(2,'Name'),fd(3,'Name')]]) |
| 1445 | | )). |
| 1446 | | :- assert_must_succeed(exhaustive_kernel_check( (equal_object([int(3),int(2),int(1)],[int(2)|T]), |
| 1447 | | equal_object(T,[int(1),int(3)])))). |
| 1448 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],equal_object([int(3),int(1)],[int(1),int(3)]))). |
| 1449 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],equal_object([int(3),int(4),int(1)],[int(4),int(1),int(3)]))). |
| 1450 | | |
| 1451 | | %:- assert_must_succeed(exhaustive_kernel_fail_check([commutative],equal_object([int(1),int(2),int(3)],global_set('NATURAL1')))). |
| 1452 | | :- 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)]) )). |
| 1453 | | % NOTE: had multiple solutions; after solving Ticket #227 it no longer has :-) |
| 1454 | | :- 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]) )). |
| 1455 | | |
| 1456 | | :- assert_must_succeed((equal_object([_X,_Y],[int(1),int(2)]))). |
| 1457 | | :- 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)))))), |
| 1458 | | 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))). |
| 1459 | | |
| 1460 | | :- use_module(bool_pred). |
| 1461 | | |
| 1462 | ? | equal_object(V1,V2) :- equal_object_wf(V1,V2,no_wf_available). |
| 1463 | ? | equal_object(V1,V2,Origin) :- equal_object_wf(V1,V2,Origin,no_wf_available). |
| 1464 | ? | equal_object_optimized(V1,V2,Origin) :- equal_object_optimized_wf(V1,V2,Origin,no_wf_available). |
| 1465 | ? | equal_object_optimized(V1,V2) :- equal_object_optimized(V1,V2,unknown). |
| 1466 | | |
| 1467 | | :- load_files(library(system), [when(compile_time), imports([environ/2])]). |
| 1468 | | :- if(environ(prob_safe_mode,true)). |
| 1469 | | /* a version of equal_object which will convert lists to avl if possible */ |
| 1470 | | equal_object_optimized_wf(V1,V2,Origin,WF) :- |
| 1471 | | ( var(V1) -> (var(V2) -> V1=V2 ; equal_object_opt3(V2,V1,WF)) |
| 1472 | | ; equal_object_opt3(V1,V2,WF)), |
| 1473 | | check_value(V1,Origin), check_value(V2,Origin). |
| 1474 | | equal_object_wf(V1,V2,Origin,WF) :- ( (var(V1);var(V2)) -> V1=V2 |
| 1475 | | ; nonvar(V1) -> equal_object3(V1,V2,WF) |
| 1476 | | ; equal_object3(V2,V1,WF)), |
| 1477 | | check_value(V1,val1(Origin)), check_value(V2,val2(Origin)). |
| 1478 | | equal_object_wf(V1,V2,WF) :- ( (var(V1);var(V2)) -> V1=V2 |
| 1479 | | ; nonvar(V1) -> equal_object3(V1,V2,WF) |
| 1480 | | ; equal_object3(V2,V1,WF)), |
| 1481 | | check_value(V1,equal_object1), check_value(V2,equal_object2). |
| 1482 | | check_value(X,Origin) :- nonvar(X) -> check_value_aux(X,Origin) ; true. |
| 1483 | | check_value_aux((A,B),Origin) :- !, check_value(A,pair1(Origin)), check_value(B,pair2(Origin)). |
| 1484 | | check_value_aux([H|T],Origin) :- !, check_value(H,head(Origin)), check_value(T,tail(Origin)). |
| 1485 | | check_value_aux(avl_set(X),Origin) :- !, |
| 1486 | | (var(X) -> add_warning(Origin,'Variable avl_set') |
| 1487 | | ; X=empty -> add_warning(Origin,'Empty avl_set') ; true). |
| 1488 | | check_value_aux(closure(P,T,B),Origin) :- !, |
| 1489 | | (ground(P),ground(T),nonvar(B) -> true |
| 1490 | | ; add_warning(Origin,illegal_closure(P,T,B))). |
| 1491 | | check_value_aux(_,_Origin). |
| 1492 | | :- else. |
| 1493 | | /* a version of equal_object which will convert lists to avl if possible */ |
| 1494 | | equal_object_optimized_wf(V1,V2,_Origin,WF) :- |
| 1495 | ? | ( var(V1) -> (var(V2) -> V1=V2 ; equal_object_opt3(V2,V1,WF)) |
| 1496 | ? | ; equal_object_opt3(V1,V2,WF)). |
| 1497 | | |
| 1498 | | equal_object_wf(V1,V2,_Origin,WF) :- ( (var(V1);var(V2)) -> V1=V2 |
| 1499 | ? | ; nonvar(V1) -> equal_object3(V1,V2,WF) |
| 1500 | | ; equal_object3(V2,V1,WF)). |
| 1501 | | equal_object_wf(V1,V2,WF) :- ( (var(V1);var(V2)) -> V1=V2 |
| 1502 | ? | ; nonvar(V1) -> equal_object3(V1,V2,WF) |
| 1503 | | ; equal_object3(V2,V1,WF)). |
| 1504 | | :- endif. |
| 1505 | | |
| 1506 | | |
| 1507 | | equal_object_opt3(int(X),Y,_WF) :- !, Y=int(X). |
| 1508 | | equal_object_opt3(fd(X,T),Y,_WF) :- !, Y=fd(X,T). |
| 1509 | | equal_object_opt3(string(X),Y,_WF) :- !, Y=string(X). |
| 1510 | | equal_object_opt3(pred_false,Y,_WF) :- !, Y=pred_false. |
| 1511 | | equal_object_opt3(pred_true,Y,_WF) :- !, Y=pred_true. |
| 1512 | | equal_object_opt3(X,S2,WF) :- var(S2), %unbound_variable(S2), % is it ok to assing an AVL set in one go ?! |
| 1513 | | should_be_converted_to_avl_from_lists(X), !, % does a ground(X) check |
| 1514 | | construct_avl_from_lists_wf(X,S2,WF). |
| 1515 | | %equal_object_opt3([H|T],S2) :- var(S2),ground(H),ground(T), !, construct_avl_from_lists([H|T],S2). |
| 1516 | ? | equal_object_opt3(X,Y,WF) :- equal_object3(X,Y,WF). |
| 1517 | | |
| 1518 | | |
| 1519 | | %%equal_object3c(X,Y) :- if(equal_object3(X,Y),true, |
| 1520 | | %% (print_message(equal_object3_failed(X,Y)),equal_object3(X,Y),fail)). %% |
| 1521 | | :- if(environ(prob_safe_mode,true)). |
| 1522 | | equal_object3(X,Y,_WF) :- (nonvar(Y) -> type_error(X,Y) ; illegal_value(X)), |
| 1523 | | add_internal_error('Internal Typing Error (please report as bug !) : ',equal_object(X,Y)),fail. |
| 1524 | | :- endif. |
| 1525 | | equal_object3(closure(Par,ParTypes,Clo),Y,WF) :- var(Y),!, |
| 1526 | | ( closure_occurs_check(Y,Par,ParTypes,Clo) |
| 1527 | | -> print(occurs_check(Y,Par)),nl, |
| 1528 | | expand_custom_set_wf(closure(Par,ParTypes,Clo),Expansion,equal_object3,WF), |
| 1529 | | equal_object_optimized_wf(Y,Expansion,equal_object3,WF) |
| 1530 | | ; Y = closure(Par,ParTypes,Clo)). |
| 1531 | | equal_object3(closure(Parameters,PT,Cond),Y,WF) :- |
| 1532 | | equal_object_custom_explicit_set(closure(Parameters,PT,Cond),Y,WF). |
| 1533 | | %equal_object3(Obj,Y) :- is_custom_explicit_set(Obj,equal_object3_Obj), |
| 1534 | | % equal_object_custom_explicit_set(Obj,Y,WF). % inlined below for performance |
| 1535 | | equal_object3(global_set(X),Y,WF) :- equal_object_custom_explicit_set(global_set(X),Y,WF). |
| 1536 | | equal_object3(freetype(X),Y,WF) :- equal_object_custom_explicit_set(freetype(X),Y,WF). |
| 1537 | ? | equal_object3(avl_set(X),Y,WF) :- equal_object_custom_explicit_set(avl_set(X),Y,WF). |
| 1538 | | equal_object3(pred_true /* bool_true */,pred_true /* bool_true */,_WF). |
| 1539 | | equal_object3(pred_false /* bool_false */,pred_false /* bool_false */,_WF). |
| 1540 | | equal_object3(term(X),term(X),_WF). |
| 1541 | | equal_object3(string(X),string(X),_WF). |
| 1542 | ? | equal_object3(rec(F1),rec(F2),WF) :- equal_fields_wf(F1,F2,WF). |
| 1543 | | equal_object3(freeval(Id,C,F1),freeval(Id,C,F2),WF) :- |
| 1544 | | instantiate_freetype_case(Id,C,C), |
| 1545 | | equal_object_wf(F1,F2,WF). |
| 1546 | | equal_object3(int(X),int(X),_WF). |
| 1547 | | equal_object3(fd(X,Type),fd(Y,Type),_WF) :- eq_fd(X,Y). |
| 1548 | | equal_object3((X,Y),(X2,Y2),WF) :- |
| 1549 | ? | 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 |
| 1550 | | equal_object3([],X,WF) :- empty_set_wf(X,WF). |
| 1551 | | equal_object3([H|T],S2,WF) :- nonvar(S2), is_custom_explicit_set_nonvar(S2),!, |
| 1552 | ? | equal_custom_explicit_set_cons_wf(S2,H,T,WF). |
| 1553 | | %equal_object3([H|T],S2,WF) :- equal_cons_wf(S2,H,T,WF). % leads to time-out for test 1270 : TODO investigate |
| 1554 | ? | equal_object3([H|T],S2,_WF) :- equal_cons(S2,H,T). |
| 1555 | | |
| 1556 | | equal_object_custom_explicit_set(Obj,Y,WF) :- |
| 1557 | | (var(Y) -> Y = Obj |
| 1558 | | ; (is_custom_explicit_set_nonvar(Y) -> equal_explicit_sets_wf(Obj,Y,WF) |
| 1559 | | ; (Y=[] -> is_empty_explicit_set_wf(Obj,WF) |
| 1560 | ? | ; Y=[H|T] -> equal_custom_explicit_set_cons_wf(Obj,H,T,WF) |
| 1561 | | ; add_internal_error('Illegal set: ',equal_object_custom_explicit_set(Obj,Y,WF)),fail |
| 1562 | | ) |
| 1563 | | )). |
| 1564 | | |
| 1565 | | equal_custom_explicit_set_cons_wf(CS,H,T,_WF) :- CS \= avl_set(_), |
| 1566 | | var(H),var(T), % TO DO: should we move this treatment below ? to equal_cons_lwf |
| 1567 | | % YES, I THINK WE CAN DELETE THIS NOW for avl_sets; but not yet for global_set,... |
| 1568 | | % print_term_summary(equal_custom_explicit_set_cons(CS,H,T)),nl, (debug_mode(on) -> trace ; true), |
| 1569 | | unbound_variable(H), |
| 1570 | | unbound_variable_for_cons(T), |
| 1571 | | !, |
| 1572 | | remove_minimum_element_custom_set(CS,Min,NewCS), |
| 1573 | | (H,T) = (Min,NewCS). |
| 1574 | | equal_custom_explicit_set_cons_wf(avl_set(AVL),H,T,_WF) :- var(H), |
| 1575 | | is_unbound_ordered_list_skeleton(H,T),!, % TO DO: provide this also for global_set(_) |
| 1576 | | % below we check if H can be removed from AVL and remove it |
| 1577 | | remove_minimal_elements([H|T],avl_set(AVL),SkeletonToUnify), |
| 1578 | | [H|T] = SkeletonToUnify. |
| 1579 | | equal_custom_explicit_set_cons_wf(Obj,H,T,WF) :- |
| 1580 | ? | equal_cons_lwf(Obj,H,T,2,WF). |
| 1581 | | %equal_cons_wf(Obj,H,T,WF). % equal_cons_wf causes issues to tests 799, (but not anymore 1751, 1642, 1708) |
| 1582 | | |
| 1583 | | |
| 1584 | | :- block equal_fields_wf(-,-,?). |
| 1585 | | equal_fields_wf([],[],_). |
| 1586 | | equal_fields_wf([field(Name1,V1)|T1],[field(Name2,V2)|T2],WF) :- |
| 1587 | | check_field_name_compatibility(Name1,Name2,equal_fields_wf), |
| 1588 | | equal_object_wf(V1,V2,field,WF), |
| 1589 | ? | equal_fields_wf(T1,T2,WF). |
| 1590 | | |
| 1591 | | |
| 1592 | | % is just like equal_cons, but H and T are guaranteed by the caller to be free |
| 1593 | | % this just gives one next element of the set; can be used to iterate over sets. |
| 1594 | | get_next_element(R,H,T) :- var(R),!,R=[H|T]. |
| 1595 | | get_next_element([H1|T1],H,T) :- !,(H1,T1)=(H,T). |
| 1596 | | get_next_element(R,H,T) :- equal_cons(R,H,T). |
| 1597 | | |
| 1598 | | |
| 1599 | ? | equal_cons_wf(R,H,T,WF) :- WF == no_wf_available,!, equal_cons_lwf(R,H,T,2,WF). |
| 1600 | | equal_cons_wf(R,H,T,WF) :- |
| 1601 | | %get_cardinality_wait_flag(R,equal_cons_wf,WF,LWF), |
| 1602 | | %get_binary_choice_wait_flag(equal_cons_wf,WF,LWF), %old version |
| 1603 | | LWF = lwf_card(R,equal_cons_wf,WF), % will be instantiated by instantiate_lwf |
| 1604 | ? | equal_cons_lwf(R,H,T,LWF,WF). |
| 1605 | | |
| 1606 | | % a deterministic version; will never instantiate non-deterministically: |
| 1607 | | % probably better to use equal_cons_wf if possible |
| 1608 | | %equal_cons_det(R,H,T) :- equal_cons_lwf4(R,H,T,_). |
| 1609 | | |
| 1610 | | equal_cons(R,H,T) :- |
| 1611 | ? | equal_cons_lwf(R,H,T,2,no_wf_available). %lwf_first(2)). |
| 1612 | | |
| 1613 | | :- block blocking_equal_cons_lwf(-,?,?,?,?). |
| 1614 | ? | blocking_equal_cons_lwf(E,H,T,LWF,WF) :- equal_cons_lwf(E,H,T,LWF,WF). |
| 1615 | | |
| 1616 | | %equal_cons_lwf4(R,H,T,LWF) :- equal_cons_lwf(R,H,T,LWF,no_wf_available). |
| 1617 | | |
| 1618 | ? | equal_cons_lwf(R,H,T,_,_) :- var(R),!,add_new_el(T,H,R). |
| 1619 | | equal_cons_lwf([HR|TR],H,T,_,WF) :- ground_value(H), %print(delete_exact(H,[HR|TR])),nl, |
| 1620 | | try_quick_delete_exact_member([HR|TR],H,Rest), % try and see if we can find an exact member in the list |
| 1621 | | % adds quadratic complexity if TR is a list; TODO: maybe do a sort |
| 1622 | | !, |
| 1623 | | %equal_object(Rest,T,equal_cons_lwf_1). |
| 1624 | ? | equal_object_wf(Rest,T,equal_cons_lwf_1,WF). |
| 1625 | ? | equal_cons_lwf([HR|TR],H,T,LWF,WF) :- !, equal_cons_cons(HR,TR,H,T,LWF,WF). |
| 1626 | | equal_cons_lwf(avl_set(AVL),H,T,LWF,WF) :- !, |
| 1627 | | (is_one_element_custom_set(avl_set(AVL),El) |
| 1628 | ? | -> empty_set(T), % was T=[], but T could be an empty closure ! |
| 1629 | | equal_object_wf(El,H,equal_cons_lwf_2,WF) |
| 1630 | | ; T==[] -> fail % we have a one element set and AVL is not |
| 1631 | | ; element_can_be_added_or_removed_to_avl(H) -> |
| 1632 | | remove_element_from_explicit_set(avl_set(AVL),H,AR), |
| 1633 | ? | equal_object_wf(AR,T,equal_cons_lwf_3,WF) |
| 1634 | | ; nonvar(T),T=[H2|T2],element_can_be_added_or_removed_to_avl(H2) -> |
| 1635 | | remove_element_from_explicit_set(avl_set(AVL),H2,AR), |
| 1636 | ? | equal_object_wf(AR,[H|T2],equal_cons_lwf_4,WF) |
| 1637 | | % TO DO: move all such H2 to the front ?? |
| 1638 | | % Common pattern for function application patterns f(a) = 1 & f(b) = 2 & f = AVL |
| 1639 | | % We have f = [(a,1),(b,2)|_] to be unified with an avl_set |
| 1640 | | ; at_most_one_match_possible(H,AVL,Pairs) -> Pairs=[H2], % unification could fail if no match found |
| 1641 | | % this optimisation is redundant wrt definitely_not_in_list optimisation below; check test 1716 |
| 1642 | | % but it has better performance for large sets, e.g., when unifying with a large sequence skeleton |
| 1643 | | % TODO: it could be useful even if there are more than one matches?? |
| 1644 | | equal_object_wf(H,H2,WF), |
| 1645 | | % element_can_be_added_or_removed_to_avl not checked ! |
| 1646 | | % we may need to call another predicate to remove, which only checks index |
| 1647 | | % or at_most_one_match_possible should remove the element itself |
| 1648 | | remove_element_from_explicit_set(avl_set(AVL),H2,AR), % print(removed_from_avl_by_equal_cons(H)),nl, |
| 1649 | | equal_object_wf(AR,T,equal_cons_lwf_3,WF) %% |
| 1650 | | ; expand_custom_set_wf(avl_set(AVL),ES,equal_cons_lwf,WF), % length(ES,LenES),print(expanded(LenES,T)),nl, |
| 1651 | | % before attempting unification quickly look if lengths are compatible: |
| 1652 | ? | quick_check_length_compatible(ES,[H|T]), % not really sure this is worth it: we have propagate_card in equal_cons_cons below |
| 1653 | | %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 |
| 1654 | | equal_cons_perf_message(AVL,H,T,WF), |
| 1655 | ? | equal_cons_lwf(ES,H,T,LWF,WF) ). |
| 1656 | | equal_cons_lwf(C,H,T,LWF,WF) :- |
| 1657 | | is_interval_closure_or_integerset(C,Low,Up), |
| 1658 | | (T==[] -> true ; finite_bound(Low), finite_bound(Up)), |
| 1659 | | !, |
| 1660 | ? | equal_cons_interval(H,T,Low,Up,LWF,WF). |
| 1661 | | equal_cons_lwf(closure(P,Ty,B),H,T,LWF,WF) :- !, |
| 1662 | ? | equal_cons_closure(P,Ty,B,H,T,LWF,WF). |
| 1663 | | equal_cons_lwf(freetype(ID),H,T,LWF,WF) :- !, expand_custom_set_wf(freetype(ID),ES,equal_cons_lwf,WF), |
| 1664 | | blocking_equal_cons_lwf(ES,H,T,LWF,WF). |
| 1665 | ? | equal_cons_lwf(global_set(G),H,T,LWF,WF) :- equal_cons_global_set(G,H,T,LWF,WF). |
| 1666 | | |
| 1667 | | |
| 1668 | | :- use_module(probsrc(avl_tools),[avl_height_less_than/2]). |
| 1669 | | :- use_module(performance_messages,[perf_format_wf/3]). |
| 1670 | | equal_cons_perf_message(AVL,H,T,WF) :- preference(performance_monitoring_on,true), |
| 1671 | | \+ avl_height_less_than(AVL,5), |
| 1672 | | \+ is_unbound_ordered_list_skeleton(H,T), % otherwise H will be set to minimum of AVL deterministically |
| 1673 | | !, |
| 1674 | | translate:translate_bvalue(avl_set(AVL),AS), |
| 1675 | | translate:translate_bvalue([H|T],HTS), |
| 1676 | | perf_format_wf('Expanding avl_set for set-unification~n ~w~n =~n ~w~n',[AS,HTS],WF). |
| 1677 | | equal_cons_perf_message(_,_,_,_). |
| 1678 | | |
| 1679 | | equal_cons_closure(P,Ty,B,_H,T,_LWF,_WF) :- nonvar(T), |
| 1680 | | is_definitely_finite(T), % move earlier; is_infinite_closure can perform expansions, e.g., for nested closures |
| 1681 | | is_infinite_closure(P,Ty,B), |
| 1682 | | !, |
| 1683 | | fail. % an infinite set cannot be equal to a finite one. |
| 1684 | | equal_cons_closure(Par,Types,B,H,T,LWF,WF) :- |
| 1685 | | % used to be expand_custom_set_wf(closure(Par,Types,B),ES,equal_cons_closure,WF) which calls: |
| 1686 | | expand_closure_to_list(Par,Types,B,ES,Done,equal_cons_closure,WF), |
| 1687 | ? | lazy_check_elements_of_closure([H|T],Done, Par,Types,B,WF), % relevant for test 2466 |
| 1688 | | % the lazy check in custom_explicit_sets does not trigger, as we cannot unify [H|T] with ES (unlike in equal_expansions3) |
| 1689 | | % because we do not know if [H|T] is ordered |
| 1690 | ? | blocking_equal_cons_lwf(ES,H,T,LWF,WF). |
| 1691 | | |
| 1692 | | is_definitely_finite(Var) :- var(Var),!,fail. |
| 1693 | | is_definitely_finite([]). |
| 1694 | | is_definitely_finite([_|T]) :- is_definitely_finite(T). |
| 1695 | | is_definitely_finite(avl_set(_)). |
| 1696 | | |
| 1697 | | %get_wf_from_lwf(LWF,WF) :- % TO DO: a cleaner, less hacky version; passing WF around if possible |
| 1698 | | % (nonvar(LWF),LWF=lwf_card(_,_,WF1) -> WF=WF1 ; WF = no_wf_available). |
| 1699 | | |
| 1700 | | finite_bound(I) :- (var(I) -> true /* inf would be created straightaway */ ; number(I)). |
| 1701 | | |
| 1702 | | % 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 |
| 1703 | | equal_cons_interval(H,T,Low,Up,_LWF,_WF) :- T==[],!, % Low..Up = {H} -> Low=H & Up=H |
| 1704 | | % unification will fail if Low or Up are not numbers (inf) |
| 1705 | | (int(Low),int(Up)) = (H,H). |
| 1706 | | %equal_cons_interval(_H,_T,Low,Up,_LWF,WF) :- (nonvar(Low),\+ number(Low) ; nonvar(Up),\+ number(Up)),!, |
| 1707 | | % gen_enum_warning_wf('OPEN INTERVAL',Low:Up,'cannot expand',trigger_throw(equal_cons_interval),WF), |
| 1708 | | % % we could try and instantiate T to an infinite closure |
| 1709 | | % fail. |
| 1710 | | equal_cons_interval(H,T,Low,Up,LWF,WF) :- |
| 1711 | | (number(Low),number(Up) -> true % we can expand interval fully |
| 1712 | | ; propagate_in_interval([H|T],int(Low),int(Up),0)), |
| 1713 | | expand_interval_closure_to_avl(Low,Up,ES), |
| 1714 | ? | blocking_equal_cons_lwf(ES,H,T,LWF,WF). |
| 1715 | | |
| 1716 | | :- block propagate_in_interval(-,?,?,?). |
| 1717 | | propagate_in_interval([],Low,Up,Sze) :- |
| 1718 | | (Sze > 0 -> S1 is Sze-1, int_plus(Low,int(S1),Up) ; true). % Test should always be true |
| 1719 | | propagate_in_interval([H|T],Low,Up,Sze) :- |
| 1720 | | in_nat_range(H,Low,Up), % without enumeration |
| 1721 | | S1 is Sze+1, |
| 1722 | | propagate_in_interval(T,Low,Up,S1). |
| 1723 | | propagate_in_interval(avl_set(_A),_Low,_Up,_). % TO DO: propagate if Low/Up not instantiated |
| 1724 | | propagate_in_interval(closure(_,_,_),_,_,_). |
| 1725 | | propagate_in_interval(global_set(_),_,_,_). |
| 1726 | | |
| 1727 | | quick_check_length_compatible([],R) :- !, |
| 1728 | | (var(R) -> R=[] % can we force R=[] here ?? |
| 1729 | | ; R \= [_|_]). %(R \= [_|_] -> true ; print(incompatible(R)),fail). |
| 1730 | | quick_check_length_compatible([_|T],R) :- |
| 1731 | | (var(R) -> true |
| 1732 | | ; R = [] -> fail |
| 1733 | ? | ; R = [_|RT] -> quick_check_length_compatible(T,RT) |
| 1734 | | ; true). |
| 1735 | | |
| 1736 | | :- block equal_cons_global_set(-,?,?,?,?). |
| 1737 | ? | equal_cons_global_set(G,H,T,LWF,WF) :- is_infinite_global_set(G,_),!, |
| 1738 | | % for maximal sets we could complement_set([H],global(G),Res), |
| 1739 | | /* should normally fail, unless T is not a list but contains closure or global set */ |
| 1740 | | test_finite_set_wf(T,Finite,WF), dif(Finite,pred_true), |
| 1741 | | when((nonvar(Finite);nonvar(LWF)),equal_cons_global_set_warning(LWF,G,H,T,WF)). |
| 1742 | | % used to be : expand_custom_set(global_set(G),ES), equal_cons_lwf4(ES,H,T,LWF))). |
| 1743 | | equal_cons_global_set(G,H,T,LWF,WF) :- |
| 1744 | | %(is_infinite_global_set(G,_) -> test_finite_set_wf(T,Finite,WF), Finite \== pred_true ; true), |
| 1745 | | expand_custom_set_wf(global_set(G),ES,equal_cons_global_set,WF), |
| 1746 | ? | equal_cons_lwf(ES,H,T,LWF,WF). |
| 1747 | | |
| 1748 | | |
| 1749 | | :- block equal_cons_global_set_warning(-,?,?,?,?). |
| 1750 | | equal_cons_global_set_warning(_,G,H,T,WF) :- |
| 1751 | | add_new_event_in_error_scope(enumeration_warning(enumerating(G),G,'{}',finite,critical), |
| 1752 | | print_equal_cons_warning(G,H,T,WF)), |
| 1753 | | fail. % WITH NEW SEMANTICS OF ENUMERATION WARNING WE SHOULD PROBABLY ALWAYS FAIL HERE ! |
| 1754 | | |
| 1755 | | % THROWING, Span added by add_new_event_in_error_scope |
| 1756 | | print_equal_cons_warning(G,H,T,WF,THROWING,Span) :- |
| 1757 | | print('### Enumeration Warning: trying to deconstruct infinite set: '), |
| 1758 | | translate:print_bvalue(global_set(G)),nl, |
| 1759 | | print('### Source: '), print(equal_cons_global_set(G,H,T)),nl, |
| 1760 | | print_throwing_wf(THROWING,unknown_info,Span,WF). |
| 1761 | | |
| 1762 | | add_new_el(T,H,R) :- var(T),!,R=[H|T]. |
| 1763 | | add_new_el(T,H,R) :- nonvar(T), is_custom_explicit_set_nonvar(T), |
| 1764 | | add_element_to_explicit_set_wf(T,H,Res,no_wf_available), % will fail for closure/3 |
| 1765 | | !, |
| 1766 | | Res=R. |
| 1767 | | add_new_el([HT|TT],H,R) :- !,R=[H,HT|TT]. |
| 1768 | | add_new_el([],H,R) :- !, R=[H]. |
| 1769 | | add_new_el(Set,H,R) :- expand_custom_set_to_list(Set,ESet,_,add_new_el), |
| 1770 | | add_new_el(ESet,H,R). |
| 1771 | | |
| 1772 | | %delete_exact_member(V,_,_) :- var(V),!,fail. |
| 1773 | | %delete_exact_member([H|T],El,Res) :- |
| 1774 | | % (H==El -> Res=T |
| 1775 | | % ; Res=[H|TR], delete_exact_member(T,El,TR)). |
| 1776 | | |
| 1777 | | % a version of delete_exact_member with a cut off |
| 1778 | | % avoids spending useless time traversing large non-ground lists |
| 1779 | | % for a list consisting only of non-ground elements delete_exact_member will never succeed ! |
| 1780 | | % this occurs e.g., when a large list skeleton generated by e.g. size_of_sequence is unified with an avl_set |
| 1781 | | % (e.g., m = READ_PGM_IMAGE_FILE("pgm_files/yuv_1.pgm") & %i.(i:1..550| m(i) /|\ 725)) |
| 1782 | | try_quick_delete_exact_member(List,El,Result) :- |
| 1783 | | try_quick_delete_exact_member(List,1,El,Result). |
| 1784 | | try_quick_delete_exact_member(V,_,_,_) :- var(V),!,fail. |
| 1785 | | try_quick_delete_exact_member([H|T],Sz,El,Res) :- |
| 1786 | | (H==El -> Res=T |
| 1787 | | ; Res=[H|TR], |
| 1788 | | (Sz>50 |
| 1789 | | -> ground_value(H), % after a certain limit we only proceed if there are ground elements |
| 1790 | | % we could also check: preferences:preference(use_smt_mode,true) |
| 1791 | | Sz=30 % check again in 20 steps |
| 1792 | | ; Sz1 is Sz+1), |
| 1793 | | try_quick_delete_exact_member(T,Sz1,El,TR)). |
| 1794 | | |
| 1795 | | |
| 1796 | | %unbound_variable(V) :- !, unbound_variable_check(V). |
| 1797 | | unbound_variable(V) :- free_var(V), frozen(V,Residue), |
| 1798 | | %unbound_residue(Residue,V). |
| 1799 | | (unbound_residue(Residue,V) -> true ; %print(bound_var(V,Residue)),nl,trace,unbound_residue(Residue,V), |
| 1800 | | fail). |
| 1801 | | unbound_residue((A,B),V) :- !,unbound_residue(A,V), unbound_residue(B,V). |
| 1802 | | unbound_residue(true,_) :- !. |
| 1803 | | unbound_residue(Module:Call,Variable) :- unbound_residue_m(Module,Call,Variable). |
| 1804 | | |
| 1805 | | unbound_residue_m(external_functions,to_string_aux(GrV,_Val,Str),V) :- !, %GrV checks for groundness of _Val |
| 1806 | | V==GrV,unbound_variable(Str). |
| 1807 | | unbound_residue_m(external_functions,format_to_string_aux(GrV,_Format,_Val,Str),V) :- !, |
| 1808 | | %GrV checks for groundness of _Val |
| 1809 | | V==GrV,unbound_variable(Str). |
| 1810 | | % TO DO: we need to detect other functions (e.g., B function application,...) which result in values which are not used |
| 1811 | | %unbound_residue_m(_,ground_value_check(V1,V2),V) :- !, V1==V, unbound_variable(V2). % V1==V not necessary?! cycle check |
| 1812 | | unbound_residue_m(Module,Residue,Var) :- unbound_basic_residue(Module,Residue,Var). |
| 1813 | | |
| 1814 | | %unbound_basic_residue(_,true,_). |
| 1815 | | unbound_basic_residue(_,ground_value_check(V1,V2),Var) :- !, Var==V1, % == check to prevent loops |
| 1816 | | % in particularly in SWI, where residues also contain calls where Var==V2; e.g., test 639 |
| 1817 | | unbound_variable(V2). |
| 1818 | | unbound_basic_residue(_,ground_value_check_aux(V1,V2,V3),Var) :- !, (Var==V1 -> true ; Var==V2), unbound_variable(V3). |
| 1819 | | % we could also treat ground_value_opt_check |
| 1820 | | unbound_basic_residue(b_interpreter_components,observe_variable_block(_,_,_,_,_),_). % when in -p TRACE_INFO TRUE mode |
| 1821 | | unbound_basic_residue(b_interpreter_components,observe_variable1_block(_,_,_,_),_). % (provide_trace_information pref) |
| 1822 | | unbound_basic_residue(kernel_objects,mark_as_to_be_computed(_),_). |
| 1823 | | unbound_basic_residue(custom_explicit_sets,block_copy_waitflag_store(_,_,_,_,_),_). % this stems from checking the domain predicate of function application check_element_of_function_closure |
| 1824 | | %unbound_basic_residue(kernel_objects,ordered_value(V,_),_). % <-- TO DO: treat this and then assign minimal value ! |
| 1825 | | %unbound_basic_residue(kernel_ordering,ordered_value2(V,_),_). |
| 1826 | | % b_tighter_enumerate_sorted_value_and_continue |
| 1827 | | %unbound_basic_residue(M,U,Var) :- print(bound_basic_residue(M,U,Var)),nl,fail. |
| 1828 | | |
| 1829 | | % check if we have an unbound list_skeleton with optionally just ordering constraints |
| 1830 | | % check if it is safe to assign H minimal value |
| 1831 | | % TO DO: also accept if all elements have the same co-routines constraints attached (e.g., because of +-> check) |
| 1832 | | is_unbound_ordered_list_skeleton(H,T) :- |
| 1833 | | is_unbound_ordered_list_skeleton3(H,T,[allow_ordered_values]). |
| 1834 | | is_unbound_list_skeleton(H,T) :- |
| 1835 | ? | is_unbound_ordered_list_skeleton3(H,T,[]). |
| 1836 | | |
| 1837 | | is_unbound_ordered_list_skeleton(H,T,Ordered) :- |
| 1838 | ? | is_unbound_ordered_list_skeleton3(H,T,List), |
| 1839 | | % if List gets instantiated it will become [allow_ordered_values|_] |
| 1840 | | (var(List) -> Ordered=unordered ; Ordered=ordered). |
| 1841 | | |
| 1842 | | is_unbound_ordered_list_skeleton3(H,T,Options) :- |
| 1843 | | free_var(H), |
| 1844 | | (var(T) -> unbound_variable(H), |
| 1845 | ? | unbound_ordered_tail(T,Options) % or ? unbound_variable_for_cons(T) |
| 1846 | | ; T = [H2|T2], |
| 1847 | | unbound_variable_or_ordered(H,'$$',H2,T,Options), |
| 1848 | | is_unbound_ordered_list_skeleton5(H,H2,T2,[H|T],Options)). |
| 1849 | | is_unbound_ordered_list_skeleton5(Prev,H,T,All,Options) :- |
| 1850 | | free_var(H), |
| 1851 | | (var(T) -> unbound_variable_or_ordered(H,Prev,'$$',All,Options), |
| 1852 | | unbound_ordered_tail(T,Options) |
| 1853 | | ; T==[] -> unbound_variable_or_ordered(H,Prev,'$$',All,Options) |
| 1854 | | ; T = [H2|T2], |
| 1855 | | unbound_variable_or_ordered(H,Prev,H2,All,Options), |
| 1856 | | is_unbound_ordered_list_skeleton5(H,H2,T2,All,Options)). |
| 1857 | | |
| 1858 | | % utility: if is_unbound_ordered_list_skeleton is true, extract for every element in the list one minimal element from CS |
| 1859 | | remove_minimal_elements(T,CS,Res) :- var(T),!,Res=CS. |
| 1860 | | remove_minimal_elements([],CS,Res) :- !, empty_set(CS),Res=[]. |
| 1861 | | remove_minimal_elements([_H|T],CS,[Min|Rest]) :- |
| 1862 | | remove_minimum_element_custom_set(CS,Min,NewCS), % _H will be unified in one go with Min later |
| 1863 | | remove_minimal_elements(T,NewCS,Rest). |
| 1864 | | |
| 1865 | | % it is unbound or can be assigned the minimal value of a set |
| 1866 | | unbound_variable_or_ordered(Var,Prev,Nxt,All,Options) :- |
| 1867 | | free_var(Var), frozen(Var,Residue), |
| 1868 | | unbound_ord_residue_aux(Residue,Prev,Var,Nxt,All,Options). |
| 1869 | | unbound_ord_residue_aux(true,_Prev,_,_Nxt,_All,_Options). |
| 1870 | | unbound_ord_residue_aux((A,B),Prev,V,Nxt,All,Options) :- !, |
| 1871 | | unbound_ord_residue_aux(A,Prev,V,Nxt,All,Options), |
| 1872 | | unbound_ord_residue_aux(B,Prev,V,Nxt,All,Options). |
| 1873 | | unbound_ord_residue_aux(Module:Call,Prev,V,Nxt,All,Options) :- |
| 1874 | | unbound_ord_residue_m(Module,Call,Prev,V,Nxt,All,Options). |
| 1875 | | unbound_ord_residue_m(Module,Residue,_,Var,_,_,_) :- unbound_basic_residue(Module,Residue,Var),!. |
| 1876 | | unbound_ord_residue_m(bsets_clp,check_index(V2,_),_,V,_,_,_) :- !, |
| 1877 | | V2==V. % assumes all index elements in the sequence are being checked; this is the case |
| 1878 | | unbound_ord_residue_m(kernel_objects,ordered_value(A,B),Prev,V,Nxt,_,Options) :- !, |
| 1879 | | % there is also a bsets_clp version |
| 1880 | | ((A,B)==(Prev,V) ; (A,B)==(V,Nxt)), |
| 1881 | | (member(allow_ordered_values,Options) -> true). |
| 1882 | | unbound_ord_residue_m(kernel_objects,not_equal_object_wf(A,B,_),_,V,_,All,_) :- !, |
| 1883 | | % check for all diff constraint; e.g., set up by not_element_of_wf(H,SoFar,WF) in cardinality_as_int2; |
| 1884 | | % anyway: all elements in a list must be different |
| 1885 | | (A==V -> exact_member_in_skel(B,All) ; B==V, exact_member_in_skel(A,All)). |
| 1886 | | unbound_ord_residue_m(kernel_objects,not_element_of_wf1(Set,Val,_),_,V,_,All,_) :- !, Val==V, |
| 1887 | | open_tail(All,Tail), Tail==Set. % ditto, again just stating that Values are distinct in the list |
| 1888 | | %unbound_ord_residue_m(A,Prev,V,Nxt,All) :- |
| 1889 | | % print(unbound_ord_residue_aux(A,Prev,V,Nxt,All)),nl,fail. |
| 1890 | | |
| 1891 | | % get tail of an open list: |
| 1892 | | open_tail(X,Res) :- var(X),!,Res=X. |
| 1893 | | open_tail([_|T],Res) :- open_tail(T,Res). |
| 1894 | | % exact member in a possibly open list: |
| 1895 | | exact_member_in_skel(X,List) :- nonvar(List), List=[Y|T], |
| 1896 | | (X==Y -> true ; exact_member_in_skel(X,T)). |
| 1897 | | |
| 1898 | | |
| 1899 | | unbound_ordered_tail(T,Options) :- free_var(T), frozen(T,Residue), |
| 1900 | ? | unbound_ordered_tail_aux(Residue,T,Options). |
| 1901 | | unbound_ordered_tail_aux(true,_,_). |
| 1902 | | unbound_ordered_tail_aux(kernel_objects:propagate_card(A,B,_Eq),V,_) :- |
| 1903 | | (V==A ; V==B). % just specifies A and B have same cardinality |
| 1904 | | unbound_ordered_tail_aux(prolog:dif(X,Y),V,_) :- (V==X,Y==[] ; V==Y,X==[]). |
| 1905 | | unbound_ordered_tail_aux(dif(X,Y),V,_) :- (V==X,Y==[] ; V==Y,X==[]). |
| 1906 | | unbound_ordered_tail_aux(kernel_objects:lazy_ordered_value(W,_),T,Options) :- |
| 1907 | | W==T, %% difference with just_cardinality_constraints |
| 1908 | | (member(allow_ordered_values,Options)->true). |
| 1909 | | unbound_ordered_tail_aux(bsets_clp:propagate_empty_set(_,_),_,_). |
| 1910 | | unbound_ordered_tail_aux(kernel_objects:prop_non_empty(_,W,_),T,_) :- W==T. |
| 1911 | | unbound_ordered_tail_aux(kernel_objects:cardinality_as_int2(W,_,_,_,_,_),T,_) :- W==T. |
| 1912 | | unbound_ordered_tail_aux(kernel_objects:cardinality3(W,_,_),Var,_) :- W==Var. |
| 1913 | | unbound_ordered_tail_aux((A,B),T,Options) :- |
| 1914 | ? | (unbound_ordered_tail_aux(A,T,Options) -> true ; unbound_ordered_tail_aux(B,T,Options)). |
| 1915 | | % TODO: call unbound_basic_residue |
| 1916 | | |
| 1917 | | % co-routine used to mark certain values as to be computed; avoid instantiating them |
| 1918 | | :- block mark_as_to_be_computed(-). |
| 1919 | | mark_as_to_be_computed(_). |
| 1920 | | |
| 1921 | | is_marked_to_be_computed(X) :- var(X),frozen(X,G), %nl,print(check_frozen(X,G)),nl, |
| 1922 | | marked_aux(G,X). |
| 1923 | | marked_aux((A,B),V) :- (marked_aux(A,V) -> true ; marked_aux(B,V)). |
| 1924 | | marked_aux(kernel_objects:mark_as_to_be_computed(M),V) :- V==M. |
| 1925 | | |
| 1926 | | :- public unbound_variable_check/1. |
| 1927 | | % currently not used; but can be useful for debugging |
| 1928 | | unbound_variable_check(V) :- free_var(V), % check no bool_pred attributes |
| 1929 | | (frozen(V,Goal), Goal\=true |
| 1930 | | -> nl,print('### WARNING: goal attached to unbound variable expression'),nl,print(V:Goal),nl, %trace, |
| 1931 | | fail |
| 1932 | | ; true). |
| 1933 | | |
| 1934 | | % 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 |
| 1935 | | unbound_variable_for_cons(Set) :- var(Set),frozen(Set,F), |
| 1936 | | \+ 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 |
| 1937 | | |
| 1938 | | % prolog:dif(X,Y) with Y == [] is ok |
| 1939 | | contains_problematic_coroutine_for_cons(custom_explicit_sets:element_of_avl_set_wf3(Var,_,_,_,_),V) :- V==Var. % occurs in test 1270 |
| 1940 | | contains_problematic_coroutine_for_cons(kernel_objects:non_free(_),_). % has been marked as non-free |
| 1941 | | contains_problematic_coroutine_for_cons(kernel_objects:mark_as_to_be_computed(_),_). % has been marked to be computed by closure expansion |
| 1942 | | % contains_problematic_coroutine_for_cons(bsets_clp:range_wf(_,Var,_),V) :- V==Var. % will be computed by range, range does not propagate well backwards (does it?) |
| 1943 | | % contains_problematic_coroutine_for_cons(custom_explicit_sets:expand_custom_set_to_list3(_From,Var,_Done,_Source,_WF),V) :- V==Var. % this can propagate backwards |
| 1944 | | contains_problematic_coroutine_for_cons((A,B),Var) :- |
| 1945 | | (contains_problematic_coroutine_for_cons(A,Var) -> true |
| 1946 | | ; contains_problematic_coroutine_for_cons(B,Var)). |
| 1947 | | %contains_problematic_coroutine_for_cons(M:Call,Var) :- |
| 1948 | | % functor(Call,F,N), format('~w:~w/~w for ~w~n',[M,F,N,Var]),fail. |
| 1949 | | |
| 1950 | | unbound_variable_for_card(Set) :- % when do we allow card to instantiate a list skeleton |
| 1951 | | preference(data_validation_mode,true), |
| 1952 | | !, |
| 1953 | | unbound_variable(Set). |
| 1954 | | unbound_variable_for_card(Set) :- unbound_variable_for_cons(Set). |
| 1955 | | |
| 1956 | | |
| 1957 | | |
| 1958 | | % handling equal_object for [HR|TR] = [H|T] |
| 1959 | | |
| 1960 | | equal_cons_cons(HR,TR,H,T,_LWF,WF) :- TR==[],!, |
| 1961 | ? | empty_set_wf(T,WF), % was T=[], but T could be an empty closure |
| 1962 | | equal_object_wf(HR,H,equal_cons_cons_1,WF). |
| 1963 | | equal_cons_cons(HR,TR,H,T,_LWF,WF) :- T==[],!, |
| 1964 | ? | empty_set_wf(TR,WF), % was TR=[], but TR could be an empty closure |
| 1965 | | equal_object_wf(HR,H,equal_cons_cons_2,WF). |
| 1966 | | equal_cons_cons(HR,TR,H,T,_LWF,WF) :- |
| 1967 | | %(is_unbound_list_skeleton(H,T) -> true ; is_unbound_list_skeleton(HR,TR)), |
| 1968 | ? | (is_unbound_ordered_list_skeleton(H,T,Ordered) |
| 1969 | | -> (Ordered = unordered -> true |
| 1970 | | ; is_unbound_ordered_list_skeleton(HR,TR)) |
| 1971 | ? | ; is_unbound_list_skeleton(HR,TR)), |
| 1972 | | % if both are ordered: then the first elements must be equal, |
| 1973 | | % if one or both are not ordered: the unification HR=H is only ok if the other is unbound |
| 1974 | | % beware of tests 1078 and 1101 when allowing ordered lists |
| 1975 | | !, |
| 1976 | | % HR is variable: no constraints/co-routines attached to it; no other element in TR is constrained either |
| 1977 | | %(HR,TR)=(H,T). %fails, e.g., if TR=[] and T= empty closure ! |
| 1978 | | % at the moment : unbound_check does not allow ordered set skeletons |
| 1979 | | HR=H, equal_object_wf(TR,T,equal_cons_cons3,WF). |
| 1980 | | equal_cons_cons(HR,TR,H,T,LWF,WF) :- |
| 1981 | | % here we use LWF for the first time |
| 1982 | | %(number(LWF) -> LWF2=LWF ; true), |
| 1983 | | equality_objects_lwf(HR,H,EqRes,LWF2,WF), |
| 1984 | ? | equal_cons1(EqRes,HR,TR,H,T,LWF,LWF2,WF). |
| 1985 | | |
| 1986 | | equal_cons1(EqRes,_HR,TR,_H,T,_LWF,_LWF2,WF) :- EqRes == pred_true,!, |
| 1987 | ? | equal_object_wf(TR,T,equal_cons1,WF). |
| 1988 | | equal_cons1(EqRes,HR,TR,H,T,_LWF,_LWF2,WF) :- var(EqRes), |
| 1989 | | (definitely_not_in_list(TR,H) |
| 1990 | | ; definitely_not_in_list(T,HR) % this can induce a quadratic complexity for large list skeletons |
| 1991 | | ), |
| 1992 | | !, |
| 1993 | | EqRes=pred_true, % H cannot appear in TR; it must match HR |
| 1994 | ? | equal_object_wf(TR,T,equal_cons1,WF). |
| 1995 | | equal_cons1(EqRes,HR,TR,H,T,LWF,LWF2,WF) :- |
| 1996 | ? | instantiate_lwf(LWF,LWF2), % instantiate later to ensure var(EqRes) can hold if LWF already bound |
| 1997 | | %print(eq_cons_cons_lwf2(HR,H,EqRes,LWF2)),nl, |
| 1998 | ? | equal_cons2(EqRes,HR,TR,H,T,LWF2,WF), |
| 1999 | | propagate_card(TR,T,EqRes). % prevents tail recursion; move earlier/remove if EqRes nonvar? |
| 2000 | | %,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 |
| 2001 | | |
| 2002 | | |
| 2003 | | % this will instantiate LWF if it has not yet been computed |
| 2004 | | % (Idea: get_cardinality_wait_flag can be expensive; only do it if we really need the wait_flag) |
| 2005 | | instantiate_lwf(LWF,R) :- var(LWF),!,R=LWF. |
| 2006 | | instantiate_lwf(lwf_card(Set,Info,WF),LWF) :- !, % TO DO: in prob_data_validation_mode: increase or get_last_waitflag |
| 2007 | ? | get_cardinality_wait_flag(Set,Info,WF,LWF). |
| 2008 | | %% get_cardinality_powset_wait_flag(Set,Info,WF,_,LWF). |
| 2009 | | %instantiate_lwf(lwf_first(X),R) :- !, R=X. |
| 2010 | | instantiate_lwf(LWF,LWF). |
| 2011 | | |
| 2012 | | :- block equal_cons2(-,?,?,?,?,?,?). |
| 2013 | ? | equal_cons2(pred_true,_HR,TR,_H,T,_,WF) :- equal_object_wf(TR,T,equal_cons2,WF). |
| 2014 | | equal_cons2(pred_false,HR,TR, H,T,LWF,WF) :- |
| 2015 | ? | equal_cons_lwf(T,HR,TR2,LWF,WF), % look for HR inside T |
| 2016 | | T2=TR2, |
| 2017 | ? | equal_cons_lwf(TR,H,T2,LWF,WF). %, was instead of T2=TR2: equal_object(TR2,T2). |
| 2018 | | |
| 2019 | | :- use_module(kernel_tools,[cannot_match/2]). |
| 2020 | | % TO DO: investigate whether we should not use kernel_equality or at least a blocking version |
| 2021 | | definitely_not_in_list(V,_) :- var(V),!,fail. |
| 2022 | | definitely_not_in_list([],_). |
| 2023 | | definitely_not_in_list([H|T],X) :- cannot_match(H,X), definitely_not_in_list(T,X). |
| 2024 | | |
| 2025 | | |
| 2026 | | :- block propagate_card(-,-,-). |
| 2027 | | propagate_card(X,Y,EqRes) :- |
| 2028 | | (nonvar(EqRes) -> true % we no longer need to propagate; equal_cons will traverse |
| 2029 | | ; nonvar(X) -> propagate_card2(X,Y,EqRes) |
| 2030 | | ; propagate_card2(Y,X,EqRes)). |
| 2031 | | propagate_card2([],Y,_) :- !,empty_set(Y). |
| 2032 | | propagate_card2([_|TX],Y,EqRes) :- !, |
| 2033 | | (var(Y) -> Y= [_|TY], propagate_card(TX,TY,EqRes) |
| 2034 | | ; Y=[] -> fail |
| 2035 | | ; Y=[_|TY] -> propagate_card(TX,TY,EqRes) |
| 2036 | | ; true |
| 2037 | | ). % TO DO: add more propagation |
| 2038 | | propagate_card2(_,_,_). |
| 2039 | | |
| 2040 | | %same_card_and_expand(A,B,ExpA,ExpB) :- .... + reorder ?? |
| 2041 | | |
| 2042 | | |
| 2043 | | % CODE FOR CHECKING FOR TYPE ERRORS AT RUNTIME |
| 2044 | | |
| 2045 | | % explicitly check for type errors between two terms |
| 2046 | | % can be useful for some external functions were users provide predicates/values at runtime |
| 2047 | | % should be called before attempting e.g., equal_object |
| 2048 | | check_values_have_same_type(TermA,TermB,_Pos) :- (var(TermA) ; var(TermB)),!. |
| 2049 | | check_values_have_same_type((A1,A2),(B1,B2),Pos) :- !, |
| 2050 | | check_values_have_same_type(A1,B1,Pos), |
| 2051 | | check_values_have_same_type(A2,B2,Pos). |
| 2052 | | % TODO: better checking for fields |
| 2053 | | check_values_have_same_type(TermA,TermB,Pos) :- type_error(TermA,TermB),!, |
| 2054 | | add_error(kernel_objects,'Type error, values are incompatible:',(TermA,TermB),Pos). |
| 2055 | | check_values_have_same_type(_,_,_). |
| 2056 | | |
| 2057 | | % the following is used by some kernel predicates if(environ(prob_safe_mode,true)). |
| 2058 | | :- assert_must_succeed(type_error([],int(1))). |
| 2059 | | :- assert_must_succeed(type_error((int(1),int(2)),[pred_true])). |
| 2060 | | :- assert_must_succeed(type_error(string('Name'),global_set('Name'))). |
| 2061 | | :- assert_must_fail((type_error([],[_]))). |
| 2062 | | type_error(pred_true,Y) :- \+ bool_val(Y). |
| 2063 | | type_error(pred_false,Y) :- \+ bool_val(Y). |
| 2064 | | type_error([],Y) :- no_set_type_error(Y). |
| 2065 | | type_error([_|_],Y) :- no_set_type_error(Y). |
| 2066 | | %type_error(X,Y) :- is_custom_explicit_set(X,type_error1), no_set_type_error(Y). |
| 2067 | | type_error(avl_set(A),Y) :- illegal_avl_set(A) -> true ; no_set_type_error(Y). |
| 2068 | | type_error(global_set(_),Y) :- no_set_type_error(Y). |
| 2069 | | type_error(freetype(_),Y) :- no_set_type_error(Y). |
| 2070 | | type_error(closure(P,_,B),Y) :- |
| 2071 | | (var(P) -> true ; var(B) -> true ; P=[] -> true ; P=[P1|_], var(P1) -> true ; no_set_type_error(Y)). |
| 2072 | | type_error((_,_),Y) :- Y \= (_,_). |
| 2073 | | type_error(fd(_,T1),Y) :- (Y= fd(_,T2) -> nonvar(T1),nonvar(T2),T1 \=T2 ; true). |
| 2074 | | type_error(int(_),Y) :- Y\= int(_). |
| 2075 | | type_error(term(_),Y) :- Y\= term(_). |
| 2076 | | type_error(rec(FX),Y) :- (Y = rec(FY) -> type_error_fields(FX,FY,'$') ; true). |
| 2077 | | type_error(freeval(ID,_,_),Y) :- Y \= freeval(ID,_,_). |
| 2078 | | type_error(string(_),Y) :- Y \= string(_). |
| 2079 | | % Should raise type error: kernel_objects:union([int(1)],[[]],R). |
| 2080 | | |
| 2081 | | bool_val(pred_true). |
| 2082 | | bool_val(pred_false). |
| 2083 | | |
| 2084 | | type_error_fields(X,Y,_) :- (var(X);var(Y)),!,fail. |
| 2085 | | type_error_fields([],[_|_],_). |
| 2086 | | type_error_fields([_|_],[],_). |
| 2087 | | type_error_fields([F1|T1],[F2|T2],PrevField) :- |
| 2088 | | nonvar(F1),nonvar(F2),F1=field(Name1,_),F2=field(Name2,_), |
| 2089 | | nonvar(Name1), |
| 2090 | | (Name1 @=< PrevField -> true % not sorted |
| 2091 | | ; Name1 \= Name2 -> true % other record has different field |
| 2092 | | ; type_error_fields(T1,T2,Name1)). |
| 2093 | | |
| 2094 | | :- public illegal_value/1. |
| 2095 | | illegal_value(X) :- var(X),!,fail. |
| 2096 | | illegal_value(avl_set(A)) :- illegal_avl_set(A). |
| 2097 | | illegal_value([H|T]) :- illegal_value(H) -> true ; illegal_value(T). |
| 2098 | | illegal_value(global_set(G)) :- \+ ground(G). |
| 2099 | | illegal_value(N) :- number(N). |
| 2100 | | illegal_value((A,B)) :- illegal_value(A) -> true ; illegal_value(B). |
| 2101 | | % TO DO: complete this |
| 2102 | | |
| 2103 | | illegal_avl_set(X) :- var(X),!. |
| 2104 | | illegal_avl_set(empty). |
| 2105 | | illegal_avl_set(X) :- (X=node(_,_,_,_,_) -> \+ ground(X) ; true). |
| 2106 | | |
| 2107 | | no_set_type_error(int(_)). |
| 2108 | | no_set_type_error(fd(_,_)). |
| 2109 | | no_set_type_error((_,_)). |
| 2110 | | no_set_type_error(rec(_)). |
| 2111 | | no_set_type_error(pred_true /* bool_true */). |
| 2112 | | no_set_type_error(pred_false /* bool_false */). |
| 2113 | | no_set_type_error(term(_)). |
| 2114 | | no_set_type_error(string(_)). |
| 2115 | | no_set_type_error(freeval(_,_,_)). |
| 2116 | | no_set_type_error(avl_set(A)) :- illegal_avl_set(A). |
| 2117 | | %% END OF TYPE CHECKING CODE |
| 2118 | | |
| 2119 | | |
| 2120 | | :- assert_must_succeed(not_equal_object(term(a),term(b))). |
| 2121 | | :- assert_must_succeed(not_equal_object(string('a'),string('b'))). |
| 2122 | | :- assert_must_succeed(not_equal_object(int(1),int(2))). |
| 2123 | | :- assert_must_succeed(not_equal_object(rec([field(a,int(1))]),rec([field(a,int(2))]))). |
| 2124 | | :- assert_must_succeed(not_equal_object(rec([field(a,int(1)),field(b,int(2))]), |
| 2125 | | rec([field(a,int(1)),field(b,int(3))]))). |
| 2126 | | :- assert_must_fail(not_equal_object(rec([field(a,int(1))]),rec([field(a,int(1))]))). |
| 2127 | | :- assert_must_fail(not_equal_object(rec([field(a,int(1)),field(b,int(2))]), |
| 2128 | | rec([field(a,int(1)),field(b,int(2))]))). |
| 2129 | | :- assert_must_fail(not_equal_object(term(msg),int(2))). |
| 2130 | | :- assert_must_fail(not_equal_object(fd(1,a),term(msg))). |
| 2131 | | :- assert_must_succeed(not_equal_object(global_set(a),global_set(b))). |
| 2132 | | :- assert_must_succeed(not_equal_object([term(a),term(b)],[term(a),term(c)])). |
| 2133 | | :- assert_must_succeed((not_equal_object([(int(1),[Y])],[(int(X),[Z])]), |
| 2134 | | Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[int(2)])). |
| 2135 | | :- assert_must_succeed(not_equal_object((int(1),int(2)),(int(3),int(4)))). |
| 2136 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_equal_object((int(1),int(2)),(int(1),int(4))))). |
| 2137 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_equal_object((int(1),int(4)),(int(3),int(4))))). |
| 2138 | | :- assert_must_fail(not_equal_object((int(1),int(4)),(int(1),int(4)))). |
| 2139 | | :- assert_must_succeed(not_equal_object((int(1),string('a')),(int(1),string('b')))). |
| 2140 | | :- assert_must_fail(not_equal_object((int(1),string('b')),(int(1),string('b')))). |
| 2141 | | :- assert_must_fail(not_equal_object([(term(a),[])],[(term(a),[])])). |
| 2142 | | :- assert_must_fail((not_equal_object([(int(1),[Y])],[(int(X),[Z])]), |
| 2143 | | Y=(term(a),Y2), X=1, Z=(term(a),[]), Y2=[])). |
| 2144 | | :- assert_must_fail(not_equal_object([int(1),int(2)],[int(2),int(1)])). |
| 2145 | | :- assert_must_succeed(not_equal_object(term(msg),term(another_msg))). |
| 2146 | | :- assert_must_succeed(not_equal_object([int(1),int(2)],[int(0),int(4)])). |
| 2147 | | :- assert_must_fail((sample_closure(C), |
| 2148 | | not_equal_object(C,[int(1),int(2)]))). |
| 2149 | | :- assert_must_succeed((sample_closure(C), |
| 2150 | | not_equal_object(C,[int(1),int(0)]))). |
| 2151 | | :- assert_must_succeed((sample_closure(C), |
| 2152 | | not_equal_object(C,global_set('NAT')))). |
| 2153 | | :- assert_must_fail((not_equal_object( |
| 2154 | | [[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')], |
| 2155 | | [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(3,'Name'),fd(2,'Name')]] |
| 2156 | | ,[[],[fd(1,'Name')],[fd(1,'Name'),fd(2,'Name')], |
| 2157 | | [fd(1,'Name'),fd(2,'Name'),fd(3,'Name')],[fd(2,'Name')],[fd(2,'Name'),fd(3,'Name')]]) |
| 2158 | | )). |
| 2159 | | :- assert_must_fail((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,a,int(2))))). |
| 2160 | | :- assert_must_succeed((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,a,int(3))))). |
| 2161 | | :- assert_must_succeed((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,b,int(2))))). |
| 2162 | | :- assert_must_succeed((not_equal_object(freeval(selfcx,a,int(2)),freeval(selfcx,a,int(3))))). |
| 2163 | | |
| 2164 | | :- assert_must_succeed((not_equal_object(pred_true /* bool_true */,X), X==pred_false /* bool_false */)). |
| 2165 | | :- assert_must_succeed((not_equal_object([],X),X=[_|_])). |
| 2166 | | %:- assert_must_succeed((not_equal_object([],X), nonvar(X),X=[_|_])). |
| 2167 | | :- assert_must_succeed((not_equal_object(X,[]), X=[_|_])). |
| 2168 | | :- assert_must_succeed((not_equal_object(X,pred_false /* bool_false */), X==pred_true /* bool_true */)). |
| 2169 | | |
| 2170 | | :- assert_must_succeed(not_equal_object([_X],[int(1),int(3)])). % Inefficiency example of setlog |
| 2171 | | :- assert_must_succeed_any(not_equal_object([_X],[int(1)])). % Inefficiency example of setlog |
| 2172 | | :- assert_must_succeed((not_equal_object([X],[pred_true /* bool_true */]),X==pred_false /* bool_false */)). |
| 2173 | | :- assert_must_succeed((not_equal_object([pred_true /* bool_true */],[X]),X==pred_false /* bool_false */)). |
| 2174 | | :- assert_must_succeed((not_equal_object([[X]],[[pred_true /* bool_true */]]),X==pred_false /* bool_false */)). |
| 2175 | | :- assert_must_succeed((not_equal_object([[pred_true /* bool_true */]],[[X]]),X==pred_false /* bool_false */)). |
| 2176 | | :- 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 */)). |
| 2177 | | :- 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 */)). |
| 2178 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([],[int(3333)]))). |
| 2179 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([],[int(2),int(1),int(3)]))). |
| 2180 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([int(3)],[int(2),int(1),int(3)]))). |
| 2181 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([int(3),int(1),int(4)],[int(2),int(1),int(3)]))). |
| 2182 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],not_equal_object([int(2),int(1),int(3),int(5)],[int(2),int(1),int(3)]))). |
| 2183 | | % X in 3..4, kernel_objects:not_equal_object([int(2),int(3)],[int(2),int(X)]), X==4. in clpfd Mode |
| 2184 | | |
| 2185 | | |
| 2186 | | not_equal_object_wf(X,Y,WF) :- |
| 2187 | | (var(X) |
| 2188 | | -> (var(Y) |
| 2189 | | -> X \== Y, |
| 2190 | | when((nonvar(X);nonvar(Y);?=(X,Y)), not_equal_object_wf0(X,Y,WF)) |
| 2191 | | ; not_equal_object_wf1(Y,X,WF) % invert arguments |
| 2192 | | ) |
| 2193 | ? | ; not_equal_object_wf1(X,Y,WF)). |
| 2194 | | |
| 2195 | | %:- block not_equal_object_wf0(-,-,?). |
| 2196 | | /* TO DO: implement a better _wf version ; use bool_dif if possible */ |
| 2197 | | % block is relevant for tests 1374, 1737 |
| 2198 | | not_equal_object_wf0(X,Y,WF) :- |
| 2199 | | %(X==Y -> print(not_eq_pruned(X,Y)),nl,fail ; true), |
| 2200 | | %X\==Y, % could be expensive if X,Y assigned to large term simultaneously (just woken up by when) |
| 2201 | | (var(X) -> X\==Y, not_equal_object_wf1(Y,X,WF) |
| 2202 | | ; not_equal_object_wf1(X,Y,WF)). |
| 2203 | | |
| 2204 | | not_equal_object_wf1([],R,WF) :- !, not_empty_set_wf(R,WF). |
| 2205 | | not_equal_object_wf1(R,E,WF) :- E==[],!, not_empty_set_wf(R,WF). |
| 2206 | ? | not_equal_object_wf1(X,Y,WF) :- not_equal_object2_wf(X,Y,WF). |
| 2207 | | |
| 2208 | | not_equal_object(X,Y) :- |
| 2209 | ? | ( nonvar(X) -> not_equal_object2_wf(X,Y,no_wf_available) |
| 2210 | | ; nonvar(Y) -> not_equal_object2_wf(Y,X,no_wf_available) |
| 2211 | | ; X\==Y, when((?=(X,Y);nonvar(X);nonvar(Y)), not_equal_object0(X,Y))). |
| 2212 | | |
| 2213 | | not_equal_object0(X,Y) :- X\==Y,(var(X) -> not_equal_object2_wf(Y,X,no_wf_available) |
| 2214 | | ; not_equal_object2_wf(X,Y,no_wf_available)). |
| 2215 | | |
| 2216 | | %not_equal_object2_wf(X,Y,_) :- print(not_equal_object2_wf(X,Y)),nl,fail. |
| 2217 | | not_equal_object2_wf(pred_true /* bool_true */,R,_) :- !, R=pred_false /* bool_false */. |
| 2218 | | not_equal_object2_wf(pred_false /* bool_false */,R,_) :- !, R=pred_true /* bool_true */. |
| 2219 | | not_equal_object2_wf(fd(X,Type),R,_) :- !, get_global_type_value(R,Type,Y), % also sets up FD range for Y if R was var |
| 2220 | | neq_fd(X,Y,Type). |
| 2221 | | not_equal_object2_wf(int(X),R,_WF) :- !, R=int(Y), integer_dif(X,Y). |
| 2222 | | not_equal_object2_wf(string(X),R,_) :- !, R=string(Y), dif(X,Y). |
| 2223 | | not_equal_object2_wf(term(X),R,WF) :- !, R=term(Y), not_equal_term_wf(X,Y,WF). |
| 2224 | | not_equal_object2_wf(rec(F1),R,WF) :- !, R=rec(F2), |
| 2225 | | not_equal_fields_wf(F1,F2,WF). |
| 2226 | | not_equal_object2_wf([],X,WF) :- !, not_empty_set_wf(X,WF). |
| 2227 | | not_equal_object2_wf((X1,X2),R,WF) :- !, R=(Y1,Y2), |
| 2228 | ? | not_equal_couple_wf(X1,Y1,X2,Y2,WF). |
| 2229 | | not_equal_object2_wf(X,Y,WF) :- is_custom_explicit_set(X,not_equal_object2),!, |
| 2230 | ? | not_equal_explicit_set_wf(X,Y,WF). |
| 2231 | ? | not_equal_object2_wf(X,Y,WF) :- not_equal_object3(X,Y,WF). |
| 2232 | | |
| 2233 | | :- block not_equal_term_wf(-,-,?). |
| 2234 | | not_equal_term_wf(X,Y,_WF) :- % triggered e.g. in test 1225 or 1227 for nil (freetypes) |
| 2235 | | dif(X,Y). |
| 2236 | | % TO DO: should we treat floating/1 in a special way? |
| 2237 | | |
| 2238 | | :- block not_equal_explicit_set_wf(?,-,?). |
| 2239 | | not_equal_explicit_set_wf(X,Y,WF) :- |
| 2240 | | is_custom_explicit_set_nonvar(Y),!, |
| 2241 | | not_equal_explicit_sets_wf(X,Y,WF). |
| 2242 | | not_equal_explicit_set_wf(X,[],WF) :- !, |
| 2243 | | is_non_empty_explicit_set_wf(X,WF). |
| 2244 | | not_equal_explicit_set_wf(CS,[H|T],WF) :- |
| 2245 | | is_simple_infinite_set(CS), % global_set(.) or open interval |
| 2246 | | !, % TODO: maybe also detect other infinite sets |
| 2247 | | test_finite_set_wf(T,Finite,WF), |
| 2248 | | when(nonvar(Finite),(Finite=pred_true -> true % infinite set cannot be equal finite one |
| 2249 | | ; not_equal_explicit_set_expand(CS,[H|T],WF))). |
| 2250 | | not_equal_explicit_set_wf(X,Y,WF) :- |
| 2251 | ? | not_equal_explicit_set_expand(X,Y,WF). |
| 2252 | | |
| 2253 | | not_equal_explicit_set_expand(X,Y,WF) :- |
| 2254 | | expand_custom_set_wf(X,EX,not_equal_explicit_set_wf,WF), |
| 2255 | ? | not_equal_object3_block(EX,Y,WF). |
| 2256 | | |
| 2257 | | :- block not_equal_object3_block(-,?,?). |
| 2258 | ? | not_equal_object3_block(EX,Y,WF) :- not_equal_object3(EX,Y,WF). |
| 2259 | | |
| 2260 | | :- load_files(library(system), [when(compile_time), imports([environ/2])]). |
| 2261 | | :- block not_equal_object3(?,-,?). |
| 2262 | | :- if(environ(prob_safe_mode,true)). |
| 2263 | | not_equal_object3(X,Y,_) :- nonvar(X),type_error(X,Y), |
| 2264 | | add_internal_error('Internal Typing Error (please report as bug !) : ',not_equal_object(X,Y)), |
| 2265 | | fail. |
| 2266 | | :- endif. |
| 2267 | | not_equal_object3(X,Y,WF) :- is_custom_explicit_set(Y,not_equal_object2),!, |
| 2268 | ? | not_equal_explicit_set_wf(Y,X,WF). % TODO: will uselessly check for X being custom_set or [] |
| 2269 | | not_equal_object3(freeval(ID,Case1,Value1),freeval(ID,Case2,Value2),WF) :- |
| 2270 | | instantiate_freetype_case(ID,Case1,Case2), |
| 2271 | | when(?=(Case1,Case2), % we first have to be able to decide the case; if cases are different types of values may be different |
| 2272 | | not_equal_freeval_wf(Case1,Value1,Case2,Value2,WF)). |
| 2273 | | not_equal_object3([],X,WF) :- not_empty_set_wf(X,WF). |
| 2274 | | not_equal_object3([H|T],Set2,WF) :- |
| 2275 | | (Set2==[] -> true % note second argument is nonvar |
| 2276 | | ; cardinality_peano_wf([H|T],N1,no_wf_available), |
| 2277 | | cardinality_peano_wf(Set2,N2,no_wf_available), % TODO(?): pending co-routines if Set2 infinite |
| 2278 | ? | when(?=(N1,N2), % when we trigger code below, = can be decided: |
| 2279 | | (N1=N2 -> neq_cons_wf(Set2,H,T,WF) ; true))). |
| 2280 | | % (dif(N1,N2) ; (N1=N2, neq_cons_wf(Set2,H,T,WF)))). %not_equal_object_sets(Set1,Set2) )) ). |
| 2281 | | |
| 2282 | | not_equal_freeval_wf(Case1,Value1,Case2,Value2,WF) :- |
| 2283 | | (Case1=Case2 -> not_equal_object_wf(Value1,Value2,WF) ; true). |
| 2284 | | |
| 2285 | | :- block not_equal_object_sets_wf(-,?,?), not_equal_object_sets_wf(?,-,?). |
| 2286 | | not_equal_object_sets_wf([H|T],Set2,WF) :- !, |
| 2287 | | ( Set2=[H2|_T2] |
| 2288 | ? | -> not_equal_object_sets2(H,T,H2,Set2,WF) |
| 2289 | | ; Set2=[] -> true |
| 2290 | | ; not_equal_object2_wf(Set2,[H|T],WF) % avl_set probably |
| 2291 | | ). |
| 2292 | | not_equal_object_sets_wf(Set1,Set2,WF) :- % Note : if Set1 =[] then we can fail, as both sets have same length |
| 2293 | | % we could have empty set or avl_set can sometimes creep into end of lists |
| 2294 | | not_equal_object2_wf(Set1,Set2,WF). |
| 2295 | | |
| 2296 | | :- block not_equal_object_sets2(-,?,?,?,?), not_equal_object_sets2(?,?,-,?,?). |
| 2297 | | not_equal_object_sets2(H,_T,_H2,Set2,WF) :- |
| 2298 | | % TO DO: should we not use kernel_equality:membership_test_wf here ?? |
| 2299 | | not_element_of_wf(H,Set2,WF). |
| 2300 | | not_equal_object_sets2(H,T,_H2,Set2,WF) :- |
| 2301 | | remove_element_wf(H,Set2,Del2,WF), % used to be remove_element(X,Set,Res) :- equal_cons(Set,X,Res). |
| 2302 | | not_equal_object_wf(T,Del2,WF). |
| 2303 | | |
| 2304 | | |
| 2305 | | :- block neq_cons_wf(-,?,?,?). |
| 2306 | | neq_cons_wf([],_,_,_) :- !. |
| 2307 | | neq_cons_wf([H2|T2],H1,T1,WF) :- !, |
| 2308 | | (T2==[],T1==[] |
| 2309 | | -> not_equal_object_wf(H1,H2,WF) |
| 2310 | | ; check_and_remove([H2|T2],H1,NewSet2,RemoveSuccesful), |
| 2311 | ? | neq_cons2(RemoveSuccesful,T1,NewSet2,WF) |
| 2312 | | ). |
| 2313 | | neq_cons_wf(avl_set(A),H1,T1,WF) :- element_can_be_added_or_removed_to_avl(H1),!, |
| 2314 | | (remove_element_from_explicit_set(avl_set(A),H1,RA) |
| 2315 | | -> not_equal_object_wf(T1,RA,WF) |
| 2316 | | ; true ). |
| 2317 | | neq_cons_wf(ES,H1,T1,WF) :- is_custom_explicit_set(ES,neq_cons), |
| 2318 | | expand_custom_set_wf(ES,ExpSet,neq_cons_wf,WF), |
| 2319 | | neq_cons_wf(ExpSet,H1,T1,WF). |
| 2320 | | |
| 2321 | | :- block neq_cons2(-,?,?,?). |
| 2322 | | neq_cons2(not_successful,_T1,_NewSet2,_WF). % one element could not be removed: the sets are different |
| 2323 | ? | neq_cons2(successful,T1,NewSet2,WF) :- not_equal_object_sets_wf(T1,NewSet2,WF). |
| 2324 | | |
| 2325 | | % kernel_objects:not_equal_couple(int(1),int(Y),B,pred_true). |
| 2326 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(int(1),int(Y),B,pred_true,no_wf_available),Y=1, B==pred_false)). |
| 2327 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(int(Y),int(1),B,pred_true,no_wf_available),Y=1, B==pred_false)). |
| 2328 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(int(Y),int(1),B,pred_false,no_wf_available),Y=1, B==pred_true)). |
| 2329 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(int(Y),int(1),pred_false,B,no_wf_available),Y=1, B==pred_true)). |
| 2330 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(int(Y),int(1),B,pred_true,no_wf_available),Y=2, var(B))). |
| 2331 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(B,pred_true,int(Y),int(1),no_wf_available),Y=1, B==pred_false)). |
| 2332 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(B,fd(C,'Code'),fd(Y,'Name'),F,no_wf_available),F=fd(1,'Name'),Y=1,B=fd(1,'Code'),C=2 )). |
| 2333 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(B,pred_true,fd(Y,'Name'),F,no_wf_available),F=fd(1,'Name'),Y=1, B==pred_false)). |
| 2334 | | |
| 2335 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(int(2500),int(50),_,_,no_wf_available))). |
| 2336 | | :- assert_must_succeed(( kernel_objects:not_equal_couple_wf(_,_,int(2500),int(50),no_wf_available))). |
| 2337 | | |
| 2338 | | |
| 2339 | | %was too lax (but works): :- block not_equal_couple_wf(-,?,-,?,?),not_equal_couple_wf(?,-,?,-,?). |
| 2340 | | % but not sure if this new declaration below is worth it, also since X1==Y1 or X2==Y2 is possible |
| 2341 | | :- block not_equal_couple_wf(-,?,-,?,?), % X1 or X2 must be known |
| 2342 | | not_equal_couple_wf(?,-,?,-,?), % Y1 or Y2 must be known |
| 2343 | | not_equal_couple_wf(?,-,-,?,?), % X2 or Y1 must be known |
| 2344 | | not_equal_couple_wf(-,?,?,-,?). % X1 or Y2 must be known |
| 2345 | | % (X1,X2) /= (Y1,Y2) |
| 2346 | | |
| 2347 | | % using CLPFD results in less propagation it seems |
| 2348 | | % e.g. post_constraint((A1 #\= A2 #\/ B1 #\= B2), dif((A1,B1),(A2,B2))) will not propagate if A1=A2 or B1=B2 |
| 2349 | | % we could do something like |
| 2350 | | % post_constraint((N*A1 + B1 #\= N*A2 + B2), dif((A1,B1),(A2,B2))). ; but we need to know good value for N |
| 2351 | | % TO DO: pass typing information when available ?? or not needed because type info extracted ? |
| 2352 | | |
| 2353 | | not_equal_couple_wf(X1,Y1,X2,Y2,WF) :- var(X1), var(Y1),!, |
| 2354 | | (X1==Y1 -> not_equal_object_wf(X2,Y2,WF) |
| 2355 | | ; not_equal_couple_wf_aux(X2,Y2,X1,Y1,WF)). % change order to test |
| 2356 | | not_equal_couple_wf(X1,Y1,X2,Y2,WF) :- |
| 2357 | ? | not_equal_couple_wf_aux(X1,Y1,X2,Y2,WF). |
| 2358 | | |
| 2359 | | not_equal_couple_wf_aux(X1,Y1,X2,Y2,WF) :- |
| 2360 | ? | equality_objects_wf(X1,Y1,EqRes1,WF), |
| 2361 | | (var(EqRes1) |
| 2362 | | -> equality_objects_wf(X2,Y2,EqRes2,WF), |
| 2363 | | not_equal_couple4(EqRes1,X1,Y1,EqRes2,X2,Y2) |
| 2364 | | ; EqRes1=pred_true -> not_equal_object_wf(X2,Y2,WF) |
| 2365 | | ; true). |
| 2366 | | |
| 2367 | | :- block not_equal_couple4(-,?,?,-,?,?). |
| 2368 | | not_equal_couple4(EqRes1,X1,Y1,EqRes2,X2,Y2) :- |
| 2369 | | (var(EqRes1) |
| 2370 | ? | -> not_equal_couple5(EqRes2,X1,Y1,EqRes1) |
| 2371 | | ; not_equal_couple5(EqRes1,X2,Y2,EqRes2)). |
| 2372 | | |
| 2373 | | not_equal_couple5(pred_true,_X2,_Y2,EqResOther) :- EqResOther=pred_false. |
| 2374 | | not_equal_couple5(pred_false,_,_,_). |
| 2375 | | |
| 2376 | | |
| 2377 | | /* To do: provide special support for things like |
| 2378 | | couple of fd's [done], list of fd's, set of fd's */ |
| 2379 | | |
| 2380 | | :- use_module(kernel_records,[check_field_name_compatibility/3]). |
| 2381 | | :- block not_equal_fields_wf(-,-,?). |
| 2382 | | not_equal_fields_wf([field(ID1,V1)|T1],[field(ID2,V2)|T2],WF) :- |
| 2383 | | % should we wait for ID1 or ID2 to become nonvar? |
| 2384 | | check_field_name_compatibility(ID1,ID2,not_equal_fields_wf), |
| 2385 | | (T1==[] |
| 2386 | | -> T2=[], not_equal_object_wf(V1,V2,WF) |
| 2387 | | ; not_equal_couple_wf(V1,V2,rec(T1),rec(T2),WF) % would be slightly more efficient to have a custom version of not_equal_couple |
| 2388 | | ). |
| 2389 | | |
| 2390 | | |
| 2391 | | /* ------------------------------------------- */ |
| 2392 | | /* equality_objects/3 function */ |
| 2393 | | /* ------------------------------------------- */ |
| 2394 | | |
| 2395 | | %% :- ensure_loaded(kernel_equality). |
| 2396 | | |
| 2397 | | % ---------------------------------------------------------- |
| 2398 | | % ---------------------------------------------------------- |
| 2399 | | |
| 2400 | | |
| 2401 | | |
| 2402 | | :- use_module(kernel_equality). |
| 2403 | | |
| 2404 | | % ---------------------------------------------------------- |
| 2405 | | % ---------------------------------------------------------- |
| 2406 | | |
| 2407 | | /* ---------------> */ |
| 2408 | | /* This should probably be more systematically applied before every kernel call |
| 2409 | | + expanded for other symbolic representations !! */ |
| 2410 | | |
| 2411 | | |
| 2412 | | |
| 2413 | | /* underlying assumption: if G is a global set: we get back the |
| 2414 | | global_set tag immediately: no need to use when to wait; |
| 2415 | | better: ensure that b_compute_expression always returns a nonvar term */ |
| 2416 | | |
| 2417 | | integer_global_set('NAT'). |
| 2418 | | integer_global_set('NATURAL'). |
| 2419 | | integer_global_set('NAT1'). |
| 2420 | | integer_global_set('NATURAL1'). |
| 2421 | | integer_global_set('INT'). |
| 2422 | | integer_global_set('INTEGER'). |
| 2423 | | |
| 2424 | | string_global_set('STRING'). % TODO : check what happens when we have STRING in Event-B as a set |
| 2425 | | real_global_set('REAL'). % TODO: ditto |
| 2426 | | real_global_set('FLOAT'). % TODO: ditto |
| 2427 | | |
| 2428 | | |
| 2429 | | :- assert_must_succeed(( kernel_objects:element_of_global_set(int(0),'NATURAL'))). |
| 2430 | | :- assert_must_fail(( kernel_objects:element_of_global_set(int(0),'NATURAL1'))). |
| 2431 | | :- assert_must_fail(( kernel_objects:element_of_global_set(int(-1),'NATURAL'))). |
| 2432 | | :- assert_must_succeed(( kernel_objects:element_of_global_set(int(-1),'INTEGER'))). |
| 2433 | | :- assert_must_succeed(( kernel_objects:element_of_global_set(int(0),'NAT'))). |
| 2434 | | :- assert_must_fail(( kernel_objects:element_of_global_set(int(0),'NAT1'))). |
| 2435 | | :- assert_must_succeed(( kernel_objects:element_of_global_set(X,'NAT'),X=int(1))). |
| 2436 | | :- assert_must_succeed(( kernel_objects:element_of_global_set(X,'NATURAL'),X=int(1))). |
| 2437 | | |
| 2438 | | element_of_global_set(X,GS) :- |
| 2439 | ? | init_wait_flags(WF),element_of_global_set_wf(X,GS,WF),ground_wait_flags(WF). |
| 2440 | | |
| 2441 | | element_of_global_set_wf(El,Set,WF) :- element_of_global_set_wf(El,Set,WF,unknown). |
| 2442 | | |
| 2443 | | :- use_module(kernel_reals,[is_real/1, is_float_wf/2, is_not_float/1]). |
| 2444 | | :- block element_of_global_set_wf(?,-,?,?). |
| 2445 | ? | element_of_global_set_wf(El,Set,WF,_) :- b_global_set(Set),!, |
| 2446 | | global_type_wf(El,Set,WF). |
| 2447 | | element_of_global_set_wf(X,'STRING',_WF,_) :- !, X=string(_). |
| 2448 | | element_of_global_set_wf(X,'REAL',_WF,_) :- !, is_real(X). |
| 2449 | | element_of_global_set_wf(X,'FLOAT',WF,_) :- !, is_float_wf(X,WF). |
| 2450 | | element_of_global_set_wf(int(X),GS,WF,Span) :- |
| 2451 | | element_of_global_integer_set_wf(GS,X,WF,Span). |
| 2452 | | |
| 2453 | | /* what about BOOL ?? */ |
| 2454 | | element_of_global_integer_set_wf('NAT',X,WF,_) :- |
| 2455 | | preferences:get_preference(maxint,MAXINT), |
| 2456 | | in_nat_range_wf(int(X),int(0),int(MAXINT),WF). |
| 2457 | | element_of_global_integer_set_wf('NATURAL',X,WF,Span) :- |
| 2458 | | (ground(X) -> X>=0 |
| 2459 | | ; is_natural(int(X),WF), |
| 2460 | | %get_last_wait_flag(element_of_global_set(int(X),'NATURAL'),WF,LWF), |
| 2461 | | get_integer_enumeration_wait_flag(X,'NATURAL',WF,LWF), |
| 2462 | | enumerate_natural(X,0,LWF,Span,WF) |
| 2463 | | ). |
| 2464 | | element_of_global_integer_set_wf('NAT1',X,WF,_) :- |
| 2465 | | preferences:get_preference(maxint,MAXINT), |
| 2466 | | in_nat_range_wf(int(X),int(1),int(MAXINT),WF). |
| 2467 | | element_of_global_integer_set_wf('NATURAL1',X,WF,Span) :- |
| 2468 | | (ground(X) -> X>=1 |
| 2469 | | ; is_natural1(int(X),WF), |
| 2470 | | %get_last_wait_flag(element_of_global_set_wf(int(X),'NATURAL1'),WF,LWF), |
| 2471 | | get_integer_enumeration_wait_flag(X,'NATURAL1',WF,LWF), |
| 2472 | | enumerate_natural(X,1,LWF,Span,WF) |
| 2473 | | ). |
| 2474 | | element_of_global_integer_set_wf('INT',X,WF,_) :- |
| 2475 | | preferences:get_preference(minint,MININT), |
| 2476 | | preferences:get_preference(maxint,MAXINT), |
| 2477 | | in_nat_range_wf(int(X),int(MININT),int(MAXINT),WF). |
| 2478 | | element_of_global_integer_set_wf('INTEGER',X,WF,Span) :- |
| 2479 | | (ground(X) -> true |
| 2480 | | ; get_integer_enumeration_wait_flag(X,'INTEGER',WF,LWF), |
| 2481 | | enumerate_int_wf(X,LWF,'INTEGER',WF,Span) |
| 2482 | | ). |
| 2483 | | |
| 2484 | | |
| 2485 | | get_integer_enumeration_wait_flag(X,SET,WF,LWF) :- |
| 2486 | | clpfd_domain(X,FDLow,FDUp), finite_domain(FDLow,FDUp),!, |
| 2487 | | Size is 1+FDUp-FDLow, |
| 2488 | | get_wait_flag(Size,element_of_global_set_wf(int(X),SET),WF,LWF). |
| 2489 | | get_integer_enumeration_wait_flag(X,SET,WF,LWF) :- |
| 2490 | | get_integer_enumeration_wait_flag(element_of_global_set_wf(int(X),SET),WF,LWF). |
| 2491 | | % important for e.g., solving r = /*@symbolic*/ {u|#x.(x : NATURAL & u : {x |-> x * x,x |-> x + x})} & 10|->20 : r |
| 2492 | | % 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 |
| 2493 | | |
| 2494 | | :- assert_must_succeed((kernel_objects:enumerate_int_wf(X,4,self_check,no_wf_available,unknown),X==2)). |
| 2495 | | :- block enumerate_int_wf(-,-,?,?,?). |
| 2496 | | enumerate_int_wf(X,_LWF,Source,WF,Span) :- |
| 2497 | | (ground(X) -> true |
| 2498 | | ; add_call_stack_to_span(Span,WF,Span2), % TODO: necessary? |
| 2499 | ? | enumerate_int_with_span(X,trigger_true(Source),Span2,WF)). |
| 2500 | | |
| 2501 | | :- assert_must_succeed(not_element_of_global_set(int(-1),'NAT')). |
| 2502 | | :- assert_must_succeed(not_element_of_global_set(int(-1),'NATURAL')). |
| 2503 | | :- assert_must_succeed(not_element_of_global_set(int(0),'NAT1')). |
| 2504 | | :- assert_must_succeed(not_element_of_global_set(int(0),'NATURAL1')). |
| 2505 | | not_element_of_global_set(_,GS) :- is_maximal_global_set(GS),!, fail. % covers REAL, STRING, INTEGER |
| 2506 | | not_element_of_global_set(X,'FLOAT') :- !, is_not_float(X). |
| 2507 | | not_element_of_global_set(int(X),GS) :- |
| 2508 | | (var(GS) -> add_error(kernel_objects,var_not_element_of_global_set,(int(X),GS)) ; true), |
| 2509 | ? | not_element_of_global_set2(GS,X). |
| 2510 | | not_element_of_global_set2('NAT',X) :- |
| 2511 | | preferences:get_preference(maxint,MAXINT), |
| 2512 | ? | clpfd_not_in_non_empty_range(X,0,MAXINT). %when(nonvar(X), (X<0 ; X>MAXINT)). |
| 2513 | | not_element_of_global_set2('NATURAL',X) :- is_not_natural(int(X)). |
| 2514 | | not_element_of_global_set2('NAT1',X) :- |
| 2515 | | preferences:get_preference(maxint,MAXINT), |
| 2516 | ? | clpfd_not_in_non_empty_range(X,1,MAXINT). %when(nonvar(X),(X<1 ; X>MAXINT)). |
| 2517 | | not_element_of_global_set2('NATURAL1',X) :- is_not_natural1(int(X)). |
| 2518 | | not_element_of_global_set2('INT',X) :- |
| 2519 | | preferences:get_preference(minint,MININT), |
| 2520 | | preferences:get_preference(maxint,MAXINT), |
| 2521 | | clpfd_not_in_non_empty_range(X,MININT,MAXINT). %when(nonvar(X), (X < MININT ; X > MAXINT)). |
| 2522 | | %not_element_of_global_set(string(_X),'STRING') :- fail. |
| 2523 | | %not_element_of_global_set(int(_X),'INTEGER') :- fail. |
| 2524 | | %not_element_of_global_set(_El,Set) :- b_global_set(Set), fail. |
| 2525 | | |
| 2526 | | |
| 2527 | | |
| 2528 | | /* ---- */ |
| 2529 | | /* SETS */ |
| 2530 | | /* ---- */ |
| 2531 | | |
| 2532 | | %:- block is_a_set(-). |
| 2533 | | %is_a_set(X) :- is_a_set2(X). |
| 2534 | | %is_a_set2([]) :- !. |
| 2535 | | %is_a_set2([_|_]) :- !. |
| 2536 | | %is_a_set2(X) :- is_custom_explicit_set(X,is_a_set2). |
| 2537 | | |
| 2538 | | |
| 2539 | | |
| 2540 | | |
| 2541 | | :- assert_must_succeed(exhaustive_kernel_fail_check(empty_set([int(4),int(3)]))). |
| 2542 | | :- assert_must_fail((empty_set([int(2),int(1)]))). |
| 2543 | | :- assert_must_fail((empty_set([int(1)]))). |
| 2544 | | :- assert_must_fail((empty_set([[]]))). |
| 2545 | | :- assert_must_fail((empty_set(global_set('Name')))). |
| 2546 | | :- assert_must_fail((empty_set(X),X=[int(1)])). |
| 2547 | | :- assert_must_succeed((empty_set([]))). |
| 2548 | | empty_set(X) :- (var(X) -> X=[] |
| 2549 | | ; X=[] -> true |
| 2550 | | % ; X=[_|_] -> fail |
| 2551 | | ; is_custom_explicit_set_nonvar(X),is_empty_explicit_set(X)). |
| 2552 | | empty_set_wf(X,WF) :- (var(X) -> X=[] |
| 2553 | | ; X=[] -> true |
| 2554 | | % ; X=[_|_] -> fail |
| 2555 | | ; is_custom_explicit_set_nonvar(X),is_empty_explicit_set_wf(X,WF)). |
| 2556 | | |
| 2557 | | |
| 2558 | | :- assert_must_succeed(exhaustive_kernel_check(not_empty_set([int(4),int(3)]))). |
| 2559 | | :- assert_must_succeed((kernel_objects:not_empty_set([int(2),int(1)]))). |
| 2560 | | :- assert_must_succeed((kernel_objects:not_empty_set([int(1)]))). |
| 2561 | | :- assert_must_succeed((kernel_objects:not_empty_set([[]]))). |
| 2562 | | :- assert_must_succeed((kernel_objects:not_empty_set(global_set('Name')))). |
| 2563 | | :- assert_must_succeed((kernel_objects:not_empty_set_lwf(X,1),nonvar(X),X=[_|_])). |
| 2564 | | :- assert_must_succeed((kernel_objects:not_empty_set_lwf([int(1)],_))). |
| 2565 | | :- assert_must_fail((kernel_objects:not_empty_set([]))). |
| 2566 | | |
| 2567 | | :- use_module(kernel_non_empty_attr,[mark_var_set_as_non_empty/1]). |
| 2568 | | |
| 2569 | | not_empty_set_wf(S,WF) :- WF==no_wf_available,!, not_empty_set2(S,WF). |
| 2570 | | not_empty_set_wf(S,WF) :- var(S), !, |
| 2571 | | (preferences:preference(use_smt_mode,true) -> S=[_|_] |
| 2572 | | % ; WF=no_wf_available -> not_empty_set(S) |
| 2573 | | ; get_large_finite_wait_flag(not_empty_set_wf,WF,LWF), |
| 2574 | | % print(not_empty(S)),nl, % TO DO: set kernel_cardinality attribute if variable |
| 2575 | | mark_var_set_as_non_empty(S), |
| 2576 | | not_empty_set_lwf(S,LWF)). |
| 2577 | | not_empty_set_wf(closure(P,T,B),WF) :- !, is_non_empty_explicit_set_wf(closure(P,T,B),WF). |
| 2578 | | not_empty_set_wf(S,WF) :- not_empty_set2(S,WF). |
| 2579 | | |
| 2580 | | :- block not_empty_set_lwf(-,-). |
| 2581 | | % the instantiation with a list skeleton can easily cause multiple solutions for the same |
| 2582 | | % set to be found: hence we guard it by a wait flag |
| 2583 | | not_empty_set_lwf(S,_LWF) :- var(S),!, |
| 2584 | | S=[_|_]. |
| 2585 | | not_empty_set_lwf(S,_) :- not_empty_set(S). |
| 2586 | | |
| 2587 | | not_empty_set(Set) :- not_empty_set2(Set,no_wf_available). |
| 2588 | | |
| 2589 | | :- use_module(error_manager,[add_warning/2]). |
| 2590 | | :- block not_empty_set2(-,?). |
| 2591 | | %not_empty_set(S) :- var(S),!,S=[_|_]. |
| 2592 | | % not_empty_set(X) :- not_equal_object([],X). |
| 2593 | | not_empty_set2([_|_],_). |
| 2594 | | not_empty_set2(avl_set(A),_) :- (A==empty -> add_warning(not_empty_set,'Empty avl_set'),fail ; true). |
| 2595 | | not_empty_set2(closure(P,T,B),WF) :- is_non_empty_explicit_set_wf(closure(P,T,B),WF). % TO DO: also use WF |
| 2596 | | not_empty_set2(global_set(Type),_) :- b_non_empty_global_set(Type). |
| 2597 | | not_empty_set2(freetype(ID),_) :- kernel_freetypes:is_non_empty_freetype(ID). |
| 2598 | | |
| 2599 | | % there also exists: eq_empty_set , a reified version, i.e., test_empty_set |
| 2600 | | |
| 2601 | | |
| 2602 | | :- assert_must_succeed((exact_element_of(int(1),[int(2),int(1)]))). |
| 2603 | | :- assert_must_succeed((exact_element_of(int(1),[int(2),int(3),int(4),int(1)]))). |
| 2604 | | :- assert_must_succeed((exact_element_of(int(4),[int(2),int(3),int(4),int(1)]))). |
| 2605 | | :- assert_must_succeed((exact_element_of(int(1),[int(2),int(3)|T]), T=[int(4),int(1)])). |
| 2606 | | :- assert_must_fail((exact_element_of(int(5),[int(2),int(3)|T]), T=[int(4),int(1)])). |
| 2607 | | :- assert_must_succeed((exact_element_of(fd(1,'Name'),global_set('Name')))). |
| 2608 | | :- assert_must_succeed((exact_element_of([int(2),int(1)],[[],[int(2),int(1)]]))). |
| 2609 | | :- assert_must_fail((exact_element_of([int(1),int(2)],[[],[int(2),int(1)]]))). |
| 2610 | | %:- assert_must_succeed((exact_element_of([(int(1),fd(2,'Name'))], |
| 2611 | | % closure([zzzz],[set(couple(integer,global('Name')))], 'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2612 | | % 'Seq'(value([fd(1,'Name'),fd(2,'Name')]))))) )). |
| 2613 | | %:- assert_must_succeed((exact_element_of(XX, |
| 2614 | | % closure([zzzz],[set(couple(integer,global('Name')))], 'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2615 | | % 'Seq'(value([fd(1,'Name'),fd(2,'Name')]))))), |
| 2616 | | % equal_object(XX,[(int(1),fd(1,'Name'))]) )). |
| 2617 | | %:- assert_must_succeed(( |
| 2618 | | %exact_element_of(XX,closure([zzzz],[set(couple(integer,global('Name')))], |
| 2619 | | % 'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2620 | | % 'Perm'(value([fd(1,'Name'),fd(2,'Name')]))))), |
| 2621 | | % equal_object(XX,[(int(1),fd(2,'Name')),(int(2),fd(1,'Name'))]) )). |
| 2622 | | |
| 2623 | | %:- assert_must_succeed(( exact_element_of(X, |
| 2624 | | % closure([zzzz],[set(record([field(balance,integer),field(name,global('Code'))]))], |
| 2625 | | % 'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2626 | | % 'PowerSet'(value(closure([zzzz], |
| 2627 | | % [record([field(balance,integer),field(name,global('Code'))])],'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2628 | | % 'SetOfRecords'(value(cons_expr(field(balance,global_set('NAT')), |
| 2629 | | % cons_expr(field(name,global_set('Code')),nil_expr))))))))))), |
| 2630 | | % X=[rec([field(balance,int(0)),field(name,fd(2,'Code'))])] )). |
| 2631 | | %:- assert_must_fail(( exact_element_of(X, |
| 2632 | | % closure([zzzz],[set(record([field(balance,integer),field(name,global('Code'))]))], |
| 2633 | | % 'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2634 | | % 'PowerSet'(value(closure([zzzz], |
| 2635 | | % [record([field(balance,integer),field(name,global('Code'))])],'In'('ListExpression'(['Identifier'(zzzz)]), |
| 2636 | | % 'SetOfRecords'(value(cons_expr(field(balance,global_set('NAT')), |
| 2637 | | % cons_expr(field(name,global_set('Code')),nil_expr))))))))))), |
| 2638 | | % X=[rec([field(balance,int(-1)),field(name,fd(2,'Code'))])] )). |
| 2639 | | |
| 2640 | | |
| 2641 | | /* use this to compute elements */ |
| 2642 | | exact_element_of(X,Set) :- |
| 2643 | | dif(Set,[]), |
| 2644 | ? | exact_element_of2(Set,X). |
| 2645 | | :- block exact_element_of2(-,?). |
| 2646 | | exact_element_of2([H|_],H). |
| 2647 | ? | exact_element_of2([_|T],E) :- exact_element_of3(T,E). |
| 2648 | | exact_element_of2(X,E) :- is_custom_explicit_set_nonvar(X), check_element_of(E,X). |
| 2649 | | :- block exact_element_of3(-,?). |
| 2650 | | exact_element_of3([H|_],H). |
| 2651 | ? | exact_element_of3([_|T],E) :- exact_element_of3(T,E). |
| 2652 | | |
| 2653 | | |
| 2654 | | :- assert_must_succeed(exhaustive_kernel_check(check_element_of(int(1),[int(2),int(1)]))). |
| 2655 | | :- assert_must_succeed(exhaustive_kernel_fail_check(check_element_of(int(3),[int(2),int(1)]))). |
| 2656 | | :- assert_must_succeed(exhaustive_kernel_fail_check(check_element_of(int(1),[]))). |
| 2657 | | |
| 2658 | | /* uses equal_object instead of unification */ |
| 2659 | | :- assert_must_succeed((check_element_of(X, |
| 2660 | | [(int(1),(int(1),(int(1),int(1)))),(int(2),(int(1),(int(1),int(1)))), |
| 2661 | | (int(1),(int(1),(int(1),int(2)))),(int(2),(int(1),(int(1),int(2))))]), |
| 2662 | | equal_object(X, (int(2),(int(1),(int(1),int(2))))) )). |
| 2663 | | :- assert_must_succeed((check_element_of(X, |
| 2664 | | [ (((int(1),int(1)),int(1)),int(1)), (((int(1),int(1)),int(1)),int(2)), |
| 2665 | | (((int(1),int(1)),int(1)),int(3)), (((int(1),int(1)),int(1)),int(4)), |
| 2666 | | (((int(1),int(1)),int(2)),int(1)), (((int(1),int(1)),int(2)),int(2)) |
| 2667 | | ]), equal_object(X, (((int(1),int(1)),int(2)),int(1))) |
| 2668 | | )). |
| 2669 | | :- assert_must_succeed((check_element_of(fd(1,'Name'),global_set('Name')))). |
| 2670 | | %:- assert_must_succeed_multiple(check_element_of(X,[[fd(1,'Name')],[]])). |
| 2671 | | :- assert_must_succeed((check_element_of((int(1),int(2)),[(int(1),int(2))]))). |
| 2672 | | :- assert_must_succeed((check_element_of((_X,_Y),[(fd(2,'Code'),fd(2,'Code'))]))). |
| 2673 | | :- assert_must_succeed((init_wait_flags(WF), |
| 2674 | | check_element_of_wf((X,Y),[(fd(2,'Code'),fd(2,'Code'))],WF), |
| 2675 | | ground_det_wait_flag(WF), X= fd(2,'Code'), Y= fd(2,'Code'), |
| 2676 | | kernel_waitflags:ground_wait_flags(WF) )). |
| 2677 | | :- assert_must_succeed((init_wait_flags(WF), |
| 2678 | | check_element_of_wf((Y,X),[(fd(2,'Code'),fd(2,'Code'))],WF), |
| 2679 | | ground_det_wait_flag(WF), X= fd(2,'Code'), Y= fd(2,'Code'), |
| 2680 | | kernel_waitflags:ground_wait_flags(WF) )). |
| 2681 | | :- assert_must_succeed((check_element_of([int(1),int(2)],[[int(2),int(1)]]))). |
| 2682 | | |
| 2683 | | :- assert_must_succeed((check_element_of([int(1),int(2)],[[],[int(2),int(1)]]))). |
| 2684 | | :- assert_must_succeed((check_element_of(X,[[],[int(2),int(1)]]), X==[] )). |
| 2685 | | :- assert_must_succeed((check_element_of_wf(X,[[],[int(2),int(1)]],_WF), |
| 2686 | | equal_object(X,[int(1),int(2)]) )). |
| 2687 | | :- assert_must_succeed((check_element_of_wf(XX,global_set('Name'),WF),kernel_waitflags:ground_wait_flags(WF), XX==fd(3,'Name') )). |
| 2688 | | :- assert_must_fail(check_element_of([fd(2,'Name')],[[fd(1,'Name')],[]])). |
| 2689 | | :- assert_must_fail((check_element_of([int(2)],[[],[int(2),int(1)]]))). |
| 2690 | | :- assert_must_succeed((check_element_of(int(1),_X))). |
| 2691 | | :- assert_must_succeed((check_element_of((int(2),_X),[(int(1),[(int(1),int(22))]),(int(2),[(int(1),int(55))])]))). |
| 2692 | | |
| 2693 | | check_element_of(X,Set) :- init_wait_flags(WF,[check_element_of]), |
| 2694 | | check_element_of_wf(X,Set,WF), |
| 2695 | ? | ground_wait_flags(WF). |
| 2696 | | |
| 2697 | | % new test: check_element_of(int(1),X). |
| 2698 | | % new test: check_element_of(int(1),[int(2)|X]). |
| 2699 | | |
| 2700 | | check_element_of_wf(X,Set,WF) :- %print(el_of(X,Set)),nl, |
| 2701 | | dif(Set,[]), |
| 2702 | | % TO do: mark Set as non-empty not_empty_set_wf from kernel_cardinality_attr |
| 2703 | ? | check_element_of1(X,Set,WF). |
| 2704 | | |
| 2705 | | %check_element_of1(X,Set,WF) :- var(X),var(Set),unbound_variable_check(Set),!, |
| 2706 | | % Set=[_|_], check_element_of2(Set,X,WF). |
| 2707 | | %:- block check_element_of1(-,-,?). %% |
| 2708 | | |
| 2709 | | |
| 2710 | | %:- block check_element_of1(-,-,?). % leads to time-out in test 292 for {x,S,S2|x : S & S <: (1 .. 213) & S \/ {x} = S2 & x /: S2} and test 1976 in data_validation mode and CLPFD false |
| 2711 | | check_element_of1(X,Set,WF) :- |
| 2712 | | (unbound_variable_for_element_of(Set), |
| 2713 | | preference(data_validation_mode,false) % TODO: this leads to failure of test 1976 with CLPFD FALSE |
| 2714 | | % but avoids instantiating Sets to lists early on: can disturb enumeration and efficient computation/unification of large sets |
| 2715 | ? | -> check_element_of_unbound_set(X,Set,WF) |
| 2716 | ? | ; check_element_of2(Set,X,WF) |
| 2717 | | ). |
| 2718 | | |
| 2719 | | check_element_of_unbound_set(X,Set,_WF) :- |
| 2720 | | mark_as_non_free(X,check_element_of_unbound_set), |
| 2721 | | Set=[X|_]. % Note: X needs to be nonvar so that other code knows X is not free anymore |
| 2722 | | % TO DO: normalise X ? |
| 2723 | | % TO DO: do this using CHR/attributes rather than by instantiation |
| 2724 | | |
| 2725 | | |
| 2726 | | unbound_variable_for_element_of(Set) :- unbound_variable_for_cons(Set). |
| 2727 | | |
| 2728 | | % attach co-routine to mark a given term as not a real variable |
| 2729 | | mark_as_non_free(X,_Info) :- var(X) -> non_free(X) ; true. |
| 2730 | | mark_as_non_free(X) :- var(X) -> non_free(X) ; true. |
| 2731 | | :- block non_free(-). |
| 2732 | | non_free([H|T]) :- !, mark_as_non_free(H), mark_as_non_free(T). |
| 2733 | | non_free((A,B)) :- !, mark_as_non_free(A), mark_as_non_free(B). |
| 2734 | | non_free(rec(Fields)) :- !, mark_as_non_free_fields(Fields). |
| 2735 | | non_free(_). |
| 2736 | | :- block mark_as_non_free_fields(-). |
| 2737 | | mark_as_non_free_fields([]). |
| 2738 | | mark_as_non_free_fields([field(_,Val)|T]) :- mark_as_non_free(Val),mark_as_non_free_fields(T). |
| 2739 | | |
| 2740 | | :- use_module(clpfd_lists,[lazy_fd_value_check/4]). |
| 2741 | | |
| 2742 | | :- block check_element_of2(-,?,?). |
| 2743 | | check_element_of2(CS,El,WF) :- |
| 2744 | ? | is_custom_explicit_set_nonvar(CS),!, element_of_custom_set_wf(El,CS,WF). |
| 2745 | | check_element_of2([],_,_) :- !,fail. |
| 2746 | | %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, |
| 2747 | | % element_of_custom_set_wf(El,AVL,WF). |
| 2748 | | check_element_of2([H|T],E,WF) :- !, % print(check_element_of4w(E,H,T,WF)),nl, |
| 2749 | | % try and transform E : Set into clpfd:element(_,FDVals,EFD) check: |
| 2750 | | lazy_fd_value_check([H|T],E,WF,FullyChecked), |
| 2751 | | %get_partial_set_priority([H|T],WF,LWF), %% |
| 2752 | | %get_wait_flag(2,check_element_of2([H|T],E),WF,LWF), %% |
| 2753 | | (FullyChecked==true,ground(E) -> true % no need to check |
| 2754 | | ; get_cardinality_wait_flag([H|T],check_element_of2,WF,LWF), |
| 2755 | ? | 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) |
| 2756 | | ). |
| 2757 | | check_element_of2(freetype(Id),E,WF) :- !, is_a_freetype_wf(E,Id,WF). |
| 2758 | | check_element_of2(term(Z),_E,_WF) :- Z==undefined,!, |
| 2759 | | add_error_fail(check_element_of2,'Encountered uninitialised set variable', ''). |
| 2760 | | check_element_of2(Set,E,WF) :- |
| 2761 | | add_internal_error('Illegal argument: ',check_element_of2(Set,E,WF)),fail. |
| 2762 | | |
| 2763 | | |
| 2764 | | % call if you already have an explicit waitflag (LWF) setup for the cardinality of the set |
| 2765 | | :- block check_element_of_wf_lwf(?,-,?,?). |
| 2766 | | check_element_of_wf_lwf(El,CS,WF,_LWF) :- |
| 2767 | ? | is_custom_explicit_set_nonvar(CS),!, element_of_custom_set_wf(El,CS,WF). |
| 2768 | ? | check_element_of_wf_lwf(E,[H|T],WF,LWF) :- check_element_of4w(E,H,T,WF,LWF). |
| 2769 | | check_element_of_wf_lwf(E,freetype(Id),WF,_) :- !, is_a_freetype_wf(E,Id,WF). |
| 2770 | | |
| 2771 | | :- block check_element_of4w(-,?,-,?,-). |
| 2772 | | % check_element_of4w(E,H,T,_WF,_LWF) :- print(check_element_of4w(E,H,T,_WF,_LWF)),nl,fail. |
| 2773 | ? | check_element_of4w(E,H,T,_WF,_LWF) :- T==[],!,equal_object(E,H,check_element_of4w). |
| 2774 | | check_element_of4w(E,H,_T,_WF,_LWF) :- E==H ,!. %,print(eq(E,H)),nl. % added by mal, 17.10 2007 |
| 2775 | | check_element_of4w(E,H,T,WF,LWF) :- T\==[], |
| 2776 | ? | equality_objects_lwf(E,H,Res,LWF,WF), |
| 2777 | ? | check_element_of4(Res,E,T,WF,LWF). |
| 2778 | | |
| 2779 | | :- block check_element_of4(-,?,?,?,-). |
| 2780 | | check_element_of4(pred_true,_E,_,_WF,_LWF). |
| 2781 | | check_element_of4(pred_false,E,T,WF,LWF) :- |
| 2782 | ? | (var(T) -> T = [E|_] ; check_element_of5(E,T,WF,LWF)). |
| 2783 | | |
| 2784 | | :- block check_element_of5(?,-,?,?). |
| 2785 | | check_element_of5(E,R,WF,LWF) :- |
| 2786 | | get_next_element(R,H,T), |
| 2787 | ? | check_element_of4w(E,H,T,WF,LWF). |
| 2788 | | |
| 2789 | | |
| 2790 | | |
| 2791 | | :- assert_must_succeed(exhaustive_kernel_check(not_element_of(int(3),[int(2),int(1)]))). |
| 2792 | | :- assert_must_succeed(exhaustive_kernel_check(not_element_of(int(3),[int(2),int(1),int(4)]))). |
| 2793 | | :- assert_must_succeed(exhaustive_kernel_fail_check(not_element_of(int(1),[int(2),int(1)]))). |
| 2794 | | :- assert_must_succeed((kernel_objects:not_element_of(int(3),[int(2),int(1)]))). |
| 2795 | | :- assert_must_succeed((kernel_objects:not_element_of(fd(1,'Name'),[]))). |
| 2796 | | :- assert_must_fail((kernel_objects:not_element_of(fd(1,'Name'),global_set('Name')))). |
| 2797 | | :- assert_must_succeed((kernel_objects:not_element_of(X,[fd(1,'Name')]),X = fd(2,'Name'))). |
| 2798 | | :- assert_must_fail((kernel_objects:not_element_of(X,[fd(1,'Name')]),X = fd(1,'Name'))). |
| 2799 | | :- assert_must_succeed(kernel_objects:not_element_of(term(a),[])). |
| 2800 | | :- assert_must_fail((kernel_objects:not_element_of(int(1),[int(2),int(1)]))). |
| 2801 | | :- assert_must_succeed((kernel_objects:not_element_of([int(1),int(2)], |
| 2802 | | [[int(1)],[int(0),int(4)],[int(0),int(3)],[int(0),int(1)],[int(0)],[]]))). |
| 2803 | | :- assert_must_fail((kernel_objects:not_element_of(term(3),[int(2),int(1)]))). |
| 2804 | | |
| 2805 | | |
| 2806 | | not_element_of(X,Set) :- init_wait_flags(WF,[not_element_of]), |
| 2807 | ? | not_element_of_wf(X,Set,WF), |
| 2808 | ? | ground_wait_flags(WF). |
| 2809 | | |
| 2810 | | :- use_module(b_global_sets,[b_get_fd_type_bounds/3]). |
| 2811 | | :- block not_element_of_wf(-,-,?). |
| 2812 | | not_element_of_wf(_,Set,_) :- Set==[],!. |
| 2813 | | not_element_of_wf(El,Set,WF) :- nonvar(El),El=fd(X,GS),b_get_fd_type_bounds(GS,N,N),!, |
| 2814 | | % we have a global set with a single element; Set must be empty |
| 2815 | | X=N,empty_set_wf(Set,WF). |
| 2816 | ? | not_element_of_wf(El,Set,WF) :- not_element_of_wf1(Set,El,WF). |
| 2817 | | |
| 2818 | | :- block not_element_of_wf1(-,?,?). |
| 2819 | | not_element_of_wf1(X,E,WF) :- is_custom_explicit_set_nonvar(X),!, |
| 2820 | | not_element_of_custom_set_wf(E,X,WF). |
| 2821 | | not_element_of_wf1([],_E,_WF). |
| 2822 | | not_element_of_wf1([H|T],E,WF) :- |
| 2823 | ? | not_equal_object_wf(E,H,WF), |
| 2824 | ? | not_element_of_wf1(T,E,WF). |
| 2825 | | |
| 2826 | | |
| 2827 | | :- assert_must_succeed(exhaustive_kernel_check(add_element(int(3),[int(2),int(1)],[int(1),int(3),int(2)]))). |
| 2828 | | :- assert_must_succeed(exhaustive_kernel_fail_check(add_element(int(2),[int(2),int(1)],[int(1),int(3),int(2)]))). |
| 2829 | | :- assert_must_succeed(exhaustive_kernel_fail_check(add_element(int(4),[int(2),int(1)],[int(1),int(3),int(2)]))). |
| 2830 | | :- assert_must_succeed((kernel_objects:add_element(int(3),[int(2),int(1)],R), |
| 2831 | | kernel_objects:equal_object(R,[int(1),int(2),int(3)]))). |
| 2832 | | :- assert_must_succeed((kernel_objects:add_element([int(2)],[[int(2),int(1)],[]],R), |
| 2833 | | kernel_objects:equal_object(R,[[],[int(1),int(2)],[int(2)]]))). |
| 2834 | | :- assert_must_succeed((kernel_objects:add_element([int(1),int(2)],[[int(2),int(1)],[]],R), |
| 2835 | | kernel_objects:equal_object(R,[[],[int(1),int(2)]]))). |
| 2836 | | :- assert_must_succeed((kernel_objects:add_element(X,[int(2),int(1)],R), |
| 2837 | | kernel_objects:equal_object(R,[int(1),int(2)]), X = int(1))). |
| 2838 | | :- assert_must_succeed((kernel_objects:add_element([int(1),int(2)], |
| 2839 | | [[int(1)],[int(0),int(4)],[int(0),int(3)],[int(0),int(1)],[int(0)],[]], _R))). |
| 2840 | | |
| 2841 | | :- assert_must_succeed((kernel_objects:add_element(int(3),[int(X),int(1)],R,D), |
| 2842 | | var(D), X=3, R==[int(3),int(1)], D==done)). |
| 2843 | | |
| 2844 | | :- assert_must_fail((kernel_objects:add_element(term(msg),[int(2),int(1)],_R))). |
| 2845 | | :- assert_must_succeed((kernel_objects:add_element(int(3),[int(2),int(X)],R), |
| 2846 | | nonvar(R), R =[H|T], H==int(2), nonvar(T),T=[_HH|TT],var(TT), |
| 2847 | | X=4, T==[int(4),int(3)])). |
| 2848 | | :- assert_must_succeed((kernel_objects:add_element(int(3),[int(2),int(X)],R), |
| 2849 | | nonvar(R), R =[H|T], H==int(2), nonvar(T),T=[_HH|TT],var(TT), |
| 2850 | | X=3, T==[int(3)])). |
| 2851 | | :- assert_must_succeed((kernel_objects:add_element(int(3),X,[int(2),int(3)]), |
| 2852 | | kernel_objects:equal_object(X,[int(2)]) )). |
| 2853 | | :- assert_must_succeed((kernel_objects:add_element(int(3),X,[int(3)]), |
| 2854 | | kernel_objects:equal_object(X,[]) )). |
| 2855 | | :- assert_must_succeed((add_element(X,[int(1)],[int(1)]),X==int(1))). |
| 2856 | | :- assert_must_succeed((add_element(X,[],[int(1)]),X==int(1))). |
| 2857 | | % kernel_objects:add_element(E,[H],R,Done), H = int(X), E=int(Y), X in 1..10, Y in 11..20. |
| 2858 | | |
| 2859 | | |
| 2860 | | add_element(E,Set,NewSet) :- add_element(E,Set,NewSet,_). |
| 2861 | | add_element(Element,Set,NewSet,Done) :- add_element_wf(Element,Set,NewSet,Done,no_wf_available). |
| 2862 | | add_element_wf(E,Set,NewSet,WF) :- add_element_wf(E,Set,NewSet,_,WF). |
| 2863 | | |
| 2864 | | :- block add_element_wf(?,-,?,?,?). |
| 2865 | | add_element_wf(Element,Set,NewSet,Done,_WF) :- Set==[],!, |
| 2866 | | % try and convert to AVL if possible: |
| 2867 | ? | equal_object_optimized(NewSet,[Element]), % we could call equal_object_opt3 directly |
| 2868 | | Done=done. |
| 2869 | | add_element_wf(E,Set,NewSet,Done,WF) :- add_element1_wf(E,Set,NewSet,Done,WF). |
| 2870 | | |
| 2871 | | :- block %add_element1(-,?,-,?), |
| 2872 | | add_element1_wf(?,-,?,?,?). |
| 2873 | | add_element1_wf(E,Set,NewSet,Done,WF) :- var(E),!, add_element_var(Set,NewSet,E,Done,WF). |
| 2874 | | 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 |
| 2875 | | equal_object_wf(NewSet,[H|T],add_element1_1,WF),Done=done. |
| 2876 | | add_element1_wf(E,Set,NewSet,Done,WF) :- |
| 2877 | | nonvar(Set), is_custom_explicit_set_nonvar(Set), |
| 2878 | | add_element_to_explicit_set_wf(Set,E,R,WF),!, |
| 2879 | | equal_object_wf(R,NewSet,add_element1_2,WF),Done=done. |
| 2880 | | add_element1_wf(E,Set,NewSet,Done,WF) :- |
| 2881 | | expand_custom_set_to_list_wf(Set,ESet,_,add_element1,WF), % we could avoid this expansion by treating avl_set,... below in add_element3 |
| 2882 | | add_element2_wf(ESet,E,NewSet,Done,WF). |
| 2883 | | |
| 2884 | | |
| 2885 | | add_element_var([],Res,Element,Done,WF) :- !, |
| 2886 | | equal_cons_wf(Res,Element,[],WF),Done=done. |
| 2887 | | add_element_var(Set,Res,Element,Done,WF) :- Set \= [], Set \= closure(_,_,_), |
| 2888 | | is_one_element_set(Res,ResEl), !, |
| 2889 | | % the result is a one element set; hence Element *must* be the element in that set |
| 2890 | | equal_object_wf(Element,ResEl,add_element_var_1,WF), |
| 2891 | | equal_object_wf(Set,Res,add_element_var_2,WF), Done=done. |
| 2892 | | add_element_var(Set,Res,Element,Done,WF) :- %when(nonvar(Element), add_element(Element,Set,Res,Done)). |
| 2893 | | expand_custom_set_to_list_wf(Set,ESet,_,add_element_var,WF), |
| 2894 | | add_element2_wf(ESet,Element,Res,Done,WF). |
| 2895 | | |
| 2896 | | is_one_element_set(S,_) :- var(S),!,fail. |
| 2897 | | is_one_element_set([H|T],H) :- T==[]. |
| 2898 | | is_one_element_set(avl_set(S),El) :- is_one_element_custom_set(avl_set(S),El). |
| 2899 | | |
| 2900 | | :- block add_element2_wf(-,?,?,?,?). |
| 2901 | | add_element2_wf([],E,Res,Done,WF) :- var(Res),should_be_converted_to_avl(E), |
| 2902 | | construct_avl_from_lists_wf([E],R,WF),!, |
| 2903 | | (R,Done)=(Res,done). |
| 2904 | | add_element2_wf(S,E,Res,Done,WF) :- copy_list_skeleton(S,Res,WF), |
| 2905 | | add_element3_wf(S,E,Res,Done,WF). |
| 2906 | | |
| 2907 | | % TO DO: use something else, like subset to propagate info that Set1 <: Set1 \/ {New} |
| 2908 | | :- block copy_list_skeleton(-,?,?). |
| 2909 | | copy_list_skeleton([],_,_WF) :- !. |
| 2910 | | 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 |
| 2911 | | ((ground_value(H) ; unbound_variable_for_cons(R) ; |
| 2912 | | custom_explicit_sets:singleton_set(R,_) % if R is a singleton set {EL} then H must be EL and T=[] |
| 2913 | | ) |
| 2914 | | -> equal_cons_wf(R,H,RR,WF), |
| 2915 | | copy_list_skeleton(T,RR,WF) |
| 2916 | | ; %nl,print(not_copying([H|T],R)),nl, |
| 2917 | | 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 |
| 2918 | | ). |
| 2919 | | copy_list_skeleton(Set,R,WF) :- !,is_custom_explicit_set(Set,copy_list_skeleton), |
| 2920 | | expand_custom_set_to_list_wf(Set,ESet,_,copy_list_skeleton,WF), copy_list_skeleton(ESet,R,WF). |
| 2921 | | copy_list_skeleton(Skel,R,WF) :- add_internal_error('Argument not a set: ',copy_list_skeleton(Skel,R,WF)). |
| 2922 | | |
| 2923 | | :- block add_element3_wf(-,?,?,?,?). |
| 2924 | | add_element3_wf([],E,Res,Done,WF) :- % Res must be {E} |
| 2925 | | equal_cons_wf(Res,E,[],WF), |
| 2926 | | Done=done. |
| 2927 | | add_element3_wf([H|T],E,Res,Done,WF) :- |
| 2928 | | equality_objects_wf(H,E,EqRes,WF), |
| 2929 | ? | equal_cons_wf(Res,H,TailRes,WF), % was: equal_object([H|TailRes],Res), % use WF? |
| 2930 | | (var(EqRes) |
| 2931 | | -> has_not_to_be_added([H|T],Res,EqRes,0) |
| 2932 | | ; true), |
| 2933 | | %(when(nonvar(EqRes),(print(nv(EqRes,H,T,WF)),nl))), |
| 2934 | | add_element4_wf(EqRes,T,E,TailRes,Done,WF). |
| 2935 | | |
| 2936 | | |
| 2937 | | % check if an element has not to be added to arg1 to obtain arg2 |
| 2938 | | :- block has_not_to_be_added(?,-,?,?),has_not_to_be_added(-,?,?,?). |
| 2939 | | %has_not_to_be_added(A,B,R,Sz) :- print(has_not_to_be_added(A,B,R,Sz)),nl,fail. |
| 2940 | | has_not_to_be_added([],[],R,Sz) :- !,(Sz=1 -> R=pred_true % we have 1 element: force equality with first element |
| 2941 | | ; true). |
| 2942 | | has_not_to_be_added([],[_H|T],R,_Sz) :- !, %(var(R) -> print(add_f([],[_H|T],R,_Sz)),nl ; true), |
| 2943 | | empty_set(T),R=pred_false. % R=pred_false means with add an element |
| 2944 | | has_not_to_be_added([_|_],[],_,_) :- !,fail. % we can either add or not; in both cases we do not obtain [] |
| 2945 | | has_not_to_be_added([_|T1],[_|T2],R,Sz) :- !, S1 is Sz+1, has_not_to_be_added(T1,T2,R,S1). |
| 2946 | | has_not_to_be_added(_,_,_,_). % to do: support custom explicit sets |
| 2947 | | |
| 2948 | | :- block add_element4_wf(-,?,?,?,?,?). |
| 2949 | | add_element4_wf(pred_true, T,_E,TRes,Done,WF) :- equal_object_wf(T,TRes,add_element4_wf,WF), Done=done. |
| 2950 | | add_element4_wf(pred_false,T, E,TRes,Done,WF) :- add_element3_wf(T,E,TRes,Done,WF). |
| 2951 | | |
| 2952 | | |
| 2953 | | :- assert_must_succeed((kernel_objects:add_new_element(int(3),[int(2),int(1)],R), |
| 2954 | | kernel_objects:equal_object(R,[int(1),int(2),int(3)]))). |
| 2955 | | :- assert_must_succeed((kernel_objects:add_new_element([int(2)],[[int(2),int(1)],[]],R), |
| 2956 | | kernel_objects:equal_object(R,[[],[int(1),int(2)],[int(2)]]))). |
| 2957 | | |
| 2958 | | % TO DO : get rid of need for non-WF version in enumeration basic type: |
| 2959 | | add_new_element(E,Set,NewSet) :- init_wait_flags(WF), |
| 2960 | | add_new_element_wf(E,Set,NewSet,WF), ground_wait_flags(WF). |
| 2961 | | |
| 2962 | | % use when you are sure the element to add is not in the set |
| 2963 | | % to be used for adding elements to an accumulator |
| 2964 | | :- block add_new_element_wf(?,-,?,?). |
| 2965 | | %%add_new_element(E,Set,NewSet) :- add_element(E,Set,NewSet). % TO DO : Improve |
| 2966 | | add_new_element_wf(E,Set,NewSet,WF) :- |
| 2967 | | is_custom_explicit_set(Set,add_element), |
| 2968 | | add_element_to_explicit_set_wf(Set,E,R,WF),!, |
| 2969 | | equal_object_wf(R,NewSet,add_new_element_wf,WF). |
| 2970 | | add_new_element_wf(E,Set,NewSet,WF) :- |
| 2971 | | expand_custom_set_to_list_wf(Set,ESet,_,add_new_element_wf,WF), |
| 2972 | | add_new_element2(ESet,E,NewSet,WF). |
| 2973 | | |
| 2974 | | :- block add_new_element2(-,?,?,?). |
| 2975 | | add_new_element2([],E,Res,WF) :- var(Res),should_be_converted_to_avl(E), |
| 2976 | | construct_avl_from_lists_wf([E],R,WF),!,equal_object_wf(R,Res,add_new_element2,WF). |
| 2977 | | add_new_element2(S,E,Res,WF) :- equal_cons_wf(Res,E,S,WF). |
| 2978 | | |
| 2979 | | |
| 2980 | | |
| 2981 | | |
| 2982 | | :- assert_must_succeed(exhaustive_kernel_check(remove_element_wf(int(3),[int(3),int(1)], |
| 2983 | | [int(1)],_WF))). |
| 2984 | | :- assert_must_succeed(exhaustive_kernel_check(remove_element_wf(int(1),[int(3),int(1)], |
| 2985 | | [int(3)],_WF))). |
| 2986 | | :- assert_must_succeed(exhaustive_kernel_fail_check(remove_element_wf(int(1),[int(3),int(1)], |
| 2987 | | [int(1)],_WF))). |
| 2988 | | :- assert_must_succeed(exhaustive_kernel_fail_check(remove_element_wf(int(11),[int(1)], |
| 2989 | | [int(1)],_WF))). |
| 2990 | | :- assert_must_succeed(exhaustive_kernel_fail_check(remove_element_wf(int(1),[int(3),int(1)], |
| 2991 | | [],_WF))). |
| 2992 | | :- assert_must_succeed((kernel_objects:remove_element_wf(fd(1,'Name'),X,[fd(2,'Name'),fd(3,'Name')],_WF), |
| 2993 | | kernel_objects:equal_object(X,global_set('Name')))). |
| 2994 | | :- assert_must_succeed((kernel_objects:remove_element_wf(int(1),X,[int(2)],_WF), |
| 2995 | | kernel_objects:equal_object(X,[int(2),int(1)]))). |
| 2996 | | :- 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)] )). |
| 2997 | | :- 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)] )). |
| 2998 | | :- 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 */] )). |
| 2999 | | |
| 3000 | ? | remove_element_wf(X,Set,Res,WF) :- remove_element_wf(X,Set,Res,WF,_DONE). |
| 3001 | | |
| 3002 | | :- block remove_element_wf(?,-, -,?,?). |
| 3003 | | remove_element_wf(X,Set,Res,WF,_DONE) :- Res==[],!, % we know that X must be the only element in Set |
| 3004 | | equal_object_wf(Set,[X],remove_element_wf,WF). |
| 3005 | | remove_element_wf(X,Set,Res,WF,DONE) :- |
| 3006 | ? | remove_element_wf1(X,Set,Res,WF,DONE). |
| 3007 | | |
| 3008 | | :- block remove_element_wf1(?,-, ?,?,?). |
| 3009 | | remove_element_wf1(X,avl_set(A),Res,WF,DONE) :- element_can_be_added_or_removed_to_avl(X),!, |
| 3010 | | /* TO DO: try and move the check about whether X can be added to later; when either X is known |
| 3011 | | or LWF is instantiated */ |
| 3012 | | remove_element_from_explicit_set(avl_set(A),X,AR), |
| 3013 | | equal_object_wf(AR,Res,remove_element_wf1,WF), DONE=done. |
| 3014 | | remove_element_wf1(X,Set,Res,WF,DONE) :- /* DONE is ground when element actually removed */ |
| 3015 | | expand_custom_set_to_list_wf(Set,ESet,_,remove_element_wf1,WF), |
| 3016 | | %% nl,print(remove_element_wf1(X,Set,ESet,Res,WF,DONE)),nl,nl, %% |
| 3017 | | remove_element_wf2(X,ESet,Res,LWF,DONE), |
| 3018 | | %when(nonvar(DONE), print_bt_message(removed(X,ESet,Res,LWF))), |
| 3019 | | (DONE==done -> true |
| 3020 | | ; same_card_prop(ESet,[X|Res]), % in case result is instantiated: check compatible with inputs |
| 3021 | ? | get_cardinality_wait_flag(ESet,remove_element_wf1(X,ESet,Res),WF,LWF), |
| 3022 | | quick_propagation_element_information(Set,X,WF,_) % use Set rather than ESet; better if still closure or AVL |
| 3023 | | ). |
| 3024 | | |
| 3025 | | :- block same_card_prop(-,?), same_card_prop(?,-). |
| 3026 | | same_card_prop([],[_|_]) :- !, fail. |
| 3027 | | same_card_prop([_|T],R) :- !, |
| 3028 | | (R=[] -> fail |
| 3029 | | ; R=[_|RT] -> same_card_prop(T,RT) |
| 3030 | | ; true). % just ignore |
| 3031 | | same_card_prop(_,_). |
| 3032 | | |
| 3033 | | :- block remove_element_wf2(?,-,?,?,?). |
| 3034 | | remove_element_wf2(H1,[H2|T],Res,LWF,DONE) :- Res==[],!, |
| 3035 | | equal_object(H1,H2,remove_element_wf2), |
| 3036 | | remove_element_wf3(pred_true,H1,H2,T,Res,LWF,DONE). |
| 3037 | | remove_element_wf2(H1,[H2|T],Res,LWF,DONE) :- |
| 3038 | | prop_empty_set(T,EqRes), |
| 3039 | ? | equality_objects_lwf(H1,H2,EqRes,LWF,no_wf_available), % TODO: pass WF |
| 3040 | ? | remove_element_wf3(EqRes,H1,H2,T,Res,LWF,DONE). |
| 3041 | | /* important for total_bijection that this has higher priority than other expansions */ |
| 3042 | | |
| 3043 | | :- block prop_empty_set(-,?). |
| 3044 | | % force second argument to pred_true if first arg is empty set |
| 3045 | | prop_empty_set([],R) :- !, R=pred_true. |
| 3046 | | prop_empty_set(_,_). |
| 3047 | | |
| 3048 | | :- block remove_element_wf3(-,?,?,?,?,-,?). |
| 3049 | | % remove_element_wf3(EqRes,H1,H2,T,Res,LWF,DONE) :- print(remove_element_wf3(EqRes,H1,H2,T,Res,LWF,DONE)),nl,fail. |
| 3050 | | remove_element_wf3(pred_true,_H1,_H2,T,Res,_LWF,DONE) :- |
| 3051 | ? | equal_object(T,Res,remove_element_wf3_1),DONE=done. |
| 3052 | | remove_element_wf3(pred_false,E,H,T,Res,LWF,DONE) :- |
| 3053 | ? | equal_object([H|RT],Res,remove_element_wf3_2), |
| 3054 | ? | remove_element_wf2(E,T,RT,LWF,DONE). |
| 3055 | | |
| 3056 | | /* the same as above: but do not remove if infinite or closure */ |
| 3057 | | |
| 3058 | | :- block remove_element_wf_if_not_infinite_or_closure(?,-,?,?,?,?). |
| 3059 | | remove_element_wf_if_not_infinite_or_closure(X,Set, Res,WF,LWF,Done) :- |
| 3060 | | (dont_expand(Set) |
| 3061 | | -> check_element_of_wf(X,Set,WF), |
| 3062 | | equal_object_wf(Res,Set,remove_element_wf_if_not_infinite_or_closure,WF), |
| 3063 | | Done=true % or should we wait until X known ? |
| 3064 | | %(var(Res)->Res=Set ; equal_object(Res,Set)) |
| 3065 | | ; expand_custom_set_to_list_wf(Set,ESet,_,remove_element_wf_if_not_infinite_or_closure,WF), |
| 3066 | ? | remove_element_wf2(X,ESet,Res,LWF,Done) |
| 3067 | | ). |
| 3068 | | |
| 3069 | | %:- use_module(bmachine_construction,[external_procedure_used/1]). |
| 3070 | | %dont_expand(global_set('STRING')) :- !. % s: STRING +-> ... will generate new strings ! |
| 3071 | | %(external_procedure_used(_) -> true). % we could check if there is a STRING generating procedure involved |
| 3072 | | % unless we use external functions, there is *no* way that new strings can be generated from a B machine ! |
| 3073 | | % Hence: we can expand STRING safely and thus avoid infinite enumeration of partial functions, ... |
| 3074 | | % example: procs : STRING +-> {"waiting"} & card( dom(procs) ) = 6 thus fails quickly |
| 3075 | | dont_expand(avl_set(_)) :- !,fail. |
| 3076 | | dont_expand(closure(_,_,_)) :- !. % relevant for tests 283, 1609, 1858 |
| 3077 | | dont_expand(Set) :- |
| 3078 | | is_infinite_or_very_large_explicit_set(Set). |
| 3079 | | % should we use a smaller bound than 20000 (comprehension_set_symbolic_limit)? see test 1609 |
| 3080 | | |
| 3081 | | |
| 3082 | | :- assert_must_succeed((kernel_objects:check_no_duplicates_in_list([int(1),int(2)],[],no_wf_available))). |
| 3083 | | :- assert_must_fail((kernel_objects:check_no_duplicates_in_list([int(1),int(2),int(1)],[],no_wf_available))). |
| 3084 | | |
| 3085 | | :- block check_no_duplicates_in_list(-,?,?). |
| 3086 | | check_no_duplicates_in_list([],_,_) :- !. |
| 3087 | | check_no_duplicates_in_list([H|T],ElementsSoFar,WF) :- !, |
| 3088 | | not_element_of_wf(H,ElementsSoFar,WF), |
| 3089 | | add_new_element_wf(H,ElementsSoFar,ElementsSoFar2,WF), |
| 3090 | | check_no_duplicates_in_list(T,ElementsSoFar2,WF). |
| 3091 | | check_no_duplicates_in_list(CS,ElementsSoFar,WF) :- |
| 3092 | | disjoint_sets(CS,ElementsSoFar,WF). |
| 3093 | | |
| 3094 | | :- public warn_if_duplicates_in_list/3. |
| 3095 | | % code for debugging / safe mode execution to check for duplicates |
| 3096 | | warn_if_duplicates_in_list(List,Src,WF) :- |
| 3097 | | %get_last_wait_flag(warn_if_duplicates_in_list,WF,WFX), % we may wish to use another WF here !? |
| 3098 | | get_enumeration_finished_wait_flag(WF,WFX), |
| 3099 | | when(nonvar(WFX),warn_if_duplicates_in_list(List,[],Src,WF)). |
| 3100 | | |
| 3101 | | :- block warn_if_duplicates_in_list(-,?,?,?). |
| 3102 | | warn_if_duplicates_in_list([],_,_,_) :- !. |
| 3103 | | warn_if_duplicates_in_list([H|T],ElementsSoFar,Src,WF) :- !, |
| 3104 | | membership_test_wf(ElementsSoFar,H,MemRes,WF), |
| 3105 | | warn_aux(MemRes,H,T,ElementsSoFar,Src,WF). |
| 3106 | | warn_if_duplicates_in_list(CS,ElementsSoFar,Src,WF) :- |
| 3107 | | when(ground(CS), |
| 3108 | | (disjoint_sets(CS,ElementsSoFar,WF) |
| 3109 | | -> true |
| 3110 | | ; add_error(Src,'Duplicates in list: ',CS:ElementsSoFar:Src))). |
| 3111 | | |
| 3112 | | :- block warn_aux(-,?,?,?,?,?). |
| 3113 | | warn_aux(pred_true,H,_,ElementsSoFar,Src,_WF) :- |
| 3114 | | add_error(Src,'Duplicate in list: ',H:ElementsSoFar:Src). |
| 3115 | | warn_aux(pred_false,H,T,ElementsSoFar,Src,WF) :- |
| 3116 | | add_new_element_wf(H,ElementsSoFar,ElementsSoFar2,WF), |
| 3117 | | warn_if_duplicates_in_list(T,ElementsSoFar2,Src,WF). |
| 3118 | | |
| 3119 | | |
| 3120 | | :- assert_must_succeed((kernel_objects:remove_exact_first_element([int(1),int(2)],X,[[]]), |
| 3121 | | X = [[int(1),int(2)],[]])). |
| 3122 | | :- assert_must_succeed((kernel_objects:remove_exact_first_element(X,global_set('Name'),T), |
| 3123 | | X==fd(1,'Name'),T==[fd(2,'Name'),fd(3,'Name')])). |
| 3124 | | :- assert_must_fail((kernel_objects:remove_exact_first_element([[]],X,_), |
| 3125 | | X = [[int(1),int(2)],[]])). |
| 3126 | | |
| 3127 | | :- assert_must_succeed((kernel_objects:remove_exact_first_element(X,C,R), |
| 3128 | | kernel_objects:gen_test_interval_closure(1,2,C), |
| 3129 | | X == int(1), R == [int(2)] )). |
| 3130 | | |
| 3131 | | gen_test_interval_closure(From,To,CL) :- |
| 3132 | | CL=closure(['_zzzz_unary'],[integer],b(member( b(identifier('_zzzz_unary'),integer,[]), |
| 3133 | | b(interval(b(value(int(From)),integer,[]), |
| 3134 | | b(value(int(To)),integer,[])),set(integer),[])),pred,[])). |
| 3135 | | |
| 3136 | | :- block remove_exact_first_element(?,-,?). |
| 3137 | | remove_exact_first_element(X,Set,Res) :- remove_exact_first_element1(Set,X,Res). |
| 3138 | | |
| 3139 | | remove_exact_first_element1([],_,_) :- fail. |
| 3140 | | remove_exact_first_element1([H|T],H,T). |
| 3141 | | remove_exact_first_element1(avl_set(A),H,T) :- remove_minimum_element_custom_set(avl_set(A),H,T). |
| 3142 | | remove_exact_first_element1(global_set(GS),H,T) :- |
| 3143 | | remove_minimum_element_custom_set(global_set(GS),H,T). |
| 3144 | | remove_exact_first_element1(freetype(GS),H,T) :- |
| 3145 | | remove_minimum_element_custom_set(freetype(GS),H,T). |
| 3146 | | remove_exact_first_element1(closure(P,Types,B),H,T) :- |
| 3147 | | remove_minimum_element_custom_set(closure(P,Types,B),H,T). |
| 3148 | | |
| 3149 | | |
| 3150 | | :- assert_must_succeed((kernel_objects:delete_element_wf(fd(1,'Name'),X,[fd(2,'Name'),fd(3,'Name')],_WF), |
| 3151 | | X = global_set('Name'))). |
| 3152 | | :- assert_must_succeed((kernel_objects:delete_element_wf(int(1),X,[int(2)],_WF), |
| 3153 | | X = [int(2),int(1)])). |
| 3154 | | :- assert_must_succeed((kernel_objects:delete_element_wf([int(1),int(2)],X,[],_WF), |
| 3155 | | X = [[int(2),int(1)]])). |
| 3156 | | :- assert_must_succeed((kernel_objects:delete_element_wf(int(3),X,[int(2),int(1)],_WF), |
| 3157 | | X = [int(2),int(1)])). |
| 3158 | | :- assert_must_succeed((kernel_objects:delete_element_wf(int(1),X,X,_WF), |
| 3159 | | X = [])). |
| 3160 | | :- assert_must_fail((kernel_objects:delete_element_wf(int(X),[int(1)],[int(1)],_WF), |
| 3161 | | X = 1)). |
| 3162 | | |
| 3163 | | /* WARNING: only use when R is not instantiated by something else; |
| 3164 | | (except for R=[]) */ |
| 3165 | | |
| 3166 | | |
| 3167 | | :- block delete_element_wf(?,-,?,?). |
| 3168 | | delete_element_wf(X,Set,Res,WF) :- |
| 3169 | | ground(X), |
| 3170 | | try_expand_and_convert_to_avl_with_check(Set,ESet,delete_element_wf),!, |
| 3171 | | delete_element0(X,ESet,Res,WF). |
| 3172 | | delete_element_wf(X,Set,Res,WF) :- delete_element1(X,Set,Res,WF). |
| 3173 | | |
| 3174 | | :- block delete_element0(?,-,?,?). |
| 3175 | | delete_element0(X,ESet,Res,WF) :- |
| 3176 | | ( is_custom_explicit_set(ESet,delete_element), |
| 3177 | | delete_element_from_explicit_set(ESet,X,DS) |
| 3178 | | -> equal_object_wf(DS,Res,delete_element0,WF) |
| 3179 | | ; delete_element1(X,ESet,Res,WF) |
| 3180 | | ). |
| 3181 | | |
| 3182 | | delete_element1(X,Set,Res,WF) :- expand_custom_set_to_list_wf(Set,ESet,_,delete_element1,WF), |
| 3183 | | %check_is_expanded_set(ESet,delete_element2), |
| 3184 | | delete_element2(ESet,X,Res,WF). |
| 3185 | | |
| 3186 | | :- block delete_element2(-,?,?,?). |
| 3187 | | delete_element2([],_,[],_). /* same as above, but allow element to be absent */ |
| 3188 | | delete_element2([H2|T],E,R,WF) :- |
| 3189 | | equality_objects_wf(H2,E,EqRes,WF), |
| 3190 | | delete_element3(EqRes,H2,T,E,R,WF). |
| 3191 | | %when_sufficiently_instantiated(E,H2,delete_element3(H1,[H2|T],R)). /* added by Michael Leuschel, 16/3/06 */ |
| 3192 | | |
| 3193 | | :- block delete_element3(-,?,?,?,?,?). |
| 3194 | | delete_element3(pred_true,_H2,T,_,R,WF) :- equal_object_wf(R,T,delete_element3,WF). |
| 3195 | | delete_element3(pred_false,H2,T,E,Res,WF) :- equal_cons_wf(Res,H2,RT,WF),delete_element2(T,E,RT,WF). |
| 3196 | | |
| 3197 | | |
| 3198 | | |
| 3199 | | |
| 3200 | | :- assert_must_succeed(kernel_objects:check_is_expanded_set([int(1)],test)). |
| 3201 | | |
| 3202 | | :- public check_is_expanded_set/2. |
| 3203 | | check_is_expanded_set(X,Source) :- |
| 3204 | | (nonvar(X),(X=[] ; X= [_|_]) -> true |
| 3205 | | ; add_internal_error('Is not expanded set: ',check_is_expanded_set(X,Source)) |
| 3206 | | ). |
| 3207 | | |
| 3208 | | |
| 3209 | | /* union/3 */ |
| 3210 | | |
| 3211 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(3)],[int(2),int(1),int(3)],[int(1),int(3),int(2)]))). |
| 3212 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(1)],[int(1),int(2)],[int(1),int(2)]))). |
| 3213 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(3)],[int(2),int(1)],[int(1),int(3),int(2)]))). |
| 3214 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],union([int(3),int(2)],[int(2),int(1)],[int(1),int(3),int(2)]))). |
| 3215 | | :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],union([int(3),int(4)],[int(2),int(1)],[int(1),int(3),int(2)]))). |
| 3216 | | :- assert_must_succeed((kernel_objects:union([int(1)],[int(2)],Res),kernel_objects:equal_object(Res,[_,_]))). |
| 3217 | | :- assert_must_succeed((kernel_objects:union([],[int(2)],Res), |
| 3218 | | kernel_objects:equal_object(Res,[int(2)]))). |
| 3219 | | :- assert_must_succeed((kernel_objects:union([int(2)],[],Res), |
| 3220 | | kernel_objects:equal_object(Res,[int(2)]))). |
| 3221 | | :- assert_must_succeed((kernel_objects:union([int(2)],[int(2)],Res), |
| 3222 | | kernel_objects:equal_object(Res,[int(2)]))). |
| 3223 | | :- assert_must_succeed((kernel_objects:union([int(1)],Res,[int(1),int(2)]), |
| 3224 | | kernel_objects:equal_object(Res,[int(2)]))). |
| 3225 | | :- assert_must_succeed((kernel_objects:union([fd(1,'Name')],X,Res),X=global_set('Name'), |
| 3226 | | kernel_objects:equal_object(Res,X))). |
| 3227 | | :- assert_must_succeed((kernel_objects:union(X,global_set('Name'),Res),X=[fd(2,'Name'),fd(1,'Name')], |
| 3228 | | kernel_objects:equal_object(Res,global_set('Name')))). |
| 3229 | | :- assert_must_succeed((kernel_objects:union([fd(1,'Name')],[fd(3,'Name'),fd(2,'Name')],Res), |
| 3230 | | kernel_objects:equal_object(Res,global_set('Name')))). |
| 3231 | | %:- assert_must_succeed((kernel_objects:union([fd(1,'Name')],[fd(3,'Name'),fd(2,'Name')],Res), |
| 3232 | | % kernel_objects:equal_object(Res,X),X=global_set('Name'))). |
| 3233 | | :- assert_must_fail((kernel_objects:union([int(1)],[int(2)],Res), |
| 3234 | | (kernel_objects:equal_object(Res,[_]);kernel_objects:equal_object(Res,[_,_,_|_])))). |
| 3235 | | :- assert_must_fail((kernel_objects:union([int(1)],[int(1)],Res),(Res=[];kernel_objects:equal_object(Res,[_,_|_])))). |
| 3236 | | :- assert_must_fail((kernel_objects:union([fd(1,'Name')],[fd(2,'Name')],Res), |
| 3237 | | kernel_objects:equal_object(Res,global_set('Name')))). |
| 3238 | | % kernel_objects:union([int(1),int(2)],X,[int(1),int(2),int(3)]) |
| 3239 | | |
| 3240 | | union(S1,S2,Res) :- init_wait_flags(WF,[union]), union_wf(S1,S2,Res,WF), ground_wait_flags(WF). |
| 3241 | | |
| 3242 | | :- block union_wf(-,-,-,?). |
| 3243 | | %union_wf(Set1,Set2,Res,_WF) :- print(union_wf(Set1,Set2,Res)),nl,fail. |
| 3244 | | union_wf(Set1,Set2,Res,WF) :- Set1==[],!,equal_object_wf(Set2,Res,union_wf_1,WF). |
| 3245 | | union_wf(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,union_wf_2,WF). |
| 3246 | | union_wf(Set1,Set2,Res,WF) :- Res==[],!,empty_set_wf(Set1,WF), empty_set_wf(Set2,WF). |
| 3247 | ? | union_wf(Set1,Set2,Res,WF) :- union0(Set1,Set2,Res,WF). |
| 3248 | | |
| 3249 | | :- block union0(-,-,?,?), union0(-,?,-,?), union0(?,-,-,?). % require two arguments to be known |
| 3250 | | union0(Set1,Set2,Res,WF) :- Set1==[],!,equal_object_wf(Set2,Res,union0_1,WF). |
| 3251 | | union0(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,union0_2,WF). |
| 3252 | | union0(Set1,Set2,Res,WF) :- Res==[],!,empty_set_wf(Set1,WF), empty_set_wf(Set2,WF). |
| 3253 | | union0(Set1,Set2,Res,WF) :- nonvar(Res), singleton_set(Res,X),!, |
| 3254 | | (var(Set1) -> union0_to_singleton_set(Set2,Set1,X,WF) ; union0_to_singleton_set(Set1,Set2,X,WF)). |
| 3255 | ? | union0(Set1,Set2,Res,WF) :- (var(Set1) -> union1(Set2,Set1,Res,WF) ; union1(Set1,Set2,Res,WF)). |
| 3256 | | |
| 3257 | | % optimized version for Set1 \/ Set2 = {X} |
| 3258 | | % TO DO: is not triggered when Set1 and Set2 are instantiated first (before result) |
| 3259 | | % >>> z:11..12 & {x,y} \/ {v} = {z} does not work |
| 3260 | | union0_to_singleton_set([],Set2,X,WF) :- !, equal_object_wf(Set2,[X],union0_3,WF). % cannot be reached, due to checks above |
| 3261 | | union0_to_singleton_set([H|T],Set2,X,WF) :- !, empty_set_wf(T,WF), equal_object_wf(H,X,WF), |
| 3262 | | check_subset_of_wf(Set2,[X],WF). |
| 3263 | | union0_to_singleton_set(avl_set(A),Set2,X,WF) :- !, singleton_set(avl_set(A),AEl), |
| 3264 | | equal_object_wf(AEl,X,WF), |
| 3265 | | check_subset_of_wf(Set2,[X],WF). |
| 3266 | | union0_to_singleton_set(Set1,Set2,X,WF) :- % closure or global_set; revert to normal treatment |
| 3267 | | union1(Set1,Set2,[X],WF). |
| 3268 | | |
| 3269 | | union1(Set1,Set2,Res,WF) :- var(Set2), dont_expand_this_explicit_set(Set1), !, |
| 3270 | | block_union1e(Set2,Set1,Res,WF). % try avoid expanding Set1 and wait until Set2 becomes known, may enable symbolic union |
| 3271 | | union1(Set1,Set2,Res,WF) :- |
| 3272 | | try_expand_and_convert_to_avl_unless_large_or_closure_wf(Set1,ESet1,WF), |
| 3273 | | try_expand_and_convert_to_avl_unless_large_or_closure_wf(Set2,ESet2,WF), |
| 3274 | ? | union1e(ESet1,ESet2,Res,WF). |
| 3275 | | |
| 3276 | | try_expand_and_convert_to_avl_unless_large_or_closure_wf(Set,ESet,_) :- |
| 3277 | | (var(Set);Set=closure(_,_,_)),!,ESet=Set. |
| 3278 | | try_expand_and_convert_to_avl_unless_large_or_closure_wf(Set,ESet,WF) :- |
| 3279 | | try_expand_and_convert_to_avl_unless_large_wf(Set,ESet,WF). |
| 3280 | | |
| 3281 | | :- block block_union1e(-,?,?,?). |
| 3282 | | block_union1e(Set1,Set2,Res,WF) :- Res==[],!, |
| 3283 | | empty_set_wf(Set1,WF), empty_set_wf(Set2,WF). |
| 3284 | | block_union1e(Set1,Set2,Res,WF) :- |
| 3285 | | union1e(Set1,Set2,Res,WF). |
| 3286 | | |
| 3287 | | union1e(Set1,Set2,Res,WF) :- |
| 3288 | | is_custom_explicit_set(Set1,union1e), |
| 3289 | | union_of_explicit_set(Set1,Set2,Union), |
| 3290 | | !, equal_object_wf(Union,Res,union1e,WF). |
| 3291 | | union1e(Set2,Set1,Res,WF) :- % Set2=avl_set(_), nonvar(Set1), Set1 \= avl_set(_), |
| 3292 | | nonvar(Set1), Set1=avl_set(_), Set2 \= avl_set(_), \+ ground(Set2), |
| 3293 | | !, % avoid expanding Set2 |
| 3294 | | expand_custom_set_to_list_wf(Set1,ESet1,_,union1e_1,WF), |
| 3295 | ? | union2(ESet1,Set2,Res,WF), lazy_check_subset_of(Set2,Res,WF). |
| 3296 | | union1e(Set1,Set2,Res,WF) :- |
| 3297 | | expand_custom_set_to_list_wf(Set1,ESet1,_,union1e_2,WF), % we could avoid this expansion by treating avl_set,... below in union2 |
| 3298 | ? | union2(ESet1,Set2,Res,WF), |
| 3299 | | lazy_check_subset_of(Set1,Res,WF), % ADDED to solve {x,y| { x \/ y } <: {{1} \/ {2}}} |
| 3300 | | lazy_check_subset_of(Set2,Res,WF) % could perform additional constraint checking |
| 3301 | | % ,try_prop_card_leq(ESet1,Res), try_prop_card_leq(Set2,Res). %%% seems to slow down ProB: investigate |
| 3302 | | . |
| 3303 | | |
| 3304 | | /* not yet used: |
| 3305 | | % lazy_check_in_union(R,Set1,Set2,WF): check if all elements of R appear in at least one of the sets Sets1/2: |
| 3306 | | :- block lazy_check_in_union(-,?,?,?). |
| 3307 | | lazy_check_in_union([],_,_,_) :- !. |
| 3308 | | lazy_check_in_union([H|T],Set1,Set2,WF) :- !, |
| 3309 | | in_one_of_sets(H,Set1,Set2,WF), |
| 3310 | | lazy_check_in_union(T,Set1,Set2,WF). |
| 3311 | | lazy_check_in_union(_,_,_,_). |
| 3312 | | |
| 3313 | | % check if an element appear in at least one of the two sets: |
| 3314 | | in_one_of_sets(H,Set1,Set2,WF) :- |
| 3315 | | membership_test_wf(Set1,H,MemRes1,WF), |
| 3316 | | (MemRes1==pred_true -> true |
| 3317 | | ; one_true(MemRes1,MemRes2), |
| 3318 | | membership_test_wf(Set2,H,MemRes2,WF) |
| 3319 | | ). |
| 3320 | | |
| 3321 | | :- block one_true(-,-). |
| 3322 | | one_true(MemRes1,MemRes2) :- var(MemRes1),!, |
| 3323 | | (MemRes2=pred_false -> MemRes1=pred_true ; true). |
| 3324 | | one_true(pred_true,_). |
| 3325 | | one_true(pred_false,pred_true). |
| 3326 | | */ |
| 3327 | | |
| 3328 | | |
| 3329 | | :- block lazy_try_check_element_of(?,-,?). |
| 3330 | ? | lazy_try_check_element_of(H,Set,WF) :- lazy_check_element_of_aux(Set,H,WF). |
| 3331 | | |
| 3332 | ? | lazy_check_element_of_aux(closure(P,T,B),H,WF) :- !, check_element_of_wf(H,closure(P,T,B),WF). |
| 3333 | ? | lazy_check_element_of_aux(avl_set(A),H,WF) :- !, check_element_of_wf(H,avl_set(A),WF). |
| 3334 | | lazy_check_element_of_aux([X|T],H,WF) :- !, lazy_check_element_of_list(T,X,H,WF). |
| 3335 | | lazy_check_element_of_aux(_,_,_). |
| 3336 | | |
| 3337 | | :- block lazy_check_element_of_list(-,?,?,?). |
| 3338 | | lazy_check_element_of_list([],X,H,WF) :- !, equal_object_wf(X,H,WF). |
| 3339 | | lazy_check_element_of_list([Y|T],X,H,WF) :- !, |
| 3340 | | quick_propagation_element_information([X,Y|T],H,WF,_). % TO DO: check that we loose no performance due to this |
| 3341 | | lazy_check_element_of_list(_,_,_,_). |
| 3342 | | |
| 3343 | | % an incomplete subset check without enumeration |
| 3344 | | :- block lazy_check_subset_of(-,?,?), lazy_check_subset_of(?,-,?). |
| 3345 | | lazy_check_subset_of(Set1,Set2,WF) :- nonvar(Set2), |
| 3346 | | (Set2=closure(_,_,_) ; Set2=avl_set(_)),!, lazy_check_subset_of2(Set1,Set2,WF). |
| 3347 | | lazy_check_subset_of(_,_,_). % ignore other set representations |
| 3348 | | :- block lazy_check_subset_of2(-,?,?). |
| 3349 | | lazy_check_subset_of2([],_,_WF) :- !. |
| 3350 | | lazy_check_subset_of2([H|T],Set,WF) :- !, check_element_of_wf(H,Set,WF), lazy_check_subset_of2(T,Set,WF). |
| 3351 | | lazy_check_subset_of2(_,_,_). % ignore other set representations |
| 3352 | | |
| 3353 | | :- block union2(-,?,?,?). |
| 3354 | ? | union2([],S,Res,WF) :- equal_object_optimized_wf(S,Res,union2,WF). |
| 3355 | | union2([H|T],Set2,Res,WF) :- |
| 3356 | | (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 |
| 3357 | | % the constraint is not yet detected straight away: x:S & S<:1..12 & S \/ {x} /= S |
| 3358 | ? | -> union3(H2,T2,[H|T],Res,WF) |
| 3359 | ? | ; union3(H,T,Set2,Res,WF) |
| 3360 | | ). |
| 3361 | | union3(H,T,Set2,Res,WF) :- |
| 3362 | | add_element_wf(H,Set2,R,Done,WF), |
| 3363 | ? | lazy_try_check_element_of(H,Res,WF), % TO DO: propagate constraint that H is in Res |
| 3364 | | (T==[] |
| 3365 | ? | -> equal_object_optimized_wf(R,Res,union3,WF) %union2(T,R,Res,WF) |
| 3366 | ? | ; union4(Done,T,R,Res,WF)). |
| 3367 | | :- block union4(-,?,?,?,?). |
| 3368 | ? | 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 |
| 3369 | | |
| 3370 | | |
| 3371 | | :- assert_must_succeed(exhaustive_kernel_check(union_generalized([[int(3)],[int(2),int(1),int(3)]],[int(1),int(3),int(2)]))). |
| 3372 | | :- assert_must_succeed(exhaustive_kernel_check(union_generalized([[int(3),int(2)],[],[int(2),int(1),int(3)]],[int(1),int(3),int(2)]))). |
| 3373 | | :- 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)]))). |
| 3374 | | :- assert_must_succeed((kernel_objects:union_generalized([[]],Res),Res=[])). |
| 3375 | | :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2)]],Res), |
| 3376 | | kernel_objects:equal_object(Res,[_,_]))). |
| 3377 | | :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2),int(1)]],Res), |
| 3378 | | kernel_objects:equal_object(Res,[_,_]))). |
| 3379 | | :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2),int(1)],[],[int(2)]],Res), |
| 3380 | | kernel_objects:equal_object(Res,[_,_]))). |
| 3381 | | :- assert_must_succeed((kernel_objects:union_generalized([[int(1)],[int(2)],X],Res), |
| 3382 | | kernel_objects:equal_object(X,Res), X = [int(2),int(1),int(3)])). |
| 3383 | | :- assert_must_succeed((kernel_objects:union_generalized([global_set('Name'),X,X,X],Res), |
| 3384 | | kernel_objects:equal_object(global_set('Name'),Res), X = [fd(2,'Name'),fd(1,'Name')])). |
| 3385 | | :- assert_must_succeed((kernel_objects:union_generalized([X,global_set('Name')],Res), |
| 3386 | | kernel_objects:equal_object(global_set('Name'),Res), X = [fd(2,'Name'),fd(1,'Name')])). |
| 3387 | | :- assert_must_fail((kernel_objects:union_generalized([[int(1)],[int(2)]],Res),(Res=[_]; |
| 3388 | | kernel_objects:equal_object(Res,[_,_,_|_])))). |
| 3389 | | :- assert_must_fail((kernel_objects:union_generalized([[int(1)],[int(1)]],Res),(Res=[]; |
| 3390 | | kernel_objects:equal_object(Res,[_,_|_])))). |
| 3391 | | |
| 3392 | | % treates the general_union AST node (union(.) in B syntax) |
| 3393 | | union_generalized(S,Res) :- init_wait_flags(WF), union_generalized_wf(S,Res,WF), ground_wait_flags(WF). |
| 3394 | | |
| 3395 | | :- block union_generalized_wf(-,-,?). |
| 3396 | | union_generalized_wf(SetsOfSets,Res,WF) :- var(SetsOfSets), Res==[],!, |
| 3397 | | expand_custom_set_to_list_wf(SetsOfSets,ESetsOfSets,_,union_generalized_wf,WF), |
| 3398 | | all_empty_sets_wf(ESetsOfSets,WF). |
| 3399 | | union_generalized_wf(SetsOfSets,Res,WF) :- |
| 3400 | | union_generalized_wf2(SetsOfSets,Res,WF). |
| 3401 | | |
| 3402 | | :- block union_generalized_wf2(-,?,?). |
| 3403 | | union_generalized_wf2(SetsOfSets,Res,WF) :- |
| 3404 | | custom_explicit_sets:union_generalized_explicit_set(SetsOfSets,ARes,WF),!, |
| 3405 | | equal_object_optimized_wf(ARes,Res,union_generalized_avl_set,WF). |
| 3406 | | union_generalized_wf2(SetsOfSets,Res,WF) :- |
| 3407 | | expand_custom_set_to_list_wf(SetsOfSets,ESetsOfSets,_,union_generalized_wf2,WF), |
| 3408 | | union_generalized2(ESetsOfSets,[],Res,WF). |
| 3409 | | |
| 3410 | | :- block union_generalized2(-,?,?,?). |
| 3411 | | union_generalized2([],S,Res,WF) :- equal_object_optimized_wf(S,Res,union_generalized2,WF). |
| 3412 | | union_generalized2([H|T],UnionSoFar,Res,WF) :- |
| 3413 | | Res==[], |
| 3414 | | !, |
| 3415 | | empty_set_wf(H,WF), |
| 3416 | | empty_set_wf(UnionSoFar,WF), |
| 3417 | | all_empty_sets_wf(T,WF). |
| 3418 | | union_generalized2([H|T],UnionSoFar,Res,WF) :- union_wf(H,UnionSoFar,UnionSoFar2,WF), |
| 3419 | | ((var(T);var(UnionSoFar2)), |
| 3420 | | 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) |
| 3421 | | -> check_subset_of_wf(H,Res,WF) |
| 3422 | | % 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 |
| 3423 | | ; true), |
| 3424 | | union_generalized2(T,UnionSoFar2,Res,WF). |
| 3425 | | |
| 3426 | | :- block all_empty_sets_wf(-,?). |
| 3427 | | all_empty_sets_wf([],_). |
| 3428 | | all_empty_sets_wf([H|T],WF) :- empty_set_wf(H,WF), all_empty_sets_wf(T,WF). |
| 3429 | | |
| 3430 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],intersection([int(3)],[int(2),int(1),int(3)],[int(3)]))). |
| 3431 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],intersection([int(4),int(3),int(2)],[int(2),int(1),int(3)],[int(2),int(3)]))). |
| 3432 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],intersection([int(4),int(3),int(2)],[],[]))). |
| 3433 | | :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],intersection([int(1),int(3)],[int(4),int(3),int(2)],[]))). |
| 3434 | | :- assert_must_succeed((kernel_objects:intersection(Y,X,Res),X=global_set('Name'), |
| 3435 | | kernel_objects:equal_object(Res,Y), Y =[fd(1,'Name')])). |
| 3436 | | :- assert_must_succeed((kernel_objects:intersection([int(1)],[int(2)],Res),Res=[])). |
| 3437 | | :- assert_must_succeed((kernel_objects:intersection([int(1)],[int(2)],[]))). |
| 3438 | | :- assert_must_fail((kernel_objects:intersection([int(1),int(4),int(3)],[int(2),int(3)],[]))). |
| 3439 | | :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(1)],_))). |
| 3440 | | :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(1)],[int(2),int(1)]))). |
| 3441 | | :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(1)],[int(1),int(2)]))). |
| 3442 | | :- assert_must_succeed((kernel_objects:intersection([int(1),int(2)],[int(2),int(3)],Res), |
| 3443 | | kernel_objects:equal_object(Res,[int(2)]))). |
| 3444 | | :- assert_must_succeed((kernel_objects:intersection([int(2)],[int(2)],Res), |
| 3445 | | kernel_objects:equal_object(Res,[int(2)]))). |
| 3446 | | :- assert_must_succeed((kernel_objects:intersection([int(2),int(3)],[int(3),int(4),int(2)],Res), |
| 3447 | | kernel_objects:equal_object(Res,[int(2),int(3)]))). |
| 3448 | | :- assert_must_fail((kernel_objects:intersection([int(1)],[int(2)],Res),( |
| 3449 | | kernel_objects:equal_object(Res,[_|_])))). |
| 3450 | | :- assert_must_fail((kernel_objects:intersection([int(1)],[int(1)],Res),(Res=[]; |
| 3451 | | kernel_objects:equal_object(Res,[_,_|_])))). |
| 3452 | | :- assert_must_fail((kernel_objects:intersection([fd(1,'Name')],X,Res),X=global_set('Name'), |
| 3453 | | kernel_objects:equal_object(Res,X))). |
| 3454 | | |
| 3455 | | |
| 3456 | | intersection(S1,S2,Res) :- init_wait_flags(WF,[intersection]), intersection(S1,S2,Res,WF), ground_wait_flags(WF). |
| 3457 | | |
| 3458 | | :- block intersection(-,-,-,?). |
| 3459 | | intersection(Set1,Set2,Res,WF) :- (Set1==[] ; Set2==[]),!, empty_set_wf(Res,WF). |
| 3460 | | intersection(Set1,Set2,Res,WF) :- quick_same_value(Set1,Set2),!, |
| 3461 | | equal_object_wf(Res,Set1,inter0_equal,WF). |
| 3462 | | intersection(Set1,Set2,Res,WF) :- Res==[],!, |
| 3463 | | disjoint_sets(Set1,Set2,WF). |
| 3464 | | 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 |
| 3465 | | intersection0(Set1,Set2,Res,WF), |
| 3466 | | propagate_intersection(Set1,Set2,Res,WF). |
| 3467 | | |
| 3468 | | :- block propagate_intersection(?,?,-,?). % propagate constraint that result elements must be in both sets |
| 3469 | | propagate_intersection(Set1,Set2,[H|T],WF) :- |
| 3470 | | preference(data_validation_mode,false), |
| 3471 | | !, |
| 3472 | | propagate_intersection_aux(Set1,Set2,H,T,WF). |
| 3473 | | propagate_intersection(Set1,Set2,avl_set(A),WF) :- !, |
| 3474 | | ((unknown_set(Set1) ; unknown_set(Set2)) % otherwise intersection0 has already triggered below |
| 3475 | | -> custom_explicit_sets:avl_approximate_size(A,Size), |
| 3476 | | (Size<20 |
| 3477 | | -> expand_custom_set_to_list_wf(avl_set(A),ESet,_,propagate_intersection,WF) |
| 3478 | | ; avl_min(A,Min), avl_max(A,Max), ESet=[Min,Max] |
| 3479 | | ), |
| 3480 | | propagate_intersection(Set1,Set2,ESet,WF) |
| 3481 | | ; true). |
| 3482 | | % other cases: Set1,2,3 could be interval closure with unknown bounds,... |
| 3483 | | propagate_intersection(_,_,_,_). |
| 3484 | | |
| 3485 | | :- block propagate_intersection_aux(-,-,-,?,?). |
| 3486 | | propagate_intersection_aux(Set1,Set2,H,T,WF) :- |
| 3487 | | ((unknown_set(Set1) ; unknown_set(Set2)) % otherwise intersection0 has already triggered below |
| 3488 | | -> check_element_of_wf(H,Set1,WF), % should we do this lazily ? |
| 3489 | | check_element_of_wf(H,Set2,WF), |
| 3490 | | propagate_intersection(Set1,Set2,T,WF) |
| 3491 | | ; true). |
| 3492 | | |
| 3493 | | unknown_set(Set) :- var(Set),!. |
| 3494 | | unknown_set([H|T]) :- (unknown_val(H) -> true ; unknown_set(T)). |
| 3495 | | unknown_val(Val) :- var(Val),!. |
| 3496 | | unknown_val(int(X)) :- var(X). |
| 3497 | | unknown_val(string(X)) :- var(X). |
| 3498 | | unknown_val(fd(X,_)) :- var(X). |
| 3499 | | unknown_val((A,B)) :- (unknown_val(A) -> true ; unknown_val(B)). |
| 3500 | | unknown_val([H|T]) :- (unknown_val(H) -> true ; unknown_set(T)). |
| 3501 | | |
| 3502 | | :- block intersection0(-,?,?,?), intersection0(?,-,?,?). |
| 3503 | | intersection0(Set1,Set2,Res,WF) :- |
| 3504 | | (Set1==[] ; Set2==[]),!, empty_set_wf(Res,WF). |
| 3505 | | intersection0(Set1,Set2,Res,WF) :- quick_same_value(Set1,Set2),!, |
| 3506 | | equal_object_wf(Res,Set1,inter0_equal,WF). |
| 3507 | | intersection0(Set1,Set2,Res,WF) :- Res==[],!, |
| 3508 | | disjoint_sets(Set1,Set2,WF). |
| 3509 | | intersection0([El1|T1],[El2|T2],Res,WF) :- T1==[],T2==[], |
| 3510 | | !, % avoid doing intersection_with_interval_closure, especially for nonvar El1,El2 ; see test 2021 |
| 3511 | | equality_objects_wf(El1,El2,EqRes,WF), |
| 3512 | | kernel_equality:empty_set_test_wf(Res,Empty,WF), |
| 3513 | | bool_pred:negate(Empty,EqRes), |
| 3514 | | intersection_pair(EqRes,El1,El2,Res,WF). |
| 3515 | | intersection0(Set1,Set2,Res,WF) :- |
| 3516 | ? | intersection_with_interval_closure(Set1,Set2,Inter),!, % avoid expanding intervals at all |
| 3517 | | equal_object_wf(Inter,Res,intersection0,WF). |
| 3518 | | intersection0(Set1,Set2,Res,WF) :- |
| 3519 | | try_expand_and_convert_to_avl_unless_large_wf(Set1,ESet1,WF), |
| 3520 | | try_expand_and_convert_to_avl_unless_large_wf(Set2,ESet2,WF), |
| 3521 | | intersection1(ESet1,ESet2,Res,WF). |
| 3522 | | |
| 3523 | | % treat {El1} /\ {El2} = Res |
| 3524 | | :- block intersection_pair(-,?,?,?,?). |
| 3525 | | intersection_pair(pred_false,_,_,_,_). % empty_set_test_wf above will set Res to empty_set |
| 3526 | | intersection_pair(pred_true,El1,_El2,Res,WF) :- equal_object_wf(Res,[El1],intersection_pair,WF). |
| 3527 | | |
| 3528 | | intersection1(Set1,Set2,Res,WF) :- nonvar(Set1),is_custom_explicit_set(Set1,intersection), |
| 3529 | | intersection_of_explicit_set_wf(Set1,Set2,Inter,WF), !, |
| 3530 | | equal_object_wf(Inter,Res,intersection1,WF). |
| 3531 | | intersection1(Set1,Set2,Res,WF) :- |
| 3532 | | (Res==[] -> |
| 3533 | | disjoint_sets(Set1,Set2,WF) |
| 3534 | | ; |
| 3535 | | (swap_set(Set1,Set2) -> intersection2(Set2,Set1,Res,WF) |
| 3536 | | ; intersection2(Set1,Set2,Res,WF)) |
| 3537 | | ). |
| 3538 | | |
| 3539 | | swap_set(Set1,_Set2) :- var(Set1),!. |
| 3540 | | swap_set(_Set1,Set2) :- var(Set2),!,fail. |
| 3541 | | %swap_set(_Set1,Set2) :- is_infinite_explicit_set(Set2),!,fail. |
| 3542 | | swap_set(avl_set(_),Set2) :- \+ functor(Set2,avl_set,2), %Set2 \= avl_set(_), |
| 3543 | | Set2 \= [], |
| 3544 | | \+ functor(Set2,closure,3), %Set2 \= closure(_,_,_), |
| 3545 | | \+ functor(Set2,global_set,1). %Set2 \= global_set(_). % if it was a small closure, intersection_of_explicit_set should have triggered |
| 3546 | | 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 |
| 3547 | | swap_set(global_set(_GS),Set2) :- ok_to_swap(Set2). |
| 3548 | | |
| 3549 | | ok_to_swap(global_set(GS)) :- !, \+ is_infinite_or_very_large_explicit_set(global_set(GS),1000000). |
| 3550 | | ok_to_swap(closure(P,T,B)) :- !,\+ is_infinite_or_very_large_explicit_set(closure(P,T,B),1000000). |
| 3551 | | ok_to_swap(_). |
| 3552 | | % maybe also use is_efficient_custom_set as below ?? |
| 3553 | | % what about freetype ? |
| 3554 | | |
| 3555 | | |
| 3556 | | intersection2(Set1,Set2,Res,WF) :- |
| 3557 | | expand_custom_set_to_list_wf(Set1,ESet1,_,intersection2,WF), |
| 3558 | | intersection3(ESet1,Set2,Res,WF). |
| 3559 | | :- block intersection3(-,?,?,?). |
| 3560 | | intersection3([],_,Res,WF) :- empty_set_wf(Res,WF). |
| 3561 | | intersection3([H|T],Set,Res,WF) :- |
| 3562 | | (Res==[] |
| 3563 | | -> not_element_of_wf(H,Set,WF),intersection3(T,Set,Res,WF) |
| 3564 | | ; membership_test_wf(Set,H,MemRes,WF), |
| 3565 | ? | intersection4(MemRes,H,T,Set,Res,WF) |
| 3566 | | ). |
| 3567 | | |
| 3568 | | :- block intersection4(-,?,?, ?,?,?). |
| 3569 | | intersection4(pred_true,H,T,Set,Result,WF) :- |
| 3570 | ? | equal_object_wf([H|Res],Result,intersection4,WF), |
| 3571 | | intersection3(T,Set,Res,WF). |
| 3572 | | intersection4(pred_false,_H,T,Set,Res,WF) :- |
| 3573 | ? | intersection3(T,Set,Res,WF). |
| 3574 | | |
| 3575 | | |
| 3576 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(disjoint_sets([int(5)],[int(2),int(1),int(3)],WF),WF)). |
| 3577 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(disjoint_sets([int(5)],[],WF),WF)). |
| 3578 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(disjoint_sets([int(5),int(2)],[int(6),int(1),int(3)],WF),WF)). |
| 3579 | | |
| 3580 | | disjoint_sets(S1,S2) :- init_wait_flags(WF,[disjoint_sets]), |
| 3581 | | disjoint_sets(S1,S2,WF), |
| 3582 | | ground_wait_flags(WF). |
| 3583 | | |
| 3584 | | :- block disjoint_sets(-,?,?), disjoint_sets(?,-,?). |
| 3585 | | disjoint_sets(S1,S2,WF) :- |
| 3586 | | % TO DO: we could provide faster code for two avl sets / intervals; but probably caught in intersection code above? |
| 3587 | | ((S1==[];S2==[]) -> true |
| 3588 | | ; is_interval_closure_or_integerset(S1,Low1,Up1), |
| 3589 | | nonvar(Low1), nonvar(Up1), % avoid applying it to e.g., {x} /\ 0..2000 = {} from test 1165 |
| 3590 | | is_interval_closure_or_integerset(S2,Low2,Up2), nonvar(Low2), nonvar(Up2) -> |
| 3591 | | custom_explicit_sets:disjoint_intervals_with_inf(Low1,Up1,Low2,Up2) |
| 3592 | | ; is_efficient_custom_set(S2) -> expand_custom_set_to_list_wf(S1,ESet1,_,disjoint_sets_1,WF), |
| 3593 | | % TODO: treat is_infinite_or_symbolic_closure S1 |
| 3594 | | disjoint_sets2(ESet1,S2,WF) |
| 3595 | | ; is_efficient_custom_set(S1) -> expand_custom_set_to_list_wf(S2,ESet2,_,disjoint_sets_2,WF), |
| 3596 | | disjoint_sets2(ESet2,S1,WF) |
| 3597 | | ; expand_custom_set_to_list_wf(S1,ESet1,_,disjoint_sets_3,WF), |
| 3598 | | %expand_custom_set_to_list_wf(S2,ESet2,_,disjoint_sets_4,WF), |
| 3599 | | disjoint_sets2(ESet1,S2,WF) |
| 3600 | | ). |
| 3601 | | |
| 3602 | | % TO DO: we could infer some constraints on the possible max sizes of the sets |
| 3603 | | % for finite types (sum of size must be <= size of type) |
| 3604 | | :- block disjoint_sets2(-,?,?). |
| 3605 | | disjoint_sets2([],_,_WF). |
| 3606 | | disjoint_sets2([H|T],S2,WF) :- not_element_of_wf(H,S2,WF), disjoint_sets2(T,S2,WF). |
| 3607 | | |
| 3608 | | % NOT YET USED: not_disjoint_sets could be used for S /\ R /= {} |
| 3609 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(not_disjoint_sets([int(3)],[int(2),int(1),int(3)],WF),WF)). |
| 3610 | | :- block not_disjoint_sets(-,?,?), not_disjoint_sets(?,-,?). |
| 3611 | | not_disjoint_sets(S1,S2,WF) :- |
| 3612 | | ((S1==[];S2==[]) -> fail |
| 3613 | | ; is_efficient_custom_set(S2) -> expand_custom_set_to_list_wf(S1,ESet1,_,disjoint_sets_1,WF), |
| 3614 | | not_disjoint_sets2(ESet1,S2,WF) |
| 3615 | | ; is_efficient_custom_set(S1) -> expand_custom_set_to_list_wf(S2,ESet2,_,disjoint_sets_2,WF), |
| 3616 | | not_disjoint_sets2(ESet2,S1,WF) |
| 3617 | | ; expand_custom_set_to_list_wf(S1,ESet1,_,disjoint_sets_3,WF), |
| 3618 | | %expand_custom_set_to_list_wf(S2,ESet2,_,disjoint_sets_4,WF), |
| 3619 | | not_disjoint_sets2(ESet1,S2,WF) |
| 3620 | | ). |
| 3621 | | |
| 3622 | | :- block not_disjoint_sets2(-,?,?). |
| 3623 | | not_disjoint_sets2([],_,_WF). |
| 3624 | | not_disjoint_sets2([H|T],S2,WF) :- membership_test_wf(S2,H,MemRes,WF), not_disjoint3(MemRes,T,S2,WF). |
| 3625 | | |
| 3626 | | :- block not_disjoint3(-,?,?,?). |
| 3627 | | not_disjoint3(pred_true,_,_,_). |
| 3628 | | not_disjoint3(pred_false,T,S2,WF) :- not_disjoint_sets2(T,S2,WF). |
| 3629 | | |
| 3630 | | test_disjoint_wf(S1,S2,DisjRes,WF) :- |
| 3631 | | intersection(S1,S2,Inter,WF), % TODO: could be done more efficiently, without computing full intersection |
| 3632 | | empty_set_test_wf(Inter,DisjRes,WF). |
| 3633 | | |
| 3634 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(intersection_generalized_wf([[int(3)],[int(2),int(1),int(3)]],[int(3)],unknown,WF),WF)). |
| 3635 | | :- 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)). |
| 3636 | | :- 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))), |
| 3637 | | 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))), |
| 3638 | | avl_set(node(fd(2,'Name'),true,0,empty,empty)),unknown,_WF))). |
| 3639 | | :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(1)],[int(2)]],Res,unknown,_WF),Res=[])). |
| 3640 | | :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(1)],[int(2),int(1)]],Res,unknown,_WF), |
| 3641 | | kernel_objects:equal_object(Res,[int(1)]))). |
| 3642 | | :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(1)],X,[int(2),int(3),int(1)]],Res,unknown,_WF), |
| 3643 | | X = [int(2),int(1)], |
| 3644 | | kernel_objects:equal_object(Res,[int(1)]))). |
| 3645 | | :- assert_must_succeed((kernel_objects:intersection_generalized_wf([X,X,[int(2),int(3),int(1)]],Res,unknown,_WF), |
| 3646 | | X = [int(2),int(1)], kernel_objects:equal_object(Res,[int(1),int(2)]))). |
| 3647 | | :- assert_must_succeed((kernel_objects:intersection_generalized_wf([[int(2),int(1),int(3)],X,[int(1),int(2)],X],Res,unknown,_WF), |
| 3648 | | kernel_objects:equal_object(X,Res), X = [int(2),int(1)])). |
| 3649 | | :- assert_must_succeed((kernel_objects:intersection_generalized_wf([global_set('Name'),X],Res,unknown,_WF), |
| 3650 | | kernel_objects:equal_object(X,Res), X = [fd(2,'Name'),fd(1,'Name')])). |
| 3651 | | :- assert_must_fail((kernel_objects:intersection_generalized_wf([[int(1)],[int(2)]],Res,unknown,_WF),( |
| 3652 | | kernel_objects:equal_object(Res,[_|_])))). |
| 3653 | | :- assert_must_fail((kernel_objects:intersection_generalized_wf([[int(1)],[int(1)]],Res,unknown,_WF),(Res=[]; |
| 3654 | | kernel_objects:equal_object(Res,[_,_|_])))). |
| 3655 | | :- assert_must_abort_wf(kernel_objects:intersection_generalized_wf([],_R,unknown,WF),WF). |
| 3656 | | |
| 3657 | | % code for general_intersection |
| 3658 | | :- block intersection_generalized_wf(-,?,?,?). |
| 3659 | | intersection_generalized_wf(SetsOfSets,Res,Span,WF) :- |
| 3660 | | expand_custom_set_to_list_wf(SetsOfSets,ESetsOfSets,_,intersection_generalized_wf,WF), |
| 3661 | | intersection_generalized2(ESetsOfSets,Res,Span,WF). |
| 3662 | | |
| 3663 | | intersection_generalized2([],Res,Span,WF) :- /* Atelier-B manual requires argument to inter to be non-empty */ |
| 3664 | | add_wd_error_set_result('inter applied to empty set','',Res,[],Span,WF). |
| 3665 | | intersection_generalized2([H|T],Res,_Span,WF) :- intersection_generalized3(T,H,Res,WF). |
| 3666 | | :- block intersection_generalized3(-,?,?,?). |
| 3667 | | intersection_generalized3([],SoFar,Res,WF) :- equal_object_optimized_wf(SoFar,Res,intersection_generalized3,WF). |
| 3668 | | intersection_generalized3([H|T],InterSoFar,Res,WF) :- |
| 3669 | | intersection(H,InterSoFar,InterSoFar2,WF), |
| 3670 | | intersection_generalized3(T,InterSoFar2,Res,WF). |
| 3671 | | |
| 3672 | | :- assert_must_succeed(exhaustive_kernel_check(difference_set([int(3),int(2)],[int(2),int(1),int(3)],[]))). |
| 3673 | | :- assert_must_succeed(exhaustive_kernel_check(difference_set([int(3),int(2)],[int(2),int(1),int(4)],[int(3)]))). |
| 3674 | | :- assert_must_succeed((kernel_objects:difference_set(SSS,[[int(1),int(2)]],[]), |
| 3675 | | kernel_objects:equal_object(SSS,[[int(2),int(1)]]))). |
| 3676 | | :- assert_must_succeed((kernel_objects:difference_set(SSS,[[int(1),int(2)]],R), kernel_objects:equal_object(R,[]), |
| 3677 | | kernel_objects:equal_object(SSS,[[int(2),int(1)]]))). |
| 3678 | | :- assert_must_succeed((kernel_objects:difference_set(SSS,[[fd(1,'Name'),fd(2,'Name')]],R), |
| 3679 | | kernel_objects:equal_object(R,[]), |
| 3680 | | kernel_objects:equal_object(SSS,[[fd(2,'Name'),fd(1,'Name')]]))). |
| 3681 | | :- assert_must_succeed((kernel_objects:difference_set(SSS,[[int(1),int(2)]],[]), |
| 3682 | | kernel_objects:equal_object(SSS,[[int(1),int(2)]]))). |
| 3683 | | :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[int(1)],_))). |
| 3684 | | :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[int(2)],_))). |
| 3685 | | :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[int(2)],[int(1)]))). |
| 3686 | | :- assert_must_succeed((kernel_objects:difference_set([int(1),int(2)],[],[int(2),int(1)]))). |
| 3687 | | :- assert_must_succeed((kernel_objects:difference_set([],[int(1),int(2)],[]))). |
| 3688 | | :- assert_must_succeed((kernel_objects:difference_set(Y,X,Res),X=global_set('Name'), |
| 3689 | | kernel_objects:equal_object(Res,[]), Y =[fd(1,'Name')])). |
| 3690 | | :- assert_must_succeed((kernel_objects:difference_set(X,Y,Res),X=global_set('Name'), |
| 3691 | | kernel_objects:equal_object(Res,[fd(3,'Name'),fd(1,'Name')]), Y =[fd(2,'Name')])). |
| 3692 | | :- assert_must_fail((kernel_objects:difference_set(X,Y,Res),X=global_set('Name'), |
| 3693 | | kernel_objects:equal_object(Res,[]), Y =[fd(1,'Name'),fd(2,'Name')])). |
| 3694 | | :- assert_must_fail((kernel_objects:difference_set(Y,X,Res),X=global_set('Name'), |
| 3695 | | kernel_objects:equal_object(Res,Y), Y =[fd(1,'Name')])). |
| 3696 | | |
| 3697 | | % deals with set_subtraction AST node |
| 3698 | | difference_set(Set1,Set2,Res) :- init_wait_flags(WF), |
| 3699 | ? | difference_set_wf(Set1,Set2,Res,WF), |
| 3700 | ? | ground_wait_flags(WF). |
| 3701 | | |
| 3702 | | :- block difference_set_wf(-,-,?,?). |
| 3703 | | difference_set_wf(Set1,_,Res,WF) :- Set1==[],!,empty_set_wf(Res,WF). |
| 3704 | | difference_set_wf(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,difference_set_wf,WF). |
| 3705 | ? | difference_set_wf(Set1,Set2,Res,WF) :- difference_set1(Set1,Set2,Res,WF). |
| 3706 | | |
| 3707 | | |
| 3708 | | :- block difference_set1(?,-,-,?), difference_set1(-,?,-,?). |
| 3709 | | difference_set1(Set1,Set2,Res,WF) :- |
| 3710 | | nonvar(Set1),is_custom_explicit_set(Set1,difference_set), |
| 3711 | | difference_of_explicit_set_wf(Set1,Set2,Diff,WF), !, |
| 3712 | | equal_object_wf(Diff,Res,difference_set1_1,WF). |
| 3713 | | difference_set1(Set1,Set2,Res,WF) :- Set2==[],!,equal_object_wf(Set1,Res,difference_set1_2,WF). |
| 3714 | ? | difference_set1(Set1,Set2,Res,WF) :- Res==[],!, check_subset_of_wf(Set1,Set2,WF). |
| 3715 | | difference_set1(Set1,Set2,Res,WF) :- |
| 3716 | | expand_custom_set_to_list_wf(Set1,ESet1,_,difference_set1,WF), |
| 3717 | | compute_diff(ESet1,Set2,Res,WF), |
| 3718 | | propagate_into2(Res,ESet1,Set2,WF). |
| 3719 | | |
| 3720 | | :- block compute_diff(-,?,?,?). |
| 3721 | | compute_diff([],_Set2,Res,WF) :- empty_set_wf(Res,WF). |
| 3722 | | compute_diff([H|T],Set2,Res,WF) :- |
| 3723 | | membership_test_wf(Set2,H,MemRes,WF),compute_diff2(MemRes,H,T,Set2,Res,WF). |
| 3724 | | |
| 3725 | | :- block compute_diff2(-,?,?,?,?,?). |
| 3726 | | compute_diff2(pred_true,_H,T,Set2,Res,WF) :- compute_diff(T,Set2,Res,WF). |
| 3727 | ? | compute_diff2(pred_false,H,T,Set2,Res,WF) :- equal_object_wf([H|R2],Res,compute_diff2,WF), |
| 3728 | | compute_diff(T,Set2,R2,WF). |
| 3729 | | |
| 3730 | | % propagate all elements from one set into another one; do not use for computation; may skip elements ... |
| 3731 | | /* this version not used at the moment: |
| 3732 | | :- block propagate_into(-,?,?). |
| 3733 | | propagate_into(_,Set2,_WF) :- nonvar(Set2), |
| 3734 | | is_custom_explicit_set(Set2,propagate_into),!. % second set already fully known |
| 3735 | | propagate_into([],_,_WF) :- !. |
| 3736 | | propagate_into([H|T],Set,WF) :- !,check_element_of_wf(H,Set,WF), propagate_into(T,Set,WF). |
| 3737 | | propagate_into(Set1,Set2,WF) :- is_custom_explicit_set(Set1,propagate_into),!, |
| 3738 | | (is_infinite_explicit_set(Set1) -> true ; |
| 3739 | | expand_custom_set_to_list(Set1,ESet1), propagate_into(ESet1,Set2,WF)). */ |
| 3740 | | |
| 3741 | | :- block propagate_into2(-,?,?,?). |
| 3742 | | propagate_into2(_,Set2,_NegSet,_WF) :- nonvar(Set2), |
| 3743 | | is_custom_explicit_set(Set2,propagate_into),!. % second set already fully known |
| 3744 | | propagate_into2([],_,_,_WF) :- !. |
| 3745 | | propagate_into2([H|T],PosSet,NegSet,WF) :- !, |
| 3746 | | check_element_of_wf(H,PosSet,WF), |
| 3747 | | not_element_of_wf(H,NegSet,WF),propagate_into2(T,PosSet,NegSet,WF). |
| 3748 | | propagate_into2(Set1,PosSet,NegSet,WF) :- is_custom_explicit_set(Set1,propagate_into),!, |
| 3749 | | (is_infinite_explicit_set(Set1) -> true ; |
| 3750 | | expand_custom_set_to_list_wf(Set1,ESet1,_,propagate_into2,WF), propagate_into2(ESet1,PosSet,NegSet,WF)). |
| 3751 | | |
| 3752 | | :- 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)). |
| 3753 | | :- block in_difference_set_wf(-,-,-,?). |
| 3754 | | in_difference_set_wf(A,X,Y,WF) :- |
| 3755 | | (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)), |
| 3756 | | % symbolic treatment would also make sense when A is nonvar and X var to force A to be in X ?! |
| 3757 | | !, |
| 3758 | | check_element_of_wf(A,X,WF), not_element_of_wf(A,Y,WF). |
| 3759 | | in_difference_set_wf(A,X,Y,WF) :- |
| 3760 | | difference_set_wf(X,Y,Diff,WF), |
| 3761 | | check_element_of_wf(A,Diff,WF). |
| 3762 | | |
| 3763 | | treat_arg_symbolically(X) :- var(X),!. |
| 3764 | | treat_arg_symbolically(global_set(_)). |
| 3765 | | treat_arg_symbolically(freetype(_)). |
| 3766 | | treat_arg_symbolically(closure(P,T,B)) :- \+ small_interval(P,T,B). |
| 3767 | | |
| 3768 | | small_interval(P,T,B) :- is_interval_closure(P,T,B,Low,Up), |
| 3769 | | integer(Low), integer(Up), |
| 3770 | | Up-Low < 500. % Magic Constant; TO DO: determine good value |
| 3771 | | |
| 3772 | | |
| 3773 | | :- 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)). |
| 3774 | | :- 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)). |
| 3775 | | :- 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)). |
| 3776 | | |
| 3777 | | :- block not_in_difference_set_wf(-,-,-,?). |
| 3778 | | not_in_difference_set_wf(A,X,Y,WF) :- |
| 3779 | | (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)), |
| 3780 | | !, |
| 3781 | | % A : (X-Y) <=> A:X & not(A:Y) |
| 3782 | | % A /: (X-Y) <=> A/: X or A:Y |
| 3783 | | membership_test_wf(X,A,AX_Res,WF), |
| 3784 | | (AX_Res==pred_false -> true |
| 3785 | | ; bool_pred:negate(AX_Res,NotAX_Res), |
| 3786 | | 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 ? |
| 3787 | | membership_test_wf(Y,A,AY_Res,WF) |
| 3788 | | ). |
| 3789 | | not_in_difference_set_wf(A,X,Y,WF) :- |
| 3790 | | difference_set_wf(X,Y,Diff,WF), |
| 3791 | | not_element_of_wf(A,Diff,WF). |
| 3792 | | |
| 3793 | | |
| 3794 | | :- 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)). |
| 3795 | | |
| 3796 | | :- block in_intersection_set_wf(-,-,-,?). |
| 3797 | | in_intersection_set_wf(A,X,Y,WF) :- |
| 3798 | | (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) |
| 3799 | | ; preference(convert_comprehension_sets_into_closures,true)), |
| 3800 | | (preference(data_validation_mode,true) -> nonvar(X) ; true), |
| 3801 | | % otherwise we may change enumeration order and enumerate with Y first; |
| 3802 | | % see private_examples/ClearSy/2019_May/perf_3264/rule_186.mch (but also test 1976); |
| 3803 | | % we could check if A is ground |
| 3804 | | !, |
| 3805 | | Y \== [], % avoid setting up check_element_of for X then |
| 3806 | | check_element_of_wf(A,X,WF), check_element_of_wf(A,Y,WF). |
| 3807 | | in_intersection_set_wf(A,X,Y,WF) :- |
| 3808 | | intersection(X,Y,Inter,WF), |
| 3809 | | check_element_of_wf(A,Inter,WF). |
| 3810 | | |
| 3811 | | :- 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)). |
| 3812 | | :- block not_in_intersection_set_wf(-,-,-,?). |
| 3813 | | not_in_intersection_set_wf(_A,_X,Y,_WF) :- Y == [], !. % intersection will be empty; avoid analysing X |
| 3814 | | not_in_intersection_set_wf(A,X,Y,WF) :- |
| 3815 | | (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)), |
| 3816 | | !, |
| 3817 | | % A : (X /\ Y) <=> A:X & A:Y |
| 3818 | | % A /: (X /\ Y) <=> A/:X or A/:Y |
| 3819 | | membership_test_wf(X,A,AX_Res,WF), |
| 3820 | | (AX_Res==pred_false -> true |
| 3821 | | ; bool_pred:negate(AX_Res,NotAX_Res), bool_pred:negate(AY_Res,NotAY_Res), |
| 3822 | | 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 ? |
| 3823 | | membership_test_wf(Y,A,AY_Res,WF) |
| 3824 | | ). |
| 3825 | | not_in_intersection_set_wf(A,X,Y,WF) :- |
| 3826 | | intersection(X,Y,Inter,WF), |
| 3827 | | not_element_of_wf(A,Inter,WF). |
| 3828 | | |
| 3829 | | :- 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)). |
| 3830 | | :- 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)). |
| 3831 | | |
| 3832 | | :- block in_union_set_wf(-,-,-,?). |
| 3833 | | in_union_set_wf(A,X,Y,WF) :- |
| 3834 | | (treat_arg_symbolically(X) ; treat_arg_symbolically(Y) ; preference(convert_comprehension_sets_into_closures,true)), |
| 3835 | | % symbolic treatment would also make sense when A is nonvar and X var to force A to be in X ?! |
| 3836 | | !, |
| 3837 | | membership_test_wf(X,A,AX_Res,WF), |
| 3838 | | (AX_Res==pred_true -> true |
| 3839 | | ; 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 ? |
| 3840 | | membership_test_wf(Y,A,AY_Res,WF) |
| 3841 | | ). |
| 3842 | | in_union_set_wf(A,X,Y,WF) :- |
| 3843 | | union_wf(X,Y,Union,WF), |
| 3844 | | check_element_of_wf(A,Union,WF). |
| 3845 | | |
| 3846 | | :- 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)). |
| 3847 | | |
| 3848 | | :- block not_in_union_set_wf(-,-,-,?). |
| 3849 | | not_in_union_set_wf(A,X,Y,WF) :- |
| 3850 | | not_element_of_wf(A,X,WF), |
| 3851 | | not_element_of_wf(A,Y,WF). |
| 3852 | | |
| 3853 | | % --------------------- |
| 3854 | | |
| 3855 | | |
| 3856 | | strict_subset_of(X,Y) :- |
| 3857 | | init_wait_flags(WF,[strict_subset_of]), |
| 3858 | | strict_subset_of_wf(X,Y,WF), |
| 3859 | | ground_wait_flags(WF). |
| 3860 | | |
| 3861 | | :- assert_must_succeed(exhaustive_kernel_check(strict_subset_of_wf([int(3),int(2)],[int(2),int(1),int(3)],_))). |
| 3862 | | :- assert_must_succeed(exhaustive_kernel_check(strict_subset_of_wf([],[int(2),int(1),int(3)],_))). |
| 3863 | | :- assert_must_succeed(exhaustive_kernel_check(strict_subset_of_wf([],[ [] ],_))). |
| 3864 | | :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([int(3),int(2),int(1)],[int(2),int(1),int(3)],_))). |
| 3865 | | :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([int(1),int(4)],[int(2),int(1),int(3)],_))). |
| 3866 | | :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([[]],[],_))). |
| 3867 | | :- assert_must_succeed(exhaustive_kernel_fail_check(strict_subset_of_wf([],[],_))). |
| 3868 | | :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [int(1)], X=[int(2),int(1)])). |
| 3869 | | :- assert_must_succeed((kernel_objects:strict_subset_of(Y,X), Y = [int(1)], X=[int(2),int(1)])). |
| 3870 | | :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [], X=[int(2),int(1)])). |
| 3871 | | :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [[int(1),int(2)]], X=[[int(2)],[int(2),int(1)]])). |
| 3872 | | :- assert_must_succeed((kernel_objects:strict_subset_of_wf(Y,X,_WF), Y = [fd(1,'Name')], kernel_objects:equal_object(X,global_set('Name')))). |
| 3873 | | :- 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')))). |
| 3874 | | :- 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'))). |
| 3875 | | :- 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')))). |
| 3876 | | :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(1)], X=[int(2),int(1)])). |
| 3877 | | :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(1),int(2)], X=[int(2),int(1)])). |
| 3878 | | :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(2)], X=[int(2)])). |
| 3879 | | :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [int(2)], X=[int(1)])). |
| 3880 | | :- assert_must_fail((kernel_objects:strict_subset_of_wf(X,Y,_WF), Y = [], X=[int(1)])). |
| 3881 | | |
| 3882 | | |
| 3883 | | :- use_module(chrsrc(chr_set_membership),[chr_subset_strict/2, chr_not_subset_strict/2]). |
| 3884 | | :- use_module(chrsrc(chr_integer_inequality),[chr_in_interval/4]). |
| 3885 | | |
| 3886 | | strict_subset_of_wf(Set1,Set2,WF) :- |
| 3887 | | (preference(use_chr_solver,true) -> chr_subset_strict(Set1,Set2) |
| 3888 | | ; Set1 \== Set2), % relevant for test 1326 |
| 3889 | | strict_subset_of_wf_aux(Set1,Set2,WF). |
| 3890 | | |
| 3891 | | %:- block strict_subset_of_wf(-,-,?). |
| 3892 | | strict_subset_of_wf_aux(Set1,Set2,WF) :- Set1==[],!,not_empty_set_wf(Set2,WF). |
| 3893 | | %strict_subset_of_wf_aux(Set1,Set2,WF) :- var(Set2),nonvar(Set1), print(subs(Set1,Set2)),nl,fail. |
| 3894 | | strict_subset_of_wf_aux(Set1,Set2,WF) :- nonvar(Set2), singleton_set(Set2,_),!, empty_set_wf(Set1,WF). |
| 3895 | | strict_subset_of_wf_aux(Set1,Set2,WF) :- |
| 3896 | | not_empty_set_wf(Set2,WF), |
| 3897 | | get_cardinality_powset_wait_flag(Set2,strict_subset_of_wf,WF,_,LWF), |
| 3898 | | % we could subtract 1 from priority !? (get_cardinality_pow1set_wait_flag) |
| 3899 | | when(((nonvar(LWF),(nonvar(Set1);ground(Set2))) ; (nonvar(Set1),nonvar(Set2)) ), |
| 3900 | | strict_subset_of_aux_block(Set1,Set2,WF,LWF)). |
| 3901 | | |
| 3902 | | strict_subset_of_aux_block(Set1,_Set2,_WF,_LWF) :- |
| 3903 | | Set1==[], |
| 3904 | | !. % we have already checked that Set2 is not empty |
| 3905 | | strict_subset_of_aux_block(Set1,Set2,WF,_LWF) :- |
| 3906 | | nonvar(Set2), is_definitely_maximal_set(Set2), |
| 3907 | | !, |
| 3908 | | not_equal_object_wf(Set1,Set2,WF). |
| 3909 | | strict_subset_of_aux_block(Set1,Set2,WF,_LWF) :- nonvar(Set2), singleton_set(Set2,_),!, |
| 3910 | | empty_set_wf(Set1,WF). |
| 3911 | | strict_subset_of_aux_block(Set1,Set2,_WF,_LWF) :- |
| 3912 | | both_global_sets(Set1,Set2,G1,G2), |
| 3913 | | !, %(print(check_strict_subset_of_global_sets(G1,G2)),nl, |
| 3914 | | check_strict_subset_of_global_sets(G1,G2). |
| 3915 | | strict_subset_of_aux_block(Set1,Set2,WF,LWF) :- |
| 3916 | | var(Set1), nonvar(Set2), Set2=avl_set(_), |
| 3917 | | check_card_waitflag_less(LWF,4097), % if the number is too big strict_subset_of0 has better chance of working ?! |
| 3918 | | % without avl_set check test 1003 leads to time out for plavis-TransData_SP_13.prob, with |
| 3919 | | % memp : seq(STRING) & dom(memp) <<: ( mdp + 1 .. ( mdp + 43 ) ) |
| 3920 | | !, |
| 3921 | | %non_free(Set1), % as we used to force order, now we use equal_object_wf in gen_strict_subsets and no longer need non_free checking |
| 3922 | | expand_custom_set_to_list_wf(Set2,ESet2,_,strict_subset_of_wf,WF), |
| 3923 | | gen_strict_subsets(Set1,ESet2,WF). |
| 3924 | | strict_subset_of_aux_block(Set1,Set2,WF,LWF) :- |
| 3925 | ? | strict_subset_of0(Set1,Set2,WF,LWF). |
| 3926 | | % TO DO (26.10.2014): test 1270 now passes thanks to maximal set check above |
| 3927 | | % but we should need a better way of ensuring that something like {ssu|ssu<<:POW(elements)} is efficiently computed |
| 3928 | | % (which it no longer is once the unbound_variable check had been fixed) |
| 3929 | | % we could also just generally use Set1 <: Set2 & Set1 /= Set2 |
| 3930 | | |
| 3931 | | check_card_waitflag_less(float(Nr),Limit) :- number(Nr), Nr<Limit. |
| 3932 | | |
| 3933 | | % avoid generating different ordering of the same subset ([1,2] and [2,1] for example), useful for test 642 |
| 3934 | | % Note: remove_element_wf in strict_subset_of2 will create different orders |
| 3935 | | % for sequence domains gen_strict_subsets uses just the wrong order (deciding to remove 1 first); |
| 3936 | | % cf test 1003 where not including 1 in domain is bad: memp : seq(STRING) & dom(memp) <<: ( mdp + 1 .. ( mdp + 43 ) ) |
| 3937 | | gen_strict_subsets(T,[H2|T2],WF) :- |
| 3938 | | not_element_of_wf(H2,T,WF), |
| 3939 | | gen_subsets(T,T2,WF). |
| 3940 | | gen_strict_subsets(SubSet,[H2|T2],WF) :- |
| 3941 | | equal_object_wf([H2|T],SubSet,gen_strict_subsets,WF), |
| 3942 | | gen_strict_subsets(T,T2,WF). |
| 3943 | | |
| 3944 | | |
| 3945 | | %:- block strict_subset_of0(-,?,?,?). % required to wait: we know Set2 must be non-empty, but Set1 could be an avl-tree or closure |
| 3946 | | strict_subset_of0(Set1,Set2,WF,_) :- |
| 3947 | | subset_of_explicit_set(Set1,Set2,Code,WF),!, |
| 3948 | | call(Code), |
| 3949 | | not_equal_object_wf(Set1,Set2,WF). |
| 3950 | | strict_subset_of0(Set1,Set2,WF,LWF) :- |
| 3951 | | expand_custom_set_to_list_wf(Set1,ESet1,_,strict_subset_of0,WF), |
| 3952 | | (ESet1==[] -> true %not_empty_set(Set2) already checked above |
| 3953 | ? | ; is_infinite_explicit_set(Set2) -> |
| 3954 | | % Set1 is expanded to a list ESet1 and thus finite: it is sufficient to check subset relation |
| 3955 | | check_subset_of_wf(ESet1,Set2,WF) |
| 3956 | | ; try_expand_custom_set_wf(Set2,ESet2,strict_subset_of0,WF), |
| 3957 | | %%try_prop_card_lt(ESet1,ESet2), try_prop_card_gt(ESet2,ESet1), |
| 3958 | ? | strict_subset_of2(ESet1,[],ESet2,WF,LWF) |
| 3959 | | ). |
| 3960 | | |
| 3961 | | :- block strict_subset_of2(-,?,?,?,-). |
| 3962 | | %strict_subset_of2(S,SoFar,Set2,WF,LWF) :- nl,print(strict_subset_of2(S,SoFar,Set2,WF,LWF)),nl,fail. |
| 3963 | | strict_subset_of2([],SoFar,RemS,WF,_LWF) :- |
| 3964 | | not_empty_set_wf(RemS,WF), % check remaining set (elements in Set2 not in Set1) is not empty |
| 3965 | | disjoint_sets(RemS,SoFar). % ensure we have not accidentally created Set2 with duplicates |
| 3966 | | % if a duplicate is in RemS, we may not have a strict_subset (test 2480) ! |
| 3967 | | strict_subset_of2([H|T],SoFar,Set2,WF,LWF) :- var(Set2),!, |
| 3968 | | equal_cons_wf(Set2,H,Set2R,WF), %was Set2 = [H|Set2R], |
| 3969 | | not_element_of_wf(H,SoFar,WF), |
| 3970 | | add_new_element_wf(H,SoFar,SoFar2,WF), %was SoFar2 = [H|SoFar], |
| 3971 | | strict_subset_of2(T,SoFar2,Set2R,WF,LWF). |
| 3972 | | strict_subset_of2([H|T],SoFar,Set2,WF,LWF) :- |
| 3973 | | % when_sufficiently_for_member(H,Set2,WF, |
| 3974 | ? | remove_element_wf(H,Set2,RS2,WF), |
| 3975 | | not_empty_set_wf(RS2,WF), |
| 3976 | | not_element_of_wf(H,SoFar,WF), /* consistent((H,SoFar)), necessary? */ |
| 3977 | | when((nonvar(T) ; (ground(LWF),ground(RS2))), |
| 3978 | | (add_new_element_wf(H,SoFar,SoFar2,WF), %SoFar2 = [H|SoFar], |
| 3979 | | strict_subset_of2(T,SoFar2,RS2,WF,LWF) )). |
| 3980 | | |
| 3981 | | |
| 3982 | | |
| 3983 | | |
| 3984 | | :- assert_must_succeed(exhaustive_kernel_check(partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ],_))). |
| 3985 | | :- assert_must_succeed(exhaustive_kernel_check(partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)] ],_))). |
| 3986 | | :- assert_must_succeed(exhaustive_kernel_check(partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5)],[int(1)] ],_))). |
| 3987 | | :- assert_must_succeed(exhaustive_kernel_fail_check(partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)], [int(3)] ],_))). |
| 3988 | | :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ], _))). |
| 3989 | | :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2)],[ [int(2)], [int(1)], [] ], _))). |
| 3990 | | :- assert_must_fail((kernel_objects:partition_wf([int(1),int(2)],[ [int(2)], [int(1),int(2)] ], _))). |
| 3991 | | :- assert_must_fail((kernel_objects:partition_wf([int(1),int(3)],[ [int(1)], [int(2)] ], _))). |
| 3992 | | :- assert_must_fail((kernel_objects:partition_wf([int(1),int(2),int(3)],[ [int(1)], [int(2)] ], _))). |
| 3993 | | :- assert_must_succeed((kernel_objects:partition_wf([int(1)],[S1,S2],_WF), S1=[H|T], S2==[],T==[],H==int(1))). |
| 3994 | | :- 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)))). |
| 3995 | | :- 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))). |
| 3996 | | :- assert_must_succeed((kernel_objects:partition_wf([int(1),int(2),int(3)],[[int(1)],X,[int(2)]],_WF), |
| 3997 | | X==[int(3)])). |
| 3998 | | |
| 3999 | | :- use_module(bsets_clp,[disjoint_union_generalized_wf/3]). |
| 4000 | | :- use_module(kernel_tools,[ground_value/1]). |
| 4001 | | :- block partition_wf(?,-,?). |
| 4002 | | partition_wf(Set,ListOfSets,WF) :- |
| 4003 | | partition_disj_union_wf(Set,ListOfSets,WF), |
| 4004 | | all_disjoint(ListOfSets,WF). |
| 4005 | | |
| 4006 | | % just check that the disjoint union of all sets is equal to Set |
| 4007 | | partition_disj_union_wf(Set,ListOfSets,WF) :- |
| 4008 | | ground_value(Set),find_non_ground_set(ListOfSets,NGS,Rest),!, |
| 4009 | | disjoint_union_generalized_wf(Rest,RestSet,WF), |
| 4010 | | check_subset_of_wf(RestSet,Set,WF), % otherwise this is not a partition of Set |
| 4011 | | difference_set(Set,RestSet,NGS). |
| 4012 | | partition_disj_union_wf(Set,ListOfSets,WF) :- |
| 4013 | | disjoint_union_generalized_wf(ListOfSets,Set,WF). |
| 4014 | | |
| 4015 | | :- 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)])). |
| 4016 | | find_non_ground_set([H|T],NG,Rest) :- |
| 4017 | | (ground_value(H) -> Rest=[H|TR], find_non_ground_set(T,NG,TR) |
| 4018 | | ; ground_value(T),NG=H, Rest=T). |
| 4019 | | |
| 4020 | | :- block all_disjoint(-,?). |
| 4021 | | % check if a list of sets is all disjoint (Note: this is not a set of sets) |
| 4022 | | all_disjoint([],_WF) :- !. |
| 4023 | | all_disjoint([H|T],WF) :- !, |
| 4024 | | all_disjoint_with(T,H,WF), |
| 4025 | | all_disjoint(T,WF). |
| 4026 | | all_disjoint(S,WF) :- add_internal_error('Not a list for partition:',all_disjoint(S,WF)),fail. |
| 4027 | | |
| 4028 | | :- block all_disjoint_with(-,?,?). |
| 4029 | | all_disjoint_with([],_,_WF). |
| 4030 | | all_disjoint_with([H|T],Set1,WF) :- disjoint_sets(Set1,H,WF), all_disjoint_with(T,Set1,WF). |
| 4031 | | |
| 4032 | | |
| 4033 | | % a utility to check for duplicates in set lists and enter debugger |
| 4034 | | %:- block check_set_for_repetitions(-,?). |
| 4035 | | %check_set_for_repetitions([],_) :- !. |
| 4036 | | %check_set_for_repetitions([H|T],Acc) :- !, |
| 4037 | | % when(ground(H),(member(H,Acc) -> tools:print_bt_message(duplicate(H,Acc)),trace |
| 4038 | | % ; check_set_for_repetitions(T,[H|Acc]))). |
| 4039 | | %check_set_for_repetitions(_,_). |
| 4040 | | |
| 4041 | | :- assert_must_succeed(exhaustive_kernel_fail_check(not_partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ],_))). |
| 4042 | | :- assert_must_succeed(exhaustive_kernel_fail_check(not_partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)] ],_))). |
| 4043 | | :- assert_must_succeed(exhaustive_kernel_fail_check(not_partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5)],[int(1)] ],_))). |
| 4044 | | :- assert_must_succeed(exhaustive_kernel_check(not_partition_wf([int(1),int(2),int(5)],[ [int(2)], [int(5),int(1)], [int(3)] ],_))). |
| 4045 | | :- assert_must_fail((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(2)], [int(1)] ], _))). |
| 4046 | | :- assert_must_fail((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(2)], [int(1)], [] ], _))). |
| 4047 | | :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(2)], [int(1),int(2)] ], _))). |
| 4048 | | :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(3)],[ [int(1)], [int(2)] ], _))). |
| 4049 | | :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(2),int(3)],[ [int(1)], [int(2)] ], _))). |
| 4050 | | :- assert_must_succeed((kernel_objects:not_partition_wf([int(1),int(2)],[ [int(1),int(2)], [int(1),int(2)] ], _))). |
| 4051 | | |
| 4052 | | not_partition_wf(FullSet,ListOfSets,WF) :- |
| 4053 | ? | test_partition_wf(FullSet,ListOfSets,pred_false,WF). |
| 4054 | | |
| 4055 | | |
| 4056 | | :- use_module(b_interpreter_check,[imply_true/2]). % TODO: move to another module |
| 4057 | | :- block test_partition_wf(?,-,?,?). |
| 4058 | | test_partition_wf(FullSet,ListOfSets,PredRes,WF) :- |
| 4059 | | bool_pred:negate(PredRes,NotPredRes), |
| 4060 | | propagate_partition_true(FullSet,ListOfSets,PredRes,WF), |
| 4061 | ? | test_partition_wf2(ListOfSets,[],FullSet,PredRes,NotPredRes,WF). |
| 4062 | | |
| 4063 | | :- block propagate_partition_true(?,?,-,?). |
| 4064 | | propagate_partition_true(FullSet,ListOfSets,pred_true,WF) :- |
| 4065 | | % ensure we propagate more info; required for tests 1059, 1060 |
| 4066 | | partition_disj_union_wf(FullSet,ListOfSets,WF). |
| 4067 | | propagate_partition_true(_,_,pred_false,_). |
| 4068 | | |
| 4069 | | :- block test_partition_wf2(-,?,?, ?,?,?). |
| 4070 | | %test_partition_wf2(Sets,SoFar,_,Pred,_,_) :- print_term_summary(test_partition_wf2(Sets,SoFar,Pred)),nl,fail. |
| 4071 | ? | test_partition_wf2([],ElementsSoFar,FullSet,PredRes,_,WF) :- !, equality_objects_wf(ElementsSoFar,FullSet,PredRes,WF). |
| 4072 | | test_partition_wf2([Set1|Rest],ElementsSoFar,FullSet,PredRes,NotPredRes,WF) :- !, |
| 4073 | | expand_custom_set_to_list_wf(Set1,ESet1,_,test_partition_wf2,WF), % TODO: requires finite set; choose instantiated sets first |
| 4074 | ? | test_partition_wf3(ESet1,ElementsSoFar,ElementsSoFar,Rest,FullSet,PredRes,NotPredRes,WF). |
| 4075 | | test_partition_wf2(A,E,FS,PR,NPR,WF) :- |
| 4076 | | add_internal_error('Not a list for partition:',test_partition_wf2(A,E,FS,PR,NPR,WF)),fail. |
| 4077 | | |
| 4078 | | :- block test_partition_wf3(-,?,?,?, ?,?,?,?). |
| 4079 | | test_partition_wf3([],_,NewElementsSoFar,OtherSets,FullSet,PredRes,NPR,WF) :- |
| 4080 | ? | test_partition_wf2(OtherSets,NewElementsSoFar,FullSet,PredRes,NPR,WF). % finished treating this set |
| 4081 | | test_partition_wf3([H|T],ElementsSoFar,NewElementsSoFar,OtherSets,FullSet,PredRes,NotPredRes,WF) :- |
| 4082 | | imply_true(MemRes,NotPredRes), % if not disjoint (MemRes=pred_true) then we do not have a partition |
| 4083 | | membership_test_wf(ElementsSoFar,H,MemRes,WF), |
| 4084 | ? | test_partition_wf4(MemRes,H,T,ElementsSoFar,NewElementsSoFar,OtherSets,FullSet,PredRes,NotPredRes,WF). |
| 4085 | | |
| 4086 | | :- block test_partition_wf4(-,?,?,?,?, ?,?,?,?,?). |
| 4087 | | test_partition_wf4(pred_true,_,_,_,_,_,_,pred_false,_,_). % Not disjoint |
| 4088 | | test_partition_wf4(pred_false,H,T,ElementsSoFar,NewElementsSoFar,OtherSets,FullSet,PredRes,NotPredRes,WF) :- |
| 4089 | | add_element_wf(H,NewElementsSoFar,NewElementsSoFar2,WF), % we could also already check whether H in FullSet or not |
| 4090 | | %(PredRes==pred_true -> check_element_of_wf(H,FullSet,WF) ; true), |
| 4091 | ? | test_partition_wf3(T,ElementsSoFar,NewElementsSoFar2,OtherSets,FullSet,PredRes,NotPredRes,WF). |
| 4092 | | |
| 4093 | | |
| 4094 | | |
| 4095 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(check_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1),int(3)]))). |
| 4096 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(check_subset_of([int(1),int(2),int(5)],[int(2),int(5),int(1)]))). |
| 4097 | | :- assert_must_succeed(exhaustive_kernel_fail_check(check_subset_of([int(1),int(3),int(5)],[int(2),int(5),int(1)]))). |
| 4098 | | :- assert_must_succeed((kernel_objects:power_set(global_set('Name'),PS),kernel_objects:check_subset_of(X,PS), |
| 4099 | | kernel_objects:equal_object(X,[[fd(2,'Name'),fd(1,'Name')]]))). |
| 4100 | | :- assert_must_succeed(findall(X,kernel_objects:check_subset_of(X,[[int(1),int(2)],[]]),[_1,_2,_3,_4])). |
| 4101 | | :- assert_must_succeed((kernel_objects:check_subset_of(X,[[int(1),int(2)],[]]), |
| 4102 | | nonvar(X), |
| 4103 | | kernel_objects:equal_object(X,[[int(2),int(1)]]))). |
| 4104 | | :- assert_must_succeed((kernel_objects:check_subset_of_wf(Y,X,_WF), Y = [fd(1,'Name')], |
| 4105 | | nonvar(X),X=[H|T], var(T), H==fd(1,'Name'), X=Y)). |
| 4106 | | :- assert_must_succeed((kernel_objects:check_subset_of(Y,X), Y = [fd(1,'Name')], kernel_objects:equal_object(X,global_set('Name')))). |
| 4107 | | :- 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')))). |
| 4108 | | :- 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')))). |
| 4109 | | :- assert_must_succeed((kernel_objects:sample_closure(C),kernel_objects:check_subset_of(C,global_set('NAT')))). |
| 4110 | | :- assert_must_succeed((kernel_objects:check_subset_of(global_set('NAT'),global_set('NAT')))). |
| 4111 | | :- assert_must_succeed((kernel_objects:check_subset_of(global_set('NAT'),global_set('NATURAL')))). |
| 4112 | | :- assert_must_fail((kernel_objects:check_subset_of(global_set('NAT'),global_set('NATURAL1')))). |
| 4113 | | :- assert_must_fail((kernel_objects:check_subset_of(global_set('NAT'),global_set('NAT1')))). |
| 4114 | | :- assert_must_fail((kernel_objects:check_subset_of(X,Y), Y = [fd(1,'Name')], kernel_objects:equal_object(X,global_set('Name')))). |
| 4115 | | /* TO DO: add special treatment for closures and type checks !! */ |
| 4116 | | |
| 4117 | | check_subset_of(Set1,Set2) :- init_wait_flags(WF), |
| 4118 | ? | check_subset_of_wf(Set1,Set2,WF), |
| 4119 | ? | ground_wait_flags(WF). |
| 4120 | | |
| 4121 | | check_finite_subset_of_wf(Set1,Set2,WF) :- |
| 4122 | | check_subset_of_wf(Set1,Set2,WF), |
| 4123 | | is_finite_set_wf(Set1,WF). |
| 4124 | | |
| 4125 | | :- block check_subset_of_wf(-,-,?). |
| 4126 | | check_subset_of_wf(Set1,Set2,WF) :- |
| 4127 | | (both_global_sets(Set1,Set2,G1,G2) |
| 4128 | | -> check_subset_of_global_sets(G1,G2) |
| 4129 | ? | ; check_subset_of0(Set1,Set2,WF) |
| 4130 | | ). |
| 4131 | | |
| 4132 | | both_global_sets(S1,S2,G1,G2) :- nonvar(S1),nonvar(S2), |
| 4133 | | is_global_set(S1,G1), is_global_set(S2,G2). |
| 4134 | | |
| 4135 | | % check if we have a global set or interval |
| 4136 | | % is_global_set([],R) :- !, R=interval(0,-1). % useful ??? |
| 4137 | | is_global_set(global_set(G1),R) :- !, |
| 4138 | | (custom_explicit_sets:get_integer_set_interval(G1,Low,Up) -> R=interval(Low,Up) ; R=G1). |
| 4139 | | is_global_set(Closure,R) :- |
| 4140 | | custom_explicit_sets:is_interval_closure_or_integerset(Closure,Low,Up),!, |
| 4141 | | R=interval(Low,Up). |
| 4142 | | |
| 4143 | | |
| 4144 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(0,0),interval(minus_inf,inf))). |
| 4145 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(-200,1000),interval(minus_inf,inf))). |
| 4146 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(10,1000),interval(0,inf))). |
| 4147 | | :- assert_must_fail(kernel_objects:check_subset_of_global_sets(interval(-10,1000),interval(0,inf))). |
| 4148 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(0,inf),interval(0,inf))). |
| 4149 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(0,inf),interval(minus_inf,inf))). |
| 4150 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(1,inf),interval(0,inf))). |
| 4151 | | :- assert_must_succeed(kernel_objects:check_subset_of_global_sets(interval(1,inf),interval(minus_inf,inf))). |
| 4152 | | |
| 4153 | | % to do: also extend to allow intervals with inf/minus_inf |
| 4154 | | check_subset_of_global_sets(X,Y) :- (var(X) ; var(Y)), |
| 4155 | | add_internal_error('Illegal call: ',check_subset_of_global_sets(X,Y)),fail. |
| 4156 | | check_subset_of_global_sets(interval(Low1,Up1),interval(Low2,Up2)) :- !, |
| 4157 | | interval_subset(Low1,Up1,Low2,Up2). |
| 4158 | | check_subset_of_global_sets(X,X) :- !. % both args must be atomic and ground (global set names) |
| 4159 | | % BUT WE COULD HAVE {x|x>0} <: NATURAL1 ? interval(0,inf) <: NATURAL1 |
| 4160 | | check_subset_of_global_sets(X,Y) :- check_strict_subset_of_global_sets(X,Y). |
| 4161 | | |
| 4162 | | % To do: perform some treatment of inf, minus_inf values here <---- |
| 4163 | | interval_subset(Low1,Up1,Low2,Up2) :- |
| 4164 | | (var(Low1) ; var(Up1)), % otherwise we can use code below |
| 4165 | | finite_interval(Low1,Up1), finite_interval(Low2,Up2), % inf can appear as term; but only directly not later |
| 4166 | | !, |
| 4167 | | % Maybe to do: try to avoid CLPFD overflows if possible; pass WF to force case distinction between empty/non-empty intervals |
| 4168 | | clpfd_in_interval(Low1,Up1,Low2,Up2). |
| 4169 | | interval_subset(Low1,Up1,Low2,Up2) :- |
| 4170 | | interval_subset_aux(Low1,Up1,Low2,Up2). |
| 4171 | | |
| 4172 | | % check if we have a finite interval (fails for inf/minus_inf terms) |
| 4173 | | finite_interval(Low1,Up1) :- (var(Low1) -> true ; integer(Low1)), (var(Up1) -> true ; integer(Up1)). |
| 4174 | | finite_val(LowUp) :- (var(LowUp) -> true ; integer(LowUp)). |
| 4175 | | |
| 4176 | | |
| 4177 | | |
| 4178 | | % assert Low1..Up1 <: Low2..Up2 |
| 4179 | | clpfd_in_interval(Low1,Up1,Low2,Up2) :- |
| 4180 | | (preferences:preference(use_chr_solver,true) |
| 4181 | | -> chr_in_interval(Low1,Up1,Low2,Up2) ; true), |
| 4182 | | % TO DO: improve detection of Low1 #=< Up1; maybe outside of CHR ?; we could also add a choice point here |
| 4183 | | % example: p..q <: 0..25 & p<q -> should constrain p,q to p:0..24 & q:1..25 |
| 4184 | | clpfd_interface:post_constraint2((Low1 #=< Up1) #=> ((Low2 #=< Low1) #/\ (Up1 #=< Up2)),Posted), |
| 4185 | | (Posted==true -> true ; interval_subset_aux(Low1,Up1,Low2,Up2)). |
| 4186 | | |
| 4187 | | :- block interval_subset_aux(-,?,?,?), interval_subset_aux(?,-,?,?). |
| 4188 | | interval_subset_aux(Low1,Up1,_,_) :- safe_less_than_with_inf(Up1,Low1). %Set 1 is empty. |
| 4189 | | interval_subset_aux(Low1,Up1,Low2,Up2) :- |
| 4190 | | safe_less_than_equal_with_inf(Low1,Up1), % Set 1 is not empty |
| 4191 | | safe_less_than_equal_with_inf_clpfd(Low2,Low1), safe_less_than_equal_with_inf_clpfd(Up1,Up2). % may call CLPFD |
| 4192 | | |
| 4193 | | % a version of safe_less_than which allows minus_inf and inf, but only if those terms appear straightaway at the first call |
| 4194 | | % assumes any variable will only be bound to a number |
| 4195 | | safe_less_than_with_inf(X,Y) :- (X==Y ; X==inf ; Y==minus_inf), !,fail. |
| 4196 | | safe_less_than_with_inf(X,Y) :- (X==minus_inf ; Y==inf), !. |
| 4197 | | safe_less_than_with_inf(X,Y) :- safe_less_than(X,Y). |
| 4198 | | |
| 4199 | | safe_less_than_with_inf_clpfd(X,Y) :- (X==Y ; X==inf ; Y==minus_inf), !,fail. |
| 4200 | | safe_less_than_with_inf_clpfd(X,Y) :- (X==minus_inf ; Y==inf), !. |
| 4201 | | safe_less_than_with_inf_clpfd(X,Y) :- less_than_direct(X,Y). % this can also call CLPFD |
| 4202 | | |
| 4203 | | % a version of safe_less_than_equal which allows minus_inf and inf, but only if those terms appear straightaway at the first call |
| 4204 | | safe_less_than_equal_with_inf(X,Y) :- X==Y,!. |
| 4205 | | safe_less_than_equal_with_inf(X,Y) :- (X==inf ; Y==minus_inf), !,fail. |
| 4206 | | safe_less_than_equal_with_inf(X,Y) :- (X==minus_inf ; Y==inf), !. |
| 4207 | | safe_less_than_equal_with_inf(X,Y) :- safe_less_than_equal(X,Y). |
| 4208 | | |
| 4209 | | safe_less_than_equal_with_inf_clpfd(X,Y) :- X==Y,!. |
| 4210 | | safe_less_than_equal_with_inf_clpfd(X,Y) :- (X==inf ; Y==minus_inf), !,fail. |
| 4211 | | safe_less_than_equal_with_inf_clpfd(X,Y) :- (X==minus_inf ; Y==inf), !. |
| 4212 | | safe_less_than_equal_with_inf_clpfd(X,Y) :- less_than_equal_direct(X,Y). % this can also call CLPFD |
| 4213 | | |
| 4214 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,2),interval(1,3))). |
| 4215 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,1),interval(1,2))). |
| 4216 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,1),interval(0,1))). |
| 4217 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(2,1),interval(33,34))). |
| 4218 | | :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(3,1),interval(4,2))). |
| 4219 | | :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(3,1),interval(2,1))). |
| 4220 | | :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(1,2),interval(1,2))). |
| 4221 | | :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(1,2),interval(2,3))). |
| 4222 | | :- assert_must_fail(kernel_objects:check_strict_subset_of_global_sets(interval(2,3),interval(1,2))). |
| 4223 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(0,1000),interval(0,inf))). |
| 4224 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(1,1000),interval(1,inf))). |
| 4225 | | :- assert_must_succeed(kernel_objects:check_strict_subset_of_global_sets(interval(-200,1000),interval(minus_inf,inf))). |
| 4226 | | % for any other term we have global enumerated or deferred sets: they cannot be a strict subset of each other |
| 4227 | | check_strict_subset_of_global_sets('FLOAT','REAL'). |
| 4228 | | check_strict_subset_of_global_sets(interval(Low1,Up1),interval(Low2,Up2)) :- |
| 4229 | ? | check_strict_subset_intervals(Low1,Up1,Low2,Up2). |
| 4230 | | |
| 4231 | | check_strict_subset_intervals(Low1,Up1,Low2,Up2) :- |
| 4232 | | safe_less_than_equal_with_inf_clpfd(Low2,Up2), % Low2..Up2 not empty |
| 4233 | ? | check_strict_subset_intervals1(Low1,Up1,Low2,Up2). |
| 4234 | | |
| 4235 | | check_strict_subset_intervals1(Low1,Up1,Low2,Up2) :- % we cannot have inf as term (yet) here |
| 4236 | | %preferences:preference(use_clpfd_solver,true), |
| 4237 | | (var(Low1) ; var(Up1)), |
| 4238 | | finite_interval(Low1,Up1), finite_interval(Low2,Up2), |
| 4239 | | !, |
| 4240 | | clpfd_interface:post_constraint2((Low1 #=< Up1) #=> ((Low2 #=< Low1) #/\ (Up1 #=< Up2) #/\ (Low1 #\= Low2 #\/ Up1 #\= Up2)),Posted), |
| 4241 | | (Posted==true -> true ; check_strict_subset_intervals2(Low1,Up1,Low2,Up2)). |
| 4242 | ? | check_strict_subset_intervals1(Low1,Up1,Low2,Up2) :- check_strict_subset_intervals2(Low1,Up1,Low2,Up2). |
| 4243 | | |
| 4244 | | :- block check_strict_subset_intervals2(-,?,?,?),check_strict_subset_intervals2(?,-,?,?), |
| 4245 | | check_strict_subset_intervals2(?,?,-,?). |
| 4246 | | check_strict_subset_intervals2(Low1,Up1,_,_) :- safe_less_than_with_inf(Up1,Low1). % interval 1 empty |
| 4247 | | check_strict_subset_intervals2(Low1,Up1,Low2,Up2) :- |
| 4248 | | safe_less_than_equal_with_inf(Low1,Up1), % interval 1 not empty |
| 4249 | | ( safe_less_than_with_inf(Low2,Low1), safe_less_than_equal_with_inf_clpfd(Up1,Up2) |
| 4250 | | ; |
| 4251 | | Low1=Low2,safe_less_than_with_inf_clpfd(Up1,Up2) |
| 4252 | | ). |
| 4253 | | |
| 4254 | | :- use_module(custom_explicit_sets,[is_definitely_maximal_set/1,singleton_set/2]). |
| 4255 | | :- use_module(kernel_tools,[ground_value_check/2, quick_same_value/2]). |
| 4256 | | |
| 4257 | | check_subset_of0(Set1,_Set2,_WF) :- Set1==[],!. |
| 4258 | | check_subset_of0(Set1,Set2,WF) :- Set2==[], |
| 4259 | | %nonvar(Set2),Set2=[], %var(Set1), |
| 4260 | | !, |
| 4261 | | empty_set_wf(Set1,WF). |
| 4262 | | check_subset_of0(_Set1,Set2,_WF) :- |
| 4263 | | nonvar(Set2),is_definitely_maximal_set(Set2),!. |
| 4264 | | %singleton |
| 4265 | | check_subset_of0(Set1,Set2,_) :- |
| 4266 | | quick_same_value(Set1,Set2), % important for e.g. test 1948 for closures with different info fields |
| 4267 | | !. |
| 4268 | | check_subset_of0(Set1,Set2,WF) :- custom_explicit_sets:singleton_set(Set1,El),!, |
| 4269 | | check_element_of_wf(El,Set2,WF). |
| 4270 | | check_subset_of0(Set1,Set2,WF) :- % Note: two intervals are treated in check_subset_of_global_sets |
| 4271 | | subset_of_explicit_set(Set1,Set2,Code,WF),!, |
| 4272 | | call(Code). |
| 4273 | | check_subset_of0(Set1,Set2,WF) :- nonvar(Set1),!, |
| 4274 | | get_cardinality_powset_wait_flag(Set2,check_subset_of0,WF,_,LWF), |
| 4275 | | expand_custom_set_to_list_wf(Set1,ESet1,_,check_subset_of1,WF), |
| 4276 | | try_expand_and_convert_to_avl_unless_large_wf(Set2,ESet2,WF), |
| 4277 | | % b_interpreter_components:observe_instantiation(ESet1,'ESet1',ESet1), |
| 4278 | ? | check_subset_of2(ESet1,[],ESet2,WF,LWF,none). |
| 4279 | | check_subset_of0(Set1,Set2,WF) :- |
| 4280 | | is_wait_flag_info(WF,wfx_no_enumeration),!, |
| 4281 | | check_subset_of0_lwf(Set1,Set2,WF,_LWF,_). |
| 4282 | | check_subset_of0(Set1,Set2,WF) :- |
| 4283 | | % DO we need LWF if Set1=avl_set(_) ?? |
| 4284 | | get_cardinality_powset_wait_flag(Set2,check_subset_of0,WF,_Card,LWF), |
| 4285 | | ground_value_check(Set2,GS2), |
| 4286 | ? | check_subset_of0_lwf(Set1,Set2,WF,LWF,GS2). |
| 4287 | | |
| 4288 | | :- use_module(custom_explicit_sets,[is_infinite_or_very_large_explicit_set/2]). |
| 4289 | | |
| 4290 | | :- block check_subset_of0_lwf(-,?,?,-,?),check_subset_of0_lwf(-,?,?,?,-). |
| 4291 | | check_subset_of0_lwf(Set1,_Set2,_WF,_LWF,_GS2) :- Set1==[],!. |
| 4292 | | %check_subset_of0_lwf(Set1,Set2,WF,_LWF) :- Set2==[],!, % can never trigger as Set2 was already nonvar |
| 4293 | | % empty_set_wf(Set1,WF). |
| 4294 | | check_subset_of0_lwf(Set1,Set2,WF,_LWF,_GS2) :- custom_explicit_sets:singleton_set(Set1,El),!, |
| 4295 | | check_element_of_wf(El,Set2,WF). |
| 4296 | | check_subset_of0_lwf(Set1,Set2,_WF,_,_) :- |
| 4297 | | both_global_sets(Set1,Set2,G1,G2),!, % may now succeed compared to same check above, as Set1/Set2 now instantiated |
| 4298 | | check_subset_of_global_sets(G1,G2). |
| 4299 | | check_subset_of0_lwf(Set1,Set2,WF,_LWF,_GS2) :- % Note: two intervals are treated in check_subset_of_global_sets |
| 4300 | | nonvar(Set1), % otherwise we have already checked this code above |
| 4301 | | subset_of_explicit_set(Set1,Set2,Code,WF),!, |
| 4302 | | call(Code). |
| 4303 | | check_subset_of0_lwf(Set1,Set2,WF,LWF,_GS2) :- |
| 4304 | | (nonvar(Set1) ; nonvar(Set2),dont_expand_this_explicit_set(Set2)), |
| 4305 | | !, |
| 4306 | | expand_custom_set_to_list_wf(Set1,ESet1,_,check_subset_of1,WF), |
| 4307 | | try_expand_and_convert_to_avl_unless_large_wf(Set2,ESet2,WF), |
| 4308 | | % b_interpreter_components:observe_instantiation(ESet1,'ESet1',ESet1), |
| 4309 | ? | check_subset_of2(ESet1,[],ESet2,WF,LWF,none). |
| 4310 | | check_subset_of0_lwf(Set1,Set2,WF,_LWF,_GS2) :- |
| 4311 | | expand_custom_set_to_list_wf(Set2,ESet2,_,check_subset_of0_lwf,WF), % Set2 is ground |
| 4312 | | % THIS WILL ENUMERATE, for something like dom(f) <: SET this is problematic, as information cannot be used |
| 4313 | | % hence we use wfx_no_enumeration above |
| 4314 | | %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 ? |
| 4315 | ? | gen_subsets(Set1,ESet2,WF). |
| 4316 | | |
| 4317 | | :- block check_subset_of2(-,?,?,?,-, ?). |
| 4318 | | check_subset_of2([],_SoFar,_Set2,_WF,_LWF,_Last). |
| 4319 | | check_subset_of2(HT,SoFar,Set2,WF,LWF,Last) :- |
| 4320 | | (var(HT),Set2 = avl_set(AVL) |
| 4321 | | -> % the value is chosen by the enumerator |
| 4322 | ? | custom_explicit_sets:safe_avl_member(H,AVL), |
| 4323 | | % this forces H to be ground; if Last /= none then it will be ground |
| 4324 | | (Last==none -> true ; Last @< H), |
| 4325 | | % TO DO: we could write a safe_avl_member_greater_than(H,Last,AVL) |
| 4326 | | not_element_of_wf(H,SoFar,WF), |
| 4327 | | NewLast=H, |
| 4328 | | HT = [H|T] |
| 4329 | | ; % the value may have been chosen by somebody else or will not be enumerated in order below |
| 4330 | | HT = [H|T], |
| 4331 | | not_element_of_wf(H,SoFar,WF), |
| 4332 | ? | check_element_of_wf_lwf(H,Set2,WF,LWF), |
| 4333 | | %check_element_of_wf(H,Set2,WF), |
| 4334 | | |
| 4335 | | NewLast = Last |
| 4336 | | ), |
| 4337 | ? | check_subset_of3(H,T,SoFar,Set2,WF,LWF,NewLast). |
| 4338 | | |
| 4339 | | % TO DO: write specific subsets code for avl_set(Set2) + try expand when becomes ground; merge with enumerate_tight_set ,... |
| 4340 | | % TO DO: ensure that it also works with global_set(T) instead of avl_set(_) or with interval closures |
| 4341 | | |
| 4342 | | |
| 4343 | | :- block check_subset_of3(?,-,-,?,?,-,?), check_subset_of3(?,-,?,-,?,-,?), check_subset_of3(?,-,-,-,?,?,?). |
| 4344 | | check_subset_of3(_,T,_,_Set2,_WF,_LWF,_) :- T==[],!. |
| 4345 | | check_subset_of3(H,T,SoFar,Set2,WF,LWF,Last) :- var(T),!, |
| 4346 | | % Sofar, Set2 and LWF must be set |
| 4347 | ? | when((nonvar(T);(ground(Set2),ground(H),ground(SoFar))), |
| 4348 | | (T==[] -> true |
| 4349 | | ; add_new_element_wf(H,SoFar,SoFar2,WF), %SoFar2 = [H|SoFar], |
| 4350 | | check_subset_of2(T,SoFar2,Set2,WF,LWF,Last))). |
| 4351 | | check_subset_of3(H,T,SoFar,Set2,WF,LWF,Last) :- |
| 4352 | | % T must be set and not equal to [] |
| 4353 | | T = [H2|T2], |
| 4354 | | add_new_element_wf(H,SoFar,SoFar2,WF), %SoFar2 = [H|SoFar], |
| 4355 | | %check_subset_of2(T,SoFar2,Set2,WF,LWF))), |
| 4356 | ? | check_element_of_wf(H2,Set2,WF), |
| 4357 | | not_element_of_wf(H2,SoFar2,WF), |
| 4358 | | check_subset_of3(H2,T2,SoFar2,Set2,WF,LWF,Last). |
| 4359 | | |
| 4360 | | |
| 4361 | | :- block gen_subsets(?,-,?). |
| 4362 | | gen_subsets([],_,_). |
| 4363 | | gen_subsets(SubSet,Set,WF) :- |
| 4364 | ? | ordered_delete(DH,Set,NewSet), |
| 4365 | | equal_object_wf([DH|T],SubSet,gen_subsets,WF), |
| 4366 | ? | gen_subsets(T,NewSet,WF). |
| 4367 | | |
| 4368 | | % note: this is not select/3 |
| 4369 | | ordered_delete(H,[H|T],T). |
| 4370 | ? | ordered_delete(H,[_|T],R) :- ordered_delete(H,T,R). |
| 4371 | | |
| 4372 | | |
| 4373 | | :- 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)). |
| 4374 | | :- assert_must_succeed(exhaustive_kernel_check_wf(check_finite_non_empty_subset_of_wf([int(1),int(5)], [int(5),int(1)],WF),WF)). |
| 4375 | | check_finite_non_empty_subset_of_wf(Set1,Set2,WF) :- |
| 4376 | ? | check_non_empty_subset_of_wf(Set1,Set2,WF), |
| 4377 | | is_finite_set_wf(Set1,WF). |
| 4378 | | |
| 4379 | | :- 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)). |
| 4380 | | :- assert_must_succeed(exhaustive_kernel_fail_check_wfdet(check_non_empty_subset_of_wf([int(2)], [int(5),int(1)],WF),WF)). |
| 4381 | | :- assert_must_succeed(exhaustive_kernel_fail_check_wfdet(check_non_empty_subset_of_wf([], [int(1)],WF),WF)). |
| 4382 | | |
| 4383 | | check_non_empty_subset_of_wf(S1,S2,WF) :- not_empty_set_wf(S1,WF), |
| 4384 | ? | check_subset_of_wf(S1,S2,WF). |
| 4385 | | |
| 4386 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_subset_of([int(1),int(2),int(5)], [int(2),int(4),int(1),int(3)]))). |
| 4387 | | :- assert_must_succeed(exhaustive_kernel_fail_check(not_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1),int(3)]))). |
| 4388 | | :- assert_must_succeed((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name')], X=global_set('Name'))). |
| 4389 | | :- assert_must_succeed((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name')], X=[fd(2,'Name')])). |
| 4390 | | :- assert_must_succeed((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name')], X=[fd(1,'Name'),fd(2,'Name')])). |
| 4391 | | :- assert_must_fail((kernel_objects:not_subset_of(Y,X), Y = [fd(1,'Name'),fd(3,'Name')], X=global_set('Name'))). |
| 4392 | | :- assert_must_fail((kernel_objects:not_subset_of(Y,X), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))). |
| 4393 | | :- assert_must_fail((kernel_objects:not_subset_of(X,Y), Y = [fd(1,'Name'),fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))). |
| 4394 | | :- assert_must_fail((kernel_objects:not_subset_of(global_set('NAT'),global_set('NAT')))). |
| 4395 | | :- assert_must_succeed((kernel_objects:not_subset_of(global_set('NAT'),global_set('NAT1')))). |
| 4396 | | |
| 4397 | | |
| 4398 | | not_subset_of(Set1,Set2) :- init_wait_flags(WF), |
| 4399 | | not_subset_of_wf(Set1,Set2,WF), |
| 4400 | | ground_wait_flags(WF). |
| 4401 | | |
| 4402 | | :- 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))). |
| 4403 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf(global_set('NATURAL'), global_set('INTEGER'),_WF))). |
| 4404 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf(global_set('INTEGER'), global_set('INTEGER'),_WF))). |
| 4405 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_finite_subset_of_wf([int(1)], [],_WF))). |
| 4406 | | |
| 4407 | | :- block not_finite_subset_of_wf(-,?,?). |
| 4408 | | not_finite_subset_of_wf(Set1,Set2,WF) :- test_finite_set_wf(Set1,Finite,WF), |
| 4409 | | not_finite_subset_of_wf_aux(Finite,Set1,Set2,WF). |
| 4410 | | :- block not_finite_subset_of_wf_aux(-,?,?,?). |
| 4411 | | not_finite_subset_of_wf_aux(pred_false,_Set1,_Set2,_WF). |
| 4412 | | not_finite_subset_of_wf_aux(pred_true,Set1,Set2,WF) :- not_subset_of_wf(Set1,Set2,WF). |
| 4413 | | |
| 4414 | | :- block not_subset_of_wf(-,?,?). |
| 4415 | | not_subset_of_wf([],_,_WF) :- !, fail. |
| 4416 | | not_subset_of_wf(Set1,Set2,WF) :- Set2==[],!, not_empty_set_wf(Set1,WF). |
| 4417 | | not_subset_of_wf(Set1,Set2,WF) :- |
| 4418 | | (both_global_sets(Set1,Set2,G1,G2) % also catches intervals |
| 4419 | | -> check_not_subset_of_global_sets(G1,G2) |
| 4420 | | ; not_subset_of_wf1(Set1,Set2,WF) |
| 4421 | | ). |
| 4422 | | not_subset_of_wf1(_Set1,Set2,_WF) :- |
| 4423 | | nonvar(Set2), is_definitely_maximal_set(Set2),!,fail. |
| 4424 | | not_subset_of_wf1(Set1,Set2,_WF) :- quick_same_value(Set1,Set2), |
| 4425 | | !, fail. |
| 4426 | | not_subset_of_wf1(Set1,Set2,WF) :- custom_explicit_sets:singleton_set(Set1,El),!, |
| 4427 | | not_element_of_wf(El,Set2,WF). |
| 4428 | ? | not_subset_of_wf1(Set1,Set2,WF) :- not_subset_of_explicit_set(Set1,Set2,Code,WF),!, |
| 4429 | | call(Code). |
| 4430 | | not_subset_of_wf1(Set1,Set2,WF) :- |
| 4431 | | expand_custom_set_to_list_wf(Set1,ESet1,_,not_subset_of_wf1,WF), |
| 4432 | | not_subset_of2(ESet1,Set2,WF). |
| 4433 | | |
| 4434 | | |
| 4435 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(0,2),interval(1,3))). |
| 4436 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(1,2),interval(0,-1))). |
| 4437 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(1,2),interval(4,3))). |
| 4438 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(1,3))). |
| 4439 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(1,9000),interval(2,9999))). |
| 4440 | | :- assert_must_succeed((kernel_objects:check_not_subset_of_global_sets(interval(X2,X4),interval(1,3)), |
| 4441 | | X2=2, X4=4)). |
| 4442 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(1,4))). |
| 4443 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(2,4))). |
| 4444 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(2,4),interval(0,10))). |
| 4445 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(0,2),interval(1,inf))). |
| 4446 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(-1,2),interval(0,inf))). |
| 4447 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,2),interval(1,inf))). |
| 4448 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(0,2),interval(0,inf))). |
| 4449 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(-1,2),interval(minus_inf,inf))). |
| 4450 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(0,inf),interval(1,inf))). |
| 4451 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(minus_inf,inf),interval(1,inf))). |
| 4452 | | :- assert_must_succeed(kernel_objects:check_not_subset_of_global_sets(interval(minus_inf,inf),interval(0,inf))). |
| 4453 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,inf),interval(minus_inf,inf))). |
| 4454 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,inf),interval(1,inf))). |
| 4455 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(1,inf),interval(0,inf))). |
| 4456 | | :- assert_must_fail(kernel_objects:check_not_subset_of_global_sets(interval(0,inf),interval(0,inf))). |
| 4457 | | |
| 4458 | | :- block check_not_subset_of_global_sets(-,?), check_not_subset_of_global_sets(?,-). |
| 4459 | | check_not_subset_of_global_sets(interval(Low1,Up1),G2) :- !, |
| 4460 | | safe_less_than_equal_with_inf_clpfd(Low1,Up1), % Set 1 is not empty; otherwise it will always be a subset |
| 4461 | | not_subset_interval_gs_aux(G2,Low1,Up1). |
| 4462 | | check_not_subset_of_global_sets(G1,G2) :- |
| 4463 | | \+ check_subset_of_global_sets(G1,G2). |
| 4464 | | |
| 4465 | | not_subset_interval_gs_aux(interval(Low2,Up2),Low1,Up1) :- |
| 4466 | | finite_interval(Low1,Up1), finite_interval(Low2,Up2), |
| 4467 | | !, |
| 4468 | | % post_constraint2((Low1 #<Low2 #\/ Up1 #> Up2 #\/ Up2 #< Low1),Posted), %% X #<100 #\/ X#<0. does not constraint X ! but X #<max(100,0) does |
| 4469 | | post_constraint2((Low1 #<Low2 #\/ Up2 #< max(Up1,Low1)),Posted), |
| 4470 | | (Posted==true -> true ; not_interval_subset(Low1,Up1,Low2,Up2)). |
| 4471 | | not_subset_interval_gs_aux(interval(Low2,Up2),Low1,Up1) :- !, not_interval_subset(Low1,Up1,Low2,Up2). |
| 4472 | | not_subset_interval_gs_aux(GS2,Low1,Up1) :- |
| 4473 | | when((nonvar(Low1),nonvar(Up1)), \+ check_subset_of_global_sets(interval(Low1,Up1),GS2)). |
| 4474 | | |
| 4475 | | not_interval_subset(Val1,Up1,Low2,Up2) :- var(Val1), Val1==Up1, |
| 4476 | | !, % better propagation for singleton set |
| 4477 | | (Up2==inf -> Low2\==minus_inf, less_than_direct(Val1,Low2) |
| 4478 | | ; Low2=minus_inf -> less_than_direct(Up2,Val1) |
| 4479 | | ; not_in_nat_range(int(Val1),int(Low2),int(Up2))). |
| 4480 | | not_interval_subset(Low1,_,Low2,Up2) :- Up2==inf, finite_val(Low2), finite_val(Low1), |
| 4481 | | % typical case x..y /<: NATURAL <==> x < 0 |
| 4482 | | !, |
| 4483 | | less_than_direct(Low1,Low2). |
| 4484 | | not_interval_subset(_,Up1,Low2,Up2) :- Low2==minus_inf, finite_val(Up2), finite_val(Up1), |
| 4485 | | % covers x..y /<: {x|x<=0} <==> y > 0 |
| 4486 | | !, |
| 4487 | | less_than_direct(Up2,Up1). |
| 4488 | | not_interval_subset(Low1,Up1,Low2,Up2) :- not_interval_subset_block(Low1,Up1,Low2,Up2). |
| 4489 | | :- block not_interval_subset_block(-,?,?,?), not_interval_subset_block(?,-,?,?), |
| 4490 | | not_interval_subset_block(?,?,-,?), not_interval_subset_block(?,?,?,-). |
| 4491 | | not_interval_subset_block(Low1,Up1,Low2,Up2) :- % this could be decided earlier, e.g. 1..n /<: 1..inf is false |
| 4492 | | \+ interval_subset(Low1,Up1,Low2,Up2). |
| 4493 | | |
| 4494 | | |
| 4495 | | :- block not_subset_of2(-,?,?). |
| 4496 | | not_subset_of2([H|T],Set2,WF) :- |
| 4497 | | (T==[] |
| 4498 | | -> not_element_of_wf(H,Set2,WF) |
| 4499 | | ; membership_test_wf(Set2,H,MemRes,WF), |
| 4500 | | propagate_empty_set_to_pred_false(T,MemRes), % if T becomes empty, we know that H must not be in Set2 |
| 4501 | | not_subset_of3(MemRes,T,Set2,WF) |
| 4502 | | ). |
| 4503 | | |
| 4504 | | :- block not_subset_of3(-,?,?,?). |
| 4505 | | not_subset_of3(pred_false,_T,_Set2,_WF). |
| 4506 | | not_subset_of3(pred_true,T,Set2,WF) :- not_subset_of2(T,Set2,WF). |
| 4507 | | |
| 4508 | | :- block propagate_empty_set_to_pred_false(-,-). |
| 4509 | | propagate_empty_set_to_pred_false(X,PredRes) :- X==[],!,PredRes=pred_false. |
| 4510 | | propagate_empty_set_to_pred_false(_,_). |
| 4511 | | |
| 4512 | | :- assert_must_succeed(exhaustive_kernel_check_wf(not_both_subset_of([int(1),int(2),int(5)], [] |
| 4513 | | ,[int(2),int(4),int(1),int(3)],[],WF),WF)). |
| 4514 | | :- assert_must_succeed(exhaustive_kernel_check_wf(not_both_subset_of([int(1),int(2),int(5)], [int(3)], |
| 4515 | | [int(2),int(5),int(1),int(3)],[int(1),int(4)],WF),WF)). |
| 4516 | | |
| 4517 | | not_both_subset_of(Set1A,Set1B, Set2A,Set2B, WF) :- |
| 4518 | | kernel_equality:subset_test(Set1A,Set2A,Result,WF), % not yet implemented ! % TODO ! -> sub_set,equal,super_set |
| 4519 | | not_both_subset_of_aux(Result,Set1B,Set2B,WF). |
| 4520 | | |
| 4521 | | :- block not_both_subset_of_aux(-,?,?,?). |
| 4522 | | not_both_subset_of_aux(pred_false,_Set1B,_Set2B,_WF). |
| 4523 | | not_both_subset_of_aux(pred_true,Set1B,Set2B,WF) :- |
| 4524 | | not_subset_of_wf(Set1B,Set2B,WF). |
| 4525 | | |
| 4526 | | /***********************************/ |
| 4527 | | /* not_strict_subset_of(Set1,Set2) */ |
| 4528 | | /* Set1 /<<: Set2 */ |
| 4529 | | /**********************************/ |
| 4530 | | |
| 4531 | | |
| 4532 | | :- 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)]))). |
| 4533 | | :- assert_must_succeed(exhaustive_kernel_succeed_check(not_strict_subset_of([int(1),int(2),int(5)], [int(2),int(5),int(1)]))). |
| 4534 | | :- 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)]))). |
| 4535 | | :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [int(1)], X=[int(2),int(1)])). |
| 4536 | | :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [], X=[int(2),int(1)])). |
| 4537 | | :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [[int(1),int(2)]], X=[[int(2)],[int(2),int(1)]])). |
| 4538 | | :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [fd(1,'Name')], X=global_set('Name'))). |
| 4539 | | :- assert_must_fail((kernel_objects:not_strict_subset_of(Y,X), Y = [fd(3,'Name'),fd(2,'Name')], X=global_set('Name'))). |
| 4540 | | :- 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'))). |
| 4541 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [fd(1,'Name'),fd(3,'Name')], X=global_set('Name'))). |
| 4542 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(1)], X=[int(2),int(1)])). |
| 4543 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(1),int(2)], X=[int(2),int(1)])). |
| 4544 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(2)], X=[int(2)])). |
| 4545 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [int(2)], X=[int(1)])). |
| 4546 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of(X,Y), Y = [], X=[int(1)])). |
| 4547 | | |
| 4548 | | not_strict_subset_of(Set1,Set2) :- |
| 4549 | | (preference(use_chr_solver,true) -> chr_not_subset_strict(Set1,Set2) ; true), |
| 4550 | | init_wait_flags(WF,[not_strict_subset_of]), |
| 4551 | | not_strict_subset_of_wf(Set1,Set2,WF), |
| 4552 | | ground_wait_flags(WF). |
| 4553 | | |
| 4554 | | :- block not_strict_subset_of_wf(-,?,?),not_strict_subset_of_wf(?,-,?). |
| 4555 | | not_strict_subset_of_wf(Set1,Set2,WF) :- |
| 4556 | | (both_global_sets(Set1,Set2,G1,G2) |
| 4557 | | -> not_strict_subset_of_global_sets(G1,G2) |
| 4558 | | ; not_strict_subset_of_wf1(Set1,Set2,WF) |
| 4559 | | ). |
| 4560 | ? | not_strict_subset_of_wf1(Set1,Set2,WF) :- not_subset_of_explicit_set(Set1,Set2,Code,WF),!, |
| 4561 | | equality_objects_wf(Set1,Set2,EqRes,WF), |
| 4562 | | not_strict_eq_check(EqRes,Code). |
| 4563 | | not_strict_subset_of_wf1(Set1,Set2,WF) :- |
| 4564 | | % OLD VERSION: not_subset_of(Set1,Set2) ; check_equal_object(Set1,Set2). |
| 4565 | | expand_custom_set_to_list_wf(Set1,ESet1,_,not_strict_subset_of_wf1,WF), |
| 4566 | | (nonvar(Set2),is_infinite_explicit_set(Set2) -> Inf=infinite ; Inf=unknown), |
| 4567 | | not_strict_subset_of2(ESet1,Set2,Inf,WF). |
| 4568 | | |
| 4569 | | :- block not_strict_eq_check(-,?). |
| 4570 | | not_strict_eq_check(pred_true,_). % if equal then not strict subset is true |
| 4571 | | not_strict_eq_check(pred_false,Code) :- call(Code). % check if not subset |
| 4572 | | |
| 4573 | | :- block not_strict_subset_of2(-,?,?,?). |
| 4574 | | not_strict_subset_of2([],R,_,WF) :- empty_set_wf(R,WF). |
| 4575 | | not_strict_subset_of2([H|T],Set2,Inf,WF) :- |
| 4576 | | membership_test_wf(Set2,H,MemRes,WF), |
| 4577 | | not_strict_subset_of3(MemRes,H,T,Set2,Inf,WF). |
| 4578 | | |
| 4579 | | :- block not_strict_subset_of3(-,?,?,?,?,?). |
| 4580 | | not_strict_subset_of3(pred_false,_H,_T,_Set2,_,_WF). |
| 4581 | | not_strict_subset_of3(pred_true,H,T,Set2,Inf,WF) :- |
| 4582 | | (Inf=infinite |
| 4583 | | -> RS2=Set2 % Set1 is finite; we just have to check that all elements are in Set2 and we have a strict subset |
| 4584 | | ; remove_element_wf(H,Set2,RS2,WF)), |
| 4585 | | not_strict_subset_of2(T,RS2,Inf,WF). |
| 4586 | | |
| 4587 | | |
| 4588 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,2),interval(1,3))). |
| 4589 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,2),interval(0,-1))). |
| 4590 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,2),interval(4,3))). |
| 4591 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(1,3))). |
| 4592 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,9000),interval(2,9999))). |
| 4593 | | :- assert_must_succeed((kernel_objects:not_strict_subset_of_global_sets(interval(X2,X4),interval(1,3)), |
| 4594 | | X2=2, X4=4)). |
| 4595 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(1,4))). |
| 4596 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(2,4))). |
| 4597 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(2,4),interval(0,10))). |
| 4598 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,2),interval(1,inf))). |
| 4599 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(-1,2),interval(0,inf))). |
| 4600 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(1,2),interval(1,inf))). |
| 4601 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(0,2),interval(0,inf))). |
| 4602 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(-1,2),interval(minus_inf,inf))). |
| 4603 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,inf),interval(1,inf))). |
| 4604 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(minus_inf,inf),interval(1,inf))). |
| 4605 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(minus_inf,inf),interval(0,inf))). |
| 4606 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(1,inf),interval(minus_inf,inf))). |
| 4607 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(1,inf),interval(1,inf))). |
| 4608 | | :- assert_must_fail(kernel_objects:not_strict_subset_of_global_sets(interval(1,inf),interval(0,inf))). |
| 4609 | | :- assert_must_succeed(kernel_objects:not_strict_subset_of_global_sets(interval(0,inf),interval(0,inf))). |
| 4610 | | |
| 4611 | | :- block not_strict_subset_of_global_sets(-,?), not_strict_subset_of_global_sets(?,-). |
| 4612 | | not_strict_subset_of_global_sets(interval(Low1,Up1),interval(Low2,Up2)) :- !, |
| 4613 | | % Note: if Low2>Up2 then nothing is a strict subset of the empty set, i.e., everything is not a strict subset |
| 4614 | | (finite_interval(Low1,Up1), finite_interval(Low2,Up2) |
| 4615 | | -> clpfd_interface:post_constraint2(((Low2 #=< Up2) #=> (Low1 #=< Up1 #/\ ((Low2 #> Low1) #\/ (Up1 #> Up2) #\/ ((Low1 #= Low2 #/\ Up1 #= Up2))))),Posted) |
| 4616 | | ; Posted=false), |
| 4617 | | (Posted==true -> true ; not_strict_subset_intervals(Low1,Up1,Low2,Up2)). |
| 4618 | | not_strict_subset_of_global_sets(G1,G2) :- |
| 4619 | | when((ground(G1),ground(G2)), \+check_strict_subset_of_global_sets(G1,G2)). |
| 4620 | | |
| 4621 | | :- block not_strict_subset_intervals(?,?,-,?), not_strict_subset_intervals(?,?,?,-). |
| 4622 | | % Instead of blocking on Low2,Up2 we could post bigger constraint (Low2 <= Up2 => (Low1 <= Up1 /\ .... |
| 4623 | | not_strict_subset_intervals(_Low1,_Up1,Low2,Up2) :- safe_less_than_with_inf(Up2,Low2),!. |
| 4624 | | not_strict_subset_intervals(Low1,Up1,Low2,Up2) :- |
| 4625 | | safe_less_than_equal_with_inf_clpfd(Low1,Up1), % if Low1..Up1 is empty then it would be a strict subset |
| 4626 | | not_check_strict_subset_intervals2(Low1,Up1,Low2,Up2). |
| 4627 | | :- block not_check_strict_subset_intervals2(-,?,?,?),not_check_strict_subset_intervals2(?,-,?,?), |
| 4628 | | not_check_strict_subset_intervals2(?,?,-,?). |
| 4629 | ? | not_check_strict_subset_intervals2(Low1,Up1,Low2,Up2) :- \+ check_strict_subset_intervals2(Low1,Up1,Low2,Up2). |
| 4630 | | |
| 4631 | | |
| 4632 | | /* Set1 /: FIN1(Set2) */ |
| 4633 | | :- assert_must_succeed((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(2)])). |
| 4634 | | :- assert_must_succeed((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X=[int(1)], Y=[int(1),int(2)])). |
| 4635 | | :- assert_must_succeed((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[])). |
| 4636 | | :- assert_must_fail((kernel_objects:not_non_empty_finite_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(1)])). |
| 4637 | | |
| 4638 | | :- block not_non_empty_finite_subset_of_wf(-,?,?). |
| 4639 | | not_non_empty_finite_subset_of_wf(Set1,Set2,WF) :- test_finite_set_wf(Set1,Finite,WF), |
| 4640 | | not_non_empty_finite_subset_of_aux(Finite,Set1,Set2,WF). |
| 4641 | | :- block not_non_empty_finite_subset_of_aux(-,?,?,?). |
| 4642 | | not_non_empty_finite_subset_of_aux(pred_false,_Set1,_Set2,_WF). |
| 4643 | | not_non_empty_finite_subset_of_aux(pred_true,Set1,Set2,WF) :- not_non_empty_subset_of_wf(Set1,Set2,WF). |
| 4644 | | |
| 4645 | | /* Set1 /: POW1(Set2) */ |
| 4646 | | :- assert_must_succeed(exhaustive_kernel_check_wf(not_non_empty_subset_of_wf([int(1)], [int(2),int(3)],WF),WF)). |
| 4647 | | :- assert_must_succeed(exhaustive_kernel_fail_check_wf(not_non_empty_subset_of_wf([int(2)], [int(2),int(3)],WF),WF)). |
| 4648 | | :- assert_must_succeed((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(2)])). |
| 4649 | | :- assert_must_succeed((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X=[int(1)], Y=[int(1),int(2)])). |
| 4650 | | :- assert_must_succeed((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[])). |
| 4651 | | :- assert_must_fail((kernel_objects:not_non_empty_subset_of_wf(Y,X,_WF), X = [int(1)], Y=[int(1)])). |
| 4652 | | |
| 4653 | | % Set1 /: POW1(Set2) |
| 4654 | | :- block not_non_empty_subset_of_wf(-,?,?). |
| 4655 | | not_non_empty_subset_of_wf(Set1,_,_WF) :- Set1==[],!. |
| 4656 | | not_non_empty_subset_of_wf(Set1,Set2,WF) :- % Maybe introduce binary choice point ? |
| 4657 | | empty_set_wf(Set1,WF) ; |
| 4658 | | not_subset_of_wf(Set1,Set2,WF). |
| 4659 | | |
| 4660 | | |
| 4661 | | /* min, max */ |
| 4662 | | |
| 4663 | | :- assert_must_succeed(exhaustive_kernel_check(minimum_of_set([int(1)],int(1),unknown,_WF))). |
| 4664 | | :- assert_must_succeed(exhaustive_kernel_check(minimum_of_set([int(2),int(3),int(1)],int(1),unknown,_WF))). |
| 4665 | | :- assert_must_succeed(exhaustive_kernel_fail_check(minimum_of_set([int(2),int(3),int(1)],int(2),unknown,_WF))). |
| 4666 | | :- assert_must_succeed((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(1)])). |
| 4667 | | :- assert_must_succeed((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(2),int(1)])). |
| 4668 | | :- assert_must_succeed((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(1),int(2),int(1),int(3)])). |
| 4669 | | :- assert_must_fail((kernel_objects:minimum_of_set(Y,X,unknown,_WF), X = int(2), Y=[int(1),int(2),int(1),int(3)])). |
| 4670 | | :- assert_must_abort_wf(kernel_objects:minimum_of_set([],_R,unknown,WF),WF). |
| 4671 | | %:- must_succeed(kernel_waitflags:assert_must_abort2_wf(kernel_objects:minimum_of_set([],_R,WF),WF)). |
| 4672 | | |
| 4673 | | :- block minimum_of_set_extension_list(-,?,?,?). |
| 4674 | | minimum_of_set_extension_list(ListOfValues,int(Min),Span,WF) :- |
| 4675 | | minimum_of_set2(ListOfValues,Min,Span,WF). |
| 4676 | | |
| 4677 | | :- block minimum_of_set(-,?,?,?). |
| 4678 | | minimum_of_set(Set1,Res,_Span,WF) :- is_custom_explicit_set(Set1,minimum_of_set), |
| 4679 | | min_of_explicit_set_wf(Set1,Min,WF), !, |
| 4680 | | equal_object_wf(Min,Res,minimum_of_set,WF). |
| 4681 | | minimum_of_set(Set1,int(Min),Span,WF) :- |
| 4682 | | expand_custom_set_to_list_wf(Set1,ESet1,_,minimum_of_set,WF), |
| 4683 | | (var(ESet1),Set1=closure(_,_,_) |
| 4684 | | -> quick_propagation_element_information(Set1,int(Min),WF,_) ; true), |
| 4685 | | minimum_of_set2(ESet1,Min,Span,WF). |
| 4686 | | :- block minimum_of_set2(-,?,?,?). |
| 4687 | | minimum_of_set2([],Res,Span,WF) :- |
| 4688 | | add_wd_error_set_result('min applied to empty set','',Res,int(0),Span,WF). |
| 4689 | | minimum_of_set2([int(N)|T],Min,_,_) :- clpfd_geq2(N,Min,_),minimum_of_set3(T,N,Min,[N]). |
| 4690 | | |
| 4691 | | :- block minimum_of_set3(-,?,?,?). % with CLPFD: makes sense to also unfold if Min Variable; hence no longer block on : minimum_of_set3(?,-,-). |
| 4692 | | minimum_of_set3([],MinSoFar,MinSoFar,ListOfValues) :- |
| 4693 | | (var(MinSoFar) -> clpfd_minimum(MinSoFar,ListOfValues) ; true). |
| 4694 | | minimum_of_set3([int(M)|T],MinSoFar,Min,ListOfValues) :- clpfd_geq2(M,Min,_), |
| 4695 | | minimum(M,MinSoFar,NewMinSoFar), |
| 4696 | | minimum_of_set3(T,NewMinSoFar,Min,[M|ListOfValues]). |
| 4697 | | |
| 4698 | | |
| 4699 | | :- block minimum(-,?,?), minimum(?,-,?). |
| 4700 | | minimum(M1,M2,Min) :- M1<M2 -> Min=M1 ; Min=M2. |
| 4701 | | |
| 4702 | | :- assert_must_succeed(exhaustive_kernel_check(maximum_of_set([int(1)],int(1),unknown,_WF))). |
| 4703 | | :- assert_must_succeed(exhaustive_kernel_check(maximum_of_set([int(2),int(3),int(1)],int(3),unknown,_WF))). |
| 4704 | | :- assert_must_succeed(exhaustive_kernel_fail_check(maximum_of_set([int(2),int(3),int(1)],int(2),unknown,_WF))). |
| 4705 | | :- assert_must_succeed((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(1), Y=[int(1)])). |
| 4706 | | :- assert_must_succeed((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(2), Y=[int(2),int(1)])). |
| 4707 | | :- assert_must_succeed((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(3), Y=[int(1),int(2),int(1),int(3)])). |
| 4708 | | :- assert_must_fail((kernel_objects:maximum_of_set(Y,X,unknown,_WF), X = int(2), Y=[int(1),int(2),int(1),int(3)])). |
| 4709 | | :- assert_must_fail((preferences:preference(use_clpfd_solver,true), |
| 4710 | | kernel_objects:maximum_of_set([int(X),int(_Y)],int(3),unknown,_WF), X = 4)). % in CLPFD modus |
| 4711 | | :- assert_must_fail((preferences:preference(use_clpfd_solver,true), |
| 4712 | | kernel_objects:maximum_of_set([int(_),int(X)],int(3),unknown,_WF), X = 4)).% in CLPFD modus |
| 4713 | | :- assert_must_abort_wf(kernel_objects:maximum_of_set([],_R,unknown,WF),WF). |
| 4714 | | |
| 4715 | | :- block maximum_of_set_extension_list(-,?,?,?). |
| 4716 | | maximum_of_set_extension_list(ListOfValues,int(Max),Span,WF) :- |
| 4717 | | maximum_of_set2(ListOfValues,Max,Span,WF). |
| 4718 | | |
| 4719 | | :- block maximum_of_set(-,?,?,?). |
| 4720 | | maximum_of_set(Set1,Res,_Span,WF) :- |
| 4721 | | is_custom_explicit_set(Set1,maximum_of_set), |
| 4722 | | max_of_explicit_set_wf(Set1,Max,WF), !, |
| 4723 | | equal_object_wf(Max,Res,maximum_of_set,WF). |
| 4724 | | maximum_of_set(Set1,int(Max),Span,WF) :- |
| 4725 | | expand_custom_set_to_list_wf(Set1,ESet1,_,maximum_of_set,WF), |
| 4726 | | (var(ESet1),Set1=closure(_,_,_) |
| 4727 | | -> quick_propagation_element_information(Set1,int(Max),WF,_) ; true), |
| 4728 | | maximum_of_set2(ESet1,Max,Span,WF). |
| 4729 | | :- block maximum_of_set2(-,?,?,?). |
| 4730 | | maximum_of_set2([],Res,Span,WF) :- |
| 4731 | | 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))). |
| 4732 | | maximum_of_set2([int(N)|T],Max,_Span,_) :- clpfd_geq2(Max,N,_), |
| 4733 | | maximum_of_set3(T,N,Max,[N]). |
| 4734 | | |
| 4735 | | :- block maximum_of_set3(-,?,?,?). % with CLPFD: makes sense to also unfold if Max Variable; hence no longer block on : maximum_of_set3(?,-,-). |
| 4736 | | maximum_of_set3([],MaxSoFar,MaxSoFar,ListOfValues) :- |
| 4737 | | (var(MaxSoFar) -> clpfd_maximum(MaxSoFar,ListOfValues) ; true). |
| 4738 | | maximum_of_set3([int(M)|T],MaxSoFar,Max,ListOfValues) :- clpfd_geq2(Max,M,_), |
| 4739 | | maximum(M,MaxSoFar,NewMaxSoFar), |
| 4740 | | maximum_of_set3(T,NewMaxSoFar,Max,[M|ListOfValues]). |
| 4741 | | |
| 4742 | | :- block maximum(-,?,?), maximum(?,-,?). |
| 4743 | | maximum(M1,M2,Max) :- M1>M2 -> Max=M1 ; Max=M2. |
| 4744 | | |
| 4745 | | % card(ran(Function)); useful e.g. for q : 1 .. 16 --> 1 .. 16 & card(ran(q))=16 |
| 4746 | | :- block cardinality_of_range(-,?,?). |
| 4747 | | cardinality_of_range(CS,Card,WF) :- |
| 4748 | | is_custom_explicit_set(CS,cardinality_of_range), |
| 4749 | | range_of_explicit_set_wf(CS,Res,WF),!, |
| 4750 | | cardinality_as_int_wf(Res,Card,WF). |
| 4751 | | cardinality_of_range(Function,Card,WF) :- |
| 4752 | | expand_custom_set_to_list_wf(Function,EF1,Done,cardinality_of_range,WF), |
| 4753 | | project_on_range(EF1,ERange), |
| 4754 | | % when Done is set: we have a complete list and can compute MaxCard; TODO: maybe provide a version that can trigger earlier |
| 4755 | | when(nonvar(Done),cardinality_of_set_extension_list(ERange,Card,WF)). |
| 4756 | | |
| 4757 | | :- block project_on_range(-,?). |
| 4758 | | project_on_range([],[]). |
| 4759 | | project_on_range([(_,Ran)|T],[Ran|TR]) :- project_on_range(T,TR). |
| 4760 | | |
| 4761 | | |
| 4762 | | :- assert_must_succeed((cardinality_of_set_extension_list([fd(1,'Name')],R,_WF), R = int(1))). |
| 4763 | | :- assert_must_succeed((cardinality_of_set_extension_list([int(X),int(Y)],int(1),_WF), X=22, Y==22)). |
| 4764 | | |
| 4765 | | cardinality_of_set_extension_list(List,int(Card),WF) :- |
| 4766 | | length(List,MaxCard), less_than_equal_direct(Card,MaxCard), |
| 4767 | | cardinality_of_set_extension_list2(List,[],0,MaxCard,Card,WF). |
| 4768 | | |
| 4769 | | :- block cardinality_of_set_extension_list2(-,?,?,?,?,?). |
| 4770 | | cardinality_of_set_extension_list2([],_,AccSz,_MaxCard,Res,_WF) :- Res=AccSz. |
| 4771 | | cardinality_of_set_extension_list2([H|T],Acc,AccSz,MaxCard,Res,WF) :- |
| 4772 | | membership_test_wf(Acc,H,MemRes,WF), |
| 4773 | | (MaxCard==Res -> /* only solution is for H to be not in Acc */ MemRes=pred_false |
| 4774 | | ; AccSz==Res -> /* only solution is for H to be in Acc */ MemRes=pred_true |
| 4775 | | ; (var(Res),var(MemRes)) -> kernel_equality:equality_int(MaxCard,Res,EqMaxC),prop_if_pred_true(EqMaxC,MemRes,pred_false), |
| 4776 | | kernel_equality:equality_int(AccSz,Res,EqAccSz),prop_if_pred_true(EqAccSz,MemRes,pred_true) |
| 4777 | | ; true), |
| 4778 | | cardinality_of_set_extension_list3(MemRes,H,T,Acc,AccSz,MaxCard,Res,WF). |
| 4779 | | |
| 4780 | | :- block prop_if_pred_true(-,?,?). |
| 4781 | | prop_if_pred_true(pred_true,X,X). |
| 4782 | | prop_if_pred_true(pred_false,_,_). |
| 4783 | | |
| 4784 | | :- block cardinality_of_set_extension_list3(-,?,?,?,?,?,?,?). |
| 4785 | | cardinality_of_set_extension_list3(pred_true,_,T,Acc,AccSz,MaxCard,Res,WF) :- |
| 4786 | | % H is a member of Acc, do not increase Acc nor AccSz; however MaxCard now decreases |
| 4787 | | less_than_direct(Res,MaxCard), M1 is MaxCard-1, |
| 4788 | | cardinality_of_set_extension_list2(T,Acc,AccSz,M1,Res,WF). |
| 4789 | | cardinality_of_set_extension_list3(pred_false,H,T,Acc,AccSz,MaxCard,Res,WF) :- |
| 4790 | | A1 is AccSz+1, less_than_equal_direct(A1,Res), |
| 4791 | | cardinality_of_set_extension_list2(T,[H|Acc],A1,MaxCard,Res,WF). |
| 4792 | | |
| 4793 | | :- assert_must_succeed(exhaustive_kernel_check(is_finite_set_wf([fd(1,'Name'),fd(2,'Name')],_WF))). |
| 4794 | | :- assert_must_succeed((is_finite_set_wf(Y,_WF), Y = [])). |
| 4795 | | :- assert_must_succeed((is_finite_set_wf(Y,_WF), Y = [int(1),int(2)])). |
| 4796 | | :- use_module(typing_tools,[contains_infinite_type/1]). |
| 4797 | | :- use_module(custom_explicit_sets,[card_for_specific_custom_set/3]). |
| 4798 | | |
| 4799 | | is_finite_set_wf(Set,WF) :- test_finite_set_wf(Set,pred_true,WF). |
| 4800 | | |
| 4801 | | :- assert_must_succeed(exhaustive_kernel_fail_check(is_infinite_set_wf([fd(1,'Name'),fd(2,'Name')],_WF))). |
| 4802 | | :- assert_must_fail((is_infinite_set_wf(Y,_WF), Y = [int(1),int(2)])). |
| 4803 | | |
| 4804 | | is_infinite_set_wf(Set,WF) :- test_finite_set_wf(Set,pred_false,WF). |
| 4805 | | |
| 4806 | | %! test_finite_set_wf(+Set,?X,+WF) |
| 4807 | | :- block test_finite_set_wf(-,?,?). |
| 4808 | | %test_finite_set_wf(A,B,C) :- print(test_finite_set_wf(A,B,C)),nl,fail. |
| 4809 | | test_finite_set_wf([],X,_WF) :- !, X=pred_true. |
| 4810 | | test_finite_set_wf([_|T],X,WF) :- !, test_finite_set_wf(T,X,WF). % what if Tail contains closure ?? |
| 4811 | | test_finite_set_wf(avl_set(_),X,_WF) :- !, X=pred_true. |
| 4812 | | test_finite_set_wf(closure(_P,T,_B),X,_WF) :- \+ contains_infinite_type(T), !, X=pred_true. |
| 4813 | | test_finite_set_wf(closure(P,T,B),X,WF) :- !, test_finite_closure(P,T,B,X,WF). |
| 4814 | | test_finite_set_wf(Set,X,WF) :- /* also deals with global_set(_) */ |
| 4815 | | /* explicit_set_cardinality may trigger an enum warning */ |
| 4816 | | explicit_set_cardinality_wf(Set,Card,WF), |
| 4817 | | set_finite_result(Card,Set,explicit_set,X). |
| 4818 | | |
| 4819 | | :- use_module(bsyntaxtree,[is_a_disjunct/3]). |
| 4820 | | % we already check that contains_infinite_type above |
| 4821 | | test_finite_closure(P,T,B,X,WF) :- is_a_disjunct(B,D1,D2),!, |
| 4822 | | test_finite_closure(P,T,D1,X1,WF), |
| 4823 | | test_finite_disj2(X1,P,T,D2,X,WF). |
| 4824 | | % TO DO: add is_closure1_value_closure |
| 4825 | | test_finite_closure(P,T,B,X,WF) :- when(ground(B), test_finite_closure_ground(P,T,B,X,WF)). |
| 4826 | | |
| 4827 | | test_finite_disj2(pred_false,_P,_T,_D2,X,_WF) :- X=pred_false. |
| 4828 | | test_finite_disj2(pred_true,P,T,D2,X,WF) :- test_finite_closure(P,T,D2,X,WF). |
| 4829 | | |
| 4830 | | |
| 4831 | | % first: we need to check all constructors such as POW, FIN, ... which card_for_specific_custom_set supports |
| 4832 | | % 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) |
| 4833 | | test_finite_closure_ground(P,T,B,X,WF) :- |
| 4834 | | is_powerset_closure(closure(P,T,B),_Type,Subset), |
| 4835 | | % note: whether Type is fin, fin1, pow, or pow1 does not matter |
| 4836 | | !, |
| 4837 | | test_finite_set_wf(Subset,X,WF). |
| 4838 | | test_finite_closure_ground(P,T,B,X,WF) :- |
| 4839 | | custom_explicit_sets:is_lambda_value_domain_closure(P,T,B, Subset,_Expr), !, |
| 4840 | | test_finite_set_wf(Subset,X,WF). |
| 4841 | | test_finite_closure_ground(P,T,B,X,WF) :- |
| 4842 | | custom_explicit_sets:is_cartesian_product_closure(closure(P,T,B), A1,B2), !, |
| 4843 | | test_finite_set_wf(A1,AX,WF), |
| 4844 | | test_finite_set_wf(B2,BX,WF), |
| 4845 | | test_finite_cartesian_product_wf(AX,BX,A1,B2,X,WF). |
| 4846 | | test_finite_closure_ground(Par,Typ,Body, X,_WF) :- |
| 4847 | | custom_explicit_sets:is_geq_leq_interval_closure(Par,Typ,Body,Low,Up), !, |
| 4848 | | custom_explicit_sets:card_of_interval_inf(Low,Up,Card), |
| 4849 | | set_finite_result_no_warn(Card,X). |
| 4850 | | test_finite_closure_ground(P,T,B,X,WF) :- |
| 4851 | | closures:is_member_closure(P,T,B,_,SET), nonvar(SET), |
| 4852 | | unary_member_closure_for_finite(SET,Check,SET1), |
| 4853 | | !, |
| 4854 | | (Check==finite -> test_finite_set_wf(SET1,X,WF) |
| 4855 | | ; kernel_equality:empty_set_test_wf(SET1,X,WF)). |
| 4856 | | % TO DO: catch other special cases : relations, struct,... |
| 4857 | | test_finite_closure_ground(P,T,B,X,_WF) :- |
| 4858 | | custom_explicit_sets:card_for_specific_closure(closure(P,T,B),ClosureKind,Card,Code),!, |
| 4859 | | call(Code), % TO DO: catch if we convert large integer due to overflow to inf ! |
| 4860 | | % maybe we can set / transmit a flag for is_overflowcheck ? overflow_float_pown ? factorial ? |
| 4861 | | set_finite_result(Card,closure(P,T,B),ClosureKind,X). |
| 4862 | | test_finite_closure_ground(P,T,B,X,WF) :- |
| 4863 | | on_enumeration_warning(expand_only_custom_closure_global(closure(P,T,B),Result,check,WF),fail), |
| 4864 | | !, |
| 4865 | | test_finite_set_wf(Result,X,WF). |
| 4866 | | test_finite_closure_ground(P,T,B,X,WF) :- X==pred_true, !, |
| 4867 | | get_enumeration_finished_wait_flag(WF,AWF), % only add warning if indeed we find a solution |
| 4868 | | finite_warning(AWF,P,T,B,is_finite_set_closure(P)). |
| 4869 | | test_finite_closure_ground(P,T,B,_X,_WF) :- !, |
| 4870 | | finite_warning(now,P,T,B,test_finite_closure(P)), |
| 4871 | | fail. % now we fail; used to be X=pred_true. % we assume set to be finite, but print a warning |
| 4872 | | % we could set up the closure and do a deterministic phase: if it fails or all variables become bounded, then it is finite |
| 4873 | | |
| 4874 | | unary_member_closure_for_finite(seq(b(value(SET1),_,_)),empty,SET1). % finite if SET1 is empty |
| 4875 | | unary_member_closure_for_finite(seq1(b(value(SET1),_,_)),empty,SET1). |
| 4876 | | unary_member_closure_for_finite(perm(b(value(SET1),_,_)),finite,SET1). % finite if SET1 is finite |
| 4877 | | unary_member_closure_for_finite(iseq(b(value(SET1),_,_)),finite,SET1). |
| 4878 | | unary_member_closure_for_finite(iseq1(b(value(SET1),_,_)),finite,SET1). |
| 4879 | | unary_member_closure_for_finite(identity(b(value(SET1),_,_)),finite,SET1). |
| 4880 | | % we could deal with POW/POW1... here |
| 4881 | | |
| 4882 | | :- block test_finite_cartesian_product_wf(-,?,?,?,?,?), test_finite_cartesian_product_wf(?,-,?,?,?,?). |
| 4883 | | test_finite_cartesian_product_wf(pred_true, pred_true, _,_,X,_) :- !, X=pred_true. % both finite |
| 4884 | | test_finite_cartesian_product_wf(pred_false,pred_false,_,_,X,_) :- !, X=pred_false. % both infinite |
| 4885 | | test_finite_cartesian_product_wf(pred_false,pred_true, _,B,X,WF) :- !, |
| 4886 | | kernel_equality:empty_set_test_wf(B,X,WF). % only finite if B empty |
| 4887 | | test_finite_cartesian_product_wf(pred_true, pred_false,A,_,X,WF) :- !, |
| 4888 | | kernel_equality:empty_set_test_wf(A,X,WF). % only finite if B empty |
| 4889 | | |
| 4890 | | |
| 4891 | | :- block set_finite_result_no_warn(-,?). |
| 4892 | | set_finite_result_no_warn(inf,X) :- !, X=pred_false. |
| 4893 | | set_finite_result_no_warn(_,pred_true). |
| 4894 | | |
| 4895 | | :- block set_finite_result(-,?,?,?). |
| 4896 | | set_finite_result(inf,_Set,_ClosureKind,X) :- !, |
| 4897 | | %(Set=closure(P,T,B), \+ precise_closure_kind(ClosureKind) |
| 4898 | | % -> finite_warning(now,P,T,B,test_finite_closure(P)) % we sometimes return inf for very large sets % TO DO: fix |
| 4899 | | % ; true), |
| 4900 | | X=pred_false. |
| 4901 | | set_finite_result(_,_,_,pred_true). |
| 4902 | | |
| 4903 | | % inf is now always real infinity; inf_overflow is finite very large cardinality not representable as number |
| 4904 | | %precise_closure_kind(special_closure). % is_special_infinite_closure is precise, inf is real infinity %%% |
| 4905 | | %precise_closure_kind(interval_closure). % here we also should never produce inf for a finite but large set |
| 4906 | | |
| 4907 | | |
| 4908 | | :- assert_must_succeed(exhaustive_kernel_check(cardinality_as_int([int(2),int(4),int(1)],int(3)))). |
| 4909 | | :- assert_must_succeed((cardinality_as_int(Y,int(2)), Y = [fd(1,'Name'),fd(2,'Name')])). |
| 4910 | | :- assert_must_succeed((cardinality_as_int(Y,int(2)), |
| 4911 | | nonvar(Y), Y = [H1|YY], nonvar(YY), YY=[H2], H1=int(0), H2=int(3) )). |
| 4912 | | :- assert_must_succeed((cardinality_as_int([A|Y],int(3)), |
| 4913 | | nonvar(Y), Y = [B|YY], nonvar(YY), YY=[C], A=int(1),B=int(3),C=int(2) )). |
| 4914 | | :- assert_must_succeed((cardinality_as_int(Y,int(1)), Y = [fd(1,'Name')])). |
| 4915 | | :- assert_must_succeed((cardinality_as_int(Y,int(0)), Y = [])). |
| 4916 | | :- assert_must_succeed((cardinality_as_int(X,int(3)), equal_object(X,global_set('Name')))). |
| 4917 | | :- assert_must_fail((cardinality_as_int(Y,int(X)), Y = [fd(1,'Name'),fd(2,'Name')],dif(X,2))). |
| 4918 | | :- assert_must_succeed_any((preferences:preference(use_clpfd_solver,false) ; |
| 4919 | | cardinality_as_int_wf(S,int(C),WF), clpfd_interface:try_post_constraint('#>='(C,2)), kernel_waitflags:ground_wait_flags(WF), nonvar(S),S=[_|T],nonvar(T))). |
| 4920 | | :- assert_must_succeed((cardinality_as_int([int(1)|avl_set(node(int(3),true,0,empty,empty))],int(2)))). |
| 4921 | | :- assert_must_succeed((cardinality_as_int([int(1)|avl_set(node(int(3),true,0,empty,empty))],X),X==int(2))). |
| 4922 | | % check that we deal with repeated elements, in case no other predicate sets up a list ! |
| 4923 | | :- assert_must_fail((cardinality_as_int([int(1),int(1)],int(2)))). |
| 4924 | | :- assert_must_fail((cardinality_as_int([int(1),int(1)],_))). |
| 4925 | | :- assert_must_fail((cardinality_as_int(X,int(2)),X=[int(1),int(1)])). |
| 4926 | | :- assert_must_fail((cardinality_as_int([int(3)|avl_set(node(int(3),true,0,empty,empty))],_))). |
| 4927 | | :- assert_must_fail((cardinality_as_int([X|avl_set(node(int(3),true,0,empty,empty))],int(2)),X=int(3))). |
| 4928 | | |
| 4929 | | |
| 4930 | | cardinality_as_int(S,I) :- cardinality_as_int_wf(S,I,no_wf_available). % TO DO: remove this predicate ? |
| 4931 | | :- load_files(library(system), [when(compile_time), imports([environ/2])]). |
| 4932 | | :- if(environ(prob_data_validation_mode,true)). |
| 4933 | | :- block cardinality_as_int_wf(-,?,?). % avoid instantiating list skeletons; cause backtracking in unifications,... |
| 4934 | | :- else. |
| 4935 | | :- block cardinality_as_int_wf(-,-,?). |
| 4936 | | :- endif. |
| 4937 | | % can return inf ! |
| 4938 | | cardinality_as_int_wf(Set,int(Card),WF) :- |
| 4939 | | cardinality_as_int1(Set,Card,Card,WF). |
| 4940 | | |
| 4941 | | cardinality_as_int1(Set,Card,ResCard,WF) :- |
| 4942 | | (number(Card) |
| 4943 | | -> cardinality_as_int1b(Set,Card,ResCard,WF) |
| 4944 | | ; cardinality_as_int1b(Set,Card,ResCard,WF), |
| 4945 | | (var(Set) -> |
| 4946 | | (clpfd_domain(Card,Low,_Up), |
| 4947 | | number(Low), Low>1, |
| 4948 | | unbound_variable_for_card(Set) |
| 4949 | | % TO DO: also use this optimization later in cardinality_as_int2 |
| 4950 | | -> setup_ordered_list_skeleton(Low,Skel,open,WF), |
| 4951 | | Skel=Set |
| 4952 | | ; get_wait_flag(1,force_non_empty(Set,Card),WF,LWF), |
| 4953 | | force_non_empty0(Set,Card,LWF) |
| 4954 | | ) |
| 4955 | | ; true) |
| 4956 | | ). |
| 4957 | | % tests 1418, 1419, 1628, 1776 require that cardinality_as_int1b be triggered quickly |
| 4958 | | :- block cardinality_as_int1b(-,-,?,?). % with this the self-check with post_constraint('#>='(C,2) fails |
| 4959 | | % cardinality_as_int1(Set, CardValue, ComputedCardValue) : CardValue should be unified with ComputedCardValue afterwards |
| 4960 | | cardinality_as_int1b(Set,Card,ResCard,WF) :- |
| 4961 | | %portray_waitflags(WF),nl, |
| 4962 | | number(Card), unbound_variable_for_card(Set), |
| 4963 | | !, % we know the cardinality and the set is not yet bound; this improvement is tested in tests 1417, 1418 |
| 4964 | | setup_ordered_list_skeleton(Card,Skel,closed,WF), |
| 4965 | | (Card,Set) = (ResCard,Skel). % bypass equal_object: assign variable in one-go |
| 4966 | | cardinality_as_int1b(Set,Card,ResCard,WF) :- nonvar(Set),!, |
| 4967 | | cardinality_as_int2(Set,0,Card,ResCard,[],WF). |
| 4968 | | cardinality_as_int1b(Set,Card,ResCard,WF) :- |
| 4969 | | % Set is a variable but not unbound_variable_for_cons |
| 4970 | | % Unifications can be very expensive when we set up long lists |
| 4971 | | % Idea: multiply Card by a factor and delay instantiating; maybe we get a avl_set; see test 456 |
| 4972 | | Prio is Card*100, |
| 4973 | | get_wait_flag(Prio,cardinality_as_int1(Set,Card),WF,LWF2), |
| 4974 | | when((nonvar(Set) ; nonvar(LWF2)), |
| 4975 | | cardinality_as_int2(Set,0,Card,ResCard,[],WF)). |
| 4976 | | %force_non_empty0(Set,Card,1). |
| 4977 | | |
| 4978 | | :- if(environ(prob_data_validation_mode,true)). |
| 4979 | | :- block cardinality_as_int2(-,?,?,?,?,?). % avoid instantiating list skeletons; cause backtracking in unifications,... |
| 4980 | | :- else. |
| 4981 | | :- block cardinality_as_int2(-,?,-,?,?,?). |
| 4982 | | :- endif. |
| 4983 | | cardinality_as_int2(X,C,Res,ResultValue,_,WF) :- |
| 4984 | | C==Res,!,empty_set_wf(X,WF),ResultValue=Res. % avoid choice point below |
| 4985 | | cardinality_as_int2(X,C,Res,ResultValue,SoFar,WF) :- nonvar(X), X \= [], X\= [_|_],!, |
| 4986 | | (is_custom_explicit_set(X) |
| 4987 | | -> explicit_set_cardinality_wf(X,ESC,WF), blocking_add_card(C,ESC,ResultValue), |
| 4988 | | disjoint_sets(X,SoFar,WF) |
| 4989 | | ; add_error_fail(cardinality_as_int2,'First argument not set: ',cardinality_as_int2(X,C,Res)) |
| 4990 | | ). |
| 4991 | | cardinality_as_int2([],C,Res,ResultValue,_,_WF) :- C=ResultValue, Res=ResultValue. |
| 4992 | | cardinality_as_int2([H|T],C,Res,ResultValue,SoFar,WF) :- |
| 4993 | | C1 is C+1, |
| 4994 | | not_element_of_wf(H,SoFar,WF), % do we always need to check this ? relevant for test 1828 |
| 4995 | | add_new_element_wf(H,SoFar,SoFar2,WF), |
| 4996 | | (ground(Res) -> safe_less_than_equal(cardinality_as_int2,C1,Res) |
| 4997 | | /* check consistency so far if cardinality provided */ |
| 4998 | | ; clpfd_geq(Res,C1,_) |
| 4999 | | ), |
| 5000 | | force_non_empty(T,C1,Res,1), % Use WF ? |
| 5001 | | cardinality_as_int2(T,C1,Res,ResultValue,SoFar2,WF). |
| 5002 | | |
| 5003 | | % setup an list skeleton with ordering constraints to avoid duplicate solutions |
| 5004 | | setup_ordered_list_skeleton(0,R,Closed,_WF) :- !, (Closed=closed -> R=[] ; true). |
| 5005 | | setup_ordered_list_skeleton(N,[H|T],Closed,WF) :- |
| 5006 | | all_different_wf([H|T],WF), |
| 5007 | | N1 is N-1, setup_list_skel_aux(N1,H,T,Closed). |
| 5008 | | |
| 5009 | | |
| 5010 | | :- use_module(kernel_ordering,[ordered_value/2]). |
| 5011 | | %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 |
| 5012 | | setup_list_skel_aux(0,Prev,R,Closed) :- !, (Closed=closed -> R=[] ; lazy_ordered_value(R,Prev)). |
| 5013 | | setup_list_skel_aux(N,Prev,[H|T],Closed) :- ordered_value(Prev,H), |
| 5014 | | N>0, N1 is N-1, setup_list_skel_aux(N1,H,T,Closed). |
| 5015 | | |
| 5016 | | :- block lazy_ordered_value(-,?). |
| 5017 | | lazy_ordered_value([H|T],Prev) :- !, ordered_value(Prev,H), lazy_ordered_value(T,H). |
| 5018 | | lazy_ordered_value(_,_). |
| 5019 | | |
| 5020 | | |
| 5021 | | % TO DO: use clpfd all_different for integers !? |
| 5022 | | % get_integer_list(Set,IntList), clpfd_alldifferent(IntList). |
| 5023 | | % ensure we have all different constraint in case ordered_value does not succeed in enforcing order! |
| 5024 | | all_different_wf(ListOfValues,WF) :- |
| 5025 | | all_different2(ListOfValues,[],WF). |
| 5026 | | :- block all_different2(-,?,?). |
| 5027 | | all_different2([],_,_) :- !. |
| 5028 | | all_different2([H|T],SoFar,WF) :- !, all_different3(SoFar,H,WF), all_different2(T,[H|SoFar],WF). |
| 5029 | | all_different2(CS,SoFar,WF) :- is_custom_explicit_set(CS), |
| 5030 | | disjoint_sets(CS,SoFar,WF). % already done above by cardinality_as_int2 ? |
| 5031 | | all_different3([],_,_). |
| 5032 | | all_different3([H|T],X,WF) :- not_equal_object_wf(H,X,WF), all_different3(T,X,WF). |
| 5033 | | |
| 5034 | | :- block force_non_empty0(-,-,-). |
| 5035 | | force_non_empty0(Set,Card,LWF) :- var(Set), var(Card), |
| 5036 | | clpfd_domain(Card,Low,Up), |
| 5037 | | (integer(Low) ; integer(Up)), !, % we know we have a finite cardinality |
| 5038 | | clpfd_interface:try_post_constraint((Card#=0) #<=> EmptyR01), |
| 5039 | | prop_non_empty(EmptyR01,Set,LWF). |
| 5040 | | force_non_empty0(_,_,_). |
| 5041 | | |
| 5042 | | % here we assume that the cardinalities cannot be infinite inf |
| 5043 | | :- block force_non_empty(-,?,-,-). |
| 5044 | | force_non_empty(Set,CSoFar,TotalCard,LWF) :- |
| 5045 | | var(Set), var(TotalCard), |
| 5046 | | preference(data_validation_mode,false),!, |
| 5047 | | clpfd_interface:try_post_constraint((TotalCard#=CSoFar) #<=> EmptyR01), |
| 5048 | | prop_non_empty(EmptyR01,Set,LWF). |
| 5049 | | force_non_empty(_,_,_,_). |
| 5050 | | :- block prop_non_empty(-,-,?). |
| 5051 | | prop_non_empty(_,X,_) :- nonvar(X),!. % do nothing; cardinality_as_int2 will be called anyway |
| 5052 | | prop_non_empty(0,X,LWF) :- /* X is var; first arg nonvar */ !, not_empty_set_lwf(X,LWF). |
| 5053 | | %prop_non_empty(1,X,_). % empty_set not really required: TotalCard is now instantiated; cardinality_as_int2 will get called |
| 5054 | | prop_non_empty(_,_,_). |
| 5055 | | |
| 5056 | | |
| 5057 | | |
| 5058 | | :- assert_must_succeed(exhaustive_kernel_check(cardinality_as_int_for_wf(global_set('NATURAL'),inf))). |
| 5059 | | :- assert_must_succeed(exhaustive_kernel_check(cardinality_as_int_for_wf([],0))). |
| 5060 | | :- assert_must_succeed(exhaustive_kernel_check_opt(cardinality_as_int_for_wf([int(2)],1), |
| 5061 | | preferences:get_preference(convert_comprehension_sets_into_closures,false))). % in this case inf returned for closures |
| 5062 | | :- assert_must_succeed(exhaustive_kernel_check_opt(cardinality_as_int_for_wf([int(3),int(1),int(-1),int(100)],4), |
| 5063 | | preferences:get_preference(convert_comprehension_sets_into_closures,false))). |
| 5064 | | :- assert_must_succeed(exhaustive_kernel_fail_check_opt(cardinality_as_int_for_wf([int(3),int(1),int(-1),int(100)],1000), |
| 5065 | | preferences:get_preference(convert_comprehension_sets_into_closures,false))). |
| 5066 | | :- assert_must_succeed(exhaustive_kernel_fail_check_opt(cardinality_as_int_for_wf(global_set('NATURAL'),1000), |
| 5067 | | preferences:get_preference(convert_comprehension_sets_into_closures,false))). |
| 5068 | | % a simpler version without propagation to result; for waitflag priority computation or similar |
| 5069 | | % it may return inf for closures marked as symbolic ! |
| 5070 | | cardinality_as_int_for_wf(Set,Card) :- cardinality_as_int_for_wf0(Set,0,Card). |
| 5071 | | :- block cardinality_as_int_for_wf0(-,?,-). |
| 5072 | | cardinality_as_int_for_wf0(X,C,Res) :- |
| 5073 | ? | (nonvar(X) -> cardinality_as_int_for_wf1(X,C,Res) |
| 5074 | | ; Res==inf -> cardinality_as_int_for_inf(X,C) |
| 5075 | | % TODO: what about inf_overflow here |
| 5076 | | ; cardinality_as_int_for_wf2(X,C,Res)). |
| 5077 | | |
| 5078 | | :- block cardinality_as_int_for_inf(-,?). |
| 5079 | | cardinality_as_int_for_inf(X,C) :- cardinality_as_int_for_wf1(X,C,inf). |
| 5080 | | |
| 5081 | | cardinality_as_int_for_wf1([],C,Res) :- !,C=Res. |
| 5082 | | cardinality_as_int_for_wf1([_H|T],C,Res) :- !,C1 is C+1, |
| 5083 | ? | cardinality_as_int_for_wf0(T,C1,Res). |
| 5084 | | cardinality_as_int_for_wf1(X,C,Res) :- is_custom_explicit_set(X),!, |
| 5085 | ? | explicit_set_cardinality_for_wf(X,ESC), blocking_add_card(C,ESC,Res). |
| 5086 | | cardinality_as_int_for_wf1(term(T),C,Res) :- nonvar(T), T=no_value_for(ID), |
| 5087 | | 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 |
| 5088 | | !, C=Res. |
| 5089 | | cardinality_as_int_for_wf1(X,C,Res) :- |
| 5090 | | add_internal_error('First arg is not a set: ',cardinality_as_int_for_wf1(X,C,Res)),fail. |
| 5091 | | |
| 5092 | | % first argument was var, third argument not inf hence third arg must be set |
| 5093 | | %cardinality_as_int_for_wf2([],C,C). |
| 5094 | | cardinality_as_int_for_wf2([],C,Res) :- (C==Res -> ! ; C=Res). |
| 5095 | | cardinality_as_int_for_wf2([_H|T],C,Res) :- C<Res, C1 is C+1, |
| 5096 | | (var(T) -> cardinality_as_int_for_wf2(T,C1,Res) ; cardinality_as_int_for_wf1(T,C1,Res)). |
| 5097 | | |
| 5098 | | |
| 5099 | | |
| 5100 | | :- assert_must_succeed(exhaustive_kernel_check_wf(same_cardinality_wf(global_set('NATURAL'),global_set('NATURAL'),WF),WF)). |
| 5101 | | :- assert_must_succeed(exhaustive_kernel_check_wf(same_cardinality_wf(global_set('NATURAL'),global_set('NATURAL1'),WF),WF)). |
| 5102 | | :- assert_must_succeed(exhaustive_kernel_check_wf(same_cardinality_wf([int(2),int(1)],[int(11),int(22)],WF),WF)). |
| 5103 | | :- assert_must_succeed(exhaustive_kernel_fail_check_wf(same_cardinality_wf([],[int(11),int(22)],WF),WF)). |
| 5104 | | :- assert_must_succeed(exhaustive_kernel_fail_check_wf(same_cardinality_wf([int(11),int(22),int(33)],[int(11),int(22)],WF),WF)). |
| 5105 | | :- assert_must_succeed(exhaustive_kernel_fail_check_wf(same_cardinality_wf(global_set('NATURAL1'),[int(11),int(22)],WF),WF)). |
| 5106 | | |
| 5107 | | :- block same_cardinality_wf(-,-,?). |
| 5108 | | same_cardinality_wf(Set1,Set2,WF) :- |
| 5109 | | (var(Set1) -> same_card_aux(Set2,Set1,WF) ; same_card_aux(Set1,Set2,WF)). |
| 5110 | | |
| 5111 | | same_card_aux(Set1,Set2,WF) :- |
| 5112 | | (nonvar(Set1),is_custom_explicit_set(Set1,cardinality) |
| 5113 | | -> explicit_set_cardinality_wf(Set1,Card,WF), |
| 5114 | | (Card==inf -> is_infinite_set_wf(Set2,WF) |
| 5115 | | % assumption: if inf then immediately infinite; TO DO: distinguish between infinite(s) and very large |
| 5116 | | ; cardinality_as_int_wf(Set2,int(Card),WF) |
| 5117 | | ) |
| 5118 | | ; cardinality3(Set1,PCard,WF), |
| 5119 | | cardinality_peano_wf(Set2,PCard,WF) |
| 5120 | | ). |
| 5121 | | |
| 5122 | | :- assert_must_succeed(exhaustive_kernel_check(cardinality_peano_wf([],0,no_wf_available))). |
| 5123 | | :- assert_must_succeed(exhaustive_kernel_check(cardinality_peano_wf([int(11)],s(0),no_wf_available))). |
| 5124 | | :- assert_must_succeed(exhaustive_kernel_check(cardinality_peano_wf([int(11),int(22)],s(s(0)),no_wf_available))). |
| 5125 | | % cardinality as peano number |
| 5126 | | :- block cardinality_peano_wf(-,-,?). |
| 5127 | | cardinality_peano_wf(Set,PCard,WF) :- |
| 5128 | | (nonvar(Set),is_custom_explicit_set(Set,cardinality) |
| 5129 | | -> explicit_set_cardinality_wf(Set,Card,WF), |
| 5130 | | card_convert_int_to_peano(Card,PCard) |
| 5131 | | ; cardinality3(Set,PCard,WF) |
| 5132 | | ). |
| 5133 | | |
| 5134 | | :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(3,s(s(s(0)))))). |
| 5135 | | :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(2,S),S==s(s(0)))). |
| 5136 | | :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(X,s(s(s(0)))),X==3)). |
| 5137 | | :- assert_must_succeed((kernel_objects:card_convert_int_to_peano(X,s(s(s(Y)))),X=4,Y==s(0))). |
| 5138 | | :- assert_must_fail((kernel_objects:card_convert_int_to_peano(X,s(s(s(_Y)))),X=2)). |
| 5139 | | |
| 5140 | | :- block card_convert_int_to_peano(-,-). |
| 5141 | | card_convert_int_to_peano(X,S0) :- var(X), !, |
| 5142 | | peel_s(S0,SX,RemS), |
| 5143 | | (RemS==0 -> X=SX |
| 5144 | | ; int_plus(int(X1),int(SX),int(X)), |
| 5145 | | greater_than_equal(int(X1),int(0)), |
| 5146 | | card_convert_int_to_peano(X1,RemS)). |
| 5147 | | card_convert_int_to_peano(inf,X) :- !, |
| 5148 | | infinite_peano(X), |
| 5149 | | add_message(cardinality,'*** WARNING: Large or infinite Cardinality.'). |
| 5150 | | %convert_int_to_peano(100,X). % used to limit to 100 |
| 5151 | | card_convert_int_to_peano(X,P) :- convert_int_to_peano(X,P). |
| 5152 | | |
| 5153 | | :- block infinite_peano(-). |
| 5154 | | infinite_peano(inf). |
| 5155 | | infinite_peano(0) :- fail. |
| 5156 | | infinite_peano(s(X)) :- infinite_peano(X). |
| 5157 | | |
| 5158 | | peel_s(0,0,0). |
| 5159 | | peel_s(s(X),Res,SX) :- (var(X) -> Res=1, SX=X ; peel_s(X,RX,SX), Res is RX+1). |
| 5160 | | |
| 5161 | | :- block cardinality3(-,?,?). % avoids instantiating set; to do: use kernel_cardinality instead |
| 5162 | | % 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 |
| 5163 | | % :- block cardinality3(-,-,?). |
| 5164 | | cardinality3(Set,SC,WF) :- var(Set),!, |
| 5165 | | (SC=0 -> Set=[] ; SC=s(C),Set=[_|T],cardinality3(T,C,WF)). |
| 5166 | | cardinality3([],0,_). |
| 5167 | ? | cardinality3([_|T],s(C),WF) :- cardinality3(T,C,WF). |
| 5168 | | cardinality3(avl_set(AVL),Res,WF) :- cardinality_peano_wf(avl_set(AVL),Res,WF). |
| 5169 | | cardinality3(closure(P,T,B),Res,WF) :- cardinality_peano_wf(closure(P,T,B),Res,WF). |
| 5170 | | |
| 5171 | | |
| 5172 | | |
| 5173 | | |
| 5174 | | |
| 5175 | | |
| 5176 | | :- assert_must_succeed(exhaustive_kernel_check(card_geq([int(2),int(4),int(1)],s(s(s(0)))))). |
| 5177 | | :- assert_must_succeed((kernel_objects:card_geq(global_set('Name'),s(s(s(0)))))). |
| 5178 | | :- assert_must_succeed((kernel_objects:card_geq([int(1),int(2)],s(s(0))))). |
| 5179 | | :- assert_must_succeed((kernel_objects:card_geq([int(1),int(2)],s(0)))). |
| 5180 | | :- assert_must_fail((kernel_objects:card_geq(global_set('Name'),s(s(s(s(0))))))). |
| 5181 | | :- assert_must_fail((kernel_objects:card_geq([int(1),int(2)],s(s(s(0)))))). |
| 5182 | | |
| 5183 | ? | card_geq(Set,Card) :- card_geq_wf(Set,Card,no_wf_available). |
| 5184 | | |
| 5185 | | :- block card_geq_wf(-,-,?). |
| 5186 | | card_geq_wf(Set,Card,WF) :- |
| 5187 | | (nonvar(Set),is_custom_explicit_set(Set,card_geq) |
| 5188 | ? | -> explicit_set_cardinality_wf(Set,CCard,WF), geq_int_peano(CCard,Card) |
| 5189 | | ; card_geq2(Set,Card,WF) ). |
| 5190 | | % should we call setup_ordered_list_skeleton(Card,Set,open) |
| 5191 | | :- block card_geq2(?,-,?). |
| 5192 | | card_geq2(_,C,_) :- C==0,!. |
| 5193 | | card_geq2(S,C,_) :- S==[],!,C=0. |
| 5194 | | card_geq2(S,s(C),WF) :- var(S),!,S=[_|T],card_geq2(T,C,WF). |
| 5195 | | card_geq2([_|T],s(C),WF) :- card_geq2(T,C,WF). |
| 5196 | | card_geq2(avl_set(A),s(C),WF) :- card_geq_wf(avl_set(A),s(C),WF). |
| 5197 | | card_geq2(closure(P,T,B),s(C),WF) :- card_geq_wf(closure(P,T,B),s(C),WF). |
| 5198 | | card_geq2(global_set(G),s(C),WF) :- card_geq_wf(global_set(G),s(C),WF). |
| 5199 | | |
| 5200 | | :- block geq_int_peano(-,-). |
| 5201 | | geq_int_peano(_,0). |
| 5202 | ? | geq_int_peano(X,s(C)) :- geq_int_peano1(X,C). |
| 5203 | | :- block geq_int_peano1(-,?). |
| 5204 | | geq_int_peano1(inf,_) :- !. |
| 5205 | | geq_int_peano1(inf_overflow,_) :- !. |
| 5206 | ? | geq_int_peano1(X,C) :- X>0, X1 is X-1, geq_int_peano(X1,C). |
| 5207 | | |
| 5208 | | :- block convert_int_to_peano(-,?). |
| 5209 | | convert_int_to_peano(X,Y) :- convert_int_to_peano2(X,Y). |
| 5210 | | convert_int_to_peano2(inf,_). |
| 5211 | | convert_int_to_peano2(inf_overflow,_). |
| 5212 | | convert_int_to_peano2(X,R) :- number(X), |
| 5213 | | (X>100000 |
| 5214 | | -> print('*** Warning: converting large integer to peano: '),print(X),nl, |
| 5215 | | (X>1000000000 -> print('*** treat like inf'),nl % no hope of ever finishing, do not instantiate just like inf |
| 5216 | | ; convert_int_to_peano3(X,R)) |
| 5217 | | ; convert_int_to_peano3(X,R) |
| 5218 | | ). |
| 5219 | | convert_int_to_peano3(0,R) :- !, R=0. |
| 5220 | | convert_int_to_peano3(X,s(P)) :- |
| 5221 | | (X>0 -> X1 is X-1, convert_int_to_peano3(X1,P) |
| 5222 | | ; X<0 -> add_error_and_fail(convert_int_to_peano,'Negative nr cannot be converted to peano: ',X) |
| 5223 | | ). |
| 5224 | | |
| 5225 | | % not used: |
| 5226 | | %:- block convert_peano_to_int(-,?). |
| 5227 | | %convert_peano_to_int(0,0). |
| 5228 | | %convert_peano_to_int(s(P),X) :- convert_peano_to_int(P,X1), X is X1+1. |
| 5229 | | |
| 5230 | | :- assert_must_succeed((kernel_objects:cardinality_greater_equal(Set,set(integer),int(X),integer,_WF), X=3, |
| 5231 | | nonvar(Set),Set=[_|S2],nonvar(S2),S2=[_|S3],nonvar(S3),S3=[_|S4],var(S4), Set=[int(1),int(2),int(3)] )). |
| 5232 | | :- assert_must_succeed((kernel_objects:cardinality_greater(Set,set(integer),int(X),integer,_WF), X=2, |
| 5233 | | nonvar(Set),Set=[_|S2],nonvar(S2),S2=[_|S3],nonvar(S3),S3=[_|S4],var(S4), Set=[int(1),int(2),int(3)] )). |
| 5234 | | /* special predicates called for e.g. card(Set)>X */ |
| 5235 | | cardinality_greater(Set,TypeSet,int(X),_,WF) :- |
| 5236 | | kernel_objects:max_cardinality(TypeSet,MaxCard), |
| 5237 | | (number(MaxCard) -> less_than(int(X),int(MaxCard)) ; true), |
| 5238 | | card_greater2(Set,X,WF). |
| 5239 | | :- block card_greater2(?,-,?). |
| 5240 | | card_greater2(Set,X,WF) :- X1 is X+1, card_greater_equal2(Set,X1,WF). |
| 5241 | | |
| 5242 | | cardinality_greater_equal(Set,TypeSet,int(X),_,WF) :- |
| 5243 | | kernel_objects:max_cardinality(TypeSet,MaxCard), |
| 5244 | | (number(MaxCard) -> less_than_equal(int(X),int(MaxCard)) ; true), |
| 5245 | | card_greater_equal2(Set,X,WF). |
| 5246 | | :- block card_greater_equal2(?,-,?). |
| 5247 | | card_greater_equal2(Set,X,WF) :- |
| 5248 | | (X<1 -> true % potential WD issue, hence this predicates should only be called when no wd issue |
| 5249 | | ; X=1 -> not_empty_set_wf(Set,WF) % ditto: Set could be infinite |
| 5250 | | ; var(Set) -> setup_ordered_list_skeleton(X,Set,open,WF) |
| 5251 | | ; convert_int_to_peano(X,Peano), |
| 5252 | | card_geq_wf(Set,Peano,WF)). |
| 5253 | | |
| 5254 | | |
| 5255 | | |
| 5256 | | %is_cartesian_pair_or_times(P,X,Y) :- is_cartesian_pair(P,X,Y). |
| 5257 | | %is_cartesian_pair_or_times(int(Z),int(X),int(Y)) :- times(int(X),int(Y),int(Z)). |
| 5258 | | |
| 5259 | | is_cartesian_pair_wf((X,Y),XType,YType,WF) :- |
| 5260 | | check_element_of_wf(X,XType,WF), check_element_of_wf(Y,YType,WF). |
| 5261 | | |
| 5262 | | :- assert_must_succeed(exhaustive_kernel_check_wf(kernel_objects:not_is_cartesian_pair((int(1),int(1)), |
| 5263 | | [int(1),int(2)],[int(2),int(3)],WF),WF)). |
| 5264 | | :- assert_must_succeed(exhaustive_kernel_check_wf(kernel_objects:not_is_cartesian_pair((int(3),int(2)), |
| 5265 | | [int(1),int(2)],[int(2),int(3)],WF),WF)). |
| 5266 | | :- assert_must_succeed((kernel_objects:not_is_cartesian_pair((int(1),int(1)), |
| 5267 | | [int(1),int(2)],[int(2),int(3)],_WF))). |
| 5268 | | :- assert_must_succeed((kernel_objects:not_is_cartesian_pair((int(3),int(1)), |
| 5269 | | [int(1),int(2)],[int(2),int(3)],_WF))). |
| 5270 | | :- assert_must_fail((kernel_objects:not_is_cartesian_pair((int(1),int(3)), |
| 5271 | | [int(1),int(2)],[int(2),int(3)],_WF))). |
| 5272 | | :- assert_must_succeed((kernel_objects:not_is_cartesian_pair((X,int(3)), |
| 5273 | | [int(1),int(2)],[int(2),int(3)],_WF),X=int(4))). |
| 5274 | | |
| 5275 | | |
| 5276 | | not_is_cartesian_pair((X,Y),XType,YType,WF) :- |
| 5277 | | not_is_cartesian_pair0(X,Y,XType,YType,WF). |
| 5278 | | |
| 5279 | | :- block not_is_cartesian_pair0(-,-,?,?,?). |
| 5280 | | not_is_cartesian_pair0(X,Y,XType,YType,WF) :- |
| 5281 | | (nonvar(X) -> not_is_cartesian_pair1(X,Y,XType,YType,WF) |
| 5282 | | ; not_is_cartesian_pair1(Y,X,YType,XType,WF)). |
| 5283 | | |
| 5284 | | not_is_cartesian_pair1(X,Y,XType,YType,WF) :- |
| 5285 | | membership_test_wf(XType,X,MemResX,WF), |
| 5286 | | (var(MemResX) -> membership_test_wf(YType,Y,MemResY,WF) ; true), |
| 5287 | | not_is_cartesian_pair3(MemResX,X,XType,MemResY,Y,YType,WF). |
| 5288 | | |
| 5289 | | :- block not_is_cartesian_pair3(-,?,?, -,?,?, ?). |
| 5290 | | not_is_cartesian_pair3(MemResX,X,XType, MemResY,Y,YType, WF) :- |
| 5291 | | (MemResX==pred_false -> true |
| 5292 | | ; MemResY==pred_false -> true |
| 5293 | | ; MemResX==pred_true -> not_element_of_wf(Y,YType,WF) |
| 5294 | | ; not_element_of_wf(X,XType,WF) |
| 5295 | | ). |
| 5296 | | |
| 5297 | | |
| 5298 | | |
| 5299 | | /***************************/ |
| 5300 | | /* power_set(Set,TypeSet) */ |
| 5301 | | /* Set : POW(TypeSet) */ |
| 5302 | | /***************************/ |
| 5303 | | |
| 5304 | | :- assert_must_succeed(exhaustive_kernel_check(power_set([int(2),int(4)],[[int(2)], |
| 5305 | | [int(4)],[],[int(4),int(2)]]))). |
| 5306 | | :- assert_must_succeed(power_set([int(1)],[[int(1)],[]])). |
| 5307 | | :- assert_must_succeed((power_set([int(1),int(2)],R), |
| 5308 | | equal_object(R,[[],[int(1)],[int(2)],[int(1),int(2)]]))). |
| 5309 | | :- assert_must_succeed(power_set([],[[]])). |
| 5310 | | |
| 5311 | | % not used anymore, except for empty set and singleton sets (see do_not_keep_symbolic_unary) |
| 5312 | | :- block power_set(-,?). |
| 5313 | | power_set([],Res) :- !,equal_object_optimized([[]],Res,power_set). |
| 5314 | | power_set(Set1,Res) :- custom_explicit_sets:singleton_set(Set1,El),!, |
| 5315 | | equal_object_optimized([[],[El]],Res,power_set). |
| 5316 | | power_set(S,Res) :- |
| 5317 | | cardinality_peano_wf(S,Card,no_wf_available), |
| 5318 | | when(ground(Card), /* when all elements are known */ |
| 5319 | | (expand_custom_set_to_list_wf(S,SE,Done,power_set,no_wf_available), |
| 5320 | | when(nonvar(Done), |
| 5321 | | (gen_all_subsets(SE,PowerS), |
| 5322 | | equal_object_optimized(PowerS,Res,power_set) ) |
| 5323 | | ) |
| 5324 | | )). |
| 5325 | | |
| 5326 | | :- assert_must_succeed((kernel_objects:gen_all_subsets([X],R), R== [[],[X]])). |
| 5327 | | :- assert_must_succeed((kernel_objects:gen_all_subsets([X,Y],R), R== [[],[Y],[X],[Y,X]])). |
| 5328 | | % we do not use findall to keep variable links, see test 2103 |
| 5329 | | gen_all_subsets(List,AllSubLists) :- gen_all_subsets(List,[[]],AllSubLists). |
| 5330 | | add_el(H,T,[H|T]). |
| 5331 | | gen_all_subsets([],Acc,Acc). |
| 5332 | | gen_all_subsets([H|T],Acc,Res) :- gen_all_subsets(T,Acc,R1), |
| 5333 | | append(R1,R2,Res), % DCG would be better; but power_set is not really used anymore for longer lists |
| 5334 | | maplist(add_el(H),Acc,Acc2), gen_all_subsets(T,Acc2,R2). |
| 5335 | | |
| 5336 | | |
| 5337 | | :- assert_must_succeed(exhaustive_kernel_check(non_empty_power_set([int(2),int(4)],[[int(2)], |
| 5338 | | [int(4)],[int(4),int(2)]]))). |
| 5339 | | :- assert_must_succeed(non_empty_power_set([int(1)],[[int(1)]])). |
| 5340 | | :- assert_must_succeed((non_empty_power_set([int(1),int(2)],R), |
| 5341 | | equal_object(R,[[int(1)],[int(2)],[int(1),int(2)]]))). |
| 5342 | | :- assert_must_succeed(non_empty_power_set([],[])). |
| 5343 | | |
| 5344 | | :- block non_empty_power_set(-,?). |
| 5345 | | non_empty_power_set([],Res) :- !,equal_object_optimized([],Res,non_empty_power_set). |
| 5346 | | non_empty_power_set(Set1,Res) :- custom_explicit_sets:singleton_set(Set1,El),!, |
| 5347 | | equal_object_optimized([[El]],Res,non_empty_power_set). |
| 5348 | | non_empty_power_set(S,Res) :- |
| 5349 | | cardinality_peano_wf(S,Card,no_wf_available), |
| 5350 | | when(ground(Card), /* when all elements are known */ |
| 5351 | | (expand_custom_set_to_list_wf(S,SE,Done,non_empty_power_set,no_wf_available), |
| 5352 | | when(nonvar(Done), |
| 5353 | | (gen_all_subsets(SE,PowerS), |
| 5354 | | delete(PowerS,[],NE_PowerS), |
| 5355 | | equal_object_optimized(NE_PowerS,Res,non_empty_power_set) ) |
| 5356 | | ) |
| 5357 | | )). |
| 5358 | | |
| 5359 | | |
| 5360 | | |
| 5361 | | /* ------- */ |
| 5362 | | /* BOOLEAN */ |
| 5363 | | /* ------- */ |
| 5364 | | |
| 5365 | | % following predicates are not used: |
| 5366 | | %is_boolean(pred_true /* bool_true */). |
| 5367 | | %is_boolean(pred_false /* bool_false */). |
| 5368 | | %is_not_boolean(X) :- dif(X,pred_true /* bool_true */), dif(X,pred_false /* bool_false */). |
| 5369 | | |
| 5370 | | /* ------- */ |
| 5371 | | /* NUMBERS */ |
| 5372 | | /* ------- */ |
| 5373 | | |
| 5374 | | |
| 5375 | | is_integer(int(X),_WF) :- when(ground(X),integer(X)). |
| 5376 | | :- block is_not_integer(-). |
| 5377 | | is_not_integer(X) :- X \= int(_), % will be called for x /: INTEGER; should always fail. |
| 5378 | | add_internal_error('Wrong type argument: ',is_not_integer(X)),fail. |
| 5379 | | |
| 5380 | | is_natural(int(X),_WF) :- clpfd_geq2(X,0,Posted), (Posted==true -> true ; number_geq(X,0)). |
| 5381 | | is_natural1(int(X),_WF) :- clpfd_geq2(X,1,Posted), (Posted==true -> true ; number_geq(X,1)). |
| 5382 | | :- block number_geq(-,?). |
| 5383 | | number_geq(X,N) :- X>=N. |
| 5384 | | :- block number_leq(-,?). |
| 5385 | | number_leq(X,N) :- X=<N. |
| 5386 | | |
| 5387 | | :- assert_must_succeed(is_implementable_int(int(0),_WF)). |
| 5388 | | :- assert_must_fail(is_not_implementable_int(int(0))). |
| 5389 | | |
| 5390 | | |
| 5391 | | is_implementable_int(int(X),WF) :- element_of_global_integer_set_wf('INT',X,WF,unkmown). |
| 5392 | | is_implementable_nat(int(X),WF) :- element_of_global_integer_set_wf('NAT',X,WF,unknown). |
| 5393 | | is_implementable_nat1(int(X),WF) :- element_of_global_integer_set_wf('NAT1',X,WF,unknown). |
| 5394 | | is_not_implementable_int(X) :- not_element_of_global_set(X,'INT'). |
| 5395 | | is_not_implementable_nat(X) :- not_element_of_global_set(X,'NAT'). |
| 5396 | | is_not_implementable_nat1(X) :- not_element_of_global_set(X,'NAT1'). |
| 5397 | | |
| 5398 | | is_not_natural(int(X)) :- clpfd_geq2(-1,X,Posted), (Posted=true -> true ; number_leq(X,-1)). |
| 5399 | | is_not_natural1(int(X)) :- clpfd_geq2(0,X,Posted), (Posted==true -> true ; number_leq(X,0)). |
| 5400 | | |
| 5401 | | :- assert_must_succeed(exhaustive_kernel_check(less_than(int(2),int(3)))). |
| 5402 | | :- assert_must_succeed(( safe_less_than(A,B),A=3,B=5 )). |
| 5403 | | :- assert_must_succeed(( safe_less_than(A,B),B=5,A=3 )). |
| 5404 | | :- assert_must_fail(( safe_less_than(A,B),A=5,B=3 )). |
| 5405 | | :- assert_must_fail(( safe_less_than(A,B),B=3,A=5 )). |
| 5406 | | :- assert_must_fail(( safe_less_than(A,B),A=5,B=5 )). |
| 5407 | | :- assert_must_fail(( safe_less_than(A,B),B=5,A=5 )). |
| 5408 | | |
| 5409 | | less_than(int(X),int(Y)) :- |
| 5410 | | (number(X),number(Y) -> X < Y |
| 5411 | | ; clpfd_lt(X,Y,Posted), |
| 5412 | | (Posted=true -> true ; safe_less_than(X,Y))). |
| 5413 | | less_than_direct(X,Y) :- |
| 5414 | | (number(X),number(Y) -> X < Y |
| 5415 | | ; clpfd_lt(X,Y,Posted), |
| 5416 | | (Posted=true -> true ; safe_less_than(X,Y))). |
| 5417 | | :- block safe_less_than(-,?), safe_less_than(?,-). |
| 5418 | | safe_less_than(X,Y) :- |
| 5419 | | (number(X),number(Y) -> X<Y |
| 5420 | | ; add_internal_error('Arguments not numbers: ',safe_less_than(X,Y))). |
| 5421 | | |
| 5422 | | :- assert_must_succeed(exhaustive_kernel_check(less_than_equal(int(33),int(33)))). |
| 5423 | | less_than_equal(int(X),int(Y)) :- |
| 5424 | | (number(X),number(Y) -> X =< Y |
| 5425 | | ; clpfd_leq(X,Y,Posted), |
| 5426 | | (Posted=true -> true ; safe_less_than_equal(less_than_equal,X,Y))). |
| 5427 | | less_than_equal_direct(X,Y) :- |
| 5428 | | (number(X),number(Y) -> X =< Y |
| 5429 | ? | ; clpfd_leq(X,Y,Posted), |
| 5430 | | (Posted=true -> true ; safe_less_than_equal(less_than_equal_direct,X,Y))). |
| 5431 | | |
| 5432 | | safe_less_than_equal(X,Y) :- |
| 5433 | | safe_less_than_equal(safe_less_than_equal,X,Y). |
| 5434 | | :- block safe_less_than_equal(?,-,?), safe_less_than_equal(?,?,-). |
| 5435 | | safe_less_than_equal(PP,X,Y) :- |
| 5436 | | (number(X),number(Y) -> X=<Y |
| 5437 | | ; add_internal_error('Arguments not numbers: ',safe_less_than_equal(PP,X,Y))). |
| 5438 | | |
| 5439 | | :- assert_must_succeed(exhaustive_kernel_check(greater_than(int(2),int(1)))). |
| 5440 | | :- assert_must_succeed(exhaustive_kernel_fail_check(greater_than(int(2),int(2)))). |
| 5441 | | greater_than(int(X),int(Y)) :- less_than_direct(Y,X). |
| 5442 | | :- assert_must_succeed(exhaustive_kernel_check(greater_than(int(2),int(1)))). |
| 5443 | | :- assert_must_succeed(exhaustive_kernel_check(greater_than_equal(int(2),int(2)))). |
| 5444 | | :- assert_must_succeed(exhaustive_kernel_fail_check(greater_than_equal(int(1),int(2)))). |
| 5445 | | greater_than_equal(int(X),int(Y)) :- less_than_equal_direct(Y,X). |
| 5446 | | |
| 5447 | | |
| 5448 | | |
| 5449 | | |
| 5450 | | |
| 5451 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],int_plus(int(2),int(3),int(5)))). |
| 5452 | | :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],int_plus(int(2),int(3),int(6)))). |
| 5453 | | |
| 5454 | | :- assert_must_succeed(int_plus(int(1),int(2),int(3))). |
| 5455 | | :- assert_must_succeed(( int_plus2(A,B,C),A=3,B=2,C==5 )). |
| 5456 | | :- assert_must_succeed(( int_plus2(A,B,C),A=3,C=5,B==2 )). |
| 5457 | | :- assert_must_succeed(( int_plus2(A,B,C),B=2,A=3,C==5 )). |
| 5458 | | :- assert_must_succeed(( int_plus2(A,B,C),B=2,C=5,A==3 )). |
| 5459 | | :- assert_must_succeed(( int_plus2(A,B,C),C=5,A=3,B==2 )). |
| 5460 | | :- assert_must_succeed(( int_plus2(A,B,C),C=5,B=2,A==3 )). |
| 5461 | | :- assert_must_succeed(( int_plus2(A,B,C),A=0,B==C )). |
| 5462 | | :- assert_must_succeed(( int_plus2(A,B,C),B=0,A==C )). |
| 5463 | | |
| 5464 | | int_plus(int(X),int(Y),int(Plus)) :- |
| 5465 | ? | (two_vars_or_more(X,Y,Plus) |
| 5466 | | -> clpfd_eq(Plus,X+Y) % can have performance problems |
| 5467 | | ; true % otherwise we can compute the value directly below; we could skip the block declaration |
| 5468 | | ), |
| 5469 | ? | int_plus2(X,Y,Plus). |
| 5470 | | two_vars_or_more(X,Y,Z) :- var(X),!, (var(Y) ; var(Z)). |
| 5471 | | two_vars_or_more(_X,Y,Z) :- var(Y) , var(Z). |
| 5472 | | |
| 5473 | | :- block int_plus2(-,-,-). |
| 5474 | | int_plus2(X,Y,Plus) :- |
| 5475 | ? | ( ground(X) -> int_plus3(X,Y,Plus) |
| 5476 | | ; ground(Y) -> int_plus3(Y,X,Plus) |
| 5477 | | ; int_minus3(Plus,X,Y)). |
| 5478 | | |
| 5479 | | % int_plus3/3: the first argument must be ground when called |
| 5480 | | int_plus3(0,Y,Plus) :- !, Y=Plus. % not inferred by CLP(FD): Z #= Y+X, X=0. does not infer Y==Z |
| 5481 | | int_plus3(X,Y,Plus) :- % integer_dif(Y,Plus), % this generates overflows for test 1353, 1014 |
| 5482 | ? | int_plus4(X,Y,Plus). |
| 5483 | | |
| 5484 | | % int_plus4/3: the first argument must be ground when called |
| 5485 | | :- block int_plus4(?,-,-). |
| 5486 | | int_plus4(X,Y,Plus) :- |
| 5487 | | ( var(Plus) -> Plus is X+Y |
| 5488 | | ; Y is Plus-X). |
| 5489 | | |
| 5490 | | :- assert_must_succeed(exhaustive_kernel_check(int_minus(int(2),int(3),int(-1)))). |
| 5491 | | :- assert_must_succeed(exhaustive_kernel_fail_check(int_minus(int(2),int(3),int(1)))). |
| 5492 | | :- assert_must_succeed(int_minus(int(3),int(1),int(2))). |
| 5493 | | :- assert_must_succeed(( int_minus2(A,B,C),A=3,B=2,C==1 )). |
| 5494 | | :- assert_must_succeed(( int_minus2(A,B,C),A=3,C=1,B==2 )). |
| 5495 | | :- assert_must_succeed(( int_minus2(A,B,C),B=2,A=3,C==1 )). |
| 5496 | | :- assert_must_succeed(( int_minus2(A,B,C),B=2,C=1,A==3 )). |
| 5497 | | :- assert_must_succeed(( int_minus2(A,B,C),C=1,A=3,B==2 )). |
| 5498 | | :- assert_must_succeed(( int_minus2(A,B,C),C=1,B=2,A==3 )). |
| 5499 | | :- assert_must_succeed(( int_minus2(A,B,C),B=0,A==C )). |
| 5500 | | :- assert_must_succeed(( int_minus2(A,B,C),B=0,C=5,A==5 )). |
| 5501 | | :- assert_must_succeed(( int_minus2(A,B,5),B=0,A==5 )). |
| 5502 | | |
| 5503 | | int_minus(int(X),int(Y),int(Minus)) :- |
| 5504 | ? | int_minus2(X,Y,Minus), |
| 5505 | ? | (two_vars_or_more(X,Y,Minus) -> clpfd_eq(Minus,X-Y) % can have performance problems. |
| 5506 | | % we could also set Minus to 0 if X==Y; this is done in CHR (chr_integer_inequality) |
| 5507 | | ; true). % we can compute the value directly anyway |
| 5508 | | :- block int_minus2(-,-,-). |
| 5509 | | int_minus2(X,Y,Minus) :- |
| 5510 | | ( ground(Y) -> |
| 5511 | | ( Y=0 -> X=Minus |
| 5512 | ? | ; Y2 is -Y, int_plus3(Y2,X,Minus)) |
| 5513 | | ; ground(X) -> |
| 5514 | ? | int_minus3(X,Y,Minus) |
| 5515 | | ; int_plus3(Minus,Y,X) % will infer that Y=X if Minus=0 |
| 5516 | | ). |
| 5517 | | |
| 5518 | | % int_minus3/3: the first argument must be ground when called |
| 5519 | | :- block int_minus3(?,-,-). |
| 5520 | | int_minus3(X,Y,Minus) :- |
| 5521 | | ( var(Minus) -> Minus is X-Y |
| 5522 | | ; Y is X-Minus). |
| 5523 | | |
| 5524 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(2),int(3),int(0),unknown,_WF))). |
| 5525 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(7),int(2),int(3),unknown,_WF))). |
| 5526 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(8),int(2),int(4),unknown,_WF))). |
| 5527 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(9),int(2),int(4),unknown,_WF))). |
| 5528 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(2),int(-1),int(-2),unknown,_WF))). |
| 5529 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(9),int(-2),int(-4),unknown,_WF))). |
| 5530 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(-9),int(-3),int(3),unknown,_WF))). |
| 5531 | | :- assert_must_succeed(exhaustive_kernel_check(division(int(-1),int(4),int(0),unknown,_WF))). |
| 5532 | | :- assert_must_succeed((platform_is_64_bit |
| 5533 | | -> exhaustive_kernel_check(division(int(4294967296),int(2),int(2147483648),unknown,_WF)) |
| 5534 | | ; exhaustive_kernel_check(division(int(134217728),int(2),int(67108864),unknown,_WF)))). |
| 5535 | | :- assert_must_succeed((platform_is_64_bit |
| 5536 | | -> exhaustive_kernel_check(division(int(4294967296),int(2147483648),int(2),unknown,_WF)) |
| 5537 | | ; exhaustive_kernel_check(division(int(134217728),int(67108864),int(2),unknown,_WF)))). |
| 5538 | | :- assert_must_succeed(exhaustive_kernel_fail_check(division(int(2),int(3),int(1),unknown,_WF))). |
| 5539 | | :- assert_must_succeed(( division3(A,B,C,unknown,_),A=15,B=4,C==3 )). |
| 5540 | | :- assert_must_succeed(( division3(A,B,C,unknown,_),B=4,A=15,C==3 )). |
| 5541 | | |
| 5542 | | division(int(X),int(Y),int(XDY),Span,WF) :- var(Y), (var(X) ; var(XDY)), |
| 5543 | | preferences:preference(use_clpfd_solver,true),!, |
| 5544 | | (preferences:preference(disprover_mode,true) |
| 5545 | | -> clpfd_eq_div(XDY,X,Y) /* we can assume well-definedness */ |
| 5546 | | ; clpfd_eq_guarded_div(XDY,X,Y), |
| 5547 | | % TO DO: we could set up a choice point just before enumeration of infinite types for Y=0 & Y/=0; |
| 5548 | | % same for modulo |
| 5549 | | check_nonzero(X,Y,XDY,Span,WF) |
| 5550 | | ). |
| 5551 | | division(int(X),int(Y),int(XDY),Span,WF) :- |
| 5552 | | %% clpfd_eq_expr(XDY,X/Y), % can have performance problems; could hide division by 0 ! |
| 5553 | | division3(X,Y,XDY,Span,WF). |
| 5554 | | |
| 5555 | | :- block check_nonzero(?,-,?,?,?). |
| 5556 | | check_nonzero(X,Y,XDY,Span,WF) :- |
| 5557 | | (Y=0 -> add_wd_error_set_result('division by zero','/'(X,Y),XDY,0,Span,WF) |
| 5558 | | ; true). |
| 5559 | | |
| 5560 | | :- block division3(?,-,?,?,?). |
| 5561 | | division3(X,Y,XDY,Span,WF) :- |
| 5562 | | ( Y==0 -> add_wd_error_set_result('division by zero','/'(X,Y),XDY,0,Span,WF) |
| 5563 | | ; nonvar(X) -> XDY is X // Y |
| 5564 | | ; Y == 1 -> X=XDY |
| 5565 | | ; Y == -1,nonvar(XDY) -> X is -XDY |
| 5566 | | ; clpfd_eq_div(XDY,X,Y)). % we could setup constraint before Y is known; could hide division by 0 ? |
| 5567 | | |
| 5568 | | |
| 5569 | | |
| 5570 | | :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(2),int(3),int(0),unknown,_WF))). |
| 5571 | | :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(7),int(2),int(3),unknown,_WF))). |
| 5572 | | :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(-1),int(4),int(-1),unknown,_WF))). |
| 5573 | | :- assert_must_succeed(exhaustive_kernel_check(floored_division(int(-9),int(-3),int(3),unknown,_WF))). |
| 5574 | | floored_division(int(X),int(Y),int(XDY),Span,WF) :- var(Y), (var(X) ; var(XDY)), |
| 5575 | | preferences:preference(use_clpfd_solver,true),!, |
| 5576 | | (preferences:preference(disprover_mode,true) |
| 5577 | | -> clpfd_eq_fdiv(XDY,X,Y) /* we can assume well-definedness */ |
| 5578 | | ; clpfd_eq_guarded_fdiv(XDY,X,Y), |
| 5579 | | check_nonzero(X,Y,XDY,Span,WF) |
| 5580 | | ). |
| 5581 | | floored_division(int(X),int(Y),int(XDY),Span,WF) :- |
| 5582 | | %% clpfd_eq_expr(XDY,X/Y), % can have performance problems; could hide division by 0 ! |
| 5583 | | floored_division3(X,Y,XDY,Span,WF). |
| 5584 | | :- block floored_division3(?,-,?,?,?). |
| 5585 | | floored_division3(X,Y,XDY,Span,WF) :- |
| 5586 | | ( Y==0 -> add_wd_error_set_result('division by zero','/'(X,Y),XDY,0,Span,WF) |
| 5587 | | ; nonvar(X) -> XDY is X div Y |
| 5588 | | ; Y == 1 -> X=XDY |
| 5589 | | ; (Y == -1,nonvar(XDY)) -> X is -XDY |
| 5590 | | ; clpfd_eq_guarded_fdiv(XDY,X,Y)). % we could setup constraint before Y is known; could hide division by 0 ? |
| 5591 | | |
| 5592 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(modulo(int(2),int(3),int(2),unknown,WF),WF)). |
| 5593 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(modulo(int(7),int(2),int(1),unknown,WF),WF)). |
| 5594 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(modulo(int(8),int(2),int(0),unknown,WF),WF)). |
| 5595 | | :- assert_must_succeed(exhaustive_kernel_check_wfdet(modulo(int(9),int(2),int(1),unknown,WF),WF)). |
| 5596 | | :- assert_must_succeed((platform_is_64_bit |
| 5597 | | -> exhaustive_kernel_check_wfdet(modulo(int(4294967296),int(2147483648),int(0),unknown,WF),WF) |
| 5598 | | ; exhaustive_kernel_check_wfdet(modulo(int(134217728),int(67108864),int(0),unknown,WF),WF))). |
| 5599 | | :- assert_must_succeed((platform_is_64_bit |
| 5600 | | -> exhaustive_kernel_check_wfdet(modulo(int(4294967299),int(2147483648),int(3),unknown,WF),WF) |
| 5601 | | ; exhaustive_kernel_check_wfdet(modulo(int(134217731),int(67108864),int(3),unknown,WF),WF))). |
| 5602 | | :- assert_must_succeed(( modulo2(A,B,C,unknown,_),A=7,B=5,C==2 )). |
| 5603 | | :- assert_must_fail(( modulo2(A,B,C,unknown,_),A=7,B=5,C==3 )). |
| 5604 | | |
| 5605 | | modulo(int(X),int(Y),int(Modulo),Span,WF) :- |
| 5606 | | %% clpfd_eq(Modulo,X mod Y), % can have performance problems; could hide division by 0 ! |
| 5607 | | modulo2(X,Y,Modulo,Span,WF), |
| 5608 | | % assert that Modulo<Y, Modulo>=0 |
| 5609 | | (nonvar(X),nonvar(Y) -> true % we already have computed Modulo using modulo2 |
| 5610 | | ; nonvar(Modulo), Modulo < 0 -> true % we will generate well-definedness error; see comment next line |
| 5611 | | ; 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 !! |
| 5612 | | ; clpfd_modulo_prop(X,Y,Modulo,WF) |
| 5613 | | ). |
| 5614 | | :- use_module(specfile,[z_or_tla_minor_mode/0]). |
| 5615 | | :- block modulo2(-,?,?,?,?), modulo2(?,-,?,?,?). |
| 5616 | | modulo2(X,Y,Modulo,Span,WF) :- |
| 5617 | | ( Y>0 -> (X<0 -> (z_or_tla_minor_mode -> Modulo is X mod Y |
| 5618 | | ; add_wd_error_set_result('mod not defined for negative numbers in B:',mod(X,Y),Modulo,0,Span,WF)) |
| 5619 | | ; Modulo is X mod Y) |
| 5620 | | ; Y==0 -> add_wd_error_set_result('mod by zero:',mod(X,Y),Modulo,0,Span,WF) |
| 5621 | | ; 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 ? |
| 5622 | | |
| 5623 | | % propagate information about Modulo result if part of the information known |
| 5624 | | clpfd_modulo_prop(X,Y,Modulo,WF) :- %preferences:preference(use_clpfd_solver,true),!, |
| 5625 | | % in CLP(FD) this is sufficient; for non-CLPFD mode it is better to call in_nat_range to restrict enumeration |
| 5626 | | less_than_direct(Modulo,Y), |
| 5627 | | less_than_equal_direct(0,Modulo), % 0 <= Modulo < Y -> by transitivity this forces Y>0 and we no longer detect wd-errors |
| 5628 | | %less_than_equal_direct(Modulo,X). % by transitivity this imposes X >= 0 and we will never find WD problems with negative X |
| 5629 | | (preference(use_clpfd_solver,true) |
| 5630 | | -> get_wait_flag0(WF,WF0), |
| 5631 | | % avoid propagating complex too early, e.g., for x>2 & x:3..10 & x mod 3 = 1 & x mod 3 = 2 in test 2126 |
| 5632 | | % also see test 1959 which was initially failing due to adding WF0 delay |
| 5633 | | clpfd_modulo_prop2(X,Y,Modulo,WF0) |
| 5634 | | ; true). |
| 5635 | | |
| 5636 | | :- block clpfd_modulo_prop2(?,?,?,-). |
| 5637 | | clpfd_modulo_prop2(X,Y,Modulo,_WF0) :- |
| 5638 | | number(Modulo), % this test is required for test 1009, 417 : TO DO : investigate cause |
| 5639 | | var(X), % or should this be var(X) ; var(Y) ?? |
| 5640 | | fd_min(Y,MinY), number(MinY), MinY>0, |
| 5641 | | fd_min(X,MinX), number(MinX), MinX>=0, % modulo is well-defined |
| 5642 | | !, |
| 5643 | | clpfd_interface:clpfd_leq_expr(Modulo,X), |
| 5644 | | clpfd_interface:try_post_constraint(Modulo #= X mod Y). |
| 5645 | | %clpfd_modulo_prop2(X,Y,Modulo,_WF0) :- number(Y),!, |
| 5646 | | % % also makes tests 1009, 417 fail, but would enable solving x mod 256 = 0 & x>0 |
| 5647 | | % clpfd_interface:try_post_constraint(X#>=0 #=> Modulo #= X mod Y). % will also assert X#>Modulo |
| 5648 | | clpfd_modulo_prop2(X,_Y,_Modulo,_WF0) :- X==0,!. % no need to propagate, we already assert 0 <= Modulo above |
| 5649 | | clpfd_modulo_prop2(X,_Y,Modulo,_WF0) :- |
| 5650 | | 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). |
| 5651 | | % we could reify: Y>0 => Modulo <Y ? Is it worth it ? |
| 5652 | | % we could also use the CLP(FD) modulo operator X in 3..100, 1 #= X mod 20 infers X in 21..81 |
| 5653 | | % try_post_constraint((X#>=0 #/\ Y#>0) #=> Modulo #= X mod Y) |
| 5654 | | % 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.) |
| 5655 | | /* clpfd_modulo_prop(X,Y,Modulo,WF) :- clpfd_modulo_noclp(X,Y,Modulo,WF). |
| 5656 | | :- block clpfd_modulo_noclp(-,-,-,?). |
| 5657 | | clpfd_modulo_noclp(X,Y,Modulo,WF) :- print(mod(X,Y,Modulo,WF)),nl, |
| 5658 | | var(X),var(Modulo),number(Y),!, |
| 5659 | | Y1 is Y-1, |
| 5660 | | in_nat_range_wf(int(Modulo),int(0),int(Y1),WF). % problem: could enumerate lambda return variables !! |
| 5661 | | clpfd_modulo_noclp(_X,_Y,_Modulo,_WF). |
| 5662 | | */ |
| 5663 | | |
| 5664 | | |
| 5665 | | :- assert_must_succeed(exhaustive_kernel_check(unary_minus_wf(int(2),int(-2),_WF))). |
| 5666 | | :- assert_must_succeed(exhaustive_kernel_fail_check(unary_minus_wf(int(2),int(2),_WF))). |
| 5667 | | :- assert_must_succeed(( unary_minus2(A,B),A=7,B== -7 )). |
| 5668 | | :- assert_must_succeed(( unary_minus2(A,B),A= -7,B==7 )). |
| 5669 | | :- assert_must_succeed(( unary_minus2(B,A),A=7,B== -7 )). |
| 5670 | | :- assert_must_succeed(( unary_minus2(B,A),A= -7,B==7 )). |
| 5671 | | :- assert_must_fail(( unary_minus2(B,A),A= -7,B=6 )). |
| 5672 | | :- assert_must_fail(( unary_minus2(A,B),A= -7,B=6 )). |
| 5673 | | |
| 5674 | | unary_minus_wf(int(X),int(MX),_WF) :- |
| 5675 | | unary_minus2(X,MX), |
| 5676 | | (var(X),var(MX) -> clpfd_eq(MX,0 - X) % can have performance problems |
| 5677 | | ; true % we can compute the value without CLPFD |
| 5678 | | ). |
| 5679 | | :- block unary_minus2(-,-). |
| 5680 | | unary_minus2(X,MX) :- |
| 5681 | | ( ground(X) -> MX is -X |
| 5682 | | ; X is -MX). |
| 5683 | | |
| 5684 | | :- assert_must_succeed(first_of_pair((int(1),int(2)),int(1))). |
| 5685 | | :- assert_must_succeed(second_of_pair((int(1),int(2)),int(2))). |
| 5686 | | |
| 5687 | | first_of_pair((A,_B),R) :- equal_object(R,A,first_of_pair). |
| 5688 | | second_of_pair((_A,B),R) :- equal_object(R,B,second_of_pair). |
| 5689 | | |
| 5690 | | |
| 5691 | | :- assert_must_succeed(exhaustive_kernel_check(cartesian_product([int(2),int(4)],[int(3),int(1)], |
| 5692 | | [(int(2),int(1)),(int(2),int(3)),(int(4),int(3)),(int(4),int(1))]))). |
| 5693 | | :- assert_must_succeed(exhaustive_kernel_check(cartesian_product([],[int(3),int(1)],[]))). |
| 5694 | | :- assert_must_succeed(exhaustive_kernel_check(cartesian_product([int(3)],[],[]))). |
| 5695 | | :- assert_must_succeed(exhaustive_kernel_fail_check(cartesian_product([int(3)],[int(2)],[]))). |
| 5696 | | :- assert_must_succeed((cartesian_product(global_set('NAT'),[int(2)],_Res))). |
| 5697 | | :- assert_must_succeed((cartesian_product([int(1)],[int(2)],Res), |
| 5698 | | equal_object(Res,[(int(1),int(2))]))). |
| 5699 | | :- assert_must_succeed((cartesian_product([int(1)],[int(2)],[(int(1),int(2))]))). |
| 5700 | | :- assert_must_succeed((cartesian_product([],[int(1),int(2)],Res), |
| 5701 | | equal_object(Res,[]))). |
| 5702 | | :- assert_must_succeed((cartesian_product([int(1),int(2)],[],Res), |
| 5703 | | equal_object(Res,[]))). |
| 5704 | | :- assert_must_succeed((cartesian_product([int(1),int(2)],[int(2),int(3)],Res), |
| 5705 | | equal_object(Res,[(int(1),int(2)),(int(1),int(3)),(int(2),int(2)),(int(2),int(3))]))). |
| 5706 | | :- assert_must_succeed((cartesian_product([int(1)|T],[int(2)|T2],Res), |
| 5707 | | T = [int(2)], T2 = [int(3)], |
| 5708 | | equal_object(Res,[(int(1),int(2)),(int(1),int(3)),(int(2),int(2)),(int(2),int(3))]))). |
| 5709 | | :- assert_must_fail((cartesian_product([int(1)],[int(2),int(3)],Res),(Res=[_]; |
| 5710 | | equal_object(Res,[_,_,_|_])))). |
| 5711 | | |
| 5712 | | |
| 5713 | | cartesian_product(Set1,Set2,Res) :- cartesian_product_wf(Set1,Set2,Res,no_wf_available). |
| 5714 | | |
| 5715 | | :- block cartesian_product_wf(-,?,?,?), cartesian_product_wf(?,-,?,?). |
| 5716 | | cartesian_product_wf(Set1,Set2,Res,WF) :- |
| 5717 | | expand_custom_set_to_list_wf(Set1,ESet1,_,cartesian_product1,WF), |
| 5718 | | (ESet1==[] -> empty_set_wf(Res,WF) |
| 5719 | | ; expand_custom_set_to_list_wf(Set2,ESet2,_,cartesian_product2,WF), |
| 5720 | | (var(Res) |
| 5721 | | -> cartesian_product2(ESet1,ESet2,CRes,WF), |
| 5722 | | equal_object_optimized_wf(CRes,Res,cart_product,WF) |
| 5723 | | ; cartesian_product2(ESet1,ESet2,Res,WF)) |
| 5724 | | ). |
| 5725 | | |
| 5726 | | :- block cartesian_product2(-,?,?,?). |
| 5727 | | cartesian_product2([],_,Res,WF) :- empty_set_wf(Res,WF). |
| 5728 | | cartesian_product2([H|T],Set2,Res,WF) :- |
| 5729 | | cartesian_el_product(Set2,H,Res,InnerRes,WF), |
| 5730 | | cartesian_product2(T,Set2,InnerRes,WF). |
| 5731 | | |
| 5732 | | :- block cartesian_el_product(-,?,?,?,?). |
| 5733 | | cartesian_el_product([],_El,Res,InnerRes,WF) :- equal_object_optimized_wf(Res,InnerRes,cartesian_el_product_1,WF). |
| 5734 | | cartesian_el_product([H|T],El,ResSoFar,InnerRes,WF) :- |
| 5735 | | equal_object_wf(ResSoFar,[(El,H)|NewResSoFar],cartesian_el_product_2,WF), |
| 5736 | | cartesian_el_product(T,El,NewResSoFar,InnerRes,WF). |
| 5737 | | |
| 5738 | | |
| 5739 | | |
| 5740 | | :- assert_must_succeed(exhaustive_kernel_check(in_nat_range(int(2),int(2),int(3)))). |
| 5741 | | :- assert_must_succeed(exhaustive_kernel_check(in_nat_range_wf(int(2),int(2),int(3),_WF))). |
| 5742 | | :- assert_must_succeed(exhaustive_kernel_fail_check(in_nat_range_wf(int(2),int(3),int(2),_WF))). |
| 5743 | | :- assert_must_succeed((in_nat_range_wf(X,int(11),int(12),WF), |
| 5744 | | kernel_waitflags:ground_wait_flags(WF), X==int(12) )). |
| 5745 | | :- assert_must_fail((in_nat_range_wf(X,int(11),int(12),_WF), X=int(10) )). |
| 5746 | | :- assert_must_fail((in_nat_range_wf(X,int(11),int(12),_WF), X=int(13) )). |
| 5747 | | :- assert_must_succeed((in_nat_range_wf(X,int(11),int(12),_WF), X=int(11) )). |
| 5748 | | :- assert_must_fail((in_nat_range_wf(X,int(11),int(10),_WF), X=int(11) )). |
| 5749 | | :- assert_must_fail((in_nat_range_wf(X,int(11),int(10),_WF), X=int(10) )). |
| 5750 | | :- assert_must_fail((in_nat_range_wf(X,int(11),int(10),_WF), X=int(12) )). |
| 5751 | | |
| 5752 | | in_nat_range(int(X),int(Y),int(Z)) :- % does not enumerate, in contrast to in_nat_range_wf |
| 5753 | | clpfd_inrange(X,Y,Z,Posted), % better to call inrange rather than leq twice, avoids unecessary propagation |
| 5754 | | (Posted==true -> true |
| 5755 | | ; safe_less_than_equal(in_nat_range,Y,X), |
| 5756 | | safe_less_than_equal(in_nat_range,X,Z) |
| 5757 | | ). |
| 5758 | | in_nat_range_wf(int(X),int(Y),int(Z),WF) :- |
| 5759 | | clpfd_inrange(X,Y,Z,Posted), % better to call inrange rather than leq twice, avoids unecessary propagation |
| 5760 | | (Posted==true -> |
| 5761 | | % if the constraint was posted: we do not need to add safe_less_than_equal,...: |
| 5762 | | % if overflow happes whole computation will fail anyway |
| 5763 | | block_add_fd_variable_for_labeling(X,Y,Z,WF) % do we really need to do this ? maybe add just before enum finished ?, see also test 328 |
| 5764 | | ; safe_less_than_equal(in_nat_range_wf,Y,X), |
| 5765 | | safe_less_than_equal(in_nat_range_wf,X,Z), |
| 5766 | | (ground(X) -> true |
| 5767 | | ; get_int_domain(X,Y,Z,RL,RU),get_nat_range_prio(X,RL,RU,WF,LWF), |
| 5768 | ? | call_enumerate_int(X,RL,RU,LWF)) |
| 5769 | | ). |
| 5770 | | |
| 5771 | | :- block block_add_fd_variable_for_labeling(-,-,?,?), block_add_fd_variable_for_labeling(?,-,-,?). |
| 5772 | | block_add_fd_variable_for_labeling(X,_Y,_Z,_WF) :- nonvar(X),!. % no need to label it |
| 5773 | | block_add_fd_variable_for_labeling(X,_Y,_Z,WF) :- add_fd_variable_for_labeling(X,WF). |
| 5774 | | |
| 5775 | | :- block get_nat_range_prio(?,-,?,?,?), get_nat_range_prio(?,?,-,?,?). |
| 5776 | | get_nat_range_prio(_Variable,Y,Z,WF,LWF) :- Size is Z+1-Y, |
| 5777 | | (Size>1 -> |
| 5778 | | % we do not use add_fd_variable_for_labeling(Variable,Size,WF,LWF) % will use CLP(FD) labeling |
| 5779 | | % either clpfd is off or we had a time-out or overflow; so labeling may generate instantiation error |
| 5780 | | get_wait_flag(Size,get_nat_range_prio(Y,Z),WF,LWF) |
| 5781 | | ; LWF=Size /* Size=0 or 1 -> we can either fail or determine variable */). |
| 5782 | | |
| 5783 | | :- assert_must_succeed((kernel_objects:call_enumerate_int(X,1,2,g), X==2)). |
| 5784 | | :- block call_enumerate_int(-,?,?,-). |
| 5785 | | call_enumerate_int(X,RL,RU,_LWF) :- |
| 5786 | | (ground(X) -> true |
| 5787 | | ; % get_int_domain(X,RL,RU,RLL,RUU) : if clp(fd) active then CLP(FD) labeling is used anyway |
| 5788 | ? | enumerate_int(X,RL,RU)). |
| 5789 | | |
| 5790 | | |
| 5791 | | |
| 5792 | | |
| 5793 | | :- assert_must_succeed(exhaustive_kernel_check(not_in_nat_range(int(2),int(3),int(2)))). |
| 5794 | | :- assert_must_succeed(exhaustive_kernel_fail_check(not_in_nat_range(int(2),int(2),int(3)))). |
| 5795 | | :- assert_must_succeed((not_in_nat_range(X,int(11),int(12)), X=int(10) )). |
| 5796 | | :- assert_must_succeed((not_in_nat_range(X,int(11),int(12)), X=int(13) )). |
| 5797 | | :- assert_must_fail((not_in_nat_range(X,int(11),int(12)), X=int(11) )). |
| 5798 | | :- assert_must_succeed((not_in_nat_range(X,int(11),int(10)), X=int(11) )). |
| 5799 | | :- assert_must_succeed((not_in_nat_range(X,int(11),int(10)), X=int(10) )). |
| 5800 | | :- assert_must_succeed((not_in_nat_range(X,int(11),int(10)), X=int(12) )). |
| 5801 | | |
| 5802 | ? | not_in_nat_range_wf(X,Y,Z,_WF) :- not_in_nat_range(X,Y,Z). |
| 5803 | | not_in_nat_range(int(X),int(Y),int(Z)) :- |
| 5804 | | (number(Y),number(Z) |
| 5805 | ? | -> (Z>=Y -> clpfd_not_in_non_empty_range(X,Y,Z) ; true /* interval empty */) |
| 5806 | | ; clpfd_not_inrange(X,Y,Z) |
| 5807 | | ). |
| 5808 | | |
| 5809 | | |
| 5810 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(1),int(0),int(10),pred_true,WF),WF)). |
| 5811 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(10),int(10),int(10),pred_true,WF),WF)). |
| 5812 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(1),int(1),int(10),pred_true,WF),WF)). |
| 5813 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(10),int(0),int(10),pred_true,WF),WF)). |
| 5814 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(11),int(10),int(9),pred_false,WF),WF)). |
| 5815 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(11),int(13),int(12),pred_false,WF),WF)). |
| 5816 | | :- assert_must_succeed(exhaustive_kernel_check_wf(test_in_nat_range_wf(int(11),int(13),int(15),pred_false,WF),WF)). |
| 5817 | | |
| 5818 | | % reified version |
| 5819 | | :- block test_in_nat_range_wf(-,-,?,-,?), test_in_nat_range_wf(-,?,-,-,?), test_in_nat_range_wf(?,-,-,-,?). |
| 5820 | | test_in_nat_range_wf(X,Y,Z,PredRes,WF) :- PredRes==pred_true,!, |
| 5821 | | in_nat_range_wf(X,Y,Z,WF). |
| 5822 | | test_in_nat_range_wf(X,Y,Z,PredRes,WF) :- PredRes==pred_false,!, |
| 5823 | ? | not_in_nat_range_wf(X,Y,Z,WF). |
| 5824 | | test_in_nat_range_wf(int(X),int(Low),int(Up),PredRes,WF) :- |
| 5825 | | clpfd_interface:post_constraint2(C1 #<=> (X #>= Low #/\ X #=< Up #/\ Low #=< Up),Posted1), |
| 5826 | | (Posted1 == true -> prop_01(C1,PredRes) ; test_in_nat_range_no_clpfd(X,Low,Up,PredRes,WF)). |
| 5827 | | |
| 5828 | | % Note: A #<=> (X #>= Low #/\ X#=< Up #/\ Low #=< Up), Low in 11..15, Up in 7..8. -> CLPFD infers A=0 |
| 5829 | | % without the redundant Low #=< Up it does not infer it ! |
| 5830 | | :- block prop_01(-,-). |
| 5831 | | prop_01(0,pred_false). |
| 5832 | | prop_01(1,pred_true). |
| 5833 | | |
| 5834 | | :- block test_in_nat_range_no_clpfd(-,?,?,-,?), test_in_nat_range_no_clpfd(?,-,?,-,?), |
| 5835 | | test_in_nat_range_no_clpfd(?,?,-,-,?). |
| 5836 | | test_in_nat_range_no_clpfd(X,Y,Z,PredRes,WF) :- PredRes==pred_true,!, |
| 5837 | | in_nat_range_wf(int(X),int(Y),int(Z),WF). |
| 5838 | | test_in_nat_range_no_clpfd(X,Y,Z,PredRes,WF) :- PredRes==pred_false,!, |
| 5839 | | not_in_nat_range_wf(int(X),int(Y),int(Z),WF). |
| 5840 | | test_in_nat_range_no_clpfd(X,Y,Z,PredRes,_WF) :- % X,Y,Z must be ground integers |
| 5841 | | (X >= Y, X =< Z, Y =< Z -> PredRes=pred_true ; PredRes=pred_false). |
| 5842 | | |
| 5843 | | :- assert_must_succeed(exhaustive_kernel_check_wf(square(int(3),int(9),WF),WF)). |
| 5844 | | % is now only called when CLPFD is FALSE |
| 5845 | | square(int(X),int(Sqr),WF) :- |
| 5846 | | int_square(X,Sqr,WF), |
| 5847 | | (var(X) -> clpfd_eq(Sqr,X * X) |
| 5848 | | ; true). % we can compute the value directly |
| 5849 | | |
| 5850 | | :- block int_square(-,-,?). |
| 5851 | | int_square(X,Sqr,_) :- ground(X),!, Sqr is X*X. |
| 5852 | | int_square(X,Sqr,WF) :- get_binary_choice_wait_flag(int_square,WF,WF2), int_square2(X,Sqr,WF2). |
| 5853 | | :- block int_square2(-,?,-). |
| 5854 | | int_square2(X,Sqr,_) :- ground(X),!, Sqr is X*X. |
| 5855 | | int_square2(X,Sqr,_WF2) :- |
| 5856 | | integer_square_root(Sqr,X). |
| 5857 | | |
| 5858 | | :- assert_must_succeed(( kernel_objects:integer_square_root(0,X),X==0 )). |
| 5859 | | :- assert_must_succeed(( kernel_objects:integer_square_root(1,X),X==1 )). |
| 5860 | | :- assert_must_succeed(( kernel_objects:integer_square_root(4,X),X==2 )). |
| 5861 | | :- assert_must_succeed(( kernel_objects:integer_square_root(49,X),X==7 )). |
| 5862 | | :- assert_must_succeed(( kernel_objects:integer_square_root(49,X),X==(-7) )). |
| 5863 | | :- assert_must_fail(( kernel_objects:integer_square_root(5,_) )). |
| 5864 | | :- assert_must_succeed(( X= 123456789, Y is X*X, kernel_objects:integer_square_root(Y,Z),Z==X)). |
| 5865 | | :- assert_must_fail(( X= 123456789, Y is 1+X*X, kernel_objects:integer_square_root(Y,_Z))). |
| 5866 | | :- assert_must_succeed(( X= 12345678900, Y is X*X, kernel_objects:integer_square_root(Y,Z),Z==X)). |
| 5867 | | |
| 5868 | | integer_square_root(0,Root) :- !, Root = 0. |
| 5869 | | :- if(current_prolog_flag(dialect, swi)). |
| 5870 | | % SWI's behavior when converting bigint to float is suboptimal - |
| 5871 | | % the value is always truncated toward zero instead of rounded to the nearest value, |
| 5872 | | % which introduces slight inaccuracies that don't happen on SICStus. |
| 5873 | | % See: https://github.com/SWI-Prolog/swipl-devel/issues/545 |
| 5874 | | % As a workaround, use CLP(FD) to calculate integer square roots. |
| 5875 | | % On SWI, CLP(FD) works with unlimited size integers and can calculate exact integer n-th roots. |
| 5876 | | :- use_module(library(clpfd), [(#=)/2, (#>)/2, (#=<)/2]). |
| 5877 | | integer_square_root(Sqr,Root) :- |
| 5878 | | Root*Root #= Sqr, |
| 5879 | | (Root #> 0 ; Root #=< 0). |
| 5880 | | :- else. |
| 5881 | | integer_square_root(Sqr,PMRoot) :- |
| 5882 | | Sqr>0, Root is truncate(sqrt(Sqr)), Sqr is Root*Root, |
| 5883 | | (PMRoot = Root ; PMRoot is -(Root)). |
| 5884 | | :- endif. |
| 5885 | | |
| 5886 | | % integer multiplication |
| 5887 | | times(int(X),int(Y),int(Times)) :- |
| 5888 | | int_times2(X,Y,Times), |
| 5889 | ? | (two_vars_or_more(X,Y,Times) -> clpfd_eq(Times,X * Y) % can have performance problems. |
| 5890 | | ; true). % we can compute the value directly |
| 5891 | | |
| 5892 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],times(int(2),int(3),int(6)))). |
| 5893 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],times(int(2),int(1),int(2)))). |
| 5894 | | :- assert_must_succeed(exhaustive_kernel_check([commutative],times(int(2),int(0),int(0)))). |
| 5895 | | :- assert_must_succeed(exhaustive_kernel_check(times(int(0),int(1),int(0)))). |
| 5896 | | :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],times(int(2),int(3),int(5)))). |
| 5897 | | :- assert_must_succeed(exhaustive_kernel_fail_check([commutative],times(int(1),int(3),int(2)))). |
| 5898 | | :- assert_must_succeed(( int_times2(A,B,C),A=3,B=2,C==6 )). |
| 5899 | | :- assert_must_succeed(( int_times2(A,B,C),A=3,C=6,B==2 )). |
| 5900 | | :- assert_must_succeed(( int_times2(A,B,C),B=2,A=3,C==6 )). |
| 5901 | | :- assert_must_succeed(( int_times2(A,B,C),B=2,C=6,A==3 )). |
| 5902 | | :- assert_must_succeed(( int_times2(A,B,C),C=6,A=3,B==2 )). |
| 5903 | | :- assert_must_succeed(( int_times2(A,B,C),C=6,B=2,A==3 )). |
| 5904 | | :- assert_must_succeed(( int_times2(A,_,C),A=0,C==0 )). |
| 5905 | | :- assert_must_succeed(( int_times2(_,B,C),B=0,C==0 )). |
| 5906 | | :- assert_must_succeed(( int_times2(A,B,C),A=1,B==C )). |
| 5907 | | :- assert_must_succeed(( int_times2(A,B,C),B=1,A==C )). |
| 5908 | | :- assert_must_succeed(( int_times2(A,1,C),A=2,C==2 )). |
| 5909 | | :- assert_must_succeed(( int_times2(_A,0,C),C==0 )). |
| 5910 | | :- assert_must_succeed(( int_times2(A,_,C),C=0,A=0 )). |
| 5911 | | :- assert_must_succeed(( int_times2(_,B,C),C=0,B=0 )). |
| 5912 | | :- assert_must_succeed(( int_times2(A,B,0),A=0,B=2 )). |
| 5913 | | :- assert_must_succeed(( int_times2(A,B,0),B=2,A=0 )). |
| 5914 | | :- assert_must_succeed(( int_times2(B,A,0),A=0,B=2 )). |
| 5915 | | :- assert_must_succeed(( int_times2(B,A,0),B=2,A=0 )). |
| 5916 | | :- assert_must_fail(( int_times2(A,_,C),A=3,C=7 )). |
| 5917 | | :- assert_must_fail(( int_times2(A,_,C),C=7,A=3 )). |
| 5918 | | :- assert_must_fail(( int_times2(_,B,C),B=2,C=7 )). |
| 5919 | | :- assert_must_fail(( int_times2(_,B,C),C=7,B=2 )). |
| 5920 | | :- assert_must_fail(( int_times2(A,_,C),C=7,A=0 )). |
| 5921 | | :- assert_must_fail(( int_times2(_,B,C),C=7,B=0 )). |
| 5922 | | :- assert_must_fail(( int_times2(B,A,0),B=2,A=1 )). |
| 5923 | | |
| 5924 | | :- block int_times2(-,-,-). |
| 5925 | | int_times2(X,Y,Times) :- |
| 5926 | | ( ground(X) -> |
| 5927 | | ( X==1 -> Y=Times |
| 5928 | | ; X==0 -> Times=0 |
| 5929 | | ; int_times3(X,Y,Times)) |
| 5930 | | ; ground(Y) -> |
| 5931 | | ( Y==1 -> X=Times |
| 5932 | | ; Y==0 -> Times=0 |
| 5933 | | ; int_times3(Y,X,Times)) |
| 5934 | | ; int_times4(X,Y,Times)). |
| 5935 | | % int_times3/3: First argument must be ground when called and non-zero |
| 5936 | | :- block int_times3(?,-,-). |
| 5937 | | int_times3(X,Y,Times) :- |
| 5938 | | ( ground(Y) -> Times is X*Y |
| 5939 | | ; Y is Times // X, Times is X*Y). |
| 5940 | | % int_times4/3: Third argument must be ground when called |
| 5941 | | :- block int_times4(-,-,?). |
| 5942 | | int_times4(X,Y,Times) :- |
| 5943 | | ( Times==0 -> |
| 5944 | | ( ground(X) -> (X==0 -> true; Y=0 ) |
| 5945 | | ; /* ground(Y) -> */ (Y==0 -> true; X=0 )) |
| 5946 | | ; /* Times /== 0 */ |
| 5947 | | ( ground(X) -> X\==0, Y is Times // X, Times is X*Y |
| 5948 | | ; /* ground(Y) -> */ Y\==0, X is Times // Y, Times is X*Y)). |
| 5949 | | |
| 5950 | | |
| 5951 | | :- assert_must_succeed(exhaustive_kernel_check(int_power(int(2),int(3),int(8),unknown,_))). |
| 5952 | | :- assert_must_succeed(exhaustive_kernel_check(int_power(int(2),int(1),int(2),unknown,_))). |
| 5953 | | :- assert_must_succeed(exhaustive_kernel_check(int_power(int(3),int(0),int(1),unknown,_))). |
| 5954 | | :- assert_must_succeed(exhaustive_kernel_check(int_power(int(1),int(3),int(1),unknown,_))). |
| 5955 | | :- assert_must_succeed(exhaustive_kernel_check(int_power(int(0),int(3),int(0),unknown,_))). |
| 5956 | | :- assert_must_succeed(exhaustive_kernel_check(int_power(int(0),int(0),int(1),unknown,_))). |
| 5957 | | :- assert_must_succeed(exhaustive_kernel_fail_check(int_power(int(2),int(3),int(6),unknown,_))). |
| 5958 | | :- assert_must_succeed(exhaustive_kernel_fail_check(int_power(int(0),int(0),int(0),unknown,_))). |
| 5959 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=2,B=5,C==32 )). |
| 5960 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A= -2,B=5,C== -32 )). |
| 5961 | | %:- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=1,B= -5,C==1 )). % now aborts ! |
| 5962 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=1,C=1, B= -5 )). |
| 5963 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=1,C= 1,B = -5 )). |
| 5964 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=2,C=32,B==5 )). |
| 5965 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=10,C=1000,B==3 )). |
| 5966 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A= -2,C= -32,B==5 )). |
| 5967 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A= -2,C= 16,B==4 )). |
| 5968 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=2,C=1,B==0 )). |
| 5969 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,B=2,C==0 )). |
| 5970 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,C=0,B=2 )). |
| 5971 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,B=0,C==1 )). |
| 5972 | | :- assert_must_succeed(( int_power2(A,B,C,unknown,_),A=0,C=1,B==0 )). |
| 5973 | | :- assert_must_succeed(( int_power2(17,13,C,unknown,_),C==9904578032905937 )). |
| 5974 | | :- assert_must_succeed((platform_is_64_bit |
| 5975 | | -> int_power2(A,13,C,unknown,_),C=9904578032905937,A=17 |
| 5976 | | ; int_power2(A,9,C,unknown,_),C=134217728,A=8 )). |
| 5977 | | :- assert_must_fail((platform_is_64_bit |
| 5978 | | -> int_power2(A,13,C,unknown,_),C=9904578032905936,A=17 |
| 5979 | | ; int_power2(A,9,C,unknown,_),C=134217727,A=8 )). |
| 5980 | | :- assert_must_succeed((platform_is_64_bit |
| 5981 | | -> int_power2(A,10,C,unknown,_),C=576650390625,A=15 |
| 5982 | | ; true)). |
| 5983 | | :- assert_must_fail((platform_is_64_bit |
| 5984 | | -> int_power2(A,10,C,unknown,_),C=576650390626,A=15 |
| 5985 | | ; false)). |
| 5986 | | :- assert_must_succeed(( int_power2(A,100,C,unknown,_),A=2,C==1267650600228229401496703205376 )). |
| 5987 | | :- assert_must_fail(( int_power2(A,100,C,unknown,_),C=1267650600228229401496703205375,A=2 )). |
| 5988 | | :- assert_must_fail(( int_power2(A,100,C,unknown,_),C=1267650600228229401496703205377,A=2 )). |
| 5989 | | |
| 5990 | | :- assert_must_fail(( int_power2(A,B,C,unknown,_),A=2,B=5,C=33 )). |
| 5991 | | :- assert_must_abort_wf(( int_power2(A,B,_,unknown,WF),A=2,B= -5 ),WF). |
| 5992 | | :- assert_must_fail(( int_power2(A,_,C,unknown,_),A= -2,C=32 )). |
| 5993 | | :- assert_must_fail(( int_power2(A,_,C,unknown,_),A= -2,C= -16 )). |
| 5994 | | % Note: 0**0=1 (see SIMP_SPECIAL_EXPN_0 in https://wiki.event-b.org/index.php/All_Rewrite_Rules) |
| 5995 | | % TODO: in TLA+ it is undefined (TLC says 0^0 is undefined.) |
| 5996 | | |
| 5997 | | :- use_module(specfile,[eventb_mode/0]). |
| 5998 | | % TODO: calculate X from Y und Pow (i.e., Yth root of Pow); in CLPFD mode this is more or less done |
| 5999 | | int_power(int(X),int(Y),int(Pow),Span,WF) :- % power_of AST node |
| 6000 | | ( preferences:preference(use_clpfd_solver,true) |
| 6001 | | -> int_power2(X,Y,Pow,Span,WF), int_power_clpfd_propagation(X,Y,Pow) |
| 6002 | | ; int_power1(X,Y,Pow,Span,WF)). |
| 6003 | | % TO DO ?: if all are variables we can still infer some knowledge |
| 6004 | | % e.g. if X is positive then Pow must be positive; but it is probably quite rare that we have models with unknown exponent ? |
| 6005 | | :- block int_power1(-,?,?,?,?). % ensure that Base X is known if CLPFD off |
| 6006 | | int_power1(X,Y,Pow,Span,WF) :- |
| 6007 | | int_power2(X,Y,Pow,Span,WF). |
| 6008 | | :- block int_power2(-,-,?,?,?), int_power2(?,-,-,?,?). % we know Y or both X&Pow |
| 6009 | | int_power2(X,Y,Pow,Span,WF) :- |
| 6010 | | ( ground(Y) -> |
| 6011 | | ( Y>=0 -> (integer(X) -> safe_int_power0(X,Y,PowXY,Span,WF), |
| 6012 | | clpfd_nr_eq(PowXY,Pow) % try and prevent overflow if PowXY is large |
| 6013 | | ; safe_int_power0(X,Y,Pow,Span,WF)) |
| 6014 | | ; add_wd_error_set_result('power with negative exponent','**'(X,Y),Pow,1,Span,WF)) |
| 6015 | | ; /* X & POW are ground */ |
| 6016 | | ( X==1 -> Pow==1 /* 1**Y = 1 */ |
| 6017 | | ; X==0, Pow==1 -> Y=0 |
| 6018 | | ; X==0 -> (Pow==1 -> Y=1 /* 0**0=1 */ ; Pow==0 -> integer_dif(Y,0)) |
| 6019 | | ; X>0, Pow>0 -> |
| 6020 | | checked_precise_log(X,Y,Pow,Span,WF) |
| 6021 | | % TO DO: X<0 should raise WD error for Event-B ? |
| 6022 | | ; X<0, eventb_mode -> add_wd_error_set_result('power with negative base','^'(X,Y),Pow,1,Span,WF) |
| 6023 | | ; X<0, Pow<0 -> |
| 6024 | | PosPow is -(Pow), |
| 6025 | | NegX is -(X), |
| 6026 | | checked_precise_log(NegX,Y,PosPow,Span,WF), |
| 6027 | | odd(Y) |
| 6028 | | ; X<0, Pow>0 -> |
| 6029 | | NegX is -(X), |
| 6030 | | checked_precise_log(NegX,Y,Pow,Span,WF), |
| 6031 | | even(Y))). |
| 6032 | | |
| 6033 | | :- assert_must_succeed(( integer_log(3,59049,Log),Log==10 )). |
| 6034 | | :- assert_must_succeed(( integer_log(2,1024,Log),Log==10 )). |
| 6035 | | :- assert_must_succeed(( integer_log(4,1024,Log),Log==5 )). |
| 6036 | | :- assert_must_succeed(( integer_log(10,1,Log),Log==0 )). |
| 6037 | | :- assert_must_succeed(( integer_log(10,2,Log),Log==0 )). |
| 6038 | | :- assert_must_succeed(( integer_log(10,10,Log),Log==1 )). |
| 6039 | | :- assert_must_succeed(( integer_log(10,11,Log),Log==1 )). |
| 6040 | | :- assert_must_succeed(( integer_log(10,1000,Log),Log==3 )). |
| 6041 | | :- use_module(tools_portability, [check_arithmetic_function/1]). |
| 6042 | | integer_log(Base,Power,_Exp) :- (Base =< 0 ; Power =< 0), !, |
| 6043 | | add_error_and_fail(integer_log,'Logarithm only defined for positive values: ',log(Base,Power)). |
| 6044 | | :- if(check_arithmetic_function(log(2, 4))). |
| 6045 | | % Native log(Base, Power) function is available - use it. is available in SICStus |
| 6046 | | integer_log(Base, Power, Exp) :- ApproximateExp is truncate(log(Base, Power)), |
| 6047 | | % it is precise for power of 2 it seems, but not for 3 |
| 6048 | | % | ?- X is log(3,59049). X = 9.999999999999998 ? -> truncate gives 9, correct value is 10 |
| 6049 | | correct_integer_log_approximation(Base,Power,ApproximateExp,_,Exp). |
| 6050 | | :- else. |
| 6051 | | % No native log(Base, Power) support, so construct it using natural logarithms. |
| 6052 | | integer_log(Base, Power, Exp) :- ApproximateExp is truncate(log(Power) / log(Base)), |
| 6053 | | correct_integer_log_approximation(Base,Power,ApproximateExp,_,Exp). |
| 6054 | | :- endif. |
| 6055 | | |
| 6056 | | correct_integer_log_approximation(Base,Power,Exp,Correction,Res) :- |
| 6057 | | BE is Base ^ Exp, |
| 6058 | | (Correction=decreasing, BE > Power % not sure this case will ever trigger |
| 6059 | | -> Exp1 is Exp-1, %write(dec(Base,Bower,Exp1)),nl, |
| 6060 | | correct_integer_log_approximation(Base,Power,Exp1,Correction,Res) |
| 6061 | | ; Correction=increasing, BE*Base =< Power |
| 6062 | | -> Exp1 is Exp+1, %write(inc(Base,Bower,Exp1)),nl, |
| 6063 | | correct_integer_log_approximation(Base,Power,Exp1,Correction,Res) |
| 6064 | | ; Res=Exp). |
| 6065 | | |
| 6066 | | % TO DO for checked_precise_log: we should take pre-cautions with try_find_abort |
| 6067 | | % 2**x + y = 1024 & y:0..100 -> will give x=10, y=0 but not give rise to possible WD error |
| 6068 | | checked_precise_log(1,Exp,Pow,_,_) :- !, % the SICStus Prolog log function does not work for Base=1 |
| 6069 | | Pow=1, less_than_equal_direct(0,Exp). |
| 6070 | | checked_precise_log(Base,Exp,Pow,Span,WF) :- |
| 6071 | | integer_log(Base,Pow,Exp), |
| 6072 | | safe_int_power(Base,Exp,Pow,Span,WF). % we have the perfect solution |
| 6073 | | % ; Exp is Try+1, write(inc(Base,Pow,Try)),nl, safe_int_power(Base,Exp,Pow,Span,WF) ,write(pow(Base,Exp,Pow)),nl). |
| 6074 | | |
| 6075 | | :- block even(-). |
| 6076 | | even(X) :- 0 is X mod 2. |
| 6077 | | :- block odd(-). |
| 6078 | | odd(X) :- 1 is X mod 2. |
| 6079 | | |
| 6080 | | % propagation rules if only one of the args known |
| 6081 | | :- block int_power_clpfd_propagation(-,-,-). |
| 6082 | | int_power_clpfd_propagation(Base,Exp,Pow) :- Exp==0, var(Base),var(Pow),!, % B**0 = 1 |
| 6083 | | Pow = 1. |
| 6084 | | int_power_clpfd_propagation(Base,Exp,Pow) :- Exp==1, var(Base),var(Pow),!, % B**1 = B |
| 6085 | | Pow = Base. |
| 6086 | | int_power_clpfd_propagation(Base,Exp,Pow) :- Base==1, var(Exp),var(Pow),!, % 1**E = 1 |
| 6087 | | Pow = Base. |
| 6088 | | int_power_clpfd_propagation(Base,Exp,Pow) :- Base==0, var(Exp),var(Pow),!, % 0**E = 0 if E>0 |
| 6089 | | (fd_min(Exp,MinExp), number(MinExp), MinExp>0 -> Pow=0 |
| 6090 | | ; true). % case Exp=0 is treated in int_power itself |
| 6091 | | %int_power_clpfd_propagation(Base,Exp,Pow) :- number(Base), Base>0,var(Exp),var(Pow),!, |
| 6092 | | % clpfd_leq(1,Pow,_). % causes problem with test 305 |
| 6093 | | int_power_clpfd_propagation(X,Y,Pow) :- |
| 6094 | | fd_min(X,MinX), number(MinX), MinX>0, |
| 6095 | | fd_min(Y,MinY), number(MinY), MinY>0, % ensures no WD problem possible |
| 6096 | | MinPow is MinX^MinY, |
| 6097 | | \+ integer_too_large_for_clpfd(MinPow), |
| 6098 | | fd_max(X,MaxX), number(MaxX), |
| 6099 | | fd_max(Y,MaxY), number(MaxY), |
| 6100 | | MaxPow is MaxX^MaxY, |
| 6101 | | \+ integer_too_large_for_clpfd(MaxPow), |
| 6102 | | % only do propagation if we are sure not to produce a CLPFD overflow |
| 6103 | | !, |
| 6104 | | clpfd_inrange(Pow,MinPow,MaxPow), |
| 6105 | | (number(X), fd_max(Pow,MaxPow2), number(MaxPow2), get_new_upper_bound(X,MaxPow2,NewMaxExp,NewMaxPow) |
| 6106 | | -> clpfd_leq(Pow,NewMaxPow,_), |
| 6107 | | clpfd_leq(Y,NewMaxExp,_) |
| 6108 | | ; true), |
| 6109 | | (number(X), fd_min(Pow,MinPow2), number(MinPow2), get_new_lower_bound(X,MinPow2,NewMinExp,NewMinPow) |
| 6110 | | -> clpfd_leq(NewMinPow,Pow,_), |
| 6111 | | clpfd_leq(NewMinExp,Y,_) |
| 6112 | | ; true), |
| 6113 | | true. |
| 6114 | | %result of this propagation: x = 3**y & y:3..5 & x /= 27 & x /= 243 -> deterministically forces x=81, y=4 |
| 6115 | | int_power_clpfd_propagation(Base,Exp,Pow) :- number(Base), Base>1, var(Exp), var(Pow), |
| 6116 | | fd_max(Pow,MaxPow), number(MaxPow),!, |
| 6117 | | (MaxPow =< 0 -> fail % Base^Exp will always be strictly positive |
| 6118 | | ; integer_log(Base,MaxPow,Log) |
| 6119 | | -> clpfd_leq(Exp,Log,_) |
| 6120 | | ; add_internal_error('Failed:',integer_log(Base,MaxPow,_)), |
| 6121 | | clpfd_lt(Exp,MaxPow,_Posted)). |
| 6122 | | int_power_clpfd_propagation(_,_,_). |
| 6123 | | % 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 |
| 6124 | | |
| 6125 | | :- assert_must_succeed((kernel_objects:get_new_lower_bound(2,3,E,P),E==2,P==4)). |
| 6126 | | :- assert_must_succeed((kernel_objects:get_new_lower_bound(2,11,E,P),E==4,P==16)). |
| 6127 | | :- assert_must_fail((kernel_objects:get_new_lower_bound(2,16,_,_))). |
| 6128 | | % given Base and Power, determine if Power is a proper power of Exp, if not determine the next possible power of Base |
| 6129 | | get_new_lower_bound(Base,Power,MinExp,MinPower) :- Base > 1, Power> 0, |
| 6130 | | integer_log(Base,Power,Exp), |
| 6131 | | BE is Base^Exp, |
| 6132 | | BE < Power, |
| 6133 | | MinPower is Base*BE, |
| 6134 | | MinPower>Power, |
| 6135 | | MinPower < 1125899906842624, % 2^50 \+ integer_too_large_for_clpfd(MinPower), |
| 6136 | | MinExp is Exp+1. |
| 6137 | | :- assert_must_succeed((kernel_objects:get_new_upper_bound(2,3,E,P),E==1,P==2)). |
| 6138 | | :- assert_must_succeed((kernel_objects:get_new_upper_bound(2,11,E,P),E==3,P==8)). |
| 6139 | | :- assert_must_fail((kernel_objects:get_new_upper_bound(2,16,_,_))). |
| 6140 | | get_new_upper_bound(Base,Power,MaxExp,MaxPower) :- Base > 1, Power> 0, |
| 6141 | | integer_log(Base,Power,MaxExp), |
| 6142 | | MaxPower is Base^MaxExp, |
| 6143 | | MaxPower < Power, |
| 6144 | | \+ integer_too_large_for_clpfd(MaxPower), |
| 6145 | | MaxPower*Base > Power. |
| 6146 | | |
| 6147 | | % safe exponentiation using the squaring algorithm (CLPFD supports exponentiation only for SICStus 4.9 or later) |
| 6148 | | % Note: in TLA mode 0^0 is undefined according to TLC; for B/Rodin it is 1 |
| 6149 | | safe_int_power0(Base,Exp,Result,Span,WF) :- var(Base), |
| 6150 | | 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 |
| 6151 | | % 3**38 generates overflow; 4**30 generates overflow on 64-bit systems |
| 6152 | | % To do: examine whether we should already delay with a smaller or larger exponent |
| 6153 | | when(nonvar(Base),safe_int_power(Base,Exp,Result,Span,WF)). % wait until Base is known to avoid CLPFD overflow |
| 6154 | | safe_int_power0(Base,Exp,Result,Span,WF) :- safe_int_power(Base,Exp,Result,Span,WF). |
| 6155 | | |
| 6156 | | :- assert_must_succeed(( safe_int_power(0,0,P,unknown,_),P==1 )). |
| 6157 | | safe_int_power(Base,Exp,Result,Span,WF) :- number(Base), Base<0, eventb_mode,!, |
| 6158 | | add_wd_error_set_result('power with negative base','^'(Base,Exp),Result,1,Span,WF). |
| 6159 | | safe_int_power(_Base,0,Result,_,_WF) :- !, Result = 1. |
| 6160 | | safe_int_power(Base,Exp,Result,_,_) :- number(Base),!, |
| 6161 | | Result is Base^Exp. % new integer exponentiation operator in SICStus 4.3, Note: X is 0^0. -> X=1 |
| 6162 | | safe_int_power(Base,Exp,Result,_,_) :- |
| 6163 | | Msb is msb(Exp), % most significant bit |
| 6164 | | ExpMask is 1<<Msb, |
| 6165 | | safe_int_power_clpfd2(ExpMask,Exp,Base,1,Result). |
| 6166 | | |
| 6167 | | :- use_module(clpfd_interface,[clpfd_eq_expr/2]). |
| 6168 | | safe_int_power_clpfd2(0,_,_,Prev,Result) :- !, Prev=Result. |
| 6169 | | safe_int_power_clpfd2(Mask,Exp,Base,Prev,Result) :- |
| 6170 | | P is Exp /\ Mask, % P is Exp's highest bit |
| 6171 | | Mask2 is Mask>>1, |
| 6172 | | clpfd_eq_expr(Quad,Prev*Prev), |
| 6173 | | ( P==0 -> Next = Quad |
| 6174 | | ; clpfd_eq_expr(Next,Quad*Base) ), |
| 6175 | | safe_int_power_clpfd2(Mask2,Exp,Base,Next,Result). |
| 6176 | | %% ------------------------------------------------------- |
| 6177 | | |
| 6178 | | :- assert_must_succeed(( singleton_set_element([int(1)],E,unknown,_WF), E==int(1) )). |
| 6179 | | :- assert_must_succeed(( singleton_set_element([int(X)],int(1),unknown,_WF), X==1 )). |
| 6180 | | :- assert_must_fail(singleton_set_element([int(1)],int(2),unknown,_WF) ). |
| 6181 | | :- assert_must_abort_wf(kernel_objects:singleton_set_element([int(1),int(2)],_E,unknown,WF),WF). |
| 6182 | | % This predicate computes the effect of the MU operator. |
| 6183 | | % Set should be a singleton set and Elem its only element. |
| 6184 | | % In case Set is empty or has more than one element, an error |
| 6185 | | % message is generated. |
| 6186 | | :- block singleton_set_element(-,?,?,?). |
| 6187 | | singleton_set_element([],_,Span,WF) :- !, |
| 6188 | | add_wd_error_span('argument of MU expression must have cardinality 1, but is empty ', '', Span,WF). |
| 6189 | | singleton_set_element([H|T],Elem,Span,WF) :- !, |
| 6190 | | empty_set_test_wf(T,Empty,WF), |
| 6191 | | when(nonvar(Empty), |
| 6192 | | (Empty=pred_true -> equal_object_wf(Elem,H,singleton_set_element,WF) |
| 6193 | | ; add_wd_error_span('argument of MU expression has more than one element ', |
| 6194 | | b(value([H|T]),set(any),[]), Span,WF))). |
| 6195 | | singleton_set_element(avl_set(A),Elem,Span,WF) :- !, |
| 6196 | | (is_one_element_avl(A,AEl) -> equal_object_wf(Elem,AEl,singleton_set_element,WF) |
| 6197 | | ; add_wd_error_span('argument of MU expression has more than one element ', |
| 6198 | | b(value(avl_set(A)),set(any),[]), Span,WF)). |
| 6199 | | singleton_set_element(Set,Elem,Span,WF) :- |
| 6200 | | cardinality_as_int_wf(Set,Card,WF), % we have a comprehension set; could return inf ! |
| 6201 | | singleton_set_element1(Card,Set,Elem,Span,WF). |
| 6202 | | :- block singleton_set_element1(-,?,?,?,?). |
| 6203 | | singleton_set_element1(int(Card),Set,Elem,Span,WF) :- !, |
| 6204 | | % we could check if fd_dom of Card is set up and call equality_objects_lwf(Card,int(1),IsSingleton,LWF,WF) if it is |
| 6205 | | singleton_set_element2(Card,Set,Elem,Span,WF). |
| 6206 | | singleton_set_element1(XX,_Set,_Elem,Span,WF) :- |
| 6207 | | add_wd_error_span('argument of MU expression must have cardinality 1, but has ', XX, Span,WF). |
| 6208 | | |
| 6209 | | :- block singleton_set_element2(-,?,?,?,?). |
| 6210 | | singleton_set_element2(1,Set,Elem,_Span,_WF) :- !, |
| 6211 | | exact_element_of(Elem,Set). |
| 6212 | | singleton_set_element2(Card,_Set,_Elem,Span,WF) :- |
| 6213 | | add_wd_error_span('argument of MU expression must have cardinality 1, but has ', Card, Span,WF). |
| 6214 | | |
| 6215 | | :- assert_must_succeed(( singleton_set_element_wd([int(1)],E,unknown,_WF), E==int(1) )). |
| 6216 | | :- assert_must_succeed(( singleton_set_element_wd([int(X)],int(1),unknown,_WF), X==1 )). |
| 6217 | | %:- assert_must_succeed(( singleton_set_element_wd([int(X)|T],int(1),unknown,_WF), X==1, T==[] )). |
| 6218 | | :- assert_must_fail(singleton_set_element_wd([int(1)],int(2),unknown,_WF) ). |
| 6219 | | % MU_WD: a version of singleton_set_element which propagates more strongly from result to input |
| 6220 | | % and thus may not raise WD errors in this case |
| 6221 | | :- block singleton_set_element_wd(-,-,?,?). |
| 6222 | | singleton_set_element_wd(Set,Elem,Span,WF) :- nonvar(Set),!, % TODO: first check if Elem is ground |
| 6223 | | singleton_set_element(Set,Elem,Span,WF). |
| 6224 | | singleton_set_element_wd(Set,Elem,_,WF) :- % TODO: only propagate if fully known? |
| 6225 | | %(debug_mode(on) -> add_message_wf('MU_WD','MU_WD result instantiated: ',Elem,Span,WF) ; true), |
| 6226 | | equal_object_wf(Set,[Elem],singleton_set_element_wd,WF). |
| 6227 | | |
| 6228 | | |
| 6229 | | %:- print(finished_loading_kernel_objects),nl. |