1 % (c) 2009-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 % tcltk_interface.pl
6
7 % do we still need this ?
8 prob_use_module(X) :- load_files(X,[if(changed),load_type(source),compilation_mode(compile)]).
9
10 /* load all necessary modules */
11 :- use_module(library(random)).
12 :- use_module(library(lists)).
13 :- use_module(library(system)).
14
15 :- use_module(library(ordsets)).
16 :- use_module(library(avl)).
17 :- use_module(library(process)).
18
19 :- prob_use_module(typechecker).
20 :- prob_use_module(self_check).
21 :- prob_use_module(kernel_waitflags).
22
23 :- use_module(probsrc(specfile)).
24 :- use_module(probsrc(translate)).
25 :- use_module(probsrc(tools)).
26 :- use_module(probsrc(b_enumerate)).
27 :- use_module(probsrc(b_state_model_check)).
28 :- use_module(probsrc(bmachine)).
29
30
31 :- use_module(probsrc(debug)).
32 :- use_module(probsrc(preferences)).
33 :- prob_use_module(version).
34 :- use_module(probsrc(b_interpreter)).
35 :- use_module(probsrc(predicate_debugger)).
36 :- use_module(probsrc(b_trace_checking)).
37 :- prob_use_module(gensym).
38 :- use_module(delay).
39 :- use_module(probsrc(bsyntaxtree)).
40
41 :- prob_use_module(kernel_objects).
42 :- prob_use_module(bsets_clp).
43
44 :- use_module(probsrc(state_space)).
45 :- use_module(probsrc(state_space_exploration_modes)).
46
47
48 :- prob_use_module(b_compiler).
49 :- prob_use_module(error_manager).
50 :- use_module(extension('plspec/plspec/plspec_core'),[set_error_handler/1]).
51 :- use_module(extension('plspec/plspec/prettyprinter'),[pretty_print_error/1]).
52 prob_plspec_error_handler(ErrTerm) :- plspec:pretty_print_error(ErrTerm),
53 add_internal_error('Error detected by plspec',ErrTerm).
54 :- set_error_handler(user:prob_plspec_error_handler).
55 :- prob_use_module(model_checker).
56
57 :- prob_use_module(visualize_graph).
58 :- prob_use_module(state_space_reduction).
59 :- prob_use_module(state_custom_dot_graph).
60 :- prob_use_module(fdr_csp_generator).
61 :- prob_use_module(coverage_statistics).
62 :- prob_use_module(succeed_max).
63 :- prob_use_module(tools_commands).
64
65 %:- prob_use_module(testcase_generator).
66
67 :- use_module(prozsrc(proz),[open_proz_file/2]).
68
69 :- use_module(extension('ltsmin/ltsmin')).
70
71
72 :- prob_use_module(reduce_graph_state_space).
73 :- prob_use_module(b_read_write_info).
74 %:- prob_use_module(flow).
75
76 :- use_module(probltlsrc(ltl)).
77 :- use_module(probltlsrc(ctl)).
78 :- use_module(kodkodsrc(kodkod)).
79 :- prob_use_module(graph_canon).
80 %:- prob_use_module('promela/promela_ncprinter').
81
82 :- prob_use_module(sap).
83
84 :- use_module(probsrc(system_call),[generate_temporary_cspm_file/2, get_writable_compiled_filename/3, system_call_keep_open/7, system_call_keep_open_no_pipes/4]).
85
86 :- prob_use_module(bvisual2).
87 :- prob_use_module(b_show_history).
88 :- prob_use_module(enabling_analysis).
89 :- prob_use_module(mcdc_coverage).
90 :- prob_use_module(prologTasks).
91 :- prob_use_module(meta_interface).
92
93 % Modules from por folder
94 :- use_module(probporsrc(dot_graphs_static_analysis)).
95 :- use_module(probporsrc(static_analysis)).
96 :- use_module(probporsrc(ample_sets)).
97 :- use_module(probpgesrc(pge_algo)).
98
99 :- use_module(probcspsrc(haskell_csp),[parse_and_load_cspm_file/1,
100 get_csp_assertions_as_string/2,get_csp_processes/1,
101 parse_and_load_cspm_file_into_specific_pl_file/2, load_cspm_pl_file/1,
102 evaluate_csp_expression/2,evaluate_csp_expression/3,
103 parse_single_csp_expression_file/3, parse_single_csp_declaration/3]).
104 %:- use_module(probcspsrc(slicer_csp),[slice_from_program_point/14]).
105
106 :- use_module(value_persistance, [save_constants/1,add_new_transitions_to_cache/1]).
107
108 %:- use_module(ast_inspector).
109 :- use_module(tcltk_tree_inspector).
110
111 :- use_module(state_viewer_images).
112
113 :- prob_use_module(symbolic_model_checker(cbc_ba)).
114 :- prob_use_module(symbolic_model_checker(bmc)).
115 :- prob_use_module(symbolic_model_checker(kinduction)).
116 :- prob_use_module(symbolic_model_checker(ic3)).
117 :- prob_use_module(symbolic_model_checker(ctigar)).
118 :- use_module(probsrc(unsat_cores)).
119
120 /* main program
121 * ============
122 */
123
124 % use module_info/3 because we are not in a module here
125 :- use_module(module_information).
126 :- module_info(tcltk_interface,group,infrastructure).
127 :- module_info(tcltk_interface,description,'Interface between the Tcl/Tk GUI, the CLI and the internal modules.').
128
129 /*
130 Start server for LTSmin
131 */
132
133 :- use_module(extension('ltsmin/ltsmin'),[start_ltsmin/4]).
134
135 :- public tcltk_run_ltsmin/5.
136 % Backend = symbolic or sequential
137 tcltk_run_ltsmin(Backend,NoDead,NoInv,UsePOR,Res) :-
138 % in case of POR we can also enable/disable use_cbc_analysis preference
139 (UsePOR == true -> MoreFlags = [por] ; MoreFlags=[]),
140 start_ltsmin(Backend, [NoDead, NoInv], MoreFlags,Result),
141 get_check_name(NoDead,NoInv,Kind),
142 process_ltsmin_result(Result,Kind,Res).
143
144 get_check_name(true,false,Kind) :- Kind = 'INVARIANT'.
145 get_check_name(false,true,Kind) :- Kind = 'DEADLOCK'.
146
147 :- use_module(tools_printing,[format_with_colour/4]).
148 :- use_module(extension('ltsmin/ltsmin_trace'),[csv_to_trace/3]).
149 process_ltsmin_result(ltsmin_model_checking_ok,Kind,no_counter_example_found) :-
150 format_with_colour(user_output,green,'LTSMin found no ~w Counter Example\n',Kind).
151 process_ltsmin_result(ltsmin_counter_example_found(CsvFile),Kind,counter_example_found) :-
152 format_with_colour(user_output,[red,bold],'LTSMin found ~w Counter Example\n',Kind),
153 csv_to_trace(CsvFile,States,Transitions),
154 print('*** REPLAYING TRACE: '),nl,print(Transitions),nl,
155 %print(States),nl,
156 length(Transitions,TLen), length(States,SLen), print(len(TLen,SLen)),nl,
157 (replay_ltsmin_trace(States,Transitions) -> true
158 ; add_error(process_ltsmin_result,'Could not replay trace:',Transitions)).
159
160 replay_ltsmin_trace([],[]).
161 replay_ltsmin_trace([State|TS],[TransName|TT]) :-
162 (find_successor_state(State,TransName)
163 -> replay_ltsmin_trace(TS,TT)
164 ; add_error(replay_ltsmin_trace,'Could not execute:',TransName),fail).
165
166 find_successor_state(EState,'$init_state') :- !,
167 compute_all_inits,
168 is_initial_state_id(NewID),
169 state_space:visited_expression(NewID,State),
170 %print(try_init(NewID,State)),nl, print(EState),nl,
171 expand_const_and_vars_to_full_store(State,EState1),
172 %print(EState1),nl,
173 EState1=EState,
174 tcltk_reset,
175 tcltk_execute_trace_to_node(NewID).
176 find_successor_state(EState,TransName) :-
177 user:tcltk_get_options(_),
178 current_options(Options), % print(Options),nl,
179 member( (_,_Action,ActionOpAsTerm,NewID), Options),
180 get_operation_name(ActionOpAsTerm,TransName),
181 state_space:visited_expression(NewID,State),
182 expand_const_and_vars_to_full_store(State,EState), % TO DO: only compare variables
183 tcltk_goto_state(ActionOpAsTerm,NewID).
184
185 % compute all INITIALISATIONS
186 compute_all_inits :- is_concrete_constants_state_id(ID), compute_all_transitions_if_necessary(ID),fail.
187 compute_all_inits.
188
189 /* -------------------------------------------------------------------- */
190
191 %tcltk_find_untyped_vars(Vs) :- find_untyped_vars(Vs), Vs \== [].
192
193 %tcltk_find_untyped_consts(Vs) :- find_untyped_consts(Vs), Vs \== [].
194
195 :- public tcltk_find_max_reached_node/0.
196 tcltk_find_max_reached_node :- tcltk_find_max_reached_node(_).
197 tcltk_find_max_reached_node(ID) :- max_reached_or_timeout_for_node(ID).
198
199 :- public tcltk_current_node_has_no_real_transition/0.
200 tcltk_current_node_has_no_real_transition :-
201 \+ tcltk_current_node_has_real_transition.
202 tcltk_current_node_has_real_transition :-
203 current_state_id(CurID),
204 transition(CurID,Trans,_),
205 (CurID \= root ; Trans \= '$partial_setup_constants'),!.
206 tcltk_current_node_has_partial_transition :-
207 current_state_id(CurID),
208 transition(CurID,'$partial_setup_constants',_),!.
209
210 /* --------------------------------------------------------------------- */
211 tcltk_goto_state(ActionAsTerm,StateID) :-
212 (var(StateID) -> print_message(var_state(tcltk_goto_state(ActionAsTerm,StateID))) ;true),
213 (visited_expression_id(StateID)
214 -> true
215 ; ajoin(['State ',StateID,' does not exist. Could be due to insufficient memory. Transition: '],Msg),
216 add_warning(tcltk_goto_state,Msg,ActionAsTerm),
217 fail
218 ),
219 (retract(current_state_id(CurID))->true;print(no_current_state_id),nl),
220 assert(current_state_id(StateID)),
221 (transition(CurID,ActionAsTerm,OpID,StateID)
222 -> /* ok: proper transition */
223 add_to_op_trace_ids(OpID),
224 add_id_to_history(CurID)
225 ; (CurID=StateID
226 -> true
227 ; debug_println(19,jumping(CurID,ActionAsTerm,StateID)),
228 add_to_op_trace_ids(jump(StateID)),
229 add_id_to_history(CurID)
230 )
231 ).
232
233 add_id_to_history(CurID) :-
234 (retract(history(History))->true),
235 assert(history([CurID|History])), retractall(forward_history(_)).
236
237 initialise_operation_not_yet_covered :- retractall(operation_not_yet_covered(_)),
238 b_or_z_mode,
239 ? b_top_level_operation(Name),
240 % b_get_machine_operation(Name,_,Par,_), length(Par,Arity), functor(Op,Name,Arity),
241 % Note: no '-->' added
242 assert(operation_not_yet_covered(Name)),
243 debug_println(operation_not_yet_covered(Name)),
244 fail.
245 /* Missing: treat operations with return values */
246 initialise_operation_not_yet_covered.
247
248
249 tcltk_add_new_transition(FromID,Action,ToID,ToTempl,TransInfo) :-
250 tcltk_add_new_transition_transid(FromID,Action,ToID,ToTempl,TransInfo,_TransId).
251
252 tcltk_add_new_transition_transid(FromID,Action,ToID,ToTempl,TransInfo,TransId) :-
253 get_id_of_node_and_add_if_required(ToTempl,ToID,Exists,FromID),
254 %% print_message(tcltk_add_new_transition(FromID,Action,ToID,Exists)), %%
255 (Exists=exists,
256 (preferences:preference(store_only_one_incoming_transition,true)
257 %-> transition(FromID,_,_,_) % add transition to prevent deadlock being detected
258 ; transition(FromID,Action,TransId,ToID))
259 -> true %,print(not_adding(FromID,ToID,Exists)),nl
260 ; (preferences:preference(forget_state_space,true)
261 -> (any_transition(FromID,_,_) -> true
262 ; store_transition(FromID,'$NO_DEADLOCK',FromID,TransId)) /* just add dummy transition */
263 ; store_transition(FromID,Action,ToID,TransId),
264 (store_transition_infos(TransInfo,TransId) -> true
265 ; add_internal_error('storing transition info failed', store_transition_infos(TransInfo,TransId)))
266 ),
267 add_cover(Action,OpName),
268 animation_mode(Mode),
269 (FromID \= ToID, b_or_z_mode(Mode), not_all_transitions_added(ToID)
270 -> add_additional_destination_infos(FromID,OpName,ToID)
271 ; true
272 )
273 ).
274
275 add_cover('-->'(Action1,_),OpName) :- !,add_cover_aux(Action1,OpName).
276 add_cover(Action1,OpName) :- add_cover_aux(Action1,OpName).
277 add_cover_aux(Action1,OpName) :- functor(Action1,OpName,_),
278 (retract(operation_not_yet_covered(OpName))
279 -> (preferences:get_preference(provide_trace_information,true)
280 -> print(cover(OpName)),nl ; true),
281 ? (operation_not_yet_covered(_) -> true ; formatsilent('~nALL OPERATIONS COVERED~n',[]))
282 ; true
283 ).
284
285
286 add_additional_destination_infos(FromID,ActionName,ToID) :-
287 preference(try_operation_reuse,true),
288 ToID \= FromID,
289 animation_mode(b),
290 preference(symmetry_mode,MODE), (MODE=off ; MODE=flood),
291 % TO DO: can we enable this trick in symmetry mode ?
292 bmachine:reuse_operation_effect(ActionName,OtherAction),
293 \+ reuse_operation(ToID,OtherAction,_,_),
294 assert(reuse_operation(ToID,OtherAction,FromID,ActionName)),
295 % print(reuse_operation(ToID,OtherAction,FromID,ActionName)),nl, %%
296 fail.
297 add_additional_destination_infos(FromID,ActionName,ToID) :- %print(add_dest(FromID,ActionName,ToID)),nl,
298 ( b_specialized_invariant_for_op(ActionName,_),
299 \+ invariant_not_yet_checked(FromID),
300 \+ invariant_violated(FromID) % if Invariant does not hold in previous state, we have no idea about invariants in the new state (proof assumes invariant holds before)
301 ->
302 (retract(specialized_inv(ToID,OldAVL)) -> true ; empty_avl(OldAVL)),
303 avl_store(ActionName,OldAVL,nothing,NewAVL),
304 % TO DO: provide a special value if an operation preserves the entire invariant ??
305 %print(specialized_inv(ToID,NewAVL)),nl,
306 assert(specialized_inv(ToID,NewAVL))
307 ; true
308 ).
309 /*
310 Store names of incoming transitions in an AVL tree
311 Used to calculate invariant in presence of proof information
312 */
313
314
315
316
317
318 :- use_module(state_space_exploration_modes,[set_depth_breadth_first_mode/1,dbf_modes/3]).
319
320
321 tcltk_set_dbf_mode(Nr) :- dbf_modes(Nr,Mode,_),!,
322 set_depth_breadth_first_mode(Mode).
323 tcltk_set_dbf_mode(Nr) :- add_error(tcltk_set_dbf_mode,'Unknown mode: ',Nr).
324
325 tcltk_dbf_modes(list(Names)) :- findall(N,dbf_modes(_,_,N),Names).
326
327
328 :- dynamic prev_randomise_enumeration_order/1.
329
330 :- public tcltk_mark_current_node_to_be_recomputed_wo_timeout/0.
331 tcltk_mark_current_node_to_be_recomputed_wo_timeout :-
332 current_state_id(CurID), print(recomputing(CurID)),nl,
333 tcltk_mark_node_for_recomputed(CurID),
334 (use_no_timeout(CurID) -> true ; assert(use_no_timeout(CurID))).
335 :- public tcltk_mark_current_node_to_be_recomputed_with_random_enum/0. % used for recomputing a state with random enumeration
336 tcltk_mark_current_node_to_be_recomputed_with_random_enum :-
337 current_state_id(CurID), print(recomputing(CurID)),nl,
338 tcltk_mark_node_for_recomputed(CurID),
339 % TO DO: delete all destinations only reached by CurID
340 retractall(transition(CurID,_,_,_)),
341 temporary_set_preference(randomise_enumeration_order,true,PREV),
342 assert(prev_randomise_enumeration_order(PREV)).
343 :- public tcltk_finish_current_node_to_be_recomputed_with_random_enum/0.
344 tcltk_finish_current_node_to_be_recomputed_with_random_enum :-
345 retract(prev_randomise_enumeration_order(PREV)),
346 reset_temporary_preference(randomise_enumeration_order,PREV).
347
348 tcltk_mark_node_for_recomputed(ID) :-
349 (not_all_transitions_added(ID) -> true
350 ; add_id_at_front(ID)),
351 retractall(max_reached_for_node(ID)),
352 retractall(time_out_for_node(ID,_,_)),
353 (transition(ID,'$partial_setup_constants',ID2)
354 -> delete_node(ID2) ; true),
355 retractall(state_space:transition(ID,'$partial_setup_constants',_,_)).
356
357 transitions_computed_for_node(ID) :-
358 \+(not_all_transitions_added(ID)),
359 \+ is_not_interesting(ID).
360
361
362
363
364
365
366 equivalent_states(S1,true,S2,true) :- \+(\+(S1=S2)). /* IMPROVE, may even
367 allow hash functions */
368
369 :- public tcltk_set_initial_machine/0.
370 tcltk_set_initial_machine :-
371 tcltk_clear_machine,
372 b_set_initial_machine,
373 set_animation_mode(b).
374
375 % new profiler
376 %:- use_module('../extensions/profiler/profiler.pl').
377
378 % old profiler
379 :- use_module(runtime_profiler,[reset_runtime_profiler/0]).
380
381 % the following clears the entire state space and uses the current state as now starting initial state
382 tcltk_clear_state_space_and_refocus_to_current_state :-
383 Op = 'REFOCUS-ANIMATOR',
384 current_expression(_CurID,CurState),
385 (CurState = const_and_vars(ConstID,VarState) ->
386 visited_expression(ConstID,ConstState),
387 transition(root,SetupConstantAction,_,ConstID)
388 ; ConstState=[]),
389 announce_event(reset_specification),
390 (ConstState=[]
391 -> add_trans_id(root,Op,CurState,[],NewID,[],_TransId)
392 ; add_trans_id(root,SetupConstantAction,ConstState,[],NewConstID,[],_),
393 add_trans_id(NewConstID,Op,const_and_vars(NewConstID,VarState),[],NewID,[],_),
394 (retract_open_node(NewConstID) -> true ; true),
395 tcltk_goto_state(Op,NewConstID)
396 ),
397 tcltk_goto_state(Op,NewID),
398 (retract_open_node(root) -> true ; true).
399
400 :- use_module(eval_strings,[reset_eval_strings/0]).
401 :- use_module(eventhandling, [announce_event/1]).
402 tcltk_clear_machine :-
403 announce_event(reset_specification),
404 announce_event(clear_specification),
405 retractall(cached_state_as_strings(_,_)),
406 set_animation_mode(b),
407 bmachine:b_set_empty_machine,
408 reset_errors,
409 reset_eval_strings,
410 % reset_dynamics, % new profiler
411 % Now done via event handling: b_interpreter:reset_b_interpreter,reset_model_checker,
412 % bmachine:b_machine_reset,
413 % haskell_csp:clear_cspm_spec, state_space_initialise, reduce_graph_state_space:reduce_graph_reset, reset_runtime_profiler reset_refinement_checker
414 % b_machine_hierarchy:reset_hierarchy, reset_all_temporary_preferences,
415 % retractall(refinement_checker: generated_predeterministic_refinement(_,_,_)),
416 % retractall(refinement_checker: determinism_check_div_found(_)),
417 % retractall(counterexample_node(_)), retractall(counterexample_op(_))
418 % clear_dynamic_predicates_for_POR,
419 % clear_dynamic_predicates_for_PGE,
420 garbage_collect_atoms. % reclaim atoms if possible
421
422 :- use_module(prob2_interface, [start_animation/0, update_preferences_from_spec/0]).
423 :- public tcltk_initialise/0.
424 tcltk_initialise :-
425 prob2_interface:update_preferences_from_spec,
426 prob2_interface:start_animation,
427 tcltk_try_reload.
428
429 :- public tcltk_reset/0.
430 tcltk_reset :- reset_errors,
431 history(H), op_trace_ids(T),
432 current_state_id(CurID),
433 (forward_history(FH) -> true ; FH=[]),
434 state_space_reset,
435 gen_forward_history(T,[CurID|H],FH,FwdHist),
436 retractall(forward_history(_)),
437 assert(forward_history(FwdHist)).
438
439 gen_forward_history([],H,R,R) :- (H=[root] -> true ; print(unexpected_remaining_hist(H)),nl).
440 gen_forward_history([A|TT],[ID|TH],Acc,Res) :-
441 gen_forward_history(TT,TH,[forward(ID,A)|Acc],Res).
442
443
444
445 /* ---- getting available options ----- */
446
447 :- public tcltk_get_options_dest_info/1.
448 tcltk_get_options_dest_info(L) :-
449 tcltk_get_options_dest_info(L,[]). %[no_query_operations]).
450 tcltk_get_options_dest_info(list(DestinationInfos),Options) :-
451 debug_println(9,start_tcltk_get_options_dest_info),
452 % get a list of all options which are skip events
453 current_state_id(CurID),
454 compute_all_transitions_if_necessary(CurID),
455 findall(Res, (transition(CurID,ActionAsTerm,ID), % check no_query_operations
456 (member(no_query_operations,Options) -> \+ query_op_transition(ActionAsTerm) ; true),
457 option_dest_info(ID,ActionAsTerm,CurID,Res)),DestinationInfos).
458
459 option_dest_info(DestID,ActionAsTerm,CurID,Res) :- DestID=CurID,!,
460 (query_op_transition(ActionAsTerm) -> Res=query ; Res=skip).
461 option_dest_info(DestID,_,_,Res) :- not_all_transitions_added(DestID),!, Res=open.
462 option_dest_info(DestID,_,_,Res) :- invariant_violated(DestID),!,Res=invariant_violated.
463 option_dest_info(DestID,_,_,Res) :- is_deadlocked(DestID),!,Res=deadlock.
464 option_dest_info(_DestID,_,_,unknown).
465
466 query_op_transition(Term) :- b_or_z_mode,
467 get_operation_name(Term,OpName),
468 b_operation_cannot_modify_state(OpName).
469
470 :- public tcltk_get_options/1.
471 tcltk_get_options(O) :-
472 tcltk_get_options(O,[]). %[no_query_operations]).
473 tcltk_get_options(list(Options),Parameters) :-
474 current_state_id(CurID), debug_println(9,start_tcltk_get_options(CurID)),
475 on_exception(user_interrupt_signal,
476 tcltk_compute_options(CurID,TransSpecs),
477 (assert_time_out_for_node(CurID,'unspecified_operation_interrupted_by_user',user_interrupt_signal),
478 tcltk_get_computed_options(CurID,TransSpecs))
479 ),
480 extract_actions(TransSpecs,CurID,Parameters,ActionsAndIDs,Actions),
481 set_current_options(ActionsAndIDs),
482 %print(Actions),nl,
483 debug_println(9,finished_tcltk_get_options(CurID)),
484 Actions = Options.
485
486 :- use_module(tools_timeout,[time_out_call/2]).
487 :- use_module(translate,[translate_event_with_src_and_target_id/4]).
488 extract_actions([],_,_,[],[]).
489 extract_actions([(_,Term,_)|T],CurID,Parameters,Srest,ET) :-
490 member(no_query_operations,Parameters),
491 query_op_transition(Term),
492 !,
493 extract_actions(T,CurID,Parameters,Srest,ET).
494 extract_actions([(ActionId,Term,Dst)|T],CurID,Parameters,[(ActionId,Str,Term,Dst)|Srest],[Str|ET]) :-
495 time_out_call(translate_event_with_src_and_target_id(Term,CurID,Dst,Str),
496 Str='**TIMEOUT**'),
497 extract_actions(T,CurID,Parameters,Srest,ET).
498
499
500 compute_state_information_if_necessary(CurID) :-
501 compute_all_transitions_if_necessary(CurID,true).
502
503 :- public tcltk_compute_options/2.
504 tcltk_compute_options(CurID,ActionsAndIDs) :-
505 compute_state_information_if_necessary(CurID),
506 %print(found_transitions(CurID)),nl,
507 tcltk_get_computed_options(CurID,ActionsAndIDs).
508
509 tcltk_get_computed_options(CurID,ActionsAndIDs) :-
510 findall((ActId,ActionAsTerm,DestID),
511 transition(CurID,ActionAsTerm,ActId,DestID),
512 % TO DO: sort or group, especially if we randomize transition/3
513 ActionsAndIDs).
514
515 :- public tcltk_get_status/3.
516 tcltk_get_status(INVVIOLATED,MAXREACHED,TIMEOUT) :- debug_println(9,start_tcltk_get_status),
517 current_state_id(CurID),
518 (time_out_for_invariant(CurID) -> INVVIOLATED = 2
519 ; invariant_violated(CurID) -> INVVIOLATED = 1
520 ; not_invariant_checked(CurID) -> INVVIOLATED = 3
521 ; otherwise -> INVVIOLATED = 0
522 ),
523 (max_reached_for_node(CurID) -> MAXREACHED = 1 ; MAXREACHED = 0),
524 (time_out_for_node(CurID,_,time_out) -> TIMEOUT = 1
525 ; time_out_for_node(CurID,_,user_interrupt_signal) -> TIMEOUT = 3 % CTRL-C
526 ; time_out_for_node(CurID,_,virtual_time_out(kodkod_timeout)) -> TIMEOUT = 1 % KODKOD; regular time-out
527 ; time_out_for_node(CurID,_,_) -> TIMEOUT = 2 % virtual_time_out
528 ; TIMEOUT = 0),
529 debug_println(9,got_status(INVVIOLATED,MAXREACHED,TIMEOUT)).
530
531
532 %%fd_copy_term(X,Y,true) :- copy_term(X,Y).
533
534
535
536 /* --------------------------------------------------------------------- */
537 :- public tcltk_get_history/1.
538 tcltk_get_history(list(StringHistory)) :- debug_println(9,start_tcltk_get_trace),
539 get_action_trace(History),
540 convert_trace_to_list_of_strings(History,StringHistory).
541
542 convert_trace_to_list_of_strings([],[]).
543 convert_trace_to_list_of_strings([action(AS,_)|T],[AS|CT]) :- !,
544 %truncate_atom(AS,1000,TruncatedAS), % especially SETUP_CONSTANTS, INITIALISATION can be very large; leading to performance issues
545 % get_action_trace now truncates
546 convert_trace_to_list_of_strings(T,CT).
547 convert_trace_to_list_of_strings([H|T],[H|CT]) :- convert_trace_to_list_of_strings(T,CT).
548
549
550 /* --------------------------------------------------------------------- */
551
552 :- dynamic cached_state_as_strings/2.
553 :- public tcltk_get_state/1.
554 %tcltk_get_state(list(List)) :- !,List=[]. % comment in to disable State Properties View in ProB Tcl/Tk
555 tcltk_get_state(list(List)) :- debug_println(9,start_tcltk_get_state),
556 current_expression(CurID,CurState),
557 compute_state_information_if_necessary(CurID),
558 (time_out_for_invariant(CurID) -> List = [invariant_time_out|StateAsStrings]
559 ; invariant_violated(CurID) -> List = [invariant_violated|StateAsStrings]
560 ; invariant_not_yet_checked(CurID) -> List = [invariant_not_checked|StateAsStrings]
561 ; CurID=root -> List = StateAsStrings
562 ; CurState = concrete_constants(_) -> List = StateAsStrings
563 ; specfile:b_or_z_mode -> List=[invariant_ok|StateAsStrings] % only in b_or_z_mode do we add not_invariant_checked facts and check invariant while model checking/animating
564 ; List=StateAsStrings),
565 (cached_state_as_strings(CurID,StateAsStrings) % TO DO: separate constant / variable properties ?
566 -> true
567 ; retractall(cached_state_as_strings(_,_)),
568 time_out_call(tcltk_get_state(StateAsStrings,CurState),
569 StateAsStrings = ['***TIMEOUT-PROPERTY***']),
570 assert(cached_state_as_strings(CurID,StateAsStrings))
571 ),
572 debug_println(9,finished_tcltk_get_state).
573
574 :- public tcltk_get_state/2.
575 tcltk_get_state(StateAsStrings,State) :-
576 %print(get_state),nl,
577 findall(Prop,property(State,Prop),StateProps),
578 %print(translating(StateProps)),nl,
579 translate:translate_properties_with_limit(StateProps,StateAsStrings).
580 %print(translated(StateAsStrings)),nl.
581
582 :- dynamic current_state_errors/1.
583
584 :- public tcltk_get_state_errors/1.
585 tcltk_get_state_errors(list(ErrorsAsStrings)) :-
586 current_state_id(CurID),
587 findall(Error,( state_error(CurID,_,Error), Error \== invariant_violated ), Errors),
588 ~~mnf(tcltk_get_state,translate:translate_state_errors(Errors,ErrorsAsStrings)),
589 retractall(current_state_errors(_)),
590 assert(current_state_errors(Errors)).
591
592 :- dynamic last_detailed_error/2.
593 :- public tcltk_get_detailed_state_error/6.
594 tcltk_get_detailed_state_error(Num,ErrorMsg,Srow,Scol,Erow,Ecol) :-
595 retractall(last_detailed_error(_,_)),
596 current_state_errors(Errors),
597 nth0(Num,Errors,Error),
598 !, %print(explaining(Error)),nl,
599 explain_state_error(Error,Span,ErrorMsg), %print(span(Span)),nl,
600 assert(last_detailed_error(Span,ErrorMsg)), % save info, so that we can debug if Span contains a span_predicate
601 %(generate_dot_from_last_span_predicate('~/Desktop/err.dot') -> true ; true),
602 (extract_line_col_for_main_file(Span,Srow,Scol,Erow,Ecol)
603 -> true
604 ; Srow= -1, Scol= -1, Erow= -2, Ecol= -2).
605
606 can_generate_dot_from_last_state_error :- last_detailed_error(span_predicate(_,_,_),_).
607 generate_dot_from_last_span_predicate(FileName) :-
608 last_detailed_error(span_predicate(P,LS,State),_ErrorMsg), % also works with expressions
609 write_dot_file_for_pred_expr_and_state(P, LS, State,FileName).
610
611 :- public tcltk_current_state_invariant_violated/0.
612 tcltk_current_state_invariant_violated :-
613 current_state_id(CurID),
614 invariant_violated(CurID).
615
616 tcltk_state_exists_with_invariant_violated :-
617 (invariant_violated(_) -> true).
618
619 /* --------------------------------------------------------------------- */
620
621 :- public tcltk_save_history_as_trace_file/1.
622 :- use_module(b_trace_checking, [tcltk_save_history_as_trace_file/2]).
623 tcltk_save_history_as_trace_file(File) :-
624 tcltk_save_history_as_trace_file(prolog,File).
625
626
627 /* --------------------------------------------------------------------- */
628
629 :- use_module(translate, [get_bexpression_column_template/4]).
630 :- meta_predicate call_pred_on_expanded_state(3,-,-,-).
631 :- meta_predicate map_over_history(3,-).
632
633 evaluate_bexpr_over_state(Stream,Expr,ValueTemplate,Columns,ResultColStrings,BState,OpName) :-
634 format(Stream,'~w,',[OpName]),
635 b_compute_expression_with_prob_ids(Expr,BState,Value),
636 copy_term((ValueTemplate,Columns),(Value,ResultCols)),
637 my_print_csv_value(ResultCols,Stream),
638 maplist(translate:translate_bvalue,ResultCols,ResultColStrings),
639 nl(Stream).
640
641 :- public evaluate_expression_over_history_to_csv_file/2.
642 % evaluate an expression over the history and save the result to a CSV file
643 evaluate_expression_over_history_to_csv_file(Expr,File) :-
644 parse_machine_expression(Expr,TypedExpr),
645 get_bexpression_column_template(TypedExpr,ValueTemplate,ColHeaders,Columns),
646 format('Writing CSV file: ~w~n',[File]),
647 open(File,write,Stream),
648 format(Stream,'OPERATION,',[]),
649 my_print_csv_atoms(ColHeaders,Stream),
650 call_cleanup(map_over_history(evaluate_bexpr_over_state(Stream,TypedExpr,ValueTemplate,Columns),_),
651 close(Stream)),
652 format('Finished writing CSV file: ~w~n',[File]).
653
654 :- public tcltk_evaluate_expression_over_history/2.
655 tcltk_evaluate_expression_over_history(Expr,list([list(['OPERATION','State Id'|ColHeaders])|ColumnLists])) :-
656 parse_machine_expression(Expr,TypedExpr),
657 get_bexpression_column_template(TypedExpr,ValueTemplate,ColHeaders,Columns),
658 map_over_history(evaluate_bexpr_over_state(user_output,TypedExpr,ValueTemplate,Columns),
659 ColumnLists).
660
661 map_over_history(Pred,ResColumnLists) :-
662 history(H), current_state_id(CurID),
663 reverse([CurID|H],RH),
664 state_space:trace(T), reverse(T,RT),
665 maplist(call_pred_on_expanded_state(Pred),RH,[action(root,root)|RT],ColumnLists),
666 prune_list(ColumnLists,ResColumnLists).
667 % remove unknown elements at front for Tk
668 prune_list([unknown|T],Res) :- !, prune_list(T,Res).
669 prune_list(R,R).
670
671 call_pred_on_expanded_state(_Pred,root,_,ColList) :- !, ColList=unknown.
672 call_pred_on_expanded_state(Pred,StateId,action(_,ActionTerm),ResColList) :- print(StateId),nl,
673 specfile:get_operation_name(ActionTerm,OpName),
674 format('Processing state ~w (reached via ~w)~n',[StateId,OpName]),
675 visited_expression(StateId,State),
676 (state_corresponds_to_initialised_b_machine(State,BState)
677 -> call(Pred,ColList,BState,OpName), ResColList = list([OpName,StateId|ColList])
678 ; ResColList = unknown ).
679
680 :- use_module(b_global_sets,[add_prob_deferred_set_elements_to_store/3]).
681 b_compute_expression_with_prob_ids(Expr,BState,Value) :-
682 add_prob_deferred_set_elements_to_store(BState,BState1,visible),
683 b_interpreter:b_compute_expression_nowf(Expr,[],BState1,Value).
684
685
686 my_print_csv_atoms([A,B|T],Stream) :- !, format(Stream,'"~w",',[A]),
687 my_print_csv_atoms([B|T],Stream).
688 my_print_csv_atoms([A],Stream) :- format(Stream,'"~w"~n',[A]).
689
690 my_print_csv_value([A,B|T],Stream) :- !,
691 my_print_csv_value([A],Stream),
692 write(Stream,','),
693 my_print_csv_value([B|T],Stream).
694 my_print_csv_value([V],Stream) :-
695 (no_quotes_necessary(V) -> true ; write(Stream,'"')),
696 translate:print_bvalue_stream(Stream,V),
697 (no_quotes_necessary(V) -> true ; write(Stream,'"')).
698
699 no_quotes_necessary(int(_)).
700 no_quotes_necessary(pred_false).
701 no_quotes_necessary(pred_true).
702
703
704 /* --------------------------------------------------------------------- */
705
706 :- public tcltk_execute_until/1.
707 tcltk_execute_until(FormulaAsAtom) :-
708 (ltl_tools: temporal_parser(FormulaAsAtom,ltl,Ltl) ->
709 true
710 ; otherwise ->
711 add_error(ltl,'LTL Parser failed: ',FormulaAsAtom),fail),
712 ( Ltl=syntax_error ->
713 add_error(ltl,'Syntax error while parsing: ',FormulaAsAtom),fail
714 ; otherwise ->
715 preprocess_formula(Ltl,Ltl2)
716 ),
717 current_state_id(CurID),
718 prob2_interface: find_trace1(CurID,Ltl2,no_loop,1000,Trace,_Result),
719 %TODO: check if result is deadlock. Will not fail.
720 update_history_from_trace(Trace).
721
722 update_history_from_trace([]). % TODO: Can we get an empty trace from find_trace predicate?
723 update_history_from_trace([op(OpID,_Name,CurID,NextID)]) :-
724 add_id_to_history(CurID),
725 add_to_op_trace_ids(OpID),
726 add_id_to_history(NextID),
727 set_id_as_current_state(NextID).
728 update_history_from_trace([op(OpID,_Name,CurID,NextID)|T]) :-
729 add_id_to_history(CurID),
730 add_to_op_trace_ids(OpID),
731 add_id_to_history(NextID),
732 update_history_from_trace(T).
733
734 set_id_as_current_state(CurID) :-
735 retract(current_state_id(_ID)),
736 assert(current_state_id(CurID)).
737
738 :- public tcltk_random_perform/0.
739 tcltk_random_perform :- tcltk_random_perform(_).
740 tcltk_random_perform(ActionId) :-
741 current_options(Options),
742 length(Options,Len),
743 (Len>0
744 -> L1 is Len+1,
745 random(1,L1,RanChoice),
746 tcltk_perform_nr_option(RanChoice,Options,ActionId)
747 ; true
748 ).
749
750 :- public tcltk_get_line_col/5.
751 tcltk_get_line_col(Nr,list(StartLine),list(StartCol),list(EndLine),list(EndCol)) :- /* just get the location in the source code */
752 current_options(Options),
753 nth1(Nr,Options,(_Id,_Action,ActionAsTerm,_NewID)),
754 %print(get_source_text(ActionAsTerm)),nl,
755 time_out_call(get_source_text_positions(ActionAsTerm,StartLine,StartCol,EndLine,EndCol),
756 add_error_and_fail(tcltk_get_line_col,'Timeout determining source code position: ',ActionAsTerm)),
757 StartLine \= []. % otherwise fail
758 % print(startlines(StartLine)),nl,print(startcols(StartCol)),nl,
759 % print(endlines(EndLine)),nl, print(endcol(EndCol)),nl.
760
761 tcltk_is_sync_event(Nr) :-
762 current_options(Options),
763 nth1(Nr,Options,(_Id,_Action,ActionAsTerm,_NewID)),
764 extract_span_from_event(ActionAsTerm,SPAN,_,_),
765 extract_span_info(SPAN,Info),
766 % print(extracted_span_info_for_sync(Info,SPAN)),nl,
767 member(sharing,Info).
768
769 % counter-part to tcltk_get_options, to execute the option/operation number Nr in that list
770 tcltk_perform_nr(Nr) :-
771 current_options(Options),
772 tcltk_perform_nr_option(Nr,Options,_).
773
774 :- public tcltk_perform_nr_option/3.
775 tcltk_perform_nr_option(Nr,Options,ActionId) :-
776 (nth1(Nr,Options,(ActionId,_Action,ActionAsTerm,NewID))
777 -> (forward_history([forward(NewID,ActionId)|_FwdHist])
778 -> tcltk_forward
779 ; tcltk_perform_action_term(ActionAsTerm,NewID),
780 retractall(forward_history(_))
781 )
782 ; tcltk_backtrack /* interpret as backtrack */
783 ).
784
785
786 tcltk_can_backtrack :- history([_|_]).
787
788 :- public tcltk_backtrack/0.
789 tcltk_backtrack :- \+ tcltk_can_backtrack,!,
790 print_message('Cannot backtrack'),fail.
791 tcltk_backtrack :-
792 remove_from_op_trace_ids(LastTraceH),
793 retract(history(History)),
794 retract(current_state_id(CurID)),!,
795 History= [LastID|EHist],
796 assert(history(EHist)),
797 %visited_expression(LastID,LastExpr,LastBody),
798 assert(current_state_id(LastID)),
799 (retract(forward_history(FwdHist)) -> true ; FwdHist=[]),
800 assert(forward_history([forward(CurID,LastTraceH)|FwdHist])).
801 :- public tcltk_backtrack/1. % used for right-clicks in history
802 tcltk_backtrack(N) :- N =< 0, !.
803 tcltk_backtrack(N) :- tcltk_backtrack, N1 is N-1, tcltk_backtrack(N1).
804
805 :- dynamic saved_forward_history/2.
806 :- volatile saved_forward_history/2.
807
808 :- public tcltk_prepare_for_reload/0.
809 % save certain information to restore when reload is completed:
810 tcltk_prepare_for_reload :- retractall(saved_forward_history(_,_)),
811 get_action_term_trace(TrA),reverse(TrA,Tr),
812 %print(prepare_reloading(Tr)),nl,
813 maplist(gen_unknown_forward,Tr,SavedForwardHistory),
814 % TO DO: add current forward history as well
815 animation_mode(Mode),
816 assert(saved_forward_history(SavedForwardHistory,Mode)).
817
818 gen_unknown_forward(Step,forward('$UNKNOWN',Step)).
819
820 % try reloading certain information from previous load of same model
821 tcltk_try_reload :-
822 retract(saved_forward_history(SavedForwardHistory,Mode)),
823 animation_mode(Mode), % we are in the same mode as when saved
824 !,
825 % TO DO: also retractall in other places
826 %print(reloading(SavedForwardHistory)),nl,
827 retractall(forward_history(_)),
828 assert(forward_history(SavedForwardHistory)).
829 tcltk_try_reload.
830
831 :- public tcltk_fast_forward/0.
832 % go forward while possible
833 tcltk_fast_forward :- tcltk_can_forward,!, tcltk_forward,
834 current_state_id(CurID),
835 compute_state_information_if_necessary(CurID),
836 tcltk_fast_forward.
837 tcltk_fast_forward.
838
839 tcltk_can_forward :- forward_history([_|_]).
840 tcltk_forward :- \+ tcltk_can_forward,!,
841 print_message('Cannot go forward'),fail.
842 tcltk_forward :-
843 retract(forward_history([forward(FwdID,LastTraceH)|FwdHist])),
844 % TO DO: check if FwdID is '$UNKNOWN' -> then try to find successor which can be reached via LastTraceH
845 retract(history(EHist)),
846 retract(current_state_id(CurID)),!,
847 go_forward(FwdID,LastTraceH,FwdHist,CurID,EHist).
848 go_forward('$UNKNOWN',ActionAsTerm,FwdHist,CurID,EHist) :-
849 transition(CurID,ActionAsTerm,TransitionID,FwdID),!,
850 %print(found(CurID,ActionAsTerm,TransitionID,FwdID)),nl,
851 go_forward(FwdID,TransitionID,FwdHist,CurID,EHist).
852 % TO DO: try and execute by predicat in case max_reached is true !
853 go_forward('$UNKNOWN',ActionAsTerm,FwdHist,CurID,EHist) :-
854 is_initialisation_op(ActionAsTerm),
855 % maybe PROPERTIES/INITIALISATION has changed; try and replay with other values
856 transition(CurID,ActionAsTerm2,TransitionID,FwdID),
857 is_initialisation_op(ActionAsTerm2),
858 !,
859 %print(found(CurID,ActionAsTerm,TransitionID,FwdID)),nl,
860 translate_event(ActionAsTerm,Action),
861 format('Could not replay ~w.~nUsing other possible transition instead.~n',[Action]),
862 go_forward(FwdID,TransitionID,FwdHist,CurID,EHist).
863 go_forward('$UNKNOWN',ActionAsTerm,_FwdHist,CurID,EHist) :- !,
864 assert(forward_history([])),
865 assert(history(EHist)),
866 assert(current_state_id(CurID)),
867 translate_event(ActionAsTerm,Action),
868 add_error(tcltk_forward,'Cannot replay step after reload: ',Action).
869 go_forward(FwdID,LastTraceH,FwdHist,CurID,EHist) :-
870 assert(forward_history(FwdHist)),
871 assert(history([CurID|EHist])),
872 add_to_op_trace_ids(LastTraceH),
873 assert(current_state_id(FwdID)),
874 re_execute_transition_if_necessary(CurID,LastTraceH,FwdID).
875 %visited_expression(FwdID,FwdExpr,FwdBody).
876
877 is_initialisation_op(Op) :-
878 (functor(Op,'$setup_constants',_) ;functor(Op,'$initialise_machine',_)).
879
880 % re-execute operation with side-effects if necessary and if preference set
881 % TO DO: tie into tcltk_perform so that not only the forward button but also double click
882 % in operations pane works
883 re_execute_transition_if_necessary(FromID,TransitionID,ToID) :-
884 b_or_z_mode,
885 get_preference(re_execute_operations_with_side_effects,true),
886 bmachine_construction:external_procedure_used(_), % TO DO: check if operation itself has side-effects
887 !,
888 (re_execute_transition(FromID,TransitionID,ToID)
889 -> true
890 ; add_error(tcltk_forward,'Could not re-execute operation: ',TransitionID)).
891 re_execute_transition_if_necessary(_,_,_).
892
893 re_execute_transition(FromID,TransitionID,ToID) :-
894 transition(FromID,ActionTerm,TransitionID,ToID),
895 %%print(trans(ActionTerm)),nl,
896 specfile:get_operation_name(ActionTerm,OpName),
897 debug_println(9,re_executing_operation(OpName,FromID,TransitionID,ToID)),
898 visited_expression(FromID,InState),
899 specfile:b_trans(InState,OpName,ActionTerm,_NewState,_TransInfo),
900 debug_println(9,re_executed(OpName)).
901
902 :- public tcltk_perform_action_string/3.
903 % a version of tcltk_perform_action_term which can be given only the String (e.g., for trace checking)
904 tcltk_perform_action_string(ActionString,ActionAsTerm,NewID) :-
905 current_state_id(CurID),
906 transition(CurID,ActionAsTerm,_,NewID),
907 translate_event_with_src_and_target_id(ActionAsTerm,CurID,NewID,ActionString),
908 tcltk_goto_state(ActionAsTerm,NewID).
909 % translate_event_with_limit(ActionAsTerm,5000,ActionString). % should use same limit as below; otherwise trace checking will fail; ideally we should check ActionString is prefix
910 %translate_event(ActionAsTerm,ActionString).
911
912 :- public tcltk_perform_action_term/2.
913 % perform the Action with term ActionAsTerm leading to new state NewID
914 tcltk_perform_action_term(ActionAsTerm,NewID) :- %print(tcltk_perform_action_term(Action,ActionAsTerm,NewID)),nl,
915 (var(ActionAsTerm)
916 -> add_internal_error('Illegal call: ',tcltk_perform_action_term(ActionAsTerm,NewID)) ; true),
917 tcltk_goto_state(ActionAsTerm,NewID).
918
919 /* allows one to execute an action in term form, from the current state: */
920 %tcltk_perform_action(T,Cur) :- print_message(perf(T,Cur)),fail.
921
922 :- public tcltk_perform_action/2.
923 tcltk_perform_action(ActionAsTerm,NewID) :-
924 current_state_id(CurID),
925 tcltk_perform_action(CurID,ActionAsTerm,NewID).
926 tcltk_perform_action(CurID,ActionAsTerm,NewID) :-
927 tcltk_perform_action(CurID,ActionAsTerm,NewID,_).
928 tcltk_perform_action(CurID,ActionAsTerm,TransitionID,NewStateID) :-
929 transition(CurID,ActionAsTerm,TransitionID,NewStateID),
930 tcltk_goto_state(ActionAsTerm,NewStateID).
931
932 tcltk_no_constants_or_no_inititalisation_found :-
933 (current_expression(root,_) ; current_expression(_,concrete_constants(_))),
934 current_options([]).
935
936 /* ------------ */
937 /* tcltk_open/1 */
938 /* ------------ */
939
940
941 %prolog_check_load_errors :-
942 % (tcltk_find_untyped_consts(ErrRes)
943 % -> add_error(prolog_open,'These constants were not given a proper type:', ErrRes)
944 % ; true),
945 % (tcltk_find_untyped_vars(ErrRes)
946 % -> add_error(prolog_open,'These variables were not given a proper type:', ErrRes)
947 % ; true).
948
949 :- public tcltk_open_b_file_for_minor_mode/2.
950 tcltk_open_b_file_for_minor_mode(File,Minor) :- tcltk_open_b_file(File),
951 set_animation_minor_mode(Minor).
952
953 :- public tcltk_open_b_file/1.
954 tcltk_open_b_file(File) :- print(tcltk_open_b_file(File)),nl,
955 tcltk_clear_machine,
956 set_animation_mode(b),
957 print_message(loading(File)),flush_output,
958 (bmachine:b_load_machine_from_file(File)
959 -> print_message(loaded),
960 set_currently_opened_file(File)
961 ; set_failed_to_open_file(File),
962 fail
963 ).
964
965 :- public tcltk_open_xtl_file/1.
966 :- use_module(xtl_interface,[open_xtl_file/1]).
967 tcltk_open_xtl_file(File) :-
968 tcltk_clear_machine,
969 set_animation_mode(xtl),
970 open_xtl_file(File), set_currently_opened_file(File).
971
972
973 :- public tcltk_open_cspm_file/1.
974 tcltk_open_cspm_file(File) :-
975 tcltk_clear_machine,
976 set_animation_mode(cspm),
977 xtl_interface:open_cspm_file(File), set_currently_opened_file(File).
978
979 :- prob_use_module(xtl_interface).
980 %tcltk_open_promela_file(File) :-
981 % tcltk_clear_machine,
982 % set_animation_mode(promela),
983 % xtl_interface:open_promela_file(File), set_currently_opened_file(File).
984
985 % disabled because Java parser seems broken
986 %tcltk_open_smv_file(File) :-
987 % tcltk_clear_machine,
988 % set_animation_mode(smv),
989 % xtl_interface:open_smv_file(File), set_currently_opened_file(File).
990
991 :- use_module(specfile,[type_check_csp_and_b/0]).
992 :- public tcltk_add_csp_file/1.
993 tcltk_add_csp_file(File) :-
994 unset_animation_minor_modes(L), % we could be in z or tla or eventb mode
995 set_animation_mode(csp_and_b),
996 reset_animation_minor_modes(L),
997 xtl_interface:open_cspm_file(File),
998 notify_change_of_animation_mode,
999 type_check_csp_and_b.
1000
1001 notify_change_of_animation_mode :-
1002 announce_event(change_of_animation_mode).
1003 % clear_applicable_flag. % no done via event handling
1004
1005
1006 :- public tcltk_open_z_file/1.
1007 tcltk_open_z_file(File) :-
1008 tcltk_clear_machine,
1009 tcltk_open_z_file2(File).
1010 tcltk_open_z_file2(File) :-
1011 open_proz_file(File,BMachine),
1012 set_animation_mode(b), set_animation_minor_mode(z),
1013 b_set_typed_machine(BMachine),
1014 set_currently_opened_file(File).
1015
1016 :- use_module(parsercall,[call_fuzz_parser/2]).
1017 tcltk_open_z_tex_file(TexFile) :-
1018 tcltk_clear_machine,
1019 call_fuzz_parser(TexFile,FuzzFile),
1020 tcltk_open_z_file2(FuzzFile).
1021
1022
1023 :- use_module(eclipse_interface,[load_eventb_file/1]).
1024 :- public tcltk_load_packaged_eventb_file/1.
1025 tcltk_load_packaged_eventb_file(File) :-
1026 tcltk_clear_machine,
1027 load_eventb_file(File).
1028
1029 :- use_module(parsercall,[call_alloy2pl_parser/2]).
1030 :- use_module(probsrc('alloy2b/alloy2b'),[load_alloy_ast_prolog_file/1]).
1031 tcltk_open_alloy_file(AlloyFile) :-
1032 tcltk_clear_machine,
1033 start_ms_timer(T1),
1034 formatsilent('Parsing Alloy file: ~w~n',[AlloyFile]),
1035 call_alloy2pl_parser(AlloyFile,PrologFile),
1036 (silent_mode(off) -> stop_ms_walltimer_with_msg(T1,'parsing and type checking: ') ; true),
1037 %printsilent(generated_prolog_ast(PrologFile)),nls,
1038 start_ms_timer(T2),
1039 load_alloy_ast_prolog_file(PrologFile),
1040 (silent_mode(off) -> stop_ms_walltimer_with_msg(T2,'loading and translation to B: ') ; true),
1041 set_currently_opened_file(AlloyFile).
1042
1043 /* --------------------------------------------------------------------- */
1044
1045 tcltk_exists_an_open_node :-
1046 not_all_transitions_added(_) ; not_interesting(_).
1047 tcltk_goto_an_open_node :-
1048 (not_all_transitions_added(ID) ; not_interesting(ID)),!,
1049 tcltk_goto_state(find_open_node,ID).
1050 tcltk_goto_max_reached_node :-
1051 (max_reached_for_node(ID) ; time_out_for_node(ID)),!,
1052 tcltk_goto_state(find_max_reached_node,ID).
1053
1054 tcltk_goto_an_invariant_violation :-
1055 invariant_violated(ID),!,
1056 tcltk_goto_state(find_inv_violation,ID).
1057
1058
1059 tcltk_goto_node_with_id(ToID) :-
1060 current_state_id(ToID),!.
1061 tcltk_goto_node_with_id(ID) :-
1062 visited_expression_id(ID),
1063 tcltk_execute_trace_to_node(ID).
1064 /* --------------------------------------------------------------------- */
1065
1066 % TO DO: clean up and move into model_checker module
1067
1068 tcltk_state_space_only_has_root_node :- transition(root,_,ID),
1069 \+ not_all_transitions_added(ID),!,fail.
1070 tcltk_state_space_only_has_root_node.
1071
1072 tcltk_search_among_existing_nodes(TclTkRes,FindDeadlocks,FindInvViolations,
1073 FindGoal,FindAssViolations) :-
1074 search_among_existing_nodes(Res,FindDeadlocks,FindInvViolations,
1075 FindGoal,FindAssViolations),
1076 translate_error_for_tclk(Res,TclTkRes).
1077
1078 % if tcltk_state_space_only_has_root_node is true: then we should call search_among_existing_nodes before doing open_search to ensure that we uncover state_errors in the root node
1079 search_among_existing_nodes(invariant_violation,_FindDeadlocks,FindInvViolations,
1080 _FindGoal,_FindAssViolations) :-
1081 (get_state_space_stats(_,_,PrN), PrN>100
1082 -> print_message('Search Among Processed Nodes'), print_message(number_of_nodes(PrN)) ; true),
1083 FindInvViolations=1,
1084 (invariant_violated(ResID) -> true
1085 ; find_invariant_violation_among_not_checked_nodes(ResID)),
1086 tcltk_execute_trace_to_node(ResID).
1087 search_among_existing_nodes(DEADLOCK,FindDeadlocks,_,_,_) :-
1088 FindDeadlocks=1,
1089 visited_expression_id(ResID),
1090 transitions_computed_for_node(ResID),
1091 is_deadlocked(ResID),
1092 (time_out_for_node(ResID)
1093 -> DEADLOCK = possible_deadlock_timeout ; DEADLOCK = deadlock),
1094 print_message(deadlock_among_existing_nodes(ResID)),
1095 tcltk_execute_trace_to_node(ResID).
1096 search_among_existing_nodes(goal_found,_,_,FindGoal,_) :-
1097 FindGoal=1,
1098 %visited_expression(ResID,_CurState),
1099 %\+(not_all_transitions_added(ResID)), % if commented out: will also look at open nodes
1100 test_goal_in_node(ResID),
1101 tcltk_execute_trace_to_node(ResID).
1102 search_among_existing_nodes(assertion_violation,_,_,_,FindAssViolations) :-
1103 FindAssViolations=1,
1104 b_machine_has_assertions,
1105 visited_expression(ResID,CurState),
1106 transitions_computed_for_node(ResID),
1107 state_violates_assertions(ResID,CurState),
1108 tcltk_execute_trace_to_node(ResID).
1109 search_among_existing_nodes(ERR,_,_,_,_) :-
1110 state_space:state_error(ResID,_,Error), Error \== invariant_violated,
1111 (Error = abort_error(ERR,_,_,_) -> true ; ERR = state_error),
1112 tcltk_execute_trace_to_node(ResID).
1113 search_among_existing_nodes(all,_,_,_,_).
1114
1115 :- public test_goal_in_node/1.
1116 test_goal_in_node(ResID) :- b_get_machine_goal(Goal),
1117 eclipse_interface:test_boolean_expression_in_node(ResID,Goal).
1118
1119 :- public compute_all_transitions_if_necessary/0.
1120 compute_all_transitions_if_necessary :-
1121 current_state_id(CurID),
1122 compute_all_transitions_if_necessary(CurID,false).
1123 :- public compute_all_transitions_if_necessary/1.
1124 compute_all_transitions_if_necessary(CurID) :-
1125 compute_all_transitions_if_necessary(CurID,false).
1126
1127 compute_all_transitions_if_necessary(CurID,CheckInvariant) :-
1128 (retract_open_node(CurID) % will assert not_invariant_checked
1129 -> set_context_state(CurID),
1130 % first check invariant, relevant if we want to use specialized_inv proof information
1131 visited_expression(CurID,State),
1132 % TO DO: this does not expand concrete_constants: the expansion may be done twice below:
1133 % once for compute_invariant (corresponds_to_b...) and once for compute_all_transitions (prepare_state_for_specfile_trans)
1134 prepare_state_for_specfile_trans(State,PreparedState),
1135 (CheckInvariant==true
1136 -> compute_invariant_if_necessary_and_requested(CurID,PreparedState) ; true),
1137 compute_all_transitions(CurID,PreparedState),
1138 clear_context_state
1139 ; true).
1140 %compute_all_transitions_if_necessary(CurID,CurState) :-
1141 % ((not_all_transitions_added(CurID);not_interesting(CurID))
1142 % -> compute_all_transitions(CurID,CurState) ; true).
1143
1144
1145 compute_invariant_if_necessary_and_requested(ID,State) :-
1146 enter_new_error_scope(ErrScID,compute_invariant_if_necessary_and_requested), % here we setup a new error scope; see comment for force_check_invariantKO below
1147 compute_invariant_if_necessary(ID,State),
1148 exit_error_scope(ErrScID,_ErrOcc,compute_invariant_if_necessary_and_requested). % should we do something with error occured result ?
1149
1150 compute_invariant_if_necessary(ID,State) :-
1151 animation_mode(MODE),compute_invariant_if_necessary(ID,State,MODE).
1152 compute_invariant_if_necessary(ID,State,MODE) :-
1153 ( check_invariantKO(MODE,ID,State) -> true ; true).
1154
1155 check_invariantKO(ID,State) :-
1156 animation_mode(MODE),check_invariantKO(MODE,ID,State).
1157 check_invariantKO(b,ID,State) :-
1158 check_invariantKO2(ID,State).
1159 check_invariantKO(csp_and_b,ID,State) :-
1160 check_invariantKO2(ID,State).
1161
1162
1163 check_invariantKO2(ID,_) :- invariant_violated(ID),!.
1164 check_invariantKO2(ID,CurState) :-
1165 set_invariant_checked(ID), % only succeeds if we haven't checked invariant for ID yet
1166 % print(check_inv(ID)),nl,
1167 state_corresponds_to_initialised_b_machine(CurState,CurBState),
1168 ( preferences:preference(do_invariant_checking,false) -> assert(not_invariant_checked(ID))
1169 ; force_check_invariantKO(ID,CurBState)).
1170
1171 :- meta_predicate catch_clpfd_overflow_call_for_state(-,0,0).
1172
1173 force_check_invariantKO(ID,CurBState) :-
1174 % Note: this checks the invariant without setting up a new error scope
1175 % (Reason: in the model checker it would be relatively expensive to set up an error scope for each state
1176 % the model checker stops anyway when the first error is found and then exits its error scope)
1177 catch_clpfd_overflow_call_for_state(ID,
1178 b_state_violates_invariant(ID,CurBState),true) ->
1179 %(b_state_violates_invariant(ID,CurBState) ->
1180 set_invariant_violated(ID).
1181 % TO DO ?: call state_satisfies_negation_of_invariant if double_evaluation_when_analysing is true ?
1182
1183 % try and find an invariant violation among those nodes that have not yet been checked
1184 find_invariant_violation_among_not_checked_nodes(ID) :-
1185 retract(not_invariant_checked(ID)), %print(checking_invariant(ID)),nl,
1186 visited_expression(ID,State),
1187 state_corresponds_to_initialised_b_machine(State,CurBState),
1188 force_check_invariantKO(ID,CurBState).
1189
1190 % computing ample sets (model_checker.pl)
1191 compute_ample_set(CurID,CurState,POROptions) :-
1192 catch_clpfd_overflow_call_for_state(CurID,compute_ample_set2(CurID,CurState,POROptions),clear_context_state).
1193
1194 % preferences:preference(use_clpfd_solver,false)
1195 compute_all_transitions(CurID,CurState) :-
1196 catch_clpfd_overflow_call_for_state(CurID,compute_all_transitions2(CurID,CurState),clear_context_state).
1197
1198
1199 %catch_clpfd_overflow_call_for_state(_CurID, Call,_ExtraCleanUpCode) :-
1200 % preferences:preference(use_clpfd_solver,false),!, % Overflow should not occur
1201 % call(Call).
1202 :- use_module(clpfd_interface,[catch_clpfd_overflow_call2/2]).
1203 catch_clpfd_overflow_call_for_state(CurID, Call,ExtraCleanUpCode) :-
1204 catch_clpfd_overflow_call2(Call,
1205 ( store_state_error(CurID,'CLPFD_integer_overflow',_),
1206 call(ExtraCleanUpCode)) ).
1207
1208
1209
1210
1211 :- use_module(probsrc(succeed_max),[reset_max_reached/0,max_reached/0, max_reached/1]).
1212 compute_all_transitions2(CurID,CurState) :- /* compute all outgoing transitions for a given node */
1213 % set_context_state(CurID), % error_context is set for each operation below anyway.
1214 reset_max_reached,
1215 prepare_state_for_specfile_trans(CurState,PreparedCurState), % will perform unpacking of constants just once, for example
1216 ((time_out_preference_disabled % e.g., when using probcli -disable_time_out
1217 ; use_no_timeout(CurID))
1218 -> add_transitions_fail_loop(CurID,PreparedCurState)
1219 ; preferences:preference(time_out,CurTO),
1220 add_transitions__with_timeout_fail_loop(CurID,PreparedCurState,CurTO)
1221 ),
1222 add_partial_transitions(CurID,PreparedCurState), % also copies unsat component infos
1223 (max_reached -> assert_max_reached_for_node(CurID),MaxReached=true ; MaxReached=false), % TO DO: use max_reached(OpID)
1224 (CurID==root -> save_constants(MaxReached) ; add_new_transitions_to_cache(CurID))
1225 . %,clear_context_state.
1226
1227 add_transitions_fail_loop(CurID,CurState) :-
1228 specfile_possible_trans_name_for_successors(CurState,ActionName),
1229 %print(adding_transition_no_timeout(CurID,ActionName)),nl,
1230 set_error_context(operation(ActionName,CurID)),
1231 add_transition(CurID,CurState,ActionName,_NewId), % TO DO: transmit animation_mode value?
1232 fail.
1233 add_transitions_fail_loop(_,_) :- clear_error_context.
1234
1235 :- use_module(library(timeout),[time_out/3]).
1236 my_timeout_test(1000000) :- print('.'), !, my_timeout_test(0).
1237 my_timeout_test(X) :- X1 is X+1, my_timeout_test(X1).
1238 :- public my_timeout_test/0.
1239 my_timeout_test :- time_out(my_timeout_test(0),500,TO), nl,
1240 print(time_out_result(TO)),nl, TO==time_out.
1241 :- assert_must_succeed(user:my_timeout_test).
1242
1243 add_transitions__with_timeout_fail_loop(CurID,CurState,CurTO) :-
1244 enter_new_error_scope(Level,add_transitions__with_timeout_fail_loop),
1245 call_cleanup(add_transitions__with_timeout_fail_loop2(Level,CurID,CurState,CurTO),
1246 exit_error_scope(Level,_,add_transitions__with_timeout_fail_loop)).
1247
1248 % new profiler
1249 %:- use_module('../extensions/profiler/profiler.pl').
1250 %:- use_module('../extensions/profiler/profiler_te.pl').
1251 %:- enable_profiling(add_transions__with_timeout_fail_loop2/4).
1252
1253 % old profiler
1254 :- use_module(runtime_profiler,[profile_failure_driven_loop/2]).
1255
1256 add_transitions__with_timeout_fail_loop2(Level,CurID,CurState,CurTO) :- % statistics(runtime,_),
1257 % TO DO: prepare computing the state: expanding const and vars, unpacking, ...
1258 ? specfile_possible_trans_name_for_successors(CurState,ActionName),
1259 profile_failure_driven_loop(ActionName,CurID),
1260 % Note: we enumerate possible transition names so that we can catch the time-out per name !
1261 % statistics(runtime,[T1,DeltaT]), print(delta_time(ActionName,DeltaT)),nl, %%
1262 % first enumerate possible Operations/... to obtain timeout per operation/...
1263 % TO DO: divide CurTO by number of transitions ???
1264 % We could also decide to have one time-out per state, only if that one is triggered move to
1265 % finer-grained timeouts
1266 % For probcli ../prob_examples/public_examples/B/Benchmarks/Cruise_finite1.mch --model-check, there are 35360 calls to timeout/3 (one per state the model checker reached and per transition group), with -disable-timeout none
1267 % In SICS 4.3.5 the runtime increased from 1.480 to 2.270 seconds = 0.022 ms per timeout call
1268 % In SICS 4.4.1 the runtime increased from 1.494 to 3.033 seconds. = 0.044 ms per timeout call.
1269 %% statistics(runtime,[T1,_]), print(try(ActionName,T1)),nl,%%
1270 set_error_context(operation(ActionName,CurID)),
1271 ? time_out_with_enum_warning_for_findall_in_current_error_scope(Level,add_transition(CurID,CurState,ActionName,_NewId),CurTO,TimeOutRes),
1272 %% statistics(runtime,[T2,_]), TDiff is T2-T1, print(added_transition(CurID,ActionName,TDiff,TimeOutRes)),nl, %%
1273 %% add_transition(CurID,CurState,ActionName,_NewId) ,
1274 ((TimeOutRes==time_out ; nonvar(TimeOutRes),TimeOutRes=virtual_time_out(_), \+ max_reached(ActionName))
1275 % virtual time outs not relevant if we have already stopped earlier anyway; TO DO: does not seem to work for INITIALISATION
1276 -> (TimeOutRes=virtual_time_out(_) -> true
1277 ; print_message('TIME OUT: '),print_message(CurID),
1278 print_message(CurTO),print_message(ActionName)
1279 ),
1280 (var(ActionName)
1281 -> assert_time_out_for_node(CurID,'unspecified_operation',TimeOutRes)
1282 ; assert_time_out_for_node(CurID,ActionName,TimeOutRes)) % TO DO: assert info per ActionSkeleton ?
1283 ; true
1284 ),fail.
1285 add_transitions__with_timeout_fail_loop2(_,_,_,_) :- clear_error_context.
1286 % statistics(runtime,[_,DeltaT]), print(delta_time(end,DeltaT)),nl.
1287
1288
1289 add_transition(CurID,CurState,ActionName,PreviousSuccessorID) :-
1290 %(var(ActionName) -> add_error_fail(add_transition,'ActionName is a variable: ',CurID) ; true),
1291 nonvar(ActionName), % can happen in CSP, CSP||B, XTL, ... modes but also in B mode
1292 candidate_operation_for_reuse(ActionName), % can only be true when try_operation_reuse preference is true
1293 retract(reuse_operation(CurID,ActionName,PreviousID,_FromOp)),!,
1294 % we don't have to compute the operation again; simply reuse pre-computed effect
1295 b_get_operation_normalized_read_write_info(ActionName,_Read,WrittenVariables),
1296 build_up_b_real_operation(ActionName,ActionTemplate), % missing add any parameters
1297 % print(reusing_operation(ActionName,ActionTemplate, from(PreviousID), for(CurID),via(FromOp))),nl,
1298 transition(PreviousID,ActionTemplate,TransID,PreviousSuccessorID),
1299 findall(Info,transition_info(TransID,Info),TransInfos),
1300 visited_expression(PreviousSuccessorID,PreviousExpression,true),
1301 ~~mnf(patch_state(CurState,WrittenVariables,PreviousExpression,NewExpression)),
1302 % (specfile_trans(CurState,ActionName,ActionTemplate,NewExpression,_,_)
1303 % -> true ; add_error(add_transition,'Mismatch in operation reuse',ActionName),
1304 % print(CurID),nl, print(ActionName), print(' via '), print(via(PrevOp)),nl),
1305 ~~mnf(add_trans_id(CurID,ActionTemplate,NewExpression,[],_NewID,TransInfos,_)).
1306 :- if(debug:global_debug_flag).
1307 add_transition(CurID,CurState,ActionName,NewId) :-
1308 %debug:watch(30,specfile:specfile_trans(CurState,ActionName,Act,NewExpression,TransInfo,Residue)),
1309 %debug:watch(30,user:add_trans_id(CurID,Act,NewExpression,Residue,_NewId,TransInfo,_)).
1310 debug:timer_call(ActionName,specfile:specfile_trans(CurState,ActionName,Act,NewExpression,TransInfo,Residue)),
1311 debug:timer_call(user:add_trans_id(CurID,Act,NewExpression,Residue,NewId,TransInfo,_)).
1312 :- else.
1313 add_transition(CurID,CurState,ActionName,NewId) :-
1314 /* ActionName maybe pre-instantiated */
1315 ? specfile_trans(CurState,ActionName,Act,NewExpression,TransInfo,Residue),
1316 %% print_bt_message(specfile_trans(CurState,ActionName,Act,NewExpression,TransInfo,Residue)), %%
1317 add_trans_id(CurID,Act,NewExpression,Residue,NewId,TransInfo,_).
1318 :- endif.
1319
1320 patch_state(const_and_vars(ConstID,Vars),WrittenVariables,PrevState,
1321 const_and_vars(ConstID,PatchedVars)) :- !,
1322 patch_state(Vars,WrittenVariables,PrevState,PatchedVars).
1323 patch_state(expanded_const_and_vars(ConstID,Vars,_FullState),WrittenVariables,PrevState,
1324 const_and_vars(ConstID,PatchedVars)) :- !,
1325 patch_state(Vars,WrittenVariables,PrevState,PatchedVars).
1326 %patch_state(FullState,WrittenVariables,PrevState,PatchedFullState). % do we need to patch both ?
1327 patch_state([],_Write,_Prev,[]) :- !.
1328 patch_state([bind(Variable,Value)|T],WrittenVariables,PrevState,[bind(Variable,NewValue)|PT]) :- !,
1329 (ord_member(Variable,WrittenVariables)
1330 -> lookup_variable(PrevState,Variable,NewValue)
1331 ; NewValue=Value
1332 ), patch_state(T,WrittenVariables,PrevState,PT).
1333 patch_state(S,WV,PS,Res) :- add_internal_error('Illegal state: ',patch_state(S,WV,PS,Res)), Res=S.
1334
1335 lookup_variable(const_and_vars(_ConstID,Vars),Var,Val) :- !,
1336 lookup_value_for_existing_id(Var,Vars,Val).
1337 lookup_variable(expanded_const_and_vars(_ConstID,Vars,_FullState),Var,Val) :- !,
1338 lookup_value_for_existing_id(Var,Vars,Val).
1339 lookup_variable(Store,Var,Val) :- lookup_value_for_existing_id(Var,Store,Val).
1340
1341
1342 add_trans_id(CurID,Act,NewExpression,Residue,NewID,TransInfo,TransId) :-
1343 (Residue=[] -> true ; add_error(add_trans_id,'Residue: ',CurID:Act:Residue)),
1344 tcltk_add_new_transition_transid(CurID,Act,NewID,NewExpression,TransInfo,TransId).
1345
1346
1347 add_partial_transitions(root,CurState) :-
1348 /* for the moment the only state where partial transitions are computed */
1349 \+ any_transition(root,_,_), /* adding normal transitions was not successful */
1350 partial_trans(CurState,Act,NewExpression,Residue),
1351 add_trans_id(root,Act,NewExpression,Residue,_NewID,[],_),fail.
1352 add_partial_transitions(_CurID,_).
1353
1354 /* --------------------------------------------------------------------- */
1355
1356 /* A bit like AO* algorithm: expands open nodes (i.e., states whose transitions
1357 have not yet been computed */
1358
1359 %:- use_module(linda_slave).
1360 :- use_module(model_checker).
1361 :- public tcltk_model_check/11.
1362 tcltk_model_check(Nr,TclTkRes,FindDeadlocks,FindInvViolations,FindGoal,FindAssViolations,StopFullCoverage,PartialOrderReduction,PartialGuardsEvaluation,TIMELIMIT,TotalTime) :-
1363 statistics(walltime,[CurTime,_]), /* get current time in ms */
1364 LimitTime is CurTime+TIMELIMIT,
1365 %debug_println(10,start_tcltk_model_check(Nr,TIMELIMIT)),
1366 InspectExistingNodes = 0,
1367 (do_model_check(Nr,_A,LimitTime,Res,FindDeadlocks,FindInvViolations,FindGoal,
1368 FindAssViolations,StopFullCoverage,PartialOrderReduction,PartialGuardsEvaluation,InspectExistingNodes)
1369 -> translate_error_for_tclk(Res,TclTkRes)
1370 ; add_internal_error('Call failed: ',do_model_check(Nr,_A,LimitTime,Res,FindDeadlocks,FindInvViolations,FindGoal,
1371 FindAssViolations,StopFullCoverage,PartialOrderReduction,PartialGuardsEvaluation,InspectExistingNodes)),
1372 TclTkRes=error),
1373 statistics(walltime,[CurTime2,_]),
1374 TotalTime is CurTime2-CurTime,
1375 debug_println(10,tcltk_model_check(Nr,TotalTime,Res)).
1376
1377 translate_error_for_tclk([timeout,Nr],Res) :- !, Res=[timeout,Nr].
1378 translate_error_for_tclk(state_error(S),String) :- !, translate_state_err_for_tcltk(S,String).
1379 translate_error_for_tclk(S,R) :- atomic(S),!,R=S.
1380 translate_error_for_tclk(S,R) :- nonvar(S), add_error(translate_error_for_tclk,'Unknown Model Check result: ',S), R=unknown.
1381
1382 translate_state_err_for_tcltk(abort_error(TYPE,_,_,_),ERR) :- !, ERR = TYPE.
1383 translate_state_err_for_tcltk(eventerror(Event,Error,_),ERR) :- !,
1384 functor(Error,F,_),
1385 ajoin(['event_error:',Event,':',F],ERR).
1386 translate_state_err_for_tcltk(Error,ERR) :-
1387 functor(Error, StateError, _), atom_concat('state_error:',StateError,ERR).
1388
1389
1390 :- public do_model_check/12.
1391 do_model_check(_Nr,NodesAnalysed,_LimitTime,Res,FindDeadlocks,FindInvViolations,FindGoal,
1392 FindAssViolations,_StopFullCoverage,_PartialOrderReduction,_PartialGuardsEvaluation,ForceInspectExistingNodes) :-
1393 (tcltk_state_space_only_has_root_node -> true % Then also look at the root node
1394 ; ForceInspectExistingNodes == 1),
1395 search_among_existing_nodes(Res,FindDeadlocks,FindInvViolations,FindGoal,
1396 FindAssViolations), Res \=all, NodesAnalysed=0.
1397 do_model_check(LimitNr,NodesAnalysed,LimitTime,Res,FindDeadlocks,FindInvViolations,FindGoal,
1398 FindAssViolations,StopFullCoverage,PartialOrderReduction,PartialGuardsEvaluation,_) :-
1399 update_ass(FindAssViolations,FindAssViolations2),
1400 open_search(LimitNr,NodesAnalysed,LimitTime,Res,FindDeadlocks,FindInvViolations,FindGoal,
1401 FindAssViolations2,StopFullCoverage,PartialOrderReduction,PartialGuardsEvaluation).
1402
1403 update_ass(1,FindAssViol) :- \+ b_machine_has_assertions,!, % no need to check assertions
1404 FindAssViol=0.
1405 update_ass(X,X).
1406
1407 /* --------------------------------------------------- */
1408
1409 /* constraint-based checking of refinements */
1410 :- use_module(cbc_refinement_checks).
1411 tcltk_cbc_refinement_check(list(List),ErrorOccured) :-
1412 cbc_refinement_check(List,ErrorOccured).
1413
1414 /* constraint-based/model search for invariant violations */
1415
1416 :- dynamic cbc_inv_error_found/2.
1417 :- public tcltk_constraint_based_check/1.
1418 tcltk_constraint_based_check(L) :- tcltk_constraint_based_check(L,_).
1419 tcltk_constraint_based_check(list(List),ErrorsOrTimeoutWereFound) :-
1420 retractall(cbc_inv_error_found(_,_)),
1421 findall(Res, (tcltk_constraint_based_check_with_timeout(OpName,ErrorDesc),
1422 (ErrorDesc=ok -> true ; assert(cbc_inv_error_found(OpName,ErrorDesc))),
1423 string_concatenate(' == ',ErrorDesc,Res1),
1424 string_concatenate(OpName,Res1,Res)), List),
1425 %%print(list(List)),nl, %%
1426 (cbc_inv_error_found(_,_) ->
1427 (cbc_inv_error_found(_,X),X\=time_out
1428 -> ErrorsOrTimeoutWereFound=true ; ErrorsOrTimeoutWereFound=time_out
1429 )
1430 ; ErrorsOrTimeoutWereFound = false).
1431
1432 % can also be called with uninstantiated OpName
1433 tcltk_constraint_based_check_with_timeout(OpName,ErrorDesc) :-
1434 preferences:get_computed_preference(debug_time_out,DebugTimeOut),
1435 valid_operation_or_init(OpName),
1436 (time_out_with_enum_warning_one_solution(tcltk_constraint_based_check_op(OpName,ErrorDesc),DebugTimeOut,TimeOutRes)
1437 -> (is_time_out_result(TimeOutRes)
1438 -> print_message('TIME OUT: '), print_message(OpName), print_message(DebugTimeOut),
1439 ErrorDesc = timeout
1440 ; true
1441 )).
1442 valid_operation_or_init(OpName) :- b_get_machine_operation(OpName,_,_,_).
1443 valid_operation_or_init('INITIALISATION').
1444
1445 tcltk_constraint_based_check_op(OpName,ErrorDesc) :-
1446 (OpName == 'INITIALISATION' ; OpName = '$initialise_machine'),
1447 !,
1448 (call_cbc_command(tcltk_cbc_find_invariant_violation('',Res))
1449 -> (Res = no_solution_found -> ErrorDesc = 'ok'
1450 ; Res = time_out -> ErrorDesc = time_out
1451 ; ajoin(['invariant_violated_after(',OpName,')'],ErrorDesc)
1452 )
1453 ; ErrorDesc = 'internal_error'
1454 ).
1455 tcltk_constraint_based_check_op(OpName,ErrorDesc) :-
1456 call_cbc_command(state_model_check(OpName,State,Operation,NewState)),!,
1457 %fd_copy_term(NewState,ResTempl,ResBody), print(ResTempl),print(ResBody),nl,
1458 %fd_copy_term(State,PriorTempl,PriorBody),
1459 tcltk_add_new_transition_transid(root,'$JUMP'(constraint_based_check),PriorID,State,[],TransId1),
1460 translate_event(Operation,Action),
1461 tcltk_add_new_transition_transid(PriorID,Operation,NewID,NewState,[],TransId2),
1462 retractall(current_state_id(_)),
1463 assert(current_state_id(NewID)),
1464 reset_op_trace_ids,
1465 add_to_op_trace_ids(TransId1), add_to_op_trace_ids(TransId2),
1466 retractall(history(_)),
1467 retractall(forward_history(_)),
1468 assert(history([PriorID,root])),
1469 ajoin(['invariant_violated_after(',Action,')'],ErrorDesc).
1470 tcltk_constraint_based_check_op(_,'ok').
1471
1472 :- public tcltk_cbc_find_trace/2.
1473 % try to find constants, parameters that make a given trace feasible
1474 tcltk_cbc_find_trace(TraceToBeFound,Res) :-
1475 tcltk_cbc_find_trace(TraceToBeFound,'',first_solution,Res).
1476 :- public tcltk_cbc_find_invariant_violation/2.
1477 tcltk_cbc_find_invariant_violation(TraceToBeFound,Res) :-
1478 tcltk_cbc_find_trace(TraceToBeFound,'#not_invariant',first_solution,Res).
1479
1480 tcltk_cbc_find_trace(TraceToBeFound,TargetPredString,FindAll,Res) :-
1481 b_parse_optional_machine_predicate(TargetPredString,TargetPred),
1482 formatsilent('Looking for solution for trace ~w~n',[TraceToBeFound]),
1483 split_atom(TraceToBeFound,[',',';',' '],TraceAsList),
1484 (maplist(check_valid_operation,TraceAsList)
1485 -> start_ms_timer(Timer),
1486 tcltk_cbc_find_trace_aux(Timer,TraceAsList,TargetPred,FindAll,Res)
1487 ; Res = error).
1488 tcltk_cbc_find_trace_aux(Timer,TraceAsList,TargetPred,FindAll,Res) :-
1489 preferences:get_computed_preference(debug_time_out,DebugTimeOut),
1490 reset_nr_cbc_sols,
1491 time_out_with_enum_warning_one_solution(sap:create_testcase_path_nondet(init,TraceAsList,TargetPred,Transitions),DebugTimeOut,TimeOutRes),
1492 stop_ms_timer(Timer),
1493 (is_time_out_result(TimeOutRes)
1494 -> !,
1495 print_message('*** TIME OUT: '), print_message(DebugTimeOut), Res = time_out
1496 ; FindAll = findall -> inc_nr_cbc_sols,
1497 print('% *** FOUND PATH: '), maplist(print_trans,Transitions),nl,
1498 fail % backtrack to find further solutions
1499 ; !,Res = ok,
1500 print('% *** FOUND PATH: '), maplist(print_trans,Transitions),nl,
1501 maplist(extract_trans_id,Transitions,TransIds),
1502 set_trace_by_transition_ids(TransIds)
1503 ).
1504 tcltk_cbc_find_trace_aux(Timer,_TraceToBeFound,_TargetPred,findall,R) :- !, stop_ms_timer(Timer),
1505 R=nr_cbc_sols(Res),
1506 nr_cbc_sols(Res),
1507 print_message('*** ALL SOLUTIONS FOUND ').
1508 tcltk_cbc_find_trace_aux(Timer,_TraceToBeFound,_TargetPred,_FindAll,no_solution_found) :-
1509 stop_ms_timer(Timer),
1510 print_message('*** NO SOLUTION FOUND'),nl.
1511
1512 :- dynamic nr_cbc_sols/1.
1513 nr_cbc_sols(0).
1514 reset_nr_cbc_sols :- retractall(nr_cbc_sols(_)), assert(nr_cbc_sols(0)).
1515 inc_nr_cbc_sols :-
1516 retract(nr_cbc_sols(N)), N1 is N+1, assert(nr_cbc_sols(N1)).
1517 extract_trans_id( (TransId,_,_,_), TransId).
1518 print_trans( (_,Event,_,_)) :- translate_event(Event,S), print(S), print(' ').
1519 check_valid_operation(Op) :-
1520 (get_possible_language_specific_top_level_event(Op,_,_) -> true
1521 ; add_error(cbc_find_sequence,'Unknown operation/event: ',Op),fail).
1522
1523
1524
1525 % ------------
1526
1527 :- use_module(bsyntaxtree).
1528 tcltk_constraint_find_valid_state_with_pred(ParameterBindList,RestPreCond,UseConstantsFromStateID) :-
1529 parse_tclk_parameter_values_and_pred('$initialise_machine',ParameterBindList,RestPreCond,CustomPredicate),
1530 UseInvariant=true,
1531 call_cbc_command(
1532 b_state_model_check:b_set_up_valid_state_with_pred(State,CustomPredicate,
1533 UseInvariant,UseConstantsFromStateID)),
1534 tcltk_add_cbc_state(State,find_valid_state).
1535 tcltk_constraint_find_valid_state :-
1536 call_cbc_command(b_set_up_valid_state(State)),
1537 tcltk_add_cbc_state(State,find_valid_state).
1538
1539 :- use_module(clpfd_interface,[catch_clpfd_overflow_call1/1]).
1540 :- use_module(error_manager,[call_in_fresh_error_scope_for_one_solution/1]).
1541 % catch CLPFD overflows and catch other errors
1542 call_cbc_command(Command) :-
1543 call_in_fresh_error_scope_for_one_solution(
1544 (catch_clpfd_overflow_call1(Command) -> true
1545 ; translate_events_in_current_scope_to_warnings(cbc,'Warning: '),fail
1546 % Maybe we should raise error when Command fails and enumeration warnings are there ?
1547 )).
1548
1549 :- public tcltk_constraint_find_deadlock_state/1.
1550 tcltk_constraint_find_deadlock_state(Res) :-
1551 check_we_are_in_b_mode(cbc_deadlock_freedom_check),
1552 create_texpr(truth,pred,[],True),
1553 call_cbc_command(cbc_deadlock_freedom_check(State,True,0)),
1554 (State == time_out -> Res = time_out
1555 ; tcltk_add_cbc_state(State,cbc_deadlock), Res=deadlock).
1556 :- public tcltk_constraint_find_deadlock_state_with_goal/2.
1557 tcltk_constraint_find_deadlock_state_with_goal(Filter,Res) :-
1558 check_we_are_in_b_mode(cbc_deadlock_freedom_check),
1559 ( b_get_machine_goal(Goal) -> true
1560 ; otherwise -> create_texpr(truth,pred,[],Goal)),
1561 call_cbc_command(cbc_deadlock_freedom_check(State,Goal,Filter)),
1562 (State == time_out -> Res = time_out
1563 ; tcltk_add_cbc_state(State,cbc_deadlock), Res=deadlock).
1564
1565 check_we_are_in_b_mode(_) :- b_or_z_mode,!.
1566 check_we_are_in_b_mode(Cmd) :- add_error(check_we_are_in_b_mode,'This command can only be performed in B,Z or TLA+ mode: ',Cmd),fail.
1567
1568 tcltk_constraint_find_deadlock_state_with_goal(true,_Filter,Res) :-
1569 !,tcltk_constraint_find_deadlock_state(Res).
1570 tcltk_constraint_find_deadlock_state_with_goal(GoalPred,Filter,Res) :-
1571 bmachine:b_set_machine_goal(GoalPred),
1572 tcltk_constraint_find_deadlock_state_with_goal(Filter,Res).
1573
1574 :- use_module(enabling_analysis,[check_if_feasible_operation/5]).
1575 tcltk_check_if_feasible_operation(OpName,UseInvariant,TimeOutFactor,Result) :- % UseInvariant currently always 1 from Tcl
1576 check_if_feasible_operation(OpName,UseInvariant,TimeOutFactor,Result,ResultState),
1577 tcltk_add_cbc_state(ResultState,feasibility_check(OpName)).
1578
1579 tcltk_add_cbc_state('$UNKNOWN_STATE',_) :- !.
1580 tcltk_add_cbc_state(State,OpName) :-
1581 seperate_state_into_const_and_vars(State,Constants,Variables),
1582 !,
1583 % store the constants separately: important for memory consumption when continuing animation/model checking
1584 tcltk_add_new_transition_transid(root,'$setup_constants',CstID,concrete_constants(Constants),[],TransId1),
1585 FullState = const_and_vars(CstID,Variables),
1586 tcltk_add_new_transition_transid(CstID,'$JUMP'(OpName),NewID,FullState,[],TransId2),
1587 set_cbc_state(NewID,[TransId1,TransId2],[CstID,root]).
1588 tcltk_add_cbc_state(State,OpName) :-
1589 tcltk_add_new_transition_transid(root,'$JUMP'(OpName),NewID,State,[],TransId),
1590 set_cbc_state(NewID,[TransId],[root]).
1591
1592 set_cbc_state(NewID,TransIds,His) :-
1593 retractall(current_state_id(_)),
1594 assert(current_state_id(NewID)),
1595 reset_op_trace_ids,
1596 maplist(add_to_op_trace_ids,TransIds),
1597 retractall(history(_)),
1598 retractall(forward_history(_)),
1599 assert(history(His)). %, print(State),nl.
1600
1601 is_constant_binding(SortedCsts,bind(ID,_)) :-
1602 ord_member(ID,SortedCsts).
1603
1604 :- use_module(bsyntaxtree, [get_texpr_ids/2]).
1605 seperate_state_into_const_and_vars(State,Constants,Variables) :-
1606 b_get_machine_constants(TCs), get_texpr_ids(TCs,Cs),
1607 sort(Cs,SortedCsts),
1608 include(is_constant_binding(SortedCsts),State,Constants),
1609 Constants \= [],
1610 exclude(is_constant_binding(SortedCsts),State,Variables).
1611
1612
1613
1614 :- public tcltk_constraint_find_static_assertion_violation/1.
1615 tcltk_constraint_find_static_assertion_violation(TclResult) :-
1616 cbc_constraint_find_static_assertion_violation(Result,[]),
1617 functor(Result,TclResult,_).
1618 cbc_constraint_find_static_assertion_violation(Result,Options) :-
1619 call_cbc_command(cbc_static_assertions_check(State,Options)),
1620 ( State = counterexample_found(CE) ->
1621 Result = counterexample_found,
1622 tcltk_add_cbc_state(CE,static_assertion_check)
1623 ; otherwise ->
1624 Result = State).
1625
1626 /* --------------------------------------------------- */
1627
1628
1629 :- use_module(error_manager,[extract_all_line_col/5]).
1630 :- use_module(probcspsrc(haskell_csp),[extract_span_from_event/4,extract_span_info/2]).
1631
1632 get_source_text_positions(Event,Line,Col,EndLine,EndCol) :-
1633 extract_span_from_action(Event,SPAN),
1634 extract_all_line_col(SPAN,Line,Col,EndLine,EndCol).
1635
1636 extract_span_from_action(Event,Span) :- csp_mode,
1637 extract_span_from_event(Event,Span,_,_).
1638 extract_span_from_action(Event,Pos) :- b_or_z_mode,
1639 get_operation_name(Event,ID),
1640 b_get_machine_operation(ID,_Res,_TParas,_Body,_OType,Pos).
1641
1642
1643 /* -------------------------------------------------------------------- */
1644
1645 get_current_option_eventtrace(OptionNum,Trace) :-
1646 % the option number starts with 0 (coming from a TK listbox)
1647 current_options(ActionsAndIDs),
1648 nth0(OptionNum,ActionsAndIDs,(Id,_,_,_)),
1649 transition_info(Id,eventtrace(Trace)),!.
1650
1651 :- public tcltk_has_eventtrace/1.
1652 tcltk_has_eventtrace(OptionNum) :-
1653 get_current_option_eventtrace(OptionNum,_Trace).
1654
1655 :- public tcltk_show_eventtrace/2.
1656 tcltk_show_eventtrace(OptionNum,Desc) :-
1657 get_current_option_eventtrace(OptionNum,Trace),
1658 explain_event_trace(Trace,Desc).
1659
1660
1661
1662 /* --------------------------------------------------- */
1663
1664 :- use_module(prob2_interface,[execute_model/5]).
1665
1666 tcltk_execute_model(MaxNrSteps,ExecutedSteps,Result) :-
1667 current_state_id(CurID),
1668 execute_model(CurID,MaxNrSteps,_TransitionInfo,ExecutedSteps,Result).
1669
1670
1671 :- public tcltk_find_shortest_trace_to_current_node/1.
1672 tcltk_find_shortest_trace_to_current_node(list(StringList)) :-
1673 find_trace_to_current_node(OpL),
1674 translate_events(OpL,StringList).
1675
1676 :- public tcltk_execute_trace_to_current_node/0.
1677 tcltk_execute_trace_to_current_node :-
1678 current_state_id(CurID),
1679 tcltk_execute_trace_to_node(CurID).
1680
1681 tcltk_execute_trace_to_node(ToID) :- /* can be useful for TestCase Generation */
1682 set_target_id(ToID),
1683 tcltk_execute_trace_from_to_found_predicate(root,_,_).
1684
1685 tcltk_execute_trace_from_to_found_predicate(From,OpL,IDList) :-
1686 printsilent(finding_trace_from_to(From)),nls, flush_output(user),
1687 find_shortest_path_from_to_found_predicate(From,OpL,IDList,ToID), !,
1688 /* mal: replaced by shortest 5/12/2006 */
1689 (current_state_id(From) -> true ; state_space_reset),
1690 debug_println(9,executing_trace(From,OpL,ToID)), flush_output(user),
1691 execute_id_trace_from_current(ToID,OpL,IDList).
1692 % print(executing_trace_to(ID,OpL,IDList)),nl,
1693 %compute_history(OpL,IDList,History), print(new_history(History)),nl,
1694
1695
1696 find_trace_to_current_node(Trace) :-
1697 current_state_id(CurID),
1698 find_shortest_path_from_to(root,CurID,L,_),
1699 extract_term_trace_from_transition_ids(L,Trace).
1700
1701 :- use_module(state_space_dijkstra).
1702
1703 find_shortest_trace_to_node(FromID,ToID,OpIDListe,StateIDList) :-
1704 find_shortest_path_from_to(FromID,ToID,OpIDListe,StateIDList).
1705
1706
1707 /* --------------------------------------------------- */
1708
1709
1710
1711 :- public tcltk_goto_a_non_deterministic_node/0.
1712 tcltk_goto_a_non_deterministic_node :- /* same transition leads to different resulting state */
1713 transition(ID,X,ID2),
1714 transition(ID,X,ID3), dif_ID(ID2,ID3),
1715 print_message(found_non_det_op(X)),
1716 %tcltk_goto_state(find_non_det_node,ID).
1717 tcltk_execute_trace_to_node(ID).
1718
1719 dif_ID(ID1,ID2) :- (number(ID1),number(ID2) -> ID2>ID1 ; ID1 \= ID2).
1720
1721 :- public tcltk_goto_a_branching_node/0.
1722 tcltk_goto_a_branching_node :- /* two different events/operations enabled */
1723 transition(ID,X,ID2), get_operation_name(X,NX),
1724 transition(ID,Y,ID3), dif_ID(ID2,ID3), get_operation_name(Y,NY), NX\=NY,
1725 print_message(found_branching_op(ID,NX,NY)),
1726 %tcltk_goto_state(find_branching_node,ID),
1727 tcltk_execute_trace_to_node(ID).
1728
1729 :- public tcltk_goto_a_non_resetable_node/0.
1730 tcltk_goto_a_non_resetable_node :-
1731 find_resetable_nodes,
1732 visited_expression_id(ID),
1733 \+(resetable_node(ID)),
1734 \+(not_all_transitions_added(ID)), !,
1735 %tcltk_goto_state(find_non_resetable_node,ID).
1736 tcltk_execute_trace_to_node(ID).
1737
1738 operation_name_covered(OpName) :- operation_name_covered(OpName,_).
1739 operation_name_covered(OpName,Template) :- b_get_machine_operation(OpName,Results,Par,_),
1740 \+ operation_not_yet_covered(OpName),
1741 length(Par,Arity),
1742 functor(Op,OpName,Arity),
1743 (Results\=[] -> Template = '-->'(Op,_) ; Template = Op).
1744
1745 :- public tcltk_goto_event_list_property_violation/3.
1746 tcltk_goto_event_list_property_violation(Property,EventSelection,list(OperationList)) :-
1747 % first translate Tk EventSelection Number list into Events
1748 sap:get_selected_events(EventSelection,_AllEvents,OperationList),
1749 include(operation_name_covered,OperationList,_,EnabledOpList), % only keep operations that can be enabled anyway
1750 maplist(operation_name_covered,EnabledOpList,TemplateList), % replace by template
1751 print(find_property_violation_for_template(Property,TemplateList)),nl,
1752 visited_expression(ID,S), ID \= root, S\= concrete_constants(_),
1753 \+(not_all_transitions_added(ID)),
1754 \+( check_event_list_property(Property,ID,TemplateList) ),
1755 print(found_event_list_property_violation(Property,ID)),nl,
1756 tcltk_execute_trace_to_node(ID).
1757
1758 check_event_list_property(relative_deadlock_freedom,ID,TemplateList) :-
1759 relative_deadlock_freedom(ID,TemplateList).
1760 check_event_list_property(valid_controller,ID,TemplateList) :-
1761 is_valid_controller_state(ID,TemplateList).
1762 check_event_list_property(det_controller,ID,TemplateList) :-
1763 is_det_controller_state(ID,TemplateList).
1764
1765 relative_deadlock_freedom(ID,TemplateList) :- member(Template,TemplateList),
1766 transition(ID,Template,_).
1767 is_valid_controller_state(ID,TemplateList) :- % check that exactly one event from TemplateList is enabled
1768 append(_,[LiveEvent|RestTemplate],TemplateList),
1769 transition(ID,LiveEvent,_),!, % we found one enabled event
1770 \+ relative_deadlock_freedom(ID,RestTemplate). % all other events from list must be disabled
1771 is_det_controller_state(ID,TemplateList) :- % check that *at most* one event from TemplateList is enabled
1772 append(_,[LiveEvent|RestTemplate],TemplateList),
1773 transition(ID,LiveEvent,_),!, % we found one enabled event from list
1774 \+ relative_deadlock_freedom(ID,RestTemplate). % all other events from list must be disabled
1775 is_det_controller_state(_,_) :- true. % no event enabled is also ok
1776
1777 :- public tcltk_goto_state_enabling_operation/2.
1778 tcltk_goto_state_enabling_operation(TclOpName,FromCurrent) :-
1779 predicate_debugger:adapt_tcl_operation_name(TclOpName,OpName),
1780 operation_name_covered(OpName,Template),
1781 set_found_predicate(ID, transition(ID,Template,_)),
1782 print(template(Template,FromCurrent)),nl,
1783 print_message('Computing trace to node'),
1784 (FromCurrent=1
1785 -> current_state_id(FromID) % inefficient: better to do one dijkstra from FromID !
1786 ; FromID = root
1787 ),
1788 tcltk_execute_trace_from_to_found_predicate(FromID,_,_).
1789 % tcltk_goto_state(find_enabled(OpName),ID).
1790
1791 :- public tcltk_operations_covered_info/2.
1792 % quickly compute which operations have already been covered and which ones not
1793 tcltk_operations_covered_info(list([list(['Operation','Covered'])|OpCov]),Precise) :-
1794 findall(list([OpName,Cov]),
1795 (specfile:get_possible_event(OpName),
1796 (operation_name_not_yet_covered(OpName)
1797 -> not_yet_covered_info(Precise,OpName,Cov)
1798 ; Cov = 'yes')),OpCov).
1799
1800 not_yet_covered_info(precise,OpName,Cov) :-
1801 enabling_analysis:feasible_operation(OpName,Res),!, Res=Cov.
1802 not_yet_covered_info(precise,_,R) :- !, R='unknown'.
1803 not_yet_covered_info(_,_,'uncovered').
1804
1805 :- dynamic resetable_node/1.
1806
1807 resetable_node(a).
1808
1809 :- public find_resetable_nodes/0.
1810 :- dynamic find_flag/2.
1811 find_resetable_nodes :-
1812 retractall(find_flag(_,_)),
1813 retractall(resetable_node(_)),
1814 any_transition(root,_,ID), /* add nodes reachable from root */
1815 assert(find_flag(ID,0)),
1816 fail.
1817 find_resetable_nodes :-
1818 visited_expression(CID,concrete_constants(_C)),
1819 any_transition(CID,_,ID), /* add nodes reachable after a setup_constants */
1820 assert(find_flag(ID,0)),
1821 fail.
1822 find_resetable_nodes :- find_resetable_nodes_loop,
1823 print_message('Not resetable:'),
1824 visited_expression_id(ID),
1825 \+(resetable_node(ID)),
1826 print_message(ID),
1827 fail.
1828 find_resetable_nodes :-
1829 print_message('Done').
1830
1831
1832 find_resetable_nodes_loop :-
1833 retract(find_flag(ID,N)), !, find_resetable_nodes_loop(ID,N).
1834 find_resetable_nodes_loop.
1835
1836 find_resetable_nodes_loop(ID,N) :- N1 is N+1,
1837 assert(resetable_node(ID)),
1838 any_transition(NewID,_,ID),
1839 \+(resetable_node(NewID)),
1840 \+(find_flag(NewID,_)),
1841 assert(find_flag(NewID,N1)),
1842 fail.
1843 find_resetable_nodes_loop(_,_) :- find_resetable_nodes_loop.
1844
1845
1846 :- use_module(bmachine, [determine_type_of_formula/2]).
1847 :- public tcltk_show_expression_as_dot/2.
1848 tcltk_show_expression_as_dot(VorE,File) :-
1849 parse_machine_expression(VorE,TypedExpr),
1850 tcltk_show_typed_expression_as_dot_graph(TypedExpr,File).
1851 tcltk_show_expression_as_dot(_VorE,File) :-
1852 add_error(tcltk_show_expression_as_dot,'Computing Value Dot Representation Failed for: ',File),
1853 fail.
1854
1855 tcltk_show_typed_expression_as_dot_graph(TypedExpr,File) :-
1856 determine_type_of_formula(TypedExpr,Type),
1857 get_state(Type,BState),
1858 decompose_expression_for_dot(TypedExpr,ExprList,[]), % decompose pairs so that user can provide multiple values/graphs
1859 compute_for_dot(ExprList,BState,GraphState), % compute value for each sub-component
1860 format('Writing value to DOT file: ~w~n',[File]),
1861 graph_canon:print_cstate_graph(GraphState,File),
1862 format('Finished writing value to DOT file: ~w~n',[File]).
1863
1864 get_state(requires_nothing,[]).
1865 get_state(requires_constants,BState) :-
1866 current_expression(_CurID,State),
1867 (state_corresponds_to_set_up_constants(State,BState) -> true ;
1868 add_error(tcltk_show_expression_as_dot,'Please setup constants or initialise machine first: '),fail).
1869 get_state(requires_variables,BState) :-
1870 current_expression(_CurID,State),
1871 (state_corresponds_to_initialised_b_machine(State,BState) -> true ;
1872 add_error(tcltk_show_expression_as_dot,'Please initialise machine first: '),fail).
1873
1874 :- use_module(bmachine, [b_parse_machine_expression_from_codes_with_prob_ids/2, type_with_errors/4]).
1875 parse_machine_expression(RawAST,TypedExpr) :- compound(RawAST),!, % allow to pass raw AST as well
1876 type_with_errors(RawAST,[prob_ids(visible),variables],Type,TypedExpr),
1877 ((Type=pred ; Type=subst)
1878 -> add_error(state_space_reduction,'Expected expression formula but obtained: ',Type),fail
1879 ; true ).
1880 parse_machine_expression(VorE,TypedExpr) :-
1881 atom_codes(VorE,VorECodes),
1882 b_parse_machine_expression_from_codes_with_prob_ids(VorECodes,TypedExpr).
1883
1884 compute_for_dot([],_,[]).
1885 compute_for_dot([String,TypedExpr|Tail],BState,[bind(Str,Value)|TS]) :-
1886 % allow user to specify labels for graphs ("lbl1", e1, "lbl2", e2, ...)
1887 get_texpr_expr(String,string(Str)),!,
1888 translate:translate_bexpression_with_limit(TypedExpr,100,EStr),
1889 format('Computing value for expression: ~w~n',[EStr]),
1890 b_compute_expression_with_prob_ids(TypedExpr,BState,Value),
1891 compute_for_dot(Tail,BState,TS).
1892 compute_for_dot([TypedExpr|Tail],BState,[bind(Str,Value)|TS]) :-
1893 translate:translate_bexpression_with_limit(TypedExpr,100,Str),
1894 format('Computing value for expression: ~w~n',[Str]),
1895 b_compute_expression_with_prob_ids(TypedExpr,BState,Value),
1896 compute_for_dot(Tail,BState,TS).
1897
1898
1899
1900 decompose_expression_for_dot(b(couple(A,B),_,_)) --> !,
1901 decompose_expression_for_dot(A), decompose_expression_for_dot(B).
1902 decompose_expression_for_dot(b(rec(Fields),_,_)) --> !,decompose_fields_for_dot(Fields).
1903 decompose_expression_for_dot(X) --> [X].
1904
1905 decompose_fields_for_dot([]) --> [].
1906 decompose_fields_for_dot([field(Name,Val)|T]) --> [b(string(Name),string,[]),Val], decompose_fields_for_dot(T).
1907
1908 /* ------------------------------------------------------------------ */
1909
1910
1911
1912 print_property_partitions :- print('PARTITIONS OF PROPERTIES'),nl,
1913 b_interpreter:b_get_properties_from_machine(Properties),
1914 bsyntaxtree:predicate_components(Properties,Comp),
1915 length(Comp,Len), print(Len), print(' partitions found'),nl,
1916 member(component(P,Vars),Comp), nl,print(Vars),nl,translate:print_bexpr(P),nl,fail.
1917 print_property_partitions :- nl, print(' ============== '),nl.
1918
1919 :- public tcltk_add_user_executed_operation/2.
1920 tcltk_add_user_executed_operation(TclOpName,CustomPredicate) :-
1921 tcltk_add_user_executed_operation(TclOpName,[],CustomPredicate).
1922
1923 tcltk_add_user_executed_operation(TclOpName,ParameterBindList,RestPreCond) :-
1924 predicate_debugger:adapt_tcl_operation_name(TclOpName,OpName),
1925 parse_tclk_parameter_values_and_pred(OpName,ParameterBindList,RestPreCond,CustomPredicate),
1926 b_trans_one_solution_with_pred(OpName,CustomPredicate,_,_).
1927
1928 parse_tclk_parameter_values_and_pred(OpName,ParameterBindList,RestPreCond,CustomPredicate) :-
1929 b_parse_machine_operation_pre_post_predicate(RestPreCond,RestTypedPred,OpName),
1930 get_animation_operation_parameters(OpName,Parameters),
1931 % print(tcltk_add_user_executed_operation(OpName,ParameterBindList,Parameters)),nl,
1932 parse_parameter_values(ParameterBindList,Parameters,List),
1933 conjunct_predicates([RestTypedPred|List],CustomPredicate).
1934
1935 get_animation_operation_parameters('$setup_constants',Parameters) :-
1936 b_get_machine_operation_typed_parameters('$setup_constants',Parameters).
1937 get_animation_operation_parameters(OpName,FullParameters) :-
1938 b_get_machine_operation_for_animation(OpName,_Results,Parameters,_Body,_OType,_TopLevel),
1939 b_get_operation_non_det_modifies(OpName,NonDetVars), % also allow setting non-deterministically assigned vars
1940 b_get_machine_variables(Vars),
1941 include(non_det_modified(NonDetVars),Vars,ParaVars),
1942 append(ParaVars,Parameters,FullParameters).
1943
1944 non_det_modified(NonDetVars,TID) :- get_texpr_id(TID,ID), ord_member(ID,NonDetVars).
1945
1946 % parse a list of variable names and expressions and turn into equal predicates
1947 % Motivation: this can also deal with Z-style identifiers like in?, ... which cannot be parsed
1948 :- use_module(btypechecker, [unify_types_strict/2]).
1949 parse_parameter_values([],_,Res) :- !,Res=[].
1950 parse_parameter_values(['='(ParameterID,ExpressionStr)|T],Parameters,[Pred|PT]) :-
1951 atom_codes(ExpressionStr,Codes),
1952 format('Parsing for ~w : ~w~n',[ParameterID,ExpressionStr]),
1953 !,
1954 b_parse_machine_expression_from_codes_with_prob_ids(Codes,TypedExpr),
1955 get_texpr_type(TypedExpr,Type),
1956 TID = b(identifier(ParameterID),Type,[]),
1957 (member(b(identifier(ParameterID),Type2,_),Parameters)
1958 -> (unify_types_strict(Type,Type2)
1959 -> Pred = b(equal(TID,TypedExpr),pred,[]),
1960 translate:print_bexpr(Pred),nl,
1961 parse_parameter_values(T,Parameters,PT)
1962 ;
1963 pretty_type(Type,String1), pretty_type(Type2,String2),
1964 ajoin(['Value for parameter ',ParameterID,' has unexpected type ',String1,', expected: '],Msg),
1965 add_error(parse_parameter_values,Msg,String2),
1966 fail
1967 )
1968 ; add_error(parse_parameter_values,'Unknown operation parameter: ',ParameterID),
1969 fail).
1970 parse_parameter_values(PB,P,_) :- add_internal_error('Illegal parameter binding: ',parse_parameter_values(PB,P,_)),fail.
1971
1972
1973 :- public tcltk_add_user_executed_operation_typed/3.
1974 % just as above but with typed predicate
1975 tcltk_add_user_executed_operation_typed(OpName,TypedCustomPredicate,NewID) :-
1976 tcltk_add_user_executed_operation_typed(OpName,_,TypedCustomPredicate,NewID).
1977 tcltk_add_user_executed_operation_typed(OpName,Operation,TypedCustomPredicate,NewID) :-
1978 b_trans_one_solution_with_pred(OpName,TypedCustomPredicate,Operation,NewID).
1979
1980 b_trans_one_solution_with_pred(OpName,TypedCustomPredicate,Operation,NewID) :-
1981 call_cleanup(b_trans_one_solution_with_pred2(OpName,TypedCustomPredicate,Operation,NewID),
1982 bmachine:reset_temp_predicate).
1983
1984 % find one solution from current state using OpName and respecting temp_predicate
1985 b_trans_one_solution_with_pred2(OpName,TypedCustomPredicate,Operation,NewID) :-
1986 b_top_level_operation(OpName),
1987 !,
1988 current_expression(CurID,InState),
1989 set_context_state(CurID),
1990 call_cleanup(execute_operation_by_predicate_in_state(InState,OpName,TypedCustomPredicate,Operation,NewState),
1991 clear_context_state),
1992 !,
1993 debug_format(19,'Executed by predicate: ~w~n',[OpName]),
1994 %debug_format(19,'Executed ~w: ~w~nOut=~w~n',[OpName,Operation,NewState]),
1995 add_trans_id(CurID,Operation,NewState,[],NewID,[],_TransId),
1996 tcltk_goto_state(Operation,NewID).
1997 b_trans_one_solution_with_pred2(OpName,TypedCustomPredicate,Operation,NewID) :-
1998 bmachine:assert_temp_typed_predicate(TypedCustomPredicate),
1999 current_expression(CurID,InState),
2000 set_context_state(CurID),
2001 temporary_set_preference(maxNrOfEnablingsPerOperation,1,Max),
2002 temporary_set_preference(maxNrOfInitialisations,1,MaxI),
2003 start_ms_timer(Timer),
2004 call_cleanup((specfile:b_trans(InState,OpName,Operation,NewState,TransInfo) -> true),
2005 (stop_ms_timer(Timer),
2006 reset_temporary_preference(maxNrOfEnablingsPerOperation,Max),
2007 reset_temporary_preference(maxNrOfInitialisations,MaxI),
2008 clear_context_state)
2009 ),
2010 debug_println(9,found_solution(NewState)),nl,
2011 % now add a transition to the state space:
2012 Residue=[],
2013 add_trans_id(CurID,Operation,NewState,Residue,NewID,TransInfo,_),
2014 tcltk_goto_state(Operation,NewID).
2015
2016 % allow user to execute any statement
2017 % TO DO: catch operation_calls and route them differently
2018 % translate operation_call arguments into predicate and call tcltk_add_user_executed_operation_typed(OpName,Operation,TypedCustomPredicate,NewID)
2019 tcltk_add_user_executed_statement(Statement,Updates,NewID) :-
2020 current_expression(CurID,InState),
2021 state_corresponds_to_initialised_b_machine(InState,BState),
2022 set_context_state(CurID),
2023 %start_ms_timer(Timer),
2024 call_cleanup((user:b_full_execute_top_level_statement_with_probids(Statement,BState,Updates,NewState)->true),
2025 clear_context_state),
2026 % TO DO: do we need to catch enumeration warnings ?
2027 %stop_ms_timer(Timer),
2028 Residue=[], TransInfo = [],
2029 debug_println(4,executed(Updates,NewState)),
2030 compute_all_transitions_if_necessary(CurID), % first ensure we have already computed outgoing transitions as usual, so that we can detect if a new state is added
2031 (get_id_of_node_and_add_if_required(NewState,NewID,Exists,CurID),
2032 Exists=exists,
2033 transition(CurID,Action,TransId,NewID)
2034 -> debug_println(4,transition_exists_already(Action,TransId))
2035 ; translate:translate_substitution(Statement,OpLabel),
2036 add_trans_id(CurID,'$USER'(OpLabel),NewState,Residue,NewID,TransInfo,_),
2037 format('Added new user-initiated transition to ~w via: ~w~n',[NewID,OpLabel])
2038 ),
2039 tcltk_goto_state(OpLabel,NewID).
2040
2041 :- use_module(kernel_waitflags,[init_wait_flags/1, ground_wait_flags/1]).
2042 %% allows one to execute any statement (not just operations).
2043 b_full_execute_top_level_statement_with_probids(Body,InState,Updates,NewState) :-
2044 add_prob_deferred_set_elements_to_store(InState,InState1,visible),
2045 init_wait_flags(WF),
2046 b_execute_top_level_statement(Body,[],InState1,Updates,WF,_Path1,output_not_required),
2047 ground_wait_flags(WF),
2048 store:store_updates_and_normalise(Updates,InState,NewState).
2049
2050 % --------------------------------------------------------------------------------------
2051
2052
2053 :- use_module(bmachine).
2054 :- use_module(specfile).
2055 :- use_module(tools).
2056 :- use_module(library(lists)).
2057 :- use_module(store).
2058 :- use_module(self_check).
2059 :- use_module(b_global_sets).
2060 :- use_module(translate).
2061 :- use_module(predicate_debugger).
2062
2063
2064 /* --------------------------------------------------------- */
2065 /* --------------------------------------------------------- */
2066
2067
2068 /* ----------------------------------*/
2069 /* b_analyse_conjunction */
2070 /* ----------------------------------*/
2071
2072 :- public tcltk_analyse_option/2.
2073 /* provide list of possible options for analysis */
2074 tcltk_analyse_option(invariant,'INVARIANT') :- b_or_z_mode.
2075 tcltk_analyse_option(properties,S) :- b_or_z_mode,
2076 get_specification_description(properties,S).
2077 tcltk_analyse_option(assertions,S) :- (b_or_z_mode ; csp_mode),
2078 get_specification_description(assertions,S).
2079 tcltk_analyse_option(deadlock,'DEADLOCKED') :- b_or_z_mode.
2080
2081 :- public tcltk_analyse/6.
2082 :- use_module(predicate_evaluator).
2083 /* perform the various analysis */
2084 tcltk_analyse(Mode,Type,ListWithResults,Total,False,Unknown) :-
2085 (Mode == unicode
2086 -> set_unicode_mode,
2087 call_cleanup(tcltk_analyse2(Type,ListWithResults,Summary),unset_unicode_mode)
2088 ; tcltk_analyse2(Type,ListWithResults,Summary)),
2089 (member(total/Total,Summary) -> true ; Total=0),
2090 (member(false/False,Summary) -> true ; False=0),
2091 (member(unknown/Unknown,Summary) -> true ; Unknown=0).
2092 tcltk_analyse2(invariant,L,Summary) :- !,tcltk_analyse_invariant(L,Summary).
2093 tcltk_analyse2(properties,L,Summary) :- !,tcltk_analyse_properties(L,Summary).
2094 tcltk_analyse2(assertions,L,Summary) :- !,tcltk_analyse_assertions(L,Summary).
2095 tcltk_analyse2(deadlock,L,Summary) :- !,tcltk_analyse_deadlock(L,Summary).
2096 tcltk_analyse2(X,L,Summary) :- add_error(tcltk_analyse, 'Unknown type of formula: ', X),
2097 L=[], Summary=[].
2098
2099
2100 /* --------------------------------- */
2101
2102 :- public tcltk_show_current_state/1.
2103 tcltk_show_current_state(TransBState) :-
2104 current_b_expression(B),
2105 mnf(translate_bstate(B,TransBState)).
2106
2107 :- public tcltk_show_typing_of_variables_and_constants/1.
2108 tcltk_show_typing_of_variables_and_constants(list(List)) :-
2109 b_get_machine_variables(TypedVarList),
2110 convert_typed_varlist(TypedVarList,VarList,Types),
2111 generate_typing_list(VarList,Types,VList,VarCard),
2112 length(VarList,NrVars),
2113 format_to_codes(' VARIABLES [nr=~w,card=~w]',[NrVars,VarCard],Codes1),atom_codes(VARAtom,Codes1),
2114
2115 b_get_machine_all_constants(TypedCstList),
2116 convert_typed_varlist(TypedCstList,CVarList,CTypes),
2117 find_non_det_constants,
2118 generate_typing_list(CVarList,CTypes,CList,CCard),
2119 ( CList = []
2120 -> List = [VARAtom|VList]
2121 ; length(CVarList,NrCsts),
2122 format_to_codes(' CONSTANTS [nr=~w,card=~w]',[NrCsts,CCard],Codes2),atom_codes(CstAtom,Codes2),
2123 append([CstAtom|CList],[VARAtom|VList],List)
2124 ),!.
2125 tcltk_show_typing_of_variables_and_constants(list(['TYPE ERROR in MACHINE'])).
2126
2127 :- public tcltk_get_constants_predicate/2.
2128 %%% Used to get the constant values for the currently loaded B machine in form of a B predicate.
2129 %%% In case that the constants in the model has not been set up then all possible constants'
2130 %%% evaluations will be provided in form of a predicate in Disjunctive Normal Form.
2131 %%% Predicate used for setting up constants when model checking with TLC. (TLA)
2132 tcltk_get_constants_predicate(P,N) :-
2133 current_state_id(CurID),
2134 (CurID==root
2135 -> get_constants_as_disjoint_predicate(N,P)
2136 ; prob2_interface:get_state(CurID,EState),
2137 filter_constants_bindings(EState,X), % this will only get current constants values
2138 translate: translate_bstate(X,P)
2139 ).
2140
2141 get_constants_as_disjoint_predicate(N,Res) :-
2142 findall(R,get_set_up_constants_solution(R),L),
2143 get_a_part_of_the_found_solutions(L,N,Part),
2144 add_or_between_constant_predicates(Part,Res).
2145
2146 get_a_part_of_the_found_solutions(L,N,Part) :-
2147 length(L,Length),
2148 (N>=Length
2149 -> Part=L
2150 ; sublist(L,Part,_B,N,_A)).
2151
2152
2153 get_set_up_constants_solution(R) :-
2154 %\+ max_reached_or_timeout_for_node(root),!, % then lookup constants rather than computing them
2155 transition(root,_,Dst),
2156 visited_expression(Dst,concrete_constants(X)),
2157 translate:translate_bstate(X,R).
2158 %get_set_up_constants_solution(R) :-
2159 % b_interpreter: b_set_up_concrete_constants(X),
2160 % translate:translate_bstate(X,R).
2161
2162 add_or_between_constant_predicates([],'1=1').
2163 add_or_between_constant_predicates(L,Res) :-
2164 tools: ajoin_with_sep(L,' or ',Res).
2165
2166 filter_constants_bindings(EState,R) :-
2167 b_get_machine_all_constants(C),
2168 convert_typed_varlist(C,CVarList,_CTypes),
2169 filter_constants_bindings1(EState,CVarList,R).
2170
2171 filter_constants_bindings1([],_,[]).
2172 filter_constants_bindings1([bind(Ident,Val)|T],CVarList,Res) :-
2173 (member(Ident,CVarList) -> Res = [bind(Ident,Val)|Rest]; Res = Rest),
2174 filter_constants_bindings1(T,CVarList,Rest).
2175
2176 convert_typed_varlist([],[],[]).
2177 convert_typed_varlist([b(identifier(ID),Type,_)|T],[ID|IT],[Type|TT]) :-
2178 %print(ID), print(' : '), print(Type),nl,
2179 % db : set(couple(global(Name),global(Code))) a : set(integer) boolean
2180 convert_typed_varlist(T,IT,TT).
2181 %--------------------------------------
2182
2183
2184 :- use_module(symmetry_marker,[type_allows_for_precise_marker/1]).
2185 :- use_module(bmachine,[b_is_unused_constant/1]).
2186 :- use_module(library(codesio),[format_to_codes/3]).
2187 generate_typing_list([],[],[],1).
2188 generate_typing_list([Var|VT],[BasicType|TT],[Translation|Rest],TotCard) :-
2189 pretty_type(BasicType,PrettyType),
2190 (kernel_objects:max_cardinality(BasicType,Card) -> true ; Card='??'),
2191 (b_get_constant_represented_inside_global_set(Var,BasicType)
2192 -> Imp='(treated as enumerated) '
2193 ; (preference(symmetry_mode,hash),
2194 \+type_allows_for_precise_marker(BasicType))
2195 -> Imp = '(IMPRECISE for HASH) '
2196 ; Imp = ''
2197 ),
2198 (non_det_constant(Var)
2199 -> MulSol ='[multiple solutions in SETUP_CONSTANTS]'
2200 ; MulSol=''),
2201 (b_is_unused_constant(Var) -> Unused=' (unused)' ; Unused=''),
2202 % mnf(translate:translate_bexpression(b(member(identifier(Var),BasicType),pred,[]),Translation)),
2203 format_to_codes('~w:~w [card=~w]~w~w~w',[Var,PrettyType,Card,MulSol,Imp,Unused],Codes),
2204 atom_codes(Translation,Codes),
2205 generate_typing_list(VT,TT,Rest,RestCard),
2206 kernel_objects:safe_mul(RestCard,Card,TotCard).
2207
2208 :- use_module(symmetry_marker,[hash_model_checking_imprecise/2]).
2209 :- use_module(translate,[pretty_type/2]).
2210 :- public tcltk_hash_model_checking_imprecise/0.
2211 tcltk_hash_model_checking_imprecise :-
2212 hash_model_checking_imprecise(ID,BasicType),!,
2213 print(' * Note: Hashing may be imprecise for: '),
2214 print(ID), print(' : '),translate:pretty_type(BasicType,S),print(S), print(' !'),nl.
2215
2216
2217 /* find constants which are assigned multiple values */
2218 :- dynamic non_det_constant/1.
2219 find_non_det_constants :-
2220 retractall(non_det_constant(_)),
2221 findall(Csts,visited_expression(_,concrete_constants(Csts),_),CL),
2222 (CL=[Valuation1|O],O=[_|_] -> find_non_det_constants1(Valuation1,O)
2223 ; true /* 0 or 1 valuation only */
2224 ).
2225
2226 find_non_det_constants1([],_).
2227 find_non_det_constants1([bind(C,Value)|T],Other) :- check_cst(Other, C, Value, PeeledOther),
2228 find_non_det_constants1(T,PeeledOther).
2229
2230 check_cst([],_,_,[]).
2231 check_cst([ [bind(C,OtherVal)|T1] | TT], C, Value, [ T1 | PTT]) :-
2232 (Value=OtherVal -> check_cst(TT,C,Value,PTT)
2233 ; assert(non_det_constant(C)), peel2(TT,PTT)).
2234 peel2([],[]).
2235 peel2([ [_|T1] | TT], [ T1 | PTT]) :- peel2(TT,PTT).
2236
2237
2238 /* --------------------------------- */
2239
2240
2241 /* for tcltk: */
2242 :- use_module(pref_definitions,[b_get_definition_string_list_from_spec/2, b_get_definition_string_from_spec/2]).
2243 /* --------------------------------- */
2244
2245 %%
2246 % Visualize Invariant...
2247 %
2248 % Siehe bvisual.pl
2249
2250 :- use_module(bvisual).
2251
2252 :- public generate_dot_from_invariant/1.
2253 generate_dot_from_invariant(FileName):-
2254 bmachine:b_get_invariant_from_machine(BExpr),
2255 write_dot_file_for_pred_expr(BExpr,FileName).
2256
2257
2258 :- public generate_dot_from_operation/2.
2259 generate_dot_from_operation(TclOpName,FileName) :-
2260 predicate_debugger:adapt_tcl_operation_name(TclOpName,OpName),
2261 bvisual:get_operation_pre(OpName, BExpr, _BecomesSuchVars),
2262 write_dot_file_for_pred_expr(BExpr,FileName).
2263 %generate_tree_from_boolean_expression(BExpr, Tree,BecomesSuchVars),
2264 %write_dot_graph_to_file(Tree,FileName).
2265
2266
2267 generate_dot_from_properties(FileName) :-
2268 (current_state_corresponds_to_fully_setup_b_machine -> CreateExists=false; CreateExists=true),
2269 bvisual:get_properties(BExpr,CreateExists),
2270 write_dot_file_for_pred_expr(BExpr,FileName).
2271
2272 :- use_module(bsyntaxtree,[conjunct_predicates/2]).
2273
2274 generate_dot_from_assertions(FileName) :-
2275 (current_state_corresponds_to_setup_constants_b_machine,
2276 bmachine:b_get_dynamic_assertions_from_machine(BExpr), BExpr \=[]
2277 -> true
2278 ; bmachine:b_get_static_assertions_from_machine(BExpr)
2279 ),
2280 conjunct_predicates(BExpr,BE),
2281 write_dot_file_for_pred_expr(BE,FileName).
2282
2283 generate_dot_from_goal(FileName) :-
2284 b_get_machine_goal(BExpr),!,
2285 write_dot_file_for_pred_expr(BExpr,FileName).
2286 generate_dot_from_goal(FileName) :-
2287 write_dot_file_for_pred_expr_and_state(b(string('No GOAL DEFINITION available'),string,[]),[],[],FileName).
2288
2289 generate_dot_from_deadlock_po(FileName) :-
2290 b_state_model_check:get_unsorted_all_guards_false_pred(BExpr),
2291 %print('% CHECKING: '),translate_bexpression(BExpr,PT), print(PT),nl,
2292 write_dot_file_for_pred_expr(BExpr,FileName). % we do not check it is a predicate anymore
2293
2294
2295 generate_dot_from_formula(Pred,FileName) :-
2296 format('Parsing formula ~w~n',[Pred]),
2297 parse_machine_formula(Pred,TypedExpr),
2298 format('Writing dot formula ~w~n',[TypedExpr]),
2299 write_dot_file_for_pred_expr(TypedExpr,FileName).
2300
2301
2302 :- use_module(bmachine, [b_parse_machine_formula/3, type_with_errors/4]).
2303 parse_machine_formula(RawAST,TypedPred) :- compound(RawAST),!, % allow to pass raw AST as well
2304 type_with_errors(RawAST,[prob_ids(visible),variables],_Type,TypedPred).
2305 parse_machine_formula(PredStr,TypedExpr) :-
2306 b_parse_machine_formula(PredStr,[prob_ids(visible),variables],TypedExpr).
2307
2308
2309 write_dot_file_for_pred_expr(BExpr,FileName) :-
2310 generate_tree_in_cur_state(BExpr, Tree,[]),
2311 printsilent('% Writing to: '), printsilent(FileName),nls,
2312 mnf(write_dot_graph_to_file(Tree,FileName)).
2313 write_dot_file_for_pred_expr_and_state(BExpr, LocalState, State,FileName) :-
2314 mnf(get_tree_from_expr(Tree, BExpr, LocalState, State)),
2315 printsilent('% Writing to: '), printsilent(FileName),nls,
2316 mnf(write_dot_graph_to_file(Tree,FileName)).
2317
2318 generate_tree_in_cur_state(BExpr,Tree,BSVars):-
2319 ( current_state_corresponds_to_setup_constants_b_machine,
2320 current_b_expression(CurState0),
2321 % print(cur(CurState0)),nl,
2322 insert_before_substitution_variables(BSVars,[],CurState0,CurState0,CurState)
2323 ;
2324 CurState = []
2325 ),!,
2326 mnf(get_tree_from_expr(Tree, BExpr, [], CurState)).
2327
2328 tcltk_bv_get_tops(Tops) :-
2329 bv_get_top_level(Tops).
2330 tcltk_bv_get_structure(Id,Label,list(Subs)) :-
2331 bv_expand_formula(Id,Label,Subs).
2332 tcltk_bv_is_leaf(Id,Label) :-
2333 bv_expand_formula(Id,Label,[]).
2334 tcltk_bv_get_values(Ids,list(RTexts),list(Tags)) :-
2335 current_state_id(StateId),
2336 bv_get_values(Ids,StateId,Values),
2337 predicate_debugger:maplist5(user:retrieve_tag_adapted_text_for_id,Ids,Values,Tags,RTexts).
2338 tcltk_bv_get_value(Id,RText,Tag) :-
2339 tcltk_bv_get_values([Id],list([RText]),list([Tag])).
2340 tcltk_bv_show_formula_as_dot_tree(Id,File) :-
2341 bv_get_stored_formula_expr(Id,TExpr),
2342 write_dot_file_for_pred_expr(TExpr,File).
2343 tcltk_bv_show_formula_as_dot_graph(Id,File) :-
2344 bv_get_stored_formula_expr(Id,TExpr),
2345 get_texpr_type(TExpr,Type),
2346 Type \= pred, Type \= subst,
2347 % tcltk_show_typed_expression_as_dot_graph decomposes expressions and shows value as graph: could be useful for pre-configured DEFINITIONS
2348 tcltk_show_typed_expression_as_dot_graph(TExpr,File).
2349
2350 retrieve_tag_adapted_text_for_id(Id,Value,Tag,RText) :-
2351 retrieve_tag_text_for_id(Id,Value,Tag,Text),
2352 (Text = '[]' -> RText = '[ ]' ; RText=Text). % for some reason the empty sequence translation [] gets transformed into '' by the tcltk library
2353
2354 retrieve_tag_text_for_id(Id,Value,FullTag,Text) :-
2355 retrieve_tag_text(Value,Tag,Text),
2356 (bv_is_explanation_node(Id) -> convert_explain_tag(Tag,FullTag) ; FullTag=Tag).
2357 retrieve_tag_text(i, inac, '').
2358 retrieve_tag_text(e(Text), error, Text).
2359 retrieve_tag_text(v(Text), value, Text).
2360 retrieve_tag_text(p(true), ptrue, true).
2361 retrieve_tag_text(p(false),pfalse, false).
2362
2363 :- public tcltk_bv_get_unlimited_value/3.
2364 tcltk_bv_get_unlimited_value(Id,Text,Tag) :-
2365 current_state_id(StateId),
2366 bv_get_value_unlimited(Id,StateId,Value),
2367 retrieve_tag_text_for_id(Id,Value,Tag,Text1),
2368 atom_codes(Text1,Text). % TODO: In the end, the result was converted from codes to atom and back
2369
2370 convert_explain_tag(ptrue,explaintrue).
2371 convert_explain_tag(pfalse,explainfalse).
2372 convert_explain_tag(X,X).
2373
2374 % -----------------------------------------
2375
2376 % STILL TO DO: refactor eval from here and probcli into separate module
2377
2378 :- dynamic eval_elapsed_time/1.
2379 :- meta_predicate tcltk_time_call(0).
2380 tcltk_time_call(Call) :-
2381 cputime(T1),Call,cputime(T2),ElapsedTime is T2-T1,
2382 retractall(eval_elapsed_time(_)),assert(eval_elapsed_time(ElapsedTime)).
2383
2384 :- use_module(eval_strings).
2385
2386 :- public tcltk_eval/4.
2387 tcltk_eval(String,StringResult,EnumWarning,Solution) :-
2388 get_computed_preference(debug_time_out,DTO),
2389 %print(debug_time_out(DTO)),nl,
2390 time_out_with_enum_warning_one_solution(eval_string(String,StringResult,EnumWarning,LocalState),DTO,TimeOutRes),
2391 (LocalState=[] -> Solution='' ; translate_bstate(LocalState,Solution)),
2392 (is_time_out_result(TimeOutRes) ->
2393 StringResult = '**** TIME-OUT ****', print(StringResult), print(' ('),print(DTO), print('ms)'),nl,
2394 EnumWarning = no
2395 ; print_last_info).
2396
2397 :- public tcltk_eval_string_in_cur_state/2.
2398 tcltk_eval_string_in_cur_state(String,TclValue) :-
2399 eval_string_in_cur_state(String,_,Value),
2400 convert_value_to_tcl(Value,TclValue).
2401 convert_value_to_tcl(int(X),R) :- !, R=X.
2402 convert_value_to_tcl(pred_true,R) :- !, R=1.
2403 convert_value_to_tcl(pred_false,R) :- !, R=0.
2404 convert_value_to_tcl(string(X),R) :- !, R=X.
2405 % TO DO: add sets,...
2406 convert_value_to_tcl(R,R) :- print(cannot_convert_to_tcl(R,R)),nl.
2407
2408 eval_string_in_cur_state(String,Typed,Value) :-
2409 %format('Parsing : "~w"~n',[String]),
2410 bmachine:parse_expression_raw_or_atom_with_prob_ids(String,Typed),
2411 current_state_id(CurID), prob2_interface:get_state(CurID,EState),
2412 %print(evaluating_in_state(CurID)),nl,
2413 b_compute_expression_with_prob_ids(Typed,EState,Value).
2414
2415 % code to translate an expression into a list of lists that can be displayed as a table in Tk
2416 % TO DO: make more robust and add more fancy translations
2417 :- use_module(table_tools).
2418 tcltk_eval_as_table(String,Res) :-
2419 eval_string_in_cur_state(String,Typed,Value),
2420 Res = list([list(Header)|Table]),
2421 expand_and_translate_to_table_for_expr(Typed,Value,Header,Table,['no-row-numbers']).
2422
2423 :- use_module(user_interrupts,[interruptable_call/1, interruptable_call/2]).
2424 interruptable_tcltk_eval(String,StringResult,EnumWarning,Solution) :-
2425 if(interruptable_call(tcltk_eval(String,StringResult,EnumWarning,Solution)),true,
2426 (StringResult = 'Error or User-Interrupt', EnumWarning=unknown, Solution='')).
2427
2428 % -----------------------------------------
2429 % B Simplifier
2430 :- use_module(probporsrc(b_simplifier),[tcltk_simplify_b_predicate/2]).
2431 tcltk_simplify_predicate(String,StringResult) :-
2432 tcltk_simplify_b_predicate(String,StringResult).
2433
2434
2435 % -----------------------------------------
2436 % CBC Check
2437
2438 get_cbc_data_base_id_checks(IDs) :-
2439 findall(ID,b_state_model_check: cbc_check(ID,_Text,_Call,_Res,_Ok),IDs).
2440 get_cbc_data_base_text_checks(Strings) :-
2441 findall(Text1,(b_state_model_check: cbc_check(_ID,Text,_Call,_Res,_Ok),tools: string_concatenate(Text,';',Text1)),Strings).
2442
2443
2444 % -----------------------------------------
2445
2446 % CSP Refinement Search
2447
2448 :- dynamic tcltk_cspm_mode/0.
2449
2450 set_tcltk_cspm_mode :- assert(tcltk_cspm_mode).
2451 unset_tcltk_cspm_mode :- retractall(tcltk_cspm_mode).
2452
2453 :- meta_predicate add_csp_process_id1(-,-,1).
2454
2455 get_new_csp_process_id(E,File,ID) :-
2456 ( parse_single_csp_expression_file(E,File,Proc) ->
2457 haskell_csp: check_compiled_term(Proc), add_csp_process_id1(Proc,ID,animatable_process)
2458 ; add_error(parse_single_csp_expression_file,'Invalid process expression: ',E),fail
2459 ).
2460
2461 %parse_and_analyze_process_expression(ProcExp,File,Proc) :-
2462 % ( parse_single_csp_expression_file(ProcExp,File,Proc) -> true
2463 % ; add_error(parse_single_csp_expression_file,'Invalid process expression: ',ProcExp),fail
2464 % ).
2465
2466 :- use_module(refinement_checker).
2467 get_csp_process_id(Process,ID) :- get_start_transition_term(Process,Trans),
2468 transition(root,Trans,ID).
2469
2470 :- use_module(probcspsrc(haskell_csp),[animatable_process_without_arguments/1,animatable_process/1,animatable_process_cli/1]).
2471 add_csp_process_id(Process,NewID) :-
2472 add_csp_process_id1(Process,NewID,animatable_process_cli).
2473
2474 add_csp_process_id1(Process,NewID,Pred) :-
2475 (call(Pred,Process)
2476 -> get_start_transition_term(Process,Trans),
2477 (transition(root,Trans,_,DestID) -> NewID=DestID % process already set up
2478 ; xtl_interface:get_start_expr(Process,NewState),
2479 add_trans_id(root,Trans,NewState,[],NewID,[],_)
2480 )
2481 ; add_error_fail(add_csp_process_id,'Not an animatable CSP Process: ',Process)).
2482
2483 get_start_transition_term('MAIN',R) :- !, R= start_cspm_MAIN.
2484 get_start_transition_term(agent_call(_Src,'MAIN',[]),R) :- !, R= start_cspm_MAIN.
2485 get_start_transition_term(P,start_cspm(P)).
2486
2487 add_csp_general_process_id(val_of(Process,_),ID) :- !,
2488 ( animatable_process_without_arguments(Process) % in case the called processes is one without arguments, then we don't have to parse the expression
2489 -> add_csp_process_id(Process,ID)
2490 % code below not covered; loaded_main_file only defined for probcli entry point !
2491 %; animation_mode(cspm),
2492 % loaded_main_file(CSPFile),
2493 % parse_and_analyze_process_expression(Process,CSPFile,Proc),
2494 % (transition(root,start_cspm(Proc),_TransID,ID) -> true
2495 % ; otherwise -> add_trans_id(root,start_cspm(Proc),Proc,[],ID,[],_)
2496 % )
2497 ).
2498 add_csp_general_process_id(GenProcExpr,ID) :-
2499 % stripping out the source-loc info
2500 haskell_csp_analyzer: clear_span(GenProcExpr,GenProcExpr1),
2501 get_start_transition_term(GenProcExpr1,Trans),
2502 (transition(root,Trans,_TransID,ID)
2503 -> true
2504 ; add_trans_id(root,Trans,GenProcExpr1,[],ID,[],_)
2505 ).
2506
2507 :- public tcltk_csp_in_situ_refinement/4.
2508 tcltk_csp_in_situ_refinement(ImplProcess,AbsProcess,ResTrace,Style) :-
2509 format('Checking ~w ~w ~w~n',[AbsProcess,Style,ImplProcess]),
2510 tcltk_csp_in_situ_refinement(ImplProcess,AbsProcess,ResTrace,Style,10000000).
2511 csp_ref_style('[T=',trace). % Trace Refinement
2512 csp_ref_style('T',trace). % Trace Refinement
2513 csp_ref_style('[SF=',singleton_failures). % Singleton Failures Refinement
2514 csp_ref_style('[F=',failures). % Failures Refinement
2515 csp_ref_style('[R=',refusals). % Refusals Refinement
2516 csp_ref_style('[RD=',refusals_div). % Refusals-Divergence Refinement
2517 csp_ref_style('F',failures). % Failures Refinement
2518 csp_ref_style('[FD=',X) :- csp_ref_style('FailureDivergence',X).
2519 csp_ref_style('FD',X) :- csp_ref_style('FailureDivergence',X).
2520 csp_ref_style('Trace',trace).
2521 csp_ref_style('Failure',failures).
2522 csp_ref_style('FailureDivergence',failure_divergences).
2523 csp_ref_style('RefusalTesting',refusals).
2524 csp_ref_style('RefusalTestingDiv',refusals_div).
2525 csp_ref_style('RevivalTesting',revival) :- add_error(unsupported_refinement_operator,'[V= refinement not yet supported.').
2526 csp_ref_style('RevivalTestingDiv',revival_div) :- add_error(unsupported_refinement_operator,'[VD= refinement not yet supported.').
2527
2528 translate_csp_ref_style(Style,RefStyle) :- (csp_ref_style(Style,RefStyle) -> true ;
2529 add_error_fail(csp,'Unknown refinement style: ',Style)).
2530
2531 % tcltk_csp_in_situ_refinement('P','Q',R,0,1000). tcltk_csp_in_situ_refinement('Q','P',R,1000).
2532 tcltk_csp_in_situ_refinement(ImplProcess,AbsProcess,ResTrace,Style,MaxNrOfNewNodes) :-
2533 add_csp_process_id(ImplProcess,ImplNodeID),
2534 add_csp_process_id(AbsProcess,SpecNodeID),
2535 translate_csp_ref_style(Style,RefStyle),
2536 refinement_checker:in_situ_ref_search(ImplNodeID,SpecNodeID,ResTrace,RefStyle,MaxNrOfNewNodes).
2537
2538 :- use_module(probcspsrc(haskell_csp),[get_csp_assertions/1,translate_csp_assertion/2]).
2539 :- public tcltk_check_csp_assertions/2.
2540 tcltk_check_csp_assertions([],Summary) :- get_csp_assertions(Assertions),
2541 treat_csp_ass(Assertions,_List,0,0,0,Summary). % TO DO: display _List
2542
2543 treat_csp_ass([],[],T,F,U,[total/Tot, true/T, false/F, unknown/U]) :- Tot is T+F+U.
2544 treat_csp_ass([Assertion|T],['='(PP,Ok)|TPP],True,False,U,Summary) :- !,
2545 (checkAssertion(Assertion,PP,_,Ok,_)
2546 -> U1=U, (Ok=true -> T1 is True+1, F1=False ; T1=True, F1 is False+1)
2547 ; U1 is U+1, T1=True, F1=False,Ok=unknown),
2548 treat_csp_ass(T,TPP,T1,F1,U1,Summary).
2549 treat_csp_ass([H|T],TP,T1,F1,U,Summary) :- add_error(treat_csp_ass,'Unknown CSP assertion: ',H),
2550 U1 is U+1, treat_csp_ass(T,TP,T1,F1,U1,Summary).
2551
2552 % assertModelCheckExt(False,val_of(P3,src_span(25,8,25,10,562,2)),DeadlockFree,F)
2553
2554 run_assertion_check(assertModelCheckExt(Negated,Spec,Type,ModelStyle),Negated,ResTrace) :-
2555 haskell_csp_analyzer: compile_body(Spec,'assertModelCheck',[],[],CSpec),
2556 debug_println(9,assertModelCheckExt(Negated,CSpec,Type,ModelStyle)),
2557 add_csp_general_process_id(CSpec,SpecNodeID),
2558 translate_csp_ref_style(ModelStyle,RefStyle),
2559 refinement_checker:in_situ_model_check(SpecNodeID,ResTrace,Type,RefStyle,10000000),
2560 print(result_trace),nl,print(ResTrace),nl.
2561 run_assertion_check(assertModelCheck(Negated,Spec,Style),Negated,ResTrace) :-
2562 run_assertion_check(assertModelCheckExt(Negated,Spec,Style,'FailureDivergence'),Negated,ResTrace).
2563 run_assertion_check(assertRef(Negated,Spec,Style,Impl,Span),Negated,ResTrace) :-
2564 haskell_csp_analyzer: compile_body(Spec,'assertRef',[],[],CSpec),
2565 haskell_csp_analyzer: compile_body(Impl,'assertRef',[],[],CImpl),
2566 debug_println(9,assertRef(Negated,CSpec,Style,CImpl,Span)),
2567 add_csp_general_process_id(CSpec,SpecNodeID),
2568 add_csp_general_process_id(CImpl,ImplNodeID),
2569 translate_csp_ref_style(Style,RefStyle),
2570 refinement_checker:in_situ_ref_search(ImplNodeID,SpecNodeID,ResTrace,RefStyle,10000000).
2571 run_assertion_check(assertLtl(Negated,Spec,FormulaAsAtom,_Span),Negated,ResTrace) :-
2572 add_csp_process_id_normalized(Spec,'assertLtl',CSpec,CSpecNodeID),
2573 %% print(add_csp_general_process_id(Spec,CSpec,SpecNodeID)),nl,
2574 tcltk_reset,
2575 ltl:ltl_model_check_with_ce1(CSpec,FormulaAsAtom,-1,specific_node(CSpecNodeID),Result),
2576 translate_ltl_result(Result,ResTrace),
2577 debug_println(9,ltl_result(Negated,CSpec,CSpecNodeID,FormulaAsAtom,Result)).
2578 run_assertion_check(assertCtl(Negated,Spec,FormulaAsAtom,_Span),Negated,ResTrace) :-
2579 add_csp_process_id_normalized(Spec,'assertCtl',CSpec,CSpecNodeID),
2580 tcltk_reset,
2581 ctl: ctl_model_check_with_ce(CSpec,FormulaAsAtom,-1,specific_node(CSpecNodeID),Result,Trace),
2582 debug_println(9,ctl_result(Negated,CSpec,CSpecNodeID,FormulaAsAtom,Result)),
2583 translate_ctl_result(Result,Trace,ResTrace).
2584
2585 checkAssertion(Assertion,PP,Negated,Ok,ResTrace) :-
2586 (silent_mode(on) -> true
2587 ; print('CHECKING '),
2588 translate_csp_assertion(Assertion,PP),
2589 print(PP),nl
2590 ),
2591 debug_println(9,checkAssertion(Assertion)),
2592 reset_refinement_checker,
2593 (run_assertion_check(Assertion,Negated,ResTrace)
2594 -> debug_println(9,result(ResTrace)),
2595 (ResTrace=no_counter_example
2596 -> (Negated = 'False' -> Ok=true
2597 ; %add_error(check_assertRef,'Assertion FAILS (expected refinement not to hold): ',PP),
2598 Ok=false)
2599 ; (ResTrace=[interrupted|_]
2600 -> Ok=interrupted
2601 ; (Negated = 'False' -> %add_error(check_assertRef,'Assertion FAILS: ',PP),
2602 Ok=false ; Ok=true)
2603 )
2604 ),
2605 (Ok=true -> printsilent('OK'),nls
2606 ; Ok=interrupted -> print('*** Execution interrupted by user ***'),nl
2607 ; print('*** FALSE ***'),nl
2608 )
2609 ; add_error_fail(checkAssertion,'Internal Error, Assertion Checking Failed for: ',PP)
2610 ).
2611
2612 add_csp_process_id_normalized(Spec,Functor,CSpec,CSpecNodeID) :-
2613 % stripping out the src_span info
2614 haskell_csp_analyzer: clear_span(Spec,SpecNoSpan),
2615 haskell_csp_analyzer: compile_body(SpecNoSpan,Functor,[],[],CSpec),
2616 add_csp_general_process_id(CSpec,CSpecNodeID).
2617
2618 translate_ltl_result(ok,Res) :- !,
2619 Res = no_counter_example.
2620 translate_ltl_result(no,Res) :- !,
2621 Res = no.
2622 translate_ltl_result(ce(Atom),Res) :-
2623 !, % we have a counter-example for the LTL formula
2624 Res=Atom.
2625 translate_ltl_result(interrupted,Res) :-
2626 !,
2627 Res=[interrupted].
2628 translate_ltl_result(Status,_Res) :-
2629 add_error_fail(ltl_assertions_result, 'Internal Error: unknown LTL assertion result ', Status).
2630
2631 translate_ctl_result(true,_Trace,ResTrace) :- !,
2632 ResTrace = no_counter_example.
2633 translate_ctl_result(false,ce(Atom),ResTrace) :- !,
2634 ResTrace = Atom.
2635 translate_ctl_result(interrupted,_TRace,ResTrace) :-
2636 !,
2637 ResTrace=[interrupted].
2638 translate_ctl_result(Status,_Trace,_ResTrace) :-
2639 add_error_fail(ctl_assertions_result, 'Internal Error: unknown CTL assertion result ', Status).
2640
2641 :- public tcltk_check_csp_assertion/4.
2642 tcltk_check_csp_assertion(Assertion,CSPFile,Negated,Result) :-
2643 tcltk_check_csp_assertion(Assertion,CSPFile,Negated,_PlTerm,Result).
2644
2645 tcltk_check_csp_assertion(Assertion,CSPFile,Negated,PlTerm,Result) :-
2646 parse_single_csp_declaration(Assertion,CSPFile,PlTerm),
2647 checkAssertion(PlTerm,_PP,Negated,_Ok,Result).
2648
2649 :- public tcltk_play_ltl_ctl_counterexample_trace/4.
2650 tcltk_play_ltl_ctl_counterexample_trace(Assertion,CSPFile,Type,FairnessChecked) :-
2651 announce_event(play_counterexample),
2652 ( Type == ltl -> Functor = assertLtl
2653 ; Type == ctl -> Functor = assertCtl
2654 ; otherwise -> add_error_fail(ltl_ctl_counterexample, 'Internal Error: Model checker type unknown: ',Type)),
2655 % constructing the prolog declaration term
2656 PlDeclTerm =.. [Functor,_Negated,Spec,FormulaAsAtom,_Span],
2657 parse_single_csp_declaration(Assertion,CSPFile,PlDeclTerm),
2658 haskell_csp_analyzer: clear_span(Spec,SpecNoSpan),
2659 haskell_csp_analyzer: compile_body(SpecNoSpan,'assertLtl',[],[],CSpec),
2660 % parsing and preprocessing the LTL/CTL formula
2661 parse_and_preprocess_formula(FormulaAsAtom,Type,PF),
2662 (is_fairness_implication(PF) -> FairnessChecked='yes'; FairnessChecked='no'),
2663 % need to reset history and current state before loading the counter-example
2664 tcltk_reset,
2665 tcltk_play_counterexample(Type,CSpec,PF).
2666
2667 tcltk_play_counterexample(ltl,Spec,Formula) :- !,
2668 ltl: tcltk_play_ltl_counterexample(Spec,Formula).
2669 tcltk_play_counterexample(ctl,Spec,Formula) :- !,
2670 ctl: tcltk_play_ctl_counterexample(Spec,Formula).
2671 tcltk_play_counterexample(Type,Spec,Formula) :-
2672 add_error_fail(ltl_ctl_counterexample, 'Internal Error: Unknown domain type: ', (Type,Spec,Formula)).
2673
2674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675
2676 :- public get_ltl_formulas_from_file/2.
2677 %%%% Parse and get LTL formulas from LTL File %%%%
2678 get_ltl_formulas_from_file(Filename,Text) :-
2679 parse_ltlfile(Filename, Formulas),
2680 extract_formulas(Formulas,Fs,_,_),
2681 translate_ltl_formulas(Fs,Text).
2682
2683 translate_ltl_formulas(Formulas,Text) :-
2684 maplist(translate_ltl_formula,Formulas,Strings),
2685 haskell_csp: concatenate_string_list(Strings,Text).
2686
2687 translate_ltl_formula(Formula,Text) :-
2688 pp_ltl_formula(Formula,T),
2689 string_concatenate(T,'$',Text).
2690
2691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692
2693 :- public tcltk_explore_csp_process/2.
2694 tcltk_explore_csp_process(ProcString,SpecNodeID) :-
2695 haskell_csp: parse_single_csp_expression(ltl,ProcString,Res),
2696 haskell_csp_analyzer: clear_span(Res,ResNoSpan),
2697 haskell_csp_analyzer: compile_body(ResNoSpan,'assertLtl',[],[],CRes),
2698 add_csp_general_process_id(CRes,SpecNodeID),
2699 refinement_checker:dfs_check(SpecNodeID,_ResTrace,false,false).
2700
2701 tcltk_visualize_csp_process(SpecNodeID,F) :-
2702 visualize_graph: tcltk_print_csp_process_states_for_dot(F,SpecNodeID).
2703
2704 :- public get_csp_process_stats/1.
2705 :- dynamic nr_csp_process_state/1.
2706 get_csp_process_stats(NrNodes) :-
2707 assert(nr_csp_process_state(0)),
2708 count_nodes,
2709 nr_csp_process_state(NrNodes),
2710 retractall(nr_csp_process_state(_)).
2711
2712 count_nodes :-
2713 refinement_checker: dvisited(_NodeID),
2714 nr_csp_process_state(NrNodes),
2715 NewNrNodes is NrNodes +1,
2716 retractall(nr_csp_process_state(_)),
2717 assert(nr_csp_process_state(NewNrNodes)),
2718 fail.
2719 count_nodes.
2720
2721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722
2723 tcltk_machine_has_assertions :-
2724 ( b_get_static_assertions_from_machine([_|_]); b_get_dynamic_assertions_from_machine([_|_]) ), !.
2725
2726 tcltk_unique_top_level_operation(Name) :- b_top_level_operation(Name),
2727 \+ (b_top_level_operation(N2), N2 \= Name).
2728
2729 tcltk_top_level_operations(list(Res)) :-
2730 findall(Name,b_top_level_operation(Name),Names),
2731 length(Names,L),
2732 (L>5 -> sort(Names,Res) ; Res=Names).
2733
2734 tcltk_get_vacuous_guards(list(R)) :-
2735 eclipse_interface:get_vacuous_guards(L),
2736 (L=[] -> R = ['No vacuous guards']
2737 ; R=L).
2738
2739 tcltk_get_vacuous_invariants(list(L)) :-
2740 eclipse_interface:get_vacuous_invariants(LP),
2741 (LP=[] -> L = ['No vacuous invariants']
2742 ; maplist(translate:translate_bexpression,LP,L)).