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