2004-07-15 17:23:44 +01:00
|
|
|
|
|
|
|
|
2004-11-16 16:38:09 +00:00
|
|
|
:- module(clpbn, [{}/1]).
|
2004-07-15 17:23:44 +01:00
|
|
|
|
|
|
|
:- use_module(library(atts)).
|
|
|
|
:- use_module(library(lists)).
|
|
|
|
:- use_module(library(terms)).
|
|
|
|
|
|
|
|
:- op( 500, xfy, with).
|
|
|
|
|
|
|
|
%
|
|
|
|
% avoid the overhead of using goal_expansion/2.
|
|
|
|
%
|
|
|
|
:- multifile
|
|
|
|
user:term_expansion/2.
|
|
|
|
|
|
|
|
:- dynamic
|
|
|
|
user:term_expansion/2.
|
|
|
|
|
|
|
|
:- multifile
|
|
|
|
user:term_expansion/2.
|
|
|
|
|
|
|
|
:- attribute key/1, dist/1, evidence/1, done/1, starter/0.
|
|
|
|
|
|
|
|
|
|
|
|
:- use_module('clpbn/bnt', [dump_as_bnt/2,
|
|
|
|
check_if_bnt_done/1
|
|
|
|
]).
|
|
|
|
|
2004-11-16 16:38:09 +00:00
|
|
|
:- use_module('clpbn/vel', [vel/3,
|
2004-07-15 17:23:44 +01:00
|
|
|
check_if_vel_done/1
|
|
|
|
]).
|
|
|
|
|
|
|
|
:- use_module('clpbn/evidence', [add_to_evidence/1,
|
|
|
|
execute_pre_evidence/0
|
|
|
|
]).
|
|
|
|
|
|
|
|
use(vel).
|
|
|
|
|
|
|
|
{Var = Key with Dist} :-
|
|
|
|
% key_entry(Key,Indx),
|
|
|
|
% array_element(clpbn,Indx,El),
|
|
|
|
% attributes:put_att(El,3,indx(Indx)),
|
2004-11-16 16:38:09 +00:00
|
|
|
put_atts(El,[key(Key),dist((E->Domain))]),
|
2004-07-15 17:23:44 +01:00
|
|
|
extract_dist(Dist, E, Domain),
|
|
|
|
add_evidence(Var,El).
|
|
|
|
|
|
|
|
extract_dist(V, (Tab.Inps), Domain) :- var(V), !,
|
|
|
|
V = p(Domain, Tab, Inps).
|
|
|
|
extract_dist(p(Domain, Tab, []), Tab, Domain) :- !.
|
|
|
|
extract_dist(p(Domain, Tab, Inps), (Tab.Inps), Domain).
|
|
|
|
extract_dist(p(Domain, Tab), Tab, Domain).
|
|
|
|
|
|
|
|
key_entry(Key, I) :-
|
|
|
|
hash_table_size(Size),
|
|
|
|
term_hash(Key, -1, Size, Hash),
|
|
|
|
collision(Hash, Size, I),
|
|
|
|
( array_element(keys, I, El) ->
|
|
|
|
update_array(keys, I, Key)
|
|
|
|
;
|
|
|
|
El = Key),
|
|
|
|
!.
|
|
|
|
|
|
|
|
% go from beginning
|
|
|
|
collision(Size, Size, I) :- !,
|
|
|
|
collision(0, Size, I).
|
|
|
|
collision(Hash, _, Hash).
|
|
|
|
collision(Hash, Size, I) :-
|
|
|
|
Hash1 is Hash+1,
|
|
|
|
collision(Hash1, Size, I).
|
|
|
|
|
|
|
|
%
|
|
|
|
% just fetch skolems so that we can process them carefully.
|
|
|
|
%
|
|
|
|
fetch_skolems(A, A) --> { var(A) }, !. %meta-calls
|
|
|
|
fetch_skolems((A,B), (NA,NB)) --> !,
|
|
|
|
fetch_skolems(A, NA),
|
|
|
|
fetch_skolems(B, NB).
|
|
|
|
% do not allow disjunctive clauses, at least for now.
|
|
|
|
fetch_skolems((A;B), (A;B)) --> !.
|
|
|
|
fetch_skolems((A|B), (A|B)) --> !.
|
|
|
|
fetch_skolems((A->B), (NA->NB)) --> !,
|
|
|
|
fetch_skolems(A, NA),
|
|
|
|
fetch_skolems(B, NB).
|
|
|
|
fetch_skolems(M:A, M:NA) --> !,
|
|
|
|
fetch_skolems(A, NA).
|
|
|
|
fetch_skolems(X = { Constraints }, true) --> !,
|
|
|
|
[ [X|Constraints] ].
|
|
|
|
fetch_skolems(G, G) --> [].
|
|
|
|
|
|
|
|
%
|
|
|
|
% just fetch skolems so that we can process them carefully.
|
|
|
|
%
|
|
|
|
handle_body_goals((A,B), (NA,NB)) :- !,
|
|
|
|
handle_body_goals(A, NA),
|
|
|
|
handle_body_goals(B, NB).
|
|
|
|
% do not allow disjunctive clauses, at least for now.
|
|
|
|
handle_body_goals((A;B), (A;B)) :- !.
|
|
|
|
handle_body_goals((A|B), (A|B)) :- !.
|
|
|
|
handle_body_goals((A->B), (NA->NB)) :- !,
|
|
|
|
handle_body_goals(A, NA),
|
|
|
|
handle_body_goals(B, NB).
|
|
|
|
handle_body_goals(M:A, M:NA) :- !,
|
|
|
|
handle_body_goals(A, NA).
|
|
|
|
handle_body_goals(findall(V,G,L), (findall(V,G,L), aggs:fix_vars(L))) :- !.
|
|
|
|
handle_body_goals(setof(V,G,L), (setof(V,G,L),aggs:fix_vars(L))) :- !.
|
|
|
|
handle_body_goals(bagof(V,G,L), (bagof(V,G,L),aggs:fix_vars(L))) :- !.
|
|
|
|
handle_body_goals(G, G).
|
|
|
|
|
|
|
|
|
|
|
|
compile_skolems([[X|Constraints]], Vars, NVars, A, Code) :- !,
|
|
|
|
compile_skolem(X, Vars, NVars, A, Code, Constraints).
|
|
|
|
compile_skolems([[X|Constraints]|Cs], Vars, NVars, A, (Code, RCode)) :-
|
|
|
|
compile_skolem(X, Vars, NVars, A, Code, Constraints),
|
|
|
|
compile_skolems(Cs, Vars, NVars, A, RCode).
|
|
|
|
|
|
|
|
compile_skolem(EVar, Vars, NVars, Head, Code, Constraints) :-
|
|
|
|
compile_constraints(Constraints, Vars, NVars, Head, Code, EVar).
|
|
|
|
|
|
|
|
compile_constraints((A : B), Vars, NVars, Head, (CA , CB), EVar) :- !,
|
|
|
|
compile_first_constraint(A, Head, CA, EVar),
|
|
|
|
compile_second_constraint(B, Vars, NVars, CB, EVar).
|
|
|
|
|
|
|
|
compile_first_constraint(SkKey, Head, (KeyGoal, /* cycle(Key,EVar), */ array_element(clpbn, Id, EVar), clpbn:put_atts(EVar,[key(KeyDesc),indx(Id)])), EVar) :-
|
|
|
|
functor(SkKey, Name, _),!,
|
|
|
|
SkKey =.. [_|Key],
|
|
|
|
generate_key_goal(Head, Name, Key, KeyGoal, KeyDesc, Id).
|
|
|
|
|
|
|
|
compile_second_constraint(Constraint, Vars, NVars, clpbn:put_atts(EVar,[dist(NC)]), EVar) :-
|
|
|
|
check_constraint(Constraint, Vars, NVars, NC).
|
|
|
|
|
|
|
|
check_constraint(Constraint, _, _, Constraint) :- var(Constraint), !.
|
2004-11-16 16:38:09 +00:00
|
|
|
check_constraint((A->D), _, _, (A->D)) :- var(A), !.
|
|
|
|
check_constraint((([A|B].L)->D), Vars, NVars, (([A|B].NL)->D)) :- !,
|
2004-07-15 17:23:44 +01:00
|
|
|
check_cpt_input_vars(L, Vars, NVars, NL).
|
|
|
|
check_constraint(Dist, _, _, Dist).
|
|
|
|
|
|
|
|
check_cpt_input_vars([], _, _, []).
|
|
|
|
check_cpt_input_vars([V|L], Vars, NVars, [NV|NL]) :-
|
|
|
|
replace_var(Vars, V, NVars, NV),
|
|
|
|
check_cpt_input_vars(L, Vars, NVars, NL).
|
|
|
|
|
|
|
|
replace_var([], V, [], V).
|
|
|
|
replace_var([V|_], V0, [NV|_], NV) :- V == V0, !.
|
|
|
|
replace_var([_|Vars], V, [_|NVars], NV) :-
|
|
|
|
replace_var(Vars, V, NVars, NV).
|
|
|
|
|
|
|
|
generate_key_goal(Head, Name, Key, clpbn_aux:KeyGoal, KeyDesc, Id) :-
|
|
|
|
functor(Head, _, Ar),
|
|
|
|
atom_chars(Name, NaS),
|
|
|
|
number_codes(Ar, ArS),
|
|
|
|
append("/", ArS, S1),
|
|
|
|
append(NaS, S1, S2),
|
|
|
|
append("key_", S2, SNNa),
|
|
|
|
atom_chars(NNa, SNNa),
|
|
|
|
append(Key,[Id],LArgs),
|
|
|
|
KeyGoal =.. [NNa|LArgs],
|
|
|
|
KeyDesc =.. [Name|Key],
|
|
|
|
length(Key, N),
|
|
|
|
NAr is N+1,
|
|
|
|
abolish(clpbn_aux:(NNa/NAr)),
|
|
|
|
reset_clpbn,
|
|
|
|
dynamic_predicate(clpbn_aux:(NNa/NAr), logical),
|
|
|
|
assert((clpbn_aux:KeyGoal :- new_key(Id), asserta(clpbn_aux:(KeyGoal :- !)))).
|
|
|
|
|
|
|
|
new_key(Key) :-
|
|
|
|
get_value(clpbn_key, Key),
|
|
|
|
X is Key+1,
|
|
|
|
set_value(clpbn_key, X).
|
|
|
|
|
|
|
|
skolem_vars([], []).
|
|
|
|
skolem_vars([[V|_]|LV], [V|NLV]) :-
|
|
|
|
skolem_vars(LV, NLV).
|
|
|
|
|
|
|
|
|
|
|
|
skolem_new_vars([], [], []).
|
|
|
|
skolem_new_vars([[_|B]|Sks], [NV|Vs], [[NV|B]|NSks]) :-
|
|
|
|
skolem_new_vars(Sks, Vs, NSks).
|
|
|
|
|
|
|
|
|
|
|
|
fresh_vars([], [], B, B).
|
|
|
|
fresh_vars([V|LV], [NV|NLV], (clpbn:add_evidence(V,NV),B), B0) :-
|
|
|
|
fresh_vars(LV, NLV, B, B0).
|
|
|
|
|
|
|
|
|
|
|
|
add_evidence(V,NV) :-
|
|
|
|
nonvar(V), !,
|
|
|
|
clpbn:put_atts(NV,evidence(V)).
|
|
|
|
add_evidence(V,V).
|
|
|
|
|
|
|
|
%
|
|
|
|
% called by top-level
|
|
|
|
%
|
|
|
|
project_attributes(GVars, AVars) :-
|
|
|
|
AVars = [_|_], !,
|
|
|
|
execute_pre_evidence,
|
|
|
|
sort_vars_by_key(AVars,SortedAVars,DiffVars),
|
|
|
|
get_clpbn_vars(GVars,CLPBNGVars),
|
|
|
|
write_out(CLPBNGVars, SortedAVars,DiffVars).
|
|
|
|
project_attributes(_, _).
|
|
|
|
|
|
|
|
get_clpbn_vars([],[]).
|
|
|
|
get_clpbn_vars([V|GVars],[V|CLPBNGVars]) :-
|
|
|
|
get_atts(V, [key(_)]), !,
|
|
|
|
get_clpbn_vars(GVars,CLPBNGVars).
|
|
|
|
get_clpbn_vars([_|GVars],CLPBNGVars) :-
|
|
|
|
get_clpbn_vars(GVars,CLPBNGVars).
|
|
|
|
|
|
|
|
sort_vars_by_key(AVars,SortedAVars, UnifiableVars) :-
|
|
|
|
get_keys(AVars, KeysVars),
|
|
|
|
keysort(KeysVars, KVars),
|
|
|
|
merge_same_key(KVars, SortedAVars, [], UnifiableVars).
|
|
|
|
|
|
|
|
get_keys([], []).
|
|
|
|
get_keys([V|AVars], [K-V|KeysVars]) :-
|
|
|
|
get_atts(V, [key(K)]),
|
|
|
|
get_keys(AVars, KeysVars).
|
|
|
|
|
|
|
|
merge_same_key([], [], _, []).
|
|
|
|
merge_same_key([K1-V1,K2-V2|Vs], SortedAVars, Ks, UnifiableVars) :-
|
|
|
|
K1 == K2, !, V1 = V2,
|
|
|
|
merge_same_key([K1-V1|Vs], SortedAVars, Ks, UnifiableVars).
|
|
|
|
merge_same_key([K1-V1,K2-V2|Vs], [V1|SortedAVars], Ks, [K1|UnifiableVars]) :-
|
|
|
|
(in_keys(K1, Ks) ; \+ \+ K1 = K2), !,
|
|
|
|
add_to_keys(K1, Ks, NKs),
|
|
|
|
merge_same_key([K2-V2|Vs], SortedAVars, NKs, UnifiableVars).
|
|
|
|
merge_same_key([K-V|Vs], [V|SortedAVars], Ks, UnifiableVars) :-
|
|
|
|
add_to_keys(K, Ks, NKs),
|
|
|
|
merge_same_key(Vs, SortedAVars, NKs, UnifiableVars).
|
|
|
|
|
|
|
|
in_keys(K1,[K|_]) :- \+ \+ K1 = K, !.
|
|
|
|
in_keys(K1,[_|Ks]) :-
|
|
|
|
in_keys(K1,Ks).
|
|
|
|
|
|
|
|
add_to_keys(K1, Ks, Ks) :- ground(K1), !.
|
|
|
|
add_to_keys(K1, Ks, [K1|Ks]).
|
|
|
|
|
|
|
|
write_out(GVars, AVars, DiffVars) :-
|
|
|
|
use(vel),
|
|
|
|
vel(GVars, AVars, DiffVars).
|
|
|
|
write_out(GVars, AVars, _) :-
|
|
|
|
use(bnt),
|
|
|
|
dump_as_bnt(GVars, AVars).
|
|
|
|
% starter_vars(GVars).
|
|
|
|
|
|
|
|
starter_vars([]).
|
|
|
|
starter_vars([Var|Vs]) :-
|
|
|
|
get_atts(Var, [key(_)]),
|
|
|
|
put_atts(Var, [starter]),
|
|
|
|
starter_vars(Vs).
|
|
|
|
|
|
|
|
|
|
|
|
get_bnode(Var, Goal) :-
|
|
|
|
get_atts(Var, [key(Key),dist(X)]),
|
|
|
|
dist_goal(X, Key, Goal0),
|
|
|
|
include_evidence(Var, Goal0, Key, Goali),
|
|
|
|
include_starter(Var, Goali, Key, Goal).
|
|
|
|
|
2004-11-16 16:38:09 +00:00
|
|
|
include_evidence(Var, Goal0, Key, ((Key:-Ev),Goal0)) :-
|
2004-07-15 17:23:44 +01:00
|
|
|
get_atts(Var, [evidence(Ev)]), !.
|
|
|
|
include_evidence(_, Goal0, _, Goal0).
|
|
|
|
|
2004-11-16 16:38:09 +00:00
|
|
|
include_starter(Var, Goal0, Key, ((:-Key),Goal0)) :-
|
2004-07-15 17:23:44 +01:00
|
|
|
get_atts(Var, [starter]), !.
|
|
|
|
include_starter(_, Goal0, _, Goal0).
|
|
|
|
|
|
|
|
dist_goal(norm(M,V), Key, (Key=norm(M,V))) :- !.
|
|
|
|
dist_goal(avg(L), Key, (Key=avg(L))) :- !.
|
|
|
|
dist_goal(Dist, Key, (Key=NDist)) :-
|
|
|
|
term_variables(Dist, DVars),
|
|
|
|
process_vars(DVars, DKeys),
|
|
|
|
my_copy_term(Dist,DVars, NDist,DKeys).
|
|
|
|
|
|
|
|
my_copy_term(V, DVars, Key, DKeys) :-
|
|
|
|
find_var(DVars, V, Key, DKeys).
|
|
|
|
my_copy_term(A, _, A, _) :- atomic(A), !.
|
|
|
|
my_copy_term(T, Vs, NT, Ks) :-
|
|
|
|
T =.. [Na|As],
|
|
|
|
my_copy_terms(As, Vs, NAs, Ks),
|
|
|
|
NT =.. [Na|NAs].
|
|
|
|
|
|
|
|
my_copy_terms([], _, [], _).
|
|
|
|
my_copy_terms([A|As], Vs, [NA|NAs], Ks) :-
|
|
|
|
my_copy_term(A, Vs, NA, Ks),
|
|
|
|
my_copy_terms(As, Vs, NAs, Ks).
|
|
|
|
|
|
|
|
find_var([V1|_], V, Key, [Key|_]) :- V1 == V, !.
|
|
|
|
find_var([_|DVars], V, Key, [_|DKeys]) :-
|
|
|
|
find_var(DVars, V, Key, DKeys).
|
|
|
|
|
|
|
|
process_vars([], []).
|
|
|
|
process_vars([V|Vs], [K|Ks]) :-
|
|
|
|
process_var(V, K),
|
|
|
|
process_vars(Vs, Ks).
|
|
|
|
|
|
|
|
process_var(V, K) :- get_atts(V, [key(K)]), !.
|
|
|
|
% oops: this variable has no attributes.
|
|
|
|
process_var(V, _) :- throw(error(instantiation_error,clpbn(attribute_goal(V)))).
|
|
|
|
|
|
|
|
%
|
|
|
|
% unify a CLPBN variable with something.
|
|
|
|
%
|
|
|
|
verify_attributes(Var, T, Goals) :-
|
|
|
|
get_atts(Var, [key(Key),dist(Dist)]), !,
|
|
|
|
/* oops, someone trying to bind a clpbn constrained variable */
|
|
|
|
Goals = [],
|
|
|
|
bind_clpbn(T, Var, Key, Dist).
|
|
|
|
verify_attributes(_, _, []).
|
|
|
|
|
|
|
|
|
|
|
|
bind_clpbn(T, _, Key, Dist) :- var(T),
|
|
|
|
get_atts(T, [key(Key1),dist(Dist1)]), !,
|
|
|
|
bind_clpbns(Key, Dist, Key1, Dist1).
|
|
|
|
bind_clpbn(_, Var, _, _) :-
|
|
|
|
use(bnt),
|
|
|
|
check_if_bnt_done(Var), !.
|
|
|
|
bind_clpbn(_, Var, _, _) :-
|
|
|
|
use(vel),
|
|
|
|
check_if_vel_done(Var), !.
|
|
|
|
bind_clpbn(T, Var, Key0, _) :-
|
|
|
|
get_atts(Var, [key(Key0)]), !,
|
|
|
|
(
|
|
|
|
Key = Key0 -> true
|
|
|
|
;
|
|
|
|
format(user_error, "trying to force evidence ~w through unification with key ~w~n",[T, Key])
|
|
|
|
).
|
|
|
|
|
|
|
|
fresh_attvar(Var, NVar) :-
|
|
|
|
get_atts(Var, LAtts),
|
|
|
|
put_atts(NVar, LAtts).
|
|
|
|
|
|
|
|
bind_clpbns(Key, Dist, Key, Dist1) :- !,
|
|
|
|
( Dist = Dist1 -> true ; throw(error(domain_error(bayesian_domain),bind_clpbns))).
|
|
|
|
bind_clpbns(_, _, _, _, _) :-
|
|
|
|
format(user_error, "unification of two bayesian vars not supported~n").
|
|
|
|
|
|
|
|
:- yap_flag(toplevel_hook,clpbn:init_clpbn).
|
|
|
|
|
|
|
|
hash_table_size(300000).
|
|
|
|
|
|
|
|
init_clpbn :-
|
|
|
|
reset_clpbn,
|
|
|
|
fail.
|
|
|
|
%init_clpbn :-
|
|
|
|
% hash_table_size(HashTableSize),
|
|
|
|
% array(clpbn,HashTableSize),
|
|
|
|
% catch(static_array(keys,HashTableSize,term),_,true).
|
|
|
|
|
|
|
|
|
|
|
|
random_tmp_number(I) :-
|
|
|
|
get_value(clpbn_random_tmp_number,I),
|
|
|
|
I1 is I+1,
|
|
|
|
set_value(clpbn_random_tmp_number,I1).
|
|
|
|
|
|
|
|
reset_clpbn :-
|
|
|
|
current_predicate(_, clpbn_aux:P),
|
|
|
|
retract(clpbn_aux:(P :- !)),
|
|
|
|
fail.
|
|
|
|
reset_clpbn :-
|
|
|
|
set_value(clpbn_key, 0), fail.
|
|
|
|
reset_clpbn :-
|
|
|
|
set_value(clpbn_random_tmp_number, 0), fail.
|
|
|
|
reset_clpbn.
|
|
|
|
|
|
|
|
|
|
|
|
user:term_expansion((A :- {}), ( :- true )) :- !, % evidence
|
|
|
|
prolog_load_context(module, M),
|
|
|
|
add_to_evidence(M:A).
|
|
|
|
|