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