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 |