/* Deterministcally table a predicate of the form K -> RV where the K are the first N-1 arguments. Note that this does not include support for backtracking */ :- module(clpbn_table, [clpbn_table/1, clpbn_tableallargs/1, clpbn_table_nondet/1, clpbn_tabled_clause/2, clpbn_tabled_clause_ref/3, clpbn_tabled_retract/2, clpbn_tabled_abolish/1, clpbn_tabled_asserta/1, clpbn_tabled_assertz/1, clpbn_tabled_asserta/2, clpbn_tabled_assertz/2, clpbn_tabled_dynamic/1, clpbn_tabled_number_of_clauses/2, clpbn_reset_tables/0, clpbn_reset_tables/1, clpbn_is_tabled/1 ]). :- use_module(library(bhash), [b_hash_new/4, b_hash_lookup/3, b_hash_insert/4 ]). :- meta_predicate clpbn_table(:), clpbn_tabled_clause(:.?), clpbn_tabled_clause_ref(:.?,?), clpbn_tabled_retract(:), clpbn_tabled_abolish(:), clpbn_tabled_asserta(:), clpbn_tabled_assertz(:), clpbn_tabled_asserta(:,-), clpbn_tabled_assertz(:,-), clpbn_tabled_number_of_clauses(:,-), clpbn_is_tabled(:). :- use_module(library(terms), [instantiated_term_hash/4, variant/2 ]). :- use_module(evidence, [put_evidence/2]). :- dynamic clpbn_table/3. :- meta_predicate clpbn_table(:), clpbn_table_all_args(:). :- initialization(init). init :- clpbn_reset_tables. clpbn_reset_tables :- clpbn_reset_tables(2048). clpbn_reset_tables(Sz) :- b_hash_new(Tab, Sz, myf, myc), nb_setval(clpbn_tables, Tab). myf(Key, Size, Index) :- instantiated_term_hash(Key, -1, Size, Index). myc(A, B) :- ground(A), !, B == A. myc(A, B) :- variant(A,B), term_variables(A,L1), term_variables(B,L2), match_keys(L1,L2). match_keys([],[]). match_keys([V1|L1],[V2|L2]) :- clpbn:get_atts(V1,[key(K)]), clpbn:get_atts(V2,[key(K)]), match_keys(L1,L2). clpbn_table(M:X) :- !, clpbn_table(X,M). clpbn_table(X) :- prolog_load_context(module, M), clpbn_table(X,M). clpbn_table(M:X,_) :- !, clpbn_table(X,M). clpbn_table((P1,P2),M) :- !, clpbn_table(P1,M), clpbn_table(P2,M). clpbn_table(F/N,M) :- functor(S,F,N), S =.. L0, take_tail(L0, A0, L1, V2, L2), Key =.. L1, atom_concat(F, '___tabled', NF), L2 = [_|Args2], Goal =.. [NF|Args2], L0 = [_|Args0], IGoal =.. [NF|Args0], asserta(clpbn_table(S, M, IGoal)), assert((M:S :- !, b_getval((clpbn_tables), Tab), % V2 is unbound. (b_hash_lookup(Key, V2, Tab) -> % (attvar(V2) -> writeln(ok:A0:V2) ; writeln(error(V2:should_be_attvar(S)))), (var(A0) -> A0 = V2 ; put_evidence(A0, V2)) ; % writeln(new), b_hash_insert(Tab, Key, V2, NewTab), b_setval(clpbn_tables,NewTab), once(M:Goal), !, % enter evidence after binding. (var(A0) -> A0 = V2 ; put_evidence(A0, V2)) ; clpbn:clpbn_flag(solver,none) -> true ; throw(error(tabled_clpbn_predicate_should_never_fail,S)) ) )). take_tail([V], V, [], V1, [V1]) :- !. take_tail([A|L0], V, [A|L1], V1, [A|L2]) :- take_tail(L0, V, L1, V1, L2). clpbn_tableallargs(M:X) :- !, clpbn_tableallargs(X,M). clpbn_tableallargs(X) :- prolog_load_context(module, M), clpbn_tableallargs(X,M). clpbn_tableallargs(M:X,_) :- !, clpbn_tableallargs(X,M). clpbn_tableallargs((P1,P2),M) :- !, clpbn_tableallargs(P1,M), clpbn_tableallargs(P2,M). clpbn_tableallargs(F/N,M) :- functor(Key,F,N), Key =.. [F|Args], atom_concat(F, '___tabled', NF), NKey =.. [NF|Args], asserta(clpbn_table(Key, M, NKey)), assert((M:Key :- !, b_getval(clpbn_tables, Tab), (b_hash_lookup(Key, Out, Tab) -> true ; b_hash_insert(Tab, Key, Out, NewTab), b_setval(clpbn_tables, NewTab), once(M:NKey) ) )). clpbn_table_nondet(M:X) :- !, clpbn_table_nondet(X,M). clpbn_table_nondet(X) :- prolog_load_context(module, M), clpbn_table_nondet(X,M). clpbn_table_nondet(M:X,_) :- !, clpbn_table_nondet(X,M). clpbn_table_nondet((P1,P2),M) :- !, clpbn_table_nondet(P1,M), clpbn_table_nondet(P2,M). clpbn_table_nondet(F/N,M) :- functor(Key,F,N), Key =.. [F|Args], atom_concat(F, '___tabled', NF), NKey =.. [NF|Args], asserta(clpbn_table(Key, M, NKey)), assert((M:Key :- % writeln(in:Key), b_getval(clpbn_tables, Tab), (b_hash_lookup(Key, Out, Tab) -> fail ; b_hash_insert(Tab, Key, Out, NewTab), b_setval(clpbn_tables, NewTab), M:NKey ) )). user:term_expansion((P :- Gs), NC) :- clpbn_table(P, M, NP), prolog_load_context(module, M), !, assert(M:(NP :- Gs)), NC = (:-true). in_table(K, V) :- b_getval(clpbn_tables, Tab), b_hash_lookup(K, V, Tab). store_in_table(K, V) :- b_getval(clpbn_tables, Tab), b_hash_insert(Tab, K, V). clpbn_tabled_clause(M:Head, Body) :- !, clpbn_tabled_clause(Head, M, Body). clpbn_tabled_clause(Head, Body) :- prolog_load_context(module, M), clpbn_tabled_clause(Head, M, Body). clpbn_tabled_clause(M:Head, _, Body) :- !, clpbn_tabled_clause(Head, M, Body). clpbn_tabled_clause(Head, M, Body) :- clpbn_table(Head, M, THead), clause(M:THead, Body). clpbn_tabled_clause_ref(M:Head, Body, Ref) :- !, clpbn_tabled_clause_ref(Head, M, Body, Ref). clpbn_tabled_clause_ref(Head, Body, Ref) :- prolog_load_context(module, M), clpbn_tabled_clause_ref(Head, M, Body, Ref). clpbn_tabled_clause_ref(M:Head, _, Body, Ref) :- !, clpbn_tabled_clause_ref(Head, M, Body, Ref). clpbn_tabled_clause_ref(Head, M, Body, Ref) :- clpbn_table(Head, M, THead), clause(M:THead, Body, Ref). clpbn_tabled_retract(M:Head) :- !, clpbn_tabled_retract(Head, M). clpbn_tabled_retract(Head) :- prolog_load_context(module, M), clpbn_tabled_retract(Head, M). clpbn_tabled_retract(M:Head, _) :- !, clpbn_tabled_retract(Head, M). clpbn_tabled_retract(Head, M) :- clpbn_table(Head, M, THead), retract(M:THead). clpbn_tabled_assertz(M:Clause) :- !, clpbn_tabled_assertz2(Clause, M). clpbn_tabled_assertz(Clause) :- prolog_load_context(module, M), clpbn_tabled_assertz2(Clause, M). clpbn_tabled_assertz2(M:Clause, _) :- !, clpbn_tabled_assertz2(Clause, M). clpbn_tabled_assertz2((Head:-Body), M) :- !, clpbn_table(Head, M, THead), assertz(M:(THead :- Body)). clpbn_tabled_assertz2(Head, M) :- clpbn_table(Head, M, THead), assertz(THead). clpbn_tabled_assertz(M:Clause, Ref) :- !, clpbn_tabled_assertz2(Clause, M, Ref). clpbn_tabled_assertz(Clause, Ref) :- prolog_load_context(module, M), clpbn_tabled_assertz2(Clause, M, Ref). clpbn_tabled_assertz2(M:Clause, _, Ref) :- !, clpbn_tabled_assertz2(Clause, M, Ref). clpbn_tabled_assertz2((Head:-Body), M, Ref) :- !, clpbn_table(Head, M, THead), assertz(M:(THead :- Body), Ref). clpbn_tabled_assertz2(Head, M, Ref) :- clpbn_table(Head, M, THead, Ref), assertz(THead). clpbn_tabled_asserta(M:Clause) :- !, clpbn_tabled_asserta2(Clause, M). clpbn_tabled_asserta(Clause) :- prolog_load_context(module, M), clpbn_tabled_asserta2(Clause, M). clpbn_tabled_asserta2(M:Clause, _) :- !, clpbn_tabled_asserta2(Clause, M). clpbn_tabled_asserta2((Head:-Body), M) :- !, clpbn_table(Head, M, THead), asserta(M:(THead :- Body)). clpbn_tabled_asserta2(Head, M) :- clpbn_table(Head, M, THead), asserta(THead). clpbn_tabled_asserta(M:Clause, Ref) :- !, clpbn_tabled_asserta2(Clause, M, Ref). clpbn_tabled_asserta(Clause, Ref) :- prolog_load_context(module, M), clpbn_tabled_asserta2(Clause, M, Ref). clpbn_tabled_asserta2(M:Clause, _, Ref) :- !, clpbn_tabled_asserta2(Clause, M, Ref). clpbn_tabled_asserta2((Head:-Body), M, Ref) :- !, clpbn_table(Head, M, THead), asserta(M:(THead :- Body), Ref). clpbn_tabled_asserta2(Head, M, Ref) :- clpbn_table(Head, M, THead, Ref), asserta(THead). clpbn_tabled_abolish(M:Clause) :- !, clpbn_tabled_abolish(Clause, M). clpbn_tabled_abolish(Clause) :- prolog_load_context(module, M), clpbn_tabled_abolish(Clause, M). clpbn_tabled_abolish(M:Clause, _) :- !, clpbn_tabled_abolish(Clause, M). clpbn_tabled_abolish(N/A, M) :- functor(Head, N, A), clpbn_table(Head, M, THead), functor(THead, TN, A), abolish(M:TN/A). clpbn_tabled_dynamic(M:Clause) :- !, clpbn_tabled_dynamic(Clause, M). clpbn_tabled_dynamic(Clause) :- prolog_load_context(module, M), clpbn_tabled_dynamic(Clause, M). clpbn_tabled_dynamic(M:Clause, _) :- !, clpbn_tabled_dynamic(Clause, M). clpbn_tabled_dynamic(N/A, M) :- functor(Head, N, A), clpbn_table(Head, M, THead), functor(THead, TN, A), dynamic(M:TN/A). clpbn_tabled_number_of_clauses(M:Clause, N) :- !, clpbn_tabled_number_of_clauses(Clause, M, N). clpbn_tabled_number_of_clauses(Clause, N) :- prolog_load_context(module, M), clpbn_tabled_number_of_clauses(Clause, M, N). clpbn_tabled_number_of_clauses(M:Clause, _, N) :- !, clpbn_tabled_number_of_clauses(Clause, M, N). clpbn_tabled_number_of_clauses(Head, M, N) :- clpbn_table(Head, M, THead), predicate_property(M:THead,number_of_clauses(N)). clpbn_is_tabled(M:Clause) :- !, clpbn_is_tabled(Clause, M). clpbn_is_tabled(Clause) :- prolog_load_context(module, M), clpbn_is_tabled(Clause, M). clpbn_is_tabled(M:Clause, _) :- !, clpbn_is_tabled(Clause, M). clpbn_is_tabled(Head, M) :- clpbn_table(Head, M, _).