1 % (c) 2009-2026 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 %:- set_prolog_flag(source_info,on).
6 % comment in if you want source location, e.g., for exceptions,...
7 % you can also comment in a line in remove_debugging_calls in debugging_calls_te.pl to see location of nl/0
8 % (and ensure debugging_calls.pl is loaded below and in term_expansion hook is set in debugging_calls_te.pl)
9 % with ?- trace, leash(off). one can creep without entering return in the debugger; with leash([redo]) the debugger only stops at the Redo-Port. Use @<RETURN> to enter Prolog commands in the debugger.
10 % leash(exception) also useful
11 % Note: to run probcli from source for ProB2 change change probcli.sh: PROBCOMMAND=probproxy and start probsli -s 8888
12
13 :- module(prob_cli, [go_cli/0,
14 run_probcli/2, run_probcli_with_argv_string/1,
15 reset_cli/0, recognised_cli_option/4, recognised_option/2, go_proxy/0,
16 print_version/1, cli_print_statistics/1]).
17
18 :- set_prolog_flag(double_quotes, codes).
19
20 :- if(predicate_property(expects_dialect(_), _)).
21 :- expects_dialect(sicstus4).
22 :- endif.
23
24 :- multifile user:portray_message/2.
25 user:portray_message(informational, imported(_Nr,_M1,_M2)) :- !.
26 user:portray_message(informational, loading(_Nr,_,_File)) :- !.
27 %user:portray_message(informational, loaded(_Nr,compiled,_File,M,MS,_)) :- !, format('~w ms for ~w~n',[MS,M]).
28 user:portray_message(informational, loaded(_Nr,_CompiledLoaded,_File,_Module,_TimeMS,_Bytes)) :- !.
29 user:portray_message(informational, foreign_resource(_Nr,_Status,_File,_Mod)) :- !.
30 user:portray_message(informational, chr_banner) :- !.
31 %user:portray_message(informational, halt) :- !.
32 %user:portray_message(informational, prompt(off,0,user,off,off,off)) :- !.
33 %user:portray_message(informational, M) :- !, write(M),nl,nl.
34
35
36 :- meta_predicate if_option_set(-,0).
37 :- meta_predicate if_option_set(-,0,0).
38 :- meta_predicate if_options_set(-,0).
39 :- meta_predicate if_option_set_loaded(-,-,0).
40 :- meta_predicate ifm_option_set(-,0).
41 :- meta_predicate ifm_option_set(-,-,0).
42 :- meta_predicate ifm_option_set_loaded(-,-,0).
43
44
45 % patch for SICStus 4.3.3 performance issue
46 % sprm_14972_patch.pl BEGIN
47 :- if((current_prolog_flag(dialect, sicstus),
48 current_prolog_flag(version_data, sicstus(4,3,3,_,_)))).
49 prolog:wf_call_like_arg(A, B, C, D, E, F, G, H, I, _) :-
50 prolog:wellformed_body_iso(A, B, C, D, E, F, G, H, I, quiet),
51 !.
52 prolog:wf_call_like_arg(A, B, C, A, D, _, E, _, _, _) :-
53 F=E:A,
54 prolog:condense_layout(B, G),
55 prolog:comp_layout2(B, G, B, H),
56 C=call(F),
57 prolog:comp_layout1(B, H, D).
58 :- endif.
59 % sprm_14972_patch.pl END
60
61
62 %:- include('self_check_off.pl').
63
64 :- use_module(module_information).
65 :- module_info(group,cli).
66 :- module_info(description,'ProB start file in cli mode.').
67
68 %:- use_module(debugging_calls).
69 %:- register_debugging_calls([pp_mnf(*), pp_cll(*), mnf(*), mnf(-,*), det_call(*)]).
70 %:- disable_debugging_calls.
71
72 :- use_module(prob_startup, [startup_prob/0, stop_prob/0]).
73 %:- use_module(pathes,[set_search_pathes/0]). % called first to set_compile_time_search_pathes
74 :- use_module(tools,[string_concatenate/3,arg_is_number/2, print_memory_used_wo_gc/1, print_memory_used_wo_gc/0,
75 split_atom/3, get_options/5, get_elapsed_walltime/2,
76 start_ms_timer/1, stop_ms_timer/1, stop_ms_timer/2, stop_ms_timer_with_msg/2]).
77 :- use_module(tools_printing,[print_error/1,format_with_colour/4, format_with_colour_nl/4]).
78 :- use_module(tools_strings,[atom_split/4,convert_atom_to_number/2]).
79 :- use_module(tools_meta,[safe_time_out/3]).
80 :- use_module(tools_lists,[count_occurences/2]).
81 :- use_module(covsrc(hit_profiler),[add_to_profile_stats/2]).
82
83 :- use_module(preferences).
84 :- set_prob_application_type(probcli). %
85
86 :- use_module(library(lists)).
87 :- use_module(library(file_systems),[file_exists/1]).
88 :- use_module(library(system)).
89 :- use_module(library(codesio)).
90 :- use_module(library(between),[between/3]).
91 :- use_module(library(terms),[term_hash/2]).
92 :- use_module(library(random),[random/3, setrand/1]).
93
94 :- use_module(self_check,[disable_interaction_on_errors/0,
95 perform_self_check/2,turn_off_run_time_type_checks/0,turn_on_run_time_type_checks/0]).
96 :- use_module(debug).
97 :- use_module(error_manager).
98 :- use_module(translate,[pretty_type/2]).
99 :- use_module(tools,[safe_absolute_file_name/2, safe_absolute_file_name/3, convert_ms_time_to_string/2]).
100 :- use_module(extension('counter/counter'),
101 [counter_init/0, new_counter/1, get_counter/2, inc_counter/1, inc_counter/2, reset_counter/1]).
102 :- use_module(state_space,[current_expression/2]).
103
104
105 :- dynamic junit_mode/1.
106 :- use_module(junit_tests,[set_junit_dir/1, create_and_print_junit_result/4]).
107
108 :- use_module(b_trace_checking,[check_default_trace_for_specfile/1, tcltk_check_state_sequence_from_file/1,
109 tcltk_check_sequence_from_file/3, get_default_trace_file/3,
110 tcltk_save_history_as_trace_file/2,tcltk_save_history_as_trace_file/3]).
111 :- use_module(eventhandling,[store_virtual_event/1]).
112 :- use_module(bmachine,[b_set_initial_machine/0]).
113 :- use_module(specfile).
114 :- use_module(test_typechecker,[run_typecheck_testcase/2]).
115 :- use_module(basic_unit_tests). % basic unit tests
116 :- use_module(bsyntaxtree,[size_of_conjunction/2, get_texpr_id/2, get_texpr_description/2,
117 conjunction_to_list/2,
118 get_texpr_label/2, predicate_components/2, get_texpr_pos/2]).
119 :- use_module(bmachine,[b_write_machine_representation_to_file/3,
120 full_b_machine/1, b_write_eventb_machine_to_classicalb_to_file/1]).
121 :- use_module(state_space,[current_state_id/1, get_state_space_stats/4, compute_full_state_space_hash/1]).
122 :- use_module(xtl_interface,[set_cspm_main_process/1]).
123 :- use_module(extrasrc(meta_interface),[is_dot_command/1, call_dot_command_with_engine/4,
124 is_dot_command_for_expr/1,call_dot_command_with_engine_for_expr/5,
125 is_plantuml_command/1, is_plantuml_command_for_expr/1,
126 is_table_command/1, is_table_command_for_expr/1,
127 call_plantuml_command/2, call_plantuml_command_for_expr/4,
128 call_command/5, is_table_command/6,
129 write_table_to_text_file/2, write_table_to_csv_file/3,
130 command_description/3]).
131 :- use_module(kodkodsrc(kodkod_test),[test_kodkod/1, compare_kodkod_performance/2]).
132 :- use_module(kodkodsrc(predicate_analysis),[test_predicate_analysis/0]).
133 :- use_module(b_show_history,[write_history_to_file/2,write_values_to_file/1,
134 write_all_values_to_dir/1,write_history_to_user_output/1]).
135 :- use_module(cbcsrc(sap), [write_all_deadlocking_paths_to_xml/1, test_generation_by_xml_description/1]).
136 :- use_module(smtlib_solver(smtlib2_cli),[smtlib2_file/2, get_smtlib2_result_infos/1]).
137 :- use_module(disproversrc(disprover_test_runner), [run_disprover_on_all_pos/1,
138 load_po_file/1,print_disprover_stats/0, set_disprover_timeout/1,
139 set_disprover_options/1, reset_disprover_timeout/0]).
140 :- use_module(extrasrc(latex_processor), [process_latex_file/2]).
141 :- use_module(probltlsrc(ltl),[ltl_check_assertions/2,ltl_model_check/4]).
142 :- use_module(probltlsrc(ctl),[ctl_model_check/4]).
143
144 :- use_module(logger).
145 :- use_module(extension('zmq/master/master'),[start_master/8]).
146 :- use_module(extension('zmq/worker/worker'),[start_worker/5]).
147 :- use_module(extension('ltsmin/ltsmin'),
148 [start_ltsmin/4,ltsmin_init/3,ltsmin_loop/1,ltsmin_teardown/2,ltsmin_generate_ltlfile/2]).
149 :- use_module(extrasrc(coverage_statistics),[compute_the_coverage/5]).
150 :- use_module(value_persistance, [set_storage_directory/2, print_value_persistance_stats/0,
151 delete_cache_files_for_machine/1, delete_cache_files/0,
152 ignore_value_persistance_cache_for/1,
153 get_value_persistance_stats/1, show_cache_file_contents/1]).
154 :- use_module(prob_socketserver,[start_prob_socketserver/2]).
155 :- use_module(tcltk_interface).
156 %:- compile(gui_tcltk).
157 :- use_module(eclipse_interface).
158 :- use_module(prob2_interface,[start_animation/0, is_initialised_state/1, reset_animator/0,
159 set_eclipse_preference/2, update_preferences_from_spec/1,
160 load_cspm_spec_from_cspm_file/1, load_xtl_spec_from_prolog_file/1]).
161
162 start_probcli_timer(timer(T1,WT1)) :-
163 statistics(runtime,[T1,_]),
164 statistics(walltime,[WT1,_]).
165 stop_probcli_debug_timer(Timer,Msg) :-
166 (debug_mode(on) -> stop_probcli_timer(Timer,Msg),print_memory_used_wo_gc,nl ; true).
167 stop_probcli_timer(timer(T1,WT1),Msg) :- stop_probcli_timer(timer(T1,WT1),Msg,_).
168 stop_probcli_timer(timer(T1,WT1),Msg,WTotTime) :-
169 statistics(runtime,[T2,_]), TotTime is T2-T1,
170 statistics(walltime,[WT2,_]), WTotTime is WT2-WT1,
171 convert_ms_time_to_string(WT2,WTString),
172 format('~w ~w ms walltime (~w ms runtime), since start: ~w~n',[Msg,WTotTime,TotTime,WTString]),
173 !.
174 stop_probcli_timer(Timer,Msg,_) :- add_internal_error('Illegal timer call: ',stop_probcli_timer(Timer,Msg)).
175 print_total_probcli_timer :-
176 statistics(runtime,[T2,_]),
177 statistics(walltime,[WT2,_]),
178 format('Since start of probcli: ~w ms walltime (~w ms runtime)~n',[WT2,T2]).
179 get_probcli_elapsed_walltime(timer(_,WT1),WTotTime) :-
180 statistics(walltime,[WT2,_]), WTotTime is WT2-WT1.
181 get_probcli_elapsed_runtime(timer(RT1,_),RTotTime) :-
182 statistics(runtime,[RT2,_]), RTotTime is RT2-RT1.
183
184 :- meta_predicate timeout_call(0,-,-).
185 timeout_call(Call,NOW,PP) :- option(timeout(TO)),!,
186 statistics(runtime,[T1,_]),
187 safe_time_out(Call,TO,Res),
188 statistics(runtime,[T2,_]), Runtime is T2-T1,
189 formatsilent('Runtime for ~w: ~w ms~n',[PP,Runtime]),
190 (Res=time_out -> print('*** Timeout occurred: '), print(TO),nl,
191 print('*** Call: '), print(Call),nl,
192 nl,
193 writeln_log(timeout_occurred(NOW,Call))
194 ; true).
195 timeout_call(Call,_NOW,PP) :-
196 statistics(runtime,[T1,_]),
197 call(Call),
198 statistics(runtime,[T2,_]), Runtime is T2-T1,
199 formatsilent('Runtime for ~w: ~w ms~n',[PP,Runtime]).
200
201 set_junit_mode(X) :-
202 set_junit_dir(X),
203 retractall(junit_mode(_)),
204 statistics(runtime,[Start,_]),
205 assertz(junit_mode(Start)).
206
207 go_proxy :-
208 catch( run_probcli(['-s','8888'],[proxy]), halt(ExitCode),
209 ( nl,write('CLI halt prevented, exit code '),write(ExitCode),nl) ).
210
211 go_cli :-
212 % set_prob_application_type(probcli) is already done at compile_time
213 current_prolog_flag(argv,ArgV),
214 run_probcli_with_junit_check(ArgV).
215
216 initialise_cli :- counter_init,
217 new_counter(cli_execute_inits),
218 new_counter(cli_errors), new_counter(cli_warnings),
219 new_counter(cli_expected_errors),
220 new_counter(eval_string_nr).
221
222 % called from test_runner.pl:
223 reset_cli :-
224 announce_event(clear_specification),
225 announce_event(reset_prob),
226 reset_cli_options,
227 reset_expected_error_occurred,
228 reset_optional_errors_or_warnings,
229 reset_counter(cli_errors), reset_counter(cli_warnings),
230 reset_counter(cli_expected_errors),
231 reset_counter(eval_string_nr),
232 retractall(accumulated_infos(_,_,_)),
233 retractall(merged_individual_file_infos(_,_,_)),
234 retractall(individual_file_infos(_,_,_)),
235 (file_loaded(_)
236 -> clear_loaded_machines, % TODO: also treat by reset_prob eventhandling?
237 retractall(file_loaded(_,_)),
238 retractall(loaded_main_file(_,_))
239 ; true).
240
241 reset_cli_options :- option_verbose,verbose_off,fail.
242 reset_cli_options :- option(set_gc_trace(_X)),set_gc_trace(off),fail.
243 reset_cli_options :- option(profiling_on),profiling_off,fail.
244 % TODO: are there more options to reset?
245 reset_cli_options.
246
247 run_probcli_with_junit_check(ArgV) :-
248 catch( run_probcli(ArgV,[junit]),
249 halt(ExitCode),
250 ( ExitCode = 0 ->
251 true
252 ; ( junit_mode(S) ->
253 statistics(runtime,[E,_]), T is E - S,
254 create_and_print_junit_result(['Integration Tests'],ArgV,T,error([ExitCode]))
255 ; true),
256 throw(halt(ExitCode)))).
257
258
259 % a useful entry point for Jupyter to mimic probcli execution in notebooks
260 run_probcli_with_argv_string(ArgVAtom) :- split_argv_string(ArgVAtom,Atoms),
261 (Atoms = [probcli|Atoms2] -> true ; Atoms2=Atoms),
262 run_probcli(Atoms2,[run_probcli_with_argv_string]).
263
264 split_argv_string(ArgVAtom,Atoms) :- split_atom(ArgVAtom,[' '],Atoms). % TODO: treat quoting
265
266 run_probcli(ArgV,Context) :- % format(user_output,'~n* Starting probcli with argv: ~w~n~n',[ArgV]),
267 (catch(
268 run_probcli2(ArgV),
269 Exc,
270 process_exception(Exc,Context)
271 )
272 -> stop_prob
273 ; flush_output,
274 print_error('INTERNAL ERROR OCCURRED (run_probcli failed) !'),nl,
275 error_occurred(internal_error),
276 halt_exception(1)
277 ).
278
279 :- use_module(translate,[translate_error_term/2]).
280 %process_exception(Exception,_) :- write('Exception: '),write(Exception),nl,fail. % for debugging
281 process_exception(halt(A),_) :- !, throw(halt(A)).
282 process_exception(unwind(halt(A)),_) :- !, throw(halt(A)). % SWI Prolog; other values for unwind are abort, thread_exit
283 process_exception('$aborted',_) :- !, throw('$aborted'). % thrown by SWI-Prolog on abort by user
284 process_exception(user_interrupt_signal,Context) :- !,
285 %add_error(probcli,'probcli interrupted by user (CTRL-C)').
286 statistics(walltime,[WStart,_]),
287 format_with_colour_nl(user_error,[red],'~nprobcli interrupted by user (CTRL-C), total walltime ~w ms',[WStart]),
288 (member(test_runner,Context)
289 -> throw(user_interrupt_signal) % will be caught by test_runner
290 ; error_occurred_with_msg(user_interrupt_signal,'probcli interrupted by user (CTRL-C)')
291 ).
292 process_exception(Exc,_) :-
293 (translate_error_term(Exc,S)
294 -> format_error_with_nl('Uncaught exception in probcli: ~w',[S])
295 ; true),
296 error_occurred(internal_error(exception(Exc))),fail.
297
298 no_command_issued :- \+ command_option(_).
299 command_option(X) :- option(X), \+ not_command_option(X).
300 not_command_option(verbose(_)).
301 not_command_option(profiling_on).
302 not_command_option(set_pref(_,_)).
303 not_command_option(set_preference_group(_,_)).
304 not_command_option(set_card(_,_)).
305 not_command_option(set_argv(_)).
306 not_command_option(silent).
307 not_command_option(strict_raise_error).
308 not_command_option(no_color).
309
310 probcli_startup :-
311 %print_total_probcli_timer,
312 startup_prob, % % startup_prob will already call init_preferences
313 %myheap_init,
314 initialise_cli.
315
316 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
317 :- if(environ(prob_logging_mode,true)).
318 cli_set_options(ArgV,RemArgV) :-
319 cli_init_options(['-ll'|ArgV],RemArgV). %% adds -ll to have an automatically logging probcli to /tmp/prob_cli_debug.log
320 :- else.
321 cli_set_options(ArgV,RemArgV) :- cli_init_options(ArgV,RemArgV).
322 :- endif.
323
324 %:- use_module(extension('myheap/myheap')).
325 run_probcli2(ArgV) :- %print(probcli_startup),nl_time,
326 treat_important_options_beforehand(ArgV),
327 probcli_startup,
328 external_functions:reset_argv,
329 cli_set_options(ArgV,RemArgV), % recognise command-line options
330 %% cli_set_options(['-vv','-version'|ArgV],RemArgV), %% comment in to have an automatically verbose probcli
331 maplist(prob_cli:check_atom_looks_like_file,RemArgV),
332 (option(prolog_trace) -> error_manager:safe_trace ; true),
333 !,
334 run_probcli3(ArgV,RemArgV).
335
336 % treat important options beforehand, e.g., to enable debug prints straight-away, e.g., before probcli_startup
337 treat_important_options_beforehand(ArgV) :-
338 ? member(Opt,ArgV),recognised_option(Opt,RecognisedOpt),treat_important_option(RecognisedOpt),fail.
339 treat_important_options_beforehand(_).
340
341 treat_important_option(verbose(Nr)) :- verbose(Nr).
342 treat_important_option(set_gc_trace(X)) :- set_gc_trace(X).
343 treat_important_option(profiling_on) :- profiling_on.
344
345
346 run_probcli3(ArgV,RemArgV) :-
347 ( RemArgV=[File],no_command_issued,
348 get_filename_extension(File,Ext),
349 \+ do_not_execute_automatically(Ext)
350 % then assume we want to do -execute_all:
351 -> assert_option(execute(2147483647,false,current_state(1)))
352 ; true),
353 if_option_set(set_application_type(PAT),set_prob_application_type(PAT)),
354 if_option_set(test_mode,set_random_seed_to_deterministic_start_seed, set_new_random_seed),
355 ifm_option_set(verbose(VN),
356 verbose(VN), %tcltk_turn_debugging_on(5)),
357 tcltk_turn_debugging_off),
358 % TODO: reset the next three to default values if no flags present, in case we use them for tests:
359 if_option_set(set_gc_trace(GCT),set_gc_trace(GCT)),
360 if_option_set(set_gc_margin(GCM),set_gc_margin(GCM)),
361 if_option_set(set_gc_on_off(GCO),set_gc_on_off(GCO)),
362 if_option_set(profiling_on,profiling_on),
363 debug_print(9,'Command Line Arguments: '),debug_println(9,ArgV),
364 (debug_level_active_for(5) -> print_options ; true),
365 debug_print(6,'Command Line File Args: '),debug_println(6,RemArgV),
366 debug_flush_output,
367 if_option_set(cache_storage(StorageDir,SetStorMode), set_storage_directory(StorageDir,SetStorMode)),
368 if_option_set(parsercp(ParserLoc),
369 (add_message(parsercp,'Command -parcercp PATH deprecated, use -p JAVA_PARSER_PATH PATH',''),
370 set_preference(path_to_java_parser,ParserLoc))
371 ),
372 if_option_set(parserport(ParserPort),
373 connect_to_external_console_parser_on_port(ParserPort)),
374 generate_time_stamp(Datime,NOW),
375 if_option_set(log(LogF,Mode),
376 cli_start_logging(LogF,Mode,NOW,Datime,RemArgV)),
377 if_option_set(runtimechecking,
378 turn_on_run_time_type_checks,
379 turn_off_run_time_type_checks),
380 if_option_set(junit(JUX),
381 set_junit_mode(JUX)),
382 set_prefs,
383 (option_verbose, (option(set_prefs_from_file(_)) ; option(set_preference_group(_,_))),
384 get_non_default_preferences(list(NDPrefs))
385 -> format('Non-default preferences:~n',[]),print_list(NDPrefs),nl ; true),
386 set_optional_errors,
387 check_unavailable_options,
388 cli_show_help(ArgV,RemArgV),
389 if_option_set(set_argv(ArgVStr),
390 set_argv(ArgVStr)),
391 if_option_set(selfcheck(_,_),
392 cli_start_selfcheck),
393 if_option_set(typechecker_test(Filename),
394 (run_typecheck_testcase(Filename,typesok) -> halt_prob(NOW,0); halt_prob(NOW,1))),
395 if_option_set(install_prob_lib(LIBTOINSTALL,INSTALLOPTS), install_prob_lib(LIBTOINSTALL,INSTALLOPTS)),
396 if_options_set(print_version(VERSIONKIND), print_version(VERSIONKIND)),
397 if_option_set(check_java_version, check_java_version),
398 (debug_level_active_for(5) -> preferences:print_preferences ; true),
399 if_option_set(zmq_worker(Identifier), zmq_start_worker(Identifier, NOW)),
400 %if_option_set(zmq_worker2(MasterIP, Port, ProxyID, Logfile), zmq_start_worker(MasterIP,Port,ProxyID,Logfile,NOW)),
401 % process remaining arguments as files to load
402 % some utility commands which do not require main file:
403 ifm_option_set(indent_b_file_to_file(PPBFILE0,OUTFILE,OPTS),
404 indent_b_file_to_file(PPBFILE0,OUTFILE,OPTS)), % utility to format B file
405 ifm_option_set(pretty_print_prolog_file(PPFILE0,OUTFILE),
406 pretty_print_prolog_file(PPFILE0,OUTFILE)), % utility to print Prolog file
407 debug_println(6,processing(RemArgV)),
408 cli_load_files(RemArgV,NOW), % all CLI arguments which are not understood are supposed to be files to be treated
409 debug_println(19,finished_loading(RemArgV)),
410 if_option_set(socket(Port,Loopback),
411 cli_start_socketserver(Port,Loopback)),
412 % check_all_expected_errors_occurred(NOW), % is now checked for each file; socket_server should not generate errors ?
413 debug_println(20,'% probcli execution finished'),
414 cli_print_junit_results(ArgV),
415 debug_println(20,'% Stored Junit results'),
416 stop_xml_probcli_run(NOW),
417 debug_println(20,'% ProB Finished').
418
419 % finish logxml file by writing total number of errors and warnings
420 stop_xml_probcli_run(NOW) :-
421 get_counter(cli_errors,CErrs), get_counter(cli_warnings,CWarns), get_counter(cli_expected_errors,EErrs),
422 writeln_log_time(prob_finished(NOW,CErrs,CWarns)),
423 (EErrs>0
424 -> write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns,expected_errors/EErrs])
425 ; write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns])
426 ),
427 ((CErrs>0 ; CWarns>0) -> format(user_error,'! Total Errors: ~w, Warnings:~w~n',[CErrs,CWarns]) ; true),
428 stop_xml_group_in_log('probcli-run'). % Generating this tag means probcli ran to completion without segfault,...
429
430 % check if a cli argument looks like a proper filename
431 :- public check_file_arg/2. % is actually called when parsing options
432 check_file_arg(File,Command) :- normalise_option_atom(File,NF),
433 recognised_option(NF,_,_,_),!,
434 ajoin(['Command-line file argument for ', Command, ' looks like another probcli command: '],Msg),
435 add_warning(probcli,Msg,File).
436 check_file_arg(File,Command) :-
437 tools:check_filename_arg(File,Command).
438
439 % check if a remaining argument looks suspicious (e.g., like an unknown command)
440 check_atom_looks_like_file(Number) :- number(Number),!,
441 add_warning(probcli,'Command-line argument is a number (expected file name or probcli command): ',Number).
442 check_atom_looks_like_file(File) :- atom(File), !, atom_codes(File,Codes),
443 check_codes_look_like_file(Codes,File).
444 check_atom_looks_like_file(Arg) :-
445 add_warning(probcli,'Command-line argument is a compound term (expected file name or probcli command): ',Arg).
446 check_codes_look_like_file(Codes,Arg) :-
447 check_codes_resembles_command(Codes,Arg),!.
448 check_codes_look_like_file([D|T],Arg) :- is_digit_code(D),
449 (T=[] -> true
450 ; T = [D2|_], is_digit_code(D2),
451 nonmember(0'/,T), nonmember(0'.,T) % detect things like 01_Jan/a.mch
452 ),
453 !,
454 add_message(probcli,'Command-line argument looks like a number: ',Arg).
455 check_codes_look_like_file(_,_).
456
457 is_digit_code(D) :- D >= 0'0, D =< 0'9.
458
459 check_codes_resembles_command([45|_],Arg) :- !,
460 (get_possible_fuzzy_match_options(Arg,FuzzyMatches),
461 FuzzyMatches \= []
462 -> (FuzzyMatches=[FM]
463 -> ajoin(['Command-line argument ', Arg, ' looks like a probcli command! Did you mean: '],Msg),
464 add_warning(probcli,Msg,FM)
465 ; ajoin(['Command-line argument ', Arg, ' looks like a probcli command! Did you mean any of: '],Msg),
466 add_warning(probcli,Msg,FuzzyMatches)
467 )
468 ; get_possible_options_completion_msg(Arg,Completions)
469 -> ajoin(['Command-line argument ', Arg, ' looks like a probcli command! Did you mean: '],Msg),
470 add_warning(probcli,Msg,Completions)
471 ; add_message(probcli,'Command-line argument looks like an unknown probcli command: ',Arg)).
472
473 :- use_module(extrasrc(refinement_checker),[valid_failures_model/2]).
474 check_failures_mode(Shortcut,FailuresModel) :- valid_failures_model(FailuresModel,Shortcut),!.
475 check_failures_mode(Shortcut,trace) :-
476 add_warning(probcli,'Unrecognised refinement model flag (must be F, FD, T, R, RD, SF, V, VD; using default trace model T): ',Shortcut).
477
478 % ----------
479
480 cli_init_options(ArgV,RemArgV) :- %print(argv(ArgV)),nl,
481 append(ProBArgV,['--'|BArgV],ArgV),!, % pass arguments after -- to B via external_functions
482 cli_init_options2(ProBArgV,RemArgV),
483 debug_println(20,set_argv_from_list(BArgV)),
484 external_functions:set_argv_from_list(BArgV).
485 cli_init_options(ArgV,RemArgV) :- cli_init_options2(ArgV,RemArgV).
486 cli_init_options2(ArgV,RemArgV) :-
487 reset_options,
488 %%assertz(option(log('/tmp/ProBLog.log'))), print('LOGGING'),nl, %% coment in to build a version of probcli that automatically logs
489 ( get_options(ArgV,recognised_cli_option,Options,RemArgV,throw(halt(1))) ->
490 assert_all_options(Options)
491 ;
492 print_error(get_options_failed(ArgV)),definite_error_occurred).
493 cli_show_help(ArgV,RemArgV) :-
494 ( (option(help) ; ArgV=[]) ->
495 print_help, (RemArgV=[] -> halt_exception ; true)
496 ; true).
497 cli_start_logging(F,Mode,NOW,Datime,RemArgV) :-
498 debug_print(20,'%logging to: '), debug_println(20,F),
499 set_log_file(F), set_logging_mode(Mode),
500 start_xml_group_in_log('probcli-run'),
501 writeln_log(start_logging(NOW,F)),
502 version(V1,V2,V3,Suffix), revision(Rev), lastchangeddate(LCD),
503 writeln_log(version(NOW,V1,V2,V3,Suffix,Rev,LCD)), % still used by log_analyser
504 current_prolog_flag(version,PV),
505 write_xml_element_to_log(version,[major/V1,minor/V2,patch/V3,suffix/Suffix,revision/Rev,lastchanged/LCD,prolog/PV]),
506 findall(Opt, option(Opt), Options),
507 write_prolog_term_as_xml_to_log(options(NOW,Options)),
508 write_prolog_term_as_xml_to_log(files(NOW,RemArgV)), %
509 datime(Datime,DateRecord),
510 writeln_log(date(NOW,DateRecord)),
511 (DateRecord=datime(Yr,Mon,Day,Hr,Min,Sec)
512 -> write_xml_element_to_log(date,[year/Yr,month/Mon,day/Day,hour/Hr,minutes/Min,seconds/Sec]) ; true).
513
514 cli_start_selfcheck :-
515 %clear_loaded_machines_wo_errors,
516 b_set_initial_machine,
517 set_animation_mode(b),
518 store_virtual_event(clear_specification), % TO DO: try and get rid of the need for this
519 start_animation,
520 option(selfcheck(ModuleCombo,Opts)),
521 (atom(ModuleCombo),
522 atom_split(Module,':',TestNrA,ModuleCombo)
523 -> convert_atom_to_number(TestNrA,TestNr),
524 Opts2=[run_only_nr(TestNr)|Opts]
525 ; Module=ModuleCombo, Opts2=Opts
526 ),
527 (option(silent) -> Opts3=[silent|Opts2] ; option_verbose -> Opts3=[verbose|Opts2] ; Opts3=Opts2),
528 (perform_self_check(Module,Opts3) -> true ; error_occurred(selfcheck)),
529 fail.
530 cli_start_selfcheck.
531
532
533 :- dynamic file_loaded/2.
534 file_loaded(Status) :- file_loaded(Status,_File).
535
536
537 cli_load_files([],NOW) :- % no files are provided
538 !,
539 ( options_allow_start_without_file
540 -> debug_format(19,'Using empty machine to process probcli command~n',[]),
541 cli_set_empty_machine
542 ; we_did_something -> true
543 ; print('No file to process'),nl),
544 writeln_log_time(start_processing_empty_machine(NOW)),
545 start_xml_feature(process_file,filename,'$EMPTY_MACHINE',FINFO),
546 cli_process_loaded_file(NOW,'$EMPTY_MACHINE'),
547 check_all_expected_errors_occurred(NOW), % check that all expected errors occurred; below they will be checked for each file
548 stop_xml_feature(process_file,FINFO),
549 print_accumulated_infos_if_necessary.
550 cli_load_files(RemArgV,NOW) :-
551 cli_load_files2(RemArgV,NOW,0).
552
553 print_accumulated_infos_if_necessary :-
554 (option(benchmark_info_csv_output(_,_,_)) -> print_accumulated_infos(0) ; true).
555
556 cli_set_empty_machine :- % TO DO: do this more properly here and for initialise_required
557 set_animation_mode(b),
558 bmachine:b_set_empty_machine,
559 assertz(file_loaded(true,'$$empty_machine')).
560
561 empty_machine_loaded :- file_loaded(true,'$$empty_machine').
562
563
564 options_allow_start_without_file :- option(run_benchmark(_,_,_)).
565 options_allow_start_without_file :- option(eval_repl(_)).
566 options_allow_start_without_file :- option(eval_string_or_file(_,_,_,_,_)).
567 options_allow_start_without_file :- option(check_log(_)).
568 options_allow_start_without_file :- option(process_latex_file(_,_)).
569 options_allow_start_without_file :- option(socket(_,_)).
570
571 we_did_something :- option(print_version(_)).
572 we_did_something :- option(check_java_version).
573 we_did_something :- option(check_parser_version).
574 we_did_something :- option(install_prob_lib(_,_)).
575 we_did_something :- option(indent_b_file_to_file(_,_,_)).
576 we_did_something :- option(pretty_print_prolog_file(_,_)).
577
578 option_only_works_for_single_file(zmq_assertion(_Identifier)).
579 option_only_works_for_single_file(zmq_master(_Identifier)).
580
581 clear_loaded_files :-
582 (file_loaded(_) -> clear_loaded_machines_wo_errors ; true).
583
584 % called if we have at least one file
585 cli_load_files2([],_,NrFilesProcessed) :- !,
586 debug_println(19,finished_procesing_all_files(NrFilesProcessed)),
587 print_accumulated_infos(NrFilesProcessed). % print summary of all runs for different files
588 cli_load_files2([F1,F2|T],NOW,_NrFilesProcessed) :-
589 option(Option),
590 option_only_works_for_single_file(Option),!,
591 add_error(probcli,'The following option can only be used for a single file: ',Option),
592 add_error(probcli,'Multiple files provided: ',[F1,F2|T]),
593 halt_prob(NOW,0).
594 cli_load_files2(RemArgV,NOW,NrFilesProcessed) :-
595 %print_total_probcli_timer,
596 clear_loaded_files,
597 retractall(file_loaded(_,_)),
598 RemArgV = [MainFile0|Rest],!,
599 N1 is NrFilesProcessed+1,
600 cli_load_files3(MainFile0,Rest,NOW,N1).
601 cli_load_files3(MainFile0,Rest,NOW,NrOfFile) :-
602 safe_absolute_file_name(MainFile0,MainFile,[access(none)]), % converts Windows slash into Unix slash,...
603 if_option_set(file_info,print_file_info(MainFile)),
604 ((Rest=[_|_] ; NrOfFile>1)
605 -> length(Rest,RLen), Tot is NrOfFile+RLen,
606 format('~n~n% Processing file ~w/~w: ~w~n',[NrOfFile,Tot,MainFile]) % was formatsilent
607 ; true),
608 start_ms_timer(ProcessFileTimer),
609 start_xml_feature(process_file,filename,MainFile,FINFO),
610 ( file_exists(MainFile) ->
611 debug_println(6,file_exists(MainFile)),
612 ( load_main_file(MainFile,NOW,Already_FullyProcessed) ->
613 (Already_FullyProcessed==true
614 -> true
615 ; assertz(file_loaded(true,MainFile)),
616 trimcore_if_useful(Rest),
617 writeln_log_time(start_processing(NOW)),
618 start_probcli_timer(Timer),
619 catch((cli_process_loaded_file(NOW,MainFile)
620 -> stop_probcli_debug_timer(Timer,'% Finished processing file after')
621 ; print_error('Processing or loading file failed: '), print_error(MainFile),
622 start_repl_even_after_failure
623 ),
624 user_interrupt_signal, % catch CTRL-C by user but give chance to enter REPL
625 start_repl_even_after_failure
626 ),
627 writeln_log_time(finished_processing(NOW))
628 )
629 ;
630 assertz(file_loaded(error,MainFile)),
631 print_error('Loading Specification Failed'),
632 writeln_log_time(loading_failed(NOW,MainFile)),
633 error_occurred(load_main_file)
634 %start_repl_even_after_failure : TODO: fix issues with bmachine not precompiled and counter extension
635 ),
636 nls,
637 ifm_option_set(indent_main_b_file(PPFILE0),
638 indent_main_b_file(PPFILE0)),
639 ifm_option_set(pretty_print_prolog_file(PPFILE0),
640 pretty_print_prolog_file(PPFILE0))
641 ; % not file_exists
642 nl, assertz(file_loaded(error,MainFile)),
643 (number(MainFile0)
644 -> add_error(load_main_file,'Command-line argument is a number which is not associated with a command and does not exist as file: ',MainFile0)
645 ; atom_codes(MainFile0,[45|_]) % starts with a dash - : probably an illegal command-line option
646 -> add_error(load_main_file,'Specified option or file does not exist: ',MainFile0)
647 ; get_filename_extension(MainFile,Ext), \+ known_spec_file_extension(Ext,_)
648 -> (Ext = '' -> EMsg = 'Specified file does not exist and has no file extension:'
649 ; ajoin(['Specified file does not exist and has an unrecognised file extension ".',Ext,'" :'], EMsg)
650 ),
651 add_error(load_main_file,EMsg,MainFile)
652 ; add_error(load_main_file,'Specified file does not exist:',MainFile)
653 )
654 ),
655 check_all_expected_errors_occurred(NOW),
656 get_elapsed_walltime(ProcessFileTimer,WT1), add_to_profile_stats(total_file_processing_walltime,WT1),
657 accumulate_default_infos,
658 stop_xml_feature(process_file,FINFO),
659
660 debug_println(19,reset_expected_error_occurred),
661 reset_expected_error_occurred, % reset for next file
662 debug_println(19,resetting_errors),
663 reset_errors,
664 debug_println(19,update_time_stamp),
665 NOW1 is NOW+1,
666 update_time_stamp(NOW1),
667 debug_println(19,remaining_files_to_process(Rest)),
668 cli_load_files2(Rest,NOW1,NrOfFile).
669
670 start_repl_even_after_failure :-
671 (option(eval_repl([]))
672 -> format_with_colour_nl(user_output,[blue],'Starting REPL, but ignoring any other commands',[]),
673 % TODO: check if setup_constants_fails and then suggest e.g. :core @PROPERTIES command
674 start_repl_if_required % can be useful to debug properties, e.g, one can fix an error and reload
675 ; true
676 ).
677
678 print_file_info(F) :-
679 print('Specification_File('), print(F), print(')'),nl.
680
681 :- use_module(probsrc(tools),[statistics_memory_used/1]).
682 trimcore_if_useful(_) :- option(release_java_parser),!, prob_trimcore.
683 % if user wants to release java parser, this is an indication that the .prob files are big and it can be good to free memory
684 trimcore_if_useful([]) :- % try and reduce Prologs memory consumption, see also PROLOGKEEPSIZE parameter
685 % a lot of memory can be consumed loading .prob file and doing machine construction
686 !,
687 (option(X), memory_intensive_option(X)
688 -> debug_format(9,'Not trimming memory usage because of memory intensive option: ~w~n',[X])
689 ; statistics_memory_used(M), M< 300000000 % less than 300 MB used
690 -> debug_format(9,'Not trimming memory usage because of memory used is already low: ~w~n',[M])
691 ; prob_trimcore
692 ).
693 trimcore_if_useful(_) :- debug_println(9,'Not trimming memory usage as there are still files to process').
694
695 prob_trimcore :- (option_verbose ; option(release_java_parser)),!,prob_trimcore_verbose.
696 prob_trimcore :- prob_trimcore_silent.
697
698 prob_trimcore_verbose :-
699 print('Memory used before trimming: '),print_memory_used_wo_gc,flush_output, nl_time,
700 prob_trimcore_silent,
701 print('Memory used after trimming : '),print_memory_used_wo_gc,flush_output, nl_time.
702 prob_trimcore_silent :-
703 garbage_collect, % is important, otherwise trimming may achieve very little
704 trimcore.
705
706 memory_intensive_option(cli_mc(_)).
707 memory_intensive_option(ltl_formula_model_check(_,_)).
708 memory_intensive_option(ctl_formula_model_check(_,_)).
709 memory_intensive_option(pctl_formula_model_check(_,_)).
710 memory_intensive_option(refinement_check(_,_,_)).
711 memory_intensive_option(generate_all_traces_until(_,_,_)).
712
713 % ---------------------
714
715 % process all the commands for a loaded file:
716 cli_process_loaded_file(NOW,MainFile) :-
717 (real_error_occurred -> print_error('% *** Errors occurred while loading ! ***'),nl,nl ; true),
718 get_errors, reset_errors,
719 if_option_set(kodkod_performance(KPFile,Iterations),
720 compare_kodkod_performance1(KPFile,Iterations,NOW)),
721 if_option_set(kodkod_comparision(MaxResiduePreds),
722 test_kodkod_and_exit(MaxResiduePreds,NOW)),
723 % if_option_set(add_csp_guide(CspGuide), tcltk_add_csp_file(CspGuide)), %% moved to later to ensure B machine is precompiled; allows e.g. type_check_csp_and_b to run
724
725 if_option_set(csp_main(MAINPROC),
726 set_cspm_main_process(MAINPROC)),
727
728 if_option_set(zmq_master(Identifier), zmq_start_master(invariant,Identifier)),
729 %if_option_set(zmq_master(IP, Logfile), zmq_start_master(invariant,200,-1,5000,0,IP,Logfile)),
730
731 ifm_option_set(check_machine_file_sha(FileToCheck,ExpectedSha1Hash),
732 check_machine_file_sha(FileToCheck,ExpectedSha1Hash)),
733 ifm_option_set(clear_value_persistance_cache(MachineToClear),
734 delete_cache_files_for_machine(MachineToClear)),
735 ifm_option_set(ignore_value_persistance_cache_for(MachineToIgnore),
736 ignore_value_persistance_cache_for(MachineToIgnore)),
737 ifm_option_set(clear_value_persistance_cache,
738 delete_cache_files),
739
740 % STARTING ANIMATION/MODEL CHECKING
741 cli_start_animation(NOW),
742
743 if_option_set_loaded(cli_core_properties(MaxCoreSize),cli_core_properties,
744 cli_core_properties(MaxCoreSize)),
745
746 if_option_set_loaded(default_trace_check,default_trace_check,
747 cli_start_default_trace_check(MainFile)),
748 if_option_set_loaded(trace_check(TrStyle,TraceFile,ChkMode),trace_check,
749 cli_start_trace_check(TrStyle,TraceFile,ChkMode)),
750
751 cli_process_loaded_file_afer_start_animation(NOW).
752
753 cli_process_loaded_file_afer_start_animation(NOW) :-
754 ifm_option_set(cli_print_machine_info(IKind),
755 cli_print_machine_info(IKind)),
756 ifm_option_set(pretty_print_internal_rep(PPFILE1,MachName1,TYPES1,ASCII1),
757 pretty_print_internal_rep(PPFILE1,MachName1,TYPES1,ASCII1)),
758 ifm_option_set(pretty_print_internal_rep_to_B(PPFILE3),
759 b_write_eventb_machine_to_classicalb_to_file(PPFILE3)),
760
761 if_option_set_loaded(state_trace(TraceFile),state_trace,
762 cli_start_trace_state_check(TraceFile)),
763
764 if_option_set(evaldot(EvalDotF),
765 set_eval_dot_file(EvalDotF)),
766
767 (initialise_required
768 -> check_loaded(initialise),
769 cli_start_initialisation(NOW),
770 writeln_log_time(initialised(NOW))
771 ; true),
772 if_option_set(check_abstract_constants,
773 check_abstract_constants),
774
775 if_option_set(zmq_assertion(Identifier),
776 zmq_start_master(assertion,Identifier)),
777
778 if_option_set(cli_lint,cli_lint(_)),
779 ifm_option_set_loaded(cli_lint(LintCheck),cli_lint,cli_lint(LintCheck)),
780 if_option_set(cli_wd_check(Disch,TotPos),cli_wd_check(Disch,TotPos)),
781 if_option_set(cli_wd_inv_proof(UnchangedNr,ProvenNr,TotPOsNr),cli_wd_inv_proof(UnchangedNr,ProvenNr,TotPOsNr)),
782 if_option_set(cli_start_mc_with_tlc,cli_start_mc_with_tlc),
783 if_option_set(cli_start_sym_mc_with_lts(LType),cli_start_sym_mc_with_lts(LType)),
784
785 if_option_set(cli_symbolic_model_check(Algorithm),cli_symbolic_model_check(Algorithm)),
786
787 if_option_set_loaded(cli_check_properties,check_properties,
788 cli_check_properties(NOW)),
789 ifm_option_set_loaded(cli_check_assertions(ALL,ReqInfos),check_assertions,
790 cli_check_assertions(ALL,ReqInfos,NOW)),
791 if_option_set(set_goal(GOAL),
792 cli_set_goal(GOAL)),
793 if_option_set(set_searchscope(SCOPE),
794 cli_set_searchscope(SCOPE)),
795 ifm_option_set_loaded(cli_mc(Nr,MCOpts),model_check,
796 cli_start_model_check(Nr,NOW,MCOpts)),
797 ifm_option_set_loaded(cli_simulate(File,Reps,Steps,SimOpts),simulate,
798 cli_simulate(File,Reps,Steps,SimOpts)),
799 ifm_option_set_loaded(cli_random_animate(Steps,ErrOnDeadlock),animate,
800 cli_random_animate(NOW,Steps,ErrOnDeadlock)),
801 ifm_option_set_loaded(execute(ESteps,ErrOnDeadlock,From),execute,
802 cli_execute(ESteps,ErrOnDeadlock,From)),
803 ifm_option_set_loaded(animate_until_ltl(LTLFormula,ExOption,ExpResult,ExpSteps),execute,
804 animate_until_ltl(LTLFormula,ExOption,ExpResult,ExpSteps)),
805 if_option_set_loaded(pa_check,predicate_analysis,
806 test_predicate_analysis),
807
808 cbc_check(NOW),
809
810 ifm_option_set_loaded(logxml_write_ids(Prefix,IDScope),logxml_write_ids,
811 logxml_write_ids(Prefix,IDScope)),
812
813 if_options_set(generate_read_write_matrix_csv(RWCsvFile),
814 generate_read_write_matrix(RWCsvFile)),
815 if_options_set(feasibility_analysis_csv(TimeOut,EnablingCsvFile),
816 do_feasibility_analysis(TimeOut,EnablingCsvFile)),
817 ifm_option_set_loaded(mcm_tests(ADepth1,AMaxS,ATarget1,Output1),mcm_test_cases,
818 mcm_test_case_generation(ADepth1,AMaxS,ATarget1,Output1)),
819 ifm_option_set_loaded(all_deadlocking_paths(File),all_deadlocking_paths,
820 write_all_deadlocking_paths_to_xml(File)),
821 ifm_option_set_loaded(cbc_tests(ADepth2,ATarget2,Output2),cb_test_cases,
822 cbc_test_case_generation(ADepth2,ATarget2,Output2)),
823 ifm_option_set_loaded(test_description(TestDescFile),cb_test_cases,
824 test_generation_by_xml_description(TestDescFile)),
825 if_options_set(csp_in_situ_refinement_check(RP,RType,RQ),
826 cli_csp_in_situ_refinement_check(RP,RType,RQ,NOW)),
827 if_options_set(csp_checkAssertion(Proc,Model,AssertionType),
828 cli_checkAssertion(Proc,Model,AssertionType,NOW)),
829 if_options_set(check_csp_assertion(Assertion),
830 cli_check_csp_assertion(Assertion,NOW)),
831 if_options_set(refinement_check(RefFile,FailuresModel,RefNrNodes),
832 cli_start_refinement_check(RefFile,FailuresModel,RefNrNodes,NOW)),
833 if_options_set(ctl_formula_model_check(CFormula,CExpected),
834 (timeout_call(cli_ctl_model_check(CFormula,init,CExpected,_),NOW,ctl_model_check) -> true; true)),
835 if_options_set(pctl_formula_model_check(PFormula,PExpected),
836 (timeout_call(cli_pctl_model_check(PFormula,init,PExpected,_),NOW,ctl_model_check) -> true; true)),
837 % TO DO print ctl/ltl statistics
838 if_options_set(csp_get_assertions,cli_csp_get_assertions),
839 if_options_set(eval_csp_expression(CspExpr),cli_eval_csp_expression(CspExpr)),
840 if_options_set(csp_translate_to_file(PlFile),cli_csp_translate_to_file(PlFile)),
841 if_options_set(get_coverage_information(CovFileName),cli_get_coverage_information(CovFileName)), %% TODO: replace
842 if_options_set(vacuity_check,cli_vacuity_check),
843 if_option_set_loaded(check_goal,check_goal,cli_check_goal),
844 if_option_set_loaded(animate,animate,
845 (interactive_animate_machine -> true ; true)),
846 if_option_set(ltsmin, start_ltsmin_srv('/tmp/ltsmin.probz', NOW)),
847 if_option_set(ltsmin2(EndpointPath), start_ltsmin_srv(EndpointPath, NOW)),
848 if_option_set(ltsmin_ltl_output(Path), ltsmin_ltl_output(Path, NOW)),
849 if_options_set(run_benchmark(Kind,Option,Path), run_benchmark(Kind,Option,Path)),
850 evaluate_from_commandline,
851 if_option_set_loaded(ltl_assertions,check_ltl_assertions,
852 (timeout_call(ltl_check_assertions,NOW,check_ltl_assertions) -> true; true)),
853 ifm_option_set_loaded(ltl_formula_model_check(LFormula,LExpected),check_ltl_assertions,
854 (option(cli_start_sym_mc_with_lts(_))-> true % we request LTSMin, do not start prob model check
855 ; timeout_call(cli_ltl_model_check(LFormula,init,LExpected,_),NOW,ltl_formula_model_check)
856 -> true; true)),
857 ifm_option_set_loaded(ltl_file(LtlFilename),check_ltl_file,
858 (ltl_check_file(LtlFilename) -> true; true)),
859 ifm_option_set_loaded(visb_history(VJSONFile,VHTMLFile,Options),visb,
860 cli_visb_history(VJSONFile,VHTMLFile,Options)),
861 ifm_option_set_loaded(history(HistoryFilename),history,
862 cli_print_history(HistoryFilename)),
863 ifm_option_set_loaded(print_values(ValuesFilename),sptxt,
864 cli_print_values(ValuesFilename)),
865 ifm_option_set_loaded(print_all_values(ValuesDirname),print_all_values,
866 cli_print_all_values(ValuesDirname)),
867 ifm_option_set_loaded(generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix),generate_all_traces_until,
868 cli_generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix)),
869 if_options_set(save_state_for_refinement(SaveRefF),
870 tcltk_save_specification_state_for_refinement(SaveRefF)),
871 if_options_set(rule_report(File),
872 rule_validation:generate_report(File)),
873 if_options_set(proof_export(Style,File),
874 sequent_prover_exports:export_proof_for_current_state(Style,File)),
875 if_options_set(dot_command(DCommand1,DotFile1,DotEngine1),
876 dot_command(DCommand1,DotFile1,DotEngine1)),
877 if_options_set(dot_command_for_expr(DECommand,Expr,DotFile,Opts,DotEngine),
878 dot_command_for_expr(DECommand,Expr,DotFile,Opts,DotEngine)),
879 if_options_set(plantuml_command(PCommand1,UmlFile1),
880 plantuml_command(PCommand1,UmlFile1)),
881 if_options_set(plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts),
882 plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts)),
883 if_options_set(csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile),
884 csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile)),
885 if_options_set(evaluate_expression_over_history_to_csv_file(HistExpr,HistDotFile),
886 tcltk_interface:evaluate_expression_over_history_to_csv_file(HistExpr,HistDotFile)),
887 if_options_set(enabling_analysis_csv(EnablingCsvFile),
888 do_enabling_analysis_csv(EnablingCsvFile,NOW)),
889 if_options_set(process_latex_file(LatexF1,LatexF2),
890 process_latex_file(LatexF1,LatexF2)),
891 ifm_option_set(coverage(Nodes,Operations,ShowEnabledInfo),
892 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW)),
893 ifm_option_set(check_statespace_hash(ExpectedHash,Kind),
894 cli_check_statespace_hash(ExpectedHash,Kind)),
895 ifm_option_set(check_op_cache(ExpectedC),
896 cli_check_op_cache(ExpectedC)),
897 ifm_option_set(coverage(ShowEnabledInfo),
898 cli_show_coverage(ShowEnabledInfo,NOW)),
899 if_option_set(save_state_space(StateFile),
900 save_state_space(StateFile)),
901 ifm_option_set(cli_print_statistics(SPARA),
902 cli_print_statistics(SPARA)),
903 if_option_set(show_cache(SCVM),
904 show_cache(SCVM)),
905 if_option_set(cli_cache_stats_check(CStats),cli_cache_stats_check(CStats)),
906 if_option_set(check_complete, check_complete),
907 if_option_set(check_complete_operation_coverage, check_complete_operation_coverage),
908 if_option_set(check_scc_for_ltl_formula(LtlFormulaSCC,SCC),cli_check_scc_for_ltl_formula(LtlFormulaSCC,SCC)).
909
910 % what needs to be done for files like .po files, where all processing is already done:
911 cli_process_options_for_alrady_fully_processed_file(_MainFile) :-
912 ifm_option_set(cli_print_statistics(SPARA),
913 cli_print_statistics(SPARA)).
914
915 show_cache(default) :- !,
916 (option_verbose -> show_cache(normal) ; show_cache(verbose)).
917 show_cache(Verbose) :- % -show_cache_verbose
918 show_cache_file_contents(Verbose).
919
920 cli_cache_stats_check(Expected) :-
921 get_value_persistance_stats(Stats),
922 check_required_infos(Expected,Stats,check_cache_stats).
923
924 % new profiler
925 %:- use_module('../extensions/profiler/profiler.pl').
926 %cli_print_statistics :- pen,nl,garbage_collect,statistics,nl,state_space:state_space_initialise_with_stats.
927
928 :- use_module(runtime_profiler,[print_runtime_profile/0]).
929 :- use_module(source_profiler,[print_source_profile/0]).
930 :- use_module(memoization,[print_memo_profile/0]).
931 :- use_module(state_packing,[print_state_packing_profile/0]).
932 :- use_module(external_functions,[print_external_function_instantiation_profile/0]).
933
934 % old profiler
935 :- use_module(covsrc(hit_profiler),[print_hit_profile_statistics/0]).
936 :- use_module(extrasrc(b_operation_cache),[print_op_cache_profile/0, reset_b_operation_cache_with_statistics/0]).
937 :- use_module(memoization,[reset_memo_with_statistics/0]).
938 :- use_module(disproversrc(disprover),[print_prover_result_stats/0]).
939 :- use_module(probsrc(tools),[print_mb/1]).
940 cli_print_statistics(hshow) :- !,
941 print_machine_topological_order.
942 cli_print_statistics(memory) :- !,
943 print_memory_statistics(user_output).
944 cli_print_statistics(value_persistance_stats) :- !,
945 print_value_persistance_stats.
946 cli_print_statistics(sicstus_profile) :- !,
947 format('SICStus Prolog PROFILE STATISTICS~n',[]),
948 sicstus_profile_statistics.
949 cli_print_statistics(disprover_profile) :- !,
950 print_prover_result_stats.
951 cli_print_statistics(prob_profile) :- !,
952 statistics(walltime,[WT,_]),
953 statistics(runtime,[RT,_]),
954 format('--------------------------~nPROB PROFILING INFORMATION after ~w ms walltime (~w ms runtime) ',[WT,RT]),
955 statistics_memory_used(M), print_mb(M),nl,
956 print_source_profile,
957 print_runtime_profile,
958 print_memo_profile,
959 print_state_packing_profile,
960 print_external_function_instantiation_profile,
961 (get_preference(operation_reuse_setting,false) -> true ; print_op_cache_profile). % relevant for test 2152 under SWI
962 cli_print_statistics(hit_profile) :- !,
963 (print_hit_profile_statistics -> true ; true). % mainly used by external functions
964 cli_print_statistics(op_cache_profile) :- !,
965 get_preference(try_operation_reuse,OR),
966 format('PROB OPERATION_REUSE (value:~w) STATISTICS~n',[OR]),
967 print_op_cache_profile.
968 cli_print_statistics(simb_profile) :- !,
969 print_simb_profile.
970 cli_print_statistics(full) :- format('PROB FULL STATISTICS~n',[]),
971 sicstus_profile_statistics,
972 garbage_collect,
973 statistics,
974 nl,
975 print_op_cache_profile,
976 print_prover_result_stats,
977 state_space:state_space_initialise_with_stats,
978 reset_memo_with_statistics,
979 reset_b_operation_cache_with_statistics.
980
981 print_memory_statistics(Stream) :-
982 garbage_collect,
983 write(Stream,'ProB memory used: '),
984 print_memory_used_wo_gc(Stream), nl(Stream), flush_output(Stream).
985
986 sicstus_profile_statistics :-
987 %(hit_profiler:print_hit_profile_statistics -> true ; true), % only used by external functions
988 (option(profiling_on)
989 -> catch(print_profile,
990 error(existence_error(_,_),_),
991 print_red('SICStus Prolog Profiler can only be used when running from source'))
992 ; true).
993
994
995 :- use_module(state_space,[not_all_transitions_added/1, not_invariant_checked/1,
996 not_interesting/1, get_operation_name_coverage_infos/4]).
997 check_complete :-
998 (tcltk_find_max_reached_node(Node1) ->
999 add_error(check_complete,'Maximum number of transitions reached for at least one state: ',Node1) ; true),
1000 (not_all_transitions_added(Node2) ->
1001 add_error(check_complete,'At least one state was not examined: ',Node2) ; true),
1002 (not_invariant_checked(Node3) ->
1003 add_error(check_complete,'The invariant was not checked for at least one state: ',Node3) ; true),
1004 (not_interesting(Node4) ->
1005 add_message(check_complete,'At least one state was ignored (not satisfying the SCOPE predicate): ',Node4) ; true).
1006
1007 check_complete_operation_coverage :-
1008 (state_space: operation_name_not_yet_covered(OpName) ->
1009 add_error(check_complete_operation_coverage,'At least one operation is not covered: ', OpName)
1010 ; true).
1011
1012 show_operation_coverage_summary(NOW) :-
1013 get_operation_name_coverage_infos(PossibleNr,FeasibleNr,UncovNr,UncoveredList),
1014 writeln_log(uncovered_info(NOW,PossibleNr,UncoveredList)),
1015 (UncovNr=0 -> format(' All ~w possible operations have been covered',[PossibleNr]),nl
1016 ; (FeasibleNr=PossibleNr
1017 -> format(' The following ~w operations (out of ~w) were not covered:~n ~w~n',
1018 [UncovNr, PossibleNr,UncoveredList])
1019 ; INr is PossibleNr-FeasibleNr,
1020 format(' The following ~w operations (out of ~w with ~w infeasible) were not covered:~n ~w~n',
1021 [UncovNr, PossibleNr, INr,UncoveredList])
1022 )).
1023 show_initialisation_summary(NOW) :-
1024 findall(ID,state_space:is_concrete_constants_state_id(ID),L),
1025 length(L,Nr), N1 is Nr+1, % for root
1026 writeln_log(uninitialised_states(NOW,N1)),
1027 format(' Uninitialised states: ~w (root and constants only)~n',[N1]).
1028
1029 % ---------------------
1030
1031 animation_mode_does_not_support_animation(File) :-
1032 loaded_main_file(smt2,File).
1033 cli_start_animation(NOW) :-
1034 file_loaded(true,LoadedFile),
1035 \+ animation_mode_does_not_support_animation(LoadedFile),
1036 !,
1037 debug_println(20,'% Starting Animation'),
1038 writeln_log_time(start_animation(NOW)),
1039 start_probcli_timer(Timer1),
1040 start_animation_without_computing,
1041 stop_probcli_debug_timer(Timer1,'% Finished starting animation after'),
1042 if_option_set(add_csp_guide(CspGuide), tcltk_add_csp_file(CspGuide)),
1043
1044 xml_log_machine_statistics,
1045 getAllOperations(Ops),
1046 debug_print(20,'Operations: '), debug_println(20,Ops),
1047
1048 (we_need_only_static_assertions(ALL)
1049 -> debug_println(20,'% Projecting on static ASSERTIONS'),
1050 b_interpreter:set_projection_on_static_assertions(ALL) ; true),
1051
1052 (option(load_state(File))
1053 -> debug_println(20,'% Loading stored state from file'),
1054 state_space:tcltk_load_state(File)
1055 ; computeOperations_for_root_required ->
1056 debug_println(20,'% Searching for valid initial states'),
1057 start_probcli_timer(Timer2),
1058 cli_computeOperations(EO),
1059 stop_probcli_debug_timer(Timer2,'% Finished searching for valid initial states after'),
1060 debug_println(10,EO)
1061 ; debug_println(20,'% No initialisation required')
1062 ).
1063 cli_start_animation(_NOW).
1064
1065 start_animation_without_computing :-
1066 update_preferences_from_spec(ListOfPrefs),
1067 (ListOfPrefs=[] -> true ; write_prolog_term_as_xml_to_log(b_machine_preferences(ListOfPrefs))),
1068 set_prefs, % override SET_PREF in DEFINITIONS with values from command-line;
1069 start_animation,
1070 ifm_option_set(add_additional_property(PROP),
1071 cli_add_additional_property(PROP)),
1072 get_errors.
1073
1074 animate_until_ltl(LTLFormula,ExOption,ExpectedResult,ExpectedNrSteps) :-
1075 tcltk_animate_until(LTLFormula,ExOption,StepsExecuted,Result),
1076 formatsilent('Found trace of length ~w for LTL formula. Result: ~w ~n',[StepsExecuted,Result]),
1077 print_history_as_counter_example(false), % TODO: only print from current id before command
1078 (ExpectedResult=Result -> true % Result can be ltl_found, maximum_nr_of_steps_reached, deadlock
1079 ; add_error(animate_until_ltl,'Unexpected animation result: ',Result),
1080 error_occurred(animate_until_ltl)
1081 ),
1082 (ExpectedNrSteps=StepsExecuted -> true
1083 ; add_error(animate_until_ltl,'Unexpected number of animation steps: ',StepsExecuted),
1084 error_occurred(animate_until_ltl)
1085 ).
1086
1087 % ---------------------
1088
1089 % an execution engine with minimal overhead: states are not stored in visited_expression database, only first enabled operation is taken
1090
1091 cli_execute(Steps,ErrorOnDeadlock,FromWhere) :-
1092 temporary_set_preference(operation_reuse_setting,false,ChangeOccured),
1093 (ChangeOccured=true % operation reuse not compatible with cut used below after solution found
1094 -> add_debug_message(execute_model,'Disabling OPERATION_REUSE preference for -execute ',Steps) ; true),
1095 call_cleanup(cli_execute2(Steps,ErrorOnDeadlock,FromWhere),
1096 reset_temporary_preference(operation_reuse_setting,ChangeOccured)).
1097 cli_execute2(Steps,ErrorOnDeadlock,FromWhere) :-
1098 FromWhere=from_all_initial_states,!,
1099 % try out all initial states and from each of those perform deterministic execution
1100 start_ms_timer(Start),
1101 format('Running execute from all initial states~n',[]),
1102 reset_counter(cli_execute_inits),
1103 findall(Result,
1104 (cli_trans(root,Action,CurState,0,'$NO_OPERATION'), %print(Action),nl,
1105 (\+ functor(Action,'$setup_constants',_)
1106 -> inc_counter(cli_execute_inits,Nr),
1107 format('~nExecuting model from initial state ~w~n',[Nr]),
1108 (option(animate_stats) -> print_state_silent(CurState) ; true),
1109 (cli_execute_from(CurState,Steps,ErrorOnDeadlock,1,Result) -> true)
1110 ; format('~nInitialising state~n',[]), % we need to execute initialise_machine
1111 cli_trans(CurState,_ActionName,NewState,0,'$NO_OPERATION'),
1112 inc_counter(cli_execute_inits,Nr),
1113 format('~nExecuting model from initial state ~w with constants~n',[Nr]),
1114 (option(animate_stats) -> print_state_silent(NewState) ; true),
1115 (cli_execute_from(NewState,Steps,ErrorOnDeadlock,2,Result) -> true)
1116 )), Results),
1117 get_counter(cli_execute_inits,Nr),
1118 format('---------~nTotal runtime for all ~w executions:',[Nr]),nl,
1119 stop_ms_timer(Start),
1120 count_occurences(Results,Occs), format('Results: ~w~n',[Occs]).
1121 cli_execute2(Steps,ErrorOnDeadlock,current_state(Repetitions)) :-
1122 current_expression(ID,CurState),
1123 start_xml_feature(execute,max_steps,Steps,FINFO),
1124 start_ms_timer(Start),
1125 (between(1,Repetitions,RepNr),
1126 % with -strict option we will stop after first error found
1127 % for repetitions you should probably set RANDOMISE_OPERATION_ORDER and RANDOMISE_ENUMERATION_ORDER to TRUE
1128 debug_format(19,'Starting execute (~w/~w) from state ~w with maximum number of steps ~w~n',[RepNr,Repetitions,ID,Steps]),
1129 (cli_execute_from(CurState,Steps,ErrorOnDeadlock,1,_Result) -> fail ; fail)
1130 ; Repetitions>1 -> stop_ms_timer_with_msg(Start,'-execute-repeat')
1131 ; true),
1132 stop_xml_feature(execute,FINFO).
1133
1134 :- use_module(bmachine,[b_top_level_operation/1]).
1135 allow_filter_unused_constants :-
1136 b_or_z_mode,
1137 b_top_level_operation(_), % we can filter out unused constants, unless there are no operations in which case the user probably wants to see the constant values
1138 \+ options_can_eval_any_cst,
1139 \+ option(cache_storage(_,_)). % we do not know what constants other machines using the cache may use
1140
1141 options_can_eval_any_cst :- option(eval_repl(_)).
1142 options_can_eval_any_cst :- option(eval_string_or_file(_,_,_,_,_)).
1143 options_can_eval_any_cst :- option(dot_command(_,_,_)).
1144 options_can_eval_any_cst :- option(dot_command_for_expr(_,_,_,_,_)).
1145 options_can_eval_any_cst :- option(process_latex_file(_,_)).
1146 options_can_eval_any_cst :- option(logxml_write_ids(all,_)). % the user writes out constants (not just variables) to file: also do not filter
1147
1148 :- dynamic execute_timeout_occurred/0.
1149
1150 cli_execute_from(CurState,Steps,ErrorOnDeadlock,FirstStepNr,Result) :-
1151 retractall(max_walltime(_,_,_)),
1152 retractall(execute_timeout_occurred),
1153 start_ms_timer(Start),
1154 (allow_filter_unused_constants -> temporary_set_preference(filter_unused_constants,true,CHNG) ; true),
1155 cli_execute_aux(FirstStepNr,Steps,CurState,_MEMO,ErrorOnDeadlock,'$NO_OPERATION',Result),
1156 (allow_filter_unused_constants -> reset_temporary_preference(filter_unused_constants,CHNG) ; true),
1157 (option(silent) -> true ; stop_ms_timer_with_msg(Start,'-execute')),
1158 print_max_walltime.
1159
1160 :- use_module(tools_strings,[ajoin/2, ajoin_with_sep/3]).
1161 :- use_module(external_functions,[reset_side_effect_occurred/0, side_effect_occurred/1]).
1162 cli_execute_aux(Nr,Steps,CurState,_,_ErrorOnDeadlock,_LastActionName,Result) :- Nr>Steps,!,
1163 formatsilent('Stopping execution after ~w steps~n',[Steps]), Result = stopped,
1164 print_state_silent(CurState),
1165 cli_execute_add_virtual_transition(Steps,CurState,Result).
1166 cli_execute_aux(Nr,Steps,CurState0,MEMO,ErrorOnDeadlock,LastActionName,Result) :-
1167 (Nr mod 5000 =:= 0, \+option(animate_stats), \+option(silent)
1168 -> (var(LastActionName) -> format('Step ~w~n',[Nr])
1169 ; format('Step ~w (after ~w)~n',[Nr,LastActionName])),
1170 (option_verbose -> print_state_silent(CurState0) ; true),
1171 %copy_term(CurState0,CurState), tools_printing:print_term_summary((CurState0)),nl,
1172 !,
1173 garbage_collect,
1174 !,
1175 print('Memory used: '),print_memory_used_wo_gc,flush_output,nl %nl_time
1176 ; true),
1177 prepare_state_for_specfile_trans(CurState0,unknown,MEMO,CurState), % ensure we memoize expanded constants in MEMO
1178 % avoid re-expanding constants in every state !
1179 % relevant e.g. for probcli -execute 20001 DataValidationTestSmallStep.mch -init
1180 (cli_invariant_ko(CurState,LastActionName,InvStatus,CliErr) -> % also recognises no_inv command
1181 N1 is Nr-1,
1182 ajoin(['INVARIANT ',InvStatus,' after ',N1,' steps (after ',LastActionName,').'],ErrMsg),
1183 format('~w~n',[ErrMsg]),!,
1184 print_state_silent(CurState),
1185 error_occurred_with_msg(CliErr,ErrMsg),
1186 Result=CliErr,
1187 cli_execute_add_virtual_transition(N1,CurState,Result,NewID),
1188 %(option_verbose -> b_interpreter:analyse_invariant_for_state(NewID) ; true)
1189 b_interpreter:analyse_invariant_for_state(NewID)
1190 ; cli_assertions_ko(CurState,LastActionName,AssRes) -> % also recognises no_inv command
1191 N1 is Nr-1,
1192 format('ASSERTIONS ~w after ~w steps (after ~w).~n',[AssRes,N1,LastActionName]),!,
1193 print_state_silent(CurState),
1194 error_occurred(assertion_violation), Result=assertion_violation,
1195 cli_execute_add_virtual_transition(N1,CurState,Result)
1196 ; cli_goal_found(CurState) -> % also recognizes no_goal command
1197 N1 is Nr-1,
1198 format('GOAL FOUND after ~w steps (after ~w).~n',[N1,LastActionName]),!,
1199 print_state_silent(CurState), Result=goal_found,
1200 cli_execute_add_virtual_transition(N1,CurState,Result)
1201 ; reset_side_effect_occurred,
1202 cli_trans(CurState,ActionName,NewState,Nr,LastActionName), % Compute new transition
1203 !,
1204 N1 is Nr+1,
1205 (NewState=CurState0, % could be expensive for large states; states are expanded ! % TO DO: look only at written variables ?!
1206 \+ side_effect_occurred(file)
1207 -> formatsilent('Infinite loop reached after ~w steps (looping on ~w).~n',[N1,ActionName]),
1208 Result=loop,
1209 print_state_silent(CurState),
1210 cli_execute_add_virtual_transition(N1,CurState,Result)
1211 ; cli_execute_aux(N1,Steps,NewState,MEMO,ErrorOnDeadlock,ActionName,Result))
1212 ).
1213 cli_execute_aux(Nr,_Steps,CurState,_,_ErrorOnDeadlock,LastActionName,Result) :- execute_timeout_occurred,!,
1214 N1 is Nr-1,
1215 formatsilent('Timeout occurred after ~w steps (after ~w).~n',[N1,LastActionName]),
1216 Result=time_out,
1217 print_state_silent(CurState),
1218 cli_execute_add_virtual_transition(N1,CurState,Result).
1219 cli_execute_aux(Nr,_Steps,CurState,_,ErrorOnDeadlock,LastActionName,Result) :- N1 is Nr-1,
1220 formatsilent('Deadlock reached after ~w steps (after ~w).~n',[N1,LastActionName]),
1221 Result=deadlock,
1222 (ErrorOnDeadlock=true,\+ option(no_deadlocks) -> error_occurred(deadlock) ; true),
1223 print_state_silent(CurState),
1224 cli_execute_add_virtual_transition(N1,CurState,Result).
1225
1226 check_nr_of_steps(Steps) :- option(execute_expect_steps(ExpSteps)),
1227 (Steps = ExpSteps -> formatsilent('The expected number of steps were executed: ~w~n',[Steps]),fail
1228 ; true),
1229 !,
1230 ajoin(['Unexpected number of steps ',Steps,', expected:'],Msg),
1231 add_error(cli_execute,Msg,ExpSteps).
1232 check_nr_of_steps(_).
1233
1234 cli_execute_add_virtual_transition(Steps,CurState,Result) :-
1235 cli_execute_add_virtual_transition(Steps,CurState,Result,_).
1236 cli_execute_add_virtual_transition(Steps,CurState,Result,ToID) :-
1237 current_state_id(CurID),
1238 write_xml_element_to_log(executed,[steps/Steps,result/Result]),
1239 (Steps=0 -> true
1240 ; some_command_requires_state_space % check whether storing is actually useful for any outstanding command
1241 -> (CurID=root
1242 -> tcltk_interface:tcltk_add_cbc_state(CurState,'$execute'(Steps)) % generate separate constants state
1243 ; tcltk_interface:tcltk_add_new_transition(CurID,'$execute'(Steps),ToID,CurState,[]),
1244 tcltk_goto_state('$execute'(Steps),ToID)
1245 ),
1246 debug_format(19,'Added transition ~w -> ~w to state space for ~w execution steps~n',[CurID,ToID,Steps])
1247 ; debug_format(19,'Not adding transition for -execute ~w steps; not required by other commands~n',[Steps])
1248 ),
1249 check_nr_of_steps(Steps).
1250
1251 some_command_requires_state_space :-
1252 option(X),
1253 \+ does_not_require_state_space(X),
1254 !.
1255 does_not_require_state_space(execute_expect_steps(_)).
1256 does_not_require_state_space(execute(_,_,_)).
1257 does_not_require_state_space(animate_stats).
1258 does_not_require_state_space(execute_monitoring).
1259 does_not_require_state_space(set_pref(_,_)).
1260 does_not_require_state_space(set_preference_group(_,_)).
1261 does_not_require_state_space(timeout(_)).
1262 does_not_require_state_space(verbose(_)).
1263 does_not_require_state_space(verbose_off).
1264 does_not_require_state_space(silent).
1265 does_not_require_state_space(force_no_silent).
1266 does_not_require_state_space(strict_raise_error).
1267 does_not_require_state_space(release_java_parser).
1268 does_not_require_state_space(fast_read_prob).
1269 does_not_require_state_space(file_info).
1270 does_not_require_state_space(print_version(_)).
1271 does_not_require_state_space(check_java_version).
1272 does_not_require_state_space(pretty_print_internal_rep(_,_,_,_)).
1273 does_not_require_state_space(expect_error(_)).
1274 does_not_require_state_space(optional_error(_)).
1275 does_not_require_state_space(no_deadlocks).
1276 does_not_require_state_space(no_invariant_violations).
1277 does_not_require_state_space(no_goal).
1278 does_not_require_state_space(no_assertion_violations).
1279 does_not_require_state_space(no_state_errors).
1280 does_not_require_state_space(no_counter_examples).
1281 does_not_require_state_space(no_color).
1282 % TODO: register more commands that do not require the state space
1283
1284 :- dynamic max_walltime/3.
1285 print_max_walltime :- (max_walltime(Action,Nr,WT),option_verbose
1286 -> format('% Maximum walltime ~w ms at step ~w for ~w.~n',[WT,Nr,Action]) ; true).
1287
1288 % will be used to compute a single successor
1289 % b_operation_cannot_modify_state
1290 cli_trans(CurState,ActionName,NewState,Nr,LastActionName) :-
1291 option(animate_stats),!, % provide statistics about the animation
1292 start_probcli_timer(Timer),
1293 cli_trans_aux(CurState,ActionName,Act,NewState,Nr,LastActionName),
1294 (option_verbose -> translate:translate_event(Act,TStr)
1295 ; translate:translate_event_with_limit(Act,100,TStr)),
1296 format('~w~5|: ~w~n',[Nr,TStr]),
1297 format(' ~5|',[]),stop_probcli_timer(Timer,' '),
1298 (option_verbose -> format(' ~5|',[]),print_memory_used_wo_gc,nl ; true),
1299 flush_output,
1300 get_probcli_elapsed_walltime(Timer,WallTime),
1301 get_probcli_elapsed_runtime(Timer,RunTime),
1302 accumulate_infos(animate_stats,[step-1,step_nr-Nr,runtime-RunTime,walltime-WallTime]),
1303 (max_walltime(_,_,MWT), MWT >= WallTime -> true
1304 ; retractall(max_walltime(_,_,_)),
1305 assertz(max_walltime(ActionName,Nr,WallTime))).
1306 cli_trans(CurState,ActionName,NewState,Nr,LastActionName) :-
1307 cli_trans_aux(CurState,ActionName,_,NewState,Nr,LastActionName).
1308
1309 cli_trans_aux(CurState,ActionName,Act,NewState,Nr,LastActionName) :-
1310 option(timeout(TO)),!,
1311 safe_time_out(cli_trans_aux2(CurState,ActionName,Act,NewState,LastActionName),TO,Res),
1312 (Res=time_out -> format_error_with_nl('! Timeout occurred while performing step ~w of execute: ~w ms',[Nr,TO]),
1313 % TO DO: try and obtain operation name in which time-out occured
1314 error_occurred(time_out,execute),
1315 assertz(execute_timeout_occurred),
1316 fail
1317 ; true).
1318 cli_trans_aux(CurState,ActionName,Act,NewState,_Nr,LastActionName) :-
1319 cli_trans_aux2(CurState,ActionName,Act,NewState,LastActionName).
1320
1321 cli_trans_aux2(CurState,ActionName,Act,NewState,LastActionName) :-
1322 catch_enumeration_warning_exceptions(
1323 (throw_enumeration_warnings_in_current_scope,
1324 cli_execute_trans(CurState,ActionName,Act,NewState,LastActionName), % no time-out !
1325 (error_occurred_in_error_scope -> ErrorEvent=true ; ErrorEvent=false)
1326 ),
1327 (error_occurred(virtual_time_out_execute),
1328 ActionName = '*** VIRTUAL_TIME_OUT ***', Act=ActionName,
1329 CurState=NewState) % this forces loop detection above; not very elegant way of signalling
1330 ),
1331 (ErrorEvent==true,option(strict_raise_error)
1332 -> print('*** ERROR OCCURED DURING EXECUTE ***'),nl, error_occurred(execute),fail
1333 ; true).
1334
1335 :- use_module(runtime_profiler,[profile_single_call/3]).
1336 :- use_module(specfile,[get_specification_description/2]).
1337 cli_execute_trans(CurState,ActionName,Act,NewState,LastActionName) :-
1338 statistics(runtime,[StartExecuteForState,_]),
1339 get_possible_next_operation_for_execute(CurState,LastActionName,ActionName),
1340 start_check_disabled(ActionName,StartActionTime),
1341 catch(
1342 profile_single_call(ActionName,
1343 unknown, % state Unknown
1344 specfile_trans_with_check(CurState,ActionName,Act,NewState,Residue) % no time-out !
1345 ),
1346 EXC,
1347 (translate_exception(EXC,EMSG),
1348 (nonvar(ActionName)
1349 -> get_specification_description(operation,OP),
1350 format_with_colour_nl(user_error,[red,bold],'~n*** ~w while executing ~w "~w"~n',[EMSG,OP,ActionName])
1351 ; get_specification_description(operations,OP),
1352 format_with_colour_nl(user_error,[red,bold],'~n*** ~w while computing ~w~n',[EMSG,OP])
1353 ),
1354 perform_feedback_options_after_exception,
1355 throw(EXC))),
1356 (Residue=[]
1357 -> check_trans_time(StartExecuteForState,StartActionTime,ActionName)
1358 ; error_occurred(cli_execute_residue(ActionName,Residue,Act))).
1359
1360 :- use_module(probsrc(value_persistance),[cache_is_activated/0]).
1361 :- use_module(probsrc(static_enabling_analysis),[static_cannot_enable/2,
1362 static_disables_itself/1, static_disabled_after/2]).
1363 % compute all possible next operations to try out in -execute, based on LastActionName
1364 % the predicate makes use of the fact that operations are tried in order
1365 get_possible_next_operation_for_execute(CurState,LastActionName,ActionName) :-
1366 get_preference(randomise_operation_order,false),
1367 get_preference(use_po,true), % PROOF_INFO: should we use a proper preference for use_po_for_execute ?
1368 b_or_z_mode,
1369 b_top_level_operation(LastActionName),
1370 % prevent trying ActionName which we know is infeasible according to previous LastActionName
1371 % we rely on the fact that execute tries the operations in order
1372 findall(AN,specfile_possible_trans_name_for_successors(CurState,AN),ANS),
1373 !,
1374 member_with_last(ActionName,ANS,LastActionName,FoundLast),
1375 (var(FoundLast)
1376 -> % ActionName occurs before LastActionName, this means
1377 % we did try this ActionName at the last execution step and it was not possible
1378 % format('** Checking operation ~w against ~w~n',[ActionName,LastActionName]),debug:nl_time,
1379 %Note: we could use result of cbc enabling analysis if it was performed
1380 (static_cannot_enable(LastActionName,ActionName)
1381 -> debug_format(9,'** Operation ~w cannot be enabled by ~w~n',[ActionName,LastActionName]),
1382 %print('- '),
1383 fail
1384 ; true
1385 )
1386 ; ActionName=LastActionName, static_disables_itself(ActionName)
1387 -> debug_format(9,'** Operation ~w cannot be enabled after itself~n',[ActionName]),
1388 fail
1389 ; cache_is_activated, % TODO: check if this more general case is worth it in general
1390 % for the cache we need to hash the operation's input values; which could be expensive
1391 static_disabled_after(LastActionName,ActionName)
1392 -> debug_format(9,'** Operation ~w cannot be enabled after ~w~n',[ActionName,LastActionName]),
1393 fail
1394 ; true % we did not try this ActionName at the last execution step
1395 ).
1396 get_possible_next_operation_for_execute(CurState,_LastActionName,ActionName) :-
1397 specfile_possible_trans_name_for_successors(CurState,ActionName).
1398
1399 % like member but instantiate FoundLast when we pass the element Last
1400 member_with_last(X,[H|T],Last,FoundLast) :-
1401 (H=Last -> !,FoundLast=true, member(X,[H|T]) ; X=H).
1402 member_with_last(X,[_|T],Last,FoundLast) :- member_with_last(X,T,Last,FoundLast).
1403
1404 :- use_module(probsrc(value_persistance),[start_cache_execute_modus/1,stop_cache_execute_modus/0,
1405 add_new_transition_to_cache_from_expanded_state/4]).
1406 % also checks whether a setup_constants_inconsistent error should be raised:
1407 specfile_trans_with_check(CurState,ActionName,Act,NewState,Residue) :-
1408 start_cache_execute_modus(CacheInfo),
1409 if(specfile_trans_or_partial_trans(CurState,ActionName,Act,NewState,_TransInfo,Residue,Partial), % no time-out !
1410 (check_partial_trans(Partial,ActionName),
1411 (Partial=true -> true ; add_new_transition_to_cache_from_expanded_state(CurState,Act,NewState,CacheInfo)),
1412 stop_cache_execute_modus
1413 ),
1414 (stop_cache_execute_modus,
1415 check_deadlock_fail(ActionName) % add_deadlock_to_cache_from_expanded_state(CurState,ActionName)
1416 )
1417 ).
1418
1419 % check whether we should raise errors on deadlock in -execute:
1420 check_deadlock_fail('$setup_constants') :- !, error_occurred(setup_constants_inconsistent),fail.
1421
1422 % check whether we should raise errors due to partial transitions in -execute:
1423 check_partial_trans(true,'$setup_constants') :- !, error_occurred(setup_constants_inconsistent).
1424 check_partial_trans(true,ActionName) :- !, format('Unknown partial transition: ~w~n',[ActionName]),
1425 error_occurred(setup_constants_inconsistent).
1426 check_partial_trans(_,_).
1427
1428 % check if we did not spend too much time on disabled operations and print warning if we do
1429 check_trans_time(StartExecuteForState,StartActionTime,ActionName) :-
1430 option(execute_monitoring),
1431 statistics(runtime,[CurrentTime,_]),
1432 Delta1 is StartActionTime-StartExecuteForState,
1433 Delta2 is CurrentTime-StartActionTime,
1434 Delta1 > 100, Delta1 > Delta2,
1435 !,
1436 format_with_colour(user_output,[blue],'~n ~5|: WARNING from -execute_monitor: ~w ms for disabled operations and ~w ms for operation ~w itself~n',[Delta1,Delta2,ActionName]).
1437 check_trans_time(_,_,_).
1438
1439 % check if we did not spend too much time on a single disabled operations and print warning if we do
1440 start_check_disabled(ActionName,StartActionTime) :- option(execute_monitoring),!,
1441 statistics(runtime,[StartActionTime,_]),
1442 (true
1443 ; statistics(runtime,[EndActionTime,_]),
1444 Delta is EndActionTime - StartActionTime,
1445 Delta > 50,
1446 format_with_colour(user_output,[blue],'~n ~5|: WARNING from -execute_monitor: ~w ms for disabled operation ~w~n',[Delta,ActionName]),
1447 fail
1448 ).
1449 start_check_disabled(_,0).
1450
1451 translate_exception(user_interrupt_signal,'User-Interrupt (CTRL-C)').
1452 translate_exception(enumeration_warning(_,_,_,_,_),'Enumeration Warning').
1453 translate_exception(E,E).
1454
1455 :- use_module(bmachine,[b_machine_has_constants/0]).
1456 print_state_silent(_) :- option(silent),!.
1457 print_state_silent(CurState) :- \+ b_or_z_mode, !, translate:print_state(CurState), nl.
1458 print_state_silent(CurState) :- (option_verbose;\+ b_machine_has_constants),!,
1459 translate:print_bstate_limited(CurState,1000,-1),nl.
1460 print_state_silent(CurState) :- remove_constants(CurState,VarState),
1461 % only print variables
1462 format('VARIABLES (use -v to see constants or -silent to suppress output):~n',[]),
1463 translate:print_bstate_limited(VarState,1000,-1),nl.
1464
1465 :- use_module(bmachine,[b_is_constant/1]).
1466 is_constant_binding(bind(C,_)) :- b_is_constant(C).
1467 remove_constants(const_and_vars(_,Vars),Res) :- !,Res=Vars.
1468 remove_constants([H|T],Res) :- !,exclude(prob_cli:is_constant_binding,[H|T],Res).
1469 remove_constants(root,Res) :- !,Res=[].
1470 remove_constants(concrete_constants(_),Res) :- !, Res=[].
1471 remove_constants(X,X).
1472
1473 % write vars to xml log file if they start with a given prefix
1474 logxml_write_ids(variables,Prefix) :- !,
1475 current_expression(_,CurState),
1476 remove_constants(CurState,VarState),
1477 % TO DO: store also final state in xml_log
1478 write_bstate_to_log(VarState,Prefix).
1479 logxml_write_ids(_,Prefix) :- !,
1480 current_expression(_,CurState),
1481 expand_const_and_vars_to_full_store(CurState,EState),
1482 write_bstate_to_log(EState,Prefix).
1483
1484 :- use_module(bmachine,[b_get_invariant_from_machine/1, b_specialized_invariant_for_op/2, b_machine_has_constants/0]).
1485 cli_invariant_ko(_,_,_,_) :- option(no_invariant_violations),!,fail. % user asks not to check it
1486 cli_invariant_ko(_,_,_,_) :- get_preference(do_invariant_checking,false),!,fail. % user asks not to check it via preference
1487 cli_invariant_ko(CurState,LastActionName,ResInvStatus,CliError) :-
1488 profile_single_call('INVARIANT',unknown,cli_invariant_ko2(CurState,LastActionName,ResInvStatus,CliError)).
1489 cli_invariant_ko2(CurState,LastActionName,ResInvStatus,CliError) :-
1490 state_corresponds_to_initialised_b_machine(CurState,BState),!,
1491 start_probcli_timer(InvTimer),
1492 (b_specialized_invariant_for_op(LastActionName,Invariant) -> true
1493 %, print('Specialized invariant: '),translate:print_bexpr(Invariant),nl
1494 ; b_get_invariant_from_machine(Invariant)),
1495 cli_test_pred(BState,'INVARIANT',Invariant,ResInvStatus),
1496 stop_probcli_debug_timer(InvTimer,'Finished invariant checking after'),
1497 ResInvStatus \= 'TRUE',
1498 (ResInvStatus == 'FALSE' -> CliError = invariant_violation
1499 ; ResInvStatus == 'UNKNOWN' -> CliError = invariant_unknown
1500 ; ResInvStatus == 'TIME-OUT' -> CliError = invariant_time_out
1501 ; format_error_with_nl('Unexpected invariant status: ~w',[ResInvStatus]),
1502 CliError= invariant_unknown).
1503 %cli_invariant_ko(_,_,_,_) :- fail. % not yet initialised
1504
1505 :- use_module(b_interpreter,[b_test_boolean_expression_for_ground_state/4]).
1506 cli_test_pred(BState,PredKind,Pred) :- cli_test_pred(BState,PredKind,Pred,'TRUE').
1507 % comment in following clause to get more precise location for exceptions/virtual timeouts:
1508 %cli_test_pred(BState,PredKind,Pred,Res) :- option_verbose, bsyntaxtree:decompose_conjunct(Pred,A,B),!,
1509 % cli_test_pred(BState,PredKind,A,ResA), (ResA = 'TRUE' -> cli_test_pred(BState,PredKind,B,Res) ; Res = ResA).
1510 cli_test_pred(BState,PredKind,Pred,Res) :- option(timeout(TO)),!,
1511 debug_format(9,'Testing ~w with time-out ~w~n',[PredKind,TO]),
1512 safe_time_out(cli_test_pred2(BState,PredKind,Pred,Res), TO, TRes),
1513 (Res=time_out -> TRes='TIME-OUT' ; true).
1514 cli_test_pred(BState,PredKind,Pred,Res) :-
1515 debug_format(9,'Checking ~w without a time-out~n',[PredKind]),
1516 cli_test_pred2(BState,PredKind,Pred,Res).
1517 cli_test_pred2(BState,PredKind,Pred,Res) :-
1518 % currently does not do a time-out: % b_interpreter calls: time_out_with_enum_warning_one_solution_no_new_error_scope
1519 catch(
1520 on_enumeration_warning(b_test_boolean_expression_for_ground_state(Pred,[],BState,PredKind ), (
1521 add_error(cli_test_pred,'Enumeration warning while testing',PredKind,Pred),
1522 cli_print_pred_info(Pred),
1523 Res='UNKNOWN')
1524 ),
1525 E,
1526 (
1527 ajoin(['VIRTUAL TIME-OUT or exception while testing ',PredKind,': '],Msg),
1528 add_error(cli_test_pred,Msg,E,Pred), % E can also be user_interrupt_signal
1529 cli_print_pred_info(Pred),
1530 Res='UNKNOWN'
1531 )
1532 ),
1533 !,
1534 (var(Res) -> Res = 'TRUE' ; true).
1535 cli_test_pred2(_BState,_PredKind,_Pred,'FALSE').
1536
1537 cli_print_pred_info(Pred) :- get_texpr_label(Pred,Label),
1538 format('Label = ~w~n',[Label]),fail.
1539 cli_print_pred_info(Pred) :- get_texpr_description(Pred,Desc),
1540 format('Description = ~w~n',[Desc]),fail.
1541 %cli_print_pred_info(Pred) :- bsyntaxtree:get_texpr_pos(Pred,Pos), Pos \= none, translate_span(Pos,Str),
1542 % format('Location = ~w~n',[Str]),fail.
1543 cli_print_pred_info(Pred) :-
1544 option_verbose,
1545 write('Predicate: '), translate:nested_print_bexpr(Pred),nl.
1546
1547 :- use_module(bmachine,[get_assertions_from_machine/2]).
1548 % TO DO: also check static assertions
1549 cli_assertions_ko(_,_,_) :- option(no_assertion_violations),!,fail. % user asks not to check it
1550 cli_assertions_ko(CurState,_LastActionName,Res) :-
1551 state_corresponds_to_initialised_b_machine(CurState,BState),
1552 get_assertions_from_machine(dynamic,Assertions), % TO DO: do something similar to b_specialized_invariant_for_op
1553 !,
1554 profile_single_call('ASSERTIONS',unknown,cli_assertions_ko2(BState,Assertions,Res)).
1555
1556
1557 cli_assertions_ko2(BState,Assertions,Res) :-
1558 start_probcli_timer(AssTimer),
1559 %nl,nl,print(check),nl,maplist(translate:print_bexpr,Assertions),nl,
1560 (member(Ass,Assertions),
1561 cli_test_pred(BState,'ASSERTION',Ass,Res),
1562 Res \= 'TRUE' -> true
1563 ; Res = 'TRUE'
1564 ),
1565 stop_probcli_debug_timer(AssTimer,'Finished checking assertions after'),
1566 Res \= 'TRUE'.
1567
1568
1569 :- use_module(bmachine,[b_get_machine_goal/1]).
1570 cli_goal_found(_):- option(no_goal),!,fail.
1571 cli_goal_found(CurState) :-
1572 b_get_machine_goal(Goal),
1573 state_corresponds_to_initialised_b_machine(CurState,BState),
1574 profile_single_call('GOAL',unknown,cli_goal_found2(Goal,BState)).
1575 cli_goal_found2(Goal,BState) :-
1576 b_test_boolean_expression_for_ground_state(Goal,[],BState,'GOAL').
1577
1578
1579 :- use_module(extrasrc(simb_parser),[load_simb_file/1]).
1580 :- use_module(extrasrc(simb_simulator),[run_simb_simulation/2, print_simb_profile/0]).
1581 % SimB simulation
1582 cli_simulate(File,Repetitions,Steps,SimOpts) :-
1583 load_simb_file(File),!,
1584 findall(O,get_simb_option(O),SimOpts2,SimOpts),
1585 debug_format(19,'Simulate max. ~w steps with options ~w~n',[Steps,SimOpts2]),
1586 run_simb_simulations(Repetitions,Steps,SimOpts2).
1587 run_simb_simulations(Reps,_,_) :- Reps<1, !.
1588 run_simb_simulations(Reps,Steps,SimOpts) :-
1589 run_simb_simulation(Steps,SimOpts),!,
1590 R1 is Reps-1,
1591 run_simb_simulations(R1,Steps,SimOpts).
1592
1593 :- use_module(probltlsrc(ltl_tools),[temporal_parser/3]).
1594 get_simb_option(O) :- option(simb_option(O)).
1595 get_simb_option(ltl_stop_condition(LtlStopFormula)) :-
1596 option(simb_ltl_stop_condition(LTL_Stop_AsAtom)),
1597 temporal_parser(LTL_Stop_AsAtom,ltl,LtlStopFormula).
1598
1599 % random animation
1600 :- public cli_random_animate/2. % for repl to use -animate command
1601 cli_random_animate(Steps,Err) :- probcli_time_stamp(NOW),
1602 cli_random_animate(NOW,Steps,Err).
1603 cli_random_animate(_NOW,Steps,ErrorOnDeadlock) :-
1604 start_xml_feature(random_animate,max_steps,Steps,FINFO),
1605 start_ms_timer(Start),
1606 perform_random_steps(Steps,ErrorOnDeadlock),
1607 (option(silent) -> true ; stop_ms_timer_with_msg(Start,'-animate')),
1608 %tcltk_save_history_as_trace_file(prolog,user),
1609 stop_xml_feature(random_animate,FINFO).
1610
1611 :- use_module(bmachine,[b_get_assertions/3]).
1612 we_need_only_static_assertions(ALL) :- specfile:b_or_z_mode,
1613 (option(cli_check_assertions(main,_)) -> ALL=main
1614 ; option(cli_check_assertions(ALL,_))),
1615 % we do an assertion check
1616 \+ ((option(A), option_requires_all_properties(A))),
1617 b_get_assertions(ALL,dynamic,[]). % the assertions do not reference variables
1618
1619 % do we need all properties/constants of the machine, or only certain ones (e.g., static)
1620 option_requires_all_properties(cli_mc(_,_)).
1621 option_requires_all_properties(cli_check_properties). % we may want to check all properties
1622 option_requires_all_properties(cli_core_properties(_)).
1623 option_requires_all_properties(cli_random_animate(_)).
1624 option_requires_all_properties(default_trace_check).
1625 option_requires_all_properties(trace_check(_,_,_)).
1626 option_requires_all_properties(state_trace(_)).
1627 option_requires_all_properties(mcm_tests(_,_,_,_)).
1628 option_requires_all_properties(cbc_tests(_,_,_)).
1629 option_requires_all_properties(animate).
1630 option_requires_all_properties(initialise). % INITIALISATION may access constants
1631 option_requires_all_properties(eval_repl(_)).
1632 option_requires_all_properties(eval_string_or_file(_,_,_,_,_)).
1633 option_requires_all_properties(ltl_assertions).
1634 option_requires_all_properties(ltl_file(_)).
1635 option_requires_all_properties(refinement_check(_,_,_)).
1636 option_requires_all_properties(cli_start_mc_with_tlc).
1637 option_requires_all_properties(cli_symbolic_model_check(_)).
1638 option_requires_all_properties(process_latex_file(_,_)).
1639 option_requires_all_properties(cli_wd_check(_,_)).
1640 option_requires_all_properties(cli_lint(_)).
1641 option_requires_all_properties(visb_history(_,_,_)).
1642
1643 :- use_module(b_intelligent_trace_replay,[replay_json_trace_file/2]).
1644 :- public default_trace_check/0.
1645 default_trace_check :- loaded_main_file(_,MainFile),
1646 cli_start_default_trace_check(MainFile).
1647 cli_start_default_trace_check(MainFile) :-
1648 debug_println(20,'% Starting Default Trace Check: '),
1649 (check_default_trace_for_specfile(MainFile) -> true ; error_occurred(trace_check)).
1650
1651 default_json_trace_save :-
1652 loaded_main_file(_,MainFile),
1653 get_default_trace_file(MainFile,'.prob2trace',HistFile),
1654 format('Saving history to JSON ProB2-UI default trace file: ~w~n',[HistFile]),
1655 tcltk_save_history_as_trace_file(json,HistFile).
1656 cli_start_trace_check(json,File,default_trace_replay) :- !,
1657 replay_json_trace_file(File,Status),
1658 (Status=perfect -> true
1659 ; Status = imperfect -> add_warning(trace_replay,'Imperfect JSON trace replay:',Status)
1660 ; add_error(trace_replay,'Failed JSON trace replay:',Status)
1661 ).
1662 cli_start_trace_check(Style,File,Mode) :-
1663 debug_format(20,'% Starting Trace Check (~w:~w): ~w~n',[Style,Mode,File]),
1664 (tcltk_check_sequence_from_file(Style,File,Mode) -> true ; error_occurred(trace_check)).
1665 cli_start_trace_state_check(File) :-
1666 debug_println(20,'% Starting Trace Check: '),
1667 (tcltk_check_state_sequence_from_file(File) -> true ; error_occurred(state_trace)).
1668
1669 % is it necessary to compute enabled operations for root state
1670 computeOperations_for_root_required :- initialise_required.
1671 computeOperations_for_root_required :- option(default_trace_check).
1672 computeOperations_for_root_required :- option(trace_check(_,_,_)).
1673 computeOperations_for_root_required :- option(state_trace(_)).
1674 computeOperations_for_root_required :- option(ltl_assertions).
1675 computeOperations_for_root_required :- option(cli_random_animate(_,_)).
1676 computeOperations_for_root_required :- option(socket(_,_)).
1677 computeOperations_for_root_required :- option(cli_mc(_,_)).
1678 computeOperations_for_root_required :- option(ltl_file(_)).
1679 computeOperations_for_root_required :- option(ltl_formula_model_check(_,_)).
1680 computeOperations_for_root_required :- option(ctl_formula_model_check(_,_)).
1681 computeOperations_for_root_required :- option(pctl_formula_model_check(_,_)).
1682 computeOperations_for_root_required :- option(refinement_check(_,_,_)).
1683 computeOperations_for_root_required :- option(csp_in_situ_refinement_check(_,_)).
1684 computeOperations_for_root_required :- option(csp_checkAssertion(_,_)).
1685 computeOperations_for_root_required :- option(mcm_tests(_,_,_,_)).
1686 computeOperations_for_root_required :- option(mcm_cover(_)).
1687
1688 % is an initialisation mandatory:
1689 initialise_required :- option(initialise), \+ empty_machine_loaded.
1690 initialise_required :- \+ option(default_trace_check), \+ option(trace_check(_,_,_)), \+ option(state_trace(_)),
1691 \+ option(load_state(_)),
1692 \+ empty_machine_loaded,
1693 \+ (option(execute(Nr,_,_)), Nr>=2), % execute will also initialise machine
1694 init_req2.
1695 init_req2 :- option(cli_check_properties).
1696 init_req2 :- option(zmq_assertion(_,_,_)).
1697 init_req2 :- option(cli_check_assertions(_,_)).
1698 init_req2 :- option(process_latex_file(_,_)).
1699 init_req2 :- option(eval_string_or_file(_,_,_,_,_)). % ensure that we initialise/precompile empty machine in case no main file specified; currently no longer required
1700 init_req2 :- option(check_abstract_constants).
1701 init_req2 :- option(visb_click(_)).
1702 init_req2 :- option(dot_command_for_expr(Cat,_,_,_,_)),
1703 nonmember(Cat,[transition_diagram,expression_coverage]). % see test 1033, option also works with empty state space
1704 %init_req2 :- option(csv_table_command(Cat,_,_,_)), ...
1705
1706 :- public initialise/0. % for REPL
1707 initialise :- probcli_time_stamp(NOW),cli_start_initialisation(NOW).
1708
1709 cli_start_initialisation(NOW) :-
1710 debug_println(20,'% Performing INITIALISATION: '),
1711 (perform_random_initialisation -> true ;
1712 writeln_log_time(cli_start_initialisation_failed(NOW)),
1713 fail).
1714
1715 :- use_module(wdsrc(well_def_analyser),[analyse_wd_for_machine/4]).
1716 :- public cli_wd_check/2. % for REPL
1717 cli_wd_check(ExpectedDis,ExpectedTot) :-
1718 (option(timeout(TO)) -> true ; TO=5000), % this is global_time_out option
1719 (option(silent) -> Opts=[discharge_po,ignore_wd_infos,reorder_conjuncts]
1720 ; Opts=[create_not_discharged_msg(warning),discharge_po,ignore_wd_infos,reorder_conjuncts]),
1721 statistics(walltime,[W1,_]),
1722 safe_time_out(analyse_wd_for_machine(NrDischarged,NrTot,_Res,Opts),TO,Res),
1723 statistics(walltime,[W2,_]), WT is W2-W1,
1724 (Res=time_out -> accumulate_infos(wd_check,[timeout-1,walltime-WT]), % discharged and total are unknown
1725 add_error(cli_wd_check,'TIME-OUT in WD Analysis (use -global_time_out X to increase it)')
1726 ; format(user_output,'WD Analysis Result: discharged ~w / ~w',[NrDischarged,NrTot]),
1727 (NrTot >0
1728 -> Perc is 100*NrDischarged/NrTot,
1729 (NrDischarged=NrTot -> Col=[green,bold] ; Col=[red])
1730 ; Perc = 100, Col=[]),
1731 format_with_colour(user_output,Col,' (~2f %)~n',[Perc]),
1732 WDInfos = [discharged-NrDischarged,timeout-0,total-NrTot,walltime-WT],
1733 accumulate_infos(wd_check,WDInfos),
1734 (ExpectedDis==ExpectedTot, ExpectedTot = NrTot -> true ; true), % for -wd-check-all: bind ExpectedDis
1735 check_required_infos([discharged-ExpectedDis,total-ExpectedTot],WDInfos,cli_wd_check)
1736 ).
1737 :- use_module(wdsrc(well_def_analyser),[analyse_invariants_for_machine/5]).
1738 cli_wd_inv_proof(UnchangedNr,ProvenNr,TotPOsNr) :-
1739 (option(timeout(TO)) -> true ; TO=5000),
1740 Options=[],
1741 statistics(walltime,[W1,_]),
1742 safe_time_out(analyse_invariants_for_machine(UnchangedNr,ProvenNr,UnProvenNr,TotPOsNr,Options),TO,Res),
1743 statistics(walltime,[W2,_]), WT is W2-W1,
1744 (Res=time_out -> accumulate_infos(wd_inv_proof,[timeout-1,walltime-WT]), % discharged and total are unknown
1745 add_error(cli_wd_check,'TIME-OUT in WD Invariant Proving (use -global_time_out X to increase it)')
1746 ;
1747 (TotPOsNr>0 -> Perc is (UnchangedNr+ProvenNr)*100/ TotPOsNr ; Perc = 100.0),
1748 format('Proof summary for ~w Invariant POs (~2f % discharged): ~w unchanged, ~w proven, ~w unproven~n',
1749 [TotPOsNr,Perc,UnchangedNr,ProvenNr,UnProvenNr]),
1750 WDInfos = [proven-ProvenNr,timeout-0,total-TotPOsNr,unchanged-UnchangedNr,unproven-UnProvenNr,walltime-WT],
1751 accumulate_infos(wd_inv_proof,WDInfos)
1752 ).
1753
1754
1755 :- use_module(bmachine_static_checks,[extended_static_check_machine/1]).
1756 :- use_module(visbsrc(visb_visualiser),[extended_static_check_default_visb_file/0]).
1757 :- use_module(extrasrc(simb_parser),[extended_static_check_default_simb_file/0]).
1758 % perform some additional static checks
1759 :- public cli_lint/0. % for REPL
1760 cli_lint(Check) :-
1761 extended_static_check_machine(Check),
1762 (unavailable_extension(visb_extension,_) -> true
1763 ; (var(Check) ; Check=visb) -> extended_static_check_default_visb_file
1764 ; true),
1765 (Check=simb -> extended_static_check_default_simb_file ; true).
1766 cli_lint :- cli_lint(_).
1767
1768
1769 :- use_module(extrasrc(predicate_debugger),[tcltk_debug_properties/3]).
1770 :- use_module(state_space,[current_state_corresponds_to_setup_constants_b_machine/0]).
1771 :- public cli_check_properties/0. % for REPL
1772 cli_check_properties :- probcli_time_stamp(NOW),
1773 cli_check_properties(NOW).
1774 cli_check_properties(NOW) :-
1775 printsilent('% Checking PROPERTIES: '),nls,
1776 writeln_log_time(starting_check_properties(NOW)),
1777 ( current_state_corresponds_to_setup_constants_b_machine ->
1778 set_analyse_hook('_P'),
1779 predicate_evaluator:tcltk_analyse_properties(_PROPRES,PROPInfos),
1780 unset_analyse_hook,
1781 printsilent(PROPInfos),nls, % ex: [total/33,true/29,false/0,unknown/4,timeout/4,runtime/49950]
1782 accumulate_infos(properties,PROPInfos),
1783 write_important_xml_element_to_log(check_properties,PROPInfos),
1784 (predicate_evaluator:check_summary_all_true(PROPInfos) -> true
1785 ; print_error('Not all PROPERTIES true'), error_occurred(check_properties))
1786 ;
1787 (tcltk_debug_properties(list(PROPRES),false,Satisfiable)
1788 -> printsilent(PROPRES),nls,
1789 printsilent(Satisfiable),nls
1790 ; error_occurred(debug_properties_failed))
1791 ),
1792 writeln_log_time(finished_check_properties(NOW,PROPInfos)),
1793 loaded_root_filename(RootName),
1794 formatsilent('% Finished checking PROPERTIES of ~w~n',[RootName]).
1795
1796 % TODO: provide argument so that we run it only if necessary; e.g., when ProB has not already found a solution
1797
1798 cli_core_properties(Algorithm) :-
1799 format('% Checking CONSISTENCY of PROPERTIES by finding UNSAT CORE (using ~w)~n',[Algorithm]),
1800 b_get_properties_from_machine(Properties),!,
1801 size_of_conjunction(Properties,NrOfConjuncts),
1802 statistics(walltime,[W1,_]),
1803 (find_core(Algorithm,Properties,Core,Result)
1804 -> statistics(walltime,[W2,_]), WTime is W2-W1,
1805 length(Core,Len),
1806 accumulate_infos(properties_core,[contradiction_found-1,core_length-Len,
1807 properties-NrOfConjuncts,walltime-WTime]),
1808 format('UNSAT CORE of length ~w found, PROPERTIES are inconsistent! (~w, ~w ms walltime using ~w)~n',[Len,Result,WTime,Algorithm]),
1809 translate:nested_print_bexpr_as_classicalb(Core),
1810 format('% END OF UNSAT CORE (~w conjuncts)~n',[Len])
1811 % TODO: raise setup_constants_fails and avoid trying to solve properties later
1812 ; statistics(walltime,[W2,_]), WTime is W2-W1,
1813 accumulate_infos(properties_core,[contradiction_found-0,core_length-0,
1814 properties-NrOfConjuncts,walltime-WTime]),
1815 format('No small UNSAT CORE found, PROPERTIES may be consistent (~w ms walltime).~n',[WTime])
1816 ).
1817
1818 :- use_module(extrasrc(unsat_cores),[quick_bup_core_up_to/4]).
1819 :- use_module(wdsrc(well_def_analyser),[find_inconsistent_axiom/3]).
1820 find_core(wd_prover,_,Core,Result) :-
1821 find_inconsistent_axiom([],Axiom,NecHyps),
1822 Core = [Axiom|NecHyps], Result = contradiction_found.
1823 find_core(z3_bup(MaxSize),Properties,Core,Result) :-
1824 (var(MaxSize) -> MaxSize=2 ; true),
1825 quick_bup_core_up_to(Properties,MaxSize,Core,Result).
1826
1827
1828 % -----------------------
1829
1830 :- public cli_check_assertions/2. % for REPL
1831 cli_check_assertions(ALL,RI) :-
1832 probcli_time_stamp(NOW),
1833 cli_check_assertions(ALL,RI,NOW).
1834 cli_check_assertions(ALL,ReqInfos,NOW) :-
1835 printsilent('% Checking ASSERTIONS: '),nls,
1836 writeln_log_time(starting_check_assertions(NOW)),
1837 set_analyse_hook('_A'), % for dot output, in case users wants to generate dot files for assertions
1838 predicate_evaluator:tcltk_analyse_assertions(ALL,_ASSRES,Infos), % also checks CSP assertions
1839 unset_analyse_hook,
1840 printsilent(Infos),nls,
1841 accumulate_infos(assertions,Infos),
1842 write_important_xml_element_to_log(check_assertions,Infos),
1843 check_required_infos(ReqInfos,Infos,check_assertions),
1844 writeln_log_time(finished_check_assertions(NOW,Infos)),
1845 loaded_root_filename(RootName),
1846 formatsilent('% Finished checking ASSERTIONS of ~w~n',[RootName]),!.
1847 cli_check_assertions(ALL,ReqInfos,NOW) :-
1848 add_internal_error('Analyse ASSERTIONS unexpectedly failed',cli_check_assertions(ALL,ReqInfos,NOW)),
1849 error_occurred(internal_error).
1850 cli_set_goal(GOAL) :-
1851 debug_println(20,set_goal(GOAL)), %print(set_goal(GOAL)), nl,
1852 (bmachine:b_set_machine_goal(GOAL) -> true
1853 ; add_error(scope,'Setting GOAL predicate failed:',GOAL)).
1854 cli_add_additional_property(PROP) :-
1855 debug_println(20,add_additional_property(PROP)),
1856 (bmachine:add_additional_property(PROP,'command line -property') -> true
1857 ; add_error(scope,'Adding additional predicate to PROPERTIES failed:',PROP)).
1858 cli_set_searchscope(GOAL) :-
1859 debug_println(20,set_searchscope(GOAL)),
1860 format('Setting SCOPE for verification: ~w~n (Only states satisfying this predicate will be examined)~n',[GOAL]),
1861 (b_or_z_mode, bmachine:b_set_machine_searchscope(GOAL) -> true
1862 ; (xtl_mode, xtl_interface:xtl_set_search_scope(GOAL) -> true
1863 ; add_error(scope,'Setting model checking search SCOPE failed:',GOAL))
1864 ).
1865 cli_check_goal :- \+ b_get_machine_goal(_),!,
1866 add_error(cli_check_goal,'No GOAL DEFINITION found'),
1867 error_occurred(cli_check_goal).
1868 cli_check_goal :-
1869 printsilent('% Checking GOAL predicate: '),nls,
1870 tcltk_analyse_goal(_List,Summary),
1871 debug_println(20,Summary),
1872 accumulate_infos(check_goal,Summary),
1873 write_important_xml_element_to_log(check_goal,Summary),
1874 check_required_infos([false/0,unknown/0],Summary,check_goal).
1875 :- public cli_mc/2. % for REPL
1876 cli_mc(Nr,Opts) :- probcli_time_stamp(NOW), cli_start_model_check(Nr,NOW,Opts).
1877 cli_start_model_check(Nr,NOW,Options) :-
1878 (member(reset_state_space,Options)
1879 -> formatsilent('Resetting state space for benchmarking model checking (limit:~w, options:~w)~n',[Nr, Options]),
1880 announce_event(reset_specification) % for benchmarking purposes
1881 %,state_space:portray_state_space,nl
1882 ; true),
1883 start_xml_feature(model_check,max_states,Nr,FINFO),
1884 regular_safety_model_check_now(Nr,Time,WallTime,MCRes,NOW),
1885 %nl,
1886 stop_xml_feature(model_check,FINFO),
1887 get_state_space_stats(TS,TT,PT,IgnT),
1888 statistics_memory_used(Mem),
1889 (MCRes=time_out -> TInfos=[timeout/1] ; TInfos=[]),
1890 accumulate_infos(model_check,[runtime-Time,walltime-WallTime, % mc only runtime, and total wall time
1891 processed_states/PT,total_states/TS,total_transitions/TT,
1892 ignored_states/IgnT, memory_used/Mem|TInfos]), %for bench_csv output
1893 writeln_log_time(model_check(NOW,Nr,Time,WallTime,MCRes)),
1894 (select(repeat(RepNr),Options,RestOptions)
1895 -> (RepNr>1
1896 -> N1 is RepNr-1,
1897 cli_start_model_check(Nr,NOW,[repeat(N1)|RestOptions])
1898 ; merge_accumulated_infos(model_check)
1899 )
1900 ; true
1901 ).
1902
1903 cli_start_mc_with_tlc :-
1904 (animation_mode(b), \+ animation_minor_mode(eventb) -> true
1905 ; error_manager: add_error_and_fail(mc_with_tlc,'TLC4B tool can be used only for classical B models.')),
1906 % TO DO: use b_write_eventb_machine_to_classicalb_to_file to do conversion
1907 catch(
1908 safe_absolute_file_name(prob_lib('TLC4B.jar'),TLC4BTool),
1909 error(E,_),
1910 error_manager:add_error_fail(get_tlc_command,'Could not find TLC4B.jar file.',E)),
1911 start_xml_feature(model_check_with_tlc,tlc4bjar,TLC4BTool,FINFO),
1912 construct_and_execute_tlc_command(TLC4BTool),
1913 stop_xml_feature(model_check_with_tlc,FINFO).
1914
1915 :- use_module(system_call,[system_call/4]).
1916 construct_and_execute_tlc_command(TLC4BTool) :-
1917 parsercall: get_java_command_path(JavaCmd),
1918 loaded_main_file(File),
1919 % determine extra arguments:
1920 (get_preference(tlc_number_of_workers,TLCWorkers), TLCWorkers>1
1921 -> number_codes(TLCWorkers,CC), atom_codes(TLAWA,CC), WW = ['-workers',TLAWA]
1922 ; WW=[]),
1923 (option(no_assertion_violations) -> WA = ['-noass'] ; WA=[]),
1924 (option(no_deadlocks) -> WD = ['-nodead'] ; WD=[]),
1925 (option(no_invariant_violations) -> WI = ['-noinv'] ; WI=[]),
1926 (option(no_goal) -> WG = ['-nogoal'] ; WG=[]),
1927 (option(no_ltl) -> WL = ['-noltl'] ; WL=[]),
1928 (option_verbose -> WV = ['-verbose'] ; WV=[]),
1929 (option(silent) -> WS = ['-silent'] ; WS=[]),
1930 (option(logtlc(Log)) -> WLG = ['-log',Log] ; WLG=[]),
1931 (get_preference(tlc_use_prob_constant_setup,true),
1932 tcltk_get_constants_predicate(DNF_Pred)
1933 -> WCS = ['-constantssetup', DNF_Pred]
1934 ; WCS=[]),
1935 append([WW,WA,WD,WI,WG,WL,WCS,WV,WS,WLG,[File]],TLCArgs),
1936 debug_println(19,tlc_args(TLCArgs)),
1937 statistics(walltime,[W1,_]),
1938 % we could call get_jvm_options: '-Xss5m' is useful e.g. for Generated1000.mch
1939 system_call(JavaCmd, ['-Xss5m', '-jar', TLC4BTool | TLCArgs], Text,JExit),
1940 statistics(walltime,[W2,_]),
1941 WTime is W2-W1,
1942 formatsilent('exit : ~w walltime: ~w ms~n',[JExit,WTime]),
1943 (JExit=exit(0)
1944 -> accumulate_infos(mc_with_tlc,[walltime-WTime,model_check_ok-1])
1945 ; accumulate_infos(mc_with_tlc,[walltime-WTime,model_check_error-1]),
1946 add_error(construct_and_execute_tlc_command,'Error while model checking with TLC: ',TLC4BTool/File),
1947 atom_codes(T,Text),
1948 add_error_fail(construct_and_execute_tlc_command,'Std error: ',T)
1949 ).
1950
1951 % SymbolicOrSequential = symbolic or sequential
1952 cli_start_sym_mc_with_lts(SymbolicOrSequential) :-
1953 (option(no_deadlocks) -> NoDead = true ; NoDead = false),
1954 (option(no_invariant_violations) -> NoInv = true ; NoInv = false), % does LTSMin support goal checking
1955 findall(Option,option(ltsmin_option(Option)),MoreFlags1),
1956 findall(ltl_formula(LTLF),option(ltl_formula_model_check(LTLF,_)),MoreFlags2),
1957 append(MoreFlags1,MoreFlags2,MoreFlags),
1958 (NoDead = false, NoInv = false ->
1959 print_error('ERROR: cannot start LTSmin with both deadlock and invariant checking'),
1960 print_error(' use either the -noinv or -nodead flag'),
1961 flush_output(user_error)
1962 ; true),
1963 formatsilent('starting prob2lts-sym/seq (flags nodead=~w, noinv=~w, moreflags=~w)~n',[NoDead,NoInv,MoreFlags]),
1964 statistics(walltime,[W1,_]),
1965 start_ltsmin(SymbolicOrSequential, [NoDead, NoInv], MoreFlags,Result),
1966 process_ltsmin_result(Result,AccInfos),
1967 statistics(walltime,[W2,_]), WT is W2-W1,
1968 accumulate_infos(mc_with_lts_min(SymbolicOrSequential),[walltime-WT|AccInfos]).
1969 % TO DO: start lts-sym + start start_ltsmin_srv('/tmp/ltsmin.probz', NOW) + print output
1970
1971 :- use_module(extension('ltsmin/ltsmin_trace'),[csv_to_trace/3]).
1972 process_ltsmin_result(ltsmin_model_checking_ok,[model_check_ok-1]) :-
1973 print_green('LTSMin found no counter example\n').
1974 process_ltsmin_result(ltsmin_model_checking_aborted,[model_check_aborted-1]) :-
1975 add_warning(ltsmin_model_checking_aborted,'LTSMin was aborted (e.g., by CTRL-C)').
1976 process_ltsmin_result(ltsmin_counter_example_found(CsvFile),[model_check_counter_example-1]) :-
1977 add_error(ltsmin_counter_example_found,'LTSMin found a counter example, written to:',CsvFile),
1978 (option(silent) -> true
1979 ; csv_to_trace(CsvFile,_States,Transitions) ->
1980 print('*** TRACE: '),nl,print_list(Transitions) % ,print(_States),nl
1981 ; add_error(ltsmin,'Could not extract trace information from LTSmin file: ',CsvFile)
1982 ).
1983
1984 :- use_module(symbolic_model_checker(ic3), [ic3_symbolic_model_check/1]).
1985 :- use_module(symbolic_model_checker(ctigar), [ctigar_symbolic_model_check/1]).
1986 :- use_module(symbolic_model_checker(kinduction), [kinduction_symbolic_model_check/1,
1987 tinduction_symbolic_model_check/1]).
1988 :- use_module(symbolic_model_checker(bmc), [bmc_symbolic_model_check/1]).
1989 cli_symbolic_model_check(Algorithm) :-
1990 debug_format(20,'% Starting Symbolic Model Check. Using ~w Algorithm', [Algorithm]),
1991 start_xml_feature(model_check,algorithm,Algorithm,FINFO),
1992 (animation_mode(b)
1993 -> true
1994 ; error_manager:add_error_and_fail(cli_symbolic_model_check,'Symbolic Model Checking is currently only available for B and Event-B.')),
1995 perform_symbolic_model_checking(Algorithm,Result),
1996 handle_symbolic_model_check_result(Result),
1997 stop_xml_feature(model_check,FINFO).
1998
1999 perform_symbolic_model_checking(ic3,Result) :- !, ic3_symbolic_model_check(Result).
2000 perform_symbolic_model_checking(ctigar,Result) :- !, ctigar_symbolic_model_check(Result).
2001 perform_symbolic_model_checking(kinduction,Result) :- !, kinduction_symbolic_model_check(Result).
2002 perform_symbolic_model_checking(tinduction,Result) :- !, tinduction_symbolic_model_check(Result).
2003 perform_symbolic_model_checking(bmc,Result) :- !, bmc_symbolic_model_check(Result).
2004 perform_symbolic_model_checking(Alg,_) :- add_error_fail(cli_symbolic_model_check,'Invalid symbolic model checking algorithm: ',Alg).
2005
2006 handle_symbolic_model_check_result(counterexample_found) :- !, error_occurred(invariant_violation).
2007 handle_symbolic_model_check_result(property_holds) :- !,
2008 format('Model checking complete, invariant holds~n',[]).
2009 handle_symbolic_model_check_result(solver_and_provers_too_weak) :- !,
2010 format('Model checking incomplete because a constraint could not be solved in time~n',[]),
2011 error_occurred(model_check_incomplete).
2012 handle_symbolic_model_check_result(limit_reached) :- !,
2013 format('Model checking incomplete because an iteration limit was reached~n',[]),
2014 error_occurred(model_check_incomplete).
2015
2016 zmq_start_master(invariant,Identifier) :-
2017 start_animation_without_computing,
2018 zmq_get_initialisation_term(InitTerm),
2019 (option(strict_raise_error) -> Strict = 1 ; Strict = 0),
2020 get_preference(port, PortStart),
2021 get_preference(max_states, Max),
2022 get_preference(ip, IP),
2023 get_preference(logdir, LogDir),
2024 get_preference(tmpdir, TmpDir),
2025 get_preference(hash_cycle, HashCycle),
2026 atom_concat(LogDir, '/distb-', ATmp),
2027 atom_concat(ATmp, Identifier, Logfile),
2028 atom_concat(TmpDir, '/db-distb-', TTmp),
2029 atom_concat(TTmp, Identifier, TmpDir2),
2030 start_master(InitTerm,Max,PortStart,Strict,IP,Logfile,TmpDir2,HashCycle),
2031 halt.
2032 zmq_start_master(assertion,Identifier) :-
2033 get_preference(port, PortStart),
2034 get_preference(logdir, LogDir),
2035 get_preference(ip, IP),
2036 get_preference(tmpdir, TmpDir),
2037 get_preference(hash_cycle, HashCycle),
2038 atom_concat(LogDir, '/distb-', ATmp),
2039 atom_concat(ATmp, Identifier, Logfile),
2040 atom_concat(TmpDir, '/db-distb-', TTmp),
2041 atom_concat(TTmp, Identifier, TmpDir2),
2042 current_state_corresponds_to_setup_constants_b_machine,
2043 animation_mode(b),
2044 full_b_machine(Machine),
2045 b_get_assertions(_,static,SAss),
2046 b_get_assertions(_,dynamic,DAss),
2047 append(SAss,DAss,Ass),
2048 count_assertions(Ass,0,N),
2049 assertz(master:assertion_count(N)),
2050 current_expression(_,State1),
2051 specfile:state_corresponds_to_set_up_constants(State1,State),
2052 zmq_get_important_options(Options),
2053 (option(strict_raise_error) -> Strict = 1 ; Strict = 0),
2054 %start_master(assertions(classical_b(Machine,Options),State,Ass),2,-1,PortStart,0,Strict,IP,Logfile,TmpDir2),
2055 start_master(assertions(classical_b(Machine,Options),State,Ass),2,PortStart,Strict,IP,Logfile,TmpDir2,HashCycle),
2056 halt.
2057
2058 zmq_get_initialisation_term(Term) :-
2059 (animation_mode(b) ; animation_mode(csp_and_b)), % CSP file not yet added when ZMQ master starts working
2060 \+ animation_minor_mode(eventb),
2061 option(add_csp_guide(CspGuide)),
2062 !, % Classical B + CSP
2063 debug_println(20,'ZMQ: Transferring CSP || B model'),
2064 full_b_machine(Machine),
2065 % TO DO: extract CSP Term rather than file name: will not work for distribution on other file-systems
2066 zmq_get_important_options(Options),
2067 Term = classical_b_with_csp(Machine,CspGuide,Options).
2068 zmq_get_initialisation_term(Term) :-
2069 debug_println(20,'Generating ZMQ Worker Initialisation'),
2070 animation_mode(b), \+ animation_minor_mode(eventb), !, % Classical B
2071 debug_println(20,'ZMQ: Transferring Classical-B model'),
2072 full_b_machine(Machine),
2073 zmq_get_important_options(Options),
2074 Term = classical_b(Machine,Options).
2075 zmq_get_initialisation_term(Term) :-
2076 animation_mode(b), animation_minor_mode(eventb), !, % Event-B
2077 debug_println(20,'ZMQ: Transferring Event-B model'),
2078 full_b_machine(Machine),
2079 zmq_get_important_options(Options),
2080 Term = eventb(Machine,Options).
2081 zmq_get_initialisation_term(Term) :-
2082 animation_mode(cspm),
2083 loaded_main_file(MainCSPFile),!, % TO DO: pass CSP Prolog term rather than file name (for distribution)
2084 zmq_get_important_options(Options),
2085 debug_println(20,'ZMQ: Transferring CSP specification'),
2086 Term = csp_specification(MainCSPFile,Options).
2087 zmq_get_initialisation_term(_Term) :-
2088 \+ real_error_occurred, % otherwise error occured while loading
2089 animation_mode(Mode),
2090 add_internal_error('Unsupported formalism for ZMQ', Mode),
2091 fail.
2092
2093 zmq_get_initialisation_term(filename(FN)) :-
2094 loaded_main_file(FN).
2095
2096 % get important command-line options to be transmitted to probcli worker
2097 zmq_get_important_options(Options) :- findall(O, (option(O), zmq_important_option(O)), Options),
2098 debug_println(20,transferring_zmq_options_to_workers(Options)).
2099 zmq_important_option(coverage(_)).
2100 zmq_important_option(expect_error(_)).
2101 zmq_important_option(optional_error(_)).
2102 zmq_important_option(file_info).
2103 zmq_important_option(log(_)).
2104 zmq_important_option(print_version(_)).
2105 zmq_important_option(profiling_on).
2106 zmq_important_option(set_card(_,_)).
2107 zmq_important_option(set_pref(_,_)).
2108 zmq_important_option(set_preference_group(_,_)).
2109 zmq_important_option(statistics).
2110 zmq_important_option(csv_table_command(_,_,_,_)).
2111 zmq_important_option(verbose(_)).
2112 zmq_important_option(set_searchscope(_)).
2113 zmq_important_option(no_invariant_violations).
2114 %zmq_important_option(no_deadlocks).
2115 %zmq_important_option(no_goal).
2116 % we could consider also supporting: -argv, -cache, -prefs FILE csp_main(ProcessName) profiling_on prob_profile runtimechecking
2117
2118 % set options received by a zmq worker
2119 :- use_module(b_global_sets, [set_user_defined_scope/2]).
2120 :- use_module(tools_strings, [convert_cli_arg/2]).
2121 zmq_set_important_options(Options) :- debug_println(20,setting_zmq_options(Options)),
2122 maplist(prob_cli:zmq_set_option,Options).
2123 zmq_set_option(file_info) :- !, file_info.
2124 zmq_set_option(log(F)) :- !,
2125 generate_time_stamp(Datime,NOW),
2126 cli_start_logging(F,ascii,NOW,Datime,[zmq_worker]).
2127 zmq_set_option(print_version(V)) :- !, print_version(V).
2128 zmq_set_option(profiling_on) :- !, profiling_on.
2129 zmq_set_option(set_card(Set,V)) :- !,
2130 convert_cli_arg(V,Value),
2131 set_user_defined_scope(Set,Value).
2132 zmq_set_option(set_pref(P,V)) :- !, set_pref(P,V).
2133 zmq_set_option(set_preference_group(P,V)) :- !, set_preference_group(P,V).
2134 zmq_set_option(verbose(Nr)) :- !, verbose(Nr).
2135 zmq_set_option(O) :- zmq_delayed_option(O),!, assert_option(O). % DO IT LATER
2136 zmq_set_option(O) :- add_internal_error('Unsupported option for ZMQ worker: ',zmq_set_option(O)).
2137
2138 zmq_delayed_option(coverage(_)).
2139 zmq_delayed_option(expect_error(_)).
2140 zmq_delayed_option(expect_error_pos(_,_,_)).
2141 zmq_delayed_option(optional_error(_)).
2142 zmq_delayed_option(statistics).
2143 zmq_delayed_option(set_searchscope(_)).
2144 zmq_delayed_option(no_invariant_violations). % not supported yet
2145
2146 ltsmin_ltl_output(Filename, NOW) :-
2147 if_option_set(ltl_formula_model_check(Formula, _),true),
2148 ltsmin_generate_ltlfile(Formula, Filename),
2149 halt_prob(NOW,0). % if we additionally specify -ltsformula, we do not want to model check it
2150
2151
2152 start_ltsmin_srv(X, NOW) :-
2153 nls,println_silent('Starting LTSMin Server...'),
2154 if_option_set(ltl_formula_model_check(Formula, _),true),
2155 ltsmin_init(X, Zocket, Formula),
2156 ltsmin_loop(Zocket),
2157 ltsmin_teardown(Zocket, X),
2158 nls,println_silent('Stopped LTSMin Server.'),
2159 halt_prob(NOW,0). % if we additionally specify -ltsformula, we do not want to model check it
2160
2161 zmq_start_worker(Identifier, NOW) :-
2162 get_preference(port, Port),
2163 get_preference(logdir, LogDir),
2164 get_preference(tmpdir, TmpDir),
2165 get_preference(proxynumber, ProxyNumber),
2166 /* TODO: ensure directory exists (pk, 09.01.2018) */
2167 atom_concat(LogDir, '/worker-', ATmp),
2168 atom_concat(ATmp, Identifier, Logfile),
2169 % TODO: tmp dir currently not used
2170 atom_concat(TmpDir, '/db-worker-', TTmp),
2171 atom_concat(TTmp, Identifier, TmpDir2),
2172 start_worker(Port,ProxyNumber,Logfile,TmpDir2,zmq_worker_load_model),
2173 formatsilent('ZMQ worker finished (Port:~w)~n',[Port]),
2174 cli_process_loaded_file_afer_start_animation(NOW),
2175 println_silent('Exiting probcli worker'),
2176 halt_prob(NOW,0).
2177
2178 zmq_start_animation :-
2179 prob2_interface:start_animation,
2180 if_option_set(set_goal(GOAL),
2181 cli_set_goal(GOAL)), % not used yet
2182 if_option_set(set_searchscope(SCOPE),
2183 cli_set_searchscope(SCOPE)),
2184 cli_computeOperations(_).
2185 zmq_worker_load_model(classical_b(Machine,Options)) :- !,
2186 debug_println(20,'ZMQ WORKER: Loading classical B model'),
2187 zmq_set_important_options(Options),
2188 bmachine:b_machine_reset, bmachine:assert_main_machine(Machine),
2189 set_animation_mode(b),
2190 zmq_start_animation.
2191 zmq_worker_load_model(classical_b_with_csp(Machine,CspGuide,Options)) :- !,
2192 debug_println(20,'ZMQ WORKER: Loading CSP || B model'),
2193 zmq_set_important_options(Options),
2194 bmachine:b_machine_reset, bmachine:assert_main_machine(Machine),
2195 set_animation_mode(b),
2196 prob2_interface:start_animation,
2197 tcltk_add_csp_file(CspGuide), % TO DO: use CSP Prolog term rather than filename <----------------
2198 zmq_start_animation.
2199 zmq_worker_load_model(eventb(Machine,Options)) :- !,
2200 print(loading_eventb(Options)),nl,
2201 zmq_set_important_options(Options),
2202 bmachine:b_machine_reset, bmachine:assert_main_machine(Machine),
2203 set_animation_mode(b), set_animation_minor_mode(eventb),
2204 zmq_start_animation.
2205 zmq_worker_load_model(csp_specification(CSPFile,Options)) :-
2206 zmq_set_important_options(Options),
2207 load_cspm_spec_from_cspm_file(CSPFile), % TO DO: pass CSP Prolog term rather than filename
2208 zmq_start_animation.
2209 zmq_worker_load_model(filename(FN)) :- !,
2210 printsilent('loading file by filename\n'),flush_output,
2211 ( is_eventb_b(FN) ->
2212 eclipse_interface:load_eventb_file(FN)
2213 ;
2214 bmachine:b_load_machine_probfile(FN)),
2215 zmq_start_animation.
2216 zmq_worker_load_model(assertions(Machine,State,Assertions)) :- !,
2217 assertz(assertion_counter(-1)),
2218 println_silent(loaded_model_for_assertion_checking),
2219 zmq_worker_load_model(Machine),
2220 assertz(worker:assertion_state(State)),
2221 make_assertionwps(Assertions).
2222 % assert current state
2223 zmq_worker_load_model(Other) :-
2224 add_internal_error('ZMQ worker: Unexpected machine description', zmq_worker_load_model(Other)),
2225 fail.
2226
2227
2228 :-dynamic assertion_counter/1.
2229
2230 count_assertions([],A,A).
2231 count_assertions([H|T],A,R) :- size_of_conjunction(H,N1),
2232 NN is A + N1,
2233 count_assertions(T,NN,R).
2234
2235 make_assertionwps([]).
2236 make_assertionwps([H|T]) :- conjunction_to_list(H,HL),
2237 sort_assertions(HL,SL),
2238 append_assertion(SL),
2239 make_assertionwps(T).
2240
2241 append_assertion([]).
2242 append_assertion([H|T]) :- assertion_counter(N),
2243 retractall(assertion_counter(_)),
2244 N1 is N + 1,
2245 assertz(assertion_counter(N1)),
2246 assertz(worker:assertion_task(N1,H)),
2247 append_assertion(T).
2248
2249 %assertions_order(A,B) :- term_size(A,NA),term_size(B,NB), NA > NB.
2250 sort_assertions(X,X).
2251 % :- samsort(assertions_order,X,Y).
2252
2253
2254
2255 is_eventb_b(FN) :- append(_,FN,".eventb").
2256 % load_model(Initialisation)
2257
2258
2259 :- use_module(predicate_evaluator).
2260 :- use_module(bmachine,[b_machine_name/1]).
2261 set_analyse_hook(AddPrefix) :- % set a hook to write false/unknown expressions into a dot file
2262 reset_dot_file_number,
2263 if_options_set(dot_analyse_output_prefix(_Path),
2264 (set_dot_file_prefix_if_option_set(AddPrefix),
2265 register_conjunct_error_hook(prob_cli:pred_eval_hook))).
2266 unset_analyse_hook :- predicate_evaluator:reset_conjunct_error_hook.
2267
2268 :- use_module(tools,[get_modulename_filename/2]).
2269 loaded_root_filename(RootName) :- loaded_main_file(MainFile),
2270 get_modulename_filename(MainFile,RootName).
2271
2272 set_dot_file_prefix_if_option_set(AddPrefix) :-
2273 if_options_set(dot_analyse_output_prefix(Path),
2274 (loaded_root_filename(RootName),
2275 % we could also use b_machine_hierarchy:main_machine_name(RootName)
2276 string_concatenate(Path,RootName,P1),
2277 string_concatenate(P1,AddPrefix,FullPath),
2278 set_dot_file_prefix(FullPath),
2279 debug_println(9,dot_file_prefix(FullPath)))).
2280
2281 % Status: true, false, unknown
2282 :- public pred_eval_hook/5.
2283 pred_eval_hook(_Conjunct,true,_EnumWarning,_IsExpanded, _CS) :-
2284 \+ option(dot_generate_for_all_formulas),!. % don't generate .dot for true formulas, unless explicitly requested
2285 pred_eval_hook(Conjunct,Status,_EnumWarning,_IsExpanded, CS) :-
2286 printsilent('Generating dotfile for: '),printsilent(CS),nls,
2287 (write_dot_graph_to_new_file(Status,Conjunct) -> true
2288 ; add_error(dot_output,'Writing dot to file failed: ',CS)).
2289
2290
2291 :- dynamic dot_file_prefix/1.
2292 :- dynamic dot_file_number/1.
2293
2294 dot_file_prefix('~/Desktop/dot').
2295 set_dot_file_prefix(F) :- retractall(dot_file_prefix(_)), assertz(dot_file_prefix(F)).
2296 dot_file_number(0).
2297 reset_dot_file_number :- retractall(dot_file_number(_)), assertz(dot_file_number(0)).
2298 get_next_nr(GNr) :- retract(dot_file_number(Nr)), N1 is Nr+1,
2299 assertz(dot_file_number(N1)), GNr = Nr.
2300 write_dot_graph_to_new_file(Status,BExpr) :-
2301 dot_file_prefix(Dir),get_next_nr(Nr),
2302 string_concatenate('_',Status,Str1),
2303 string_concatenate(Nr,Str1,NS),
2304 string_concatenate(Dir,NS,F1),
2305 atom_concat(F1,'.dot',FileName),
2306 tcltk_interface:write_dot_file_for_pred_expr(BExpr,FileName).
2307
2308 % get dot file name if dot_output has been set
2309 get_dot_file(Type,FileName) :- option(dot_analyse_output_prefix(_)),
2310 set_dot_file_prefix_if_option_set(Type),
2311 dot_file_prefix(Dir),
2312 string_concatenate('_',Type,Str1),
2313 string_concatenate(Dir,Str1,F1),
2314 atom_concat(F1,'.dot',FileName).
2315
2316 :- use_module(extrasrc(refinement_checker),
2317 [tcltk_refinement_search/3, tcltk_load_refine_spec_file/1, tcltk_save_specification_state_for_refinement/1]).
2318 cli_csp_in_situ_refinement_check(P,Type,Q,NOW) :-
2319 debug_println(20,'% Starting CSP Refinement Check'),
2320 loaded_main_file(CSPFile),
2321 ajoin_with_sep(['assert',P,Type,Q], ' ',Assertion),
2322 start_xml_feature(csp_refinement_check,assertion,Assertion,FINFO),
2323 ( timeout_call(tcltk_interface:tcltk_check_csp_assertion(Assertion,CSPFile,'False',_PlTerm,RefTrace),NOW,'cspref')
2324 -> check_ref_result(RefTrace)
2325 ; true),
2326 stop_xml_feature(csp_refinement_check,FINFO).
2327 cli_start_refinement_check(RefFile,FailuresModel,RefNrNodes,NOW) :-
2328 start_xml_feature(refinement_check,file,RefFile,FINFO),
2329 tcltk_load_refine_spec_file(RefFile),
2330 ( timeout_call(tcltk_refinement_search(RefTrace,FailuresModel,RefNrNodes),NOW,refinement_check)
2331 -> check_ref_result(RefTrace)
2332 ; true),
2333 stop_xml_feature(refinement_check,FINFO).
2334 check_ref_result(RefTrace) :-
2335 ( RefTrace==no_counter_example ->
2336 print('==> Refinement Check Successful'),nl
2337 ; RefTrace==no_counter_example_found ->
2338 print('==> Refinement Check did not find Counter-Example but is incomplete'),nl,
2339 error_occurred(refinement_check_incomplete)
2340 ;
2341 print('*** Refinement Check Counter-Example: ***'),nl, print(RefTrace),nl,
2342 print('*** Refinement Check Failed ***'),nl,
2343 error_occurred(refinement_check_fails)).
2344 cli_checkAssertion(Proc,Model,AssertionType,_NOW) :-
2345 loaded_main_file(CSPFile),
2346 ajoin(['assert ',Proc,' :[ ',AssertionType,'[',Model,']',' ]'],Assertion),
2347 start_xml_feature(csp_deadlock_check,assertion,Assertion,FINFO),
2348 ( /*timeout_call(*/tcltk_interface:tcltk_check_csp_assertion(Assertion,CSPFile,'False',_PlTerm,ResTrace)/*,NOW,a)*/
2349 -> check_model_result(Assertion,ResTrace)
2350 ; true),
2351 stop_xml_feature(csp_deadlock_check,FINFO).
2352 cli_check_csp_assertion(Assertion,NOW) :-
2353 start_xml_feature(csp_assertion_check,assertion,Assertion,FINFO),
2354 loaded_main_file(CSPFile),
2355 ajoin(['assert ',Assertion],AssertionFull),
2356 ( timeout_call(tcltk_interface:tcltk_check_csp_assertion(AssertionFull,CSPFile,_Negated,PlTerm,ResTrace),NOW,csp_assertion_check)
2357 -> check_model_result(PlTerm,ResTrace)
2358 ; true),
2359 stop_xml_feature(csp_assertion_check,FINFO).
2360
2361
2362
2363 check_model_result(AssertionPlTerm,ResTrace) :-
2364 ( ResTrace==no_counter_example ->
2365 printsilent('==> Model Check Successful'),nls
2366 ;
2367 (functor(AssertionPlTerm,assertRef,_Arity) ->
2368 print('*** Refinement Check Counter-Example: ***'),nl, print(ResTrace),nl,
2369 print('*** Refinement Check Failed ***'),nl,
2370 error_occurred(refinement_check_fails)
2371 ;
2372 print('*** Model Check Counterexample: ***'),nl,print(ResTrace),nl,
2373 print('*** Model Check Failed ***'),nl,
2374 error_occurred(model_check_fails))
2375 ).
2376 :- use_module(probcspsrc(haskell_csp),[get_csp_assertions_as_string/2,
2377 parse_and_load_cspm_file_into_specific_pl_file/2,
2378 evaluate_csp_expression/2, evaluate_csp_expression/3]).
2379 cli_csp_get_assertions :-
2380 loaded_main_file(CSPFile),
2381 get_csp_assertions_as_string(CSPFile,String),
2382 print('*** Assertions in File (separated by $) ***'),nl,print(String),nl.
2383 cli_eval_csp_expression(E) :-
2384 (loaded_main_file(CSPFile) ->
2385 evaluate_csp_expression(E, CSPFile, Res)
2386 ; evaluate_csp_expression(E,Res)
2387 ), print('Evaluated Expression: '),nl,print(Res),nl.
2388 cli_csp_translate_to_file(PlFile) :-
2389 loaded_main_file(CSPFile),
2390 parse_and_load_cspm_file_into_specific_pl_file(CSPFile,PlFile).
2391 :- use_module(probltlsrc(ltl_fairness),[check_scc_ce/2]).
2392 cli_check_scc_for_ltl_formula(LtlFormula,SCC) :-
2393 check_scc_ce(LtlFormula,SCC).
2394
2395 :- use_module(extrasrc(coverage_statistics),[pretty_print_coverage_information_to_file/1]).
2396 cli_get_coverage_information(FileName) :-
2397 pretty_print_coverage_information_to_file(FileName).
2398 cli_vacuity_check :-
2399 eclipse_interface:get_vacuous_invariants(L),
2400 (L=[] -> print('No vacuous invariants'),nl
2401 ; maplist(prob_cli:add_vacuous_invariant,L)).
2402 add_vacuous_invariant(Inv) :-
2403 translate:translate_bexpression(Inv,TI),
2404 add_error(vacuity_check,'Vacuous invariant: ',TI).
2405 cli_start_socketserver(Port,Loopback) :-
2406 printsilent('Starting Socket Server'),nls,
2407 safe_absolute_file_name(prob_home('.'),AppDir),
2408 printsilent('Application Path: '),printsilent(AppDir),nls,
2409 disable_interaction_on_errors,
2410 ( start_prob_socketserver(Port,Loopback) -> true
2411 ;
2412 print('Starting socket server failed, Port: '), print(Port),nl),
2413 printsilent('Finished Socket Server'),nls.
2414 :- use_module(tools_platform, [platform_is_64_bit/0]).
2415 cli_check_statespace_hash(Expected,Kind) :-
2416 printsilent('Computing hash of entire statespace: '),
2417 compute_full_state_space_hash(Hash),
2418 printsilent(Hash),nls, % TO DO: maybe also compute hash for transitions and check that
2419 (Hash=Expected -> true
2420 ; Kind=='64bit', \+ platform_is_64_bit -> format('Hash does not match ~w (but was computed on 64-bit system)~n',[Expected])
2421 ; Kind=='32bit', platform_is_64_bit -> format('Hash does not match ~w (but was computed on 32-bit system)~n',[Expected])
2422 ; add_error(hash,'Expected Statespace Hash to be: ',Expected)).
2423 :- use_module(extrasrc(b_operation_cache),[get_op_cache_stats/1]).
2424 cli_check_op_cache(ReqInfos) :-
2425 get_op_cache_stats(Stats),
2426 (ReqInfos=[] -> format('Operation caching statistics: ~w~n',[Stats])
2427 ; formatsilent('Operation caching statistics: ~w~n',[Stats])),
2428 accumulate_infos(op_cache,Stats),
2429 check_required_infos(ReqInfos,Stats,op_cache_stats).
2430 cli_show_coverage(ShowEnabledInfo,NOW) :-
2431 cli_show_coverage(_Nodes,_Operations,ShowEnabledInfo,NOW).
2432 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW) :-
2433 ShowEnabledInfo == just_check_stats,!, % no printing of individual transition coverage
2434 get_state_space_stats(TotalNodeSum,TotalTransSum,_ProcessedTotal,_), % no computation overhead
2435 writeln_log(computed_coverage(NOW,TotalNodeSum,TotalTransSum)),
2436 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum).
2437 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW) :-
2438 ShowEnabledInfo == just_summary,
2439 !, % no printing of detailed transition coverage (avoid traversing state space)
2440 get_state_space_stats(TotalNodeSum,TotalTransSum,ProcessedTotal,Ignored), % no computation overhead
2441 writeln_log(computed_coverage(NOW,TotalNodeSum,TotalTransSum)),
2442 format('Coverage:~n States: ~w (~w processed, ~w ignored)~n Transitions: ~w~n',
2443 [TotalNodeSum,ProcessedTotal,Ignored,TotalTransSum]),
2444 show_initialisation_summary(NOW),
2445 show_operation_coverage_summary(NOW),
2446 (invariant_violated(ID) -> format('At least one state violates the invariant (~w) ~n',[ID]) ; true),
2447 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum).
2448 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW) :-
2449 write('Coverage Information:'),nl,
2450 compute_the_coverage(Res,TotalNodeSum,TotalTransSum,ShowEnabledInfo,false),
2451 writeln_log(computed_coverage(NOW,TotalNodeSum,TotalTransSum)),
2452 write_table_to_text_file(user_output,Res),
2453 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum).
2454 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum) :-
2455 ( Nodes=TotalNodeSum -> true
2456 ;
2457 add_error(probcli,'Unexpected number of nodes: ',TotalNodeSum),
2458 add_error(probcli,'Expected: ',Nodes),error_occurred(coverage)),
2459 ( Operations=TotalTransSum -> true
2460 ;
2461 add_error(probcli,'Unexpected number of transitions: ',TotalTransSum),
2462 add_error(probcli,'Expected: ',Operations),error_occurred(coverage)).
2463
2464
2465 :- use_module(bmachine,[b_machine_statistics/2, b_get_main_filename/1, b_get_all_used_filenames/1,get_full_b_machine_sha_hash/1]).
2466 :- use_module(tools_strings,[get_hex_bytes/2]).
2467 cli_print_machine_info(statistics) :-
2468 b_machine_name(Name),
2469 %(b_get_main_filename(File) -> true ; File=unknown),
2470 format('Machine statistics for ~w:~n',[Name]),
2471 findall(Key/Nr,b_machine_statistics(Key,Nr),L),
2472 maplist(prob_cli:print_keynr,L),!.
2473 cli_print_machine_info(files(WithSha)) :-
2474 b_machine_name(Name),
2475 (WithSha = with_sha -> Msg2='and SHA1 ' ; Msg2=''),
2476 format('Files ~wused for machine ~w:~n',[Msg2,Name]),
2477 b_get_all_used_filenames(Files),
2478 maplist(prob_cli:print_individual_file(WithSha),Files),!.
2479 cli_print_machine_info(hash(Expected)) :-
2480 b_machine_name(MainName), % to do: findall machines and hashes
2481 get_full_b_machine_sha_hash(HashBytes),
2482 get_hex_bytes(HashBytes,Hash),
2483 format('SHA hash for machine ~w = ~s~n',[MainName,Hash]),!,
2484 write_xml_element_to_log(machine_hash,[hash/Hash]),
2485 (var(Expected) -> true
2486 ; atom_codes(Expected,Hash)
2487 -> format_with_colour_nl(user_output,[green],'Machine hash for ~w matches provided hash.',[MainName])
2488 ; add_error(machine_hash_check,'Unexpected machine hash, expected: ',Expected)).
2489 cli_print_machine_info(Kind) :- add_error(machine_stats,'Could not obtain machine information:',Kind).
2490 print_keynr(Key/Nr) :- format(' ~w : ~w~n',[Key,Nr]).
2491 :- use_module(extension('probhash/probhash'),[raw_sha_hash_file/3]).
2492 :- use_module(tools_strings,[get_hex_bytes/2]).
2493 print_individual_file(with_sha,File) :- Span = machine_info,
2494 raw_sha_hash_file(File,Term,Span),
2495 get_hex_bytes(Term,SHAHexCodes),
2496 format(' ~w, ~s~n',[File,SHAHexCodes]).
2497 print_individual_file(_,File) :- format(' ~w~n',[File]).
2498
2499 check_machine_file_sha(File,ExpectedHash) :- Span = check_machine_file_sha,
2500 get_full_machine_file_path(File,AbsFile),
2501 raw_sha_hash_file(AbsFile,Term,Span),
2502 get_hex_bytes(Term,SHAHexCodes), atom_codes(ExpectedHash,ExpectedShaCodes),
2503 (SHAHexCodes=ExpectedShaCodes
2504 -> format_with_colour_nl(user_output,[green],'Checked SHA1 hash for file ~w is ~s',[AbsFile,SHAHexCodes])
2505 ; add_error(check_machine_file_sha,'Unexpected SHA1 hash of file:',AbsFile),
2506 format_with_colour_nl(user_error,[orange],'! Expected: ~w~n! Actual : ~s',[ExpectedHash,SHAHexCodes])
2507 ).
2508
2509 :- use_module(bmachine,[get_machine_file_number/4, b_absolute_file_name_relative_to_main_machine/2]).
2510 :- use_module(probsrc(tools), [get_parent_directory/2]).
2511 get_full_machine_file_path(File,AbsFile) :-
2512 get_modulename_filename(File,Name),
2513 (get_filename_extension(File,ExtF), ExtF \= ''
2514 -> true ; debug_format(19,'No extension provided for file ~w~n',[File])),
2515 (get_machine_file_number(Name,ExtF,_Nr,AbsFile)
2516 -> get_parent_directory(File,Parent),
2517 (Parent='' -> true % no path provided
2518 ; File=AbsFile -> true % full path provided
2519 ; b_absolute_file_name_relative_to_main_machine(File,AbsFile) -> true % consistent partial path provided
2520 ; add_error(check_machine_file_sha,'File path (relative to main model) is inconsistent with used file:',File),
2521 b_absolute_file_name_relative_to_main_machine(File,AbsFile1),
2522 format_with_colour_nl(user_error,[orange],'! Full path in -check_machine_file_sha:~n ~w',[AbsFile1]),
2523 format_with_colour_nl(user_error,[orange],'! File actually used in B main model :~n ~w',[AbsFile])
2524 )
2525 ; get_machine_file_number(_,_,_,_) ->
2526 add_error(check_machine_file_sha,'Could not locate the file for:',File),
2527 b_absolute_file_name_relative_to_main_machine(File,AbsFile)
2528 ; add_message(check_machine_file_sha,'No main B machine loaded for, converting to absolute path: ',File),
2529 absolute_file_name(File,AbsFile)
2530 ).
2531
2532 :- use_module(tools,[get_tail_filename/2]).
2533 xml_log_machine_statistics :-
2534 animation_mode(Major),
2535 (animation_minor_mode(Minor) -> true ; Minor=none),
2536 write_xml_element_to_log(animation_mode,[major/Major,minor/Minor]),
2537 (b_or_z_mode, b_machine_name(Main)
2538 -> findall(Key/Nr,b_machine_statistics(Key,Nr),BMachStats),
2539 (b_get_main_filename(MainFile) -> get_tail_filename(MainFile,TailFile) ; TailFile = unknown),
2540 write_xml_element_to_log(b_machine_statistics,[machine_name/Main, tail_filename/TailFile|BMachStats])
2541 ; true).
2542
2543 cli_print_junit_results(ArgV) :-
2544 junit_mode(S),!,
2545 statistics(runtime,[E,_]),
2546 T is E - S,
2547 create_and_print_junit_result(['Integration Tests'],ArgV,T,pass).
2548 cli_print_junit_results(_).
2549
2550 :- use_module(visbsrc(visb_visualiser),[load_visb_file/1,
2551 tcltk_perform_visb_click_event/1, generate_visb_html_for_history/2]).
2552 cli_visb_history(JSONFile,HTMLFile,Options) :-
2553 (load_visb_file(JSONFile)
2554 -> ifm_option_set(visb_click(SVGID),tcltk_perform_visb_click_event(SVGID)), % simulate clicks if requested
2555 generate_visb_html_for_history(HTMLFile,Options)
2556 ; true). % errors already reported
2557
2558 cli_print_history(HistFile) :-
2559 findall( O, option(history_option(O)), Options),
2560 debug_println(9,writing_history_to_file(HistFile)),
2561 (select(trace_file,Options,ROpt) -> tcltk_save_history_as_trace_file(prolog,ROpt,HistFile) % save as Prolog trace file for replay with -t
2562 ; select(json,Options,ROpt) -> tcltk_save_history_as_trace_file(json,ROpt,HistFile) % save for replay with ProB2 UI
2563 ; write_history_to_file(HistFile,Options) -> true
2564 ; add_error(history,'Writing history to file failed: ',HistFile)).
2565
2566 cli_print_values(ValuesFilename) :-
2567 (write_values_to_file(ValuesFilename) -> true ; add_error(sptxt,'Writing values to file failed: ',ValuesFilename)).
2568 cli_print_all_values(ValuesDirname) :-
2569 (write_all_values_to_dir(ValuesDirname) -> true ; add_error(sstxt,'Writing all values to directory failed: ',ValuesDirname)).
2570
2571 :- use_module(probltlsrc(trace_generator),[generate_all_traces_until/4]).
2572
2573 cli_generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix) :-
2574 generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix,Result,NrTracesGenerated),
2575 format_with_colour_nl(user_error,[blue],'Generated ~w traces, result=~w~n',[NrTracesGenerated,Result]).
2576
2577 :- dynamic probcli_time_stamp/1.
2578 generate_time_stamp(NOW,TS) :- retractall(probcli_time_stamp(_)),
2579 now(NOW),
2580 current_prolog_flag(argv,ArgV),term_hash(ArgV,Hash),
2581 Rnd is Hash mod 1000,
2582 % random(0,1000,Rnd), always returns 216 % TO DO: try to get milliseconds from some library function
2583 TS is (NOW*1000)+Rnd,
2584 assertz(probcli_time_stamp(TS)).
2585 update_time_stamp(NOW1) :- retractall(probcli_time_stamp(_)),
2586 assertz(probcli_time_stamp(NOW1)).
2587
2588 %get_errors :- \+ real_error_occurred,!, (get_error(_Source,_Msg) -> print('*** Warnings occurred'),nl ; true), reset_errors.
2589 get_errors :-
2590 (get_preference(view_probcli_errors_using_bbresults,true)
2591 -> tools_commands:show_errors_with_bb_results([current]) ; true),
2592 get_error_sources.
2593
2594 get_error_sources :- get_error_with_span(ErrSource,Msg,Span), !,
2595 error_occurred_with_msg(ErrSource,Msg,Span),
2596 findall(1,get_error(ErrSource,_),L), length(L,Nr),
2597 (Nr>0 -> N1 is Nr+1, get_error_category_and_type(ErrSource,Cat,Type),
2598 (Type=error -> print_error('*** Occurences of this error: ')
2599 ; print_error('*** Occurences of this warning: ')),
2600 print_error(N1),
2601 write_xml_element_to_log(multiple_errors_occurred,[category/Cat,(type)/Type,number/N1])
2602 ; true),
2603 get_error_sources.
2604 get_error_sources.
2605
2606 :- use_module(state_space,[state_error/3, invariant_violated/1, time_out_for_invariant/1, time_out_for_assertions/1, time_out_for_node/3]).
2607 ?get_state_space_errors :- option(strict_raise_error),
2608 !,
2609 (\+ option(no_invariant_violations),invariant_violated(ID)
2610 -> (option_verbose ->
2611 format('Invariant violation in state with id = ~w~n',[ID]),
2612 b_interpreter:analyse_invariant_for_state(ID) % caused issue for test 1076
2613 ; format('Invariant violation in state with id = ~w (use -v to print more details)~n',[ID])
2614 ),
2615 error_occurred(invariant_violation)
2616 ; true),
2617 (state_error(_,_,abort_error(TYPE,Msg,_,Span)) -> error_occurred(TYPE,error,Span,Msg) ; true),
2618 get_state_errors(_).
2619 get_state_space_errors.
2620
2621 get_state_errors(ID) :- state_error(ID,_,X), X\=invariant_violated, X\=abort_error(_,_,_,_),
2622 create_state_error_description(X,Msg),error_occurred(Msg),fail.
2623 get_state_errors(ID) :- time_out_for_invariant(ID),error_occurred(time_out_for_invariant),fail.
2624 get_state_errors(ID) :- time_out_for_assertions(ID),error_occurred(time_out_for_assertions),fail.
2625 get_state_errors(ID) :- time_out_for_node(ID,_,time_out),error_occurred(time_out),fail.
2626 get_state_errors(ID) :-
2627 time_out_for_node(ID,_,virtual_time_out(_)), %print(virtual_time_out_for_node(ID)),nl,
2628 error_occurred(virtual_time_out),fail.
2629 get_state_errors(_).
2630
2631
2632 create_state_error_description(eventerror(Event,Error,_),Description) :- !,
2633 functor(Error,Functor,_),
2634 ajoin(['event_error:',Event,':',Functor],Description).
2635 create_state_error_description(StateError,Description) :-
2636 functor(StateError,Functor,_),
2637 atom_concat('state_error:',Functor,Description).
2638
2639 % require a real machine to be loaded
2640 check_loaded_not_empty(Action) :-
2641 file_loaded(true,'$$empty_machine'),!,
2642 add_error(probcli,'No file specified; cannot perform command: ',Action),
2643 error_occurred(loading),fail.
2644 check_loaded_not_empty(Action) :- check_loaded(Action).
2645
2646 check_loaded(Action) :-
2647 ( file_loaded(true) -> true
2648 ; file_loaded(error) -> fail /* we have already generated error message */
2649 ;
2650 add_error(probcli,'No file specified; cannot perform action: ',Action),
2651 error_occurred(loading),fail).
2652
2653 :- dynamic loaded_main_file/2.
2654 loaded_main_file(File) :- loaded_main_file(_Ext,File).
2655
2656 :- use_module(tools,[get_filename_extension/2]).
2657 load_main_file(MainFile,NOW,Already_FullyProcessed) :- retractall(loaded_main_file(_,_)),
2658 debug_print(20,'% Loading: '), debug_println(20,MainFile),
2659 writeln_log_time(loading(NOW,MainFile)),
2660 get_filename_extension(MainFile,Ext),
2661 debug_println(6,file_extension(Ext)),
2662 file_extension_can_be_loaded(Ext,MainFile),
2663 start_probcli_timer(Timer),
2664 load_spec_file(Ext,MainFile,Already_FullyProcessed),
2665 stop_probcli_debug_timer(Timer,'% Finished loading file after'),
2666 (Already_FullyProcessed==true -> true
2667 ; assertz(loaded_main_file(Ext,MainFile))).
2668
2669 known_spec_file_extension('P',xtl).
2670 known_spec_file_extension(als,alloy).
2671 known_spec_file_extension(csp,csp).
2672 known_spec_file_extension(cspm,csp).
2673 known_spec_file_extension(def,b).
2674 known_spec_file_extension(eval,b_eval).
2675 known_spec_file_extension(eventb,eventb).
2676 known_spec_file_extension(fuzz,z).
2677 known_spec_file_extension(imp,b).
2678 known_spec_file_extension(mch,b).
2679 known_spec_file_extension(pb,b).
2680 known_spec_file_extension(pl,xtl).
2681 known_spec_file_extension(pla,alloy). % Prolog AST of Alloy translation
2682 known_spec_file_extension(probpo,sequent_prover). % disprover PO files
2683 known_spec_file_extension(prob,b).
2684 known_spec_file_extension(ref,b).
2685 known_spec_file_extension(rmch,b_rules).
2686 known_spec_file_extension(smt,smt).
2687 known_spec_file_extension(smt2,smt).
2688 known_spec_file_extension(sys,b).
2689 known_spec_file_extension(tex,z).
2690 known_spec_file_extension(tla,tla).
2691 known_spec_file_extension(zed,z).
2692
2693 :- use_module(pathes_extensions_db, [load_spec_file_requires_extension/2]).
2694 :- use_module(pathes_lib, [available_extension/1, unavailable_extension/2]).
2695 % check if we can load the file extension given available ProB extensions
2696 file_extension_can_be_loaded(FileExt,_) :- known_spec_file_extension(FileExt,Mode),
2697 load_spec_file_requires_extension(Mode,ProBExtension),
2698 unavailable_extension(ProBExtension,Reason),!,
2699 ajoin(['File with ending .', FileExt,' cannot be loaded because extension not available (',Reason,'):'],Msg),
2700 add_error(probcli,Msg,ProBExtension),
2701 fail.
2702 file_extension_can_be_loaded(_,_). % assume ok; if unrecognized we will load as B machine
2703
2704 %load_spec_file('pl',MainFile) :- !, load_cspm_spec_from_pl_file(MainFile). % no longer needed ?
2705 load_spec_file('pl',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile).
2706 load_spec_file('csp',MainFile) :- !, load_cspm_spec_from_cspm_file(MainFile).
2707 load_spec_file('cspm',MainFile) :- !, load_cspm_spec_from_cspm_file(MainFile).
2708 load_spec_file('P',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile).
2709 load_spec_file('p',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile). % sometimes windows is confused about the upper case letter....
2710 load_spec_file('probpo',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile). % load (Disprover) PO files in sequent_prover mode
2711 load_spec_file('eventb',MainFile) :- !, load_eventb_file(MainFile).
2712 load_spec_file('v',MainFile) :- !,
2713 print('Warning: .v proof rule file format no longer supported, use -eval_rule_file FILE'),nl,
2714 % but even that may not work; some older rule files required predicate variables
2715 load_b_file_with_options(MainFile). % Siemens Rule File; now use -eval_rule_file
2716 load_spec_file('prob',MainFile) :- !,load_prob_file_with_options(MainFile). % .prob files
2717 load_spec_file('mch',MainFile) :- !,load_b_file_with_options(MainFile).
2718 load_spec_file('sys',MainFile) :- !,load_b_file_with_options(MainFile).
2719 load_spec_file('ref',MainFile) :- !,load_b_file_with_options(MainFile).
2720 load_spec_file('imp',MainFile) :- !,load_b_file_with_options(MainFile).
2721 load_spec_file('rmch',MainFile) :- !,load_b_file_with_options(MainFile).
2722 load_spec_file('def',MainFile) :- !,load_b_file_with_options(MainFile). % .def DEFINITIONS file
2723 load_spec_file('fuzz',MainFile) :- !,tcltk_open_z_file(MainFile).
2724 load_spec_file('tex',MainFile) :- !,tcltk_open_z_tex_file(MainFile).
2725 load_spec_file('zed',MainFile) :- !,tcltk_open_z_tex_file(MainFile). % proz .zed file
2726 load_spec_file('als',MainFile) :- !,tcltk_open_alloy_file(MainFile).
2727 load_spec_file('pla',MainFile) :- !,tcltk_open_alloy_prolog_ast_file(MainFile). % maybe we should detect .als.pl
2728 load_spec_file('tla',MainFile) :- !, load_tla_file(MainFile).
2729 load_spec_file('cnf',MainFile) :- !, load_cnf_file_with_options(MainFile).
2730 load_spec_file('eval',File) :- !, % .eval file
2731 cli_set_empty_machine,
2732 assertz(option(eval_string_or_file(file(default),File,exists,_,norecheck))).
2733 load_spec_file('pb',File) :- !, cli_set_empty_machine, % .pb file
2734 cli_set_empty_machine,
2735 assertz(option(eval_string_or_file(file(default),File,exists,_,norecheck))).
2736 %load_spec_file('pml',MainFile) :- !,parsercall:call_promela_parser(MainFile),
2737 % parsercall:promela_prolog_filename(MainFile,PrologFile),
2738 % println_silent(consulting(PrologFile)),
2739 % tcltk_open_promela_file(PrologFile).
2740 load_spec_file(EXT,MainFile) :- print_error('Unknown file extension, assuming B machine:'),
2741 print_error(EXT),
2742 load_b_file_with_options(MainFile).
2743
2744 load_spec_file(EXT,MainFile, Already_FullyProcessed) :-
2745 (EXT='probpo' ; EXT= 'pl'),
2746 % we could check: xtl_interface:check_is_po_file(MainFile,EXT); adds warning for .pl files
2747 load_pl_file_with_disprover(MainFile), !,
2748 Already_FullyProcessed=true,
2749 printsilent('Processing PO file: '),printsilent(MainFile),nls,
2750 load_po_file(MainFile),
2751 (option(timeout(TO)) -> set_disprover_timeout(TO) ; reset_disprover_timeout),
2752 (option(disprover_options(L)) -> set_disprover_options(L) ; set_disprover_options([])),
2753 println_silent('Running ProB Disprover'),
2754 run_disprover_on_all_pos(Summary),
2755 print_disprover_stats,
2756 accumulate_infos(disprover,[po_files-1|Summary]),
2757 get_errors,
2758 (option(cli_check_disprover_result(Infos)) -> check_required_infos(Infos,Summary,load_po_file)
2759 ; option(strict_raise_error) -> check_required_infos([false-0,unknown-0,failure-0],Summary,load_po_file)
2760 % TO DO: provide way for user to specify expected info
2761 ; true),
2762 cli_process_options_for_alrady_fully_processed_file(MainFile),
2763 clear_loaded_machines.
2764 load_spec_file(EXT,MainFile,Already_FullyProcessed) :- (EXT='smt2' ; EXT= 'smt'), !,
2765 Already_FullyProcessed=true,
2766 printsilent('Processing SMT file: '),printsilent(MainFile),nls,
2767 (option(eval_repl([])) -> Opts = [repl] ; Opts=[]),
2768 start_probcli_timer(Timer),
2769 get_total_number_of_errors(TE1),
2770 smtlib2_file(MainFile,Opts),
2771 get_probcli_elapsed_walltime(Timer,WallTime),
2772 get_probcli_elapsed_runtime(Timer,RunTime),
2773 get_total_number_of_errors(TE2), Errs is TE2-TE1,
2774 get_smtlib2_result_infos(Result),
2775 accumulate_file_infos(MainFile,smtlib2_file,[file-1,runtime-RunTime,walltime-WallTime,errors-Errs|Result]).
2776 load_spec_file(EXT,F,false) :- load_spec_file(EXT,F).
2777
2778 % check if we should load a pl file using the disprover runner; if not we will load it in XTL mode
2779 load_pl_file_with_disprover(_MainFile) :- option(disprover_options(_)).
2780 load_pl_file_with_disprover(_MainFile) :- option(cli_check_disprover_result(_)).
2781 load_pl_file_with_disprover(_) :-
2782 \+ computeOperations_for_root_required,
2783 \+ (option(A), option_requires_all_properties(A)).
2784
2785
2786 load_cnf_file_with_options(File) :-
2787 get_b_load_options(Options),
2788 load_cnf_file(File,Options) .
2789
2790 get_b_load_options(Options) :-
2791 (option(release_java_parser) -> Options = [release_java_parser,use_fastread]
2792 ; option(fast_read_prob) -> Options = [use_fastread] % use fastread for large .prob files
2793 ; Options = []).
2794 % TO DO: automatically release if no option requires parsing and no more file uses it;
2795 % or print warning if release will affect other options like -repl (DEFINITIONS not available,...)
2796
2797 load_prob_file_with_options(File) :-
2798 get_b_load_options(Options),
2799 load_prob_file(File,Options).
2800 load_b_file_with_options(File) :-
2801 get_b_load_options(Options),
2802 load_b_file(File,Options).
2803
2804 % do not perform -execute_all if no parameters provided
2805 do_not_execute_automatically('pl').
2806 do_not_execute_automatically('smt2').
2807
2808 test_kodkod_and_exit(MaxResiduePreds,NOW) :-
2809 start_animation_without_computing,
2810 test_kodkod(MaxResiduePreds),
2811 halt_prob(NOW,0).
2812
2813 compare_kodkod_performance1(KPFile,Iterations,NOW) :-
2814 start_animation_without_computing,
2815 compare_kodkod_performance(KPFile,Iterations),
2816 halt_prob(NOW,0).
2817
2818 :- use_module(parsercall,[check_java_version/2,get_parser_version/1, ensure_console_parser_launched/0,
2819 connect_to_external_console_parser_on_port/1]).
2820 check_java_version :- check_java_version(V,Result),
2821 format('Result of checking Java version:~n ~w~n',[V]),
2822 (Result=compatible -> check_parser_version
2823 ; add_error(check_java_version,V)).
2824
2825 check_parser_version :- get_parser_version(PV),!,
2826 format(' ProB B Java Parser available in version: ~w.~n',[PV]). % will also launch parser
2827 check_parser_version :- add_error(check_parser_version,'Cannot start Java B Parser to obtain version number').
2828
2829 :- use_module(pathes_lib,[install_lib_component/2]).
2830 install_prob_lib(Lib,Opts) :- install_lib_component(Lib,Opts).
2831
2832 print_version(Kind) :- print_version(Kind,user_output).
2833
2834 print_version(short,Stream) :- print_short_version(Stream).
2835 print_version(cpp,Stream) :- print_cpp_version(Stream).
2836 print_version(java,Stream) :- print_java_version(Stream).
2837 print_version(full,Stream) :- print_full_version(Stream).
2838 print_version(full_verbose,Stream) :- print_full_version(Stream,verbose).
2839 print_version(host,Stream) :- print_host_version(Stream).
2840 print_version(lib,Stream) :- check_lib_contents(Stream,verbose).
2841
2842 :- use_module(version).
2843 print_short_version(Stream) :-
2844 version(V1,V2,V3,Suffix),revision(Rev),
2845 format(Stream,'VERSION ~p.~p.~p-~p (~p)~N',[V1,V2,V3,Suffix,Rev]).
2846
2847 :- use_module(parsercall,[get_parser_version/1, get_java_command_path/1, get_java_fullversion/1]).
2848 :- use_module(pathes_lib,[check_lib_contents/2]).
2849 print_full_version(Stream) :-
2850 (option_verbose ->
2851 (option_very_verbose
2852 -> print_full_version(Stream,very_verbose)
2853 ; print_full_version(Stream,verbose)
2854 )
2855 ; print_full_version(Stream,normal)
2856 ).
2857 print_full_version(Stream,Verbose) :-
2858 format(Stream,'ProB Command Line Interface~n',[]),
2859 print_probcli_version(Stream),
2860 ( Verbose=normal -> true
2861 ;
2862 current_prolog_flag(system_type,SysType),
2863 format(Stream,' Prolog System Type: ~p~N', [SysType]), % development or runtime
2864 safe_absolute_file_name(prob_home('.'),AppDir),
2865 format(Stream,' Application Path: ~p~N', [AppDir]),
2866 print_host_version(Stream),
2867 print_java_version(Stream),
2868 print_cpp_version(Stream),
2869 (Verbose = very_verbose
2870 -> print_prolog_flags(Stream), print_extensions(Stream), print_modules(Stream),
2871 check_lib_contents(Stream,verbose)
2872 ; check_lib_contents(Stream,silent)
2873 )
2874 ), print_compile_time_flags.
2875
2876 print_java_version(Stream) :-
2877 (get_java_command_path(JavaPath)
2878 -> format(Stream,' Java Runtime: ~p~N', [JavaPath]),
2879 (get_java_fullversion(JavaVersion)
2880 -> format(Stream,' Java Version: ~s~N', [JavaVersion])
2881 ; format(Stream,' Java Version: *** not available ***~N',[])
2882 ),
2883 (get_parser_version(ParserVersion)
2884 -> format(Stream,' Java Parser: ~p~N', [ParserVersion])
2885 ; format(Stream,' Java Parser: *** not available ***~N',[])
2886 )
2887 ; format(Stream,' Java Runtime: *** not available ***~N',[])
2888 ).
2889
2890 :- use_module(tools_platform, [host_platform/1, host_processor/1]).
2891 print_host_version(Stream) :-
2892 host_platform(HP),
2893 host_processor(Proc),
2894 (platform_is_64_bit -> Bits=64 ; Bits=32),
2895 format(Stream,' Host Processor: ~w (~w bits)~n Host Operating System: ~w~n',[Proc,Bits,HP]).
2896
2897
2898 print_probcli_version(Stream) :-
2899 full_version_str(VersStr),
2900 revision(Rev), lastchangeddate(LCD),
2901 current_prolog_flag(dialect, Dialect),
2902 (Dialect= swi, current_prolog_flag(version_git,PV) -> true
2903 ; current_prolog_flag(version,PV)
2904 ),
2905 format(Stream,' VERSION ~w (~p)~N ~p~N Prolog (~w): ~p~N',
2906 [VersStr,Rev,LCD,Dialect, PV]).
2907
2908
2909 :- use_module(compile_time_flags,[compile_time_flags/1, relevant_prolog_flags/1]).
2910 :- use_module(extension('regexp/regexp'),[get_cpp_version/1]).
2911 print_compile_time_flags :-
2912 compile_time_flags(list(Flags)),
2913 (Flags=[], \+ option_verbose -> true ; format(' COMPILE TIME FLAGS: ~w~N',[Flags])).
2914 print_prolog_flags(Stream) :-
2915 relevant_prolog_flags(Flags),
2916 format(Stream,' PROLOG FLAGS: ~w~N',[Flags]).
2917 print_extensions(Stream) :- findall(E,available_extension(E),Es),
2918 format(Stream,' EXTENSIONS: ~w~N',[Es]).
2919 print_cpp_version(Stream) :-
2920 available_extension(regexp_extension),!,
2921 get_cpp_version(V),
2922 format(Stream,' C++ Version for extensions: ~w~n',[V]).
2923 print_cpp_version(_).
2924 print_modules(Stream) :- findall(M,current_module(M),Ms), sort(Ms,SMs),
2925 format(Stream,' PROLOG MODULES: ~w~N',[SMs]).
2926
2927 print_logo :-
2928 % should be improved considerably; doesn't look very nice yet on macOS terminal due to line separation
2929 % â–„â–„â–„â–„ â–„â–„â–„â–„
2930 % â–ˆ â–ˆ â–ˆ â–ˆ
2931 % █▀▀▀ ▄ ▄▄▄ █▀▀▀▄
2932 % █ █ █▄█ █▄▄▄▀
2933 format_with_colour_nl(user_output,[blue],' ~s',[[9604,9604,9604,9604,32,32,32,32,32,32,32,9604,9604,9604,9604]]),
2934 format_with_colour_nl(user_output,[blue],' ~s',[[9608,32,32,32,9608,32,32,32,32,32,32,9608,32,32,32,9608]]),
2935 format_with_colour_nl(user_output,[blue],' ~s',[[9608,9600,9600,9600,32,9604,32,9604,9604,9604,32,9608,9600,9600,9600,9604]]),
2936 format_with_colour_nl(user_output,[blue],' ~s',[[9608,32,32,32,9608,32,32,9608,9604,9608,32,9608,9604,9604,9604,9600]]).
2937
2938 print_help :-
2939 print_version(full),
2940 print('Usage: probcli FILE [OPTIONS]'),nl,
2941 print(' OPTIONS are: '),nl,
2942 print(' -mc Nr model check; checking at most Nr states'),nl,
2943 print(' -model_check model check without limit on states explored'),nl,
2944 ( \+ option_verbose ->
2945 print(' -noXXX XXX=dead,inv,goal,ass (for model check)'),nl % -nodead, -noinv, -nogoal, -noass
2946 ;
2947 print(' -nodead do not look for deadlocks (for model check, animate, execute)'),nl,
2948 print(' -noinv do not look for invariant violations (for model check, animate, execute)'),nl,
2949 print(' -nogoal do not look for GOAL predicate (for model check, execute)'),nl,
2950 print(' -noass do not look for ASSERTION violations (for model check, execute)'),nl
2951 ),
2952 print(' -bf proceed breadth-first (default is mixed bf/df)'),nl,
2953 print(' -df proceed depth-first'),nl,
2954 print(' -mc_mode M M=hash,heuristic,random,dlk,breadth-first,depth-first,mixed,size'),nl, % dlk stands for out_degree_hash
2955 print(' -global_time_out N total timeout in ms for model/refinement checking and'),nl,
2956 print(' and execute steps and disprover checks'),nl,
2957 print(' -disable_timeout disable timeouts for operations, invariants,....'),nl, % speeds up mc
2958 print(' -t trace check (associated .trace file must exist)'),nl,
2959 print(' -trace_replay K F replay trace file F in format K (prolog,json,B)'),nl,
2960 print(' -init initialise specification'),nl,
2961 print(' -cbc OPNAME constraint-based invariant checking for an operation'),nl,
2962 print(' (you can also use OPNAME=all)'),nl,
2963 print(' -cbc_deadlock constraint-based deadlock checking'),nl,
2964 ( \+ option_verbose -> true ;
2965 print(' -cbc_deadlock_pred PRED as above but with additional predicate'),nl
2966 ),
2967 print(' -cbc_assertions constraint-based static assertion checking'),nl,
2968 print(' -cbc_refinement constraint-based static refinement checking'),nl,
2969 print(' -cbc_sequence S constraint-based search for sequence of operations'),nl,
2970 print(' -strict raise error if model-checking finds counter example'),nl,
2971 print(' or trace checking fails or any error state found'),nl,
2972 print(' -expcterr ERR expect error to occur (ERR=cbc,mc,ltl,...)'),nl,
2973 print(' -animate Nr random animation (max. Nr steps)'),nl,
2974 print(' -animate_all random animation until a deadlock is reached'),nl,
2975 print(' -animate_until_ltl P random animation until LTL property satisfied on trace'),nl,
2976 print(' -animate_until_ltl_state_property P until state satisfies LTL state property)'),nl,
2977 print(' -animate_stats provide feedback which operations are animated or executed'),nl,
2978 print(' -execute Nr execute specification (maximally Nr steps)'),nl,
2979 print(' in contrast to -animate: stops at first operation found, is deterministic,'),nl,
2980 print(' does not store intermediate states and does not use TIME_OUT preference'),nl,
2981 print(' -execute_all execute until a deadlock, direct loop, goal or error is reached'),nl,
2982 print(' -execute_monitor monitor performance of execute'),nl,
2983 print(' -his File write history to File'),nl,
2984 print(' -his_option O additional option when writing a history (show_init,show_states,json,trace_file)'),nl,
2985 print(' -sptxt File save constants and variable values of last discovered state to File'),nl,
2986 print(' -sstxt Dir save constants and variable values of all discovered states to files in Dir'),nl,
2987 print(' -cache Directory automatically save constants and operations to files to avoid recomputation'),nl,
2988 print(' -det_check check if animation steps are deterministic'),nl,
2989 print(' -det_constants only check if SETUP_CONSTANTS step is deterministic'),nl,
2990 ( \+ option_verbose -> true ;
2991 print(' -i interactive animation. Only for interactive sessions,'),nl,
2992 print(' the output can arbitrarily change in future versions. '),nl,
2993 print(' Do not build automatic tools using the interactive mode'),nl
2994 ),
2995 print(' -repl start interactive read-eval-loop'),nl,
2996 print(' -eval "E" evaluate expression or predicate'),nl,
2997 print(' -eval_file FILE evaluate expression or predicate from file'),nl,
2998 print(' -c print coverage statistics'),nl,
2999 print(' -cc Nr Nr print and check coverage statistics'),nl,
3000 print(' -vacuity_check look for vacuous implications in invariant'),nl,
3001 print(' -cbc_redundant_invariants Nr find redundant invariants, expecting Nr'),nl, % Nr exepcted
3002 print(' -statistics print memory and other statistics at the end'),nl,
3003 print(' -p PREF Val set preference to value'),nl,
3004 print(' -prefs FILE set preferences from Prolog file'),nl,
3005 print(' -pref_group G S set group G of preferences to predefined value set S'),nl,
3006 print(' -card GS Val set cardinality (aka scope) of B deferred set'),nl,
3007 print(' -goal "PRED" set GOAL predicate for model checker'),nl,
3008 print(' -check_goal check GOAL (after -mc, -t, or -animate)'),nl,
3009 print(' -scope "PRED" set scope predicate for model checker'),nl,
3010 print(' (only states satsifying this predicate will be examined)'),nl,
3011 print(' -property "PRED" virtually add predicate to PROPERTIES'),nl,
3012 print(' -s Port start socket server on given port'),nl,
3013 print(' -ss start socket server on port 9000'),nl,
3014 print(' -sf start socket server on some free port'),nl,
3015 print(' -l LogFile log activities in LogFile'),nl,
3016 print(' -ll log activities in /tmp/prob_cli_debug.log'),nl,
3017 print(' -logxml LogFile log activities in XML LogFile'),nl,
3018 print(' -logxml_write_ids P write variables/constants starting with P to XML LogFile'),nl,
3019 print(' -pp FILE pretty-print internal representation to file (or user_output)'), nl,
3020 print(' -ppf FILE like -pp, but force printing of all type infos'),nl,
3021 print(' -ppAB FILE like -ppf, but make output readable by Atelier-B'),nl,
3022 print(' -ppB FILE pretty-print Event-B model to file in valid B syntax'),nl,
3023 ( \+ option_verbose -> true ;
3024 print(' -ppi FILE pretty-print B model main file with indenatation'),nl,
3025 print(' -indent_b_file BFILE FILE pretty-print BFILE to FILE with indenatation'),nl,
3026 print(' -reformat_b_file BFILE FILE reformat BFILE to FILE (may insert newlines)'),nl,
3027 print(' -pp_pl_file PLFILE FILE indent Prolog PLFILE to FILE'),nl
3028 ),
3029 print(' -v verbose'),nl,
3030 ( \+ option_verbose -> true ;
3031 print(' -vv very verbose'),nl
3032 ),
3033 print(' -mc_with_tlc model check using TLC (see also TLC_WORKERS preference)'),nl,
3034 print(' -mc_with_lts_sym model check using LTSmin (symbolic)'),nl,
3035 print(' -mc_with_lts_seq model check using LTSmin (sequential)'),nl,
3036
3037 ( \+ option_verbose -> true ;
3038 print(' -ltsmin_option OPT set option for LTSmin (e.g, por)'),nl,
3039 print(' -ltsmin_ltl_output FILE set output file for LTSMin'),nl,
3040 print(' -symbolic_model_check ALGO ALGO is bmc, kinduction, ctigar, ic3'),nl,
3041 print(' -enabling_analysis_csv FILE perform operation enabling analysis'),nl,
3042 print(' -feasibility_analysis perform operation feasibility analysis'),nl,
3043 print(' -feasibility_analysis_csv FILE write feasibility result to file'),nl,
3044 print(' -read_write_matrix show read/write matrix for operations'),nl
3045 ),
3046 print(' -version print version information (-svers for short info)'),nl,
3047 print(' -check_java_version check that Java version compatible with ProB parser'),nl,
3048 print(' -assertions check ASSERTIONS'),nl,
3049 print(' -main_assertions check ASSERTIONS from main file only'),nl,
3050 print(' -properties check PROPERTIES'),nl,
3051 print(' -ccache Dir like -cache Dir but create directoy if it does not exist'),nl,
3052 print(' -show_cache show contents of cache'),nl,
3053 print(' -show_cache_verbose show contents of cache in more detail'),nl,
3054 print(' -cache_statistics show statistics about cache reuse'),nl,
3055 print(' -clear_cache clear the cache'),nl,
3056 print(' -clear_cache_for M clear the cache for machine M'),nl,
3057 print(' -show_inclusion_hierarchy useful to determine order for pre-populating cache for constants'),nl,
3058 print(' -ltlfile F check LTL formulas in file F'),nl,
3059 print(' -ltlassertions check LTL assertions (in DEFINITIONS)'),nl,
3060 print(' -ltllimit L explore at most L states when model-checking LTL or CTL'),nl,
3061 print(' -ltlformula \"F\" check the LTL formula F'),nl,
3062 print(' -ctlformula \"F\" check the CTL formula F'),nl,
3063 print(' -save File save state space for later refinement check'),nl,
3064 print(' -refchk File refinement check against previous saved state space'),nl,
3065 print(' -mcm_tests Depth MaxStates EndPredicate File'),nl,
3066 print(' generate test cases with maximum length Depth, explore'),nl,
3067 print(' maximally MaxStates, the last state satisfies EndPredicate'),nl,
3068 print(' and the test cases are written to File'),nl,
3069 print(' -mcm_cover Operation'),nl,
3070 print(' when generating MCM test cases, Operation should be covered'),nl,
3071 print(' -cbc_tests Depth EndPredicate File'),nl,
3072 print(' generate test cases by constraint solving with maximum'),nl,
3073 print(' length Depth, the last state satisfies EndPredicate'),nl,
3074 print(' and the test cases are written to File'),nl,
3075 print(' -cbc_cover Operation'),nl,
3076 print(' when generating CBC test cases, Operation should be covered'),nl,
3077 % print(' -cbc_cover_all try and cover all operations'),nl, % is now default if no cbc_cover provided
3078 print(' -test_description File'),nl,
3079 print(' read information for test generation from File'),nl,
3080 print(' -dot CMD File write a graph to a dot file, with CMD being one of:'),nl,
3081 (is_dot_command(Cmd),command_description(Cmd,_,Desc),
3082 format(' ~w : ~w~n',[Cmd,Desc]),fail
3083 ; true),
3084 print(' -dotexpr CMD Expr File write a graph for Expr to a dot file, with CMD:'),nl,
3085 (is_dot_command_for_expr(Cmd),command_description(Cmd,_,Desc),
3086 format(' ~w : ~w~n',[Cmd,Desc]),fail
3087 ; true),
3088 print(' -puml CMD File write a graph to a plantuml file, with CMD being one of:'),nl,
3089 (is_plantuml_command(Cmd),command_description(Cmd,_,Desc),
3090 format(' ~w : ~w~n',[Cmd,Desc]),fail
3091 ; true),
3092 print(' -pumlexpr CMD Expr File write a graph for Expr to a plantuml file, with CMD:'),nl,
3093 (is_plantuml_command_for_expr(Cmd),command_description(Cmd,_,Desc),
3094 format(' ~w : ~w~n',[Cmd,Desc]),fail
3095 ; true),
3096 print(' -csv CMD File write a table to a CSV file, with CMD being one of:'),nl,
3097 (is_table_command(Cmd),command_description(Cmd,_,Desc),
3098 format(' ~w : ~w~n',[Cmd,Desc]),fail
3099 ; true),
3100 print(' -csvexpr CMD Expr File write a table for Expr to a CSV file, with CMD:'),nl,
3101 (is_table_command_for_expr(Cmd),command_description(Cmd,_,Desc),
3102 format(' ~w : ~w~n',[Cmd,Desc]),fail
3103 ; true),
3104 print(' -dot_output Path generate dot files for false assertions/properties'),nl,
3105 print(' -dot_all also generate dot files for true assertions/properties'),nl,
3106 print(' -rule_report generate HTML validation report for rules machines (.rmch)'),nl,
3107 print(' -proof_export generate HTML proof export in sequent prover mode (for .probpo PO files)'),nl,
3108 print(' -csvhist E File evaluate expression over history and generate CSV file'),nl,
3109 print(' -visb JFile HFile use VisB JSON file JFILE to create HTML visualistion of history'),nl,
3110 print(' -visb_with_vars JFile HFile (similar, but also show variable values)'),nl,
3111 print(' -load_state File load state of ProB from a saved state space (generated by ProB Tcl/Tk or -save_state)'),nl,
3112 % For Eclipse Version only
3113 %% print(' -parsercp CP class path of the B Parser, this has to be a valid Java class path'),nl,
3114 %% print(' -cspm load CSP-M .csp file rather than B Machine .mch/.ref/.imp File'),nl,
3115 %% print(' -csp load CSP-M .pl file rather than B Machine File'),nl,
3116
3117 /* Options -cspref, -cspdeadlock, -cspdeterministic, and -csplivelock are deprecated, should be excluded in favor of -csp_assertion */
3118 print(' -cspref Spec [m= Impl File'),nl,
3119 print(' checks a refinement statement,'),nl,
3120 print(' where Spec and Impl are processes from File, and \'m\' the type of the refinement:'),nl,
3121 print(' \'T\' for traces, \'F\' for failures, or \'FD\' for failures-divergences.'),nl,
3122 print(' -cspdeadlock P m File'),nl,
3123 print(' checks a process for deadlock,'),nl,
3124 print(' where \'P\' is a process from File, and \'m\' the type of the model:'),nl,
3125 print(' \'F\' for failures and \'FD\' for failures-divergences.'),nl,
3126 print(' -cspdeterministic P m File'),nl,
3127 print(' checks a process for determinism,'),nl,
3128 print(' where \'P\' is a process from File, and \'m\' the type of the model:'),nl,
3129 print(' \'F\' for failures and \'FD\' for failures-divergences.'),nl,
3130 print(' -csplivelock P File'),nl,
3131 print(' checks a process for divergence,'),nl,
3132 print(' where \'P\' is a process from File.'),nl,
3133 /* Options -cspref, -cspdeadlock, -cspdeterministic, and -csplivelock are deprecated, should be excluded in favor of -csp_assertion */
3134
3135 print(' -csp_assertion \"A\" File'),nl,
3136 print(' checks the CSP assertion \'A\' on file \'File\''),nl,
3137 print(' -csp_eval "E" evaluate CSP-M expression.'),nl,
3138 print(' -csp_guide File CSP||B: Use the CSP File to control the B machine'),nl,
3139 print(' '),nl,
3140 ( \+ option_verbose -> true
3141 ;
3142 print(' -test_mode set random seed to the Prolog\'s current random state'),nl,
3143 print(' -rc runtime checking of types/pre-/post-conditions'),nl,
3144 print(' -state_trace File read a file of B predicates (one per line) and try find a matching trace.'),nl
3145
3146 ),
3147 print(' FILE extensions are: '),nl,
3148 print(' .mch for B abstract machines'),nl,
3149 print(' .ref for B refinement machines'),nl,
3150 print(' .imp for B implementation machines'),nl,
3151 print(' .sys for Event-B abstract machines'),nl,
3152 print(' .rmch for B Rule DSL machines'),nl,
3153 print(' .csp, .cspm for CSP-M files, same format as FDR'),nl,
3154 print(' .eventb for Event-B packages exported from Rodin ProB Plugin'),nl,
3155 print(' .tex, .zed for Z models'),nl,
3156 print(' .tla for TLA+ models'),nl,
3157 print(' .als for Alloy models'),nl,
3158 print(' .P for Prolog XTL models'),nl,
3159 ( option_verbose ->
3160 print(' Preferences PREF are: '),nl,
3161 print_eclipse_prefs
3162 ;
3163 print(' Use --help -v to print available preferences PREF'),nl
3164 ),
3165 print(' Use -no_color or set NO_COLOR environment variable to disable terminal colors'),nl,
3166 print(' More info at: https://prob.hhu.de/w/index.php/ProB_Cli'),nl,
3167 nl.
3168
3169
3170 set_argv(V) :-
3171 debug_println(20,set_argv(V)),
3172 external_functions:set_argv_from_atom(V).
3173
3174 :- use_module(b_global_sets, [set_user_defined_scope/2]).
3175 :- use_module(state_space_exploration_modes,[set_depth_breadth_first_mode/1, get_current_breadth_first_level/1]).
3176 :- use_module(tools_strings, [convert_cli_arg/2]).
3177 set_prefs :-
3178 if_option_set(cli_start_sym_mc_with_lts(_),
3179 preferences:set_preference(try_operation_reuse,false)), % LTSMIN does its own OPERATION_REUSE
3180 if_option_set(socket(_,_), % then we may need the event(.) transition_info for the Java API
3181 preferences:set_preference(store_event_transinfo,true)),
3182 option(set_prefs_from_file(File)),
3183 debug_println(20,load_preferences(File)),
3184 preferences:load_preferences(File),
3185 fail.
3186 set_prefs :-
3187 option(set_preference_group(P,V)),
3188 debug_println(20,set_preference_group(P,V)),
3189 set_preference_group(P,V),
3190 fail.
3191 % eclipse preference or 'normal preference'
3192 set_prefs :-
3193 ? option(set_pref(P,V)),
3194 set_pref(P,V),
3195 fail.
3196 set_prefs :- option(set_card(Set,V)),
3197 debug_println(20,set_card(Set,V)),
3198 convert_cli_arg(V,Value),
3199 set_user_defined_scope(Set,Value),
3200 fail.
3201 set_prefs :-
3202 ( option(breadth_first) -> set_depth_breadth_first_mode(breadth_first)
3203 ; option(depth_first) -> set_depth_breadth_first_mode(depth_first)
3204 ; option(depth_breadth_first_mode(M)) -> set_depth_breadth_first_mode(M)
3205 ; true
3206 ).
3207 :- use_module(tools_matching,[get_possible_preferences_matches_msg/2]).
3208 set_pref(P,V) :-
3209 debug_println(20,set_pref(P,V)),
3210 ? ( eclipse_preference(P,_)
3211 -> set_eclipse_preference(P,V)
3212 ; deprecated_eclipse_preference(P,_,_,_) -> set_eclipse_preference(P,V)
3213 ; obsolete_eclipse_preference(P) -> probcli_add_light_warning('Obsolete preference: ',P)
3214 ; obsolete_preference(P) -> probcli_add_light_warning('Obsolete preference: ',P)
3215 ; % might be a term if its a plugin preference
3216 atom_codes(P,Codes),
3217 append(Codes,".",Codes2), % to make term readable by read_from_codes
3218 read_from_codes(Codes2,Preference),
3219 (nonvar(Preference),preference_val_type(Preference,_)
3220 -> convert_cli_arg(V,Value),
3221 set_preference(Preference,Value)
3222 ; P=timeout ->
3223 add_error(probcli,'Unknown preference timeout. Either set preference TIME_OUT or use -gobal_time_out command','')
3224 ; get_possible_preferences_matches_msg(P,FuzzyMsg) ->
3225 ajoin(['Unknown preference: ',P,'. Did you mean:'],Msg),
3226 add_error(probcli,Msg,FuzzyMsg)
3227 ; get_possible_fuzzy_match_options(P,FuzzyMatches),
3228 % will only give perfect matches as P usually does not have the hyphen in front
3229 FuzzyMatches = [FMC|_] ->
3230 ajoin(['Unknown preference ', P, ' which looks like a probcli command! Did you want to call:'],Msg),
3231 add_error(probcli,Msg,FMC)
3232 ;
3233 add_error(probcli,'Unknown preference:',P)
3234 )
3235 ).
3236
3237 % add non severe warning:
3238 probcli_add_light_warning(Msg,Term) :- option(strict_raise_error),!,
3239 add_warning(probcli,Msg,Term). % does not write on user_error
3240 probcli_add_light_warning(Msg,Term) :- add_message(probcli,Msg,Term).
3241
3242 set_optional_errors :- % register optional/expected errors in the error_manager; avoid printing on stderr
3243 reset_optional_errors_or_warnings,
3244 (option(optional_error(Type)) ; option(expect_error(Type)) ; option(expect_error_pos(Type,_Line,_Col))),
3245 register_optional_error_or_warning(Type),
3246 fail.
3247 set_optional_errors.
3248
3249 % explicit state model checking, without LTL/CTL
3250 regular_safety_model_check_now(Nr,Runtime,WallTime,MCRes,NOW) :-
3251 statistics(runtime,[T1,_]),
3252 statistics(walltime,[W1,_]),
3253 (option(timeout(TO)) -> safe_time_out(regular_safety_model_check(Nr,Time,MCRes),TO,Res)
3254 ; regular_safety_model_check(Nr,Time,MCRes), Res=success
3255 ),
3256 statistics(runtime,[T2,_]),
3257 statistics(walltime,[W2,_]),
3258 WallTime is W2-W1,
3259 Runtime is T2-T1,
3260 (Res=time_out
3261 -> add_warning(model_check_incomplete,'Not all states examined due to -global_time_out option set by user: ',TO),
3262 writeln_log(timeout_occurred(NOW,model_check(Nr,Time,MCRes))),
3263 coverage(just_summary),
3264 MCRes=time_out
3265 ; true).
3266
3267 :- use_module(model_checker,[model_checking_is_incomplete/6]).
3268
3269 % TO DO: check for ignored states
3270 % code somewhat redundant also with model_check_incomplete below
3271 add_model_checking_warnings(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations) :-
3272 %print(check(model_checking_is_incomplete(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations,Msg,Term))),nl,
3273 model_checking_is_incomplete(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations,Msg,Term),
3274 add_warning(model_check_incomplete,Msg,Term),
3275 % TO DO: store for accumulate_infos
3276 fail.
3277 add_model_checking_warnings(_,_,_,_).
3278
3279 :- use_module(state_space,[current_state_id/1]).
3280 regular_safety_model_check(Nr,Time,ErrRes) :-
3281 statistics(runtime,[T1,_]),
3282 statistics(walltime,[W1,_]),
3283 catch(model_check_aux(Nr,T1,W1,Time,ErrRes), user_interrupt_signal, (
3284 statistics(walltime,[W2,_]), TotalWT is W2-W1,
3285 format_with_colour_nl(user_error,[red],'~nmodel checking interrupted after ~w ms by user (CTRL-C)',[TotalWT]),
3286 coverage(just_summary),
3287 perform_feedback_options_after_exception,
3288 throw(user_interrupt_signal)
3289 )).
3290
3291 % perform some important options for user feedback after CTRL-C interrupts model checking, execute, ...
3292 perform_feedback_options_after_exception :-
3293 (option(check_op_cache(_)) -> cli_check_op_cache([]) ; true),
3294 if_options_set(csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile),
3295 csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile)),
3296 (option(get_coverage_information(FCC)) -> pretty_print_coverage_information_to_file(FCC) ; true),
3297 (option(cli_print_statistics(X)), (cli_print_statistics(X) -> fail) ; true).
3298
3299 model_check_aux(Nr,T1,W1,Time,ErrRes) :-
3300 (option(no_deadlocks) -> FindDeadlocks=0 ; FindDeadlocks=1),
3301 (option(no_invariant_violations) -> FindInvViolations=0 ; FindInvViolations=1),
3302 (option(no_goal) -> FindGoal=0 ; FindGoal=1),
3303 (option(no_state_errors) -> FindStateErrors=0 ; FindStateErrors=1),
3304 (option(no_assertion_violations)
3305 -> FindAssViolations=0
3306 ; FindAssViolations=1
3307 ),
3308 get_preference(por,POR),
3309 StopAtFullCoverage=0,
3310 %STOPMCAFTER = 86400000, /* 86400000 = 1 day timeout */
3311 STOPMCAFTER = 1152921504606846975, /* equals 13,343,998,895 days */
3312 InspectExistingNodes = 1,
3313 write_xml_element_to_log(model_checking_options,[find_deadlocks/FindDeadlocks,
3314 find_invariant_violations/FindInvViolations, find_goal/FindGoal,
3315 find_assertion_violations/FindAssViolations,
3316 find_state_errors/FindStateErrors,
3317 partial_order_reduction/POR,
3318 inspect_existing_nodes/InspectExistingNodes]),
3319 (tcltk_interface:do_model_check(Nr,NodesAnalysed,STOPMCAFTER,ErrRes,
3320 FindDeadlocks,FindInvViolations,FindGoal,
3321 FindAssViolations,FindStateErrors,StopAtFullCoverage,POR, InspectExistingNodes)
3322 -> (statistics(runtime,[T2,_]), statistics(walltime,[W2,_]),
3323 Time1 is T2-T1, WTime is W2-W1,
3324 (model_checker: expired_static_analysis_time(AnalysisTime) ->
3325 Time is Time1 - AnalysisTime
3326 ; Time = Time1, AnalysisTime=0),
3327 formatsilent('Model checking time: ~w ms (~w ms walltime)~n',[Time,WTime]),
3328 formatsilent('States analysed: ~w~n',[NodesAnalysed]),
3329 get_state_space_stats(_,NrTransitions,_,_),
3330 printsilent('Transitions fired: '),printsilent(NrTransitions),nls,
3331 (get_current_breadth_first_level(Level)
3332 -> formatsilent('Breadth-first levels: ~w~n',[Level]) % is this the equivalent of TLC's diameter?
3333 ; true),
3334 write_xml_element_to_log(model_checking_statistics,
3335 [result/ErrRes,runtime/Time,walltime/WTime,
3336 states/NodesAnalysed,transitions/NrTransitions,staticAnalysisTime/AnalysisTime]),
3337 (ErrRes = no
3338 -> print('No counter example Found, not all states visited'),nl,
3339 add_warning(model_check_incomplete,'Not all states examined due to limit set by user: ',Nr)
3340 ; ErrRes=all
3341 -> (tcltk_find_max_reached_node
3342 -> (not_interesting(_)
3343 -> print('No counter example found. However, not all transitions were computed (and some states not satisfying SCOPE predicate were ignored) !')
3344 ; print('No counter example found. However, not all transitions were computed !')
3345 )
3346 ; not_interesting(_)
3347 -> print_green('No counter example found. ALL states (satisfying SCOPE predicate) visited.')
3348 % b_get_machine_searchscope(Scope)
3349 ; print_green('No counter example found. ALL states visited.')
3350 ),nl,
3351 add_model_checking_warnings(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations)
3352 ; % ErrRes is not no or all
3353 print_red('*** COUNTER EXAMPLE FOUND ***'),nl,
3354 debug_println(20,ErrRes),nl,
3355 tcltk_interface:translate_error_for_tclk(ErrRes,TclTkRes),
3356 print(TclTkRes),nl,
3357 print_history_as_counter_example(true),
3358 error_occurred(TclTkRes)
3359 ),nl
3360 )
3361 ; % do_model_check failed
3362 statistics(runtime,[T2,_]), Time1 is T2-T1,
3363 (model_checker: expired_static_analysis_time(AnalysisTime) -> Time is Time1 - AnalysisTime
3364 ; Time = Time1),
3365 printsilent('Model checking time: '), printsilent(Time), printsilent(' ms'),nls,
3366 print_error('*** Model checking FAILED '),nl,
3367 ErrRes=fail,
3368 definite_error_occurred
3369 ).
3370
3371 print_history_as_counter_example(CheckInv) :-
3372 (option(silent) -> true
3373 ; option(no_counter_examples) -> true % -nocounter
3374 ; cli_print_history,
3375 (silent_mode(off), CheckInv=true,
3376 current_state_id(ID),invariant_violated(ID)
3377 -> b_interpreter:analyse_invariant_for_state(ID)
3378 ; true)
3379 ).
3380
3381 cli_print_history :-
3382 tcltk_interface:tcltk_get_history(list(Hist)),
3383 length(Hist,Len),
3384 format('*** TRACE (length=~w):~n',[Len]),
3385 reverse(Hist,Trace),
3386 print_nr_list(Trace).
3387
3388 % perform all cbc checks on current machine
3389 cbc_check(_NOW) :-
3390 option(cbc_deadlock_check(DeadlockGoalPred)),
3391 cbc_deadlock_check(DeadlockGoalPred),
3392 fail.
3393 cbc_check(_NOW) :-
3394 option(constraint_based_check(OpName)),
3395 constraint_based_check(OpName),
3396 fail.
3397 cbc_check(_NOW) :- option(cbc_assertions(AllowEnumWarning,Options)),
3398 cbc_assertions(AllowEnumWarning,Options),
3399 fail.
3400 %cbc_check(NOW) :-
3401 % option(cbc_pred(TargetPredString)),
3402 % check_loaded(cbc_pred),
3403 % print('% Starting Constraint-Based Check for Predicate: '), print(TargetPredString),nl,
3404 % b_set_up_valid_state_with_pred(NormalisedState,Pred) TO DO: add this feature
3405 cbc_check(_NOW) :- option(cbc_sequence(Sequence,TargetPredString,Findall)),
3406 cbc_sequence(Sequence,TargetPredString,Findall),
3407 fail.
3408 cbc_check(_NOW) :- option(cbc_refinement),
3409 cbc_refinement,
3410 fail.
3411 cbc_check(_NOW) :- option(cbc_redundant_invariants(NrExpected)),
3412 cbc_redundant_invariants(NrExpected),
3413 fail.
3414 cbc_check(_).
3415
3416 :- use_module(tcltk_interface,[tcltk_constraint_based_check/2,
3417 tcltk_constraint_based_check_with_timeout/2,
3418 tcltk_constraint_find_deadlock_state_with_goal/3,
3419 tcltk_cbc_find_trace/4,
3420 tcltk_cbc_refinement_check/2]).
3421 :- use_module(probsrc(bmachine),[b_is_operation_name/1]).
3422
3423 constraint_based_check(all) :-
3424 check_loaded_not_empty(constraint_based_check),
3425 print_repl_prompt_s('% Starting Constraint-Based Check for all Operations: '),nl,
3426 start_xml_feature(cbc_operation_check,all_operations,true,FINFO),
3427 (tcltk_constraint_based_check(list(Result),ErrorsWereFound)
3428 -> print('% Constraint-Based Check Result: '),nl,
3429 print(Result),nl,
3430 write_result_to_file(Result),
3431 (ErrorsWereFound=true
3432 -> print_red('*** CONSTRAINT-BASED CHECK FOUND ERRORS ***'),nl, error_occurred(cbc)
3433 ; (ErrorsWereFound=false -> print_green('NO ERRORS FOUND'),nl)
3434 ; print_red('*** TIMEOUT OCCURRED ***'),nl,error_occurred(cbc)
3435 )
3436 ; write_result_to_file(cbc_check_failed), Result=internal_error, ErrorsWereFound=false,
3437 add_internal_error('ConstraintBasedCheck unexpectedly failed. ',cbc_check(all)),definite_error_occurred
3438 ),nl,
3439 write_cbc_check_result(Result,ErrorsWereFound),
3440 stop_xml_feature(cbc_operation_check,FINFO).
3441 constraint_based_check(OpName) :- OpName\=all, % -cbc OpName
3442 check_loaded_not_empty(constraint_based_check),
3443 print_repl_prompt_s('% Starting Constraint-Based Check for Operation: '), print(OpName),nl,
3444 start_xml_feature(cbc_operation_check,operation,OpName,FINFO),
3445 (tcltk_constraint_based_check_with_timeout(OpName,Result)
3446 -> print('% Constraint-Based Check Result: '),nl, print(Result),nl,
3447 write_result_to_file(Result),
3448 (Result=time_out
3449 -> print_red('*** TIMEOUT OCCURRED ***'),nl, error_occurred(cbc)
3450 ; (Result=ok -> print_green('NO ERRORS FOUND'),nl)
3451 ; print_red('*** CONSTRAINT-BASED CHECK FOUND ERRORS ***'),nl,error_occurred(cbc) )
3452 ; write_result_to_file(constraint_based_check_failed), Result=internal_error,
3453 add_error(probcli,'ConstraintBasedCheck unexpectedly failed'),
3454 (b_is_operation_name(OpName) -> true
3455 ; add_error(probcli,'Unknown Operation Name: ',OpName)),
3456 definite_error_occurred
3457 ),nl,
3458 write_cbc_check_result(Result),
3459 stop_xml_feature(cbc_operation_check,FINFO).
3460
3461 write_cbc_check_result(Result) :-
3462 functor(Result,F,_), % example result: no_counterexample_exists(Ids,Prd,Other)
3463 write_xml_element_to_log(cbc_check_result,[result/F]).
3464 write_cbc_check_result(Result,ErrorsWereFound) :- functor(Result,F,_),
3465 write_xml_element_to_log(cbc_check_result,[result/F,errors_were_found/ErrorsWereFound]).
3466
3467 cbc_deadlock_check(DeadlockGoalPred) :-
3468 print_repl_prompt_s('% Starting Constraint-Based DEADLOCK check '),nl,
3469 start_xml_feature(cbc_deadlock_check,FINFO),
3470 (tcltk_constraint_find_deadlock_state_with_goal(DeadlockGoalPred,false,Res)
3471 -> write_result_to_file(Res),
3472 (Res=time_out ->
3473 print_red('*** TIME_OUT occurred ***'),nl,
3474 error_occurred(cbc_deadlock_check_time_out)
3475 ; print_red('*** DEADLOCK state found ***'),nl,
3476 error_occurred(cbc_deadlock_check),
3477 (silent_mode(on) -> true
3478 ; print('*** STATE = '),nl,
3479 current_b_expression(DBState), translate:print_bstate(DBState),nl,
3480 print('*** END DEADLOCKING STATE '),nl
3481 )
3482 )
3483 ; write_result_to_file(no_deadlock_found), Res=no_deadlock_found,
3484 print_green('No DEADLOCK state found'),nl
3485 ),
3486 write_cbc_check_result(Res),
3487 stop_xml_feature(cbc_deadlock_check,FINFO).
3488 cbc_assertions(AllowEnumWarning,Options) :-
3489 findall(OPT,option(cbc_option(OPT)),FullOptions,Options),
3490 check_loaded_not_empty(cbc_assertions),
3491 print_repl_prompt_s('% Starting Constraint-Based static ASSERTIONS check '),nl,
3492 start_xml_feature(cbc_assertion_check,allow_enumeration_warning,AllowEnumWarning,FINFO),
3493 write_prolog_term_as_xml_to_log(options(Options)),
3494 (cbc_constraint_find_static_assertion_violation(Res,FullOptions)
3495 -> process_cbc_assertion_result(Res,AllowEnumWarning)
3496 ; write_result_to_file(cbc_assertions_failed), Res=internal_error,
3497 print_red('CBC Check failed'),nl,
3498 error_occurred(cbc_assertions_failure)
3499 ),
3500 write_cbc_check_result(Res),
3501 stop_xml_feature(cbc_assertion_check,FINFO).
3502 cbc_sequence(Sequence,TargetPredString,Findall) :-
3503 check_loaded_not_empty(cbc_sequence),
3504 print_repl_prompt_s('% Starting Constraint-Based Check for Sequence: '), print_repl_prompt_s(Sequence),
3505 start_xml_feature(cbc_sequence_check,sequence,Sequence,FINFO),
3506 (TargetPredString='' -> true ; print(' with target: '), print(TargetPredString)),
3507 nl,
3508 write_xml_element_to_log(options,[target_predicate/TargetPredString]),
3509 (tcltk_cbc_find_trace(Sequence,TargetPredString,Findall,Res)
3510 -> (Res=ok -> print_green('Sequence found and executed'),nl
3511 ; Res=time_out -> error_occurred(cbc_sequence_time_out)
3512 ; Res=no_solution_found -> print_red('*** NO SOLUTION FOUND '),error_occurred(cbc_sequence_no_solution_found)
3513 ; Res=nr_cbc_sols(NrSols) -> print('*** # SOLUTIONS FOUND: '),print(NrSols),nl
3514 ; print_red('*** Unknown result: '), print(Res),nl,
3515 error_occurred(cbc_sequence)
3516 )
3517 ; print('*** Internal error: Check failed '), error_occurred(cbc_sequence), Res=internal_error
3518 ),
3519 write_cbc_check_result(Res),
3520 stop_xml_feature(cbc_sequence_check,FINFO).
3521 cbc_refinement :-
3522 check_loaded_not_empty(cbc_refinement),
3523 print_repl_prompt_s('% Starting Constraint-Based static refinement check '),nl,
3524 start_xml_feature(cbc_refinement_check,FINFO),
3525 tcltk_cbc_refinement_check(list(Result),ErrorsWereFound),
3526 print('% Constraint-Based Refinement Check Result: '),nl,print(Result),nl,
3527 (ErrorsWereFound = time_out -> print_red('*** TIME_OUT occurred ***'),nl,error_occurred(cbc_refinement_time_out) ;
3528 ErrorsWereFound = true -> print_red('*** Refinement Violation found ***'),nl,error_occurred(cbc_refinement) ;
3529 print_green('No static Refinement Violation found'),nl
3530 ),
3531 write_xml_element_to_log(cbc_check_result,[errors_were_found/ErrorsWereFound]),
3532 stop_xml_feature(cbc_refinement_check,FINFO).
3533 :- use_module(b_state_model_check,[cbc_find_redundant_invariants/2]).
3534 cbc_redundant_invariants(NrExpected) :-
3535 check_loaded_not_empty(cbc_redundant_invariants),
3536 print_repl_prompt_s('% Starting Constraint-Based invariant redundancy check'),nl,
3537 start_xml_feature(cbc_redundant_invariants,FINFO),
3538 cbc_find_redundant_invariants(Res,TimeoutOccured),
3539 length(Res,NrInvs),
3540 (Res = [] -> print_green('No redundant invariants found'),nl
3541 ; format('*** REDUNDANT INVARIANTS (~w) ***~n',[NrInvs]),
3542 prnt(1,Res), nl
3543 ),
3544 (NrExpected = NrInvs -> true
3545 ; format_with_colour_nl(user_error,[red],'*** Expected ~w redundant invariants (instead of ~w).',[NrExpected,NrInvs]),
3546 error_occurred(cbc_redundant_invariants)),
3547 write_xml_element_to_log(cbc_redundant_invariants,[redundant_invariants/NrInvs, timeout_occured/TimeoutOccured]),
3548 stop_xml_feature(cbc_redundant_invariants,FINFO).
3549
3550 prnt(_,[]).
3551 prnt(N,[H|T]) :- format(' ~w : ~w~n',[N,H]), N1 is N+1, prnt(N1,T).
3552
3553 :- use_module(solver_interface,[predicate_uses_unfixed_deferred_set/2, unfixed_typed_id_in_list/3]).
3554 process_cbc_assertion_result(time_out,_) :- !,
3555 write_result_to_file(no_counterexample_found('"TIME_OUT"')),
3556 print_red('*** TIME_OUT occurred ***'),nl,
3557 error_occurred(cbc_assertions_time_out).
3558 process_cbc_assertion_result(no_counterexample_exists(Constants,TotPredicate,OtherInfo),AllowEnumWarning) :- !,
3559 print_green('No counter-example to ASSERTION exists '),(OtherInfo=[] -> true ; print(OtherInfo)),nl,
3560 (unfixed_typed_id_in_list(TID,CType,Constants) % TO DO: look only at component
3561 -> write_deferred_set_used(AllowEnumWarning),
3562 get_texpr_id(TID,CID),pretty_type(CType,CTypeS),
3563 format('Warning: Some constants use deferred sets (e.g., ~w:~w) which have only been checked for a single cardinality!~n',[CID,CTypeS])
3564 ; predicate_uses_unfixed_deferred_set(TotPredicate,CType)
3565 -> write_deferred_set_used(AllowEnumWarning),pretty_type(CType,CTypeS),
3566 format('Warning: Some quantified variables use deferred sets (e.g., ~w) which have only been checked for a single cardinality!~n',[CTypeS]) % happens for tests 1173, 1174
3567 ; write_result_to_file(no_counterexample_exists)
3568 %,print('Computing unsat core: '),nl,unsat_cores:unsat_core(TotPredicate,Core),print('CORE: '),translate:print_bexpr(Core),nl
3569 ). % WE HAVE A PROOF
3570 process_cbc_assertion_result(no_counterexample_found,AllowEnumWarning) :- !,
3571 write_result_to_file(no_counterexample_found('"Enumeration Warning"')),
3572 print('No counter-example for ASSERTION found (*enumeration warning occured*)'),nl,
3573 (AllowEnumWarning=true -> true ; error_occurred(cbc_assertions_enumeration_warning)).
3574 process_cbc_assertion_result(counterexample_found,_) :- !,
3575 write_result_to_file(counterexample_found),
3576 print_red('*** Counter-example for ASSERTION found ***'),nl,
3577 error_occurred(cbc_assertions),
3578 (silent_mode(on) -> true
3579 ; print('*** STATE = '),nl,
3580 current_b_expression(DBState), translate:print_bstate(DBState),nl,
3581 print('*** END ASSERTION counter-example STATE '),nl
3582 ),
3583 (get_dot_file('cbc_assertions',DFile) -> generate_dot_from_assertions(DFile) ; true).
3584 process_cbc_assertion_result(Res,A) :-
3585 write_result_to_file(Res),
3586 add_internal_error('Unknown: ',process_cbc_assertion_result(Res,A)).
3587
3588
3589 write_deferred_set_used(AllowEnumWarning) :-
3590 write_result_to_file(no_counterexample_found('"Deferred Sets Used"')),
3591 (AllowEnumWarning=true -> true ; error_occurred(cbc_assertions_enumeration_warning)).
3592
3593 :- use_module(tools_io,[safe_open_file/4]).
3594 write_result_to_file(Result) :- option(cbc_result_file(FILE)),
3595 safe_open_file(FILE,write,Stream,[encoding(utf8)]),
3596 !,
3597 write(Stream,Result),
3598 close(Stream).
3599 write_result_to_file(_).
3600
3601
3602
3603 if_option_set(Option,Call) :-
3604 if_option_set(Option,Call,true).
3605 if_option_set(Option,Then,Else) :-
3606 (option(Option) -> call_for_option(Then) ; call_for_option(Else)).
3607 ifm_option_set(Option,Call) :-
3608 ifm_option_set(Option,Call,true).
3609 ifm_option_set(Option,Then,Else) :- % can perform multiple options
3610 findall(Then,option(Option),As),
3611 (As=[] -> call_for_option(Else) ; perform(As)).
3612 perform([]).
3613 perform([A|T]) :-
3614 call_for_option(A),
3615 perform(T).
3616 call_for_option(Call) :- (call(Call) -> true ; add_internal_error('probcli option call failed: ',Call)).
3617 if_option_set_loaded(Option,Action,Call) :-
3618 ( option(Option),check_loaded_not_empty(Action) ->
3619 call_for_option(Call)
3620 ; true).
3621 ifm_option_set_loaded(Option,Action,Call) :- % can perform multiple options
3622 findall(Call,(option(Option),check_loaded_not_empty(Action)),As),
3623 perform(As).
3624
3625
3626
3627 if_options_set(Option,Call) :- % allow multiple solutions for Option
3628 option(Option),call(Call),fail.
3629 if_options_set(_,_).
3630
3631 print_options :- print('CLI OPTIONS: '),nl,
3632 option(Option), print(Option), nl, fail.
3633 print_options :- nl.
3634
3635 :- use_module(cbcsrc(enabling_analysis),[infeasible_operation_cache/1]).
3636 :- use_module(cbcsrc(sap),[explore_and_generate_testcases/7,cbc_gen_test_cases_from_string/5, tcl_get_stored_test_cases/1]).
3637 :- use_module(translate,[print_bexpr/1]).
3638
3639 mcm_test_case_generation(ADepth,AMaxStates,ATarget,Output) :-
3640 arg_is_number(ADepth,MaxDepth),
3641 arg_is_number(AMaxStates,MaxStates),
3642 bmachine:b_parse_machine_predicate(ATarget,Target),!,
3643 get_comma_or_space_separated_options(mcm_cover,Events),
3644 (option(silent) -> true
3645 ; print('mcm test case generation, maximum search depth: '),print(MaxDepth),nl,
3646 print('mcm test case generation, maximum number of states: '),print(MaxStates),nl,
3647 print('mcm test case generation, target state predicate: '),print_bexpr(Target),nl,
3648 print('mcm test case generation, output file: '),print(Output),nl,
3649 print('mcm test case generation, events to cover: '),print_list(Events),nl
3650 ),
3651 explore_and_generate_testcases(Events,Target,MaxDepth,MaxStates,Output,NumTests,Uncovered),
3652 printsilent('mcm test case generation, generated test cases: '),printsilent(NumTests),nls,
3653 print_uncovered('mcm test case generation, ',Uncovered).
3654 mcm_test_case_generation(_ADepth,_AMaxStates,_ATarget,_Output) :-
3655 print_error('MCM Test Case Generation failed'),
3656 error_occurred(mcm_tests).
3657
3658 cbc_test_case_generation(ADepth,TargetString,Output) :-
3659 arg_is_number(ADepth,MaxDepth),
3660 ( option(cbc_cover_all) -> Events=all
3661 ; (get_comma_or_space_separated_options(cbc_cover,Events), Events \= []) -> true
3662 ; Events=all ),
3663 (\+ option(cbc_cover_final) -> FEvents = Events
3664 ; Events=all -> FEvents=all,
3665 add_error(cbc_cover_final,'Option cbc_cover_final not compatible with trying to cover all events')
3666 ; FEvents = final(Events),
3667 println_silent('constraint based test case generation, target events considered final')),
3668 printsilent('constraint based test case generation, maximum search depth: '),printsilent(MaxDepth),nls,
3669 printsilent('constraint based test case generation, target state predicate: '),printsilent(TargetString),nls,
3670 printsilent('constraint based test case generation, output file: '),printsilent(Output),nls,
3671 (TargetString = '#not_invariant' -> BMC=invariant_violation
3672 ; TargetString = '#deadlock' -> BMC=deadlock
3673 ; BMC = 'none'),
3674 (BMC \= 'none' ->
3675 printsilent('constraint based test case generation, performing bounded model checking'),nls
3676 ; option(silent) -> true
3677 ; print('constraint based test case generation, events to cover: '),print_list(Events),nl),
3678 cbc_gen_test_cases_from_string(FEvents,TargetString,MaxDepth,Output,Uncovered),
3679 !,
3680 format('constraint based test case generation finished~n',[]),
3681 (BMC \= 'none'
3682 -> tcl_get_stored_test_cases(list(Tests)), %print(tests(Tests)),nl,
3683 (Tests=[] -> print_green('No counterexample found'),nl
3684 ; Tests = [_|_], BMC=deadlock -> add_error(deadlock,'Deadlock found by bmc')
3685 ; Tests = [_|_] -> add_error(invariant_violation,'Invariant violation found by bmc')
3686 ; add_internal_error('Unexpected bmc result: ',Tests)
3687 )
3688 ; Uncovered=[_|_],option(strict_raise_error)
3689 -> add_error(cbc_tests,'Uncovered events: ',Uncovered)
3690 ; print_uncovered('constraint based test case generation, ',Uncovered)
3691 ).
3692 cbc_test_case_generation(_ADepth,_ATarget,_Output) :-
3693 print_error('Constraint based test case generation failed!'),
3694 error_occurred(cbc_tests).
3695
3696 print_uncovered(Msg,Uncovered) :-
3697 include(enabling_analysis:infeasible_operation_cache,Uncovered,Infeasible),
3698 (Infeasible=[]
3699 -> format('~wuncovered events: ',[Msg]),print_list(Uncovered),nl
3700 ; format('~winfeasible uncovered events: ',[Msg]),print_list(Infeasible),nl,
3701 exclude(enabling_analysis:infeasible_operation_cache,Uncovered,Feasible),
3702 format('~wuncovered events: ',[Msg]),print_list(Feasible),nl
3703 ).
3704
3705 print_list(all) :- print('** all **').
3706 print_list(list(L)) :- print_list(L). % possibly not used
3707 print_list([]) :- print('** none **').
3708 print_list([H|T]) :- length([H|T],Len), format('(~w) ',[Len]),
3709 print(H),print(' '),print_list2(T).
3710 print_list2([]).
3711 print_list2([H|T]) :- print(H),print(' '),print_list2(T).
3712
3713 get_comma_or_space_separated_options(Option,Selection) :-
3714 functor(O,Option,1),
3715 findall(E, (option(O),arg(1,O,CommaSep),
3716 split_by_seperator(CommaSep,Es),
3717 member(E,Es)),
3718 Selection).
3719
3720 split_by_seperator(NonAtomic,Res) :- \+ atomic(NonAtomic),!, Res=[NonAtomic].
3721 split_by_seperator(String,Strings) :-
3722 atom_chars(String,Chars),
3723 split_by_seperator2(Chars,Strings).
3724 split_by_seperator2(Chars,Result) :-
3725 append(AChars,[X|B],Chars),seperator(X),!,
3726 (AChars=[] -> Result=Rest ; atom_chars(A,AChars), Result=[A|Rest]),
3727 split_by_seperator2(B,Rest).
3728 split_by_seperator2(Chars,[String]) :- atom_chars(String,Chars).
3729
3730 seperator(',').
3731 seperator(' ').
3732 seperator(';').
3733
3734 ltl_check_assertions :-
3735 (option(ltl_limit(Limit)) -> true; Limit= -1), % -1 means no limit
3736 formatsilent('Model checking LTL assertions~n',[]),
3737 ltl_check_assertions(Limit,Outcome),!,
3738 ( Outcome = pass -> print_green('LTL check passed'),nl
3739 ; Outcome = fail -> print_red('*** LTL check failed'),nl,error_occurred(ltl)
3740 ; Outcome = no_tests -> print_red('*** No LTL assertions found, test failed'),nl,definite_error_occurred
3741 ; print_red('*** An error occurred in the LTL assertion test'),nl,
3742 definite_error_occurred).
3743 ltl_check_assertions :-
3744 add_internal_error('Call failed:',ltl_check_assertions),definite_error_occurred.
3745
3746 :- use_module(probltlsrc(ltl),[parse_ltlfile/2]).
3747 ltl_check_file(Filename) :-
3748 (option(ltl_limit(Limit)) -> true; Limit= -1), % -1 means no limit
3749 ajoin(['Model checking LTL assertions from file ',Filename],Msg),
3750 print_repl_prompt_s(Msg),nl,
3751 ( parse_ltlfile(Filename, Formulas)
3752 -> ltl_check_formulas(Formulas,Limit)
3753 ; print_red('An error occurred while parsing the LTL file.\n'),
3754 definite_error_occurred
3755 ).
3756
3757 :- use_module(probltlsrc(ltl),[ltl_model_check2/4]).
3758 ltl_check_formulas([],_) :-
3759 print_green('All LTL formulas checked.\n').
3760 ltl_check_formulas([formula(Name,F)|Rest],Limit) :-
3761 print('Checking formula '),print(Name),print(':\n'),
3762 ltl_model_check2(F,Limit,init,Status),
3763 ( Status == no ->
3764 print_red('Counter-example found for formula \"'),print_red(Name),
3765 print_red('\", saving trace file.\n'),
3766 ajoin(['ltlce_', Name, '.trace'], Tracefile),
3767 tcltk_save_history_as_trace_file(prolog,Tracefile),
3768 add_error(ltl_counterexample,'Counter-example was found')
3769 ; Status == ok ->
3770 ltl_check_formulas(Rest,Limit)
3771 ; Status == incomplete ->
3772 ajoin(['Model was not completly model-checked, aborted after ',Limit,' new states'],
3773 Msg),
3774 add_error(ltl,Msg)
3775 ;
3776 ajoin(['Model checker returns unexpected result (',Status,')'],Msg),
3777 add_error(ltl,Msg)).
3778
3779 % Mode = init or specific_node(ID) or starthere
3780 cli_ltl_model_check(Formula,Mode,ExpectedStatus,Status) :-
3781 (option(ltl_limit(Max)) -> true; Max = -1), % -1 means no limit
3782 start_xml_feature(ltl_model_check,formula,Formula,FINFO),
3783 ltl_model_check(Formula,Max,Mode,Status),
3784 write_xml_element_to_log(model_check_result,[status/Status,expected_status/ExpectedStatus,(mode)/Mode]),
3785 check_status(Status,ExpectedStatus,Formula,ltl),
3786 stop_xml_feature(ltl_model_check,FINFO).
3787
3788 % Mode = init or specific_node(ID) or starthere
3789 cli_ctl_model_check(Formula,Mode,ExpectedStatus,Status) :-
3790 (option(ltl_limit(Max)) -> true; Max = -1), % -1 means no limit
3791 start_xml_feature(ctl_model_check,formula,Formula,FINFO),
3792 ctl_model_check(Formula,Max,Mode,Status),
3793 write_xml_element_to_log(model_check_result,[status/Status,expected_status/ExpectedStatus,(mode)/Mode]),
3794 check_status(Status,ExpectedStatus,Formula,ctl),
3795 stop_xml_feature(ctl_model_check,FINFO).
3796
3797 :- use_module(extension('markov/dtmc_model_checking.pl')).
3798 cli_pctl_model_check(Formula,Mode,ExpectedStatus,Status) :-
3799 % use_module(extension('markov/dtmc_model_checking.pl')),
3800 (option(ltl_limit(Max)) -> true; Max = -1), % -1 means no limit
3801 dtmc_model_checking:pctl_model_check(Formula,Max,Mode,Status),
3802 check_status(Status,ExpectedStatus,Formula,pctl).
3803
3804 check_expected(St,Exp,Mode) :-
3805 (St=Exp -> true
3806 ; ajoin(['Unexpected ',Mode,' model checking result ',St,', expected: '],Msg),
3807 add_error(Mode,Msg,Exp)).
3808
3809 check_status(ok,Expected,Formula,ltl) :- !, % TO DO: make uniform ? CTL returns true; LTL returns ok
3810 format_with_colour_nl(user_output,[green],'LTL Formula TRUE.~nNo counter example found for ~w.',[Formula]),
3811 flush_output(user_output),
3812 check_expected(true,Expected,ltl).
3813 check_status(true,Expected,Formula,ctl) :- !,
3814 format_with_colour_nl(user_output,[green],'CTL Formula TRUE.~nNo counter example found for ~w.',[Formula]),
3815 flush_output(user_output),
3816 check_expected(true,Expected,ctl).
3817 check_status(true,Expected,Formula,pctl) :- !,
3818 format_with_colour_nl(user_output,[green],'PCTL Formula TRUE: ~w~n',[Formula]),
3819 flush_output(user_output),
3820 check_expected(true,Expected,pctl).
3821 check_status(solution(Bindings),Expected,Formula,pctl) :- !,
3822 format_with_colour_nl(user_output,[green],'PCTL Formula TRUE: ~w',[Formula]),
3823 format_with_colour_nl(user_output,[green],'PCTL Solutions: ~w~n',[Bindings]),
3824 flush_output(user_output),
3825 check_expected(true,Expected,pctl).
3826 check_status(incomplete,Expected,Formula,LTLorCTL) :- !,
3827 incomplete_warning(LTLorCTL,Warning),
3828 add_warning(Warning, 'Warning: Model Check incomplete for: ', Formula),nl,
3829 format('No counter example found so far for ~w.~n',[Formula]),
3830 check_expected(incomplete,Expected,LTLorCTL).
3831 check_status(NO,Expected,Formula,LTLorCTL) :- (NO=no ; NO=false),!, % TO DO: make uniform
3832 (Expected==false
3833 -> format_with_colour_nl(user_error,[red],'Model Check Counterexample found for: ~w',[Formula])
3834 ; add_error(LTLorCTL, 'Model Check Counterexample found for: ', Formula)
3835 ),
3836 cli_print_history,
3837 print('Formula '), print('FALSE.'),nl,
3838 debug_format(19,'Use -his FILE -his_option show_states to display states of counterexample~n',[]),
3839 nl,
3840 check_expected(false,Expected,LTLorCTL).
3841 check_status(Status,Expected,Formula,LTLorCTL) :-
3842 add_internal_error('Unknown status: ', check_status(Status,Expected,Formula,LTLorCTL)).
3843
3844 incomplete_warning(ltl,ltl_incomplete) :- !.
3845 incomplete_warning(ctl,ctl_incomplete) :- !.
3846 incomplete_warning(X,X).
3847
3848 :- if(environ(prob_release,true)).
3849
3850 run_benchmark(_, _, _) :-
3851 add_message(probcli, 'Command-line argument for benchmarking is not available in release mode.').
3852
3853 :- else.
3854
3855 :- use_module('../tests/smt_solver_benchmarks/alloy2b_benchmarks').
3856 :- use_module('../tests/smt_solver_benchmarks/smt_solver_benchmarks').
3857 run_benchmark(alloy, CmdName, AlloyFilePath) :-
3858 alloy2b_benchmarks:benchmark_alloy_command(CmdName, AlloyFilePath).
3859 run_benchmark(smt, bmc, Path) :-
3860 smt_solver_benchmarks:run_additional_bmc_benchmarks(false, [Path]), halt.
3861 run_benchmark(smt, cbc_deadlock, Path) :-
3862 smt_solver_benchmarks:run_additional_deadlock_benchmarks(false, [Path]), halt.
3863 run_benchmark(smt, cbc_inv, Path) :-
3864 smt_solver_benchmarks:run_additional_inductive_inv_benchmarks(false, [Path]), halt.
3865
3866 :- endif.
3867
3868 evaluate_from_commandline :-
3869 retractall(eval_result(_,_)),
3870 option(eval_string_or_file(A,B,Q,E,Rchk)), %print(eval(A,B,Q,E)),nl,
3871 % treat eval_string and eval_file together to ensure proper order of evaluation
3872 % (only possible side-effect at the moment: formula can add new machine_string facts)
3873 eval_string_or_file(A,B,Q,E,Rchk),
3874 fail.
3875 evaluate_from_commandline :- print_eval_results,
3876 % treat -repl option or -replay File option
3877 (option(eval_repl([File1|TF]))
3878 -> (repl_evaluate_expressions([File1|TF]) -> true ; true)
3879 ; start_repl_if_required).
3880 start_repl_if_required :-
3881 (option(eval_repl([]))
3882 -> (repl_evaluate_expressions([]) -> true ; true)
3883 ; true).
3884
3885 :- dynamic eval_result/2.
3886 add_eval_result(R) :- retract(eval_result(R,N)),!,
3887 N1 is N+1, assertz(eval_result(R,N1)).
3888 add_eval_result(R) :- assertz(eval_result(R,1)).
3889 print_eval_results :- findall(R/N, eval_result(R,N), L), sort(L,SL),
3890 (SL=[] -> true ; format('Evaluation results: ~w~n',[SL])).
3891
3892 :- use_module(tools_printing,[print_error/1, format_error_with_nl/2]).
3893 %eval_string_or_file(string,_String,_,'FALSE',_Recheck) :- !. % comment in to skip evalf
3894 eval_string_or_file(string,String,_,Expected,Recheck) :-
3895 inc_counter(eval_string_nr,EvalNr),
3896 set_current_probcli_command(eval_string(String)),
3897 (option(silent),nonvar(Expected) -> true
3898 ; nonvar(Expected) -> format('eval(~w:~w): ~w~n',[EvalNr,Expected,String])
3899 ; format('eval(~w): ~w~n',[EvalNr,String])
3900 ),
3901 reset_error_spans, % avoid underlining previous errors in eval_string
3902 (eval_string_with_time_out(String,StringResult,EnumWarning,_LS) -> true
3903 ; print_error('Eval string failed: '), print_error(String),
3904 error_occurred(eval_string),
3905 StringResult='fail'
3906 ),
3907 add_eval_result(StringResult),
3908 eval_check_result(StringResult,Expected,EnumWarning,eval_string(EvalNr),String),
3909 (Recheck=recheck(Mode) -> recheck_pp_of_last_expression(Mode,_,_) ; true),
3910 unset_current_probcli_command.
3911 eval_string_or_file(file(bench),File,Quantifier,Expected,Recheck) :- !,
3912 ( member(Solver,[prob,kodkod,sat,'sat-z3','z3', 'cdclt',clingo]),
3913 (eval_string_or_file(file(Solver),File,Quantifier,Expected,Recheck) -> fail)
3914 ; true).
3915 eval_string_or_file(file(Solver),File,Quantifier,Expected,_) :-
3916 % evaluate a single formula stored in a file
3917 set_current_probcli_command(eval_file(Solver,File)),
3918 turn_show_error_source_off, % reduce clutter in user feedback; eval_file used in ProB Logic Calculator for example
3919 formatsilent('~nEvaluating file: ~w~n',[File]),
3920 error_manager:reset_error_scopes, % TO DO: avoid that exceptions mess up error scopes in eval_string/file
3921 statistics(runtime,[Start,_]),
3922 statistics(walltime,[W1,_]),
3923 (Expected=='TRUE' -> TypeInfo=predicate(_) % avoids parsing as expression
3924 ; true),
3925 (eval_file(Solver,File,Quantifier,Result,EnumWarning,TypeInfo)
3926 -> statistics(walltime,[W2,_]), WT is W2-W1,
3927 translate_solver_result(Result,Infos),
3928 accumulate_file_infos(File,Solver,[walltime-WT|Infos]),
3929 add_eval_result(Result),
3930 eval_check_result(Result,Expected,EnumWarning,eval_file,File)
3931 ; statistics(walltime,[W2,_]), WT is W2-W1,
3932 accumulate_file_infos(File,Solver,[failure-1,false-0,true-0,unknown-1,walltime-WT]),
3933 add_eval_result(eval_file_failed),
3934 print_error('Eval from file failed: '), print_error(File),
3935 error_occurred(eval_file)
3936 ),
3937 statistics(runtime,[Stop,_]), Time is Stop - Start,
3938 debug_format(19,'Time for ~w : ~w ms (~w ms walltime)~n',[File,Time,WT]),
3939 turn_show_error_source_on,
3940 unset_current_probcli_command.
3941
3942 translate_solver_result('TRUE',I) :- !, I=[false-0,true-1,unknown-0].
3943 translate_solver_result('FALSE',I) :- !, I=[false-1,true-0,unknown-0].
3944 translate_solver_result('UNKNOWN',I) :- !,I=[false-0,true-0,unknown-1].
3945 translate_solver_result('**** TIME-OUT ****',I) :- !,I=[false-0,true-0,unknown-1].
3946 translate_solver_result(_,[false-0,true-0,unknown-1]). % we could record this as error
3947
3948 eval_check_result(StringResult,Expected,_,Origin,File) :- Expected\=StringResult,!,
3949 format_error_with_nl('! Evaluation error, expected result to be: ~w (but was ~w) in ~w',[Expected,StringResult,File]),
3950 error_occurred(Origin).
3951 eval_check_result('NOT-WELL-DEFINED',Expected,_,Origin,File) :- var(Expected),!,
3952 format_error_with_nl('! Evaluation NOT-WELL-DEFINED in ~w',[File]),
3953 error_occurred(Origin).
3954 eval_check_result(_,_,EnumWarning,_,_) :- eval_gen_enum_warning(EnumWarning).
3955
3956 eval_gen_enum_warning(false) :- !.
3957 eval_gen_enum_warning(time_out) :- !,error_occurred(eval_string_time_out).
3958 eval_gen_enum_warning(_) :- print_error('Enumeration warning occurred'),
3959 error_occurred(eval_string_enum_warning,warning).
3960 %repl :- repl_evaluate_expressions([]).
3961 :- use_module(parsercall,[ensure_console_parser_launched/0]).
3962 repl_evaluate_expressions(StartFiles) :-
3963 get_errors, % first clear any errors from earlier commands
3964 nl,
3965 print('ProB Interactive Expression and Predicate Evaluator '), nl,
3966 print('Type ":help" for more information.'),nl,
3967 turn_show_error_source_off, % reduce clutter in user feedback
3968 (option(evaldot(File))
3969 -> print('Solutions written to dot file: '), print(File),nl
3970 ; true
3971 ),
3972 (ensure_console_parser_launched
3973 -> maplist(prob_cli:set_repl_input_file(verbose),StartFiles),
3974 top_level_eval
3975 ; print_repl_prompt, write('ABORTING REPL'),nl),
3976 turn_show_error_source_on.
3977
3978 :- use_module(user_interrupts,[interruptable_call/1]).
3979 top_level_eval :-
3980 catch(top_level_eval1, halt(0), (format('~s', ["Bye."]), nl)).
3981
3982 :- use_module(tools_printing,[reset_terminal_colour/1, print_red/1, print_green/1,
3983 get_repl_prompt/1, get_repl_continuation_prompt/1]).
3984 print_repl_prompt :- get_repl_prompt(Prompt), write(Prompt),reset_terminal_colour(user_output).
3985 print_repl_prompt_s(_) :- option(silent),!.
3986 print_repl_prompt_s(P) :- print_repl_prompt(P).
3987 print_repl_prompt(P) :- reset_terminal_colour(user_output), write(P).
3988 %print_repl_prompt(P) :- tools_printing:start_terminal_colour(dark_gray,user_output), write(P), reset_terminal_colour(user_output).
3989
3990 top_level_eval1 :-
3991 (interruptable_call(eval1) -> true
3992 ; print_red('Evaluation failed or interrupted'),nl,
3993 print_repl_prompt('Use :q to quit REPL'),nl),
3994 reset_errors,
3995 top_level_eval1.
3996 eval0 :- store_last_error_location_for_repl,
3997 reset_errors, % get_errors prints errors again and quits in -strict mode
3998 % However, reset_errors means that in subsequent REPL runs errors are not printed again!!
3999 garbage_collect, eval1.
4000 eval1 :- repl_multi_read_line(Expr), eval_probcli_repl_line(Expr).
4001
4002 :- dynamic last_repl_error/2.
4003 store_last_error_location_for_repl :-
4004 retractall(last_repl_error(_,_)),
4005 check_error_span_file_linecol(_,File,Line,_,_,_),!,
4006 assertz(last_repl_error(File,Line)).
4007 store_last_error_location_for_repl.
4008
4009 :- dynamic current_repl_input_stream/2.
4010 close_repl_input_stream(file_closed) :- retract(current_repl_input_stream(X,File)),!,
4011 format(":replayed ~w~n",[File]),
4012 close(X).
4013 close_repl_input_stream(no_file).
4014 :- use_module(tools_io,[safe_open_file/4]).
4015 set_repl_input_file(_,File) :- current_repl_input_stream(_,File),!,
4016 add_error(set_repl_input_file,'Cyclic file replay: ',File).
4017 set_repl_input_file(Verbose,File) :-
4018 % close_repl_input_stream, % this way we allow one REPL file to call another
4019 safe_open_file(File,read,Stream,[encoding(utf8)]),!,
4020 (Verbose=verbose -> format('Replaying REPL commands in file: ~w~n',[File]) ; true),
4021 asserta(current_repl_input_stream(Stream,File)).
4022 set_repl_input_file(_,_).
4023
4024 repl_multi_read_line(Line) :-
4025 (current_repl_input_stream(Stream,_)
4026 -> repl_multi_read_line(Stream,Line),
4027 format(user_output,'~s~n',[Line])
4028 ; repl_multi_read_line(user_input,Line)
4029 ).
4030 repl_multi_read_line(Stream,Line) :-
4031 get_repl_prompt(Prompt),
4032 repl_multi_read_line_aux(Stream,Prompt,[],Line).
4033 repl_multi_read_line_aux(Stream,Prompt,SoFar,Line) :-
4034 prompt(OldPrompt,Prompt),
4035 call_cleanup(read_line(Stream,L), prompt(_,OldPrompt)),
4036 (L=end_of_file -> close_repl_input_stream(FileC),
4037 (SoFar=[], FileC = file_closed
4038 -> repl_multi_read_line(Line) % last line of file empty; do not process
4039 ; FileC = file_closed -> Line=SoFar
4040 ; Line=end_of_file) % user pressed CTRL-D
4041 ; append(LFront,[92],L) % line ends with slash \
4042 -> append(LFront,[10],LFront2), % insert newline instead;
4043 % note cleanup_newlines in parsercall transforms this into 8232 \x2028 Unicode
4044 append(SoFar,LFront2,NewSoFar),
4045 get_repl_continuation_prompt(NewPrompt),
4046 repl_multi_read_line_aux(Stream,NewPrompt,NewSoFar,Line)
4047 ; append(SoFar,L,Line)).
4048
4049 :- use_module(eval_strings).
4050 :- dynamic trace_eval/0.
4051
4052 generate_atom_list([],[],R) :- !, R=[].
4053 generate_atom_list([],Last,[NewAtom]) :-
4054 reverse(Last,RL),
4055 atom_codes(NewAtom,RL).
4056 generate_atom_list([39|X],[],[QuotedAtom|T]) :- !,
4057 get_quoted_atom(X,[],QuotedAtom,Rest),
4058 strip_leading_ws(Rest,X2),
4059 generate_atom_list(X2,[],T).
4060 generate_atom_list([32|X],Last,[NewAtom|T]) :- !,
4061 reverse(Last,RL),
4062 atom_codes(NewAtom,RL),
4063 strip_leading_ws(X,X2),
4064 generate_atom_list(X2,[],T).
4065 generate_atom_list([H|X],Last,Res) :- generate_atom_list(X,[H|Last],Res).
4066
4067 get_quoted_atom([],Acc,QuotedAtom,[]) :- reverse(Acc,R), atom_codes(QuotedAtom,R).
4068 get_quoted_atom([39|T],Acc,QuotedAtom,T) :- !, reverse(Acc,R), atom_codes(QuotedAtom,R).
4069 get_quoted_atom([H|T],Acc,QuotedAtom,Rest) :- get_quoted_atom(T,[H|Acc],QuotedAtom,Rest).
4070
4071
4072 strip_leading_ws([32|X],R) :- !, strip_leading_ws(X,R).
4073 strip_leading_ws(X,X).
4074
4075 :- meta_predicate call_probcli_option(0).
4076 call_probcli_option(_:Option) :- just_assert_option(Option), !,
4077 (option(Option) -> true ; assert_option(Option)).
4078 call_probcli_option(_:statistics) :- !, % avoid calling SICS version
4079 cli_print_statistics(full).
4080 call_probcli_option(Option) :-
4081 catch(call(Option), error(existence_error(A,B),E), (
4082 treat_existence_error(A,B,E,Option),
4083 nl % ensure that next prompt is printed
4084 )).
4085
4086 % commands that require no execution; just asserting option(.)
4087 just_assert_option(depth_first).
4088 just_assert_option(breadth_first).
4089 just_assert_option(strict_raise_error).
4090 just_assert_option(no_deadlocks).
4091 just_assert_option(no_invariant_violations).
4092 just_assert_option(no_goal).
4093 just_assert_option(no_ltl).
4094 just_assert_option(no_assertion_violations).
4095 just_assert_option(no_state_errors).
4096 just_assert_option(no_counter_examples).
4097
4098 treat_existence_error(source_sink,File,E,Option) :- !,
4099 format_with_colour_nl(user_error,[red],
4100 '* Could not find file ~w~n* for probcli command ~w~n* Detailed error: ~w',[File,Option,E]).
4101 treat_existence_error(_,_,E,Option) :-
4102 format_with_colour_nl(user_error,[red],
4103 '* probcli command not yet supported in REPL: ~w~n* Error: ~w',[Option,E]).
4104
4105 reload_mainfile :-
4106 file_loaded(_,MainFile),
4107 reset_errors,
4108 print_repl_prompt_s('Reloading and initialising file: '), print_repl_prompt_s(MainFile),nl,
4109 clear_loaded_files,
4110 load_main_file(MainFile,0,_),
4111 get_errors,
4112 cli_start_animation(0),
4113 cli_start_initialisation(0).
4114
4115 % REPL EVAL LOOP:
4116 eval_probcli_repl_line(end_of_file) :- !, eval_line(end_of_file).
4117 eval_probcli_repl_line(Line) :- strip_ws(Line,SLine),
4118 catch(eval_line(SLine), E, (
4119 E=halt(_) -> throw(E) % e.g., coming from :quit; will be caught above
4120 ; E=unwind(_) -> throw(E) % from SWI-Prolog
4121 ; E='$aborted' -> throw(E) % thrown by SWI-Prolog on abort by user
4122 ; add_error(repl,'Uncaught Exception in REPL: ',E),
4123 nl % ensure that next prompt is printed
4124 )).
4125
4126 % strip whitespace at end and beginning
4127 strip_ws([H|T],Res) :- is_ws(H),!, strip_ws(T,Res).
4128 strip_ws(C,Res) :- reverse(C,CR), strip_ws2(CR,SCR), reverse(SCR,Res).
4129 strip_ws2([H|T],Res) :- is_ws(H),!, strip_ws2(T,Res).
4130 strip_ws2(R,R).
4131
4132 is_ws(32).
4133
4134 :- use_module(performance_messages,[toggle_perfmessages/0]).
4135 eval_line([]) :- !, print_repl_prompt('Type :q or :quit to quit.'),nl,eval0.
4136 eval_line(end_of_file) :- !, halt_exception(0).
4137 % Haskell GHCI like syntax
4138 eval_line(":r") :- !, eval_line("--reload").
4139 eval_line(":reload") :- !, eval_line("--reload").
4140 eval_line("--reload") :- !,
4141 (reload_mainfile -> true ; get_errors,print_repl_prompt('Error(s) occured during reload (use :e to jump to first error)'),nl),
4142 eval0.
4143 % TO DO: other Haskell commands :info E :l FILE , let pattern = expression
4144 eval_line(":prefs") :- !,print_eclipse_prefs, eval0.
4145 eval_line([45|Command]) :- % -command
4146 generate_atom_list([45|Command],[],ArgV),
4147 %print(argv(ArgV)),nl,
4148 % try and parse like commands passed to probcli
4149 get_options(ArgV,recognised_cli_option,Options,[],fail),
4150 print_repl_prompt('Executing probcli command: '),print_repl_prompt(Options),nl,!,
4151 (maplist(prob_cli:call_probcli_option,Options) -> true
4152 ; print_red('Failed to execute probcli arguments'),nl),
4153 eval0.
4154 eval_line("+") :- !, add_last_expression_to_unit_tests, eval0.
4155 eval_line("$+") :- !, preferences:temporary_set_preference(expand_avl_upto,-1,CHNG),
4156 print_last_value,preferences:reset_temporary_preference(expand_avl_upto,CHNG),
4157 eval0.
4158 eval_line(Command) :- append("$file ",FC,Command),!, atom_codes(File,FC),
4159 print_last_value_to_file(File).
4160 %eval_line("$$") :- !, print_last_expression, eval0. % now in eval_strings
4161 eval_line("$$$") :- !, % $$0 - $$9 commands to print last expression with indentation
4162 indent_print_last_expression, eval0.
4163 %eval_line("$") :- !, print_last_info, eval0. % now in eval_strings
4164 eval_line("!trace") :- !, eval_line("^").
4165 eval_line("^") :- !,
4166 (retract(trace_eval) -> print_repl_prompt('TRACING OFF'),nl
4167 ; assertz(trace_eval), print_repl_prompt('TRACING ON'),nl), eval0.
4168 eval_line("!observe") :- !, toggle_observe_evaluation.
4169 eval_line("!v") :- !, tcltk_turn_debugging_off.
4170 eval_line("!p") :- !, toggle_perfmessages.
4171 eval_line("!perf") :- !, toggle_perfmessages.
4172 eval_line("!profile") :- !, eval_line("%").
4173 eval_line("!print_profile") :- !, eval_line("%%").
4174 eval_line("%") :- !, print_repl_prompt('PROFILING : '), %spy([avl:avl_size/2]),
4175 (current_prolog_flag(profiling,on)
4176 -> set_prolog_flag(profiling,off), print('OFF') ;
4177 set_prolog_flag(profiling,on), print('ON')),
4178 nl,print_repl_prompt('USE %% to print profile info'),nl,eval0.
4179 eval_line("%%") :- !, nl,print_repl_prompt('PROLOG PROFILE INFORMATION:'), nl,
4180 catch(print_profile,
4181 error(existence_error(_,_),_),
4182 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4183 nl,
4184 debug:timer_statistics,
4185 eval0.
4186 eval_line("!print_coverage") :- !, nl,print_repl_prompt('PROLOG COVERAGE INFORMATION:'), nl,
4187 (current_prolog_flag(source_info,on) -> true ; print_red('Only useful when current_prolog_flag(source_info,on)!'),nl),
4188 catch(print_coverage,
4189 error(existence_error(_,_),_),
4190 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4191 nl,
4192 eval0.
4193 eval_line("!profile_reset") :- !, nl,print_repl_prompt('RESETTING PROLOG PROFILE INFORMATION'), nl,
4194 catch(profile_reset,
4195 error(existence_error(_,_),_),
4196 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4197 eval0.
4198 eval_line("%%%") :- !, nl,print('PROFILE INFORMATION (Starting TK Viewer):'), nl,
4199 catch(
4200 (use_module(library(gauge)), gauge:view),
4201 error(existence_error(_,_),_),
4202 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4203 nl,
4204 eval0.
4205 eval_line("!debug") :- !,
4206 print_repl_prompt('ENTERING PROLOG DEBUG MODE:'),
4207 catch(
4208 debug,
4209 error(existence_error(_,_),_),
4210 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4211 nl,
4212 eval0.
4213 eval_line("@") :- !, get_preference(find_abort_values,OldVal),
4214 print_repl_prompt('Try more aggressively to detect ill-defined expressions: '),
4215 (OldVal=true -> Val=false ; Val=true), print(Val),nl,
4216 temporary_set_preference(find_abort_values,Val) , eval0.
4217 eval_line("!") :- !, toggle_eval_det,eval0.
4218 eval_line("!norm") :- !, toggle_normalising,eval0.
4219 eval_line(Codes) :- parse_eval_command(Codes,CommandName,Argument),!,
4220 debug_println(9,executing_eval_command(CommandName,Argument)),
4221 (exec_eval_command(CommandName,Argument) -> eval0
4222 ; format_with_colour_nl(user_error,[red,bold],'Command ~w failed',[CommandName]),
4223 eval0).
4224 eval_line(ExpressionOrPredicate) :- (trace_eval -> trace ; true),
4225 (eval_codes(ExpressionOrPredicate,exists,_,_,_,_)
4226 -> eval0
4227 ; print_red('Evaluation failed'),nl,eval0).
4228
4229 parse_eval_command([C|Rest],CommandName,Argument) :- [C]=":",
4230 eval_command(Cmd,CommandName),
4231 append(Cmd,RestArg,Rest),
4232 (RestArg = [Letter1|_] -> is_ws(Letter1) /* otherwise command name continues */ ; true),
4233 strip_ws(RestArg,Argument),
4234 (eval_command_help(CommandName,[],_), Argument = [_|_]
4235 -> format_with_colour_nl(user_error,[red],'WARNING: Command ~w does not take arguments!',[CommandName])
4236 ; eval_command_help(CommandName,[_|_],_), Argument = []
4237 -> format_with_colour_nl(user_error,[red],'WARNING: Command ~w requires arguments!',[CommandName])
4238 ; true).
4239
4240 % TO DO: some of these commands should also be made available in the Tcl/Tk Console
4241 eval_command("q",quit).
4242 eval_command("quit",quit).
4243 eval_command("halt",quit).
4244 eval_command("x",exit).
4245 eval_command("exit",exit).
4246 eval_command("f",find).
4247 eval_command("find",find).
4248 eval_command("*",apropos).
4249 eval_command("apropos",apropos).
4250 eval_command("help",help).
4251 eval_command("h",help).
4252 eval_command("?",help).
4253 eval_command("ctl",ctl(init)). % :ctl
4254 eval_command("ctlh",ctl(starthere)). % :ctlh
4255 eval_command("ltl",ltl(init)). % :ltl
4256 eval_command("ltlh",ltl(starthere)). % :ltlh
4257 eval_command("pctl",pctl(init)). % :pctl
4258 eval_command("pctlh",pctl(starthere)). % :pctlh
4259 eval_command("reset",reset_animator(hard)). % :reset
4260 eval_command("reset-history",reset_animator(history_only)). % :reset
4261 eval_command("statistics",statistics).
4262 eval_command("stats",statistics). % :stats
4263 eval_command("states",state_space_stats). % :states
4264 eval_command("state",show_state_info(2000)). % :state
4265 eval_command("statespace",state_space_display). % :statespace
4266 eval_command("u",unsat_core).
4267 %eval_command("core",unsat_core).
4268 eval_command("show",show_last_as_table). % :show
4269 eval_command("dot",show_last_as_dot(no_dot_viewing)). % :dot
4270 eval_command("dotty",show_last_as_dot(dotty)).
4271 eval_command("dotpdf",show_last_as_dot(dot)).
4272 eval_command("sfdp",show_last_as_dot(sfdp)).
4273 eval_command("browse",browse). % :browse
4274 eval_command("abstract_constants",check_abstract_constants). % :abstract_constants
4275 eval_command("det_check_constants",det_check_constants). % :det_check_constants
4276 eval_command("b",browse).
4277 eval_command("hbrowse",hbrowse). % :hbrowse browse hiearchy
4278 eval_command("hshow",hshow). % show inclusion hieararchy
4279 eval_command("comp",show_components). % :comp
4280 eval_command("replay",replay_repl_file). % :replay
4281 eval_command("trim",trimcore). % :trim
4282 eval_command("src",show_source). %:src
4283 eval_command("source",show_source). %:source
4284 eval_command("origin",show_origin). %:origin
4285 eval_command("edit",edit_main_file).
4286 eval_command("e",edit_main_file). % :e
4287 eval_command("comment",comment).
4288 eval_command("machine",show_machine_info(statistics)). %:machine
4289 eval_command("machine-stats",show_machine_info(statistics)). %:machine
4290 eval_command("files",show_machine_info(files)). %:files
4291 eval_command("syntax",syntax_help). % :syntax
4292 eval_command("open",open_file). % :open
4293
4294 available_commands(SLC) :-
4295 findall(Cmd,(eval_command(Cs,_),atom_codes(Cmd,[58|Cs])), LC),
4296 sort(LC,SLC).
4297
4298 eval_command_help(exit,[],'Exit ProB').
4299 eval_command_help(find,['P'],'Find state in state-space which makes LTL atomic proposition P true; LTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink').
4300 eval_command_help(ltl(starthere),['F'],'Check LTL formula F starting from current state').
4301 eval_command_help(ltl,['F'],'Check LTL formula F; LTL Operators: G,F,X,U,W,R,not,&,or,=>; LTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink; Past-LTL Operators: Y,H,O,S,T (dual to X,G,F,U,R)').
4302 eval_command_help(ctl(starthere),['F'],'Check CTL formula F starting from current state').
4303 eval_command_help(ctl(_),['F'],'Check CTL formula F in all initial states; CTL Syntax: ExUy,EXx,AXx,EFx,AGx,EX[Op]x,e(Op),{B-Pred}').
4304 eval_command_help(pctl(starthere),['F'],'Check PCTL formula F starting from current state').
4305 eval_command_help(pctl(_),['F'],'Check PCTL formula F; PCTL Operators: not, &, or, =>, {B-Pred}, e(Op), [Op], true, false, sink, P op {Exp} [PathFormula] with op in {<,<=,>=,>,=}; Path operators: X, U, F, G, U<=Bound, F<=Bound, G<=Bound').
4306 eval_command_help(browse,opt('PAT'),'Browse available constants, variables, sets and lets introduced in REPL').
4307 eval_command_help(apropos,['PAT'],'Find constant or variable whose names contains PAT').
4308 eval_command_help(hbrowse,['PAT'],'Browse machine hierarchy for all identifiers whose names contains PAT').
4309 eval_command_help(hshow,[],'Show machine inclusion hierarchy using topological sorting').
4310 eval_command_help(show_components,[],'Show components of PROPERTIES').
4311 eval_command_help(abstract_constants,[],'Show ABSTRACT_CONSTANTS and check if can be fully evaluated').
4312 eval_command_help(det_check_constants,[],'Check if values of CONSTANTS are forced and explain if they are').
4313 eval_command_help(show_last_as_table,[],'Show last evaluated expression in tabular form').
4314 eval_command_help(show_last_as_dot(_),['F'],'Show expression or predicate F as dot graph').
4315 eval_command_help(unsat_core,[],'Compute Unsatisfiable Core of last evaluated predicate').
4316 eval_command_help(help,opt('CMD'),'Provide help about REPL command CMD').
4317 eval_command_help(replay_repl_file,['FILE'],'Replay FILE of REPL commands').
4318 eval_command_help(reset_animator(_),[],'Reset history and statespace of animator').
4319 eval_command_help(show_source,['ID'],'Show origin and source code definition of identifier ID').
4320 eval_command_help(show_origin,['ID'],'Show origin of identifier ID and try opening in EDITOR').
4321 eval_command_help(show_machine_info(_),[],'Show statistics about loaded machine and files').
4322 eval_command_help(state_space_stats,[],'Show statistics about state space').
4323 eval_command_help(state_space_display,[],'Show complete state space transitions (could be very big !)').
4324 eval_command_help(show_state_info(_),[],'Show current state').
4325 eval_command_help(statistics,[],'Show statistics about last evaluation').
4326 % -machine_stats : cli_print_machine_info(statistics) -machine_files : cli_print_machine_info(files)
4327 eval_command_help(trim,[],'Trim memory usage of probcli (try and give memory back to the OS)').
4328 % implemented in eval_strings:
4329 eval_command_help(type,['E'],'Show type of expression E').
4330 eval_command_help(cvc4,['P'],'Solve predicate P using CVC4 solver').
4331 eval_command_help(kodkod,['P'],'Solve predicate P using SAT solver via Kodkod').
4332 eval_command_help(z3,['P'],'Solve predicate P using Z3 solver').
4333 eval_command_help('z3-free',['P'],'Solve predicate P using Z3 solver (ignoring current state)').
4334 eval_command_help('z3-file',['F'],'Solve predicate in File F using Z3 solver').
4335 eval_command_help('z3-free-file',['F'],'Solve predicate in File F using Z3 solver (ignoring current state)').
4336 eval_command_help(cdclt,['P'],'Solve predicate P using Prolog CDCL(T) solver').
4337 eval_command_help(cdclt-free,['P'],'Solve predicate P using Prolog CDCL(T) solver (ignoring current state)').
4338 eval_command_help(prob,['P'],'Solve predicate P using ProB solver (ignoring current state)').
4339 eval_command_help('prob-file',['F'],'Solve predicate in File F using ProB solver (ignoring current state)').
4340 eval_command_help(edit_main_file,opt('ID'),'Edit main file (or origin of identifier ID) using EDITOR (path_to_text_editor preference)').
4341 eval_command_help(comment,['STRING'],'provide STRING as a comment (mainly useful for :replay files)').
4342 eval_command_help(syntax_help,[],'Show a summary of the B syntax accepted by the REPL').
4343 eval_command_help(open_file,['FILE'],'Open FILE in preferred application.').
4344
4345 print_eval_command_help(Codes) :-
4346 eval_command(Codes,Cmd),
4347 eval_command_help(Cmd,Args,Descr),
4348 (Args = []
4349 -> format('Command ~w~n Syntax :~s~n ~w~n',[Cmd,Codes,Descr])
4350 ; Args=[Arg] -> format('Command ~w~n Syntax :~s ~w~n ~w~n',[Cmd,Codes,Arg,Descr])
4351 ; Args=opt(Arg) -> format('Command ~w~n Syntax :~s [~w]~n ~w~n',[Cmd,Codes,Arg,Descr])
4352 ; format('Command ~w~n Syntax :~s ~w~n ~w~n',[Cmd,Codes,Args,Descr])).
4353
4354 :- use_module(tools_commands,[show_dot_file/1, show_pdf_file/1, gen_dot_output/4]).
4355 :- use_module(state_space,[transition/4]).
4356 :- use_module(b_machine_hierarchy,[print_machine_topological_order/0]).
4357 exec_eval_command(quit,_) :- !, halt_exception(0).
4358 exec_eval_command(exit,_) :- !,halt.
4359 exec_eval_command(browse,CodesToMatch) :- !,
4360 (CodesToMatch=[] -> browse % maybe merge with apropos functionality
4361 ; exec_eval_command(apropos,CodesToMatch)).
4362 exec_eval_command(find,FORMULA) :-
4363 atom_codes(APF,FORMULA),cli_find_ltl_ap(APF).
4364 exec_eval_command(apropos,CodesToMatch) :- /* :* Pattern (apropos command) */
4365 browse_machine(CodesToMatch).
4366 exec_eval_command(hbrowse,CodesToMatch) :- /* :* Pattern (hbrowse command) */
4367 browse_all_machines(CodesToMatch).
4368 exec_eval_command(hshow,_) :- /* show inclusion hierarhcy */
4369 print_machine_topological_order.
4370 exec_eval_command(show_components,_) :-
4371 print_property_partitions.
4372 exec_eval_command(check_abstract_constants,_) :-
4373 check_abstract_constants.
4374 exec_eval_command(det_check_constants,_) :-
4375 det_check_constants.
4376 exec_eval_command(help,Arg) :-
4377 (Arg=[] -> eval_help
4378 ; print_eval_command_help(Arg) -> true
4379 ; (Arg=[58|RA],print_eval_command_help(RA)) -> true % remove : at front
4380 ; format('Cannot provide help about ~s~n',[Arg]),
4381 available_commands(LC), format('Available commands: ~w~n',[LC])
4382 ).
4383 exec_eval_command(ctl(Mode),FORMULA) :- % :ctl or :ctlh for ctl here
4384 atom_codes(F,FORMULA),
4385 (cli_ctl_model_check(F,Mode,_,Status)
4386 -> (Status=false -> write_history_to_user_output([show_init,show_states]) ; true)
4387 ; print('CTL Syntax: ExUy,EXx,AXx,EFx,AGx,EX[Op]x,e(Op),{B-Pred}'),nl).
4388 exec_eval_command(ltl(Mode),FORMULA) :- % :ltl or :ltlh with Mode = init or starthere
4389 atom_codes(F,FORMULA),
4390 (cli_ltl_model_check(F,Mode,_,Status)
4391 -> (Status=no -> write_history_to_user_output([show_init,show_states]) ; true)
4392 ; print('LTL Operators: G,F,X,U,W,R,not,&,or,=>,<=>'),nl,
4393 print('LTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink'),nl,
4394 print('Past-LTL Operators: Y,H,O,S,T (dual to X,G,F,U,R)'),nl
4395 ).
4396 exec_eval_command(pctl(Mode),FORMULA) :- % :pctl or :pctlh with Mode = init or starthere
4397 atom_codes(F,FORMULA),
4398 (cli_pctl_model_check(F,Mode,_,Status)
4399 -> (Status=no -> write_history_to_user_output([show_init,show_states]) ; true)
4400 ; print('PCTL Propositional Operators: not, &, or, =>'),nl,
4401 print('PCTL State Formula: P op {Exp} [PathFormula] with op in {<,<=,>=,>,=}'),nl,
4402 print('PCTL Path Formulas: X phi, phi1 U phi2, F phi, G phi'),nl,
4403 print('PCTL Bounded Path Formulas: phi1 U<=Bound phi2, F<=Bound phi, G<=Bound phi'),nl,
4404 print('PCTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink'),nl
4405 ).
4406 exec_eval_command(reset_animator(Hard),_) :- !,
4407 get_state_space_stats(TotalNodeSum,TotalTransSum,_,_),
4408 (Hard=hard ->
4409 format('Resetting statespace (~w states, ~w transitions)~n',[TotalNodeSum,TotalTransSum]),
4410 reset_animator
4411 ; format('Resetting animation history (keeping statespace: ~w states, ~w transitions)~n',[TotalNodeSum,TotalTransSum]),
4412 tcltk_reset % only resets animation history,...
4413 ).
4414 exec_eval_command(statistics,_) :- !, print_last_info.
4415 exec_eval_command(state_space_stats,_) :- !, % :states
4416 get_state_space_stats(TotalNodeSum,TotalTransSum,Processed,Ignored),
4417 (Ignored>0
4418 -> format('Statespace: ~w states (~w processed, ~w ignored) and ~w transitions.~n',
4419 [TotalNodeSum,Processed,Ignored,TotalTransSum])
4420 ; format('Statespace: ~w states (~w processed) and ~w transitions.~n',[TotalNodeSum,Processed,TotalTransSum])).
4421 exec_eval_command(state_space_display,_) :- !, % :statespace
4422 ( visited_expression(ID,State),
4423 functor(State,F,N),
4424 format('State ID ~w (~w/~w)~n',[ID,F,N]),
4425 transition(ID,OperationTerm,_OpID,ToID),
4426 get_operation_name(OperationTerm,OpName),
4427 format(' -> ~w (~w)~n',[ToID,OpName]),
4428 fail
4429 ;
4430 current_state_id(ID),
4431 format('Current State ID ~w~n',[ID])
4432 ).
4433 exec_eval_command(show_state_info(Limit),_) :- !, % :state
4434 (current_expression(ID,CurState)
4435 ->
4436 expand_const_and_vars_to_full_store(CurState,EState),
4437 format('Current state id ~w : ~n',[ID]), % MAX_DISPLAY_SET
4438 translate:print_bstate_limited(EState,Limit,-1),nl,
4439 (\+ not_all_transitions_added(ID),
4440 format('Outgoing transitions of state id ~w:~n',[ID]),
4441 transition(ID,OperationTerm,_OpID,ToID),
4442 get_operation_name(OperationTerm,OpName),
4443 format(' -> ~w (~w)~n',[ToID,OpName]),
4444 fail
4445 ; true)
4446 ; print_red('No current state available!'),nl
4447 ).
4448 exec_eval_command(unsat_core,_) :- !, % :core :u
4449 unsat_core_last_expression.
4450 exec_eval_command(trimcore,_) :- !, % :trim
4451 prob_trimcore_verbose.
4452 exec_eval_command(show_last_as_table,_) :- !, % :show
4453 show_last_expression_as_table.
4454 exec_eval_command(syntax_help,_) :- !, % :syntax
4455 syntax_help.
4456 exec_eval_command(show_last_as_dot(Show),Arg) :- !,
4457 (Arg = [] -> print('*** :dot requires an expression or predicate as argument.'),nl
4458 ; safe_absolute_file_name('~/probcli_repl.dot',AFile),
4459 set_eval_dot_file(AFile),
4460 format('Displaying evaluation result in: ~w~n',[AFile]),
4461 (eval_codes(Arg,exists,_,_,_,_) -> true ; true), unset_eval_dot_file,
4462 ( Show=no_dot_viewing -> true
4463 ; Show=dotty -> show_dot_file(AFile)
4464 ; safe_absolute_file_name('~/probcli_repl.pdf',PDFFile),
4465 gen_dot_output(AFile,Show,pdf,PDFFile),
4466 show_pdf_file(PDFFile)
4467 )).
4468 exec_eval_command(replay_repl_file,FILEC) :- !, % :replay
4469 atom_codes(File,FILEC),
4470 set_repl_input_file(not_verbose,File).
4471 exec_eval_command(show_source,IDC) :- !, % :src
4472 trim_id_back_quotes(IDC,TIDC),atom_codes(ID,TIDC),
4473 show_source(ID).
4474 exec_eval_command(show_origin,IDC) :- !, % :origin
4475 trim_id_back_quotes(IDC,TIDC),atom_codes(ID,TIDC),
4476 show_origin(ID).
4477 exec_eval_command(show_machine_info(X),_) :- !, % :machine
4478 cli_print_machine_info(X).
4479 exec_eval_command(edit_main_file,Arg) :- !, % :e
4480 (Arg=[] -> edit_main_file
4481 ; trim_quotes(Arg,FC), atom_codes(File,FC), file_exists(File) -> edit_file(File,unknown)
4482 ; exec_eval_command(show_origin,Arg)).
4483 exec_eval_command(open_file,FILEC) :- !, % :open
4484 (FILEC=[] -> open_file('.')
4485 ; atom_codes(File,FILEC),
4486 open_file(File)
4487 ).
4488 exec_eval_command(comment,_Arg) :- !. % do nothing; argument was a comment; mainly useful for :replay files
4489
4490
4491 trim_id_back_quotes([96|T],Res) :- append(Res,[96],T),!.
4492 trim_id_back_quotes(R,R).
4493
4494 trim_quotes([34|T],Res) :- append(Res,[34],T),!. % double quotes
4495 trim_quotes([39|T],Res) :- append(Res,[39],T),!. % single quotes
4496 trim_quotes(R,R).
4497
4498 :- use_module(tools_commands,[edit_file/2, open_file/1]).
4499 edit_main_file :- last_repl_error(File,Line),
4500 \+ functor(File,unknown,_), % File \= unknown(_),
4501 !,
4502 format('Showing first error from last command~n',[]),
4503 edit_file(File,Line).
4504 % Note: for the bbedit command we can also specify line numbers bbedit +LINE FILE
4505 edit_main_file :- file_loaded(_,MainFile), \+ empty_machine_loaded,
4506 !,edit_file(MainFile,unknown).
4507 edit_main_file :- format_with_colour_nl(user_error,[red],'No file loaded, cannot open EDITOR!',[]).
4508
4509
4510
4511 :- use_module(probsrc(error_manager),[extract_file_line_col/6]).
4512 open_file_at_position(OriginTerm) :-
4513 extract_file_line_col(OriginTerm,FILE,LINE,_COL,_Erow,_Ecol),
4514 edit_file(FILE,LINE).
4515
4516
4517 :- use_module(probsrc(bmachine),[source_code_for_identifier/6]).
4518 show_source(ID) :- source_code_for_identifier(ID,Kind,_Type,OriginStr,OriginTerm,Source),!,
4519 translate:translate_subst_or_bexpr(Source,PPS),
4520 %format('~w: ~w (Type: ~w)~norigin: ~w~nsource: ~w~n',[Kind,ID,_Type,Origin,PPS]).
4521 format('~w: ~w~norigin: ~w~nsource: ~w~n',[Kind,ID,OriginStr,PPS]),
4522 (OriginTerm=b(_,_,_),get_texpr_description(OriginTerm,Description)
4523 -> format('description: ~w~n',[Description]) ; true).
4524 show_source(ID) :- format_error_with_nl('! Could not find source for ~w',[ID]).
4525
4526 show_origin('') :- last_repl_error(_,_),!, % error occured: show error in editor like :e would
4527 edit_main_file.
4528 show_origin('') :- !,format_error_with_nl('! You need to provided an identifier',[]).
4529 show_origin(ID) :- source_code_for_identifier(ID,Kind,_Type,OriginStr,OriginTerm,_Source),!,
4530 format('~w: ~w~norigin: ~w~n',[Kind,ID,OriginStr]),
4531 open_file_at_position(OriginTerm).
4532 show_origin(ID) :- format_error_with_nl('! Could not find origin for ~w',[ID]).
4533
4534 profiling_on :- set_prolog_flag(profiling,on), print('% PROFILING ON'),nl.
4535 profiling_off :- set_prolog_flag(profiling,off), print('% PROFILING OFF'),nl.
4536
4537 % find a state satisfying LTL atomic property
4538 cli_find_ltl_ap(APF) :-
4539 if(ltl:find_atomic_property_formula(APF,ID),
4540 (format('Found state (id = ~w) satisfying LTL atomic property.~n',[ID]),
4541 tcltk_goto_state('LTL FIND',ID)),
4542 format('No explored state satsifies LTL atomic property.~n',[])).
4543
4544 eval_help :-
4545 print('ProB Interactive Expression and Predicate Evaluator '), nl,
4546 print('Type a valid B expressions or predicates, followed by RETURN or ENTER.'),nl,
4547 print('You can spread input over multiple lines by ending lines with "\\".'),nl,
4548 browse_machine([]),
4549 print('You can also type one of the following commands: '),nl,
4550 (option_verbose ->
4551 print(' + to save last expression to ProB unit tests.'),nl,
4552 print(' ! to go to deterministic propagation only mode.'),nl,
4553 print(' $ to print evaluation time for last expression.'),nl,
4554 print(' $$ to pretty-print last expression and its type.'),nl,
4555 print(' $$$ to pretty-print last expression in nested fashion.'),nl,
4556 print(' !p to toggle performance messages.'),nl,
4557 print(' !norm to toggle normalisation of results.'),nl,
4558 print(' :col to toggle colorizing of results.'),nl
4559 ; true),
4560 print(' :let x = E to define a new local variable x'),nl, % : optional for let
4561 print(' :unlet x to un-define a local variable'),nl,
4562 print(' #file=MYFILE to evaluate the formula in MYFILE'),nl,
4563 print(' @INVARIANT to evaluate or obtain invariant predicate'),nl,
4564 print(' @PROPERTIES, @GUARD-OpName ditto for properties and guards'),nl, % @FUZZ, @RANDOMISE also exist
4565 print(' :b or :b Prefix to browse the available identifiers'),nl,
4566 print(' :t E to get the type of an expression'),nl,
4567 print(' :r to reload the machine'),nl,
4568 print(' :show to display the last result as a table (if possible)'),nl,
4569 print(' :list CAT to display information with CAT : {files,variables,help,...}'),nl,
4570 print(' :* P to display constants/variables containing pattern P'),nl,
4571 print(' :core Pred to compute the unsat core for Pred'),nl,
4572 print(' :u to compute the unsat core for last evaluated result'),nl,
4573 print(' :stats to print the type and evaluation time for last query'),nl,
4574 print(' -PROBCLIARGS to pass command-line probcli arguments to the REPL'),nl,
4575 print(' (e.g., -v to switch to verbose mode or -p PREF VAL to set a preference)'),nl,
4576 print(' :ctl F or :ltl F to check a CTL or LTL formula.'),nl,
4577 print(' :f F to find a state satisfying LTL atomic property.'),nl,
4578 print(' :find-value PAT to find a value in current state matching PAT.'),nl,
4579 print(' :find-value OPT "String" same with OPT = prefix, infix, suffix or fuzzy.'),nl,
4580 print(' :exec S to execute an operation or substitution S.'),nl,
4581 print(' :replay FILE to replay a file of commands.'),nl,
4582 print(' :z3 P, :cvc4 P, :kodkod P to solve predicate P using alternate solver'),nl,
4583 print(' :forall P to prove predicate P as universally quantified with default solver'),nl,
4584 print(' :prove P to prove predicate P using ProB\'s own WD prover'),nl,
4585 (option_verbose ->
4586 print(' :krt P, :pp P, :ml P to prove predicate P using Atelier-B provers if installed'),nl
4587 ; true),
4588 print(' :print P to pretty print predicate in a nested fashion'),nl,
4589 print(' :min P, :max P to find a minimal/maximal model for predicate P or %x.(P|E)'),nl,
4590 print(' :prefs to print current value of preferences'),nl,
4591 print(' :reset to reset the state space of the animator.'),nl, % :reset-history only resets history
4592 print(' :help CMD to obtain more help about a command.'),nl,
4593 print(' :state, :statespace, :states,'),nl,
4594 print(' :machine, :files, :source, :orgin, :machine-stats,'),nl,
4595 print(' :apropos, :hbrowse, :abstract_constants, :det_check_constants,'),nl,
4596 print(' :dot, :dotty, :sfdp, :trim, :comp - use :help CMD for more info'),nl,
4597 print(' :syntax to show a summary of the B syntax accepted by the REPL'),nl,
4598 print(' :q to exit.'),nl.
4599
4600 :- use_module(tools,[read_atom_from_file/3]).
4601 :- dynamic prob_summary/1.
4602
4603 :- read_atom_from_file(tclsrc('prob_summary.txt'),utf8,T), assertz(prob_summary(T)).
4604 % TODO: we could just include a shorter version with predicates and expressions
4605 % TODO: provide :syntax LTL or :syntax CTL help commands
4606 syntax_help :- prob_summary(S),
4607 format(user_output,'~w',S).
4608
4609
4610 browse :- browse_machine([]), browse_repl_lets.
4611
4612 :- use_module(bmachine,[get_machine_identifiers/2]).
4613 % the CodesToMatch parameters mimics the apropos command of the Clojure-REPL
4614 browse_machine(CodesToMatch) :-
4615 get_machine_identifiers(machines,MN), display_match('MACHINES',CodesToMatch,MN),
4616 (CodesToMatch =[] -> print_sets
4617 ; get_machine_identifiers(sets,SN), display_match('SETS',CodesToMatch,SN),
4618 get_machine_identifiers(set_constants,SCN), display_match('SETS-ELEMENTS',CodesToMatch,SCN)
4619 ),
4620 get_machine_identifiers(definition_files,DFN),
4621 (DFN=[] -> true ; display_match('DEFINITIONS FILES',CodesToMatch,DFN)),
4622 get_machine_identifiers(definitions,DN),
4623 (DN=[] -> true ; display_match('DEFINITIONS',CodesToMatch,DN)),
4624 get_machine_identifiers(constants,CN),
4625 display_match('CONSTANTS',CodesToMatch,CN),
4626 get_machine_identifiers(variables,VN),
4627 display_match('VARIABLES',CodesToMatch,VN),
4628 get_machine_identifiers(operations,Ops),
4629 display_match('OPERATIONS',CodesToMatch,Ops).
4630
4631 display_match(KIND,CodesToMatch,Ids) :- display_match(KIND,CodesToMatch,Ids,show_empty).
4632 display_match(KIND,CodesToMatch,Ids,ShowEmpty) :-
4633 include(prob_cli:atom_contains_codes(CodesToMatch),Ids,MatchingIds),
4634 length(MatchingIds,LenMIds),
4635 (LenMIds=0, ShowEmpty=show_only_if_match -> true
4636 ; sort(MatchingIds,SMatchingIds),
4637 (CodesToMatch=[]
4638 -> format(' ~w: ~w ~w~n',[KIND,LenMIds,SMatchingIds])
4639 ; length(Ids,LenIds),
4640 format('Matching ~w: ~w/~w ~w~n',[KIND,LenMIds,LenIds,SMatchingIds]))
4641 ).
4642
4643 % check if an atom contains a list of codes in its name
4644 atom_contains_codes([],_) :- !.
4645 atom_contains_codes(Codes,Name) :- atom_codes(Name,NC),
4646 append([_,Codes,_],NC).
4647
4648 :- use_module(b_global_sets,[b_global_set/1]).
4649 print_sets :- print('Available SETS: '), b_global_set(GS), print_set(GS),fail.
4650 print_sets :- nl.
4651
4652 :- use_module(probsrc(b_global_sets),[is_b_global_constant/3]).
4653 print_set(GS) :- print(GS), \+ is_b_global_constant(GS,_,_),!, print(' ').
4654 print_set(GS) :- print(' = {'), is_b_global_constant(GS,_,Cst), print(Cst), print(' '),fail.
4655 print_set(_) :- print(' } ').
4656
4657 :- use_module(b_machine_hierarchy,[get_machine_identifier_names/7]).
4658 % browse all machines, shows identifiers maybe not visible at top-level
4659 browse_all_machines(CodesToMatch) :-
4660 format('Searching machine hierarchy for identifiers matching ~s~n',[CodesToMatch]),
4661 get_machine_identifier_names(Name,Params,Sets,AVars,CVars,AConsts,CConsts),
4662 format('~nMACHINE ~w~n',[Name]),
4663 display_match('PARAMS',CodesToMatch,Params,show_only_if_match),
4664 display_match('SETS',CodesToMatch,Sets,show_only_if_match),
4665 display_match('ABSTRACT_VARIABLES',CodesToMatch,AVars,show_only_if_match),
4666 display_match('CONCRETE_VARIABLES',CodesToMatch,CVars,show_only_if_match),
4667 display_match('ABSTRACT_CONSTANTS',CodesToMatch,AConsts,show_only_if_match),
4668 display_match('CONCRETE_CONSTANTS',CodesToMatch,CConsts,show_only_if_match),
4669 fail.
4670 browse_all_machines(_).
4671
4672
4673 :- use_module(bmachine,[b_get_properties_from_machine/1]).
4674 print_property_partitions :- print('PARTITIONS OF PROPERTIES'),nl,
4675 b_get_properties_from_machine(Properties),
4676 predicate_components(Properties,Comp),
4677 length(Comp,Len), print(Len), print(' components found in PROPERTIES'),nl,
4678 nth1(Nr,Comp,component(P,Vars)),
4679 format('~n& // Component ~w/~w over identifiers ~w~n',[Nr,Len,Vars]),
4680 translate:print_bexpr(P),nl,fail.
4681 print_property_partitions :- nl, print(' ============== '),nl.
4682
4683 :- use_module(store,[lookup_value_for_existing_id/3]).
4684 :- use_module(b_machine_hierarchy,[abstract_constant/2]).
4685 check_abstract_constants :-
4686 format('Checking whether abstract constants can be expanded:~n',[]),
4687 current_expression(_ID,CurState),
4688 expand_const_and_vars_to_full_store(CurState,EState),
4689 abstract_constant(AID,_),
4690 lookup_value_for_existing_id(AID,EState,Val),
4691 get_value_type(Val,VF),
4692 format(user_output,'~n*** Evaluating ABSTRACT_CONSTANT (stored value: ~w):~n',[VF]),
4693 format_with_colour_nl(user_output,[blue],' ~w',[AID]),
4694 (debug_mode(off) -> true
4695 ; translate:translate_bvalue(Val,VS), format_with_colour_nl(user_output,[blue],' Stored value = ~w',[VS])),
4696 atom_codes(AID,C),
4697 % TO DO: provide info if value symbolic and can be expanded fully + add timing
4698 % term_size, unique in state space
4699 % this command is deprecated compared to -csv constants_analysis (i.e., tcltk_analyse_constants)
4700 eval_codes(C,exists,_,_EnumWarning,_LS,_),nl, % TO DO: call try_expand_and_convert_to_avl_with_check(Val)
4701 fail.
4702 check_abstract_constants.
4703
4704 :- use_module(probsrc(custom_explicit_sets),[is_interval_closure/3]).
4705 get_value_type(CS, Res) :- is_interval_closure(CS,_,_),!, Res = 'interval closure'.
4706 get_value_type(closure(_,_,_),Res) :- !, Res= 'symbolic closure'.
4707 get_value_type(avl_set(_), Res) :- !, Res= 'explicit AVL set'.
4708 get_value_type(Val,VF) :- functor(Val,VF,_).
4709
4710 :- use_module(b_state_model_check,[cbc_constants_det_check/1]).
4711 det_check_constants :- \+ current_state_corresponds_to_setup_constants_b_machine, !,
4712 format_with_colour_nl(user_error,[red],'This command requires to setup the constants first!',[]).
4713 det_check_constants :-
4714 current_state_id(ID),
4715 %format('Checking whether constants are forced in state ~w:~n',[ID]),
4716 cbc_constants_det_check(ID).
4717
4718 % showing relations as tables:
4719
4720 :- use_module(extrasrc(table_tools),[print_value_as_table/2]).
4721 show_last_expression_as_table :- \+ last_expression(_,_Expr),!,
4722 print_red('Please evaluate an expression or predicate first.'),nl.
4723 show_last_expression_as_table :-
4724 get_last_result_value(Expr,_,Value),
4725 print_value_as_table(Expr,Value).
4726
4727
4728 % a few definitions so that probcli commands work in REPL:
4729 :- use_module(specfile,[get_internal_representation/1]).
4730 :- use_module(tools_files,[write_to_utf8_file_or_user_output/2]).
4731 :- use_module(translate,[set_unicode_mode/0, unset_unicode_mode/0, set_atelierb_mode/1, unset_atelierb_mode/0, with_translation_mode/2]).
4732 :- public pretty_print_internal_rep/4, pretty_print_internal_rep_to_B/1.
4733 pretty_print_internal_rep(PPFILE,MachName,TYPES,TransMode) :-
4734 b_or_z_mode, !,
4735 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,TransMode).
4736 pretty_print_internal_rep(PPFILE,_MachName,_TYPES,TransMode) :-
4737 with_translation_mode(TransMode,get_internal_representation(PP)),
4738 write_to_utf8_file_or_user_output(PPFILE,PP).
4739
4740 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,unicode) :- !,
4741 set_unicode_mode,
4742 call_cleanup(b_write_machine_representation_to_file(MachName,TYPES,PPFILE),unset_unicode_mode).
4743 pretty_print_internal_rep_b(PPFILE,'$auto',_TYPES,atelierb) :- animation_minor_mode(eventb),!,
4744 b_write_eventb_machine_to_classicalb_to_file(PPFILE). % old -ppB option:
4745 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,atelierb) :- !,
4746 set_atelierb_mode(native),
4747 call_cleanup(b_write_machine_representation_to_file(MachName,TYPES,PPFILE),unset_atelierb_mode).
4748 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,_) :- b_write_machine_representation_to_file(MachName,TYPES,PPFILE).
4749
4750 % -ppB option:
4751 pretty_print_internal_rep_to_B(PPFILE) :- b_write_eventb_machine_to_classicalb_to_file(PPFILE).
4752
4753 :- use_module(tools_printing,[tcltk_nested_read_prolog_file_as_codes/2]).
4754 % -pppl option: internal developer utility to pretty-print a Prolog file in nested fashion
4755 % can be useful to inspecting .prob AST files or .P XTL files
4756 pretty_print_prolog_file(PPFILE) :-
4757 file_loaded(_,MainFile),
4758 (loaded_main_file(Ext,_), \+( (Ext='P' ; Ext='prob' ; Ext= 'pl') )
4759 -> add_warning(probcli,'The -pppl command is designed to work with Prolog files (.P, .prob or .pl), not with: ',Ext) ; true),
4760 pretty_print_prolog_file(MainFile,PPFILE).
4761
4762 pretty_print_prolog_file(File,File) :- !,
4763 add_error(probcli,'Output file must be different from input Prolog file:',File).
4764 pretty_print_prolog_file(MainFile,PPFILE) :-
4765 format('Pretty-Printing Prolog file ~w to ~w~n',[MainFile,PPFILE]),
4766 tcltk_nested_read_prolog_file_as_codes(MainFile,list(Codes)),
4767 safe_intelligent_open_file(PPFILE,write,Stream),
4768 format(Stream,'~s~n',[Codes]),
4769 close(Stream).
4770
4771 :- use_module(extrasrc(source_indenter),[indent_b_file/3]).
4772 indent_main_b_file(PPFILE) :-
4773 file_loaded(_,MainFile),
4774 indent_b_file_to_file(MainFile,PPFILE,[]).
4775
4776 indent_b_file_to_file(File,File,_) :- !,
4777 add_error(probcli,'Output file must be different from input B file:',File).
4778 indent_b_file_to_file(MainFile,PPFILE,Options) :-
4779 format('Indenting B file ~w to ~w~n',[MainFile,PPFILE]), flush_output,
4780 safe_intelligent_open_file(PPFILE,write,OutStream),
4781 call_cleanup(indent_b_file(MainFile,OutStream,Options),close(OutStream)).
4782
4783
4784 % Simple Animator
4785
4786 interactive_animate_machine :-
4787 nl,print('IMPORTANT: Do not use this mode for automatic tools.'),nl,
4788 print('The output format can change arbitrarily in future versions.'),nl,
4789 print('Please terminate your input with a dot (.) and then type return.'),nl,nl,
4790 animate_machine2.
4791 animate_machine2 :-
4792 print_current_state,
4793 cli_computeOperations(Ops),
4794 length(Ops,Max),
4795 print('Enabled Operations: '),nl,
4796 print_options(Ops,1),
4797 print(' ==> '),!,
4798 read(Nr),
4799 (number(Nr),Nr>0,Nr=<Max
4800 -> cli_animateOperationNr(Nr,Ops,0)
4801 ; fail
4802 ),!,
4803 animate_machine2.
4804 animate_machine2.
4805
4806 print_current_state :- current_state_id(CurID), print('ID ==> '), print(CurID),nl,
4807 getStateValues(CurID,State),
4808 print_bindings(State),
4809 (specfile:b_or_z_mode,\+is_initialised_state(CurID)
4810 -> print_red(' Not yet initialised.'),print_mode_info, debug_println(10,state(State)) ; nl).
4811
4812 print_mode_info :- animation_mode(M), (animation_minor_mode(MM) -> true ; MM=''),
4813 format('Animation Mode = ~w [~w]~n',[M,MM]).
4814
4815 cli_computeOperations(Ops) :- option(animate_stats),!, % provide statistics about the animation
4816 nl,
4817 start_probcli_timer(Timer),
4818 current_state_id(CurID),
4819 tcltk_get_options(list(Ops)),
4820 ajoin(['Time to compute all operations in state ',CurID,': '],Msg),
4821 stop_probcli_timer(Timer,Msg).
4822 cli_computeOperations(Ops) :- tcltk_get_options(list(Ops)).
4823
4824 cli_animateOperationNr(Nr,Options,StepNr) :-
4825 (option(animate_stats)
4826 -> nth1(Nr,Options,Action),
4827 truncate_animate_action(Action,TA),
4828 (StepNr>1 -> format('performing step ~w : ~w~n',[StepNr,TA])
4829 ; format('performing ~w~n',[TA]))
4830 ; true),
4831 tcltk_perform_nr(Nr).
4832
4833 :- use_module(tools_strings,[truncate_atom/3]).
4834 % optionally truncate animation action atom for printing:
4835 truncate_animate_action(Action,TA) :-
4836 (option_verbose -> TA = Action
4837 ; \+ atom(Action) -> TA = Action
4838 ; truncate_atom(Action,100,TA)).
4839
4840 perform_random_step(StepNr) :- perform_random_step(_Ops,_Len,_RanChoice,StepNr).
4841 perform_random_step(Ops,Len,RanChoice,StepNr) :-
4842 cli_computeOperations(Ops),
4843 current_state_id(CurID), check_for_errors(CurID,StepNr),
4844 length(Ops,Len), Len>0,
4845 debug_println(20,perform_random_step(Len,StepNr)),
4846 L1 is Len+1,
4847 (do_det_checking, Len>1
4848 -> print_error('Non-deterministic step in animate or init'),
4849 print_error('State:'),
4850 print_current_state, print_error('Enabled Operations: '), print_options(Ops,1),
4851 error_occurred(det_check)
4852 ; true),
4853 random(1,L1,RanChoice),
4854 debug_println(20,random(L1,RanChoice)),
4855 cli_animateOperationNr(RanChoice,Ops,StepNr).
4856
4857 :- use_module(state_space,[visited_expression/2]).
4858 check_for_errors(CurID,StepNr) :- invariant_violated(CurID),
4859 \+ option(no_invariant_violations),
4860 get_preference(do_invariant_checking,true),
4861 ajoin(['INVARIANT VIOLATED after ',StepNr,' steps (state id ',CurID,').'],ErrMsg),
4862 format('~w~n',[ErrMsg]),
4863 visited_expression(CurID,CurState), print_state_silent(CurState),
4864 error_occurred_with_msg(invariant_violation,ErrMsg),
4865 fail.
4866 check_for_errors(CurID,_) :- get_state_errors(CurID).
4867 % TO DO: also check for assertion errors, goal, state_errors with abort
4868
4869 :- use_module(bmachine,[b_machine_has_constants_or_properties/0]).
4870 do_det_checking :- option(det_check),!.
4871 do_det_checking :- option(det_constants_check),current_state_id(root),
4872 b_or_z_mode, b_machine_has_constants_or_properties.
4873
4874 perform_random_steps(Nr,_) :- \+ number(Nr),!,
4875 print_error('Argument to animate not a number'), print_error(Nr),error_occurred(animate).
4876 perform_random_steps(Nr,_) :- Nr<0, !,
4877 print_error('Argument to animate is a negative number'), print_error(Nr),error_occurred(animate).
4878 perform_random_steps(0,_) :- !.
4879 perform_random_steps(Nr,ErrorOnDeadlock) :-
4880 (perform_random_initialisation_if_necessary(Steps) % if Nr=1 we currently will also execute the INITIALISATION ! TO DO: fix
4881 -> perform_random_steps_aux(Steps,Nr,ErrorOnDeadlock)
4882 ; % we have setup_constants_fails or initialisation_fails
4883 print_error('Could not initialise model for animation')
4884 ).
4885
4886 perform_random_steps_aux(Nr,Max,_) :- Nr >= Max,!, debug_println(9,performed_random_steps(Nr)).
4887 perform_random_steps_aux(Nr,Max,ErrorOnDeadlock) :-
4888 N1 is Nr+1,
4889 (perform_random_step(N1)
4890 -> perform_random_steps_aux(N1,Max,ErrorOnDeadlock)
4891 ; /* deadlock */
4892 write_xml_element_to_log(deadlock_found,[step/Nr]),
4893 (ErrorOnDeadlock=true, \+ option(no_deadlocks)) ->
4894 print_error('Deadlock occurred during -animate, at step number:'), print_error(Nr),
4895 error_occurred(animate)
4896 ; print('% Deadlock occurred during -animate, at step number:'), print(Nr),nl
4897 ).
4898
4899 perform_random_initialisation_if_necessary(Steps) :-
4900 b_or_z_mode, current_state_id(State), State=root,!, perform_random_initialisation(Steps).
4901 perform_random_initialisation_if_necessary(0).
4902
4903 perform_random_initialisation :- perform_random_initialisation(_).
4904 perform_random_initialisation(Steps) :- current_state_id(State), State \= root, !,
4905 print_error('init can only be used in initial state'), print_error(State),error_occurred(initialisation),
4906 Steps=0.
4907 perform_random_initialisation(Steps) :- b_mode, b_machine_has_constants_or_properties,!,
4908 (perform_random_step(Ops,_Len,RanChoice,1)
4909 -> nth1(RanChoice,Ops,Choice), %print(Choice),nl,
4910 (Choice = 'PARTIAL_SETUP_CONSTANTS'
4911 -> error_occurred(setup_constants_inconsistent)
4912 ; true)
4913 ; error_occurred(setup_constants_fails),fail), % $setup_constants TODO: properties unknown or unsat
4914 perform_random_init_after_setup_constants, Steps=2. % $initialise_machine
4915 perform_random_initialisation(Steps) :- (perform_random_step(1) -> Steps=1 ; error_occurred(initialisation_fails),fail).
4916
4917
4918 perform_random_init_after_setup_constants :- \+ option(initialise), we_need_only_static_assertions(_),!,
4919 printsilent('% NOT INITIALISING MACHINE (not required)'),nls.
4920 % debug_println(20,'% NOT INITIALISING MACHINE (not required)').
4921 perform_random_init_after_setup_constants :-
4922 (perform_random_step(2) % 2 is the step nr not the number of steps
4923 -> true
4924 ; error_occurred(initialisation_fails),
4925 fail).
4926
4927 :- use_module(cbcsrc(enabling_analysis),[tcltk_cbc_enabling_analysis/1, print_enable_table/1, is_timeout_enabling_result/1]).
4928 do_enabling_analysis_csv(EnablingCsvFile,NOW) :-
4929 start_probcli_timer(Timer1),
4930 start_xml_feature(enabling_analysis,file,EnablingCsvFile,FINFO),
4931 tcltk_cbc_enabling_analysis(list(R)),
4932 stop_probcli_timer(Timer1,'% Finished CBC Enabling Analysis',_TotWallTime),
4933 print_cbc_stats(R,NOW),
4934 debug_println(9,writing_to_file(EnablingCsvFile)),
4935 my_tell(EnablingCsvFile),
4936 print_enable_table(R),
4937 told,!,
4938 stop_xml_feature(enabling_analysis,FINFO).
4939 do_enabling_analysis_csv(EnablingCsvFile,_) :-
4940 add_error(enabling_analysis,'Enabling analysis failed',EnablingCsvFile),
4941 stop_xml_group_in_log(enabling_analysis).
4942
4943 print_cbc_stats(Res,_NOW) :- length(Res,Len), Ops is Len-2, % Header + Init
4944 CBC_Calls is Ops*(Ops+1), % +1 for INITIALISATION
4945 findall(TO,(member(list([_|T]),Res), member(TO,T),is_timeout_enabling_result(TO)),TOS),
4946 length(TOS,NrTOS),
4947 format('% CBC Enabling Stats:~n% Nr of events: ~w~n% Nr of cbc calls: ~w, Timeout results: ~w~n',[Ops,CBC_Calls,NrTOS]),
4948 write_xml_element_to_log(cbc_enabling_stats,[nr_events/Ops,cbc_calls/CBC_Calls,nr_timeouts/NrTOS]).
4949
4950
4951 :- use_module(cbcsrc(enabling_analysis),[feasible_operation_with_timeout/3]).
4952 do_feasibility_analysis(ATimeOut,EnablingCsvFile) :-
4953 arg_is_number(ATimeOut,TimeOut),
4954 start_xml_feature(feasibility_analysis,file,EnablingCsvFile,FINFO),
4955 findall(list([Op,Res]),feasible_operation_with_timeout(Op,TimeOut,Res),R),
4956 debug_println(9,writing_to_file(EnablingCsvFile)),
4957 my_tell(EnablingCsvFile),
4958 print_enable_table([list(['Event','Feasibility'])|R]),
4959 told,!,
4960 stop_xml_feature(feasibility_analysis,FINFO).
4961 do_feasibility_analysis(_,EnablingCsvFile) :-
4962 add_error(feasibility_analysis,'Feasibility analysis failed',EnablingCsvFile),
4963 stop_xml_group_in_log(feasibility_analysis).
4964
4965 :- use_module(b_read_write_info,[tcltk_read_write_matrix/1]).
4966 generate_read_write_matrix(CsvFile) :-
4967 tcltk_read_write_matrix(list(Matrix)),
4968 my_tell(CsvFile),
4969 print_enable_table(Matrix),
4970 told,!.
4971 generate_read_write_matrix(CsvFile) :-
4972 add_error(read_write_matrix,'Generating Read-Write-Matrix failed',CsvFile).
4973
4974
4975 my_tell(File) :-
4976 catch(
4977 tell(File),
4978 error(_E,_), % existence_error(_,_)
4979 add_error_fail(tell,'File cannot be written to: ',File)).
4980
4981 print_options([],_).
4982 print_options([H|T],N) :-
4983 print(' '), print(N), print(':'), print(H),nl,
4984 N1 is N+1,
4985 print_options(T,N1).
4986
4987 print_nr_list(List) :- print_nr_list(List,0,1,no_repeats).
4988
4989 print_nr_list([],NM1,_,Repeats) :- !, print_repeats(NM1,Repeats).
4990 print_nr_list([H|T],_,N,repeated(H,SinceN)) :- !, N1 is N+1,
4991 print_nr_list(T,N,N1,repeated(H,SinceN)).
4992 print_nr_list([H|T],NM1,N,Repeats) :- !,
4993 print_repeats(NM1,Repeats),
4994 N1 is N+1,
4995 print_nr_list(T,N,N1,repeated(H,N)).
4996 print_nr_list(X,_,_,_) :- print('### not a list: '), print(X),nl.
4997
4998 print_repeats(N,repeated(H,N)) :- !,
4999 format(' ~w: ~w~n',[N,H]).
5000 print_repeats(N,repeated(H,Since)) :- !, Repeats is 1+N-Since,
5001 format(' ~w - ~w: ~w (~w repetitions)~n',[Since,N,H,Repeats]).
5002 print_repeats(_,_).
5003
5004 print_bindings([]) :- !.
5005 print_bindings([binding(Var,_,PPV)|T]) :- !, print(Var),print('='),print(PPV),
5006 (T=[] -> true ; print(', '), print_bindings(T)).
5007 print_bindings([binding(Var,_,PPV,_Tag)|T]) :- !, print(Var),print('='),print(PPV),
5008 (T=[] -> true ; print(', '), print_bindings(T)).
5009 print_bindings(X) :- print('### Internal Error: illegal binding list: '), print(X),nl.
5010
5011 :- dynamic expected_error_occurred/1.
5012 :- dynamic error_did_not_occur/1.
5013 reset_expected_error_occurred :- retractall(expected_error_occurred(_)).
5014 check_all_expected_errors_occurred(NOW) :-
5015 %error_manager:display_error_statistics,
5016 get_errors, get_state_space_errors,
5017 retractall(error_did_not_occur(_)),
5018 expected_error(Type),
5019 \+ expected_error_occurred(Type),
5020 format_with_colour_nl(user_error,[red],'*** Expected Error of following type to occur: ~w',[Type]),
5021 writeln_log_time(expected_error_did_not_occur(NOW,Type)),
5022 assertz(error_did_not_occur(Type)),
5023 (option(strict_raise_error) -> definite_error_occurred ; fail).
5024 check_all_expected_errors_occurred(_NOW) :-
5025 findall(1,expected_error(_),EE), length(EE,NrExpected),
5026 (NrExpected>0
5027 -> findall(1,error_did_not_occur(_),EDNO), length(EDNO,NrNotOcc),
5028 (NrNotOcc>0
5029 -> format_with_colour_nl(user_error,[red],'*** Some expected errors (~w/~w) did NOT occur!',[NrNotOcc,NrExpected])
5030 ; format_with_colour_nl(user_output,[green],'All expected errors (~w) occurred.',[NrExpected])
5031 )
5032 ; true).
5033
5034 expected_error(Type) :- option(expect_error(Type)).
5035 expected_error(Type) :- option(expect_error_pos(Type,_Line,_Col)).
5036
5037 error_occurred(warning(Type)) :- !, error_occurred(Type,warning).
5038 error_occurred(Type) :- error_occurred(Type,error).
5039
5040 get_error_category_and_type(warning(Cat),Category,Type) :- !, Category=Cat,Type=warning.
5041 get_error_category_and_type(C,C,error).
5042
5043 error_occurred_with_msg(Type,Msg) :- error_occurred_with_msg(Type,Msg,not_yet_extracted).
5044 error_occurred_with_msg(warning(Type),Msg,Span) :- !, error_occurred(Type,warning,Span,Msg).
5045 error_occurred_with_msg(Type,Msg,Span) :- error_occurred(Type,error,Span,Msg).
5046
5047 error_occurred(Type,ErrOrWarn) :- error_occurred(Type,ErrOrWarn,not_yet_extracted,'').
5048
5049 error_occurred(Type,ErrOrWarning,ExtractedSpan,Msg) :-
5050 option(expect_error_pos(Type,Line,Col)),!,
5051 write_xml_element_to_log(expected_error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg]),
5052 assertz(expected_error_occurred(Type)),
5053 (get_error_or_warning_span(ExtractedSpan,Type,EL,EC)
5054 -> (option(expect_error_pos(Type,EL,EC))
5055 -> debug_println(9,expect_error_pos_ok(Type,EL,EC))
5056 ; format('*** Unexpected line ~w and column ~w for error ~w!~n*** Expected line ~w and column ~w.~n',[EL,EC,Type,Line,Col]),
5057 definite_error_occurred
5058 )
5059 ; format('*** Could not obtain position information for error ~w! Expected line ~w and column ~w.~n',[Type,Line,Col]),
5060 %display_error_statistics,
5061 definite_error_occurred).
5062 error_occurred(Type,ErrOrWarning,ExtractedSpan,Msg) :-
5063 functor(Type,FType,_),
5064 option(expect_error(FType)),!,
5065 inc_counter(cli_expected_errors),
5066 get_xml_span(ExtractedSpan,XML),
5067 write_xml_element_to_log(expected_error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg|XML]),
5068 assertz(expected_error_occurred(FType)).
5069 error_occurred(Type,ErrOrWarning,ExtractedSpan,Msg) :-
5070 (probcli_time_stamp(NOW) -> true ; NOW=unknown),
5071 writeln_log(error_occurred(NOW,Type)),
5072 get_xml_span(ExtractedSpan,XML),
5073 (functor(Type,FType,_),option(optional_error(FType)) ->
5074 write_xml_element_to_log(optional_error_occurred,[category/FType, (type)/ErrOrWarning, message/Msg|XML]),
5075 formatsilent('% Optional error occured: ~w~n',[Type])
5076 ;
5077 write_xml_element_to_log(error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg|XML]),
5078 (ErrOrWarning = warning -> safe_inc_counter(cli_warnings) ; safe_inc_counter(cli_errors)),
5079 flush_output, % ensure we can later associate position of error message
5080 (option(strict_raise_error) ->
5081 print_error('*** Unexpected error occurred ***'),
5082 print_error(Type),
5083 findall(Err,option(expect_error(Err)),Ls), (Ls=[] -> true ; print_error(expected(Ls))),
5084 definite_error_occurred
5085 ; ErrOrWarning=error,serious_error(Type)
5086 -> print_error('*** Serious error occurred ***'),
5087 print_error(Type),
5088 definite_error_occurred
5089 ; print_probcli_error_non_strict(Type,ErrOrWarning)
5090 )
5091 ).
5092
5093 safe_inc_counter(Counter) :-
5094 catch(inc_counter(Counter), E,
5095 format(user_error,'~n*** Exception in counter library, probably not yet initialized: ~w.~n~n',[E])).
5096
5097
5098 get_xml_span(Span,XML) :- extract_file_line_col(Span,FullFilename,Line,Col,EndLine,EndCol),!,
5099 XML = [file/FullFilename,start_line/Line,end_line/EndLine,start_col/Col,end_col/EndCol|XT],
5100 get_xml_add_description(Span,XT).
5101 get_xml_span(Span,XML) :- get_xml_add_description(Span,XML).
5102
5103 get_xml_add_description(Span,XML) :-
5104 extract_additional_description(Span,Msg),!,
5105 XML = [additional_description/Msg].
5106 get_xml_add_description(_,[]).
5107
5108 get_error_or_warning_span(not_yet_extracted,Type,EL,EC) :- check_error_span_file_linecol(Type,_File,EL,EC,_,_).
5109 get_error_or_warning_span(not_yet_extracted,Type,EL,EC) :- check_error_span_file_linecol(warning(Type),_File,EL,EC,_,_).
5110 get_error_or_warning_span(Span,_,EL,EC) :- Span \= not_yet_extracted, extract_line_col(Span,EL,EC,_,_).
5111
5112
5113 % a list of serious errors: if these occur; then return code different from 0 even in non-strict mode
5114 serious_error(get_java_command_path).
5115 serious_error(internal_error(_)).
5116
5117 print_probcli_error_non_strict(parse_machine_predicate_error,_) :-
5118 !. % have already been reported
5119 print_probcli_error_non_strict(Type,ErrOrWarning) :-
5120 (ErrOrWarning=warning -> print_error('*** warning occurred ***')
5121 ; print_error('*** error occurred ***')),
5122 print_error(Type).
5123
5124 definite_error_occurred :- print_error('*** Abnormal termination of probcli !'),
5125 (file_loaded(_,File) -> print_error('*** for_file'(File)) ; true),
5126 (current_probcli_command(Cmd) -> print_error('*** for_command'(Cmd)) ; true),
5127 (probcli_time_stamp(NOW) -> halt_prob(NOW,1)
5128 ; writeln_log(halt(1)),
5129 halt_exception(1)
5130 ).
5131
5132 :- dynamic current_probcli_command/1.
5133 set_current_probcli_command(X) :- retractall(current_probcli_command(_)),
5134 assertz(current_probcli_command(X)).
5135 unset_current_probcli_command :- retractall(current_probcli_command(_)).
5136
5137 halt_prob(ExitCode) :-
5138 (probcli_time_stamp(NOW) -> halt_prob(NOW,ExitCode) ; halt_prob(0,ExitCode)).
5139 halt_prob(NOW,ExitCode) :-
5140 write_xml_element_to_log(probcli_halted_prematurely,[now/NOW]),
5141 close_all_xml_groups_in_log_until('probcli-run'),
5142 print_accumulated_infos_if_necessary,
5143 stop_xml_probcli_run(NOW),
5144 halt_exception(ExitCode). % will announce stop_prob event
5145
5146
5147 :- dynamic accumulated_infos/3, individual_file_infos/3, merged_individual_file_infos/3.
5148 accumulate_infos(Context,Infos) :-
5149 (option(benchmark_info_csv_output(_,_,_)) -> true % -bench_csv
5150 ; option(expect_accumulated_info(_)) -> true), % -bench_expect
5151 file_loaded(_,File),
5152 get_additional_infos(Infos,Infos2), % additional infos if -machine_stats provided
5153 sort(Infos2,SInfos), % infos is a list of the form Info-Value
5154 assert_individual_file_infos(File,Context,SInfos),
5155 fail.
5156 accumulate_infos(Context,Infos) :- accumulate_infos_2(Context,Infos).
5157
5158 % accumulate some default infos like .prob loading time if no command has accumulated anything yet
5159 accumulate_default_infos :- file_loaded(_,File), \+ individual_file_infos(File,_,_),!,
5160 accumulate_infos(no_command,[]).
5161 accumulate_default_infos.
5162
5163 assert_individual_file_infos(File,Context,SInfos) :-
5164 debug_println(19,assert_file_infos(File,Context,SInfos)),
5165 assertz(individual_file_infos(File,Context,SInfos)), % store for later csv summary printing
5166 check_required_info_options(SInfos,Context).
5167
5168 % useful if this is not related to a loaded file, like -eval_file:
5169 accumulate_file_infos(File,Context,Infos) :-
5170 get_additional_stats(Infos,Infos2),
5171 sort(Infos2,SInfos), % infos is a list of the form Info-Value
5172 assert_individual_file_infos(File,Context,SInfos).
5173
5174 % join/merge accumulated infos for multiple runs (benchmarking) for a particular context/category
5175 % currently we support this for model-checking
5176 merge_accumulated_infos(Context) :- individual_file_infos(File,Context,_),!,
5177 findall(Infos,individual_file_infos(File,Context,Infos),[Infos1|RestInfos]),
5178 merge_acc(Infos1,RestInfos,1,Result),
5179 assertz(merged_individual_file_infos(File,Context,Result)).
5180
5181 merge_acc(Cur,[],_,Cur).
5182 merge_acc(Cur,[Next|T],Nr,Res) :-
5183 N1 is Nr+1,
5184 merge_acc_infos(Cur,Next,N1,NextCur),
5185 merge_acc(NextCur,T,N1,Res).
5186
5187 % merge two accumulated infos lists
5188 merge_acc_infos([],S,_,Res) :- !, Res=S.
5189 merge_acc_infos(S,[],_,Res) :- !, Res=S.
5190 merge_acc_infos([C1|T1],[C2|T2],Nr,[Cat-ResVal|MT]) :-
5191 get_accumulated_info(C1,Cat,Val1), get_accumulated_info(C2,Cat,Val2),
5192 merge_value(Cat,Val1,Val2,Nr,ResVal),!,
5193 merge_acc_infos(T1,T2,Nr,MT).
5194 merge_acc_infos([C1|T1],T2,Nr,[C1|MT]) :-
5195 add_warning(merge_acc_infos,'Missing value: ',C1),
5196 merge_acc_infos(T1,T2,Nr,MT).
5197
5198 % merge individual values
5199 merge_value(Cat,Val1,_Val2,_,ResVal) :- keep_first_value(Cat),!, ResVal=Val1.
5200 merge_value(_,Val,Val,_,ResVal) :- !, ResVal=Val.
5201 merge_value(Cat,Val1,Val2,Nr,ResVal) :- compute_average(Cat),!, ResVal is (Val1*(Nr-1)/Nr) + (Val2 / Nr).
5202 merge_value(Cat,Val1,Val2,Nr,ResVal) :-
5203 add_warning(merge_value,'Differing values: ',val(Cat,Val1,Val2)),
5204 ResVal is (Val1*(Nr-1)/Nr) + (Val2 / Nr).
5205
5206 compute_average(runtime).
5207 compute_average(total_runtime).
5208 compute_average(walltime).
5209
5210 keep_first_value(memory_used). % memory consumption of the first run is relevant
5211
5212
5213 % also store additional infos if -machine_stats provided; useful for benchmarking/articles
5214 :- use_module(covsrc(hit_profiler),[retract_profile_stats/2]).
5215 get_additional_infos(I,Res) :- option(cli_print_machine_info(statistics)),!,
5216 findall(Key-Nr,b_machine_statistics(Key,Nr),I2,I),
5217 get_additional_stats(I2,Res).
5218 get_additional_infos(I,Res) :- get_additional_stats(I,Res).
5219 get_additional_stats(I,Res) :-
5220 findall(Key-Nr,retract_profile_stats(Key,Nr),Res,I). % include additional profiling stats and retract/reset them
5221
5222 accumulate_infos_2(_,[]).
5223 accumulate_infos_2(Context,[Info|T]) :- get_accumulated_info(Info,FF,Nr),
5224 (number(Nr) -> Nr>0 ; add_internal_error('Can only accumulate numbers:',FF-Nr),fail), !,
5225 (retract(accumulated_infos(Context,FF,OldNr)) ->true ; OldNr=0),
5226 N1 is OldNr+Nr,
5227 assertz(accumulated_infos(Context,FF,N1)),
5228 accumulate_infos_2(Context,T).
5229 accumulate_infos_2(Context,[_|T]) :- accumulate_infos_2(Context,T).
5230 get_accumulated_info(FF-Nr,FF,Nr).
5231 get_accumulated_info(FF/Nr,FF,Nr).
5232
5233 :- use_module(tools_io,[safe_intelligent_open_file/3]).
5234 print_accumulated_infos(NrFilesProcessed) :-
5235 (option(benchmark_info_csv_output(File,FileMode,CSVMode)) % TODO: allow multiple entries
5236 -> safe_intelligent_open_file(File,FileMode,Stream) % FileMode is write or append
5237 ; Stream=user_output, CSVMode=csv
5238 ),
5239 formatsilent('Generating benchmark output for ~w files, mode=~w~n',[NrFilesProcessed,CSVMode]),
5240 call_cleanup(pr_acc_infos_aux(Stream,NrFilesProcessed,FileMode,CSVMode),
5241 close(Stream)), !.
5242 print_accumulated_infos(NrFilesProcessed) :-
5243 add_internal_error('Call failed:',print_accumulated_infos(NrFilesProcessed)).
5244
5245 %get_csv_mode(csv,csv).
5246 %get_csv_mode(tex,latex).
5247 %get_csv_mode(latex,latex).
5248
5249 %:- use_module(library(system),[ datime/1]).
5250 pr_acc_infos_aux(Stream,NrFilesProcessed,FileMode,CSVMode) :-
5251 (NrFilesProcessed>1,accumulated_infos(_,_,_) -> true ; option(benchmark_info_csv_output(_,_,_))),!,
5252 print_individual_file_infos_csv(Stream,FileMode,CSVMode),
5253 start_xml_group_in_log(summary,files_processed,NrFilesProcessed),
5254 ((FileMode = append ; NrFilesProcessed = 1)
5255 -> true % do not print accumulated info line
5256 ; print_summary_file_infos_csv(Stream,FileMode,CSVMode,NrFilesProcessed),
5257 findall(Context-F-Nr,accumulated_infos(Context,F,Nr),L), sort(L,SL), % supported for model_checking only
5258 (SL=[] -> true
5259 ; format(Stream,'Analysis summary (~w files processed): ',[NrFilesProcessed]),
5260 maplist(prob_cli:pracc(Stream),SL),nl(Stream)
5261 )
5262 ),
5263 % TO DO: write infos to XML log
5264 (option(print_version(VERSIONKIND)) ->
5265 datime(datime(Year,Month,Day,Hour,Min,_Sec)),
5266 format(Stream,'CSV file generated at ~w:~w on the date ~w/~w/~w using probcli:~n',[Hour,Min,Year,Month,Day]),
5267 print_version(VERSIONKIND,Stream),
5268 print_csv_prefs(Stream)
5269 ; true),
5270 (option(cli_print_statistics(memory)) -> print_memory_statistics(Stream) ; true),
5271 stop_xml_group_in_log_no_statistics(summary).
5272 pr_acc_infos_aux(_,_NrFilesProcessed,_Mode,_).
5273
5274 print_csv_prefs(Stream) :- \+ \+ option(set_preference_group(_,_)),
5275 format(Stream,'PREFERENCE GROUP,Setting~n',[]),
5276 option(set_preference_group(P,V)),
5277 format(Stream,'~w,~w~n',[P,V]),
5278 fail.
5279 print_csv_prefs(Stream) :- \+ \+ option(set_pref(_,_)),
5280 format(Stream,'PREFERENCE,Value~n',[]),
5281 option(set_pref(P,V)),
5282 format(Stream,'~w,~w~n',[P,V]),
5283 fail.
5284 print_csv_prefs(_).
5285
5286 pracc(Stream,Context-F-Nr) :- format(Stream,'~w:~w:~w ',[Context,F,Nr]).
5287 :- use_module(probsrc(tools),[gen_relative_path_to_cur_dir/2]).
5288 % print CSV summary of run
5289 print_individual_file_infos_csv(Stream,FileMode,CSVMode) :-
5290 retractall(accumulated_file_infos(_,_)), % reset sum info
5291 findall(C,individual_file_infos(_,C,_),All), sort(All,AllContexts),
5292 member(Context,AllContexts), % iterate over all Contexts
5293 (individual_file_infos(_,Context,HInfos) -> true), % pick one as header
5294 (FileMode=append
5295 -> true % do not print header line, we append to an existing table
5296 ; format(Stream,'~nFILE,ANALYSIS,',[]),
5297 print_titles(HInfos,CSVMode,Stream),nl(Stream)
5298 ),
5299 % TO DO: ensure Infos and SHInfos identical, else add 0 for missing categories
5300 (merged_individual_file_infos(File,Context,Infos)
5301 -> true % just print averages
5302 ; individual_file_infos(File,Context,Infos)
5303 ),
5304 gen_relative_path_to_cur_dir(File,RelFile),
5305 format(Stream,'~w,~w,',[RelFile,Context]),
5306 print_vals(Infos,HInfos,CSVMode,Stream),nl(Stream),
5307 fail.
5308 print_individual_file_infos_csv(_,_,_).
5309
5310 % print a line with the total sum of accumulated_file_infos
5311 print_summary_file_infos_csv(Stream,_FileMode,CSVMode,NrFilesProcessed) :-
5312 (individual_file_infos(_,_Context,HInfos) -> true), % pick one as header
5313 format(Stream,'Total (~w files),\'-\',',[NrFilesProcessed]),
5314 findall(Header-Count,accumulated_file_infos(Header,Count),SumInfo),
5315 print_vals(SumInfo,HInfos,CSVMode,Stream),nl(Stream).
5316
5317
5318 % print file infos list
5319 print_vals(_,[],_,_) :- !.
5320 print_vals([H|T],[Header|HT],Mode,Stream) :- get_accumulated_info(Header,Title,_),
5321 get_accumulated_info(H,Title,Nr), !,
5322 write_atom(Mode,Stream,Nr),
5323 update_accumulated_file_infos(Title,Nr),
5324 (T=[] -> write_csv_terminator(Mode,Stream) ; write_csv_sep(Mode,Stream), print_vals(T,HT,Mode,Stream)).
5325 print_vals(Vals,[_|HT],Mode,Stream) :- % a value is missing for this file
5326 write(Stream,'-'),
5327 (HT=[] -> write_csv_terminator(Mode,Stream) ; write_csv_sep(Mode,Stream), print_vals(Vals,HT,Mode,Stream)).
5328 print_titles([],_,_).
5329 print_titles([H|T],Mode,Stream) :- get_accumulated_info(H,FF,_),
5330 write_atom(Mode,Stream,FF),
5331 (T=[] -> write_csv_terminator(Mode,Stream) ; write_csv_sep(Mode,Stream), print_titles(T,Mode,Stream)).
5332
5333 :- dynamic accumulated_file_infos/2.
5334 update_accumulated_file_infos(Header,Count) :-
5335 (retract(accumulated_file_infos(Header,Old)) -> true ; Old=0),
5336 (number(Count), number(Old) -> New is Old+Count ; New = '-'),
5337 assert(accumulated_file_infos(Header,New)).
5338
5339 :- use_module(probsrc(tools),[latex_escape_atom/2]).
5340 write_atom(latex,Stream,Atom) :- atom(Atom), latex_escape_atom(Atom,EAtom),!,
5341 write(Stream,EAtom).
5342 write_atom(_,Stream,Term) :- write(Stream,Term).
5343
5344 write_csv_sep(latex,Stream) :- !,write(Stream,' & ').
5345 write_csv_sep(_,Stream) :- write(Stream,',').
5346 write_csv_terminator(latex,Stream) :- !,write(Stream,' \\\\').
5347 write_csv_terminator(_,_).
5348
5349 write_important_xml_element_to_log(Category,Infos) :-
5350 include(prob_cli:important_info,Infos,II),
5351 write_xml_element_to_log(Category,II).
5352 important_info(FF/Nr) :-
5353 \+ irrelevant_xml_info(FF),
5354 (Nr=0 -> \+ irrelevant_xml_if_zero(FF) ; true).
5355 irrelevant_xml_info(true_after_expansion).
5356 irrelevant_xml_info(false_after_expansion).
5357 irrelevant_xml_info(unknown_after_expansion).
5358 irrelevant_xml_info(total_after_expansion).
5359 irrelevant_xml_if_zero(timeout).
5360 irrelevant_xml_if_zero(enum_warning).
5361
5362 % check that accumulated infos for a given run correspond to expected values provided by user (-bench_expect Label Nr)
5363 check_required_info_options(Infos,ErrType) :-
5364 option(expect_accumulated_info(Expected)), % Typically Expected = Label-Nr
5365 check_required_infos([Expected],Infos,ErrType),
5366 fail.
5367 check_required_info_options(_,_).
5368
5369 % check_required_infos(ExpectedInfos,ActualInfos,ErrType)
5370 check_required_infos([],_,_).
5371 check_required_infos([H|T],Infos,ErrType) :-
5372 (check_single_info(H,Infos)
5373 -> check_required_infos(T,Infos,ErrType)
5374 ; translate_err_type(ErrType,ES),
5375 format_with_colour_nl(user_error,[red],
5376 '*** Unexpected result while checking: ~w~n*** expected : ~w~n*** in : ~w',
5377 [ES,H,Infos]),
5378 error_occurred(ErrType)).
5379 translate_err_type(check_assertions,'ASSERTIONS') :- !.
5380 translate_err_type(cli_check_assertions,'ASSERTIONS') :- !.
5381 translate_err_type(check_goal,'GOAL') :- !.
5382 translate_err_type(load_po_file,'PROOF OBLIGATIONS') :- !.
5383 translate_err_type(cli_wd_check,'WD PROOF OBLIGATIONS') :- !.
5384 translate_err_type(check_cache_stats,'CACHE STATISTICS') :- !.
5385 translate_err_type(X,X).
5386
5387 check_single_info(Label-Nr,Infos) :- !, member(Label-ActualNr,Infos),
5388 match_info(Nr,ActualNr).
5389 check_single_info(H,List) :- member(H,List).
5390 match_info(X,X).
5391 match_info(comparison_operator(Comp,Nr),ActualNr) :-
5392 number(Nr), number(ActualNr),call(Comp,ActualNr,Nr).
5393
5394 :- use_module(tools_platform, [max_tagged_integer/1]).
5395 :- public mc_ok_arg/2.
5396 mc_ok_arg(Arg,X) :- Arg==all,!,max_tagged_integer(X).
5397 mc_ok_arg(Arg,N) :- arg_is_number(Arg,N).
5398
5399
5400 :- dynamic option/1.
5401 assert_all_options([]).
5402 assert_all_options([Opt|T]) :- assert_option(Opt),
5403 assert_all_options(T).
5404
5405 :- use_module(pathes_extensions_db,[probcli_command_requires_extension/2]).
5406 cli_option_not_available(Opt,ProBExtension,Reason) :-
5407 probcli_command_requires_extension(Opt,ProBExtension),
5408 unavailable_extension(ProBExtension,Reason).
5409
5410 check_unavailable_options :-
5411 ? option(Opt),
5412 cli_option_not_available(Opt,ProBExtension,Reason),
5413 (recognised_option(Name,Opt,_,_) -> true ; Name=Opt),
5414 ajoin(['probcli command ', Name,' cannot be performed because extension not available (',Reason,'):'],Msg),
5415 add_error(probcli,Msg,ProBExtension),
5416 fail.
5417 check_unavailable_options.
5418
5419 assert_option(silent) :- option(force_no_silent),!. % ignoring silent flag
5420 assert_option(Opt) :- assertz(option(Opt)), treat_option(Opt).
5421
5422 :- use_module(tools_printing,[set_no_color/1, reset_no_color_to_default/0]).
5423 treat_option(silent) :- !, set_silent_mode(on),set_error_manager_silent_mode(on).
5424 treat_option(force_no_silent) :- !, set_silent_mode(off),set_error_manager_silent_mode(off).
5425 treat_option(no_color) :- !, set_no_color(true).
5426 treat_option(_).
5427
5428 reset_options :- retractall(option(_)),
5429 set_silent_mode(off), set_error_manager_silent_mode(off),
5430 reset_no_color_to_default.
5431
5432 % replace a leading double-dash -- by a single dash and replace inner dashes by underscores
5433 normalise_option_atom(X,RX) :- atom(X),!,
5434 atom_codes(X,CodesX),
5435 % remove leading dash
5436 (CodesX=[45,45,H|T], H\=45 % Double dash --Option
5437 -> maplist(prob_cli:convert_dash_to_underscore,[H|T],HT2),
5438 RXCodes=[45|HT2]
5439 ; CodesX = [Dash|T], is_dash(Dash) % single dash
5440 -> maplist(prob_cli:convert_dash_to_underscore,T,T2),
5441 RXCodes=[45|T2]
5442 ; maplist(prob_cli:convert_dash_to_underscore,CodesX,RXCodes)
5443 ),
5444 atom_codes(RX,RXCodes).
5445 normalise_option_atom(T,T).
5446
5447 is_dash(45). % regular dash
5448 is_dash(8212). % Unicode double dash; sometimes automatically generated from -- by e.g., macOS Mail program
5449
5450 :- public normalise_pref_name/2. % called via recognised_option
5451 % replace dashes by underscores
5452 normalise_pref_name(X,RX) :- atom(X),!,
5453 atom_codes(X,CodesX),
5454 maplist(prob_cli:convert_dash_to_underscore,CodesX,C2),
5455 atom_codes(RX,C2).
5456 normalise_pref_name(T,T).
5457
5458 convert_dash_to_underscore(45,R) :- !, R=95.
5459 convert_dash_to_underscore(X,X).
5460
5461 recognised_cli_option(X,Opt,Args,Condition) :- normalise_option_atom(X,RX),
5462 ? recognised_option(RX,Opt,Args,Condition).
5463
5464 % get a list of all options
5465 get_all_options(SOpts) :-
5466 findall(O, recognised_option(O,_,_,_), Opts),
5467 sort(Opts,SOpts).
5468
5469 :- use_module(tools_matching,[fuzzy_match_codes_lower_case/2]).
5470 % compute a set of possible fuzzy matches
5471 get_possible_fuzzy_match_options(Option,FuzzyMatches) :-
5472 normalise_option_atom(Option,RX),
5473 atom_codes(RX,OCodes),
5474 get_all_options(SOpts),
5475 findall(Target,(member(Target,SOpts),atom_codes(Target,TargetCodes),
5476 fuzzy_match_codes_lower_case(OCodes,TargetCodes)),FuzzyMatches).
5477
5478 :- use_module(tools_matching,[get_possible_completions_msg/3]).
5479 get_possible_options_completion_msg(Option,Msg) :-
5480 normalise_option_atom(Option,RX),
5481 get_all_options(SOpts),
5482 get_possible_completions_msg(RX,SOpts,Msg).
5483
5484 recognised_option(X,Opt,[],true) :- recognised_option(X,Opt). % options without arguments
5485 recognised_option(X,Opt,Args,true) :- recognised_option(X,Opt,Args). % options with arguments but no code needed to check arguments
5486
5487 recognised_option('-mc',cli_mc(N,[]),[Arg],prob_cli:mc_ok_arg(Arg,N)).
5488 recognised_option('-bench_model_check',cli_mc(LimitNr,[reset_state_space,repeat(Rep)]),[Arg],tools:arg_is_number(Arg,Rep)) :- max_tagged_integer(LimitNr).
5489 recognised_option('-model_check',cli_mc(LimitNr,[]),[],true) :- max_tagged_integer(LimitNr).
5490 recognised_option('-timeout',timeout(N),[Arg],tools:arg_is_number(Arg,N)). % for model checking, refinement checking and for disprover per PO
5491 recognised_option('-time_out',timeout(N),[Arg],tools:arg_is_number(Arg,N)).
5492 recognised_option('-global_time_out',timeout(N),[Arg],tools:arg_is_number(Arg,N)). % better name, to avoid conflict with -p timeout N which also works
5493 recognised_option('-s',socket(S,true),[Arg],tools:arg_is_number(Arg,S)).
5494 recognised_option('-cc',coverage(N,N2,just_check_stats),[Arg,Arg2],
5495 (arg_is_number_or_wildcard(Arg,N),arg_is_number_or_wildcard(Arg2,N2))).
5496 recognised_option('-csp_guide',add_csp_guide(File),[File],
5497 prob_cli:check_file_arg(File,'csp_guide')).
5498 recognised_option('-prologOut',csp_translate_to_file(PlFile),[PlFile],
5499 prob_cli:check_file_arg(PlFile,'prologOut')).
5500 recognised_option('-load_state',load_state(Filename),[Filename],
5501 prob_cli:check_file_arg(Filename,'load_state')).
5502 recognised_option('-refchk',refinement_check(Filename,trace,100000),[Filename],
5503 prob_cli:check_file_arg(Filename,'refchk')).
5504 recognised_option('-ref_check',refinement_check(Filename,FailuresModel,100000),[Shortcut,Filename],
5505 (prob_cli:check_file_arg(Filename,'ref_check'),
5506 prob_cli:check_failures_mode(Shortcut,FailuresModel))).
5507 recognised_option('-refinement_check',Option,Args,Code) :- recognised_option('-refchk',Option,Args,Code).
5508 recognised_option('-hash',check_statespace_hash(H,_),[Arg],tools:arg_is_number(Arg,H)).
5509 recognised_option('-hash64',check_statespace_hash(H,'64bit'),[Arg],tools:arg_is_number(Arg,H)).
5510 recognised_option('-hash32',check_statespace_hash(H,'32bit'),[Arg],tools:arg_is_number(Arg,H)).
5511 recognised_option('-check_op_cache_stats',
5512 check_op_cache([next_state_calls-H1,inv_check_calls-H2,
5513 operations_cached-H3,invariants_cached-H4]),[Arg1,Arg2,Arg3,Arg4],
5514 (tools:arg_is_number_or_wildcard(Arg1,H1), tools:arg_is_number_or_wildcard(Arg2,H2),
5515 tools:arg_is_number_or_wildcard(Arg3,H3), tools:arg_is_number_or_wildcard(Arg4,H4))).
5516 recognised_option('-ltllimit',ltl_limit(Nr),[Arg], tools:arg_is_number(Arg,Nr)).
5517 recognised_option('-ltlfile',ltl_file(Filename),[Filename],
5518 prob_cli:check_file_arg(Filename,'ltlfile')).
5519 recognised_option('-check_disprover_result',cli_check_disprover_result([true-TNr,false-FNr,unknown-UNr,failure-0]),[T,F,U],
5520 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(F,FNr),arg_is_number_or_wildcard(U,UNr))).
5521 recognised_option('-aa',cli_check_assertions(all,[true/TNr,false/FNr,unknown/UNr]),[T,F,U],
5522 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(F,FNr),arg_is_number_or_wildcard(U,UNr))).
5523 recognised_option('-ma',cli_check_assertions(main,[true/TNr,false/FNr,unknown/UNr]),[T,F,U],
5524 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(F,FNr),arg_is_number_or_wildcard(U,UNr))).
5525 recognised_option('-wd',cli_wd_check(DNr,TNr),[D,T],
5526 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(D,DNr))).
5527 recognised_option('-check_cache_stats',cli_cache_stats_check([value_persistance_reused_transitions-RNr,
5528 value_persistance_stored_transitions-SNr]),[R,S],
5529 (arg_is_number_or_wildcard(S,SNr),arg_is_number_or_wildcard(R,RNr))).
5530 recognised_option('-kodkod_comparision',kodkod_comparision(Nr),[Arg],tools:arg_is_number(Arg,Nr)).
5531 recognised_option('-kodkod_performance',kodkod_performance(File,Nr),[File,Arg],tools:arg_is_number(Arg,Nr)).
5532 recognised_option('-animate',cli_random_animate(N,true),[Steps],tools:arg_is_number(Steps,N)).
5533 recognised_option('-simulate',cli_simulate(File,1,N,[]),[File,Steps],tools:arg_is_number(Steps,N)).
5534 recognised_option('-rt_simulate',cli_simulate(File,1,N,[simulation_speed/1]),[File,Steps],tools:arg_is_number(Steps,N)).
5535 recognised_option('-mc_simulate',cli_simulate(File,R,N,[]),[File,Reps,Steps],(tools:arg_is_number(Steps,N),tools:arg_is_number(Reps,R))).
5536 recognised_option('-simb_profile',cli_print_statistics(simb_profile),[],true).
5537 recognised_option('-simulate_until_ltl_ap',simb_ltl_stop_condition(LTL_Stop_AsAtom),[LTL_Stop_AsAtom],true).
5538 recognised_option('-simulate_until_time',simb_option(max_simulation_time(T)),[Time],tools:arg_is_number(Time,T)).
5539 recognised_option('-execute',execute(N,true,current_state(1)),[Steps],tools:arg_is_number(Steps,N)).
5540 recognised_option('-execute_repeat',execute(N,true,current_state(R)),[Steps,Rep],
5541 (tools:arg_is_number(Steps,N),tools:arg_is_number(Rep,R))).
5542 recognised_option('-execute_expect_steps',execute_expect_steps(N),[Steps],tools:arg_is_number(Steps,N)).
5543 recognised_option('-logxml_write_vars',logxml_write_ids(variables,Prefix),[Prefix],true).
5544 recognised_option('-logxml_write_ids',logxml_write_ids(all,Prefix),[Prefix],true).
5545 recognised_option('-zmq_master',zmq_master(Identifier),[Identifier], true).
5546 recognised_option('-cbc_tests', cbc_tests(Depth,EndPred,Output),[Depth,EndPred,Output],
5547 prob_cli:check_file_arg(Output,'cbc_tests')).
5548 recognised_option('-mcm_tests', mcm_tests(Depth,MaxStates,EndPred,Output),[Depth,MaxStates,EndPred,Output],
5549 prob_cli:check_file_arg(Output,'mcm_tests')).
5550 recognised_option('-test_description', test_description(File), [File],
5551 prob_cli:check_file_arg(File,'test_description')).
5552 recognised_option('-all_paths', all_deadlocking_paths(File), [File],
5553 prob_cli:check_file_arg(File,'all_paths')).
5554 recognised_option('-dot',dot_command(Category,File,default),[Category,File],
5555 prob_cli:check_file_arg(File,'dot')).
5556 recognised_option('-spdot',dot_command(state_space,File,default),[File], prob_cli:check_file_arg(File,'spdot')). % we keep this : it is shown in Wiki
5557 % recognised_option('-spmdot',dot_command(signature_merge,File,default),[File], prob_cli:check_file_arg(File,'spmdot')).
5558 % recognised_option('-spddot',dot_command(dfa_merge,File,default),[File], prob_cli:check_file_arg(File,'spddot')).
5559 % recognised_option('-sgdot',dot_command(state_as_graph,File,default),[File], prob_cli:check_file_arg(File,'sgdot')).
5560 recognised_option('-dotexpr',dot_command_for_expr(Category,Expr,File,[],default),[Category,Expr,File],
5561 prob_cli:check_file_arg(File,'dotexpr')).
5562 recognised_option('-dot_expr',Opt,Args,Call) :- recognised_option('-dotexpr',Opt,Args,Call).
5563 %recognised_option('-sgedot',dot_command_for_expr(expr_as_graph,Expr,File,[],default),[Expr,File], prob_cli:check_file_arg(File,'sgedot')).
5564 % recognised_option('-sptdot',dot_command_for_expr(transition_diagram,Expr,File,[],default),[Expr,File],prob_cli:check_file_arg(File,'sptdot')).
5565 %recognised_option('-invdot',dot_command(invariant,File,default),[File], prob_cli:check_file_arg(File,'invdot')).
5566 %recognised_option('-propdot',dot_command(properties,File,default),[File], prob_cli:check_file_arg(File,'propdot')).
5567 %recognised_option('-assdot',dot_command(assertions,File,default),[File], prob_cli:check_file_arg(File,'assdot')).
5568 %recognised_option('-deaddot',dot_command(deadlock,File,default)(File),[File], prob_cli:check_file_arg(File,'deaddot')).
5569 recognised_option('-puml',plantuml_command(Category,File),[Category,File],
5570 prob_cli:check_file_arg(File,'plantuml')).
5571 recognised_option('-pumlexpr',plantuml_command(Category,File,[Expr]),[Category,Expr,File],
5572 prob_cli:check_file_arg(File,'plantuml')).
5573 recognised_option('-puml_expr',Opt,Args,Call) :- recognised_option('-pumlexpr',Opt,Args,Call).
5574 recognised_option('-csv',csv_table_command(Category,[],[],File),[Category,File],
5575 prob_cli:check_file_arg(File,'csv')).
5576 recognised_option('-csvexpr',csv_table_command(Category,[Expr],[],File),[Category,Expr,File],
5577 prob_cli:check_file_arg(File,'csvexpr')).
5578 recognised_option('-csv_expr',Opt,Args,Call) :- recognised_option('-csvexpr',Opt,Args,Call).
5579 recognised_option('-csv_hist',Opt,Args,Call) :- recognised_option('-csvhist',Opt,Args,Call).
5580 recognised_option('-csvhist',evaluate_expression_over_history_to_csv_file(Expr,File),[Expr,File],
5581 prob_cli:check_file_arg(File,'csvhist')).
5582 %recognised_option('-get_min_max_coverage',csv_table_command(minmax_table,[],[text_output],File),[File]). % deprecated
5583 recognised_option('-min_max_coverage',csv_table_command(minmax_table,[],[text_output],File),[File],
5584 prob_cli:check_file_arg(File,'min_max_coverage')).
5585 recognised_option('-get_coverage_information',get_coverage_information(File),[File],
5586 prob_cli:check_file_arg(File,'get_coverage_information')).
5587 %recognised_option('-vc',csv_table_command(minmax_table,[],[text_output],user_output)).
5588 recognised_option('-read_write_matrix_csv',generate_read_write_matrix_csv(CsvFile),
5589 [CsvFile],
5590 prob_cli:check_file_arg(CsvFile,'read_write_matrix_csv')).
5591 recognised_option('-feasibility_analysis_csv',feasibility_analysis_csv(TimeOut,EnablingCsvFile),
5592 [TimeOut,EnablingCsvFile],
5593 prob_cli:check_file_arg(EnablingCsvFile,'feasibility_analysis_csv')).
5594 recognised_option('-l',log(Log,prolog),[Log],
5595 prob_cli:check_file_arg(Log,'l')).
5596 recognised_option('-log',log(Log,prolog),[Log],
5597 prob_cli:check_file_arg(Log,'log')).
5598 recognised_option('-logxml',log(Log,xml),[Log],
5599 prob_cli:check_file_arg(Log,'logxml')). % see cli_start_logging
5600 recognised_option('-logtlc',logtlc(Log),[Log],
5601 prob_cli:check_file_arg(Log,'logtlc')).
5602 recognised_option('-pp',pretty_print_internal_rep(File,'$auto',needed,ascii),[File],
5603 prob_cli:check_file_arg(File,'pp')).
5604 recognised_option('-ppunicode',pretty_print_internal_rep(File,'$auto',needed,unicode),[File],
5605 prob_cli:check_file_arg(File,'pp')).
5606 recognised_option('-ppf',pretty_print_internal_rep(File,'$auto',all,ascii),[File],
5607 prob_cli:check_file_arg(File,'ppf')).
5608 recognised_option('-ppAB',pretty_print_internal_rep(File,'$auto',all,atelierb),[File],
5609 prob_cli:check_file_arg(File,'ppAB')).
5610 recognised_option('-pp_with_name',pretty_print_internal_rep(File,MachName,all,ascii),[MachName,File],
5611 prob_cli:check_file_arg(File,'pp_with_name')). % provide explicit machine name
5612 recognised_option('-ppB',pretty_print_internal_rep_to_B(File),[File],
5613 prob_cli:check_file_arg(File,'ppB')). % deprecated; is now superseded by ppAB for Event-B machines
5614 recognised_option('-pppl',pretty_print_prolog_file(File),[File],
5615 prob_cli:check_file_arg(File,'pppl')).
5616 recognised_option('-pp_pl_file',pretty_print_prolog_file(File,OutFile),[File,OutFile],
5617 (prob_cli:check_file_arg(File,'pp_pl_file'),prob_cli:check_file_arg(OutFile,'pp_pl_file'))).
5618 recognised_option('-ppi',indent_main_b_file(File),[File],
5619 prob_cli:check_file_arg(File,'ppi')).
5620 recognised_option('-indent_b_file',indent_b_file_to_file(BFile,OutFile,[]),[BFile,OutFile], % indent some other file
5621 (prob_cli:check_file_arg(BFile,'indent_b_file'),prob_cli:check_file_arg(OutFile,'indent_b_file'))).
5622 recognised_option('-reformat_b_file',indent_b_file_to_file(BFile,OutFile,
5623 [insert_new_lines_before_keywords,insert_new_lines_after_keywords]),[BFile,OutFile], % reformat some other file
5624 (prob_cli:check_file_arg(BFile,'indent_b_file'),prob_cli:check_file_arg(OutFile,'indent_b_file'))).
5625 recognised_option('-save_state',save_state_space(Filename),[Filename],
5626 prob_cli:check_file_arg(Filename,'save_state')). % possibly save_state_space would be a better name
5627 recognised_option('-save',save_state_for_refinement(Filename),[Filename],
5628 prob_cli:check_file_arg(Filename,'save')).
5629 recognised_option('-sptxt',print_values(Filename),[Filename],
5630 prob_cli:check_file_arg(Filename,'sptxt')).
5631 recognised_option('-sstxt',print_all_values(Dirname),[Dirname],
5632 prob_cli:check_file_arg(Dirname,'sstxt')).
5633 recognised_option('-latex',process_latex_file(In,Out),[In,Out],
5634 (prob_cli:check_file_arg(In,'latex'),prob_cli:check_file_arg(Out,'latex'))).
5635 recognised_option('-bench_csv',benchmark_info_csv_output(File,write,csv),[File],prob_cli:check_file_arg(File,'bench_csv')).
5636 recognised_option('-bench_csv_append',benchmark_info_csv_output(File,append,csv),[File],prob_cli:check_file_arg(File,'bench_csv')).
5637 recognised_option('-bench_tex',benchmark_info_csv_output(File,write,latex),[File],prob_cli:check_file_arg(File,'bench_tex')).
5638 recognised_option('-bench_expect',expect_accumulated_info(Label-Nr),[Label,SNr],tools:(arg_is_number(SNr,Nr))).
5639 recognised_option('-trace_replay',trace_check(Style,File,default_trace_replay),[Style,File],prob_cli:check_file_arg(File,'trace_replay')). % Style can be json, prolog or B
5640 recognised_option('-det_trace_replay',trace_check(Style,File,deterministic_trace_replay),[Style,File],prob_cli:check_file_arg(File,'det_trace_replay')).
5641 recognised_option('-replay',eval_repl([File]),[File],prob_cli:check_file_arg(File,'replay')). % used to be -eval
5642 recognised_option('-state_trace',state_trace(File),[File],prob_cli:check_file_arg(File,'state_trace')).
5643 recognised_option('-typecheckertest',typechecker_test(File),[File],prob_cli:check_file_arg(File,'typecheckertest')).
5644 recognised_option('-enabling_analysis_csv',enabling_analysis_csv(EnablingCsvFile),[EnablingCsvFile],
5645 prob_cli:check_file_arg(EnablingCsvFile,'enabling_analysis_csv')).
5646 recognised_option('-dot_output',dot_analyse_output_prefix(Path),[Path],prob_cli:check_file_arg(Path,'dot_output')).
5647 recognised_option('-evaldot',evaldot(File),[File],prob_cli:check_file_arg(File,'evaldot')).
5648 recognised_option('-his',history(File),[File],prob_cli:check_file_arg(File,'his')).
5649 recognised_option('-visb_click',visb_click(SVGID),[SVGID],true).
5650 recognised_option('-visb',visb_history(JSONFile,HTMLFile,[]),[JSONFile,HTMLFile],
5651 (prob_cli:check_file_arg(JSONFile,'visb'),prob_cli:check_file_arg(HTMLFile,'visb'))).
5652 recognised_option('-visb_with_vars',
5653 visb_history(JSONFile,HTMLFile,[show_constants(all),show_sets(all),show_variables(all)]),
5654 [JSONFile,HTMLFile],
5655 (prob_cli:check_file_arg(JSONFile,'visb_with_vars'),prob_cli:check_file_arg(HTMLFile,'visb_with_vars'))).
5656 recognised_option('-rule_report',rule_report(File), [File], prob_cli:check_file_arg(File,'rule_report')).
5657 recognised_option('-proof_export',proof_export(Style,File), [Style,File], prob_cli:check_file_arg(File,'proof_export')). % Style can be html, bpr or a dot output format
5658 recognised_option('-bench_alloy_cmd',run_benchmark(alloy,CmdNames,AlloyFilePath),[CmdNames,AlloyFilePath],prob_cli:check_file_arg(AlloyFilePath,'bench_alloy_cmd')).
5659 recognised_option('-bench_smt_cbc_inv',run_benchmark(smt,cbc_inv,Folder),[Folder],prob_cli:check_file_arg(Folder,'bench_smt_cbc_inv')).
5660 recognised_option('-bench_smt_cbc_deadlock',run_benchmark(smt,cbc_deadlock,Folder),[Folder],prob_cli:check_file_arg(Folder,'bench_smt_cbc_deadlock')).
5661 recognised_option('-bench_smt_bmc',run_benchmark(smt,bmc,Folder),[Folder],prob_cli:check_file_arg(Folder,'bench_smt_bmc')).
5662 recognised_option('-eval_file',eval_string_or_file(file(default),F,exists,_ANY,norecheck),[F],prob_cli:check_file_arg(F,'eval_file')).
5663 recognised_option('-evalt_file',eval_string_or_file(file(default),F,exists,'TRUE',norecheck),[F],prob_cli:check_file_arg(F,'evalt_file')).
5664 recognised_option('-eval_rule_file',eval_string_or_file(file(default),F,forall,_ANY,norecheck),[F],prob_cli:check_file_arg(F,'eval_rule_file')).
5665 recognised_option('-solve_file',eval_string_or_file(file(Solver),F,exists,_ANY,norecheck),[Solver,F],prob_cli:check_file_arg(F,'eval_file')).
5666
5667 recognised_option('-zmq_assertions',zmq_assertion(Identifier),[Identifier],true).
5668 recognised_option('-zmq_worker',zmq_worker(Identifier),[Identifier], true).
5669 %recognised_option('-zmq_worker2',zmq_worker2(MasterIP, Port, ProxyID, Logfile),[MasterIP, SPort, SProxyID, Logfile],
5670 % tools:(arg_is_number(SPort,Port), arg_is_number(SProxyID, ProxyID))).
5671 recognised_option('-p',set_pref(NPREF,PREFVAL),[PREF,PREFVAL],prob_cli:normalise_pref_name(PREF,NPREF)).
5672 recognised_option('-pref',set_pref(NPREF,PREFVAL),[PREF,PREFVAL],prob_cli:normalise_pref_name(PREF,NPREF)).
5673 recognised_option('-prob_application_type',set_application_type(T),[T],true).
5674 recognised_option('-cbc_redundant_invariants',cbc_redundant_invariants(Nr),[X],tools:arg_is_number(X,Nr)).
5675 recognised_option('-expcterrpos',expect_error_pos(Type,LNr,CNr),[Type,Line,Col],
5676 (tools:arg_is_number(Line,LNr),tools:arg_is_number(Col,CNr))).
5677 recognised_option('-pref_group',set_preference_group(NGroup,Val),[Group,Val],
5678 (prob_cli:normalise_option_atom(Group,NGroup))).
5679 recognised_option('-save_all_traces_until',generate_all_traces_until(Formula,FilePrefix),
5680 [Formula,FilePrefix],
5681 true). % we could check LTL formula and FilePrefix
5682 recognised_option('-check_machine_file_sha',check_machine_file_sha(FILE,SHA1),[FILE,SHA1],
5683 prob_cli:check_file_arg(FILE,'check_machine_file_sha')).
5684 recognised_option('-sha1sum',Command,Args,Call) :-
5685 recognised_option('-check_machine_file_sha',Command,Args,Call).
5686 recognised_option('-animate_until_ltl_steps',animate_until_ltl(Formula,no_loop,ltl_found,Steps),[Formula,A],
5687 tools:arg_is_number(A,Steps)).
5688 recognised_option('-gc_margin',set_gc_margin(Nr),[X], tools:arg_is_number(X,Nr)).
5689 recognised_option('-verbosity',verbose(Nr),[X], tools:arg_is_number(X,Nr)). % set verbose level by number
5690
5691 % recognised_option/3
5692 recognised_option('-prefs',set_prefs_from_file(PREFFILE),[PREFFILE]).
5693 %recognised_option('-plugin',plugin(Plugin), [Plugin]).
5694 recognised_option('-card',set_card(SET,SCOPE),[SET,SCOPE]).
5695 recognised_option('-argv',set_argv(ARGV),[ARGV]).
5696 recognised_option('-goal',set_goal(GOAL),[GOAL]).
5697 recognised_option('-property',add_additional_property(PRED),[PRED]).
5698 recognised_option('-scope',set_searchscope(GOAL),[GOAL]).
5699 recognised_option('-searchscope',set_searchscope(GOAL),[GOAL]).
5700 recognised_option('-search_scope',set_searchscope(GOAL),[GOAL]).
5701 recognised_option('-eval',eval_string_or_file(string,E,exists,_,norecheck),[E]).
5702 recognised_option('-evalt',eval_string_or_file(string,E,exists,'TRUE',norecheck),[E]).
5703 recognised_option('-evalf',eval_string_or_file(string,E,exists,'FALSE',norecheck),[E]).
5704 recognised_option('-evalt_rc',eval_string_or_file(string,E,exists,'TRUE',recheck(ascii)),[E]).
5705 recognised_option('-evalf_rc',eval_string_or_file(string,E,exists,'FALSE',recheck(ascii)),[E]).
5706 recognised_option('-evalu',eval_string_or_file(string,E,exists,'UNKNOWN',norecheck),[E]).
5707 recognised_option('-evalnwd',eval_string_or_file(string,E,exists,'NOT-WELL-DEFINED',norecheck),[E]).
5708 recognised_option('-parsercp',parsercp(L),[L]). % deprecated
5709 recognised_option('-parserport',parserport(L),[L]).
5710 recognised_option('-expcterr',expect_error(Type),[Type]).
5711 recognised_option('-expecterr',expect_error(Type),[Type]).
5712 recognised_option('-expect',expect_error(Type),[Type]).
5713 recognised_option('-opterr',optional_error(Type),[Type]).
5714 recognised_option('-his_option',history_option(Option),[Option]). % trace_file, json, show_init, show_states
5715 recognised_option('-cache',cache_storage(D,strict),[D]). % for value_persistance caching
5716 recognised_option('-ccache',cache_storage(D,create_if_needed),[D]). % ditto
5717 recognised_option('-show_cache',show_cache(default),[]).
5718 recognised_option('-show_cache_verbose',show_cache(verbose),[]).
5719 recognised_option('-cache_statistics',cli_print_statistics(value_persistance_stats),[]).
5720 recognised_option('-cache_stats',cli_print_statistics(value_persistance_stats),[]). % synonym
5721 % see also -check_cache_stats
5722 recognised_option('-clear_cache',clear_value_persistance_cache,[]).
5723 recognised_option('-clear_cache_for',clear_value_persistance_cache(Machine),[Machine]).
5724 recognised_option('-ignore_cache_for',ignore_value_persistance_cache_for(Machine),[Machine]).
5725 recognised_option('-hshow',cli_print_statistics(hshow),[]). % machine inclusion hierarchy
5726 recognised_option('-show_inclusion_hierarchy',cli_print_statistics(hshow),[]). % machine inclusion hierarchy
5727
5728 recognised_option('-MAIN',csp_main(ProcessName),[ProcessName]).
5729
5730 recognised_option('-ltlformula',ltl_formula_model_check(Formula,_),[Formula]).
5731 recognised_option('-ltlformulat',ltl_formula_model_check(Formula,true),[Formula]).
5732 recognised_option('-ltlformulaf',ltl_formula_model_check(Formula,false),[Formula]).
5733 recognised_option('-ctlformula',ctl_formula_model_check(Formula,_),[Formula]).
5734 recognised_option('-ctlformulat',ctl_formula_model_check(Formula,true),[Formula]).
5735 recognised_option('-ctlformulaf',ctl_formula_model_check(Formula,false),[Formula]).
5736 recognised_option('-pctlformula',pctl_formula_model_check(Formula,_),[Formula]).
5737 recognised_option('-pctlformulat',pctl_formula_model_check(Formula,true),[Formula]).
5738 recognised_option('-pctlformulaf',pctl_formula_model_check(Formula,false),[Formula]).
5739 recognised_option('-animate_until_ltl',animate_until_ltl(Formula,no_loop,_,_),[Formula]).
5740 recognised_option('-animate_until_ltl_state_property',animate_until_ltl(Formula,ltl_state_property,_,_),[Formula]).
5741
5742
5743 %recognised_option('-cspref',csp_in_situ_refinement_check(assertRef('False',val_of(AbsP1,no_loc_info_available),Type,val_of(ImplP2,no_loc_info_available),no_loc_info_available),'False'),[AbsP1,Type,ImplP2]).
5744 recognised_option('-cspref',csp_in_situ_refinement_check(AbsP1,Type,ImplP2),[AbsP1,Type,ImplP2]).
5745 % -cspref R [F= Q
5746 recognised_option('-cspdeadlock',csp_checkAssertion(Proc,Model,'deadlock free'),[Proc,Model]).
5747 % -cspdeadlock R F
5748 recognised_option('-cspdeterministic',csp_checkAssertion(Proc,Model,'deterministic'),[Proc,Model]).
5749 % -cspdeterministic R F
5750 recognised_option('-csplivelock',csp_checkAssertion(Proc,'FD','livelock free'),[Proc]).
5751 % -csplivelock R
5752 % -csp_assertion "P [F= Q"
5753 recognised_option('-csp_assertion',check_csp_assertion(Assertion),[Assertion]).
5754 recognised_option('-csp_eval', eval_csp_expression(Expr),[Expr]).
5755 recognised_option('-get_csp_assertions_as_string',csp_get_assertions,[]).
5756
5757 recognised_option('-variable_coverage',csv_table_command(variable_coverage,[],[text_output],user_output),[]).
5758 recognised_option('-vacuity_check',vacuity_check,[]).
5759 recognised_option('-wd_check',cli_wd_check(_,_),[]).
5760 recognised_option('-wd_check_all',cli_wd_check(X,X),[]).
5761 recognised_option('-well_definedness_check',cli_wd_check(_,_),[]).
5762 recognised_option('-wd_inv_proof',cli_wd_inv_proof(_,_,_),[]).
5763 recognised_option('-lint',cli_lint,[]). % extended static check (ESC, esc)
5764 recognised_option('-lint_operations',cli_lint(operations),[]).
5765 recognised_option('-lint_variables',cli_lint(variables),[]).
5766 recognised_option('-cbc',constraint_based_check(OpName),[OpName]). % cbc invariant checking
5767 recognised_option('-cbc_invariant',constraint_based_check(OpName),[OpName]).
5768 recognised_option('-cbc_deadlock',cbc_deadlock_check(true),[]).
5769 recognised_option('-cbc_assertions',cbc_assertions(true,[]),[]).
5770 recognised_option('-cbc_main_assertions',cbc_assertions(true,[main_assertions]),[]).
5771 recognised_option('-cbc_assertions_proof',cbc_assertions(false,[]),[]). % do not allow enumeration warnings
5772 recognised_option('-cbc_assertions_tautology_proof',cbc_assertions(false,[tautology_check]),[]). % do not allow enumeration warnings + disregard PROPERTIES, used for Atelier-B proof/disproof; TO DO: also call WD prover
5773 recognised_option('-cbc_assertions_tautology_proof_check',cbc_assertions(false,[tautology_check,contradiction_check]),[]).
5774 recognised_option('-cbc_option',cbc_option(OPT),[OPT]). % should be tautology_check,contradiction_check, unsat_core
5775 recognised_option('-cbc_result_file',cbc_result_file(FILE),[FILE]). % write result to FILE
5776 recognised_option('-cbc_refinement',cbc_refinement,[]).
5777 recognised_option('-cbc_deadlock_pred',cbc_deadlock_check(GoalPred),[GoalPred]).
5778 recognised_option('-cbc_sequence',cbc_sequence(OpSequence,'',single_solution),[OpSequence]).
5779 recognised_option('-cbc_sequence_all',cbc_sequence(OpSequence,'',findall),[OpSequence]).
5780 recognised_option('-cbc_sequence_with_target',cbc_sequence(OpSequence,TargetPredString,single_solution),[OpSequence,TargetPredString]).
5781 recognised_option('-cbc_sequence_with_target_all',cbc_sequence(OpSequence,TargetPredString,findall),[OpSequence,TargetPredString]).
5782 recognised_option('-comment',comment(UserComment),[UserComment]). % not processed by tool, but will be stored in log-file and used by log_analyser
5783 recognised_option('-junit',junit(Dir),[Dir]).
5784 recognised_option('-mcm_cover', mcm_cover(Event),[Event]).
5785 recognised_option('-cbc_cover', cbc_cover(Event),[Event]).
5786 recognised_option('-cbc_cover_match', cbc_cover(match_event(Event)),[Event]). % find events which have Event String occuring somewhere in name
5787 recognised_option('-cbc_cover_all', cbc_cover_all,[]). % is now default if no cbc_cover provided
5788 recognised_option('-cbc_cover_final', cbc_cover_final,[]).
5789 recognised_option('-bmc', cbc_tests(Depth,'#not_invariant',''),[Depth]).
5790 recognised_option('-bdc', cbc_tests(Depth,'#deadlock',''),[Depth]).
5791 recognised_option('-enabling_analysis',enabling_analysis_csv(user_output),[]).
5792 recognised_option('-feasibility_analysis',feasibility_analysis_csv(1000,user_output),[]).
5793 recognised_option('-read_write_matrix',generate_read_write_matrix_csv(user_output),[]).
5794 recognised_option('-scc_trace',check_scc_for_ltl_formula(LtlFormula,SCC),[LtlFormula,SCC]).
5795 recognised_option('-selfcheck_module',selfcheck(M,[]),[M]).
5796 recognised_option('-mc_mode',depth_breadth_first_mode(M),[M]). % can be mixed, hash, heuristic
5797 recognised_option('-assertion',cli_check_assertions(specific(X),[false/0,unknown/0]),[X]).
5798 recognised_option('-cbc_assertion',cbc_assertions(true,[specific(X)]),[X]). % check only a specific assertion
5799 recognised_option('-symbolic_model_check', cli_symbolic_model_check(Algorithm), [Algorithm]).
5800 recognised_option('-ltsmin2',ltsmin2(EndpointPath), [EndpointPath]).
5801 recognised_option('-ltsmin_ltl_output',ltsmin_ltl_output(Path), [Path]).
5802 recognised_option('-ltsmin_option', ltsmin_option(X),[X]).
5803 recognised_option('-machine_hash_check',cli_print_machine_info(hash(X)),[X]).
5804 recognised_option('-install',install_prob_lib(X,[]),[X]).
5805 recognised_option('-install_dry_run',install_prob_lib(X,[dryrun]),[X]).
5806
5807
5808 recognised_option('-dot_all',dot_generate_for_all_formulas). % generate dot also for true formulas
5809 recognised_option('-animate_all',cli_random_animate(2147483647,false)).
5810 recognised_option('-execute_all',execute(2147483647,false,current_state(1))).
5811 recognised_option('-execute_all_inits',execute(2147483647,false,from_all_initial_states)).
5812 recognised_option('-animate_stats',animate_stats).
5813 recognised_option('-execute_monitor',execute_monitoring).
5814 recognised_option('-check_goal',check_goal).
5815 recognised_option('-ltlassertions',ltl_assertions).
5816 recognised_option('-assertions',cli_check_assertions(all,[false/0,unknown/0])).
5817 recognised_option('-main_assertions',cli_check_assertions(main,[false/0,unknown/0])).
5818 recognised_option('-properties',cli_check_properties).
5819 recognised_option('-properties_core',cli_core_properties(_)). % variable as arg: try various algorithms in order
5820 recognised_option('-properties_core_wd',cli_core_properties(wd_prover)).
5821 recognised_option('-properties_core_z2',cli_core_properties(z3_bup(2))).
5822 recognised_option('-properties_core_z3',cli_core_properties(z3_bup(3))).
5823 recognised_option('-selfcheck',selfcheck(_,[])).
5824 recognised_option('-pacheck',pa_check). % predicate analysis for Kodkod
5825 recognised_option('-det_check',det_check). % check if animation is deterministic
5826 recognised_option('-det_constants',det_constants_check). % check if animation for setup_constants is deterministic
5827 recognised_option('-bf',breadth_first).
5828 recognised_option('-breadth',breadth_first).
5829 recognised_option('-df',depth_first).
5830 recognised_option('-depth',depth_first).
5831 recognised_option('-strict',strict_raise_error).
5832 recognised_option('-silent',silent).
5833 recognised_option('-quiet',silent).
5834 recognised_option('-q',silent).
5835 recognised_option('-force_no_silent',force_no_silent). % override provided silent flag; useful for gitlab test debugging
5836 recognised_option('-statistics',cli_print_statistics(full)).
5837 recognised_option('-stats',cli_print_statistics(full)).
5838 recognised_option('-memory_stats',cli_print_statistics(memory)).
5839 recognised_option('-memory_statistics',cli_print_statistics(memory)).
5840 recognised_option('-memory',cli_print_statistics(memory)).
5841 recognised_option('-profile_stats',cli_print_statistics(sicstus_profile)).
5842 recognised_option('-profile_statistics',cli_print_statistics(sicstus_profile)).
5843 recognised_option('-op_cache_profile',cli_print_statistics(op_cache_profile)).
5844 recognised_option('-hit_profile',cli_print_statistics(hit_profile)). % mainly for ProB developers
5845 recognised_option('-reset_profile_statistics',reset_profiler). % mainly for use in REPL
5846 recognised_option('-nodead',no_deadlocks).
5847 recognised_option('-no_dead',no_deadlocks).
5848 recognised_option('-no_deadlocks',no_deadlocks).
5849 recognised_option('-noinv',no_invariant_violations).
5850 recognised_option('-no_inv',no_invariant_violations).
5851 recognised_option('-no_invariant_violations',no_invariant_violations).
5852 recognised_option('-nogoal',no_goal).
5853 recognised_option('-no_goal',no_goal).
5854 recognised_option('-noltl',no_ltl). % just used for TLC at the moment
5855 recognised_option('-no_ltl',no_ltl).
5856 recognised_option('-noass',no_assertion_violations).
5857 recognised_option('-no_ass',no_assertion_violations).
5858 recognised_option('-no_assertion_violations',no_assertion_violations).
5859 recognised_option('-no_state_errors',no_state_errors). % disable checking for general_errors and transition related state_errors
5860 recognised_option('-nocounter',no_counter_examples).
5861 recognised_option('-no_counter_examples',no_counter_examples).
5862 recognised_option('-nocolor',no_color).
5863 recognised_option('-no_color',no_color).
5864 recognised_option('-no_colour',no_color).
5865 recognised_option('-disable_time_out',set_preference_group(time_out,disable_time_out)).
5866 recognised_option('-disable_timeout',set_preference_group(time_out,disable_time_out)).
5867 %recognised_option('-POR',with_reduction).
5868 recognised_option('-i',animate).
5869 recognised_option('-repl',eval_repl([])). % used to be -eval
5870 recognised_option('-c',coverage(false)).
5871 recognised_option('-cs',coverage(just_summary)).
5872 recognised_option('-coverage',coverage(false)).
5873 recognised_option('-coverage_summary',coverage(just_summary)).
5874 recognised_option('-machine_stats',cli_print_machine_info(statistics)).
5875 recognised_option('-machine_statistics',cli_print_machine_info(statistics)).
5876 recognised_option('-machine_files',cli_print_machine_info(files(no_sha))).
5877 recognised_option('-machine_files_sha',cli_print_machine_info(files(with_sha))).
5878 recognised_option('-machine_hash',cli_print_machine_info(hash(_))).
5879 recognised_option('-check_abstract_constants',check_abstract_constants).
5880 recognised_option('-op_cache_stats',check_op_cache([])).
5881 recognised_option('-op_cache_statistics',check_op_cache([])).
5882 recognised_option('-cv',coverage(true)).
5883 recognised_option('-v',verbose(19)).
5884 recognised_option('-vv',verbose(5)).
5885 recognised_option('-vvv',verbose(1)).
5886 recognised_option('-verbose',verbose(19)).
5887 recognised_option('-debug',verbose(19)).
5888 recognised_option('-verbose_off',verbose_off). % mainly useful in REPL
5889 recognised_option('-voff',verbose_off). % mainly useful in REPL
5890 recognised_option('-very_verbose',verbose(5)).
5891 recognised_option('-gc_trace',set_gc_trace(verbose)). % gc_info
5892 recognised_option('-gc_off',set_gc_on_off(off)).
5893 recognised_option('-gc_on',set_gc_on_off(on)).
5894 recognised_option('-profiling_on',profiling_on). % Prolog profiling
5895 recognised_option('-profile',cli_print_statistics(prob_profile)). % ProB Operation profiling
5896 recognised_option('-prob_profile',cli_print_statistics(prob_profile)). % ProB Operation profiling
5897 recognised_option('-prob_statistics',cli_print_statistics(prob_profile)). % synonym
5898 recognised_option('-prob_stats',cli_print_statistics(prob_profile)). % synonym
5899 recognised_option('-version',print_version(full)).
5900 recognised_option('-cpp_version',print_version(cpp)).
5901 recognised_option('-V',print_version(full)).
5902 recognised_option('-svers',print_version(short)).
5903 recognised_option('-short_version',print_version(short)).
5904 recognised_option('-check_lib',print_version(lib)).
5905 recognised_option('-check_java_version',check_java_version).
5906 recognised_option('-java_version',print_version(java)).
5907 recognised_option('-release_java_parser',release_java_parser).
5908 recognised_option('-fast_read_prob',fast_read_prob).
5909 recognised_option('-file_info',file_info).
5910 recognised_option('-t',default_trace_check).
5911 recognised_option('-init',initialise).
5912 recognised_option('-initialise',initialise).
5913 recognised_option('-ll',log('/tmp/prob_cli_debug.log',prolog)). % see cli_start_logging
5914 recognised_option('-ss',socket(9000,true)). % standard socket 9000
5915 recognised_option('-sf',socket(_,true)). % free socket
5916 recognised_option('-local_socketserver',socket(_,true)). % do not allow remote socket connections
5917 recognised_option('-remote_socketserver',socket(_,false)). % allow remote socket connections
5918 recognised_option('-help',help).
5919 recognised_option('-h',help).
5920 recognised_option('-rc',runtimechecking).
5921 recognised_option('-test_mode',test_mode).
5922 recognised_option('-check_complete',check_complete).
5923 recognised_option('-check_complete_operation_coverage', check_complete_operation_coverage).
5924 recognised_option('-mc_with_tlc', cli_start_mc_with_tlc).
5925 recognised_option('-model_check_with_tlc', cli_start_mc_with_tlc).
5926 recognised_option('-mc_with_lts_sym', cli_start_sym_mc_with_lts(symbolic)).
5927 recognised_option('-mc_with_lts_seq', cli_start_sym_mc_with_lts(sequential)).
5928 recognised_option('-core',disprover_options([disprover_option(unsat_core),unsat_core_algorithm/linear])).
5929 recognised_option('-export_po',disprover_options([disprover_option(export_po_as_machine(user_output))])).
5930 recognised_option('-ltsmin',ltsmin).
5931 recognised_option('-trace',prolog_trace). % enter Prolog debugger on development system after starting up ProB
5932
5933 % some utilities to be able to call the above options directly from repl:
5934 :- public silent/0, coverage/1, help/0.
5935 % predicate to set_verbose_mode
5936 %verbose :- tcltk_turn_debugging_on(19).
5937 %very_verbose :- tcltk_turn_debugging_on(5).
5938 verbose(Nr) :- tcltk_turn_debugging_on(Nr),
5939 (Nr<10 -> set_gc_trace(verbose) ; true). % terse is another option for gc_trace
5940 verbose_off :- set_gc_trace(off), tcltk_turn_debugging_off.
5941 file_info :- file_loaded(true,MainFile), print_file_info(MainFile).
5942 coverage(ShowEnabledInfo) :- probcli_time_stamp(NOW), cli_show_coverage(ShowEnabledInfo,NOW).
5943
5944 % Governs global stack garbage collection trace messages
5945 set_gc_trace(X) :- member(X,[off,terse,verbose]),!,set_prolog_flag(gc_trace,X).
5946 set_gc_trace(X) :- add_error(prob_cli,'Illegal value for gc_trace:',X).
5947
5948 % At least Margin kilobytes of free global stack space are guaranteed to exist after a garbage collection
5949 set_gc_margin(Margin) :- set_prolog_flag(gc_margin,Margin).
5950 set_gc_on_off(OnOff) :- set_prolog_flag(gc,OnOff).
5951
5952 silent :- (option(silent) -> true ; assert_option(silent)).
5953 help :- eval_help.
5954 dot_command(DCommand,DotFile,DotEngine) :- call_dot_command_with_engine(DCommand,DotFile,[],DotEngine).
5955 dot_command_for_expr(DECommand,Expr,DotFile,Opts,DotEngine) :-
5956 call_dot_command_with_engine_for_expr(DECommand,Expr,DotFile,Opts,DotEngine).
5957
5958 plantuml_command(PCommand,UmlFile) :- call_plantuml_command(PCommand,UmlFile).
5959 plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts) :-
5960 call_plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts).
5961
5962 :- use_module(tools_io,[safe_intelligent_open_file/3]).
5963 csv_table_command(TCommand,Formulas,Options,CSVFile) :-
5964 append(Formulas,[TableResult],ActualArgs),
5965 OptionalArgs=[],
5966 format_with_colour_nl(user_output,[blue],'Calling table command ~w',[TCommand]),
5967 call_command(table,TCommand,_,ActualArgs,OptionalArgs),
5968 write_table_to_csv_file(CSVFile,Options,TableResult),
5969 format_with_colour_nl(user_output,[blue],'Finished exporting ~w to ~w',[TCommand,CSVFile]).
5970
5971
5972 save_state_space(StateFile) :- debug_println(20,'% Saving state space to file'),
5973 state_space:tcltk_save_state_space(StateFile).
5974 :- public load_state/1. % for REPL
5975 load_state(StateFile) :- debug_println(20,'% Loading state space from file'),
5976 state_space:tcltk_load_state(StateFile).
5977 :- public execute/3. % for REPL
5978 execute(ESteps,ErrOnDeadlock,From) :- cli_execute(ESteps,ErrOnDeadlock,From).
5979
5980 option_verbose :- option(verbose(_)).
5981 option_very_verbose :- debug_level_active_for(5).
5982
5983 set_random_seed_to_deterministic_start_seed :-
5984 % in test_mode we do not change the random number generator's initial seed
5985 true. %getrand(CurrState),setrand(CurrState). % this seems to be a no-op
5986
5987 :- if(predicate_property(set_random(_), _)).
5988 % SWI-Prolog's native API for reinitializing the RNG state.
5989 % The equivalent of this call is also performed automatically by SWI
5990 % when a random number is requested for the first time.
5991 set_new_random_seed :- set_random(seed(random)).
5992 :- else.
5993 % SICStus way of (re)initializing the RNG state.
5994 % Note that on SICStus, the initial RNG state after startup is always the same,
5995 % so it *must* be manually reinitialized like this to get actually random results!
5996 %:- use_module(library(random),[setrand/1]).
5997 set_new_random_seed :-
5998 now(TimeStamp), % getting the unix time
5999 setrand(TimeStamp). % setting new random seed by every execution of probcli
6000 :- endif.
6001
6002 halt_exception :- halt_exception(0).
6003 halt_exception(Code) :-
6004 stop_prob,
6005 throw(halt(Code)).
6006
6007 % -----------------
6008
6009 start_xml_feature(FeatureName,[CErrs1,CWarns1,CEErrs1]) :-
6010 debug_format(20,'% Starting ~w~n',[FeatureName]),
6011 get_counter(cli_errors,CErrs1), get_counter(cli_warnings,CWarns1), get_counter(cli_expected_errors,CEErrs1),
6012 start_xml_group_in_log(FeatureName).
6013
6014 start_xml_feature(FeatureName,Attr,Value,[CErrs1,CWarns1,CEErrs1]) :-
6015 debug_format(20,'% Starting ~w (~w=~w)~n',[FeatureName,Attr,Value]),
6016 get_counter(cli_errors,CErrs1), get_counter(cli_warnings,CWarns1), get_counter(cli_expected_errors,CEErrs1),
6017 start_xml_group_in_log(FeatureName,Attr,Value).
6018
6019 stop_xml_feature(FeatureName,[CErrs1,CWarns1,CEErrs1]) :-
6020 get_counter(cli_errors,CErrs2), get_counter(cli_warnings,CWarns2), get_counter(cli_expected_errors,CEErrs2),
6021 CErrs is CErrs2-CErrs1, CWarns is CWarns2-CWarns1, CEErrs is CEErrs2-CEErrs1,
6022 (CEErrs>0
6023 -> write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns,expected_errors/CEErrs])
6024 ; write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns])
6025 ),
6026 debug_format(20,'% Finished ~w (errors=~w, warnings=~w, expected_errors=~w)~n',[FeatureName,CErrs,CWarns,CEErrs]),
6027 stop_xml_group_in_log(FeatureName),
6028 !.
6029 stop_xml_feature(FeatureName,L) :-
6030 add_internal_error('Illegal or failed call:',stop_xml_feature(FeatureName,L)).
6031
6032 %(CErrs>0 -> (file_loaded(_,MainFile) -> true ; MainFile=unknown), Time=unknown, % TO DO: determine time
6033 % create_and_print_junit_result(['Feature',MainFile], FeatureName, Time, error) ; true).
6034 % Note: call stop_xml_group_in_log if the feature stops unexpectedly and you do not have the Info list available
6035
6036 % -----------------
6037
6038 :- public user:runtime_entry/1.
6039 user:runtime_entry(start) :- go_cli.
6040
6041 %save :- save_program('probcli.sav').
6042
6043 :- use_module(eventhandling,[announce_event/1]).
6044 :- announce_event(compile_prob).