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