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