27
28:- module(scasp_nmr_check,
29 [ generate_nmr_check/1 30 ]).
57:- use_module(library(lists)). 58:- use_module(call_graph). 59:- use_module(common). 60:- use_module(comp_duals). 61:- use_module(program). 62:- use_module(variables). 63:- use_module(library(apply)). 64:- use_module(library(debug)). 65
66:- create_prolog_flag(scasp_compile_olon, true, []). 67:- create_prolog_flag(scasp_compile_nmr, true, []).
76:- det(generate_nmr_check/1). 77
78generate_nmr_check(M) :-
79 debug(scasp(compile), 'Generating NMR check...', []),
80 findall(R, (defined_rule(_, H, B, _), c_rule(R, H, B)), Rs), 81 olon_rules(Rs, M, Rc),
82 nmr_check(Rc, Nmrchk),
83 retractall(defined_rule('_false_0', _, _, _)), 84 negate_functor('_false_0', Nf),
85 predicate(Np, Nf, []),
86 c_rule(Nr, Np, []),
87 assert_rule(nmr(Nr)), 88 assert_nmr_check(Nmrchk).
97nmr_check([], []) :-
98 !.
99nmr_check(Rc, Nmrchk) :-
100 debug(scasp(compile), 'Creating sub-checks...', []),
101 olon_chks(Rc, Nmrchk, 1).
111:- det(olon_rules/3). 112
113olon_rules(R, M, Rc) :-
114 debug(scasp(compile), 'Detecting rules that contain odd loops over negation...', []),
115 assign_unique_ids(R, R1),
116 sort(R1, R2), 117 debug(scasp(compile), 'Building call graph...', []),
118 setup_call_cleanup(
119 build_call_graph(R2, Ns), 120 olon_rules_(R2, M, Ns, Rc),
121 destroy_call_graph).
122
123olon_rules_(R2, M, Ns, Rc) :-
124 dfs(Ns, Pc, _, _),
125 ( current_prolog_flag(scasp_dcc, true)
126 -> get_headless_rules(R2,[],Denials),
127 create_dcc_rules(Denials, M)
128 ; true
129 ),
130 ( current_prolog_flag(scasp_compile_olon, false)
131 -> Rc1 = []
132 ; extract_ids(Pc, Ic),
133 divide_rules(R2, Ic, Rc1, _) 134 ),
135 ( current_prolog_flag(scasp_compile_nmr, false)
136 -> Rc = []
137 ; get_headless_rules(R2, Rc1, Rc)
138 ).
158dfs(N, Pc, Po, Pr) :-
159 debug(scasp(compile), 'Detecting cycles in call graph...', []),
160 dfs2(N, [], [], Pc, [], Po, [], Pr).
181dfs2([], _, Pc, Pc, Po, Po, Pr, Pr).
182dfs2([X|T], V, Pci, Pco, Poi, Poo, Pri, Pro) :-
183 findall(a(X, Y, N, I), a(X, Y, N, I), As), 184 dfs3(As, [v(X, 0)|V], Vo, [], 0, Pci, Pc1, Poi, Po1, Pri, Pr1),
185 dfs2(T, Vo, Pc1, Pco, Po1, Poo, Pr1, Pro).
211:- det(dfs3/11). 212
213dfs3([], V, V, _, _, Pc, Pc, Po, Po, Pr, Pr).
214dfs3([A|T], Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, [[A]|Pro]) :- 215 A = a(X, X, 0, _),
216 !,
217 dfs3(T, Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, Pro).
218dfs3([A|T], Vi, Vo, P, N, Pci, [[A]|Pco], Poi, Poo, Pri, Pro) :- 219 A = a(X, X, 1, _),
220 !,
221 dfs3(T, Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, Pro).
222dfs3([A|T], Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, Pro) :-
223 A = a(_, Y, _, _),
224 memberchk(a(Y, _, _, _), P), 225 !,
226 check_cycle(Y, [A|P], Pci, Pc1, Poi, Po1, Pri, Pr1),
227 dfs3(T, Vi, Vo, P, N, Pc1, Pco, Po1, Poo, Pr1, Pro).
228dfs3([A|T], Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, Pro) :-
229 A = a(_, Y, N2, _),
230 update_negation(N, N2, N3),
231 memberchk(v(Y, N3), Vi), 232 !,
233 dfs3(T, Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, Pro).
234dfs3([A|T], Vi, Vo, P, N, Pci, Pco, Poi, Poo, Pri, Pro) :-
235 A = a(_, Y, N2, _), 236 !,
237 update_negation(N, N2, N3),
238 set_append(v(Y, N3), Vi, V1),
239 findall(a(Y, Y2, Y3, Y4), a(Y, Y2, Y3, Y4), As), 240 dfs3(As, V1, V2, [A|P], N3, Pci, Pc1, Poi, Po1, Pri, Pr1),
241 dfs3(T, V2, Vo, P, N, Pc1, Pco, Po1, Poo, Pr1, Pro).
258check_cycle(X, P, Pci, Pco, Poi, Poo, Pri, Pro) :-
259 get_cycle(X, P, C, N),
260 classify_cycle(N, C, Pci, Pco, Poi, Poo, Pri, Pro).
273:- det(get_cycle/4). 274
275get_cycle(X, P, C, N) :-
276 get_cycle2(X, P, C, 0, N).
289get_cycle2(X, [A|_], [A], Ni, No) :-
290 A = a(X, _, N, _),
291 !,
292 No is Ni + N.
293get_cycle2(X, [A|P], [A|C], Ni, No) :-
294 A = a(_, _, N, _),
295 N2 is N + Ni,
296 get_cycle2(X, P, C, N2, No).
313classify_cycle(0, C, Pc, Pc, Po, Po, Pr, [C|Pr]) :-
314 !.
315classify_cycle(N, C, Pc, Pc, Po, [C|Po], Pr, Pr) :-
316 N > 0,
317 N mod 2 =:= 0,
318 !.
319classify_cycle(N, C, Pc, [C|Pc], Po, Po, Pr, Pr) :-
320 N mod 2 =:= 1.
331update_negation(2, 1, 1) :-
332 !.
333update_negation(X, Y, Z) :-
334 Z is X + Y.
344set_append(X, Y, Y) :-
345 memberchk(X, Y),
346 !.
347set_append(X, Y, [X|Y]).
356extract_ids(C, I) :-
357 extract_ids2(C, [], I2),
358 sort(I2, I).
368extract_ids2([X|T], Ii, Io) :-
369 extract_ids3(X, [], I),
370 append(I, Ii, I1),
371 extract_ids2(T, I1, Io).
372extract_ids2([], I, I).
383extract_ids3([X|T], Ii, Io) :-
384 X = a(_, _, _, I), 385 once(ar(I, Ri)), 386 append(Ri, Ii, I1),
387 extract_ids3(T, I1, Io).
388extract_ids3([], I, I).
399divide_rules([X|T], Is, [X|To], To2) :- 400 rule(X, _, I, _),
401 memberchk(I, Is),
402 !,
403 divide_rules(T, Is, To, To2).
404divide_rules([X|T], Is, To, [X|To2]) :- 405 !,
406 divide_rules(T, Is, To, To2).
407divide_rules([], _, [], []).
418get_headless_rules([X|T], Rci, [X|Rco]) :-
419 rule(X, H, _, _),
420 predicate(H, '_false_0', _), 421 !,
422 get_headless_rules(T, Rci, Rco).
423get_headless_rules([_|T], Rci, Rco) :-
424 get_headless_rules(T, Rci, Rco).
425get_headless_rules([], Rc, Rc).
441olon_chks([R|T], [not(G)|Nmr], C) :-
442 rule(R, X, _, Y),
443 predicate(X, '_false_0', _), 444 !,
445 c_rule(R2, X, Y), 446 create_unique_functor('_chk_0', C, H), 447 comp_duals3(H, [R2]),
448 predicate(G, H, []), 449 C1 is C + 1,
450 olon_chks(T, Nmr, C1).
451olon_chks([R|T], [Go|Nmr], C) :-
452 rule(R, X, _, Y),
453 !,
454 ( memberchk(not(X), Y) 455 -> c_rule(R2, X, Y)
456 ; append(Y, [not(X)], Y2),
457 c_rule(R2, X, Y2) 458 ),
459 predicate(X, Hi, _),
460 split_functor(Hi, _, A), 461 atom_concat('_chk_', A, Hb),
462 create_unique_functor(Hb, C, H), 463 comp_duals3(H, [R2]),
464 var_list(A, V), 465 predicate(G, H, V),
466 define_forall(not(G), Go, V), 467 C1 is C + 1,
468 olon_chks(T, Nmr, C1).
469olon_chks([], [], _).
481assign_unique_ids(Ri, Ro) :-
482 assign_unique_ids2(Ri, Ro, 1).
493assign_unique_ids2([], [], _).
494assign_unique_ids2([X|T], [X2|T2], C) :-
495 c_rule(X, H, B), 496 !,
497 rule(X2, H, C, B),
498 C1 is C + 1,
499 assign_unique_ids2(T, T2, C1).
500assign_unique_ids2([X|T], [X2|T2], C) :-
501 X2 = -(X, C),
502 C1 is C + 1,
503 assign_unique_ids2(T, T2, C1).
504
505
506
514create_dcc_rules([], _).
515create_dcc_rules([-(-(_,_),Rule)|Rc], M) :-
516 maplist(remove_arity, Rule, Dcc),
517 revar(Dcc, RDcc, _),
518 assert_dcc_rule([], RDcc, M),
519 create_dcc_rules(Rc, M).
520
521remove_arity(not(R), not(D)) :- !,
522 remove_arity(R, D).
523remove_arity(R, D) :-
524 R =.. [RName|Args],
525 split_functor(RName, DName, _),
526 !,
527 D =.. [DName|Args].
528remove_arity(R, R).
529
530assert_dcc_rule(Prev, [A|Next], M) :-
531 !,
532 append(Prev, Next, Prev0),
533 ( skip_dcc(A)
534 -> true
535 ; assert(M:pr_dcc_predicate(dcc(A), Prev0)),
536 true
537 ),
538 append(Prev, [A], Prev1),
539 assert_dcc_rule(Prev1, Next, M).
540assert_dcc_rule(_, [], _).
541
542skip_dcc(forall(_,_)) => true.
543skip_dcc(A) => functor(A, Op, 2), operator(Op,_,_)
Detect OLON rules and construct nmr_check
Detect OLON rules and construct nmr_check.
Terminology: