1 | % (c) 2014-2022 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(enabling_predicates, [compute_enabling_predicate/5]). | |
6 | ||
7 | /* Modules and Infos for the code coverage analysis */ | |
8 | :- use_module(probsrc(module_information)). | |
9 | :- module_info(group,model_checker). | |
10 | :- module_info(description,'This module provides predicates computing weakest preconditions without taking the preconditions of the substitutions into account'). | |
11 | ||
12 | % Standard SICSTUS prolog libraries | |
13 | :- use_module(library(lists)). | |
14 | ||
15 | % Classical B prolog modules | |
16 | :- use_module(probsrc(bmachine),[b_get_machine_operation/4, b_get_invariant_from_machine/1]). | |
17 | :- use_module(probsrc(bsyntaxtree),[conjunct_predicates/2, conjunction_to_list/2, | |
18 | get_texpr_expr/2, create_texpr/4, %remove_all_infos/2, | |
19 | create_exists/3, create_or_merge_exists/3, safe_create_texpr/3, | |
20 | get_texpr_ids/2, some_id_occurs_in_expr/2]). | |
21 | :- use_module(probsrc(btypechecker), [prime_identifiers/2]). | |
22 | ||
23 | % Predicates for calculating the weakest-precondition | |
24 | :- use_module(extrasrc(weakest_preconditions), [weakest_precondition/3]). | |
25 | ||
26 | % POR modules | |
27 | :- use_module(probporsrc(b_simplifier),[simplify_b_predicate/2]). | |
28 | ||
29 | % Other ProB modules | |
30 | :- use_module(probsrc(preferences),[get_preference/2]). | |
31 | :- use_module(probsrc(translate),[translate_bexpression/2, translate_substitution/2]). | |
32 | :- use_module(probsrc(debug), [debug_mode/1]). | |
33 | :- use_module(probsrc(error_manager),[add_error/3]). | |
34 | ||
35 | ||
36 | %enumeration_warning(enumerating(n),'INTEGER',1:sup,1:3,critical) | |
37 | % TODO: After computing the weakest-precondition try to simplify the predicate | |
38 | compute_enabling_predicate(OpName,OmitOpNameGuard,Pred,FindInvViolations,Res) :- | |
39 | b_get_machine_operation(OpName,_Res,Par,Body), | |
40 | (FindInvViolations==1 -> | |
41 | b_get_invariant_from_machine(Inv), | |
42 | conjunct_predicates([Inv,Pred],Pred1) | |
43 | ; | |
44 | Pred1 = Pred | |
45 | ), | |
46 | % TODO: add a case for Event-B | |
47 | % compute wp when the source operation is deterministic | |
48 | get_preference(enable_graph_depth,Depth), | |
49 | (Depth==0 -> | |
50 | WP = b(truth,pred,[]) | |
51 | %add_warning(weakest_precondition,'Weakest precondition cannot be computed: ',(body(Body),pred(Pred))), | |
52 | %Res = invariant | |
53 | ; | |
54 | create_event_body(OpName,Par,Body,NewBody), | |
55 | compute_ep(NewBody,OmitOpNameGuard,Pred1,WP1), | |
56 | %remove_all_infos(WP1,WP2), % consider to use remove_all_infos/2 (problem: all nodeid's will be replaced by a variable, | |
57 | % this causes instatiations errors when using predicate simplifier.) | |
58 | remove_nodeid_infos(WP1,WP) | |
59 | ), | |
60 | print_weakest_precondition(OpName,Body,Pred,WP), | |
61 | %% print(weakest_precondition(WP)),nl, | |
62 | simplify_b_predicate(WP,Simplified), | |
63 | print_b_expression(Simplified), | |
64 | Res=predicate(Simplified). | |
65 | ||
66 | create_event_body(OpName,Par,Body,Res) :- | |
67 | create_event_body1(OpName,Par,Body,Res). | |
68 | ||
69 | create_event_body1(_OpName,[],Body,Res) :- !, | |
70 | Res = Body. | |
71 | create_event_body1(OpName,Par,Body,Res) :- | |
72 | is_list(Par),!, | |
73 | get_texpr_expr(Body,Expr), | |
74 | get_precondition_body(Expr,Par,OpName,InterimRes), | |
75 | create_texpr(InterimRes,subst,[],Res). | |
76 | create_event_body1(OpName,Par,Body,_Res) :- | |
77 | add_error(create_event_body,'The Parameters should be wrapped in a prolog list: ', OpName:Par/Body),fail. | |
78 | ||
79 | get_precondition_body(precondition(Condition,Action),Par,_OpName,Res) :- !, | |
80 | Res = any(Par,Condition,Action). | |
81 | get_precondition_body(Body,_Par,_OpName,Res) :- | |
82 | functor(Body,rlevent,11),!, | |
83 | Res = Body. | |
84 | get_precondition_body(OpName,Stmt,_Pre,_InnerBody) :- | |
85 | add_error(get_precondition_body,'Statement not covered yet: ', OpName:Stmt). | |
86 | ||
87 | compute_ep(Body,OmitBodyGuard,Pred,WP) :- | |
88 | (OmitBodyGuard==true -> | |
89 | get_texpr_expr(Body,Expr), | |
90 | compute_ep1(Expr,Pred,WP) | |
91 | ; | |
92 | weakest_precondition(Body,Pred,WP) | |
93 | ). | |
94 | ||
95 | compute_ep1(precondition(_Condition,Action),Pred,WP) :- !, | |
96 | % here we do not add the Condition as a conjunct | |
97 | weakest_precondition(Action,Pred,WP). | |
98 | compute_ep1(select([When]),Pred,WP) :- !, | |
99 | get_texpr_expr(When,select_when(_PreCond, Body)), | |
100 | weakest_precondition(Body,Pred,WP). | |
101 | %% compute_ep1(if([If]),Pred,WP) :- !, | |
102 | %% get_texpr_expr(If,if_elsif(_Test,Body)), | |
103 | %% weakest_precondition(Body,Pred,WP). | |
104 | compute_ep1(any(Parameters,Guard,Action),Pred,WP) :- !, | |
105 | remove_free_predicates(Parameters,Guard,NewGuard), | |
106 | weakest_precondition(Action,Pred,InnerWP), | |
107 | safe_create_texpr(conjunct(NewGuard,InnerWP),pred,UnquantifiedWP), | |
108 | create_or_merge_exists(Parameters,UnquantifiedWP,WP). | |
109 | %% weakest_preconditions: weakest_precondition2(any(Parameters,NewGuard,Action),Pred,WP). % using weakest precondition as enabling predicate is not correct | |
110 | compute_ep1(rlevent(_Name,_Section,_Stat,Parameters,Guard,_Thm,Act,_VWit,_PWit,_Unmod,_AbsEvents),Pred,EP) :- !, | |
111 | %% debug:debug_println(9,rlevent(_Name,_Section,_Stat,Parameters,Guard,_Thm,Act,_VWit,_PWit,_Unmod,_AbsEvents)), | |
112 | % we have "ANY t WHERE Q THEN T END" statement (here we need to add the guard to the WP) | |
113 | % we can sort out the free predicates from Q (at the point of testing the WP we know that there is a representation of the non-deterministic event) | |
114 | remove_free_predicates(Parameters,Guard,RestrictedGuard), | |
115 | % we normalise each event for the case that there are non-deterministic assignments | |
116 | (is_list(Act) -> | |
117 | normalise_to_deterministic_actions_event(Act,NewBody,Parameters,NewParameters,RestrictedGuard,NewGuard) | |
118 | ; | |
119 | normalise_to_deterministic_actions_event([Act],NewBody,Parameters,NewParameters,RestrictedGuard,NewGuard) | |
120 | ), | |
121 | weakest_precondition(NewBody,Pred,WP), | |
122 | (NewParameters = [] -> | |
123 | EP = WP | |
124 | ; | |
125 | safe_create_texpr(conjunct(NewGuard,WP),pred,UnquantifiedEP), | |
126 | create_exists(NewParameters,UnquantifiedEP,EP) | |
127 | ). | |
128 | compute_ep1(Body,Pred,EP) :- | |
129 | create_texpr(Body,subst,[],WrappedBody), | |
130 | weakest_precondition(WrappedBody,Pred,EP). | |
131 | ||
132 | normalise_to_deterministic_actions_event(Acts,NewBody,Parameters,NewParameters,Guard,NewGuard) :- | |
133 | normalise_nondeterministic_actions(Acts,PrimeParams,NewConjuncts,NewActs), | |
134 | append(Parameters,PrimeParams,NewParameters), | |
135 | conjunct_predicates([Guard|NewConjuncts],NewGuard), | |
136 | create_texpr(parallel(NewActs),subst,[],NewBody). | |
137 | %% safe_create_texpr(conjunct(Guard,NewConjuncts),pred,NewGuard). | |
138 | ||
139 | :- use_module(probsrc(btypechecker),[prime_identifiers0/2]). | |
140 | :- use_module(probsrc(bsyntaxtree),[rename_bt/3]). | |
141 | normalise_nondeterministic_actions([],[],[],[]). | |
142 | normalise_nondeterministic_actions([Act|Acts],Parameters,NewConjuncts,NewActs) :- | |
143 | get_texpr_expr(Act,Expr), | |
144 | (Expr = becomes_element_of(IDs,Set) -> | |
145 | prime_identifiers(IDs,Params), | |
146 | weakest_preconditions: create_members(Set,Params,SetCond), | |
147 | create_texpr(assign(IDs,Parameters),subst,[],PrimeAssign), | |
148 | append(Params,Parameters1,Parameters), | |
149 | NewConjuncts=[SetCond|NewConjuncts1], | |
150 | NewActs = [PrimeAssign|NewActs1] | |
151 | ; Expr = becomes_such(Vars,Condition) -> % x:| x<x$0 gets translated to any x$0 where x$0<x then x := x$0 end | |
152 | % also see get_operation_enabling_condition2 | |
153 | sort(Vars,Vars1), | |
154 | prime_identifiers0(Vars1,PrimedVars), % generate $0 versions for Vars | |
155 | maplist(gen_rename,Vars1,PrimedVars,RenameList1), % id -> id$0 | |
156 | maplist(gen_rename,PrimedVars,Vars1,RenameList2), % id$0 -> id | |
157 | append(RenameList1,RenameList2,RenameList), | |
158 | rename_bt(Condition,RenameList,Condition1), | |
159 | NewConjuncts=[Condition1|NewConjuncts1], | |
160 | create_texpr(assign(Vars1,PrimedVars),subst,[],PrimeAssign), | |
161 | append(PrimedVars,Parameters1,Parameters), | |
162 | NewActs = [PrimeAssign|NewActs1] | |
163 | ; | |
164 | NewConjuncts = NewConjuncts1, | |
165 | NewActs = [Act|NewActs1], | |
166 | Parameters = Parameters1 | |
167 | ), | |
168 | normalise_nondeterministic_actions(Acts,Parameters1,NewConjuncts1,NewActs1). | |
169 | ||
170 | :- use_module(probsrc(bsyntaxtree),[def_get_texpr_id/2]). | |
171 | gen_rename(TID1,TID2,rename(ID1,ID2)) :- def_get_texpr_id(TID1,ID1), def_get_texpr_id(TID2,ID2). | |
172 | ||
173 | ||
174 | remove_free_predicates(Parameters,Guard,NewGuard) :- | |
175 | conjunction_to_list(Guard,Conjuncts), | |
176 | get_texpr_ids(Parameters,Ids), | |
177 | filter_out_global_guards(Conjuncts,Ids,RestConjuncts), | |
178 | conjunct_predicates(RestConjuncts,NewGuard), | |
179 | %% bsyntaxtree:predicate_components_in_scope(Guard,Parameters,Res), | |
180 | (debug_mode(on) -> | |
181 | print('####### Remove global guards #######'),nl, | |
182 | print('Identifiers: '),print(Ids),nl, | |
183 | remove_nodeid_infos(Guard,GuardNoInfos), | |
184 | print('Guard: '),translate:print_bexpr(GuardNoInfos),nl, | |
185 | print('NewGuard: '),translate:print_bexpr(NewGuard),nl, | |
186 | print('####################################'),nl | |
187 | ; true). | |
188 | ||
189 | filter_out_global_guards([],_Ids,[]). | |
190 | filter_out_global_guards([TExpr|TExprs],Ids,Res) :- | |
191 | (some_id_occurs_in_expr(Ids,TExpr) -> | |
192 | Res=[TExpr|Res1] | |
193 | ; | |
194 | Res = Res1 | |
195 | ), filter_out_global_guards(TExprs,Ids,Res1). | |
196 | ||
197 | /* For debugging only */ | |
198 | print_weakest_precondition(Opname,Body,Guard,WP) :- | |
199 | (debug_mode(on) -> | |
200 | print('######### Weakest Precondition #########'),nl, | |
201 | remove_nodeid_infos(Guard,GuardNoInfos), | |
202 | translate_bexpression(GuardNoInfos,Guard_PP), | |
203 | translate_bexpression(WP,WP_PP), | |
204 | translate_substitution(Body,RealBody), | |
205 | print('Operation/Event '),print(Opname),print(' :: '),nl, | |
206 | print('['),print(RealBody),print(']'), | |
207 | print('('),print(Guard_PP),print(')'), | |
208 | print(' = '),print(WP_PP),nl, | |
209 | print('########################################'),nl | |
210 | ; true). | |
211 | ||
212 | print_b_expression(BExpr) :- | |
213 | (debug_mode(on) -> | |
214 | translate_bexpression(BExpr,String), | |
215 | conjunction_to_list(BExpr,List), | |
216 | print(String),nl, | |
217 | print('Conjunctions list: [ '),print_conjunct_l(List) | |
218 | ; true). | |
219 | ||
220 | print_conjunct_l([]) :- | |
221 | print(' ]'),nl. | |
222 | print_conjunct_l([Expr]) :- !, | |
223 | translate_bexpression(Expr,String), | |
224 | print(String),print(' ]'),nl. | |
225 | print_conjunct_l([Expr|Exprs]) :- | |
226 | translate_bexpression(Expr,String), | |
227 | print(String),print(', '), | |
228 | print_conjunct_l(Exprs). | |
229 | ||
230 | remove_nodeid_infos(Expr,Res) :- | |
231 | var(Expr),!, | |
232 | Res=Expr. | |
233 | remove_nodeid_infos(Expr,Res) :- | |
234 | is_list(Expr),!, | |
235 | maplist(remove_nodeid_infos,Expr,Res). | |
236 | remove_nodeid_infos(Expr,Res) :- | |
237 | Expr =.. [F|Args], | |
238 | remove_nodeid_infos1(F,Args,Res). | |
239 | ||
240 | remove_nodeid_infos1(nodeid,_Args,Res) :- | |
241 | % ignore additional node infos | |
242 | !, Res = nodeid(none). | |
243 | remove_nodeid_infos1(F,Args,Res) :- | |
244 | maplist(remove_nodeid_infos,Args,ArgsRes), | |
245 | Res =.. [F|ArgsRes]. |