preliminary support for viterbi algorithm and HMMs
some code cleanups git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1363 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
parent
46f6a08087
commit
a4b79352d5
@ -33,8 +33,10 @@ CLPBN_PROGRAMS= \
|
||||
$(srcdir)/clpbn/gibbs.yap \
|
||||
$(srcdir)/clpbn/graphs.yap \
|
||||
$(srcdir)/clpbn/graphviz.yap \
|
||||
$(srcdir)/clpbn/topsort.yap \
|
||||
$(srcdir)/clpbn/utils.yap \
|
||||
$(srcdir)/clpbn/vel.yap \
|
||||
$(srcdir)/clpbn/viterbi.yap \
|
||||
$(srcdir)/clpbn/xbif.yap
|
||||
|
||||
CLPBN_EXAMPLES=
|
||||
|
@ -44,6 +44,10 @@
|
||||
incorporate_evidence/2
|
||||
]).
|
||||
|
||||
:- use_module('clpbn/utils', [
|
||||
sort_vars_by_key/3
|
||||
]).
|
||||
|
||||
:- dynamic solver/1,output/1,use/1.
|
||||
|
||||
solver(vel).
|
||||
@ -116,37 +120,6 @@ get_clpbn_vars([V|GVars],[V|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).
|
||||
get_keys([_|AVars], KeysVars) :- % may be non-CLPBN vars.
|
||||
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(vel, GVars, AVars, DiffVars) :-
|
||||
vel(GVars, AVars, DiffVars).
|
||||
write_out(gibbs, GVars, AVars, DiffVars) :-
|
||||
|
@ -30,6 +30,9 @@
|
||||
:- use_module(library('clpbn/utils'), [
|
||||
check_for_hidden_vars/3]).
|
||||
|
||||
:- use_module(library('clpbn/topsort'), [
|
||||
topsort/2]).
|
||||
|
||||
:- dynamic gibbs_params/3.
|
||||
|
||||
:- dynamic implicit/1.
|
||||
@ -446,27 +449,6 @@ clean_up.
|
||||
|
||||
gibbs_params(5,10000,100000).
|
||||
|
||||
/* simple implementation of a topological sorting algorithm */
|
||||
/* graph is as Node-[Parents] */
|
||||
|
||||
topsort([], []) :- !.
|
||||
topsort(Graph0,Sorted) :-
|
||||
add_parentless(Graph0, Sorted, IncludedI, Graph1, SortedRest),
|
||||
sort(IncludedI, Included),
|
||||
delete_parents(Graph1, Included, NoParents),
|
||||
topsort(NoParents, SortedRest).
|
||||
|
||||
add_parentless([], Sorted, [], [], Sorted).
|
||||
add_parentless([Node-[]|Graph0], [Node|Sorted], [Node|Included], Graph1, SortedRest) :- !,
|
||||
add_parentless(Graph0, Sorted, Included, Graph1, SortedRest).
|
||||
add_parentless([Node|Graph0], Sorted, Included, [Node|Graph1], SortedRest) :-
|
||||
add_parentless(Graph0, Sorted, Included, Graph1, SortedRest).
|
||||
|
||||
delete_parents([], _, []).
|
||||
delete_parents([Node-Parents|Graph1], Included, [Node-NewParents|NoParents]) :-
|
||||
ord_subtract(Parents, Included, NewParents),
|
||||
delete_parents(Graph1, Included, NoParents).
|
||||
|
||||
cvt2problist([], []).
|
||||
cvt2problist([[[_|E]]|Est0], [Ps|Probs]) :-
|
||||
sum_all(E,0,Sum),
|
||||
@ -486,6 +468,6 @@ do_probs([E|Es],Sum,[P|Ps]) :-
|
||||
show_sorted([], _) :- nl.
|
||||
show_sorted([I|VarOrder], Graph) :-
|
||||
arg(I,Graph,var(V,I,_,_,_,_,_,_,_)),
|
||||
clpbn:get_atts(V,[key(K)]),
|
||||
% clpbn:get_atts(V,[key(K)]),
|
||||
% format('~w ',[K]),
|
||||
show_sorted(VarOrder, Graph).
|
||||
|
27
CLPBN/clpbn/topsort.yap
Normal file
27
CLPBN/clpbn/topsort.yap
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
:- module(topsort, [topsort/2]).
|
||||
|
||||
:- use_module(library(ordsets),
|
||||
[ord_subtract/3]).
|
||||
|
||||
/* simple implementation of a topological sorting algorithm */
|
||||
/* graph is as Node-[Parents] */
|
||||
|
||||
topsort([], []) :- !.
|
||||
topsort(Graph0,Sorted) :-
|
||||
add_parentless(Graph0, Sorted, IncludedI, Graph1, SortedRest),
|
||||
sort(IncludedI, Included),
|
||||
delete_parents(Graph1, Included, NoParents),
|
||||
topsort(NoParents, SortedRest).
|
||||
|
||||
add_parentless([], Sorted, [], [], Sorted).
|
||||
add_parentless([Node-[]|Graph0], [Node|Sorted], [Node|Included], Graph1, SortedRest) :- !,
|
||||
add_parentless(Graph0, Sorted, Included, Graph1, SortedRest).
|
||||
add_parentless([Node|Graph0], Sorted, Included, [Node|Graph1], SortedRest) :-
|
||||
add_parentless(Graph0, Sorted, Included, Graph1, SortedRest).
|
||||
|
||||
delete_parents([], _, []).
|
||||
delete_parents([Node-Parents|Graph1], Included, [Node-NewParents|NoParents]) :-
|
||||
ord_subtract(Parents, Included, NewParents),
|
||||
delete_parents(Graph1, Included, NoParents).
|
||||
|
@ -1,7 +1,8 @@
|
||||
:- module(clpbn_utils, [
|
||||
clpbn_not_var_member/2,
|
||||
clpbn_var_member/2,
|
||||
check_for_hidden_vars/3]).
|
||||
check_for_hidden_vars/3,
|
||||
sort_vars_by_key/3]).
|
||||
|
||||
%
|
||||
% It may happen that variables from a previous query may still be around.
|
||||
@ -34,3 +35,35 @@ clpbn_not_var_member([], _).
|
||||
clpbn_not_var_member([V1|Vs], V) :- V1 \== V,
|
||||
clpbn_not_var_member(Vs, V).
|
||||
|
||||
|
||||
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]) :-
|
||||
clpbn:get_atts(V, [key(K)]), !,
|
||||
get_keys(AVars, KeysVars).
|
||||
get_keys([_|AVars], KeysVars) :- % may be non-CLPBN vars.
|
||||
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]).
|
||||
|
||||
|
@ -88,7 +88,6 @@ find_all_clpbn_vars([V|Vs], [Var|LV], ProcessedVars, [table(I,Table,Parents,Size
|
||||
|
||||
var_with_deps(V, Table, Deps, Sizes, Ev, Vals) :-
|
||||
clpbn:get_atts(V, [dist(Vals,OTable,Parents)]),
|
||||
clpbn:get_atts(V, [key(K)]), format('~w(~w) Parents: ~w~n',[V,K,Parents]),
|
||||
( clpbn:get_atts(V, [evidence(Ev)]) -> true ; true),
|
||||
reorder_CPT([V|Parents],OTable,Deps0,Table0,Sizes0),
|
||||
simplify_evidence(Deps0, Table0, Deps0, Sizes0, Table, Deps, Sizes).
|
||||
|
150
CLPBN/clpbn/viterbi.yap
Normal file
150
CLPBN/clpbn/viterbi.yap
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
:- style_check(all).
|
||||
|
||||
:- module(viterbi, [viterbi/3]).
|
||||
|
||||
:- use_module(library(lists),
|
||||
[nth/3]).
|
||||
|
||||
:- use_module(library('clpbn'), []).
|
||||
|
||||
:- use_module(library('clpbn/utils'), [
|
||||
sort_vars_by_key/3]).
|
||||
|
||||
:- use_module(library('ugraphs'), [
|
||||
vertices_edges_to_ugraph/3,
|
||||
add_edges/3,
|
||||
top_sort/3]).
|
||||
|
||||
:- attribute prob/1, emission/1, backp/1.
|
||||
|
||||
viterbi(Start,End,Trace) :-
|
||||
attributes:all_attvars(Vars0),
|
||||
sort_vars_by_key(Vars0,Vars,_),
|
||||
add_emissions(Vars),
|
||||
topsort_vars(Vars,SortedVars),
|
||||
init_viterbi(Start),
|
||||
viterbi_alg(SortedVars),
|
||||
backtrace(Start,End,[],Trace).
|
||||
|
||||
|
||||
add_emissions([]).
|
||||
add_emissions([Var|Vars]) :-
|
||||
add_emission(Var),
|
||||
add_emissions(Vars).
|
||||
|
||||
add_emission(Var) :-
|
||||
clpbn:get_atts(Var,[evidence(Ev),dist(Vals,emission(CPT),Parents)]), !,
|
||||
nth(Nth, Vals, Ev),
|
||||
find_probs(CPT,Nth,Prob),
|
||||
adde2pars(Parents,Prob).
|
||||
add_emission(_).
|
||||
|
||||
find_probs(log(Logs,_Norms),Nth,Log) :-
|
||||
arg(Nth,Logs,Log).
|
||||
% get_norm(Norms,Nth,Norm).
|
||||
|
||||
%get_norm(Norms,_,Norms) :- number(Norms), !.
|
||||
%get_norm(Norms,Nth,Norm) :-
|
||||
% arg(Nth,Norms,Norm).
|
||||
|
||||
adde2pars([],_).
|
||||
adde2pars([V|Vs],P) :-
|
||||
put_atts(V,[emission(P)]),
|
||||
adde2pars(Vs,P).
|
||||
|
||||
topsort_vars(Vars,SortedVars) :-
|
||||
vertices_edges_to_ugraph([],[],Graph0),
|
||||
sort_vars(Vars, Graph0, SortedVars).
|
||||
|
||||
%
|
||||
% take advantage of the fact that variables can be split by timestamp.
|
||||
%
|
||||
sort_vars(Vars, Graph0, SortedVars) :-
|
||||
fetch_times(Vars,T0Vars),
|
||||
keysort(T0Vars, TVars),
|
||||
sort_times(TVars, Graph0, SortedVars).
|
||||
|
||||
fetch_times([], []).
|
||||
fetch_times([V|Vs], [T-V|TVs]) :-
|
||||
clpbn:get_atts(V,[key(K)]),
|
||||
arg(1,K,T),
|
||||
fetch_times(Vs, TVs).
|
||||
|
||||
sort_times([], _, []).
|
||||
sort_times([T-V|TVs], Graph0, SortedVars) :-
|
||||
fetch_same_time(TVs, T, Vars, NTVs),
|
||||
fetch_parents([V|Vars],Graph0,Graph),
|
||||
top_sort(Graph,SortedVars0,SortedVars),
|
||||
sort_times(NTVs, Graph0, SortedVars0).
|
||||
|
||||
fetch_same_time([T-V|TVs], T, [V|Vs], TVs0) :-
|
||||
fetch_same_time(TVs, T, Vs, TVs0).
|
||||
fetch_same_time(TVs, _, [], TVs) :- !.
|
||||
|
||||
|
||||
fetch_parents([],Graph,Graph).
|
||||
fetch_parents([V|Vars],Graph0,GraphF) :-
|
||||
clpbn:get_atts(V,[dist(_,_,Parents)]),
|
||||
exp_edges(Parents,V,Graph0,GraphI),
|
||||
fetch_parents(Vars,GraphI,GraphF).
|
||||
|
||||
exp_edges([],_,Graph,Graph).
|
||||
exp_edges([P|Parents],V,Graph0,GraphF) :-
|
||||
add_edges(Graph0,[V-P],GraphI),
|
||||
exp_edges(Parents,V,GraphI,GraphF).
|
||||
|
||||
extract_vars([],[]).
|
||||
extract_vars([_-V|KVars],[V|Vars]) :-
|
||||
extract_vars(KVars,Vars).
|
||||
|
||||
init_viterbi(V) :-
|
||||
put_atts(V,[prob(0)]).
|
||||
|
||||
viterbi_alg([]).
|
||||
viterbi_alg([V|Vs]) :-
|
||||
% get the current status
|
||||
get_atts(V,[prob(P0)]), !,
|
||||
clpbn:get_atts(V,[dist(_,trans(Probs),States)]),
|
||||
% adjust to consider emission probabilities
|
||||
adjust_for_emission(V, P0, Pf),
|
||||
propagate(Probs,States,Pf,V),
|
||||
viterbi_alg(Vs).
|
||||
viterbi_alg([_|Vs]) :-
|
||||
viterbi_alg(Vs).
|
||||
|
||||
adjust_for_emission(V, P0, Pf) :-
|
||||
get_atts(V,[emission(P)]), !,
|
||||
mprob(P0,P,Pf),
|
||||
put_atts(V,[prob(Pf)]).
|
||||
adjust_for_emission(_, P, P).
|
||||
|
||||
propagate([],[],_,_).
|
||||
propagate([log(Prob,_)|Probs],[State|States],Pf,V) :-
|
||||
get_atts(State,[prob(P0)]), !,
|
||||
mprob(Pf,Prob,P),
|
||||
(P > P0 ->
|
||||
put_atts(State,[prob(P),backp(V)])
|
||||
;
|
||||
true
|
||||
),
|
||||
propagate(Probs,States,Pf,V).
|
||||
propagate([log(Prob,_)|Probs],[State|States],Pf,V) :-
|
||||
mprob(Pf,Prob,P),
|
||||
put_atts(State,[prob(P),backp(V)]),
|
||||
propagate(Probs,States,Pf,V).
|
||||
|
||||
backtrace(Start,Var,Trace,Trace) :- Start == Var, !.
|
||||
backtrace(Start,Var,Trace0,Trace) :-
|
||||
get_atts(Var,[backp(V)]),
|
||||
clpbn:get_atts(Var, [key(K)]),
|
||||
backtrace(Start,V,[K|Trace0],Trace).
|
||||
|
||||
|
||||
|
||||
mprob(*,P,P) :- !.
|
||||
mprob(P,*,P) :- !.
|
||||
mprob(P1,P2,P) :- P is P1+P2.
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user