37
38:- module('$tabling',
39 [ (table)/1, 40 untable/1, 41
42 (tnot)/1, 43 not_exists/1, 44 undefined/0,
45 answer_count_restraint/0,
46 radial_restraint/0,
47
48 current_table/2, 49 abolish_all_tables/0,
50 abolish_private_tables/0,
51 abolish_shared_tables/0,
52 abolish_table_subgoals/1, 53 abolish_module_tables/1, 54 abolish_nonincremental_tables/0,
55 abolish_nonincremental_tables/1, 56 abolish_monotonic_tables/0,
57
58 start_tabling/3, 59 start_subsumptive_tabling/3, 60 start_abstract_tabling/3, 61 start_moded_tabling/5, 62 63
64 '$tbl_answer'/4, 65
66 '$wrap_tabled'/2, 67 '$moded_wrap_tabled'/5, 68 '$wfs_call'/2, 69
70 '$set_table_wrappers'/1, 71 '$start_monotonic'/2 72 ]). 73
74:- meta_predicate
75 table(:),
76 untable(:),
77 tnot(0),
78 not_exists(0),
79 tabled_call(0),
80 start_tabling(+, +, 0),
81 start_abstract_tabling(+, +, 0),
82 start_moded_tabling(+, +, 0, +, ?),
83 current_table(:, -),
84 abolish_table_subgoals(:),
85 '$wfs_call'(0, :). 86
96
99goal_expansion(tdebug(Topic, Fmt, Args), Expansion) :-
100 ( current_prolog_flag(prolog_debug, true)
101 -> Expansion = debug(tabling(Topic), Fmt, Args)
102 ; Expansion = true
103 ).
104goal_expansion(tdebug(Goal), Expansion) :-
105 ( current_prolog_flag(prolog_debug, true)
106 -> Expansion = ( debugging(tabling(_))
107 -> ( Goal
108 -> true
109 ; print_message(error,
110 format('goal_failed: ~q', [Goal]))
111 )
112 ; true
113 )
114 ; Expansion = true
115 ).
116
117:- if(current_prolog_flag(prolog_debug, true)). 118wl_goal(tnot(WorkList), ~(Goal), Skeleton) :-
119 !,
120 '$tbl_wkl_table'(WorkList, ATrie),
121 trie_goal(ATrie, Goal, Skeleton).
122wl_goal(WorkList, Goal, Skeleton) :-
123 '$tbl_wkl_table'(WorkList, ATrie),
124 trie_goal(ATrie, Goal, Skeleton).
125
126trie_goal(ATrie, Goal, Skeleton) :-
127 '$tbl_table_status'(ATrie, _Status, M:Variant, Skeleton),
128 ( M:'$table_mode'(Goal0, Variant, _Moded)
129 -> true
130 ; Goal0 = Variant 131 ),
132 unqualify_goal(M:Goal0, user, Goal).
133
134delay_goals(List, Goal) :-
135 delay_goals(List, user, Goal).
136
137user_goal(Goal, UGoal) :-
138 unqualify_goal(Goal, user, UGoal).
139
140:- multifile
141 prolog:portray/1. 142
143user:portray(ATrie) :-
144 '$is_answer_trie'(ATrie, _),
145 trie_goal(ATrie, Goal, _Skeleton),
146 ( '$idg_falsecount'(ATrie, FalseCount)
147 -> ( '$idg_forced'(ATrie)
148 -> format('~q [fc=~d/F] for ~p', [ATrie, FalseCount, Goal])
149 ; format('~q [fc=~d] for ~p', [ATrie, FalseCount, Goal])
150 )
151 ; format('~q for ~p', [ATrie, Goal])
152 ).
153user:portray(Cont) :-
154 compound(Cont),
155 compound_name_arguments(Cont, '$cont$', [_Context, Clause, PC | Args]),
156 clause_property(Clause, file(File)),
157 file_base_name(File, Base),
158 clause_property(Clause, line_count(Line)),
159 clause_property(Clause, predicate(PI)),
160 format('~q at ~w:~d @PC=~w, ~p', [PI, Base, Line, PC, Args]).
161
162:- endif. 163
186
187table(M:PIList) :-
188 setup_call_cleanup(
189 '$set_source_module'(OldModule, M),
190 expand_term((:- table(PIList)), Clauses),
191 '$set_source_module'(OldModule)),
192 dyn_tabling_list(Clauses, M).
193
194dyn_tabling_list([], _).
195dyn_tabling_list([H|T], M) :-
196 dyn_tabling(H, M),
197 dyn_tabling_list(T, M).
198
199dyn_tabling(M:Clause, _) :-
200 !,
201 dyn_tabling(Clause, M).
202dyn_tabling((:- multifile(PI)), M) :-
203 !,
204 multifile(M:PI),
205 dynamic(M:PI).
206dyn_tabling(:- initialization(Wrap, now), M) :-
207 !,
208 M:Wrap.
209dyn_tabling('$tabled'(Head, TMode), M) :-
210 ( clause(M:'$tabled'(Head, OMode), true, Ref),
211 ( OMode \== TMode
212 -> erase(Ref),
213 fail
214 ; true
215 )
216 -> true
217 ; assertz(M:'$tabled'(Head, TMode))
218 ).
219dyn_tabling('$table_mode'(Head, Variant, Moded), M) :-
220 ( clause(M:'$table_mode'(Head, Variant0, Moded0), true, Ref)
221 -> ( t(Head, Variant, Moded) =@= t(Head, Variant0, Moded0)
222 -> true
223 ; erase(Ref),
224 assertz(M:'$table_mode'(Head, Variant, Moded))
225 )
226 ; assertz(M:'$table_mode'(Head, Variant, Moded))
227 ).
228dyn_tabling(('$table_update'(Head, S0, S1, S2) :- Body), M) :-
229 ( clause(M:'$table_update'(Head, S00, S10, S20), Body0, Ref)
230 -> ( t(Head, S0, S1, S2, Body) =@= t(Head, S00, S10, S20, Body0)
231 -> true
232 ; erase(Ref),
233 assertz(M:('$table_update'(Head, S0, S1, S2) :- Body))
234 )
235 ; assertz(M:('$table_update'(Head, S0, S1, S2) :- Body))
236 ).
237
246
247untable(M:PIList) :-
248 untable(PIList, M).
249
250untable(Var, _) :-
251 var(Var),
252 !,
253 '$instantiation_error'(Var).
254untable(M:Spec, _) :-
255 !,
256 '$must_be'(atom, M),
257 untable(Spec, M).
258untable((A,B), M) :-
259 !,
260 untable(A, M),
261 untable(B, M).
262untable(Name//Arity, M) :-
263 atom(Name), integer(Arity), Arity >= 0,
264 !,
265 Arity1 is Arity+2,
266 untable(Name/Arity1, M).
267untable(Name/Arity, M) :-
268 !,
269 functor(Head, Name, Arity),
270 ( '$get_predicate_attribute'(M:Head, tabled, 1)
271 -> abolish_table_subgoals(M:Head),
272 dynamic(M:'$tabled'/2),
273 dynamic(M:'$table_mode'/3),
274 retractall(M:'$tabled'(Head, _TMode)),
275 retractall(M:'$table_mode'(Head, _Variant, _Moded)),
276 unwrap_predicate(M:Name/Arity, table),
277 '$set_predicate_attribute'(M:Head, tabled, false),
278 '$set_predicate_attribute'(M:Head, opaque, false),
279 '$set_predicate_attribute'(M:Head, incremental, false),
280 '$set_predicate_attribute'(M:Head, monotonic, false),
281 '$set_predicate_attribute'(M:Head, lazy, false)
282 ; true
283 ).
284untable(Head, M) :-
285 callable(Head),
286 !,
287 functor(Head, Name, Arity),
288 untable(Name/Arity, M).
289untable(TableSpec, _) :-
290 '$type_error'(table_desclaration, TableSpec).
291
292untable_reconsult(PI) :-
293 print_message(informational, untable(PI)),
294 untable(PI).
295
296:- initialization
297 prolog_listen(untable, untable_reconsult). 298
299
300'$wrap_tabled'(Head, Options) :-
301 get_dict(mode, Options, subsumptive),
302 !,
303 set_pattributes(Head, Options),
304 '$wrap_predicate'(Head, table, Closure, Wrapped,
305 start_subsumptive_tabling(Closure, Head, Wrapped)).
306'$wrap_tabled'(Head, Options) :-
307 get_dict(subgoal_abstract, Options, _Abstract),
308 !,
309 set_pattributes(Head, Options),
310 '$wrap_predicate'(Head, table, Closure, Wrapped,
311 start_abstract_tabling(Closure, Head, Wrapped)).
312'$wrap_tabled'(Head, Options) :-
313 !,
314 set_pattributes(Head, Options),
315 '$wrap_predicate'(Head, table, Closure, Wrapped,
316 start_tabling(Closure, Head, Wrapped)).
317
322
323set_pattributes(Head, Options) :-
324 '$set_predicate_attribute'(Head, tabled, true),
325 ( tabled_attribute(Attr),
326 get_dict(Attr, Options, Value),
327 '$set_predicate_attribute'(Head, Attr, Value),
328 fail
329 ; current_prolog_flag(table_monotonic, lazy),
330 '$set_predicate_attribute'(Head, lazy, true),
331 fail
332 ; true
333 ).
334
335tabled_attribute(incremental).
336tabled_attribute(dynamic).
337tabled_attribute(tshared).
338tabled_attribute(max_answers).
339tabled_attribute(subgoal_abstract).
340tabled_attribute(answer_abstract).
341tabled_attribute(monotonic).
342tabled_attribute(opaque).
343tabled_attribute(lazy).
344
358
359start_tabling(Closure, Wrapper, Worker) :-
360 '$tbl_variant_table'(Closure, Wrapper, Trie, Status, Skeleton, IsMono),
361 ( IsMono == true
362 -> shift(dependency(Skeleton, Trie, Mono)),
363 ( Mono == true
364 -> tdebug(monotonic, 'Monotonic new answer: ~p', [Skeleton])
365 ; start_tabling_2(Closure, Wrapper, Worker, Trie, Status, Skeleton)
366 )
367 ; start_tabling_2(Closure, Wrapper, Worker, Trie, Status, Skeleton)
368 ).
369
370start_tabling_2(Closure, Wrapper, Worker, Trie, Status, Skeleton) :-
371 tdebug(deadlock, 'Got table ~p, status ~p', [Trie, Status]),
372 ( Status == complete
373 -> trie_gen_compiled(Trie, Skeleton)
374 ; functor(Status, fresh, 2)
375 -> catch(create_table(Trie, Status, Skeleton, Wrapper, Worker),
376 deadlock,
377 restart_tabling(Closure, Wrapper, Worker))
378 ; Status == invalid
379 -> reeval(Trie, Wrapper, Skeleton)
380 ; 381 shift_for_copy(call_info(Skeleton, Status))
382 ).
383
384create_table(Trie, Fresh, Skeleton, Wrapper, Worker) :-
385 tdebug(Fresh = fresh(SCC, WorkList)),
386 tdebug(wl_goal(WorkList, Goal, _)),
387 tdebug(schedule, 'Created component ~d for ~p', [SCC, Goal]),
388 setup_call_catcher_cleanup(
389 '$idg_set_current'(OldCurrent, Trie),
390 run_leader(Skeleton, Worker, Fresh, LStatus, Clause),
391 Catcher,
392 finished_leader(OldCurrent, Catcher, Fresh, Wrapper)),
393 tdebug(schedule, 'Leader ~p done, status = ~p', [Goal, LStatus]),
394 done_leader(LStatus, Fresh, Skeleton, Clause).
395
403
404restart_tabling(Closure, Wrapper, Worker) :-
405 tdebug(user_goal(Wrapper, Goal)),
406 tdebug(deadlock, 'Deadlock running ~p; retrying', [Goal]),
407 sleep(0.000001),
408 start_tabling(Closure, Wrapper, Worker).
409
410restart_abstract_tabling(Closure, Wrapper, Worker) :-
411 tdebug(user_goal(Wrapper, Goal)),
412 tdebug(deadlock, 'Deadlock running ~p; retrying', [Goal]),
413 sleep(0.000001),
414 start_abstract_tabling(Closure, Wrapper, Worker).
415
425
426start_subsumptive_tabling(Closure, Wrapper, Worker) :-
427 ( '$tbl_existing_variant_table'(Closure, Wrapper, Trie, Status, Skeleton)
428 -> ( Status == complete
429 -> trie_gen_compiled(Trie, Skeleton)
430 ; Status == invalid
431 -> reeval(Trie, Wrapper, Skeleton),
432 trie_gen_compiled(Trie, Skeleton)
433 ; shift_for_copy(call_info(Skeleton, Status))
434 )
435 ; more_general_table(Wrapper, ATrie),
436 '$tbl_table_status'(ATrie, complete, Wrapper, Skeleton)
437 -> '$tbl_answer_update_dl'(ATrie, Skeleton) 438 ; more_general_table(Wrapper, ATrie),
439 '$tbl_table_status'(ATrie, Status, GenWrapper, GenSkeleton)
440 -> ( Status == invalid
441 -> reeval(ATrie, GenWrapper, GenSkeleton),
442 Wrapper = GenWrapper,
443 '$tbl_answer_update_dl'(ATrie, GenSkeleton)
444 ; wrapper_skeleton(GenWrapper, GenSkeleton, Wrapper, Skeleton),
445 shift_for_copy(call_info(GenSkeleton, Skeleton, Status)),
446 unify_subsumptive(Skeleton, GenSkeleton)
447 )
448 ; start_tabling(Closure, Wrapper, Worker)
449 ).
450
455
456wrapper_skeleton(GenWrapper, GenSkeleton, Wrapper, Skeleton) :-
457 copy_term(GenWrapper+GenSkeleton, Wrapper+Skeleton),
458 tdebug(call_subsumption, 'GenSkeleton+Skeleton = ~p',
459 [GenSkeleton+Skeleton]).
460
461unify_subsumptive(X,X).
462
473
474start_abstract_tabling(Closure, Wrapper, Worker) :-
475 '$tbl_abstract_table'(Closure, Wrapper, Trie, _Abstract, Status, Skeleton),
476 tdebug(abstract, 'Wrapper=~p, Worker=~p, Skel=~p',
477 [Wrapper, Worker, Skeleton]),
478 ( is_most_general_term(Skeleton) 479 -> start_tabling_2(Closure, Wrapper, Worker, Trie, Status, Skeleton)
480 ; Status == complete
481 -> '$tbl_answer_update_dl'(Trie, Skeleton)
482 ; functor(Status, fresh, 2)
483 -> '$tbl_table_status'(Trie, _, GenWrapper, GenSkeleton),
484 abstract_worker(Worker, GenWrapper, GenWorker),
485 catch(create_abstract_table(Trie, Status, Skeleton, GenSkeleton, GenWrapper,
486 GenWorker),
487 deadlock,
488 restart_abstract_tabling(Closure, Wrapper, Worker))
489 ; Status == invalid
490 -> '$tbl_table_status'(Trie, _, GenWrapper, GenSkeleton),
491 reeval(ATrie, GenWrapper, GenSkeleton),
492 Wrapper = GenWrapper,
493 '$tbl_answer_update_dl'(ATrie, Skeleton)
494 ; shift_for_copy(call_info(GenSkeleton, Skeleton, Status)),
495 unify_subsumptive(Skeleton, GenSkeleton)
496 ).
497
498create_abstract_table(Trie, Fresh, Skeleton, GenSkeleton, Wrapper, Worker) :-
499 tdebug(Fresh = fresh(SCC, WorkList)),
500 tdebug(wl_goal(WorkList, Goal, _)),
501 tdebug(schedule, 'Created component ~d for ~p', [SCC, Goal]),
502 setup_call_catcher_cleanup(
503 '$idg_set_current'(OldCurrent, Trie),
504 run_leader(GenSkeleton, Worker, Fresh, LStatus, _Clause),
505 Catcher,
506 finished_leader(OldCurrent, Catcher, Fresh, Wrapper)),
507 tdebug(schedule, 'Leader ~p done, status = ~p', [Goal, LStatus]),
508 Skeleton = GenSkeleton,
509 done_abstract_leader(LStatus, Fresh, GenSkeleton, Trie).
510
511abstract_worker(_:call(Term), _M:GenWrapper, call(GenTerm)) :-
512 functor(Term, Closure, _),
513 GenWrapper =.. [_|Args],
514 GenTerm =.. [Closure|Args].
515
516:- '$hide'((done_abstract_leader/4)). 517
518done_abstract_leader(complete, _Fresh, Skeleton, Trie) :-
519 !,
520 '$tbl_answer_update_dl'(Trie, Skeleton).
521done_abstract_leader(final, fresh(SCC, _Worklist), Skeleton, Trie) :-
522 !,
523 '$tbl_free_component'(SCC),
524 '$tbl_answer_update_dl'(Trie, Skeleton).
525done_abstract_leader(_,_,_,_).
526
533
534:- '$hide'((done_leader/4, finished_leader/4)). 535
536done_leader(complete, _Fresh, Skeleton, Clause) :-
537 !,
538 trie_gen_compiled(Clause, Skeleton).
539done_leader(final, fresh(SCC, _Worklist), Skeleton, Clause) :-
540 !,
541 '$tbl_free_component'(SCC),
542 trie_gen_compiled(Clause, Skeleton).
543done_leader(_,_,_,_).
544
545finished_leader(OldCurrent, Catcher, Fresh, Wrapper) :-
546 '$idg_set_current'(OldCurrent),
547 ( Catcher == exit
548 -> true
549 ; Catcher == fail
550 -> true
551 ; Catcher = exception(_)
552 -> Fresh = fresh(SCC, _),
553 '$tbl_table_discard_all'(SCC)
554 ; print_message(error, tabling(unexpected_result(Wrapper, Catcher)))
555 ).
556
569
570run_leader(Skeleton, Worker, fresh(SCC, Worklist), Status, Clause) :-
571 tdebug(wl_goal(Worklist, Goal, Skeleton)),
572 tdebug(schedule, '-> Activate component ~p for ~p', [SCC, Goal]),
573 activate(Skeleton, Worker, Worklist),
574 tdebug(schedule, '-> Complete component ~p for ~p', [SCC, Goal]),
575 completion(SCC, Status, Clause),
576 tdebug(schedule, '-> Completed component ~p for ~p: ~p', [SCC, Goal, Status]),
577 ( Status == merged
578 -> tdebug(merge, 'Turning leader ~p into follower', [Goal]),
579 '$tbl_wkl_make_follower'(Worklist),
580 shift_for_copy(call_info(Skeleton, Worklist))
581 ; true 582 ).
583
584activate(Skeleton, Worker, WorkList) :-
585 tdebug(activate, '~p: created wl=~p', [Skeleton, WorkList]),
586 ( reset_delays,
587 delim(Skeleton, Worker, WorkList, []),
588 fail
589 ; true
590 ).
591
605
606delim(Skeleton, Worker, WorkList, Delays) :-
607 reset(Worker, SourceCall, Continuation),
608 tdebug(wl_goal(WorkList, Goal, _)),
609 ( Continuation == 0
610 -> tdebug('$tbl_add_global_delays'(Delays, AllDelays)),
611 tdebug(delay_goals(AllDelays, Cond)),
612 tdebug(answer, 'New answer ~p for ~p (delays = ~p)',
613 [Skeleton, Goal, Cond]),
614 '$tbl_wkl_add_answer'(WorkList, Skeleton, Delays, Complete),
615 Complete == !,
616 !
617 ; SourceCall = call_info(SrcSkeleton, SourceWL)
618 -> '$tbl_add_global_delays'(Delays, AllDelays),
619 tdebug(wl_goal(SourceWL, SrcGoal, _)),
620 tdebug(wl_goal(WorkList, DstGoal, _)),
621 tdebug(schedule, 'Suspended ~p, for solving ~p', [SrcGoal, DstGoal]),
622 '$tbl_wkl_add_suspension'(
623 SourceWL,
624 dependency(SrcSkeleton, Continuation, Skeleton, WorkList, AllDelays))
625 ; SourceCall = call_info(SrcSkeleton, InstSkeleton, SourceWL)
626 -> '$tbl_add_global_delays'(Delays, AllDelays),
627 tdebug(wl_goal(SourceWL, SrcGoal, _)),
628 tdebug(wl_goal(WorkList, DstGoal, _)),
629 tdebug(schedule, 'Suspended ~p, for solving ~p', [SrcGoal, DstGoal]),
630 '$tbl_wkl_add_suspension'(
631 SourceWL,
632 InstSkeleton,
633 dependency(SrcSkeleton, Continuation, Skeleton, WorkList, AllDelays))
634 ; '$tbl_wkl_table'(WorkList, ATrie),
635 mon_assert_dep(SourceCall, Continuation, Skeleton, ATrie)
636 -> delim(Skeleton, Continuation, WorkList, Delays)
637 ).
638
643
644'$moded_wrap_tabled'(Head, Options, ModeTest, WrapperNoModes, ModeArgs) :-
645 set_pattributes(Head, Options),
646 '$wrap_predicate'(Head, table, Closure, Wrapped,
647 ( ModeTest,
648 start_moded_tabling(Closure, Head, Wrapped,
649 WrapperNoModes, ModeArgs)
650 )).
651
652
653start_moded_tabling(Closure, Wrapper, Worker, WrapperNoModes, ModeArgs) :-
654 '$tbl_moded_variant_table'(Closure, WrapperNoModes, Trie,
655 Status, Skeleton, IsMono),
656 ( IsMono == true
657 -> shift(dependency(Skeleton/ModeArgs, Trie, Mono)),
658 ( Mono == true
659 -> tdebug(monotonic, 'Monotonic new answer: ~p', [Skeleton])
660 ; start_moded_tabling_2(Closure, Wrapper, Worker, ModeArgs,
661 Trie, Status, Skeleton)
662 )
663 ; start_moded_tabling_2(Closure, Wrapper, Worker, ModeArgs,
664 Trie, Status, Skeleton)
665 ).
666
667start_moded_tabling_2(_Closure, Wrapper, Worker, ModeArgs,
668 Trie, Status, Skeleton) :-
669 ( Status == complete
670 -> moded_gen_answer(Trie, Skeleton, ModeArgs)
671 ; functor(Status, fresh, 2)
672 -> setup_call_catcher_cleanup(
673 '$idg_set_current'(OldCurrent, Trie),
674 moded_run_leader(Wrapper, Skeleton/ModeArgs,
675 Worker, Status, LStatus),
676 Catcher,
677 finished_leader(OldCurrent, Catcher, Status, Wrapper)),
678 tdebug(schedule, 'Leader ~p done, modeargs = ~p, status = ~p',
679 [Wrapper, ModeArgs, LStatus]),
680 moded_done_leader(LStatus, Status, Skeleton, ModeArgs, Trie)
681 ; Status == invalid
682 -> reeval(Trie, Wrapper, Skeleton),
683 moded_gen_answer(Trie, Skeleton, ModeArgs)
684 ; 685 shift_for_copy(call_info(Skeleton/ModeArgs, Status))
686 ).
687
688:- public
689 moded_gen_answer/3. 690
691moded_gen_answer(Trie, Skeleton, ModedArgs) :-
692 trie_gen(Trie, Skeleton),
693 '$tbl_answer_update_dl'(Trie, Skeleton, ModedArgs).
694
695'$tbl_answer'(ATrie, Skeleton, ModedArgs, Delay) :-
696 trie_gen(ATrie, Skeleton),
697 '$tbl_answer_c'(ATrie, Skeleton, ModedArgs, Delay).
698
699moded_done_leader(complete, _Fresh, Skeleton, ModeArgs, Trie) :-
700 !,
701 moded_gen_answer(Trie, Skeleton, ModeArgs).
702moded_done_leader(final, fresh(SCC, _WorkList), Skeleton, ModeArgs, Trie) :-
703 !,
704 '$tbl_free_component'(SCC),
705 moded_gen_answer(Trie, Skeleton, ModeArgs).
706moded_done_leader(_, _, _, _, _).
707
708moded_run_leader(Wrapper, SkeletonMA, Worker, fresh(SCC, Worklist), Status) :-
709 tdebug(wl_goal(Worklist, Goal, _)),
710 tdebug(schedule, '-> Activate component ~p for ~p', [SCC, Goal]),
711 moded_activate(SkeletonMA, Worker, Worklist),
712 tdebug(schedule, '-> Complete component ~p for ~p', [SCC, Goal]),
713 completion(SCC, Status, _Clause), 714 tdebug(schedule, '-> Completed component ~p for ~p: ~p', [SCC, Goal, Status]),
715 ( Status == merged
716 -> tdebug(merge, 'Turning leader ~p into follower', [Wrapper]),
717 '$tbl_wkl_make_follower'(Worklist),
718 shift_for_copy(call_info(SkeletonMA, Worklist))
719 ; true 720 ).
721
722moded_activate(SkeletonMA, Worker, WorkList) :-
723 ( reset_delays,
724 delim(SkeletonMA, Worker, WorkList, []),
725 fail
726 ; true
727 ).
728
744
745:- public
746 update/7. 747
749update(0b11, Wrapper, M, Agg, New, Next, delete) :-
750 !,
751 M:'$table_update'(Wrapper, Agg, New, Next),
752 Agg \=@= Next.
754update(0b10, Wrapper, M, Agg, New, Next, keep) :-
755 !,
756 M:'$table_update'(Wrapper, Agg, New, Next0),
757 ( Next0 =@= Agg
758 -> Next = Agg
759 ; Next = Next0
760 ).
762update(0b01, Wrapper, M, Agg, New, Next, keep) :-
763 !,
764 M:'$table_update'(Wrapper, New, Agg, Next0),
765 ( Next0 =@= Agg
766 -> Next = Agg
767 ; Next = Next0
768 ).
770update(0b00, _Wrapper, _M, _Agg, New, New, keep) :-
771 !.
772
779
780completion(SCC, Status, Clause) :-
781 ( reset_delays,
782 completion_(SCC),
783 fail
784 ; '$tbl_table_complete_all'(SCC, Status, Clause),
785 tdebug(schedule, 'SCC ~p: ~p', [scc(SCC), Status])
786 ).
787
788completion_(SCC) :-
789 repeat,
790 ( '$tbl_pop_worklist'(SCC, WorkList)
791 -> tdebug(wl_goal(WorkList, Goal, _)),
792 tdebug(schedule, 'Complete ~p in ~p', [Goal, scc(SCC)]),
793 completion_step(WorkList)
794 ; !
795 ).
796
823
825
826completion_step(SourceWL) :-
827 '$tbl_wkl_work'(SourceWL,
828 Answer, Continuation, TargetSkeleton, TargetWL, Delays),
829 tdebug(wl_goal(SourceWL, SourceGoal, _)),
830 tdebug(wl_goal(TargetWL, TargetGoal, _Skeleton)),
831 tdebug('$tbl_add_global_delays'(Delays, AllDelays)),
832 tdebug(delay_goals(AllDelays, Cond)),
833 tdebug(schedule, 'Resuming ~p, calling ~p with ~p (delays = ~p)',
834 [TargetGoal, SourceGoal, Answer, Cond]),
835 delim(TargetSkeleton, Continuation, TargetWL, Delays),
836 fail.
837
838
839 842
848
849tnot(Goal0) :-
850 '$tnot_implementation'(Goal0, Goal), 851 ( '$tbl_existing_variant_table'(_, Goal, Trie, Status, Skeleton),
852 Status \== invalid
853 -> '$idg_add_edge'(Trie),
854 ( '$tbl_answer_dl'(Trie, _, true)
855 -> fail
856 ; '$tbl_answer_dl'(Trie, _, _)
857 -> tdebug(tnot, 'tnot: adding ~p to delay list', [Goal]),
858 add_delay(Trie)
859 ; Status == complete
860 -> true
861 ; negation_suspend(Goal, Skeleton, Status)
862 )
863 ; tdebug(tnot, 'tnot: ~p: fresh', [Goal]),
864 ( '$wrapped_implementation'(Goal, table, Implementation), 865 functor(Implementation, Closure, _),
866 start_tabling(Closure, Goal, Implementation),
867 fail
868 ; '$tbl_existing_variant_table'(_, Goal, Trie, NewStatus, NewSkeleton),
869 tdebug(tnot, 'tnot: fresh ~p now ~p', [Goal, NewStatus]),
870 ( '$tbl_answer_dl'(Trie, _, true)
871 -> fail
872 ; '$tbl_answer_dl'(Trie, _, _)
873 -> add_delay(Trie)
874 ; NewStatus == complete
875 -> true
876 ; negation_suspend(Goal, NewSkeleton, NewStatus)
877 )
878 )
879 ).
880
881floundering(Goal) :-
882 format(string(Comment), 'Floundering goal in tnot/1: ~p', [Goal]),
883 throw(error(instantiation_error, context(_Stack, Comment))).
884
885
893
894negation_suspend(Wrapper, Skeleton, Worklist) :-
895 tdebug(tnot, 'negation_suspend ~p (wl=~p)', [Wrapper, Worklist]),
896 '$tbl_wkl_negative'(Worklist),
897 shift_for_copy(call_info(Skeleton, tnot(Worklist))),
898 tdebug(tnot, 'negation resume ~p (wl=~p)', [Wrapper, Worklist]),
899 '$tbl_wkl_is_false'(Worklist).
900
907
908not_exists(Goal) :-
909 ground(Goal),
910 '$get_predicate_attribute'(Goal, tabled, 1),
911 !,
912 tnot(Goal).
913not_exists(Goal) :-
914 ( tabled_call(Goal), fail
915 ; tnot(tabled_call(Goal))
916 ).
917
918 921
922add_delay(Delay) :-
923 '$tbl_delay_list'(DL0),
924 '$tbl_set_delay_list'([Delay|DL0]).
925
926reset_delays :-
927 '$tbl_set_delay_list'([]).
928
934
935'$wfs_call'(Goal, M:Delays) :-
936 '$tbl_delay_list'(DL0),
937 reset_delays,
938 call(Goal),
939 '$tbl_delay_list'(DL1),
940 ( delay_goals(DL1, M, Delays)
941 -> true
942 ; Delays = undefined
943 ),
944 '$append'(DL0, DL1, DL),
945 '$tbl_set_delay_list'(DL).
946
947delay_goals([], _, true) :-
948 !.
949delay_goals([AT+AN|T], M, Goal) :-
950 !,
951 ( integer(AN)
952 -> at_delay_goal(AT, M, G0, Answer, Moded),
953 ( '$tbl_is_trienode'(Moded)
954 -> trie_term(AN, Answer)
955 ; true 956 )
957 ; AN = Skeleton/ModeArgs
958 -> '$tbl_table_status'(AT, _, M1:GNoModes, Skeleton),
959 M1:'$table_mode'(G0plain, GNoModes, ModeArgs),
960 G0 = M1:G0plain
961 ; '$tbl_table_status'(AT, _, G0, AN)
962 ),
963 GN = G0,
964 ( T == []
965 -> Goal = GN
966 ; Goal = (GN,GT),
967 delay_goals(T, M, GT)
968 ).
969delay_goals([AT|T], M, Goal) :-
970 atrie_goal(AT, G0),
971 unqualify_goal(G0, M, G1),
972 GN = tnot(G1),
973 ( T == []
974 -> Goal = GN
975 ; Goal = (GN,GT),
976 delay_goals(T, M, GT)
977 ).
978
979at_delay_goal(tnot(Trie), M, tnot(Goal), Skeleton, Moded) :-
980 is_trie(Trie),
981 !,
982 at_delay_goal(Trie, M, Goal, Skeleton, Moded).
983at_delay_goal(Trie, M, Goal, Skeleton, Moded) :-
984 is_trie(Trie),
985 !,
986 '$tbl_table_status'(Trie, _Status, M2:Variant, Skeleton),
987 M2:'$table_mode'(Goal0, Variant, Moded),
988 unqualify_goal(M2:Goal0, M, Goal).
989
990atrie_goal(Trie, M:Goal) :-
991 '$tbl_table_status'(Trie, _Status, M:Variant, _Skeleton),
992 M:'$table_mode'(Goal, Variant, _Moded).
993
994unqualify_goal(M:Goal, M, Goal0) :-
995 !,
996 Goal0 = Goal.
997unqualify_goal(Goal, _, Goal).
998
999
1000 1003
1013
1014abolish_all_tables :-
1015 ( '$tbl_abolish_local_tables'
1016 -> true
1017 ; true
1018 ),
1019 ( '$tbl_variant_table'(VariantTrie),
1020 trie_gen(VariantTrie, _, Trie),
1021 '$tbl_destroy_table'(Trie),
1022 fail
1023 ; true
1024 ).
1025
1026abolish_private_tables :-
1027 ( '$tbl_abolish_local_tables'
1028 -> true
1029 ; ( '$tbl_local_variant_table'(VariantTrie),
1030 trie_gen(VariantTrie, _, Trie),
1031 '$tbl_destroy_table'(Trie),
1032 fail
1033 ; true
1034 )
1035 ).
1036
1037abolish_shared_tables :-
1038 ( '$tbl_global_variant_table'(VariantTrie),
1039 trie_gen(VariantTrie, _, Trie),
1040 '$tbl_destroy_table'(Trie),
1041 fail
1042 ; true
1043 ).
1044
1051
1052abolish_table_subgoals(SubGoal0) :-
1053 '$tbl_implementation'(SubGoal0, M:SubGoal),
1054 !,
1055 '$must_be'(acyclic, SubGoal),
1056 ( '$tbl_variant_table'(VariantTrie),
1057 trie_gen(VariantTrie, M:SubGoal, Trie),
1058 '$tbl_destroy_table'(Trie),
1059 fail
1060 ; true
1061 ).
1062abolish_table_subgoals(_).
1063
1067
1068abolish_module_tables(Module) :-
1069 '$must_be'(atom, Module),
1070 '$tbl_variant_table'(VariantTrie),
1071 current_module(Module),
1072 !,
1073 forall(trie_gen(VariantTrie, Module:_, Trie),
1074 '$tbl_destroy_table'(Trie)).
1075abolish_module_tables(_).
1076
1080
1081abolish_nonincremental_tables :-
1082 ( '$tbl_variant_table'(VariantTrie),
1083 trie_gen(VariantTrie, _, Trie),
1084 '$tbl_table_status'(Trie, Status, Goal, _),
1085 ( Status == complete
1086 -> true
1087 ; '$permission_error'(abolish, incomplete_table, Trie)
1088 ),
1089 \+ predicate_property(Goal, incremental),
1090 '$tbl_destroy_table'(Trie),
1091 fail
1092 ; true
1093 ).
1094
1101
1102abolish_nonincremental_tables(Options) :-
1103 ( Options = on_incomplete(Action)
1104 -> Action == skip
1105 ; '$option'(on_incomplete(skip), Options)
1106 ),
1107 !,
1108 ( '$tbl_variant_table'(VariantTrie),
1109 trie_gen(VariantTrie, _, Trie),
1110 '$tbl_table_status'(Trie, complete, Goal, _),
1111 \+ predicate_property(Goal, incremental),
1112 '$tbl_destroy_table'(Trie),
1113 fail
1114 ; true
1115 ).
1116abolish_nonincremental_tables(_) :-
1117 abolish_nonincremental_tables.
1118
1119
1120 1123
1130
1131current_table(Variant, Trie) :-
1132 ct_generate(Variant),
1133 !,
1134 current_table_gen(Variant, Trie).
1135current_table(Variant, Trie) :-
1136 current_table_lookup(Variant, Trie),
1137 !.
1138
1139current_table_gen(M:Variant, Trie) :-
1140 '$tbl_local_variant_table'(VariantTrie),
1141 trie_gen(VariantTrie, M:NonModed, Trie),
1142 M:'$table_mode'(Variant, NonModed, _Moded).
1143current_table_gen(M:Variant, Trie) :-
1144 '$tbl_global_variant_table'(VariantTrie),
1145 trie_gen(VariantTrie, M:NonModed, Trie),
1146 \+ '$tbl_table_status'(Trie, fresh), 1147 M:'$table_mode'(Variant, NonModed, _Moded).
1148
1149current_table_lookup(M:Variant, Trie) :-
1150 M:'$table_mode'(Variant, NonModed, _Moded),
1151 '$tbl_local_variant_table'(VariantTrie),
1152 trie_lookup(VariantTrie, M:NonModed, Trie).
1153current_table_lookup(M:Variant, Trie) :-
1154 M:'$table_mode'(Variant, NonModed, _Moded),
1155 '$tbl_global_variant_table'(VariantTrie),
1156 trie_lookup(VariantTrie, NonModed, Trie),
1157 \+ '$tbl_table_status'(Trie, fresh).
1158
1159ct_generate(M:Variant) :-
1160 ( var(Variant)
1161 -> true
1162 ; var(M)
1163 ).
1164
1165 1168
1169:- multifile
1170 system:term_expansion/2,
1171 tabled/2. 1172:- dynamic
1173 system:term_expansion/2. 1174
1175wrappers(Spec, M) -->
1176 { tabling_defaults(
1177 [ (table_incremental=true) - (incremental=true),
1178 (table_shared=true) - (tshared=true),
1179 (table_subsumptive=true) - ((mode)=subsumptive),
1180 call(subgoal_size_restraint(Level)) - (subgoal_abstract=Level)
1181 ],
1182 #{}, Defaults)
1183 },
1184 wrappers(Spec, M, Defaults).
1185
1186wrappers(Var, _, _) -->
1187 { var(Var),
1188 !,
1189 '$instantiation_error'(Var)
1190 }.
1191wrappers(M:Spec, _, Opts) -->
1192 !,
1193 { '$must_be'(atom, M) },
1194 wrappers(Spec, M, Opts).
1195wrappers(Spec as Options, M, Opts0) -->
1196 !,
1197 { table_options(Options, Opts0, Opts) },
1198 wrappers(Spec, M, Opts).
1199wrappers((A,B), M, Opts) -->
1200 !,
1201 wrappers(A, M, Opts),
1202 wrappers(B, M, Opts).
1203wrappers(Name//Arity, M, Opts) -->
1204 { atom(Name), integer(Arity), Arity >= 0,
1205 !,
1206 Arity1 is Arity+2
1207 },
1208 wrappers(Name/Arity1, M, Opts).
1209wrappers(Name/Arity, Module, Opts) -->
1210 { '$option'(mode(TMode), Opts, variant),
1211 atom(Name), integer(Arity), Arity >= 0,
1212 !,
1213 functor(Head, Name, Arity),
1214 '$tbl_trienode'(Reserved)
1215 },
1216 qualify(Module,
1217 [ '$tabled'(Head, TMode),
1218 '$table_mode'(Head, Head, Reserved)
1219 ]),
1220 [ (:- initialization('$wrap_tabled'(Module:Head, Opts), now))
1221 ].
1222wrappers(ModeDirectedSpec, Module, Opts) -->
1223 { '$option'(mode(TMode), Opts, variant),
1224 callable(ModeDirectedSpec),
1225 !,
1226 functor(ModeDirectedSpec, Name, Arity),
1227 functor(Head, Name, Arity),
1228 extract_modes(ModeDirectedSpec, Head, Variant, Modes, Moded),
1229 updater_clauses(Modes, Head, UpdateClauses),
1230 mode_check(Moded, ModeTest),
1231 ( ModeTest == true
1232 -> WrapClause = '$wrap_tabled'(Module:Head, Opts),
1233 TVariant = Head
1234 ; WrapClause = '$moded_wrap_tabled'(Module:Head, Opts, ModeTest,
1235 Module:Variant, Moded),
1236 TVariant = Variant
1237 )
1238 },
1239 qualify(Module,
1240 [ '$tabled'(Head, TMode),
1241 '$table_mode'(Head, TVariant, Moded)
1242 ]),
1243 [ (:- initialization(WrapClause, now))
1244 ],
1245 qualify(Module, UpdateClauses).
1246wrappers(TableSpec, _M, _Opts) -->
1247 { '$type_error'(table_desclaration, TableSpec)
1248 }.
1249
1250qualify(Module, List) -->
1251 { prolog_load_context(module, Module) },
1252 !,
1253 clist(List).
1254qualify(Module, List) -->
1255 qlist(List, Module).
1256
1257clist([]) --> [].
1258clist([H|T]) --> [H], clist(T).
1259
1260qlist([], _) --> [].
1261qlist([H|T], M) --> [M:H], qlist(T, M).
1262
1263
1264tabling_defaults([], Dict, Dict).
1265tabling_defaults([Condition-(Opt=Value)|T], Dict0, Dict) :-
1266 ( tabling_default(Condition)
1267 -> Dict1 = Dict0.put(Opt,Value)
1268 ; Dict1 = Dict0
1269 ),
1270 tabling_defaults(T, Dict1, Dict).
1271
1272tabling_default(Flag=FValue) :-
1273 !,
1274 current_prolog_flag(Flag, FValue).
1275tabling_default(call(Term)) :-
1276 call(Term).
1277
1279
1280subgoal_size_restraint(Level) :-
1281 current_prolog_flag(max_table_subgoal_size_action, abstract),
1282 current_prolog_flag(max_table_subgoal_size, Level).
1283
1287
1288table_options(Options, _Opts0, _Opts) :-
1289 var(Options),
1290 '$instantiation_error'(Options).
1291table_options((A,B), Opts0, Opts) :-
1292 !,
1293 table_options(A, Opts0, Opts1),
1294 table_options(B, Opts1, Opts).
1295table_options(subsumptive, Opts0, Opts1) :-
1296 !,
1297 put_dict(mode, Opts0, subsumptive, Opts1).
1298table_options(variant, Opts0, Opts1) :-
1299 !,
1300 put_dict(mode, Opts0, variant, Opts1).
1301table_options(incremental, Opts0, Opts1) :-
1302 !,
1303 put_dict(#{incremental:true,opaque:false}, Opts0, Opts1).
1304table_options(monotonic, Opts0, Opts1) :-
1305 !,
1306 put_dict(monotonic, Opts0, true, Opts1).
1307table_options(opaque, Opts0, Opts1) :-
1308 !,
1309 put_dict(#{incremental:false,opaque:true}, Opts0, Opts1).
1310table_options(lazy, Opts0, Opts1) :-
1311 !,
1312 put_dict(lazy, Opts0, true, Opts1).
1313table_options(dynamic, Opts0, Opts1) :-
1314 !,
1315 put_dict(dynamic, Opts0, true, Opts1).
1316table_options(shared, Opts0, Opts1) :-
1317 !,
1318 put_dict(tshared, Opts0, true, Opts1).
1319table_options(private, Opts0, Opts1) :-
1320 !,
1321 put_dict(tshared, Opts0, false, Opts1).
1322table_options(max_answers(Count), Opts0, Opts1) :-
1323 !,
1324 restraint(max_answers, Count, Opts0, Opts1).
1325table_options(subgoal_abstract(Size), Opts0, Opts1) :-
1326 !,
1327 restraint(subgoal_abstract, Size, Opts0, Opts1).
1328table_options(answer_abstract(Size), Opts0, Opts1) :-
1329 !,
1330 restraint(answer_abstract, Size, Opts0, Opts1).
1331table_options(Opt, _, _) :-
1332 '$domain_error'(table_option, Opt).
1333
1334restraint(Name, Value0, Opts0, Opts) :-
1335 '$table_option'(Value0, Value),
1336 ( Value < 0
1337 -> Opts = Opts0
1338 ; put_dict(Name, Opts0, Value, Opts)
1339 ).
1340
1341
1346
1347mode_check(Moded, Check) :-
1348 var(Moded),
1349 !,
1350 Check = (var(Moded)->true;'$uninstantiation_error'(Moded)).
1351mode_check(Moded, true) :-
1352 '$tbl_trienode'(Moded),
1353 !.
1354mode_check(Moded, (Test->true;'$tabling':instantiated_moded_arg(Vars))) :-
1355 Moded =.. [s|Vars],
1356 var_check(Vars, Test).
1357
1358var_check([H|T], Test) :-
1359 ( T == []
1360 -> Test = var(H)
1361 ; Test = (var(H),Rest),
1362 var_check(T, Rest)
1363 ).
1364
1365:- public
1366 instantiated_moded_arg/1. 1367
1368instantiated_moded_arg(Vars) :-
1369 '$member'(V, Vars),
1370 \+ var(V),
1371 '$uninstantiation_error'(V).
1372
1373
1382
(ModeSpec, Head, Variant, Modes, ModedAnswer) :-
1384 compound(ModeSpec),
1385 !,
1386 compound_name_arguments(ModeSpec, Name, ModeSpecArgs),
1387 compound_name_arguments(Head, Name, HeadArgs),
1388 separate_args(ModeSpecArgs, HeadArgs, VariantArgs, Modes, ModedArgs),
1389 length(ModedArgs, Count),
1390 atomic_list_concat([$,Name,$,Count], VName),
1391 Variant =.. [VName|VariantArgs],
1392 ( ModedArgs == []
1393 -> '$tbl_trienode'(ModedAnswer)
1394 ; ModedArgs = [ModedAnswer]
1395 -> true
1396 ; ModedAnswer =.. [s|ModedArgs]
1397 ).
1398extract_modes(Atom, Atom, Variant, [], ModedAnswer) :-
1399 atomic_list_concat([$,Atom,$,0], Variant),
1400 '$tbl_trienode'(ModedAnswer).
1401
1409
1410separate_args([], [], [], [], []).
1411separate_args([HM|TM], [H|TA], [H|TNA], Modes, TMA):-
1412 indexed_mode(HM),
1413 !,
1414 separate_args(TM, TA, TNA, Modes, TMA).
1415separate_args([M|TM], [H|TA], TNA, [M|Modes], [H|TMA]):-
1416 separate_args(TM, TA, TNA, Modes, TMA).
1417
1418indexed_mode(Mode) :- 1419 var(Mode),
1420 !.
1421indexed_mode(index). 1422indexed_mode(+). 1423
1428
1429updater_clauses([], _, []) :- !.
1430updater_clauses([P], Head, [('$table_update'(Head, S0, S1, S2) :- Body)]) :- !,
1431 update_goal(P, S0,S1,S2, Body).
1432updater_clauses(Modes, Head, [('$table_update'(Head, S0, S1, S2) :- Body)]) :-
1433 length(Modes, Len),
1434 functor(S0, s, Len),
1435 functor(S1, s, Len),
1436 functor(S2, s, Len),
1437 S0 =.. [_|Args0],
1438 S1 =.. [_|Args1],
1439 S2 =.. [_|Args2],
1440 update_body(Modes, Args0, Args1, Args2, true, Body).
1441
1442update_body([], _, _, _, Body, Body).
1443update_body([P|TM], [A0|Args0], [A1|Args1], [A2|Args2], Body0, Body) :-
1444 update_goal(P, A0,A1,A2, Goal),
1445 mkconj(Body0, Goal, Body1),
1446 update_body(TM, Args0, Args1, Args2, Body1, Body).
1447
1448update_goal(Var, _,_,_, _) :-
1449 var(Var),
1450 !,
1451 '$instantiation_error'(Var).
1452update_goal(lattice(M:PI), S0,S1,S2, M:Goal) :-
1453 !,
1454 '$must_be'(atom, M),
1455 update_goal(lattice(PI), S0,S1,S2, Goal).
1456update_goal(lattice(Name/Arity), S0,S1,S2, Goal) :-
1457 !,
1458 '$must_be'(oneof(integer, lattice_arity, [3]), Arity),
1459 '$must_be'(atom, Name),
1460 Goal =.. [Name,S0,S1,S2].
1461update_goal(lattice(Head), S0,S1,S2, Goal) :-
1462 compound(Head),
1463 !,
1464 compound_name_arity(Head, Name, Arity),
1465 '$must_be'(oneof(integer, lattice_arity, [3]), Arity),
1466 Goal =.. [Name,S0,S1,S2].
1467update_goal(lattice(Name), S0,S1,S2, Goal) :-
1468 !,
1469 '$must_be'(atom, Name),
1470 update_goal(lattice(Name/3), S0,S1,S2, Goal).
1471update_goal(po(Name/Arity), S0,S1,S2, Goal) :-
1472 !,
1473 '$must_be'(oneof(integer, po_arity, [2]), Arity),
1474 '$must_be'(atom, Name),
1475 Call =.. [Name, S0, S1],
1476 Goal = (Call -> S2 = S0 ; S2 = S1).
1477update_goal(po(M:Name/Arity), S0,S1,S2, Goal) :-
1478 !,
1479 '$must_be'(atom, M),
1480 '$must_be'(oneof(integer, po_arity, [2]), Arity),
1481 '$must_be'(atom, Name),
1482 Call =.. [Name, S0, S1],
1483 Goal = (M:Call -> S2 = S0 ; S2 = S1).
1484update_goal(po(M:Name), S0,S1,S2, Goal) :-
1485 !,
1486 '$must_be'(atom, M),
1487 '$must_be'(atom, Name),
1488 update_goal(po(M:Name/2), S0,S1,S2, Goal).
1489update_goal(po(Name), S0,S1,S2, Goal) :-
1490 !,
1491 '$must_be'(atom, Name),
1492 update_goal(po(Name/2), S0,S1,S2, Goal).
1493update_goal(Alias, S0,S1,S2, Goal) :-
1494 update_alias(Alias, Update),
1495 !,
1496 update_goal(Update, S0,S1,S2, Goal).
1497update_goal(Mode, _,_,_, _) :-
1498 '$domain_error'(tabled_mode, Mode).
1499
1500update_alias(first, lattice('$tabling':first/3)).
1501update_alias(-, lattice('$tabling':first/3)).
1502update_alias(last, lattice('$tabling':last/3)).
1503update_alias(min, lattice('$tabling':min/3)).
1504update_alias(max, lattice('$tabling':max/3)).
1505update_alias(sum, lattice('$tabling':sum/3)).
1506
1507mkconj(true, G, G) :- !.
1508mkconj(G1, G2, (G1,G2)).
1509
1510
1511 1514
1522
1523:- public first/3, last/3, min/3, max/3, sum/3. 1524
1525first(S, _, S).
1526last(_, S, S).
1527min(S0, S1, S) :- (S0 @< S1 -> S = S0 ; S = S1).
1528max(S0, S1, S) :- (S0 @> S1 -> S = S0 ; S = S1).
1529sum(S0, S1, S) :- S is S0+S1.
1530
1531
1532 1535
1540
1541'$set_table_wrappers'(Pred) :-
1542 ( '$get_predicate_attribute'(Pred, incremental, 1),
1543 \+ '$get_predicate_attribute'(Pred, opaque, 1)
1544 -> wrap_incremental(Pred)
1545 ; unwrap_incremental(Pred)
1546 ),
1547 ( '$get_predicate_attribute'(Pred, monotonic, 1)
1548 -> wrap_monotonic(Pred)
1549 ; unwrap_monotonic(Pred)
1550 ).
1551
1552 1555
1560
1561mon_assert_dep(dependency(Dynamic), Cont, Skel, ATrie) :-
1562 '$idg_add_mono_dyn_dep'(Dynamic,
1563 dependency(Dynamic, Cont, Skel),
1564 ATrie).
1565mon_assert_dep(dependency(SrcSkel, SrcTrie, IsMono), Cont, Skel, ATrie) :-
1566 '$idg_add_monotonic_dep'(SrcTrie,
1567 dependency(SrcSkel, IsMono, Cont, Skel),
1568 ATrie).
1569
1577
1578monotonic_affects(SrcTrie, SrcSkel, IsMono, Cont, Skel, ATrie) :-
1579 '$idg_mono_affects_eager'(SrcTrie, ATrie,
1580 dependency(SrcSkel, IsMono, Cont, Skel)).
1581
1585
1586monotonic_dyn_affects(Head, Cont, Skel, ATrie) :-
1587 dyn_affected(Head, DTrie),
1588 '$idg_mono_affects_eager'(DTrie, ATrie,
1589 dependency(Head, Cont, Skel)).
1590
1596
1597wrap_monotonic(Head) :-
1598 '$wrap_predicate'(Head, monotonic, _Closure, Wrapped,
1599 '$start_monotonic'(Head, Wrapped)),
1600 '$pi_head'(PI, Head),
1601 prolog_listen(PI, monotonic_update).
1602
1606
1607unwrap_monotonic(Head) :-
1608 '$pi_head'(PI, Head),
1609 ( unwrap_predicate(PI, monotonic)
1610 -> prolog_unlisten(PI, monotonic_update)
1611 ; true
1612 ).
1613
1619
1620'$start_monotonic'(Head, Wrapped) :-
1621 ( '$tbl_collect_mono_dep'
1622 -> shift(dependency(Head)),
1623 tdebug(monotonic, 'Cont in $start_dynamic/2 with ~p', [Head]),
1624 Wrapped,
1625 tdebug(monotonic, ' --> ~p', [Head])
1626 ; Wrapped
1627 ).
1628
1632
1633:- public monotonic_update/2. 1634monotonic_update(Action, ClauseRef) :-
1635 ( atomic(ClauseRef) 1636 -> '$clause'(Head, _Body, ClauseRef, _Bindings),
1637 mon_propagate(Action, Head, ClauseRef)
1638 ; true
1639 ).
1640
1645
1646mon_propagate(Action, Head, ClauseRef) :-
1647 assert_action(Action),
1648 !,
1649 setup_call_cleanup(
1650 '$tbl_propagate_start'(Old),
1651 propagate_assert(Head), 1652 '$tbl_propagate_end'(Old)),
1653 forall(dyn_affected(Head, ATrie),
1654 '$mono_idg_changed'(ATrie, ClauseRef)). 1655mon_propagate(retract, Head, _) :-
1656 !,
1657 mon_invalidate_dependents(Head).
1658mon_propagate(rollback(Action), Head, _) :-
1659 mon_propagate_rollback(Action, Head).
1660
1661mon_propagate_rollback(Action, _Head) :-
1662 assert_action(Action),
1663 !.
1664mon_propagate_rollback(retract, Head) :-
1665 mon_invalidate_dependents(Head).
1666
1667assert_action(asserta).
1668assert_action(assertz).
1669
1673
1674propagate_assert(Head) :-
1675 tdebug(monotonic, 'Asserted ~p', [Head]),
1676 ( monotonic_dyn_affects(Head, Cont, Skel, ATrie),
1677 tdebug(monotonic, 'Propagating dyn ~p to ~p', [Head, ATrie]),
1678 '$idg_set_current'(_, ATrie),
1679 pdelim(Cont, Skel, ATrie),
1680 fail
1681 ; true
1682 ).
1683
1688
1689incr_propagate_assert(Head) :-
1690 tdebug(monotonic, 'New dynamic answer ~p', [Head]),
1691 ( dyn_affected(Head, DTrie),
1692 '$idg_mono_affects'(DTrie, ATrie,
1693 dependency(Head, Cont, Skel)),
1694 tdebug(monotonic, 'Propagating dyn ~p to ~p', [Head, ATrie]),
1695 '$idg_set_current'(_, ATrie),
1696 pdelim(Cont, Skel, ATrie),
1697 fail
1698 ; true
1699 ).
1700
1701
1705
1706propagate_answer(SrcTrie, SrcSkel) :-
1707 ( monotonic_affects(SrcTrie, SrcSkel, true, Cont, Skel, ATrie),
1708 tdebug(monotonic, 'Propagating tab ~p to ~p', [SrcTrie, ATrie]),
1709 pdelim(Cont, Skel, ATrie),
1710 fail
1711 ; true
1712 ).
1713
1723
1724pdelim(Worker, Skel, ATrie) :-
1725 reset(Worker, Dep, Cont),
1726 ( Cont == 0
1727 -> '$tbl_monotonic_add_answer'(ATrie, Skel),
1728 propagate_answer(ATrie, Skel)
1729 ; mon_assert_dep(Dep, Cont, Skel, ATrie),
1730 pdelim(Cont, Skel, ATrie)
1731 ).
1732
1738
1739mon_invalidate_dependents(Head) :-
1740 tdebug(monotonic, 'Invalidate dependents for ~p', [Head]),
1741 forall(dyn_affected(Head, ATrie),
1742 '$idg_mono_invalidate'(ATrie)).
1743
1749
1750abolish_monotonic_tables :-
1751 ( '$tbl_variant_table'(VariantTrie),
1752 trie_gen(VariantTrie, Goal, ATrie),
1753 '$get_predicate_attribute'(Goal, monotonic, 1),
1754 '$tbl_destroy_table'(ATrie),
1755 fail
1756 ; true
1757 ).
1758
1759 1762
1766
1767wrap_incremental(Head) :-
1768 tdebug(monotonic, 'Wrapping ~p', [Head]),
1769 abstract_goal(Head, Abstract),
1770 '$pi_head'(PI, Head),
1771 ( Head == Abstract
1772 -> prolog_listen(PI, dyn_update)
1773 ; prolog_listen(PI, dyn_update(Abstract))
1774 ).
1775
1776abstract_goal(M:Head, M:Abstract) :-
1777 compound(Head),
1778 '$get_predicate_attribute'(M:Head, abstract, 1),
1779 !,
1780 compound_name_arity(Head, Name, Arity),
1781 functor(Abstract, Name, Arity).
1782abstract_goal(Head, Head).
1783
1791
1792:- public dyn_update/2, dyn_update/3. 1793
1794dyn_update(_Action, ClauseRef) :-
1795 ( atomic(ClauseRef) 1796 -> '$clause'(Head, _Body, ClauseRef, _Bindings),
1797 dyn_changed_pattern(Head)
1798 ; true
1799 ).
1800
1801dyn_update(Abstract, _, _) :-
1802 dyn_changed_pattern(Abstract).
1803
1804dyn_changed_pattern(Term) :-
1805 forall(dyn_affected(Term, ATrie),
1806 '$idg_changed'(ATrie)).
1807
1808dyn_affected(Term, ATrie) :-
1809 '$tbl_variant_table'(VTable),
1810 trie_gen(VTable, Term, ATrie).
1811
1816
1817unwrap_incremental(Head) :-
1818 '$pi_head'(PI, Head),
1819 abstract_goal(Head, Abstract),
1820 ( Head == Abstract
1821 -> prolog_unlisten(PI, dyn_update)
1822 ; '$set_predicate_attribute'(Head, abstract, 0),
1823 prolog_unlisten(PI, dyn_update(_))
1824 ),
1825 ( '$tbl_variant_table'(VariantTrie)
1826 -> forall(trie_gen(VariantTrie, Head, ATrie),
1827 '$tbl_destroy_table'(ATrie))
1828 ; true
1829 ).
1830
1854
1855reeval(ATrie, Goal, Return) :-
1856 catch(try_reeval(ATrie, Goal, Return), deadlock,
1857 retry_reeval(ATrie, Goal)).
1858
1859retry_reeval(ATrie, Goal) :-
1860 '$tbl_reeval_abandon'(ATrie),
1861 tdebug(deadlock, 'Deadlock re-evaluating ~p; retrying', [ATrie]),
1862 sleep(0.000001),
1863 call(Goal).
1864
1865try_reeval(ATrie, Goal, Return) :-
1866 nb_current('$tbl_reeval', true),
1867 !,
1868 tdebug(reeval, 'Nested re-evaluation for ~p', [ATrie]),
1869 do_reeval(ATrie, Goal, Return).
1870try_reeval(ATrie, Goal, Return) :-
1871 tdebug(reeval, 'Planning reeval for ~p', [ATrie]),
1872 findall(Path, false_path(ATrie, Path), Paths0),
1873 sort(0, @>, Paths0, Paths1),
1874 clean_paths(Paths1, Paths),
1875 tdebug(forall('$member'(Path, Paths),
1876 tdebug(reeval, ' Re-eval complete path: ~p', [Path]))),
1877 reeval_paths(Paths, ATrie),
1878 do_reeval(ATrie, Goal, Return).
1879
1880do_reeval(ATrie, Goal, Return) :-
1881 '$tbl_reeval_prepare_top'(ATrie, Clause),
1882 ( Clause == 0 1883 -> '$tbl_table_status'(ATrie, _Status, M:Variant, Return),
1884 M:'$table_mode'(Goal0, Variant, ModeArgs),
1885 Goal = M:Goal0,
1886 moded_gen_answer(ATrie, Return, ModeArgs)
1887 ; nonvar(Clause) 1888 -> trie_gen_compiled(Clause, Return)
1889 ; call(Goal) 1890 ).
1891
1892
1898
1899clean_paths([], []).
1900clean_paths([[_|Path]|T0], [Path|T]) :-
1901 clean_paths(T0, Path, T).
1902
1903clean_paths([], _, []).
1904clean_paths([[_|CPath]|T0], CPath, T) :-
1905 !,
1906 clean_paths(T0, CPath, T).
1907clean_paths([[_|Path]|T0], _, [Path|T]) :-
1908 clean_paths(T0, Path, T).
1909
1916
1917reeval_paths([], _) :-
1918 !.
1919reeval_paths(BottomUp, ATrie) :-
1920 is_invalid(ATrie),
1921 !,
1922 reeval_heads(BottomUp, ATrie, BottomUp1),
1923 tdebug(assertion(BottomUp \== BottomUp1)),
1924 '$list_to_set'(BottomUp1, BottomUp2),
1925 reeval_paths(BottomUp2, ATrie).
1926reeval_paths(_, _).
1927
1928reeval_heads(_, ATrie, []) :- 1929 \+ is_invalid(ATrie),
1930 !.
1931reeval_heads([], _, []).
1932reeval_heads([[H]|B], ATrie, BT) :- 1933 reeval_node(H),
1934 !,
1935 reeval_heads(B, ATrie, BT).
1936reeval_heads([[H|T]|B], ATrie, [T|BT]) :-
1937 reeval_node(H),
1938 !,
1939 reeval_heads(B, ATrie, BT).
1940reeval_heads([FP|B], ATrie, [FP|BT]) :-
1941 reeval_heads(B, ATrie, BT).
1942
1943
1952
1953false_path(ATrie, BottomUp) :-
1954 false_path(ATrie, Path, []),
1955 '$reverse'(Path, BottomUp).
1956
1957false_path(ATrie, [ATrie|T], Seen) :-
1958 \+ memberchk(ATrie, Seen),
1959 '$idg_false_edge'(ATrie, Dep, Status),
1960 tdebug(reeval, ' ~p has dependent ~p (~w)', [ATrie, Dep, Status]),
1961 ( Status == invalid
1962 -> ( false_path(Dep, T, [ATrie|Seen])
1963 -> true
1964 ; length(Seen, Len), 1965 T = [s(2, Len, [])] 1966 ) 1967 ; status_rank(Status, Rank),
1968 length(Seen, Len),
1969 T = [s(Rank,Len,Dep)]
1970 ).
1971
1972status_rank(dynamic, 2) :- !.
1973status_rank(monotonic, 2) :- !.
1974status_rank(complete, 1) :- !.
1975status_rank(Status, Rank) :-
1976 var(Rank),
1977 !,
1978 format(user_error, 'Re-eval from status ~p~n', [Status]),
1979 Rank = 0.
1980status_rank(Rank, Rank) :-
1981 format(user_error, 'Re-eval from rank ~p~n', [Rank]).
1982
1983is_invalid(ATrie) :-
1984 '$idg_falsecount'(ATrie, FalseCount),
1985 FalseCount > 0.
1986
2000
2001reeval_node(ATrie) :-
2002 '$tbl_reeval_prepare'(ATrie, M:Variant),
2003 !,
2004 M:'$table_mode'(Goal0, Variant, _Moded),
2005 Goal = M:Goal0,
2006 tdebug(reeval, 'Re-evaluating ~p', [Goal]),
2007 ( '$idg_reset_current',
2008 setup_call_cleanup(
2009 nb_setval('$tbl_reeval', true),
2010 ignore(Goal), 2011 nb_delete('$tbl_reeval')),
2012 fail
2013 ; tdebug(reeval, 'Re-evaluated ~p', [Goal])
2014 ).
2015reeval_node(ATrie) :-
2016 '$mono_reeval_prepare'(ATrie, Size),
2017 !,
2018 reeval_monotonic_node(ATrie, Size).
2019reeval_node(ATrie) :-
2020 \+ is_invalid(ATrie).
2021
2022reeval_monotonic_node(ATrie, Size) :-
2023 setup_call_cleanup(
2024 '$tbl_propagate_start'(Old),
2025 reeval_monotonic_node(ATrie, Size, Deps),
2026 '$tbl_propagate_end'(Old)),
2027 ( Deps == []
2028 -> tdebug(reeval, 'Re-evaluation for ~p complete', [ATrie])
2029 ; Deps == false
2030 -> tdebug(reeval, 'Re-evaluation for ~p queued new answers', [ATrie]),
2031 reeval_node(ATrie)
2032 ; tdebug(reeval, 'Re-evaluation for ~p: new invalid deps: ~p',
2033 [ATrie, Deps]),
2034 reeval_nodes(Deps),
2035 reeval_node(ATrie)
2036 ).
2037
2043
2044reeval_nodes([]).
2045reeval_nodes([H|T]) :-
2046 reeval_node(H),
2047 reeval_nodes(T).
2048
2049reeval_monotonic_node(ATrie, Size, Deps) :-
2050 tdebug(reeval, 'Re-evaluating lazy monotonic ~p', [ATrie]),
2051 ( '$idg_mono_affects_lazy'(ATrie, _0SrcTrie, Dep, DepRef, Answers),
2052 length(Answers, Count),
2053 '$idg_mono_empty_queue'(DepRef, Count),
2054 ( Dep = dependency(Head, Cont, Skel)
2055 -> ( '$member'(ClauseRef, Answers),
2056 '$clause'(Head, _Body, ClauseRef, _Bindings),
2057 tdebug(monotonic, 'Propagating ~p from ~p to ~p',
2058 [Head, _0SrcTrie, ATrie]),
2059 '$idg_set_current'(_, ATrie),
2060 pdelim(Cont, Skel, ATrie),
2061 fail
2062 ; true
2063 )
2064 ; Dep = dependency(SrcSkel, true, Cont, Skel)
2065 -> ( '$member'(Node, Answers),
2066 '$tbl_node_answer'(Node, SrcSkel),
2067 tdebug(monotonic, 'Propagating ~p from ~p to ~p',
2068 [Skel, _0SrcTrie, ATrie]),
2069 '$idg_set_current'(_, ATrie),
2070 pdelim(Cont, Skel, ATrie),
2071 fail
2072 ; true
2073 )
2074 ; tdebug(monotonic, 'Skipped queued ~p, answers ~p',
2075 [Dep, Answers])
2076 ),
2077 fail
2078 ; '$mono_reeval_done'(ATrie, Size, Deps)
2079 ).
2080
2081
2082 2085
2086system:term_expansion((:- table(Preds)), Expansion) :-
2087 \+ current_prolog_flag(xref, true),
2088 prolog_load_context(module, M),
2089 phrase(wrappers(Preds, M), Clauses),
2090 multifile_decls(Clauses, Directives0),
2091 sort(Directives0, Directives),
2092 '$append'(Directives, Clauses, Expansion).
2093
2094multifile_decls([], []).
2095multifile_decls([H0|T0], [H|T]) :-
2096 multifile_decl(H0, H),
2097 !,
2098 multifile_decls(T0, T).
2099multifile_decls([_|T0], T) :-
2100 multifile_decls(T0, T).
2101
2102multifile_decl(M:(Head :- _Body), (:- multifile(M:Name/Arity))) :-
2103 !,
2104 functor(Head, Name, Arity).
2105multifile_decl(M:Head, (:- multifile(M:Name/Arity))) :-
2106 !,
2107 functor(Head, Name, Arity).
2108multifile_decl((Head :- _Body), (:- multifile(Name/Arity))) :-
2109 !,
2110 functor(Head, Name, Arity).
2111multifile_decl(Head, (:- multifile(Name/Arity))) :-
2112 !,
2113 Head \= (:-_),
2114 functor(Head, Name, Arity).
2115
2116
2117 2120
2121:- public answer_completion/2. 2122
2136
2137answer_completion(AnswerTrie, Return) :-
2138 tdebug(trie_goal(AnswerTrie, Goal, _Return)),
2139 tdebug(ac(start), 'START: Answer completion for ~p', [Goal]),
2140 call_cleanup(answer_completion_guarded(AnswerTrie, Return, Propagated),
2141 abolish_table_subgoals(eval_subgoal_in_residual(_,_))),
2142 ( Propagated > 0
2143 -> answer_completion(AnswerTrie, Return)
2144 ; true
2145 ).
2146
2147answer_completion_guarded(AnswerTrie, Return, Propagated) :-
2148 ( eval_subgoal_in_residual(AnswerTrie, Return),
2149 fail
2150 ; true
2151 ),
2152 delete_answers_for_failing_calls(Propagated),
2153 ( Propagated == 0
2154 -> mark_succeeding_calls_as_answer_completed
2155 ; true
2156 ).
2157
2163
2164delete_answers_for_failing_calls(Propagated) :-
2165 State = state(0),
2166 ( subgoal_residual_trie(ASGF, ESGF),
2167 \+ trie_gen(ESGF, _ETmp),
2168 tdebug(trie_goal(ASGF, Goal0, _)),
2169 tdebug(trie_goal(ASGF, Goal, _0Return)),
2170 '$trie_gen_node'(ASGF, _0Return, ALeaf),
2171 tdebug(ac(prune), ' Removing answer ~p from ~p', [Goal, Goal0]),
2172 '$tbl_force_truth_value'(ALeaf, false, Count),
2173 arg(1, State, Prop0),
2174 Prop is Prop0+Count-1,
2175 nb_setarg(1, State, Prop),
2176 fail
2177 ; arg(1, State, Propagated)
2178 ).
2179
2180mark_succeeding_calls_as_answer_completed :-
2181 ( subgoal_residual_trie(ASGF, _ESGF),
2182 ( '$tbl_answer_dl'(ASGF, _0Return, _True)
2183 -> tdebug(trie_goal(ASGF, Answer, _0Return)),
2184 tdebug(trie_goal(ASGF, Goal, _0Return)),
2185 tdebug(ac(prune), ' Completed ~p on ~p', [Goal, Answer]),
2186 '$tbl_set_answer_completed'(ASGF)
2187 ),
2188 fail
2189 ; true
2190 ).
2191
2192subgoal_residual_trie(ASGF, ESGF) :-
2193 '$tbl_variant_table'(VariantTrie),
2194 context_module(M),
2195 trie_gen(VariantTrie, M:eval_subgoal_in_residual(ASGF, _), ESGF).
2196
2201
2202eval_dl_in_residual(true) :-
2203 !.
2204eval_dl_in_residual((A;B)) :-
2205 !,
2206 ( eval_dl_in_residual(A)
2207 ; eval_dl_in_residual(B)
2208 ).
2209eval_dl_in_residual((A,B)) :-
2210 !,
2211 eval_dl_in_residual(A),
2212 eval_dl_in_residual(B).
2213eval_dl_in_residual(tnot(G)) :-
2214 !,
2215 tdebug(ac, ' ? tnot(~p)', [G]),
2216 current_table(G, SGF),
2217 '$tbl_table_status'(SGF, _Status, _Wrapper, Return),
2218 tnot(eval_subgoal_in_residual(SGF, Return)).
2219eval_dl_in_residual(G) :-
2220 tdebug(ac, ' ? ~p', [G]),
2221 ( current_table(G, SGF)
2222 -> true
2223 ; more_general_table(G, SGF)
2224 -> true
2225 ; writeln(user_error, 'MISSING CALL? '(G)),
2226 fail
2227 ),
2228 '$tbl_table_status'(SGF, _Status, _Wrapper, Return),
2229 eval_subgoal_in_residual(SGF, Return).
2230
2231more_general_table(G, Trie) :-
2232 term_variables(G, Vars),
2233 '$tbl_variant_table'(VariantTrie),
2234 trie_gen(VariantTrie, G, Trie),
2235 is_most_general_term(Vars).
2236
2237:- table eval_subgoal_in_residual/2. 2238
2243
2244eval_subgoal_in_residual(AnswerTrie, _Return) :-
2245 '$tbl_is_answer_completed'(AnswerTrie),
2246 !,
2247 undefined.
2248eval_subgoal_in_residual(AnswerTrie, Return) :-
2249 '$tbl_answer'(AnswerTrie, Return, Condition),
2250 tdebug(trie_goal(AnswerTrie, Goal, Return)),
2251 tdebug(ac, 'Condition for ~p is ~p', [Goal, Condition]),
2252 eval_dl_in_residual(Condition).
2253
2254
2255 2258
2264
2265:- public tripwire/3. 2266:- multifile prolog:tripwire/2. 2267
2268tripwire(Wire, _Action, Context) :-
2269 prolog:tripwire(Wire, Context),
2270 !.
2271tripwire(Wire, Action, Context) :-
2272 Error = error(resource_error(tripwire(Wire, Context)), _),
2273 tripwire_action(Action, Error).
2274
2275tripwire_action(warning, Error) :-
2276 print_message(warning, Error).
2277tripwire_action(error, Error) :-
2278 throw(Error).
2279tripwire_action(suspend, Error) :-
2280 print_message(warning, Error),
2281 break.
2282
2283
2284 2287
2288:- table
2289 system:undefined/0,
2290 system:answer_count_restraint/0,
2291 system:radial_restraint/0,
2292 system:tabled_call/1. 2293
2297
2298system:(undefined :-
2299 tnot(undefined)).
2300
2306
2307system:(answer_count_restraint :-
2308 tnot(answer_count_restraint)).
2309
2310system:(radial_restraint :-
2311 tnot(radial_restraint)).
2312
2313system:(tabled_call(X) :- call(X))