1 % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(b_interpreter_components,[
6 reset_component_info/1,
7 b_trace_test_components/3, b_trace_test_components/4,
8 b_trace_test_components_wf/4,
9 unsat_component/2, unsat_component_enumeration_warning/1,
10 unsat_or_unknown_component_exists/0,
11 unsat_component_abort_error/1,
12 unsat_conjunct_inside_component/4,
13 det_solution_for_constant/2, get_det_solution_for_constant_value_kind/2,
14 det_solution_for_constant_was_stored/0, det_solution_for_constant_was_stored/1,
15 b_tracetest_boolean_expression/5,
16 observe_state/3,
17
18 construct_optimized_exists/3, construct_optimized_exists/4,
19 construct_optimized_exists/5,
20 extract_equalities_in_quantifier/4
21 ]).
22
23 :- use_module(b_interpreter,[b_test_boolean_expression/6]).
24 :- use_module(preferences).
25 :- use_module(kernel_waitflags).
26 :- use_module(tools).
27 :- use_module(translate).
28 :- use_module(error_manager).
29 :- use_module(library(lists)).
30 :- use_module(b_enumerate, [b_tighter_enumerate_all_values/2, b_tighter_enumerate_values/3]).
31
32 :- use_module(debug,[debug_println/2, debug_mode/1]).
33 :- use_module(tools,[start_ms_timer/1, stop_ms_timer_with_msg/2, stop_ms_timer_with_debug_msg/2]).
34
35 :- use_module(chrsrc(chr_integer_inequality),[attach_chr_integer_inequality_to_wf_store/1]).
36
37
38 :- use_module(module_information,[module_info/2]).
39 :- module_info(group,interpreter).
40 :- module_info(description,'This module can be used to split a predicate into components and solving each component individually (with tracing feedback).').
41
42 /* -------------- */
43 /* dynamic bits */
44 /* -------------- */
45
46 :- dynamic skipped_unsat_conjunct/1, unsat_conjunct_inside_component/4.
47 reset_unsat_conjunct_inside_component_info :-
48 retractall(skipped_unsat_conjunct(_)),
49 retractall(unsat_conjunct_inside_component(_,_,_,_)).
50 reset_tracetest_for_component :- retractall(skipped_unsat_conjunct(_)). % to be called before trace checking a component
51
52 % individual conjuncts which are directly unsatisfiable
53 assert_skipped_failed_conjunct(ComponentNr,BE) :- assert_skipped_unsat_conjunct,
54 assertz(unsat_conjunct_inside_component(ComponentNr,BE,false,'')),
55 (preferences:get_preference(provide_trace_information,false) -> true
56 ; add_message(b_interpreter_components,' *** INCONSISTENCY DETECTED, SKIPPING COMPONENT NR: ',ComponentNr, BE),
57 (debug_mode(on) -> print_bexpr_with_limit(BE,500) ; print_bexpr_with_limit(BE,150)), nl
58 ).
59 assert_skipped_unknown_conjunct(ComponentNr,BE,Reason) :- assert_skipped_unknown_conjunct,
60 assertz(unsat_conjunct_inside_component(ComponentNr,BE,unknown,Reason)),
61 ((Reason=abort_error; Reason=well_definedness_error)
62 -> assert_unsat_component_abort_error(ComponentNr)
63 ; true),
64 (preferences:get_preference(provide_trace_information,false) -> true
65 ; get_reason_msg(Reason,MSG),format(' *** Skipping predicate due to ~w:',[MSG]),
66 write(' '),print_bexpr_with_limit(BE,150),nl,
67 format('~n *** Predicate is unknown~n *** COMPONENT NUMBER: ~w~n',[ComponentNr])
68 ).
69 assert_skipped_unsat_conjunct :-
70 (skipped_unsat_conjunct(false) -> true
71 ; retractall(skipped_unsat_conjunct(_)), assertz(skipped_unsat_conjunct(false))).
72 assert_skipped_unknown_conjunct :-
73 (skipped_unsat_conjunct(_) -> true ; assertz(skipped_unsat_conjunct(unknown))).
74
75 get_reason_msg(enumeration_warning,R) :- !, R='ENUMERATION WARNING'.
76 get_reason_msg(M,M).
77
78
79 :- dynamic unsat_component/2, unsat_component_enumeration_warning/1, unsat_component_abort_error/1.
80 reset_unsat_component_info :-
81 retractall(unsat_component(_,_)),
82 retractall(unsat_component_enumeration_warning(_)),
83 retractall(unsat_component_abort_error(_)).
84
85 reset_all_component_infos :-
86 reset_unsat_component_info,
87 reset_unsat_conjunct_inside_component_info,
88 reset_observe_state.
89
90 :- use_module(eventhandling,[register_event_listener/3]).
91 :- register_event_listener(clear_specification,reset_all_component_infos,
92 'Reset b_interpreter_components unsat component info.').
93
94
95 store_unsat_component_nr(X) :- % use if you do not know if it is unknown or unsat
96 %error_manager:print_error_scopes,
97 (critical_enumeration_warning_occured_in_error_scope
98 -> Res = unknown
99 % should we also detect abort_error_occured_in_error_scope ?
100 ; Res=false),
101 store_unsat_component_nr(X,Res).
102
103 store_unsat_component_nr(X,FalseOrUnknown) :-
104 debug_println(9,store_unsat_component_nr(X,FalseOrUnknown)),
105 (unsat_component(X,false) -> true
106 ; retractall(unsat_component(X,_)),assertz(unsat_component(X,FalseOrUnknown))
107 ),
108 (critical_enumeration_warning_occured_in_error_scope,
109 \+ unsat_component_enumeration_warning(X)
110 -> assertz(unsat_component_enumeration_warning(X)),
111 debug_println(19,enumeration_warning_in_component(X))
112 ; true),
113 (abort_error_occured_in_error_scope
114 -> assert_unsat_component_abort_error(X)
115 ; true).
116 %portray_unsat_components.
117 unsat_component_exists :- unsat_component(_,false),!.
118 unsat_or_unknown_component_exists :- unsat_component(_,_),!.
119
120 % store the fact that an abort or wd error occurred for component
121 assert_unsat_component_abort_error(X) :- \+ unsat_component_abort_error(X),
122 assertz(unsat_component_abort_error(X)),
123 debug_println(19,unsat_component_abort_error(X)).
124
125 % small utility to display status of components
126 :- public portray_unsat_components/0.
127 portray_unsat_components :- format('Unsat components~n',[]),
128 unsat_component(Comp,Status),
129 (unsat_component_abort_error(Comp) -> Abort='abort/well_definedness error' ; Abort=''),
130 (unsat_component_enumeration_warning(Comp) -> EW='enumeration_warning' ; EW=''),
131 format('* component: ~w -> ~w ~w ~w~n',[Comp,Status,Abort,EW]),
132 unsat_conjunct_inside_component(Comp,BE,S,Reason),
133 format(' -> reason for ~w: ~w : ',[S,Reason]), translate:print_bexpr_with_limit(BE,100),nl,
134 fail.
135 portray_unsat_components.
136
137 :- public nr_of_components/1.
138 :- dynamic nr_of_components/1.
139 :- dynamic allow_skipping_over_components/0.
140 reset_component_info(AllowSkip) :- retractall(allow_skipping_over_components),
141 (AllowSkip==true -> assertz(allow_skipping_over_components) ; true),
142 reset_unsat_component_info,
143 reset_unsat_conjunct_inside_component_info.
144
145 % in Disprover mode we can stop straightaway; we are not interested in finding values for identifiers in other components; unless we have an enumeration warning !!
146 % TO DO: keep track of enumeration warnings per component
147
148 /* -------------- */
149
150
151 :- use_module(library(avl)).
152 % You can use the term one as ComponentNr if you don't know the number or it is not relevant
153 b_tracetest_boolean_expression(BE,LS,S,WF,ComponentNr) :- %print(catch(ComponentNr)),nl,
154 empty_avl(Ai),
155 ? catch_enumeration_warning_exceptions_and_wd_failures(
156 b_tracetest_boolean_expression1(BE,LS,S,WF,ComponentNr,Ai,_Ao),
157 % this should not backtrack (without WF0 set); otherwise we may get problems with error blocks nesting
158 assert_skipped_unknown_conjunct(ComponentNr,BE,enumeration_warning),
159 true, % true: add exceptions as event errors
160 assert_skipped_unknown_conjunct(ComponentNr,BE,well_definedness_error), % for WD error
161 component(ComponentNr)). % Source argument for debugging
162
163 b_tracetest_boolean_expression1(b(Expr,_,Infos),LS,S,WF,ComponentNr,Ai,Ao) :-
164 ? b_tracetest_boolean_expression2(Expr,Infos,LS,S,WF,ComponentNr,Ai,Ao).
165
166 :- use_module(bsyntaxtree,[is_a_conjunct_or_neg_disj/3]).
167 b_tracetest_boolean_expression2(Conjunct,Info,LocalState,State,WF,ComponentNr,Ai,Ao) :-
168 is_a_conjunct_or_neg_disj(b(Conjunct,pred,Info),LHS,RHS),
169 % also detects: not(A or B) <=> not(A) & not(B) and not(A=>B) <=> A & not(B)
170 % \+(Info = [try_smt|_]),
171 !,
172 %% print('check lhs of conjunct: '), translate:print_bexpr(LHS),nl,
173 b_tracetest_boolean_expression1(LHS,LocalState,State,WF,ComponentNr,Ai,Aii),
174 %% print('check rhs of conjunct: '), translate:print_bexpr(RHS),nl,
175 ? b_tracetest_boolean_expression1(RHS,LocalState,State,WF,ComponentNr,Aii,Ao).
176 b_tracetest_boolean_expression2(BE,Infos,LS,S,WF,ComponentNr,Ai,Ao) :-
177 (get_preference(provide_trace_information,true)
178 -> format('~n ====> (~w) ',[ComponentNr]),
179 print_bexpr_with_limit(b(BE,pred,Infos),250),nl
180 ; true),
181 ? if(safe_b_test_boolean_expression(ComponentNr,b(BE,pred,Infos),LS,S,WF,Ai,Ao),
182 true,
183 (assert_skipped_failed_conjunct(ComponentNr,b(BE,pred,Infos)),
184 Ai=Ao)).
185
186
187 safe_b_test_boolean_expression(ComponentNr,BE,LS,S,WF,Ai,Ao) :- %print(c(_ComponentNr,WF)),nl, translate:print_bexpr(BE),nl,
188 preferences:get_preference(provide_trace_information,false),
189 \+ abort_error_occured_in_error_scope,
190 % avoid setting up new error scope for every conjunct with catch_enumeration_warning
191 % BE is only displayed in TRACE_INFO mode anyway
192 % can be a bottleneck, e.g., for :prob-file ../prob_examples/public_examples/Eval/Sudoku_SAT.eval
193 !,
194 ? if(b_test_boolean_expression(BE,LS,S,WF,Ai,Ao),true,
195 (abort_error_occured_in_error_scope
196 -> assert_unknown(ComponentNr,BE,abort_error,Ai,Ao)
197 ; fail)
198 ).
199 safe_b_test_boolean_expression(ComponentNr,BE,LS,S,WF,Ai,Ao) :-
200 catch_enumeration_warning_exceptions_and_wd_failures(
201 b_test_boolean_expression(BE,LS,S,WF,Ai,Ao), % this should not backtrack (without WF0 set);
202 % otherwise we may get problems with error blocks nesting
203 assert_unknown(ComponentNr,BE,enumeration_warning,Ai,Ao), % call when exception caught
204 true, % true: add exceptions as event errors
205 assert_unknown(ComponentNr,BE,well_definedness_error,Ai,Ao), % call when wd_error caught
206 component(ComponentNr)). % Source argument for debugging
207
208 % Note: this will only detect enumeration warnings and WD errors in WF0 phase
209
210 assert_unknown(ComponentNr,BE,Reason,Ai,Ao) :- % print(assert_unknown(ComponentNr,Reason)),nl,
211 assert_skipped_unknown_conjunct(ComponentNr,BE,Reason),Ai=Ao.
212
213 :- use_module(bsyntaxtree,[predicate_components_in_scope/3,
214 predicate_identifiers_in_scope/3]).
215 :- use_module(b_enumerate,[extract_do_not_enum_ids_from_predicate/2]).
216
217 get_typedval_id(typedval(_Val,_Type,ID,_),ID).
218 ground_typeval(typedval(Val,_Type,_ID,_)) :- ground_value(Val).
219 :- use_module(probsrc(translate), [pretty_type/2, translate_bvalue_with_limit/3]).
220 get_typedval_info(typedval(Val,Type,ID,_),Info) :-
221 pretty_type(Type,TS), translate_bvalue_with_limit(Val,100,VS),
222 ajoin([ID, ' : ', TS, ' : ', VS],Info).
223 b_trace_test_components(Properties,ConstantsState,TypedVals) :-
224 %format('b_trace_test_components(~w,~w,~w)',[Properties,ConstantsState,TypedVals]),
225 ? b_trace_test_components(Properties,ConstantsState,TypedVals,all).
226 b_trace_test_components_wf(Properties,ConstantsState,TypedVals,WF) :-
227 ? b_trace_test_components_wf(Properties,ConstantsState,TypedVals,all,[],WF).
228 b_trace_test_components(Properties,ConstantsState,TypedVals,RelevantVariables) :-
229 ? b_trace_test_components(Properties,ConstantsState,TypedVals,RelevantVariables,[]).
230 % in constract to /3 and /4 b_trace_test_components/5 does not fail if the predicate is unsatisfiable.
231 % instead it returns the unsatisfiable component as the last argument
232 % the other predicates still fail because they expect to find an empty list there
233 b_trace_test_components(Properties,ConstantsState,TypedVals,RelevantVariables,UnsatConjuncts) :-
234 ? b_trace_test_components_wf(Properties,ConstantsState,TypedVals,RelevantVariables,UnsatConjuncts,no_wf_available).
235 b_trace_test_components_wf(Properties,ConstantsState,TypedVals,RelevantVariables,UnsatConjuncts,OuterWF) :-
236 % we now treat all TypedVals as local variables:
237 % ensure that we count them in predicate_components/predicate_identifiers
238 % (in case they clash with global identifiers)!
239 %start_ms_timer(T0),
240 maplist(get_typedval_id,TypedVals,LocalVars),
241 extract_do_not_enum_ids_from_predicate(Properties,DoNotEnumVars),
242 (preferences:get_preference(partition_predicates,true)
243 -> predicate_components_in_scope(Properties,LocalVars,Components),
244 length(Components,Len), print_trace_message(nr_of_components(Len))
245 ; predicate_identifiers_in_scope(Properties,LocalVars,PropVars),
246 Components = [component(Properties,PropVars)], Len=1
247 ),
248 retractall(nr_of_components(_)),assertz(nr_of_components(Len)),
249 reset_observe_state,
250 %stop_ms_timer_with_debug_msg(T0,b_trace_test_components_preprocessing),
251 ? b_trace_test_components2(Components,ConstantsState,TypedVals,RelevantVariables,DoNotEnumVars,1,WFList,OuterWF),
252 ? get_unsat_component(WFList,Components,UnsatConjuncts).
253
254
255 get_unsat_component(_,Components,UnsatConjuncts) :-
256 unsat_component_exists, !,
257 debug_println(9,unsatisfiable_predicate),
258 unsat_component(UnsatComponentNr,false),!,
259 nth1(UnsatComponentNr,Components,component(UnsatConjuncts,_)).
260 get_unsat_component(WFList,Components,UnsatConjuncts) :-
261 ? get_unsat_component_aux(WFList,Components,UnsatConjuncts).
262
263 get_unsat_component_aux(WFList,Components,UnsatConjuncts) :-
264 print_trace_message(grounding_wait_flags), % Note: for unknown components we continue grounding
265 ? l_ground_wait_flags(WFList),
266 (unsat_component(UnsatComponentNr,Status)
267 -> debug_println(19,unsat_component(UnsatComponentNr,Status)), UnsatConjuncts \== [],
268 nth1(UnsatComponentNr,Components,component(UnsatConjuncts,_))
269 ; UnsatConjuncts=[]).
270 get_unsat_component_aux(_,Components,UnsatConjuncts) :-
271 unsat_component(UnsatComponentNr,_),!,
272 nth1(UnsatComponentNr,Components,component(UnsatConjuncts,_)).
273
274
275 :- use_module(b_ast_cleanup,[predicate_level_optimizations/2]).
276 :- use_module(debug,[printsilent_message/1]).
277 print_trace_message(Msg) :-
278 (preference(provide_trace_information,false) -> true
279 ; printsilent_message(Msg)).
280 :- use_module(probsrc(value_persistance),[cache_is_activated/0]).
281 print_trace_message_with_typed_vals(Msg,TypedVals) :-
282 (preference(provide_trace_information,false) -> true
283 ; (cache_is_activated -> exclude(ground_typeval,TypedVals,NGTypedVals) ; NGTypedVals=TypedVals),
284 (NGTypedVals=[] -> true
285 ; printsilent_message(Msg),
286 maplist(get_typedval_info,NGTypedVals,IDs),
287 printsilent_message(IDs)
288 )
289 ).
290
291 b_trace_test_components2([],_ConstantsState,TypedVals,_,_,Nr,ResWF,OuterWF) :-
292 (TypedVals=[]
293 -> print_trace_message(finished_processing_component_predicates),
294 ResWF=[]
295 ; print_trace_message_with_typed_vals('Enumerating Identifiers without constraints: ',TypedVals),
296 init_wait_flags(WF0,[b_tighter_enumerate_values]),
297 copy_wait_flag_call_stack_info(OuterWF,WF0,WF),
298 b_tighter_enumerate_all_values(TypedVals,WF), ResWF=[wf_comp(WF,Nr)]).
299 b_trace_test_components2([component(Pred,ComponentVars)|T],ConstantsState,TypedVals,RelevantVariables,DoNotEnumVars,
300 Nr,ResWF,OuterWF) :-
301 N1 is Nr+1,
302 ( RelevantVariables\=all, ComponentVars\= all,
303 lists_are_disjoint(RelevantVariables,ComponentVars)
304 -> print_trace_message(skipping_irrelevant_component(Nr,ComponentVars)),
305 b_trace_test_components2(T,ConstantsState,TypedVals,RelevantVariables,DoNotEnumVars,N1,ResWF,OuterWF)
306 ; %% print(checking_component_properties(Nr,ComponentVars)),nl, %%
307 %% print(component(Nr)),nl, translate:nested_print_bexpr_as_classicalb(Pred),debug:nl_time,
308 ResWF = [wf_comp(WF,Nr)|TWF],
309 init_wait_flags(WF0,[wf_comp(Nr)]),
310 copy_wait_flag_call_stack_info(OuterWF,WF0,WF),
311 (preferences:preference(use_chr_solver,true) -> attach_chr_integer_inequality_to_wf_store(WF) ; true),
312 (ComponentVars=all -> InTypedVals=TypedVals, OutTypedVals=[], ProjectedState=ConstantsState
313 ; project_typed_vals(TypedVals,ComponentVars,InTypedVals,OutTypedVals),
314 project_state(ConstantsState,ComponentVars,ProjectedState) % relevant, e.g., for exists which may wait on state becoming ground
315 ),
316 observe_state(InTypedVals,WF,Nr), %%
317 reset_tracetest_for_component,
318 predicate_level_optimizations(Pred,OPred),
319 %%nl,nl,print(component(Nr,ComponentVars,ProjectedState)),nl,nl,translate:print_bexpr(Pred),nl,nl,
320 %%start_ms_timer(T1),
321 ? b_tracetest_boolean_expression(OPred,[],ProjectedState,WF,Nr),
322 % Skipping can only occur in this call above, not in enumeration phase
323 %% stop_ms_timer_with_debug_msg(T1,b_tracetest_boolean_expression(Nr)),
324 %print(done_comp(Nr,WF,ComponentVars)),nl,
325 (skipped_unsat_conjunct(FalseOrUnknown)
326 -> store_unsat_component_nr(Nr,FalseOrUnknown), % can be unknown due to an enumeration warning, cf. test 1390
327 %print('UNSAT: '),translate:nested_print_bexpr(Pred),nl,nl,
328 allow_skipping_over_components % check if we allow skipping over unsat components to
329 % maybe find as many values for constants as possible (partial setup_constants),...
330 % Note: in Disprover mode or solve_predicate (REPL) we can stop and fail straightaway
331 ; %print_bt_message(setup_enumerating_constants(Nr)), %%(TypedVals)), %%
332 b_tighter_enumerate_values(InTypedVals,DoNotEnumVars,WF),
333 (preferences:get_preference(disprover_mode,false) -> true
334 ; ground_wait_flag0(WF) % ensure that we give each component the chance to run WF0 inconsistency checks
335 %, print(finished_wf0_grounding_in_disprover_mode(Nr)),nl
336 )
337 ),
338 % we could ground waitflag 1 (deterministic computations) ?
339 ? b_trace_test_components2(T,ConstantsState,OutTypedVals,RelevantVariables,DoNotEnumVars,N1,TWF,OuterWF)
340 ).
341
342
343 l_ground_wait_flags(WF) :-
344 ? l_ground_wait_flags(WF,WFE,Result),
345 (Result=false
346 -> (!,fail) % Cut: to prevent backtracking to find other solutions for earlier components !
347 % Assumption: each component is independent and finding other solution for earlier component would again lead to failure in last component checked by l_ground_wait_flags/2
348 ; grd_ef(WFE)).
349
350 l_ground_wait_flags([],_,true).
351 l_ground_wait_flags([wf_comp(_,ComponentNr)|TWF],WFE,SatResult) :-
352 unsat_component(ComponentNr,_),!, % We now longer try and ground unknown components
353 l_ground_wait_flags(TWF,WFE,SatResult).
354 l_ground_wait_flags([wf_comp(WF,ComponentNr)|TWF],WFE,SatResult) :-
355 (debug_mode(off) -> true ; print(grounding_component(ComponentNr)),nl, start_ms_timer(Timer)),
356 % print_bt_message(grounding_component(ComponentNr)), portray_waitflags(WF),nl, %%
357 % maybe we should set up new error scope ? <--- TO DO
358 ? if(ground_constraintprop_wait_flags(WF),
359 ((pending_abort_error(WF) -> assert_unsat_component_abort_error(ComponentNr) ; true),
360 (debug_mode(on) -> (pending_abort_error(WF) -> Msg='PENDING WD/ABORT ERROR'; Msg='true'),
361 stop_ms_timer_with_msg(Timer,component(ComponentNr,Msg))
362 ; true),
363 get_enumeration_finished_wait_flag(WF,WFE), % bind enumeration finished to the global outer WFE flag
364 ? l_ground_wait_flags(TWF,WFE,SatResult) % continue with other components
365 ),
366 ((debug_mode(on) -> print(unsatisfiable_component(ComponentNr)),nl,
367 stop_ms_timer_with_msg(Timer,component(ComponentNr,'false')) ; true),
368 store_unsat_component_nr(ComponentNr),
369 SatResult=false)).
370
371 project_typed_vals([],_,[],[]).
372 project_typed_vals([typedval(Val,Type,VarID,EnumWarningInfos)|Rest],ComponentVars,In,Out) :-
373 ? (member(VarID,ComponentVars)
374 -> In = [typedval(Val,Type,VarID,EnumWarningInfos)|In2], Out2=Out
375 ; Out = [typedval(Val,Type,VarID,EnumWarningInfos)|Out2], In2=In
376 ), project_typed_vals(Rest,ComponentVars,In2,Out2).
377 project_state([],_,[]).
378 project_state([bind(VarID,Value)|Rest],ComponentVars,Out) :-
379 ? (member(VarID,ComponentVars)
380 -> Out=[bind(VarID,Value)|Out2]
381 ; Out=Out2
382 ), project_state(Rest,ComponentVars,Out2).
383
384
385 :- use_module(specfile,[get_specification_description/2]).
386 :- use_module(state_packing,[pack_value/2,unpack_value/2]).
387 :- volatile det_solution_for_constant_packed/2.
388 :- dynamic det_solution_for_constant_packed/2.
389 assert_det_solution_for_constant(Var,Val) :-
390 (value_too_large(Val) -> PVal = '$TOO_LARGE' ,debug_println(4,not_storing(Var))
391 ; pack_value(Val,PVal)
392 %,translate:translate_bvalue_with_limit(Val,200,VS),format(' STORING ---> ~w = ~w~n',[Var,VS])
393 ),
394 assertz(det_solution_for_constant_packed(Var,PVal)).
395
396 det_solution_for_constant(Var,Val) :-
397 if(det_solution_for_constant_packed(Var,PVal),
398 unpack_det_sol(Var,PVal,Val),
399 (get_specification_description(properties,PROPS),
400 ajoin([PROPS, ' are *not* true and no value was found (deterministically) for the following CONSTANT: '], Msg),
401 add_message(det_value_not_found_for_constant,Msg,Var),
402 fail)
403 ).
404 unpack_det_sol(Var,PVal,Val) :-
405 (PVal = '$TOO_LARGE'
406 -> ajoin(['The following CONSTANT was not stored due to its size (set preference ALLOW_INCOMPLETE_SETUP_CONSTANTS to TRUE to store all constants found): '], Msg),
407 add_message(det_value_not_stored_for_constant,Msg,Var),
408 fail
409 ; unpack_value(PVal,Val)
410 ).
411
412 :- use_module(probsrc(translate), [translate_bvalue_kind/2]).
413 get_det_solution_for_constant_value_kind(Var,ValKind) :-
414 det_solution_for_constant_packed(Var,PVal),
415 (PVal = '$TOO_LARGE' -> ValKind='LARGE-VALUE'
416 ; unpack_value(PVal,Val),
417 (translate_bvalue_kind(Val,K) -> ValKind=K ; ValKind='UNKNOWN-VALUE')
418 ).
419
420 det_solution_for_constant_was_stored :- (det_solution_for_constant_was_stored(_) -> true).
421 det_solution_for_constant_was_stored(Var) :- det_solution_for_constant_packed(Var,_).
422
423 :- use_module(probsrc(bsyntaxtree),[map_over_bexpr/2]).
424 :- use_module(avl_tools,[avl_height_less_than/2]).
425 value_too_large(avl_set(A)) :-
426 preference(allow_incomplete_partial_setup_constants,false), %if true we always store the value
427 (preference(provide_trace_information,false) -> MaxH=7 ; MaxH=9),
428 \+ avl_height_less_than(A,MaxH).
429 % TO DO: it could be a small set but include large subsets !
430 value_too_large((A,B)) :- (value_too_large(A) -> true ; value_too_large(B)).
431 value_too_large(rec(F)) :- member(field(_,FVal),F), value_too_large(FVal).
432 value_too_large(closure(P,T,B)) :-
433 \+ custom_explicit_sets:is_interval_closure(P,T,B,_,_),
434 preference(allow_incomplete_partial_setup_constants,false),
435 uses_large_value(B).
436 % we can have large symbolic closures; cf PlanProGross.mch; see also test 1637
437
438 % assumes values are all ground:
439 uses_large_value_aux(value(V)) :- value_too_large(V).
440
441 uses_large_value(BExpr) :-
442 map_over_bexpr(uses_large_value_aux,BExpr).
443
444
445
446 :- use_module(tools_printing,[print_value_summary/1]).
447 reset_observe_state :- retractall(det_solution_for_constant_packed(_,_)).
448 observe_state(Env,WF,ComponentNr) :-
449 get_wait_flag0(WF,WF0), get_wait_flag1(observe_state,WF,WF1),
450 (preferences:get_preference(provide_trace_information,true)
451 -> when((ground(Env);nonvar(WF0)),print_success(WF0,ComponentNr,Env,WF))
452 %% ,when(nonvar(WF1),(nl, print('Starting Phase 1'),nl, portray_waitflags(WF)))
453 ; true),
454 observe_state2(Env,WF0,WF1).
455 %,when(nonvar(WF0),(print(wf0),nl,portray_waitflags(WF))), when(nonvar(WF1),(print(wf1),nl)).
456
457 :- use_module(debug,[debug_format/3]).
458 print_success(WF0,ComponentNr,_,_WF) :- nonvar(WF0),!,
459 debug_format(19,'~n-->> WF0 for component ~w grounded.~n',[ComponentNr]).
460 print_success(_,ComponentNr,Env,_WF) :-
461 (Env=[]
462 ->
463 format('~n-->> SUCCESS; processed component ~w (no identifiers)~n',[ComponentNr])
464 ; length(Env,NrVal),
465 format('~n-->> SUCCESS; all ~w identifier(s) valued in component ~w~n',[NrVal,ComponentNr])
466 ),
467 (debug_mode(on)
468 -> findall(V,member(typedval(_,_,V,_),Env),Vars),
469 statistics(walltime,[W,_]), format('-->> (walltime: ~w ms) : identifiers = ~w~n',[W,Vars])
470 ; true),
471 %%,check_for_multiple_solutions(WF,ComponentNr) %% comment in to check for multiple solutions
472 nl.
473
474 observe_state2([],_,_).
475 observe_state2([Binding|T],WF0,WF1) :- get_binding_value(Binding,VarID,Val),
476 observe_variable(VarID,Val,WF0,WF1),observe_state2(T,WF0,WF1).
477
478 get_binding_value(bind(Id,Value),Id,Value).
479 get_binding_value(typedval(Value,_Type,Id,_Trigger),Id,Value).
480
481 % print a warning message if we find multiple solutions *after* all constants have been valued
482 %:- public check_for_multiple_solutions/2.
483 %check_for_multiple_solutions(WF,ComponentNr) :- get_enumeration_finished_wait_flag(WF,EWF),
484 % retractall(solution_found(ComponentNr,_)),
485 % add_solution(EWF,ComponentNr).
486 %:- volatile solution_found/2.
487 %:- dynamic solution_found/2.
488 %:- block add_solution(-,?).
489 %add_solution(_,ComponentNr) :- retract(solution_found(ComponentNr,Nr)),!,
490 % print('*** Multiple solutions found *after valuation* for component '), print(ComponentNr),nl,
491 % N1 is Nr+1,
492 % print('*** Solution: '),print(N1),nl,
493 % assertz(solution_found(ComponentNr,N1)).
494 %add_solution(_,ComponentNr) :-
495 % assertz(solution_found(ComponentNr,1)).
496
497 observe_variable(Var,Val,WF0,_WF1) :- preferences:get_preference(provide_trace_information,false),!,
498 observe_variable_no_trace(Var,Val,WF0).
499 observe_variable(Var,Val,WF0,WF1) :-
500 ground_value_check(Val,GrVal),
501 observe_variable0_block(Var,Val,GrVal,WF0,WF1).
502 :- block observe_variable0_block(?,?,-,-,?).
503 observe_variable0_block(Var,Val,GrVal,WF0,WF1) :-
504 (var(GrVal) -> write(' :?: '), write(Var), write(' '), print_value_summary(Val),
505 observe_variable1(Var,Val,WF1)
506 ; (var(WF0) -> write('-->> ')
507 ; write('--0-->> ')), % WF0/GrVal grounded at same time probably does not happen (often)
508 write(Var),nl, write(' '),print_value_summary(Val),print_walltime,nl,
509 assert_det_solution_for_constant(Var,Val)
510 ).
511 :- use_module(kernel_tools,[ground_value/1,ground_value_check/2]).
512 :- block observe_variable_no_trace(?,-,-).
513 observe_variable_no_trace(Var,Val,WF0) :- nonvar(WF0),!, % important e.g. for test 1368
514 (ground_value(Val) -> assert_det_solution_for_constant(Var,Val) ; true).
515 observe_variable_no_trace(Var,Val,WF0) :- ground_value_check(Val,GV),
516 %tools_printing:print_term_summary(gr_val_check(Var,Val,GV)),nl,
517 observe_variable_no_trace4(Var,GV,Val,WF0).
518 :- block observe_variable_no_trace4(?,-,?,-).
519 observe_variable_no_trace4(_,GV,_,_) :- var(GV),!.
520 observe_variable_no_trace4(Var,_,Val,_) :- assert_det_solution_for_constant(Var,Val). % this could be expensive !?
521
522 print_walltime :- statistics(walltime,[Tot,Delta]),
523 (debug_mode(on) -> print(' '),tools:print_memory_used_wo_gc ; true),
524 format(' ~w ms (Delta ~w ms) ',[Tot,Delta]).
525
526 observe_variable1(Var,Val,WF1) :- ground_value_check(Val,GV),
527 observe_variable1_block(Var,Val,WF1,GV).
528 :- block observe_variable1_block(?,?,-,-).
529 observe_variable1_block(Var,Val,_WF1,GV):-
530 (nonvar(GV)
531 -> write('--1-->> '), write(Var),nl, write(' '),print_value_summary(Val),
532 assert_det_solution_for_constant(Var,Val)
533 ; write(' :?1?: '), write(Var), write(' '), print_value_summary(Val)
534 %% , when(ground(Val), (print('--ground-->> '),print(Var),print(' '), print_value_summary(Val))) % comment in to see grounding
535 %% , external_functions:observe_state([bind(Var,Val)]) % comment in to observe values
536 %% , translate:print_bstate([bind(Var,Val)]),nl % comment in to print full value with CLP(FD) info
537 ).
538
539
540 % --------------------
541
542 construct_optimized_exists(Parameters,Body,Pred) :-
543 construct_optimized_exists(Parameters,Body,Pred,true,_).
544 construct_optimized_exists(Parameters,Body,Pred,Simplify) :-
545 construct_optimized_exists(Parameters,Body,Pred,Simplify,_).
546
547 % we could also partition inside b_interpreter ?
548 construct_optimized_exists(Parameters,Body,Pred,Simplify,NrComponents) :-
549 % we can actually do more: first project out all conjuncts which do not have any variables in common with Parameters
550 % #x.(P(x) & Q) <=> #x.(P(x)) & Q
551 % we can also use a stronger version of predicate components #(x,y).( P(x,v) & Q(v,y)) <=> #(x).P(x,v) & #(y).Q(v,y)
552 get_texpr_ids(Parameters,PIDs),
553 %print(constructing_optimized_exists(PIDs)),nl,
554 LocalVars = PIDs,
555 predicate_components_with_restriction(Body,LocalVars,PIDs,Components), % we focus partition decision on PIDs, not on all identifiers
556 %length(Components,Len), print(nr_of_components_for_exists(Len,Components)),nl,
557 conjunct_components(Components,Parameters,Pred,Simplify,NrComponents).
558 % print('* EXISTS: '),translate:print_bexpr(Pred),nl.
559
560 :- use_module(bsyntaxtree).
561 conjunct_components(C,Parameters,Res,Simplify,NrComponents) :-
562 conjunct_components2(C,Parameters,List,Simplify,0,NrComponents),
563 conjunct_predicates_with_pos_info(List,Res).
564
565 conjunct_components2([],_Parameters,[],_,Nr,Nr). % :- (Parameters=[] -> true ; print(unused_existential_var(Parameters)),nl).
566 conjunct_components2([component(Pred,ComponentVars)|T],Parameters,Res,Simplify,InNr,OutNr) :-
567 augment_ids(ComponentVars,CV), % translate atomic id names into b(identifier(...
568 tools:list_intersection(CV,Parameters,ExistParas), % TO DO: use ordsets
569 (Simplify=true
570 -> create_and_simplify_exists(ExistParas,Pred,EP) % no use in recursively calling construct_optimized_exists
571 ; Simplify= no_cleanup_and_simplify
572 -> create_exists(ExistParas,Pred,EP0), % avoid loops when called from ast_cleanup
573 get_texpr_info(EP0,AllInfos0),
574 (nonmember(nodeid(_),AllInfos0),ExistParas=[Par1|_]
575 -> get_texpr_info(Par1,AllInfos1),extract_pos_infos(AllInfos1,PIs) % try and get position from ids
576 ; PIs=[]), % we already have a position info
577 add_texpr_infos(EP0,[partitioned_exists|PIs],EP) % add ,removed_typing ??
578 ; create_unsimplified_exists(ExistParas,Pred,EP)
579 ),
580 (EP=b(truth,pred,[]) % or should we allow _ for Info field ??
581 -> Res=TRes
582 ; Res=[EP|TRes]),
583 In1 is InNr+1,
584 conjunct_components2(T,Parameters,TRes,Simplify,In1,OutNr).
585
586
587 % translate a list of atomic ides into ids with the b/3 wrapper
588 augment_ids([],[]).
589 augment_ids([ID|T],[b(identifier(ID),_,_)|TT]) :- augment_ids(T,TT).
590
591 % extract and inline simple equalities to remove quantified variables; useful for exists and forall
592 % TO DO: move to b_quantifier_optimizations.pl or similar
593 extract_equalities_in_quantifier(Parameters,Pred, ReducedParas,OutPred) :-
594 extract_equalities2(Pred,Parameters,ReducedParas,NewPred,[],Subst),
595 %sort(Subst,SortedSubst),
596 %print(extracted(Subst)),nl,
597 apply_subst(Subst,NewPred,OutPred).
598 % apply equality inside expressions: note: this may duplicate expressions !
599 % However, it also works if the equalities contain parameters
600
601 :- use_module(bsyntaxtree,[is_equality/3]).
602
603 extract_equalities2(b(conjunct(A,B),pred,Info),Ids,RemIds,Res) --> !,
604 {Res=b(conjunct(PA,PB),pred,Info)},
605 extract_equalities2(A, Ids,RemIds1,PA),
606 extract_equalities2(B,RemIds1,RemIds,PB).
607 extract_equalities2(TEqual,Ids,RemIds,NewPred,InSubst,OutSubst) :-
608 is_equality(TEqual,ID,E),
609 % TODO: we could try and split equalities if possible; usually this is done by ast_cleanup though?
610 %(bsyntaxtree:split_equality(TEqual,A,B) -> nl,print('COULD BE SPLIT: '),translate:print_bexpr(TEqual),nl ; true),
611 same_id_is_member(ID,Ids,SID,RemIds),
612 %\+ occurs_in_expr(SID,E), % not cyclic; we check it again after applyng InSubst to E below
613 \+ in_subst_dom(SID,InSubst), % ensure we don't already have an equation for the same ID
614 compose_with_subst(InSubst,SID,E,OutSubst), % we can compose with existing substitution without occurs-check problem
615 always_well_defined_or_disprover_mode(E), % otherwise we may move evaluation of E forward !
616 !,
617 NewPred=b(truth,pred,[]).
618 extract_equalities2(X,Ids,Ids,X) --> [].
619
620
621
622 % compose a new binding Var/Expr with existing substitution Subst; where Subst was not yet applied to Expr
623 compose_with_subst(Subst,Var,Expr,[Var/NewExpr|ModSubst]) :-
624 apply_subst(Subst,Expr,NewExpr),
625 \+ occurs_in_expr(Var,NewExpr), % otherwise cyclic
626 apply_binding_to_substitution(Subst,Var,NewExpr,ModSubst).
627 apply_binding_to_substitution([],_,_,[]).
628 apply_binding_to_substitution([TV/TE|T],Var,Expr,[TV/TE2|NT]) :-
629 \+ occurs_in_expr(TV,Expr), % otherwise we get a cyclic substitution --> fail
630 replace_id_by_expr(TE,Var,Expr,TE2),
631 apply_binding_to_substitution(T,Var,Expr,NT).
632
633 apply_subst([],X,X).
634 apply_subst([Var/Expr|T],E,NewE) :-
635 (replace_id_by_expr(E,Var,Expr,E2) % replace identifier Var by expression Expr
636 -> %apply_to_tail(T,Var,Expr,NT), % apply binding to tail of substitution
637 apply_subst(T,E2,NewE)
638 ; add_internal_error('Call failed: ',apply_subst([Var/Expr|T],E,NewE)),NewE=E).
639
640
641 in_subst_dom(X,[I/_|T]) :- (X=I -> true ; in_subst_dom(X,T)).
642
643 same_id_is_member(X,[H|T],SID,Rest) :-
644 (same_id(X,H,SID) -> Rest=T ; Rest=[H|TR],same_id_is_member(X,T,SID,TR)).
645
646 % TO DO: investigate what is the exact difference with create_exists_opt; partition into components is only done by construct_optimized_exists/3
647 create_and_simplify_exists(Paras,Pred,ResultingPred) :-
648 extract_equalities_in_quantifier(Paras,Pred,NewParas,NewPred),
649 create_and_simplify_exists2(NewParas,NewPred,ResultingPred).
650
651 %:- use_module(b_interpreter_check,[arithmetic_op/4]). % TODO REFACTOR and move this and code below to separate module
652 create_and_simplify_exists2([],Pred,R) :- !,R=Pred.
653 % simplify #ID.(ID:E1 & ID:E2) <=> E1 /\ E2 /= {} , etc... now done in ast_cleanup
654 % simplify #ID.(ID/:E) <=> E /= FullType also done in ast_cleanup
655 % simplify #SID.(SID > Expr) <=> truth now done in ast_cleanup
656 create_and_simplify_exists2(Parameters,Body,Res) :- create_unsimplified_exists(Parameters,Body,Res).
657 % TO DO: treat nested exists
658
659
660
661 :- use_module(b_ast_cleanup,[clean_up_pred/3]).
662 :- use_module(bsyntaxtree,[add_texpr_info_if_new/3]).
663 create_unsimplified_exists(Parameters,Body,Res) :-
664 maplist(mark_generated_exists,Parameters,Para2), % mark that this is an artificially constructed; we now mark the exists
665 create_exists(Para2,Body,Res1),
666 add_texpr_info_if_new(Res1,removed_typing,Res2), % unconditionally add this info, avoid generating warnings in exists_body_warning, see test 625
667 % and avoid useless_let_message
668 % previously removed_typing was only added for disjuncts or implications
669 clean_up_pred(Res2,[],Res). % also computes used_ids,
670 % and performs some existential quantifier optimisations like replace_exists_by_not_empty
671
672 mark_generated_exists(TID1,TID2) :- add_texpr_info_if_new(TID1,generated_exists_parameter,TID2).