1 % (c) 2009-2019 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 % Flow analysis
5 % Filename: flow.pl
6
7 :- module(flow, [create_enable_graph/1, create_enable_graphs/1, reset_flow/0, print_base_guide/1,print_event_guide/2]).
8
9 :- use_module(tools).
10 :- use_module(self_check).
11
12 :- use_module(module_information,[module_info/2]).
13 :- module_info(group,experimental).
14 :- module_info(description,'Flow Analysis for Event-B models. Extracts a flow graph from a model.').
15
16 :- use_module(library(lists)).
17 :- use_module(library(ordsets)).
18
19 :-use_module(bmachine,[b_top_level_operation/1,b_get_invariant_from_machine/1,wp_untyped/3,clear_wp/0,nonchanging_guard/2]).
20 :-use_module(bsyntaxtree).
21
22 :- use_module(translate, [translate_bexpression/2]).
23
24 :- dynamic eventnumber/2.
25 :- dynamic guide_wp/3.
26 :- dynamic wp_typed/3, event_wp/3.
27
28 :- use_module(error_manager).
29 :- use_module(bmachine,[typecheck_predicates/4]).
30
31 add_wp(S,D,TypedPred) :-
32 assert( wp_typed(S,D,TypedPred) ).
33 update_typed_wp :-
34 retract( wp_untyped(S,D,P) ),
35 bmachine:typecheck_predicates(P,TypedPred,S,D),
36 add_wp(S,D,TypedPred),
37 fail.
38 update_typed_wp.
39
40 wp(S,D,TypedPred) :-
41 update_typed_wp,
42 wp_typed(S,D,TypedPred).
43
44 % ---------------------------------- Interface
45
46 :- meta_predicate print_single_enable_graph(*,3).
47 :- meta_predicate print_single_enable_graph(*,3,*).
48
49 create_enable_graph(X):- build_enable_graph,
50 print_single_enable_graph(X,wp).
51
52 create_enable_graphs(X):- build_enable_graph,
53 print_multiple_enable_graphs(X).
54
55 print_base_guide(X) :- build_enable_graph,
56 print_single_enable_graph(X,guide_wp).
57
58 print_event_guide(X,E) :- build_enable_graph,
59 retractall(event_wp(_,_,_)),
60 build_guide(E,N),
61 print_single_enable_graph(X,event_wp,N).
62
63
64 reset_flow :- retractall(done_flow(_)), retractall(guide_wp(_,_,_)).
65
66 :- use_module(eventhandling,[register_event_listener/3]).
67 :- register_event_listener(clear_specification,reset_flow,
68 'Reset flow analysis.').
69
70 :- public backward_analysis/1. % still useful ??
71 backward_analysis(Event) :- build_enable_graph,
72 print_flow_automaton(Event).
73
74 % -------------------------------- Flow Automaton
75
76 print_flow_automaton(E) :- calculate_flow_automaton([E],[],X), print(X), nl.
77
78 calculate_flow_automaton([],A,A).
79 calculate_flow_automaton([H|T],A,R) :- findall((S,P),(wp(S,H,P), \+false_predicate(P)),L), append(L,A,NA), calculate_flow_automaton(T,NA,R).
80
81
82 % -------------------------------- Enable Graph
83
84
85
86 :- dynamic done_flow/1.
87
88 build_enable_graph :- (done_flow(enable_graph) -> true;
89 ((print('Computing enable_graph'),nl,
90 enumerate_events,
91 prepare_input,
92 find_contradictions,
93 add_init_edges,
94 law_of_motion,
95 build_base_guide,
96 print('Done'),nl)
97 -> assert(done_flow(enable_graph))
98 ; add_error(flow,'Could not build enable_graph'),fail)).
99
100 print_single_enable_graph(File,NameEdges) :- events(Nodes), print_single_enable_graph(File,NameEdges,Nodes).
101
102 print_single_enable_graph(File,NameEdges,Nodes) :-
103 print(writing_to_dot_file(File)),nl,
104 tell(File),
105 dot_header('EnableGraph'),
106 dot_node(Nodes),
107 findall((S,D,P), call(NameEdges,S,D,P),WL),
108 dot_edge(WL),
109 dot_footer,
110 told,
111 print(closing(File)),nl.
112
113 print_multiple_enable_graphs(File) :-
114 print(writing_to_dot_file(File)),nl,
115 tell(File),
116 dot_header('EnableGraphs'), print('rankdir=LR'),nl, events(L), dot_node(L), print_subgraph(L),
117 dot_footer, told,
118 print(closing(File)),nl.
119
120 print_subgraph([]).
121 print_subgraph([H|T]) :- findall((H,D,P), wp(H,D,P),WL),
122 print_edges(WL),
123 print_subgraph(T).
124
125 % -------------------------------- Prepare Input / Normalize
126
127 prepare_input :- statistics(runtime,_),
128 normalize_inv,
129 normalize_wp,
130 statistics(runtime,[_,T2]), print(normalizing(T2)),nl.
131
132 normalize_wp :- findall((S,D,P), wp(S,D,P), L), clear_wp, normalize_wps(L).
133
134 normalize_wps([]).
135 normalize_wps([(S,D,P)|T]) :- conjunct_predicates(P,P3),conjunction_to_list(P3,P2),normalize_list(P2,R), add_wp(S,D,R), normalize_wps(T).
136
137
138 normalize_inv :- b_get_invariant_from_machine(Invariant),
139 conjunction_to_list(Invariant,L),
140 normalize_invs(L).
141 normalize_invs([]).
142 normalize_invs([H|T]) :- translate_bexpression(H,HP),
143 print(normalizing_inv(HP)),nl, normalize(H,HX), get_texpr_expr(HX,HR),
144 ((HR =.. [Op,X,Y] ,keep(Op)) -> assert_pred_inv(X,Op,Y);true),
145 normalize_invs(T).
146
147 normalize_guards(E) :- findall((E,X),nonchanging_guard(E,X), L),
148 print(mormalizing_grd(E,L)),nl,
149 normalize_guards2(L).
150
151 normalize_guards2([]).
152 normalize_guards2([(E,P)|T]) :- normalize_list(P,R), assert_guards(R,E), normalize_guards2(T).
153
154 assert_guards([],_).
155 assert_guards([H|T],E) :- get_texpr_expr(H,truth),!, assert_guards(T,E).
156 assert_guards([H|T],E) :- get_texpr_expr(H,HR),
157 HR =.. [Op,X,Y],!, (keep(Op) -> assert_pred_guard(Op,X,Y);true), assert_guards(T,E).
158 assert_guards([H|_],_) :- add_error(flow,'Cannot normalize: ',H),fail.
159
160 % ------------------------------ Normalizer
161
162 normalize(TExpr,TNExpr) :- remove_bt(TExpr,Expr,NExpr,TNExpr), normalize2(Expr,NExpr).
163
164 normalize2(not_equal(X,boolean_true),equal(X,boolean_false)) :- !.
165 normalize2(not_equal(X,boolean_false),equal(X,boolean_true)) :- !.
166 normalize2(negation(TExpr),R) :- !,
167 remove_bt(TExpr,Expr,NExpr,_), negate_boolean_expression(Expr,NExpr), normalize2(NExpr,R).
168 normalize2(TExpr, R) :-
169 syntaxtransformation(TExpr,TSubExpr,_,TNSubExpr,R),!, normalize_list(TSubExpr, TNSubExpr).
170 normalize2(TExpr,_) :- add_error(flow,'Unknown expression in normalize2: ',TExpr),fail.
171
172 normalize_list([],R) :- !,R=[].
173 normalize_list([H|T],[HR|TR]) :- !, normalize(H,HR),normalize_list(T,TR).
174 normalize_list(A,B) :- add_error(flow,'Illegal arguments in normalize_list: ',(A,B)),fail.
175
176 /** keep is used to specify which invariants shall be kept
177 (we keep only those parts that can be handled by the builtin prover) */
178 keep(boolean_false).
179 keep(boolean_true).
180 keep(equal).
181 keep(not_equal).
182 keep(member).
183 keep(not_member).
184 keep(less).
185 keep(greater).
186 keep(less_equal).
187 keep(greater_equal).
188
189 negate_boolean_expression(A,B) :-
190 if(neg(A,B),true, add_error_fail(flow,'Unknown operator in negate: ',neg(A,B))).
191
192
193 neg(boolean_true,boolean_false).
194 neg(boolean_false,boolean_true).
195 neg(equal(X,Y),not_equal(X,Y)).
196 neg(not_equal(X,Y),equal(X,Y)).
197 neg(equal(X,Y),not_equal(X,Y)).
198 neg(member(X,Y),not_member(X,Y)).
199 neg(not_member(X,Y),member(X,Y)).
200 neg(less(X,Y),greater_equal(X,Y)).
201 neg(less_equal(X,Y),greater(X,Y)).
202 neg(greater_equal(X,Y),less(X,Y)).
203 neg(greater(X,Y),less_equal(X,Y)).
204 neg(subset_strict(X,Y),not_subset_strict(X,Y)).
205 neg(not_subset_strict(X,Y),subset_strict(X,Y)).
206 neg(subset(X,Y),not_subset(X,Y)).
207 neg(not_subset(X,Y),subset(X,Y)).
208
209
210 :- assert_must_succeed((flow:neg(boolean_true, boolean_false))).
211 :- assert_must_succeed((flow:neg(boolean_false, boolean_true))).
212
213 :- assert_must_succeed((flow:neg(equal(1,3), not_equal(1,3)))).
214 :- assert_must_succeed((flow:neg(not_equal(1,3), equal(1,3)))).
215
216 :- assert_must_succeed((flow:neg(member(1,{2}), not_member(1,{2})))).
217 :- assert_must_succeed((flow:neg(not_member(1,{2}), member(1,{2})))).
218
219 :- assert_must_succeed((flow:neg(greater(1,2), less_equal(1,2)))).
220 :- assert_must_succeed((flow:neg(greater_equal(1,2), less(1,2)))).
221 :- assert_must_succeed((flow:neg(less(1,2), greater_equal(1,2)))).
222 :- assert_must_succeed((flow:neg(less_equal(1,2), greater(1,2)))).
223
224 :- assert_must_succeed((flow:neg(not_subset_strict(foo,bar), subset_strict(foo,bar)))).
225 :- assert_must_succeed((flow:neg(subset_strict(foo,bar), not_subset_strict(foo,bar)))).
226 :- assert_must_succeed((flow:neg(subset(foo,bar), not_subset(foo,bar)))).
227 :- assert_must_succeed((flow:neg(not_subset(foo,bar), subset(foo,bar)))).
228
229
230 % -------------------------------- Init Edges
231 add_init_edges :- events(L), add_init_edges(L).
232 add_init_edges([]).
233 add_init_edges(['INITIALISATION'|T]) :- !, add_init_edges(T).
234 add_init_edges([H|T]) :- H\='INITIALISATION',(wp('INITIALISATION',H,_)->true;add_wp('INITIALISATION',H,[])),add_init_edges(T).
235
236 % -------------------------------- Law of motion
237 law_of_motion :- events(L), law_of_motion(L).
238 law_of_motion([]).
239 law_of_motion(['INITIALISATION'|T]) :- !, law_of_motion(T).
240 law_of_motion([H|T]) :- H\='INITIALISATION',(wp(H,H,_)->true;add_wp(H,H,[])),law_of_motion(T).
241
242
243 % -------------------------------- Base Guiding Automaton
244
245 build_base_guide :- findall((S,D,P),wp(S,D,P),L), build_base_guide(L).
246 build_base_guide([]).
247 build_base_guide([(S,D,P)|T]) :- (false_predicate(P) -> true; assert(guide_wp(S,D,P))), build_base_guide(T).
248
249 build_guide(E,RV) :- guide_dfs([E],RV), retractall(event_wp(_,_,_)),filter_from_guide(RV).
250
251 guide_dfs(Stack, Visited) :- guide_dfs(Stack,[],Visited).
252
253 guide_dfs([],SeenSoFar,SeenSoFar).
254 guide_dfs([Event|Tail],SeenSoFar,Visited) :- member(Event,SeenSoFar),!, guide_dfs(Tail,SeenSoFar,Visited). % ignore!
255 guide_dfs([Event|Tail],SeenSoFar,Visited) :- findall(S,guide_wp(S,Event,_),L), append(L,Tail,Todo), guide_dfs(Todo,[Event|SeenSoFar],Visited).
256
257
258 filter_from_guide(V) :- guide_wp(S,D,P), member(S,V), member(D,V), assert(event_wp(S,D,P)), fail.
259 filter_from_guide(_).
260
261
262 % -------------------------------- Flow Graph
263
264
265
266
267
268 % --------------------------------- Prover
269 :- dynamic pred_grd/3, pred_new/3.
270 :- dynamic pred_guard/3.
271 :- dynamic pred_inv/3.
272 :- dynamic change/0.
273 :- dynamic inconsistent/0.
274 %:- dynamic trans/3.
275
276 false_predicate([b(boolean_false,boolean,[nodeid(none)])]).
277
278 find_contradictions :- findall((S,D,P), wp(S,D,P), L), clear_wp, find_contradictions(L).
279
280 find_contradictions([]).
281 find_contradictions([(S,D,P)|T]) :- retractall(inconsistent),
282 retractall(pred_grd(_,_,_)),
283 retractall(pred_new(_,_,_)),
284 retractall(pred_guard(_,_,_)),
285 normalize_guards(S),
286 find_contradictions2(P),
287 (inconsistent -> false_predicate(F), add_wp(S,D,F)
288 ; otherwise -> (simplify(P,PR), add_wp(S,D,PR))),
289 find_contradictions(T).
290
291 find_contradictions2([]).
292 find_contradictions2([H|_]) :- get_texpr_expr(H,boolean_false), !, assert(inconsistent).
293 find_contradictions2([H|T]) :- get_texpr_expr(H,HR), (HR =.. [Op,X,Y] -> assert_pred(Op,X,Y); true), (\+inconsistent -> huelle, find_contradictions2(T);true).
294
295
296 huelle :- pred(Op,X,Y),pred(Op2,Y,Z), combine(Op,Op2,Op3),
297 assert_pred(Op3,X,Z),fail.
298 huelle :- (retract(change) -> huelle2 ; true).
299
300 huelle2 :- retract(pred_new(X,Op,Y)), huelle2(X,Op,Y).
301 huelle2 :- (retract(change) -> huelle2 ; true).
302
303 huelle2(X,Op,Y) :- pred(Op2,Y,Z), combine(Op,Op2,Op3), assert_pred(Op3,X,Z),fail.
304 huelle2(Y,Op,Z) :- pred(Op2,X,Y), combine(Op2,Op,Op3), assert_pred(Op3,X,Z),fail.
305
306 assert_pred(Op,X,Y) :- %print(try(Op,X,Y)),nl,
307 pred(Op,X,Y) -> true
308 ; (assert(pred_grd(X,Op,Y)), %print(pred_grd(Op,X,Y)),nl,
309 assert(pred_new(X,Op,Y)),
310 (change -> true ; assert(change)),
311
312 %nl,print(check_inconsistent(Op,X,Y)),nl,
313
314 (inconsistent_fact(Op,X,Y) -> (assert(inconsistent), print('INCONSISTENT'), nl) ; true),
315 ((sym(Op),X\=Y)
316 -> assert(pred_grd(Y,Op,X)), assert(pred_new(X,Op,Y)) ; true)).
317
318 assert_pred_inv(Op,Y,Z) :-
319 pred_inv(Y,Op,Z) -> true
320 ; assert(pred_inv(Y,Op,Z)),
321 ((sym(Op),Z\=Y) -> assert(pred_inv(Z,Op,Y)) ; true).
322 assert_pred_guard(Op,Y,Z) :-
323 pred_guard(Y,Op,Z) -> true
324 ; assert(pred_guard(Y,Op,Z)),
325 ((sym(Op),Z\=Y) -> assert(pred_guard(Z,Op,Y)) ; true).
326
327 pred(Op,Y,Z) :- pred_grd(Y,Op,Z).
328 pred(Op,Y,Z) :- pred_inv(Y,Op,Z).
329 pred(Op,Y,Z) :- pred_guard(Y,Op,Z).
330
331 inconsistent_fact(not_equal,X,X).
332 inconsistent_fact(less,X,X).
333 inconsistent_fact(greater,X,X).
334 inconsistent_fact(equal,X,Y) :- value(X), value(Y), X \= Y.
335 inconsistent_fact(subset_strict,X,X).
336 inconsistent_fact(member,_,empty_set).
337
338 :- assert_must_succeed((flow:inconsistent_fact(not_equal,4,4))).
339 :- assert_must_succeed((flow:inconsistent_fact(less,4,4))).
340 :- assert_must_succeed((flow:inconsistent_fact(subset_strict,{4},{4}))).
341 :- assert_must_succeed((flow:inconsistent_fact(member,4,empty_set))).
342
343 :- assert_must_succeed((flow:value2(4))).
344 :- assert_must_succeed((flow:value2(boolean_false))).
345 :- assert_must_succeed((flow:value2(boolean_true))).
346 :- assert_must_succeed((flow:value2(integer(_,7)))).
347
348 value(X) :- get_texpr_expr(X,Y), value2(Y).
349
350 value2(X) :- number(X).
351 value2(boolean_false).
352 value2(boolean_true).
353 value2(integer(_,_)).
354
355 sym(equal).
356 sym(not_equal).
357
358 combine(equal,X,X).
359 combine(less_equal,less,less).
360 combine(less_equal,less_equal,less_equal).
361 combine(less,less,less).
362 combine(greater,greater,greater).
363 combine(greater_equal,greater,greater).
364 combine(greater_equal,greater_equal,greater_equal).
365 combine(subset_strict,subset_strict,subset_strict).
366
367 % ------------------------------ Simplifier
368
369 simplify([],[]).
370 simplify([H|T],R) :- (member(H,T) -> R=RT; %remove duplicates
371 otherwise -> (tautology(H) -> R=RT; %remove tautologies
372 otherwise -> R=[H|RT])),
373 simplify(T,RT).
374
375 tautology(X) :- get_texpr_expr(X,Y), tautology2(Y).
376
377 tautology2(boolean_true).
378 tautology2(equal(A,A)).
379 tautology2(subset(A,A)).
380 tautology2(less_equal(A,A)).
381 tautology2(greater_equal(A,A)).
382
383
384 % -------------------------------- Helper
385 :- dynamic count/1.
386 reset_count :- retractall(count(_)), assert(count(0)).
387 inc :- count(X), retract(count(_)), X1 is X+1, assert(count(X1)).
388
389 print_edges([]).
390 print_edges([(S,D,P)|T]) :- print_node(S,D,C,X), format_edge(C,X,P), print_edges(T).
391
392 print_node(S,D,C,X) :- eventnumber(S,C), count(X), inc, format_node(X,D).
393
394 enumerate_events :- reset_count, events(L), enumerate_events(L).
395 enumerate_events([]).
396 enumerate_events([S|T]) :- count(C), assert(eventnumber(S,C)), inc, enumerate_events(T).
397
398 events(['INITIALISATION'|L]) :- findall(OperationName, b_top_level_operation(OperationName), L).
399
400 dot_header(Name) :- print('digraph '), print(Name),print(' {'),nl.
401
402 dot_node([]).
403 dot_node([S|T]) :- eventnumber(S,C), format_node(C,S), dot_node(T).
404
405 format_node(Number,Text) :- print(Number), print(' '), print('[label="'), print(Text), print('"]'),nl.
406
407 dot_edge([]).
408 dot_edge([(S,D,P)|T]) :- eventnumber(S,SN), eventnumber(D,DN), format_edge(SN,DN,P), dot_edge(T).
409
410 format_edge(FromNumber,ToNumber,[]) :- format_edge2(FromNumber,ToNumber, green).
411 format_edge(FromNumber,ToNumber,F) :- false_predicate(F),!,format_edge2(FromNumber,ToNumber, red).
412 format_edge(FromNumber, ToNumber, LP) :- conjunct_predicates(LP,P),translate_bexpression(P,Label), print(FromNumber), print('->'), print(ToNumber), print(' '), print('[label="'), print(Label), print('"]') ,nl.
413
414 format_edge2(FromNumber, ToNumber, green) :- print(FromNumber), print('->'), print(ToNumber), print(' '), print('[color="forestgreen" label=true]') ,nl.
415 format_edge2(FromNumber, ToNumber, red) :- print(FromNumber), print('->'), print(ToNumber), print(' '), print('[color="crimson" label=false]') ,nl.
416
417 dot_footer :- print('}').
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456 % ---------------------------------- Main Program
457
458
459 % build_flow_graph:- (open(State) -> (process(State,State), retract(open(State)), count(C), inc, assert(node(State,C)), build_flow_graph);
460 % otherwise -> true).
461
462
463 % process([],_).
464 % process([H|T],State) :- findall((D,P),trans(H,D,P),L), add_edges(L,State),
465 % process(T,State).
466
467 %join_nonchanging(X,OS,NS) :- list_to_ord_set(X,OX),no_effect(X,NE),list_to_ord_set(NE,ONE), ord_intersection(OX,ONE,NonChanging),list_to_ord_set(OS,Changed),ord_union(Changed,NonChanging,NS).
468
469 % add_edges([],_).
470 % add_edges([(Dest,Pred)|T],Src) :- assert(edge(Src,Dest,Pred)), assert_open(Dest), add_edges(T,Src).
471
472 % process([],A,A).
473 % process([H|T],A,R) :- trans(H,_,S), append(S,A,NS), process(T,NS,R).
474
475 % assert_open(R) :- ( open(R) -> true; (node(R,_) -> true ; assert(open(R)))).
476
477 % no_effect(X,R) :- events(All),list_to_ord_set(All,OA),no_effect(X,OA,R).
478 % no_effect([],A,A).
479 % no_effect([H|T],A,R) :- findall(Y,wp(H,Y,_),Z), list_to_ord_set(Z,OE), ord_subtract(A,OE,NA), no_effect(T,NA,R).
480
481
482 % ---------------------------------- Output
483
484
485 % print_dot2(Name) :- atom_codes(Name,NameString), append(NameString,"_components.dot",FileName),atom_codes(File,FileName),tell(File),
486 % dot_header(Name),findall((S,D,P), trans(S,D,P),WL), print_transitions(WL),
487 % dot_footer, told.
488
489
490 % print_flow(Name) :- atom_codes(Name,NameString), append(NameString,"_flow.dot",FileName),atom_codes(File,FileName),tell(File),dot_header(Name),
491 % flow_nodes, flow_edges,
492 % dot_footer, told.
493
494 % flow_nodes :- findall((S,C),node(S,C),L), flow_node(L).
495 % flow_node([]).
496 % flow_node([(S,C)|T]) :- print(C), print(' '), print('[label="'), print(S), print('"]'),nl,flow_node(T).
497 % flow_edges :- findall((S,D,P), edge(S,P,D), L), flow_edge(L).
498 % flow_edge([]).
499 % flow_edge([(S,P,D)|T]) :- node(S,SN), node(D,DN), print(SN), print('->'), print(DN), print(' '), print('[label="'),
500 % print_pred(P),
501 % print('"]') ,nl,flow_edge(T).
502
503 % :- dynamic graph2/2.
504
505 % print_transitions([]).
506 % print_transitions([(S,D,P)|T]) :- put_node(S,SN), put_node(D,DN),
507 % print(SN), print('->'), print(DN), print(' '), print('[label="'), print(P), print('"]') ,nl, print_transitions(T).
508
509 %put_node(X,XN) :- graph2(X,XN),!.
510 % put_node(X,XN) :- count(XN),inc, assert(graph2(X,XN)), print(XN), print(' '), print('[label="'), print(X), print('"]'),nl.
511