% % Interface the Aleph ILP system to CLP(BN) % % Relies on the Aleph cost function. % It assumes Aleph work as usual, but some variables are of type random. % :- module(clpbn_aleph, [init_clpbn_cost/0, random_type/2]). :- dynamic rt/2, inited/1. :- use_module(library('clpbn'), [{}/1, clpbn_flag/2, clpbn_flag/3, set_clpbn_flag/2]). :- use_module(library('clpbn/learning/em')). :- use_module(library('clpbn/matrix_cpt_utils'), [uniform_CPT_as_list/2]). :- use_module(library('clpbn/dists'), [reset_all_dists/0, get_dist_key/2, get_dist_params/2 ]). :- use_module(library('clpbn/table'), [clpbn_tabled_abolish/1, clpbn_tabled_asserta/1, clpbn_tabled_asserta/2, clpbn_tabled_assertz/1, clpbn_tabled_clause/2, clpbn_tabled_number_of_clauses/2, clpbn_is_tabled/1, clpbn_tabled_dynamic/1]). % % Tell Aleph not to use default solver during saturation % % all work will be done by EM :- set_clpbn_flag(solver,none). % % This is the Aleph interface % examples are stored as example(Id, Type, Example) % CPT domains are stored as random_type(KeySkeleton, ListOfValues). % :- use_module(library(lists),[append/3]). :- multifile user:cost/3. % handle uninstantiated examples as hidden variables. :- user:set(skolem_examples, false). % avoid doing CLP(BN) stuff except at start :- user:set(sat_start_hook, clpbn_aleph:disable_solver). :- user:set(sat_stop_hook, clpbn_aleph:enable_solver). :- user:set(reduce_start_hook, clpbn_aleph:disable_solver). :- user:set(reduce_stop_hook, clpbn_aleph:enable_solver). :- user:set(record_testclause_hook, clpbn_aleph:do_nothing). :- user:set(newbest_hook, clpbn_aleph:store_theory). disable_solver(_) :- clpbn_flag(solver, Old, none), nb_setval(old_clpbn_solver, Old). disable_solver(_,_) :- clpbn_flag(solver, Old, none), nb_setval(old_clpbn_solver, Old). enable_solver :- nb_getval(old_clpbn_solver, Old), set_clpbn_flag(solver, Old). enable_solver(_,_) :- nb_getval(old_clpbn_solver, Old), set_clpbn_flag(solver, Old). do_nothing(_). % backup current best theory in DB. store_theory(_,_,_) :- eraseall(best_theory), fail. store_theory(_,(H:-_),_) :- clpbn_is_tabled(user:H), !, store_tabled_theory(H). store_theory(_,(H:-_),_) :- store_theory(H). store_tabled_theory(H) :- clpbn_tabled_clause(user:H,B), add_correct_cpt(B,NB), store_cl((H:-NB)), fail. store_tabled_theory(_). store_theory(H) :- clause(user:H,B), add_correct_cpt(B,NB), store_cl((H:-NB)), fail. store_theory(_). add_correct_cpt((G,B),(G,NB)) :- !, add_correct_cpt(B,NB). add_correct_cpt((clpbn:{V = K with Tab }), ({V = K with NTab})) :- correct_tab(Tab,K,NTab). add_correct_cpt(({V = K with Tab }), ({V = K with NTab})) :- correct_tab(Tab,K,NTab). correct_tab(p(Vs,_),K,p(Vs,TDist)) :- get_dist_key(Id, K), get_dist_params(Id, TDist). correct_tab(p(Vs,_,Ps),K,p(Vs,TDist,Ps)) :- get_dist_key(Id, K), get_dist_params(Id, TDist). store_cl(Cl) :- recordz(best_theory, Cl, _). :- user:set(best_clause_hook, clpbn_aleph:add_new_clause). add_new_clause(_,(_ :- true),_,_) :- !. add_new_clause(_,(H :- B),_,_) :- %trace, % user:db_usage, % user:db_dynamic, domain(H, K, V, D), user:cost((H :- B), _, Cost), format(user_error,'Current Cost: ~w.~n', [Cost]), rewrite_body(B, IB, Vs, _, ( !, { V = K with p(D, CPTList, Vs) })), % need to remember which CPT we want get_dist_key(Id, K), get_dist_params(Id, CPTList), ( clpbn_is_tabled(user:H) -> clpbn_tabled_asserta(user:(H :- IB)) ; asserta(user:(H :- IB)) ), user:setting(verbosity,V), ( V >= 1 -> user:p_message('CLP(BN) Theory'), functor(H,N,Ar), listing(user:N/Ar) ; true ). % user-defined cost function, Aleph knows about this (and only about this). user:cost((H :- B),Inf,Score) :- !, domain(H, K, V, D), check_info(Inf), rewrite_body(B, IB, Vs, Ds, ( !, { V = K with p(D, CPTList, Vs) })), uniform_cpt([D|Ds], CPTList), ( clpbn_is_tabled(user:H) -> clpbn_tabled_asserta(user:(H :- IB), R) ; asserta(user:(H :- IB), R) ), ( cpt_score(Score0) -> erase(R), Score is -Score0 ; % illegal clause, just get out of here. erase(R), fail ). user:cost(H,_Inf,Score) :- !, init_clpbn_cost(H, Score0), Score is -Score0. % this is here so that Aleph will actually compute coverage. Aleph computes % coverage only if cost actually checks Inf. check_info(_). init_clpbn_cost(_, Score) :- inited(Score), !. init_clpbn_cost(H, Score) :- functor(H,N,A), % get rid of Aleph crap ( clpbn_is_tabled(user:H) -> clpbn_tabled_abolish(user:N/A), clpbn_tabled_dynamic(user:N/A) ; abolish(user:N/A), % make it easy to add and remove clauses. dynamic(user:N/A) ), domain(H, K, V, D), uniform_cpt([D], CPTList), % This will be the default cause, called when the other rules fail. ( clpbn_is_tabled(user:H) -> clpbn_tabled_assertz(user:(H :- !, { V = K with p(D, CPTList) })) ; assert(user:(H :- !, { V = K with p(D, CPTList) })) ), cpt_score(Score), assert(inited(Score)). % receives H, and generates a key K, a random variable RV, and a domain D. domain(H, K, RV, D) :- functor(H,Name,Arity), functor(Pred,Name,Arity), ( recorded(aleph,modeh(_,Pred),_) -> true ; user:'$aleph_global'(modeh,modeh(_,Pred)) ), arg(Arity,Pred,+RType), rt(RType,D), !, key_from_head(H,K,RV). domain(H, K, V, D) :- current_predicate(_,user:domain(_)), key_from_head(H,K,V), user:domain(K,D). key_from_head(H,K,V) :- H =.. [Name|Args], ( clpbn_is_tabled(user:H) -> clpbn_tabled_number_of_clauses(user:H,NClauses) ; predicate_property(user:H,number_of_clauses(NClauses)) ), atomic_concat(Name,NClauses,NName), append(H0L,[V],Args), K =.. [NName|H0L]. % transforms_body into something that is going to be called % receives G0, and generates a list of goals, a list of variables, and a list of domains. % receives also a Tail with the constraint to append at the end. rewrite_body((A,B), (user:NA,NB), [V|Vs], [D|Ds], Tail) :- rewrite_goal(A, V, D, NA), !, rewrite_body(B, NB, Vs, Ds, Tail). rewrite_body((A,B), (user:A,NB), Vs, Ds, Tail) :- rewrite_body(B,NB, Vs, Ds, Tail). rewrite_body(A,(user:NA,Tail), [V], [D], Tail) :- rewrite_goal(A, V, D, NA), !. rewrite_body(A, (user:A,Tail), [], [], Tail). % so they need not be rewritten. rewrite_goal(A,V,D,NA) :- functor(A,Name,Arity), functor(Pred,Name,Arity), ( recorded(aleph,modeb(_,Pred),_) -> true ; user:'$aleph_global'(modeb,modeb(_,Pred)) ), arg(Arity,Pred,-RType), rt(RType,D), !, A =.. [Name|Args], replace_last_var(Args,V,NArgs), NA =.. [Name|NArgs]. replace_last_var([_],V,[V]) :- !. replace_last_var([A|Args],V,[A|NArgs]) :- replace_last_var(Args,V,NArgs). % % This is the key % cpt_score(Lik) :- findall(user:Ex, user:example(_,pos,Ex), Exs), clpbn_flag(solver, Solver), clpbn_flag(em_solver, EMSolver), set_clpbn_flag(solver, EMSolver), reset_all_dists, em(Exs, 0.01, 10, _Tables, Lik), set_clpbn_flag(solver, Solver). complete_clpbn_cost(_AlephClause). random_type(A,B) :- assert(rt(A,B)). uniform_cpt(Ds, CPTList) :- lengths(Ds, Ls), uniform_CPT_as_list(Ls, CPTList). lengths([], []). lengths([D|Ds], [L|Ls]) :- length(D, L), lengths(Ds, Ls).