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