1 % (c) 2015-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(pge_algo, [
6 %%%% Static Analysis Predicates %%%%
7 tcltk_disabling_analysis/1,
8 %%%% Model Checker predicates %%%%
9 compute_transitions_pge/2,
10 %%%% INFO %%%%
11 disabled_operations_stats/1,
12 is_pge_opt_on/0,
13 is_pge_opt_on/1,
14 compute_and_update_disabled_enabled_operations/3,
15 compute_operation_relations_for_pge/1,
16 compute_operation_relations_for_pge_if_necessary/2
17 ]).
18
19 /* SICSTUS Libraries */
20 :- use_module(library(ordsets)).
21 :- use_module(library(lists)).
22 %% :- use_module(library(timeout)).
23
24 /* B module sources */
25 :- use_module(probsrc(bmachine),[b_top_level_operation/1,b_machine_has_constants_or_properties/0]).
26 :- use_module(probsrc(b_state_model_check), [get_guard/2,get_negated_guard/3]).
27 :- use_module(probsrc(state_space),[clear_context_state/0]).
28 :- use_module(probsrc(bsyntaxtree), [conjunct_predicates/2,create_negation/2]).
29 :- use_module(probporsrc(static_analysis), [
30 get_conj_inv_predicate/3,
31 catch_and_ignore_well_definedness_error/2,
32 test_path_non_failing/6]).
33 :- use_module(cbcsrc(enabling_analysis), [init_or_op/1, print_enable_table/1]).
34 :- use_module(probsrc(b_read_write_info),[b_get_read_write/3,b_get_operation_read_guard_vars/4]).
35
36 /* Importing predicates for handling the states of a respective B/Event-B machine */
37 :- use_module(probsrc(eventhandling),[register_event_listener/3]).
38 :- use_module(probsrc(specfile),[specfile_possible_trans_name_for_successors/2,
39 prepare_state_for_specfile_trans/3,animation_mode/1]).
40 :- use_module(probsrc(state_space),[ %visited_expression/2,
41 assert_time_out_for_node/3,
42 use_no_timeout/1,assert_max_reached_for_node/1]).
43 :- use_module(probsrc(value_persistance), [save_constants/1,add_new_transitions_to_cache/1]).
44 :- use_module(probsrc(succeed_max),[reset_max_reached/0,max_reached/0]).
45 :- use_module(probsrc(preferences),[get_preference/2]).
46 :- use_module(probsrc(error_manager),[enter_new_error_scope/1, exit_error_scope/3,specific_event_occurred_at_level/2,clear_all_errors_in_error_scope/1,
47 is_time_out_result/1,set_error_context/1,clear_error_context/0,time_out_with_enum_warning_for_findall/3,
48 add_warning/3, add_error_fail/3]).
49 :- use_module(probsrc(tools),[cputime/1,print_message/1]).
50 :- use_module(probsrc(debug)).
51 :- use_module(probsrc(state_space),[find_initialised_states/1]).
52
53 /* Modules and Infos for the code coverage analysis */
54 :- use_module(probsrc(module_information)).
55 :- module_info(group,model_checker).
56 :- module_info(description,'This module contains predictes for model checking B and Event-B models using the partial guard evaluation optimisastion. Only applicable in B mode.').
57
58 %------------------------------------
59
60 %%%%%% Dynamic predicates used for: saving the enabling relations, number of skipped guard evaluations,
61 %%%%%% and sets of enabled and disabled events at the various states. %%%%%
62
63 % for the PGE analysis
64 :- dynamic disables/2, enables/2, keeps/2.
65 %%% enabling_relations(Op1,Op2,Enable,KeepEnabled,Disable,KeepDisabled)
66 :- dynamic enabling_relations/6.
67 :- dynamic pge_predicates_computed/0.
68
69 % for the state space exploration by means of PGE
70 :- dynamic disabled_operations/3.
71
72 % for keeping track of the skipped guard evaluations
73 :- dynamic nr_skipped_guard_evaluations/1.
74
75 :- register_event_listener(clear_specification,clear_dynamic_predicates_for_pge,
76 'Partial Guard Evaluation.').
77
78 clear_dynamic_predicates_for_pge :-
79 retractall(keeps(_,_)),
80 retractall(disables(_,_)),
81 retractall(disabled_operations(_,_,_)),
82 retractall(pge_predicates_computed),
83 retractall(nr_skipped_guard_evaluations(_)),
84 retractall(enabling_relations(_,_,_,_,_,_)).
85
86 disabled_operations_stats(ResPGE) :-
87 is_pge_opt_on,
88 animation_mode(b),!,
89 nr_skipped_guard_evaluations(NrSkippedEvaluations),
90 ResPGE = ['SKIPPED_GUARD_EVALUATIONS: ',NrSkippedEvaluations].
91 disabled_operations_stats(ResPGE) :- % otherwise no information is available
92 ResPGE = [].
93
94 is_pge_opt_on :-
95 get_preference(pge,Pref),
96 is_pge_opt_on(Pref).
97
98 is_pge_opt_on(off) :- !,fail.
99 is_pge_opt_on(Pref) :-
100 ? member(Pref,[disabled,disabled2,enabled,enabled2,full,full2]),!.
101 is_pge_opt_on(Pref) :-
102 add_error_fail(pge,'Unknown Partial Guard Evaluation (PGE) preference: ', Pref).
103
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %%%%%%%%%%%%%%%%% PGE Analysis %%%%%%%%%%%%%%%%%
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107
108 compute_operation_relations_for_pge_if_necessary(off,_FindInvViolations).
109 compute_operation_relations_for_pge_if_necessary(PGEPref,FindInvViolations) :-
110 is_pge_opt_on(PGEPref),!,
111 compute_operation_relations_for_pge(FindInvViolations).
112 compute_operation_relations_for_pge_if_necessary(_PGEPref,_FindInvViolations).
113
114 :- use_module(probsrc(runtime_profiler),[start_profile/2, stop_profile/4]).
115
116 compute_operation_relations_for_pge(FindInvViolations) :-
117 (pge_predicates_computed
118 -> true
119 ; debug_println(19,'********** START PGE ANALYSIS *************'),
120 start_profile(partial_order_reduction,Timer),
121 get_preference(timeout_cbc_analysis,Timeout),
122 cputime(T1),
123 enter_new_error_scope(ScopeID),
124 get_preference(pge,Pref),
125 (member(Pref,[disabled,enabled,full]) ->
126 call_cleanup(compute_impossible_keep_guaranteed(FindInvViolations,Timeout,Pref),
127 my_exit_error_scope(ScopeID))
128 ; member(Pref,[disabled2,enabled2,full2]) -> % now used for experimental issues
129 call_cleanup(compute_enabling_relations(FindInvViolations,Timeout,Pref),
130 my_exit_error_scope(ScopeID))
131 ;
132 add_warning(pge,'Unknown PGE preference: ',Pref)
133 ),
134 assert_disabled_ops_to_init_states_if_necessary,
135 cputime(T2),
136 debug_println(19,'********** PGE ANALYSIS FINISHED **********'),
137 D is T2-T1,
138 formatsilent('PGE Analysis Checking Time: ~w ms.~n',[D]),
139 assertz(pge_predicates_computed),
140 assertz(nr_skipped_guard_evaluations(0)),
141 stop_profile(partial_order_reduction,compute_pge_relations,unknown,Timer),
142 !
143 ).
144
145 %%%%%%%% Analysis for the enabling relations: keep, guaranteed, and impossible (in case 'pge' is set to 'enabled', 'disabled', or 'full') %%%%%%%%%%
146 % failure loop
147 compute_impossible_keep_guaranteed(FindInvViolations,Timeout,Pref) :-
148 ? init_or_op(OpName1),
149 b_get_read_write(OpName1,_Reads1,Writes1),
150 ? b_top_level_operation(OpName2),
151 b_get_operation_read_guard_vars(OpName2,true,GReads2,_Precise),
152 (OpName1\='INITIALISATION',\+ord_intersect(Writes1,GReads2) ->
153 assertz(keeps(OpName1,OpName2)),
154 debug_println(9,keeps(OpName1, OpName2))
155 ? ; (Pref\=enabled, disables(OpName1,OpName2,FindInvViolations,Timeout)) ->
156 assertz(disables(OpName1,OpName2)),
157 debug_println(9,disables(OpName1,OpName2))
158 ? ; (Pref\=disabled, enables(OpName1,OpName2,FindInvViolations,Timeout)) ->
159 assertz(enables(OpName1,OpName2)),
160 debug_println(9,enables(OpName1,OpName2))
161 ; true
162 ),fail.
163 compute_impossible_keep_guaranteed(_FindInvViolations,_Timeout,_Pref).
164
165 :- use_module(cbcsrc(cbc_path_solver), [testcase_path_timeout/9]).
166 disables('INITIALISATION',OpName2,FindInvViolations,Timeout) :-
167 get_goal_predicate(OpName2,FindInvViolations,no,GoalPred),
168 (catch_and_ignore_well_definedness_error(
169 cbc_path_solver:testcase_path_timeout(init,Timeout,[],GoalPred,_,_,_,_,_R),_Result) -> fail; true).
170 disables(OpName1, OpName2, FindInvViolations, Timeout) :-
171 get_start_predicate(OpName1,FindInvViolations,StartPred),
172 get_goal_predicate(OpName2,FindInvViolations,no,GoalPred),
173 (catch_and_ignore_well_definedness_error(
174 cbc_path_solver:testcase_path_timeout(StartPred,Timeout,[OpName1],GoalPred,_,_,_,_,_R),_Result) ->fail; true).
175
176 enables('INITIALISATION',OpName2,FindInvViolations,Timeout) :-
177 get_goal_predicate(OpName2,FindInvViolations,yes,GoalPred),
178 (catch_and_ignore_well_definedness_error(
179 cbc_path_solver:testcase_path_timeout(init,Timeout,[],GoalPred,_,_,_,_,_R),_Result) ->fail; true).
180 enables(OpName1, OpName2, FindInvViolations, Timeout) :-
181 get_start_predicate(OpName1,FindInvViolations,StartPred),
182 get_goal_predicate(OpName2,FindInvViolations,yes,GoalPred),
183 (catch_and_ignore_well_definedness_error(
184 cbc_path_solver:testcase_path_timeout(StartPred,Timeout,[OpName1],GoalPred,_,_,_,_,_R),_Result) ->fail; true).
185
186 get_start_predicate(OpName,FindInvViolations,StartPred) :-
187 get_guard(OpName,PosGuard),
188 (FindInvViolations=1 -> StartPred = pred(PosGuard); StartPred=typing(PosGuard)).
189
190 get_goal_predicate(OpName,FindInvViolations,Negated,GoalPred) :-
191 get_negated_guard(OpName,PosGuard,NegGuard),
192 (Negated = yes -> GuardPred = NegGuard; GuardPred = PosGuard),
193 get_conj_inv_predicate([GuardPred],FindInvViolations,GoalPred). % add invariant if we perform invariant checking
194
195 %%%%%%%% Analysis for the enabling relations: ER(e1,e2) (in case 'pge' is set to 'enabled2', 'disabled2', or 'full2') %%%%%%%%%%
196 % failure loop
197 compute_enabling_relations(FindInvViolations,Timeout,Pref) :-
198 init_or_op(OpName1),
199 b_top_level_operation(OpName2),
200 b_get_read_write(OpName1,_Reads1,Writes1),
201 b_get_operation_read_guard_vars(OpName2,true,GReads2,_Precise),
202 (OpName1='INITIALISATION' ->
203 true % we do not predict the enabling status of the events in the init state, for now...
204 ;
205 ((\+ord_intersect(Writes1,GReads2)) ->
206 assertz(enabling_relations(OpName1,OpName2,false,ok,false,ok)),
207 debug_println(9,enabling_relations(OpName1,OpName2,false,ok,false,ok))
208 ;
209 compute_cbc_enabling_relation_and_assert(OpName1,OpName2,FindInvViolations,Timeout,Pref)
210 )),fail.
211 compute_enabling_relations(_FindInvViolations,_Timeout,_Pref).
212
213 compute_cbc_enabling_relation_and_assert(OpName1,OpName2,FindInvViolations,Timeout,Pref) :-
214 b_get_read_write(OpName1,_Reads1_,Writes1),
215 get_negated_guard(OpName2,PosGuard2,NegGuard2),
216 enabling_analysis: partition_predicate(PosGuard2,Writes1,FilteredPosGuard2,StaticPosGuard2),
217 create_negation(FilteredPosGuard2,FilteredNegGuard2),
218 (OpName1==OpName2 ->
219 KeepDisabled=false, Enable=false,
220 (Pref=enabled2 ->
221 test_path_non_failing(PosGuard2,[OpName1],FilteredNegGuard2,FindInvViolations,Timeout,Disable),
222 KeepEnabled = unknown
223 ;Pref=disabled2 ->
224 translate: print_bexpr(PosGuard2),
225 translate: print_bexpr(FilteredPosGuard2),
226 test_path_non_failing(PosGuard2,[OpName1],FilteredPosGuard2,FindInvViolations,Timeout,KeepEnabled),
227 Disable = unknown
228 ;
229 test_path_non_failing(PosGuard2,[OpName1],FilteredNegGuard2,FindInvViolations,Timeout,Disable),
230 test_path_non_failing(PosGuard2,[OpName1],FilteredPosGuard2,FindInvViolations,Timeout,KeepEnabled)
231 )
232 ;
233 conjunct_predicates([StaticPosGuard2,FilteredNegGuard2],NegEnableGuard2),
234 (Pref=enabled2 -> % need to known just Disable and KeepDisabled
235 Enable = unknown, KeepEnabled = unknown,
236 test_path_non_failing(PosGuard2,[OpName1],FilteredNegGuard2,FindInvViolations,Timeout,Disable),
237 test_path_non_failing(NegGuard2,[OpName1],NegGuard2,FindInvViolations,Timeout,KeepDisabled)
238 ;Pref=disabled2 -> % need to known just Enable and KeepEnabled
239 test_path_non_failing(NegEnableGuard2,[OpName1],FilteredPosGuard2,FindInvViolations,Timeout,Enable),
240 test_path_non_failing(PosGuard2,[OpName1],FilteredPosGuard2,FindInvViolations,Timeout,KeepEnabled),
241 Disable = unknown, KeepDisabled = unknown
242 ; % we have full2
243 test_path_non_failing(NegEnableGuard2,[OpName1],FilteredPosGuard2,FindInvViolations,Timeout,Enable),
244 test_path_non_failing(PosGuard2,[OpName1],FilteredPosGuard2,FindInvViolations,Timeout,KeepEnabled),
245 test_path_non_failing(PosGuard2,[OpName1],FilteredNegGuard2,FindInvViolations,Timeout,Disable),
246 test_path_non_failing(NegGuard2,[OpName1],NegGuard2,FindInvViolations,Timeout,KeepDisabled)
247 )
248 ),
249 prove_and_assert_enabling_relation(OpName1,OpName2,Enable,KeepEnabled,Disable,KeepDisabled),
250 debug_println(9,enabling_relations(OpName1,OpName2,Enable,KeepEnabled,Disable,KeepDisabled)).
251
252 prove_and_assert_enabling_relation(OpName1,OpName2,Enable,KeepEnabled,Disable,KeepDisabled) :-
253 (maplist(nonvar,[Enable,KeepEnabled,Disable,KeepDisabled]) ->
254 assertz(enabling_relations(OpName1,OpName2,Enable,KeepEnabled,Disable,KeepDisabled))
255 ; add_warning(cbc_enabling_relation,'A variable result occurred for one of the enabling relations result',
256 [Enable,KeepEnabled,Disable,KeepDisabled])).
257
258
259 my_exit_error_scope(ScopeID) :-
260 (specific_event_occurred_at_level(ScopeID,Event) ->
261 format('### ERROR/ENUMERATION WARING OCCURED : ~w !~n',[Event])),fail.
262 my_exit_error_scope(ScopeID) :- %error_manager:print_error_scopes,
263 clear_all_errors_in_error_scope(ScopeID),
264 exit_error_scope(ScopeID,_,my_exit_error_scope).
265
266 % TODO: consider if we need this at all
267 tcltk_disabling_analysis(list([list(['Origin'|Ops])|Result])) :-
268 get_preference(timeout_cbc_analysis,Timeout),
269 findall(Op, b_top_level_operation(Op), Ops),
270 findall(list([OpName1|DisableList]),
271 (init_or_op(OpName1),
272 findall(Disables,(b_top_level_operation(OpName2),(disables(OpName1,OpName2,1,Timeout) -> Disables=yes; Disables=no)),DisableList)),
273 Result),
274 print_enable_table([list(['Origin'|Ops])|Result]).
275
276 %----------------- Auxiliary predicates for the Partial Guard Evaluation implementation
277
278 :- use_module(probsrc(tcltk_interface),[add_transition/4]).
279 add_transition_timeout(CurID,CurTO,CurState,ActionName,NewId) :-
280 set_error_context(operation(ActionName,CurID)),
281 (CurTO > 0
282 ? -> time_out_with_enum_warning_for_findall(tcltk_interface:add_transition(CurID,CurState,ActionName,NewId),CurTO,TimeOutRes),
283 check_timeout_result(CurID,ActionName,CurTO,TimeOutRes)
284 ; add_transition(CurID,CurState,ActionName,NewId)
285 ).
286
287 check_timeout_result(CurID,ActionName,CurTO,TimeOutRes) :-
288 (is_time_out_result(TimeOutRes)
289 ->
290 ( TimeOutRes = virtual_time_out(_) ->
291 true
292 ; print_message('TIME OUT: '), print_message(CurID), print_message(CurTO),
293 print_message(ActionName)
294 ),
295 (var(ActionName)
296 -> assert_time_out_for_node(CurID,'unspecified_operation',TimeOutRes)
297 ; assert_time_out_for_node(CurID,ActionName,TimeOutRes))
298 ; true
299 ).
300
301 setup_constants_state1(csp_and_b_root) :- !.
302 setup_constants_state1(CurState) :-
303 setup_constants_state(CurState).
304
305 setup_constants_state(concrete_constants(_)).
306 setup_constants_state(const_and_vars(_,_)).
307
308 % failure loop
309 assert_disabled_ops_to_init_states_if_necessary :-
310 \+b_machine_has_constants_or_properties, % we do not want to explore states prior to firing the model checker
311 findall(Op,disables('INITIALISATION',Op),DisabledOps),
312 findall(Op,enables('INITIALISATION',Op),EnabledOps),
313 % init states finds exactly the initial states of the checked machine
314 find_initialised_states(Init),
315 member(I,Init),
316 assertz(disabled_operations(I,DisabledOps,EnabledOps)),
317 fail.
318 assert_disabled_ops_to_init_states_if_necessary.
319
320
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 %%%%%%%%%%%%%%%%%% State Exploration by means of PGE %%%%%%%%%%%%%%%%%%%%%%%
323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324
325 :- use_module(probsrc(tcltk_interface),[catch_clpfd_overflow_call_for_state/4]).
326 compute_transitions_pge(CurID,CurState) :-
327 catch_clpfd_overflow_call_for_state(CurID,'computing transitions for PGE',
328 pge_algo:compute_transitions_pge2(CurID,CurState),
329 clear_context_state).
330 :- public compute_transitions_pge2/2.
331 compute_transitions_pge2(CurID,CurState) :-
332 reset_max_reached,
333 prepare_state_for_specfile_trans(CurState,CurID,PreparedCurState),
334 (use_no_timeout(CurID) ->
335 add_transitions_pge(CurID,PreparedCurState,0)
336 ;
337 preferences: preference(time_out,CurTO),
338 add_transitions_pge(CurID,PreparedCurState,CurTO)
339 ),
340 (setup_constants_state1(CurState) -> true ; retractall(disabled_operations(CurID,_,_))),
341 debug_println(9,state_has_been_explored(CurID,CurState)),
342 clear_error_context,
343 (max_reached -> assert_max_reached_for_node(CurID),MaxReached=true ; MaxReached=false),
344 (CurID==root -> save_constants(MaxReached) ; add_new_transitions_to_cache(CurID)).
345
346
347 add_transitions_pge(CurID,CurState,CurTO) :-
348 % PossiblyEnActionNames contains all possible actions that are not recognised to be disabled and need to be tested for enabledness
349 get_possible_enabled_trans_names(CurID,CurState,DisabledOperations,EnabledOperations,PossiblyEnActionNames),
350 explore_current_state_pge(PossiblyEnActionNames,CurID,CurState,CurTO,EnabledOperations,Transitions,DisabledActionsNew),
351 list_to_ord_set(DisabledActionsNew,DisabledActionsNewSet),
352 ord_union(DisabledOperations,DisabledActionsNewSet,DisabledActionsAtCurState),
353 maplist(get_first_argument,Transitions,EnabledActions),
354 list_to_ord_set(EnabledActions,EnabledActionsAtCurState),
355 compute_and_update_disabled_enabled_operations(Transitions,DisabledActionsAtCurState,EnabledActionsAtCurState).
356
357 get_possible_enabled_trans_names(CurID,CurState,DisabledOperations,EnabledOperations,PossiblyEnActionNames) :-
358 (disabled_operations(CurID,DisabledOperations,EnabledOperations) -> true; DisabledOperations = [], EnabledOperations = []),
359 get_possible_enabled_trans_names_aux(CurID,CurState,DisabledOperations,PossiblyEnActionNames).
360
361 get_possible_enabled_trans_names_aux(CurID,CurState,DisabledOperations,PossiblyEnActionNames) :-
362 findall(PossibleEnActionName,
363 (specfile_possible_trans_name_for_successors(CurState,PossibleEnActionName),
364 not_a_member_of_disabled(PossibleEnActionName,DisabledOperations)),
365 PossiblyEnActionNames),
366 debug_println(9,skipped_guard_evaluations_at_state(CurID,DisabledOperations)).
367
368 not_a_member_of_disabled(ActionName,DisabledOperations) :-
369 (ord_member(ActionName,DisabledOperations) ->
370 retract(nr_skipped_guard_evaluations(NrDisabled)),
371 NrDisabled1 is NrDisabled + 1,
372 assertz(nr_skipped_guard_evaluations(NrDisabled1)),
373 fail
374 ; true).
375
376
377 :- use_module(probsrc(preferences),[temporary_set_preference/3,reset_temporary_preference/2]).
378
379 explore_current_state_pge(ActionNames,CurID,CurState,CurTO,EnabledOperations,Transitions,DisabledActionsNew) :-
380 explore_current_state_pge1(ActionNames,CurID,CurState,CurTO,EnabledOperations,[],Transitions,[],DisabledActionsNew).
381
382 explore_current_state_pge1([],_CurID,_CurState,_CurTO,_EnabledOperations,Transitions,Transitions,DisabledActions,DisabledActions).
383 explore_current_state_pge1([ActionName|R],CurID,CurState,CurTO,EnabledOperations,TransitionsGen,Transitions,DisabledActionsGen,DisabledActions) :-
384 (ord_member(ActionName,EnabledOperations) ->
385 retract(nr_skipped_guard_evaluations(NrDisabled)),
386 NrDisabled1 is NrDisabled +1,
387 assertz(nr_skipped_guard_evaluations(NrDisabled1)),
388 debug_println(9,do_not_evaluate_guard(ActionName)),
389 temporary_set_preference(ltsmin_do_not_evaluate_top_level_guards,full,CHNG)
390 ;
391 CHNG=false % so that reset_temporary_preference does nothing
392 ),
393 findall(NewId,add_transition_timeout(CurID,CurTO,CurState,ActionName,NewId),NewIds),
394 (NewIds = [] -> % ActionName is disabled at CurState
395 TransitionsGen1 = TransitionsGen,
396 DisabledActionsGen1 = [ActionName|DisabledActionsGen]
397 ;
398 TransitionsGen1 = [(ActionName,NewIds)|TransitionsGen],
399 DisabledActionsGen1 = DisabledActionsGen
400 ),
401 reset_temporary_preference(ltsmin_do_not_evaluate_top_level_guards,CHNG),
402 explore_current_state_pge1(R,CurID,CurState,CurTO,EnabledOperations,TransitionsGen1,Transitions,DisabledActionsGen1,DisabledActions).
403
404 compute_and_update_disabled_enabled_operations([],_DisabledActionsAtCurState,_EnabledActionsAtCurState).
405 compute_and_update_disabled_enabled_operations([(ActionName,SuccStates)|R],DisabledActionsAtCurState,EnabledActionsAtCurState) :-
406 compute_disabled_operations(ActionName,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateDisabledActions),
407 compute_enabled_operations(ActionName,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateEnabledActions),
408 update_disabled_enabled_operations_l(SuccStates,SuccStateDisabledActions,SuccStateEnabledActions),
409 compute_and_update_disabled_enabled_operations(R,DisabledActionsAtCurState,EnabledActionsAtCurState).
410
411 compute_disabled_operations(ActionName,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateDisabledActions) :-
412 get_preference(pge,Pref),
413 (check_only_enabled(Pref) ->
414 SuccStateDisabledActions = []
415 ; compute_disabled_operations_after_state(Pref,ActionName,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateDisabledActions)
416 ).
417
418 compute_enabled_operations(ActionName,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateEnabledActions) :-
419 get_preference(pge,Pref),
420 (check_only_disabled(Pref) ->
421 SuccStateEnabledActions = []
422 ; compute_enabled_operations_after_state(Pref,ActionName,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateEnabledActions)
423 ).
424
425 update_disabled_enabled_operations_l(StateIDs,NewDisabledOperations,NewEnabledOperations) :-
426 maplist(update_disabled_enabled_operations(NewDisabledOperations,NewEnabledOperations),StateIDs).
427
428 update_disabled_enabled_operations(NewDisabledOperations,NewEnabledOperations,StateID) :-
429 (disabled_operations(StateID,DisabledOperations,EnabledOperations) ->
430 ord_union(DisabledOperations,NewDisabledOperations,DisabledOperations1),
431 ord_union(EnabledOperations,NewEnabledOperations,EnabledOperations1),
432 retractall(disabled_operations(StateID,_,_)),
433 assertz(disabled_operations(StateID,DisabledOperations1,EnabledOperations1))
434 ;
435 assertz(disabled_operations(StateID,NewDisabledOperations,NewEnabledOperations))
436 ).
437
438 compute_disabled_operations_after_state(Pref,OpName1,DisabledActionsAtCurState,_EnabledActionsAtCurState,SuccStateDisabledActions) :-
439 (Pref = disabled; Pref = full),!,
440 findall(OpName2,disables(OpName1,OpName2),ImpossibleEnabled),
441 findall(OpName2,get_disabled_action_by_keep(OpName1,DisabledActionsAtCurState,OpName2),SuccStateDisabledActions1,ImpossibleEnabled),
442 list_to_ord_set(SuccStateDisabledActions1,SuccStateDisabledActions).
443 compute_disabled_operations_after_state(Pref,OpName1,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateDisabledActions) :-
444 (Pref = disabled2; Pref = full2),!,
445 findall(OpName2,(member(OpName2,EnabledActionsAtCurState),enabling_relations(OpName1,OpName2,_,false,_,_)),DisbaledOps1),
446 findall(OpName2,(animation_mode(b),member(OpName2,DisabledActionsAtCurState),enabling_relations(OpName1,OpName2,false,_,_,_)),DisabledOps2,DisbaledOps1),
447 list_to_ord_set(DisabledOps2,SuccStateDisabledActions).
448 compute_disabled_operations_after_state(_Pref,_OpName1,_DisabledActionsAtCurState,_EnabledActionsAtCurState,[]).
449
450 get_disabled_action_by_keep(OpName1,DisabledActionsAtCurState,OpName2) :-
451 animation_mode(b),!, % can be applied only in B mode, for CSP||B is generally not sound
452 ? member(OpName2,DisabledActionsAtCurState),
453 keeps(OpName1,OpName2).
454
455 compute_enabled_operations_after_state(Pref,OpName1,_DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateEnabledActions) :-
456 (Pref = enabled; Pref = full),!,
457 findall(OpName2,enables(OpName1,OpName2),GuaranteedEnabled),
458 findall(OpName2,get_enabled_action_by_keep(OpName1,EnabledActionsAtCurState,OpName2),SuccStateEnabledActions1,GuaranteedEnabled),
459 list_to_ord_set(SuccStateEnabledActions1,SuccStateEnabledActions).
460 compute_enabled_operations_after_state(Pref,OpName1,DisabledActionsAtCurState,EnabledActionsAtCurState,SuccStateEnabledActions) :-
461 (Pref = enabled2; Pref = full2),!,
462 findall(OpName2,(member(OpName2,EnabledActionsAtCurState),enabling_relations(OpName1,OpName2,_,_,false,_)),EnabledOps1),
463 findall(OpName2,(animation_mode(b),member(OpName2,DisabledActionsAtCurState),enabling_relations(OpName1,OpName2,_,_,_,false)),EnabledOps2,EnabledOps1),
464 list_to_ord_set(EnabledOps2,SuccStateEnabledActions).
465 compute_enabled_operations_after_state(_Pref,_OpName1,_DisabledActionsAtCurState,_EnabledActionsAtCurState,[]).
466
467 get_enabled_action_by_keep(OpName1,EnabledActionsAtCurState,OpName2) :-
468 ? member(OpName2,EnabledActionsAtCurState),
469 keeps(OpName1,OpName2).
470
471 get_first_argument((A,_B),A).
472
473 check_only_disabled(disabled).
474 check_only_disabled(disabled2).
475
476 check_only_enabled(enabled).
477 check_only_enabled(enabled2).
478
479 %------------------------------