36
   37:- module('$tabling',
   38          [ (table)/1,                     39
   40            current_table/2,               41            abolish_all_tables/0,
   42            abolish_table_subgoals/1,      43
   44            start_tabling/2,               45            start_tabling/4                46          ]).   47
   48:- meta_predicate
   49    start_tabling(+, 0),
   50    start_tabling(+, 0, +, ?),
   51    current_table(:, -),
   52    abolish_table_subgoals(:).   53
   63
   84
   85table(PIList) :-
   86    throw(error(context_error(nodirective, table(PIList)), _)).
   87
   97
   98start_tabling(Wrapper, Worker) :-
   99    '$tbl_variant_table'(Wrapper, Trie, Status),
  100    (   Status == complete
  101    ->  trie_gen(Trie, Wrapper, _)
  102    ;   (   '$tbl_create_component'
  103        ->  catch(run_leader(Wrapper, Worker, Trie),
  104                  E, true),
  105            (   var(E)
  106            ->  trie_gen(Trie, Wrapper, _)
  107            ;   '$tbl_table_discard_all',
  108                throw(E)
  109            )
  110        ;   run_follower(Status, Wrapper, Worker, Trie)
  111        )
  112    ).
  113
  114run_leader(Wrapper, Worker, Trie) :-
  115    activate(Wrapper, Worker, Trie, _Worklist),
  116    completion,
  117    '$tbl_completed_component'.
  118
  119run_follower(fresh, Wrapper, Worker, Trie) :-
  120    !,
  121    activate(Wrapper, Worker, Trie, Worklist),
  122    shift(call_info(Wrapper, Worklist)).
  123run_follower(Worklist, Wrapper, _Worker, _Trie) :-
  124    shift(call_info(Wrapper, Worklist)).
  125
  126activate(Wrapper, Worker, Trie, WorkList) :-
  127    '$tbl_new_worklist'(WorkList, Trie),
  128    (   delim(Wrapper, Worker, WorkList),
  129        fail
  130    ;   true
  131    ).
  132
  133
  138
  139start_tabling(Wrapper, Worker, WrapperNoModes, ModeArgs) :-
  140    '$tbl_variant_table'(WrapperNoModes, Trie, Status),
  141    (   Status == complete
  142    ->  trie_gen(Trie, WrapperNoModes, ModeArgs)
  143    ;   (   Status == fresh
  144        ->  '$tbl_create_subcomponent',
  145            catch(run_leader(Wrapper, WrapperNoModes, ModeArgs, Worker, Trie),
  146                  E, true),
  147            (   var(E)
  148            ->  trie_gen(Trie, WrapperNoModes, ModeArgs)
  149            ;   '$tbl_table_discard_all',
  150                throw(E)
  151            )
  152        ;     153            shift(call_info(Wrapper, Status))
  154        )
  155    ).
  156
  157get_wrapper_no_mode_args(M:Wrapper, M:WrapperNoModes, ModeArgs) :-
  158    M:'$table_mode'(Wrapper, WrapperNoModes, ModeArgs).
  159
  160run_leader(Wrapper, WrapperNoModes, ModeArgs, Worker, Trie) :-
  161    activate(Wrapper, WrapperNoModes, ModeArgs, Worker, Trie, _Worklist),
  162    completion,
  163    '$tbl_completed_component'.
  164
  165activate(Wrapper, WrapperNoModes, _ModeArgs, Worker, Trie, WorkList) :-
  166    '$tbl_new_worklist'(WorkList, Trie),
  167    (   delim(Wrapper, WrapperNoModes, Worker, WorkList),
  168        fail
  169    ;   true
  170    ).
  171
  175
  176delim(Wrapper, Worker, WorkList) :-
  177    reset(work_and_add_answer(Worker, Wrapper, WorkList),
  178          SourceCall, Continuation),
  179    add_answer_or_suspend(Continuation, Wrapper,
  180                          WorkList, SourceCall).
  181
  182work_and_add_answer(Worker, Wrapper, WorkList) :-
  183    call(Worker),
  184    '$tbl_wkl_add_answer'(WorkList, Wrapper).
  185
  186
  187add_answer_or_suspend(0, _Wrapper, _WorkList, _) :-
  188    !.
  189add_answer_or_suspend(Continuation, Wrapper, WorkList,
  190                      call_info(SrcWrapper, SourceWL)) :-
  191    '$tbl_wkl_add_suspension'(
  192        SourceWL,
  193        dependency(SrcWrapper, Continuation, Wrapper, WorkList)).
  194
  198
  199delim(Wrapper, WrapperNoModes, Worker, WorkList) :-
  200    reset(work_and_add_moded_answer(Worker, Wrapper, WrapperNoModes, WorkList),
  201          SourceCall, Continuation),
  202    add_answer_or_suspend(Continuation, Wrapper, WrapperNoModes,
  203                          WorkList, SourceCall).
  204
  205work_and_add_moded_answer(Worker, Wrapper, WrapperNoModes, WorkList) :-
  206    call(Worker),
  207    get_wrapper_no_mode_args(Wrapper, _, ModeArgs),
  208    '$tbl_wkl_mode_add_answer'(WorkList, WrapperNoModes,
  209                               ModeArgs, Wrapper).
  210
  211add_answer_or_suspend(0, _Wrapper, _WrapperNoModes, _WorkList, _) :-
  212    !.
  213add_answer_or_suspend(Continuation, Wrapper, _WrapperNoModes, WorkList,
  214                      call_info(SrcWrapper, SourceWL)) :-
  215    '$tbl_wkl_add_suspension'(
  216        SourceWL,
  217        dependency(SrcWrapper, Continuation, Wrapper, WorkList)).
  218
  219
  226
  227:- public
  228    update/4.  229
  230update(M:Wrapper, A1, A2, A3) :-
  231    M:'$table_update'(Wrapper, A1, A2, A3),
  232    A1 \=@= A3.
  233
  234
  238
  239completion :-
  240    '$tbl_pop_worklist'(WorkList),
  241    !,
  242    completion_step(WorkList),
  243    completion.
  244completion :-
  245    '$tbl_table_complete_all'.
  246
  247completion_step(SourceTable) :-
  248    (   '$tbl_trienode'(Reserved),
  249        '$tbl_wkl_work'(SourceTable,
  250                        Answer, ModeArgs,
  251                        Goal, Continuation, Wrapper, TargetTable),
  252        (   ModeArgs == Reserved
  253        ->  Goal = Answer,
  254            delim(Wrapper, Continuation, TargetTable)
  255        ;   get_wrapper_no_mode_args(Goal, Answer, ModeArgs),
  256            get_wrapper_no_mode_args(Wrapper, WrapperNoModes, _),
  257            delim(Wrapper, WrapperNoModes, Continuation, TargetTable)
  258        ),
  259        fail
  260    ;   true
  261    ).
  262
  263                   266
  275
  276abolish_all_tables :-
  277    '$tbl_abolish_all_tables'.
  278
  282
  283abolish_table_subgoals(M:SubGoal) :-
  284    '$tbl_variant_table'(VariantTrie),
  285    current_module(M),
  286    forall(trie_gen(VariantTrie, M:SubGoal, Trie),
  287           '$tbl_destroy_table'(Trie)).
  288
  289
  290                   293
  297
  298current_table(M:Variant, Trie) :-
  299    '$tbl_variant_table'(VariantTrie),
  300    (   (var(Variant) ; var(M))
  301    ->  trie_gen(VariantTrie, M:Variant, Trie)
  302    ;   trie_lookup(VariantTrie, M:Variant, Trie)
  303    ).
  304
  305
  306                   309
  310:- multifile
  311    system:term_expansion/2,
  312    prolog:rename_predicate/2,
  313    tabled/2.  314:- dynamic
  315    system:term_expansion/2.  316
  317wrappers(Var) -->
  318    { var(Var),
  319      !,
  320      '$instantiation_error'(Var)
  321    }.
  322wrappers((A,B)) -->
  323    !,
  324    wrappers(A),
  325    wrappers(B).
  326wrappers(Name//Arity) -->
  327    { atom(Name), integer(Arity), Arity >= 0,
  328      !,
  329      Arity1 is Arity+2
  330    },
  331    wrappers(Name/Arity1).
  332wrappers(Name/Arity) -->
  333    { atom(Name), integer(Arity), Arity >= 0,
  334      !,
  335      functor(Head, Name, Arity),
  336      check_undefined(Name/Arity),
  337      atom_concat(Name, ' tabled', WrapName),
  338      Head =.. [Name|Args],
  339      WrappedHead =.. [WrapName|Args],
  340      prolog_load_context(module, Module),
  341      '$tbl_trienode'(Reserved)
  342    },
  343    [ '$tabled'(Head),
  344      '$table_mode'(Head, Head, Reserved),
  345      (   Head :-
  346             start_tabling(Module:Head, WrappedHead)
  347      )
  348    ].
  349wrappers(ModeDirectedSpec) -->
  350    { callable(ModeDirectedSpec),
  351      !,
  352      functor(ModeDirectedSpec, Name, Arity),
  353      functor(Head, Name, Arity),
  354      check_undefined(Name/Arity),
  355      atom_concat(Name, ' tabled', WrapName),
  356      Head =.. [Name|Args],
  357      WrappedHead =.. [WrapName|Args],
  358      extract_modes(ModeDirectedSpec, Head, Variant, Modes, Moded),
  359      updater_clauses(Modes, Head, UpdateClauses),
  360      prolog_load_context(module, Module),
  361      mode_check(Moded, ModeTest),
  362      (   ModeTest == true
  363      ->  WrapClause = (Head :- start_tabling(Module:Head, WrappedHead))
  364      ;   WrapClause = (Head :- ModeTest,
  365                            start_tabling(Module:Head, WrappedHead,
  366                                          Module:Variant, Moded))
  367      )
  368    },
  369    [ '$tabled'(Head),
  370      '$table_mode'(Head, Variant, Moded),
  371      WrapClause
  372    | UpdateClauses
  373    ].
  374wrappers(TableSpec) -->
  375    { '$type_error'(table_desclaration, TableSpec)
  376    }.
  377
  383
  384check_undefined(Name/Arity) :-
  385    functor(Head, Name, Arity),
  386    prolog_load_context(module, Module),
  387    clause(Module:Head, _),
  388    !,
  389    '$permission_error'(table, procedure, Name/Arity).
  390check_undefined(_).
  391
  396
  397mode_check(Moded, Check) :-
  398    var(Moded),
  399    !,
  400    Check = (var(Moded)->true;'$uninstantiation_error'(Moded)).
  401mode_check(Moded, true) :-
  402    '$tbl_trienode'(Moded),
  403    !.
  404mode_check(Moded, (Test->true;'$tabling':instantiated_moded_arg(Vars))) :-
  405    Moded =.. [s|Vars],
  406    var_check(Vars, Test).
  407
  408var_check([H|T], Test) :-
  409    (   T == []
  410    ->  Test = var(H)
  411    ;   Test = (var(H),Rest),
  412        var_check(T, Rest)
  413    ).
  414
  415:- public
  416    instantiated_moded_arg/1.  417
  418instantiated_moded_arg(Vars) :-
  419    '$member'(V, Vars),
  420    \+ var(V),
  421    '$uninstantiation_error'(V).
  422
  423
  432
(ModeSpec, Head, Variant, Modes, ModedAnswer) :-
  434    compound_name_arguments(ModeSpec, Name, ModeSpecArgs),
  435    compound_name_arguments(Head, Name, HeadArgs),
  436    separate_args(ModeSpecArgs, HeadArgs, VariantArgs, Modes, ModedArgs),
  437    length(ModedArgs, Count),
  438    atomic_list_concat([$,Name,$,Count], VName),
  439    Variant =.. [VName|VariantArgs],
  440    (   ModedArgs == []
  441    ->  '$tbl_trienode'(ModedAnswer)
  442    ;   ModedArgs = [ModedAnswer]
  443    ->  true
  444    ;   ModedAnswer =.. [s|ModedArgs]
  445    ).
  446
  454
  455separate_args([], [], [], [], []).
  456separate_args([HM|TM], [H|TA], [H|TNA], Modes, TMA):-
  457    indexed_mode(HM),
  458    !,
  459    separate_args(TM, TA, TNA, Modes, TMA).
  460separate_args([M|TM], [H|TA], TNA, [M|Modes], [H|TMA]):-
  461    separate_args(TM, TA, TNA, Modes, TMA).
  462
  463indexed_mode(Mode) :-                             464    var(Mode),
  465    !.
  466indexed_mode(index).                              467indexed_mode(+).                                  468
  473
  474updater_clauses([], _, []) :- !.
  475updater_clauses([P], Head, [('$table_update'(Head, S0, S1, S2) :- Body)]) :- !,
  476    update_goal(P, S0,S1,S2, Body).
  477updater_clauses(Modes, Head, [('$table_update'(Head, S0, S1, S2) :- Body)]) :-
  478    length(Modes, Len),
  479    functor(S0, s, Len),
  480    functor(S1, s, Len),
  481    functor(S2, s, Len),
  482    S0 =.. [_|Args0],
  483    S1 =.. [_|Args1],
  484    S2 =.. [_|Args2],
  485    update_body(Modes, Args0, Args1, Args2, true, Body).
  486
  487update_body([], _, _, _, Body, Body).
  488update_body([P|TM], [A0|Args0], [A1|Args1], [A2|Args2], Body0, Body) :-
  489    update_goal(P, A0,A1,A2, Goal),
  490    mkconj(Body0, Goal, Body1),
  491    update_body(TM, Args0, Args1, Args2, Body1, Body).
  492
  493update_goal(Var, _,_,_, _) :-
  494    var(Var),
  495    !,
  496    '$instantiation_error'(Var).
  497update_goal(lattice(M:PI), S0,S1,S2, M:Goal) :-
  498    !,
  499    '$must_be'(atom, M),
  500    update_goal(lattice(PI), S0,S1,S2, Goal).
  501update_goal(lattice(Name/Arity), S0,S1,S2, Goal) :-
  502    !,
  503    '$must_be'(oneof(integer, lattice_arity, [3]), Arity),
  504    '$must_be'(atom, Name),
  505    Goal =.. [Name,S0,S1,S2].
  506update_goal(lattice(Name), S0,S1,S2, Goal) :-
  507    !,
  508    '$must_be'(atom, Name),
  509    update_goal(lattice(Name/3), S0,S1,S2, Goal).
  510update_goal(po(Name/Arity), S0,S1,S2, Goal) :-
  511    !,
  512    '$must_be'(oneof(integer, po_arity, [2]), Arity),
  513    '$must_be'(atom, Name),
  514    Call =.. [Name, S0, S1],
  515    Goal = (Call -> S2 = S0 ; S2 = S1).
  516update_goal(po(M:Name/Arity), S0,S1,S2, Goal) :-
  517    !,
  518    '$must_be'(atom, M),
  519    '$must_be'(oneof(integer, po_arity, [2]), Arity),
  520    '$must_be'(atom, Name),
  521    Call =.. [Name, S0, S1],
  522    Goal = (M:Call -> S2 = S0 ; S2 = S1).
  523update_goal(po(M:Name), S0,S1,S2, Goal) :-
  524    !,
  525    '$must_be'(atom, M),
  526    '$must_be'(atom, Name),
  527    update_goal(po(M:Name/2), S0,S1,S2, Goal).
  528update_goal(po(Name), S0,S1,S2, Goal) :-
  529    !,
  530    '$must_be'(atom, Name),
  531    update_goal(po(Name/2), S0,S1,S2, Goal).
  532update_goal(Alias, S0,S1,S2, Goal) :-
  533    update_alias(Alias, Update),
  534    !,
  535    update_goal(Update, S0,S1,S2, Goal).
  536update_goal(Mode, _,_,_, _) :-
  537    '$domain_error'(tabled_mode, Mode).
  538
  539update_alias(first, lattice('$tabling':first/3)).
  540update_alias(-,     lattice('$tabling':first/3)).
  541update_alias(last,  lattice('$tabling':last/3)).
  542update_alias(min,   lattice('$tabling':min/3)).
  543update_alias(max,   lattice('$tabling':max/3)).
  544update_alias(sum,   lattice('$tabling':sum/3)).
  545
  546mkconj(true, G,  G) :- !.
  547mkconj(G1,   G2, (G1,G2)).
  548
  549
  550		   553
  561
  562:- public first/3, last/3, min/3, max/3, sum/3.  563
  564first(S, _, S).
  565last(_, S, S).
  566min(S0, S1, S) :- (S0 @< S1 -> S = S0 ; S = S1).
  567max(S0, S1, S) :- (S0 @> S1 -> S = S0 ; S = S1).
  568sum(S0, S1, S) :- S is S0+S1.
  569
  570
  571		   574
  579
  580prolog:rename_predicate(M:Head0, M:Head) :-
  581    '$flushed_predicate'(M:'$tabled'(_)),
  582    call(M:'$tabled'(Head0)),
  583    \+ current_prolog_flag(xref, true),
  584    !,
  585    rename_term(Head0, Head).
  586
  587rename_term(Compound0, Compound) :-
  588    compound(Compound0),
  589    !,
  590    compound_name_arguments(Compound0, Name, Args),
  591    atom_concat(Name, ' tabled', WrapName),
  592    compound_name_arguments(Compound, WrapName, Args).
  593rename_term(Name, WrapName) :-
  594    atom_concat(Name, ' tabled', WrapName).
  595
  596
  597system:term_expansion((:- table(Preds)),
  598                      [ (:- multifile('$tabled'/1)),
  599                        (:- multifile('$table_mode'/3)),
  600                        (:- multifile('$table_update'/4))
  601                      | Clauses
  602                      ]) :-
  603    \+ current_prolog_flag(xref, true),
  604    phrase(wrappers(Preds), Clauses)