diff options
| author | ziejd2 | 2018-03-14 23:23:33 -0500 |
|---|---|---|
| committer | GitHub | 2018-03-14 23:23:33 -0500 |
| commit | 1ff6baa44e22b91eefb48aea6f3befa078c0489b (patch) | |
| tree | e0fd79d2e32fd2aedda2eadaed0f19af3514c520 /sourcecodes/bnt-master/BNT/inference | |
| parent | 6882395afdadf4e982b25b5215071a0932730950 (diff) | |
| parent | c80226899f5cdd9f11c163817d59445213f5bef0 (diff) | |
| download | BNW-1ff6baa44e22b91eefb48aea6f3befa078c0489b.tar.gz | |
Merge pull request #1 from ziejd2/octave_php_separate
Octave php separate
Diffstat (limited to 'sourcecodes/bnt-master/BNT/inference')
507 files changed, 20238 insertions, 0 deletions
diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Entries new file mode 100644 index 00000000..a5ebeece --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/bnet_from_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/get_field.m/1.1.1.1/Wed May 29 15:59:56 2002// +/inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/set_fields.m/1.1.1.1/Wed May 29 15:59:56 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..24f16336 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Repository new file mode 100644 index 00000000..07b838d4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/@inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..ce1f8c1e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Entries @@ -0,0 +1,3 @@ +/marginal_family_pot.m/1.1.1.1/Wed May 29 15:59:56 2002// +/observed_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..de36d64e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/@inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/marginal_family_pot.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/marginal_family_pot.m new file mode 100644 index 00000000..c1e63710 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/marginal_family_pot.m @@ -0,0 +1,14 @@ +function pot = marginal_family_pot(engine, i) +% MARGINAL_FAMILY_POT Compute the marginal on i's family and return as a potentila (inf_engine) +% function pot = marginal_family_pot(engine,i) + +% This function is only called by solve_limid. +% It requires that engine's marginal_family function return a potential. +% This is true for jtree_inf_engine, but not for, say, jtree_ndx_inf_engine. +% All limids must be solved using potentials, +% but this is not true for bnets. + +%[m, pot] = marginal_family(engine, i); + +bnet = bnet_from_engine(engine); +[m, pot] = marginal_nodes(engine, family(bnet.dag, i)); diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/observed_nodes.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/observed_nodes.m new file mode 100644 index 00000000..97fccdb3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/Old/observed_nodes.m @@ -0,0 +1,5 @@ +function onodes = observed_nodes(engine) +% OBSERVED_NODES Return nodes that are guaranteed to be observed, indep of evidence (generic inf_engine) +% onodes = observed_nodes(engine) + +onodes = []; diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/bnet_from_engine.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/bnet_from_engine.m new file mode 100644 index 00000000..cf579fb0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/bnet_from_engine.m @@ -0,0 +1,12 @@ +function bnet = bnet_from_engine(engine) +% BNET_FROM_ENGINE Return the bnet structure stored inside the engine (inf_engine) +% bnet = bnet_from_engine(engine) + +bnet = engine.bnet; + +% We cannot write 'engine.bnet' without writing a 'subsref' function, +% since engine is an object with private parts. +% The bnet field should be the only thing external users of the engine should need access to. +% We do not pass bnet as a separate argument, since it could get out of synch with the one +% encoded inside the engine. + diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/get_field.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/get_field.m new file mode 100644 index 00000000..a1d16335 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/get_field.m @@ -0,0 +1,15 @@ +function val = get_field(engine, name) +% GET_FIELD Get the value of a named field from a generic engine +% val = get_field(engine, name) +% +% The following fields can be accessed +% +% bnet +% +% e.g., bnet = get_field(engine, 'bnet') + +switch name + case 'bnet', val = engine.bnet; + otherwise, + error(['invalid argument name ' name]); +end diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/inf_engine.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/inf_engine.m new file mode 100644 index 00000000..f08e2438 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/inf_engine.m @@ -0,0 +1,6 @@ +function engine = inf_engine(bnet) + +engine.bnet = bnet; +engine = class(engine, 'inf_engine'); + + diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/marginal_family.m new file mode 100644 index 00000000..0107f1d3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/marginal_family.m @@ -0,0 +1,24 @@ +function m = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on i's family (inf_engine) +% m = marginal_family(engine, i, t) +% +% t defaults to 1. + +if nargin < 3, t = 1; end + +bnet = bnet_from_engine(engine); +if t==1 + m = marginal_nodes(engine, family(bnet.dag, i)); +else + ss = length(bnet.intra); + fam = family(bnet.dag, i+ss); + if any(fam<=ss) + % i has a parent in the preceeding slice + % Hence the lowest numbered slice containing the family is t-1 + m = marginal_nodes(engine, fam, t-1); + else + % The family all fits inside slice t + % Hence shift the indexes back to slice 1 + m = marginal_nodes(engine, fam-ss, t); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/set_fields.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/set_fields.m new file mode 100644 index 00000000..e75cfa45 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/set_fields.m @@ -0,0 +1,13 @@ +function engine = set_fields(engine, varargin) +% SET_FIELDS Set the fields for a generic engine +% engine = set_fields(engine, name/value pairs) +% +% e.g., engine = set_fields(engine, 'maximize', 1) + +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'maximize', engine.maximize = args{i+1}; + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/@inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/@inf_engine/update_engine.m new file mode 100644 index 00000000..afafdeb9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/@inf_engine/update_engine.m @@ -0,0 +1,7 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (inf_engine). +% engine = update_engine(engine, newCPDs) +% +% This generic method is suitable for engines that do not process the parameters until 'enter_evidence'. + +engine.bnet.CPD = newCPDs; diff --git a/sourcecodes/bnt-master/BNT/inference/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/CVS/Entries new file mode 100644 index 00000000..1ab405cf --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/CVS/Entries @@ -0,0 +1,2 @@ +/dummy/1.1.1.1/Sat Jan 18 22:22:22 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/CVS/Entries.Log new file mode 100644 index 00000000..09d6954b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/CVS/Entries.Log @@ -0,0 +1,4 @@ +A D/@inf_engine//// +A D/dynamic//// +A D/online//// +A D/static//// diff --git a/sourcecodes/bnt-master/BNT/inference/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/CVS/Repository new file mode 100644 index 00000000..7889e181 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference diff --git a/sourcecodes/bnt-master/BNT/inference/CVS/Root b/sourcecodes/bnt-master/BNT/inference/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dummy b/sourcecodes/bnt-master/BNT/inference/dummy new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dummy diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Entries new file mode 100644 index 00000000..5cd139de --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Entries @@ -0,0 +1,10 @@ +/bk_ff_hmm_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_init_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_marginal_from_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_predict_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_update_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_update_bel1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..b2cd71e0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Repository new file mode 100644 index 00000000..af5c9df5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@bk_ff_hmm_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/bk_ff_hmm_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/bk_ff_hmm_inf_engine.m new file mode 100644 index 00000000..c726a1fd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/bk_ff_hmm_inf_engine.m @@ -0,0 +1,21 @@ +function engine = bk_ff_hmm_inf_engine(bnet) +% BK_FF_HMM_INF_ENGINE Naive (HMM-based) implementation of fully factored form of Boyen-Koller +% engine = bk_ff_hmm_inf_engine(bnet) +% +% This is implemented on top of the forwards-backwards algo for HMMs, +% so it is *less* efficient than exact inference! However, it is good for educational purposes, +% because it illustrates the BK algorithm very clearly. + +[persistent_nodes, transient_nodes] = partition_dbn_nodes(bnet.intra, bnet.inter); +assert(isequal(sort(bnet.observed), transient_nodes)); +[engine.prior, engine.transmat] = dbn_to_hmm(bnet); + +ss = length(bnet.intra); + +engine.bel = []; +engine.bel_marginals = []; +engine.marginals = []; + + +engine = class(engine, 'bk_ff_hmm_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_init_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_init_bel.m new file mode 100644 index 00000000..2ab39d37 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_init_bel.m @@ -0,0 +1,5 @@ +function engine = dbn_init_bel(engine) +% DBN_INIT_BEL Compute the initial belief state (bk_ff_hmm) +% engine = dbn_init_bel(engine) + +engine.bel = engine.prior(:); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_marginal_from_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_marginal_from_bel.m new file mode 100644 index 00000000..a40d43b9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_marginal_from_bel.m @@ -0,0 +1,5 @@ +function marginal = dbn_marginal_from_bel(engine, i) +% DBN_MARGINAL_FROM_BEL Compute the marginal on a node given the current belief state (bk_ff_hmm) +% marginal = dbn_marginal_from_bel(engine, i) + +marginal = pot_to_marginal(engine.bel_marginals{i}); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_predict_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_predict_bel.m new file mode 100644 index 00000000..5195e53f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_predict_bel.m @@ -0,0 +1,19 @@ +function engine = dbn_predict_bel(engine, lag) +% DBN_PREDICT_BEL Predict the belief state 'lag' steps into the future (bk_ff_hmm) +% engine = dbn_predict_bel(engine, lag) +% 'lag' defaults to 1 + +if nargin < 2, lag = 1; end + +for d=1:lag + %newbel = engine.transmat' * engine.bel; + newbel = normalise(engine.transmat' * engine.bel); + + hnodes = engine.hnodes; + bnet = bnet_from_engine(engine); + ns = bnet.node_sizes; + [marginals, marginalsT] = project_joint_onto_marginals(newbel, hnodes, ns); + newbel = combine_marginals_into_joint(marginalsT, hnodes, ns); + engine.bel_marginals = marginalsT; + engine.bel = newbel; +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_update_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_update_bel.m new file mode 100644 index 00000000..8323b38a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_update_bel.m @@ -0,0 +1,19 @@ +function [engine, loglik] = dbn_update_bel(engine, evidence) +% DBN_UPDATE_BEL Update the belief state (bk_ff_hmm) +% [engine, loglik] = dbn_update_bel(engine, evidence) +% +% evidence{i,1} contains the evidence on node i in slice t-1 +% evidence{i,2} contains the evidence on node i in slice t + +oldbel = engine.bel; +bnet = bnet_from_engine(engine); +obslik = mk_hmm_obs_lik_vec(bnet, evidence); +[newbel, lik] = normalise((engine.transmat' * oldbel) .* obslik); +loglik = log(lik); + +hnodes = engine.hnodes; +ns = bnet.node_sizes; +[marginals, marginalsT] = project_joint_onto_marginals(newbel, hnodes, ns); +newbel = combine_marginals_into_joint(marginalsT, hnodes, ns); +engine.bel_marginals = marginalsT; +engine.bel = newbel; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_update_bel1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_update_bel1.m new file mode 100644 index 00000000..6280ee77 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/dbn_update_bel1.m @@ -0,0 +1,18 @@ +function [engine, loglik] = dbn_update_bel1(engine, evidence) +% DBN_UPDATE_BEL Update the initial belief state (bk_ff_hmm) +% [engine, loglik] = dbn_update_bel(engine, evidence) +% +% evidence{i} contains the evidence on node i in slice 1 + +oldbel = engine.bel; +bnet = bnet_from_engine(engine); +obslik = mk_hmm_obs_lik_vec1(bnet, evidence); +[newbel, lik] = normalise(oldbel .* obslik); +loglik = log(lik); + +hnodes = engine.hnodes; +ns = bnet.node_sizes; +[marginals, marginalsT] = project_joint_onto_marginals(newbel, hnodes, ns); +newbel = combine_marginals_into_joint(marginalsT, hnodes, ns); +engine.bel_marginals = marginalsT; +engine.bel = newbel; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/enter_evidence.m new file mode 100644 index 00000000..4719e0e9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/enter_evidence.m @@ -0,0 +1,60 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (bk_ff_hmm) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (not yet supported), else sum-product [0] +% filter - if 1, do filtering, else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +assert(~maximize); + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +onodes = bnet.observed; +hnodes = mysetdiff(1:ss, onodes); +T = size(evidence, 2); +assertBNT(~any(isemptycell(evidence(onodes,:)))); + +obslik = mk_hmm_obs_lik_mat(bnet, onodes, evidence); + +ns = bnet.node_sizes_slice; +ns(onodes) = 1; + +[gamma, loglik, marginals, marginalsT] = bk_ff_fb(engine.prior, engine.transmat, obslik, filter, hnodes, ns); + +for t=1:T + for i=hnodes(:)' + engine.marginals{i,t} = pot_to_marginal(marginalsT{i,t}); + end + for i=onodes(:)' + m.domain = i + (t-1)*ss; + m.T = 1; + engine.marginals{i,t} = m; + end +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/marginal_family.m new file mode 100644 index 00000000..fe58a0f8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/marginal_family.m @@ -0,0 +1,5 @@ +function m = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on the specified family (bk_ff_hmm) +% marginal = marginal_family(engine, i, t) + +error('bk_ff_hmm doesn''t support marginal_family'); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..8c2f9e81 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/marginal_nodes.m @@ -0,0 +1,11 @@ +function marginal = marginal_nodes(engine, nodes, t) +% MARGINAL_NODES Compute the marginal on the specified query nodes (bk_ff_hmm) +% marginal = marginal_nodes(engine, i, t) + +assert(length(nodes)==1); +i = nodes(end); +%assert(myismember(i, engine.hnodes)); +marginal = engine.marginals{i,t}; +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +marginal.domain = i + (t-1)*ss; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..b4ab4b45 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Entries @@ -0,0 +1,8 @@ +/bk_ff_fb.m/1.1.1.1/Wed May 29 15:59:56 2002// +/combine_marginals_into_joint.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_to_hmm.m/1.1.1.1/Wed May 29 15:59:56 2002// +/mk_hmm_obs_lik_mat.m/1.1.1.1/Wed May 29 15:59:56 2002// +/mk_hmm_obs_lik_vec.m/1.1.1.1/Wed May 29 15:59:56 2002// +/mk_hmm_obs_lik_vec1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/project_joint_onto_marginals.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..3b0b141c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/bk_ff_fb.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/bk_ff_fb.m new file mode 100644 index 00000000..ca41f77c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/bk_ff_fb.m @@ -0,0 +1,59 @@ +function [gamma, loglik, marginals, marginalsT] = bk_ff_fb(prior, transmat, obslik, filter_only, hnodes, ns) +% BK_FF_FB Fully factored Boyen-Koller version of forwards-backwards +% [gamma, loglik, marginals, marginalsT] = bk_ff_hmm(prior, transmat, obslik, filter_only, hnodes, ns) + +ss = length(ns); +S = length(prior); +T = size(obslik, 2); +marginals = cell(ss,T); +marginalsT = cell(ss,T); +scale = zeros(1,T); +alpha = zeros(S, T); + +transmat2 = transmat'; +for t=1:T + if t==1 + [alpha(:,t), scale(t)] = normalise(prior(:) .* obslik(:,t)); + else + [alpha(:,t), scale(t)] = normalise((transmat2 * alpha(:,t-1)) .* obslik(:,t)); + end + [marginals(:,t), marginalsT(:,t)] = project_joint_onto_marginals(alpha(:,t), hnodes, ns); + alpha(:,t) = combine_marginals_into_joint(marginalsT(:,t), hnodes, ns); + %fprintf('alpha t=%d\n', t); + %celldisp(marginals(1:8,t)) +end +loglik = sum(log(scale)); + +if filter_only + gamma = alpha; + return; +end + +beta = zeros(S,T); +gamma = zeros(S,T); +t = T; +beta(:,t) = ones(S,1); +gamma(:,t) = normalise(alpha(:,t) .* beta(:,t)); +[marginals(:,t), marginalsT(:,t)] = project_joint_onto_marginals(gamma(:,t), hnodes, ns); + +for t=T-1:-1:1 + b = beta(:,t+1) .* obslik(:,t+1); + beta(:,t) = normalise((transmat * b)); + [junk, tempT] = project_joint_onto_marginals(beta(:,t), hnodes, ns); + beta(:,t) = combine_marginals_into_joint(tempT, hnodes, ns); + %gamma(:,t) = normalise(alpha(:,t) .* beta(:,t)); + %[marginals(:,t), marginalsT(:,t)] = project_joint_onto_marginals(gamma(:,t), hnodes, ns); +end + +gamma2 = zeros(S,T); +for t=T-1:-1:1 + b = beta(:,t+1) .* obslik(:,t+1); + xi(:,:,t) = normalise((transmat .* (alpha(:,t) * b'))); + if t==T-1 + gamma2(:,T) = sum(xi(:,:,T-1), 1)'; + end + gamma2(:,t) = sum(xi(:,:,t), 2); + [marginals(:,t), marginalsT(:,t)] = project_joint_onto_marginals(gamma2(:,t), hnodes, ns); +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/combine_marginals_into_joint.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/combine_marginals_into_joint.m new file mode 100644 index 00000000..74065662 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/combine_marginals_into_joint.m @@ -0,0 +1,8 @@ +function joint = combine_marginals_into_joint(marginalsT, hnodes, ns) + +jointT = dpot(hnodes, ns(hnodes)); +for i=hnodes(:)' + jointT = multiply_by_pot(jointT, marginalsT{i}); +end +m = pot_to_marginal(jointT); +joint = m.T(:); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/dbn_to_hmm.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/dbn_to_hmm.m new file mode 100644 index 00000000..4a921bfd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/dbn_to_hmm.m @@ -0,0 +1,41 @@ +function [prior, transmat] = dbn_to_hmm(bnet) +% DBN_TO_HMM Compute the discrete HMM matrices from a simple DBN +% [prior, transmat] = dbn_to_hmm(bnet) + +onodes = bnet.observed; +ss = length(bnet.intra); +evidence = cell(1,2*ss); +hnodes = mysetdiff(1:ss, onodes); +prior = multiply_CPTs(bnet, [], hnodes, evidence); +transmat = multiply_CPTs(bnet, hnodes, hnodes+ss, evidence); +%obsmat1 = multiply_CPTs(bnet, hnodes, onodes, evidence); +%obsmat = multiply_CPTs(bnet, hnodes+ss, onodes+ss, evidence); +%obsmat1 = obsmat if the observation matrices are tied across slices + + + +%%%%%%%%%%%% + +function mat = multiply_CPTs(bnet, pdom, cdom, evidence) + +% MULTIPLY_CPTS Make a matrix Pr(Y|X), where X represents all the parents, and Y all the children +% We assume the children have no intra-connections. +% +% e.g., Consider the DBN with interconnectivity i->i', j->j',k', k->i',k' +% Then transition matrix = Pr(i,j,k -> i',j',k') = Pr(i,k->i') Pr(j->j') Pr(j,k->k') + +dom = [pdom cdom]; +ns = bnet.node_sizes; +bigpot = dpot(dom, ns(dom)); +for j=cdom(:)' + e = bnet.equiv_class(j); + fam = family(bnet.dag, j); + pot = convert_to_pot(bnet.CPD{e}, 'd', fam(:), evidence); + bigpot = multiply_by_pot(bigpot, pot); +end +psize = prod(ns(pdom)); +csize = prod(ns(cdom)); +T = pot_to_marginal(bigpot); +mat = reshape(T.T, [psize csize]); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_mat.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_mat.m new file mode 100644 index 00000000..b3e4c4cc --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_mat.m @@ -0,0 +1,34 @@ +function obslik = mk_hmm_obs_lik_mat(bnet, onodes, evidence) +% MK_HMM_OBS_LIK_MAT Make the observation likelihood matrix for all slices +% obslik = mk_hmm_obs_lik_mat(bnet, onodes, evidence) +% +% obslik(i,t) = Pr(Y(t) | X(t)=i) + +[ss T] = size(evidence); + +hnodes = mysetdiff(1:ss, onodes); +ns = bnet.node_sizes_slice; +ns(onodes) = 1; +Q = prod(ns(hnodes)); +obslik = zeros(Q,T); + +dom = 1:ss; +for t=1:T + bigpot = dpot(dom, ns(dom)); + for i=onodes(:)' + if t==1 + e = bnet.equiv_class(i,1); + fam = family(bnet.dag, i); + else + e = bnet.equiv_class(i,2); + fam = family(bnet.dag, i, 2) + ss*(t-2); + end + pot = convert_to_pot(bnet.CPD{e}, 'd', fam(:), evidence); + pot = set_domain_pot(pot, family(bnet.dag, i)); + bigpot = multiply_by_pot(bigpot, pot); + end + m = pot_to_marginal(bigpot); + obslik(:,t) = m.T(:); +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_vec.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_vec.m new file mode 100644 index 00000000..23247bd5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_vec.m @@ -0,0 +1,27 @@ +function obslik = mk_hmm_obs_lik_vec(bnet, evidence) +% MK_HMM_OBS_LIK_VEC Make the observation likelihood vector for one slice +% obslik = mk_obs_lik(bnet, evidence) +% +% obslik(i) = Pr(y(t) | X(t)=i) +% evidence{i,1} contains the evidence on node i in slice t-1 +% evidence{i,2} contains the evidence on node i in slice t + +ns = bnet.node_sizes; +ss = length(bnet.intra); +onodes = find(~isemptycell(evidence(:))); +hnodes = find(isemptycell(evidence(:))); +ens = ns; +ens(onodes) = 1; +Q = prod(ens(hnodes)); +obslik = zeros(1,Q); +dom = (1:ss)+ss; +bigpot = dpot(dom, ens(dom)); +onodes1 = find(~isemptycell(evidence(:,1))); +for i=onodes1(:)' + e = bnet.equiv_class(i,2); + fam = family(bnet.dag, i, 2); + pot = convert_to_pot(bnet.CPD{e}, 'd', fam, evidence); + bigpot = multiply_by_pot(bigpot, pot); +end +m = pot_to_marginal(bigpot); +obslik = m.T(:); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_vec1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_vec1.m new file mode 100644 index 00000000..6d0c1d35 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/mk_hmm_obs_lik_vec1.m @@ -0,0 +1,25 @@ +function obslik = mk_hmm_obs_lik_vec1(bnet, evidence) +% MK_HMM_OBS_LIK_VEC1 Make the observation likelihood vector for the first slice +% obslik = mk_hmm_obs_lik_vec1(engine, evidence) +% +% obslik(i) = Pr(y(1) | X(1)=i) +% evidence{i} contains the evidence on node i in slice 1 + +ns = bnet.node_sizes; +ss = length(ns); +onodes = find(~isemptycell(evidence(:))); +hnodes = find(isemptycell(evidence(:))); +ens = ns; +ens(onodes) = 1; +Q = prod(ens(hnodes)); +obslik = zeros(1,Q); +dom = (1:ss); +bigpot = dpot(dom, ens(dom)); +for i=onodes(:)' + e = bnet.equiv_class(i,1); + fam = family(bnet.dag, i); + pot = convert_to_pot(bnet.CPD{e}, 'd', fam(:), evidence); + bigpot = multiply_by_pot(bigpot, pot); +end +m = pot_to_marginal(bigpot); +obslik = m.T(:); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/project_joint_onto_marginals.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/project_joint_onto_marginals.m new file mode 100644 index 00000000..3f4036db --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_ff_hmm_inf_engine/private/project_joint_onto_marginals.m @@ -0,0 +1,11 @@ +function [marginals, marginalsT] = project_joint_onto_marginals(joint, hnodes, ns) + +ss = length(ns); +jointT = dpot(hnodes, ns(hnodes), joint); +marginalsT = cell(1, ss); +marginals = cell(1,ss); +for i=hnodes(:)' + marginalsT{i} = marginalize_pot(jointT, i); + m = pot_to_marginal(marginalsT{i}); + marginals{i} = m.T(:); +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Entries new file mode 100644 index 00000000..b071e13e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Entries @@ -0,0 +1,11 @@ +/bk_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_init_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_marginal_from_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_update_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/dbn_update_bel1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence.m/1.1.1.1/Sat Jan 11 18:13:50 2003// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Repository new file mode 100644 index 00000000..5e810837 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@bk_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/bk_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/bk_inf_engine.m new file mode 100644 index 00000000..2ca0350f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/bk_inf_engine.m @@ -0,0 +1,107 @@ +function engine = bk_inf_engine(bnet, varargin) +% BK_INF_ENGINE Boyen-Koller approximate inference algorithm for DBNs. +% +% In the BK algorithm, the belief state is represented as a product of marginals, +% even though the factors may not be independent. +% +% engine = bk_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - if a cell array, clusters{i} specifies the terms in the i'th factor. +% - 'exact' means create one cluster that contains all the nodes in a slice [exact] +% - 'ff' means create one cluster per node (ff = fully factorised). +% +% +% For details, see +% - "Tractable Inference for Complex Stochastic Processes", X. Boyen and D. Koller, UAI 98. +% - "Approximate learning of dynamic models", X. Boyen and D. Koller, NIPS 98. +% (The UAI98 paper discusses filtering and theory, and the NIPS98 paper discusses smoothing.) + +ss = length(bnet.intra); +% set default params +clusters = 'exact'; + + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'clusters', clusters = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end + end +end + +if strcmp(clusters, 'exact') + %clusters = { compute_interface_nodes(bnet.intra, bnet.inter) }; + clusters = { 1:ss }; +elseif strcmp(clusters, 'ff') + clusters = num2cell(1:ss); +end + + +% We need to insert the prior on the clusters in slice 1, +% and extract the posterior on the clusters in slice 2. +C = length(clusters); +clusters2 = cell(1,2*C); +clusters2(1:C) = clusters; +for c=1:C + clusters2{c+C} = clusters{c} + ss; +end + +onodes = bnet.observed; +obs_nodes = [onodes(:) onodes(:)+ss]; +engine.sub_engine = jtree_inf_engine(bnet, 'clusters', clusters2); + +engine.clq_ass_to_cluster = zeros(C, 2); +for c=1:C + engine.clq_ass_to_cluster(c,1) = clq_containing_nodes(engine.sub_engine, clusters{c}); + engine.clq_ass_to_cluster(c,2) = clq_containing_nodes(engine.sub_engine, clusters{c}+ss); +end +engine.clusters = clusters; + +engine.clq_ass_to_node = zeros(ss, 2); +for i=1:ss + engine.clq_ass_to_node(i, 1) = clq_containing_nodes(engine.sub_engine, i); + engine.clq_ass_to_node(i, 2) = clq_containing_nodes(engine.sub_engine, i+ss); +end + + + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes, 1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end + +engine.sub_engine1 = jtree_inf_engine(bnet1, 'clusters', clusters); + +engine.clq_ass_to_cluster1 = zeros(1,C); +for c=1:C + engine.clq_ass_to_cluster1(c) = clq_containing_nodes(engine.sub_engine1, clusters{c}); +end + +engine.clq_ass_to_node1 = zeros(1, ss); +for i=1:ss + engine.clq_ass_to_node1(i) = clq_containing_nodes(engine.sub_engine1, i); +end + +engine.clpot = []; % this is where we store the results between enter_evidence and marginal_nodes +engine.filter = []; +engine.maximize = []; +engine.T = []; + +engine.bel = []; +engine.bel_clpot = []; +engine.slice1 = []; +%engine.pot_type = 'cg'; +% hack for online inference so we can cope with hidden Gaussians and discrete +% it will not affect the pot type used in enter_evidence +engine.pot_type = determine_pot_type(bnet, onodes); + +engine = class(engine, 'bk_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_init_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_init_bel.m new file mode 100644 index 00000000..fa6a27de --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_init_bel.m @@ -0,0 +1,8 @@ +function engine = dbn_init_bel(engine) +% DBN_INIT_BEL Compute the initial belief state (bk) +% engine = dbn_init_bel(engine)) + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +evidence = cell(1,ss); +engine = dbn_update_bel1(engine, evidence); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_marginal_from_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_marginal_from_bel.m new file mode 100644 index 00000000..7e5a968d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_marginal_from_bel.m @@ -0,0 +1,18 @@ +function marginal = dbn_marginal_from_bel(engine, i) +% DBN_MARGINAL_FROM_BEL Compute the marginal on a node given the current belief state (bk) +% marginal = dbn_marginal_from_bel(engine, i) + +if engine.slice1 + j = i; + c = clq_containing_nodes(engine.sub_engine1, j); +else + bnet = bnet_from_engine(engine); + ss = length(bnet.intra); + j = i+ss; + c = clq_containing_nodes(engine.sub_engine, j); +end +assert(c >= 1); +bigpot = engine.bel_clpot{c}; + +pot = marginalize_pot(bigpot, j); +marginal = pot_to_marginal(pot); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_update_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_update_bel.m new file mode 100644 index 00000000..0c8e02b5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_update_bel.m @@ -0,0 +1,37 @@ +function [engine, loglik] = dbn_update_bel(engine, evidence) +% DBN_UPDATE_BEL Update the belief state (bk) +% [engine, loglik] = dbn_update_bel(engine, evidence) +% +% evidence{i,1} contains the evidence on node i in slice t-1 +% evidence{i,2} contains the evidence on node i in slice t + +oldbel = engine.bel; + +ss = size(evidence, 1); +bnet = bnet_from_engine(engine); +CPDpot = cell(1, ss); +for n=1:ss + fam = family(bnet.dag, n, 2); + e = bnet.equiv_class(n, 2); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), evidence); +end + +observed = ~isemptycell(evidence); +onodes2 = find(observed(:)); +clqs = [engine.clq_ass_to_cluster(:,1); engine.clq_ass_to_node(:,2)]; +pots = [oldbel(:); CPDpot(:)]; + +[clpot, loglik] = enter_soft_evidence(engine.sub_engine, clqs, pots, onodes2(:), engine.pot_type); + +C = length(engine.clusters); +newbel = cell(1,C); +for c=1:C + k = engine.clq_ass_to_cluster(c,2); + cl = engine.clusters{c}; + newbel{c} = marginalize_pot(clpot{k}, cl+ss); % extract slice 2 posterior + newbel{c} = set_domain_pot(newbel{c}, cl); % shift back to slice 1 for re-use as prior +end + +engine.bel = newbel; +engine.bel_clpot = clpot; +engine.slice1 = 0; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_update_bel1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_update_bel1.m new file mode 100644 index 00000000..a3b6cc79 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/dbn_update_bel1.m @@ -0,0 +1,30 @@ +function [engine, loglik] = dbn_update_bel1(engine, evidence) +% DBN_UPDATE_BEL1 Update the initial belief state (bk) +% engine = dbn_update_bel1(engine, evidence) +% +% evidence{i} has the evidence on node i for slice 1 + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +CPDpot = cell(1,ss); +t = 1; +for n=1:ss + fam = family(bnet.dag, n); + e = bnet.equiv_class(n, 1); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), evidence); +end + +onodes = find(~isemptycell(evidence)); + +[clpot, loglik] = enter_soft_evidence(engine.sub_engine1, engine.clq_ass_to_node1, CPDpot, onodes, engine.pot_type); + +C = length(engine.clusters); +newbel = cell(1,C); +for c=1:C + k = engine.clq_ass_to_cluster1(c); + newbel{c} = marginalize_pot(clpot{k}, engine.clusters{c}); +end + +engine.bel = newbel; +engine.bel_clpot = clpot; +engine.slice1 = 1; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/enter_evidence.m new file mode 100644 index 00000000..7008137b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/enter_evidence.m @@ -0,0 +1,48 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (bk) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% filter - if 1, do filtering, else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +[ss T] = size(evidence); +engine.filter = filter; +engine.maximize = maximize; +engine.T = T; + +if maximize + error('BK does not yet support max propagation') + % because it calls enter_soft_evidence, not enter_evidence +end + +observed_bitv = ~isemptycell(evidence); +onodes = find(observed_bitv); +bnet = bnet_from_engine(engine); +pot_type = determine_pot_type(bnet, onodes); +CPDpot = convert_dbn_CPDs_to_pots(bnet, evidence, pot_type); +[engine.clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed_bitv, pot_type, filter); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..1cbc634e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/enter_soft_evidence.m @@ -0,0 +1,88 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (bk) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +C = length(engine.clusters); +Q = length(cliques_from_engine(engine.sub_engine)); +Q1 = length(cliques_from_engine(engine.sub_engine1)); +clpot = cell(Q,T); +alpha = cell(C,T); + +% Forwards +% The method is a generalization of the following HMM equation: +% alpha(j,t) = normalise( (sum_i alpha(i,t-1) * transmat(i,j)) * obsmat(j,t) ) +% where alpha(j,t) = Pr(Q(t)=j | y(1:t)) +t = 1; +[clpot(1:Q1,t), logscale(t)] = enter_soft_evidence(engine.sub_engine1, engine.clq_ass_to_node1(:), ... + CPDpot(:,1), find(observed(:,1)), pot_type); +for c=1:C + k = engine.clq_ass_to_cluster1(c); + alpha{c,t} = marginalize_pot(clpot{k,t}, engine.clusters{c}); +end +% For filtering, clpot{1} contains evidence on slice 1 only + +%fprintf('alphas t=%d\n', t); +%for c=1:8 +% temp = pot_to_marginal(alpha{c,t}); +% temp.T +%end + +% clpot{t} contains evidence from slices t-1, t for t > 1 +clqs = [engine.clq_ass_to_cluster(:,1); engine.clq_ass_to_node(:,2)]; +for t=2:T + pots = [alpha(:,t-1); CPDpot(:,t)]; + [clpot(:,t), logscale(t)] = enter_soft_evidence(engine.sub_engine, clqs, pots, find(observed(:,t-1:t)), pot_type); + for c=1:C + k = engine.clq_ass_to_cluster(c,2); + cl = engine.clusters{c}; + alpha{c,t} = marginalize_pot(clpot{k,t}, cl+ss); % extract slice 2 posterior + alpha{c,t} = set_domain_pot(alpha{c,t}, cl); % shift back to slice 1 for re-use as prior + end + +end + +loglik = sum(logscale); + +if filter + return; +end + +% Backwards +% The method is a generalization of the following HMM equation: +% beta(i,t) = (sum_j transmat(i,j) * obsmat(j,t+1) * beta(j,t+1)) +% where beta(i,t) = Pr(y(t+1:T) | Q(t)=i) +t = T; +bnet = bnet_from_engine(engine); +beta = cell(C,T); +for c=1:C + beta{c,t} = mk_initial_pot(pot_type, engine.clusters{c} + ss, bnet.node_sizes(:), bnet.cnodes(:), ... + find(observed(:,t-1:t))); +end +for t=T-1:-1:1 + clqs = [engine.clq_ass_to_cluster(:,2); engine.clq_ass_to_node(:,2)]; + pots = [beta(:,t+1); CPDpot(:,t+1)]; + temp = enter_soft_evidence(engine.sub_engine, clqs, pots, find(observed(:,t:t+1)), pot_type); + for c=1:C + k = engine.clq_ass_to_cluster(c,1); + cl = engine.clusters{c}; + beta{c,t} = marginalize_pot(temp{k}, cl); % extract slice 1 + beta{c,t} = set_domain_pot(beta{c,t}, cl + ss); % shift fwd to slice 2 + end +end + +% Combine +% The method is a generalization of the following HMM equation: +% xi(i,j,t) = normalise( alpha(i,t) * transmat(i,j) * obsmat(j,t+1) * beta(j,t+1) ) +% where xi(i,j,t) = Pr(Q(t)=i, Q(t+1)=j | y(1:T)) +for t=1:T-1 + clqs = [engine.clq_ass_to_cluster(:); engine.clq_ass_to_node(:,2)]; + pots = [alpha(:,t); beta(:,t+1); CPDpot(:,t+1)]; + clpot(:,t+1) = enter_soft_evidence(engine.sub_engine, clqs, pots, find(observed(:,t:t+1)), pot_type); +end +% for smoothing, clpot{1} is undefined +for k=1:Q1 + clpot{k,1} = []; +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/marginal_family.m new file mode 100644 index 00000000..e948b836 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/marginal_family.m @@ -0,0 +1,25 @@ +function m = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on the specified family (bk) +% marginal = marginal_family(engine, i, t) + +% This is just like inf_engine/marginal_family, except when we call +% marginal_nodes, we provide a 4th argument, to tell it's a family. + +if nargin < 3, t = 1; end + +bnet = bnet_from_engine(engine); +if t==1 + m = marginal_nodes(engine, family(bnet.dag, i), t, 1); +else + ss = length(bnet.intra); + fam = family(bnet.dag, i+ss); + if any(fam<=ss) + % i has a parent in the preceeding slice + % Hence the lowest numbered slice containing the family is t-1 + m = marginal_nodes(engine, fam, t-1, 1); + else + % The family all fits inside slice t + % Hence shift the indexes back to slice 1 + m = marginal_nodes(engine, fam-ss, t, 1); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..30bf9a9d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/marginal_nodes.m @@ -0,0 +1,67 @@ +function marginal = marginal_nodes(engine, nodes, t, fam) +% MARGINAL_NODES Compute the marginal on the specified query nodes (bk) +% +% marginal = marginal_nodes(engine, i, t) +% returns Pr(X(i,t) | Y(1:T)), where X(i,t) is the i'th node in the t'th slice. +% If enter_evidence used filtering instead of smoothing, this will return Pr(X(i,t) | Y(1:t)). +% +% marginal = marginal_nodes(engine, query, t) +% returns Pr(X(query(1),t), ... X(query(end),t) | Y(1:T)), +% where X(q,t) is the q'th node in the t'th slice. If q > ss (slice size), this is equal +% to X(q mod ss, t+1). That is, 't' specifies the time slice of the earliest node. +% 'query' cannot span more than 2 time slices. +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3. + +if nargin < 3, t = 1; end +if nargin < 4, fam = 0; else fam = 1; end + + +% clpot{t} contains slice t-1 and t +% Example +% clpot #: 1 2 3 +% slices: 1 1,2 2,3 +% For filtering, we must take care not to take future evidence into account. +% For smoothing, clpot{1} does not exist. + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); + +nodes2 = nodes; +if ~engine.filter + if t < engine.T + slice = t+1; + else % earliest t is T, so all nodes fit in one slice + slice = engine.T; + nodes2 = nodes + ss; + end +else + if t == 1 + slice = 1; + else + if all(nodes<=ss) + slice = t; + nodes2 = nodes + ss; + elseif t == engine.T + slice = t; + else + slice = t + 1; + end + end +end + +if engine.filter & t==1 + c = clq_containing_nodes(engine.sub_engine1, nodes2, fam); +else + c = clq_containing_nodes(engine.sub_engine, nodes2, fam); +end +assert(c >= 1); +bigpot = engine.clpot{c, slice}; + +pot = marginalize_pot(bigpot, nodes2); +marginal = pot_to_marginal(pot); + +% we convert the domain to the unrolled numbering system +% so that update_ess extracts the right evidence. +marginal.domain = nodes+(t-1)*ss; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/update_engine.m new file mode 100644 index 00000000..b36833a1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@bk_inf_engine/update_engine.m @@ -0,0 +1,11 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (bk) +% engine = update_engine(engine, newCPDs) + +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +engine.sub_engine = update_engine(engine.sub_engine, newCPDs); + +bnet = bnet_from_engine(engine); +eclass1 = bnet.equiv_class(:,1); +engine.sub_engine1 = update_engine(engine.sub_engine1, newCPDs(1:max(eclass1))); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Entries new file mode 100644 index 00000000..4aa8d100 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Entries @@ -0,0 +1,12 @@ +/cbk_inf_engine.m/1.1.1.1/Mon Nov 22 22:15:34 2004// +/dbn_init_bel.m/1.1.1.1/Tue Jul 29 02:44:58 2003// +/dbn_marginal_from_bel.m/1.1.1.1/Tue Jul 29 02:44:58 2003// +/dbn_update_bel.m/1.1.1.1/Tue Jul 29 02:44:58 2003// +/dbn_update_bel1.m/1.1.1.1/Tue Jul 29 02:44:58 2003// +/enter_evidence.m/1.1.1.1/Mon Jan 12 20:53:54 2004// +/enter_soft_evidence.m/1.1.1.1/Wed Feb 4 07:42:38 2004// +/junk/1.1.1.1/Wed Nov 24 20:12:38 2004// +/marginal_family.m/1.1.1.1/Tue Jul 29 02:44:58 2003// +/marginal_nodes.m/1.1.1.1/Tue Dec 16 06:17:18 2003// +/update_engine.m/1.1.1.1/Tue Jul 29 02:44:58 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Repository new file mode 100644 index 00000000..67ff288b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@cbk_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/cbk_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/cbk_inf_engine.m new file mode 100644 index 00000000..20b4c4eb --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/cbk_inf_engine.m @@ -0,0 +1,175 @@ +function engine = cbk_inf_engine(bnet, varargin) +% Just the same as bk_inf_engine, but you can specify overlapping clusters. + +ss = length(bnet.intra); +% set default params +clusters = 'exact'; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'clusters', clusters = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end + end +end + +if strcmp(clusters, 'exact') + %clusters = { compute_interface_nodes(bnet.intra, bnet.inter) }; + clusters = { 1:ss }; +elseif strcmp(clusters, 'ff') + clusters = num2cell(1:ss); +end + + +% We need to insert the prior on the clusters in slice 1, +% and extract the posterior on the clusters in slice 2. +% We don't need to care about the separators, b/c they're subsets of the clusters. +C = length(clusters); +clusters2 = cell(1,2*C); +clusters2(1:C) = clusters; +for c=1:C + clusters2{c+C} = clusters{c} + ss; +end + +onodes = bnet.observed; +obs_nodes = [onodes(:) onodes(:)+ss]; +engine.sub_engine = jtree_inf_engine(bnet, 'clusters', clusters2); + +%FH >>> +%Compute separators. +ns = bnet.node_sizes(:,1); +ns(onodes) = 1; +[clusters, separators] = build_jt(clusters, 1:length(ns), ns); +S = length(separators); +engine.separators = separators; + +%Compute size of clusters. +cl_sizes = zeros(1,C); +for c=1:C + cl_sizes(c) = prod(ns(clusters{c})); +end + +%Assign separators to the smallest cluster subsuming them. +engine.cluster_ass_to_separator = zeros(S, 1); +for s=1:S + subsuming_clusters = []; + %find smallest cluster containing s + for c=1:C + if mysubset(separators{s}, clusters{c}) + subsuming_clusters(end+1) = c; + end + end + c = argmin(cl_sizes(subsuming_clusters)); + engine.cluster_ass_to_separator(s) = subsuming_clusters(c); +end + +%<<< FH + +engine.clq_ass_to_cluster = zeros(C, 2); +for c=1:C + engine.clq_ass_to_cluster(c,1) = clq_containing_nodes(engine.sub_engine, clusters{c}); + engine.clq_ass_to_cluster(c,2) = clq_containing_nodes(engine.sub_engine, clusters{c}+ss); +end +engine.clusters = clusters; + +engine.clq_ass_to_node = zeros(ss, 2); +for i=1:ss + engine.clq_ass_to_node(i, 1) = clq_containing_nodes(engine.sub_engine, i); + engine.clq_ass_to_node(i, 2) = clq_containing_nodes(engine.sub_engine, i+ss); +end + + + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes, 1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end + +engine.sub_engine1 = jtree_inf_engine(bnet1, 'clusters', clusters); + +engine.clq_ass_to_cluster1 = zeros(1,C); +for c=1:C + engine.clq_ass_to_cluster1(c) = clq_containing_nodes(engine.sub_engine1, clusters{c}); +end + +engine.clq_ass_to_node1 = zeros(1, ss); +for i=1:ss + engine.clq_ass_to_node1(i) = clq_containing_nodes(engine.sub_engine1, i); +end + +engine.clpot = []; % this is where we store the results between enter_evidence and marginal_nodes +engine.filter = []; +engine.maximize = []; +engine.T = []; + +engine.bel = []; +engine.bel_clpot = []; +engine.slice1 = []; +%engine.pot_type = 'cg'; +% hack for online inference so we can cope with hidden Gaussians and discrete +% it will not affect the pot type used in enter_evidence +engine.pot_type = determine_pot_type(bnet, onodes); + +engine = class(engine, 'cbk_inf_engine', inf_engine(bnet)); + + + + +function [cliques, seps, jt_size] = build_jt(cliques, vars, ns) +% BUILD_JT connects the cliques into a jtree, computes the respective +% separators and the size of the resulting jtree. +% +% [cliques, seps, jt_size] = build_jt(cliques, vars, ns) +% ns(i) has to hold the size of vars(i) +% vars has to be a superset of the union of cliques. + +%======== Compute the jtree with tool from BNT. This wants the vars to be 1:N. +%==== Map from nodes to their indices. +%disp('Computing jtree for cliques with vars and ns:'); +%cliques +%vars +%ns' + +inv_nodes = sparse(1,max(vars)); +N = length(vars); +for i=1:N + inv_nodes(vars(i)) = i; +end + +tmp_cliques = cell(1,length(cliques)); +%==== Temporarily map clique vars to their indices. +for i=1:length(cliques) + tmp_cliques{i} = inv_nodes(cliques{i}); +end + +%=== Compute the jtree, using BNT. +[jtree, root, B, w] = cliques_to_jtree(tmp_cliques, ns); + + +%======== Now, compute the separators between connected cliques and their weights. +seps = {}; +s_w = []; +[is,js] = find(jtree > 0); +for k=1:length(is) + i = is(k); j = js(k); + sep = vars(find(B(i,:) & B(j,:))); % intersect(cliques{i}, cliques{j}); + if i>j | length(sep) == 0, continue; end; + seps{end+1} = sep; + s_w(end+1) = prod(ns(inv_nodes(seps{end}))); +end + +cl_w = sum(w); +sep_w = sum(s_w); +assert(cl_w > sep_w, 'Weight of cliques must be bigger than weight of separators'); + +jt_size = cl_w + sep_w; +% jt.cliques = cliques; +% jt.seps = seps; +% jt.size = jt_size; +% jt.ns = ns'; +% jt; \ No newline at end of file diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_init_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_init_bel.m new file mode 100644 index 00000000..fa6a27de --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_init_bel.m @@ -0,0 +1,8 @@ +function engine = dbn_init_bel(engine) +% DBN_INIT_BEL Compute the initial belief state (bk) +% engine = dbn_init_bel(engine)) + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +evidence = cell(1,ss); +engine = dbn_update_bel1(engine, evidence); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_marginal_from_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_marginal_from_bel.m new file mode 100644 index 00000000..7e5a968d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_marginal_from_bel.m @@ -0,0 +1,18 @@ +function marginal = dbn_marginal_from_bel(engine, i) +% DBN_MARGINAL_FROM_BEL Compute the marginal on a node given the current belief state (bk) +% marginal = dbn_marginal_from_bel(engine, i) + +if engine.slice1 + j = i; + c = clq_containing_nodes(engine.sub_engine1, j); +else + bnet = bnet_from_engine(engine); + ss = length(bnet.intra); + j = i+ss; + c = clq_containing_nodes(engine.sub_engine, j); +end +assert(c >= 1); +bigpot = engine.bel_clpot{c}; + +pot = marginalize_pot(bigpot, j); +marginal = pot_to_marginal(pot); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_update_bel.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_update_bel.m new file mode 100644 index 00000000..0c8e02b5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_update_bel.m @@ -0,0 +1,37 @@ +function [engine, loglik] = dbn_update_bel(engine, evidence) +% DBN_UPDATE_BEL Update the belief state (bk) +% [engine, loglik] = dbn_update_bel(engine, evidence) +% +% evidence{i,1} contains the evidence on node i in slice t-1 +% evidence{i,2} contains the evidence on node i in slice t + +oldbel = engine.bel; + +ss = size(evidence, 1); +bnet = bnet_from_engine(engine); +CPDpot = cell(1, ss); +for n=1:ss + fam = family(bnet.dag, n, 2); + e = bnet.equiv_class(n, 2); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), evidence); +end + +observed = ~isemptycell(evidence); +onodes2 = find(observed(:)); +clqs = [engine.clq_ass_to_cluster(:,1); engine.clq_ass_to_node(:,2)]; +pots = [oldbel(:); CPDpot(:)]; + +[clpot, loglik] = enter_soft_evidence(engine.sub_engine, clqs, pots, onodes2(:), engine.pot_type); + +C = length(engine.clusters); +newbel = cell(1,C); +for c=1:C + k = engine.clq_ass_to_cluster(c,2); + cl = engine.clusters{c}; + newbel{c} = marginalize_pot(clpot{k}, cl+ss); % extract slice 2 posterior + newbel{c} = set_domain_pot(newbel{c}, cl); % shift back to slice 1 for re-use as prior +end + +engine.bel = newbel; +engine.bel_clpot = clpot; +engine.slice1 = 0; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_update_bel1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_update_bel1.m new file mode 100644 index 00000000..a3b6cc79 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/dbn_update_bel1.m @@ -0,0 +1,30 @@ +function [engine, loglik] = dbn_update_bel1(engine, evidence) +% DBN_UPDATE_BEL1 Update the initial belief state (bk) +% engine = dbn_update_bel1(engine, evidence) +% +% evidence{i} has the evidence on node i for slice 1 + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +CPDpot = cell(1,ss); +t = 1; +for n=1:ss + fam = family(bnet.dag, n); + e = bnet.equiv_class(n, 1); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), evidence); +end + +onodes = find(~isemptycell(evidence)); + +[clpot, loglik] = enter_soft_evidence(engine.sub_engine1, engine.clq_ass_to_node1, CPDpot, onodes, engine.pot_type); + +C = length(engine.clusters); +newbel = cell(1,C); +for c=1:C + k = engine.clq_ass_to_cluster1(c); + newbel{c} = marginalize_pot(clpot{k}, engine.clusters{c}); +end + +engine.bel = newbel; +engine.bel_clpot = clpot; +engine.slice1 = 1; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/enter_evidence.m new file mode 100644 index 00000000..f6057ba2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/enter_evidence.m @@ -0,0 +1,48 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% this is unchanged from bk_inf_engine. +% ENTER_EVIDENCE Add the specified evidence to the network (bk) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% filter - if 1, do filtering, else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +[ss T] = size(evidence); +engine.filter = filter; +engine.maximize = maximize; +engine.T = T; + +if maximize + error('BK does not yet support max propagation') + % because it calls enter_soft_evidence, not enter_evidence +end + +observed_bitv = ~isemptycell(evidence); +onodes = find(observed_bitv); +bnet = bnet_from_engine(engine); +pot_type = determine_pot_type(bnet, onodes); +CPDpot = convert_dbn_CPDs_to_pots(bnet, evidence, pot_type); +[engine.clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed_bitv, pot_type, filter); \ No newline at end of file diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..e102a11e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/enter_soft_evidence.m @@ -0,0 +1,115 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (bk) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +C = length(engine.clusters); +S = length(engine.separators); +Q = length(cliques_from_engine(engine.sub_engine)); +Q1 = length(cliques_from_engine(engine.sub_engine1)); +clpot = cell(Q,T); +alpha = cell(C,T); + +% Forwards +% The method is a generalization of the following HMM equation: +% alpha(j,t) = normalise( (sum_i alpha(i,t-1) * transmat(i,j)) * obsmat(j,t) ) +% where alpha(j,t) = Pr(Q(t)=j | y(1:t)) +t = 1; +[clpot(1:Q1,t), logscale(t)] = enter_soft_evidence(engine.sub_engine1, engine.clq_ass_to_node1(:), ... + CPDpot(:,1), find(observed(:,1)), pot_type); +for c=1:C + k = engine.clq_ass_to_cluster1(c); + alpha{c,t} = marginalize_pot(clpot{k,t}, engine.clusters{c}); +end + +%=== FH: For each separator s, divide some cluster potential by s's potential +alpha_orig = alpha(:,t); +for s=1:S + c = engine.cluster_ass_to_separator(s); + alpha{c,t} = divide_by_pot(alpha{c,t}, marginalize_pot(alpha_orig{c}, engine.separators{s})); +end + +% For filtering, clpot{1} contains evidence on slice 1 only + +%fprintf('alphas t=%d\n', t); +%for c=1:8 +% temp = pot_to_marginal(alpha{c,t}); +% temp.T +%end + +% clpot{t} contains evidence from slices t-1, t for t > 1 +clqs = [engine.clq_ass_to_cluster(:,1); engine.clq_ass_to_node(:,2)]; +for t=2:T + pots = [alpha(:,t-1); CPDpot(:,t)]; + [clpot(:,t), logscale(t)] = enter_soft_evidence(engine.sub_engine, clqs, pots, find(observed(:,t-1:t)), pot_type); + for c=1:C + k = engine.clq_ass_to_cluster(c,2); + cl = engine.clusters{c}; + alpha{c,t} = marginalize_pot(clpot{k,t}, cl+ss); % extract slice 2 posterior + alpha{c,t} = set_domain_pot(alpha{c,t}, cl); % shift back to slice 1 for re-use as prior + end + %=== FH: For each separator s, divide some cluster potential by s's potential + alpha_orig = alpha(:,t); + for s=1:S + c = engine.cluster_ass_to_separator(s); + alpha{c,t} = divide_by_pot(alpha{c,t}, marginalize_pot(alpha_orig{c}, engine.separators{s})); + end +end + +loglik = sum(logscale); + +if filter + return; +end + +% Backwards +% The method is a generalization of the following HMM equation: +% beta(i,t) = (sum_j transmat(i,j) * obsmat(j,t+1) * beta(j,t+1)) +% where beta(i,t) = Pr(y(t+1:T) | Q(t)=i) +t = T; +bnet = bnet_from_engine(engine); +beta = cell(C,T); +for c=1:C + beta{c,t} = mk_initial_pot(pot_type, engine.clusters{c} + ss, bnet.node_sizes(:), bnet.cnodes(:), ... + find(observed(:,t-1:t))); +end +%=== FH: For each separator s, divide some cluster potential by s's potential +beta_orig = beta(:,t); +for s=1:S + c = engine.cluster_ass_to_separator(s); + beta{c,t} = divide_by_pot(beta{c,t}, marginalize_pot(beta_orig{c}, engine.separators{s}+ss)); +end + +for t=T-1:-1:1 + clqs = [engine.clq_ass_to_cluster(:,2); engine.clq_ass_to_node(:,2)]; + pots = [beta(:,t+1); CPDpot(:,t+1)]; + temp = enter_soft_evidence(engine.sub_engine, clqs, pots, find(observed(:,t:t+1)), pot_type); + for c=1:C + k = engine.clq_ass_to_cluster(c,1); + cl = engine.clusters{c}; + beta{c,t} = marginalize_pot(temp{k}, cl); % extract slice 1 + beta{c,t} = set_domain_pot(beta{c,t}, cl + ss); % shift fwd to slice 2 + end + %=== FH: For each separator s, divide some cluster potential by s's potential + beta_orig = beta(:,t); + for s=1:S + c = engine.cluster_ass_to_separator(s); + beta{c,t} = divide_by_pot(beta{c,t}, marginalize_pot(beta_orig{c}, engine.separators{s}+ss)); + end +end + +% Combine +% The method is a generalization of the following HMM equation: +% xi(i,j,t) = normalise( alpha(i,t) * transmat(i,j) * obsmat(j,t+1) * beta(j,t+1) ) +% where xi(i,j,t) = Pr(Q(t)=i, Q(t+1)=j | y(1:T)) +for t=1:T-1 + clqs = [engine.clq_ass_to_cluster(:); engine.clq_ass_to_node(:,2)]; + pots = [alpha(:,t); beta(:,t+1); CPDpot(:,t+1)]; + clpot(:,t+1) = enter_soft_evidence(engine.sub_engine, clqs, pots, find(observed(:,t:t+1)), pot_type); +end +% for smoothing, clpot{1} is undefined +for k=1:Q1 + clpot{k,1} = []; +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/junk b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/junk new file mode 100644 index 00000000..31e9cab8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/junk @@ -0,0 +1,176 @@ +function engine = cbk_inf_engine(bnet, varargin) +% Just the same as bk_inf_engine, but you can specify overlapping clusters. + +ss = length(bnet.intra); +% set default params +clusters = 'exact'; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'clusters', clusters = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end + end +end + +if strcmp(clusters, 'exact') + %clusters = { compute_interface_nodes(bnet.intra, bnet.inter) }; + clusters = { 1:ss }; +elseif strcmp(clusters, 'ff') + clusters = num2cell(1:ss); +end + + +% We need to insert the prior on the clusters in slice 1, +% and extract the posterior on the clusters in slice 2. +% We don't need to care about the separators, b/c they're subsets of the clusters. +C = length(clusters); +clusters2 = cell(1,2*C); +clusters2(1:C) = clusters; +for c=1:C + clusters2{c+C} = clusters{c} + ss; +end + +onodes = bnet.observed; +obs_nodes = [onodes(:) onodes(:)+ss]; +engine.sub_engine = jtree_inf_engine(bnet, 'clusters', clusters2); + +%FH >>> +%Compute separators. +ns = bnet.node_sizes(:,1); +ns(onodes) = 1; +[clusters, separators] = build_jt(clusters, 1:length(ns), ns); +S = length(separators); +engine.separators = separators; + +%Compute size of clusters. +cl_sizes = zeros(1,C); +for c=1:C + cl_sizes(c) = prod(ns(clusters{c})); +end + +%Assign separators to the smallest cluster subsuming them. +engine.cluster_ass_to_separator = zeros(S, 1); +for s=1:S + subsuming_clusters = []; + %find smaunk + + for c=1:C + if mysubset(separators{s}, clusters{c}) + subsuming_clusters(end+1) = c; + end + end + c = argmin(cl_sizes(subsuming_clusters)); + engine.cluster_ass_to_separator(s) = subsuming_clusters(c); +end + +%<<< FH + +engine.clq_ass_to_cluster = zeros(C, 2); +for c=1:C + engine.clq_ass_to_cluster(c,1) = clq_containing_nodes(engine.sub_engine, clusters{c}); + engine.clq_ass_to_cluster(c,2) = clq_containing_nodes(engine.sub_engine, clusters{c}+ss); +end +engine.clusters = clusters; + +engine.clq_ass_to_node = zeros(ss, 2); +for i=1:ss + engine.clq_ass_to_node(i, 1) = clq_containing_nodes(engine.sub_engine, i); + engine.clq_ass_to_node(i, 2) = clq_containing_nodes(engine.sub_engine, i+ss); +end + + + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes, 1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end + +engine.sub_engine1 = jtree_inf_engine(bnet1, 'clusters', clusters); + +engine.clq_ass_to_cluster1 = zeros(1,C); +for c=1:C + engine.clq_ass_to_cluster1(c) = clq_containing_nodes(engine.sub_engine1, clusters{c}); +end + +engine.clq_ass_to_node1 = zeros(1, ss); +for i=1:ss + engine.clq_ass_to_node1(i) = clq_containing_nodes(engine.sub_engine1, i); +end + +engine.clpot = []; % this is where we store the results between enter_evidence and marginal_nodes +engine.filter = []; +engine.maximize = []; +engine.T = []; + +engine.bel = []; +engine.bel_clpot = []; +engine.slice1 = []; +%engine.pot_type = 'cg'; +% hack for online inference so we can cope with hidden Gaussians and discrete +% it will not affect the pot type used in enter_evidence +engine.pot_type = determine_pot_type(bnet, onodes); + +engine = class(engine, 'cbk_inf_engine', inf_engine(bnet)); + + + + +function [cliques, seps, jt_size] = build_jt(cliques, vars, ns) +% BUILD_JT connects the cliques into a jtree, computes the respective +% separators and the size of the resulting jtree. +% +% [cliques, seps, jt_size] = build_jt(cliques, vars, ns) +% ns(i) has to hold the size of vars(i) +% vars has to be a superset of the union of cliques. + +%======== Compute the jtree with tool from BNT. This wants the vars to be 1:N. +%==== Map from nodes to their indices. +%disp('Computing jtree for cliques with vars and ns:'); +%cliques +%vars +%ns' + +inv_nodes = sparse(1,max(vars)); +N = length(vars); +for i=1:N + inv_nodes(vars(i)) = i; +end + +tmp_cliques = cell(1,length(cliques)); +%==== Temporarily map clique vars to their indices. +for i=1:length(cliques) + tmp_cliques{i} = inv_nodes(cliques{i}); +end + +%=== Compute the jtree, using BNT. +[jtree, root, B, w] = cliques_to_jtree(tmp_cliques, ns); + + +%======== Now, compute the separators between connected cliques and their weights. +seps = {}; +s_w = []; +[is,js] = find(jtree > 0); +for k=1:length(is) + i = is(k); j = js(k); + sep = vars(find(B(i,:) & B(j,:))); % intersect(cliques{i}, cliques{j}); + if i>j | length(sep) == 0, continue; end; + seps{end+1} = sep; + s_w(end+1) = prod(ns(inv_nodes(seps{end}))); +end + +cl_w = sum(w); +sep_w = sum(s_w); +assert(cl_w > sep_w, 'Weight of cliques must be bigger than weight of separators'); + +jt_size = cl_w + sep_w; +% jt.cliques = cliques; +% jt.seps = seps; +% jt.size = jt_size; +% jt.ns = ns'; +% jt; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/marginal_family.m new file mode 100644 index 00000000..e948b836 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/marginal_family.m @@ -0,0 +1,25 @@ +function m = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on the specified family (bk) +% marginal = marginal_family(engine, i, t) + +% This is just like inf_engine/marginal_family, except when we call +% marginal_nodes, we provide a 4th argument, to tell it's a family. + +if nargin < 3, t = 1; end + +bnet = bnet_from_engine(engine); +if t==1 + m = marginal_nodes(engine, family(bnet.dag, i), t, 1); +else + ss = length(bnet.intra); + fam = family(bnet.dag, i+ss); + if any(fam<=ss) + % i has a parent in the preceeding slice + % Hence the lowest numbered slice containing the family is t-1 + m = marginal_nodes(engine, fam, t-1, 1); + else + % The family all fits inside slice t + % Hence shift the indexes back to slice 1 + m = marginal_nodes(engine, fam-ss, t, 1); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..30bf9a9d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/marginal_nodes.m @@ -0,0 +1,67 @@ +function marginal = marginal_nodes(engine, nodes, t, fam) +% MARGINAL_NODES Compute the marginal on the specified query nodes (bk) +% +% marginal = marginal_nodes(engine, i, t) +% returns Pr(X(i,t) | Y(1:T)), where X(i,t) is the i'th node in the t'th slice. +% If enter_evidence used filtering instead of smoothing, this will return Pr(X(i,t) | Y(1:t)). +% +% marginal = marginal_nodes(engine, query, t) +% returns Pr(X(query(1),t), ... X(query(end),t) | Y(1:T)), +% where X(q,t) is the q'th node in the t'th slice. If q > ss (slice size), this is equal +% to X(q mod ss, t+1). That is, 't' specifies the time slice of the earliest node. +% 'query' cannot span more than 2 time slices. +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3. + +if nargin < 3, t = 1; end +if nargin < 4, fam = 0; else fam = 1; end + + +% clpot{t} contains slice t-1 and t +% Example +% clpot #: 1 2 3 +% slices: 1 1,2 2,3 +% For filtering, we must take care not to take future evidence into account. +% For smoothing, clpot{1} does not exist. + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); + +nodes2 = nodes; +if ~engine.filter + if t < engine.T + slice = t+1; + else % earliest t is T, so all nodes fit in one slice + slice = engine.T; + nodes2 = nodes + ss; + end +else + if t == 1 + slice = 1; + else + if all(nodes<=ss) + slice = t; + nodes2 = nodes + ss; + elseif t == engine.T + slice = t; + else + slice = t + 1; + end + end +end + +if engine.filter & t==1 + c = clq_containing_nodes(engine.sub_engine1, nodes2, fam); +else + c = clq_containing_nodes(engine.sub_engine, nodes2, fam); +end +assert(c >= 1); +bigpot = engine.clpot{c, slice}; + +pot = marginalize_pot(bigpot, nodes2); +marginal = pot_to_marginal(pot); + +% we convert the domain to the unrolled numbering system +% so that update_ess extracts the right evidence. +marginal.domain = nodes+(t-1)*ss; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/update_engine.m new file mode 100644 index 00000000..b36833a1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine/update_engine.m @@ -0,0 +1,11 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (bk) +% engine = update_engine(engine, newCPDs) + +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +engine.sub_engine = update_engine(engine.sub_engine, newCPDs); + +bnet = bnet_from_engine(engine); +eclass1 = bnet.equiv_class(:,1); +engine.sub_engine1 = update_engine(engine.sub_engine1, newCPDs(1:max(eclass1))); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Entries new file mode 100644 index 00000000..fda92284 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Entries @@ -0,0 +1,8 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/ff_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/filter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/smooth_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Repository new file mode 100644 index 00000000..56fb63d3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@ff_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..dd45ee37 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Entries @@ -0,0 +1,4 @@ +/enter_soft_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..5582c6dd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@ff_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence.m new file mode 100644 index 00000000..1e2acffb --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence.m @@ -0,0 +1,59 @@ +function [marginals, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (bk_ff) +% [marginals, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +assert(pot_type == 'd'); +[ss T] = size(CPDpot); +fwd = cell(ss,T); +hnodes = engine.hnodes(:)'; +onodes = engine.onodes(:)'; +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +onodes2 = [onodes onodes+ss]; +ns(onodes2) = 1; + +logscale = zeros(1,T); +local_logscale = zeros(1,length(hnodes)); + +t = 1; +for i=hnodes + fwd{i,t} = CPDpot{i,t}; +end +for i=onodes + p = parents(bnet.dag, i); + assert(length(p)==1); + ev = marginalize_pot(CPDpot{i,t}, p); + fwd{p,t} = multiply_by_pot(fwd{p,t}, ev); +end +for i=hnodes + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); +end +logscale(t) = sum(local_logscale); + +for t=2:T + for i=hnodes + ps = parents(bnet.dag, i+ss); + assert(all(ps<=ss)); % in previous slice + prior = CPDpot{i,t}; + for p=ps(:)' + prior = multiply_by_pot(prior, fwd{p,t-1}); + end + fwd{i,t} = marginalize_pot(prior, i+ss); + fwd{i,t} = set_domain_pot(fwd{i,t}, i); + end + for i=onodes + p = parents(bnet.dag, i); + assert(length(p)==1); + temp = pot_to_marginal(CPDpot{i,t}); + ev = dpot(p, ns(p), temp.T); + fwd{p,t} = multiply_by_pot(fwd{p,t}, ev); + end + + for i=hnodes + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); + end + logscale(t) = sum(local_logscale); +end + +marginals = fwd; +loglik = sum(logscale); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence1.m new file mode 100644 index 00000000..b4ff1a02 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence1.m @@ -0,0 +1,94 @@ +function [marginals, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (ff) +% [marginals, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +assert(pot_type == 'd'); +[ss T] = size(CPDpot); +fwd = cell(ss,T); +hnodes = engine.hnodes(:)'; +onodes = engine.onodes(:)'; +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +onodes2 = [onodes onodes+ss]; +ns(onodes2) = 1; + +logscale = zeros(1,T); +H = length(hnodes); +local_logscale = zeros(1,ss); + +obschild = zeros(1,ss); +for i=hnodes + ocs = myintersect(children(bnet.dag, i), onodes); + assert(length(ocs)==1); + obschild(i) = ocs(1); +end + +t = 1; +for i=hnodes + fwd{i,t} = CPDpot{i,t}; + c = obschild(i); + temp = pot_to_marginal(CPDpot{c,t}); + ev = dpot(i, ns(i), temp.T); + fwd{i,t} = multiply_by_pot(fwd{i,t}, ev); + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); +end +logscale(t) = sum(local_logscale); + +for t=2:T + for i=hnodes + ps = parents(bnet.dag, i+ss); + assert(all(ps<=ss)); % in previous slice + prior = CPDpot{i,t}; + for p=ps(:)' + prior = multiply_by_pot(prior, fwd{p,t-1}); + end + fwd{i,t} = marginalize_pot(prior, i+ss); + fwd{i,t} = set_domain_pot(fwd{i,t}, i); + c = obschild(i); + temp = pot_to_marginal(CPDpot{c,t}); + ev = dpot(i, ns(i), temp.T); + fwd{i,t} = multiply_by_pot(fwd{i,t}, ev); + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); + end + logscale(t) = sum(local_logscale); +end + +loglik = sum(logscale); + + +if filter + marginals = fwd; + return; +end + +back = cell(ss,T); +t = T; +for i=hnodes + back{i,t} = dpot(i, ns(i)); + back{i,t} = set_domain_pot(back{i,t}, i+ss); +end +for t=T-1:-1:1 + for i=hnodes + pot = CPDpot{i,t+1}; + pot = multiply_by_pot(pot, back{i,t+1}); + c = obschild(i); + temp = pot_to_marginal(CPDpot{c,t+1}); + ev = dpot(i, ns(i), temp.T); + pot = multiply_by_pot(pot, ev); + back{i,t} = marginalize_pot(pot, i); + back{i,t} = normalize_pot(back{i,t}); + back{i,t} = set_domain_pot(back{i,t}, i+ss); + end +end + + + +% COMBINE +for t=1:T + for i=hnodes + back{i,t} = set_domain_pot(back{i,t}, i); + fwd{i,t} = multiply_by_pot(fwd{i,t}, back{i,t}); + marginals{i,t} = normalize_pot(fwd{i,t}); + %fwdback{i,t} = normalize_pot(multiply_pots(fwd{i,t}, back{i,t})); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/marginal_family.m new file mode 100644 index 00000000..99813571 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/marginal_family.m @@ -0,0 +1,38 @@ +function marginal = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on the specified family (ff) +% marginal = marginal_family(engine, i, t) + +if nargin < 3, t = 1; end + +% The method is similar to the following HMM equation: +% xi(i,j,t) = normalise( alpha(i,t) * transmat(i,j) * obsmat(j,t+1) * beta(j,t+1) ) +% where xi(i,j,t) = Pr(Q(t)=i, Q(t+1)=j | y(1:T)) + +bnet = bnet_from_engine(engine); + +if myismember(i, engine.onodes) + ps = parents(bnet.dag, i); + p = ps(1); + marginal = pot_to_marginal(engine.marginals{p,t}); + marginal.domain = [p i]; + return; +end + +if t==1 + marginal = pot_to_marginal(engine.marginals{i,t}); + return; +end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +pot = engine.CPDpot{i,t}; +c = engine.obschild(i); +pot = multiply_by_pot(pot, engine.CPDpot{c,t}); +pot = multiply_by_pot(pot, engine.back{i,t}); +ps = parents(bnet.dag, i+ss); +for p=ps(:)' + pot = multiply_by_pot(pot, engine.fwd{p,t-1}); +end +marginal = pot_to_marginal(normalize_pot(pot)); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_evidence.m new file mode 100644 index 00000000..7fa9fa9b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_evidence.m @@ -0,0 +1,62 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (ff) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or +% column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (not yet supported), else sum-product [0] +% filter - if 1, do filtering, else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +assert(~maximize); + + +[ss T] = size(evidence); +observed = ~isemptycell(evidence); +bnet = bnet_from_engine(engine); +%pot_type = determine_pot_type(find(observed(:,1)), bnet.cnodes_slice, bnet.intra); +pot_type = determine_pot_type(bnet, observed); +% we assume we can use the same pot_type in all slices + +CPDpot = convert_dbn_CPDs_to_pots(bnet, evidence, pot_type); + +% Now convert CPDs on observed nodes to be potentials just on their parents +assert(pot_type == 'd'); +onodes = bnet.observed(:); +ns = bnet.node_sizes_slice; +ns(onodes) = 1; +for t=1:T + for i=onodes + p = parents(bnet.dag, i); + %CPDpot{i,t} = set_domain_pot(CPDpot{i,t}, p); % leaves size too long + temp = pot_to_marginal(CPDpot{i,t}); + CPDpot{i,t} = dpot(p, ns(p), temp.T); % assumes pot_type = d + end +end + +[engine.marginals, engine.fwd, engine.back, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter); + +engine.CPDpot = CPDpot; +engine.filter = filter; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..db16f39b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_soft_evidence.m @@ -0,0 +1,11 @@ +function [marginals, fwd, back, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (ff) +% [marginals, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +if filter + [fwd, loglik] = filter_evidence(engine, CPDpot, observed, pot_type); + marginals = fwd; + back = []; +else + [marginals, fwd, back, loglik] = smooth_evidence(engine, CPDpot, observed, pot_type); +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/ff_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/ff_inf_engine.m new file mode 100644 index 00000000..ade26106 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/ff_inf_engine.m @@ -0,0 +1,44 @@ +function engine = ff_inf_engine(bnet) +% FF_INF_ENGINE Factored frontier inference engine for DBNs +% engine = ff_inf_engine(bnet) +% +% The model must be topologically isomorphic to an HMM. +% In addition, each hidden node is assumed to have at most one observed child, +% and each observed child is assumed to have exactly one hidden parent. +% +% For details of this algorithm, see +% "The Factored Frontier Algorithm for Approximate Inference in DBNs", +% Kevin Murphy and Yair Weiss, UAI 2001. +% +% THIS IS HIGHLY EXPERIMENTAL CODE! + +ss = length(bnet.intra); +onodes = bnet.observed; +hnodes = mysetdiff(1:ss, onodes); + +[persistent_nodes, transient_nodes] = partition_dbn_nodes(bnet.intra, bnet.inter); +assert(isequal(onodes, transient_nodes)); +assert(isequal(hnodes, persistent_nodes)); + +engine.onodes = onodes; +engine.hnodes = hnodes; +engine.marginals = []; +engine.fwd = []; +engine.back = []; +engine.CPDpot = []; +engine.filter = []; + +obschild = zeros(1,ss); +for i=engine.hnodes(:)' + %ocs = myintersect(children(bnet.dag, i), onodes); + ocs = children(bnet.intra, i); + assert(length(ocs) <= 1); + if length(ocs)==1 + obschild(i) = ocs(1); + end +end +engine.obschild = obschild; + + +engine = class(engine, 'ff_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/filter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/filter_evidence.m new file mode 100644 index 00000000..3dd4835c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/filter_evidence.m @@ -0,0 +1,48 @@ +function [fwd, loglik] = filter_evidence(engine, CPDpot, observed, pot_type) +% [fwd, loglik] = filter_evidence(engine, CPDpot, observed, pot_type) (ff) + +[ss T] = size(CPDpot); +fwd = cell(ss,T); +hnodes = engine.hnodes(:)'; +onodes = engine.onodes(:)'; +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +onodes2 = [onodes onodes+ss]; +ns(onodes2) = 1; + +logscale = zeros(1,T); +H = length(hnodes); +local_logscale = zeros(1,ss); + +t = 1; +for i=hnodes + fwd{i,t} = CPDpot{i,t}; + c = engine.obschild(i); + if c > 0 + fwd{i,t} = multiply_by_pot(fwd{i,t}, CPDpot{c, t}); + end + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); +end +logscale(t) = sum(local_logscale); + +for t=2:T + for i=hnodes + ps = parents(bnet.dag, i+ss); + assert(all(ps<=ss)); % in previous slice + prior = CPDpot{i,t}; + for p=ps(:)' + prior = multiply_by_pot(prior, fwd{p,t-1}); + end + fwd{i,t} = marginalize_pot(prior, i+ss); + fwd{i,t} = set_domain_pot(fwd{i,t}, i); + c = engine.obschild(i); + if c > 0 + fwd{i,t} = multiply_by_pot(fwd{i,t}, CPDpot{c,t}); + end + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); + end + logscale(t) = sum(local_logscale); +end + +loglik = sum(logscale); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_family.m new file mode 100644 index 00000000..bdc783b7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_family.m @@ -0,0 +1,44 @@ +function marginal = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on the specified family (ff) +% marginal = marginal_family(engine, i, t) + + +if engine.filter + error('can''t currently use marginal_family when filtering with ff'); +end + +if nargin < 3, t = 1; end + +% The method is similar to the following HMM equation: +% xi(i,j,t) = normalise( alpha(i,t) * transmat(i,j) * obsmat(j,t+1) * beta(j,t+1) ) +% where xi(i,j,t) = Pr(Q(t)=i, Q(t+1)=j | y(1:T)) + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); + +if myismember(i, engine.onodes) + ps = parents(bnet.dag, i); + p = ps(1); + marginal = pot_to_marginal(engine.marginals{ps(1),t}); + fam = ([ps i]) + (t-1)*ss; +elseif t==1 + marginal = pot_to_marginal(engine.marginals{i,t}); + fam = i + (t-1)*ss; +else + pot = engine.CPDpot{i,t}; + c = engine.obschild(i); + if c>0 + pot = multiply_by_pot(pot, engine.CPDpot{c,t}); + end + pot = multiply_by_pot(pot, engine.back{i,t}); + ps = parents(bnet.dag, i+ss); + for p=ps(:)' + pot = multiply_by_pot(pot, engine.fwd{p,t-1}); + end + marginal = pot_to_marginal(normalize_pot(pot)); + fam = ([ps i+ss]) + (t-2)*ss; +end + +% we convert the domain to the unrolled numbering system +% so that update_ess extracts the right evidence. +marginal.domain = fam; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..f65a3bec --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_nodes.m @@ -0,0 +1,20 @@ +function marginal = marginal_nodes(engine, nodes, t) +% MARGINAL_NODES Compute the marginal on the specified query nodes (ff) +% marginal = marginal_nodes(engine, i, t) +% returns Pr(X(i,t) | Y(1:T)), where X(i,t) is the i'th node in the t'th slice. +% If enter_evidence used filtering instead of smoothing, this will return Pr(X(i,t) | Y(1:t)). + +if nargin < 3, t = 1; end +assert(length(nodes)==1); +i = nodes(end); +if myismember(i, engine.hnodes) + marginal = pot_to_marginal(engine.marginals{i,t}); +else + marginal = pot_to_marginal(dpot(i, 1, 1)); % observed +end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +% we convert the domain to the unrolled numbering system +% so that update_ess extracts the right evidence. +marginal.domain = nodes+(t-1)*ss; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/smooth_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/smooth_evidence.m new file mode 100644 index 00000000..782f07aa --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/smooth_evidence.m @@ -0,0 +1,89 @@ +function [marginals, fwd, back, loglik] = smooth_evidence(engine, CPDpot, observed, pot_type) +% [marginals, fwd, back, loglik] = smooth_evidence(engine, CPDpot, observed, pot_type) (ff) + +error('ff smoothing is broken'); + +[ss T] = size(CPDpot); +fwd = cell(ss,T); +hnodes = engine.hnodes(:)'; +onodes = engine.onodes(:)'; +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +onodes2 = [onodes onodes+ss]; +ns(onodes2) = 1; + +logscale = zeros(1,T); +H = length(hnodes); +local_logscale = zeros(1,ss); + +t = 1; +for i=hnodes + fwd{i,t} = CPDpot{i,t}; + c = engine.obschild(i); + if 0 % c > 0 + fwd{i,t} = multiply_by_pot(fwd{i,t}, CPDpot{c, t}); + end + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); +end +logscale(t) = sum(local_logscale); + +for t=2:T + for i=hnodes + ps = parents(bnet.dag, i+ss); + assert(all(ps<=ss)); % in previous slice + prior = CPDpot{i,t}; + for p=ps(:)' + prior = multiply_by_pot(prior, fwd{p,t-1}); + end + fwd{i,t} = marginalize_pot(prior, i+ss); + fwd{i,t} = set_domain_pot(fwd{i,t}, i); + c = engine.obschild(i); + if 0 % c > 0 + fwd{i,t} = multiply_by_pot(fwd{i,t}, CPDpot{c,t}); + end + [fwd{i,t}, local_logscale(i)] = normalize_pot(fwd{i,t}); + end + logscale(t) = sum(local_logscale); +end + +loglik = sum(logscale); + +back = cell(ss,T); +t = T; +for i=hnodes + pot = dpot(i, ns(i)); + cs = children(bnet.intra, i); + for c=cs(:)' + pot = multiply_pots(pot, CPDpot{c,t}); + end + back{i,t} = marginalize_pot(pot, i); + back{i,t} = normalize_pot(back{i,t}); + back{i,t} = set_domain_pot(back{i,t}, i+ss); +end +for t=T-1:-1:1 + for i=hnodes + pot = dpot(i, ns(i)); + cs = children(bnet.inter, i); + for c=cs(:)' + pot = multiply_pots(pot, back{c,t+1}); + pot = multiply_pots(pot, CPDpot{c,t+1}); + end + cs = children(bnet.intra, i); + for c=cs(:)' + pot = multiply_pots(pot, CPDpot{c,t}); + end + back{i,t} = marginalize_pot(pot, i); + back{i,t} = normalize_pot(back{i,t}); + back{i,t} = set_domain_pot(back{i,t}, i+ss); + end +end + + +% COMBINE +for t=1:T + for i=hnodes + back{i,t} = set_domain_pot(back{i,t}, i); + fwd{i,t} = multiply_by_pot(fwd{i,t}, back{i,t}); + marginals{i,t} = normalize_pot(fwd{i,t}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Entries new file mode 100644 index 00000000..79297e05 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/frontier_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/set_fwdback.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Repository new file mode 100644 index 00000000..0e85f66f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@frontier_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/enter_evidence.m new file mode 100644 index 00000000..bd30a57c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/enter_evidence.m @@ -0,0 +1,44 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (frontier) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (not yet supported), else sum-product [0] +% filter - if 1, do filtering, else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +assert(~maximize); + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +onodes = find(~isemptycell(evidence)); +cnodes = unroll_set(bnet.cnodes(:), ss, T); +pot_type = determine_pot_type(bnet, onodes); + +CPDpot = convert_dbn_CPDs_to_pots(bnet, evidence, pot_type); + +[engine.fwdback, loglik, engine.fwd_frontier, engine.back_frontier] = ... + enter_soft_evidence(engine, CPDpot, onodes, pot_type, filter); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..8da339c7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/enter_soft_evidence.m @@ -0,0 +1,142 @@ +function [fwdback, loglik, fwd_frontier, back_frontier] = enter_soft_evidence(engine, CPD, onodes, pot_type, filter) +% ENTER_SOFT_EVIDENCE Add soft evidence to network (frontier) +% [fwdback, loglik] = enter_soft_evidence(engine, CPDpot, onodes, filter) + +if nargin < 3, filter = 0; end + +[ss T] = size(CPD); +bnet = bnet_from_engine(engine); +ns = repmat(bnet.node_sizes_slice(:), 1, T); +cnodes = unroll_set(bnet.cnodes(:), ss, T); + +% FORWARDS +fwd = cell(ss,T); +ll = zeros(1,T); +S = 2*ss; % num. intermediate frontiers to get from t to t+1 +frontier = cell(S,T); + +% Start with empty frontier, and add each node in slice 1 +init = mk_initial_pot(pot_type, [], ns, cnodes, onodes); +t = 1; +s = 1; +j = 1; +frontier{s,t} = update(init, j, 1, CPD{j}, engine.fdom1{s}, pot_type, ns, cnodes, onodes); +fwd{j} = frontier{s,t}; +for s=2:ss + j = s; % add node j at step s + frontier{s,t} = update(frontier{s-1,t}, j, 1, CPD{j}, engine.fdom1{s}, pot_type, ns, cnodes, onodes); + fwd{j} = frontier{s,t}; +end +frontier{S,t} = frontier{ss,t}; +[frontier{S,t}, ll(1)] = normalize_pot(frontier{S,t}); + +% Now move frontier from slice to slice +OPS = engine.ops; +add = OPS>0; +nodes = [zeros(S,1) unroll_set(abs(OPS(:)), ss, T-1)]; +for t=2:T + offset = (t-2)*ss; + for s=1:S + if s==1 + prev_ndx = (t-2)*S + S; % S,t-1 + else + prev_ndx = (t-1)*S + s-1; % s-1,t + end + j = nodes(s,t); + frontier{s,t} = update(frontier{prev_ndx}, j, add(s), CPD{j}, engine.fdom{s}+offset, pot_type, ns, cnodes, onodes); + if add(s) + fwd{j} = frontier{s,t}; + end + end + [frontier{S,t}, ll(t)] = normalize_pot(frontier{S,t}); +end +loglik = sum(ll); + + +fwd_frontier = frontier; + +if filter + fwdback = fwd; + return; +end + + +% BACKWARDS +back = cell(ss,T); +add = ~add; % forwards add = backwards remove +frontier = cell(S,T+1); +t = T; +dom = (1:ss) + (t-1)*ss; +frontier{1,T+1} = mk_initial_pot(pot_type, dom, ns, cnodes, onodes); % all 1s for last slice +for t=T:-1:2 + offset = (t-2)*ss; + for s=S:-1:1 % reverse order + if s==S + prev_ndx = t*S + 1; % 1,t+1 + else + prev_ndx = (t-1)*S + (s+1); % s+1,t + end + j = nodes(s,t); + if ~add(s) + back{j} = frontier{prev_ndx}; % save frontier before removing + end + frontier{s,t} = rev_update(frontier{prev_ndx}, t, s, j, add(s), CPD{j}, engine.fdom{s}+offset, pot_type, ns, cnodes, onodes); + end + frontier{1,t} = normalize_pot(frontier{1,t}); +end +% Remove each node in first slice until left with empty set +t = 1; +frontier{ss+1,t} = frontier{1,2}; +add = 0; +for s=ss:-1:1 + j = s; % remove node j at step s + back{j} = frontier{s+1,t}; + frontier{s,t} = rev_update(frontier{s+1,t}, t, s, j, add, CPD{j}, 1:s, pot_type, ns, cnodes, onodes); +end + +% COMBINE +for t=1:T + for i=1:ss + %fwd{i,t} = multiply_by_pot(fwd{i,t}, back{i,t}); + %fwdback{i,t} = normalize_pot(fwd{i,t}); + fwdback{i,t} = normalize_pot(multiply_pots(fwd{i,t}, back{i,t})); + end +end + +back_frontier = frontier; + +%%%%%%%%%% +function new_frontier = update(old_frontier, j, add, CPD, newdom, pot_type, ns, cnodes, onodes) + +if add + new_frontier = mk_initial_pot(pot_type, newdom, ns, cnodes, onodes); + new_frontier = multiply_by_pot(new_frontier, old_frontier); + new_frontier = multiply_by_pot(new_frontier, CPD); +else + new_frontier = marginalize_pot(old_frontier, mysetdiff(domain_pot(old_frontier), j)); +end + + +%%%%%% +function new_frontier = rev_update(old_frontier, t, s, j, add, CPD, junk, pot_type, ns, cnodes, onodes) + +olddom = domain_pot(old_frontier); +assert(isequal(junk, olddom)); + +if add + % add: extend domain to include j by multiplying by 1 + newdom = myunion(olddom, j); + new_frontier = mk_initial_pot(pot_type, newdom, ns, cnodes, onodes); + new_frontier = multiply_by_pot(new_frontier, old_frontier); + %fprintf('t=%d, s=%d, add %d to %s to make %s\n', t, s, j, num2str(olddom), num2str(newdom)); +else + % remove: multiply in CPT and then marginalize out j + % parents of j are guaranteed to be in old_frontier, else couldn't have added j on fwds pass + old_frontier = multiply_by_pot(old_frontier, CPD); + newdom = mysetdiff(olddom, j); + new_frontier = marginalize_pot(old_frontier, newdom); + %newdom2 = domain_pot(new_frontier); + %fprintf('t=%d, s=%d, rem %d from %s to make %s\n', t, s, j, num2str(olddom), num2str(newdom2)); +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/frontier_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/frontier_inf_engine.m new file mode 100644 index 00000000..fd550579 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/frontier_inf_engine.m @@ -0,0 +1,121 @@ +function engine = frontier_inf_engine(bnet) +% FRONTIER_INF_ENGINE Inference engine for DBNs which which uses the frontier algorithm. +% engine = frontier_inf_engine(bnet) +% +% The frontier algorithm extends the forwards-backwards algorithm to DBNs in the obvious way, +% maintaining a joint distribution (frontier) over all the nodes in a time slice. +% When all the hidden nodes in the DBN are persistent (have children in the next time slice), +% its theoretical running time is often similar to that of the junction tree algorithm, +% although in practice, this algorithm seems to very slow (at least in matlab). +% However, it is extremely simple to describe and implement. +% +% Suppose there are n binary nodes per slice, so the frontier takes O(2^n) space. +% Each time step takes between O(n 2^{n+1}) and O(n 2^{2n}) operations, depending on the graph structure. +% The lower bound is achieved by a set of n independent chains, as in a factorial HMM. +% The upper bound is achieved by a set of n fully interconnected chains, as in an HMM. +% +% The factor of n arises because we need to multiply in each CPD from slice t+1. +% The second factor depends on the size of the frontier to which we add the new node. +% In an FHMM, once we have added X(i,t+1), we can marginalize out X(i,t) from the frontier, since +% no other nodes depend on it; hence the frontier never contains more than n+1 nodes. +% In a fully coupled HMM, we must leave X(i,t) in the frontier until all X(j,t+1) have been +% added; hence the frontier will contain 2*n nodes at its peak. +% +% For details, see +% "The Factored Frontier Algorithm for Approximate Inference in DBNs", +% Kevin Murphy and Yair Weiss, UAI 01. + +ns = bnet.node_sizes_slice; +onodes = bnet.observed; +ns(onodes) = 1; +ss = length(bnet.intra); + +[engine.ops, engine.fdom] = best_first_frontier_seq(ns, bnet.dag); +engine.ops1 = 1:ss; + +engine.fwdback = []; +engine.fwd_frontier = []; +engine.back_frontier = []; + +engine.fdom1 = cell(1,ss); +for s=1:ss + engine.fdom1{s} = 1:s; +end + +engine = class(engine, 'frontier_inf_engine', inf_engine(bnet)); + + +%%%%%%%%% + +function [ops, frontier_set] = best_first_frontier_seq(ns, dag) +% BEST_FIRST_FRONTIER_SEQ Do a greedy search for the sequence of additions/removals to the frontier. +% [ops, frontier_set] = best_first_frontier_seq(ns, dag) +% +% We maintain 3 sets: the frontier (F), the right set (R), and the left set (L). +% The invariant is that the nodes in R are d-separated from L given F. +% We start with slice 1 in F and slice 2 in R. +% The goal is to move slice 1 from F to L, and slice 2 from R to F, so as to minimize the size +% of the frontier at each step, where the size(F) = product of the node-sizes of nodes in F. +% A node may be removed (from F to L) if it has no children in R. +% A node may be added (from R to F) if its parents are in F. +% +% ns(i) = num. discrete values node i can take on (i=1..ss, where ss = slice size) +% dag is the (2*ss) x (2*ss) adjacency matrix for the 2-slice DBN. + +% Example: +% +% 4 9 +% ^ ^ +% | | +% 2 -> 7 +% ^ ^ +% | | +% 1 -> 6 +% | | +% v v +% 3 -> 8 +% | | +% v V +% 5 10 +% +% ops = -4, -5, 6, -1, 7, -2, 8, -3, 9, 10 + +ss = length(ns); +ns = [ns(:)' ns(:)']; +ops = zeros(1,ss); +L = []; F = 1:ss; R = (1:ss)+ss; +frontier_set = cell(1,2*ss); +for s=1:2*ss + remcost = inf*ones(1,2*ss); + %disp(['L: ' num2str(L) ', F: ' num2str(F) ', R: ' num2str(R)]); + maybe_removable = myintersect(F, 1:ss); + for n=maybe_removable(:)' + cs = children(dag, n); + if isempty(myintersect(cs, R)) + remcost(n) = prod(ns(mysetdiff(F, n))); + end + end + %remcost + if any(remcost < inf) + n = argmin(remcost); + ops(s) = -n; + L = myunion(L, n); + F = mysetdiff(F, n); + else + addcost = inf*ones(1,2*ss); + for n=R(:)' + ps = parents(dag, n); + if mysubset(ps, F) + addcost(n) = prod(ns(myunion(F, [ps n]))); + end + end + %addcost + assert(any(addcost < inf)); + n = argmin(addcost); + ops(s) = n; + R = mysetdiff(R, n); + F = myunion(F, n); + end + %fprintf('op at step %d = %d\n\n', s, ops(s)); + frontier_set{s} = F; +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/marginal_family.m new file mode 100644 index 00000000..4d28263b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/marginal_family.m @@ -0,0 +1,7 @@ +function marginal = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on node i in slice t and its parents (frontier) +% marginal = marginal_family(engine, i, t) + +bnet = bnet_from_engine(engine); +fam = family(bnet.dag, i, t); +marginal = pot_to_marginal(normalize_pot(marginalize_pot(engine.fwdback{i,t}, fam))); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..898d1130 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/marginal_nodes.m @@ -0,0 +1,21 @@ +function marginal = marginal_nodes(engine, nodes, t) +% MARGINAL_NODES Compute the marginal on the specified query nodes (frontier) +% marginal = marginal_nodes(engine, nodes, t) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' cannot span more than 2 time slices. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end +assert(length(nodes)==1); +i = nodes(1); +bigpot = engine.fwdback{i,t}; +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +nodes = nodes + (t-1)*ss; +%if t > 1, nodes = nodes + ss; end +marginal = pot_to_marginal(marginalize_pot(bigpot, nodes)); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/set_fwdback.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/set_fwdback.m new file mode 100644 index 00000000..6752d827 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@frontier_inf_engine/set_fwdback.m @@ -0,0 +1,8 @@ +function engine = set_fwdback(engine, fb) +% SET_FWDBACK Set the field 'fwdback', which contains the frontiers after propagation +% engine = set_fwdback(engine, fb) +% +% This is used by frontier_fast_inf_engine/enter_evidence +% as a workaround for Matlab's annoying privacy control + +engine.fwdback = fb; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Entries new file mode 100644 index 00000000..e1ab6d00 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Entries @@ -0,0 +1,9 @@ +/enter_evidence.m/1.2/Sat Sep 17 17:00:30 2005// +/find_mpe.m/1.1.1.1/Thu Jun 20 00:18:24 2002// +/fwdback_twoslice.m/1.1/Sat Nov 26 01:24:09 2005// +/hmm_inf_engine.m/1.1.1.1/Thu Nov 14 20:05:36 2002// +/marginal_family.m/1.1.1.1/Thu Nov 14 20:05:36 2002// +/marginal_nodes.m/1.1.1.1/Thu Nov 14 20:03:28 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/Old//// +D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Repository new file mode 100644 index 00000000..b7392efa --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@hmm_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..528b5843 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Entries @@ -0,0 +1,4 @@ +/dhmm_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..f82b2bea --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@hmm_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/dhmm_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/dhmm_inf_engine.m new file mode 100644 index 00000000..2b0c8810 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/dhmm_inf_engine.m @@ -0,0 +1,34 @@ +function engine = dhmm_inf_engine(bnet, onodes) +% DHMM_INF_ENGINE Inference engine for discrete DBNs which uses the forwards-backwards algorithm. +% engine = dhmm_inf_engine(bnet, onodes) +% +% 'onodes' specifies which nodes are observed; these must be leaves, and can be discrete or continuous. +% The remaining nodes are all hidden, and must be discrete. +% The DBN is converted to an HMM, with a single meganode, but which may have factored obs. + +ss = length(bnet.intra); +hnodes = mysetdiff(1:ss, onodes); +evidence = cell(ss, 2); +ns = bnet.node_sizes; +Q = prod(ns(hnodes)); +tmp = dpot_to_table(compute_joint_pot(bnet, hnodes, evidence)); +engine.startprob = reshape(tmp, Q, 1); +tmp = dpot_to_table(compute_joint_pot(bnet, [hnodes hnodes+ss], evidence)); +engine.transprob = mk_stochastic(reshape(tmp, Q, Q)); +engine.obsprob = cell(1, length(onodes)); +for i=1:length(onodes) + tmp = dpot_to_table(compute_joint_pot(bnet, [hnodes onodes(i)], evidence)); + O = ns(onodes(i)); + engine.obsprob{i} = mk_stochastic(reshape(tmp, Q, O)); +end + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.gamma = []; +engine.xi = []; + +engine.onodes = onodes; +engine.hnodes = hnodes; +engine.maximize = []; + +engine = class(engine, 'dhmm_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/marginal_family.m new file mode 100644 index 00000000..681e1591 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/marginal_family.m @@ -0,0 +1,31 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (hmm) +% marginal = marginal_nodes(engine, i, t, add_ev) +% + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +if t==1 + fam = family(bnet.dag, i); + bigpot = engine.one_slice_marginal{t}; + nodes = fam; +else + fam = family(bnet.dag, i+ss); + if any(fam <= ss) % family spans 2 slices + bigpot = engine.two_slice_marginal{t-1}; % t-1 and t + nodes = fam + (t-2)*ss; + else + bigpot = engine.one_slice_marginal{t}; + nodes = fam-ss + (t-1)*ss; + end +end + +marginal = pot_to_marginal(marginalize_pot(bigpot, nodes, engine.maximize)); + +if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/marginal_nodes.m new file mode 100644 index 00000000..4b8d6008 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/Old/marginal_nodes.m @@ -0,0 +1,30 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (hmm) +% marginal = marginal_nodes(engine, nodes, t, add_ev) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' cannot span more than 2 time slices. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +if all(nodes <= ss) + bigpot = engine.one_slice_marginal{t}; +else + bigpot = engine.two_slice_marginal{t}; +end + +nodes = nodes + (t-1)*ss; +marginal = pot_to_marginal(marginalize_pot(bigpot, nodes, engine.maximize)); + +if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/enter_evidence.m new file mode 100644 index 00000000..8af97edf --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/enter_evidence.m @@ -0,0 +1,64 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (hmm) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (not yet supported), else sum-product [0] +% filter - if 1, does filtering, else smoothing [0] +% oneslice - 1 means only compute marginals on nodes within a single slice [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; +oneslice = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + case 'oneslice', oneslice = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +[ss T] = size(evidence); +engine.maximize = maximize; +engine.evidence = evidence; +bnet = bnet_from_engine(engine); +engine.node_sizes = repmat(bnet.node_sizes_slice(:), [1 T]); + +obs_bitv = ~isemptycell(evidence(:)); +bitv = reshape(obs_bitv, ss, T); +for t=1:T + onodes = find(bitv(:,t)); + if ~isequal(onodes, bnet.observed(:)) + error(['dbn was created assuming observed nodes per slice were '... + num2str(bnet.observed(:)') ' but the evidence in slice ' num2str(t) ... + ' has observed nodes ' num2str(onodes(:)')]); + end +end + +obslik = mk_hmm_obs_lik_matrix(engine, evidence); + +%[alpha, beta, gamma, loglik, xi] = fwdback(engine.startprob, engine.transprob, obslik, ... +[alpha, beta, gamma, loglik, xi] = fwdback_twoslice(engine, engine.startprob,... + engine.transprob, obslik, ... + 'maximize', maximize, 'fwd_only', filter, ... + 'compute_xi', ~oneslice); + +engine.one_slice_marginal = gamma; % gamma(:,t) for t=1:T +if ~oneslice + Q = size(gamma,1); + engine.two_slice_marginal = reshape(xi, [Q*Q T-1]); % xi(:,t) for t=1:T-1 +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/find_mpe.m new file mode 100644 index 00000000..ba2cba74 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/find_mpe.m @@ -0,0 +1,16 @@ +function mpe = find_mpe(engine, evidence) +% FIND_MPE Find the most probable explanation (Viterbi) +% mpe = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% + +obslik = mk_hmm_obs_lik_matrix(engine, evidence); +path = viterbi_path(engine.startprob, engine.transprob, obslik); +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes_slice; +ns(bnet.observed) = 1; +ass = ind2subv(ns, path); +mpe = num2cell(ass'); +mpe(bnet.observed,:) = evidence(bnet.observed,:); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/fwdback_twoslice.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/fwdback_twoslice.m new file mode 100644 index 00000000..0565e727 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/fwdback_twoslice.m @@ -0,0 +1,198 @@ +function [alpha, beta, gamma, loglik, xi, gamma2] = fwdback_twoslice(engine, init_state_distrib, transmat, obslik, varargin) +% FWDBACK Compute the posterior probs. in an HMM using the forwards backwards algo. +% +% [alpha, beta, gamma, loglik, xi, gamma2] = fwdback(init_state_distrib, transmat, obslik, ...) +% +% Notation: +% Y(t) = observation, Q(t) = hidden state, M(t) = mixture variable (for MOG outputs) +% A(t) = discrete input (action) (for POMDP models) +% +% INPUT: +% init_state_distrib(i) = Pr(Q(1) = i) +% transmat(i,j) = Pr(Q(t) = j | Q(t-1)=i) +% or transmat{a}(i,j) = Pr(Q(t) = j | Q(t-1)=i, A(t-1)=a) if there are discrete inputs +% obslik(i,t) = Pr(Y(t)| Q(t)=i) +% (Compute obslik using eval_pdf_xxx on your data sequence first.) +% +% Optional parameters may be passed as 'param_name', param_value pairs. +% Parameter names are shown below; default values in [] - if none, argument is mandatory. +% +% For HMMs with MOG outputs: if you want to compute gamma2, you must specify +% 'obslik2' - obslik(i,j,t) = Pr(Y(t)| Q(t)=i,M(t)=j) [] +% 'mixmat' - mixmat(i,j) = Pr(M(t) = j | Q(t)=i) [] +% +% For HMMs with discrete inputs: +% 'act' - act(t) = action performed at step t +% +% Optional arguments: +% 'fwd_only' - if 1, only do a forwards pass and set beta=[], gamma2=[] [0] +% 'scaled' - if 1, normalize alphas and betas to prevent underflow [1] +% 'maximize' - if 1, use max-product instead of sum-product [0] +% +% OUTPUTS: +% alpha(i,t) = p(Q(t)=i | y(1:t)) (or p(Q(t)=i, y(1:t)) if scaled=0) +% beta(i,t) = p(y(t+1:T) | Q(t)=i)*p(y(t+1:T)|y(1:t)) (or p(y(t+1:T) | Q(t)=i) if scaled=0) +% gamma(i,t) = p(Q(t)=i | y(1:T)) +% loglik = log p(y(1:T)) +% xi(i,j,t-1) = p(Q(t-1)=i, Q(t)=j | y(1:T)) +% gamma2(j,k,t) = p(Q(t)=j, M(t)=k | y(1:T)) (only for MOG outputs) +% +% If fwd_only = 1, these become +% alpha(i,t) = p(Q(t)=i | y(1:t)) +% beta = [] +% gamma(i,t) = p(Q(t)=i | y(1:t)) +% xi(i,j,t-1) = p(Q(t-1)=i, Q(t)=j | y(1:t)) +% gamma2 = [] +% +% Note: we only compute xi if it is requested as a return argument, since it can be very large. +% Similarly, we only compute gamma2 on request (and if using MOG outputs). +% +% Examples: +% +% [alpha, beta, gamma, loglik] = fwdback(pi, A, multinomial_prob(sequence, B)); +% +% [B, B2] = mixgauss_prob(data, mu, Sigma, mixmat); +% [alpha, beta, gamma, loglik, xi, gamma2] = fwdback(pi, A, B, 'obslik2', B2, 'mixmat', mixmat); + + +if nargout >= 5, compute_xi = 1; else compute_xi = 0; end +if nargout >= 6, compute_gamma2 = 1; else compute_gamma2 = 0; end + +[obslik2, mixmat, fwd_only, scaled, act, maximize, compute_xi, compute_gamma2] = process_options(varargin, 'obslik2', [], 'mixmat', [], 'fwd_only', 0, 'scaled', 1, 'act', [], 'maximize', 0, 'compute_xi', compute_xi, 'compute_gamma2', compute_gamma2); + + +[Q T] = size(obslik); + +if isempty(obslik2) + compute_gamma2 = 0; +end + +if isempty(act) + act = ones(1,T); + transmat = { transmat } ; +end + +scale = ones(1,T); + +% scale(t) = Pr(O(t) | O(1:t-1)) = 1/c(t) as defined by Rabiner (1989). +% Hence prod_t scale(t) = Pr(O(1)) Pr(O(2)|O(1)) Pr(O(3) | O(1:2)) = Pr(O(1), ... ,O(T)) +% or log P = sum_t log scale(t). +% Rabiner suggests multiplying beta(t) by scale(t), but we can instead +% normalise beta(t) - the constants will cancel when we compute gamma. + +loglik = 0; + +alpha = zeros(Q,T); +gamma = zeros(Q,T); +if compute_xi + xi = zeros(Q,Q,T-1); +else + xi = []; +end + + +%%%%%%%%% Forwards %%%%%%%%%% + +t = 1; +alpha(:,1) = init_state_distrib(:) .* obslik(:,t); +if scaled + %[alpha(:,t), scale(t)] = normaliseC(alpha(:,t)); + [alpha(:,t), scale(t)] = normalise(alpha(:,t)); +end +if scaled, assert(approxeq(sum(alpha(:,t)),1)), end +for t=2:T + %trans = transmat(:,:,act(t-1))'; + trans = transmat{act(t-1)}; + if maximize + m = max_mult(trans', alpha(:,t-1)); + %A = repmat(alpha(:,t-1), [1 Q]); + %m = max(trans .* A, [], 1); + else + m = trans' * alpha(:,t-1); + end + alpha(:,t) = m(:) .* obslik(:,t); + if scaled + %[alpha(:,t), scale(t)] = normaliseC(alpha(:,t)); + [alpha(:,t), scale(t)] = normalise(alpha(:,t)); + end + if compute_xi & fwd_only % useful for online EM + %xi(:,:,t-1) = normaliseC((alpha(:,t-1) * obslik(:,t)') .* trans); + xi(:,:,t-1) = normalise((alpha(:,t-1) * obslik(:,t)') .* trans); + end + if scaled, assert(approxeq(sum(alpha(:,t)),1)), end +end +if scaled + if any(scale==0) + loglik = -inf; + else + loglik = sum(log(scale)); + end +else + loglik = log(sum(alpha(:,T))); +end + +if fwd_only + gamma = alpha; + beta = []; + gamma2 = []; + return; +end + + +%%%%%%%%% Backwards %%%%%%%%%% + +beta = zeros(Q,T); +if compute_gamma2 + M = size(mixmat, 2); + gamma2 = zeros(Q,M,T); +else + gamma2 = []; +end + +beta(:,T) = ones(Q,1); +%gamma(:,T) = normaliseC(alpha(:,T) .* beta(:,T)); +gamma(:,T) = normalise(alpha(:,T) .* beta(:,T)); +t=T; +if compute_gamma2 + denom = obslik(:,t) + (obslik(:,t)==0); % replace 0s with 1s before dividing + gamma2(:,:,t) = obslik2(:,:,t) .* mixmat .* repmat(gamma(:,t), [1 M]) ./ repmat(denom, [1 M]); + %gamma2(:,:,t) = normaliseC(obslik2(:,:,t) .* mixmat .* repmat(gamma(:,t), [1 M])); % wrong! +end +for t=T-1:-1:1 + b = beta(:,t+1) .* obslik(:,t+1); + %trans = transmat(:,:,act(t)); + trans = transmat{act(t)}; + if maximize + B = repmat(b(:)', Q, 1); + beta(:,t) = max(trans .* B, [], 2); + else + beta(:,t) = trans * b; + end + if scaled + %beta(:,t) = normaliseC(beta(:,t)); + beta(:,t) = normalise(beta(:,t)); + end + %gamma(:,t) = normaliseC(alpha(:,t) .* beta(:,t)); + gamma(:,t) = normalise(alpha(:,t) .* beta(:,t)); + if compute_xi + %xi(:,:,t) = normaliseC((trans .* (alpha(:,t) * b'))); + xi(:,:,t) = normalise((trans .* (alpha(:,t) * b'))); + %xi(:,:,t) = (trans .* (alpha(:,t) * b')); + end + if compute_gamma2 + denom = obslik(:,t) + (obslik(:,t)==0); % replace 0s with 1s before dividing + gamma2(:,:,t) = obslik2(:,:,t) .* mixmat .* repmat(gamma(:,t), [1 M]) ./ repmat(denom, [1 M]); + %gamma2(:,:,t) = normaliseC(obslik2(:,:,t) .* mixmat .* repmat(gamma(:,t), [1 M])); + end +end + + +% We now explain the equation for gamma2 +% Let zt=y(1:t-1,t+1:T) be all observations except y(t) +% gamma2(Q,M,t) = P(Qt,Mt|yt,zt) = P(yt|Qt,Mt,zt) P(Qt,Mt|zt) / P(yt|zt) +% = P(yt|Qt,Mt) P(Mt|Qt) P(Qt|zt) / P(yt|zt) +% Now gamma(Q,t) = P(Qt|yt,zt) = P(yt|Qt) P(Qt|zt) / P(yt|zt) +% hence +% P(Qt,Mt|yt,zt) = P(yt|Qt,Mt) P(Mt|Qt) [P(Qt|yt,zt) P(yt|zt) / P(yt|Qt)] / P(yt|zt) +% = P(yt|Qt,Mt) P(Mt|Qt) P(Qt|yt,zt) / P(yt|Qt) +% \ No newline at end of file diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/hmm_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/hmm_inf_engine.m new file mode 100644 index 00000000..3de17b40 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/hmm_inf_engine.m @@ -0,0 +1,71 @@ +function engine = hmm_inf_engine(bnet, varargin) +% HMM_INF_ENGINE Inference engine for DBNs which uses the forwards-backwards algorithm. +% engine = hmm_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - 1 means max-product, 0 means sum-product [0] +% +% The DBN is converted to an HMM with a single meganode, but the observed nodes remain factored. +% This can be faster than jtree if the num. hidden nodes is low, because of lower constant factors. +% +% All hidden nodes must be discrete. +% All observed nodes are assumed to be leaves, i.e., they cannot be parents of anything. +% The parents of each observed leaf are assumed to be a subset of the hidden nodes within the same slice. +% The only exception is if bnet is an AR-HMM, where the parents are assumed to be self in the +% previous slice (continuous), plus all the discrete nodes in the current slice. + +ss = bnet.nnodes_per_slice; + +engine.maximize = 0; +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', engine.maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +% Stuff to do with speeding up marginal_family +[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter); +engine.persist_bitv = zeros(1, ss); +engine.persist_bitv(engine.persist) = 1; + + +ns = bnet.node_sizes(:); +ns(bnet.observed) = 1; +ns(bnet.observed+ss) = 1; +engine.eff_node_sizes = ns; + +for o=bnet.observed(:)' + %if bnet.equiv_class(o,1) ~= bnet.equiv_class(o,2) + % error(['observed node ' num2str(o) ' is not tied']) + %end + cs = children(bnet.dag, o); + if ~isempty(cs) + error(['observed node ' num2str(o) ' is not allowed children']) + end +end + +[engine.startprob, engine.transprob, engine.obsprob] = dbn_to_hmm(bnet); + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.one_slice_marginal = []; +engine.two_slice_marginal = []; + +ss = length(bnet.intra); +engine.evidence = []; +engine.node_sizes = []; + +% avoid the need to do bnet_from_engine, which is slow +engine.slice_size = ss; +engine.parents = bnet.parents; + +engine = class(engine, 'hmm_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/marginal_family.m new file mode 100644 index 00000000..56b9fb6c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/marginal_family.m @@ -0,0 +1,35 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (hmm) +% marginal = marginal_family(engine, i, t, add_ev) + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +ns = engine.eff_node_sizes(:); +ss = engine.slice_size; + +if t==1 | ~engine.persist_bitv(i) + bigT = engine.one_slice_marginal(:,t); + ps = engine.parents{i}; + dom = [ps i] + (t-1)*ss; + bigdom = 1:ss; + bigsz = ns(bigdom); + bigdom = bigdom + (t-1)*ss; +else % some parents are in previous slice + bigT = engine.two_slice_marginal(:,t-1); % t-1 and t + ps = engine.parents{i+ss}; + dom = [ps i+ss] + (t-2)*ss; + bigdom = 1:(2*ss); % domain of xi(:,:,t) + bigsz = ns(bigdom); + bigdom = bigdom + (t-2)*ss; +end +marginal.domain = dom; + +marginal.T = marg_table(bigT, bigdom, bigsz, dom, engine.maximize); +marginal.mu = []; +marginal.Sigma = []; + +if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..0a2bec4f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/marginal_nodes.m @@ -0,0 +1,29 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (hmm) +% marginal = marginal_nodes(engine, nodes, t, add_ev) +% +% 'nodes' must be a single node. +% t is the time slice. + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +assert(length(nodes)==1) +ss = engine.slice_size; + +i = nodes(1); +bigT = engine.one_slice_marginal(:,t); +dom = i + (t-1)*ss; + +ns = engine.eff_node_sizes(:); +bigdom = 1:ss; +marginal.T = marg_table(bigT, bigdom + (t-1)*ss, ns(bigdom), dom, engine.maximize); + +marginal.domain = dom; +marginal.mu = []; +marginal.Sigma = []; + +if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..a35185ea --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Entries @@ -0,0 +1,3 @@ +/mk_hmm_obs_lik_matrix.m/1.1.1.1/Sun May 4 21:42:26 2003// +/mk_hmm_obs_lik_vec.m/1.1.1.1/Thu Jan 23 18:50:10 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..20dfc6fd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@hmm_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/mk_hmm_obs_lik_matrix.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/mk_hmm_obs_lik_matrix.m new file mode 100644 index 00000000..441f3c0a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/mk_hmm_obs_lik_matrix.m @@ -0,0 +1,30 @@ +function obslik = mk_hmm_obs_lik_matrix(engine, evidence) + +T = size(evidence,2); +Q = length(engine.startprob); +obslik = ones(Q, T); +bnet = bnet_from_engine(engine); +% P(o1,o2| Q1,Q2) = P(o1|Q1,Q2) * P(o2|Q1,Q2) +onodes = bnet.observed; +for i=1:length(onodes) + data = cell2num(evidence(onodes(i),:)); + if bnet.auto_regressive(onodes(i)) + params = engine.obsprob{i}; + mu = params.big_mu; + Sigma = params.big_Sigma, + W = params.big_W; + mu0 = params.big_mu0; + Sigma0 = params.big_Sigma0; + %obslik_i = mk_arhmm_obs_lik(data, mu, Sigma, W, mu0, Sigma0 + obslik_i = clg_prob(data(:,1:T-1), data(:,2:T), mu, Sigma, W); + obslik_i = [mixgauss_prob(data(:,1), mu0, Sigma0) obslik_i]; + elseif myismember(onodes(i), bnet.dnodes) + %obslik_i = eval_pdf_cond_multinomial(data, engine.obsprob{i}.big_CPT); + obslik_i = multinomial_prob(data, engine.obsprob{i}.big_CPT); + else + %obslik_i = eval_pdf_cond_gauss(data, engine.obsprob{i}.big_mu, engine.obsprob{i}.big_Sigma); + obslik_i = mixgauss_prob(data, engine.obsprob{i}.big_mu, engine.obsprob{i}.big_Sigma); + end + obslik = obslik .* obslik_i; +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/mk_hmm_obs_lik_vec.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/mk_hmm_obs_lik_vec.m new file mode 100644 index 00000000..16d30aec --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/private/mk_hmm_obs_lik_vec.m @@ -0,0 +1,52 @@ +function obslik = mk_hmm_obs_lik_vec(engine, evidence) + +% P(o1,o2| h) = P(o1|h) * P(o2|h) where h = Q1,Q2,... + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +onodes = bnet.observed; +hnodes = mysetdiff(1:ss, onodes); +ns = bnet.node_sizes(:); +ns(onodes) = 1; + +Q = length(engine.startprob); +obslik = ones(Q, 1); + +for i=1:length(onodes) + o = onodes(i); + %data = cell2num(evidence(o,1)); + data = evidence{o,1}; + if myismember(o, bnet.dnodes) + obslik_i = eval_pdf_cond_multinomial(data, engine.obsprob{i}.CPT); + else + if bnet.auto_regressive(o) + error('can''t handle AR nodes') + end + %% calling mk_ghmm_obs_lik, which calls gaussian_prob, is slow, so we inline it + %% and use the pre-computed inverse matrix + %obslik_i = mk_ghmm_obs_lik(data, engine.obsprob{i}.mu, engine.obsprob{i}.Sigma); + x = data(:); + m = engine.obsprob{i}.mu; + Qi = size(m, 2); + obslik_i = size(Qi, 1); + invC = engine.obsprob{i}.inv_Sigma; + denom = engine.obsprob{i}.denom; + for j=1:Qi + numer = exp(-0.5 * (x-m(:,j))' * invC(:,:,j) * (x-m(:,j))); + obslik_i(j) = numer / denom(j); + end + end + % convert P(o|ps) into P(o|h) by multiplying onto a (h,o) potential of all 1s + ps = bnet.parents{o}; + dom = [ps o]; + obspot_i = dpot(dom, ns(dom), obslik_i); + dom = [hnodes o]; + obspot = dpot(dom, ns(dom)); + obspot = multiply_by_pot(obspot, obspot_i); + % compute p(oi|h) * p(oj|h) + S = struct(obspot); + obslik = obslik .* S.T(:); +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/update_engine.m new file mode 100644 index 00000000..e6cd1f79 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@hmm_inf_engine/update_engine.m @@ -0,0 +1,8 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (hmm) +% engine = update_engine(engine, newCPDs) + +%engine.inf_engine.bnet.CPD = newCPDs; +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +[engine.startprob, engine.transprob, engine.obsprob] = dbn_to_hmm(bnet_from_engine(engine)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Entries new file mode 100644 index 00000000..3baa09c7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Entries @@ -0,0 +1,6 @@ +/enter_soft_evidence1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence2.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence3.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence4.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Repository new file mode 100644 index 00000000..a9b61e36 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence1.m new file mode 100644 index 00000000..8f82b57e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence1.m @@ -0,0 +1,119 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = zeros(1,T); +bnet = bnet_from_engine(engine); + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). +% Then propagate from D to later slices. + +C = engine.out_clq; +assert(C==engine.jtree_struct.root_clq); +D = engine.in_clq; +slice1 = 1:ss; +slice2 = slice1 + ss; +for t=2:T + if t==2 + clqs = engine.jtree_struct.clq_ass_to_node([slice1 slice2]); + pots = CPDpot(:,t-1:t); + else + %clqs = [D; engine.clq_ass_to_node(:,2)]; + clqs = [D engine.jtree_struct.clq_ass_to_node(slice2)]; + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + pots = [ {phiC}; CPDpot(:,t)]; % CPDpot domains are always slice 2 + end + [clpot(:,t), seppot(:,:,t)] = init_pot(engine.jtree_struct.cliques, clqs, pots, pot_type, ... + find(observed(:,t-1:t)), bnet.node_sizes(:), bnet.cnodes); + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(C); + + phiC = marginalize_pot(clpot{C,t}, engine.interface+ss, engine.maximize); +end + + + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +C = engine.in_clq; +D = engine.out_clq; +for t=T:-1:2 + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(C); + + if t >= 3 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end + +loglik = sum(logscale); + + +%%%%%%% +function [clpot, seppot] = init_pot(cliques, clqs, pots, pot_type, onodes, ns, cnodes); + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, ns, cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 + + +%%%% +function [clpot, seppot] = collect_evidence(clpot, seppot, maximize, postorder, postorder_parents,... + separator) +for n=postorder %postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}, maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + + +%%%% +function [clpot, seppot] = distribute_evidence(clpot, seppot, maximize, preorder, preorder_children,... + separator) +for n=preorder + for c=preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence2.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence2.m new file mode 100644 index 00000000..0adfef0d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence2.m @@ -0,0 +1,143 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = ones(1,T); % log(logscale(1)) = 0 +bnet = bnet_from_engine(engine); + +slice1 = 1:ss; +slice2 = slice1+ss; + +% calibrate each 2-slice jtree in isolation +for t=2:T + if t==2 + clqs = engine.jtree_struct.clq_ass_to_node([slice1 slice2]); + pots = CPDpot(:,t-1:t); + else + clqs = engine.jtree_struct.clq_ass_to_node(slice2); + pots = CPDpot(:,t); % CPDpot domains are always slice 2 + end + [clpot(:,t), sepot(:,:,t)] = init_pot(engine.jtree_struct.cliques, clqs, pots, pot_type, ... + find(observed(:,t-1:t)), bnet.node_sizes(:), bnet.cnodes); + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); +end + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). +% Then propagate from D to later slices. + +C = engine.out_clq; +D = engine.in_clq; +for t=2:T-1 + phiC = marginalize_pot(clpot{C,t}, engine.interface+ss, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + phiD = marginalize_pot(clpot{D,t+1}, engine.interface, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t+1} = multiply_by_pot(clpot{D,t+1}, ratio); + + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(1); +end + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +C = engine.in_clq; +D = engine.out_clq; +for t=T:-1:2 + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(1); + + if t >= 3 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end + +loglik = sum(logscale); + +%%%%%%%%%% + +function [clpot, seppot] = calibrate(engine, clpot, seppot) + + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + + +%%%%%%% +function [clpot, seppot] = init_pot(cliques, clqs, pots, pot_type, onodes, ns, cnodes); + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, ns, cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 + + +%%%% +function [clpot, seppot] = collect_evidence(clpot, seppot, maximize, postorder, postorder_parents,... + separator) +for n=postorder %postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}, maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + + +%%%% +function [clpot, seppot] = distribute_evidence(clpot, seppot, maximize, preorder, preorder_children,... + separator) +for n=preorder + for c=preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence3.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence3.m new file mode 100644 index 00000000..c1189460 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence3.m @@ -0,0 +1,125 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = zeros(1,T); +bnet = bnet_from_engine(engine); + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). +% Then propagate from D to later slices. + +C = engine.out_clq; +assert(C==engine.jtree_struct.root_clq); +D = engine.in_clq; +slice1 = 1:ss; +slice2 = slice1 + ss; +Ntransient = length(engine.transient); +trans = cell(Ntransient,1); +for t=2:T + if t==2 + clqs = engine.jtree_struct.clq_ass_to_node([slice1 slice2]); + pots = CPDpot(:,t-1:t); + else + %clqs = [D; engine.clq_ass_to_node(:,2)]; + clqs = [D engine.jtree_struct.clq_ass_to_node([engine.transient slice2])]; + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + for i=1:Ntransient + trans{i} = CPDpot{engine.transient(i), t-1}; + trans{i} = set_domain_pot(trans{i}, domain_pot(trans{i})-ss); % shift back to slice 1 + end + pots = [ {phiC}; trans; CPDpot(:,t)]; + end + [clpot(:,t), seppot(:,:,t)] = init_pot(engine.jtree_struct.cliques, clqs, pots, pot_type, ... + find(observed(:,t-1:t)), bnet.node_sizes(:), bnet.cnodes); + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(C); + + phiC = marginalize_pot(clpot{C,t}, engine.interface+ss, engine.maximize); +end + + + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +C = engine.in_clq; +D = engine.out_clq; +for t=T:-1:2 + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(C); + + if t >= 3 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end + +loglik = sum(logscale); + + +%%%%%%% +function [clpot, seppot] = init_pot(cliques, clqs, pots, pot_type, onodes, ns, cnodes); + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, ns, cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 + + +%%%% +function [clpot, seppot] = collect_evidence(clpot, seppot, maximize, postorder, postorder_parents,... + separator) +for n=postorder %postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}, maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + + +%%%% +function [clpot, seppot] = distribute_evidence(clpot, seppot, maximize, preorder, preorder_children,... + separator) +for n=preorder + for c=preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence4.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence4.m new file mode 100644 index 00000000..a4ec90c6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/enter_soft_evidence4.m @@ -0,0 +1,149 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = ones(1,T); % log(logscale(1)) = 0 +bnet = bnet_from_engine(engine); + +slice1 = 1:ss; +slice2 = slice1+ss; +Ntransient = length(engine.transient); +trans = cell(Ntransient,1); + +% calibrate each 2-slice jtree in isolation +for t=2:T + if t==2 + clqs = engine.jtree_struct.clq_ass_to_node([slice1 slice2]); + pots = CPDpot(:,t-1:t); + else + clqs = engine.jtree_struct.clq_ass_to_node([engine.transient slice2]); + for i=1:Ntransient + trans{i} = CPDpot{engine.transient(i), t-1}; + trans{i} = set_domain_pot(trans{i}, domain_pot(trans{i})-ss); % shift back to slice 1 + end + pots = [ trans; CPDpot(:,t)]; + end + [clpot(:,t), sepot(:,:,t)] = init_pot(engine.jtree_struct.cliques, clqs, pots, pot_type, ... + find(observed(:,t-1:t)), bnet.node_sizes(:), bnet.cnodes); + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); +end + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). +% Then propagate from D to later slices. + +C = engine.out_clq; +D = engine.in_clq; +for t=2:T-1 + phiC = marginalize_pot(clpot{C,t}, engine.interface+ss, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + phiD = marginalize_pot(clpot{D,t+1}, engine.interface, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t+1} = multiply_by_pot(clpot{D,t+1}, ratio); + + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(1); +end + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +C = engine.in_clq; +D = engine.out_clq; +for t=T:-1:2 + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(1); + + if t >= 3 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end + +loglik = sum(logscale); + +%%%%%%%%%% + +function [clpot, seppot] = calibrate(engine, clpot, seppot) + + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + + +%%%%%%% +function [clpot, seppot] = init_pot(cliques, clqs, pots, pot_type, onodes, ns, cnodes); + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, ns, cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 + + +%%%% +function [clpot, seppot] = collect_evidence(clpot, seppot, maximize, postorder, postorder_parents,... + separator) +for n=postorder %postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}, maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + + +%%%% +function [clpot, seppot] = distribute_evidence(clpot, seppot, maximize, preorder, preorder_children,... + separator) +for n=preorder + for c=preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/marginal_nodes.m new file mode 100644 index 00000000..fe1d38f6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Broken/marginal_nodes.m @@ -0,0 +1,51 @@ +function marginal = marginal_nodes(engine, nodes, t, fam) +% MARGINAL_NODES Compute the marginal on the specified query nodes (bk) +% +% marginal = marginal_nodes(engine, i, t) +% returns Pr(X(i,t) | Y(1:T)), where X(i,t) is the i'th node in the t'th slice. +% +% marginal = marginal_nodes(engine, query, t) +% returns Pr(X(query(1),t), ... X(query(end),t) | Y(1:T)), +% where 't' specifies the time slice of the earliest node in the query. +% 'query' cannot span more than 2 time slices. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3. + +if nargin < 3, t = 1; end +if nargin < 4, fam = 0; else fam = 1; end + + +% clpot{t} contains slice t-1 and t +% Example +% clpot #: 1 2 3 +% slices: 1 1,2 2,3 +% For filtering, we must take care not to take future evidence into account. +% For smoothing, clpot{1} does not exist. + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); + +if t < engine.T + slice = t+1; + nodes2 = nodes; +else % earliest t is T, so all nodes fit in one slice + slice = engine.T; + nodes2 = nodes + ss; +end + +c = clq_containing_nodes(engine.jtree_engine, nodes2, fam); +assert(c >= 1); + +%disp(['computing marginal on ' num2str(nodes) ' t = ' num2str(t)]); +%disp(['using ' num2str(nodes2) ' slice = ' num2str(slice) 'clq = ' num2str(c)]); + +bigpot = engine.clpot{c, slice}; + +pot = marginalize_pot(bigpot, nodes2, engine.maximize); +marginal = pot_to_marginal(pot); + +% we convert the domain to the unrolled numbering system +% so that update_ess extracts the right evidence. +marginal.domain = nodes+(t-1)*ss; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Entries new file mode 100644 index 00000000..aea2a602 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Entries @@ -0,0 +1,6 @@ +/enter_evidence.m/1.1.1.1/Sat Jan 11 18:41:30 2003// +/enter_soft_evidence.m/1.1.1.1/Thu Feb 19 01:12:08 2004// +/jtree_dbn_inf_engine.m/1.1.1.1/Thu Nov 14 16:32:00 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Fri Nov 22 23:51:58 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..2fb9e4b6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Entries.Log @@ -0,0 +1,2 @@ +A D/Broken//// +A D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Repository new file mode 100644 index 00000000..590182fa --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@jtree_dbn_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..0bc2d941 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Entries @@ -0,0 +1,6 @@ +/enter_soft_evidence_nonint.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence_trans.m/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_dbn_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_dbn_inf_engine1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_dbn_inf_engine2.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..0b90d866 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/enter_soft_evidence_nonint.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/enter_soft_evidence_nonint.m new file mode 100644 index 00000000..72641580 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/enter_soft_evidence_nonint.m @@ -0,0 +1,135 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = zeros(1,T); +bnet = bnet_from_engine(engine); + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). +% Then propagate from D to later slices. + +C = engine.out_clq; +assert(C==engine.jtree_struct.root_clq); +D = engine.in_clq; +slice1 = 1:ss; +slice2 = slice1 + ss; +Nnonint = length(engine.nonint); +nonint = cell(Nnonint, 1); +for t=1:T + if t==1 + pots = [CPDpot(:,1); CPDpot(engine.interface, 2)]; + clqs = engine.jtree_struct.clq_ass_to_node([slice1 engine.interface+ss]); + obs = find(observed(:,1:2)); + elseif t==T + clqs = [D engine.jtree_struct.clq_ass_to_node(engine.nonint)]; + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + for i=1:Nnonint + nonint{i} = CPDpot{engine.nonint(i), t}; + nonint{i} = set_domain_pot(nonint{i}, domain_pot(nonint{i})-ss); % shift back to slice 1 + end + pots = [ {phiC}; nonint]; + obs = find(observed(:,T)); + else + clqs = [D engine.jtree_struct.clq_ass_to_node([engine.nonint engine.interface+ss])]; + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + for i=1:Nnonint + nonint{i} = CPDpot{engine.nonint(i), t}; + nonint{i} = set_domain_pot(nonint{i}, domain_pot(nonint{i})-ss); % shift back to slice 1 + end + pots = [ {phiC}; nonint; CPDpot(engine.interface, t+1)]; + obs = find(observed(:,t:t+1)); + end + [clpot(:,t), seppot(:,:,t)] = init_pot(engine.jtree_struct.cliques, clqs, pots, pot_type, ... + obs, bnet.node_sizes(:), bnet.cnodes); + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(C); + + phiC = marginalize_pot(clpot{C,t}, engine.interface+ss, engine.maximize); +end + + + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +C = engine.in_clq; +D = engine.out_clq; +for t=T:-1:1 + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + %logscale(t) = ll(C); + + if t >= 2 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end + +loglik = sum(logscale); + + +%%%%%%% +function [clpot, seppot] = init_pot(cliques, clqs, pots, pot_type, onodes, ns, cnodes); + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, ns, cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 + + +%%%% +function [clpot, seppot] = collect_evidence(clpot, seppot, maximize, postorder, postorder_parents,... + separator) +for n=postorder %postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}, maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + + +%%%% +function [clpot, seppot] = distribute_evidence(clpot, seppot, maximize, preorder, preorder_children,... + separator) +for n=preorder + for c=preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/enter_soft_evidence_trans.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/enter_soft_evidence_trans.m new file mode 100644 index 00000000..b9c85b80 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/enter_soft_evidence_trans.m @@ -0,0 +1,135 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type, filter) + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = zeros(1,T); +bnet = bnet_from_engine(engine); + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). +% Then propagate from D to later slices. + +C = engine.out_clq; +assert(C==engine.jtree_struct.root_clq); +D = engine.in_clq; +slice1 = 1:ss; +slice2 = slice1 + ss; +Ntransient = length(engine.transient); +trans = cell(Ntransient,1); +for t=1:T + if t==1 + pots = [CPDpot(:,1); CPDpot(engine.persist, 2)]; + clqs = engine.jtree_struct.clq_ass_to_node([slice1 engine.persist+ss]); + obs = find(observed(:,1:2)); + elseif t==T + clqs = [D engine.jtree_struct.clq_ass_to_node(engine.transient)]; + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + for i=1:Ntransient + trans{i} = CPDpot{engine.transient(i), t}; + trans{i} = set_domain_pot(trans{i}, domain_pot(trans{i})-ss); % shift back to slice 1 + end + pots = [ {phiC}; trans]; + obs = find(observed(:,T)); + else + clqs = [D engine.jtree_struct.clq_ass_to_node([engine.transient engine.persist+ss])]; + phiC = set_domain_pot(phiC, engine.interface); % shift back to slice 1 + for i=1:Ntransient + trans{i} = CPDpot{engine.transient(i), t}; + trans{i} = set_domain_pot(trans{i}, domain_pot(trans{i})-ss); % shift back to slice 1 + end + pots = [ {phiC}; trans; CPDpot(engine.persist, t+1)]; + obs = find(observed(:,t:t+1)); + end + [clpot(:,t), seppot(:,:,t)] = init_pot(engine.jtree_struct.cliques, clqs, pots, pot_type, ... + obs, bnet.node_sizes(:), bnet.cnodes); + [clpot(:,t), seppot(:,:,t)] = collect_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.postorder, ... + engine.jtree_struct.postorder_parents,... + engine.jtree_struct.separator); + + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(C); + + phiC = marginalize_pot(clpot{C,t}, engine.interface+ss, engine.maximize); +end + + + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +C = engine.in_clq; +D = engine.out_clq; +for t=T:-1:1 + [clpot(:,t), seppot(:,:,t)] = distribute_evidence(clpot(:,t), seppot(:,:,t), engine.maximize, ... + engine.jtree_struct.preorder, ... + engine.jtree_struct.preorder_children, ... + engine.jtree_struct.separator); + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + %logscale(t) = ll(C); + + if t >= 2 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end + +loglik = sum(logscale); + + +%%%%%%% +function [clpot, seppot] = init_pot(cliques, clqs, pots, pot_type, onodes, ns, cnodes); + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, ns, cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 + + +%%%% +function [clpot, seppot] = collect_evidence(clpot, seppot, maximize, postorder, postorder_parents,... + separator) +for n=postorder %postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}, maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + + +%%%% +function [clpot, seppot] = distribute_evidence(clpot, seppot, maximize, preorder, preorder_children,... + separator) +for n=preorder + for c=preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine.m new file mode 100644 index 00000000..5b5cc8ba --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine.m @@ -0,0 +1,67 @@ +function engine = jtree_dbn_inf_engine(bnet, varargin) +% JTREE_DBN_INF_ENGINE Junction tree inference algorithm for DBNs. + +ss = length(bnet.intra); + +onodes = []; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'observed', onodes = args{i+1}; + end + end +end + +[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter); +%engine.interface = engine.persist; % WRONG! +engine.interface = int; +engine.nonint = mysetdiff(1:ss, int); + +if 0 + % Create a 2 slice jtree + % We force there to be cliques containing the in and out interfaces for slices t and t+1. + obs_nodes = [onodes(:) onodes(:)+ss]; + engine.jtree_engine = jtree_inf_engine(bnet, 'observed', obs_nodes(:), ... + 'clusters', {int, int+ss}, 'root', int+ss); +else + % Create a "1.5 slice" jtree, containing slice 1 and the interface nodes of slice 2 + nodes15 = [1:ss int+ss]; + N = length(nodes15); + dag15 = bnet.dag(nodes15, nodes15); + ns15 = bnet.node_sizes(nodes15); + eclass15 = bnet.equiv_class(nodes15); + discrete_bitv = zeros(1,2*ss); + discrete_bitv(bnet.dnodes) = 1; + discrete15 = find(discrete_bitv(nodes15)); + bnet15 = mk_bnet(dag15, ns15, 'equiv_class', eclass15, 'discrete', discrete15); + bnet15.CPD = bnet.CPD; % CPDs for non-interface nodes in slice 2 will not be used + obs_bitv = zeros(1, 2*ss); + obs_bitv([onodes onodes+ss]) = 1; + obs_nodes15 = find(obs_bitv(nodes15)); + int_bitv = zeros(1,ss); + int_bitv(int) = 1; + engine.jtree_engine = jtree_inf_engine(bnet15, 'observed', obs_nodes15(:), ... + 'clusters', {int, int+ss}, 'root', int+ss); +end + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); + +engine.clq_ass_to_node = zeros(ss, 2); +for i=1:ss + engine.clq_ass_to_node(i, 1) = clq_containing_nodes(engine.jtree_engine, i); + engine.clq_ass_to_node(i, 2) = clq_containing_nodes(engine.jtree_engine, i+ss); +end + +engine.jtree_struct = struct(engine.jtree_engine); % violate object privacy + +% stuff needed by marginal_nodes +engine.clpot = []; +engine.maximize = []; +engine.T = []; + +engine = class(engine, 'jtree_dbn_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine1.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine1.m new file mode 100644 index 00000000..5edad836 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine1.m @@ -0,0 +1,62 @@ +function engine = jtree_dbn_inf_engine(bnet, varargin) +% JTREE_DBN_INF_ENGINE Junction tree inference algorithm for DBNs. + +ss = length(bnet.intra); + +onodes = []; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'observed', onodes = args{i+1}; + end + end +end + +[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter); +%engine.interface = engine.persist; % WRONG! +engine.interface = int; +engine.nonint = mysetdiff(1:ss, int); + +if 1 + % Create a 2 slice jtree + % We force there to be cliques containing the in and out interfaces for slices t and t+1. + obs_nodes = [onodes(:) onodes(:)+ss]; + engine.jtree_engine = jtree_inf_engine(bnet, 'observed', obs_nodes(:), ... + 'clusters', {int, int+ss}, 'root', int+ss); +else + % Create a "1.5 slice" jtree, containing slice 1 and the interface nodes of slice 2 + % To keep the node numbering the same, we simply disconnect the non-interface nodes + % from slice 2. + intra15 = bnet.intra; + for i=engine.nonint(:)' + intra15(i,:) = 0; + intra15(:,i) = 0; + end + bnet15 = mk_dbn(intra15, bnet.inter, bnet.node_sizes_slice, bnet.dnodes_slice, ... + bnet.equiv_class(:,1), bnet.equiv_class(:,2), bnet.intra); + obs_nodes = [onodes(:) onodes(:)+ss]; + engine.jtree_engine = jtree_inf_engine(bnet15, 'observed', obs_nodes(:), ... + 'clusters', {int, int+ss}, 'root', int+ss); +end + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); + +engine.clq_ass_to_node = zeros(ss, 2); +for i=1:ss + engine.clq_ass_to_node(i, 1) = clq_containing_nodes(engine.jtree_engine, i); + engine.clq_ass_to_node(i, 2) = clq_containing_nodes(engine.jtree_engine, i+ss); +end + +engine.jtree_struct = struct(engine.jtree_engine); % violate object privacy + +% stuff needed by marginal_nodes +engine.clpot = []; +engine.maximize = []; +engine.T = []; + +engine = class(engine, 'jtree_dbn_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine2.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine2.m new file mode 100644 index 00000000..68ac2aff --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/Old/jtree_dbn_inf_engine2.m @@ -0,0 +1,57 @@ +function engine = jtree_dbn_inf_engine(bnet, varargin) +% JTREE_DBN_INF_ENGINE Junction tree inference algorithm for DBNs. + +ss = length(bnet.intra); + +onodes = []; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'observed', onodes = args{i+1}; + end + end +end + +[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter); +%engine.interface = engine.persist; % WRONG! +engine.interface = int; +engine.nonint = mysetdiff(1:ss, int); + + +% Create a 2 slice jtree +% We force there to be cliques containing the in and out interfaces for slices t and t+1. +obs_nodes = [onodes(:) onodes(:)+ss]; +engine.jtree_engine = jtree_inf_engine(bnet, 'observed', obs_nodes(:), ... + 'clusters', {int, int+ss}, 'root', int+ss); + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); +engine.jtree_struct = struct(engine.jtree_engine); % violate object privacy + + + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, bnet.dnodes, bnet.equiv_class(:,1)); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end + +engine.jtree_engine1 = jtree_inf_engine(bnet1, 'observed', onodes, 'clusters', {int}, ... + 'root', int); + +engine.in_clq1 = clq_containing_nodes(engine.jtree_engine1, int); +engine.jtree_struct1 = struct(engine.jtree_engine1); % violate object privacy + + + + +% stuff needed by marginal_nodes +engine.clpot = []; +engine.T = []; +engine.maximize = []; + +engine = class(engine, 'jtree_dbn_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/enter_evidence.m new file mode 100644 index 00000000..e21bb07d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/enter_evidence.m @@ -0,0 +1,70 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree_dbn) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [engine.maximize] +% softCPDpot{n,t} - use soft potential for node n instead of its CPD; set to [] to use CPD +% soft_evidence_nodes(i,1:2) = [n t] means the i'th piece of soft evidence is on node n in slice t +% soft_evidence{i} - prob distribution over values for soft_evidence_nodes(i,:) +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + + +% for add_ev in marginal_nodes +T = size(evidence, 2); +engine.evidence = evidence; +bnet = bnet_from_engine(engine); +ss = length(bnet.node_sizes_slice); +ns = bnet.node_sizes_slice(:); +engine.node_sizes = repmat(ns, [1 T]); +softCPDpot = cell(ss,T); +soft_evidence = {}; +soft_evidence_nodes = []; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', engine.maximize = args{i+1}; + case 'softCPDpot', softCPDpot = args{i+1}; + case 'soft_evidence', soft_evidence = args{i+1}; + case 'soft_evidence_nodes', soft_evidence_nodes = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +engine.jtree_engine = set_fields(engine.jtree_engine, 'maximize', engine.maximize); +engine.jtree_engine1 = set_fields(engine.jtree_engine1, 'maximize', engine.maximize); + +[ss T] = size(evidence); +engine.T = T; +observed_bitv = ~isemptycell(evidence); +onodes = find(observed_bitv); +pot_type = determine_pot_type(bnet, onodes); +CPDpot = convert_dbn_CPDs_to_pots(bnet, evidence, pot_type, softCPDpot); + +if ~isempty(soft_evidence_nodes) + nsoft = size(soft_evidence_nodes,1); + for i=1:nsoft + n = soft_evidence_nodes(i,1); + t = soft_evidence_nodes(i,2); + if t==1 + dom = n; + else + dom = n+ss; + end + pot = dpot(dom, ns(n), soft_evidence{i}); + CPDpot{n,t} = multiply_by_pot(CPDpot{n,t}, pot); + end +end + +[engine.clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed_bitv, pot_type); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..5ffc55b0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/enter_soft_evidence.m @@ -0,0 +1,126 @@ +function [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified soft evidence to the network (jtree_dbn) +% [clpot, loglik] = enter_soft_evidence(engine, CPDpot, observed, pot_type) + +scale = 1; +verbose = 0; + +[ss T] = size(CPDpot); +Q = length(engine.jtree_struct.cliques); +clpot = cell(Q,T); % clpot{t} contains evidence from slices (t-1, t) +seppot = cell(Q,Q,T); +ll = zeros(1,Q); +logscale = zeros(1,T); +bnet = bnet_from_engine(engine); +root = engine.jtree_struct.root_clq; + +% Forwards pass. +% Compute distribution on clq C, +% where C is the out interface to (t-1,t). +% Then pass this to clq D, where D is the in inferface to (t+1,t). + +% Then propagate from D to later slices. + +slice1 = 1:ss; +slice2 = slice1 + ss; +transient = engine.transient; +persist = engine.persist; +Ntransient = length(transient); +trans = cell(Ntransient,1); +if verbose, fprintf('forward pass\n'); end +for t=1:T + if verbose, fprintf('%d ', t); end + if t==1 + pots = [CPDpot(:,1); CPDpot(persist, 2)]; + clqs = engine.jtree_struct.clq_ass_to_node([slice1 persist+ss]); + obs = find(observed(:,1:2)); + elseif t==T + clqs = [engine.in_clq1 engine.jtree_struct1.clq_ass_to_node(transient)]; + phi = set_domain_pot(phi, engine.interface); % shift back to slice 1 + for i=1:Ntransient + trans{i} = CPDpot{transient(i), t}; + trans{i} = set_domain_pot(trans{i}, domain_pot(trans{i})-ss); % shift back to slice 1 + end + pots = [ {phi}; trans]; + obs = find(observed(:,T)); + else + clqs = [engine.in_clq engine.jtree_struct.clq_ass_to_node([transient persist+ss])]; + phi = set_domain_pot(phi, engine.interface); % shift back to slice 1 + for i=1:Ntransient + trans{i} = CPDpot{transient(i), t}; + trans{i} = set_domain_pot(trans{i}, domain_pot(trans{i})-ss); % shift back to slice 1 + end + pots = [ {phi}; trans; CPDpot(persist, t+1)]; + obs = find(observed(:,t:t+1)); + end + + if t < T + [clpot(1:Q,t), seppot(1:Q,1:Q,t)] = init_pot(engine.jtree_engine, clqs, pots, pot_type, obs); + [clpot(1:Q,t), seppot(1:Q,1:Q,t)] = collect_evidence(engine.jtree_engine, clpot(1:Q,t), seppot(1:Q,1:Q,t)); + else + Q = length(engine.jtree_struct1.cliques); + root = engine.jtree_struct1.root_clq; + [clpot(1:Q,t), seppot(1:Q,1:Q,t)] = init_pot(engine.jtree_engine1, clqs, pots, pot_type, obs); + [clpot(1:Q,t), seppot(1:Q,1:Q,t)] = collect_evidence(engine.jtree_engine1, clpot(1:Q,t), seppot(1:Q,1:Q,t)); + end + + + if scale + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + logscale(t) = ll(root); + end + + if t < T + % bug fix by Bob Welch 30 Jan 04 + phi = marginalize_pot(clpot{engine.out_clq,t}, engine.interface+ss,engine.maximize); + %phi = marginalize_pot(clpot{root,t}, engine.interface+ss, engine.maximize); + end +end + +if scale +loglik = sum(logscale); +else +loglik = []; +end + + +% Backwards pass. +% Pass evidence from clq C to clq D, +% where C is the in interface to (t,t+1) and D is the out inferface to (t-1,t) +% Then propagate evidence from D to earlier slices. +% (C and D are reversed names from the tech report!) +D = engine.out_clq; +if verbose, fprintf('\nbackwards pass\n'); end +for t=T:-1:1 + if verbose, fprintf('%d ', t); end + + if t == T + Q = length(engine.jtree_struct1.cliques); + C = engine.in_clq1; + [clpot(1:Q,t), seppot(1:Q,1:Q,t)] = distribute_evidence(engine.jtree_engine1, clpot(1:Q,t), seppot(1:Q,1:Q,t)); + else + Q = length(engine.jtree_struct.cliques); + C = engine.in_clq; + [clpot(1:Q,t), seppot(1:Q,1:Q,t)] = distribute_evidence(engine.jtree_engine, clpot(1:Q,t), seppot(1:Q,1:Q,t)); + end + + if scale + for c=1:Q + [clpot{c,t}, ll(c)] = normalize_pot(clpot{c,t}); + end + end + + if t >= 2 + phiC = marginalize_pot(clpot{C,t}, engine.interface, engine.maximize); + phiC = set_domain_pot(phiC, engine.interface+ss); % shift forward to slice 2 + phiD = marginalize_pot(clpot{D,t-1}, engine.interface+ss, engine.maximize); + ratio = divide_by_pot(phiC, phiD); + clpot{D,t-1} = multiply_by_pot(clpot{D,t-1}, ratio); + end +end +if verbose, fprintf('\n'); end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/jtree_dbn_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/jtree_dbn_inf_engine.m new file mode 100644 index 00000000..c49ba4c4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/jtree_dbn_inf_engine.m @@ -0,0 +1,109 @@ +function engine = jtree_dbn_inf_engine(bnet, varargin) +% JTREE_DBN_INF_ENGINE Junction tree inference algorithm for DBNs. +% engine = jtree_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - specifies variables that must be grouped in the 1.5 slice DBN +% maximize - 1 means max-product, 0 means sum-product [0] +% +% e.g., engine = jtree_dbn_inf_engine(dbn, 'clusters', {[1 2]}); +% +% This uses all of slice t-1 plus the backwards interface of slice t. +% By contrast, jtree_2TBN_inf_engine in the online directory uses +% the forwards interface of slice t-1 plus all of slice t. +% See my thesis for details. + +ss = length(bnet.intra); + +engine.maximize = 0; +clusters = {}; + +args = varargin; +for i=1:2:length(args) + switch args{i}, + case 'clusters', clusters = args{i+1}; + case 'maximize', engine.maximize = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end +end + + +engine.evidence = []; +engine.node_sizes = []; + +[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter); +engine.interface = int; +engine.nonint = mysetdiff(1:ss, int); + +onodes = bnet.observed; + +if 0 + % Create a 2 slice jtree + % We force there to be cliques containing the in and out interfaces for slices t and t+1. + obs_nodes = [onodes(:) onodes(:)+ss]; + engine.jtree_engine = jtree_inf_engine(bnet, 'observed', obs_nodes(:), ... + 'clusters', {int, int+ss}, 'root', int+ss); +else + % Create a "1.5 slice" jtree, containing slice 1 and the interface nodes of slice 2 + % To keep the node numbering the same, we simply disconnect the non-interface nodes + % from slice 2, and set their size to 1. + % We do this to speed things up, and so that the likelihood is computed correctly - we do not need to do + % this if we just want to compute marginals. + intra15 = bnet.intra; + for i=engine.nonint(:)' + intra15(i,:) = 0; + intra15(:,i) = 0; + end + dag15 = [bnet.intra bnet.inter; + zeros(ss) intra15]; + ns = bnet.node_sizes(:); + ns(engine.nonint+ss) = 1; % disconnected nodes get size 1 + obs_nodes = [onodes(:) onodes(:)+ss]; + bnet15 = mk_bnet(dag15, ns, 'discrete', bnet.dnodes, 'equiv_class', bnet.equiv_class(:), ... + 'observed', obs_nodes(:)); + + %bnet15 = mk_dbn(intra15, bnet.inter, bnet.node_sizes_slice, bnet.dnodes_slice, ... + % bnet.equiv_class(:,1), bnet.equiv_class(:,2), bnet.intra); + % with the dbn, we can't independently control the sizes of slice 2 nodes + + if 1 + % use unconstrained elimination, + % but force there to be a clique containing both interfaces + clusters(end+1:end+2) = {int, int+ss}; + engine.jtree_engine = jtree_inf_engine(bnet15, 'clusters', clusters, 'root', int+ss); + else + % Use constrained elimination - this induces a clique that contain the 2nd interface, + % but not the first. + % Hence we throw in the first interface as an extra. + stages = {1:ss, [1:ss]+ss}; + clusters(end+1:end+2) = {int, int+ss}; + engine.jtree_engine = jtree_inf_engine(bnet15, 'clusters', clusters, ... + 'stages', stages, 'root', int+ss); + end +end + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); +engine.jtree_struct = struct(engine.jtree_engine); % violate object privacy + + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes,1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end + +engine.jtree_engine1 = jtree_inf_engine(bnet1, 'clusters', {int}, 'root', int); + +engine.in_clq1 = clq_containing_nodes(engine.jtree_engine1, int); +engine.jtree_struct1 = struct(engine.jtree_engine1); % violate object privacy + +% stuff needed by marginal_nodes +engine.clpot = []; +engine.T = []; + +engine = class(engine, 'jtree_dbn_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/marginal_family.m new file mode 100644 index 00000000..1fe59f61 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/marginal_family.m @@ -0,0 +1,26 @@ +function m = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_dbn) +% marginal = marginal_family(engine, i, t) + +% This is just like inf_engine/marginal_family, except when we call +% marginal_nodes, we provide a 4th argument, to tell it's a family. + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +bnet = bnet_from_engine(engine); +if t==1 + m = marginal_nodes(engine, family(bnet.dag, i), t, add_ev, 1); +else + ss = length(bnet.intra); + fam = family(bnet.dag, i+ss); + if any(fam<=ss) + % i has a parent in the preceeding slice + % Hence the lowest numbered slice containing the family is t-1 + m = marginal_nodes(engine, fam, t-1, add_ev, 1); + else + % The family all fits inside slice t + % Hence shift the indexes back to slice 1 + m = marginal_nodes(engine, fam-ss, t, add_ev, 1); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..c9a40488 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_dbn_inf_engine/marginal_nodes.m @@ -0,0 +1,66 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev, fam) +% MARGINAL_NODES Compute the marginal on the specified query nodes (bk) +% +% marginal = marginal_nodes(engine, i, t) +% returns Pr(X(i,t) | Y(1:T)), where X(i,t) is the i'th node in the t'th slice. +% +% marginal = marginal_nodes(engine, query, t) +% returns Pr(X(query(1),t), ... X(query(end),t) | Y(1:T)), +% where 't' specifies the time slice of the earliest node in the query. +% 'query' cannot span more than 2 time slices. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3. +% +% marginal = marginal_nodes(engine, nodes, t, add_ev, fam) +% add_ev is an optional argument; if 1, we will "inflate" the marginal of observed nodes +% to their original size, adding 0s to the positions which contradict the evidence + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end +if nargin < 5, fam = 0; end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); + +if t==1 | t==engine.T + slice = t; + nodes2 = nodes; +elseif mysubset(nodes, engine.persist) + slice = t-1; + nodes2 = nodes+ss; +else + slice = t; + nodes2 = nodes; +end + +%disp(['computing marginal on ' num2str(nodes) ' t = ' num2str(t) ' fam = ' num2str(fam)]); + +if t==engine.T + c = clq_containing_nodes(engine.jtree_engine1, nodes2, fam); +else + c = clq_containing_nodes(engine.jtree_engine, nodes2, fam); +end +if c == -1 + error(['no clique contains ' nodes2]) +end + + +%disp(['using ' num2str(nodes2) ' slice = ' num2str(slice) ' clq = ' num2str(c)]); + +bigpot = engine.clpot{c, slice}; + +pot = marginalize_pot(bigpot, nodes2, engine.maximize); +%pot = normalize_pot(pot); +marginal = pot_to_marginal(pot); + + +% we convert the domain to the unrolled numbering system +% so that add_ev_to_dmarginal (maybe called in update_ess) extracts the right evidence. +marginal.domain = nodes+(t-1)*ss; + +if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Entries new file mode 100644 index 00000000..2809c39f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Entries @@ -0,0 +1,6 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_unrolled_dbn_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Repository new file mode 100644 index 00000000..e9fd6fe5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..eafb1997 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Entries @@ -0,0 +1,3 @@ +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..2ad645e2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/marginal_family.m new file mode 100644 index 00000000..efb38b26 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/marginal_family.m @@ -0,0 +1,10 @@ +function marginal = marginal_family(engine, i, t) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_unrolled_dbn) +% marginal = marginal_family(engine, i, t) + +if nargin < 3, t = 1; end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +marginal = marginal_family(engine.sub_engine, i + (t-1)*ss); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/marginal_nodes.m new file mode 100644 index 00000000..b0cfb04e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/Old/marginal_nodes.m @@ -0,0 +1,18 @@ +function marginal = marginal_nodes(engine, nodes, t) +% MARGINAL_NODES Compute the marginal on the specified query nodes (jtree_unrolled_dbn) +% marginal = marginal_nodes(engine, nodes, t) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' must occur in some clique. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +query = nodes + (t-1)*ss; +marginal = marginal_nodes(engine.sub_engine, query); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/enter_evidence.m new file mode 100644 index 00000000..48b230c9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/enter_evidence.m @@ -0,0 +1,43 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree_unrolled_dbn) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% filter - if 1, does filtering (not supported), else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +if filter + error('jtree_unrolled_dbn does not support filtering') +end + +if size(evidence,2) ~= engine.nslices + error(['engine was created assuming there are ' num2str(engine.nslices) ... + ' slices, but evidence has ' num2str(size(evidence,2))]) +end + +[engine.unrolled_engine, loglik] = enter_evidence(engine.unrolled_engine, evidence, 'maximize', maximize); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/jtree_unrolled_dbn_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/jtree_unrolled_dbn_inf_engine.m new file mode 100644 index 00000000..156c6ee2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/jtree_unrolled_dbn_inf_engine.m @@ -0,0 +1,57 @@ +function engine = jtree_unrolled_dbn_inf_engine(bnet, T, varargin) +% JTREE_UNROLLED_DBN_INF_ENGINE Unroll the DBN for T time-slices and apply jtree to the resulting static net +% engine = jtree_unrolled_dbn_inf_engine(bnet, T, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% useC - 1 means use jtree_C_inf_engine instead of jtree_inf_engine [0] +% constrained - 1 means we constrain ourselves to eliminate slice t before t+1 [1] +% +% e.g., engine = jtree_unrolled_inf_engine(bnet, 'useC', 1); + +% set default params +N = length(bnet.intra); +useC = 0; +constrained = 1; + +if nargin >= 3 + args = varargin; + nargs = length(args); + if isstr(args{1}) + for i=1:2:nargs + switch args{i}, + case 'useC', useC = args{i+1}; + case 'constrained', constrained = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end + else + error(['invalid argument name ' args{1}]); + end +end + +bnet2 = dbn_to_bnet(bnet, T); +ss = length(bnet.intra); +engine.ss = ss; + +% If constrained_order = 1 we constrain ourselves to eliminate slice t before t+1. +% This prevents cliques containing nodes from far-apart time-slices. +if constrained + stages = num2cell(unroll_set(1:ss, ss, T), 1); +else + stages = { 1:length(bnet2.dag) }; +end +if useC + jengine = jtree_C_inf_engine(bnet2, 'stages', stages); +else + jengine = jtree_inf_engine(bnet2, 'stages', stages); +end + +engine.unrolled_engine = jengine; +% we don't inherit from jtree_inf_engine, because that would only store bnet2, +% and we would lose access to the DBN-specific fields like intra/inter + +engine.nslices = T; +engine = class(engine, 'jtree_unrolled_dbn_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/marginal_family.m new file mode 100644 index 00000000..a40f2974 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/marginal_family.m @@ -0,0 +1,11 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_unrolled_dbn) +% marginal = marginal_family(engine, i, t) + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end +assert(~add_ev); + +%marginal = marginal_family(engine.unrolled_engine, i + (t-1)*engine.ss, add_ev); +marginal = marginal_family(engine.unrolled_engine, i + (t-1)*engine.ss); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..0fb095e5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/marginal_nodes.m @@ -0,0 +1,16 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (loopy_unrolled_dbn) +% marginal = marginal_nodes(engine, nodes, t) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' must occur in some clique. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +marginal = marginal_nodes(engine.unrolled_engine, nodes + (t-1)*engine.ss, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/update_engine.m new file mode 100644 index 00000000..5c42d4f6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@jtree_unrolled_dbn_inf_engine/update_engine.m @@ -0,0 +1,7 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (jtree_unrolled_dbn) +% engine = update_engine(engine, newCPDs) + +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +engine.unrolled_engine = update_engine(engine.unrolled_engine, newCPDs); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Entries new file mode 100644 index 00000000..dce274e1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Entries @@ -0,0 +1,5 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/kalman_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Repository new file mode 100644 index 00000000..674f2eea --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@kalman_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/enter_evidence.m new file mode 100644 index 00000000..4ba51942 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/enter_evidence.m @@ -0,0 +1,83 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (kalman) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (same as sum-product for Gaussians!), else sum-product [0] +% filter - if 1, do filtering, else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +assert(~maximize); + +bnet = bnet_from_engine(engine); +n = length(bnet.intra); +onodes = bnet.observed; +hnodes = mysetdiff(1:n, onodes); +T = size(evidence, 2); +ns = bnet.node_sizes; +O = sum(ns(onodes)); +data = reshape(cat(1, evidence{onodes,:}), [O T]); + +A = engine.trans_mat; +C = engine.obs_mat; +Q = engine.trans_cov; +R = engine.obs_cov; +init_x = engine.init_state; +init_V = engine.init_cov; + +if filter + [x, V, VV, loglik] = kalman_filter(data, A, C, Q, R, init_x, init_V); +else + [x, V, VV, loglik] = kalman_smoother(data, A, C, Q, R, init_x, init_V); +end + + +% Wrap the posterior inside a potential, so it can be marginalized easily +engine.one_slice_marginal = cell(1,T); +engine.two_slice_marginal = cell(1,T); +ns(onodes) = 0; +ns(onodes+n) = 0; +ss = length(bnet.intra); +for t=1:T + dom = (1:n); + engine.one_slice_marginal{t} = mpot(dom+(t-1)*ss, ns(dom), 1, x(:,t), V(:,:,t)); +end +% for t=1:T-1 +% dom = (1:(2*n)); +% mu = [x(:,t); x(:,t)]; +% Sigma = [V(:,:,t) VV(:,:,t+1)'; +% VV(:,:,t+1) V(:,:,t+1)]; +% engine.two_slice_marginal{t} = mpot(dom+(t-1)*ss, ns(dom), 1, mu, Sigma); +% end +for t=2:T + %dom = (1:(2*n)); + current_slice = hnodes; + next_slice = hnodes + ss; + dom = [current_slice next_slice]; + mu = [x(:,t-1); x(:,t)]; + Sigma = [V(:,:,t-1) VV(:,:,t)'; + VV(:,:,t) V(:,:,t)]; + engine.two_slice_marginal{t-1} = mpot(dom+(t-2)*ss, ns(dom), 1, mu, Sigma); +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/kalman_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/kalman_inf_engine.m new file mode 100644 index 00000000..df03a56f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/kalman_inf_engine.m @@ -0,0 +1,23 @@ +function engine = kalman_inf_engine(bnet) +% KALMAN_INF_ENGINE Inference engine for Linear-Gaussian state-space models. +% engine = kalman_inf_engine(bnet) +% +% 'onodes' specifies which nodes are observed; these must be leaves. +% The remaining nodes are all hidden. All nodes must have linear-Gaussian CPDs. +% The hidden nodes must be persistent, i.e., they must have children in +% the next time slice. In addition, they may not have any children within the current slice, +% except to the observed leaves. In other words, the topology must be isomorphic to a standard LDS. +% +% There are many derivations of the filtering and smoothing equations for Linear Dynamical +% Systems in the literature. I particularly like the following +% - "From HMMs to LDSs", T. Minka, MIT Tech Report, (no date), available from +% ftp://vismod.www.media.mit.edu/pub/tpminka/papers/minka-lds-tut.ps.gz + +[engine.trans_mat, engine.trans_cov, engine.obs_mat, engine.obs_cov, engine.init_state, engine.init_cov] = ... + dbn_to_lds(bnet); + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.one_slice_marginal = []; +engine.two_slice_marginal = []; + +engine = class(engine, 'kalman_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..738c30dc --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/marginal_nodes.m @@ -0,0 +1,25 @@ +function marginal = marginal_nodes(engine, nodes, t) +% MARGINAL_NODES Compute the marginal on the specified query nodes (kalman) +% marginal = marginal_nodes(engine, nodes, t) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' cannot span more than 2 time slices. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +if all(nodes <= ss) + bigpot = engine.one_slice_marginal{t}; +else + bigpot = engine.two_slice_marginal{t}; +end + +nodes = nodes + (t-1)*ss; +pot = marginalize_pot(bigpot, nodes); +marginal = pot_to_marginal(pot); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..9a351a87 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Entries @@ -0,0 +1,3 @@ +/dbn_to_lds.m/1.1.1.1/Wed May 29 15:59:56 2002// +/extract_params_from_gbn.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..3f67aee0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@kalman_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/dbn_to_lds.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/dbn_to_lds.m new file mode 100644 index 00000000..6249ac0d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/dbn_to_lds.m @@ -0,0 +1,26 @@ +function [trans_mat, trans_cov, obs_mat, obs_cov, init_state, init_cov] = dbn_to_lds(bnet) +% DBN_TO_LDS Compute the Linear Dynamical System parameters from the Gaussian DBN. +% [trans_mat, trans_cov, obs_mat, obs_cov, init_state, init_cov] = dbn_to_lds(bnet) + +onodes = bnet.observed; +ss = length(bnet.intra); +num_nodes = ss*2; +assert(isequal(bnet.cnodes_slice, 1:ss)); +[W,D,mu] = extract_params_from_gbn(bnet); + +hnodes = mysetdiff(1:ss, onodes); +bs = bnet.node_sizes(:); % block sizes + +obs_mat = W(block(hnodes,bs), block(onodes,bs))'; +u = block(onodes,bs); +obs_cov = D(u,u); + +trans_mat = W(block(hnodes,bs), block(hnodes + ss, bs))'; +u = block(hnodes + ss, bs); +trans_cov = D(u,u); + +u = block(hnodes,bs); +init_cov = D(u,u); +init_state = mu(u); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/extract_params_from_gbn.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/extract_params_from_gbn.m new file mode 100644 index 00000000..86345830 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/private/extract_params_from_gbn.m @@ -0,0 +1,38 @@ +function [B,D,mu] = extract_params_from_gbn(bnet) +% Extract all the local parameters of each Gaussian node, and collect them into global matrices. +% [B,D,mu] = extract_params_from_gbn(bnet) +% +% B(i,j) is a block matrix that contains the transposed weight matrix from node i to node j. +% D(i,i) is a block matrix that contains the noise covariance matrix for node i. +% mu(i) is a block vector that contains the shifted noise mean for node i. + +% In Shachter's model, the mean of each node in the global gaussian is +% the same as the node's local unconditional mean. +% In Alag's model (which we use), the global mean gets shifted. + + +num_nodes = length(bnet.dag); +bs = bnet.node_sizes(:); % bs = block sizes +N = sum(bs); % num scalar nodes + +B = zeros(N,N); +D = zeros(N,N); +mu = zeros(N,1); + +for i=1:num_nodes % in topological order + ps = parents(bnet.dag, i); + e = bnet.equiv_class(i); + %[m, Sigma, weights] = extract_params_from_CPD(bnet.CPD{e}); + s = struct(bnet.CPD{e}); % violate privacy of object + m = s.mean; Sigma = s.cov; weights = s.weights; + if length(ps) == 0 + mu(block(i,bs)) = m; + else + mu(block(i,bs)) = m + weights * mu(block(ps,bs)); + end + B(block(ps,bs), block(i,bs)) = weights'; + D(block(i,bs), block(i,bs)) = Sigma; +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/update_engine.m new file mode 100644 index 00000000..d89605e7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@kalman_inf_engine/update_engine.m @@ -0,0 +1,9 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (kalman) +% engine = update_engine(engine, newCPDs) + +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +[engine.trans_mat, engine.trans_cov, engine.obs_mat, engine.obs_cov, engine.init_state, engine.init_cov] = ... + dbn_to_lds(bnet_from_engine(engine)); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Entries new file mode 100644 index 00000000..84a6daa1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Entries @@ -0,0 +1,6 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_ev.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/pearl_dbn_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/Old//// +D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Repository new file mode 100644 index 00000000..b7a44128 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@pearl_dbn_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..d729c48f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Entries @@ -0,0 +1,8 @@ +/correct_smooth.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/filter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/filter_evidence_obj_oriented.m/1.1.1.1/Wed May 29 15:59:56 2002// +/smooth_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/smooth_evidence_fast.m/1.1.1.1/Wed May 29 15:59:56 2002// +/wrong_smooth.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..db9771c6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/correct_smooth.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/correct_smooth.m new file mode 100644 index 00000000..275afd41 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/correct_smooth.m @@ -0,0 +1,244 @@ +function [marginal, msg, loglik] = smooth_evidence(engine, evidence) +% [marginal, msg, loglik] = smooth_evidence(engine, evidence) (pearl_dbn) + +disp('warning: broken'); + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +bnet2 = dbn_to_bnet(bnet, T); +ns = bnet2.node_sizes; +hnodes = mysetdiff(1:ss, engine.onodes); +hnodes = hnodes(:)'; + +onodes2 = unroll_set(engine.onodes(:), ss, T); +onodes2 = onodes2(:)'; + +hnodes2 = unroll_set(hnodes(:), ss, T); +hnodes2 = hnodes2(:)'; + +[engine.parent_index, engine.child_index] = mk_pearl_msg_indices(bnet2); + +msg = init_msgs(bnet2.dag, ns, evidence, bnet2.equiv_class, bnet2.CPD); + +verbose = 0; + +niter = 1; +for iter=1:niter + % FORWARD + for t=1:T + if verbose, fprintf('t=%d\n', t); end + % observed leaves send lambda to parents + for i=engine.onodes(:)' + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + for p=ps(:)' + j = engine.child_index{p}(n); % n is p's j'th child + if t > 1 + e = bnet.equiv_class(i, 2); + else + e = bnet.equiv_class(i, 1); + end + lam_msg = normalise(compute_lambda_msg(bnet.CPD{e}, n, ps, msg, p)); + msg{p}.lambda_from_child{j} = lam_msg; + if verbose, fprintf('%d sends lambda to %d\n', n, p); disp(lam_msg); end + end + end + + % update pi + for i=hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + if t==1 + e = bnet.equiv_class(i,1); + else + e = bnet.equiv_class(i,2); + end + msg{n}.pi = compute_pi(bnet.CPD{e}, n, ps, msg); + if verbose, fprintf('%d computes pi\n', n); disp(msg{n}.pi); end + end + + % send pi msg to children + for i=hnodes + n = i + (t-1)*ss; + %cs = myintersect(children(bnet2.dag, n), hnodes2); + cs = children(bnet2.dag, n); + for c=cs(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + pi_msg = normalise(compute_pi_msg(n, cs, msg, c, ns)); + msg{c}.pi_from_parent{j} = pi_msg; + if verbose, fprintf('%d sends pi to %d\n', n, c); disp(pi_msg); end + end + end + end + + % BACKWARD + for t=T:-1:1 + if verbose, fprintf('t = %d\n', t); end + % update lambda + for i=hnodes + n = i + (t-1)*ss; + cs = children(bnet2.dag, n); + msg{n}.lambda = compute_lambda(n, cs, msg, ns); + if verbose, fprintf('%d computes lambda\n', n); disp(msg{n}.lambda); end + end + % send lambda msgs to parents + for i=hnodes + n = i + (t-1)*ss; + %ps = myintersect(parents(bnet2.dag, n), hnodes2); + ps = parents(bnet2.dag, n); + for p=ps(:)' + j = engine.child_index{p}(n); % n is p's j'th child + if t > 1 + e = bnet.equiv_class(i, 2); + else + e = bnet.equiv_class(i, 1); + end + lam_msg = normalise(compute_lambda_msg(bnet.CPD{e}, n, ps, msg, p)); + msg{p}.lambda_from_child{j} = lam_msg; + if verbose, fprintf('%d sends lambda to %d\n', n, p); disp(lam_msg); end + end + end + end + +end + + +marginal = cell(ss,T); +lik = zeros(1,ss*T); +for t=1:T + for i=1:ss + n = i + (t-1)*ss; + [bel, lik(n)] = normalise(msg{n}.pi .* msg{n}.lambda); + marginal{i,t} = bel; + end +end + +loglik = sum(log(lik)); + + + +%%%%%%% + +function lambda = compute_lambda(n, cs, msg, ns) +% Pearl p183 eq 4.50 +lambda = prod_lambda_msgs(n, cs, msg, ns); + +%%%%%%% + +function pi_msg = compute_pi_msg(n, cs, msg, c, ns) +% Pearl p183 eq 4.53 and 4.51 +pi_msg = msg{n}.pi .* prod_lambda_msgs(n, cs, msg, ns, c); + +%%%%%%%%% + +function lam = prod_lambda_msgs(n, cs, msg, ns, except) + +if nargin < 5, except = -1; end + +lam = msg{n}.lambda_from_self(:); +lam = ones(ns(n), 1); +for i=1:length(cs) + c = cs(i); + if c ~= except + lam = lam .* msg{n}.lambda_from_child{i}; + end +end + + +%%%%%%%%% + +function msg = init_msgs(dag, ns, evidence, eclass, CPD) +% INIT_MSGS Initialize the lambda/pi message and state vectors (pearl_dbn) +% msg = init_msgs(dag, ns, evidence) + +N = length(dag); +msg = cell(1,N); +observed = ~isemptycell(evidence(:)); + +for n=1:N + ps = parents(dag, n); + msg{n}.pi_from_parent = cell(1, length(ps)); + for i=1:length(ps) + p = ps(i); + msg{n}.pi_from_parent{i} = ones(ns(p), 1); + end + + cs = children(dag, n); + msg{n}.lambda_from_child = cell(1, length(cs)); + for i=1:length(cs) + c = cs(i); + msg{n}.lambda_from_child{i} = ones(ns(n), 1); + end + + msg{n}.lambda = ones(ns(n), 1); + msg{n}.lambda_from_self = ones(ns(n), 1); + msg{n}.pi = ones(ns(n), 1); + + % Initialize the lambdas with any evidence + if observed(n) + v = evidence{n}; + %msg{n}.lambda_from_self = zeros(ns(n), 1); + %msg{n}.lambda_from_self(v) = 1; % delta function + msg{n}.lambda = zeros(ns(n), 1); + msg{n}.lambda(v) = 1; % delta function + end + +end + + +%%%%%%%% + +function msg = init_ev_msgs(engine, evidence, msg) + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +pot_type = 'd'; +t = 1; +hnodes = mysetdiff(1:ss, engine.onodes); +for i=engine.onodes(:)' + fam = family(bnet.dag, i); + e = bnet.equiv_class(i, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + temp = pot_to_marginal(CPDpot); + msg{i}.lambda_from_self = temp.T; +end +for t=2:T + for i=engine.onodes(:)' + fam = family(bnet.dag, i, 2); % extract from slice t + e = bnet.equiv_class(i, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + temp = pot_to_marginal(CPDpot); + n = i + (t-1)*ss; + msg{n}.lambda_from_self = temp.T; + end +end + + +%%%%%%%%%%% + +function msg = init_ev_msgs2(engine, evidence, msg) + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +pot_type = 'd'; +t = 1; +hnodes = mysetdiff(1:ss, engine.onodes); +for i=engine.onodes(:)' + fam = family(bnet.dag, i); + e = bnet.equiv_class(i, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + temp = pot_to_marginal(CPDpot); + msg{i}.lambda_from_self = temp.T; +end +for t=2:T + for i=engine.onodes(:)' + fam = family(bnet.dag, i, 2); % extract from slice t + e = bnet.equiv_class(i, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + temp = pot_to_marginal(CPDpot); + n = i + (t-1)*ss; + msg{n}.lambda_from_self = temp.T; + end +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/enter_evidence.m new file mode 100644 index 00000000..18e7519b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/enter_evidence.m @@ -0,0 +1,123 @@ +function [engine, loglik] = enter_evidence(engine, evidence, filter) +% ENTER_EVIDENCE Add the specified evidence to the network (pearl_dbn) +% [engine, loglik] = enter_evidence(engine, evidence, filter) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% If filter = 1, we do filtering, otherwise smoothing (default). + +if nargin < 3, filter = 0; end + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +bnet2 = dbn_to_bnet(bnet, T); +ns = bnet2.node_sizes; +hnodes = mysetdiff(1:ss, engine.onodes); +hnodes = hnodes(:)'; + +[engine.parent_index, engine.child_index] = mk_pearl_msg_indices(bnet2); + +msg = init_msgs(bnet2.dag, ns, evidence); +msg = init_ev_msgs(engine, evidence, msg); + +niter = 1; +for iter=1:niter + % FORWARD + for t=1:T + % update pi + for i=1:ss %hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + if t==1 + e = bnet.equiv_class(i,1); + else + e = bnet.equiv_class(i,2); + end + msg{n}.pi = compute_pi(bnet.CPD{e}, n, ps, msg); + %msg{n}.pi = normalise(msg{n}.pi(:) .* msg{n}.lambda_from_self(:)); + end + % send pi msg to children + for i=1:ss % hnodes + n = i + (t-1)*ss; + cs = children(bnet2.dag, n); + for c=cs(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + msg{c}.pi_from_parent{j} = normalise(compute_pi_msg(n, cs, msg, c, ns)); + end + end + end + + if filter + disp('skipping smoothing'); + break; + end + + % BACKWARD + for t=T:-1:1 + % update lambda + for i=1:ss % hnodes + n = i + (t-1)*ss; + cs = children(bnet2.dag, n); + msg{n}.lambda = compute_lambda(n, cs, msg, ns); + end + % send lambda msgs to parents + for i=1:ss % hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + for p=ps(:)' + j = engine.child_index{p}(n); % n is p's j'th child + if t > 1 + e = bnet.equiv_class(i, 2); + else + e = bnet.equiv_class(i, 1); + end + msg{p}.lambda_from_child{j} = normalise(compute_lambda_msg(bnet.CPD{e}, n, ps, msg, p)); + end + end + end + +end + + +engine.marginal = cell(ss,T); +lik = zeros(1,ss*T); +for t=1:T + for i=1:ss + n = i + (t-1)*ss; + [bel, lik(n)] = normalise(msg{n}.pi .* msg{n}.lambda); + engine.marginal{i,t} = bel; + end +end + +engine.evidence = evidence; % needed by marginal_nodes and marginal_family +engine.msg = msg; % needed by marginal_family +loglik = sum(log(lik)); + + + +%%%%%%% + +function lambda = compute_lambda(n, cs, msg, ns) +% Pearl p183 eq 4.50 +lambda = prod_lambda_msgs(n, cs, msg, ns); + +%%%%%%% + +function pi_msg = compute_pi_msg(n, cs, msg, c, ns) +% Pearl p183 eq 4.53 and 4.51 +pi_msg = msg{n}.pi .* prod_lambda_msgs(n, cs, msg, ns, c); + +%%%%%%%%% + +function lam = prod_lambda_msgs(n, cs, msg, ns, except) + +if nargin < 5, except = -1; end + +lam = msg{n}.lambda_from_self(:); +%lam = ones(ns(n), 1); +for i=1:length(cs) + c = cs(i); + if c ~= except + lam = lam .* msg{n}.lambda_from_child{i}; + end +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/filter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/filter_evidence.m new file mode 100644 index 00000000..a3462437 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/filter_evidence.m @@ -0,0 +1,146 @@ +function [marginal, msg, loglik] = filter_evidence(engine, evidence) + +error('broken'); + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +onodes = engine.onodes; +hnodes = mysetdiff(1:ss, onodes); +hnodes = hnodes(:)'; + +ns = bnet.node_sizes(:); +onodes2 = [onodes(:); onodes(:)+ss]; +ns(onodes2) = 1; + +verbose = 1; +if verbose, fprintf('\nnew filtering\n'); end + +pot_type = 'd'; +niter = engine.max_iter; + +% msg(i1,t1,i2,j2) (i1,t1) -> (i2,t2) +%lambda_msg = cell(ss,T,ss,T); +%pi_msg = cell(ss,T,ss,T); + +% intra_lambda_msg(i,j,t) (i,t) -> (j,t), i is child +% inter_lambda_msg(i,j,t) (i,t+1) -> (j,t), i is child +% inter_pi_msg(i,j,t) (i,t-1) -> (j,t), i is parent +intra_lambda_msg = cell(ss,ss,T); +inter_lambda_msg = cell(ss,ss,T); +inter_pi_msg = cell(ss,ss,T); + +lambda = cell(ss,T); +pi = cell(ss,T); + +for t=1:T + for i=1:ss + lambda{i,t} = ones(ns(i), 1); + pi{i,t} = ones(ns(i), 1); + + cs = children(bnet.intra, i); + for c=cs(:)' + intra_lambda_msg{c,i,t} = ones(ns(i),1); + end + + cs = children(bnet.inter, i); + for c=cs(:)' + inter_lambda_msg{c,i,t} = ones(ns(i),1); + end + + ps = parents(bnet.inter, i); + for p=ps(:)' + inter_pi_msg{p,i,t} = ones(ns(i), 1); % not used for t==1 + end + end +end + +% each hidden node absorbs lambda from its observed child (if any) +for t=1:T + for i=hnodes + c = engine.obschild(i); + if c > 0 + if t==1 + fam = family(bnet.dag, c); + e = bnet.equiv_class(c, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + else + fam = family(bnet.dag, c, 2); % within 2 slice network + e = bnet.equiv_class(c, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + end + temp = pot_to_marginal(CPDpot); + lam_msg = normalise(temp.T); + %if verbose, fprintf('(%d,%d) sends lambda to (%d,%d)\n', c,t, i,t); disp(lam_msg); end + intra_lambda_msg{c,i,t} = lam_msg; + end + end +end + +% FORWARD +for t=1:T + % update pi + for i=hnodes + if t==1 + e = bnet.equiv_class(i,1); + temp = struct(bnet.CPD{e}); + pi{i,t} = temp.CPT; + else + e = bnet.equiv_class(i,2); + temp = struct(bnet.CPD{e}); + ps = parents(bnet.inter, i); + dom = [ps i+ss]; + pot = dpot(dom, ns(dom), temp.CPT); + for p=ps(:)' + temp = dpot(p, ns(p), inter_pi_msg{p,i,t}); + pot = multiply_by_pot(pot, temp); + end + pot = marginalize_pot(pot, i+ss); + temp = pot_to_marginal(pot); + pi{i,t} = temp.T; + %if verbose, fprintf('(%d,%d) computes pi\n', i,t); disp(pi{i,t}); end + end + + c = engine.obschild(i); + if c > 0 + pi{i,t} = normalise(pi{i,t} .* intra_lambda_msg{c,i,t}); + end + %if verbose, fprintf('(%d,%d) recomputes pi\n', i,t); disp(pi{i,t}); end + if verbose, fprintf('%d recomputes pi\n', i+(t-1)*ss); disp(pi{i,t}); end + end + + % send pi msg to children + for i=hnodes + cs = children(bnet.inter, i); + for c=cs(:)' + pot = pi{i,t}; + for k=cs(:)' + if k ~= c + pot = pot .* inter_lambda_msg{k,i,t}; + end + end + cs2 = children(bnet.intra, i); + for k=cs2(:)' + pot = pot .* intra_lambda_msg{k,i,t}; + end + pot = normalise(pot); + %if verbose, fprintf('(%d,%d) sends pi to (%d,%d)\n', i,t, c,t+1); disp(pot); end + if verbose, fprintf('%d sends pi to %d\n', i+(t-1)*ss, c+t*ss); disp(pot); end + inter_pi_msg{i,c,t+1} = pot; + end + end +end + + +marginal = cell(ss,T); +for t=1:T + for i=hnodes + %marginal{i,t} = normalise(pi{i,t} .* lambda{i,t}); + marginal{i,t} = normalise(pi{i,t}); + end +end + +loglik = 0; + +msg.inter_pi_msg = inter_pi_msg; +msg.inter_lambda_msg = inter_lambda_msg; +msg.intra_lambda_msg = intra_lambda_msg; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/filter_evidence_obj_oriented.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/filter_evidence_obj_oriented.m new file mode 100644 index 00000000..fec80b11 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/filter_evidence_obj_oriented.m @@ -0,0 +1,158 @@ +function [marginal, msg, loglik] = filter_evidence_old(engine, evidence) +% [marginal, msg, loglik] = filter_evidence(engine, evidence) (pearl_dbn) + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +bnet2 = dbn_to_bnet(bnet, T); +ns = bnet2.node_sizes; +hnodes = mysetdiff(1:ss, engine.onodes); +hnodes = hnodes(:)'; + +[engine.parent_index, engine.child_index] = mk_pearl_msg_indices(bnet2); + +msg = init_msgs(bnet2.dag, ns, evidence); +msg = init_ev_msgs(engine, evidence, msg); + +verbose = 1; +if verbose, fprintf('\nold filtering\n'); end + +for t=1:T + % update pi + for i=hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + if t==1 + e = bnet.equiv_class(i,1); + else + e = bnet.equiv_class(i,2); + end + msg{n}.pi = compute_pi(bnet.CPD{e}, n, ps, msg); + %if verbose, fprintf('%d computes pi\n', n); disp(msg{n}.pi); end + msg{n}.pi = normalise(msg{n}.pi(:) .* msg{n}.lambda_from_self(:)); + if verbose, fprintf('%d recomputes pi\n', n); disp(msg{n}.pi); end + end + % send pi msg to children + for i=hnodes + n = i + (t-1)*ss; + cs = children(bnet2.dag, n); + for c=cs(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + pi_msg = normalise(compute_pi_msg(n, cs, msg, c, ns)); + msg{c}.pi_from_parent{j} = pi_msg; + if verbose, fprintf('%d sends pi to %d\n', n,c); disp(pi_msg); end + end + end +end + + +marginal = cell(ss,T); +lik = zeros(1,ss*T); +for t=1:T + for i=1:ss + n = i + (t-1)*ss; + %[bel, lik(n)] = normalise(msg{n}.pi .* msg{n}.lambda); + [bel, lik(n)] = normalise(msg{n}.pi); + marginal{i,t} = bel; + end +end + +loglik = sum(log(lik)); + + + +%%%%%%% + +function lambda = compute_lambda(n, cs, msg, ns) +% Pearl p183 eq 4.50 +lambda = prod_lambda_msgs(n, cs, msg, ns); + +%%%%%%% + +function pi_msg = compute_pi_msg(n, cs, msg, c, ns) +% Pearl p183 eq 4.53 and 4.51 +pi_msg = msg{n}.pi .* prod_lambda_msgs(n, cs, msg, ns, c); + +%%%%%%%%% + +function lam = prod_lambda_msgs(n, cs, msg, ns, except) + +if nargin < 5, except = -1; end + +%lam = msg{n}.lambda_from_self(:); +lam = ones(ns(n), 1); +for i=1:length(cs) + c = cs(i); + if c ~= except + lam = lam .* msg{n}.lambda_from_child{i}; + end +end + + +%%%%%%%%%%% + +function msg = init_msgs(dag, ns, evidence) +% INIT_MSGS Initialize the lambda/pi message and state vectors (pearl_dbn) +% msg = init_msgs(dag, ns, evidence) +% +% We assume all the hidden nodes are discrete. + +N = length(dag); +msg = cell(1,N); +observed = ~isemptycell(evidence(:)); + +for n=1:N + ps = parents(dag, n); + msg{n}.pi_from_parent = cell(1, length(ps)); + for i=1:length(ps) + p = ps(i); + msg{n}.pi_from_parent{i} = ones(ns(p), 1); + end + + cs = children(dag, n); + msg{n}.lambda_from_child = cell(1, length(cs)); + for i=1:length(cs) + c = cs(i); + msg{n}.lambda_from_child{i} = ones(ns(n), 1); + end + + msg{n}.lambda = ones(ns(n), 1); + msg{n}.pi = ones(ns(n), 1); + + msg{n}.lambda_from_self = ones(ns(n), 1); +end + + +%%%%%%%%% + +function msg = init_ev_msgs(engine, evidence, msg) +% Initialize the lambdas with any evidence + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +pot_type = 'd'; +t = 1; +hnodes = mysetdiff(1:ss, engine.onodes); +for i=hnodes(:)' + c = engine.obschild(i); + if c > 0 + fam = family(bnet.dag, c); + e = bnet.equiv_class(c, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + temp = pot_to_marginal(CPDpot); + n = i; + msg{n}.lambda_from_self = temp.T; + end +end +for t=2:T + for i=hnodes(:)' + c = engine.obschild(i); + if c > 0 + fam = family(bnet.dag, c, 2); + e = bnet.equiv_class(c, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + temp = pot_to_marginal(CPDpot); + n = i + (t-1)*ss; + msg{n}.lambda_from_self = temp.T; + end + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/smooth_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/smooth_evidence.m new file mode 100644 index 00000000..554b579f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/smooth_evidence.m @@ -0,0 +1,181 @@ +function [marginal, msg, loglik] = smooth_evidence(engine, evidence) + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +onodes = engine.onodes; +hnodes = mysetdiff(1:ss, onodes); +hnodes = hnodes(:)'; + +ns = bnet.node_sizes(:); +onodes2 = [onodes(:); onodes(:)+ss]; +ns(onodes2) = 1; + +verbose = 0; +pot_type = 'd'; +niter = engine.max_iter; + +if verbose, fprintf('new smooth\n'); end + +% msg(i1,t1,i2,j2) (i1,t1) -> (i2,t2) +%lambda_msg = cell(ss,T,ss,T); +%pi_msg = cell(ss,T,ss,T); + +% intra_lambda_msg(i,j,t) (i,t) -> (j,t), i is child +% inter_lambda_msg(i,j,t) (i,t+1) -> (j,t), i is child +% inter_pi_msg(i,j,t) (i,t-1) -> (j,t), i is parent +intra_lambda_msg = cell(ss,ss,T); +inter_lambda_msg = cell(ss,ss,T); +inter_pi_msg = cell(ss,ss,T); + +lambda = cell(ss,T); +pi = cell(ss,T); + +for t=1:T + for i=1:ss + lambda{i,t} = ones(ns(i), 1); + pi{i,t} = ones(ns(i), 1); + + cs = children(bnet.intra, i); + for c=cs(:)' + intra_lambda_msg{c,i,t} = ones(ns(i),1); + end + + cs = children(bnet.inter, i); + for c=cs(:)' + inter_lambda_msg{c,i,t} = ones(ns(i),1); + end + + ps = parents(bnet.inter, i); + for p=ps(:)' + inter_pi_msg{p,i,t} = ones(ns(i), 1); % not used for t==1 + end + end +end + + +% each hidden node absorbs lambda from its observed child (if any) +for t=1:T + for i=hnodes + c = engine.obschild(i); + if c > 0 + if t==1 + fam = family(bnet.dag, c); + e = bnet.equiv_class(c, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + else + fam = family(bnet.dag, c, 2); % within 2 slice network + e = bnet.equiv_class(c, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + end + temp = pot_to_marginal(CPDpot); + lam_msg = normalise(temp.T); + intra_lambda_msg{c,i,t} = lam_msg; + end + end +end + +for iter=1:engine.max_iter + % FORWARD + for t=1:T + % update pi + for i=hnodes + if t==1 + e = bnet.equiv_class(i,1); + CPD = struct(bnet.CPD{e}); + pi{i,t} = CPD.CPT; + else + e = bnet.equiv_class(i,2); + CPD = struct(bnet.CPD{e}); + ps = parents(bnet.inter, i); + dom = [ps i+ss]; + pot = dpot(dom, ns(dom), CPD.CPT); + for p=ps(:)' + temp = dpot(p, ns(p), inter_pi_msg{p,i,t}); + pot = multiply_by_pot(pot, temp); + end + pot = marginalize_pot(pot, i+ss); + temp = pot_to_marginal(pot); + pi{i,t} = temp.T; + end + if verbose, fprintf('%d updates pi\n', i+(t-1)*ss); disp(pi{i,t}); end + end + + % send pi msg to children + for i=hnodes + cs = children(bnet.inter, i); + for c=cs(:)' + pot = pi{i,t}; + for k=cs(:)' + if k ~= c + pot = pot .* inter_lambda_msg{k,i,t}; + end + end + cs2 = children(bnet.intra, i); + for k=cs2(:)' + pot = pot .* intra_lambda_msg{k,i,t}; + end + inter_pi_msg{i,c,t+1} = normalise(pot); + if verbose, fprintf('%d sends pi to %d\n', i+(t-1)*ss, c+t*ss); disp(inter_pi_msg{i,c,t+1}); end + end + end + end + + if verbose, fprintf('backwards\n'); end + % BACKWARD + for t=T:-1:1 + % update lambda + for i=hnodes + pot = ones(ns(i), 1); + cs = children(bnet.inter, i); + for c=cs(:)' + pot = pot .* inter_lambda_msg{c,i,t}; + end + cs = children(bnet.intra, i); + for c=cs(:)' + pot = pot .* intra_lambda_msg{c,i,t}; + end + lambda{i,t} = normalise(pot); + if verbose, fprintf('%d computes lambda\n', i+(t-1)*ss); disp(lambda{i,t}); end + end + + % send lambda msgs to hidden parents in prev slcie + for i=hnodes + ps = parents(bnet.inter, i); + if t > 1 + e = bnet.equiv_class(i, 2); + CPD = struct(bnet.CPD{e}); + fam = [ps i+ss]; + for p=ps(:)' + pot = dpot(fam, ns(fam), CPD.CPT); + temp = dpot(i+ss, ns(i), lambda{i,t}); + pot = multiply_by_pot(pot, temp); + for k=ps(:)' + if k ~= p + temp = dpot(k, ns(k), inter_pi_msg{k,i,t}); + pot = multiply_by_pot(pot, temp); + end + end + pot = marginalize_pot(pot, p); + temp = pot_to_marginal(pot); + inter_lambda_msg{i,p,t-1} = normalise(temp.T); + if verbose, fprintf('%d sends lambda to %d\n', i+(t-1)*ss, p+(t-2)*ss); disp(inter_lambda_msg{i,p,t-1}); end + end + end + end + end +end + + + +marginal = cell(ss,T); +for t=1:T + for i=hnodes + marginal{i,t} = normalise(pi{i,t} .* lambda{i,t}); + end +end + +loglik = 0; + +msg.inter_pi_msg = inter_pi_msg; +msg.inter_lambda_msg = inter_lambda_msg; +msg.intra_lambda_msg = intra_lambda_msg; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/smooth_evidence_fast.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/smooth_evidence_fast.m new file mode 100644 index 00000000..8f4ebd2f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/smooth_evidence_fast.m @@ -0,0 +1,179 @@ +function [marginal, msg, loglik] = smooth_evidence_fast(engine, evidence) + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +onodes = engine.onodes; +hnodes = mysetdiff(1:ss, onodes); +hnodes = hnodes(:)'; + +ns = bnet.node_sizes(:); +onodes2 = [onodes(:); onodes(:)+ss]; +ns(onodes2) = 1; + +verbose = 0; +pot_type = 'd'; +niter = engine.max_iter; + +if verbose, fprintf('new smooth\n'); end + +% msg(i1,t1,i2,j2) (i1,t1) -> (i2,t2) +%lambda_msg = cell(ss,T,ss,T); +%pi_msg = cell(ss,T,ss,T); + +% intra_lambda_msg(i,j,t) (i,t) -> (j,t), i is child +% inter_lambda_msg(i,j,t) (i,t+1) -> (j,t), i is child +% inter_pi_msg(i,j,t) (i,t-1) -> (j,t), i is parent +intra_lambda_msg = cell(ss,ss,T); +inter_lambda_msg = cell(ss,ss,T); +inter_pi_msg = cell(ss,ss,T); + +lambda = cell(ss,T); +pi = cell(ss,T); + +for t=1:T + for i=1:ss + lambda{i,t} = ones(ns(i), 1); + pi{i,t} = ones(ns(i), 1); + + cs = children(bnet.intra, i); + for c=cs(:)' + intra_lambda_msg{c,i,t} = ones(ns(i),1); + end + + cs = children(bnet.inter, i); + for c=cs(:)' + inter_lambda_msg{c,i,t} = ones(ns(i),1); + end + + ps = parents(bnet.inter, i); + for p=ps(:)' + inter_pi_msg{p,i,t} = ones(ns(i), 1); % not used for t==1 + end + end +end + + +% each hidden node absorbs lambda from its observed child (if any) +for t=1:T + for i=hnodes + c = engine.obschild(i); + if c > 0 + if t==1 + fam = family(bnet.dag, c); + e = bnet.equiv_class(c, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + else + fam = family(bnet.dag, c, 2); % within 2 slice network + e = bnet.equiv_class(c, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + end + temp = pot_to_marginal(CPDpot); + lam_msg = normalise(temp.T); + intra_lambda_msg{c,i,t} = lam_msg; + end + end +end + +for iter=1:engine.max_iter + % FORWARD + for t=1:T + % update pi + for i=hnodes + if t==1 + e = bnet.equiv_class(i,1); + temp = struct(bnet.CPD{e}); + pi{i,t} = temp.CPT; + else + e = bnet.equiv_class(i,2); + CPD = struct(bnet.CPD{e}); + ps = parents(bnet.inter, i); + temp = CPD.CPT; + for p=ps(:)' + temp(:) = temp(:) .* inter_pi_msg{p,i,t}(engine.mult_parent_ndx{i,p}); + end + dom = [ps i+ss]; + pot = dpot(dom, ns(dom), temp); + pot = marginalize_pot(pot, i+ss); + temp = pot_to_marginal(pot); + pi{i,t} = temp.T; + end + if verbose, fprintf('%d updates pi\n', i+(t-1)*ss); disp(pi{i,t}); end + end + + % send pi msg to children + for i=hnodes + cs = children(bnet.inter, i); + for c=cs(:)' + pot = pi{i,t}; + for k=cs(:)' + if k ~= c + pot = pot .* inter_lambda_msg{k,i,t}; + end + end + cs2 = children(bnet.intra, i); + for k=cs2(:)' + pot = pot .* intra_lambda_msg{k,i,t}; + end + inter_pi_msg{i,c,t+1} = normalise(pot); + if verbose, fprintf('%d sends pi to %d\n', i+(t-1)*ss, c+t*ss); disp(inter_pi_msg{i,c,t+1}); end + end + end + end + + if verbose, fprintf('backwards\n'); end + % BACKWARD + for t=T:-1:1 + % update lambda + for i=hnodes + pot = ones(ns(i), 1); + cs = children(bnet.inter, i); + for c=cs(:)' + pot = pot .* inter_lambda_msg{c,i,t}; + end + cs = children(bnet.intra, i); + for c=cs(:)' + pot = pot .* intra_lambda_msg{c,i,t}; + end + lambda{i,t} = normalise(pot); + if verbose, fprintf('%d computes lambda\n', i+(t-1)*ss); disp(lambda{i,t}); end + end + + % send lambda msgs to hidden parents in prev slcie + for i=hnodes + ps = parents(bnet.inter, i); + if t > 1 + e = bnet.equiv_class(i, 2); + CPD = struct(bnet.CPD{e}); + for p=ps(:)' + temp = CPD.CPT(:) .* lambda{i,t}(engine.mult_self_ndx{i}); + for k=ps(:)' + if k ~= p + temp(:) = temp(:) .* inter_pi_msg{k,i,t}(engine.mult_parent_ndx{i,k}); + end + end + fam = [ps i+ss]; + pot = dpot(fam, ns(fam), temp); + pot = marginalize_pot(pot, p); + temp = pot_to_marginal(pot); + inter_lambda_msg{i,p,t-1} = normalise(temp.T); + if verbose, fprintf('%d sends lambda to %d\n', i+(t-1)*ss, p+(t-2)*ss); disp(inter_lambda_msg{i,p,t-1}); end + end + end + end + end +end + + + +marginal = cell(ss,T); +for t=1:T + for i=hnodes + marginal{i,t} = normalise(pi{i,t} .* lambda{i,t}); + end +end + +loglik = 0; + +msg.inter_pi_msg = inter_pi_msg; +msg.inter_lambda_msg = inter_lambda_msg; +msg.intra_lambda_msg = intra_lambda_msg; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/wrong_smooth.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/wrong_smooth.m new file mode 100644 index 00000000..d66d61ad --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/Old/wrong_smooth.m @@ -0,0 +1,210 @@ +function [marginal, msg, loglik] = smooth_evidence(engine, evidence) +% [marginal, msg, loglik] = smooth_evidence(engine, evidence) (pearl_dbn) + +disp('warning: pearl_dbn smoothing is broken'); + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +bnet2 = dbn_to_bnet(bnet, T); +ns = bnet2.node_sizes; +hnodes = mysetdiff(1:ss, engine.onodes); +hnodes = hnodes(:)'; + +onodes2 = unroll_set(engine.onodes(:), ss, T); +onodes2 = onodes2(:)'; + +hnodes2 = unroll_set(hnodes(:), ss, T); +hnodes2 = hnodes2(:)'; + +[engine.parent_index, engine.child_index] = mk_pearl_msg_indices(bnet2); + +msg = init_msgs(bnet2.dag, ns, evidence, bnet2.equiv_class, bnet2.CPD); + +verbose = 0; +pot_type = 'd'; +niter = 1; +for iter=1:niter + % FORWARD + for t=1:T + if verbose, fprintf('t=%d\n', t); end + + % each hidden node absorbs lambda from its observed child (if any) + for i=hnodes + c = engine.obschild(i); + if c > 0 + if t==1 + fam = family(bnet.dag, c); + e = bnet.equiv_class(c, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + else + fam = family(bnet.dag, 2); % within 2 slice network + e = bnet.equiv_class(c, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + end + temp = pot_to_marginal(CPDpot); + n = i + (t-1)*ss; + lam_msg = normalise(temp.T); + j = engine.child_index{n}(c+(t-1)*ss); + assert(j==1); + msg{n}.lambda_from_child{j} = lam_msg; + if verbose, fprintf('%d sends lambda to %d\n', c + (t-1)*ss, n); disp(lam_msg); end + end + end + + % update pi + for i=hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + if t==1 + e = bnet.equiv_class(i,1); + else + e = bnet.equiv_class(i,2); + end + msg{n}.pi = compute_pi(bnet.CPD{e}, n, ps, msg); + if verbose, fprintf('%d computes pi\n', n); disp(msg{n}.pi); end + end + + % send pi msg to children in next slice + for i=hnodes + n = i + (t-1)*ss; + %cs = myintersect(children(bnet2.dag, n), hnodes2); + cs = children(bnet2.dag, n); + for c=cs(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + pi_msg = normalise(compute_pi_msg(n, cs, msg, c, ns)); + msg{c}.pi_from_parent{j} = pi_msg; + if verbose, fprintf('%d sends pi to %d\n', n, c); disp(pi_msg); end + end + end + end + + % BACKWARD + for t=T:-1:1 + if verbose, fprintf('t = %d\n', t); end + + % update lambda + for i=hnodes + n = i + (t-1)*ss; + cs = children(bnet2.dag, n); + msg{n}.lambda = compute_lambda(n, cs, msg, ns); + if verbose, fprintf('%d computes lambda\n', n); disp(msg{n}.lambda); end + end + + % send lambda msgs to hidden parents in prev slcie + for i=hnodes + n = i + (t-1)*ss; + %ps = myintersect(parents(bnet2.dag, n), hnodes2); + ps = parents(bnet2.dag, n); + for p=ps(:)' + j = engine.child_index{p}(n); % n is p's j'th child + if t > 1 + e = bnet.equiv_class(i, 2); + else + e = bnet.equiv_class(i, 1); + end + lam_msg = normalise(compute_lambda_msg(bnet.CPD{e}, n, ps, msg, p)); + msg{p}.lambda_from_child{j} = lam_msg; + if verbose, fprintf('%d sends lambda to %d\n', n, p); disp(lam_msg); end + end + end + + % send pi msg to observed children + if 0 + for i=hnodes + n = i + (t-1)*ss; + cs = myintersect(children(bnet2.dag, n), onodes2); + %cs = children(bnet2.dag, n); + for c=cs(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + pi_msg = normalise(compute_pi_msg(n, cs, msg, c, ns)); + msg{c}.pi_from_parent{j} = pi_msg; + if verbose, fprintf('%d sends pi to %d\n', n, c); disp(pi_msg); end + end + end + end + + end +end + + +marginal = cell(ss,T); +lik = zeros(1,ss*T); +for t=1:T + for i=hnodes + n = i + (t-1)*ss; + [bel, lik(n)] = normalise(msg{n}.pi .* msg{n}.lambda); + marginal{i,t} = bel; + end +end + +loglik = 0; +%loglik = sum(log(lik)); + + + +%%%%%%% + +function lambda = compute_lambda(n, cs, msg, ns) +% Pearl p183 eq 4.50 +lambda = prod_lambda_msgs(n, cs, msg, ns); + +%%%%%%% + +function pi_msg = compute_pi_msg(n, cs, msg, c, ns) +% Pearl p183 eq 4.53 and 4.51 +pi_msg = msg{n}.pi .* prod_lambda_msgs(n, cs, msg, ns, c); + +%%%%%%%%% + +function lam = prod_lambda_msgs(n, cs, msg, ns, except) + +if nargin < 5, except = -1; end + +%lam = msg{n}.lambda_from_self(:); +lam = ones(ns(n), 1); +for i=1:length(cs) + c = cs(i); + if c ~= except + lam = lam .* msg{n}.lambda_from_child{i}; + end +end + + +%%%%%%%%% + +function msg = init_msgs(dag, ns, evidence, eclass, CPD) +% INIT_MSGS Initialize the lambda/pi message and state vectors (pearl_dbn) +% msg = init_msgs(dag, ns, evidence) + +N = length(dag); +msg = cell(1,N); +observed = ~isemptycell(evidence(:)); + +for n=1:N + ps = parents(dag, n); + msg{n}.pi_from_parent = cell(1, length(ps)); + for i=1:length(ps) + p = ps(i); + msg{n}.pi_from_parent{i} = ones(ns(p), 1); + end + + cs = children(dag, n); + msg{n}.lambda_from_child = cell(1, length(cs)); + for i=1:length(cs) + c = cs(i); + msg{n}.lambda_from_child{i} = ones(ns(n), 1); + end + + msg{n}.lambda = ones(ns(n), 1); + msg{n}.pi = ones(ns(n), 1); + + % Initialize the lambdas with any evidence + if observed(n) + v = evidence{n}; + msg{n}.lambda = zeros(ns(n), 1); + msg{n}.lambda(v) = 1; % delta function + msg{n}.lambda = []; + end + +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/enter_evidence.m new file mode 100644 index 00000000..624cac96 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/enter_evidence.m @@ -0,0 +1,35 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (loopy_dbn) +% [engine, loglik] = enter_evidence(engine, evidence, ....) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (not yet supported), else sum-product [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +assert(~maximize); +assert(~filter); + +[engine.marginal, engine.msg, loglik] = enter_soft_ev(engine, evidence); +engine.evidence = evidence; % needed by marginal_nodes and marginal_family diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/enter_soft_ev.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/enter_soft_ev.m new file mode 100644 index 00000000..5c88f53f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/enter_soft_ev.m @@ -0,0 +1,137 @@ +function [marginal, msg, loglik] = enter_soft_ev(engine, evidence) +% [marginal, msg, loglik] = smooth_evidence(engine, evidence) (pearl_dbn) + + +[ss T] = size(evidence); +bnet = bnet_from_engine(engine); +bnet2 = dbn_to_bnet(bnet, T); +ns = bnet2.node_sizes; +hnodes = mysetdiff(1:ss, engine.onodes); +hnodes = hnodes(:)'; + +onodes2 = unroll_set(engine.onodes(:), ss, T); +onodes2 = onodes2(:)'; + +hnodes2 = unroll_set(hnodes(:), ss, T); +hnodes2 = hnodes2(:)'; + +[engine.parent_index, engine.child_index] = mk_pearl_msg_indices(bnet2); + +rand_init = 0; +use_ev = 0; +msg = init_pearl_msgs(bnet2.dag, ns, evidence, rand_init, use_ev); +msg = init_pearl_dbn_ev_msgs(bnet, evidence, engine); + +verbose = 0; +pot_type = 'd'; +niter = engine.max_iter; + +if verbose, fprintf('old smooth\n'); end + +for iter=1:niter + % FORWARD + for t=1:T + if verbose, fprintf('t=%d\n', t); end + + % update pi + for i=hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + if t==1 + e = bnet.equiv_class(i,1); + else + e = bnet.equiv_class(i,2); + end + msg{n}.pi = compute_pi(bnet.CPD{e}, n, ps, msg); + if verbose, fprintf('%d computes pi\n', n); disp(msg{n}.pi); end + end + + % send pi msg to children + for i=hnodes + n = i + (t-1)*ss; + %cs = myintersect(children(bnet2.dag, n), hnodes2); + cs = children(bnet2.dag, n); % must use all children to get index right + for c=cs(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + pi_msg = normalise(compute_pi_msg(n, cs, msg, c, ns)); + msg{c}.pi_from_parent{j} = pi_msg; + if verbose, fprintf('%d sends pi to %d\n', n, c); disp(pi_msg); end + end + end + end + + % BACKWARD + for t=T:-1:1 + if verbose, fprintf('t = %d\n', t); end + + % update lambda + for i=hnodes + n = i + (t-1)*ss; + cs = children(bnet2.dag, n); + msg{n}.lambda = compute_lambda(n, cs, msg, ns); + if verbose, fprintf('%d computes lambda\n', n); disp(msg{n}.lambda); end + end + + % send lambda msgs to hidden parents in prev slcie + for i=hnodes + n = i + (t-1)*ss; + ps = parents(bnet2.dag, n); + for p=ps(:)' + j = engine.child_index{p}(n); % n is p's j'th child + if t > 1 + e = bnet.equiv_class(i, 2); + else + e = bnet.equiv_class(i, 1); + end + lam_msg = normalise(compute_lambda_msg(bnet.CPD{e}, n, ps, msg, p)); + msg{p}.lambda_from_child{j} = lam_msg; + if verbose, fprintf('%d sends lambda to %d\n', n, p); disp(lam_msg); end + end + end + + end +end + + +marginal = cell(ss,T); +lik = zeros(1,ss*T); +for t=1:T + for i=hnodes + n = i + (t-1)*ss; + [bel, lik(n)] = normalise(msg{n}.pi .* msg{n}.lambda); + marginal{i,t} = bel; + end +end + +loglik = 0; +%loglik = sum(log(lik)); + + + +%%%%%%% + +function lambda = compute_lambda(n, cs, msg, ns) +% Pearl p183 eq 4.50 +lambda = prod_lambda_msgs(n, cs, msg, ns); + +%%%%%%% + +function pi_msg = compute_pi_msg(n, cs, msg, c, ns) +% Pearl p183 eq 4.53 and 4.51 +pi_msg = msg{n}.pi .* prod_lambda_msgs(n, cs, msg, ns, c); + +%%%%%%%%% + +function lam = prod_lambda_msgs(n, cs, msg, ns, except) + +if nargin < 5, except = -1; end + +%lam = msg{n}.lambda_from_self(:); +lam = ones(ns(n), 1); +for i=1:length(cs) + c = cs(i); + if c ~= except + lam = lam .* msg{n}.lambda_from_child{i}; + end +end + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..9440459a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/marginal_nodes.m @@ -0,0 +1,18 @@ +function marginal = marginal_nodes(engine, nodes, t) +% MARGINAL_NODES Compute the marginal on the specified query nodes (pearl_dbn) +% marginal = marginal_nodes(engine, i, t) +% returns Pr(X(i,t) | Y(1:T)), where X(i,t) is the i'th node in the t'th slice. +% If enter_evidence used filtering instead of smoothing, this will return Pr(X(i,t) | Y(1:t)). + +if nargin < 3, t = 1; end +assert(length(nodes)==1); +i = nodes(end); +if ~myismember(i, engine.onodes) + marginal.T = engine.marginal{i,t}; +else + marginal.T = 1; % observed +end + +% we convert the domain to the unrolled numbering system +% so that update_ess extracts the right evidence. +marginal.domain = nodes+(t-1)*engine.ss; diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/pearl_dbn_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/pearl_dbn_inf_engine.m new file mode 100644 index 00000000..2e0509fd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/pearl_dbn_inf_engine.m @@ -0,0 +1,65 @@ +function engine = pearl_dbn_inf_engine(bnet, varargin) +% LOOPY_DBN_INF_ENGINE Loopy Pearl version of forwards-backwards +% engine = loopy_dbn_inf_engine(bnet, ...) +% +% Optional arguments +% 'max_iter' - specifies the max num. forward-backward passes to perform [1] +% 'tol' - as in loopy_pearl [1e-3] +% 'momentum' - as in loopy_pearl [0] + +error('pearl_dbn does not work yet') + +max_iter = 1; +tol = 1e-3; +momentum = 0; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'max_iter', max_iter = args{i+1}; + case 'tol', tol = args{i+1}; + case 'momentum', momentum = args{i+1}; + end + end +end + + +engine.max_iter = max_iter; +engine.tol = tol; +engine.momentum = momentum; +engine.pearl_engine = []; +engine.T = []; +engine.ss = length(bnet.intra); + +engine.marginal = []; +engine.evidence = []; +engine.msg = []; +engine.parent_index = []; +engine.child_index = []; +%[engine.parent_index, engine.child_index] = mk_pearl_msg_indices(bnet); % need to unroll first + +ss = length(bnet.intra); +engines.ss = ss; +onodes = bnet.observed; +hnodes = mysetdiff(1:ss, onodes); +obschild = zeros(1,ss); +for i=hnodes(:)' + %ocs = myintersect(children(bnet.dag, i), onodes); + ocs = children(bnet.intra, i); + assert(length(ocs) <= 1); + if length(ocs)==1 + obschild(i) = ocs(1); + end +end +engine.obschild = obschild; + +engine.mult_self_ndx = []; +engine.mult_parent_ndx = []; +engine.marg_self_ndx = []; +engine.marg_parent_ndx = []; + + +engine = class(engine, 'loopy_dbn_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..e35b6662 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Entries @@ -0,0 +1,2 @@ +/init_pearl_dbn_ev_msgs.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..2cb0fa7a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@pearl_dbn_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/init_pearl_dbn_ev_msgs.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/init_pearl_dbn_ev_msgs.m new file mode 100644 index 00000000..893af2ae --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_dbn_inf_engine/private/init_pearl_dbn_ev_msgs.m @@ -0,0 +1,28 @@ +function msg = init_pearl_dbn_ev_msgs(bnet, evidence, engine) + +[ss T] = size(evidence); +pot_type = 'd'; + +% each hidden node absorbs lambda from its observed child (if any) +for t=1:T + for i=hnodes + c = engine.obschild(i); + if c > 0 + if t==1 + fam = family(bnet.dag, c); + e = bnet.equiv_class(c, 1); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,1)); + else + fam = family(bnet.dag, c, 2); % within 2 slice network + e = bnet.equiv_class(c, 2); + CPDpot = CPD_to_pot(pot_type, bnet.CPD{e}, fam, bnet.node_sizes(:), bnet.cnodes(:), evidence(:,t-1:t)); + end + temp = pot_to_marginal(CPDpot); + n = i + (t-1)*ss; + lam_msg = normalise(temp.T); + j = engine.child_index{n}(c+(t-1)*ss); + assert(j==1); + msg{n}.lambda_from_child{j} = lam_msg; + end + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Entries new file mode 100644 index 00000000..d2a809f0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Entries @@ -0,0 +1,6 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/pearl_unrolled_dbn_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Repository new file mode 100644 index 00000000..5c0fed50 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/enter_evidence.m new file mode 100644 index 00000000..a9731ffd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/enter_evidence.m @@ -0,0 +1,41 @@ +function [engine, loglik, niter] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (loopy_unrolled_dbn) +% [engine, loglik, niter] = enter_evidence(engine, evidence, ....) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product (not yet supported), else sum-product [0] +% filename - as in loopy_pearl +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filename = engine.filename; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filename', filename = args{i+1}; + end + end +end + + +[ss T] = size(evidence); +if T ~= engine.T + bnetT = dbn_to_bnet(bnet_from_engine(engine), T); + engine.unrolled_engine = pearl_inf_engine(bnetT, 'protocol', engine.protocol, ... + 'max_iter', engine.max_iter_per_slice * T, ... + 'tol', engine.tol, 'momentum', engine.momentum); + engine.T = T; +end +[engine.unrolled_engine, loglik, niter] = enter_evidence(engine.unrolled_engine, evidence(:), ... + 'maximize', maximize, 'filename', filename); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/marginal_family.m new file mode 100644 index 00000000..a40f2974 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/marginal_family.m @@ -0,0 +1,11 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_unrolled_dbn) +% marginal = marginal_family(engine, i, t) + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end +assert(~add_ev); + +%marginal = marginal_family(engine.unrolled_engine, i + (t-1)*engine.ss, add_ev); +marginal = marginal_family(engine.unrolled_engine, i + (t-1)*engine.ss); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..0fb095e5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/marginal_nodes.m @@ -0,0 +1,16 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (loopy_unrolled_dbn) +% marginal = marginal_nodes(engine, nodes, t) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' must occur in some clique. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +marginal = marginal_nodes(engine.unrolled_engine, nodes + (t-1)*engine.ss, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/pearl_unrolled_dbn_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/pearl_unrolled_dbn_inf_engine.m new file mode 100644 index 00000000..637d29c8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/pearl_unrolled_dbn_inf_engine.m @@ -0,0 +1,39 @@ +function engine = pearl_unrolled_dbn_inf_engine(bnet, varargin) +% LOOPY_DBN_INF_ENGINE Loopy Pearl version of forwards-backwards +% engine = loopy_unrolld_dbn_inf_engine(bnet, ...) +% +% Optional arguments +% 'max_iter' - specifies the max num. forward-backward passes to perform PER SLICE [2] +% 'tol' - as in loopy_pearl [1e-3] +% 'momentum' - as in loopy_pearl [0] +% protocol - tree or parallel [parallel] +% filename - as in pearl [ '' ] + +max_iter_per_slice = 2; +tol = 1e-3; +momentum = 0; +protocol = 'parallel'; +filename = ''; + +args = varargin; +for i=1:2:length(args) + switch args{i}, + case 'max_iter', max_iter_per_slice = args{i+1}; + case 'tol', tol = args{i+1}; + case 'momentum', momentum = args{i+1}; + case 'protocol', protocol = args{i+1}; + case 'filename', filename = args{i+1}; + end +end + +engine.filename = filename; +engine.max_iter_per_slice = max_iter_per_slice; +engine.tol = tol; +engine.momentum = momentum; +engine.unrolled_engine = []; +engine.T = -1; +engine.ss = length(bnet.intra); +engine.protocol = protocol; + +engine = class(engine, 'pearl_unrolled_dbn_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/update_engine.m new file mode 100644 index 00000000..e8613a43 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@pearl_unrolled_dbn_inf_engine/update_engine.m @@ -0,0 +1,6 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (pearl_unrolled_dbn) +% engine = update_engine(engine, newCPDs) + +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +engine.unrolled_engine = update_engine(engine.unrolled_engine, newCPDs); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Entries new file mode 100644 index 00000000..cb266b88 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/enter_evidence.m/1.1.1.1/Wed Feb 19 09:52:12 2003// +/marginal_family.m/1.1.1.1/Wed Feb 19 09:52:12 2003// +/marginal_nodes.m/1.1.1.1/Wed Feb 19 09:52:12 2003// +/stable_ho_inf_engine.m/1.1.1.1/Fri Mar 14 09:45:34 2003// +/test_ho_inf_enginge.m/1.1.1.1/Wed Feb 19 09:52:12 2003// +/update_engine.m/1.1.1.1/Wed Feb 19 09:52:12 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Repository new file mode 100644 index 00000000..0769f5f6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic/@stable_ho_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/enter_evidence.m new file mode 100644 index 00000000..48b230c9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/enter_evidence.m @@ -0,0 +1,43 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree_unrolled_dbn) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% filter - if 1, does filtering (not supported), else smoothing [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +maximize = 0; +filter = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filter', filter = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +if filter + error('jtree_unrolled_dbn does not support filtering') +end + +if size(evidence,2) ~= engine.nslices + error(['engine was created assuming there are ' num2str(engine.nslices) ... + ' slices, but evidence has ' num2str(size(evidence,2))]) +end + +[engine.unrolled_engine, loglik] = enter_evidence(engine.unrolled_engine, evidence, 'maximize', maximize); + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/marginal_family.m new file mode 100644 index 00000000..a40f2974 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/marginal_family.m @@ -0,0 +1,11 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_unrolled_dbn) +% marginal = marginal_family(engine, i, t) + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end +assert(~add_ev); + +%marginal = marginal_family(engine.unrolled_engine, i + (t-1)*engine.ss, add_ev); +marginal = marginal_family(engine.unrolled_engine, i + (t-1)*engine.ss); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..0fb095e5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/marginal_nodes.m @@ -0,0 +1,16 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (loopy_unrolled_dbn) +% marginal = marginal_nodes(engine, nodes, t) +% +% 't' specifies the time slice of the earliest node in 'nodes'. +% 'nodes' must occur in some clique. +% +% Example: +% Consider a DBN with 2 nodes per slice. +% Then t=2, nodes=[1 3] refers to node 1 in slice 2 and node 1 in slice 3, +% i.e., nodes 3 and 5 in the unrolled network, + +if nargin < 3, t = 1; end +if nargin < 4, add_ev = 0; end + +marginal = marginal_nodes(engine.unrolled_engine, nodes + (t-1)*engine.ss, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/stable_ho_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/stable_ho_inf_engine.m new file mode 100644 index 00000000..523a2fbb --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/stable_ho_inf_engine.m @@ -0,0 +1,67 @@ +function engine = dv_unrolled_dbn_inf_engine(bnet, T, varargin) +% JTREE_UNROLLED_DBN_INF_ENGINE Unroll the DBN for T time-slices and apply jtree to the resulting static net +% engine = jtree_unrolled_dbn_inf_engine(bnet, T, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% useC - 1 means use jtree_C_inf_engine instead of jtree_inf_engine [0] +% constrained - 1 means we constrain ourselves to eliminate slice t before t+1 [1] +% +% e.g., engine = jtree_unrolled_inf_engine(bnet, 'useC', 1); + +% set default params +N = length(bnet.intra); +useC = 0; +constrained = 1; + +if nargin >= 3 + args = varargin; + nargs = length(args); + if isstr(args{1}) + for i=1:2:nargs + switch args{i}, + case 'useC', useC = args{i+1}; + case 'constrained', constrained = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end + else + error(['invalid argument name ' args{1}]); + end +end + +bnet2 = hodbn_to_bnet(bnet, T); +ss = length(bnet.intra); +engine.ss = ss; + +% If constrained_order = 1 we constrain ourselves to eliminate slice t before t+1. +% This prevents cliques containing nodes from far-apart time-slices. +if constrained + stages = num2cell(unroll_set(1:ss, ss, T), 1); +else + stages = { 1:length(bnet2.dag) }; +end +if useC + %jengine = jtree_C_inf_engine(bnet2, 'stages', stages); + %function is not implemented + assert(0) +else + jengine = stab_cond_gauss_inf_engine(bnet2); +end + +engine.unrolled_engine = jengine; +% we don't inherit from jtree_inf_engine, because that would only store bnet2, +% and we would lose access to the DBN-specific fields like intra/inter + +engine.nslices = T; +engine = class(engine, 'stable_ho_inf_engine', inf_engine(bnet)); + + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/test_ho_inf_enginge.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/test_ho_inf_enginge.m new file mode 100644 index 00000000..6165f500 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/test_ho_inf_enginge.m @@ -0,0 +1,87 @@ +function [engine,engine2] = test_ho_inf_enginge(order,T) + +assert(order >= 1) +% Model a SISO system, i. e. all node are one-dimensional +% The nodes are numbered as follows +% u(t) = 1 input +% y(t) = 2 model output +% z(t) = 3 noise +% q(t) = 4 observed output = noise + model output + +ns = [1 1 1 1]; + +% Model a linear system, i.e. there are no discrete nodes +dn = []; + +% Modeling of connections within a time slice +intra = zeros(4); +intra(2,4) = 1; % Connection y(t) -> q(t) +intra(3,4) = 1; % Connection z(t) -> q(t) + +% Connections to the next time slice +inter = zeros(4,4,order); +inter(1,2,1) = 1; % u(t) -> y(t+1); +inter(2,2,1) = 1; %y(t) -> y(t+1); +inter(3,3,1) = 1; %z(t) -> z(t+1); + +if order >= 2 + inter(1,2,2) = 1; % u(t) -> y(t+2); + inter(2,2,2) = 1; % y(t) -> y(t+2); +end + +for i = 3: order + inter(:,:,i) = inter(:,:,i-1); %u(t) -> y(t+i) y(t) -> y(t) +i +end; + + +% Compution of a higer order Markov Model +bnet = mk_higher_order_dbn(intra,inter,ns,'discrete',dn); +bnet2 = mk_dbn(intra,inter(:,:,1),ns,'discrete',dn) + + +%Calculation of the number of nodes with different parameters +%There is one input and one output nodes 2 +%There are two different disturbance node 2 +%There are order +1 nodes for y 1 + order +numOfNodes = 5 + order; + +% First input node +bnet.CPD{1} = gaussian_CPD(bnet,1,'mean',0); +bnet2.CPD{1} = gaussian_CPD(bnet,1,'mean',0); +% Modeled output +bnet.CPD{2} = gaussian_CPD(bnet,2,'mean',0); +bnet2.CPD{2} = gaussian_CPD(bnet,2,'mean',0); +%Disturbance +bnet.CPD{3} = gaussian_CPD(bnet,3,'mean',0); +bnet2.CPD{3} = gaussian_CPD(bnet,3,'mean',0); + +%Qutput +bnet.CPD{4} = gaussian_CPD(bnet,4,'mean',0); +bnet2.CPD{4} = gaussian_CPD(bnet,4,'mean',0); + + +%Output node in the second time-slice +%Remember that node number 6 is an example for +%the fifth equivalence class +bnet.CPD{5} = gaussian_CPD(bnet,6,'mean',0); +bnet2.CPD{5} = gaussian_CPD(bnet,6,'mean',0); + +%Disturbance node in the second time slice +bnet.CPD{6} = gaussian_CPD(bnet,7,'mean',0); +bnet2.CPD{6} = gaussian_CPD(bnet,7,'mean',0); + +% Modeling of the remaining nodes for y +for i = 7:numOfNodes + bnet.CPD{i} = gaussian_CPD(bnet,(i - 6)*4 + 7,'mean',0); +end + +% Generation of the inference engine +engine = dv_unrolled_dbn_inf_engine(bnet,T); +engine2 = jtree_unrolled_dbn_inf_engine(bnet,T); + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/update_engine.m new file mode 100644 index 00000000..5c42d4f6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/@stable_ho_inf_engine/update_engine.m @@ -0,0 +1,7 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (jtree_unrolled_dbn) +% engine = update_engine(engine, newCPDs) + +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +engine.unrolled_engine = update_engine(engine.unrolled_engine, newCPDs); + diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Entries new file mode 100644 index 00000000..0593a1e2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Entries @@ -0,0 +1,2 @@ +/dummy/1.1.1.1/Sat Jan 18 22:22:28 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Entries.Log new file mode 100644 index 00000000..ab4d0aa0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Entries.Log @@ -0,0 +1,12 @@ +A D/@bk_ff_hmm_inf_engine//// +A D/@bk_inf_engine//// +A D/@cbk_inf_engine//// +A D/@ff_inf_engine//// +A D/@frontier_inf_engine//// +A D/@hmm_inf_engine//// +A D/@jtree_dbn_inf_engine//// +A D/@jtree_unrolled_dbn_inf_engine//// +A D/@kalman_inf_engine//// +A D/@pearl_dbn_inf_engine//// +A D/@pearl_unrolled_dbn_inf_engine//// +A D/@stable_ho_inf_engine//// diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Repository new file mode 100644 index 00000000..cc4cac18 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/dynamic diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Root b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/dynamic/dummy b/sourcecodes/bnt-master/BNT/inference/dynamic/dummy new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/dynamic/dummy diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Entries new file mode 100644 index 00000000..9e03c43e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Entries @@ -0,0 +1,6 @@ +/bnet_from_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/filter_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Repository new file mode 100644 index 00000000..02b22e5e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@filter_engine diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/bnet_from_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/bnet_from_engine.m new file mode 100644 index 00000000..b57ee5f4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/bnet_from_engine.m @@ -0,0 +1,5 @@ +function bnet = bnet_from_engine(engine) +% BNET_FROM_ENGINE Return the bnet structure stored inside the engine (smoother_engine) +% bnet = bnet_from_engine(engine) + +bnet = bnet_from_engine(engine.tbn_engine); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/enter_evidence.m new file mode 100644 index 00000000..ab360c68 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/enter_evidence.m @@ -0,0 +1,14 @@ +function [engine, LL] = enter_evidence(engine, ev, t) +% ENTER_EVIDENCE Call the online filter +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) + +engine.old_f = engine.f; +if t==1 + [engine.f, LL] = fwd1(engine.tbn_engine, ev, 1); +else + [engine.f, LL] = fwd(engine.tbn_engine, engine.old_f, ev, t); +end +engine.b = backT(engine.tbn_engine, engine.f, t); +engine.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/filter_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/filter_engine.m new file mode 100644 index 00000000..437a247e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/filter_engine.m @@ -0,0 +1,10 @@ +function engine = filter_engine(tbn_engine) +% FILTER_ENGINE Create an engine which does online filtering +% function engine = filter_engine(tbn_engine) + +engine.tbn_engine = tbn_engine; +engine.f = []; % space to store filtered message +engine.old_f = []; +engine.b = []; % space to store smoothed message +engine.t = []; +engine = class(engine, 'filter_engine'); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/marginal_family.m new file mode 100644 index 00000000..21faea53 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/marginal_family.m @@ -0,0 +1,11 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the joint distribution on a set of family (filter_engine) +% function marginal = marginal_family(engine, i, t, add_ev) + +if nargin < 4, add_ev = 0; end + +if t ~= engine.t + error('mixed up time stamps') +end + +marginal = marginal_family(engine.tbn_engine, engine.b, i, t, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/marginal_nodes.m new file mode 100644 index 00000000..4d83ea93 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@filter_engine/marginal_nodes.m @@ -0,0 +1,10 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the joint distribution on a set of nodes (filter_engine) +% function marginal = marginal_nodes(engine, nodes, t, add_ev) + +if nargin < 4, add_ev = 0; end + +if t ~= engine.t + error('mixed up time stamps') +end +marginal = marginal_nodes(engine.tbn_engine, engine.b, nodes, t, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Entries new file mode 100644 index 00000000..9d562fd8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Entries @@ -0,0 +1,9 @@ +/back.m/1.1.1.1/Wed May 29 15:59:56 2002// +/backT.m/1.1.1.1/Wed May 29 15:59:56 2002// +/fwd.m/1.1.1.1/Wed May 29 15:59:56 2002// +/fwd1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/hmm_2TBN_inf_engine.m/1.1.1.1/Thu Nov 14 20:03:50 2002// +/marginal_family.m/1.1.1.1/Thu Nov 14 20:05:36 2002// +/marginal_nodes.m/1.1.1.1/Thu Nov 14 20:02:46 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..b2cd71e0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Repository new file mode 100644 index 00000000..858ed017 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@hmm_2TBN_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/back.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/back.m new file mode 100644 index 00000000..8ad416f7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/back.m @@ -0,0 +1,21 @@ +function b = back(engine, bfuture, f, t) + +if f.t ~= t + error('mixed up time stamps') +end + +b.t = t; +b.obslik = f.obslik; +bb_future = bfuture.beta .* bfuture.obslik; +if engine.maximize + B = repmat(bb_future(:)', length(bfuture.beta), 1); + b.beta = normalise(max(engine.transprob .* B, [], 2)); +else + b.beta = normalise((engine.transprob * bb_future)); +end +b.gamma = normalise(f.alpha .* b.beta); +if t > 1 + bb_t = b.beta .* b.obslik; + b.xi = normalise((engine.transprob .* (f.past_alpha * bb_t'))); % t-1,t +end + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/backT.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/backT.m new file mode 100644 index 00000000..ffeb6628 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/backT.m @@ -0,0 +1,11 @@ +function b = backT(engine, f, t) + +b.t = t; +b.obslik = f.obslik; +Q = length(f.alpha); +b.beta = ones(Q,1); +b.gamma = f.alpha; +if t > 1 + bb_t = b.obslik; + b.xi = normalise((engine.transprob .* (f.past_alpha * bb_t'))); % T-1,T +end diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/fwd.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/fwd.m new file mode 100644 index 00000000..3afdf714 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/fwd.m @@ -0,0 +1,17 @@ +function [f, logscale] = fwd(engine, fpast, ev, t) +% Forwards pass. + +f.obslik = mk_hmm_obs_lik_vec(engine, ev); +transmat = engine.transprob; +f.past_alpha = fpast.alpha; +if engine.maximize + Q = length(fpast.alpha); + A = repmat(fpast.alpha, [1 Q]); + m = max(transmat .* A, [], 1); + [f.alpha, scale] = normalise(m(:) .* f.obslik); +else + [f.alpha, scale] = normalise((transmat' * fpast.alpha) .* f.obslik); +end +logscale = log(scale); +%f.xi = normalise((fpast.alpha * obslik') .* transmat); % t-1,t +f.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/fwd1.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/fwd1.m new file mode 100644 index 00000000..ec16db4b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/fwd1.m @@ -0,0 +1,11 @@ +function [f, logscale] = fwd1(engine, ev, t) +% Forwards pass for slice 1. + +if t ~= 1 + error('mixed up time stamps') +end +prior = engine.startprob(:); +f.obslik = mk_hmm_obs_lik_vec(engine, ev); +[f.alpha, lik] = normalise(prior .* f.obslik); +logscale = log(lik); +f.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/hmm_2TBN_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/hmm_2TBN_inf_engine.m new file mode 100644 index 00000000..8504124b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/hmm_2TBN_inf_engine.m @@ -0,0 +1,86 @@ +function engine = hmm_2TBN_inf_engine(bnet, varargin) +% HMM_2TBN_INF_ENGINE Inference engine for DBNs which uses the forwards-backwards algorithm. +% engine = hmm_2TBN_inf_engine(bnet, ...) +% +% The DBN is converted to an HMM with a single meganode, but the observed nodes remain factored. +% This can be faster than jtree if the num. hidden nodes is low, because of lower constant factors. +% +% All hidden nodes must be discrete. +% All observed nodes are assumed to be leaves. +% The parents of each observed leaf are assumed to be a subset of the hidden nodes within the same slice. +% The only exception is if bnet is an AR-HMM, where the parents are assumed to be self in the +% previous slice (continuous), plus all the discrete nodes in the current slice. + + +%% Optional arguments +%% ndx_type - 'B', 'D', or 'SD', used in marginal_family [ 'SD' ] + +ndx_type = 'SD'; +ss = bnet.nnodes_per_slice; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + %case 'ndx_type', ndx_type = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +% Stuff to do with speeding up marginal_family +%engine.ndx_type = ndx_type; + +[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter); +engine.persist_bitv = zeros(1, ss); +engine.persist_bitv(engine.persist) = 1; + + +ns = bnet.node_sizes(:); +ns(bnet.observed) = 1; +ns(bnet.observed+ss) = 1; +engine.eff_node_sizes = ns; + +% for n=1:ss +% dom = 1:(2*ss); % domain of xi(:,:,1) +% fam = family(bnet.dag, n+ss); +% engine.marg_fam2_ndx_id(n) = add_ndx(dom, fam, ns, ndx_type); + +% dom = 1:ss; % domain of gamma(:,:,1) +% fam = family(bnet.dag, n); +% engine.marg_fam1_ndx_id(n) = add_ndx(dom, fam, ns, ndx_type); + +% engine.marg_singleton_ndx_id(n) = add_ndx(dom, n, ns, ndx_type); +% end + +for o=bnet.observed(:)' + %if bnet.equiv_class(o,1) ~= bnet.equiv_class(o,2) + % error(['observed node ' num2str(o) ' is not tied']) + %end + cs = children(bnet.dag, o); + if ~isempty(cs) + error(['observed node ' num2str(o) ' is not allowed children']) + end +end + +[engine.startprob, engine.transprob, engine.obsprob] = dbn_to_hmm(bnet); + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.one_slice_marginal = []; +engine.two_slice_marginal = []; + +ss = length(bnet.intra); +engine.maximize = []; +engine.evidence = []; +engine.node_sizes = []; + +% avoid the need to do bnet_from_engine, which is slow +engine.slice_size = ss; +engine.parents = bnet.parents; + +engine.bel = []; +engine = class(engine, 'hmm_2TBN_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/marginal_family.m new file mode 100644 index 00000000..cd8a6997 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/marginal_family.m @@ -0,0 +1,35 @@ +function marginal = marginal_family(engine, b, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (hmm_2TBN) +% marginal = marginal_family(engine, b, i, t, add_ev) + +ns = engine.eff_node_sizes(:); +ss = engine.slice_size; + +if t==1 % | ~engine.persist_bitv(i) + bigT = b.gamma; + ps = engine.parents{i}; + dom = [ps i]; + %id = engine.marg_fam1_ndx_id(i); + bigdom = 1:ss; + bigsz = ns(bigdom); + bigdom = bigdom + (t-1)*ss; +else % some parents are in previous slice + bigT = b.xi; % (t-1,t) + ps = engine.parents{i+ss}; + dom = [ps i+ss] + (t-2)*ss; + %id = engine.marg_fam2_ndx_id(i); + bigdom = 1:(2*ss); % domain of xi(:,:,t) + bigsz = ns(bigdom); + bigdom = bigdom + (t-2)*ss; +end +marginal.domain = dom; + +%ndx = get_ndx(id, engine.ndx_type); +%marginal.T = marg_table_ndx(bigT, engine.maximize, ndx, engine.ndx_type); +%global SD_NDX +%ndx = SD_NDX{id}; +%marginal.T = marg_table_ndxSD(bigT, engine.maximize, ndx); +marginal.T = marg_table(bigT, bigdom, bigsz, dom, engine.maximize); + +assert(~add_ev); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..6fa6c2b3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/marginal_nodes.m @@ -0,0 +1,27 @@ +function marginal = marginal_nodes(engine, b, nodes, t, add_ev) +% MARGINAL_NODES Compute the marginal on the specified nodes (hmm_2TBN) +% marginal = marginal_nodes(engine, b, nodes, t, add_ev) +% +% nodes must be a singleton set + +assert(length(nodes)==1) +ss = engine.slice_size; + +i = nodes(1); +bigT = b.gamma; +dom = i + (t-1)*ss; + +%id = engine.marg_singleton_ndx_id(i); +%global SD_NDX +%ndx = SD_NDX{id}; +%marginal.T = marg_table_ndxSD(bigT, engine.maximize, ndx); + +ns = engine.eff_node_sizes(:); +bigdom = 1:ss; +marginal.T = marg_table(bigT, bigdom + (t-1)*ss, ns(bigdom), dom, engine.maximize); + +marginal.domain = dom; +assert(~add_ev); +%if add_ev +% marginal = add_ev_to_dmarginal(marginal, engine.evidence, engine.node_sizes); +%end diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..c37a30a9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Entries @@ -0,0 +1,2 @@ +/mk_hmm_obs_lik_vec.m/1.1.1.1/Sun May 4 21:47:44 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..81419e91 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@hmm_2TBN_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/mk_hmm_obs_lik_vec.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/mk_hmm_obs_lik_vec.m new file mode 100644 index 00000000..915a2f39 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/private/mk_hmm_obs_lik_vec.m @@ -0,0 +1,53 @@ +function obslik = mk_hmm_obs_lik_vec(engine, evidence) + +% P(o1,o2| h) = P(o1|h) * P(o2|h) where h = Q1,Q2,... + +bnet = bnet_from_engine(engine); +ss = length(bnet.intra); +onodes = bnet.observed; +hnodes = mysetdiff(1:ss, onodes); +ns = bnet.node_sizes(:); +ns(onodes) = 1; + +Q = length(engine.startprob); +obslik = ones(Q, 1); + +for i=1:length(onodes) + o = onodes(i); + %data = cell2num(evidence(o,1)); + data = evidence{o,1}; + if myismember(o, bnet.dnodes) + %obslik_i = eval_pdf_cond_multinomial(data, engine.obsprob{i}.CPT); + obslik_i = multinomial_prob(data, engine.obsprob{i}.CPT); + else + if bnet.auto_regressive(o) + error('can''t handle AR nodes') + end + %% calling mk_ghmm_obs_lik, which calls gaussian_prob, is slow, so we inline it + %% and use the pre-computed inverse matrix + %obslik_i = mk_ghmm_obs_lik(data, engine.obsprob{i}.mu, engine.obsprob{i}.Sigma); + x = data(:); + m = engine.obsprob{i}.mu; + Qi = size(m, 2); + obslik_i = size(Qi, 1); + invC = engine.obsprob{i}.inv_Sigma; + denom = engine.obsprob{i}.denom; + for j=1:Qi + numer = exp(-0.5 * (x-m(:,j))' * invC(:,:,j) * (x-m(:,j))); + obslik_i(j) = numer / denom(j); + end + end + % convert P(o|ps) into P(o|h) by multiplying onto a (h,o) potential of all 1s + ps = bnet.parents{o}; + dom = [ps o]; + obspot_i = dpot(dom, ns(dom), obslik_i); + dom = [hnodes o]; + obspot = dpot(dom, ns(dom)); + obspot = multiply_by_pot(obspot, obspot_i); + % compute p(oi|h) * p(oj|h) + S = struct(obspot); + obslik = obslik .* S.T(:); +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/update_engine.m new file mode 100644 index 00000000..e6cd1f79 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@hmm_2TBN_inf_engine/update_engine.m @@ -0,0 +1,8 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (hmm) +% engine = update_engine(engine, newCPDs) + +%engine.inf_engine.bnet.CPD = newCPDs; +engine.inf_engine = update_engine(engine.inf_engine, newCPDs); +[engine.startprob, engine.transprob, engine.obsprob] = dbn_to_hmm(bnet_from_engine(engine)); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Entries new file mode 100644 index 00000000..b64945b2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Entries @@ -0,0 +1,13 @@ +/back.m/1.1.1.1/Mon Jun 17 23:34:12 2002// +/back1.m/1.1.1.1/Mon Jun 17 23:34:26 2002// +/back1_mpe.m/1.1.1.1/Mon Jun 17 23:49:40 2002// +/backT.m/1.1.1.1/Mon Jun 17 23:34:20 2002// +/backT_mpe.m/1.1.1.1/Mon Jun 17 23:38:56 2002// +/back_mpe.m/1.1.1.1/Sun Jul 21 00:32:52 2002// +/fwd.m/1.1.1.1/Mon Jun 17 23:46:06 2002// +/fwd1.m/1.1.1.1/Mon Jun 17 23:46:20 2002// +/jtree_2TBN_inf_engine.m/1.1.1.1/Thu Nov 14 16:31:58 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/set_fields.m/1.1.1.1/Sun Jul 21 01:25:30 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..24f16336 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Repository new file mode 100644 index 00000000..7f0022ff --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@jtree_2TBN_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..794b5de2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Entries @@ -0,0 +1,2 @@ +/jtree_2TBN_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..a7b1e665 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@jtree_2TBN_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/jtree_2TBN_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/jtree_2TBN_inf_engine.m new file mode 100644 index 00000000..b271e583 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/Old/jtree_2TBN_inf_engine.m @@ -0,0 +1,116 @@ +function engine = jtree_2TBN_inf_engine(bnet, varargin) +% JTREE_ONLINE_INF_ENGINE Online Junction tree inference algorithm for DBNs. +% engine = jtree_online_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - specifies variables that must be grouped in the 1.5 slice DBN +% maximize - 1 means do max-product, 0 means sum-product [0] +% +% The same nodes must be observed in every slice. + +ss = length(bnet.intra); +clusters = {}; +engine.maximize = 0; + +args = varargin; +nargs = length(args); +for i=1:2:length(args) + switch args{i}, + case 'clusters', clusters = args{i+1}; + case 'maximize', engine.maximize = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end +end + +engine.evidence = []; +engine.node_sizes = []; + +%int = compute_interface_nodes(bnet.intra, bnet.inter); +int = []; + +if 1 +% include nodes with any outgoing arcs +for u=1:ss + if any(bnet.inter(u,:)) + int = [int u]; + end +end +end + +if 0 +% include nodes with any incoming arcs +incoming = []; +for u=1:ss + if any(bnet.inter(:,u)) + int = [int u]; + incoming = [incoming u]; + end +end +% include nodes which are parents of nodes with incoming +for u=1:ss + cs = children(bnet.intra, u); + if ~isempty(cs) & mysubset(cs, incoming) + int = [int u]; + end +end +int = unique(int); +end % if + +int +engine.interface = int; +engine.nonint = mysetdiff(1:ss, int); + +onodes = bnet.observed; + +% Create a "1.5 slice" jtree, containing the interface nodes of slice 1 +% and all the nodes of slice 2 +% To keep the node numbering the same, we simply disconnect the non-interface nodes +% from slice 1, and set their size to 1. +% We do this to speed things up, and so that the likelihood is computed correctly - we do not need to do +% this if we just want to compute marginals (i.e., we can include nodes whose potentials will +% be left as all 1s). +intra15 = bnet.intra; +for i=engine.nonint(:)' + intra15(:,i) = 0; + intra15(i,:) = 0; +end +dag15 = [intra15 bnet.inter; + zeros(ss) bnet.intra]; +ns = bnet.node_sizes(:); +%ns(engine.nonint) = 1; % disconnected nodes get size 1 +obs_nodes = [onodes(:) onodes(:)+ss]; +bnet15 = mk_bnet(dag15, ns, 'discrete', bnet.dnodes, 'equiv_class', bnet.equiv_class(:), ... + 'observed', obs_nodes(:)); + +% use unconstrained elimination, +% but force there to be a clique containing both interfaces +clusters(end+1:end+2) = {int, int+ss}; +engine.jtree_engine = jtree_inf_engine(bnet15, 'clusters', clusters, 'root', int+ss); +jtree_engine = struct(engine.jtree_engine); % violate object privacy + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); +engine.clq_ass_to_node = jtree_engine.clq_ass_to_node; +engine.root = jtree_engine.root_clq; + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes,1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end +engine.jtree_engine1 = jtree_inf_engine(bnet1, 'clusters', {int}, 'root', int); +jtree_engine1 = struct(engine.jtree_engine1); % violate object privacy +engine.int_clq1 = clq_containing_nodes(engine.jtree_engine1, int); +engine.clq_ass_to_node1 = jtree_engine1.clq_ass_to_node; +engine.root1 = jtree_engine1.root_clq; + +engine.observed = [onodes onodes+ss]; +engine.observed1 = onodes; +engine.pot_type = determine_pot_type(bnet, onodes); +engine.slice_size = bnet.nnodes_per_slice; + +engine = class(engine, 'jtree_2TBN_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back.m new file mode 100644 index 00000000..7f686d55 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back.m @@ -0,0 +1,27 @@ +function b = back(engine, bfuture, f, t) + +if f.t ~= t + error('mixed up time stamps') +end +if t==1 + b = back1(engine, bfuture, f, t); + return; +end + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +int = engine.interface; +D = engine.in_clq; +C = engine.out_clq; +phiD = marginalize_pot(bfuture.clpot{D}, int, engine.maximize); +phiD = set_domain_pot(phiD, int+ss); % shift to slice 2 +phiC = marginalize_pot(f.clpot{C}, int+ss, engine.maximize); +ratio = divide_by_pot(phiD, phiC); +f.clpot{C} = multiply_by_pot(f.clpot{C}, ratio); + +[b.clpot, seppot] = distribute_evidence(engine.jtree_engine, f.clpot, f.seppot); +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back1.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back1.m new file mode 100644 index 00000000..a8587a72 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back1.m @@ -0,0 +1,21 @@ +function b = back1(engine, bfuture, f, t) + +if t ~= 1 + error('mixed up time stamps') +end +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +int = engine.interface; +D = engine.in_clq; % from J2 +C = engine.int_clq1; % from J1 +phiD = marginalize_pot(bfuture.clpot{D}, int, engine.maximize); +phiC = marginalize_pot(f.clpot{C}, int, engine.maximize); +ratio = divide_by_pot(phiD, phiC); +f.clpot{C} = multiply_by_pot(f.clpot{C}, ratio); + +[b.clpot, seppot] = distribute_evidence(engine.jtree_engine1, f.clpot, f.seppot); +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back1_mpe.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back1_mpe.m new file mode 100644 index 00000000..b20bfa57 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back1_mpe.m @@ -0,0 +1,22 @@ +function [b, mpe] = back1_mpe(engine, bfuture, f, ev1, t) + +if t ~= 1 + error('mixed up time stamps') +end +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; +maximize = 1; + +int = engine.interface; +D = engine.in_clq; % from J2 +C = engine.int_clq1; % from J1 +phiD = marginalize_pot(bfuture.clpot{D}, int, maximize); +phiC = marginalize_pot(f.clpot{C}, int, maximize); +ratio = divide_by_pot(phiD, phiC); +f.clpot{C} = multiply_by_pot(f.clpot{C}, ratio); + +[mpe, b.clpot] = find_max_config(engine.jtree_engine1, f.clpot, f.seppot, ev1); +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/backT.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/backT.m new file mode 100644 index 00000000..7f7a1b42 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/backT.m @@ -0,0 +1,11 @@ +function b = backT(engine, f, t) + +if t==1 + [b.clpot, seppot] = distribute_evidence(engine.jtree_engine1, f.clpot, f.seppot); +else + [b.clpot, seppot] = distribute_evidence(engine.jtree_engine, f.clpot, f.seppot); +end +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/backT_mpe.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/backT_mpe.m new file mode 100644 index 00000000..93084eae --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/backT_mpe.m @@ -0,0 +1,16 @@ +function [b, mpe] = backT_mpe(engine, f, ev2, t) + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +if t==1 + % ev2 is just the evidence on slice 1 + [mpe, b.clpot] = find_max_config(engine.jtree_engine1, f.clpot, f.seppot, ev2); +else + [mpe, b.clpot] = find_max_config(engine.jtree_engine, f.clpot, f.seppot, ev2); + mpe = mpe((1:ss)+ss); % extract values for slice 2 +end +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back_mpe.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back_mpe.m new file mode 100644 index 00000000..9fdba411 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/back_mpe.m @@ -0,0 +1,28 @@ +function [b, mpe] = back_mpe(engine, bfuture, f, ev2, t) + +if f.t ~= t + error('mixed up time stamps') +end +if t==1 + error('should call back1_mpe') +end + +maximize = 1; +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +int = engine.interface; +D = engine.in_clq; +C = engine.out_clq; +phiD = marginalize_pot(bfuture.clpot{D}, int, maximize); +phiD = set_domain_pot(phiD, int+ss); % shift to slice 2 +phiC = marginalize_pot(f.clpot{C}, int+ss, maximize); +ratio = divide_by_pot(phiD, phiC); +f.clpot{C} = multiply_by_pot(f.clpot{C}, ratio); + +[mpe, b.clpot] = find_max_config(engine.jtree_engine, f.clpot, f.seppot, ev2); +mpe = mpe((1:ss)+ss); % extract values for slice 2 +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/fwd.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/fwd.m new file mode 100644 index 00000000..9c59cc3b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/fwd.m @@ -0,0 +1,44 @@ +function [f, logscale] = fwd(engine, fpast, ev, t) +% Forwards pass. + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +ev2 = cell(ss, 2); +ev2(:,1) = fpast.evidence; +ev2(:,2) = ev; + +CPDpot = cell(1,ss); +for n=1:ss + fam = family(bnet.dag, n, 2); + e = bnet.equiv_class(n, 2); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), ev2); +end +f.evidence = ev; +f.t = t; + +% get prior +int = engine.interface; +if fpast.t==1 + prior = marginalize_pot(fpast.clpot{engine.int_clq1}, int, engine.maximize); +else + prior = marginalize_pot(fpast.clpot{engine.out_clq}, int+ss, engine.maximize); + prior = set_domain_pot(prior, int); % shift back to slice 1 +end + +pots = [ {prior} CPDpot ]; +slice1 = 1:ss; +slice2 = slice1 + ss; +CPDclqs = engine.clq_ass_to_node(slice2); +D = engine.in_clq; +clqs = [D CPDclqs]; + +[f.clpot, f.seppot] = init_pot(engine.jtree_engine, clqs, pots, engine.pot_type, engine.observed); +[f.clpot, f.seppot] = collect_evidence(engine.jtree_engine, f.clpot, f.seppot); +for c=1:length(f.clpot) + [f.clpot{c}, ll(c)] = normalize_pot(f.clpot{c}); +end +logscale = ll(engine.root); + + + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/fwd1.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/fwd1.m new file mode 100644 index 00000000..68de1e50 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/fwd1.m @@ -0,0 +1,26 @@ +function [f, logscale] = fwd1(engine, ev, t) +% Forwards pass for slice 1. + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +CPDpot = cell(1,ss); +for n=1:ss + fam = family(bnet.dag, n, 1); + e = bnet.equiv_class(n, 1); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), ev); +end +f.t = t; +f.evidence = ev; + +pots = CPDpot; +slice1 = 1:ss; +CPDclqs = engine.clq_ass_to_node1(slice1); + +[f.clpot, f.seppot] = init_pot(engine.jtree_engine1, CPDclqs, CPDpot, engine.pot_type, engine.observed1); +[f.clpot, f.seppot] = collect_evidence(engine.jtree_engine1, f.clpot, f.seppot); +for c=1:length(f.clpot) + [f.clpot{c}, ll(c)] = normalize_pot(f.clpot{c}); +end +logscale = ll(engine.root1); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/jtree_2TBN_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/jtree_2TBN_inf_engine.m new file mode 100644 index 00000000..2d56445c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/jtree_2TBN_inf_engine.m @@ -0,0 +1,69 @@ +function engine = jtree_2TBN_inf_engine(bnet, varargin) +% JTREE_ONLINE_INF_ENGINE Online Junction tree inference algorithm for DBNs. +% engine = jtree_online_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - specifies variables that must be grouped in the 1.5 slice DBN +% +% The same nodes must be observed in every slice. +% +% This uses the forwards interface of slice t-1 plus all of slice t. +% By contrast, jtree_dbn uses all of slice t-1 plus the backwards interface of slice t. +% See my thesis for details. + + +clusters = {}; + +args = varargin; +nargs = length(args); +for i=1:2:length(args) + switch args{i}, + case 'clusters', clusters = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end +end + +engine.maximize = 0; +engine.evidence = []; +engine.node_sizes = []; + +int = compute_fwd_interface(bnet.intra, bnet.inter); +engine.interface = int; +ss = length(bnet.intra); +engine.nonint = mysetdiff(1:ss, int); +onodes = bnet.observed; + +bnet15 = mk_slice_and_half_dbn(bnet, int); + +% use unconstrained elimination, +% but force there to be a clique containing both interfaces +clusters(end+1:end+2) = {int, int+ss}; +engine.jtree_engine = jtree_inf_engine(bnet15, 'clusters', clusters, 'root', int+ss); +jtree_engine = struct(engine.jtree_engine); % violate object privacy + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); +engine.clq_ass_to_node = jtree_engine.clq_ass_to_node; +engine.root = jtree_engine.root_clq; + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes,1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end +engine.jtree_engine1 = jtree_inf_engine(bnet1, 'clusters', {int}, 'root', int); +jtree_engine1 = struct(engine.jtree_engine1); % violate object privacy +engine.int_clq1 = clq_containing_nodes(engine.jtree_engine1, int); +engine.clq_ass_to_node1 = jtree_engine1.clq_ass_to_node; +engine.root1 = jtree_engine1.root_clq; + +engine.observed = [onodes onodes+ss]; +engine.observed1 = onodes; +engine.pot_type = determine_pot_type(bnet, onodes); +engine.slice_size = bnet.nnodes_per_slice; + +engine = class(engine, 'jtree_2TBN_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/marginal_family.m new file mode 100644 index 00000000..0b6e6186 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/marginal_family.m @@ -0,0 +1,12 @@ +function m = marginal_family(engine, b, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_2TBN) +% marginal = marginal_family(engine, b, i, t, add_ev) + +bnet = bnet_from_engine(engine); +if t==1 + m = marginal_nodes(engine, b, family(bnet.dag, i), t, add_ev, 1); +else + ss = length(bnet.intra); + fam = family(bnet.dag, i+ss); + m = marginal_nodes(engine, b, fam, t, add_ev, 1); +end diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..e7ee2ae9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/marginal_nodes.m @@ -0,0 +1,32 @@ +function marginal = marginal_nodes(engine, b, nodes, t, add_ev, is_fam) +% function marginal = marginal_nodes(engine, b, nodes, t, add_ev, is_fam) (jtree_2TBN) + +if nargin < 6, is_fam = 0; end +ss = engine.slice_size; + +if ~is_fam & (t > 1) & all(nodes<=ss) + nodes = nodes + ss; +end + +if t==1 + c = clq_containing_nodes(engine.jtree_engine1, nodes, is_fam); +else + c = clq_containing_nodes(engine.jtree_engine, nodes, is_fam); +end +if c == -1 + error(['no clique contains ' nodes]) +end +bigpot = b.clpot{c}; +pot = marginalize_pot(bigpot, nodes, engine.maximize); +marginal = pot_to_marginal(pot); + +% we convert the domain to the unrolled numbering system +% so that add_ev_to_dmarginal (maybe called in update_ess) extracts the right evidence. +if t > 1 + marginal.domain = nodes+(t-2)*engine.slice_size; +end +assert(~add_ev); + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/set_fields.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/set_fields.m new file mode 100644 index 00000000..51df3b32 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_2TBN_inf_engine/set_fields.m @@ -0,0 +1,16 @@ +function engine = set_fields(engine, varargin) +% SET_FIELDS Set the fields for a generic engine +% engine = set_fields(engine, name/value pairs) +% +% e.g., engine = set_fields(engine, 'maximize', 1) + +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'maximize', + engine.maximize = args{i+1}; + engine.jtree_engine = set_fields(engine.jtree_engine, 'maximize', args{i+1}); + engine.jtree_engine1 = set_fields(engine.jtree_engine1, 'maximize', args{i+1}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Entries new file mode 100644 index 00000000..14219dd2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Entries @@ -0,0 +1,10 @@ +/back.m/1.1.1.1/Wed May 29 15:59:56 2002// +/back1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/backT.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/fwd.m/1.1.1.1/Wed May 29 15:59:56 2002// +/fwd1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_sparse_2TBN_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Repository new file mode 100644 index 00000000..2c445be3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@jtree_sparse_2TBN_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/back.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/back.m new file mode 100644 index 00000000..7f686d55 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/back.m @@ -0,0 +1,27 @@ +function b = back(engine, bfuture, f, t) + +if f.t ~= t + error('mixed up time stamps') +end +if t==1 + b = back1(engine, bfuture, f, t); + return; +end + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +int = engine.interface; +D = engine.in_clq; +C = engine.out_clq; +phiD = marginalize_pot(bfuture.clpot{D}, int, engine.maximize); +phiD = set_domain_pot(phiD, int+ss); % shift to slice 2 +phiC = marginalize_pot(f.clpot{C}, int+ss, engine.maximize); +ratio = divide_by_pot(phiD, phiC); +f.clpot{C} = multiply_by_pot(f.clpot{C}, ratio); + +[b.clpot, seppot] = distribute_evidence(engine.jtree_engine, f.clpot, f.seppot); +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/back1.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/back1.m new file mode 100644 index 00000000..a8587a72 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/back1.m @@ -0,0 +1,21 @@ +function b = back1(engine, bfuture, f, t) + +if t ~= 1 + error('mixed up time stamps') +end +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +int = engine.interface; +D = engine.in_clq; % from J2 +C = engine.int_clq1; % from J1 +phiD = marginalize_pot(bfuture.clpot{D}, int, engine.maximize); +phiC = marginalize_pot(f.clpot{C}, int, engine.maximize); +ratio = divide_by_pot(phiD, phiC); +f.clpot{C} = multiply_by_pot(f.clpot{C}, ratio); + +[b.clpot, seppot] = distribute_evidence(engine.jtree_engine1, f.clpot, f.seppot); +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/backT.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/backT.m new file mode 100644 index 00000000..7f7a1b42 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/backT.m @@ -0,0 +1,11 @@ +function b = backT(engine, f, t) + +if t==1 + [b.clpot, seppot] = distribute_evidence(engine.jtree_engine1, f.clpot, f.seppot); +else + [b.clpot, seppot] = distribute_evidence(engine.jtree_engine, f.clpot, f.seppot); +end +for c=1:length(b.clpot) + [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c}); +end +b.t = t; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/enter_evidence.m new file mode 100644 index 00000000..048d9064 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/enter_evidence.m @@ -0,0 +1,22 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree_online) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% + +engine.maximize = 0; +args = varargin; +for i=1:2:length(args) + switch args{i} + case 'maximize', engine.maximize = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end +end + +[engine, loglik] = offline_smoother(engine, evidence); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/fwd.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/fwd.m new file mode 100644 index 00000000..948d8bc8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/fwd.m @@ -0,0 +1,47 @@ +function [f, logscale] = fwd(engine, fpast, ev, t) +% Forwards pass. + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +ev2 = cell(ss, 2); +ev2(:,1) = fpast.evidence; +ev2(:,2) = ev; +CPDpot = cell(1,ss); +for n=1:ss + fam = family(bnet.dag, n, 2); + e = bnet.equiv_class(n, 2); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), ev2); +end +f.evidence = ev; +f.t = t; + +% get prior +int = engine.interface; +if fpast.t==1 + prior = marginalize_pot(fpast.clpot{engine.int_clq1}, int, engine.maximize); +else + prior = marginalize_pot(fpast.clpot{engine.out_clq}, int+ss, engine.maximize); + prior = set_domain_pot(prior, int); % shift back to slice 1 +end + +pots = [ {prior} CPDpot ]; +slice1 = 1:ss; +slice2 = slice1 + ss; +CPDclqs = engine.clq_ass_to_node(slice2); +D = engine.in_clq; +clqs = [D CPDclqs]; + +[f.clpot, f.seppot] = init_pot(engine.jtree_engine, clqs, pots, engine.pot_type, engine.observed); +[f.clpot, f.seppot] = collect_evidence(engine.jtree_engine, f.clpot, f.seppot); +for c=1:length(f.clpot) + if isa(f.clpot{c}, 'struct') + domain = f.clpot{c}.domain; + sizes = f.clpot{c}.sizes; + T = f.clpot{c}.T; + f.clpot{c} = dpot(domain, sizes, T); + end + [f.clpot{c}, ll(c)] = normalize_pot(f.clpot{c}); +end +logscale = ll(engine.root); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/fwd1.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/fwd1.m new file mode 100644 index 00000000..45d28c3f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/fwd1.m @@ -0,0 +1,32 @@ +function [f, logscale] = fwd1(engine, ev, t) +% Forwards pass for slice 1. + +bnet = bnet_from_engine(engine); +ss = bnet.nnodes_per_slice; + +CPDpot = cell(1,ss); +for n=1:ss + fam = family(bnet.dag, n, 1); + e = bnet.equiv_class(n, 1); + CPDpot{n} = convert_to_pot(bnet.CPD{e}, engine.pot_type, fam(:), ev); +end +f.evidence = ev; +f.t = t; + +pots = CPDpot; +slice1 = 1:ss; +CPDclqs = engine.clq_ass_to_node1(slice1); + +[f.clpot, f.seppot] = init_pot(engine.jtree_engine1, CPDclqs, CPDpot, engine.pot_type, engine.observed1); +[f.clpot, f.seppot] = collect_evidence(engine.jtree_engine1, f.clpot, f.seppot); +for c=1:length(f.clpot) + if isa(f.clpot{c}, 'struct') + domain = f.clpot{c}.domain; + sizes = f.clpot{c}.sizes; + T = f.clpot{c}.T; + f.clpot{c} = dpot(domain, sizes, T); + end + [f.clpot{c}, ll(c)] = normalize_pot(f.clpot{c}); +end +logscale = ll(engine.root1); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/jtree_sparse_2TBN_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/jtree_sparse_2TBN_inf_engine.m new file mode 100644 index 00000000..4897e8fd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/jtree_sparse_2TBN_inf_engine.m @@ -0,0 +1,95 @@ +function engine = jtree_sparse_2TBN_inf_engine(bnet, varargin) +% JTREE_ONLINE_INF_ENGINE Online Junction tree inference algorithm for DBNs. +% engine = jtree_online_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - specifies variables that must be grouped in the 1.5 slice DBN +% maximize - 1 means do max-product, 0 means sum-product [0] +% +% The same nodes must be observed in every slice. + +ss = length(bnet.intra); +clusters = {}; +engine.maximize = 0; + +args = varargin; +nargs = length(args); +for i=1:2:length(args) + switch args{i}, + case 'clusters', clusters = args{i+1}; + case 'maximize', engine.maximize = args{i+1}; + otherwise, error(['unrecognized argument ' args{i}]) + end +end + +engine.evidence = []; +engine.node_sizes = []; + +int = []; +% include nodes with any outgoing arcs +for u=1:ss + if any(bnet.inter(u,:)) + int = [int u]; + end +end + +engine.interface = int; +engine.nonint = mysetdiff(1:ss, int); + +onodes = bnet.observed; + +% Create a "1.5 slice" jtree, containing the interface nodes of slice 1 +% and all the nodes of slice 2 +% To keep the node numbering the same, we simply disconnect the non-interface nodes +% from slice 1, and set their size to 1. +% We do this to speed things up, and so that the likelihood is computed correctly - we do not need to do +% this if we just want to compute marginals (i.e., we can include nodes whose potentials will +% be left as all 1s). +intra15 = bnet.intra; +for i=engine.nonint(:)' + intra15(:,i) = 0; + intra15(i,:) = 0; + assert(~any(bnet.inter(i,:))) +end +dag15 = [intra15 bnet.inter; + zeros(ss) bnet.intra]; +ns = bnet.node_sizes(:); +ns(engine.nonint) = 1; % disconnected nodes get size 1 +obs_nodes = [onodes(:) onodes(:)+ss]; +bnet15 = mk_bnet(dag15, ns, 'discrete', bnet.dnodes, 'equiv_class', bnet.equiv_class(:), ... + 'observed', obs_nodes(:)); + +% use unconstrained elimination, +% but force there to be a clique containing both interfaces +clusters(end+1:end+2) = {int, int+ss}; +%engine.jtree_engine = jtree_inf_engine(bnet15, 'clusters', clusters, 'root', int+ss); +engine.jtree_engine = jtree_sparse_inf_engine(bnet15, 'clusters', clusters, 'root', int+ss); +jtree_engine = struct(engine.jtree_engine); % violate object privacy + +engine.in_clq = clq_containing_nodes(engine.jtree_engine, int); +engine.out_clq = clq_containing_nodes(engine.jtree_engine, int+ss); +engine.clq_ass_to_node = jtree_engine.clq_ass_to_node; +engine.root = jtree_engine.root_clq; + +% Also create an engine just for slice 1 +bnet1 = mk_bnet(bnet.intra1, bnet.node_sizes_slice, 'discrete', myintersect(bnet.dnodes,1:ss), ... + 'equiv_class', bnet.equiv_class(:,1), 'observed', onodes); +for i=1:max(bnet1.equiv_class) + bnet1.CPD{i} = bnet.CPD{i}; +end +%engine.jtree_engine1 = jtree_inf_engine(bnet1, 'clusters', {int}, 'root', int); +engine.jtree_engine1 = jtree_sparse_inf_engine(bnet1, 'clusters', {int}, 'root', int); +jtree_engine1 = struct(engine.jtree_engine1); % violate object privacy +engine.int_clq1 = clq_containing_nodes(engine.jtree_engine1, int); +engine.clq_ass_to_node1 = jtree_engine1.clq_ass_to_node; +engine.root1 = jtree_engine1.root_clq; + +engine.observed = [onodes onodes+ss]; +engine.observed1 = onodes; +engine.pot_type = determine_pot_type(bnet, onodes); +engine.slice_size = bnet.nnodes_per_slice; + +engine = class(engine, 'jtree_sparse_2TBN_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/marginal_family.m new file mode 100644 index 00000000..0b6e6186 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/marginal_family.m @@ -0,0 +1,12 @@ +function m = marginal_family(engine, b, i, t, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree_2TBN) +% marginal = marginal_family(engine, b, i, t, add_ev) + +bnet = bnet_from_engine(engine); +if t==1 + m = marginal_nodes(engine, b, family(bnet.dag, i), t, add_ev, 1); +else + ss = length(bnet.intra); + fam = family(bnet.dag, i+ss); + m = marginal_nodes(engine, b, fam, t, add_ev, 1); +end diff --git a/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..e7ee2ae9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@jtree_sparse_2TBN_inf_engine/marginal_nodes.m @@ -0,0 +1,32 @@ +function marginal = marginal_nodes(engine, b, nodes, t, add_ev, is_fam) +% function marginal = marginal_nodes(engine, b, nodes, t, add_ev, is_fam) (jtree_2TBN) + +if nargin < 6, is_fam = 0; end +ss = engine.slice_size; + +if ~is_fam & (t > 1) & all(nodes<=ss) + nodes = nodes + ss; +end + +if t==1 + c = clq_containing_nodes(engine.jtree_engine1, nodes, is_fam); +else + c = clq_containing_nodes(engine.jtree_engine, nodes, is_fam); +end +if c == -1 + error(['no clique contains ' nodes]) +end +bigpot = b.clpot{c}; +pot = marginalize_pot(bigpot, nodes, engine.maximize); +marginal = pot_to_marginal(pot); + +% we convert the domain to the unrolled numbering system +% so that add_ev_to_dmarginal (maybe called in update_ess) extracts the right evidence. +if t > 1 + marginal.domain = nodes+(t-2)*engine.slice_size; +end +assert(~add_ev); + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Entries new file mode 100644 index 00000000..d9c315a5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Entries @@ -0,0 +1,8 @@ +/bnet_from_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Mon Jun 17 23:46:46 2002// +/find_mpe.m/1.1.1.1/Mon Jun 17 23:50:16 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/smoother_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/update_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Repository new file mode 100644 index 00000000..a10f8a08 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online/@smoother_engine diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/bnet_from_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/bnet_from_engine.m new file mode 100644 index 00000000..b57ee5f4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/bnet_from_engine.m @@ -0,0 +1,5 @@ +function bnet = bnet_from_engine(engine) +% BNET_FROM_ENGINE Return the bnet structure stored inside the engine (smoother_engine) +% bnet = bnet_from_engine(engine) + +bnet = bnet_from_engine(engine.tbn_engine); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/enter_evidence.m new file mode 100644 index 00000000..299c2331 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/enter_evidence.m @@ -0,0 +1,21 @@ +function [engine, LL] = enter_evidence(engine, ev) +% ENTER_EVIDENCE Call the offline smoother +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% + +T = size(ev, 2); +f = cell(1,T); +b = cell(1,T); % b{t}.clpot{c} +ll = zeros(1,T); +[f{1}, ll(1)] = fwd1(engine.tbn_engine, ev(:,1), 1); +for t=2:T + [f{t}, ll(t)] = fwd(engine.tbn_engine, f{t-1}, ev(:,t), t); +end +LL = sum(ll); +b{T} = backT(engine.tbn_engine, f{T}, T); +for t=T-1:-1:1 + b{t} = back(engine.tbn_engine, b{t+1}, f{t}, t); +end +engine.b = b; diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/find_mpe.m new file mode 100644 index 00000000..5415f120 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/find_mpe.m @@ -0,0 +1,33 @@ +function mpe = find_mpe(engine, ev) +% FIND_MPE Find the most probable explanation (Viterbi) +% mpe = enter_evidence(engine, evidence, ...) +% +% evidence{i,t} = [] if if X(i,t) is hidden, and otherwise contains its observed value (scalar or column vector) +% + +mpe = cell(size(ev)); +engine.tbn_engine = set_fields(engine.tbn_engine, 'maximize', 1); + +T = size(ev, 2); +f = cell(1,T); +b = cell(1,T); % b{t}.clpot{c} +ll = zeros(1,T); +[f{1}, ll(1)] = fwd1(engine.tbn_engine, ev(:,1), 1); +for t=2:T + [f{t}, ll(t)] = fwd(engine.tbn_engine, f{t-1}, ev(:,t), t); +end + +if T==1 + [b{1}, mpe(:,1)] = backT_mpe(engine.tbn_engine, f{1}, ev(:,1), 1); +else + [b{T}, mpe(:,T)] = backT_mpe(engine.tbn_engine, f{T}, ev(:,T-1:T), T); + for t=T-1:-1:2 + [b{t}, mpe(:,t)] = back_mpe(engine.tbn_engine, b{t+1}, f{t}, ev(:,t-1:t), t); + end + t = 1; + [b{t}, mpe(:,t)] = back1_mpe(engine.tbn_engine, b{t+1}, f{t}, ev(:,1), t); +end +engine.b = b; + + + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/marginal_family.m new file mode 100644 index 00000000..b7b0d7ec --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/marginal_family.m @@ -0,0 +1,6 @@ +function marginal = marginal_family(engine, i, t, add_ev) +% MARGINAL_FAMILY Compute the joint distribution on a set of family (smoother_engine) +% function marginal = marginal_family(engine, i, t, add_ev) + +if nargin < 4, add_ev = 0; end +marginal = marginal_family(engine.tbn_engine, engine.b{t}, i, t, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/marginal_nodes.m new file mode 100644 index 00000000..e8574c53 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/marginal_nodes.m @@ -0,0 +1,7 @@ +function marginal = marginal_nodes(engine, nodes, t, add_ev) +% MARGINAL_NODES Compute the joint distribution on a set of nodes (smoother_engine) +% function marginal = marginal_nodes(engine, nodes, t, add_ev) + +if nargin < 4, add_ev = 0; end + +marginal = marginal_nodes(engine.tbn_engine, engine.b{t}, nodes, t, add_ev); diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/smoother_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/smoother_engine.m new file mode 100644 index 00000000..adf7ede8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/smoother_engine.m @@ -0,0 +1,12 @@ +function engine = smoother_engine(tbn_engine) +% SMOOTHER_ENGINE Create an engine which does offline (fixed-interval) smoothing in O(T) space/time +% function engine = smoother_engine(tbn_engine) +% +% tbn_engine is any 2TBN inference engine which supports the following methods: +% fwd, fwd1, back, backT, back, marginal_nodes and marginal_family. + +engine.tbn_engine = tbn_engine; +engine.b = []; % space to store smoothed messages +engine = class(engine, 'smoother_engine'); +%engine = class(engine, 'smoother_engine', inf_engine(bnet_from_engine(tbn_engine))); + diff --git a/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/update_engine.m b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/update_engine.m new file mode 100644 index 00000000..ffe0661e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/@smoother_engine/update_engine.m @@ -0,0 +1,5 @@ +function engine = update_engine(engine, newCPDs) +% UPDATE_ENGINE Update the engine to take into account the new parameters (smoother_engine). +% engine = update_engine(engine, newCPDs) + +engine.tbn_engine = update_engine(engine.tbn_engine, newCPDs); diff --git a/sourcecodes/bnt-master/BNT/inference/online/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/online/CVS/Entries new file mode 100644 index 00000000..842483c7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/CVS/Entries @@ -0,0 +1,2 @@ +/dummy/1.1.1.1/Sat Jan 18 22:22:38 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/online/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/online/CVS/Entries.Log new file mode 100644 index 00000000..794e1320 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/CVS/Entries.Log @@ -0,0 +1,5 @@ +A D/@filter_engine//// +A D/@hmm_2TBN_inf_engine//// +A D/@jtree_2TBN_inf_engine//// +A D/@jtree_sparse_2TBN_inf_engine//// +A D/@smoother_engine//// diff --git a/sourcecodes/bnt-master/BNT/inference/online/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/online/CVS/Repository new file mode 100644 index 00000000..2918a1ee --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/online diff --git a/sourcecodes/bnt-master/BNT/inference/online/CVS/Root b/sourcecodes/bnt-master/BNT/inference/online/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/online/dummy b/sourcecodes/bnt-master/BNT/inference/online/dummy new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/online/dummy diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Entries new file mode 100644 index 00000000..a4fbc6ee --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/belprop_fg_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/find_mpe.m/1.1.1.1/Thu Jun 20 00:02:12 2002// +/loopy_converged.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/set_params.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Repository new file mode 100644 index 00000000..7e75998c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@belprop_fg_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/belprop_fg_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/belprop_fg_inf_engine.m new file mode 100644 index 00000000..1945c3f2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/belprop_fg_inf_engine.m @@ -0,0 +1,47 @@ +function engine = belprop_fg_inf_engine(fg, varargin) +% BELPROP_FG_INF_ENGINE Make a belief propagation inference engine for factor graphs +% engine = belprop_fg_inf_engine(factor_graph, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default in brackets] +% e.g., engine = belprop_inf_engine(fg, 'tol', 1e-2, 'max_iter', 10) +% +% max_iter - max. num. iterations [ 2*num_nodes ] +% momentum - weight assigned to old message in convex combination (useful for damping oscillations) [0] +% tol - tolerance used to assess convergence [1e-3] +% maximize - 1 means use max-product, 0 means use sum-product [0] +% +% This uses potential objects, like belprop_inf_engine, and hence is quite slow. + +engine = init_fields; +engine = class(engine, 'belprop_fg_inf_engine'); + +% set params to default values +N = length(fg.G); +engine.max_iter = 2*N; +engine.momentum = 0; +engine.tol = 1e-3; +engine.maximize = 0; + +% parse optional arguments +engine = set_params(engine, varargin); + +engine.fgraph = fg; + +% store results computed by enter_evidence here +engine.marginal_nodes = cell(1, fg.nvars); +engine.evidence = []; + + +%%%%%%%%%%%% + +function engine = init_fields() + +engine.fgraph = []; +engine.max_iter = []; +engine.momentum = []; +engine.tol = []; +engine.maximize = []; +engine.marginal_nodes = []; +engine.evidence = []; +engine.niter = []; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/enter_evidence.m new file mode 100644 index 00000000..e275e298 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/enter_evidence.m @@ -0,0 +1,126 @@ +function [engine, ll, niter] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Propagate evidence using belief propagation +% [engine, ll, niter] = enter_evidence(engine, evidence, ...) +% +% The log-likelihood is not computed; ll = 0. +% niter contains the number of iterations used +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - 1 means use max-product, 0 means use sum-product [0] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +ll = 0; +maximize = 0; + +if nargin >= 3 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +verbose = 0; + +ns = engine.fgraph.node_sizes; +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +cnodes = engine.fgraph.cnodes; +pot_type = determine_pot_type(engine.fgraph, onodes); + +% prime each local kernel with evidence (if any) +nfactors = engine.fgraph.nfactors; +nvars = engine.fgraph.nvars; +factors = cell(1,nfactors); +for f=1:nfactors + K = engine.fgraph.factors{engine.fgraph.equiv_class(f)}; + factors{f} = convert_to_pot(K, pot_type, engine.fgraph.dom{f}(:), evidence); +end + +% initialise msgs +msg_var_to_fac = cell(nvars, nfactors); +for x=1:nvars + for f=engine.fgraph.dep{x} + msg_var_to_fac{x,f} = mk_initial_pot(pot_type, x, ns, cnodes, onodes); + end +end +msg_fac_to_var = cell(nfactors, nvars); +dom = cell(1, nfactors); +for f=1:nfactors + %hdom{f} = myintersect(engine.fgraph.dom{f}, hnodes); + dom{f} = engine.fgraph.dom{f}(:)'; + for x=dom{f} + msg_fac_to_var{f,x} = mk_initial_pot(pot_type, x, ns, cnodes, onodes); + %msg_fac_to_var{f,x} = marginalize_pot(factors{f}, x); + end +end + + + +converged = 0; +iter = 1; +var_prod = cell(1, nvars); +fac_prod = cell(1, nfactors); + +while ~converged && (iter <= engine.max_iter) + if verbose, fprintf('iter %d\n', iter); end + + % absorb + old_var_prod = var_prod; + for x=1:nvars + var_prod{x} = mk_initial_pot(pot_type, x, ns, cnodes, onodes); + for f=engine.fgraph.dep{x} + var_prod{x} = multiply_by_pot(var_prod{x}, msg_fac_to_var{f,x}); + end + end + for f=1:nfactors + fac_prod{f} = mk_initial_pot(pot_type, dom{f}, ns, cnodes, onodes); + for x=dom{f} + fac_prod{f} = multiply_by_pot(fac_prod{f}, msg_var_to_fac{x,f}); + end + end + + % send msgs to neighbors + old_msg_var_to_fac = msg_var_to_fac; + old_msg_fac_to_var = msg_fac_to_var; + converged = 1; + for x=1:nvars + %if verbose, disp(['var ' num2str(x) ' sending to fac ' num2str(engine.fgraph.dep{x})]); end + for f=engine.fgraph.dep{x} + temp = divide_by_pot(var_prod{x}, old_msg_fac_to_var{f,x}); + msg_var_to_fac{x,f} = normalize_pot(temp); + if ~approxeq_pot(msg_var_to_fac{x,f}, old_msg_var_to_fac{x,f}, engine.tol), converged = 0; end + end + end + for f=1:nfactors + %if verbose, disp(['fac ' num2str(f) ' sending to var ' num2str(dom{f})]); end + for x=dom{f} + temp = divide_by_pot(fac_prod{f}, old_msg_var_to_fac{x,f}); + temp2 = multiply_by_pot(factors{f}, temp); + temp3 = marginalize_pot(temp2, x, maximize); + msg_fac_to_var{f,x} = normalize_pot(temp3); + if ~approxeq_pot(msg_fac_to_var{f,x}, old_msg_fac_to_var{f,x}, engine.tol), converged = 0; end + end + end + + if iter==1 + converged = 0; + end + iter = iter + 1; +end + +niter = iter - 1; +engine.niter = niter; + +for x=1:nvars + engine.marginal_nodes{x} = normalize_pot(var_prod{x}); +end + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/find_mpe.m new file mode 100644 index 00000000..439936d5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/find_mpe.m @@ -0,0 +1,49 @@ +function mpe = find_mpe(engine, evidence, varargin) +% FIND_MPE Find the most probable explanation of the data (belprop_fg) +% function mpe = find_mpe(engine, evidence,...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% This finds the marginally most likely value for each hidden node, +% and may give the wrong results even if the graph is acyclic, +% unless you set break_ties = 1. +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% break_ties is optional. If 1, we will force ties to be broken consistently +% by calling enter_evidence N times. (see Jensen96, p106) Default = 1. + +break_ties = 1; + +% parse optional params +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'break_ties', break_ties = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end + +engine = enter_evidence(engine, evidence, 'maximize', 1); + +observed = ~isemptycell(evidence); +evidence = evidence(:); % hack to handle unrolled DBNs +N = length(evidence); +mpe = cell(1,N); +for i=1:N + m = marginal_nodes(engine, i); + % observed nodes are all set to 1 inside the inference engine, so we must undo this + if observed(i) + mpe{i} = evidence{i}; + else + mpe{i} = argmax(m.T); + if break_ties + evidence{i} = mpe{i}; + [engine, ll] = enter_evidence(engine, evidence, 'maximize', 1); + end + end +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/loopy_converged.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/loopy_converged.m new file mode 100644 index 00000000..b9015e85 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/loopy_converged.m @@ -0,0 +1,12 @@ +function niter = loopy_converged(engine) +% LOOPY_CONVERGED Did loopy belief propagation converge? 0 means no, eles we return the num. iterations. +% function niter = loopy_converged(engine) +% +% We use a simple heuristic: we say convergence occurred if the number of iterations +% used was less than the maximum allowed. + +if engine.niter == engine.max_iter + niter = 0; +else + niter = engine.niter; +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..0c85aed6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/marginal_nodes.m @@ -0,0 +1,6 @@ +function marginal = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified query nodes (belprop) +% marginal = marginal_nodes(engine, query) + +assert(length(query)==1); +marginal = pot_to_marginal(engine.marginal_nodes{query}); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/set_params.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/set_params.m new file mode 100644 index 00000000..a495b3bb --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_fg_inf_engine/set_params.m @@ -0,0 +1,24 @@ +function engine = set_params(engine, varargin) +% SET_PARAMS Set the parameters (fields) for a belprop_inf_engine object +% engine = set_params(engine, name/value pairs) +% +% The following optional arguments can be specified in the form of name/value pairs: +% e.g., engine = set_params(engine, 'tol', 1e-2, 'max_iter', 10) +% +% max_iter - max. num. loopy iterations +% momentum - weight assigned to old message in convex combination +% tol - tolerance used to assess convergence +% maximize - 1 means use max-product, 0 means use sum-product + +args = varargin{1}; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'max_iter', engine.max_iter = args{i+1}; + case 'momentum', engine.momentum = args{i+1}; + case 'tol', engine.tol = args{i+1}; + case 'maximize', engine.maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Entries new file mode 100644 index 00000000..b2150de3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/belprop_inf_engine.m/1.1.1.1/Tue Dec 31 19:00:06 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/find_mpe.m/1.1.1.1/Wed Jun 19 22:08:40 2002// +/loopy_converged.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..9c6f22e4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Entries.Log @@ -0,0 +1,2 @@ +A D/Old//// +A D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Repository new file mode 100644 index 00000000..928be328 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@belprop_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..06598b7b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Entries @@ -0,0 +1,6 @@ +/belprop_gdl_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/belprop_inf_engine_nostr.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence1.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_domain.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..f6b12595 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@belprop_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/belprop_gdl_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/belprop_gdl_inf_engine.m new file mode 100644 index 00000000..f3b84925 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/belprop_gdl_inf_engine.m @@ -0,0 +1,67 @@ +function engine = belprop_gdl_inf_engine(gdl, varargin) +% BELPROP_GDL_INF_ENGINE Make a belief propagation inference engine for a GDL graph +% engine = belprop_gdl_inf_engine(gdl_graph, ...) +% +% If the GDL graph is a tree, this will give exact results. +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default in brackets] +% e.g., engine = belprop_inf_engine(gdl, 'tol', 1e-2, 'max_iter', 10) +% +% protocol - 'tree' means send messages up then down the tree, +% 'parallel' means use synchronous updates ['parallel'] +% max_iter - max. num. iterations [ 2*num_nodes ] +% momentum - weight assigned to old message in convex combination (useful for damping oscillations) [0] +% tol - tolerance used to assess convergence [1e-3] +% maximize - 1 means use max-product, 0 means use sum-product [0] + + +engine = init_fields; +engine = class(engine, 'belprop_gdl_inf_engine'); + +% set default params +N = length(gdl.G); +engine.protocol = 'parallel'; +engine.max_iter = 2*N; +engine.momentum = 0; +engine.tol = 1e-3; +engine.maximize = 0; + +engine = set_params(engine, varargin); + +engine.gdl = gdl; + +if strcmp(engine.protocol, 'tree') + % Make a rooted tree, so there is a fixed message passing order. + root = N; + [engine.tree, engine.preorder, engine.postorder, height, cyclic] = mk_rooted_tree(gdl.G, root); + assert(~cyclic); +end + +% store results computed by enter_evidence here +ndoms = length(gdl.doms); +nvars = length(gdl.vars); +engine.marginal_domains = cell(1, ndoms); + +% to compute the marginal on each variable, we need to know which domain to marginalize +% and we want to choose the lightest. We compute the weight once we have seen the evidence. +engine.dom_weight = []; +engine.evidence = []; + + +%%%%%%%%% + +function engine = init_fields() + +engine.protocol = []; +engine.gdl = []; +engine.max_iter = []; +engine.momentum = []; +engine.tol = []; +engine.maximize = []; +engine.marginal_domains = []; +engine.evidence = []; +engine.tree = []; +engine.preorder = []; +engine.postorder = []; +engine.dom_weight = []; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/belprop_inf_engine_nostr.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/belprop_inf_engine_nostr.m new file mode 100644 index 00000000..8219a868 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/belprop_inf_engine_nostr.m @@ -0,0 +1,31 @@ +function engine = belprop_inf_engine(fg, max_iter, momentum, tol, maximize) + +if nargin < 2, max_iter = length(fg.G); end +if nargin < 3, momentum = 0; end +if nargin < 4, tol = 1e-3; end +if nargin < 5, maximize = 0; end + +engine.fgraph = fg; +engine.max_iter = max_iter; +engine.momentum = momentum; +engine.tol = tol; +engine.maximize = maximize; + +% store results computed by enter_evidence here +ndoms = length(fg.doms); +nvars = length(fg.vars); +engine.marginal_domains = cell(1, ndoms); + +% to compute the marginal on each variable, we need to know which domain to marginalize +% so we represent each domain as a bit vector, and compute its (pre-evidence) weight +engine.dom_weight = []; + +% engine.dom_bitv = sparse(ndoms, nvars); +% ns = fg.node_sizes; +% for i=1:ndoms +% engine.dom_bitv(i, fg.doms{i}) = 1; +% engine.dom_weight(i) = prod(ns(fg.doms{i})); +% end + + +engine = class(engine, 'belprop_inf_engine'); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/enter_evidence.m new file mode 100644 index 00000000..54649557 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/enter_evidence.m @@ -0,0 +1,80 @@ +function engine = enter_evidence(engine, evidence) + +doms = engine.fg.doms; +ndoms = length(doms); +ns = engine.fg.node_sizes; +obs = find(~isemptycell(evidence)); +cobs = myintersect(obs, engine.fg.cnodes); +dobs = myintersect(obs, engine.fg.dnodes); +ns(cobs) = 0; +ns(dobs) = 1; + +% prime each local kernel with evidence (if any) +local_kernel = cell(1, ndoms); +for i=1:length(engine.fg.kernels_of_type) + u = engine.fg.kernels_of_type{i}; + local_kernel(u) = kernel_to_dpots(engine.fg.kernels{i}, evidence, engine.fg.domains_of_type{i}); +end + +% initialise all msgs to 1s +nedges = engine.fg.nedges; +msg = cell(1, nedges); +for i=1:nedges + msg{i} = dpot(engine.fg.sepset{i}, ns(engine.fg.sepset{i})); +end + +prod_of_msg = cell(1, ndoms); +bel = cell(1, ndoms); +old_bel = cell(1, ndoms); + +converged = 0; +iter = 1; +while ~converged & (iter <= engine.max_iter) + + % each node multiplies all its incoming msgs + for i=1:ndoms + prod_of_msg{i} = dpot(doms{i}, ns(doms{i})); + nbrs = engine.fg.nbrs{i}; + for j=1:length(nbrs) + ndx = engine.fg.edge_ndx(j,i); + prod_of_msg{i} = multiply_by_pot(prod_of_msg{i}, msg{ndx}); + end + end + old_msg = msg; + + % each node computes its local belief + for i=1:ndoms + bel{i} = normalize_pot(multiply_pots(prod_of_msg{i}, local_kernel{i})); + end + + % converged? + converged = 1; + for i=1:ndoms + if ~approxeq(bel{i}, old_bel{i}, engine.tol) + converged = 0; + break; + end + end + + if ~converged + % each node sends a msg to each of its neighbors + for i=1:ndoms + nbrs = engine.fg.nbrs{i}; + for j=1:length(nbrs) + % multiply all incoming msgs except from j + temp = prod_of_msg{i}; + ndx = engine.fg.edge_ndx(j,i); + temp = divide_by_pot(temp, old_msg{ndx}); + % send msg from i to j + temp = multiply_by_pot(temp, local_kernel{i}); + ndx = engine.fg.edge_ndx(i,j); + msg{ndx} = normalize_pot(marginalize_pot(temp, engine.fg.sepset{ndx})); + end + end + end + + iter = iter + 1; +end + + +engine.marginal = bel; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/enter_evidence1.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/enter_evidence1.m new file mode 100644 index 00000000..b38cd3cb --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/enter_evidence1.m @@ -0,0 +1,94 @@ +function engine = enter_evidence(engine, evidence) + +doms = engine.fgraph.doms; +ndoms = length(doms); +ns = engine.fgraph.node_sizes; +obs = find(~isemptycell(evidence)); +cobs = myintersect(obs, engine.fgraph.cnodes); +dobs = myintersect(obs, engine.fgraph.dnodes); +ns(cobs) = 0; +ns(dobs) = 1; + +% recompute the weight of each domain now that we know what nodes are observed +for i=1:ndoms + engine.dom_weight(i) = prod(ns(engine.fgraph.doms{i})); +end + +% prime each local kernel with evidence (if any) +local_kernel = cell(1, ndoms); +for i=1:length(engine.fgraph.kernels_of_type) + u = engine.fgraph.kernels_of_type{i}; + local_kernel(u) = kernel_to_dpots(engine.fgraph.kernels{i}, evidence, engine.fgraph.domains_of_type{i}); +end + +% initialise all msgs to 1s +msg = cell(ndoms, ndoms); +for i=1:ndoms + nbrs = engine.fgraph.nbrs{i}; + for j=nbrs(:)' + dom = engine.fgraph.sepset{i,j}; + msg{i,j} = dpot(dom, ns(dom)); + end +end + +prod_of_msg = cell(1, ndoms); +bel = cell(1, ndoms); +old_bel = cell(1, ndoms); + +converged = 0; +iter = 1; +while ~converged & (iter <= engine.max_iter) + + % each node multiplies all its incoming msgs + for i=1:ndoms + prod_of_msg{i} = dpot(doms{i}, ns(doms{i})); + nbrs = engine.fgraph.nbrs{i}; + for j=nbrs(:)' + prod_of_msg{i} = multiply_by_pot(prod_of_msg{i}, msg{j,i}); + end + end + + % each node computes its local belief + old_bel = bel; + for i=1:ndoms + bel{i} = normalize_pot(multiply_pots(prod_of_msg{i}, local_kernel{i})); + end + + % converged? + if iter==1 + converged = 0; + else + converged = 1; + for i=1:ndoms + belT = get_params(bel{i}, 'table'); + old_belT = get_params(old_bel{i}, 'table'); + if ~approxeq(belT, old_belT, engine.tol) + converged = 0; + break; + end + end + end + + if ~converged + old_msg = msg; + % each node sends a msg to each of its neighbors + for i=1:ndoms + nbrs = engine.fgraph.nbrs{i}; + for j=nbrs(:)' + % multiply all incoming msgs except from j + temp = prod_of_msg{i}; + temp = divide_by_pot(temp, old_msg{j,i}); + % send msg from i to j + temp = multiply_by_pot(temp, local_kernel{i}); + msg{i,j} = normalize_pot(marginalize_pot(temp, engine.fgraph.sepset{i,j})); + end + end + end + + iter = iter + 1 +end + +engine.marginal_domains = bel; +%for i=1:ndoms + %engine.marginal_domains{i} = get_params(bel{i}, 'table'); +%end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/marginal_domain.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/marginal_domain.m new file mode 100644 index 00000000..49ad94c5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/Old/marginal_domain.m @@ -0,0 +1,5 @@ +function marginal = marginal_domain(engine, i) +% MARGINAL_DOMAIN Return the marginal on the specified domain (belprop) +% marginal = marginal_domain(engine, i) + +marginal = pot_to_marginal(engine.marginal_domains{i}); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/belprop_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/belprop_inf_engine.m new file mode 100644 index 00000000..839af506 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/belprop_inf_engine.m @@ -0,0 +1,90 @@ +function engine = belprop_inf_engine(bnet, varargin) +% BELPROP_INF_ENGINE Make a loopy belief propagation inference engine +% engine = belprop_inf_engine(bnet, ...) +% +% This is like pearl_inf_engine, except it uses potential objects, +% instead of lambda/pi structs. Hence it is slower. +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default in brackets] +% +% protocol - 'tree' means send messages up then down the tree, +% 'parallel' means use synchronous updates ['parallel'] +% max_iter - max. num. iterations [ 2*num_nodes ] +% momentum - weight assigned to old message in convex combination (useful for damping oscillations) [0] +% tol - tolerance used to assess convergence [1e-3] +% maximize - 1 means use max-product, 0 means use sum-product [0] +% filename - name of file to write beliefs to after each iteration within enter_evidence [ [] ] +% +% e.g., engine = belprop_inf_engine(bnet, 'maximize', 1, 'max_iter', 10) + +% gdl = general distributive law +engine.gdl = bnet_to_gdl(bnet); + +% set default params +N = length(engine.gdl.G); +engine.protocol = 'parallel'; +engine.max_iter = 2*N; +engine.momentum = 0; +engine.tol = 1e-3; +engine.maximize = 0; +engine.filename = []; +engine.fid = []; + +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'max_iter', engine.max_iter = args{i+1}; + case 'momentum', engine.momentum = args{i+1}; + case 'tol', engine.tol = args{i+1}; + case 'protocol', engine.protocol = args{i+1}; + case 'filename', engine.filename = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end + + +if strcmp(engine.protocol, 'tree') + % Make a rooted tree, so there is a fixed message passing order. + root = N; + [engine.tree, engine.preorder, engine.postorder, height, cyclic] = mk_rooted_tree(engine.gdl.G, root); + assert(~cyclic); +end + +% store results computed by enter_evidence here +engine.marginal_domains = cell(1, N); + +engine.niter = []; + +engine = class(engine, 'belprop_inf_engine', inf_engine(bnet)); + +%%%%%%%%% + +function gdl = bnet_to_gdl(bnet) + +gdl.G = mk_undirected(bnet.dag); +N = length(bnet.dag); +gdl.doms = cell(1,N); +for i=1:N + gdl.doms{i} = family(bnet.dag, i); +end + +% Compute a bit vector representation of the set of domains +% dom_bitv(i,j) = 1 iff variable j occurs in domain i +gdl.dom_bitv = zeros(N, N); +for i=1:N + gdl.dom_bitv(i, gdl.doms{i}) = 1; +end + +% compute the interesection of the domains on either side of each edge (separating set) +gdl.sepset = cell(N, N); +gdl.nbrs = cell(1,N); +for i=1:N + nbrs = neighbors(gdl.G, i); + gdl.nbrs{i} = nbrs; + for j = nbrs(:)' + gdl.sepset{i,j} = myintersect(gdl.doms{i}, gdl.doms{j}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/enter_evidence.m new file mode 100644 index 00000000..88cce18e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/enter_evidence.m @@ -0,0 +1,86 @@ +function [engine, ll, niter] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Propagate evidence using belief propagation +% [engine, ll, niter] = enter_evidence(engine, evidence, ...) +% +% The log-likelihood is not computed; ll = 0. +% niter contains the number of iterations used (if engine.protocol = 'parallel') +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - 1 means use max-product, 0 means use sum-product [0] +% exclude - list of nodes whose potential will not be included in the joint [ [] ] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) + +ll = 0; +exclude = []; +maximize = 0; + +if nargin >= 3 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'exclude', exclude = args{i+1}; + case 'maximize', maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +engine.maximize = maximize; + +if ~isempty(engine.filename) + engine.fid = fopen(engine.filename, 'w'); + if engine.fid == 0 + error(['can''t open ' engine.filename]); + end +else + engine.fid = []; +end + +gdl = engine.gdl; +bnet = bnet_from_engine(engine); + +ndoms = length(gdl.doms); +ns = bnet.node_sizes; +onodes = find(~isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + +% prime each local kernel with evidence (if any) +local_kernel = cell(1, ndoms); +for i=1:ndoms + if myismember(i, exclude) + local_kernel{i} = mk_initial_pot(pot_type, gdl.doms{i}, ns, bnet.cnodes, onodes); + else + e = bnet.equiv_class(i); + local_kernel{i} = convert_to_pot(bnet.CPD{e}, pot_type, gdl.doms{i}(:), evidence); + end +end + +% initialise all msgs to 1s +msg = cell(ndoms, ndoms); +for i=1:ndoms + nbrs = gdl.nbrs{i}; + for j=nbrs(:)' + dom = gdl.sepset{i,j}; + msg{i,j} = mk_initial_pot(pot_type, dom, ns, bnet.cnodes, onodes); + end +end + +switch engine.protocol + case 'parallel', + [engine.marginal_domains, niter] = parallel_protocol(engine, evidence, pot_type, local_kernel, msg); + case 'tree', + engine.marginal_domains = serial_protocol(engine, evidence, pot_type, local_kernel, msg); + niter = 1; +end +engine.niter = niter; + +%fprintf('just finished %d iterations of belprop\n', niter); + +if ~isempty(engine.filename) + fclose(engine.fid); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/find_mpe.m new file mode 100644 index 00000000..73bd0abc --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/find_mpe.m @@ -0,0 +1,49 @@ +function mpe = find_mpe(engine, evidence, varargin) +% FIND_MPE Find the most probable explanation of the data (belprop) +% function mpe = find_mpe(engine, evidence,...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% This finds the marginally most likely value for each hidden node, +% and may give the wrong results even if the graph is acyclic, +% unless you set break_ties = 1. +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% break_ties is optional. If 1, we will force ties to be broken consistently +% by calling enter_evidence N times. (see Jensen96, p106) Default = 1. + +break_ties = 1; + +% parse optional params +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'break_ties', break_ties = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end + +engine = enter_evidence(engine, evidence, 'maximize', 1); + +observed = ~isemptycell(evidence); +evidence = evidence(:); % hack to handle unrolled DBNs +N = length(evidence); +mpe = cell(1,N); +for i=1:N + m = marginal_nodes(engine, i); + % observed nodes are all set to 1 inside the inference engine, so we must undo this + if observed(i) + mpe{i} = evidence{i}; + else + mpe{i} = argmax(m.T); + if break_ties + evidence{i} = mpe{i}; + [engine, ll] = enter_evidence(engine, evidence, 'maximize', 1); + end + end +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/loopy_converged.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/loopy_converged.m new file mode 100644 index 00000000..fba4f2fd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/loopy_converged.m @@ -0,0 +1,13 @@ +function niter = loopy_converged(engine) +% LOOPY_CONVERGED Did loopy belief propagation converge? 0 means no, eles we return the num. iterations. +% function niter = loopy_converged(engine) +% +% We use a simple heuristic: we say convergence occurred if the number of iterations +% used was less than the maximum allowed. + +if engine.niter == engine.max_iter + niter = 0; +else + niter = engine.niter; +end +%conv = (strcmp(engine.protocol, 'tree') | (engine.niter < engine.max_iter)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/marginal_family.m new file mode 100644 index 00000000..afe404a8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/marginal_family.m @@ -0,0 +1,6 @@ +function [marginal, pot] = marginal_family(engine, query) +% MARGINAL_NODES Compute the marginal on the family of the specified query node (belprop) +% [marginal, pot] = marginal_family(engine, query) + +pot = engine.marginal_domains{query}; +marginal = pot_to_marginal(pot); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..0c2b5d94 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/marginal_nodes.m @@ -0,0 +1,14 @@ +function [marginal, pot] = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified query nodes (belprop) +% [marginal, pot] = marginal_nodes(engine, query) +% +% query must be a subset of a family + +if isempty(query) + big_pot = engine.marginal_domains{1}; % pick an arbitrary domain +else + big_pot = engine.marginal_domains{query(end)}; +end +pot = marginalize_pot(big_pot, query); +marginal = pot_to_marginal(pot); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..938d9867 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Entries @@ -0,0 +1,4 @@ +/junk/1.1.1.1/Wed May 29 15:59:56 2002// +/parallel_protocol.m/1.1.1.1/Wed May 29 15:59:56 2002// +/tree_protocol.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..9681913e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@belprop_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/junk b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/junk new file mode 100644 index 00000000..11438db0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/junk @@ -0,0 +1,68 @@ +fgraph +fgraph%fgraph%fgraph%fgraph%fgraph%fgraph%fgraph%fgraph%fgraph%fgraph%fgraph%fgraph +fgraph +fgraphffgraphufgraphnfgraphcfgraphtfgraphifgraphofgraphnfgraph fgraph[fgraphbfgraphefgraphlfgraph,fgraph fgraphifgraphtfgraphefgraphrfgraph]fgraph fgraph=fgraph fgraphpfgraphafgraphrfgraphafgraphlfgraphlfgraphefgraphlfgraph_fgraphpfgraphrfgraphofgraphtfgraphofgraphcfgraphofgraphlfgraph(fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph,fgraph fgraphefgraphvfgraphifgraphdfgraphefgraphnfgraphcfgraphefgraph,fgraph fgraphpfgraphofgraphtfgraph_fgraphtfgraphyfgraphpfgraphefgraph,fgraph fgraphlfgraphofgraphcfgraphafgraphlfgraph_fgraphkfgraphefgraphrfgraphnfgraphefgraphlfgraph,fgraph fgraphmfgraphsfgraphgfgraph)fgraph +fgraph +fgraphdfgraphofgraphmfgraphsfgraph fgraph=fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphdfgraphofgraphmfgraphsfgraph;fgraph +fgraphnfgraphdfgraphofgraphmfgraphsfgraph fgraph=fgraph fgraphlfgraphefgraphnfgraphgfgraphtfgraphhfgraph(fgraphdfgraphofgraphmfgraphsfgraph)fgraph;fgraph +fgraphnfgraphsfgraph fgraph=fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphnfgraphofgraphdfgraphefgraph_fgraphsfgraphifgraphzfgraphefgraphsfgraph;fgraph +fgraphofgraphnfgraphofgraphdfgraphefgraphsfgraph fgraph=fgraph fgraphffgraphifgraphnfgraphdfgraph(fgraph~fgraphifgraphsfgraphefgraphmfgraphpfgraphtfgraphyfgraphcfgraphefgraphlfgraphlfgraph(fgraphefgraphvfgraphifgraphdfgraphefgraphnfgraphcfgraphefgraph)fgraph)fgraph;fgraph +fgraphcfgraphnfgraphofgraphdfgraphefgraphsfgraph fgraph=fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphcfgraphnfgraphofgraphdfgraphefgraphsfgraph;fgraph +fgraph +fgraphpfgraphrfgraphofgraphdfgraph_fgraphofgraphffgraph_fgraphmfgraphsfgraphgfgraph fgraph=fgraph fgraphcfgraphefgraphlfgraphlfgraph(fgraph1fgraph,fgraph fgraphnfgraphdfgraphofgraphmfgraphsfgraph)fgraph;fgraph +fgraphbfgraphefgraphlfgraph fgraph=fgraph fgraphcfgraphefgraphlfgraphlfgraph(fgraph1fgraph,fgraph fgraphnfgraphdfgraphofgraphmfgraphsfgraph)fgraph;fgraph +fgraphofgraphlfgraphdfgraph_fgraphbfgraphefgraphlfgraph fgraph=fgraph fgraphcfgraphefgraphlfgraphlfgraph(fgraph1fgraph,fgraph fgraphnfgraphdfgraphofgraphmfgraphsfgraph)fgraph;fgraph +fgraph +fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph fgraph=fgraph fgraph0fgraph;fgraph +fgraphifgraphtfgraphefgraphrfgraph fgraph=fgraph fgraph1fgraph;fgraph +fgraphwfgraphhfgraphifgraphlfgraphefgraph fgraph~fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph fgraph&fgraph fgraph(fgraphifgraphtfgraphefgraphrfgraph fgraph<fgraph=fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphmfgraphafgraphxfgraph_fgraphifgraphtfgraphefgraphrfgraph)fgraph +fgraph fgraph fgraph +fgraph fgraph fgraph%fgraph fgraphefgraphafgraphcfgraphhfgraph fgraphnfgraphofgraphdfgraphefgraph fgraphmfgraphufgraphlfgraphtfgraphifgraphpfgraphlfgraphifgraphefgraphsfgraph fgraphafgraphlfgraphlfgraph fgraphifgraphtfgraphsfgraph fgraphifgraphnfgraphcfgraphofgraphmfgraphifgraphnfgraphgfgraph fgraphmfgraphsfgraphgfgraphsfgraph fgraphafgraphnfgraphdfgraph fgraphcfgraphofgraphmfgraphpfgraphufgraphtfgraphefgraphsfgraph fgraphifgraphtfgraphsfgraph fgraphlfgraphofgraphcfgraphafgraphlfgraph fgraphbfgraphefgraphlfgraphifgraphefgraphffgraph +fgraph fgraph fgraphofgraphlfgraphdfgraph_fgraphbfgraphefgraphlfgraph fgraph=fgraph fgraphbfgraphefgraphlfgraph;fgraph +fgraph fgraph fgraphffgraphofgraphrfgraph fgraphifgraph=fgraph1fgraph:fgraphnfgraphdfgraphofgraphmfgraphsfgraph +fgraph fgraph fgraph fgraph fgraphpfgraphrfgraphofgraphdfgraph_fgraphofgraphffgraph_fgraphmfgraphsfgraphgfgraph{fgraphifgraph}fgraph fgraph=fgraph fgraphmfgraphkfgraph_fgraphifgraphnfgraphifgraphtfgraphifgraphafgraphlfgraph_fgraphpfgraphofgraphtfgraph(fgraphpfgraphofgraphtfgraph_fgraphtfgraphyfgraphpfgraphefgraph,fgraph fgraphdfgraphofgraphmfgraphsfgraph{fgraphifgraph}fgraph,fgraph fgraphnfgraphsfgraph,fgraph fgraphcfgraphnfgraphofgraphdfgraphefgraphsfgraph,fgraph fgraphofgraphnfgraphofgraphdfgraphefgraphsfgraph)fgraph;fgraph +fgraph fgraph fgraph fgraph fgraphnfgraphbfgraphrfgraphsfgraph fgraph=fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphnfgraphbfgraphrfgraphsfgraph{fgraphifgraph}fgraph;fgraph +fgraph fgraph fgraph fgraph fgraphffgraphofgraphrfgraph fgraphjfgraph=fgraphnfgraphbfgraphrfgraphsfgraph(fgraph:fgraph)fgraph'fgraph +fgraph fgraph fgraph fgraph fgraph fgraph fgraphpfgraphrfgraphofgraphdfgraph_fgraphofgraphffgraph_fgraphmfgraphsfgraphgfgraph{fgraphifgraph}fgraph fgraph=fgraph fgraphmfgraphufgraphlfgraphtfgraphifgraphpfgraphlfgraphyfgraph_fgraphbfgraphyfgraph_fgraphpfgraphofgraphtfgraph(fgraphpfgraphrfgraphofgraphdfgraph_fgraphofgraphffgraph_fgraphmfgraphsfgraphgfgraph{fgraphifgraph}fgraph,fgraph fgraphmfgraphsfgraphgfgraph{fgraphjfgraph,fgraphifgraph}fgraph)fgraph;fgraph +fgraph fgraph fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph fgraph fgraph fgraph fgraphbfgraphefgraphlfgraph{fgraphifgraph}fgraph fgraph=fgraph fgraphnfgraphofgraphrfgraphmfgraphafgraphlfgraphifgraphzfgraphefgraph_fgraphpfgraphofgraphtfgraph(fgraphmfgraphufgraphlfgraphtfgraphifgraphpfgraphlfgraphyfgraph_fgraphpfgraphofgraphtfgraphsfgraph(fgraphpfgraphrfgraphofgraphdfgraph_fgraphofgraphffgraph_fgraphmfgraphsfgraphgfgraph{fgraphifgraph}fgraph,fgraph fgraphlfgraphofgraphcfgraphafgraphlfgraph_fgraphkfgraphefgraphrfgraphnfgraphefgraphlfgraph{fgraphifgraph}fgraph)fgraph)fgraph;fgraph +fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph +fgraph fgraph fgraph%fgraph fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph?fgraph +fgraph fgraph fgraphifgraphffgraph fgraphifgraphtfgraphefgraphrfgraph=fgraph=fgraph1fgraph +fgraph fgraph fgraph fgraph fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph fgraph=fgraph fgraph0fgraph;fgraph +fgraph fgraph fgraphefgraphlfgraphsfgraphefgraph +fgraph fgraph fgraph fgraph fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph fgraph=fgraph fgraph1fgraph;fgraph +fgraph fgraph fgraph fgraph fgraphffgraphofgraphrfgraph fgraphifgraph=fgraph1fgraph:fgraphnfgraphdfgraphofgraphmfgraphsfgraph +fgraph fgraph fgraph fgraph fgraph fgraph fgraphifgraphffgraph fgraph~fgraphafgraphpfgraphpfgraphrfgraphofgraphxfgraphefgraphqfgraph_fgraphpfgraphofgraphtfgraph(fgraphbfgraphefgraphlfgraph{fgraphifgraph}fgraph,fgraph fgraphofgraphlfgraphdfgraph_fgraphbfgraphefgraphlfgraph{fgraphifgraph}fgraph,fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphtfgraphofgraphlfgraph)fgraph +fgraph fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph fgraph=fgraph fgraph0fgraph;fgraph +fgraph fgraphbfgraphrfgraphefgraphafgraphkfgraph;fgraph +fgraph fgraph fgraph fgraph fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph fgraph fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph +fgraph fgraph fgraphifgraphffgraph fgraph~fgraphcfgraphofgraphnfgraphvfgraphefgraphrfgraphgfgraphefgraphdfgraph +fgraph fgraph fgraph fgraph fgraphofgraphlfgraphdfgraph_fgraphmfgraphsfgraphgfgraph fgraph=fgraph fgraphmfgraphsfgraphgfgraph;fgraph +fgraph fgraph fgraph fgraph fgraph%fgraph fgraphefgraphafgraphcfgraphhfgraph fgraphnfgraphofgraphdfgraphefgraph fgraphsfgraphefgraphnfgraphdfgraphsfgraph fgraphafgraph fgraphmfgraphsfgraphgfgraph fgraphtfgraphofgraph fgraphefgraphafgraphcfgraphhfgraph fgraphofgraphffgraph fgraphifgraphtfgraphsfgraph fgraphnfgraphefgraphifgraphgfgraphhfgraphbfgraphofgraphrfgraphsfgraph +fgraph fgraph fgraph fgraph fgraphffgraphofgraphrfgraph fgraphifgraph=fgraph1fgraph:fgraphnfgraphdfgraphofgraphmfgraphsfgraph +fgraph fgraph fgraph fgraph fgraph fgraph fgraphnfgraphbfgraphrfgraphsfgraph fgraph=fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphnfgraphbfgraphrfgraphsfgraph{fgraphifgraph}fgraph;fgraph +fgraph fgraph fgraph fgraph fgraph fgraph fgraphffgraphofgraphrfgraph fgraphjfgraph=fgraphnfgraphbfgraphrfgraphsfgraph(fgraph:fgraph)fgraph'fgraph +fgraph fgraph%fgraph fgraphmfgraphufgraphlfgraphtfgraphifgraphpfgraphlfgraphyfgraph fgraphafgraphlfgraphlfgraph fgraphifgraphnfgraphcfgraphofgraphmfgraphifgraphnfgraphgfgraph fgraphmfgraphsfgraphgfgraphsfgraph fgraphefgraphxfgraphcfgraphefgraphpfgraphtfgraph fgraphffgraphrfgraphofgraphmfgraph fgraphjfgraph +fgraph fgraphtfgraphefgraphmfgraphpfgraph fgraph=fgraph fgraphpfgraphrfgraphofgraphdfgraph_fgraphofgraphffgraph_fgraphmfgraphsfgraphgfgraph{fgraphifgraph}fgraph;fgraph +fgraph fgraphtfgraphefgraphmfgraphpfgraph fgraph=fgraph fgraphdfgraphifgraphvfgraphifgraphdfgraphefgraph_fgraphbfgraphyfgraph_fgraphpfgraphofgraphtfgraph(fgraphtfgraphefgraphmfgraphpfgraph,fgraph fgraphofgraphlfgraphdfgraph_fgraphmfgraphsfgraphgfgraph{fgraphjfgraph,fgraphifgraph}fgraph)fgraph;fgraph +fgraph fgraph%fgraph fgraphsfgraphefgraphnfgraphdfgraph fgraphmfgraphsfgraphgfgraph fgraphffgraphrfgraphofgraphmfgraph fgraphifgraph fgraphtfgraphofgraph fgraphjfgraph +fgraph fgraphtfgraphefgraphmfgraphpfgraph fgraph=fgraph fgraphmfgraphufgraphlfgraphtfgraphifgraphpfgraphlfgraphyfgraph_fgraphbfgraphyfgraph_fgraphpfgraphofgraphtfgraph(fgraphtfgraphefgraphmfgraphpfgraph,fgraph fgraphlfgraphofgraphcfgraphafgraphlfgraph_fgraphkfgraphefgraphrfgraphnfgraphefgraphlfgraph{fgraphifgraph}fgraph)fgraph;fgraph +fgraph fgraphifgraphffgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphmfgraphafgraphxfgraphifgraphmfgraphifgraphzfgraphefgraph +fgraph fgraph fgraph fgraphtfgraphefgraphmfgraphpfgraph2fgraph fgraph=fgraph fgraphmfgraphafgraphrfgraphgfgraphifgraphnfgraphafgraphlfgraphifgraphzfgraphefgraph_fgraphpfgraphofgraphtfgraph_fgraphmfgraphafgraphxfgraph(fgraphtfgraphefgraphmfgraphpfgraph,fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphsfgraphefgraphpfgraphsfgraphefgraphtfgraph{fgraphifgraph,fgraphjfgraph}fgraph)fgraph;fgraph +fgraph fgraphefgraphlfgraphsfgraphefgraph +fgraph fgraph fgraph fgraphtfgraphefgraphmfgraphpfgraph2fgraph fgraph=fgraph fgraphmfgraphafgraphrfgraphgfgraphifgraphnfgraphafgraphlfgraphifgraphzfgraphefgraph_fgraphpfgraphofgraphtfgraph(fgraphtfgraphefgraphmfgraphpfgraph,fgraph fgraphefgraphnfgraphgfgraphifgraphnfgraphefgraph.fgraphffgraphgfgraphrfgraphafgraphpfgraphhfgraph.fgraphsfgraphefgraphpfgraphsfgraphefgraphtfgraph{fgraphifgraph,fgraphjfgraph}fgraph)fgraph;fgraph +fgraph fgraphefgraphnfgraphdfgraph +fgraph fgraphmfgraphsfgraphgfgraph{fgraphifgraph,fgraphjfgraph}fgraph fgraph=fgraph fgraphnfgraphofgraphrfgraphmfgraphafgraphlfgraphifgraphzfgraphefgraph_fgraphpfgraphofgraphtfgraph(fgraphtfgraphefgraphmfgraphpfgraph2fgraph)fgraph;fgraph +fgraph fgraph fgraph fgraph fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph fgraph fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph fgraph fgraphefgraphnfgraphdfgraph +fgraph +fgraph fgraph fgraphifgraphtfgraphefgraphrfgraph fgraph=fgraph fgraphifgraphtfgraphefgraphrfgraph fgraph+fgraph fgraph1fgraph;fgraph +fgraphefgraphnfgraphdfgraph +fgraph +gdl diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/parallel_protocol.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/parallel_protocol.m new file mode 100644 index 00000000..3e702f7b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/parallel_protocol.m @@ -0,0 +1,86 @@ +function [bel, niter] = parallel_protocol(engine, evidence, pot_type, local_kernel, msg) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +onodes = find(~isemptycell(evidence)); + +ndoms = length(engine.gdl.doms); +prod_of_msg = cell(1, ndoms); +bel = cell(1, ndoms); +old_bel = cell(1, ndoms); + +converged = 0; +iter = 1; +while ~converged && (iter <= engine.max_iter) + + % each node multiplies all its incoming msgs and computes its local belief + old_bel = bel; + for i=1:ndoms + prod_of_msg{i} = mk_initial_pot(pot_type, engine.gdl.doms{i}, ns, bnet.cnodes, onodes); + nbrs = engine.gdl.nbrs{i}; + for j=nbrs(:)' + prod_of_msg{i} = multiply_by_pot(prod_of_msg{i}, msg{j,i}); + end + bel{i} = normalize_pot(multiply_by_pot(local_kernel{i}, prod_of_msg{i})); + end + + if ~isempty(engine.fid) + for i=1:ndoms + tmp = pot_to_marginal(bel{i}); + %fprintf(engine.fid, '%9.7f ', tmp.T(1)); + fprintf(engine.fid, '%9.7f ', tmp.U(1)); + end + %fprintf(engine.fid, ' U '); + %for i=1:ndoms + % tmp = pot_to_marginal(bel{i}); + % fprintf(engine.fid, '%9.7f ', tmp.U(1)); + %end + fprintf(engine.fid, '\n'); + end + + % converged? + if iter==1 + converged = 0; + else + converged = 1; + for i=1:ndoms + if ~approxeq_pot(bel{i}, old_bel{i}, engine.tol) + converged = 0; + break; + end + end + end + + if ~converged + old_msg = msg; + % each node sends a msg to each of its neighbors + for i=1:ndoms + nbrs = engine.gdl.nbrs{i}; + for j=nbrs(:)' + % multiply all incoming msgs except from j + temp = prod_of_msg{i}; + temp = divide_by_pot(temp, old_msg{j,i}); + % send msg from i to j + temp = multiply_by_pot(temp, local_kernel{i}); + temp2 = marginalize_pot(temp, engine.gdl.sepset{i,j}, engine.maximize); + msg{i,j} = normalize_pot(temp2); + end + end + end + + iter = iter + 1; +end + + +niter = iter-1; + +if 0 +for i=1:ndoms + prod_of_msg{i} = mk_initial_pot(pot_type, engine.gdl.doms{i}, ns, bnet.cnodes, onodes); + nbrs = engine.gdl.nbrs{i}; + for j=nbrs(:)' + prod_of_msg{i} = multiply_by_pot(prod_of_msg{i}, msg{j,i}); + end + bel{i} = normalize_pot(multiply_by_pot(local_kernel{i}, prod_of_msg{i})); +end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/tree_protocol.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/tree_protocol.m new file mode 100644 index 00000000..940e74ae --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_inf_engine/private/tree_protocol.m @@ -0,0 +1,48 @@ +function bel = tree_protocol(engine, evidence, pot_type, local_kernel, msg) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +onodes = find(~isemptycell(evidence)); + +ndoms = length(engine.gdl.doms); +prod_of_msg = cell(1, ndoms); +bel = cell(1, ndoms); + +% collect to root (node to parents) +for n=engine.postorder + % absorb msgs from children + prod_of_msg{n} = mk_initial_pot(pot_type, engine.gdl.doms{n}, ns, bnet.cnodes, onodes); + for c=children(engine.tree, n) + prod_of_msg{n} = multiply_by_pot(prod_of_msg{n}, msg{c,n}); + end + % send msg to parents + for p=parents(engine.tree, n) + if iter==1 + temp = prod_of_msg{n}; + else + temp = divide_by_pot(prod_of_msg{n}, old_msg{p,n}); + end + temp = multiply_by_pot(temp, local_kernel{n}); + temp2 = marginalize_pot(temp, engine.gdl.sepset{n,p}, engine.maximize); + %fprintf('%d sends %d\n', n, p); + msg{n,p} = normalize_pot(temp2); + end +end + +% distribute from root (node to children) +for n=engine.preorder + % absorb from parents + %prod_of_msg{n} = mk_initial_pot(pot_type, doms{n}, ns, cnodes, onodes); + for p=parents(engine.tree, n) + prod_of_msg{n} = multiply_by_pot(prod_of_msg{n}, msg{p,n}); + end + bel{n} = normalize_pot(multiply_pots(prod_of_msg{n}, local_kernel{n})); + % send msg to children + for c=children(engine.tree, n) + temp = divide_by_pot(prod_of_msg{n}, msg{c,n}); + temp = multiply_by_pot(temp, local_kernel{n}); + temp2 = marginalize_pot(temp, engine.gdl.sepset{n,c}, engine.maximize); + %fprintf('%d sends %d\n', n, c); + msg{n,c} = normalize_pot(temp2); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Entries new file mode 100644 index 00000000..a2b559af --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/belprop_mrf2_inf_engine.m/1.1.1.1/Fri Jan 3 22:01:56 2003// +/bp_mrf2.m/1.1.1.1/Mon Jan 5 01:23:34 2004// +/enter_soft_evidence.m/1.1.1.1/Thu Jan 2 17:29:54 2003// +/find_mpe.m/1.1.1.1/Thu Jan 2 17:49:18 2003// +/marginal_nodes.m/1.1.1.1/Tue Dec 31 21:24:30 2002// +/set_params.m/1.1.1.1/Thu Jan 2 17:28:56 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Repository new file mode 100644 index 00000000..fe4612c3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@belprop_mrf2_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/belprop_mrf2_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/belprop_mrf2_inf_engine.m new file mode 100644 index 00000000..f7e9d695 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/belprop_mrf2_inf_engine.m @@ -0,0 +1,46 @@ +function engine = belprop_mrf2_inf_engine(mrf2, varargin) +% BELPROP_MRF2_INF_ENGINE Belief propagation for MRFs with discrete pairwise potentials +% engine = belprop_mrf2_inf_engine(mrf2, ...) +% +% This is like belprop_inf_engine, except it is designed for mrf2, so is much faster. +% +% [ ... ] = belprop_mrf2_inf_engine(..., 'param1',val1, 'param2',val2, ...) +% allows you to specify optional parameters as name/value pairs. +% Parameters modifying behavior of enter_evidence are below [default value in brackets] +% +% max_iter - max. num. iterations [ 5*nnodes] +% momentum - weight assigned to old message in convex combination +% (useful for damping oscillations) [0] +% tol - tolerance used to assess convergence [1e-3] +% verbose - 1 means print error at every iteration [0] +% +% Parameters can be changed later using set_params + + +% The advantages of pairwise potentials are +% (1) we can compute messages using vector-matrix multiplication +% (2) we can easily specify the parameters: one potential per edge +% In contrast, potentials on larger cliques are more complicated to deal with. + + +nnodes = length(mrf2.adj_mat); + +[engine.max_iter, engine.momentum, engine.tol, engine.verbose] = ... + process_options(varargin, 'max_iter', [], 'momentum', 0, 'tol', 1e-3, ... + 'verbose', 0); + +if isempty(engine.max_iter) % no user supplied value, so compute default + engine.max_iter = 5*nnodes; + %if acyclic(mrf2.adj_mat, 0) --- can be very slow! + % engine.max_iter = nnodes; + %else + % engine.max_iter = 5*nnodes; + %end +end + +engine.bel = cell(1, nnodes); % store results of enter_evidence here +engine.mrf2 = mrf2; + +engine = class(engine, 'belprop_mrf2_inf_engine'); + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/bp_mrf2.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/bp_mrf2.m new file mode 100644 index 00000000..90baaba1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/bp_mrf2.m @@ -0,0 +1,209 @@ +function [new_bel, niter, new_msg, edge_id, nstates] = bp_mrf2_general(adj_mat, pot, local_evidence, varargin) +% BP_MRF2_GENERAL Belief propagation on an MRF with pairwise potentials +% function [bel, niter] = bp_mrf2_general(adj_mat, pot, local_evidence, varargin) +% +% Input: +% adj_mat(i,j) = 1 iff there is an edge between nodes i and j +% pot(ki,kj,i,j) or pot{i,j}(ki,kj) = potential on edge between nodes i,j +% If the potentials on all edges are the same, +% you can just pass in 1 array, pot(ki,kj) +% local_evidence(state, node) or local_evidence{i}(k) = Pr(observation at node i | Xi=k) +% +% Use cell arrays if the hidden nodes do not all have the same number of values. +% +% Output: +% bel(k,i) or bel{i}(k) = P(Xi=k|evidence) +% niter contains the number of iterations used +% +% [ ... ] = bp_mrf2(..., 'param1',val1, 'param2',val2, ...) +% allows you to specify optional parameters as name/value pairs. +% Parameters names are below [default value in brackets] +% +% max_iter - max. num. iterations [ 5*nnodes] +% momentum - weight assigned to old message in convex combination +% (useful for damping oscillations) - currently ignored i[0] +% tol - tolerance used to assess convergence [1e-3] +% maximize - 1 means use max-product, 0 means use sum-product [0] +% verbose - 1 means print error at every iteration [0] +% +% fn - name of function to call at end of every iteration [ [] ] +% fnargs - we call feval(fn, bel, iter, fnargs{:}) [ [] ] + +nnodes = length(adj_mat); + +[max_iter, momentum, tol, maximize, verbose, fn, fnargs] = ... + process_options(varargin, 'max_iter', 5*nnodes, 'momentum', 0, ... + 'tol', 1e-3, 'maximize', 0, 'verbose', 0, ... + 'fn', [], 'fnargs', []); + +if iscell(local_evidence) + use_cell = 1; +else + use_cell = 0; + [nstates nnodes] = size(local_evidence); +end + +if iscell(pot) + tied_pot = 0; +else + tied_pot = (ndims(pot)==2); +end + + +% give each edge a unique number +ndx = find(adj_mat); +nedges = length(ndx); +edge_id = zeros(1, nnodes*nnodes); +edge_id(ndx) = 1:nedges; +edge_id = reshape(edge_id, nnodes, nnodes); + +% initialise messages +if use_cell + prod_of_msgs = cell(1, nnodes); + old_bel = cell(1, nnodes); + nstates = zeros(1, nnodes); + old_msg = cell(1, nedges); + for i=1:nnodes + nstates(i) = length(local_evidence{i}); + prod_of_msgs{i} = local_evidence{i}; + old_bel{i} = local_evidence{i}; + end + for i=1:nnodes + nbrs = find(adj_mat(:,i)); + for j=nbrs(:)' + old_msg{edge_id(i,j)} = normalise(ones(nstates(j),1)); + end + end +else + prod_of_msgs = local_evidence; + old_bel = local_evidence; + %old_msg = zeros(nstates, nnodes, nnodes); + old_msg = zeros(nstates, nedges); + m = normalise(ones(nstates,1)); + for i=1:nnodes + nbrs = find(adj_mat(:,i)); + for j=nbrs(:)' + old_msg(:, edge_id(i,j)) = m; + %old_msg(:,i,j) = m; + end + end +end + + +converged = 0; +iter = 1; + +while ~converged & (iter <= max_iter) + + % each node sends a msg to each of its neighbors + for i=1:nnodes + nbrs = find(adj_mat(i,:)); + for j=nbrs(:)' + if tied_pot + pot_ij = pot; + else + if iscell(pot) + pot_ij = pot{i,j}; + else + pot_ij = pot(:,:,i,j); + end + end + pot_ij = pot_ij'; % now pot_ij(xj, xi) + % so pot_ij * msg(xi) = sum_xi pot(xj,xi) msg(xi) = f(xj) + + if 1 + % Compute temp = product of all incoming msgs except from j + % by dividing out old msg from j from the product of all msgs sent to i + if use_cell + temp = prod_of_msgs{i}; + m = old_msg{edge_id(j,i)}; + else + temp = prod_of_msgs(:,i); + m = old_msg(:, edge_id(j,i)); + end + if any(m==0) + fprintf('iter=%d, send from i=%d to j=%d\n', iter, i, j); + keyboard + end + m = m + (m==0); % valid since m(k)=0 => temp(k)=0, so can replace 0's with anything + temp = temp ./ m; + temp_div = temp; + end + + if 1 + % Compute temp = product of all incoming msgs except from j in obvious way + if use_cell + %temp = ones(nstates(i),1); + temp = local_evidence{i}; + for k=nbrs(:)' + if k==j, continue, end; + temp = temp .* old_msg{edge_id(k,i)}; + end + else + %temp = ones(nstates,1); + temp = local_evidence(:,i); + for k=nbrs(:)' + if k==j, continue, end; + temp = temp .* old_msg(:, edge_id(k,i)); + end + end + end + %assert(approxeq(temp, temp_div)) + assert(approxeq(normalise(pot_ij * temp), normalise(pot_ij * temp_div))) + + if maximize + newm = max_mult(pot_ij, temp); % bottleneck + else + newm = pot_ij * temp; + end + newm = normalise(newm); + if use_cell + new_msg{edge_id(i,j)} = newm; + else + new_msg(:, edge_id(i,j)) = newm; + end + end % for j + end % for i + old_prod_of_msgs = prod_of_msgs; + + % each node multiplies all its incoming msgs and computes its local belief + if use_cell + for i=1:nnodes + nbrs = find(adj_mat(:,i)); + prod_of_msgs{i} = local_evidence{i}; + for j=nbrs(:)' + prod_of_msgs{i} = prod_of_msgs{i} .* new_msg{edge_id(j,i)}; + end + new_bel{i} = normalise(prod_of_msgs{i}); + end + err = abs(cat(1,new_bel{:}) - cat(1, old_bel{:})); + else + for i=1:nnodes + nbrs = find(adj_mat(:,i)); + prod_of_msgs(:,i) = local_evidence(:,i); + for j=nbrs(:)' + prod_of_msgs(:,i) = prod_of_msgs(:,i) .* new_msg(:,edge_id(j,i)); + end + new_bel(:,i) = normalise(prod_of_msgs(:,i)); + end + err = abs(new_bel(:) - old_bel(:)); + end + converged = all(err < tol); + if verbose, fprintf('error at iter %d = %f\n', iter, sum(err)); end + if ~isempty(fn) + if isempty(fnargs) + feval(fn, new_bel); + else + feval(fn, new_bel, iter, fnargs{:}); + end + end + + iter = iter + 1; + old_msg = new_msg; + old_bel = new_bel; +end % while + +niter = iter-1; + +fprintf('converged in %d iterations\n', niter); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..032ca064 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/enter_soft_evidence.m @@ -0,0 +1,15 @@ +function [engine, ll, niter] = enter_soft_evidence(engine, local_evidence) +% ENTER_SOFT_EVIDENCE Propagate evidence using belief propagation +% [engine, ll, niter] = enter_soft_evidence(engine, local_evidence) +% +% local_evidence{i}(j) = Pr(observation at node i | S(i)=j) +% +% The log-likelihood is not computed; ll = 0. +% niter contains the number of iterations used + +ll = 0; +mrf2 = engine.mrf2; +[bel, niter] = bp_mrf2(mrf2.adj_mat, mrf2.pot, local_evidence, ... + 'max_iter', engine.max_iter, 'momentum', engine.momentum, ... + 'tol', engine.tol, 'maximize', 0, 'verbose', engine.verbose); +engine.bel = bel; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/find_mpe.m new file mode 100644 index 00000000..fbd91265 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/find_mpe.m @@ -0,0 +1,12 @@ +function mpe = find_mpe(engine, local_evidence) +% FIND_MPE Find the most probable explanation of the data +% function mpe = find_mpe(engine, local_evidence +% +% local_evidence{i}(j) = Pr(observation at node i | S(i)=j) +% +% This finds the marginally most likely value for each hidden node. +% It may give inconsistent results if there are ties. + +[mpe, niter] = bp_mpe_mrf2(engine.mrf2.adj_mat, engine.mrf2.pot, local_evidence, ... + 'max_iter', engine.max_iter, 'momentum', engine.momentum, ... + 'tol', engine.tol); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..c51ed666 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/marginal_nodes.m @@ -0,0 +1,10 @@ +function marginal = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified query nodes (belprop) +% marginal = marginal_nodes(engine, query) +% +% query must be a single node + +if length(query)>1 + error('can only handle single node marginals') +end +marginal = engine.bel{query}; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/set_params.m b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/set_params.m new file mode 100644 index 00000000..f5328006 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@belprop_mrf2_inf_engine/set_params.m @@ -0,0 +1,15 @@ +function engine = set_params(engine, varargin) +% SET_PARAMS Modify parameters of the inference engine +% engine = set_params(engine, 'param1',val1, 'param2',val2, ...) +% +% Parameter names are listed below. +% +% max_iter - max. num. iterations +% momentum - weight assigned to old message in convex combination +% (useful for damping oscillations) +% tol - tolerance used to assess convergence +% verbose - 1 means print error at every iteration [0] + +[engine.max_iter, engine.momentum, engine.tol, engine.verbose] = ... + process_options('max_iter', engine.max_iter, 'momentum', engine.momentum, ... + 'tol', engine.tol, 'verbose', engine.verbose); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Entries new file mode 100644 index 00000000..a79c7562 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/cond_gauss_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Repository new file mode 100644 index 00000000..41961f94 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@cond_gauss_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/cond_gauss_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/cond_gauss_inf_engine.m new file mode 100644 index 00000000..166ed4cd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/cond_gauss_inf_engine.m @@ -0,0 +1,23 @@ +function engine = cond_gauss_inf_engine(bnet) +% COND_GAUSS_INF_ENGINE Conditional Gaussian inference engine +% engine = cond_gauss_inf_engine(bnet) +% +% Enumerates all the discrete roots, and runs jtree on the remaining Gaussian nodes. + +dnodes = mysetdiff(1:length(bnet.dag), bnet.cnodes); + +%onodes = dnodes; % all the discrete ndoes will be observed +%engine.sub_engine = jtree_inf_engine(bnet, onodes); +bnet2 = bnet; +bnet2.observed = dnodes; +engine.sub_engine = jtree_inf_engine(bnet2); + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.T = []; +engine.mu = []; +engine.Sigma = []; +engine.joint_dmarginal = []; +engine.onodes = []; % needed for marginal_nodes +engine.evidence = []; % needed for marginal_nodes add_ev + +engine = class(engine, 'cond_gauss_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/enter_evidence.m new file mode 100644 index 00000000..db5019b1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/enter_evidence.m @@ -0,0 +1,57 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (cond_gauss) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +observed = ~isemptycell(evidence); +onodes = find(observed); +hnodes = find(isemptycell(evidence)); +engine.evidence = evidence; + +% check there are no C->D links where C is hidden +pot_type = determine_pot_type(bnet, onodes); + +dhid = myintersect(hnodes, bnet.dnodes); +S = prod(ns(dhid)); +T = zeros(S,1); + +N = length(bnet.dag); +mu = cell(1,N); +Sigma = cell(1,N); +cobs = myintersect(bnet.cnodes, onodes); +chid = myintersect(bnet.cnodes, hnodes); +ens = ns; +ens(cobs) = 0; +for j=chid(:)' + mu{j} = zeros(ens(j), S); + Sigma{j} = zeros(ens(j), ens(j), S); +end + +for i=1:S + dvals = ind2subv(ns(dhid), i); + evidence(dhid) = num2cell(dvals); + [sub_engine, loglik] = enter_evidence(engine.sub_engine, evidence); + for j=chid(:)' + m = marginal_nodes(sub_engine, j); + mu{j}(:,i) = m.mu; + Sigma{j}(:,:,i) = m.Sigma; + end + T(i) = exp(loglik); +end + +[T, lik] = normalise(T); +loglik = log(lik); + +engine.T = T; +engine.mu = mu; +engine.Sigma = Sigma; + +dnodes = bnet.dnodes; +dobs = myintersect(dnodes, onodes); +ens(dobs) = 1; +engine.joint_dmarginal = dpot(dnodes, ens(dnodes), myreshape(engine.T, ens(dnodes))); + +engine.onodes = onodes; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..9c5d60a7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@cond_gauss_inf_engine/marginal_nodes.m @@ -0,0 +1,36 @@ +function marginal = marginal_nodes(engine, query, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (cond_gauss) +% marginal = marginal_nodes(engine, query, add_ev) +% +% 'query' must be a singleton set +% add_ev is an optional argument; if 1, we will "inflate" the marginal of observed nodes +% to their original size, adding 0s to the positions which contradict the evidence + +if nargin < 3, add_ev = 0; end + +if length(query) ~= 1 + error('cond_gauss_inf_engine can only handle marginal queries on single nodes') +end +j = query; +bnet = bnet_from_engine(engine); + +if myismember(j, bnet.cnodes) + if ~myismember(j, engine.onodes) + [m, C] = collapse_mog(engine.mu{j}, engine.Sigma{j}, engine.T); + marginal.mu = m; + marginal.Sigma = C; + marginal.T = 1.0; % single mixture component + else + marginal.mu = engine.evidence{j}; + k = bnet.node_sizes(j); + marginal.Sigma = zeros(k,k); + marginal.T = 1.0; % since P(E|E)=1 + end +else + marginal = pot_to_marginal(marginalize_pot(engine.joint_dmarginal, j)); + if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, bnet.node_sizes); + end +end + +marginal.domain = query; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Entries new file mode 100644 index 00000000..e4399482 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enumerative_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Repository new file mode 100644 index 00000000..ee8672a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@enumerative_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/enter_evidence.m new file mode 100644 index 00000000..eeb2193c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/enter_evidence.m @@ -0,0 +1,10 @@ +function [engine, loglik] = enter_evidence(engine, evidence) +% ENTER_EVIDENCE Add the specified evidence to the network (enumerative_inf) +% [engine, loglik] = enter_evidence(engine, evidence) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) + +engine.evidence = evidence; +if nargout == 2 + [m, loglik] = marginal_nodes(engine, []); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/enumerative_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/enumerative_inf_engine.m new file mode 100644 index 00000000..c31c64c9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/enumerative_inf_engine.m @@ -0,0 +1,11 @@ +function engine = enumerative_inf_engine(bnet) +% ENUMERATIVE_INF_ENGINE Inference engine for fully discrete BNs that uses exhaustive enumeration. +% engine = enumerative_inf_engine(bnet) + + +assert(isempty(bnet.cnodes)); + +% This is where we store stuff between enter_evidence and marginal_nodes +engine.evidence = []; + +engine = class(engine, 'enumerative_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..1c31eae1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@enumerative_inf_engine/marginal_nodes.m @@ -0,0 +1,41 @@ +function [marginal, loglik] = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified query nodes (enumerative_inf) +% [marginal, loglik] = marginal_nodes(engine, query) + + +if isempty(query) & nargout < 2 + marginal.T = 1; + marginal.domain = []; + return; +end + +evidence = engine.evidence; +bnet = bnet_from_engine(engine); +assert(isempty(bnet.cnodes)); +n = length(bnet.dag); +observed = ~isemptycell(evidence); +vals = cat(1,evidence{observed}); +vals = vals(:)'; +ns = bnet.node_sizes; + +sz = ns(query); +T = 0*myones(sz); +p = 0; +for i=1:prod(ns) + inst = ind2subv(ns, i); % i'th instantiation + if isempty(vals) | inst(observed) == vals % agrees with evidence + prob = exp(log_lik_complete(bnet, num2cell(inst(:)))); + p = p + prob; + v = inst(query); + j = subv2ind(sz, v); + T(j) = T(j) + prob; + end +end + +[T, lik] = normalise(T); +lik = p; +loglik = log(lik); + +Tsmall = shrink_obs_dims_in_table(T, query, evidence); +marginal.domain = query; +marginal.T = Tsmall; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Entries new file mode 100644 index 00000000..16ace516 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/gaussian_inf_engine.m/1.1.1.1/Fri May 14 01:13:26 2004// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Repository new file mode 100644 index 00000000..26418ea5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@gaussian_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/enter_evidence.m new file mode 100644 index 00000000..c509a725 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/enter_evidence.m @@ -0,0 +1,46 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (gaussian_inf_engine) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +O = find(~isemptycell(evidence)); +H = find(isemptycell(evidence)); +vals = cat(1, evidence{O}); + +% Compute Pr(H|o) +[Hmu, HSigma, loglik] = condition_gaussian(engine.mu, engine.Sigma, H, O, vals(:), ns); + +engine.Hmu = Hmu; +engine.HSigma = HSigma; +engine.hnodes = H; + +%%%%%%%% + +function [mu2, Sigma2, loglik] = condition_gaussian(mu, Sigma, X, Y, y, ns) +% CONDITION_GAUSSIAN Compute Pr(X|Y=y) where X and Y are jointly Gaussian. +% [mu2, Sigma2, ll] = condition_gaussian(mu, Sigma, X, Y, y, ns) + +if isempty(y) + mu2 = mu; + Sigma2 = Sigma; + loglik = 0; + return; +end + +use_log = 1; + +if length(Y)==length(mu) % instantiating every variable + mu2 = y; + Sigma2 = zeros(length(y)); + loglik = gaussian_prob(y, mu, Sigma, use_log); + return; +end + +[muX, muY, SXX, SXY, SYX, SYY] = partition_matrix_vec(mu, Sigma, X, Y, ns); +K = SXY*inv(SYY); +mu2 = muX + K*(y-muY); +Sigma2 = SXX - K*SYX; +loglik = gaussian_prob(y, muY, SYY, use_log); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/gaussian_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/gaussian_inf_engine.m new file mode 100644 index 00000000..3e34c166 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/gaussian_inf_engine.m @@ -0,0 +1,25 @@ +function engine = gaussian_inf_engine(bnet) +% GAUSSIAN_INF_ENGINE Computes the joint multivariate Gaussian corresponding to the bnet +% engine = gaussian_inf_engine(bnet) +% +% For details on how to compute the joint Gaussian from the bnet, see +% - "Gaussian Influence Diagrams", R. Shachter and C. R. Kenley, Management Science, 35(5):527--550, 1989. +% Once we have the Gaussian, we can apply the standard formulas for conditioning and marginalization. + +assert(isequal(bnet.cnodes, 1:length(bnet.dag))); + +[W, D, mu] = extract_params_from_gbn(bnet); +U = inv(eye(size(W)) - W')'; +Sigma = U' * D * U; + +engine.mu = mu; +engine.Sigma = Sigma; +%engine.logp = log(normal_coef(Sigma)); + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.Hmu = []; +engine.HSigma = []; +engine.hnodes = []; + +engine = class(engine, 'gaussian_inf_engine', inf_engine(bnet)); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..f3142cd5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/marginal_nodes.m @@ -0,0 +1,15 @@ +function marginal = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified query nodes (gaussian) +% marginal = marginal_nodes(engine, query) + +% Compute sum_{Hsum} Pr(Hkeep, Hsum | o) +H = engine.hnodes; +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +Hkeep = myintersect(H, query); +Hsum = mysetdiff(H, Hkeep); + +[marginal.mu, marginal.Sigma] = marginalize_gaussian(engine.Hmu, engine.HSigma, Hkeep, Hsum, ns); +marginal.domain = query; +marginal.T = 1; + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..de387328 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Entries @@ -0,0 +1,2 @@ +/extract_params_from_gbn.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..15f3d8c4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@gaussian_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/extract_params_from_gbn.m b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/extract_params_from_gbn.m new file mode 100644 index 00000000..86345830 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gaussian_inf_engine/private/extract_params_from_gbn.m @@ -0,0 +1,38 @@ +function [B,D,mu] = extract_params_from_gbn(bnet) +% Extract all the local parameters of each Gaussian node, and collect them into global matrices. +% [B,D,mu] = extract_params_from_gbn(bnet) +% +% B(i,j) is a block matrix that contains the transposed weight matrix from node i to node j. +% D(i,i) is a block matrix that contains the noise covariance matrix for node i. +% mu(i) is a block vector that contains the shifted noise mean for node i. + +% In Shachter's model, the mean of each node in the global gaussian is +% the same as the node's local unconditional mean. +% In Alag's model (which we use), the global mean gets shifted. + + +num_nodes = length(bnet.dag); +bs = bnet.node_sizes(:); % bs = block sizes +N = sum(bs); % num scalar nodes + +B = zeros(N,N); +D = zeros(N,N); +mu = zeros(N,1); + +for i=1:num_nodes % in topological order + ps = parents(bnet.dag, i); + e = bnet.equiv_class(i); + %[m, Sigma, weights] = extract_params_from_CPD(bnet.CPD{e}); + s = struct(bnet.CPD{e}); % violate privacy of object + m = s.mean; Sigma = s.cov; weights = s.weights; + if length(ps) == 0 + mu(block(i,bs)) = m; + else + mu(block(i,bs)) = m + weights * mu(block(ps,bs)); + end + B(block(ps,bs), block(i,bs)) = weights'; + D(block(i,bs), block(i,bs)) = Sigma; +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Entries new file mode 100644 index 00000000..c19ebdd4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/gibbs_sampling_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Repository new file mode 100644 index 00000000..3338daf9 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@gibbs_sampling_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/enter_evidence.m new file mode 100644 index 00000000..0710d5c8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/enter_evidence.m @@ -0,0 +1,29 @@ +function [engine, loglik] = enter_evidence(engine, evidence) +% ENTER_EVIDENCE Add the specified evidence to the network (gibbs_sampling_inf_engine) +% [engine, loglik] = enter_evidence(engine, evidence) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value +% +% loglik is not computed... we just return a 0 value + +bnet = bnet_from_engine(engine); + +engine.hnodes = find(isemptycell(evidence)); +engine.onodes = mysetdiff(1:length(evidence), engine.hnodes); + +engine.evidence = zeros(engine.slice_size, 1); + +% Reset all counts since they are no longer valid +engine.marginal_counts = {}; +%engine.state = sample_bnet (bnet, 1, 0); +engine.state = cell2num(sample_bnet(bnet)); + +% For speed, we use a normal (not cell) array. We're making use of +% the current restriction to discrete nodes. +for i = engine.onodes + engine.evidence(i) = evidence{i}; +end + +loglik = 0; + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/gibbs_sampling_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/gibbs_sampling_inf_engine.m new file mode 100644 index 00000000..3dc4b361 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/gibbs_sampling_inf_engine.m @@ -0,0 +1,104 @@ +function engine = gibbs_sampling_inf_engine(bnet, varargin) +% GIBBS_SAMPLING_INF_ENGINE +% +% engine = gibbs_sampling_inf_engine(bnet, ...) +% +% Optional parameters [default in brackets] +% 'burnin' - How long before you start using the samples [100]. +% 'gap' - how often you use the samples in the estimate [1]. +% 'T' - number of samples [1000] +% i.e, number of node flips (so, for +% example if there are 10 nodes in the bnet, and T is 1000, each +% node will get flipped 100 times (assuming a deterministic schedule)) +% The total running time is proportional to burnin + T*gap. +% +% 'order' - if the sampling schedule is deterministic, use this +% parameter to specify the order in which nodes are sampled. +% Order is allowed to include multiple copies of nodes, which is +% useful if you want to, say, focus sampling on particular nodes. +% Default is to use a deterministic schedule that goes through the +% nodes in order. +% +% 'sampling_dist' - when using a stochastic sampling method, at +% each step the node to sample is chosen according to this +% distribution (may be unnormalized) +% +% The sampling_dist and order parameters shouldn't both be used, +% and this will cause an assert. +% +% +% Written by "Bhaskara Marthi" <bhaskara@cs.berkeley.edu> Feb 02. + + +engine.burnin = 100; +engine.gap = 1; +engine.T = 1000; +use_default_order = 1; +engine.deterministic = 1; +engine.order = {}; +engine.sampling_dist = {}; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i = 1:2:nargs + switch args{i} + case 'burnin' + engine.burnin = args{i+1}; + case 'gap' + engine.gap = args{i+1}; + case 'T' + engine.T = args{i+1}; + case 'order' + assert (use_default_order); + use_default_order = 0; + engine.order = args{i+1}; + case 'sampling_dist' + assert (use_default_order); + use_default_order = 0; + engine.deterministic = 0; + engine.sampling_dist = args{i+1}; + otherwise + error(['unrecognized parameter to gibbs_sampling_inf_engine']); + end + end +end + +engine.slice_size = size(bnet.dag, 2); +if (use_default_order) + engine.order = 1:engine.slice_size; +end +engine.hnodes = []; +engine.onodes = []; +engine.evidence = []; +engine.state = []; +engine.marginal_counts = {}; + +% Precompute the strides for each CPT +engine.strides = compute_strides(bnet); + +% Precompute graphical information +engine.families = compute_families(bnet); +engine.children = compute_children(bnet); + +% For convenience, store the CPTs as tables rather than objects +engine.CPT = get_cpts(bnet); + +engine = class(engine, 'gibbs_sampling_inf_engine', inf_engine(bnet)); + + + + + + + + + + + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..8df75552 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/marginal_nodes.m @@ -0,0 +1,135 @@ +function [marginal, engine] = marginal_nodes(engine, nodes, varargin); +% MARGINAL_NODES Compute the marginal on the specified query nodes +% (gibbs_sampling_engine) +% [marginal, engine] = marginal_nodes(engine, nodes, ...) +% +% returns Pr(X(nodes) | X(observedNodes)) +% +% The engine is also modified, and so it is returned as well, since +% Matlab doesn't support passing by reference(!) So +% if you want to, for example, incrementally run gibbs for a few 100 +% steps at a time, you should use the returned value. +% +% Optional arguments : +% +% 'reset_counts' is 1 if you want to reset the counts made in the +% past, and 0 otherwise (if the current query nodes are different +% from the previous query nodes, or if marginal_nodes has not been +% called before, reset_counts should be set to 1). +% By default it is 1. + + +reset_counts = 1; + +if (nargin > 3) + args = varargin; + nargs = length(args); + for i = 1:2:nargs + switch args{i} + case 'reset_counts' + reset_counts = args{i+1}; + otherwise + error(['Incorrect argument to gibbs_sampling_engine/' ... + ' marginal_nodes']); + end + end +end + +% initialization stuff +bnet = bnet_from_engine(engine); +slice_size = engine.slice_size; +hnodes = engine.hnodes; +onodes = engine.onodes; +nonqnodes = mysetdiff(1:slice_size, nodes); +gap = engine.gap; +burnin = engine.burnin; +T_max = engine.T; +ns = bnet.node_sizes(nodes); + + +% Cache the strides for the marginal table +marg_strides = [1 cumprod(ns(1:end-1))]; + +% Reset counts if necessary +if (reset_counts == 1) + %state = sample_bnet(bnet, 1, 0); + %state = cell2num(sample_bnet(bnet, 'evidence', num2cell(engine.evidence))); + state = cell2num(sample_bnet(bnet)); + state(onodes) = engine.evidence(onodes); + if (length(ns) == 1) + marginal_counts = zeros(ns(1),1); + else + marginal_counts = zeros(ns); + end + +% Otherwise, use the counts that have been stored in the engine +else + state = engine.state; + state(onodes, :) = engine.evidence(onodes, :); + marginal_counts = engine.marginal_counts; +end + +if (engine.deterministic == 1) + pos = 1; + order = engine.order; + orderSize = length(engine.order); +else + sampling_dist = normalise(engine.sampling_dist); +end + + +for t = 1:(T_max*gap+burnin) + + % First, select node m to sample + if (engine.deterministic == 1) + m = engine.order(pos); + pos = pos+1; + if (pos > orderSize) + pos = 1; + end + else + m = my_sample_discrete(sampling_dist); + end + + + % If the node is observed, then don't bother resampling + if (myismember(m, onodes)) + continue; + end + + % Next, compute the posterior + post = compute_posterior (bnet, state, m, engine.strides, engine.families, ... + engine.children, engine.CPT); + state(m) = my_sample_discrete(post); + + % Now update our monte carlo estimate of the posterior + % distribution on the query node + if ((mod(t-burnin, gap) == 0) & (t > burnin)) + + vals = state(nodes); + index = 1+marg_strides*(vals-1); + marginal_counts(index) = marginal_counts(index)+1; + end +end + +% Store results for future computation. Note that we store +% unnormalized counts +engine.state = state; +engine.marginal_counts = marginal_counts; + +marginal.T = normalise(marginal_counts); + + + + + + + + + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CPT.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CPT.m new file mode 100644 index 00000000..772f137c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CPT.m @@ -0,0 +1,5 @@ +function c = CPT(bnet, i) +% CPT Helper function avoid having to type in +% CPD_to_CPT(bnet.CPD{i}) every time + +c = CPD_to_CPT(bnet.CPD{i}); \ No newline at end of file diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..0919a694 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Entries @@ -0,0 +1,13 @@ +/CPT.m/1.1.1.1/Wed May 29 15:59:56 2002// +/compute_children.m/1.1.1.1/Wed May 29 15:59:56 2002// +/compute_families.m/1.1.1.1/Wed May 29 15:59:56 2002// +/compute_families_dbn.m/1.1.1.1/Wed May 29 15:59:56 2002// +/compute_posterior.c/1.1.1.1/Wed May 29 15:59:56 2002// +/compute_posterior_dbn.m/1.1.1.1/Wed May 29 15:59:56 2002// +/compute_strides.m/1.1.1.1/Wed May 29 15:59:56 2002// +/get_cpts.m/1.1.1.1/Wed May 29 15:59:56 2002// +/get_slice_dbn.c/1.1.1.1/Wed May 29 15:59:56 2002// +/get_slice_dbn.m/1.1.1.1/Wed May 29 15:59:56 2002// +/my_sample_discrete.m/1.1.1.1/Wed May 29 15:59:56 2002// +/sample_single_discrete.c/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..a3027631 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@gibbs_sampling_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_children.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_children.m new file mode 100644 index 00000000..3af799f8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_children.m @@ -0,0 +1,12 @@ +function c = compute_children(bnet) +% COMPUTE_CHILDREN +% precomputes the children of nodes in a bnet +% +% The return value is a cell array for now + +ss = size(bnet.dag, 1); +c = cell(ss, 1); +for i = 1:ss + c{i} = children(bnet.dag, i); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_families.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_families.m new file mode 100644 index 00000000..e75974cc --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_families.m @@ -0,0 +1,12 @@ +function families = compute_families(bnet) +% COMPUTE_FAMILIES +% precomputes the families of nodes in a bnet +% +% The return value is a cell array for now + +ss = size(bnet.dag, 1); +families = cell(ss, 1); +for i = 1:ss + families{i} = family(bnet.dag, i); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_families_dbn.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_families_dbn.m new file mode 100644 index 00000000..7647bc28 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_families_dbn.m @@ -0,0 +1,13 @@ +function families = compute_families_dbn(bnet) +% COMPUTE_FAMILIES +% precomputes the families of nodes in a dbn +% +% The return value is a cell array for now + +ss = size(bnet.intra, 1); +families = cell(ss, 2); +for i = 1:ss + families{i, 1} = family(bnet.dag, i, 1); + families{i, 2} = family(bnet.dag, i, 2); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_posterior.c b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_posterior.c new file mode 100644 index 00000000..3c61b7f3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_posterior.c @@ -0,0 +1,107 @@ +#include "mex.h" + +/* Helper function that extracts a one-dimensional slice from a cpt */ +/* +void multiplySlice(mxArray *bnet, mxArray *state, int i, int nsi, int j, + mxArray *strides, mxArray *fam, mxArray *cpts, + double *y) +*/ +void multiplySlice(const mxArray *bnet, const mxArray *state, int i, int nsi, int j, + const mxArray *strides, const mxArray *fam, const mxArray *cpts, + double *y) +{ + mxArray *ec, *cpt, *family; + double *ecElts, *cptElts, *famElts, *strideElts, *ev; + int c1, k, famSize, startInd, strideStride, pos, stride; + + strideStride = mxGetM(strides); + strideElts = mxGetPr(strides); + + ev = mxGetPr(state); + + /* Get the CPT */ + ec = mxGetField (bnet, 0, "equiv_class"); + ecElts = mxGetPr(ec); + k = (int) ecElts[j-1]; + cpt = mxGetCell (cpts, k-1); + cptElts = mxGetPr (cpt); + + /* Get the family vector for this cpt */ + family = mxGetCell (fam, j-1); + famSize = mxGetNumberOfElements (family); + famElts = mxGetPr (family); + + /* Figure out starting position and stride */ + startInd = 0; + for (c1 = 0, pos = k-1; c1 < famSize; c1++, pos +=strideStride) { + if (famElts[c1] != i) { + startInd += strideElts[pos]*(ev[(int)famElts[c1]-1]-1); + } + else { + stride = strideElts[pos]; + } + } + + for (c1 = 0, pos = startInd; c1 < nsi; c1++, pos+=stride) { + y[c1] *= cptElts[pos]; + } +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray + *prhs[]) +{ + double *pi, *nsElts, *y, *childrenElts; + mxArray *ns, *children; + double sum; + int i, nsi, c1, numChildren; + + pi = mxGetPr(prhs[2]); + i = (int) pi[0]; + + ns = mxGetField(prhs[0], 0, "node_sizes"); + nsElts = mxGetPr(ns); + nsi = (int) nsElts[i-1]; + + /* Initialize the posterior */ + plhs[0] = mxCreateDoubleMatrix (1, nsi, mxREAL); + y = mxGetPr(plhs[0]); + for (c1 = 0; c1 < nsi; c1++) { + y[c1] = 1; + } + + /* Multiply in the cpt of the node i */ + multiplySlice(prhs[0], prhs[1], i, nsi, i, prhs[3], prhs[4], + prhs[6], y); + + + /* Multiply in cpts of children of i */ + children = mxGetCell (prhs[5], i-1); + numChildren = mxGetNumberOfElements (children); + childrenElts = mxGetPr (children); + + for (c1 = 0; c1 < numChildren; c1++) { + int j; + j = (int) childrenElts[c1]; + multiplySlice (prhs[0], prhs[1], i, nsi, j, prhs[3], prhs[4], + prhs[6], y); + } + + sum = 0; + /* normalize! */ + for (c1 = 0; c1 < nsi; c1++) { + sum += y[c1]; + } + + for (c1 = 0; c1 < nsi; c1++) { + y[c1] /= sum; + } +} + + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_posterior_dbn.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_posterior_dbn.m new file mode 100644 index 00000000..e9a69b24 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_posterior_dbn.m @@ -0,0 +1,59 @@ +function post = compute_posterior_dbn(bnet, state, i, n, strides, families, ... + CPT) +% COMPUTE_POSTERIOR +% +% post = compute_posterior(bnet, state, i, n, strides, families, +% cpts) +% +% Compute the posterior distribution on node X_i^n of a DBN, +% conditional on evidence in the cell array state +% +% strides is the cached result of compute_strides(bnet) +% families is the cached result of compute_families(bnet) +% cpt is the cached result of get_cpts(bnet) +% +% post is a one-dimensional table + + + +% First multiply in the cpt of the node itself +post = get_slice_dbn(bnet, state, i, n, i, n, strides, families, CPT); +post = post(:); + +% Then multiply in CPTs of children that are in this slice +for j = children(bnet.intra, i) + slice = get_slice_dbn(bnet, state, j, n, i, n, strides, families, CPT); + post = post.*slice(:); +end + +% Finally, if necessary, multiply in CPTs of children in the next +% slice +if (n < size(state,2)) + for j = children(bnet.inter, i) + slice = get_slice_dbn(bnet, state, j, n+1, i, n, strides, families, ... + CPT); + post = post.*slice(:); + end +end + +post = normalise(post); + + + + + + + + + + + + + + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_strides.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_strides.m new file mode 100644 index 00000000..a8e26c25 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/compute_strides.m @@ -0,0 +1,27 @@ +function strides = compute_strides(bnet) +% COMPUTE_STRIDES For each CPT and each variable in that CPT, +% returns the stride of that variable. So in future, we can +% quickly extract a slice of the CPT. +% +% The return value is a 2d array, where strides(i,j) contains the +% stride of the jth variable in the ith CPT. Cell arrays would +% have saved space but they are slower. +% + +num_cpts = size(bnet.CPD, 2); +max_cpt_dim = 1 + max(sum(bnet.dag)); +strides = zeros(num_cpts, max_cpt_dim); + +for i = 1:num_cpts + c = CPT(bnet, i); + siz = size(CPT(bnet, i)); + + % Deal with the special case of a 1-d array separately + if siz(2) == 1 + dim = 1; + else + dim = size(siz, 2); + end + + strides(i, 1:dim ) = [1 cumprod(siz(1:dim-1))]; +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_cpts.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_cpts.m new file mode 100644 index 00000000..77c86070 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_cpts.m @@ -0,0 +1,8 @@ +function c = get_cpts(bnet) +% Get all the cpts in tabular form + +cpds = bnet.CPD; +c = cell(size(cpds)); +for i = 1:length(c) + c{i} = CPT(bnet, i); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_slice_dbn.c b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_slice_dbn.c new file mode 100644 index 00000000..33540eff --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_slice_dbn.c @@ -0,0 +1,116 @@ +#include "mex.h" + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray + *prhs[]) +{ + double *pn, *pi, *pj, *pm, *y, *ecElts, *pcpt, *famElts, *strideElts, + *ev, *nsElts; + int i, k, j, m, n; + mxArray *ec, *cpt, *fam, *ns; + int c1, famSize, nsj; + int strideStride, startInd, stride, pos, numNodes; + + const int BNET = 0; + const int STATE = 1; + const int STRIDES = 6; + const int FAMILIES = 7; + const int CPT = 8; + + pn = mxGetPr(prhs[3]); + n = (int) pn[0]; + pi = mxGetPr(prhs[2]); + i = (int) pi[0]; + pj = mxGetPr(prhs[4]); + j = (int) pj[0]; + pm = mxGetPr(prhs[5]); + m = (int) pm[0]; + ev = mxGetPr(prhs[STATE]); + ns = mxGetField (prhs[BNET], 0, "node_sizes"); + nsElts = mxGetPr (ns); + numNodes = mxGetM(ns); + + strideStride = mxGetM(prhs[STRIDES]); + strideElts = mxGetPr(prhs[STRIDES]); + + + + /* Treat the case n = 1 separately */ + if (pn[0] == 1) { + + /* Get the appropriate CPT */ + ec = mxGetField (prhs[BNET], 0, "eclass1"); + ecElts = mxGetPr(ec); + k = (int) ecElts[i-1]; + cpt = mxGetCell (prhs[8], k-1); + pcpt = mxGetPr(cpt); + + nsj = (int) nsElts[j-1]; + + /* Get the correct family vector */ + /* (Note : MEX is painful) */ + fam = mxGetCell (prhs[FAMILIES], i - 1); + famSize = mxGetNumberOfElements(fam); + famElts = mxGetPr(fam); + + + /* Figure out starting position and stride */ + startInd = 0; + for (c1 = 0, pos = k-1; c1 < famSize; c1++, pos+=strideStride) { + if (famElts[c1] != j) { + startInd += strideElts[pos]*(ev[(int)famElts[c1]-1]-1); + } + else { + stride = strideElts[pos]; + } + } + + plhs[0] = mxCreateDoubleMatrix (1, nsj, mxREAL); + y = mxGetPr(plhs[0]); + for (c1 = 0, pos = startInd; c1 < nsj; c1++, pos+=stride) { + y[c1] = pcpt[pos]; + } + } + + /* Handle the case n > 1 */ + else { + + /* Get the appropriate CPT */ + ec = mxGetField (prhs[BNET], 0, "eclass2"); + ecElts = mxGetPr(ec); + k = (int) ecElts[i-1]; + cpt = mxGetCell (prhs[8], k-1); + pcpt = mxGetPr(cpt); + + /* Figure out size of slice */ + if (m == 1) { + nsj = (int) nsElts[j-1]; + } + else { + nsj = (int) nsElts[j-1+numNodes]; + } + + /* Figure out family */ + fam = mxGetCell (prhs[FAMILIES], i - 1 + numNodes); + famSize = mxGetNumberOfElements(fam); + famElts = mxGetPr(fam); + + startInd = 0; + for (c1 = 0, pos = k-1; c1 < famSize; c1++, pos+=strideStride) { + int f = (int) famElts[c1]; + + if (((f == j+numNodes) && (m == n)) || ((f == j) && (m == + n-1))) { + stride = strideElts[pos]; + } + else { + startInd += strideElts[pos] * (ev[f-1+((n-2)*numNodes)]-1); + } + } + + plhs[0] = mxCreateDoubleMatrix(1,nsj, mxREAL); + y = mxGetPr(plhs[0]); + for (c1 = 0, pos = startInd; c1 < nsj; c1++, pos+=stride) { + y[c1] = pcpt[pos]; + } + } +} diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_slice_dbn.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_slice_dbn.m new file mode 100644 index 00000000..22841784 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/get_slice_dbn.m @@ -0,0 +1,87 @@ +function slice = get_slice_dbn(bnet, state, i, n, j, m, strides, families, ... + CPT) +% slice = get_slice(bnet, state, i, n, j, m, strides, families, cpt) +% +% GET_SLICE get one-dimensional slice of the CPT for node X_i^n +% that corresponds to the different values of X_j^m, where all +% other nodes have values given by state. +% strides is the result of +% calling compute_strides(bnet) +% families is the result of calling compute_families(bnet) +% cpts is the result of calling get_cpts(bnet) +% +% slice is a 1-d array + + +if (n == 1) + + k = bnet.eclass1(i); + c = CPT{k}; + + % Figure out evidence on family + fam = families{i, 1}; + ev = state(fam, 1); + + % Remove evidence on node j + pos = find(fam == j); + ev(pos) = 1; + dim = size(ev, 1); + + % Compute initial index and stride + start_ind = 1+strides(k, 1:dim)*(ev-1); + stride = strides(k, pos); + + % Compute the slice + slice = c(start_ind:stride:start_ind+(bnet.node_sizes(j, 1)-1)*stride); + +else + + k = bnet.eclass2(i); + c = CPT{k}; + + fam = families{i, 2}; + ss = length(bnet.intra); + + % Divide the family into nodes in this time step and nodes in the + % previous time step + this_time_step = fam(find(fam > ss)); + prev_time_step = fam(find(fam <= ss)); + + % Normalize the node numbers + this_time_step = this_time_step - ss; + + % Get the evidence + this_step_ev = state(this_time_step, n); + prev_step_ev = state(prev_time_step, n-1); + + % Remove the evidence for X_j^m + if (m == n) + pos = find(this_time_step == j); + this_step_ev(pos) = 1; + pos = pos + size(prev_time_step, 2); + else + assert (m == n-1); + pos = find(prev_time_step == j); + prev_step_ev(pos) = 1; + end + + % Combine the two time steps + ev = [prev_step_ev; this_step_ev]; + dim = size(ev, 1); + + + % Compute starting index and stride + start_ind = 1 + strides(k, 1:dim)*(ev-1); + stride = strides(k, pos); + + % Compute slice + if (m == 1) + q = 1; + else + q = 2; + end + slice = c(start_ind:stride:start_ind+(bnet.node_sizes(j, q)-1)*stride); +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/my_sample_discrete.m b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/my_sample_discrete.m new file mode 100644 index 00000000..70f0615b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/my_sample_discrete.m @@ -0,0 +1,7 @@ +function M = my_sample_discrete(prob) +% A faster version that calls a c subfunction. Will update one +% day to have r and c parameters as well + +R = rand (1,1); +M = sample_single_discrete(R, prob); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/sample_single_discrete.c b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/sample_single_discrete.c new file mode 100644 index 00000000..36112de6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@gibbs_sampling_inf_engine/private/sample_single_discrete.c @@ -0,0 +1,22 @@ +#include "mex.h" + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray + *prhs[]) +{ + double *y, *pr, *dist; + int k, distSize; + double r, cumSum; + + plhs[0] = mxCreateDoubleMatrix(1,1, mxREAL); + y = mxGetPr (plhs[0]); + + pr = mxGetPr (prhs[0]); + r = pr[0]; + + dist = mxGetPr (prhs[1]); + distSize = mxGetNumberOfElements (prhs[1]); + + for (k = 0, cumSum = 0; (k < distSize) && (r >= cumSum); cumSum += dist[k], k++); + + y[0] = k; +} diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Entries new file mode 100644 index 00000000..1c5d76dd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Entries @@ -0,0 +1,6 @@ +/enter_evidence.m/1.1.1.1/Mon Jun 7 19:05:42 2004// +/find_mpe.m/1.1.1.1/Wed Jun 19 21:56:32 2002// +/global_joint_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Mon Jun 7 19:04:48 2004// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Repository new file mode 100644 index 00000000..0c8fadf5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@global_joint_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/enter_evidence.m new file mode 100644 index 00000000..105894ff --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/enter_evidence.m @@ -0,0 +1,42 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (global_joint) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value. +% +% Warning: Computing the log likelihood requires marginalizing all the nodes and can be slow. +% +% The list below gives optional arguments [default value in brackets]. +% +% exclude - list of nodes whose potential will not be included in the joint [ [] ] +% +% e.g., engine = enter_evidence(engine, ev, 'exclude', 3) + +exclude = []; +maximize = 0; + +if nargin >= 3 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'exclude', exclude = args{i+1}; + case 'maximize', maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +assert(~maximize) +bnet = bnet_from_engine(engine); +N = length(bnet.node_sizes); +%[engine.jpot, loglik] = compute_joint_pot(bnet, mysetdiff(1:N, exclude), evidence, 1:N); +[engine.jpot] = compute_joint_pot(bnet, mysetdiff(1:N, exclude), evidence, 1:N); +% jpot should not be normalized, otherwise it gives wrong resutls for limids like asia_dt1 +if nargout == 2 + [m] = marginal_nodes(engine, []); + [T, lik] = normalize(m.T); + loglik = log(lik); +end +%[engine.jpot loglik] = normalize_pot(engine.jpot); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/find_mpe.m new file mode 100644 index 00000000..92915b6c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/find_mpe.m @@ -0,0 +1,28 @@ +function [mpe, ll] = find_mpe(engine, evidence) +% FIND_MPE_GLOBAL Compute the most probable explanation(s) from the global joint +% [mpe, ll] = find_mpe(engine, evidence) +% +% mpe(k,i) is the most probable value of node i in the k'th global mode (cell array) +% +% We assume all nodes are discrete + +%engine = global_joint_inf_engine(bnet); +bnet = bnet_from_engine(engine); +engine = enter_evidence(engine, evidence); +S1 = struct(engine); % violate object privacy +S2 = struct(S1.jpot); % joint potential +prob = max(S2.T(:)); +modes = find(S2.T(:) == prob); + +ens = bnet.node_sizes; +onodes = find(~isemptycell(evidence)); +ens(onodes) = 1; +mpe = ind2subv(ens, modes); +for k=1:length(modes) + for i=onodes(:)' + mpe(k,i) = evidence{i}; + end +end +ll = log(prob); + +mpe = num2cell(mpe); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/global_joint_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/global_joint_inf_engine.m new file mode 100644 index 00000000..86bca532 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/global_joint_inf_engine.m @@ -0,0 +1,8 @@ +function engine = global_joint_inf_engine(bnet) +% GLOBAL_JOINT_INF_ENGINE Construct the global joint distribution as a potential +% engine = global_joint_inf_engine(bnet) +% +% Warning: this has size exponential in the number of discrete hidden variables + +engine.jpot = []; +engine = class(engine, 'global_joint_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/marginal_family.m new file mode 100644 index 00000000..6931814c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/marginal_family.m @@ -0,0 +1,7 @@ +function [m, pot] = marginal_family(engine, i) +% MARGINAL_FAMILY Compute the marginal on i's family (global_inf_engine) +% [m, pot] = marginal_family(engine, i) +% + +bnet = bnet_from_engine(engine); +[m, pot] = marginal_nodes(engine, family(bnet.dag, i)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..223e6574 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@global_joint_inf_engine/marginal_nodes.m @@ -0,0 +1,8 @@ +function [m, pot] = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified set of nodes (global_joint) +% [m, pot] = marginal_nodes(engine, query) + +pot = marginalize_pot(engine.jpot, query); +m = pot_to_marginal(pot); +%[m.T, lik] = normalize(m.T); +%loglik = log(lik); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Entries new file mode 100644 index 00000000..8a9c45e2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Entries @@ -0,0 +1,14 @@ +/cliques_from_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/clq_containing_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/collect_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/distribute_evidence.m/1.1.1.1/Mon Jun 17 21:00:08 2002// +/enter_evidence.m/1.1.1.1/Mon Jun 17 20:59:30 2002// +/enter_soft_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/find_max_config.m/1.1.1.1/Mon Jun 17 23:14:52 2002// +/find_mpe.m/1.1.1.1/Mon Jun 17 23:14:08 2002// +/init_pot.m/1.1.1.1/Sun Jun 16 19:34:56 2002// +/jtree_inf_engine.m/1.1.1.1/Fri Oct 31 22:37:48 2003// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/set_fields.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..24f16336 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Repository new file mode 100644 index 00000000..c25f18d5 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..5d0e75e3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Entries @@ -0,0 +1,5 @@ +/collect_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/distribute_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..cf59323d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/collect_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/collect_evidence.m new file mode 100644 index 00000000..2f7757f1 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/collect_evidence.m @@ -0,0 +1,29 @@ +function engine = collect_evidence(engine, root) + +if isempty(engine.postorder{root}) + % this is the first time we have collected to this root + % memoize the order + [jtree, preorder, postorder] = mk_rooted_tree(engine.jtree, root); + postorder_parents = cell(1,length(postorder)); + for n=postorder(1:end-1) + postorder_parents{n} = parents(jtree, n); + end + engine.postorder{root} = postorder; + engine.postorder_parents{root} = postorder_parents; +else + postorder = engine.postorder{root}; + postorder_parents = engine.postorder_parents{root}; +end + +C = length(engine.clpot); +seppot = cell(C, C); +% separators are implicitely initialized to 1s + +% collect to root (node to parents) +for n=postorder(1:end-1) + for p=postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + engine.seppot{p,n} = marginalize_pot(engine.clpot{n}, engine.separator{p,n}, engine.maximize); + engine.clpot{p} = multiply_by_pot(engine.clpot{p}, engine.seppot{p,n}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/distribute_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/distribute_evidence.m new file mode 100644 index 00000000..f8d78be4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/distribute_evidence.m @@ -0,0 +1,26 @@ +function engine = distribute_evidence(engine, root) + +if isempty(engine.preorder{root}) + % this is the first time we have distributed from this root + % memoize the order + [jtree, preorder, postorder] = mk_rooted_tree(engine.jtree, root); + preorder_children = cell(1,length(preorder)); + for n=preorder + preorder_children{n} = children(jtree, n); + end + engine.preorder{root} = preorder; + engine.preorder_children{root} = preorder_children; +else + preorder = engine.preorder{root}; + preorder_children = engine.preorder_children{root}; +end + + +% distribute from root (node to children) +for n=preorder(:)' + for c=preorder_children{n}(:)' + engine.clpot{c} = divide_by_pot(engine.clpot{c}, engine.seppot{n,c}); + engine.seppot{n,c} = marginalize_pot(engine.clpot{n}, engine.separator{n,c}, engine.maximize); + engine.clpot{c} = multiply_by_pot(engine.clpot{c}, engine.seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/enter_evidence.m new file mode 100644 index 00000000..aafeeecb --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/enter_evidence.m @@ -0,0 +1,107 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% soft - a cell array of soft/virtual evidence; +% soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ] +% +% e.g., engine = enter_evidence(engine, ev, 'soft', soft_ev) +% +% For backwards compatibility with BNT2, you can also specify the parameters in the following order +% engine = enter_evidence(engine, ev, soft_ev) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +% set default params +exclude = []; +soft_evidence = cell(1,N); +maximize = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + if iscell(args{1}) + soft_evidence = args{1}; + else + for i=1:2:nargs + switch args{i}, + case 'soft', soft_evidence = args{i+1}; + case 'maximize', maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end + end +end + +engine.maximize = maximize; + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + if strcmp(pot_type, 'cg') + check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag); +end + + +hard_nodes = 1:N; +soft_nodes = find(~isemptycell(soft_evidence)); +S = length(soft_nodes); +if S > 0 + assert(pot_type == 'd'); + assert(mysubset(soft_nodes, bnet.dnodes)); +end + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N+S); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); +end + +for i=1:S + n = soft_nodes(i); + pot{N+i} = dpot(n, ns(n), soft_evidence{n}); +end + +%clqs = engine.clq_ass_to_node([hard_nodes soft_nodes]); +%[clpot, loglik] = enter_soft_evidence(engine, clqs, pot, onodes, pot_type); +%engine.clpot = clpot; % save the results for marginal_nodes + + +clique = engine.clq_ass_to_node([hard_nodes soft_nodes]); +potential = pot; + + +% Set the clique potentials to all 1s +C = length(engine.cliques); +for i=1:C + engine.clpot{i} = mk_initial_pot(pot_type, engine.cliques{i}, ns, bnet.cnodes, onodes); +end + +% Multiply on specified potentials +for i=1:length(clique) + c = clique(i); + engine.clpot{c} = multiply_by_pot(engine.clpot{c}, potential{i}); +end + +root = 1; % arbitrary +engine = collect_evidence(engine, root); +engine = distribute_evidence(engine, root); + +ll = zeros(1, C); +for i=1:C + [engine.clpot{i}, ll(i)] = normalize_pot(engine.clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/enter_soft_evidence.m new file mode 100644 index 00000000..59671415 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/Old/enter_soft_evidence.m @@ -0,0 +1,19 @@ +function [clpot, loglik] = enter_soft_evidence(engine, clique, potential, onodes, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified potentials to the network (jtree) +% [clpot, loglik] = enter_soft_evidence(engine, clique, potential, onodes, pot_type, maximize) +% +% We multiply potential{i} onto clique(i) before propagating. +% We return all the modified clique potentials. + +[clpot, seppot] = init_pot(engine, clique, potential, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +[clpot, seppot] = distribute_evidence(engine, clpot, seppot); + +C = length(clpot); +ll = zeros(1, C); +for i=1:C + [clpot{i}, ll(i)] = normalize_pot(clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/cliques_from_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/cliques_from_engine.m new file mode 100644 index 00000000..cd9d871d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/cliques_from_engine.m @@ -0,0 +1,5 @@ +function cliques = cliques_from_engine(engine) +% CLIQUES_FROM_ENGINE Return the cliques stored inside the inf. engine (jtree) +% cliques = cliques_from_engine(engine) + +cliques = engine.cliques; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/clq_containing_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/clq_containing_nodes.m new file mode 100644 index 00000000..8904fa49 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/clq_containing_nodes.m @@ -0,0 +1,24 @@ +function c = clq_containing_nodes(engine, nodes, fam) +% CLQ_CONTAINING_NODES Find the lightest clique (if any) that contains the set of nodes +% c = clq_containing_nodes(engine, nodes, family) +% +% If the optional 'family' argument is specified, it means nodes = family(nodes(end)). +% (This is useful since clq_ass_to_node is not accessible to outsiders.) +% Returns c=-1 if there is no such clique. + +if nargin < 3, fam = 0; else fam = 1; end + +if length(nodes)==1 + c = engine.clq_ass_to_node(nodes(1)); +%elseif fam +% c = engine.clq_ass_to_node(nodes(end)); +else + B = engine.cliques_bitv; + w = engine.clique_weight; + clqs = find(all(B(:,nodes), 2)); % all selected columns must be 1 + if isempty(clqs) + c = -1; + else + c = clqs(argmin(w(clqs))); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/collect_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/collect_evidence.m new file mode 100644 index 00000000..03c00edf --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/collect_evidence.m @@ -0,0 +1,12 @@ +function [clpot, seppot] = collect_evidence(engine, clpot, seppot) +% COLLECT_EVIDENCE Do message passing from leaves to root (children then parents) +% [clpot, seppot] = collect_evidence(engine, clpot, seppot) + +for n=engine.postorder %postorder(1:end-1) + for p=engine.postorder_parents{n} + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, engine.separator{p,n}, engine.maximize); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/distribute_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/distribute_evidence.m new file mode 100644 index 00000000..403b8970 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/distribute_evidence.m @@ -0,0 +1,11 @@ +function [clpot, seppot] = distribute_evidence(engine, clpot, seppot) +% DISTRIBUTE_EVIDENCE Do message passing from root to leaves (parents then children) +% [clpot, seppot] = distribute_evidence(engine, clpot, seppot) + +for n=engine.preorder + for c=engine.preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, engine.separator{n,c}, engine.maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/enter_evidence.m new file mode 100644 index 00000000..c85d03a7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/enter_evidence.m @@ -0,0 +1,88 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% soft - a cell array of soft/virtual evidence; +% soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ] +% +% e.g., engine = enter_evidence(engine, ev, 'soft', soft_ev) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +engine.evidence = evidence; % store this for marginal_nodes with add_ev option +engine.maximize = 0; + +% set default params +exclude = []; +soft_evidence = cell(1,N); + +% parse optional params +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'soft', soft_evidence = args{i+1}; + case 'maximize', engine.maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + if strcmp(pot_type, 'cg') + check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag); +end + +if is_mnet(bnet) + pot = engine.user_pot; + clqs = engine.nums_ass_to_user_clqs; +else + % Evaluate CPDs with evidence, and convert to potentials + pot = cell(1, N); + for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + if isempty(bnet.CPD{e}) + error(['must define CPD ' num2str(e)]) + else + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); + end + end + clqs = engine.clq_ass_to_node(1:N); +end + +% soft evidence +soft_nodes = find(~isemptycell(soft_evidence)); +S = length(soft_nodes); +if S > 0 + assert(pot_type == 'd'); + assert(mysubset(soft_nodes, bnet.dnodes)); +end +for i=1:S + n = soft_nodes(i); + pot{end+1} = dpot(n, ns(n), soft_evidence{n}); +end +clqs = [clqs engine.clq_ass_to_node(soft_nodes)]; + + +[clpot, seppot] = init_pot(engine, clqs, pot, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +[clpot, seppot] = distribute_evidence(engine, clpot, seppot); + +C = length(clpot); +ll = zeros(1, C); +for i=1:C + [clpot{i}, ll(i)] = normalize_pot(clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + +engine.clpot = clpot; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..0a4346c6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/enter_soft_evidence.m @@ -0,0 +1,21 @@ +function [clpot, loglik] = enter_soft_evidence(engine, clique, potential, onodes, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified potentials to the network (jtree) +% [clpot, loglik] = enter_soft_evidence(engine, clique, potential, onodes, pot_type, maximize) +% +% We multiply potential{i} onto clique(i) before propagating. +% We return all the modified clique potentials. + +% only used by BK! + +[clpot, seppot] = init_pot(engine, clique, potential, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +[clpot, seppot] = distribute_evidence(engine, clpot, seppot); + +C = length(clpot); +ll = zeros(1, C); +for i=1:C + [clpot{i}, ll(i)] = normalize_pot(clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/find_max_config.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/find_max_config.m new file mode 100644 index 00000000..5053b1e8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/find_max_config.m @@ -0,0 +1,35 @@ +function [mpe, clpot, seppot] = find_max_config(engine, clpot, seppot, evidence) +% FIND_MAX_CONFIG Backwards pass of Viterbi fro jtree +% function [mpe, clpot, seppot] = find_max_config(engine, clpot, seppot, evidence) +% See Cowell99 p98 + +bnet = bnet_from_engine(engine); +nnodes = length(bnet.dag); +mpe = cell(1, nnodes); +maximize = 1; + +c = engine.root_clq; +pot = struct(clpot{c}); % violate object privacy +dom = pot.domain; +[indices, clpot{c}] = find_most_prob_entry(clpot{c}); +mpe(dom) = num2cell(indices); + +for n=engine.preorder + for c=engine.preorder_children{n} + clpot{c} = divide_by_pot(clpot{c}, seppot{n,c}); + seppot{n,c} = marginalize_pot(clpot{n}, engine.separator{n,c}, maximize); + clpot{c} = multiply_by_pot(clpot{c}, seppot{n,c}); + + pot = struct(clpot{c}); % violate object privacy + dom = pot.domain; + [indices, clpot{c}] = find_most_prob_entry(clpot{c}); + mpe(dom) = num2cell(indices); + end +end + +obs_nodes = find(~isemptycell(evidence)); +% indices for observed nodes will be 1 - need to overwrite these +mpe(obs_nodes) = evidence(obs_nodes); + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/find_mpe.m new file mode 100644 index 00000000..8a46c1ed --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/find_mpe.m @@ -0,0 +1,71 @@ +function mpe = find_mpe(engine, evidence, varargin) +% FIND_MPE Find the most probable explanation of the data (assignment to the hidden nodes) +% function mpe = find_mpe(engine, evidence,...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% soft - a cell array of soft/virtual evidence; +% soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ] +% + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +engine.evidence = evidence; + +% set default params +exclude = []; +soft_evidence = cell(1,N); + +% parse optional params +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'soft', soft_evidence = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end +engine.maximize = 1; + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + if strcmp(pot_type, 'cg') + check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag); +end + +hard_nodes = 1:N; +soft_nodes = find(~isemptycell(soft_evidence)); +S = length(soft_nodes); +if S > 0 + assert(pot_type == 'd'); + assert(mysubset(soft_nodes, bnet.dnodes)); +end + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N+S); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + if isempty(bnet.CPD{e}) + error(['must define CPD ' num2str(e)]) + else + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); + end +end + +for i=1:S + n = soft_nodes(i); + pot{N+i} = dpot(n, ns(n), soft_evidence{n}); +end +clqs = engine.clq_ass_to_node([hard_nodes soft_nodes]); + +[clpot, seppot] = init_pot(engine, clqs, pot, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +mpe = find_max_config(engine, clpot, seppot, evidence); % instead of distribute evidence diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/init_pot.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/init_pot.m new file mode 100644 index 00000000..857e6266 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/init_pot.m @@ -0,0 +1,20 @@ +function [clpot, seppot] = init_pot(engine, clqs, pots, pot_type, onodes, ndx) +% INIT_POT Initialise potentials with evidence (jtree_inf) +% function [clpot, seppot] = init_pot(engine, clqs, pots, pot_type, onodes) + +cliques = engine.cliques; +bnet = bnet_from_engine(engine); +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, bnet.node_sizes(:), bnet.cnodes(:), onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/jtree_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/jtree_inf_engine.m new file mode 100644 index 00000000..dd744dc0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/jtree_inf_engine.m @@ -0,0 +1,141 @@ +function engine = jtree_inf_engine(bnet, varargin) +% JTREE_INF_ENGINE Junction tree inference engine +% engine = jtree_inf_engine(bnet, ...) +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - a cell array of sets of nodes we want to ensure are in the same clique (in addition to families) [ {} ] +% root - the root of the junction tree will be a clique that contains this set of nodes [N] +% stages - stages{t} is a set of nodes we want to eliminate before stages{t+1}, ... [ {1:N} ] +% +% e.g., engine = jtree_inf_engine(bnet, 'maximize', 1); +% +% For more details on the junction tree algorithm, see +% - "Probabilistic networks and expert systems", Cowell, Dawid, Lauritzen and Spiegelhalter, Springer, 1999 +% - "Inference in Belief Networks: A procedural guide", C. Huang and A. Darwiche, +% Intl. J. Approximate Reasoning, 15(3):225-263, 1996. + + +% set default params +N = length(bnet.dag); +clusters = {}; +root = N; +stages = { 1:N }; +maximize = 0; + +if nargin >= 2 + args = varargin; + nargs = length(args); + if ~isstr(args{1}) + error('the interface to jtree has changed; now, onodes is not allowed and all optional params must be passed by name') + end + for i=1:2:nargs + switch args{i}, + case 'clusters', clusters = args{i+1}; + case 'root', root = args{i+1}; + case 'stages', stages = args{i+1}; + case 'maximize', maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +engine = init_fields; +engine = class(engine, 'jtree_inf_engine', inf_engine(bnet)); + +engine.maximize = maximize; + +onodes = bnet.observed; + +%[engine.jtree, dummy, engine.cliques, B, w, elim_order, moral_edges, fill_in_edges, strong] = ... +% dag_to_jtree(bnet, onodes, stages, clusters); + +porder = determine_elim_constraints(bnet, onodes); +strong = ~isempty(porder); +ns = bnet.node_sizes(:); +ns(onodes) = 1; % observed nodes have only 1 possible value +[engine.jtree, root2, engine.cliques, B, w] = ... + graph_to_jtree(moralize(bnet.dag), ns, porder, stages, clusters); + + +engine.cliques_bitv = B; +engine.clique_weight = w; +C = length(engine.cliques); +engine.clpot = cell(1,C); + +% Compute the separators between connected cliques. +[is,js] = find(engine.jtree > 0); +engine.separator = cell(C,C); +for k=1:length(is) + i = is(k); j = js(k); + engine.separator{i,j} = find(B(i,:) & B(j,:)); % intersect(cliques{i}, cliques{j}); +end + +% A node can be a member of many cliques, but is assigned to exactly one, to avoid +% double-counting its CPD. We assign node i to clique c if c is the "lightest" clique that +% contains i's family, so it can accomodate its CPD. + +engine.clq_ass_to_node = zeros(1, N); +for i=1:N + %c = clq_containing_nodes(engine, family(bnet.dag, i)); + clqs_containing_family = find(all(B(:,family(bnet.dag, i)), 2)); % all selected columns must be 1 + c = clqs_containing_family(argmin(w(clqs_containing_family))); + engine.clq_ass_to_node(i) = c; +end + +% Make the jtree rooted, so there is a fixed message passing order. +if strong + % the last clique is guaranteed to be a strong root + % engine.root_clq = length(engine.cliques); + + % --- 4/17/2010, by Wei Sun (George Mason University): + % It has been proved that the last clique is not necessary to be the + % strong root, instead, a clique called interface clique, that contains + % all discrete parents and at least one continuous node from a connected + % continuous component in a CLG, is guaranteed to be a strong root. + engine.root_clq = findroot(bnet, engine.cliques) ; +else + % jtree_dbn_inf_engine requires the root to contain the interface. + % This may conflict with the strong root requirement! *********** BUG ************* + engine.root_clq = clq_containing_nodes(engine, root); + if engine.root_clq <= 0 + error(['no clique contains ' num2str(root)]); + end +end + +[engine.jtree, engine.preorder, engine.postorder] = mk_rooted_tree(engine.jtree, engine.root_clq); + +% collect +engine.postorder_parents = cell(1,length(engine.postorder)); +for n=engine.postorder(:)' + engine.postorder_parents{n} = parents(engine.jtree, n); +end +% distribute +engine.preorder_children = cell(1,length(engine.preorder)); +for n=engine.preorder(:)' + engine.preorder_children{n} = children(engine.jtree, n); +end + + + +%%%%%%%% + +function engine = init_fields() + +engine.jtree = []; +engine.cliques = []; +engine.separator = []; +engine.cliques_bitv = []; +engine.clique_weight = []; +engine.clpot = []; +engine.clq_ass_to_node = []; +engine.root_clq = []; +engine.preorder = []; +engine.postorder = []; +engine.preorder_children = []; +engine.postorder_parents = []; +engine.maximize = []; +engine.evidence = []; + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/marginal_family.m new file mode 100644 index 00000000..eff60ca2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/marginal_family.m @@ -0,0 +1,11 @@ +function marginal = marginal_family(engine, i, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree) +% marginal = marginal_family(engine, i) + +if nargin < 3, add_ev = 0; end +assert(~add_ev); + +bnet = bnet_from_engine(engine); +fam = family(bnet.dag, i); +c = engine.clq_ass_to_node(i); +marginal = pot_to_marginal(marginalize_pot(engine.clpot{c}, fam)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..6413172c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/marginal_nodes.m @@ -0,0 +1,22 @@ +function marginal = marginal_nodes(engine, query, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (jtree) +% marginal = marginal_nodes(engine, query, add_ev) +% +% 'query' must be a subset of some clique; an error will be raised if not. +% add_ev is an optional argument; if 1, we will "inflate" the marginal of observed nodes +% to their original size, adding 0s to the positions which contradict the evidence + +if nargin < 3, add_ev = 0; end + +c = clq_containing_nodes(engine, query); +if c == -1 + error(['no clique contains ' num2str(query)]); +end +marginal = pot_to_marginal(marginalize_pot(engine.clpot{c}, query, engine.maximize)); + +if add_ev + bnet = bnet_from_engine(engine); + %marginal = add_ev_to_dmarginal(marginal, engine.evidence, bnet.node_sizes); + marginal = add_evidence_to_gmarginal(marginal, engine.evidence, bnet.node_sizes, bnet.cnodes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/set_fields.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/set_fields.m new file mode 100644 index 00000000..e75cfa45 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_inf_engine/set_fields.m @@ -0,0 +1,13 @@ +function engine = set_fields(engine, varargin) +% SET_FIELDS Set the fields for a generic engine +% engine = set_fields(engine, name/value pairs) +% +% e.g., engine = set_fields(engine, 'maximize', 1) + +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'maximize', engine.maximize = args{i+1}; + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Entries new file mode 100644 index 00000000..932cb3b4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Entries @@ -0,0 +1,5 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_limid_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Repository new file mode 100644 index 00000000..e8bf097c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_limid_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..0b350b99 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Entries @@ -0,0 +1,3 @@ +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes_SS.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..59988183 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_limid_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/marginal_family.m new file mode 100644 index 00000000..cd660ae4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/marginal_family.m @@ -0,0 +1,59 @@ +function [m, pot] = marginal_family(engine, query) +% MARGINAL_NODES Compute the marginal on the family of the specified node (jtree_limid) +% [m, pot] = marginal_family(engine, query) +% +% query should be a single decision node, or [] (to compute global max expected utility) + +bnet = bnet_from_engine(engine); +if isempty(query) + compute_meu = 1; + d = bnet.decision_nodes(1); % pick an arbitrary root to collect to + fam = []; % marginalize root pot down to a point +else + compute_meu = 0; + d = query; + assert(myismember(d, bnet.decision_nodes)); + fam = family(bnet.dag, d); +end + +clpot = init_clpot(bnet, engine.cliques, engine.clq_ass_to_node, engine.evidence, engine.exclude); + +% collect to root (clique containing d) +C = length(engine.cliques); +seppot = cell(C, C); % separators are implicitely initialized to 1s +for n=engine.postorder{d}(1:end-1) + for p=parents(engine.rooted_jtree{d}, n) + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, engine.separator{p,n}); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + +root = engine.clq_ass_to_node(d); +assert(root == engine.postorder{d}(end)); +pot = marginalize_pot(clpot{root}, fam); +m = pot_to_marginal(pot); + +%%%%%%%%%%% + + +function clpot = init_clpot(bnet, cliques, clq_ass_to_node, evidence, exclude) + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1, C); +ns = bnet.node_sizes; +for i=1:C + clpot{i} = upot(cliques{i}, ns(cliques{i})); +end + +N = length(bnet.dag); +nodes = mysetdiff(1:N, exclude); + +for n=nodes(:)' + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + c = clq_ass_to_node(n); + pot = convert_to_pot(bnet.CPD{e}, 'u', ns, fam, evidence); + clpot{c} = multiply_by_pot(clpot{c}, pot); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/marginal_nodes_SS.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/marginal_nodes_SS.m new file mode 100644 index 00000000..2b6ff642 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/Old/marginal_nodes_SS.m @@ -0,0 +1,52 @@ +function [pot, MEU] = marginal_nodes(engine, d) + +C = length(cliques); +%clpot = init_clpot(limid, cliques, d, clq_ass_to_node); +clpot = init_clpot(limid, cliques, [], clq_ass_to_node); + +% collect to root +if 1 + % HUGIN + seppot = cell(C, C); % separators are implicitely initialized to 1s + for n=postorder{di}(1:end-1) + for p=parents(rooted_jtree{di}, n) + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, separator{p,n}); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end + end +else + % Shafer-Shenoy + msg = cell(C,C); + for n=postorder{di}(1:end-1) + for c=children(rooted_jtree{di}, n) + clpot{n} = multiply_by_pot(clpot{n}, msg{c,n}); + end + p = parents(rooted_jtree{di}, n); + %msg{n,p} = marginalize_pot(clpot{n}, cliques{p}); + msg{n,p} = marginalize_pot(clpot{n}, separator{n,p}); + end + root = clq_ass_to_node(d); + n=postorder{di}(end); + assert(n == root); + for c=children(rooted_jtree{di}, n) + clpot{n} = multiply_by_pot(clpot{n}, msg{c,n}); + end +end + +fam = family(limid.dag, d); +pot = marginalize_pot(clpot{root}, fam); + +%%%%%%% +jpot = compute_joint_pot_limid(limid); +pot2 = marginalize_pot(jpot, fam); +assert(approxeq_pot(pot, pot2)) +%%%%%% + +[policy, score] = extract_policy(pot); + +e = limid.equiv_class(d); +limid.CPD{e} = set_params(limid.CPD{e}, 'policy', policy); + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/enter_evidence.m new file mode 100644 index 00000000..5d874803 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/enter_evidence.m @@ -0,0 +1,28 @@ +function engine = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree_limid) +% engine = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value. +% +% The list below gives optional arguments [default value in brackets]. +% +% exclude - list of nodes whose potential will not be included in the joint [ [] ] +% +% e.g., engine = enter_evidence(engine, ev, 'exclude', 3) + +exclude = []; + +if nargin >= 3 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'exclude', exclude = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +engine.exclude = exclude; +engine.evidence = evidence; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/jtree_limid_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/jtree_limid_inf_engine.m new file mode 100644 index 00000000..83dd89ef --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/jtree_limid_inf_engine.m @@ -0,0 +1,52 @@ +function engine = jtree_limid_inf_engine(bnet) +% JTREE_LIMID_INF_ENGINE Make a junction tree engine for use by solve_limid +% engine = jtree_limid_inf_engine(bnet) +% +% This engine is designed to compute marginals on decision nodes + + +MG = moralize(bnet.dag); +% We do not remove the utility nodes, because that complicates the book-keeping. +% Leaving them in will not introduce any un-necessary triangulation arcs, because they are always leaves. +% Also, since utility nodes have size 1, they do not increase the size of the potentials. + +ns = bnet.node_sizes; +elim_order = best_first_elim_order(MG, ns); +[MTG, engine.cliques] = triangulate(MG, elim_order); +[engine.jtree, root, B, w] = cliques_to_jtree(engine.cliques, ns); + +% A node can be a member of many cliques, but is assigned to exactly one, to avoid +% double-counting its CPD. We assign node i to clique c if c is the "lightest" clique that +% contains i's family, so it can accomodate its CPD. +N = length(bnet.dag); +engine.clq_ass_to_node = zeros(1, N); +for i=1:N + clqs_containing_family = find(all(B(:,family(bnet.dag, i)), 2)); % all selected columns must be 1 + c = clqs_containing_family(argmin(w(clqs_containing_family))); + engine.clq_ass_to_node(i) = c; +end + + +% Compute the separators between connected cliques. +[is,js] = find(engine.jtree > 0); +num_cliques = length(engine.cliques); +engine.separator = cell(num_cliques, num_cliques); +for k=1:length(is) + i = is(k); j = js(k); + engine.separator{i,j} = find(B(i,:) & B(j,:)); % intersect(cliques{i}, cliques{j}); +end + + +% create |D| different rooted jtree's +engine.rooted_jtree = cell(1, N); +engine.preorder = cell(1, N); +engine.postorder = cell(1, N); +for d=bnet.decision_nodes(:)' + root = engine.clq_ass_to_node(d); + [engine.rooted_jtree{d}, engine.preorder{d}, engine.postorder{d}] = mk_rooted_tree(engine.jtree, root); +end + +engine.exclude = []; +engine.evidence = []; + +engine = class(engine, 'jtree_limid_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/marginal_family.m new file mode 100644 index 00000000..dd3bf95e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/marginal_family.m @@ -0,0 +1,52 @@ +function [m, pot] = marginal_family(engine, query) +% MARGINAL_NODES Compute the marginal on the family of the specified node (jtree_limid) +% [m, pot] = marginal_family(engine, query) +% +% query should be a single decision node + +bnet = bnet_from_engine(engine); +d = query; +assert(myismember(d, bnet.decision_nodes)); +fam = family(bnet.dag, d); + +clpot = init_clpot(bnet, engine.cliques, engine.clq_ass_to_node, engine.evidence, engine.exclude); + +% collect to root (clique containing d) +C = length(engine.cliques); +seppot = cell(C, C); % separators are implicitely initialized to 1s +for n=engine.postorder{d}(1:end-1) + for p=parents(engine.rooted_jtree{d}, n) + %clpot{p} = divide_by_pot(clpot{n}, seppot{p,n}); % dividing by 1 is redundant + seppot{p,n} = marginalize_pot(clpot{n}, engine.separator{p,n}); + clpot{p} = multiply_by_pot(clpot{p}, seppot{p,n}); + end +end + +root = engine.clq_ass_to_node(d); +assert(root == engine.postorder{d}(end)); +pot = marginalize_pot(clpot{root}, fam); +m = pot_to_marginal(pot); + +%%%%%%%%%%% + + +function clpot = init_clpot(bnet, cliques, clq_ass_to_node, evidence, exclude) + +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1, C); +ns = bnet.node_sizes; +for i=1:C + clpot{i} = upot(cliques{i}, ns(cliques{i})); +end + +N = length(bnet.dag); +nodes = mysetdiff(1:N, exclude); + +for n=nodes(:)' + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + c = clq_ass_to_node(n); + pot = convert_to_pot(bnet.CPD{e}, 'u', fam(:), evidence); + clpot{c} = multiply_by_pot(clpot{c}, pot); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..d3700270 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_limid_inf_engine/marginal_nodes.m @@ -0,0 +1,17 @@ +function [m, pot] = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified nodes (jtree_limid) +% [m, pot] = marginal_nodes(engine, query) +% +% query should be a subset of a family of a decision node + +if isempty(query) + bnet = bnet_from_engine(engine); + d = bnet.decision_nodes(1); % pick an arbitrary decision node + [dummy, big_pot] = marginal_family(engine, d); +else + [dummy, big_pot] = marginal_family(engine, query); +end +pot = marginalize_pot(big_pot, query); +m = pot_to_marginal(pot); + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Entries new file mode 100644 index 00000000..33ee0f34 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/enter_evidence.m/1.1.1.1/Mon Jun 17 20:30:02 2002// +/find_mpe.m/1.1.1.1/Mon Jun 17 20:29:40 2002// +/jtree_mnet_inf_engine.m/1.1.1.1/Sat Jan 18 22:13:32 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Repository new file mode 100644 index 00000000..2deff959 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_mnet_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/enter_evidence.m new file mode 100644 index 00000000..97546f4b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/enter_evidence.m @@ -0,0 +1,82 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% soft - a cell array of soft/virtual evidence; +% soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ] +% +% e.g., engine = enter_evidence(engine, ev, 'soft', soft_ev) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +engine.evidence = evidence; % store this for marginal_nodes with add_ev option +engine.maximize = 0; + +% set default params +exclude = []; +soft_evidence = cell(1,N); + +% parse optional params +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'soft', soft_evidence = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + if strcmp(pot_type, 'cg') + check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag); +end + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + if isempty(bnet.CPD{e}) + error(['must define CPD ' num2str(e)]) + else + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); + end +end +clqs = engine.clq_ass_to_node(1:N); + +% soft evidence +soft_nodes = find(~isemptycell(soft_evidence)); +S = length(soft_nodes); +if S > 0 + assert(pot_type == 'd'); + assert(mysubset(soft_nodes, bnet.dnodes)); +end +for i=1:S + n = soft_nodes(i); + pot{end+1} = dpot(n, ns(n), soft_evidence{n}); +end +clqs = [clqs engine.clq_ass_to_node(soft_nodes)]; + + +[clpot, seppot] = init_pot(engine, clqs, pot, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +[clpot, seppot] = distribute_evidence(engine, clpot, seppot); + +C = length(clpot); +ll = zeros(1, C); +for i=1:C + [clpot{i}, ll(i)] = normalize_pot(clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + +engine.clpot = clpot; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/find_mpe.m new file mode 100644 index 00000000..f5c04ba8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/find_mpe.m @@ -0,0 +1,71 @@ +function mpe = find_mpe(engine, evidence, varargin) +% FIND_MPE Find the most probable explanation of the data (assignment to the hidden nodes) +% function mpe = find_mpe(engine, evidence,...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% soft - a cell array of soft/virtual evidence; +% soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ] +% + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +engine.evidence = evidence; + +% set default params +exclude = []; +soft_evidence = cell(1,N); + +% parse optional params +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'soft', soft_evidence = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end +end +engine.maximize = 1; + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + if strcmp(pot_type, 'cg') + check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag); +end + +hard_nodes = 1:N; +soft_nodes = find(~isemptycell(soft_evidence)); +S = length(soft_nodes); +if S > 0 + assert(pot_type == 'd'); + assert(mysubset(soft_nodes, bnet.dnodes)); +end + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N+S); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + if isempty(bnet.CPD{e}) + error(['must define CPD ' num2str(e)]) + else + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); + end +end + +for i=1:S + n = soft_nodes(i); + pot{N+i} = dpot(n, ns(n), soft_evidence{n}); +end +clqs = engine.clq_ass_to_node([hard_nodes soft_nodes]); + +[clpot, seppot] = init_pot(engine, clqs, pot, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +mpe = find_max_config(engine, clpot, seppot); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/jtree_mnet_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/jtree_mnet_inf_engine.m new file mode 100644 index 00000000..ff21ae47 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_mnet_inf_engine/jtree_mnet_inf_engine.m @@ -0,0 +1,101 @@ +function engine = jtree_mnet_inf_engine(model, varargin) +% JTREE_MNET_INF_ENGINE Junction tree inference engine for Markov nets +% engine = jtree_inf_engine(mnet, ...) +% + +% set default params +N = length(mnet.graph); +root = N; + +engine = init_fields; +engine = class(engine, 'jtree_mnet_inf_engine', inf_engine(bnet)); + +onodes = bnet.observed; +if is_mnet(bnet) + MG = bnet.graph; +else + error('should be a mnet') +end + +%[engine.jtree, dummy, engine.cliques, B, w, elim_order, moral_edges, fill_in_edges, strong] = ... +% dag_to_jtree(bnet, onodes, stages, clusters); + +porder = determine_elim_constraints(bnet, onodes); +strong = ~isempty(porder); +ns = bnet.node_sizes(:); +ns(onodes) = 1; % observed nodes have only 1 possible value +[engine.jtree, root2, engine.cliques, B, w] = ... + graph_to_jtree(MG, ns, porder, stages, clusters); + +engine.cliques_bitv = B; +engine.clique_weight = w; +C = length(engine.cliques); +engine.clpot = cell(1,C); + +% Compute the separators between connected cliques. +[is,js] = find(engine.jtree > 0); +engine.separator = cell(C,C); +for k=1:length(is) + i = is(k); j = js(k); + engine.separator{i,j} = find(B(i,:) & B(j,:)); % intersect(cliques{i}, cliques{j}); +end + +% A node can be a member of many cliques, but is assigned to exactly one, to avoid +% double-counting its CPD. We assign node i to clique c if c is the "lightest" clique that +% contains i's family, so it can accomodate its CPD. + +engine.clq_ass_to_node = zeros(1, N); +for i=1:N + %c = clq_containing_nodes(engine, family(bnet.dag, i)); + clqs_containing_family = find(all(B(:,family(bnet.dag, i)), 2)); % all selected columns must be 1 + c = clqs_containing_family(argmin(w(clqs_containing_family))); + engine.clq_ass_to_node(i) = c; +end + +% Make the jtree rooted, so there is a fixed message passing order. +if strong + % the last clique is guaranteed to be a strong root + engine.root_clq = length(engine.cliques); +else + % jtree_dbn_inf_engine requires the root to contain the interface. + % This may conflict with the strong root requirement! *********** BUG ************* + engine.root_clq = clq_containing_nodes(engine, root); + if engine.root_clq <= 0 + error(['no clique contains ' num2str(root)]); + end +end + +[engine.jtree, engine.preorder, engine.postorder] = mk_rooted_tree(engine.jtree, engine.root_clq); + +% collect +engine.postorder_parents = cell(1,length(engine.postorder)); +for n=engine.postorder(:)' + engine.postorder_parents{n} = parents(engine.jtree, n); +end +% distribute +engine.preorder_children = cell(1,length(engine.preorder)); +for n=engine.preorder(:)' + engine.preorder_children{n} = children(engine.jtree, n); +end + + + +%%%%%%%% + +function engine = init_fields() + +engine.jtree = []; +engine.cliques = []; +engine.separator = []; +engine.cliques_bitv = []; +engine.clique_weight = []; +engine.clpot = []; +engine.clq_ass_to_node = []; +engine.root_clq = []; +engine.preorder = []; +engine.postorder = []; +engine.preorder_children = []; +engine.postorder_parents = []; +engine.maximize = []; +engine.evidence = []; + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Entries new file mode 100644 index 00000000..cc6f3f5b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Entries @@ -0,0 +1,12 @@ +/cliques_from_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/clq_containing_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/collect_evidence.c/1.1.1.1/Wed May 29 15:59:56 2002// +/distribute_evidence.c/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/enter_soft_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/init_pot.c/1.1.1.1/Wed May 29 15:59:56 2002// +/jtree_sparse_inf_engine.m/1.1.1.1/Sat Jan 18 22:11:32 2003// +/marginal_family.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/set_fields.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..61d96f3f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/old//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Repository new file mode 100644 index 00000000..ccd02123 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_sparse_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/cliques_from_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/cliques_from_engine.m new file mode 100644 index 00000000..cd9d871d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/cliques_from_engine.m @@ -0,0 +1,5 @@ +function cliques = cliques_from_engine(engine) +% CLIQUES_FROM_ENGINE Return the cliques stored inside the inf. engine (jtree) +% cliques = cliques_from_engine(engine) + +cliques = engine.cliques; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/clq_containing_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/clq_containing_nodes.m new file mode 100644 index 00000000..8904fa49 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/clq_containing_nodes.m @@ -0,0 +1,24 @@ +function c = clq_containing_nodes(engine, nodes, fam) +% CLQ_CONTAINING_NODES Find the lightest clique (if any) that contains the set of nodes +% c = clq_containing_nodes(engine, nodes, family) +% +% If the optional 'family' argument is specified, it means nodes = family(nodes(end)). +% (This is useful since clq_ass_to_node is not accessible to outsiders.) +% Returns c=-1 if there is no such clique. + +if nargin < 3, fam = 0; else fam = 1; end + +if length(nodes)==1 + c = engine.clq_ass_to_node(nodes(1)); +%elseif fam +% c = engine.clq_ass_to_node(nodes(end)); +else + B = engine.cliques_bitv; + w = engine.clique_weight; + clqs = find(all(B(:,nodes), 2)); % all selected columns must be 1 + if isempty(clqs) + c = -1; + else + c = clqs(argmin(w(clqs))); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/collect_evidence.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/collect_evidence.c new file mode 100644 index 00000000..8480c701 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/collect_evidence.c @@ -0,0 +1,634 @@ +/* C mex for collect_evidence.c in @jtree_sparse_inf_engine directory */ +/* File enter_evidence.m in directory @jtree_sparse_inf_engine call it*/ + +/******************************************/ +/* collect_evidence has 3 input & 2 output*/ +/* engine */ +/* clpot */ +/* seppot */ +/* */ +/* clpot */ +/* seppot */ +/******************************************/ + +#include <math.h> +#include <stdlib.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +void reset_nzmax(mxArray *spArray, const int old_nzmax, const int new_nzmax){ + double *ptr; + void *newptr; + int *ir, *jc; + int nbytes; + + if(new_nzmax == old_nzmax) return; + nbytes = new_nzmax * sizeof(*ptr); + ptr = mxGetPr(spArray); + newptr = mxRealloc(ptr, nbytes); + mxSetPr(spArray, newptr); + nbytes = new_nzmax * sizeof(*ir); + ir = mxGetIr(spArray); + newptr = mxRealloc(ir, nbytes); + mxSetIr(spArray, newptr); + jc = mxGetJc(spArray); + jc[0] = 0; + jc[1] = new_nzmax; + mxSetNzmax(spArray, new_nzmax); +} + +mxArray* convert_ill_table_to_sparse(const double *Table, const int *sequence, const int nzCounts, const int N){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(N, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = Table[temp]; + count++; + } + return spTable; +} + +void multiply_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex, nzCounts=0; + int *samemask, *diffmask, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *sequence, *weight; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *spr, *bpr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + if(sdim == 0){ + pTemp = mxCreateSparse(NB, 1, NB, mxREAL); + mxSetField(bigPot, 0, "T", pTemp); + bpr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + sjc[0] = 0; + sjc[1] = NB; + for(i=0; i<NB; i++){ + bpr[i] = *spr; + sir[i] = i; + } + return; + } + + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + if(ND == 1){ + pTemp1 = mxGetField(smallPot, 0, "T"); + pTemp = mxDuplicateArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + return; + } + + + NZB = ND * NZS; + + diffdim = bdim - sdim; + sequence = malloc(NZB * 2 * sizeof(int)); + bigTable = malloc(NZB * sizeof(double)); + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + bigTable[nzCounts] = spr[i]; + sequence[count] = bindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(bigTable, sequence, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(sequence); + free(bigTable); + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *result, *bir, *sir, *rir, *bjc, *sjc, *rjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, *rpr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + for(i=0; i<NZB; i++){ + bpr[i] *= *spr; + } + return; + } + + pTemp1 = mxCreateSparse(NB, 1, NZB, mxREAL); + rpr = mxGetPr(pTemp1); + rir = mxGetIr(pTemp1); + rjc = mxGetJc(pTemp1); + rjc[0] = 0; + rjc[1] = NZB; + + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + rpr[nzCounts] = bpr[i] * spr[position]; + rir[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NZB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +mxArray* marginal_null_to_spPot(const mxArray *bigPot, const mxArray *sDomain, const int maximize){ + int i, j, count, bdim, sdim, NB, NS, ND; + int *mask, *sir, *sjc; + double *pbDomain, *psDomain, *pbSize, *psSize, *spr; + mxArray *pTemp, *smallPot; + const char *field_names[] = {"domain", "T", "sizes"}; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + psDomain = mxGetPr(sDomain); + sdim = mxGetNumberOfElements(sDomain); + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + + smallPot = mxCreateStructMatrix(1, 1, 3, field_names); + pTemp = mxDuplicateArray(sDomain); + mxSetField(smallPot, 0, "domain", pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + if(sdim == 0){ + pTemp = mxCreateSparse(1, 1, 1, mxREAL); + mxSetField(smallPot, 0, "T", pTemp); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + *spr = 0; + *sir = 0; + sjc[0] = 0; + sjc[1] = 1; + if(maximize) *spr = 1; + else *spr = NB; + + pTemp = mxCreateDoubleMatrix(1, 1, mxREAL); + *mxGetPr(pTemp) = 1; + mxSetField(smallPot, 0, "sizes", pTemp); + return smallPot; + } + + mask = malloc(sdim * sizeof(int)); + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + pTemp = mxCreateDoubleMatrix(1, count, mxREAL); + psSize = mxGetPr(pTemp); + NS = 1; + for(i=0; i<count; i++){ + psSize[i] = pbSize[mask[i]]; + NS *= (int)psSize[i]; + } + mxSetField(smallPot, 0, "sizes", pTemp); + + ND = NB / NS; + + pTemp = mxCreateSparse(NS, 1, NS, mxREAL); + mxSetField(smallPot, 0, "T", pTemp); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + if(maximize){ + for(i=0; i<NS; i++){ + spr[i] = 1; + sir[i] = i; + } + } + else{ + for(i=0; i<NS; i++){ + spr[i] = ND; + sir[i] = i; + } + } + sjc[0] = 0; + sjc[1] = NS; + + free(mask); + return smallPot; +} + +mxArray* marginal_spPot_to_spPot(const mxArray *bigPot, const mxArray *sDomain, const int maximize){ + int i, j, count, bdim, sdim, NB, NS, NZB, position, bindex, sindex, nzCounts=0; + int *mask, *sequence, *result, *bir, *bjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *sTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr; + mxArray *pTemp, *smallPot; + const char *field_names[] = {"domain", "T", "sizes"}; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + psDomain = mxGetPr(sDomain); + sdim = mxGetNumberOfElements(sDomain); + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + smallPot = mxCreateStructMatrix(1, 1, 3, field_names); + pTemp = mxDuplicateArray(sDomain); + mxSetField(smallPot, 0, "domain", pTemp); + + if(sdim == 0){ + pTemp = mxCreateSparse(1, 1, 1, mxREAL); + mxSetField(smallPot, 0, "T", pTemp); + spr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + *spr = 0; + *bir = 0; + bjc[0] = 0; + bjc[1] = 1; + if(maximize){ + for(i=0; i<NZB; i++){ + *spr = (*spr < bpr[i])? bpr[i] : *spr; + } + } + else{ + for(i=0; i<NZB; i++){ + *spr += bpr[i]; + } + } + + pTemp = mxCreateDoubleMatrix(1, 1, mxREAL); + *mxGetPr(pTemp) = 1; + mxSetField(smallPot, 0, "sizes", pTemp); + return smallPot; + } + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + mask = malloc(sdim * sizeof(int)); + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + pTemp = mxCreateDoubleMatrix(1, count, mxREAL); + psSize = mxGetPr(pTemp); + NS = 1; + for(i=0; i<count; i++){ + psSize[i] = pbSize[mask[i]]; + NS *= (int)psSize[i]; + } + mxSetField(smallPot, 0, "sizes", pTemp); + + + sTable = malloc(NZB * sizeof(double)); + sequence = malloc(NZB * 2 * sizeof(double)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++)sTable[i] = 0; + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sequence, nzCounts, sizeof(int)*2, compare); + if(result){ + position = (result - sequence) / 2; + if(maximize) + sTable[position] = (sTable[position] < bpr[i]) ? bpr[i] : sTable[position]; + else sTable[position] += bpr[i]; + } + else { + if(maximize) + sTable[nzCounts] = (sTable[nzCounts] < bpr[i]) ? bpr[i] : sTable[nzCounts]; + else sTable[nzCounts] += bpr[i]; + sequence[count] = sindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(sTable, sequence, nzCounts, NS); + mxSetField(smallPot, 0, "T", pTemp); + + free(sTable); + free(sequence); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); + + return smallPot; +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, n, p, np, pn, loop, loops, nCliques, temp, maximize; + int *collect_order; + double *pr, *pr1; + mxArray *pTemp, *pTemp1, *pPostP, *pClpot, *pSeppot, *pSeparator; + + pTemp = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pTemp); + loops = nCliques - 1; + pTemp = mxGetField(prhs[0], 0, "maximize"); + maximize = (int)mxGetScalar(pTemp); + pSeparator = mxGetField(prhs[0], 0, "separator"); + + collect_order = malloc(2 * loops * sizeof(int)); + + pTemp = mxGetField(prhs[0], 0, "postorder"); + pr = mxGetPr(pTemp); + pPostP = mxGetField(prhs[0], 0, "postorder_parents"); + for(i=0; i<loops; i++){ + temp = (int)pr[i] - 1; + pTemp = mxGetCell(pPostP, temp); + pr1 = mxGetPr(pTemp); + collect_order[i] = (int)pr1[0] - 1; + collect_order[i+loops] = temp; + } + + plhs[0] = mxDuplicateArray(prhs[1]); + plhs[1] = mxDuplicateArray(prhs[2]); + + for(loop=0; loop<loops; loop++){ + p = collect_order[loop]; + n = collect_order[loop+loops]; + np = p * nCliques + n; + pn = n * nCliques + p; + pClpot = mxGetCell(plhs[0], n); + pTemp1 = mxGetField(pClpot, 0, "T"); + pTemp = mxGetCell(pSeparator, pn); + if(pTemp1) + pSeppot = marginal_spPot_to_spPot(pClpot, pTemp, maximize); + else pSeppot = marginal_null_to_spPot(pClpot, pTemp, maximize); + mxSetCell(plhs[1], pn, pSeppot); + + pClpot = mxGetCell(plhs[0], p); + pTemp1 = mxGetField(pClpot, 0, "T"); + if(pTemp1) + multiply_spPot_by_spPot(pClpot, pSeppot); + else multiply_null_by_spPot(pClpot, pSeppot); + } + free(collect_order); +} + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/distribute_evidence.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/distribute_evidence.c new file mode 100644 index 00000000..8147c403 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/distribute_evidence.c @@ -0,0 +1,618 @@ +/* C mex for distribute_evidence.c in @jtree_sparse_inf_engine directory*/ +/* File enter_evidence.m in directory @jtree_sparse_inf_engine call it */ + +/*********************************************/ +/* distribute_evidence has 3 input & 2 output*/ +/* engine */ +/* clpot */ +/* seppot */ +/* */ +/* clpot */ +/* seppot */ +/*********************************************/ + +#include <math.h> +#include <stdlib.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void reset_nzmax(mxArray *spArray, const int old_nzmax, const int new_nzmax){ + double *ptr; + void *newptr; + int *ir, *jc; + int nbytes; + + if(new_nzmax == old_nzmax) return; + nbytes = new_nzmax * sizeof(*ptr); + ptr = mxGetPr(spArray); + newptr = mxRealloc(ptr, nbytes); + mxSetPr(spArray, newptr); + nbytes = new_nzmax * sizeof(*ir); + ir = mxGetIr(spArray); + newptr = mxRealloc(ir, nbytes); + mxSetIr(spArray, newptr); + jc = mxGetJc(spArray); + jc[0] = 0; + jc[1] = new_nzmax; + mxSetNzmax(spArray, new_nzmax); +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +mxArray* convert_ill_table_to_sparse(const double *Table, const int *sequence, const int nzCounts, const int N){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(N, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = Table[temp]; + count++; + } + return spTable; +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *result, *bir, *sir, *rir, *bjc, *sjc, *rjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, *rpr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + for(i=0; i<NZB; i++){ + bpr[i] *= *spr; + } + return; + } + + pTemp1 = mxCreateSparse(NB, 1, NZB, mxREAL); + rpr = mxGetPr(pTemp1); + rir = mxGetIr(pTemp1); + rjc = mxGetJc(pTemp1); + rjc[0] = 0; + rjc[1] = NZB; + + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + rpr[nzCounts] = bpr[i] * spr[position]; + rir[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NZB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void marginal_spPot_to_spPot(const mxArray *bigPot, mxArray *smallPot, const int maximize){ + int i, j, count, bdim, sdim, NB, NS, NZB, position, bindex, sindex, nzCounts=0; + int *mask, *sequence, *result, *bir, *bjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *sTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + if(sdim == 0){ + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + *spr = 0; + if(maximize){ + for(i=0; i<NZB; i++){ + *spr = (*spr < bpr[i])? bpr[i] : *spr; + } + } + else{ + for(i=0; i<NZB; i++){ + *spr += bpr[i]; + } + } + return; + } + + mask = malloc(sdim * sizeof(int)); + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + + sTable = malloc(NZB * sizeof(double)); + sequence = malloc(NZB * 2 * sizeof(double)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++){ + sTable[i] = 0; + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sequence, nzCounts, sizeof(int)*2, compare); + if(result){ + position = (result - sequence) / 2; + if(maximize) + sTable[position] = (sTable[position] < bpr[i]) ? bpr[i] : sTable[position]; + else sTable[position] += bpr[i]; + } + else { + if(maximize) + sTable[nzCounts] = (sTable[nzCounts] < bpr[i]) ? bpr[i] : sTable[nzCounts]; + else sTable[nzCounts] += bpr[i]; + sequence[count] = sindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(smallPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(sTable, sequence, nzCounts, NS); + mxSetField(smallPot, 0, "T", pTemp); + + free(sTable); + free(sequence); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void divide_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex; + int *samemask, *diffmask, *rir, *rjc, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *weight; + double *pbDomain, *psDomain, *pbSize, *psSize, *rpr, *spr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + pTemp1 = mxGetField(bigPot, 0, "T"); + if(pTemp1)mxDestroyArray(pTemp1); + pTemp = mxCreateSparse(NB, 1, NB, mxREAL); + mxSetField(bigPot, 0, "T", pTemp); + rpr = mxGetPr(pTemp); + rir = mxGetIr(pTemp); + rjc = mxGetJc(pTemp); + rjc[0] = 0; + rjc[1] = NB; + value = *spr; + if(value == 0) value = 1; + for(i=0; i<NB; i++){ + rpr[i] = 1 / value; + rir[i] = i; + } + return; + } + + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + pTemp = mxCreateSparse(NB, 1, NB, mxREAL); + rpr = mxGetPr(pTemp); + rir = mxGetIr(pTemp); + rjc = mxGetJc(pTemp); + rjc[0] = 0; + rjc[1] = NB; + for(i=0; i<NB; i++){ + rpr[i] = 1; + rir[i] = i; + } + + NZB = ND * NZS; + + diffdim = bdim - sdim; + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + rpr[bindex] = 1 / (spr[i]); + } + } + + pTemp1 = mxGetField(bigPot, 0, "T"); + if(pTemp1)mxDestroyArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void divide_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex; + int *mask, *result, *bir, *sir, *bjc, *sjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp1 = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp1); + bir = mxGetIr(pTemp1); + bjc = mxGetJc(pTemp1); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + value = *spr; + if(value == 0)value = 1; + for(i=0; i<NZB; i++){ + bpr[i] /= value; + } + return; + } + + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + bpr[i] /= spr[position]; + } + } + + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, j, loop, loops, nCliques, temp, count, parent, child, maximize, *distribute_order; + double *pr, *pr1; + mxArray *pTemp, *pPreCh, *pClpot, *pSeppot; + + pTemp = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pTemp); + loops = nCliques - 1; + pTemp = mxGetField(prhs[0], 0, "maximize"); + maximize = (int)mxGetScalar(pTemp); + + distribute_order = malloc(2 * loops * sizeof(int)); + pTemp = mxGetField(prhs[0], 0, "preorder"); + pr = mxGetPr(pTemp); + pPreCh = mxGetField(prhs[0], 0, "preorder_children"); + count = 0; + for(i=0; i<nCliques; i++){ + temp = (int)pr[i] - 1; + pTemp = mxGetCell(pPreCh, temp); + pr1 = mxGetPr(pTemp); + loop = mxGetNumberOfElements(pTemp); + for(j=0; j<loop; j++){ + distribute_order[count] = temp; + distribute_order[count + loops] = (int)pr1[j] - 1; + count++; + } + } + + plhs[0] = mxDuplicateArray(prhs[1]); + plhs[1] = mxDuplicateArray(prhs[2]); + + for(loop=0; loop<loops; loop++){ + parent = distribute_order[loop]; + child = distribute_order[loop+loops]; + i = nCliques * child + parent; + pClpot = mxGetCell(plhs[0], child); + pTemp = mxGetField(pClpot, 0, "T"); + pSeppot = mxGetCell(plhs[1], i); + if(pTemp){ + if(mxIsEmpty(pTemp)) + divide_null_by_spPot(pClpot, pSeppot); + else + divide_spPot_by_spPot(pClpot, pSeppot); + } + else divide_null_by_spPot(pClpot, pSeppot); + + pClpot = mxGetCell(plhs[0], parent); + marginal_spPot_to_spPot(pClpot, pSeppot, maximize); + mxSetCell(plhs[1], i, pSeppot); + + pClpot = mxGetCell(plhs[0], child); + multiply_spPot_by_spPot(pClpot, pSeppot); + } + free(distribute_order); +} diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/enter_evidence.m new file mode 100644 index 00000000..86041be2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/enter_evidence.m @@ -0,0 +1,100 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (jtree) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector). +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% soft - a cell array of soft/virtual evidence; +% soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ] +% +% e.g., engine = enter_evidence(engine, ev, 'soft', soft_ev) +% +% For backwards compatibility with BNT2, you can also specify the parameters in the following order +% engine = enter_evidence(engine, ev, soft_ev) + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +engine.evidence = evidence; % store this for marginal_nodes with add_ev option + +% set default params +exclude = []; +soft_evidence = cell(1,N); +maximize = 0; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + if iscell(args{1}) + soft_evidence = args{1}; + else + for i=1:2:nargs + switch args{i}, + case 'soft', soft_evidence = args{i+1}; + case 'maximize', maximize = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end + end +end + +engine.maximize = maximize; + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + if strcmp(pot_type, 'cg') + check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag); +end + +hard_nodes = 1:N; +soft_nodes = find(~isemptycell(soft_evidence)); +S = length(soft_nodes); +if S > 0 + assert(pot_type == 'd'); + assert(mysubset(soft_nodes, bnet.dnodes)); +end + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N+S); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + if isempty(bnet.CPD{e}) + error(['must define CPD ' num2str(e)]) + else + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); + end +end + +for i=1:S + n = soft_nodes(i); + pot{N+i} = dpot(n, ns(n), soft_evidence{n}); +end +clqs = engine.clq_ass_to_node([hard_nodes soft_nodes]); + +[clpot, seppot] = init_pot(engine, clqs, pot, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +[clpot, seppot] = distribute_evidence(engine, clpot, seppot); +C = length(clpot); +ll = zeros(1, C); +for i=1:C + domain = clpot{i}.domain; + sizes = clpot{i}.sizes; + T = clpot{i}.T; + clpot{i} = dpot(domain, sizes, T); +end + +for i=1:C + [clpot{i}, ll(i)] = normalize_pot(clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + +engine.clpot = clpot; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/enter_soft_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/enter_soft_evidence.m new file mode 100644 index 00000000..59671415 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/enter_soft_evidence.m @@ -0,0 +1,19 @@ +function [clpot, loglik] = enter_soft_evidence(engine, clique, potential, onodes, pot_type) +% ENTER_SOFT_EVIDENCE Add the specified potentials to the network (jtree) +% [clpot, loglik] = enter_soft_evidence(engine, clique, potential, onodes, pot_type, maximize) +% +% We multiply potential{i} onto clique(i) before propagating. +% We return all the modified clique potentials. + +[clpot, seppot] = init_pot(engine, clique, potential, pot_type, onodes); +[clpot, seppot] = collect_evidence(engine, clpot, seppot); +[clpot, seppot] = distribute_evidence(engine, clpot, seppot); + +C = length(clpot); +ll = zeros(1, C); +for i=1:C + [clpot{i}, ll(i)] = normalize_pot(clpot{i}); +end +loglik = ll(1); % we can extract the likelihood from any clique + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/init_pot.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/init_pot.c new file mode 100644 index 00000000..86e09eae --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/init_pot.c @@ -0,0 +1,624 @@ +/* C mex init_pot for in @jtree_sparse_inf_engine directory */ +/* The file enter_evidence.m in directory @jtree_sparse_inf_engine call it*/ + +/**************************************/ +/* init_pot.c has 5 input & 2 output */ +/* engine */ +/* clqs */ +/* pots */ +/* pot_type */ +/* onodes */ +/* */ +/* clpot */ +/* seppot */ +/**************************************/ +#include <math.h> +#include <stdlib.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +void reset_nzmax(mxArray *spArray, const int old_nzmax, const int new_nzmax){ + double *ptr; + void *newptr; + int *ir, *jc; + int nbytes; + + if(new_nzmax == old_nzmax) return; + nbytes = new_nzmax * sizeof(*ptr); + ptr = mxGetPr(spArray); + newptr = mxRealloc(ptr, nbytes); + mxSetPr(spArray, newptr); + nbytes = new_nzmax * sizeof(*ir); + ir = mxGetIr(spArray); + newptr = mxRealloc(ir, nbytes); + mxSetIr(spArray, newptr); + jc = mxGetJc(spArray); + jc[0] = 0; + jc[1] = new_nzmax; + mxSetNzmax(spArray, new_nzmax); +} + +mxArray* convert_ill_table_to_sparse(const double *bigTable, const int *sequence, const int nzCounts, const int NB){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(NB, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = bigTable[temp]; + count++; + } + return spTable; +} + +void multiply_null_by_fuPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, NB, NS, siz_b, siz_s, ndim, nzCounts=0; + int *mask, *sx, *sy, *cpsy, *subs, *s, *cpsy2, *bir, *bjc; + double *pbDomain, *psDomain, *pbSize, *psSize, *spr, *bpr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + siz_b = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + siz_s = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<siz_b; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<siz_s; i++){ + NS *= (int)psSize[i]; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + + pTemp1 = mxCreateSparse(NB, 1, NB, mxREAL); + bpr = mxGetPr(pTemp1); + bir = mxGetIr(pTemp1); + bjc = mxGetJc(pTemp1); + bjc[0] = 0; + bjc[1] = NB; + + if(NS == 1){ + value = *spr; + for(i=0; i<NB; i++){ + bpr[i] = value; + bir[i] = i; + } + nzCounts = NB; + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + return; + } + + if(NS == NB){ + for(i=0; i<NB; i++){ + if(spr[i] != 0){ + bpr[nzCounts] = spr[i]; + bir[nzCounts] = i; + nzCounts++; + } + } + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + return; + } + + mask = malloc(siz_s * sizeof(int)); + count = 0; + for(i=0; i<siz_s; i++){ + for(j=0; j<siz_b; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + ndim = siz_b; + sx = (int *)malloc(sizeof(int)*ndim); + sy = (int *)malloc(sizeof(int)*ndim); + for(i=0; i<ndim; i++){ + sx[i] = (int)pbSize[i]; + sy[i] = 1; + } + for(i=0; i<count; i++){ + sy[mask[i]] = sx[mask[i]]; + } + + s = (int *)malloc(sizeof(int)*ndim); + *(cpsy = (int *)malloc(sizeof(int)*ndim)) = 1; + subs = (int *)malloc(sizeof(int)*ndim); + cpsy2 = (int *)malloc(sizeof(int)*ndim); + for(i = 0; i < ndim; i++){ + subs[i] = 0; + s[i] = sx[i] - 1; + } + + for(i = 0; i < ndim-1; i++){ + cpsy[i+1] = cpsy[i]*sy[i]--; + cpsy2[i] = cpsy[i]*sy[i]; + } + cpsy2[ndim-1] = cpsy[ndim-1]*(--sy[ndim-1]); + + for(j=0; j<NB; j++){ + if(*spr != 0){ + bpr[nzCounts] = *spr; + bir[nzCounts] = j; + nzCounts++; + } + for(i = 0; i < ndim; i++){ + if(subs[i] == s[i]){ + subs[i] = 0; + if(sy[i]) + spr -= cpsy2[i]; + } + else{ + subs[i]++; + if(sy[i]) + spr += cpsy[i]; + break; + } + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + + free(sx); + free(sy); + free(s); + free(cpsy); + free(subs); + free(cpsy2); + free(mask); +} + +void multiply_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex, nzCounts=0; + int *samemask, *diffmask, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *sequence, *weight; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *spr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + if(ND == 1){ + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp1 = mxGetField(smallPot, 0, "T"); + pTemp = mxDuplicateArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + return; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + NZB = ND * NZS; + + diffdim = bdim - sdim; + sequence = malloc(NZB * 2 * sizeof(int)); + bigTable = malloc(NZB * sizeof(double)); + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + bigTable[nzCounts] = spr[i]; + sequence[count] = bindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(bigTable, sequence, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(sequence); + free(bigTable); + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void multiply_spPot_by_fuPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, bindex, sindex, nzCounts=0; + int *mask, *bir, *bjc, *rir, *rjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, *rpr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + + pTemp1 = mxCreateSparse(NB, 1, NZB, mxREAL); + rpr = mxGetPr(pTemp1); + rir = mxGetIr(pTemp1); + rjc = mxGetJc(pTemp1); + rjc[0] = 0; + rjc[1] = NZB; + + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + value = spr[sindex]; + if(value != 0){ + rpr[nzCounts] = bpr[i] * value; + rir[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NZB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *result, *bir, *sir, *rir, *bjc, *sjc, *rjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, *rpr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + pTemp1 = mxCreateSparse(NB, 1, NZB, mxREAL); + rpr = mxGetPr(pTemp1); + rir = mxGetIr(pTemp1); + rjc = mxGetJc(pTemp1); + rjc[0] = 0; + rjc[1] = NZB; + + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + rpr[nzCounts] = bpr[i] * spr[position]; + rir[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NZB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, j, c, loop, nNodes, nCliques, ndomain, ns_num, nOnodes, dims[2]; + double *pClqs, *pr, *pt, *pSize, *eff_ns; + mxArray *pTemp, *pTemp1, *pStruct, *pCliques, *pBigpot, *pSmallpot; + const char *field_names[] = {"domain", "T", "sizes"}; + + nNodes = mxGetNumberOfElements(prhs[1]); + pCliques = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pCliques); + pTemp = mxGetField(prhs[0], 0, "actual_node_sizes"); + ns_num = mxGetNumberOfElements(pTemp); + pSize = mxGetPr(pTemp); + + eff_ns = (double *)malloc(ns_num * sizeof(double)); + for(i=0; i<ns_num; i++) eff_ns[i] = pSize[i]; + nOnodes = mxGetNumberOfElements(prhs[4]); + pr = mxGetPr(prhs[4]); + for(i=0; i<nOnodes; i++) eff_ns[(int)pr[i] - 1] = 1; + + plhs[0] = mxCreateCellArray(1, &nCliques); + for(i=0; i<nCliques; i++){ + pStruct = mxCreateStructMatrix(1, 1, 3, field_names); + mxSetCell(plhs[0], i, pStruct); + pTemp = mxGetCell(pCliques, i); + ndomain = mxGetNumberOfElements(pTemp); + pt = mxGetPr(pTemp); + pTemp1 = mxDuplicateArray(pTemp); + mxSetField(pStruct, 0, "domain", pTemp1); + + pTemp = mxCreateDoubleMatrix(1, ndomain, mxREAL); + mxSetField(pStruct, 0, "sizes", pTemp); + pr = mxGetPr(pTemp); + for(j=0; j<ndomain; j++){ + pr[j] = eff_ns[(int)pt[j]-1]; + } + } + + pClqs = mxGetPr(prhs[1]); + for(loop=0; loop<nNodes; loop++){ + c = (int)pClqs[loop] - 1; + pSmallpot = mxGetCell(prhs[2], loop); + pTemp = mxGetField(pSmallpot, 0, "T"); + pBigpot = mxGetCell(plhs[0], c); + pTemp1 = mxGetField(pBigpot, 0, "T"); + if(pTemp1){ + if(mxIsSparse(pTemp)) + multiply_spPot_by_spPot(pBigpot, pSmallpot); + else multiply_spPot_by_fuPot(pBigpot, pSmallpot); + } + else{ + if(mxIsSparse(pTemp)) + multiply_null_by_spPot(pBigpot, pSmallpot); + else multiply_null_by_fuPot(pBigpot, pSmallpot); + } + } + + free(eff_ns); + dims[0] = nCliques; + dims[1] = nCliques; + plhs[1] = mxCreateCellArray(2, dims); +} + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/jtree_sparse_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/jtree_sparse_inf_engine.m new file mode 100644 index 00000000..49dcd69f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/jtree_sparse_inf_engine.m @@ -0,0 +1,126 @@ +function engine = jtree_sparse_inf_engine(bnet, varargin) +% JTREE_SPARSE_INF_ENGINE Junction tree inference engine when CPTs and Potentials are sparse +% engine = jtree_sparse_inf_engine(bnet, ...) +% It differs from jtree_inf_engine with all CPTs and potentials are 1D sparse arrays. +% +% The following optional arguments can be specified in the form of name/value pairs: +% [default value in brackets] +% +% clusters - a cell array of sets of nodes we want to ensure are in the same clique (in addition to families) [ {} ] +% root - the root of the junction tree will be a clique that contains this set of nodes [N] +% stages - stages{t} is a set of nodes we want to eliminate before stages{t+1}, ... [ {1:N} ] +% +% e.g., engine = jtree_inf_engine(bnet, 'maximize', 1); +% +% For more details on the junction tree algorithm, see +% - "Probabilistic networks and expert systems", Cowell, Dawid, Lauritzen and Spiegelhalter, Springer, 1999 +% - "Inference in Belief Networks: A procedural guide", C. Huang and A. Darwiche, +% Intl. J. Approximate Reasoning, 15(3):225-263, 1996. + + +% set default params +N = length(bnet.dag); +clusters = {}; +root = N; +stages = { 1:N }; + +if nargin >= 2 + args = varargin; + nargs = length(args); + if ~isstr(args{1}) + error('the interface to jtree has changed; now, onodes is not allowed and all optional params must be passed by name') + end + for i=1:2:nargs + switch args{i}, + case 'clusters', clusters = args{i+1}; + case 'root', root = args{i+1}; + case 'stages', stages = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +engine = init_fields; +engine = class(engine, 'jtree_sparse_inf_engine', inf_engine(bnet)); + +onodes = bnet.observed; +%[engine.jtree, dummy, engine.cliques, B, w] = dag_to_jtree(bnet, onodes, stages, clusters); + +porder = determine_elim_constraints(bnet, onodes); +strong = ~isempty(porder); +ns = bnet.node_sizes(:); +ns(onodes) = 1; % observed nodes have only 1 possible value +[engine.jtree, root2, engine.cliques, B, w] = ... + graph_to_jtree(moralize(bnet.dag), ns, porder, stages, clusters); + +engine.cliques_bitv = B; +engine.clique_weight = w; +C = length(engine.cliques); +engine.clpot = cell(1,C); + +% Compute the separators between connected cliques. +[is,js] = find(engine.jtree > 0); +engine.separator = cell(C,C); +for k=1:length(is) + i = is(k); j = js(k); + engine.separator{i,j} = find(B(i,:) & B(j,:)); % intersect(cliques{i}, cliques{j}); +end + +% A node can be a member of many cliques, but is assigned to exactly one, to avoid +% double-counting its CPD. We assign node i to clique c if c is the "lightest" clique that +% contains i's family, so it can accomodate its CPD. + +engine.clq_ass_to_node = zeros(1, N); +for i=1:N + %c = clq_containing_nodes(engine, family(bnet.dag, i)); + clqs_containing_family = find(all(B(:,family(bnet.dag, i)), 2)); % all selected columns must be 1 + c = clqs_containing_family(argmin(w(clqs_containing_family))); + engine.clq_ass_to_node(i) = c; +end + +% Make the jtree rooted, so there is a fixed message passing order. +engine.root_clq = clq_containing_nodes(engine, root); +if engine.root_clq <= 0 + error(['no clique contains ' num2str(root)]); +end + +[engine.jtree, engine.preorder, engine.postorder] = mk_rooted_tree(engine.jtree, engine.root_clq); + +% collect +engine.postorder_parents = cell(1,length(engine.postorder)); +for n=engine.postorder(:)' + engine.postorder_parents{n} = parents(engine.jtree, n); +end +% distribute +engine.preorder_children = cell(1,length(engine.preorder)); +for n=engine.preorder(:)' + engine.preorder_children{n} = children(engine.jtree, n); +end + +ns = bnet.node_sizes; +engine.actual_node_sizes = ns; + + +%%%%%%%% + +function engine = init_fields() + +engine.jtree = []; +engine.cliques = []; +engine.separator = []; +engine.cliques_bitv = []; +engine.clique_weight = []; +engine.clpot = []; +engine.clq_ass_to_node = []; +engine.root_clq = []; +engine.preorder = []; +engine.postorder = []; +engine.preorder_children = []; +engine.postorder_parents = []; +engine.maximize = []; +engine.evidence = []; +engine.actual_node_sizes = []; + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/marginal_family.m new file mode 100644 index 00000000..eff60ca2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/marginal_family.m @@ -0,0 +1,11 @@ +function marginal = marginal_family(engine, i, add_ev) +% MARGINAL_FAMILY Compute the marginal on the specified family (jtree) +% marginal = marginal_family(engine, i) + +if nargin < 3, add_ev = 0; end +assert(~add_ev); + +bnet = bnet_from_engine(engine); +fam = family(bnet.dag, i); +c = engine.clq_ass_to_node(i); +marginal = pot_to_marginal(marginalize_pot(engine.clpot{c}, fam)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..6413172c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/marginal_nodes.m @@ -0,0 +1,22 @@ +function marginal = marginal_nodes(engine, query, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (jtree) +% marginal = marginal_nodes(engine, query, add_ev) +% +% 'query' must be a subset of some clique; an error will be raised if not. +% add_ev is an optional argument; if 1, we will "inflate" the marginal of observed nodes +% to their original size, adding 0s to the positions which contradict the evidence + +if nargin < 3, add_ev = 0; end + +c = clq_containing_nodes(engine, query); +if c == -1 + error(['no clique contains ' num2str(query)]); +end +marginal = pot_to_marginal(marginalize_pot(engine.clpot{c}, query, engine.maximize)); + +if add_ev + bnet = bnet_from_engine(engine); + %marginal = add_ev_to_dmarginal(marginal, engine.evidence, bnet.node_sizes); + marginal = add_evidence_to_gmarginal(marginal, engine.evidence, bnet.node_sizes, bnet.cnodes); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Entries new file mode 100644 index 00000000..f74fd729 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Entries @@ -0,0 +1,6 @@ +/collect_evidence.c/1.1.1.1/Wed May 29 15:59:56 2002// +/distribute_evidence.c/1.1.1.1/Wed May 29 15:59:56 2002// +/init_pot.c/1.1.1.1/Wed May 29 15:59:56 2002// +/init_pot1.c/1.1.1.1/Wed May 29 15:59:56 2002// +/init_pot1.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Repository new file mode 100644 index 00000000..eb323e83 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@jtree_sparse_inf_engine/old diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/collect_evidence.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/collect_evidence.c new file mode 100644 index 00000000..3e6d35c7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/collect_evidence.c @@ -0,0 +1,635 @@ +/* C mex for collect_evidence.c in @jtree_sparse_inf_engine directory */ +/* File enter_evidence.m in directory @jtree_sparse_inf_engine call it*/ + +/******************************************/ +/* collect_evidence has 3 input & 2 output*/ +/* engine */ +/* clpot */ +/* seppot */ +/* */ +/* clpot */ +/* seppot */ +/******************************************/ + +#include <math.h> +#include <search.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +mxArray* convert_table_to_sparse(const double *bT, const int *index, const int nzCounts, const int N){ + mxArray *spTable; + int i, *irs, *jcs; + double *sr; + + spTable = mxCreateSparse(N, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + sr[i] = bT[i]; + irs[i] = index[i]; + } + return spTable; +} + +mxArray* convert_ill_table_to_sparse(const double *Table, const int *sequence, const int nzCounts, const int N){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(N, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = Table[temp]; + count++; + } + return spTable; +} + +void multiply_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex, nzCounts=0; + int *samemask, *diffmask, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *sequence, *weight; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *spr, *bpr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + if(sdim == 0){ + pTemp = mxCreateSparse(NB, 1, NB, mxREAL); + mxSetField(bigPot, 0, "T", pTemp); + bpr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + sjc[0] = 0; + sjc[1] = NB; + for(i=0; i<NB; i++){ + bpr[i] = *spr; + sir[i] = i; + } + return; + } + + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + if(ND == 1){ + pTemp1 = mxGetField(smallPot, 0, "T"); + pTemp = mxDuplicateArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + return; + } + + + NZB = ND * NZS; + + diffdim = bdim - sdim; + sequence = malloc(NZB * 2 * sizeof(int)); + bigTable = malloc(NZB * sizeof(double)); + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + bigTable[nzCounts] = spr[i]; + sequence[count] = bindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(bigTable, sequence, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(sequence); + free(bigTable); + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *index, *result, *bir, *sir, *bjc, *sjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + for(i=0; i<NZB; i++){ + bpr[i] *= *spr; + } + return; + } + + bigTable = malloc(NZB * sizeof(double)); + index = malloc(NZB * sizeof(double)); + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++){ + bigTable[i] = 0; + } + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + value = bpr[i]; + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + value *= spr[position]; + bigTable[nzCounts] = value; + index[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_table_to_sparse(bigTable, index, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(bigTable); + free(index); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +mxArray* marginal_null_to_spPot(const mxArray *bigPot, const mxArray *sDomain, const int maximize){ + int i, j, count, bdim, sdim, NB, NS, ND; + int *mask, *sir, *sjc; + double *pbDomain, *psDomain, *pbSize, *psSize, *spr; + mxArray *pTemp, *smallPot; + const char *field_names[] = {"domain", "T", "sizes"}; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + psDomain = mxGetPr(sDomain); + sdim = mxGetNumberOfElements(sDomain); + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + + smallPot = mxCreateStructMatrix(1, 1, 3, field_names); + pTemp = mxDuplicateArray(sDomain); + mxSetField(smallPot, 0, "domain", pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + if(sdim == 0){ + pTemp = mxCreateSparse(1, 1, 1, mxREAL); + mxSetField(smallPot, 0, "T", pTemp); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + *spr = 0; + *sir = 0; + sjc[0] = 0; + sjc[1] = 1; + if(maximize) *spr = 1; + else *spr = NB; + + pTemp = mxCreateDoubleMatrix(1, 1, mxREAL); + *mxGetPr(pTemp) = 1; + mxSetField(smallPot, 0, "sizes", pTemp); + return smallPot; + } + + mask = malloc(sdim * sizeof(int)); + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + pTemp = mxCreateDoubleMatrix(1, count, mxREAL); + psSize = mxGetPr(pTemp); + NS = 1; + for(i=0; i<count; i++){ + psSize[i] = pbSize[mask[i]]; + NS *= (int)psSize[i]; + } + mxSetField(smallPot, 0, "sizes", pTemp); + + ND = NB / NS; + + pTemp = mxCreateSparse(NS, 1, NS, mxREAL); + mxSetField(smallPot, 0, "T", pTemp); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + if(maximize){ + for(i=0; i<NS; i++){ + spr[i] = 1; + sir[i] = i; + } + } + else{ + for(i=0; i<NS; i++){ + spr[i] = ND; + sir[i] = i; + } + } + sjc[0] = 0; + sjc[1] = NS; + + free(mask); + return smallPot; +} + +mxArray* marginal_spPot_to_spPot(const mxArray *bigPot, const mxArray *sDomain, const int maximize){ + int i, j, count, bdim, sdim, NB, NS, NZB, position, bindex, sindex, nzCounts=0; + int *mask, *sequence, *result, *bir, *bjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *sTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr; + mxArray *pTemp, *smallPot; + const char *field_names[] = {"domain", "T", "sizes"}; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + psDomain = mxGetPr(sDomain); + sdim = mxGetNumberOfElements(sDomain); + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + smallPot = mxCreateStructMatrix(1, 1, 3, field_names); + pTemp = mxDuplicateArray(sDomain); + mxSetField(smallPot, 0, "domain", pTemp); + + if(sdim == 0){ + pTemp = mxCreateSparse(1, 1, 1, mxREAL); + mxSetField(smallPot, 0, "T", pTemp); + spr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + *spr = 0; + *bir = 0; + bjc[0] = 0; + bjc[1] = 1; + if(maximize){ + for(i=0; i<NZB; i++){ + *spr = (*spr < bpr[i])? bpr[i] : *spr; + } + } + else{ + for(i=0; i<NZB; i++){ + *spr += bpr[i]; + } + } + + pTemp = mxCreateDoubleMatrix(1, 1, mxREAL); + *mxGetPr(pTemp) = 1; + mxSetField(smallPot, 0, "sizes", pTemp); + return smallPot; + } + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + mask = malloc(sdim * sizeof(int)); + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + pTemp = mxCreateDoubleMatrix(1, count, mxREAL); + psSize = mxGetPr(pTemp); + NS = 1; + for(i=0; i<count; i++){ + psSize[i] = pbSize[mask[i]]; + NS *= (int)psSize[i]; + } + mxSetField(smallPot, 0, "sizes", pTemp); + + + sTable = malloc(NZB * sizeof(double)); + sequence = malloc(NZB * 2 * sizeof(double)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++)sTable[i] = 0; + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sequence, nzCounts, sizeof(int)*2, compare); + if(result){ + position = (result - sequence) / 2; + if(maximize) + sTable[position] = (sTable[position] < bpr[i]) ? bpr[i] : sTable[position]; + else sTable[position] += bpr[i]; + } + else { + if(maximize) + sTable[nzCounts] = (sTable[nzCounts] < bpr[i]) ? bpr[i] : sTable[nzCounts]; + else sTable[nzCounts] += bpr[i]; + sequence[count] = sindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(sTable, sequence, nzCounts, NS); + mxSetField(smallPot, 0, "T", pTemp); + + free(sTable); + free(sequence); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); + + return smallPot; +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, n, p, np, pn, loop, loops, nCliques, temp, maximize; + int *collect_order; + double *pr, *pr1; + mxArray *pTemp, *pTemp1, *pPostP, *pClpot, *pSeppot, *pSeparator; + + pTemp = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pTemp); + loops = nCliques - 1; + pTemp = mxGetField(prhs[0], 0, "maximize"); + maximize = (int)mxGetScalar(pTemp); + pSeparator = mxGetField(prhs[0], 0, "separator"); + + collect_order = malloc(2 * loops * sizeof(int)); + + pTemp = mxGetField(prhs[0], 0, "postorder"); + pr = mxGetPr(pTemp); + pPostP = mxGetField(prhs[0], 0, "postorder_parents"); + for(i=0; i<loops; i++){ + temp = (int)pr[i] - 1; + pTemp = mxGetCell(pPostP, temp); + pr1 = mxGetPr(pTemp); + collect_order[i] = (int)pr1[0] - 1; + collect_order[i+loops] = temp; + } + + plhs[0] = mxDuplicateArray(prhs[1]); + plhs[1] = mxDuplicateArray(prhs[2]); + + for(loop=0; loop<loops; loop++){ + p = collect_order[loop]; + n = collect_order[loop+loops]; + np = p * nCliques + n; + pn = n * nCliques + p; + pClpot = mxGetCell(plhs[0], n); + pTemp1 = mxGetField(pClpot, 0, "T"); + pTemp = mxGetCell(pSeparator, pn); + if(pTemp1) + pSeppot = marginal_spPot_to_spPot(pClpot, pTemp, maximize); + else pSeppot = marginal_null_to_spPot(pClpot, pTemp, maximize); + mxSetCell(plhs[1], pn, pSeppot); + + pClpot = mxGetCell(plhs[0], p); + pTemp1 = mxGetField(pClpot, 0, "T"); + if(pTemp1) + multiply_spPot_by_spPot(pClpot, pSeppot); + else multiply_null_by_spPot(pClpot, pSeppot); + } + free(collect_order); +} + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/distribute_evidence.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/distribute_evidence.c new file mode 100644 index 00000000..3d8ec66b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/distribute_evidence.c @@ -0,0 +1,613 @@ +/* C mex for distribute_evidence.c in @jtree_sparse_inf_engine directory*/ +/* File enter_evidence.m in directory @jtree_sparse_inf_engine call it */ + +/*********************************************/ +/* distribute_evidence has 3 input & 2 output*/ +/* engine */ +/* clpot */ +/* seppot */ +/* */ +/* clpot */ +/* seppot */ +/*********************************************/ + +#include "mex.h" + +#include <math.h> +#include <search.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +mxArray* convert_table_to_sparse(const double *bT, const int *index, const int nzCounts, const int N){ + mxArray *spTable; + int i, *irs, *jcs; + double *sr; + + spTable = mxCreateSparse(N, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + sr[i] = bT[i]; + irs[i] = index[i]; + } + return spTable; +} + +mxArray* convert_ill_table_to_sparse(const double *Table, const int *sequence, const int nzCounts, const int N){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(N, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = Table[temp]; + count++; + } + return spTable; +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *index, *result, *bir, *sir, *bjc, *sjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + for(i=0; i<NZB; i++){ + bpr[i] *= *spr; + } + return; + } + + bigTable = malloc(NZB * sizeof(double)); + index = malloc(NZB * sizeof(double)); + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + value = bpr[i]; + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + value *= spr[position]; + bigTable[nzCounts] = value; + index[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_table_to_sparse(bigTable, index, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(bigTable); + free(index); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void marginal_spPot_to_spPot(const mxArray *bigPot, mxArray *smallPot, const int maximize){ + int i, j, count, bdim, sdim, NB, NS, NZB, position, bindex, sindex, nzCounts=0; + int *mask, *sequence, *result, *bir, *bjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *sTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + if(sdim == 0){ + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + *spr = 0; + if(maximize){ + for(i=0; i<NZB; i++){ + *spr = (*spr < bpr[i])? bpr[i] : *spr; + } + } + else{ + for(i=0; i<NZB; i++){ + *spr += bpr[i]; + } + } + return; + } + + mask = malloc(sdim * sizeof(int)); + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + + sTable = malloc(NZB * sizeof(double)); + sequence = malloc(NZB * 2 * sizeof(double)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++){ + sTable[i] = 0; + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sequence, nzCounts, sizeof(int)*2, compare); + if(result){ + position = (result - sequence) / 2; + if(maximize) + sTable[position] = (sTable[position] < bpr[i]) ? bpr[i] : sTable[position]; + else sTable[position] += bpr[i]; + } + else { + if(maximize) + sTable[nzCounts] = (sTable[nzCounts] < bpr[i]) ? bpr[i] : sTable[nzCounts]; + else sTable[nzCounts] += bpr[i]; + sequence[count] = sindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(smallPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(sTable, sequence, nzCounts, NS); + mxSetField(smallPot, 0, "T", pTemp); + + free(sTable); + free(sequence); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void divide_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex; + int *samemask, *diffmask, *rir, *rjc, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *weight; + double *pbDomain, *psDomain, *pbSize, *psSize, *rpr, *spr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + pTemp = mxCreateSparse(NB, 1, NB, mxREAL); + mxSetField(bigPot, 0, "T", pTemp); + rpr = mxGetPr(pTemp); + rir = mxGetIr(pTemp); + rjc = mxGetJc(pTemp); + rjc[0] = 0; + rjc[1] = NB; + value = *spr; + if(value == 0) value = 1; + for(i=0; i<NB; i++){ + rpr[i] = 1 / value; + rir[i] = i; + } + return; + } + + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + + pTemp = mxCreateSparse(NB, 1, NB, mxREAL); + rpr = mxGetPr(pTemp); + rir = mxGetIr(pTemp); + rjc = mxGetJc(pTemp); + rjc[0] = 0; + rjc[1] = NB; + for(i=0; i<NB; i++){ + rpr[i] = 1; + rir[i] = i; + } + + NZB = ND * NZS; + + diffdim = bdim - sdim; + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + rpr[bindex] = 1 / (spr[i]); + } + } + + pTemp1 = mxGetField(bigPot, 0, "T"); + if(pTemp1)mxDestroyArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void divide_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex; + int *mask, *result, *bir, *sir, *bjc, *sjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp1 = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp1); + bir = mxGetIr(pTemp1); + bjc = mxGetJc(pTemp1); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + if(sdim == 0){ + value = *spr; + if(value == 0)value = 1; + for(i=0; i<NZB; i++){ + bpr[i] /= value; + } + return; + } + + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + bpr[i] /= spr[position]; + } + } + + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, j, loop, loops, nCliques, temp, count, parent, child, maximize, *distribute_order; + double *pr, *pr1; + mxArray *pTemp, *pPreCh, *pClpot, *pSeppot; + + pTemp = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pTemp); + loops = nCliques - 1; + pTemp = mxGetField(prhs[0], 0, "maximize"); + maximize = (int)mxGetScalar(pTemp); + + distribute_order = malloc(2 * loops * sizeof(int)); + pTemp = mxGetField(prhs[0], 0, "preorder"); + pr = mxGetPr(pTemp); + pPreCh = mxGetField(prhs[0], 0, "preorder_children"); + count = 0; + for(i=0; i<nCliques; i++){ + temp = (int)pr[i] - 1; + pTemp = mxGetCell(pPreCh, temp); + pr1 = mxGetPr(pTemp); + loop = mxGetNumberOfElements(pTemp); + for(j=0; j<loop; j++){ + distribute_order[count] = temp; + distribute_order[count + loops] = (int)pr1[j] - 1; + count++; + } + } + + plhs[0] = mxDuplicateArray(prhs[1]); + plhs[1] = mxDuplicateArray(prhs[2]); + + for(loop=0; loop<loops; loop++){ + parent = distribute_order[loop]; + child = distribute_order[loop+loops]; + i = nCliques * child + parent; + pClpot = mxGetCell(plhs[0], child); + pTemp = mxGetField(pClpot, 0, "T"); + pSeppot = mxGetCell(plhs[1], i); + if(pTemp) + divide_spPot_by_spPot(pClpot, pSeppot); + else divide_null_by_spPot(pClpot, pSeppot); + + pClpot = mxGetCell(plhs[0], parent); + marginal_spPot_to_spPot(pClpot, pSeppot, maximize); + mxSetCell(plhs[1], i, pSeppot); + + pClpot = mxGetCell(plhs[0], child); + multiply_spPot_by_spPot(pClpot, pSeppot); + } + free(distribute_order); +} diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot.c new file mode 100644 index 00000000..5d0ed8a3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot.c @@ -0,0 +1,637 @@ +/* C mex init_pot for in @jtree_sparse_inf_engine directory */ +/* The file enter_evidence.m in directory @jtree_sparse_inf_engine call it*/ + +/**************************************/ +/* init_pot.c has 6 input & 2 output */ +/* engine */ +/* clqs */ +/* pots */ +/* pot_type */ +/* onodes */ +/* ndx */ +/* */ +/* clpot */ +/* seppot */ +/**************************************/ +#include <math.h> +#include <search.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +mxArray* convert_to_sparse(const double *table, const int NB, const int counts){ + mxArray *spTable; + int i, k, *ir, *jc; + double *sr; + + spTable = mxCreateSparse(NB, 1, counts, mxREAL); + sr = mxGetPr(spTable); + ir = mxGetIr(spTable); + jc = mxGetJc(spTable); + + k = 0; + jc[0] = 0; + jc[1] = counts; + for(i=0; i<NB; i++){ + if(table[i] != 0.0){ + sr[k] = table[i]; + ir[k] = i; + k++; + } + } + + return spTable; +} + +mxArray* convert_table_to_sparse(const double *bT, const int *index, const int nzCounts, const int NB){ + mxArray *spTable; + int i, *irs, *jcs; + double *sr; + + spTable = mxCreateSparse(NB, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + sr[i] = bT[i]; + irs[i] = index[i]; + } + return spTable; +} + +mxArray* convert_ill_table_to_sparse(const double *bigTable, const int *sequence, const int nzCounts, const int NB){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(NB, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = bigTable[temp]; + count++; + } + return spTable; +} + +void multiply_null_by_fuPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, NB, NS, siz_b, siz_s, ndim, nzCounts=0; + int *mask, *sx, *sy, *cpsy, *subs, *s, *cpsy2, *jc; + double *pbDomain, *psDomain, *pbSize, *psSize, *bTable, *sTable, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + siz_b = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + siz_s = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<siz_b; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<siz_s; i++){ + NS *= (int)psSize[i]; + } + + pTemp = mxGetField(smallPot, 0, "T"); + sTable = mxGetPr(pTemp); + bTable = malloc(NB * sizeof(double)); + for(i=0; i<NB; i++){ + bTable[i] = 0; + } + + if(NS == 1){ + value = *sTable; + for(i=0; i<NB; i++){ + bTable[i] = value; + } + nzCounts = NB; + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_to_sparse(bTable, NB, NB); + mxSetField(bigPot, 0, "T", pTemp); + free(bTable); + return; + } + + if(NS == NB){ + for(i=0; i<NB; i++){ + bTable[i] = sTable[i]; + if(sTable[i] != 0) nzCounts++; + } + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_to_sparse(bTable, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp); + free(bTable); + return; + } + + mask = malloc(siz_s * sizeof(int)); + count = 0; + for(i=0; i<siz_s; i++){ + for(j=0; j<siz_b; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + ndim = siz_b; + sx = (int *)malloc(sizeof(int)*ndim); + sy = (int *)malloc(sizeof(int)*ndim); + for(i=0; i<ndim; i++){ + sx[i] = (int)pbSize[i]; + sy[i] = 1; + } + for(i=0; i<count; i++){ + sy[mask[i]] = sx[mask[i]]; + } + + s = (int *)malloc(sizeof(int)*ndim); + *(cpsy = (int *)malloc(sizeof(int)*ndim)) = 1; + subs = (int *)malloc(sizeof(int)*ndim); + cpsy2 = (int *)malloc(sizeof(int)*ndim); + for(i = 0; i < ndim; i++){ + subs[i] = 0; + s[i] = sx[i] - 1; + } + + for(i = 0; i < ndim-1; i++){ + cpsy[i+1] = cpsy[i]*sy[i]--; + cpsy2[i] = cpsy[i]*sy[i]; + } + cpsy2[ndim-1] = cpsy[ndim-1]*(--sy[ndim-1]); + + for(j=0; j<NB; j++){ + bTable[j] = *sTable; + if(*sTable != 0.0) nzCounts++; + for(i = 0; i < ndim; i++){ + if(subs[i] == s[i]){ + subs[i] = 0; + if(sy[i]) + sTable -= cpsy2[i]; + } + else{ + subs[i]++; + if(sy[i]) + sTable += cpsy[i]; + break; + } + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_to_sparse(bTable, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp); + pTemp1 = mxGetField(bigPot, 0, "T"); + jc = mxGetJc(pTemp1); + + free(sx); + free(sy); + free(s); + free(cpsy); + free(subs); + free(cpsy2); + free(mask); + free(bTable); +} + +void multiply_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex, nzCounts=0; + int *samemask, *diffmask, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *sequence, *weight; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *spr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + if(ND == 1){ + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp1 = mxGetField(smallPot, 0, "T"); + pTemp = mxDuplicateArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + return; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + NZB = ND * NZS; + + diffdim = bdim - sdim; + sequence = malloc(NZB * 2 * sizeof(int)); + bigTable = malloc(NZB * sizeof(double)); + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + bigTable[nzCounts] = spr[i]; + sequence[count] = bindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(bigTable, sequence, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(sequence); + free(bigTable); + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void multiply_spPot_by_fuPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, bindex, sindex, nzCounts=0; + int *mask, *index, *bir, *bjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + + bigTable = malloc(NZB * sizeof(double)); + index = malloc(NZB * sizeof(double)); + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++){ + bigTable[i] = 0; + } + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + value = spr[sindex]; + if(value != 0){ + bigTable[nzCounts] = bpr[i] * value; + index[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_table_to_sparse(bigTable, index, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(bigTable); + free(index); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *index, *result, *bir, *sir, *bjc, *sjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + bigTable = malloc(NZB * sizeof(double)); + index = malloc(NZB * sizeof(double)); + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++){ + bigTable[i] = 0; + } + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + value = bpr[i]; + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + value *= spr[position]; + bigTable[nzCounts] = value; + index[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_table_to_sparse(bigTable, index, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(bigTable); + free(index); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, j, c, loop, nNodes, nCliques, ndomain, dims[2]; + double *pClqs, *pr, *pt, *pSize; + mxArray *pTemp, *pTemp1, *pStruct, *pCliques, *pBigpot, *pSmallpot; + const char *field_names[] = {"domain", "T", "sizes"}; + + nNodes = mxGetNumberOfElements(prhs[1]); + pCliques = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pCliques); + pTemp = mxGetField(prhs[0], 0, "eff_node_sizes"); + pSize = mxGetPr(pTemp); + + plhs[0] = mxCreateCellArray(1, &nCliques); + for(i=0; i<nCliques; i++){ + pStruct = mxCreateStructMatrix(1, 1, 3, field_names); + mxSetCell(plhs[0], i, pStruct); + pTemp = mxGetCell(pCliques, i); + ndomain = mxGetNumberOfElements(pTemp); + pt = mxGetPr(pTemp); + pTemp1 = mxDuplicateArray(pTemp); + mxSetField(pStruct, 0, "domain", pTemp1); + + pTemp = mxCreateDoubleMatrix(1, ndomain, mxREAL); + mxSetField(pStruct, 0, "sizes", pTemp); + pr = mxGetPr(pTemp); + for(j=0; j<ndomain; j++){ + pr[j] = pSize[(int)pt[j]-1]; + } + } + + pClqs = mxGetPr(prhs[1]); + for(loop=0; loop<nNodes; loop++){ + c = (int)pClqs[loop] - 1; + pSmallpot = mxGetCell(prhs[2], loop); + pTemp = mxGetField(pSmallpot, 0, "T"); + pBigpot = mxGetCell(plhs[0], c); + pTemp1 = mxGetField(pBigpot, 0, "T"); + if(pTemp1){ + if(mxIsSparse(pTemp)) + multiply_spPot_by_spPot(pBigpot, pSmallpot); + else multiply_spPot_by_fuPot(pBigpot, pSmallpot); + } + else{ + if(mxIsSparse(pTemp)) + multiply_null_by_spPot(pBigpot, pSmallpot); + else multiply_null_by_fuPot(pBigpot, pSmallpot); + } + } + + dims[0] = nCliques; + dims[1] = nCliques; + plhs[1] = mxCreateCellArray(2, dims); +} + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot1.c b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot1.c new file mode 100644 index 00000000..b3a6a66d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot1.c @@ -0,0 +1,636 @@ +/* C mex init_pot for in @jtree_sparse_inf_engine directory */ +/* The file enter_evidence.m in directory @jtree_sparse_inf_engine call it*/ + +/**************************************/ +/* init_pot.c has 6 input & 2 output */ +/* engine */ +/* clqs */ +/* pots */ +/* pot_type */ +/* onodes */ +/* ndx */ +/* */ +/* clpot */ +/* seppot */ +/**************************************/ +#include <math.h> +#include <search.h> +#include "mex.h" + +int compare(const void* src1, const void* src2){ + int i1 = *(int*)src1 ; + int i2 = *(int*)src2 ; + return i1-i2 ; +} + +void ind_subv(int index, const int *cumprod, int n, int *bsubv){ + int i; + + for (i = n-1; i >= 0; i--) { + bsubv[i] = ((int)floor(index / cumprod[i])); + index = index % cumprod[i]; + } +} + +int subv_ind(const int n, const int *cumprod, const int *subv){ + int i, index=0; + + for(i=0; i<n; i++){ + index += subv[i] * cumprod[i]; + } + return index; +} + +void compute_fixed_weight(int *weight, const double *pbSize, const int *dmask, const int *bCumprod, const int ND, const int diffdim){ + int i, j; + int *eff_cumprod, *subv, *diffsize, *diff_cumprod; + + subv = malloc(diffdim * sizeof(int)); + eff_cumprod = malloc(diffdim * sizeof(int)); + diffsize = malloc(diffdim * sizeof(int)); + diff_cumprod = malloc(diffdim * sizeof(int)); + for(i=0; i<diffdim; i++){ + eff_cumprod[i] = bCumprod[dmask[i]]; + diffsize[i] = (int)pbSize[dmask[i]]; + } + diff_cumprod[0] = 1; + for(i=0; i<diffdim-1; i++){ + diff_cumprod[i+1] = diff_cumprod[i] * diffsize[i]; + } + for(i=0; i<ND; i++){ + ind_subv(i, diff_cumprod, diffdim, subv); + weight[i] = 0; + for(j=0; j<diffdim; j++){ + weight[i] += eff_cumprod[j] * subv[j]; + } + } + free(eff_cumprod); + free(subv); + free(diffsize); + free(diff_cumprod); +} + +void reset_nzmax(mxArray *spArray, const int old_nzmax, const int new_nzmax){ + double *ptr; + void *newptr; + int *ir, *jc; + int nbytes; + + if(new_nzmax == old_nzmax) return; + nbytes = new_nzmax * sizeof(*ptr); + ptr = mxGetPr(spArray); + newptr = mxRealloc(ptr, nbytes); + mxSetPr(spArray, newptr); + nbytes = new_nzmax * sizeof(*ir); + ir = mxGetIr(spArray); + newptr = mxRealloc(ir, nbytes); + mxSetIr(spArray, newptr); + jc = mxGetJc(spArray); + jc[0] = 0; + jc[1] = new_nzmax; + mxSetNzmax(spArray, new_nzmax); +} + +mxArray* convert_table_to_sparse(const double *bT, const int *index, const int nzCounts, const int NB){ + mxArray *spTable; + int i, *irs, *jcs; + double *sr; + + spTable = mxCreateSparse(NB, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + sr[i] = bT[i]; + irs[i] = index[i]; + } + return spTable; +} + +mxArray* convert_ill_table_to_sparse(const double *bigTable, const int *sequence, const int nzCounts, const int NB){ + mxArray *spTable; + int i, temp, *irs, *jcs, count=0; + double *sr; + + spTable = mxCreateSparse(NB, 1, nzCounts, mxREAL); + sr = mxGetPr(spTable); + irs = mxGetIr(spTable); + jcs = mxGetJc(spTable); + + jcs[0] = 0; + jcs[1] = nzCounts; + + for(i=0; i<nzCounts; i++){ + irs[i] = sequence[count]; + count++; + temp = sequence[count]; + sr[i] = bigTable[temp]; + count++; + } + return spTable; +} + +void multiply_null_by_fuPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, NB, NS, siz_b, siz_s, ndim, nzCounts=0; + int *mask, *sx, *sy, *cpsy, *subs, *s, *cpsy2, *bir, *bjc; + double *pbDomain, *psDomain, *pbSize, *psSize, *spr, *bpr, value; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + siz_b = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + siz_s = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<siz_b; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<siz_s; i++){ + NS *= (int)psSize[i]; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + + pTemp1 = mxCreateSparse(NB, 1, NB, mxREAL); + bpr = mxGetPr(pTemp1); + bir = mxGetIr(pTemp1); + bjc = mxGetJc(pTemp1); + bjc[0] = 0; + bjc[1] = NB; + + if(NS == 1){ + value = *spr; + for(i=0; i<NB; i++){ + bpr[i] = value; + bir[i] = i; + } + nzCounts = NB; + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + return; + } + + if(NS == NB){ + for(i=0; i<NB; i++){ + if(spr[i] != 0){ + bpr[nzCounts] = spr[i]; + bir[nzCounts] = i; + nzCounts++; + } + } + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + return; + } + + mask = malloc(siz_s * sizeof(int)); + count = 0; + for(i=0; i<siz_s; i++){ + for(j=0; j<siz_b; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + ndim = siz_b; + sx = (int *)malloc(sizeof(int)*ndim); + sy = (int *)malloc(sizeof(int)*ndim); + for(i=0; i<ndim; i++){ + sx[i] = (int)pbSize[i]; + sy[i] = 1; + } + for(i=0; i<count; i++){ + sy[mask[i]] = sx[mask[i]]; + } + + s = (int *)malloc(sizeof(int)*ndim); + *(cpsy = (int *)malloc(sizeof(int)*ndim)) = 1; + subs = (int *)malloc(sizeof(int)*ndim); + cpsy2 = (int *)malloc(sizeof(int)*ndim); + for(i = 0; i < ndim; i++){ + subs[i] = 0; + s[i] = sx[i] - 1; + } + + for(i = 0; i < ndim-1; i++){ + cpsy[i+1] = cpsy[i]*sy[i]--; + cpsy2[i] = cpsy[i]*sy[i]; + } + cpsy2[ndim-1] = cpsy[ndim-1]*(--sy[ndim-1]); + + for(j=0; j<NB; j++){ + if(*spr != 0){ + bpr[nzCounts] = *spr; + bir[nzCounts] = j; + nzCounts++; + } + for(i = 0; i < ndim; i++){ + if(subs[i] == s[i]){ + subs[i] = 0; + if(sy[i]) + spr -= cpsy2[i]; + } + else{ + subs[i]++; + if(sy[i]) + spr += cpsy[i]; + break; + } + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + reset_nzmax(pTemp1, NB, nzCounts); + mxSetField(bigPot, 0, "T", pTemp1); + + free(sx); + free(sy); + free(s); + free(cpsy); + free(subs); + free(cpsy2); + free(mask); +} + +void multiply_null_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, count1, match, temp, bdim, sdim, diffdim, NB, NS, ND, NZB, NZS, bindex, sindex, nzCounts=0; + int *samemask, *diffmask, *sir, *sjc, *bCumprod, *sCumprod, *ssubv, *sequence, *weight; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *spr; + mxArray *pTemp, *pTemp1; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + NS = 1; + for(i=0; i<sdim; i++){ + NS *= (int)psSize[i]; + } + ND = NB / NS; + + if(ND == 1){ + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp1 = mxGetField(smallPot, 0, "T"); + pTemp = mxDuplicateArray(pTemp1); + mxSetField(bigPot, 0, "T", pTemp); + return; + } + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + NZB = ND * NZS; + + diffdim = bdim - sdim; + sequence = malloc(NZB * 2 * sizeof(int)); + bigTable = malloc(NZB * sizeof(double)); + samemask = malloc(sdim * sizeof(int)); + diffmask = malloc(diffdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + weight = malloc(ND * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + count1 = 0; + for(i=0; i<bdim; i++){ + match = 0; + for(j=0; j<sdim; j++){ + if(pbDomain[i] == psDomain[j]){ + samemask[count] = i; + match = 1; + count++; + break; + } + } + if(match == 0){ + diffmask[count1] = i; + count1++; + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + count = 0; + compute_fixed_weight(weight, pbSize, diffmask, bCumprod, ND, diffdim); + for(i=0; i<NZS; i++){ + sindex = sir[i]; + ind_subv(sindex, sCumprod, sdim, ssubv); + temp = 0; + for(j=0; j<sdim; j++){ + temp += ssubv[j] * bCumprod[samemask[j]]; + } + for(j=0; j<ND; j++){ + bindex = weight[j] + temp; + bigTable[nzCounts] = spr[i]; + sequence[count] = bindex; + count++; + sequence[count] = nzCounts; + nzCounts++; + count++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + qsort(sequence, nzCounts, sizeof(int) * 2, compare); + pTemp = convert_ill_table_to_sparse(bigTable, sequence, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(sequence); + free(bigTable); + free(samemask); + free(diffmask); + free(bCumprod); + free(sCumprod); + free(weight); + free(ssubv); +} + +void multiply_spPot_by_fuPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, bindex, sindex, nzCounts=0; + int *mask, *index, *bir, *bjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + + bigTable = malloc(NZB * sizeof(double)); + index = malloc(NZB * sizeof(double)); + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + value = spr[sindex]; + if(value != 0){ + bigTable[nzCounts] = bpr[i] * value; + index[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_table_to_sparse(bigTable, index, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(bigTable); + free(index); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + +void multiply_spPot_by_spPot(mxArray *bigPot, const mxArray *smallPot){ + int i, j, count, bdim, sdim, NB, NZB, NZS, position, bindex, sindex, nzCounts=0; + int *mask, *index, *result, *bir, *sir, *bjc, *sjc, *bCumprod, *sCumprod, *bsubv, *ssubv; + double *bigTable, *pbDomain, *psDomain, *pbSize, *psSize, *bpr, *spr, value; + mxArray *pTemp; + + pTemp = mxGetField(bigPot, 0, "domain"); + pbDomain = mxGetPr(pTemp); + bdim = mxGetNumberOfElements(pTemp); + pTemp = mxGetField(smallPot, 0, "domain"); + psDomain = mxGetPr(pTemp); + sdim = mxGetNumberOfElements(pTemp); + + pTemp = mxGetField(bigPot, 0, "sizes"); + pbSize = mxGetPr(pTemp); + pTemp = mxGetField(smallPot, 0, "sizes"); + psSize = mxGetPr(pTemp); + + NB = 1; + for(i=0; i<bdim; i++){ + NB *= (int)pbSize[i]; + } + + pTemp = mxGetField(bigPot, 0, "T"); + bpr = mxGetPr(pTemp); + bir = mxGetIr(pTemp); + bjc = mxGetJc(pTemp); + NZB = bjc[1]; + + pTemp = mxGetField(smallPot, 0, "T"); + spr = mxGetPr(pTemp); + sir = mxGetIr(pTemp); + sjc = mxGetJc(pTemp); + NZS = sjc[1]; + + bigTable = malloc(NZB * sizeof(double)); + index = malloc(NZB * sizeof(double)); + mask = malloc(sdim * sizeof(int)); + bCumprod = malloc(bdim * sizeof(int)); + sCumprod = malloc(sdim * sizeof(int)); + bsubv = malloc(bdim * sizeof(int)); + ssubv = malloc(sdim * sizeof(int)); + + for(i=0; i<NZB; i++){ + bigTable[i] = 0; + } + count = 0; + for(i=0; i<sdim; i++){ + for(j=0; j<bdim; j++){ + if(psDomain[i] == pbDomain[j]){ + mask[count] = j; + count++; + break; + } + } + } + + bCumprod[0] = 1; + for(i=0; i<bdim-1; i++){ + bCumprod[i+1] = bCumprod[i] * (int)pbSize[i]; + } + sCumprod[0] = 1; + for(i=0; i<sdim-1; i++){ + sCumprod[i+1] = sCumprod[i] * (int)psSize[i]; + } + + for(i=0; i<NZB; i++){ + value = bpr[i]; + bindex = bir[i]; + ind_subv(bindex, bCumprod, bdim, bsubv); + for(j=0; j<sdim; j++){ + ssubv[j] = bsubv[mask[j]]; + } + sindex = subv_ind(sdim, sCumprod, ssubv); + result = (int *) bsearch(&sindex, sir, NZS, sizeof(int), compare); + if(result){ + position = result - sir; + value *= spr[position]; + bigTable[nzCounts] = value; + index[nzCounts] = bindex; + nzCounts++; + } + } + + pTemp = mxGetField(bigPot, 0, "T"); + if(pTemp)mxDestroyArray(pTemp); + pTemp = convert_table_to_sparse(bigTable, index, nzCounts, NB); + mxSetField(bigPot, 0, "T", pTemp); + + free(bigTable); + free(index); + free(mask); + free(bCumprod); + free(sCumprod); + free(bsubv); + free(ssubv); +} + + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ + int i, j, c, loop, nNodes, nCliques, ndomain, dims[2]; + double *pClqs, *pr, *pt, *pSize; + mxArray *pTemp, *pTemp1, *pStruct, *pCliques, *pBigpot, *pSmallpot; + const char *field_names[] = {"domain", "T", "sizes"}; + + nNodes = mxGetNumberOfElements(prhs[1]); + pCliques = mxGetField(prhs[0], 0, "cliques"); + nCliques = mxGetNumberOfElements(pCliques); + pTemp = mxGetField(prhs[0], 0, "eff_node_sizes"); + pSize = mxGetPr(pTemp); + + plhs[0] = mxCreateCellArray(1, &nCliques); + for(i=0; i<nCliques; i++){ + pStruct = mxCreateStructMatrix(1, 1, 3, field_names); + mxSetCell(plhs[0], i, pStruct); + pTemp = mxGetCell(pCliques, i); + ndomain = mxGetNumberOfElements(pTemp); + pt = mxGetPr(pTemp); + pTemp1 = mxDuplicateArray(pTemp); + mxSetField(pStruct, 0, "domain", pTemp1); + + pTemp = mxCreateDoubleMatrix(1, ndomain, mxREAL); + mxSetField(pStruct, 0, "sizes", pTemp); + pr = mxGetPr(pTemp); + for(j=0; j<ndomain; j++){ + pr[j] = pSize[(int)pt[j]-1]; + } + } + + pClqs = mxGetPr(prhs[1]); + for(loop=0; loop<nNodes; loop++){ + c = (int)pClqs[loop] - 1; + pSmallpot = mxGetCell(prhs[2], loop); + pTemp = mxGetField(pSmallpot, 0, "T"); + pBigpot = mxGetCell(plhs[0], c); + pTemp1 = mxGetField(pBigpot, 0, "T"); + if(pTemp1){ + if(mxIsSparse(pTemp)) + multiply_spPot_by_spPot(pBigpot, pSmallpot); + else multiply_spPot_by_fuPot(pBigpot, pSmallpot); + } + else{ + if(mxIsSparse(pTemp)) + multiply_null_by_spPot(pBigpot, pSmallpot); + else multiply_null_by_fuPot(pBigpot, pSmallpot); + } + } + + dims[0] = nCliques; + dims[1] = nCliques; + plhs[1] = mxCreateCellArray(2, dims); +} + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot1.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot1.m new file mode 100644 index 00000000..857e6266 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/old/init_pot1.m @@ -0,0 +1,20 @@ +function [clpot, seppot] = init_pot(engine, clqs, pots, pot_type, onodes, ndx) +% INIT_POT Initialise potentials with evidence (jtree_inf) +% function [clpot, seppot] = init_pot(engine, clqs, pots, pot_type, onodes) + +cliques = engine.cliques; +bnet = bnet_from_engine(engine); +% Set the clique potentials to all 1s +C = length(cliques); +clpot = cell(1,C); +for i=1:C + clpot{i} = mk_initial_pot(pot_type, cliques{i}, bnet.node_sizes(:), bnet.cnodes(:), onodes); +end + +% Multiply on specified potentials +for i=1:length(clqs) + c = clqs(i); + clpot{c} = multiply_by_pot(clpot{c}, pots{i}); +end + +seppot = cell(C,C); % implicitely initialized to 1 diff --git a/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/set_fields.m b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/set_fields.m new file mode 100644 index 00000000..e75cfa45 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@jtree_sparse_inf_engine/set_fields.m @@ -0,0 +1,13 @@ +function engine = set_fields(engine, varargin) +% SET_FIELDS Set the fields for a generic engine +% engine = set_fields(engine, name/value pairs) +% +% e.g., engine = set_fields(engine, 'maximize', 1) + +args = varargin; +nargs = length(args); +for i=1:2:nargs + switch args{i}, + case 'maximize', engine.maximize = args{i+1}; + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Entries new file mode 100644 index 00000000..c9482cbd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/likelihood_weighting_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Repository new file mode 100644 index 00000000..e39429d7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@likelihood_weighting_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/enter_evidence.m new file mode 100644 index 00000000..62e252aa --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/enter_evidence.m @@ -0,0 +1,39 @@ +function [engine, ll] = enter_evidence(engine, evidence, nsamples) +% ENTER_EVIDENCE Add the specified evidence to the network (likelihood_weighting) +% [engine, ll] = enter_evidence(engine, evidence, nsamples) +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% If nsamples is not specified, the value specified when the engine was created will be used. +% ll (log-likelihood) is set to []. + +ll = []; +if nargin < 3, nsamples = engine.nsamples; end + +bnet = bnet_from_engine(engine); +N = length(bnet.dag); +samples = cell(nsamples, N); +weights = zeros(1, nsamples); + +ns = bnet.node_sizes; +original_evidence = evidence; +observed = ~isemptycell(original_evidence); +for s=1:nsamples + evidence = original_evidence(:); % must be a column vector + w = 1; + for i=1:N + ps = parents(bnet.dag, i); + e = bnet.equiv_class(i); + if observed(i) + p = exp(log_prob_node(bnet.CPD{e}, evidence(i), evidence(ps))); + w = w * p; + else + x = sample_node(bnet.CPD{e}, evidence(ps)); + evidence{i} = x; + end + end + samples(s,:) = evidence; + weights(s) = w; +end + +engine.samples = samples; +engine.weights = weights; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/likelihood_weighting_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/likelihood_weighting_inf_engine.m new file mode 100644 index 00000000..eb1794fa --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/likelihood_weighting_inf_engine.m @@ -0,0 +1,25 @@ +function engine = likelihood_weighting_inf_engine(bnet, varargin) +% LIKELIHOOD_WEIGHTING_INF_ENGINE +% engine = likelihood_weighting_inf_engine(bnet, ...) +% +% Optional arguments [defaults] +% nsamples - [500] + +nsamples = 500; + +if nargin >= 2 + args = varargin; + nargs = length(args); + for i=1:2:nargs + switch args{i}, + case 'nsamples', nsamples= args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + +engine.nsamples = nsamples; +engine.samples = []; +engine.weights = []; +engine = class(engine, 'likelihood_weighting_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..d00ee606 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@likelihood_weighting_inf_engine/marginal_nodes.m @@ -0,0 +1,53 @@ +function marginal = marginal_nodes(engine, nodes) +% MARGINAL_NODES Compute the marginal on the specified query nodes (likelihood_weighting) +% marginal = marginal_nodes(engine, nodes) + +bnet = bnet_from_engine(engine); +ddom = myintersect(nodes, bnet.dnodes); +cdom = myintersect(nodes, bnet.cnodes); +nsamples = size(engine.samples, 1); +ns = bnet.node_sizes; + +%w = normalise(engine.weights); +w = engine.weights; +if mysubset(nodes, ddom) + T = 0*myones(ns(nodes)); + P = prod(ns(nodes)); + indices = ind2subv(ns(nodes), 1:P); + samples = reshape(cat(1, engine.samples{:,nodes}), nsamples, length(nodes)); + for j = 1:P + rows = find_rows(samples, indices(j,:)); + T(j) = sum(w(rows)); + end + T = normalise(T); + marginal.T = T; +elseif subset(nodes, cdom) + samples = reshape(cat(1, engine.samples{:,nodes}), nsamples*sum(ns(nodes)), length(nodes)); + [marginal.mu, marginal.Sigma] = wstats(samples', normalise(w)); +else + error('can''t handle mixed marginals yet'); +end + +marginal.domain = nodes; + +%%%%%%%%% + +function rows = find_rows(M, v) +% FINDROWS Find rows which are equal to a specified vector +% rows = findrows(M, v) +% Each row of M is a sample + +temp = abs(M - repmat(v, size(M, 1), 1)); +rows = find(sum(temp,2) == 0); + +%%%%%%%% + +function [mu, Sigma] = wstats(X, w) + +% Computes the weighted mean and weighted covariance matrix for a given +% set of observations X(:,i), and a set of normalised weights w(i). +% Each column of X is a sample. + +d = X - repmat(X * w', 1, size(X, 2)); +mu = sum(X .* repmat(w, size(X, 1), 1), 2); +Sigma = d * diag(w) * d'; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Entries new file mode 100644 index 00000000..50ed260c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Entries @@ -0,0 +1,7 @@ +/bethe_free_energy.m/1.1.1.1/Sun Jul 6 20:57:18 2003// +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/loopy_converged.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_family.m/1.1.1.1/Fri Oct 18 20:05:16 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/pearl_inf_engine.m/1.1.1.1/Sat Jan 11 18:53:28 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..b2cd71e0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Repository new file mode 100644 index 00000000..d88c6406 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@pearl_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/bethe_free_energy.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/bethe_free_energy.m new file mode 100644 index 00000000..67495fd0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/bethe_free_energy.m @@ -0,0 +1,50 @@ +function loglik = bethe_free_energy(engine, evidence) +% BETHE_FREE_ENERGY Compute Bethe free energy approximation to the log likelihood +% loglik = bethe_free_energy(engine, evidence) +% +% The Bethe free energy is given by an exact energy term and an approximate entropy term. +% Energy +% E = -sum_f sum_i b(f,i) ln theta(f,i) +% where b(f,i) = approximate Pr(family f = i) +% and theta(f,i) = Pr(f = i) +% Entropy +% S = H1 - H2 +% H1 = sum_f sum_p H(b(f)) +% where b(f) = belief on family f, H(.) = entropy +% H2 = sum_n (q(n)-1) H(b(n)) +% where q(n) = num. neighbors of n +% +% This function was written by Yair Weiss, 8/22/01. + +hidden = find(isemptycell(evidence)); +bnet = bnet_from_engine(engine); +N = length(bnet.dag); + +add_ev = 1; +E=0;H1=0;H2=0; +loglik=0; +for n=1:N + ps=parents(bnet.dag,n); + if (length(ps)==0) % root node + qi=length(children(bnet.dag,n))-1; + else + qi=length(children(bnet.dag,n)); + end + bf = marginal_family(engine, n, add_ev); + bf = bf.T(:); + e = bnet.equiv_class(n); + T = CPD_to_CPT(bnet.CPD{e}); + T = T(:); + E = E-sum(log(T+(T==0)).*bf); + + if length(ps) > 0 + % root nodes don't count as fmailies + H1 = H1+sum(log(bf+(bf==0)).*bf); + end + + bi = marginal_nodes(engine, n, add_ev); + bi = bi.T(:); + H2 = H2+qi*sum(log(bi+(bi==0)).*bi); +end +loglik=E+H1-H2; +loglik=-loglik; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/enter_evidence.m new file mode 100644 index 00000000..65e45b15 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/enter_evidence.m @@ -0,0 +1,153 @@ +function [engine, loglik, niter] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (pearl) +% [engine, loglik, num_iter] = enter_evidence(engine, evidence, ...) +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) +% +% The following optional arguments can be specified in the form of name/value pa irs: +% [default value in brackets] +% +% maximize - if 1, does max-product instead of sum-product [0] +% 'filename' - msgs will be printed to this file, so you can assess convergence while it runs [engine.filename] +% +% e.g., engine = enter_evidence(engine, ev, 'maximize', 1) +% +% For discrete nodes, loglik is the negative Bethe free energy evaluated at the final beliefs. +% For Gaussian nodes, loglik is currently always 0. +% +% 'num_iter' returns the number of iterations used. + +maximize = 0; +filename = engine.filename; + +% parse optional params +args = varargin; +nargs = length(args); +if nargs > 0 + for i=1:2:nargs + switch args{i}, + case 'maximize', maximize = args{i+1}; + case 'filename', filename = args{i+1}; + otherwise, + error(['invalid argument name ' args{i}]); + end + end +end + + +if maximize + error('can''t handle max-prop yet') +end + +engine.maximize = maximize; +engine.filename = filename; +engine.bel = []; % reset if necessary + +bnet = bnet_from_engine(engine); +N = length(bnet.dag); +ns = bnet.node_sizes(:); + +observed_bitv = ~isemptycell(evidence); +disconnected = find(engine.disconnected_nodes_bitv); +if ~all(observed_bitv(disconnected)) + error(['The following discrete nodes must be observed: ' num2str(disconnected)]) +end +msg = init_pearl_msgs(engine.msg_type, engine.msg_dag, ns, evidence); + +niter = 1; +switch engine.protocol + case 'parallel', [msg, niter] = parallel_protocol(engine, evidence, msg); + case 'tree', msg = tree_protocol(engine, evidence, msg); + otherwise, + error(['unrecognized protocol ' engine.protocol]) +end +engine.niter = niter; + +engine.marginal = cell(1,N); +nodes = find(~engine.disconnected_nodes_bitv); +for n=nodes(:)' + engine.marginal{n} = compute_bel(engine.msg_type, msg{n}.pi, msg{n}.lambda); +end + +engine.evidence = evidence; % needed by marginal_nodes and marginal_family +engine.msg = msg; % needed by marginal_family + +if (nargout >= 2) + if (engine.msg_type == 'd') + loglik = bethe_free_energy(engine, evidence); + else + loglik = 0; + end +end + + + +%%%%%%%%%%% + +function msg = init_pearl_msgs(msg_type, dag, ns, evidence) +% INIT_MSGS Initialize the lambda/pi message and state vectors +% msg = init_msgs(dag, ns, evidence) +% + +N = length(dag); +msg = cell(1,N); +observed = ~isemptycell(evidence); +lam_msg = 1; + +for n=1:N + ps = parents(dag, n); + msg{n}.pi_from_parent = cell(1, length(ps)); + for i=1:length(ps) + p = ps(i); + msg{n}.pi_from_parent{i} = mk_msg(msg_type, ns(p)); + end + + cs = children(dag, n); + msg{n}.lambda_from_child = cell(1, length(cs)); + for i=1:length(cs) + c = cs(i); + msg{n}.lambda_from_child{i} = mk_msg(msg_type, ns(n), lam_msg); + end + + msg{n}.lambda = mk_msg(msg_type, ns(n), lam_msg); + msg{n}.pi = mk_msg(msg_type, ns(n)); + + if observed(n) + msg{n}.lambda_from_self = mk_msg_with_evidence(msg_type, ns(n), evidence{n}); + else + msg{n}.lambda_from_self = mk_msg(msg_type, ns(n), lam_msg); + end +end + + + +%%%%%%%%% + +function msg = mk_msg(msg_type, sz, is_lambda_msg) + +if nargin < 3, is_lambda_msg = 0; end + +switch msg_type + case 'd', msg = ones(sz, 1); + case 'g', + if is_lambda_msg + msg.precision = zeros(sz, sz); + msg.info_state = zeros(sz, 1); + else + msg.Sigma = zeros(sz, sz); + msg.mu = zeros(sz,1); + end +end + +%%%%%%%%%%%% + +function msg = mk_msg_with_evidence(msg_type, sz, val) + +switch msg_type + case 'd', + msg = zeros(sz, 1); + msg(val) = 1; + case 'g', + %msg.observed_val = val(:); + msg.precision = inf; + msg.mu = val(:); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/loopy_converged.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/loopy_converged.m new file mode 100644 index 00000000..fba4f2fd --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/loopy_converged.m @@ -0,0 +1,13 @@ +function niter = loopy_converged(engine) +% LOOPY_CONVERGED Did loopy belief propagation converge? 0 means no, eles we return the num. iterations. +% function niter = loopy_converged(engine) +% +% We use a simple heuristic: we say convergence occurred if the number of iterations +% used was less than the maximum allowed. + +if engine.niter == engine.max_iter + niter = 0; +else + niter = engine.niter; +end +%conv = (strcmp(engine.protocol, 'tree') | (engine.niter < engine.max_iter)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/marginal_family.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/marginal_family.m new file mode 100644 index 00000000..9226afda --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/marginal_family.m @@ -0,0 +1,80 @@ +function m = marginal_family(engine, n, add_ev) +% MARGINAL_FAMILY Compute the marginal on i's family (loopy) +% m = marginal_family(engine, n, add_ev) + +if nargin < 3, add_ev = 0; end + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +ps = parents(bnet.dag, n); +dom = [ps n]; +CPD = bnet.CPD{bnet.equiv_class(n)}; + +switch engine.msg_type + case 'd', + % The method is similar to the following HMM equation: + % xi(i,j,t) = normalise( alpha(i,t) * transmat(i,j) * obsmat(j,t+1) * beta(j,t+1) ) + % where xi(i,j,t) = Pr(Q(t)=i, Q(t+1)=j | y(1:T)) + % beta == lambda, alpha == pi, alpha from each parent = pi msg + % In general, if A,B are parents of C, + % P(A,B,C) = P(C|A,B) pi_msg(A->C) pi_msg(B->C) lambda(C) + % where lambda(C) = P(ev below and including C|C) = prod incoming lamba_msg(children->C) + % and pi_msg(X->C) = P(X|ev above) etc + + T = dpot(dom, ns(dom), CPD_to_CPT(CPD)); + for j=1:length(ps) + p = ps(j); + pi_msg = dpot(p, ns(p), engine.msg{n}.pi_from_parent{j}); + T = multiply_by_pot(T, pi_msg); + end + lambda = dpot(n, ns(n), engine.msg{n}.lambda); + T = multiply_by_pot(T, lambda); + T = normalize_pot(T); + m = pot_to_marginal(T); + if ~add_ev + m.T = shrink_obs_dims_in_table(m.T, dom, engine.evidence); + end + case 'g', + if engine.disconnected_nodes_bitv(n) + m.T = 1; + m.domain = dom; + if add_ev + m = add_ev_to_dmarginal(m, engine.evidence, ns) + end + return; + end + + [m, C, W] = gaussian_CPD_params_given_dps(CPD, dom, engine.evidence); + cdom = myintersect(dom, bnet.cnodes); + pot = linear_gaussian_to_cpot(m, C, W, dom, ns, cdom, engine.evidence); + % linear_gaussian_to_cpot will set the effective size of observed nodes to 0, + % so we need to do this explicitely for the messages, too, + % so they are all the same size. + obs_bitv = ~isemptycell(engine.evidence); + ps = parents(engine.msg_dag, n); + for j=1:length(ps) + p = ps(j); + msg = engine.msg{n}.pi_from_parent{j}; + if obs_bitv(p) + pi_msg = mpot(p, 0); + else + pi_msg = mpot(p, ns(p), 0, msg.mu, msg.Sigma); + end + pot = multiply_by_pot(pot, mpot_to_cpot(pi_msg)); + end + msg = engine.msg{n}.lambda; + if obs_bitv(n) + lambda = cpot(n, 0); + else + lambda = cpot(n, ns(n), 0, msg.info_state, msg.precision); + end + pot = multiply_by_pot(pot, lambda); + m = pot_to_marginal(pot); + if add_ev + m = add_evidence_to_gmarginal(m, engine.evidence, bnet.node_sizes, bnet.cnodes); + end +end + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..bee6ec37 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/marginal_nodes.m @@ -0,0 +1,43 @@ +function marginal = marginal_nodes(engine, query, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (loopy) +% marginal = marginal_nodes(engine, query, add_ev) +% +% 'query' must be a single node. +% add_ev is an optional argument; if 1, observed nodes will be set to their original size, +% otherwise they will be treated like points. + +if nargin < 3, add_ev = 0; end + +if length(query) > 1 + error('can only compute marginal on single nodes or families') +end +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); + +switch engine.msg_type + case 'd', + T = engine.marginal{query}; + if ~add_ev + marginal.T = shrink_obs_dims_in_table(T, query, engine.evidence); + else + marginal.T = T; + end + marginal.domain = query; + + case 'g', + if engine.disconnected_nodes_bitv(query) + marginal.T = 1; + marginal.domain = query; + if add_ev + marginal = add_ev_to_dmarginal(marginal, engine.evidence, ns) + end + return; + end + + marginal = engine.marginal{query}; + marginal.domain = query; + if ~add_ev + marginal = shrink_obs_dims_in_gaussian(marginal, query, engine.evidence, ns); + end +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/pearl_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/pearl_inf_engine.m new file mode 100644 index 00000000..d4eb3059 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/pearl_inf_engine.m @@ -0,0 +1,158 @@ +function engine = pearl_inf_engine(bnet, varargin) +% PEARL_INF_ENGINE Pearl's algorithm (belief propagation) +% engine = pearl_inf_engine(bnet, ...) +% +% If the graph has no loops (undirected cycles), you should use the tree protocol, +% and the results will be exact. +% Otherwise, you should use the parallel protocol, and the results may be approximate. +% +% Optional arguments [default in brackets] +% 'protocol' - tree or parallel ['parallel'] +% +% Optional arguments for the loopy case +% 'max_iter' - specifies the max num. iterations to perform [2*num nodes] +% 'tol' - convergence criterion on messages [1e-3] +% 'momentum' - msg = (m*old + (1-m)*new). [m=0] +% 'filename' - msgs will be printed to this file, so you can assess convergence while it runs [[]] +% 'storebel' - 1 means save engine.bel{n,t} for every iteration t and hidden node n [0] +% +% If there are discrete and cts nodes, we assume all the discretes are observed. In this +% case, you must use the parallel protocol, and the evidence pattern must be fixed. + + +N = length(bnet.dag); +protocol = 'parallel'; +max_iter = 2*N; +% We use N+2 for the following reason: +% In N iterations, we get the exact answer for a tree. +% In the N+1st iteration, we notice that the results are the same as before, and terminate. +% In loopy_converged, we see that N+1 < max = N+2, and declare convergence. +tol = 1e-3; +momentum = 0; +filename = []; +storebel = 0; + +args = varargin; +for i=1:2:length(args) + switch args{i}, + case 'protocol', protocol = args{i+1}; + case 'max_iter', max_iter = args{i+1}; + case 'tol', tol = args{i+1}; + case 'momentum', momentum = args{i+1}; + case 'filename', filename = args{i+1}; + case 'storebel', storebel = args{i+1}; + end +end + +engine.filename = filename; +engine.storebel = storebel; +engine.bel = []; + +if strcmp(protocol, 'tree') + % We first send messages up to the root (pivot node), and then back towards the leaves. + % If the bnet is a singly connected graph (no loops), choosing a root induces a directed tree. + % Peot and Shachter discuss ways to pick the root so as to minimize the work, + % taking into account which nodes have changed. + % For simplicity, we always pick the root to be the last node in the graph. + % This means the first pass is equivalent to going forward in time in a DBN. + + engine.root = N; + [engine.adj_mat, engine.preorder, engine.postorder, loopy] = ... + mk_rooted_tree(bnet.dag, engine.root); + % engine.adj_mat might have different edge orientations from bnet.dag + if loopy + error('can only apply tree protocol to loop-less graphs') + end +else + engine.root = []; + engine.adj_mat = []; + engine.preorder = []; + engine.postorder = []; +end + +engine.niter = []; +engine.protocol = protocol; +engine.max_iter = max_iter; +engine.tol = tol; +engine.momentum = momentum; +engine.maximize = []; + +%onodes = find(~isemptycell(evidence)); +onodes = bnet.observed; +engine.msg_type = determine_pot_type(bnet, onodes, 1:N); % needed also by marginal_nodes +if strcmp(engine.msg_type, 'cg') + error('messages must be discrete or Gaussian') +end +[engine.msg_dag, disconnected_nodes] = mk_msg_dag(bnet, engine.msg_type, onodes); +engine.disconnected_nodes_bitv = zeros(1,N); +engine.disconnected_nodes_bitv(disconnected_nodes) = 1; + + +% this is where we store stuff between enter_evidence and marginal_nodes +engine.marginal = cell(1,N); +engine.evidence = []; +engine.msg = []; + +[engine.parent_index, engine.child_index] = mk_loopy_msg_indices(engine.msg_dag); + +engine = class(engine, 'pearl_inf_engine', inf_engine(bnet)); + + +%%%%%%%%% + +function [dag, disconnected_nodes] = mk_msg_dag(bnet, msg_type, onodes) + +% If we are using Gaussian msgs, all discrete nodes must be observed; +% they are then disconnected from the graph, so we don't try to send +% msgs to/from them: their observed value simply serves to index into +% the right set of parameters for the Gaussian nodes (which use CPD.ps +% instead of parents(dag), and hence are unaffected by this "surgery"). + +disconnected_nodes = []; +switch msg_type + case 'd', dag = bnet.dag; + case 'g', + disconnected_nodes = bnet.dnodes; + dag = bnet.dag; + for i=disconnected_nodes(:)' + ps = parents(bnet.dag, i); + cs = children(bnet.dag, i); + if ~isempty(ps), dag(ps, i) = 0; end + if ~isempty(cs), dag(i, cs) = 0; end + end +end + + +%%%%%%%%%% +function [parent_index, child_index] = mk_loopy_msg_indices(dag) +% MK_LOOPY_MSG_INDICES Compute "port numbers" for message passing +% [parent_index, child_index] = mk_loopy_msg_indices(bnet) +% +% child_index{n}(c) = i means c is n's i'th child, i.e., i = find_equiv_posns(c, children(n)) +% child_index{n}(c) = 0 means c is not a child of n. +% parent_index{n}{p} is defined similarly. +% We need to use these indices since the pi_from_parent/ lambda_from_child cell arrays +% cannot be sparse, and hence cannot be indexed by the actual number of the node. +% Instead, we use the number of the "port" on which the message arrived. + +N = length(dag); +child_index = cell(1,N); +parent_index = cell(1,N); +for n=1:N + cs = children(dag, n); + child_index{n} = sparse(1,N); + for i=1:length(cs) + c = cs(i); + child_index{n}(c) = i; + end + ps = parents(dag, n); + parent_index{n} = sparse(1,N); + for i=1:length(ps) + p = ps(i); + parent_index{n}(p) = i; + end +end + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/pearl_inf_engine.m~ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/pearl_inf_engine.m~ new file mode 100644 index 00000000..946233d0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/pearl_inf_engine.m~ @@ -0,0 +1,158 @@ +function engine = pearl_inf_engine(bnet, varargin) +% PEARL_INF_ENGINE Pearl's algorithm (belief propagation) +% engine = pearl_inf_engine(bnet, ...) +% +% If the graph has no loops (undirected cycles), you should use the tree protocol, +% and the results will be exact. +% Otherwise, you should use the parallel protocol, and the results may be approximate. +% +% Optional arguments [default in brackets] +% 'protocol' - tree or parallel ['parallel'] +% +% Optional arguments for the loopy case +% 'max_iter' - specifies the max num. iterations to perform [2*num nodes] +% 'tol' - convergence criterion on messages [1e-3] +% 'momentum' - msg = (m*old + (1-m)*new). [m=0] +% 'filename' - msgs will be printed to this file, so you can assess convergence while it runs [[]] +% 'storebel' - 1 means save engine.bel{n,t} for every iteration t and hidden node n [0] +% +% If there are discrete and cts nodes, we assume all the discretes are observed. In this +% case, you must use the parallel protocol, and the evidence pattern must be fixed. + + +N = length(bnet.dag); +protocol = []; +max_iter = 2*N; +% We use N+2 for the following reason: +% In N iterations, we get the exact answer for a tree. +% In the N+1st iteration, we notice that the results are the same as before, and terminate. +% In loopy_converged, we see that N+1 < max = N+2, and declare convergence. +tol = 1e-3; +momentum = 0; +filename = []; +storebel = 0; + +args = varargin; +for i=1:2:length(args) + switch args{i}, + case 'protocol', protocol = args{i+1}; + case 'max_iter', max_iter = args{i+1}; + case 'tol', tol = args{i+1}; + case 'momentum', momentum = args{i+1}; + case 'filename', filename = args{i+1}; + case 'storebel', storebel = args{i+1}; + end +end + +engine.filename = filename; +engine.storebel = storebel; +engine.bel = []; + +if strcmp(protocol, 'tree') + % We first send messages up to the root (pivot node), and then back towards the leaves. + % If the bnet is a singly connected graph (no loops), choosing a root induces a directed tree. + % Peot and Shachter discuss ways to pick the root so as to minimize the work, + % taking into account which nodes have changed. + % For simplicity, we always pick the root to be the last node in the graph. + % This means the first pass is equivalent to going forward in time in a DBN. + + engine.root = N; + [engine.adj_mat, engine.preorder, engine.postorder, loopy] = ... + mk_rooted_tree(bnet.dag, engine.root); + % engine.adj_mat might have different edge orientations from bnet.dag + if loopy + error('can only apply tree protocol to loop-less graphs') + end +else + engine.root = []; + engine.adj_mat = []; + engine.preorder = []; + engine.postorder = []; +end + +engine.niter = []; +engine.protocol = protocol; +engine.max_iter = max_iter; +engine.tol = tol; +engine.momentum = momentum; +engine.maximize = []; + +%onodes = find(~isemptycell(evidence)); +onodes = bnet.observed; +engine.msg_type = determine_pot_type(bnet, onodes, 1:N); % needed also by marginal_nodes +if strcmp(engine.msg_type, 'cg') + error('messages must be discrete or Gaussian') +end +[engine.msg_dag, disconnected_nodes] = mk_msg_dag(bnet, engine.msg_type, onodes); +engine.disconnected_nodes_bitv = zeros(1,N); +engine.disconnected_nodes_bitv(disconnected_nodes) = 1; + + +% this is where we store stuff between enter_evidence and marginal_nodes +engine.marginal = cell(1,N); +engine.evidence = []; +engine.msg = []; + +[engine.parent_index, engine.child_index] = mk_loopy_msg_indices(engine.msg_dag); + +engine = class(engine, 'pearl_inf_engine', inf_engine(bnet)); + + +%%%%%%%%% + +function [dag, disconnected_nodes] = mk_msg_dag(bnet, msg_type, onodes) + +% If we are using Gaussian msgs, all discrete nodes must be observed; +% they are then disconnected from the graph, so we don't try to send +% msgs to/from them: their observed value simply serves to index into +% the right set of parameters for the Gaussian nodes (which use CPD.ps +% instead of parents(dag), and hence are unaffected by this "surgery"). + +disconnected_nodes = []; +switch msg_type + case 'd', dag = bnet.dag; + case 'g', + disconnected_nodes = bnet.dnodes; + dag = bnet.dag; + for i=disconnected_nodes(:)' + ps = parents(bnet.dag, i); + cs = children(bnet.dag, i); + if ~isempty(ps), dag(ps, i) = 0; end + if ~isempty(cs), dag(i, cs) = 0; end + end +end + + +%%%%%%%%%% +function [parent_index, child_index] = mk_loopy_msg_indices(dag) +% MK_LOOPY_MSG_INDICES Compute "port numbers" for message passing +% [parent_index, child_index] = mk_loopy_msg_indices(bnet) +% +% child_index{n}(c) = i means c is n's i'th child, i.e., i = find_equiv_posns(c, children(n)) +% child_index{n}(c) = 0 means c is not a child of n. +% parent_index{n}{p} is defined similarly. +% We need to use these indices since the pi_from_parent/ lambda_from_child cell arrays +% cannot be sparse, and hence cannot be indexed by the actual number of the node. +% Instead, we use the number of the "port" on which the message arrived. + +N = length(dag); +child_index = cell(1,N); +parent_index = cell(1,N); +for n=1:N + cs = children(dag, n); + child_index{n} = sparse(1,N); + for i=1:length(cs) + c = cs(i); + child_index{n}(c) = i; + end + ps = parents(dag, n); + parent_index{n} = sparse(1,N); + for i=1:length(ps) + p = ps(i); + parent_index{n}(p) = i; + end +end + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..283482a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Entries @@ -0,0 +1,5 @@ +/compute_bel.m/1.1.1.1/Wed May 29 15:59:56 2002// +/parallel_protocol.m/1.1.1.1/Sun Aug 21 20:00:12 2005// +/prod_lambda_msgs.m/1.1.1.1/Wed May 29 15:59:56 2002// +/tree_protocol.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..e913d5b6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@pearl_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/compute_bel.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/compute_bel.m new file mode 100644 index 00000000..ebcbc747 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/compute_bel.m @@ -0,0 +1,24 @@ +function bel = compute_bel(msg_type, pi, lambda) + +switch msg_type, + case 'd', bel = normalise(pi .* lambda); + case 'g', + if isinf(lambda.precision) % ignore pi because lambda is completely certain (observed) + bel.mu = lambda.mu; + bel.Sigma = zeros(length(bel.mu)); % infinite precision => 0 variance + elseif all(pi.Sigma==0) % ignore lambda because pi is completely certain (delta fn prior) + bel.Sigma = pi.Sigma; + bel.mu = pi.mu; + elseif all(isinf(pi.Sigma)) % ignore pi because pi is completely uncertain + bel.Sigma = inv(lambda.precision); + bel.mu = bel.Sigma * lambda.info_state; + elseif all(lambda.precision == 0) % ignore lambda because lambda is completely uncertain + bel.Sigma = pi.Sigma; + bel.mu = pi.mu; + else % combine both pi and lambda + pi_precision = inv(pi.Sigma); + bel.Sigma = inv(pi_precision + lambda.precision); + bel.mu = bel.Sigma*(pi_precision * pi.mu + lambda.info_state); + end + otherwise, error(['unrecognized msg type ' msg_type]) +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m new file mode 100644 index 00000000..8aa178b4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m @@ -0,0 +1,114 @@ +function [msg, niter] = parallel_protocol(engine, evidence, msg) + +bnet = bnet_from_engine(engine); +N = length(bnet.dag); +ns = bnet.node_sizes(:); + +if ~isempty(engine.filename) + fid = fopen(engine.filename, 'w'); + if fid == 0 + error(['could not open ' engine.filename ' for writing']) + end +else + fid = []; +end + +converged = 0; +iter = 1; +hidden = find(isemptycell(evidence)); +bel = cell(1,N); +old_bel = cell(1,N); +%nodes = mysetdiff(1:N, engine.disconnected_nodes); +nodes = find(~engine.disconnected_nodes_bitv); +while ~converged && (iter <= engine.max_iter) + % Everybody updates their state in parallel + for n=nodes(:)' + cs_msg = children(engine.msg_dag, n); + %msg{n}.lambda = compute_lambda(n, cs, msg); + msg{n}.lambda = prod_lambda_msgs(n, cs_msg, msg, engine.msg_type); + ps_orig = parents(bnet.dag, n); + msg{n}.pi = CPD_to_pi(bnet.CPD{bnet.equiv_class(n)}, engine.msg_type, n, ps_orig, msg, evidence); + end + + changed = 0; + if ~isempty(fid) + fprintf(fid, 'ITERATION %d\n', iter); + end + for n=hidden(:)' % this will not contain any disconnected nodes + old_bel{n} = bel{n}; + bel{n} = compute_bel(engine.msg_type, msg{n}.pi, msg{n}.lambda); + if ~isempty(fid) + fprintf(fid, 'node %d: %s\n', n, bel_to_str(bel{n}, engine.msg_type)); + end + if engine.storebel + engine.bel{n,iter} = bel{n}; + end + if (iter == 1) | ~approxeq_bel(bel{n}, old_bel{n}, engine.tol, engine.msg_type) + changed = 1; + end + end + %converged = ~changed; + converged = ~changed && (iter > 1); % Sonia Leach changed this + + if ~converged + % Everybody sends to all their neighbors in parallel + for n=nodes(:)' + % lambda msgs to parents + ps_msg = parents(engine.msg_dag, n); + ps_orig = parents(bnet.dag, n); + for p=ps_msg(:)' + j = engine.child_index{p}(n); % n is p's j'th child + old_msg = msg{p}.lambda_from_child{j}(:); + new_msg = CPD_to_lambda_msg(bnet.CPD{bnet.equiv_class(n)}, engine.msg_type, n, ps_orig, ... + msg, p, evidence); + lam_msg = convex_combination_msg(old_msg, new_msg, engine.momentum, engine.msg_type); + msg{p}.lambda_from_child{j} = lam_msg; + end + + % pi msgs to children + cs_msg = children(engine.msg_dag, n); + for c=cs_msg(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + old_msg = msg{c}.pi_from_parent{j}(:); + %new_msg = compute_pi_msg(n, cs, msg, c)); + new_msg = compute_bel(engine.msg_type, msg{n}.pi, prod_lambda_msgs(n, cs_msg, msg, engine.msg_type, c)); + pi_msg = convex_combination_msg(old_msg, new_msg, engine.momentum, engine.msg_type); + msg{c}.pi_from_parent{j} = pi_msg; + end + end + iter = iter + 1; + end +end + +if fid > 0, fclose(fid); end +%niter = iter - 1; +niter = iter; + +%%%%%%%%%% + +function str = bel_to_str(bel, type) + +switch type + case 'd', str = sprintf('%9.4f ', bel(:)'); + case 'g', str = sprintf('%9.4f ', bel.mu(:)'); +end + + +%%%%%%% + +function a = approxeq_bel(bel1, bel2, tol, type) + +switch type + case 'd', a = approxeq(bel1, bel2, tol); + case 'g', a = approxeq(bel1.mu, bel2.mu, tol) && approxeq(bel1.Sigma, bel2.Sigma, tol); +end + + +%%%%%%% + +function msg = convex_combination_msg(old_msg, new_msg, old_weight, type) + +switch type + case 'd', msg = old_weight * old_msg + (1-old_weight)*new_msg; + case 'g', msg = new_msg; +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m~ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m~ new file mode 100644 index 00000000..cc6fe6b3 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/parallel_protocol.m~ @@ -0,0 +1,114 @@ +function [msg, niter] = parallel_protocol(engine, evidence, msg) + +bnet = bnet_from_engine(engine); +N = length(bnet.dag); +ns = bnet.node_sizes(:); + +if ~isempty(engine.filename) + fid = fopen(engine.filename, 'w'); + if fid == 0 + error(['could not open ' engine.filename ' for writing']) + end +else + fid = 0; +end + +converged = 0; +iter = 1; +hidden = find(isemptycell(evidence)); +bel = cell(1,N); +old_bel = cell(1,N); +%nodes = mysetdiff(1:N, engine.disconnected_nodes); +nodes = find(~engine.disconnected_nodes_bitv); +while ~converged & (iter <= engine.max_iter) + % Everybody updates their state in parallel + for n=nodes(:)' + cs_msg = children(engine.msg_dag, n); + %msg{n}.lambda = compute_lambda(n, cs, msg); + msg{n}.lambda = prod_lambda_msgs(n, cs_msg, msg, engine.msg_type); + ps_orig = parents(bnet.dag, n); + msg{n}.pi = CPD_to_pi(bnet.CPD{bnet.equiv_class(n)}, engine.msg_type, n, ps_orig, msg, evidence); + end + + changed = 0; + if ~isempty(fid) + fprintf(fid, 'ITERATION %d\n', iter); + end + for n=hidden(:)' % this will not contain any disconnected nodes + old_bel{n} = bel{n}; + bel{n} = compute_bel(engine.msg_type, msg{n}.pi, msg{n}.lambda); + if ~isempty(fid) + fprintf(fid, 'node %d: %s\n', n, bel_to_str(bel{n}, engine.msg_type)); + end + if engine.storebel + engine.bel{n,iter} = bel{n}; + end + if (iter == 1) | ~approxeq_bel(bel{n}, old_bel{n}, engine.tol, engine.msg_type) + changed = 1; + end + end + %converged = ~changed; + converged = ~changed & (iter > 1); % Sonia Leach changed this + + if ~converged + % Everybody sends to all their neighbors in parallel + for n=nodes(:)' + % lambda msgs to parents + ps_msg = parents(engine.msg_dag, n); + ps_orig = parents(bnet.dag, n); + for p=ps_msg(:)' + j = engine.child_index{p}(n); % n is p's j'th child + old_msg = msg{p}.lambda_from_child{j}(:); + new_msg = CPD_to_lambda_msg(bnet.CPD{bnet.equiv_class(n)}, engine.msg_type, n, ps_orig, ... + msg, p, evidence); + lam_msg = convex_combination_msg(old_msg, new_msg, engine.momentum, engine.msg_type); + msg{p}.lambda_from_child{j} = lam_msg; + end + + % pi msgs to children + cs_msg = children(engine.msg_dag, n); + for c=cs_msg(:)' + j = engine.parent_index{c}(n); % n is c's j'th parent + old_msg = msg{c}.pi_from_parent{j}(:); + %new_msg = compute_pi_msg(n, cs, msg, c)); + new_msg = compute_bel(engine.msg_type, msg{n}.pi, prod_lambda_msgs(n, cs_msg, msg, engine.msg_type, c)); + pi_msg = convex_combination_msg(old_msg, new_msg, engine.momentum, engine.msg_type); + msg{c}.pi_from_parent{j} = pi_msg; + end + end + iter = iter + 1; + end +end + +if fid > 0, fclose(fid); end +%niter = iter - 1; +niter = iter; + +%%%%%%%%%% + +function str = bel_to_str(bel, type) + +switch type + case 'd', str = sprintf('%9.4f ', bel(:)'); + case 'g', str = sprintf('%9.4f ', bel.mu(:)'); +end + + +%%%%%%% + +function a = approxeq_bel(bel1, bel2, tol, type) + +switch type + case 'd', a = approxeq(bel1, bel2, tol); + case 'g', a = approxeq(bel1.mu, bel2.mu, tol) & approxeq(bel1.Sigma, bel2.Sigma, tol); +end + + +%%%%%%% + +function msg = convex_combination_msg(old_msg, new_msg, old_weight, type) + +switch type + case 'd', msg = old_weight * old_msg + (1-old_weight)*new_msg; + case 'g', msg = new_msg; +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/prod_lambda_msgs.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/prod_lambda_msgs.m new file mode 100644 index 00000000..5a96d259 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/prod_lambda_msgs.m @@ -0,0 +1,29 @@ +function lam = prod_lambda_msgs(n, cs, msg, msg_type, except) + +if nargin < 5, except = -1; end + +lam = msg{n}.lambda_from_self; +switch msg_type + case 'd', + for i=1:length(cs) + c = cs(i); + if c ~= except + lam = lam .* msg{n}.lambda_from_child{i}; + end + end + case 'g', + if isinf(lam.precision) % isfield(lam, 'observed_val') + return; % pass on the observed msg + end + for i=1:length(cs) + c = cs(i); + if c ~= except + m = msg{n}.lambda_from_child{i}; + lam.precision = lam.precision + m.precision; + lam.info_state = lam.info_state + m.info_state; + end + end +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/tree_protocol.m b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/tree_protocol.m new file mode 100644 index 00000000..b0ba2fc8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@pearl_inf_engine/private/tree_protocol.m @@ -0,0 +1,71 @@ +function msg = tree_protocol(engine, evidence, msg) + +bnet = bnet_from_engine(engine); +N = length(bnet.dag); + +% Send messages from leaves to root +for i=1:N-1 + n = engine.postorder(i); + above = parents(engine.adj_mat, n); + msg = send_msgs_to_some_neighbors(n, msg, above, bnet, engine.child_index, engine.parent_index, ... + engine.msg_type, evidence); +end + +% Process root +n = engine.root; +cs = children(bnet.dag, n); +%msg{n}.lambda = compute_lambda(n, cs, msg, engine.msg_type); +msg{n}.lambda = prod_lambda_msgs(n, cs, msg, engine.msg_type); +ps = parents(bnet.dag, n); +msg{n}.pi = CPD_to_pi(bnet.CPD{bnet.equiv_class(n)}, engine.msg_type, n, ps, msg, evidence); + +% Send messages from root to leaves +for i=1:N + n = engine.preorder(i); + below = children(engine.adj_mat, n); + msg = send_msgs_to_some_neighbors(n, msg, below, bnet, engine.child_index, engine.parent_index, ... + engine.msg_type, evidence); +end + + +%%%%%%%%%% + +function msg = send_msgs_to_some_neighbors(n, msg, valid_nbrs, bnet, child_index, parent_index, ... + msg_type, evidence) + +verbose = 0; + +ns = bnet.node_sizes; +dag = bnet.dag; +e = bnet.equiv_class(n); +CPD = bnet.CPD{e}; + + +cs = children(dag, n); +%msg{n}.lambda = compute_lambda(n, cs, msg); +msg{n}.lambda = prod_lambda_msgs(n, cs, msg, msg_type); +if verbose, fprintf('%d computes lambda\n', n); display(msg{n}.lambda); end + +ps = parents(dag, n); +msg{n}.pi = CPD_to_pi(CPD, msg_type, n, ps, msg, evidence); +if verbose, fprintf('%d computes pi\n', n); display(msg{n}.pi); end + +ps2 = myintersect(parents(dag, n), valid_nbrs); +for p=ps2(:)' + lam_msg = CPD_to_lambda_msg(CPD, msg_type, n, ps, msg, p, evidence); + j = child_index{p}(n); % n is p's j'th child + msg{p}.lambda_from_child{j} = lam_msg; + if verbose, fprintf('%d sends lambda to %d\n', n, p); display(lam_msg); end +end + +cs2 = myintersect(cs, valid_nbrs); +for c=cs2(:)' + %pi_msg = compute_pi_msg(n, cs, msg, c); + pi_msg = compute_bel(msg_type, msg{n}.pi, prod_lambda_msgs(n, cs, msg, msg_type, c)); + j = parent_index{c}(n); % n is c's j'th parent + msg{c}.pi_from_parent{j} = pi_msg; + if verbose, fprintf('%d sends pi to %d\n', n, c); display(pi_msg); end +end + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Entries new file mode 100644 index 00000000..68df5d27 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Entries @@ -0,0 +1,4 @@ +/enter_evidence.m/1.1.1.1/Wed May 29 15:59:56 2002// +/marginal_nodes.m/1.1.1.1/Wed May 29 15:59:56 2002// +/quickscore_inf_engine.m/1.1.1.1/Wed May 29 15:59:56 2002// +D/private//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Repository new file mode 100644 index 00000000..cdd697e4 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@quickscore_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/enter_evidence.m new file mode 100644 index 00000000..c697264b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/enter_evidence.m @@ -0,0 +1,19 @@ +function engine = enter_evidence(engine, pos, neg) +% ENTER_EVIDENCE Add evidence to the QMR network +% engine = enter_evidence(engine, pos, neg) +% +% pos = list of leaves that have positive observations +% neg = list of leaves that have negative observations + +% Extract params for the observed findings +obs = myunion(pos, neg); +%inhibit_obs = engine.inhibit(obs, :); +inhibit_obs = engine.inhibit(:,obs)'; +leak_obs = engine.leak(obs); + +% Find what nodes correspond to the original observed leaves +pos2 = find_equiv_posns(pos, obs); +neg2 = find_equiv_posns(neg, obs); +engine.post = quickscore(pos2, neg2, inhibit_obs, engine.prior, leak_obs); +%engine.post = C_quickscore(pos2, neg2, inhibit_obs, engine.prior, leak_obs); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..e07c04c2 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/marginal_nodes.m @@ -0,0 +1,11 @@ +function m = marginal_nodes(engine, query) +% MARGINAL_NODES Compute the marginal on the specified query nodes (quickscore) +% marginal = marginal_nodes(engine, query) +% +% 'query' must be a single disease (root) node. + +assert(length(query)==1); +p = engine.post(query); +m.T = [1-p p]'; +m.domain = query; + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Entries new file mode 100644 index 00000000..6a6a34f0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Entries @@ -0,0 +1,6 @@ +/C_quickscore.c/1.1.1.1/Wed May 29 15:59:56 2002// +/nr.h/1.1.1.1/Wed May 29 15:59:56 2002// +/nrutil.c/1.1.1.1/Wed May 29 15:59:56 2002// +/nrutil.h/1.1.1.1/Wed May 29 15:59:56 2002// +/quickscore.m/1.1.1.1/Wed May 29 15:59:56 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Repository new file mode 100644 index 00000000..33f7b87e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@quickscore_inf_engine/private diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/C_quickscore.c b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/C_quickscore.c new file mode 100644 index 00000000..b9b46f04 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/C_quickscore.c @@ -0,0 +1,164 @@ +/* To compile, type "mex C_quickscore.c" */ + +#include <stdio.h> +#include "nrutil.h" +#include "nrutil.c" +#include <math.h> +#include "mex.h" + +#define MAX(X,Y) (X)>(Y)?(X):(Y) + +int two_to_the(int n) +{ + return 1 << n; +} + +void int2bin(int num, int nbits, int bits[]) +{ + int i, mask; + mask = 1 << (nbits-1); /* mask = 0010...0 , where the 1 is in col nbits (rightmost = col 1) */ + for (i = 0; i < nbits; i++) { + bits[i] = ((num & mask) == 0) ? 0 : 1; + num <<= 1; + } +} + + +void quickscore(int ndiseases, int nfindings, const double *fpos, int npos, const double *fneg, int nneg, + const double *inhibit, const double *prior, const double *leak, double *prob) +{ + double *Pon, *Poff, **Uon, **Uoff, **post, *pterm, *ptermOff, *ptermOn, temp, p, myp; + int *bits, nsubsets, *fmask; + int f, d, i, j, si, size_subset, sign; + + Pon = dvector(0, ndiseases); + Poff = dvector(0, ndiseases); + Pon[0] = 1; + Poff[0] = 0; + for (i=1; i <= ndiseases; i++) { + Pon[i] = prior[i-1]; + Poff[i] = 1-Pon[i]; + } + + Uon = dmatrix(0, nfindings-1, 0, ndiseases); + Uoff = dmatrix(0, nfindings-1, 0, ndiseases); + d = 0; + for (f=0; f < nfindings; f++) { + Uon[f][d] = leak[f]; + Uoff[f][d] = leak[f]; + } + for (f=0; f < nfindings; f++) { + for (d=1; d <= ndiseases; d++) { + Uon[f][d] = inhibit[f + nfindings*(d-1)]; + Uoff[f][d] = 1; + } + } + + post = dmatrix(0, ndiseases, 0, 1); + for (d = 0; d <= ndiseases; d++) { + post[d][0] = 0; + post[d][1] = 0; + } + + bits = ivector(0, npos-1); + fmask = ivector(0, nfindings-1); + pterm = dvector(0, ndiseases); + ptermOff = dvector(0, ndiseases); + ptermOn = dvector(0, ndiseases); + + nsubsets = two_to_the(npos); + + for (si = 0; si < nsubsets; si++) { + int2bin(si, npos, bits); + for (i=0; i < nfindings; i++) fmask[i] = 0; + for (i=0; i < nneg; i++) fmask[(int)fneg[i]-1] = 1; + size_subset = 0; + for (i=0; i < npos; i++) { + if (bits[i]) { + size_subset++; + fmask[(int)fpos[i]-1] = 1; + } + } + p = 1; + for (d=0; d <= ndiseases; d++) { + temp = 1; + for (j = 0; j < nfindings; j++) { + if (fmask[j]) temp *= Uoff[j][d]; + } + ptermOff[d] = temp; + + temp = 1; + for (j = 0; j < nfindings; j++) { + if (fmask[j]) temp *= Uon[j][d]; + } + ptermOn[d] = temp; + + pterm[d] = Poff[d]*ptermOff[d] + Pon[d]*ptermOn[d]; + p *= pterm[d]; + } + sign = (int) pow(-1, size_subset); + for (d=0; d <= ndiseases; d++) { + myp = p / pterm[d]; + post[d][0] += sign*(myp * ptermOff[d]); + post[d][1] += sign*(myp * ptermOn[d]); + } + } /* next si */ + + + for (d=0; d <= ndiseases; d++) { + post[d][0] *= Poff[d]; + post[d][1] *= Pon[d]; + } + for (d=0; d <= ndiseases; d++) { + temp = post[d][0] + post[d][1]; + post[d][0] /= temp; + post[d][1] /= temp; + if (d>0) { prob[d-1] = post[d][1]; } + } + + + free_dvector(Pon, 0, ndiseases); + free_dvector(Poff, 0, ndiseases); + free_dmatrix(Uon, 0, nfindings-1, 0, ndiseases); + free_dmatrix(Uoff, 0, nfindings-1, 0, ndiseases); + free_dmatrix(post, 0, ndiseases, 0, 1); + free_ivector(bits, 0, npos-1); + free_ivector(fmask, 0, nfindings-1); + free_dvector(pterm, 0, ndiseases); + free_dvector(ptermOff, 0, ndiseases); + free_dvector(ptermOn, 0, ndiseases); +} + + +void mexFunction( + int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[] + ) +{ + double *fpos, *fneg, *inhibit, *prior, *leak, *prob; + int npos, nneg, ndiseases, nfindings; + double *p; + + /* read the input args */ + fpos = mxGetPr(prhs[0]); + npos = MAX(mxGetM(prhs[0]), mxGetN(prhs[0])); + + fneg = mxGetPr(prhs[1]); + nneg = MAX(mxGetM(prhs[1]), mxGetN(prhs[1])); + + inhibit = mxGetPr(prhs[2]); /* inhibit(finding, disease) */ + nfindings = mxGetM(prhs[2]); + ndiseases = mxGetN(prhs[2]); + + prior = mxGetPr(prhs[3]); + + leak = mxGetPr(prhs[4]); + + + /* set the output pointers */ + plhs[0] = mxCreateDoubleMatrix(1, ndiseases, mxREAL); + prob = mxGetPr(plhs[0]); + + quickscore(ndiseases, nfindings, fpos, npos, fneg, nneg, inhibit, prior, leak, prob); +} + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nr.h b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nr.h new file mode 100644 index 00000000..a7751566 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nr.h @@ -0,0 +1,536 @@ +/* CAUTION: This is the ANSI C (only) version of the Numerical Recipes + utility file nr.h. Do not confuse this file with the same-named + file nr.h that is supplied in the 'misc' subdirectory. + *That* file is the one from the book, and contains both ANSI and + traditional K&R versions, along with #ifdef macros to select the + correct version. *This* file contains only ANSI C. */ + +#ifndef _NR_H_ +#define _NR_H_ + +#ifndef _FCOMPLEX_DECLARE_T_ +typedef struct FCOMPLEX {float r,i;} fcomplex; +#define _FCOMPLEX_DECLARE_T_ +#endif /* _FCOMPLEX_DECLARE_T_ */ + +#ifndef _ARITHCODE_DECLARE_T_ +typedef struct { + unsigned long *ilob,*iupb,*ncumfq,jdif,nc,minint,nch,ncum,nrad; +} arithcode; +#define _ARITHCODE_DECLARE_T_ +#endif /* _ARITHCODE_DECLARE_T_ */ + +#ifndef _HUFFCODE_DECLARE_T_ +typedef struct { + unsigned long *icod,*ncod,*left,*right,nch,nodemax; +} huffcode; +#define _HUFFCODE_DECLARE_T_ +#endif /* _HUFFCODE_DECLARE_T_ */ + +#include <stdio.h> + +void addint(double **uf, double **uc, double **res, int nf); +void airy(float x, float *ai, float *bi, float *aip, float *bip); +void amebsa(float **p, float y[], int ndim, float pb[], float *yb, + float ftol, float (*funk)(float []), int *iter, float temptr); +void amoeba(float **p, float y[], int ndim, float ftol, + float (*funk)(float []), int *iter); +float amotry(float **p, float y[], float psum[], int ndim, + float (*funk)(float []), int ihi, float fac); +float amotsa(float **p, float y[], float psum[], int ndim, float pb[], + float *yb, float (*funk)(float []), int ihi, float *yhi, float fac); +void anneal(float x[], float y[], int iorder[], int ncity); +double anorm2(double **a, int n); +void arcmak(unsigned long nfreq[], unsigned long nchh, unsigned long nradd, + arithcode *acode); +void arcode(unsigned long *ich, unsigned char **codep, unsigned long *lcode, + unsigned long *lcd, int isign, arithcode *acode); +void arcsum(unsigned long iin[], unsigned long iout[], unsigned long ja, + int nwk, unsigned long nrad, unsigned long nc); +void asolve(unsigned long n, double b[], double x[], int itrnsp); +void atimes(unsigned long n, double x[], double r[], int itrnsp); +void avevar(float data[], unsigned long n, float *ave, float *var); +void balanc(float **a, int n); +void banbks(float **a, unsigned long n, int m1, int m2, float **al, + unsigned long indx[], float b[]); +void bandec(float **a, unsigned long n, int m1, int m2, float **al, + unsigned long indx[], float *d); +void banmul(float **a, unsigned long n, int m1, int m2, float x[], float b[]); +void bcucof(float y[], float y1[], float y2[], float y12[], float d1, + float d2, float **c); +void bcuint(float y[], float y1[], float y2[], float y12[], + float x1l, float x1u, float x2l, float x2u, float x1, + float x2, float *ansy, float *ansy1, float *ansy2); +void beschb(double x, double *gam1, double *gam2, double *gampl, + double *gammi); +float bessi(int n, float x); +float bessi0(float x); +float bessi1(float x); +void bessik(float x, float xnu, float *ri, float *rk, float *rip, + float *rkp); +float bessj(int n, float x); +float bessj0(float x); +float bessj1(float x); +void bessjy(float x, float xnu, float *rj, float *ry, float *rjp, + float *ryp); +float bessk(int n, float x); +float bessk0(float x); +float bessk1(float x); +float bessy(int n, float x); +float bessy0(float x); +float bessy1(float x); +float beta(float z, float w); +float betacf(float a, float b, float x); +float betai(float a, float b, float x); +float bico(int n, int k); +void bksub(int ne, int nb, int jf, int k1, int k2, float ***c); +float bnldev(float pp, int n, long *idum); +float brent(float ax, float bx, float cx, + float (*f)(float), float tol, float *xmin); +float brent_arg(float ax, float bx, float cx, + float (*f)(float, void*), float tol, float *xmin, void *arg); +void broydn(float x[], int n, int *check, + void (*vecfunc)(int, float [], float [])); +void bsstep(float y[], float dydx[], int nv, float *xx, float htry, + float eps, float yscal[], float *hdid, float *hnext, + void (*derivs)(float, float [], float [])); +void caldat(long julian, int *mm, int *id, int *iyyy); +void chder(float a, float b, float c[], float cder[], int n); +float chebev(float a, float b, float c[], int m, float x); +void chebft(float a, float b, float c[], int n, float (*func)(float)); +void chebpc(float c[], float d[], int n); +void chint(float a, float b, float c[], float cint[], int n); +float chixy(float bang); +void choldc(float **a, int n, float p[]); +void cholsl(float **a, int n, float p[], float b[], float x[]); +void chsone(float bins[], float ebins[], int nbins, int knstrn, + float *df, float *chsq, float *prob); +void chstwo(float bins1[], float bins2[], int nbins, int knstrn, + float *df, float *chsq, float *prob); +void cisi(float x, float *ci, float *si); +void cntab1(int **nn, int ni, int nj, float *chisq, + float *df, float *prob, float *cramrv, float *ccc); +void cntab2(int **nn, int ni, int nj, float *h, float *hx, float *hy, + float *hygx, float *hxgy, float *uygx, float *uxgy, float *uxy); +void convlv(float data[], unsigned long n, float respns[], unsigned long m, + int isign, float ans[]); +void copy(double **aout, double **ain, int n); +void correl(float data1[], float data2[], unsigned long n, float ans[]); +void cosft(float y[], int n, int isign); +void cosft1(float y[], int n); +void cosft2(float y[], int n, int isign); +void covsrt(float **covar, int ma, int ia[], int mfit); +void crank(unsigned long n, float w[], float *s); +void cyclic(float a[], float b[], float c[], float alpha, float beta, + float r[], float x[], unsigned long n); +void daub4(float a[], unsigned long n, int isign); +float dawson(float x); +float dbrent(float ax, float bx, float cx, + float (*f)(float), float (*df)(float), float tol, float *xmin); +void ddpoly(float c[], int nc, float x, float pd[], int nd); +int decchk(char string[], int n, char *ch); +void derivs(float x, float y[], float dydx[]); +float df1dim(float x); +void dfour1(double data[], unsigned long nn, int isign); +void dfpmin(float p[], int n, float gtol, int *iter, float *fret, + float (*func)(float []), void (*dfunc)(float [], float [])); +float dfridr(float (*func)(float), float x, float h, float *err); +void dftcor(float w, float delta, float a, float b, float endpts[], + float *corre, float *corim, float *corfac); +void dftint(float (*func)(float), float a, float b, float w, + float *cosint, float *sinint); +void difeq(int k, int k1, int k2, int jsf, int is1, int isf, + int indexv[], int ne, float **s, float **y); +void dlinmin(float p[], float xi[], int n, float *fret, + float (*func)(float []), void (*dfunc)(float [], float[])); +double dpythag(double a, double b); +void drealft(double data[], unsigned long n, int isign); +void dsprsax(double sa[], unsigned long ija[], double x[], double b[], + unsigned long n); +void dsprstx(double sa[], unsigned long ija[], double x[], double b[], + unsigned long n); +void dsvbksb(double **u, double w[], double **v, int m, int n, double b[], + double x[]); +void dsvdcmp(double **a, int m, int n, double w[], double **v); +void eclass(int nf[], int n, int lista[], int listb[], int m); +void eclazz(int nf[], int n, int (*equiv)(int, int)); +float ei(float x); +void eigsrt(float d[], float **v, int n); +float elle(float phi, float ak); +float ellf(float phi, float ak); +float ellpi(float phi, float en, float ak); +void elmhes(float **a, int n); +float erfcc(float x); +float erff(float x); +float erffc(float x); +void eulsum(float *sum, float term, int jterm, float wksp[]); +float evlmem(float fdt, float d[], int m, float xms); +float expdev(long *idum); +float expint(int n, float x); +float f1(float x); +float f1dim(float x); +float f1dim_arg(float x, void *arg); +float f2(float y); +float f3(float z); +float factln(int n); +float factrl(int n); +void fasper(float x[], float y[], unsigned long n, float ofac, float hifac, + float wk1[], float wk2[], unsigned long nwk, unsigned long *nout, + unsigned long *jmax, float *prob); +void fdjac(int n, float x[], float fvec[], float **df, + void (*vecfunc)(int, float [], float [])); +void fgauss(float x, float a[], float *y, float dyda[], int na); +void fill0(double **u, int n); +void fit(float x[], float y[], int ndata, float sig[], int mwt, + float *a, float *b, float *siga, float *sigb, float *chi2, float *q); +void fitexy(float x[], float y[], int ndat, float sigx[], float sigy[], + float *a, float *b, float *siga, float *sigb, float *chi2, float *q); +void fixrts(float d[], int m); +void fleg(float x, float pl[], int nl); +void flmoon(int n, int nph, long *jd, float *frac); +float fmin(float x[]); +void four1(float data[], unsigned long nn, int isign); +void fourew(FILE *file[5], int *na, int *nb, int *nc, int *nd); +void fourfs(FILE *file[5], unsigned long nn[], int ndim, int isign); +void fourn(float data[], unsigned long nn[], int ndim, int isign); +void fpoly(float x, float p[], int np); +void fred2(int n, float a, float b, float t[], float f[], float w[], + float (*g)(float), float (*ak)(float, float)); +float fredin(float x, int n, float a, float b, float t[], float f[], float w[], + float (*g)(float), float (*ak)(float, float)); +void frenel(float x, float *s, float *c); +void frprmn(float p[], int n, float ftol, int *iter, float *fret, + float (*func)(float []), void (*dfunc)(float [], float [])); +void frprmn_arg(float p[], int n, float ftol, int *iter, float *fret, + float (*func)(float [], void*), void (*dfunc)(float [], float [], void*), void* arg); +void ftest(float data1[], unsigned long n1, float data2[], unsigned long n2, + float *f, float *prob); +float gamdev(int ia, long *idum); +float gammln(float xx); +float gammp(float a, float x); +float gammq(float a, float x); +float gasdev(long *idum); +void gaucof(int n, float a[], float b[], float amu0, float x[], float w[]); +void gauher(float x[], float w[], int n); +void gaujac(float x[], float w[], int n, float alf, float bet); +void gaulag(float x[], float w[], int n, float alf); +void gauleg(float x1, float x2, float x[], float w[], int n); +void gaussj(float **a, int n, float **b, int m); +void gcf(float *gammcf, float a, float x, float *gln); +float golden(float ax, float bx, float cx, float (*f)(float), float tol, + float *xmin); +void gser(float *gamser, float a, float x, float *gln); +void hpsel(unsigned long m, unsigned long n, float arr[], float heap[]); +void hpsort(unsigned long n, float ra[]); +void hqr(float **a, int n, float wr[], float wi[]); +void hufapp(unsigned long index[], unsigned long nprob[], unsigned long n, + unsigned long i); +void hufdec(unsigned long *ich, unsigned char *code, unsigned long lcode, + unsigned long *nb, huffcode *hcode); +void hufenc(unsigned long ich, unsigned char **codep, unsigned long *lcode, + unsigned long *nb, huffcode *hcode); +void hufmak(unsigned long nfreq[], unsigned long nchin, unsigned long *ilong, + unsigned long *nlong, huffcode *hcode); +void hunt(float xx[], unsigned long n, float x, unsigned long *jlo); +void hypdrv(float s, float yy[], float dyyds[]); +fcomplex hypgeo(fcomplex a, fcomplex b, fcomplex c, fcomplex z); +void hypser(fcomplex a, fcomplex b, fcomplex c, fcomplex z, + fcomplex *series, fcomplex *deriv); +unsigned short icrc(unsigned short crc, unsigned char *bufptr, + unsigned long len, short jinit, int jrev); +unsigned short icrc1(unsigned short crc, unsigned char onech); +unsigned long igray(unsigned long n, int is); +void iindexx(unsigned long n, long arr[], unsigned long indx[]); +void indexx(unsigned long n, float arr[], unsigned long indx[]); +void interp(double **uf, double **uc, int nf); +int irbit1(unsigned long *iseed); +int irbit2(unsigned long *iseed); +void jacobi(float **a, int n, float d[], float **v, int *nrot); +void jacobn(float x, float y[], float dfdx[], float **dfdy, int n); +long julday(int mm, int id, int iyyy); +void kendl1(float data1[], float data2[], unsigned long n, float *tau, float *z, + float *prob); +void kendl2(float **tab, int i, int j, float *tau, float *z, float *prob); +void kermom(double w[], double y, int m); +void ks2d1s(float x1[], float y1[], unsigned long n1, + void (*quadvl)(float, float, float *, float *, float *, float *), + float *d1, float *prob); +void ks2d2s(float x1[], float y1[], unsigned long n1, float x2[], float y2[], + unsigned long n2, float *d, float *prob); +void ksone(float data[], unsigned long n, float (*func)(float), float *d, + float *prob); +void kstwo(float data1[], unsigned long n1, float data2[], unsigned long n2, + float *d, float *prob); +void laguer(fcomplex a[], int m, fcomplex *x, int *its); +void lfit(float x[], float y[], float sig[], int ndat, float a[], int ia[], + int ma, float **covar, float *chisq, void (*funcs)(float, float [], int)); +void linbcg(unsigned long n, double b[], double x[], int itol, double tol, + int itmax, int *iter, double *err); +void linmin(float p[], float xi[], int n, float *fret, + float (*func)(float [])); +void linmin_arg(float p[], float xi[], int n, float *fret, + float (*func)(float [], void*), void *arg); +void lnsrch(int n, float xold[], float fold, float g[], float p[], float x[], + float *f, float stpmax, int *check, float (*func)(float [])); +void load(float x1, float v[], float y[]); +void load1(float x1, float v1[], float y[]); +void load2(float x2, float v2[], float y[]); +void locate(float xx[], unsigned long n, float x, unsigned long *j); +void lop(double **out, double **u, int n); +void lubksb(float **a, int n, int *indx, float b[]); +void ludcmp(float **a, int n, int *indx, float *d); +void machar(int *ibeta, int *it, int *irnd, int *ngrd, + int *machep, int *negep, int *iexp, int *minexp, int *maxexp, + float *eps, float *epsneg, float *xmin, float *xmax); +void matadd(double **a, double **b, double **c, int n); +void matsub(double **a, double **b, double **c, int n); +void medfit(float x[], float y[], int ndata, float *a, float *b, float *abdev); +void memcof(float data[], int n, int m, float *xms, float d[]); +int metrop(float de, float t); +void mgfas(double **u, int n, int maxcyc); +void mglin(double **u, int n, int ncycle); +float midexp(float (*funk)(float), float aa, float bb, int n); +float midinf(float (*funk)(float), float aa, float bb, int n); +float midpnt(float (*func)(float), float a, float b, int n); +float midsql(float (*funk)(float), float aa, float bb, int n); +float midsqu(float (*funk)(float), float aa, float bb, int n); +void miser(float (*func)(float []), float regn[], int ndim, unsigned long npts, + float dith, float *ave, float *var); +void mmid(float y[], float dydx[], int nvar, float xs, float htot, + int nstep, float yout[], void (*derivs)(float, float[], float[])); +void mnbrak(float *ax, float *bx, float *cx, float *fa, float *fb, + float *fc, float (*func)(float)); +void mnbrak_arg(float *ax, float *bx, float *cx, float *fa, float *fb, + float *fc, float (*func)(float, void*), void *arg); +void mnewt(int ntrial, float x[], int n, float tolx, float tolf); +void moment(float data[], int n, float *ave, float *adev, float *sdev, + float *var, float *skew, float *curt); +void mp2dfr(unsigned char a[], unsigned char s[], int n, int *m); +void mpadd(unsigned char w[], unsigned char u[], unsigned char v[], int n); +void mpdiv(unsigned char q[], unsigned char r[], unsigned char u[], + unsigned char v[], int n, int m); +void mpinv(unsigned char u[], unsigned char v[], int n, int m); +void mplsh(unsigned char u[], int n); +void mpmov(unsigned char u[], unsigned char v[], int n); +void mpmul(unsigned char w[], unsigned char u[], unsigned char v[], int n, + int m); +void mpneg(unsigned char u[], int n); +void mppi(int n); +void mprove(float **a, float **alud, int n, int indx[], float b[], + float x[]); +void mpsad(unsigned char w[], unsigned char u[], int n, int iv); +void mpsdv(unsigned char w[], unsigned char u[], int n, int iv, int *ir); +void mpsmu(unsigned char w[], unsigned char u[], int n, int iv); +void mpsqrt(unsigned char w[], unsigned char u[], unsigned char v[], int n, + int m); +void mpsub(int *is, unsigned char w[], unsigned char u[], unsigned char v[], + int n); +void mrqcof(float x[], float y[], float sig[], int ndata, float a[], + int ia[], int ma, float **alpha, float beta[], float *chisq, + void (*funcs)(float, float [], float *, float [], int)); +void mrqmin(float x[], float y[], float sig[], int ndata, float a[], + int ia[], int ma, float **covar, float **alpha, float *chisq, + void (*funcs)(float, float [], float *, float [], int), float *alamda); +void newt(float x[], int n, int *check, + void (*vecfunc)(int, float [], float [])); +void odeint(float ystart[], int nvar, float x1, float x2, + float eps, float h1, float hmin, int *nok, int *nbad, + void (*derivs)(float, float [], float []), + void (*rkqs)(float [], float [], int, float *, float, float, + float [], float *, float *, void (*)(float, float [], float []))); +void orthog(int n, float anu[], float alpha[], float beta[], float a[], + float b[]); +void pade(double cof[], int n, float *resid); +void pccheb(float d[], float c[], int n); +void pcshft(float a, float b, float d[], int n); +void pearsn(float x[], float y[], unsigned long n, float *r, float *prob, + float *z); +void period(float x[], float y[], int n, float ofac, float hifac, + float px[], float py[], int np, int *nout, int *jmax, float *prob); +void piksr2(int n, float arr[], float brr[]); +void piksrt(int n, float arr[]); +void pinvs(int ie1, int ie2, int je1, int jsf, int jc1, int k, + float ***c, float **s); +float plgndr(int l, int m, float x); +float poidev(float xm, long *idum); +void polcoe(float x[], float y[], int n, float cof[]); +void polcof(float xa[], float ya[], int n, float cof[]); +void poldiv(float u[], int n, float v[], int nv, float q[], float r[]); +void polin2(float x1a[], float x2a[], float **ya, int m, int n, + float x1, float x2, float *y, float *dy); +void polint(float xa[], float ya[], int n, float x, float *y, float *dy); +void powell(float p[], float **xi, int n, float ftol, int *iter, float *fret, + float (*func)(float [])); +void predic(float data[], int ndata, float d[], int m, float future[], int nfut); +float probks(float alam); +void psdes(unsigned long *lword, unsigned long *irword); +void pwt(float a[], unsigned long n, int isign); +void pwtset(int n); +float pythag(float a, float b); +void pzextr(int iest, float xest, float yest[], float yz[], float dy[], + int nv); +float qgaus(float (*func)(float), float a, float b); +void qrdcmp(float **a, int n, float *c, float *d, int *sing); +float qromb(float (*func)(float), float a, float b); +float qromo(float (*func)(float), float a, float b, + float (*choose)(float (*)(float), float, float, int)); +void qroot(float p[], int n, float *b, float *c, float eps); +void qrsolv(float **a, int n, float c[], float d[], float b[]); +void qrupdt(float **r, float **qt, int n, float u[], float v[]); +float qsimp(float (*func)(float), float a, float b); +float qtrap(float (*func)(float), float a, float b); +float quad3d(float (*func)(float, float, float), float x1, float x2); +void quadct(float x, float y, float xx[], float yy[], unsigned long nn, + float *fa, float *fb, float *fc, float *fd); +void quadmx(float **a, int n); +void quadvl(float x, float y, float *fa, float *fb, float *fc, float *fd); +float ran0(long *idum); +float ran1(long *idum); +float ran2(long *idum); +float ran3(long *idum); +float ran4(long *idum); +void rank(unsigned long n, unsigned long indx[], unsigned long irank[]); +void ranpt(float pt[], float regn[], int n); +void ratint(float xa[], float ya[], int n, float x, float *y, float *dy); +void ratlsq(double (*fn)(double), double a, double b, int mm, int kk, + double cof[], double *dev); +double ratval(double x, double cof[], int mm, int kk); +float rc(float x, float y); +float rd(float x, float y, float z); +void realft(float data[], unsigned long n, int isign); +void rebin(float rc, int nd, float r[], float xin[], float xi[]); +void red(int iz1, int iz2, int jz1, int jz2, int jm1, int jm2, int jmf, + int ic1, int jc1, int jcf, int kc, float ***c, float **s); +void relax(double **u, double **rhs, int n); +void relax2(double **u, double **rhs, int n); +void resid(double **res, double **u, double **rhs, int n); +float revcst(float x[], float y[], int iorder[], int ncity, int n[]); +void reverse(int iorder[], int ncity, int n[]); +float rf(float x, float y, float z); +float rj(float x, float y, float z, float p); +void rk4(float y[], float dydx[], int n, float x, float h, float yout[], + void (*derivs)(float, float [], float [])); +void rkck(float y[], float dydx[], int n, float x, float h, + float yout[], float yerr[], void (*derivs)(float, float [], float [])); +void rkdumb(float vstart[], int nvar, float x1, float x2, int nstep, + void (*derivs)(float, float [], float [])); +void rkqs(float y[], float dydx[], int n, float *x, + float htry, float eps, float yscal[], float *hdid, float *hnext, + void (*derivs)(float, float [], float [])); +void rlft3(float ***data, float **speq, unsigned long nn1, + unsigned long nn2, unsigned long nn3, int isign); +float rofunc(float b); +void rotate(float **r, float **qt, int n, int i, float a, float b); +void rsolv(float **a, int n, float d[], float b[]); +void rstrct(double **uc, double **uf, int nc); +float rtbis(float (*func)(float), float x1, float x2, float xacc); +float rtflsp(float (*func)(float), float x1, float x2, float xacc); +float rtnewt(void (*funcd)(float, float *, float *), float x1, float x2, + float xacc); +float rtsafe(void (*funcd)(float, float *, float *), float x1, float x2, + float xacc); +float rtsec(float (*func)(float), float x1, float x2, float xacc); +void rzextr(int iest, float xest, float yest[], float yz[], float dy[], int nv); +void savgol(float c[], int np, int nl, int nr, int ld, int m); +void score(float xf, float y[], float f[]); +void scrsho(float (*fx)(float)); +float select(unsigned long k, unsigned long n, float arr[]); +float selip(unsigned long k, unsigned long n, float arr[]); +void shell(unsigned long n, float a[]); +void shoot(int n, float v[], float f[]); +void shootf(int n, float v[], float f[]); +void simp1(float **a, int mm, int ll[], int nll, int iabf, int *kp, + float *bmax); +void simp2(float **a, int n, int l2[], int nl2, int *ip, int kp, float *q1); +void simp3(float **a, int i1, int k1, int ip, int kp); +void simplx(float **a, int m, int n, int m1, int m2, int m3, int *icase, + int izrov[], int iposv[]); +void simpr(float y[], float dydx[], float dfdx[], float **dfdy, + int n, float xs, float htot, int nstep, float yout[], + void (*derivs)(float, float [], float [])); +void sinft(float y[], int n); +void slvsm2(double **u, double **rhs); +void slvsml(double **u, double **rhs); +void sncndn(float uu, float emmc, float *sn, float *cn, float *dn); +double snrm(unsigned long n, double sx[], int itol); +void sobseq(int *n, float x[]); +void solvde(int itmax, float conv, float slowc, float scalv[], + int indexv[], int ne, int nb, int m, float **y, float ***c, float **s); +void sor(double **a, double **b, double **c, double **d, double **e, + double **f, double **u, int jmax, double rjac); +void sort(unsigned long n, float arr[]); +void sort2(unsigned long n, float arr[], float brr[]); +void sort3(unsigned long n, float ra[], float rb[], float rc[]); +void spctrm(FILE *fp, float p[], int m, int k, int ovrlap); +void spear(float data1[], float data2[], unsigned long n, float *d, float *zd, + float *probd, float *rs, float *probrs); +void sphbes(int n, float x, float *sj, float *sy, float *sjp, float *syp); +void splie2(float x1a[], float x2a[], float **ya, int m, int n, float **y2a); +void splin2(float x1a[], float x2a[], float **ya, float **y2a, int m, int n, + float x1, float x2, float *y); +void spline(float x[], float y[], int n, float yp1, float ypn, float y2[]); +void splint(float xa[], float ya[], float y2a[], int n, float x, float *y); +void spread(float y, float yy[], unsigned long n, float x, int m); +void sprsax(float sa[], unsigned long ija[], float x[], float b[], + unsigned long n); +void sprsin(float **a, int n, float thresh, unsigned long nmax, float sa[], + unsigned long ija[]); +void sprspm(float sa[], unsigned long ija[], float sb[], unsigned long ijb[], + float sc[], unsigned long ijc[]); +void sprstm(float sa[], unsigned long ija[], float sb[], unsigned long ijb[], + float thresh, unsigned long nmax, float sc[], unsigned long ijc[]); +void sprstp(float sa[], unsigned long ija[], float sb[], unsigned long ijb[]); +void sprstx(float sa[], unsigned long ija[], float x[], float b[], + unsigned long n); +void stifbs(float y[], float dydx[], int nv, float *xx, + float htry, float eps, float yscal[], float *hdid, float *hnext, + void (*derivs)(float, float [], float [])); +void stiff(float y[], float dydx[], int n, float *x, + float htry, float eps, float yscal[], float *hdid, float *hnext, + void (*derivs)(float, float [], float [])); +void stoerm(float y[], float d2y[], int nv, float xs, + float htot, int nstep, float yout[], + void (*derivs)(float, float [], float [])); +void svbksb(float **u, float w[], float **v, int m, int n, float b[], + float x[]); +void svdcmp(float **a, int m, int n, float w[], float **v); +void svdfit(float x[], float y[], float sig[], int ndata, float a[], + int ma, float **u, float **v, float w[], float *chisq, + void (*funcs)(float, float [], int)); +void svdvar(float **v, int ma, float w[], float **cvm); +void toeplz(float r[], float x[], float y[], int n); +void tptest(float data1[], float data2[], unsigned long n, float *t, float *prob); +void tqli(float d[], float e[], int n, float **z); +float trapzd(float (*func)(float), float a, float b, int n); +void tred2(float **a, int n, float d[], float e[]); +void tridag(float a[], float b[], float c[], float r[], float u[], + unsigned long n); +float trncst(float x[], float y[], int iorder[], int ncity, int n[]); +void trnspt(int iorder[], int ncity, int n[]); +void ttest(float data1[], unsigned long n1, float data2[], unsigned long n2, + float *t, float *prob); +void tutest(float data1[], unsigned long n1, float data2[], unsigned long n2, + float *t, float *prob); +void twofft(float data1[], float data2[], float fft1[], float fft2[], + unsigned long n); +void vander(double x[], double w[], double q[], int n); +void vegas(float regn[], int ndim, float (*fxn)(float [], float), int init, + unsigned long ncall, int itmx, int nprn, float *tgral, float *sd, + float *chi2a); +void voltra(int n, int m, float t0, float h, float *t, float **f, + float (*g)(int, float), float (*ak)(int, int, float, float)); +void wt1(float a[], unsigned long n, int isign, + void (*wtstep)(float [], unsigned long, int)); +void wtn(float a[], unsigned long nn[], int ndim, int isign, + void (*wtstep)(float [], unsigned long, int)); +void wwghts(float wghts[], int n, float h, + void (*kermom)(double [], double ,int)); +int zbrac(float (*func)(float), float *x1, float *x2); +void zbrak(float (*fx)(float), float x1, float x2, int n, float xb1[], + float xb2[], int *nb); +float zbrent(float (*func)(float), float x1, float x2, float tol); +void zrhqr(float a[], int m, float rtr[], float rti[]); +float zriddr(float (*func)(float), float x1, float x2, float xacc); +void zroots(fcomplex a[], int m, fcomplex roots[], int polish); + +#endif /* _NR_H_ */ diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nrutil.c b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nrutil.c new file mode 100644 index 00000000..059dce54 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nrutil.c @@ -0,0 +1,321 @@ +/* CAUTION: This is the ANSI C (only) version of the Numerical Recipes + utility file nrutil.c. Do not confuse this file with the same-named + file nrutil.c that is supplied in the 'misc' subdirectory. + *That* file is the one from the book, and contains both ANSI and + traditional K&R versions, along with #ifdef macros to select the + correct version. *This* file contains only ANSI C. */ + +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#define NR_END 1 +#define FREE_ARG char* + +void nrerror(char error_text[]) +/* Numerical Recipes standard error handler */ +{ + fprintf(stderr,"Numerical Recipes run-time error...\n"); + fprintf(stderr,"%s\n",error_text); + fprintf(stderr,"...now exiting to system...\n"); + exit(1); +} + +float *vector(long nl, long nh) +/* allocate a float vector with subscript range v[nl..nh] */ +{ + float *v; + + v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float))); + if (!v) nrerror("allocation failure in vector()"); + return v-nl+NR_END; +} + +int *ivector(long nl, long nh) +/* allocate an int vector with subscript range v[nl..nh] */ +{ + int *v; + + v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int))); + if (!v) nrerror("allocation failure in ivector()"); + return v-nl+NR_END; +} + +unsigned char *cvector(long nl, long nh) +/* allocate an unsigned char vector with subscript range v[nl..nh] */ +{ + unsigned char *v; + + v=(unsigned char *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(unsigned char))); + if (!v) nrerror("allocation failure in cvector()"); + return v-nl+NR_END; +} + +unsigned long *lvector(long nl, long nh) +/* allocate an unsigned long vector with subscript range v[nl..nh] */ +{ + unsigned long *v; + + v=(unsigned long *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(long))); + if (!v) nrerror("allocation failure in lvector()"); + return v-nl+NR_END; +} + +double *dvector(long nl, long nh) +/* allocate a double vector with subscript range v[nl..nh] */ +{ + double *v; + + v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double))); + if (!v) nrerror("allocation failure in dvector()"); + return v-nl+NR_END; +} + +float **matrix(long nrl, long nrh, long ncl, long nch) +/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +double **dmatrix(long nrl, long nrh, long ncl, long nch) +/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + double **m; + + /* allocate pointers to rows */ + m=(double **) malloc((size_t)((nrow+NR_END)*sizeof(double*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + /* allocate rows and set pointers to them */ + m[nrl]=(double *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(double))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +int **imatrix(long nrl, long nrh, long ncl, long nch) +/* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */ +{ + long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; + int **m; + + /* allocate pointers to rows */ + m=(int **) malloc((size_t)((nrow+NR_END)*sizeof(int*))); + if (!m) nrerror("allocation failure 1 in matrix()"); + m += NR_END; + m -= nrl; + + + /* allocate rows and set pointers to them */ + m[nrl]=(int *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(int))); + if (!m[nrl]) nrerror("allocation failure 2 in matrix()"); + m[nrl] += NR_END; + m[nrl] -= ncl; + + for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch, + long newrl, long newcl) +/* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */ +{ + long i,j,nrow=oldrh-oldrl+1,ncol=oldcl-newcl; + float **m; + + /* allocate array of pointers to rows */ + m=(float **) malloc((size_t) ((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure in submatrix()"); + m += NR_END; + m -= newrl; + + /* set pointers to rows */ + for(i=oldrl,j=newrl;i<=oldrh;i++,j++) m[j]=a[i]+ncol; + + /* return pointer to array of pointers to rows */ + return m; +} + +float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch) +/* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix +declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 +and ncol=nch-ncl+1. The routine should be called with the address +&a[0][0] as the first argument. */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1; + float **m; + + /* allocate pointers to rows */ + m=(float **) malloc((size_t) ((nrow+NR_END)*sizeof(float*))); + if (!m) nrerror("allocation failure in convert_matrix()"); + m += NR_END; + m -= nrl; + + /* set pointers to rows */ + m[nrl]=a-ncl; + for(i=1,j=nrl+1;i<nrow;i++,j++) m[j]=m[j-1]+ncol; + /* return pointer to array of pointers to rows */ + return m; +} + +double **convert_dmatrix(double *a, long nrl, long nrh, long ncl, long nch) +/* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix +declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 +and ncol=nch-ncl+1. The routine should be called with the address +&a[0][0] as the first argument. */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1; + double **m; + + /* allocate pointers to rows */ + m=(double **) malloc((size_t) ((nrow+NR_END)*sizeof(double*))); + if (!m) nrerror("allocation failure in convert_dmatrix()"); + m += NR_END; + m -= nrl; + + /* set pointers to rows */ + m[nrl]=a-ncl; + for(i=1,j=nrl+1;i<nrow;i++,j++) m[j]=m[j-1]+ncol; + /* return pointer to array of pointers to rows */ + return m; +} + +float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh) +/* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */ +{ + long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1; + float ***t; + + /* allocate pointers to pointers to rows */ + t=(float ***) malloc((size_t)((nrow+NR_END)*sizeof(float**))); + if (!t) nrerror("allocation failure 1 in f3tensor()"); + t += NR_END; + t -= nrl; + + /* allocate pointers to rows and set pointers to them */ + t[nrl]=(float **) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float*))); + if (!t[nrl]) nrerror("allocation failure 2 in f3tensor()"); + t[nrl] += NR_END; + t[nrl] -= ncl; + + /* allocate rows and set pointers to them */ + t[nrl][ncl]=(float *) malloc((size_t)((nrow*ncol*ndep+NR_END)*sizeof(float))); + if (!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()"); + t[nrl][ncl] += NR_END; + t[nrl][ncl] -= ndl; + + for(j=ncl+1;j<=nch;j++) t[nrl][j]=t[nrl][j-1]+ndep; + for(i=nrl+1;i<=nrh;i++) { + t[i]=t[i-1]+ncol; + t[i][ncl]=t[i-1][ncl]+ncol*ndep; + for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep; + } + + /* return pointer to array of pointers to rows */ + return t; +} + +void free_vector(float *v, long nl, long nh) +/* free a float vector allocated with vector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_ivector(int *v, long nl, long nh) +/* free an int vector allocated with ivector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_cvector(unsigned char *v, long nl, long nh) +/* free an unsigned char vector allocated with cvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_lvector(unsigned long *v, long nl, long nh) +/* free an unsigned long vector allocated with lvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_dvector(double *v, long nl, long nh) +/* free a double vector allocated with dvector() */ +{ + free((FREE_ARG) (v+nl-NR_END)); +} + +void free_matrix(float **m, long nrl, long nrh, long ncl, long nch) +/* free a float matrix allocated by matrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch) +/* free a double matrix allocated by dmatrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch) +/* free an int matrix allocated by imatrix() */ +{ + free((FREE_ARG) (m[nrl]+ncl-NR_END)); + free((FREE_ARG) (m+nrl-NR_END)); +} + +void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch) +/* free a submatrix allocated by submatrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch) +/* free a matrix allocated by convert_matrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_convert_dmatrix(double **b, long nrl, long nrh, long ncl, long nch) +/* free a matrix allocated by convert_matrix() */ +{ + free((FREE_ARG) (b+nrl-NR_END)); +} + +void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch, + long ndl, long ndh) +/* free a float f3tensor allocated by f3tensor() */ +{ + free((FREE_ARG) (t[nrl][ncl]+ndl-NR_END)); + free((FREE_ARG) (t[nrl]+ncl-NR_END)); + free((FREE_ARG) (t+nrl-NR_END)); +} diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nrutil.h b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nrutil.h new file mode 100644 index 00000000..45b1447f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/nrutil.h @@ -0,0 +1,79 @@ +/* CAUTION: This is the ANSI C (only) version of the Numerical Recipes + utility file nrutil.h. Do not confuse this file with the same-named + file nrutil.h that is supplied in the 'misc' subdirectory. + *That* file is the one from the book, and contains both ANSI and + traditional K&R versions, along with #ifdef macros to select the + correct version. *This* file contains only ANSI C. */ + +#ifndef _NR_UTILS_H_ +#define _NR_UTILS_H_ + +static float sqrarg; +#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) + +static double dsqrarg; +#define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg) + +static double dmaxarg1,dmaxarg2; +#define DMAX(a,b) (dmaxarg1=(a),dmaxarg2=(b),(dmaxarg1) > (dmaxarg2) ?\ + (dmaxarg1) : (dmaxarg2)) + +static double dminarg1,dminarg2; +#define DMIN(a,b) (dminarg1=(a),dminarg2=(b),(dminarg1) < (dminarg2) ?\ + (dminarg1) : (dminarg2)) + +static float maxarg1,maxarg2; +#define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ + (maxarg1) : (maxarg2)) + +static float minarg1,minarg2; +#define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\ + (minarg1) : (minarg2)) + +static long lmaxarg1,lmaxarg2; +#define LMAX(a,b) (lmaxarg1=(a),lmaxarg2=(b),(lmaxarg1) > (lmaxarg2) ?\ + (lmaxarg1) : (lmaxarg2)) + +static long lminarg1,lminarg2; +#define LMIN(a,b) (lminarg1=(a),lminarg2=(b),(lminarg1) < (lminarg2) ?\ + (lminarg1) : (lminarg2)) + +static int imaxarg1,imaxarg2; +#define IMAX(a,b) (imaxarg1=(a),imaxarg2=(b),(imaxarg1) > (imaxarg2) ?\ + (imaxarg1) : (imaxarg2)) + +static int iminarg1,iminarg2; +#define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ + (iminarg1) : (iminarg2)) + +#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) + +void nrerror(char error_text[]); +float *vector(long nl, long nh); +int *ivector(long nl, long nh); +unsigned char *cvector(long nl, long nh); +unsigned long *lvector(long nl, long nh); +double *dvector(long nl, long nh); +float **matrix(long nrl, long nrh, long ncl, long nch); +double **dmatrix(long nrl, long nrh, long ncl, long nch); +int **imatrix(long nrl, long nrh, long ncl, long nch); +float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch, + long newrl, long newcl); +float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch); +double **convert_dmatrix(double *a, long nrl, long nrh, long ncl, long nch); +float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh); +void free_vector(float *v, long nl, long nh); +void free_ivector(int *v, long nl, long nh); +void free_cvector(unsigned char *v, long nl, long nh); +void free_lvector(unsigned long *v, long nl, long nh); +void free_dvector(double *v, long nl, long nh); +void free_matrix(float **m, long nrl, long nrh, long ncl, long nch); +void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch); +void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch); +void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch); +void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch); +void free_convert_dmatrix(double **b, long nrl, long nrh, long ncl, long nch); +void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch, + long ndl, long ndh); + +#endif /* _NR_UTILS_H_ */ diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/quickscore.m b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/quickscore.m new file mode 100644 index 00000000..1a9b534a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/private/quickscore.m @@ -0,0 +1,76 @@ +function prob = quickscore(fpos, fneg, inhibit, prior, leak) +% QUICKSCORE Heckerman's algorithm for BN2O networks. +% prob = quickscore(fpos, fneg, inhibit, prior, leak) +% +% Consider a BN2O (Binary Node 2-layer Noisy-or) network such as QMR with +% dieases on the top and findings on the bottom. (We assume all findings are observed, +% since hidden leaves can be marginalized away.) +% This algorithm takes O(2^|fpos|) time to compute the marginal on all the diseases. +% +% Inputs: +% fpos = the positive findings (a vector of numbers in {1, ..., Nfindings}) +% fneg = the negative findings (a vector of numbers in {1, ..., Nfindings}) +% inhibit(i,j) = inhibition prob. for finding i, disease j, or 1.0 if j is not a parent. +% prior(j) = prior prob. disease j is ON. We assume prior(off) = 1-prior(on). +% leak(i) = inhibition prob. for the leak node for finding i +% +% Output: +% prob(d) = Pr(disease d = on | ev) +% +% For details, see +% - Heckerman, "A tractable inference algorithm for diagnosing multiple diseases", UAI89. +% - Rish and Dechter, "On the impact of causal independence", UCI tech report, 1998. +% +% Note that this algorithm is numerically unstable, since it adds a large number of positive and +% negative terms and hopes that some of them exactly cancel. +% +% For matlab experts, use 'mex' to compile C_quickscore, which has identical behavior to this function. + +[nfindings ndiseases] = size(inhibit); + +% make the first disease be always on, for the leak term +Pon = [1 prior(:)']; +Poff = 1-Pon; +Uon = [leak(:) inhibit]; % U(f,d) = Pr(f=0|d=1) +Uoff = [leak(:) ones(nfindings, ndiseases)]; % Uoff(f,d) = Pr(f=0|d=0) +ndiseases = ndiseases + 1; + +npos = length(fpos); +post = zeros(ndiseases, 2); +% post(d,1) = alpha Pr(d=off), post(d,2) = alpha Pr(d=m) + +FP = length(fpos); +%allbits = logical(dec2bitv(0:(2^FP - 1), FP)); +allbits = logical(ind2subv(2*ones(1,FP), 1:(2^FP))-1); + +for si=1:2^FP + bits = allbits(si,:); + fprime = fpos(bits); + fmask = zeros(1, nfindings); + fmask(fneg)=1; + fmask(fprime)=1; + fmask = logical(fmask); + p = 1; + pterm = zeros(1, ndiseases); + ptermOff = zeros(1, ndiseases); + ptermOn = zeros(1, ndiseases); + for d=1:ndiseases + ptermOff(d) = prod(Uoff(fmask,d)); + ptermOn(d) = prod(Uon(fmask,d)); + pterm(d) = Poff(d)*ptermOff(d) + Pon(d)*ptermOn(d); + end + p = prod(pterm); + sign = (-1)^(length(fprime)); + for d=1:ndiseases + myp = p / pterm(d); + post(d,1) = post(d,1) + sign*(myp * ptermOff(d)); + post(d,2) = post(d,2) + sign*(myp * ptermOn(d)); + end +end + +post(:,1) = post(:,1) .* Poff(:); +post(:,2) = post(:,2) .* Pon(:); +post = mk_stochastic(post); +prob = post(2:end,2)'; % skip the leak term + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/quickscore_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/quickscore_inf_engine.m new file mode 100644 index 00000000..a9463c40 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@quickscore_inf_engine/quickscore_inf_engine.m @@ -0,0 +1,38 @@ +function engine = quickscore_inf_engine(inhibit, leak, prior) +% QUICKSCORE_INF_ENGINE Exact inference for the QMR network +% engine = quickscore_inf_engine(inhibit, leak, prior) +% +% We create an inference engine for QMR-like networks. +% QMR is a bipartite graph, where the top layer contains hidden disease nodes, +% and the bottom later contains observed finding nodes. +% The diseases have Bernoulli CPDs, the findings noisy-or CPDs. +% The original QMR (Quick Medical Reference) network has specific parameter values which we are not +% allowed to release, for commercial reasons. +% +% inhibit(f,d) = inhibition probability on f->d arc for disease d, finding f +% If inhibit(f,d) = 1, there is effectively no arc from d->f +% leak(j) = inhibition prob. on leak node -> finding j arc +% prior(i) = prob. disease i is on +% +% We use exact inference, which takes O(2^P) time, where P is the number of positive findings. +% For details, see +% - Heckerman, "A tractable inference algorithm for diagnosing multiple diseases", UAI 89. +% - Rish and Dechter, "On the impact of causal independence", UCI tech report, 1998. +% Note that this algorithm is numerically unstable, since it adds a large number of positive and +% negative terms and hopes that some of them exactly cancel. +% +% For an interesting variational approximation, see +% - Jaakkola and Jordan, "Variational probabilistic inference and the QMR-DT network", JAIR 10, 1999. +% +% See also +% - "Loopy belief propagation for approximate inference: an empirical study", +% K. Murphy, Y. Weiss and M. Jordan, UAI 99. + +engine.inhibit = inhibit; +engine.leak = leak; +engine.prior = prior; + +% store results here between enter_evidence and marginal_nodes +engine.post = []; + +engine = class(engine, 'quickscore_inf_engine'); % not a child of the inf_engine class! diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Entries new file mode 100644 index 00000000..055aa4df --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Entries @@ -0,0 +1,11 @@ +/README/1.1.1.1/Sun May 11 15:39:50 2003// +/clq_containing_nodes.m/1.1.1.1/Wed May 29 11:59:46 2002// +/enter_evidence.m/1.1.1.1/Wed Mar 12 10:38:00 2003// +/marginal_difclq_nodes.m/1.1.1.1/Fri Feb 21 11:20:32 2003// +/marginal_nodes.m/1.1.1.1/Fri Feb 21 11:13:10 2003// +/marginal_singleclq_nodes.m/1.1.1.1/Wed Jan 29 11:23:58 2003// +/problems.txt/1.1.1.1/Wed May 29 11:59:46 2002// +/push.m/1.1.1.1/Mon Feb 10 15:38:04 2003// +/push_pot_toclique.m/1.1.1.1/Wed May 29 11:59:46 2002// +/stab_cond_gauss_inf_engine.m/1.1.1.1/Fri Mar 28 17:12:42 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Entries.Log new file mode 100644 index 00000000..24f16336 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Entries.Log @@ -0,0 +1 @@ +A D/Old//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Repository new file mode 100644 index 00000000..849daef7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@stab_cond_gauss_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Entries new file mode 100644 index 00000000..ce0c4813 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Entries @@ -0,0 +1,2 @@ +/initialize_engine.m/1.1.1.1/Wed May 29 11:59:46 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Repository new file mode 100644 index 00000000..eb292815 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@stab_cond_gauss_inf_engine/Old diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/initialize_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/initialize_engine.m new file mode 100644 index 00000000..6fb51c2e --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/Old/initialize_engine.m @@ -0,0 +1,65 @@ +function [engine, loglik] = initialize_engine(engine) +%initialize +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +N = length(bnet.dag); + +pot_type = 'scg' +check_for_cd_arcs([], bnet.cnodes, bnet.dag); + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N); +C = length(engine.cliques); +inited = zeros(1, C); +clpot = cell(1, C); +evidence = cell(1, N); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + pot{n} = CPD_to_scgpot(bnet.CPD{e}, fam, ns, bnet.cnodes, evidence); + cindex = engine.clq_ass_to_node(n); + if inited(cindex) + %clpot{cindex} = direct_combine_pots(clpot{cindex}, pot{n}); + clpot{cindex} = direct_combine_pots(pot{n}, clpot{cindex}); + else + clpot{cindex} = pot{n}; + inited(cindex) = 1; + end +end + +for i=1:C + if inited(i) == 0 + clpot{i} = scgpot([], [], [], []); + end +end + +seppot = cell(C, C); +% separators are is not need to initialize + +% collect to root (node to parents) +for n=engine.postorder(1:end-1) + for p=parents(engine.jtree, n) + [margpot, comppot] = complement_pot(clpot{n}, engine.separator{p,n}); + margpot = marginalize_pot(clpot{n}, engine.separator{p,n}); + clpot{n} = comppot; + %seppot{p, n} = margpot; + clpot{p} = combine_pots(clpot{p}, margpot); + %clpot{p} = combine_pots(margpot, clpot{p}); + end +end + +temppot = clpot; +%temppot = clpot{engine.root}; +for n=engine.preorder + for c=children(engine.jtree, n) + seppot{n,c} = marginalize_pot(temppot{n}, engine.separator{n,c}); + %seppot{n,c} = marginalize_pot(clpot{n}, engine.separator{n,c}); + %clpot{c} = direct_combine_pots(clpot{c}, seppot{n,c}); + temppot{c} = direct_combine_pots(temppot{c}, seppot{n,c}); + end +end + +engine.clpot = clpot; +engine.seppot = seppot; + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/README b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/README new file mode 100644 index 00000000..e905e28c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/README @@ -0,0 +1,12 @@ +% Stable conditional Gaussian inference +% Originally written by Huang, Shan <shan.huang@intel.com> 2001 +% Fixed by Rainer Deventer 2003 + + +@techreport{Lauritzen99, + author = "S. Lauritzen and F. Jensen", + title = "Stable Local Computation with Conditional {G}aussian Distributions", + year = 1999, + number = "R-99-2014", + institution = "Dept. Math. Sciences, Aalborg Univ." +} diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/clq_containing_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/clq_containing_nodes.m new file mode 100644 index 00000000..c64d2bff --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/clq_containing_nodes.m @@ -0,0 +1,24 @@ +function c = clq_containing_nodes(engine, nodes, fam) +% CLQ_CONTAINING_NODES Find the lightest clique (if any) that contains the set of nodes +% c = clq_containing_nodes(engine, nodes, family) +% +% If the optional 'family' argument is specified, it means nodes = family(nodes(end)). +% (This is useful since clq_ass_to_node is not accessible to outsiders.) +% Returns c=-1 if there is no such clique. + +if nargin < 3, fam = 0; else fam = 1; end + +if length(nodes)==1 + c = engine.clq_ass_to_node(nodes(1)); +elseif fam + c = engine.clq_ass_to_node(nodes(end)); +else + B = engine.cliques_bitv; + w = engine.clique_weight; + clqs = find(all(B(:,nodes), 2)); % all selected columns must be 1 + if isempty(clqs) + c = -1; + else + c = clqs(argmin(w(clqs))); + end +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/enter_evidence.m new file mode 100644 index 00000000..4b02fc8f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/enter_evidence.m @@ -0,0 +1,260 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE enter evidence to engine including discrete and continuous evidence +% [engine, ll] = enter_evidence(engine, evidence) +% +% ll is always 0, which is wrong. + +if ~isempty(engine.evidence) + bnet = bnet_from_engine(engine); + engine = stab_cond_gauss_inf_engine(bnet); + engine.evidence = evidence; +else + engine.evidence = evidence; + bnet = bnet_from_engine(engine); +end + +engine.evidence = evidence; +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes(:); +observed = ~isemptycell(evidence); +onodes = find(observed); +hnodes = find(isemptycell(evidence)); +cobs = myintersect(bnet.cnodes, onodes); +dobs = myintersect(bnet.dnodes, onodes); + +engine = incorporate_dis_evidence(engine, dobs, evidence); +l = length(cobs); +for i = 1:l + node = cobs(i); + engine = incorporate_singleconts_evidence(engine, node, evidence); +end +clpot = engine.clpot; + +clq_num = length(engine.cliques); +for n=engine.postorder(1:end-1) + for p=parents(engine.jtree, n) + [margpot, comppot] = complement_pot(clpot{n}, engine.separator{p,n}); + clpot{n} = comppot; + clpot{p} = combine_pots(clpot{p}, margpot); + end +end + +temppot = clpot; +for n=engine.preorder + for c=children(engine.jtree, n) + seppot{n,c} = marginalize_pot(temppot{n}, engine.separator{n,c}); + temppot{c} = direct_combine_pots(temppot{c}, seppot{n,c}); + end +end +engine.clpot = clpot; +engine.seppot = seppot; + +[pot,loglik]=normalize_pot(clpot{engine.root}); + +%%%%%%%%%%%%%%%%%% +function engine = incorporate_dis_evidence(engine, donodes, evidence) +l = length(donodes); +for i=donodes(:)' + node = i; + clqid = engine.clq_ass_to_node(node); + pot = struct(engine.clpot{clqid}); + ns = zeros(1, max(pot.domain)); + ns(pot.ddom) = pot.dsizes; + ns(pot.cheaddom) = pot.cheadsizes; + ns(pot.ctaildom) = pot.ctailsizes; + ddom = pot.ddom; + + potcarray = cell(1, pot.dsize); + for j =1:pot.dsize + tpotc = struct(pot.scgpotc{j}); + potcarray{j} = scgcpot(tpotc.cheadsize, tpotc.ctailsize, 0, tpotc.A, tpotc.B, tpotc.C); + end + + if length(ns(ddom)) == 1 + matrix = pot.scgpotc; + else + matrix = reshape(pot.scgpotc,ns(ddom)); + potcarray = reshape(potcarray, ns(ddom)); + end + + map = find_equiv_posns(node, ddom); + vals = cat(1, evidence{node}); + index = mk_multi_index(length(ddom), map, vals); + potcarray(index{:}) = matrix(index{:}); + potcarray = potcarray(:); + %keyboard; + engine.clpot{clqid} = scgpot(pot.ddom, pot.cheaddom, pot.ctaildom, ns, potcarray); +end + +%%%%%%%%%%%%%%%%%% +function engine = incorporate_singleconts_evidence(engine, node, evidence) +%incorporate_singleconts_evidence incorporate evidence of 1 continuous node +B = engine.cliques_bitv; +clqs_containnode = find(all(B(:,node), 2)); % all selected columns must be 1 +% Every continuous node necessarily apears as head in exactly one clique, +% which is the clique where it appears closest to the strong root. In all other +% clique potentials where it appears, it must be a tail node. +clq_ev_as_head = []; +for i = clqs_containnode(:)' + pot = struct(engine.clpot{i}); + if myismember(node, pot.cheaddom) + clq_ev_as_head = [clq_ev_as_head i]; + break; + end +end + +% If we will incorporate the evidence node which is head of a potential we must rearrange +% the juntion tree by push operation until the tail of the include potential is empty +if ~isempty(clq_ev_as_head) + assert(1 == length(clq_ev_as_head)); + i = clq_ev_as_head; + pot = struct(engine.clpot{i}); + while ~isempty(pot.ctaildom) + [engine, clqtoroot] = push(engine, i, node); + i = clqtoroot; + pot = struct(engine.clpot{i}); + end + B = engine.cliques_bitv; + clqs_containnode = find(all(B(:,node), 2)); +end + +for i = clqs_containnode(:)' + pot = struct(engine.clpot{i}); + if myismember(node, pot.cheaddom) + engine.clpot{i} = incoporate_evidence_headnode(engine.clpot{i}, node, evidence); + else + %assert(myismember(node, pot.ctaildom)); + engine.clpot{i} = incoporate_evidence_tailnode(engine.clpot{i}, node, evidence); + end +end + +%%%%%%%%%%%%%%%%%% +function newscgpot = incoporate_evidence_tailnode(pot, node, evidence) +%ENTER_EVIDENCE_TAILNODE enter the evidence of 1 tailnode of the scgpot +newscgpot = pot; +pot = struct(pot); +%if isempty(pot.ctaildom) +if ~myismember(node, pot.ctaildom) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % In this case there is no real dependency of the head nodes % + % on the tail. The potential should be returned unchanged % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + return; +end +%newscgpot = scgpot([], [], [], []); +assert(myismember(node, pot.ctaildom)); +ni = block(find_equiv_posns(node, pot.ctaildom), pot.ctailsizes); + +ctaildom = mysetdiff(pot.ctaildom, node); +cheaddom = pot.cheaddom; +ddom = pot.ddom; +domain = mysetdiff(pot.domain, node); +dsize = pot.dsize; +ns = zeros(1, max(pot.domain)); +ns(pot.ddom) = pot.dsizes; +ns(pot.cheaddom) = pot.cheadsizes; +ns(pot.ctaildom) = pot.ctailsizes; +cheadsizes = pot.cheadsizes; +cheadsize = pot.cheadsize; +ctailsizes = ns(ctaildom); +ctailsize = sum(ns(ctaildom)); + +potarray = cell(1, dsize); +for i=1:dsize + potc = struct(pot.scgpotc{i}); + B = potc.B; + A = potc.A + B(:, ni)*evidence{node}; + B(:, ni) = []; + potarray{i} = scgcpot(cheadsize, ctailsize, potc.p, A, B, potc.C); +end + +newscgpot = scgpot(ddom, cheaddom, ctaildom, ns, potarray); + +%%%%%%%%%%%%%%%% +function newscgpot = incoporate_evidence_headnode(pot, node, evidence) +%ENTER_EVIDENCE_HEADNODE +pot = struct(pot); +y2 = evidence{node}; +assert(myismember(node, pot.cheaddom)); +assert(isempty(pot.ctaildom)); +ddom = pot.ddom; +cheaddom = mysetdiff(pot.cheaddom, node); +ctaildom = pot.ctaildom; +dsize = pot.dsize; +domain = mysetdiff(pot.domain, node); + +ns = zeros(1, max(pot.domain)); +ns(pot.ddom) = pot.dsizes; +ns(pot.cheaddom) = pot.cheadsizes; +ns(pot.ctaildom) = pot.ctailsizes; +ctailsizes = ns(ctaildom); +ctailsize = sum(ctailsizes); +cheadsizes = ns(cheaddom); +cheadsize = sum(cheadsizes); +onodesize = ns(node); + +p = zeros(1,dsize); +A1 = zeros(cheadsize, dsize); +A2 = zeros(onodesize, dsize); +C11 = zeros(cheadsize, cheadsize, dsize); +C12 = zeros(cheadsize, onodesize, dsize); +C21 = zeros(onodesize, cheadsize, dsize); +C22 = zeros(onodesize, onodesize, dsize); +ZM = zeros(onodesize, onodesize); + +n1i = block(find_equiv_posns(cheaddom, pot.cheaddom), pot.cheadsizes); +n2i = block(find_equiv_posns(node, pot.cheaddom), pot.cheadsizes); + +indic = 0; +for i=1:dsize + potc = struct(pot.scgpotc{i}); + p(i) = potc.p; + if ~isempty(n1i) + A1(:,i) = potc.A(n1i); + end + if ~isempty(n2i) + A2(:,i) = potc.A(n2i); + end + C11(:,:,i) = potc.C(n1i, n1i); + C12(:,:,i) = potc.C(n1i, n2i); + C21(:,:,i) = potc.C(n2i, n1i); + C22(:,:,i) = potc.C(n2i, n2i); + if isequal(0, C22(:,:,i)) & isequal(evidence{node}, A2(:, i)) + indic = i; + end +end + +np = zeros(1,dsize); +nA = zeros(cheadsize, dsize); +nC = zeros(cheadsize, cheadsize, dsize); + +if indic + np(:) = 0; + np(indic) = p(indic); + nA = A1; + nC = C11; +else + for i=1:dsize + if isequal(0, C22(:,:,i)) + p(i) = 0; + nA(:, i) = A1(:, i); + nC(:,:,i) = C11(:,:,i); + else + sq = (y2 - A2(:,i))' * inv(C22(:,:,i)) * (y2 - A2(:,i)); + ex = exp(-0.5*sq); + %np(i) = p(i) * ex / ( (2 * pi)^(-onodesize/2) * sqrt(det(C22(:,:,i))) ); + np(i) = p(i) * ex / ( (2 * pi)^(onodesize/2) * sqrt(det(C22(:,:,i))) ); + nA(:,i) = A1(:,i) + C12(:,:,i) * inv(C22(:,:,i)) * (y2 - A2(:,i)); + tmp1 = C12(:,:,i) * inv(C22(:,:,i)) * C21(:,:,i); + nC(:,:,i) = C11(:,:,i) - tmp1; + end + end +end + +scpot = cell(1, dsize); +W = zeros(cheadsize,ctailsize); +for i=1:dsize + scpot{i} = scgcpot(cheadsize, ctailsize, np(i), nA(:,i), W, nC(:,:,i)); +end +ns(node) = 0; +newscgpot = scgpot(ddom, cheaddom, ctaildom, ns, scpot); diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_difclq_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_difclq_nodes.m new file mode 100644 index 00000000..e1cad6c7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_difclq_nodes.m @@ -0,0 +1,55 @@ +function marginal = marginal_difclq_nodes(engine, query_nodes) +% MARGINAL_DIFCLQ_NODES get the marginal distribution of nodes which is not in a single clique +% marginal = marginal_difclq_nodes(engine, query_nodes) + +keyboard +num_clique = length(engine.cliques); +B = engine.cliques_bitv; +clqs_containnodes = []; +for i=1:length(query_nodes) + node = query_nodes(i); + tnodes = find(all(B(:, node), 2)); + clqs_containnodes = myunion(clqs_containnodes, tnodes); +end +% get all cliques contains query nodes + +% get the minimal sub tree in junction which contains these cliques and the node closest to the root of jtree +[subtree, nroot_node] = min_subtree_conti_nodes(engine.jtree, engine.root, clqs_containnodes); +if ~mysubset(query_nodes, engine.cliques{nroot_node}); + % if query nodes is not all memers of the clique closest to the root clique performe push operation + engine = push_tree(engine, subtree, query_nodes, nroot_node); +end + +if ~(nroot_node == engine.root) + % if the clique closest to the root clique is not the root clique we must direct combine the + % potential with the potential stored in separator toward to root + p = parents(engine.jtree, nroot_node); + tpot = direct_combine_pots(engine.clpot{nroot_node}, engine.seppot{p, nroot_node}); +else + tpot = engine.clpot{nroot_node}; +end + +pot = marginalize_pot(tpot, query_nodes); +marginal = pot_to_marginal(pot); +marginal.T = normalise(marginal.T); + + + +function engine = push_tree(engine, tree, query_nodes, inode) +% PUSH_TREE recursive perform push opeartion on tree +% engine = push_tree(engine, tree, query_nodes, inode) + +cs = children(tree, inode); +for i = 1:length(cs) + node = cs(i); + push_tree(engine, tree, query_nodes, node); + push_dom = myintersect(engine.cliques{node}, query_nodes); + [engine, clqtoroot] = push(engine, node, push_dom); +end + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..063c2439 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_nodes.m @@ -0,0 +1,77 @@ +function marginal = marginal_nodes(engine, query, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (stab_cond_gauss) +% marginal = marginal_nodes(engine, query, add_ev) +% +% 'query' must be a singleton set. +% add_ev is an optional argument; if 1, we will "inflate" the marginal of observed nodes +% to their original size, adding 0s to the positions which contradict the evidence + +if nargin < 3, add_ev = 0; end +if isempty(engine.evidence) + hquery = query; +else + hquery = []; + for i = query + if isempty(engine.evidence{i}) + hquery = [hquery i]; + end + end +end + +bnet = bnet_from_engine(engine); + +nclq = length(engine.cliques); +clique = 0; +for i = 1:nclq + if mysubset(hquery, engine.cliques{i}) + pot = struct(engine.clpot{i}); + %if mysubset(hquery, pot.cheaddom) | mysubset(hquery, pot.ddom) + if mysubset(hquery, pot.domain) + clique = i; + break; + end + end +end + +if isempty(hquery) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % If all requested variables are observed, no query is necessary % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + marginal.mu = []; + marginal.Sigma = []; + marginal.T = 1.0; + marginal.domain = query; +else + if clique == 0 + marginal = marginal_difclq_nodes(engine, hquery); + else + marginal = marginal_singleclq_nodes(engine, clique, hquery); + end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Change the format of output, so that it is identical to the % + % format obtained by the same request for the junction-tree % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + marginal.domain = query; + bnet = bnet_from_engine(engine); + dquery = myintersect(bnet.dnodes,hquery); + ns = bnet.node_sizes(dquery); + if length(ns) == 0 + marginal.T = 1; + else + if length(ns) == 1 + ns = [1 ns]; + end + marginal.T = reshape(marginal.T,ns); + end +end +if add_ev + bnet = bnet_from_engine(engine); + %marginal = add_ev_to_dmarginal(marginal, engine.evidence, bnet.node_sizes); + marginal = add_evidence_to_gmarginal(marginal, engine.evidence, bnet.node_sizes, bnet.cnodes); +end + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_singleclq_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_singleclq_nodes.m new file mode 100644 index 00000000..d755617f --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_singleclq_nodes.m @@ -0,0 +1,30 @@ +function marginal = marginal_singleclq_nodes(engine, i, query) +% MARGINAL_SINGLECLQ_NODES get the marginal distribution of nodes which is in a single clique +% marginal = marginal_singleclq_nodes(engine, i, query) + +pot = struct(engine.clpot{i}); +if isempty(pot.ctaildom) + if i ~= engine.root + p = parents(engine.jtree, i); + tpot = direct_combine_pots(engine.clpot{i}, engine.seppot{p, i}); + else + tpot = engine.clpot{i}; + end + pot = marginalize_pot(tpot, query); + + marginal = pot_to_marginal(pot); + marginal.T = normalise(marginal.T); +else + [engine, clqtoroot] = push(engine, i, query); + if clqtoroot == engine.root + tpot = engine.clpot{clqtoroot}; + else + p = parents(engine.jtree, clqtoroot); + tpot = direct_combine_pots(engine.clpot{clqtoroot}, engine.seppot{p, clqtoroot}); + end + pot = marginalize_pot(tpot, query); + + marginal = pot_to_marginal(pot); + marginal.T = normalise(marginal.T); +end + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/problems.txt b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/problems.txt new file mode 100644 index 00000000..fa7c6be8 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/problems.txt @@ -0,0 +1,76 @@ +PROBLEMS WITH STAB_COND_GAUSS_INF_ENGINE + + +- enter_evidence always returns ll=0 + (I set ll=0 since it is not computed) + +- fails on scg_3node, probably because the engine needs to be +re-initialized every time before enter_evidence is called, not just +when the engine is constructed. + +??? Error using ==> assert +assertion violated: + +K>> dbstack +dbstack +> In /home/eecs/murphyk/matlab/BNT/HMM/assert.m at line 9 + In /home/eecs/murphyk/matlab/BNT/examples/static/SCG/scg_3node.m at line 45 + + + +- crashes on scg3 + +Error in ==> /home/eecs/murphyk/matlab/BNT/inference/static/@stab_cond_gauss_inf_engine/stab_cond_gauss_inf_engine.m +On line 77 ==> clpot{cindex} = direct_combine_pots(pot{n}, clpot{cindex}); + +K>> dbstack +dbstack +> In /home/eecs/murphyk/matlab/BNT/inference/static/@stab_cond_gauss_inf_engine/stab_cond_gauss_inf_engine.m at line 77 + In /home/eecs/murphyk/matlab/BNT/examples/static/SCG/scg3.m at line 41 +K>> + + + + + +- fails on scg1 and scg2 + +Warning: One or more output arguments not assigned during call to 'min_subtree_conti_nodes (nearsest_node2)'. +Warning in ==> /home/eecs/murphyk/matlab/BNT/graph/min_subtree_conti_nodes.m (nearsest_node2) +On line 60 ==> nea_node = nearsest_node2(tree, nodes, n); + +K>> dbstack +dbstack +> In /home/eecs/murphyk/matlab/BNT/graph/min_subtree_conti_nodes.m (nearsest_node2) at line 60 + In /home/eecs/murphyk/matlab/BNT/graph/min_subtree_conti_nodes.m (nearest_node) at line 50 + In /home/eecs/murphyk/matlab/BNT/graph/min_subtree_conti_nodes.m at line 11 + In /home/eecs/murphyk/matlab/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_difclq_nodes.m at line 17 + In /home/eecs/murphyk/matlab/BNT/inference/static/@stab_cond_gauss_inf_engine/marginal_nodes.m at line 23 + In /home/eecs/murphyk/matlab/BNT/examples/static/SCG/scg1.m at line 42 + + + + + +- This code fragment, from BNT/graph/min_subtree_conti_nodes, is clearly redundant + +function nea_node = nearest_node(tree, root, nodes) +%get the nearest node to the root in the tree +nea_node = nearsest_node2(tree, nodes, root); + +function nea_node = nearsest_node2(tree, nodes, inode) +if myismember(inode, nodes) + nea_node = inode; + return; +end +cs = children(tree, inode); +for i = 1:length(cs) + n = cs(i); + nea_node = nearsest_node2(tree, nodes, n); +end + + +- Some names are badly chosen. 'nearsest' is a mis-spelling. 'min_subtree_conti_nodes' should be +'min_subtree_containing_nodes' or 'min_subtree_con_nodes'. + +- In general, the code needs some heavy polishing. diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/push.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/push.m new file mode 100644 index 00000000..193bf722 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/push.m @@ -0,0 +1,38 @@ +function [engine, clqtoroot] = push(engine, clq, pushdom) +%PUSH_POT push the variables in putshdom which is subset of clq to the clique toword the root and get new engine +%pushdom is pushed variables set +%clq is the index of the clique that pushdom belongs to + +clqdom = engine.cliques{clq}; +assert( mysubset(pushdom, clqdom)); +clqtoroot = parents(engine.jtree, clq); +%sepdom = engine.separator{clq, clqtoroot}; +sepdom = engine.separator{clqtoroot, clq}; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Calculate the strong marginal of the union of pushdom and and the separatordomain and % +% the corresponding complement % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%[margpot, comppot] = complement_pot(engine.clpot{clq}, pushdom); +newsepdom = myunion(pushdom,sepdom); +[margpot,comppot] = complement_pot(engine.clpot{clq}, newsepdom); +engine.clpot{clqtoroot} = direct_combine_pots(engine.clpot{clqtoroot}, margpot); +engine.clpot{clq} = comppot; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Calculation of the new separator and separatorpotential of the junction tree % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +engine.seppot{clqtoroot, clq} = direct_combine_pots(engine.seppot{clqtoroot, clq}, margpot); +engine.separator{clqtoroot, clq} = myunion(engine.separator{clqtoroot, clq}, pushdom); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Add pushdomain to the clique towards the root % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +engine.cliques{clqtoroot} = myunion(engine.cliques{clqtoroot}, pushdom); + +num_cliques = length(engine.cliques); +B = sparse(num_cliques, 1); +for i=1:num_cliques + B(i, engine.cliques{i}) = 1; +end +engine.cliques_bitv = B; diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/push_pot_toclique.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/push_pot_toclique.m new file mode 100644 index 00000000..4bcd0ed0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/push_pot_toclique.m @@ -0,0 +1,7 @@ +function engine = push_pot_toclique(engine, clqtarget, clq, nodes) +% PUSH_POT push the variables in putshdom which is subset of clq to the target clique toword the root and get new engine +% engine = push_pot_toclique(engine, clqtarget, clq, nodes) +[engine, clqtoroot] = push_pot(engine, clq, nodes) +while clqtoroot ~= clqtarget + [engine, clqtoroot] = push_pot(engine, clqtoroot, nodes) +end \ No newline at end of file diff --git a/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/stab_cond_gauss_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/stab_cond_gauss_inf_engine.m new file mode 100644 index 00000000..42c47c6a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@stab_cond_gauss_inf_engine/stab_cond_gauss_inf_engine.m @@ -0,0 +1,178 @@ +function engine = stab_cond_gauss_inf_engine(bnet) +% STAB_COND_GAUSS_INF_ENGINE Junction tree using stable CG potentials +% engine = cond_gauss_inf_engine(bnet) +% +% This class was written by Shan Huang (shan.huang@intel.com) 2001 +% and fixed by Rainer Deventer deventer@informatik.uni-erlangen.de March 2003 +N = length(bnet.dag); +clusters = {}; +root = N; +stages = { 1:N }; +onodes = []; +engine = init_fields; +engine.evidence = []; +engine = class(engine, 'stab_cond_gauss_inf_engine', inf_engine(bnet)); + +ns = bnet.node_sizes(:); +ns(onodes) = 1; % observed nodes have only 1 possible value + +%[engine.jtree, dummy, engine.cliques, B, w, elim_order, moral_edges, fill_in_edges, strong] = ... +% dag_to_jtree(bnet, onodes, stages, clusters); + + +partial_order = determine_elim_constraints(bnet, onodes); +strong = ~isempty(partial_order); +stages = {}; +clusters = {}; +[engine.jtree, dummy_root, engine.cliques, B, w, elim_order] = + graph_to_jtree(moralize(bnet.dag), ns, partial_order, stages, clusters); + + +engine.cliques_bitv = B; +engine.clique_weight = w; +C = length(engine.cliques); +engine.clpot = cell(1,C); + +% A node can be a member of many cliques, but is assigned to exactly one, to avoid +% double-counting its CPD. We assign node i to clique c if c is the "lightest" clique that +% contains i's family, so it can accomodate its CPD. + +engine.clq_ass_to_node = zeros(1, N); +num_cliques = length(engine.cliques); +for i=1:N + clqs_containing_family = find(all(B(:,family(bnet.dag, i)), 2)); % all selected columns must be 1 + c = clqs_containing_family(argmin(w(clqs_containing_family))); + engine.clq_ass_to_node(i) = c; +end + +% Compute the separators between connected cliques. +[is,js] = find(engine.jtree > 0); +engine.separator = cell(num_cliques, num_cliques); +for k=1:length(is) + i = is(k); j = js(k); + engine.separator{i,j} = find(B(i,:) & B(j,:)); % intersect(cliques{i}, cliques{j}); +end +%keyboard; +engine.seppot = cell(C,C); + +pot_type = 'scg'; +check_for_cd_arcs([], bnet.cnodes, bnet.dag); + +% Make the jtree rooted, so there is a fixed message passing order. +if strong + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Start the search for the strong root at the clique with the % + % highest number. % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + root = length(engine.cliques); + root_found = 0; + + while ((~root_found) & (root >= 1)) + root_found = test_strong_root(engine.jtree,engine.cliques,bnet.dnodes,root); + if ~root_found + root = root - 1; + end + end + assert(root > 0) + engine.root = root; + % the last clique is guaranteed to be a strong root + %engine.root = length(engine.cliques); +else + % jtree_dbn_inf_engine requires the root to contain the interface. + % This may conflict with the strong root requirement! *********** BUG ************* + engine.root = clq_containing_nodes(engine, root); + if engine.root <= 0 + error(['no clique contains ' num2str(root)]); + end +end + +[engine.jtree, engine.preorder, engine.postorder] = mk_rooted_tree(engine.jtree, engine.root); + +% Evaluate CPDs with evidence, and convert to potentials +pot = cell(1, N); +inited = zeros(1, C); +clpot = cell(1, C); +evidence = cell(1, N); +for n=1:N + fam = family(bnet.dag, n); + e = bnet.equiv_class(n); + %pot{n} = CPD_to_scgpot(bnet.CPD{e}, fam, ns, bnet.cnodes, evidence); + pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence); + cindex = engine.clq_ass_to_node(n); + if inited(cindex) + clpot{cindex} = direct_combine_pots(pot{n}, clpot{cindex}); + else + clpot{cindex} = pot{n}; + inited(cindex) = 1; + end +end + +for i=1:C + if inited(i) == 0 + clpot{i} = scgpot([], [], [], []); + end +end + +seppot = cell(C, C); +% separators are is not need to initialize + +% collect to root (node to parents) +% Unlike the HUGIN architecture the complements are stored in the cliques during COLLECT +% and the separators are not playing a specific role during this process +for n=engine.postorder(1:end-1) + for p=parents(engine.jtree, n) + if ~isempty(engine.separator{p,n}) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % The empty case might happen for unlinked nodes, i.e. the DAG is not % + % a single tree, but a forest % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + [margpot, comppot] = complement_pot(clpot{n}, engine.separator{p,n}); + clpot{n} = comppot; + clpot{p} = combine_pots(clpot{p}, margpot); + end + end +end + +% distribute message from root +% We have not to store the weak clique marginals and keep the original complement potentials. +% This is a minor variation of HUGIN architecture. +temppot = clpot; +for n=engine.preorder + for c=children(engine.jtree, n) + seppot{n,c} = marginalize_pot(temppot{n}, engine.separator{n,c}); + temppot{c} = direct_combine_pots(temppot{c}, seppot{n,c}); + end +end + +engine.clpot = clpot; +engine.seppot = seppot; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% init_fields() % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function engine = init_fields() + +engine.evidence = []; +engine.jtree = []; +engine.cliques = []; +engine.cliques_bitv = []; +engine.clique_weight = []; +engine.preorder = []; +engine.postorder = []; +engine.root = []; +engine.clq_ass_to_node = []; +engine.separator = []; +engine.clpot =[]; +engine.seppot = []; + + + + + + + + + + + + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Entries new file mode 100644 index 00000000..0cfdeafe --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Entries @@ -0,0 +1,5 @@ +/enter_evidence.m/1.1.1.1/Wed Jun 19 22:05:04 2002// +/find_mpe.m/1.1.1.1/Wed Jun 19 22:11:42 2002// +/marginal_nodes.m/1.1.1.1/Thu Sep 30 03:09:00 2004// +/var_elim_inf_engine.m/1.1.1.1/Wed Jun 19 22:04:50 2002// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Repository new file mode 100644 index 00000000..8595410d --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static/@var_elim_inf_engine diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/enter_evidence.m b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/enter_evidence.m new file mode 100644 index 00000000..ed3fbe19 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/enter_evidence.m @@ -0,0 +1,12 @@ +function [engine, loglik] = enter_evidence(engine, evidence, varargin) +% ENTER_EVIDENCE Add the specified evidence to the network (var_elim) +% [engine, loglik] = enter_evidence(engine, evidence, ...) +% +% evidence{i} = [] if if X(i) is hidden, and otherwise contains its observed value (scalar or column vector) + +% we could pre-process the evidence here, to prevent repeated work, but we don't. +engine.evidence = evidence; + +if nargout == 2 + [m, loglik] = marginal_nodes(engine, [1]); +end diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/find_mpe.m b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/find_mpe.m new file mode 100644 index 00000000..63be5625 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/find_mpe.m @@ -0,0 +1,163 @@ +function mpe = find_mpe(engine, new_evidence, max_over) +% FIND_MPE Find the most probable explanation of the data (assignment to the hidden nodes) +% function mpe = find_mpe(engine, evidence, order) +% +% PURPOSE: +% CALC_MPE Computes the most probable explanation to the network nodes +% given the evidence. +% +% [mpe, ll] = calc_mpe(engine, new_evidence, max_over) +% +% INPUT: +% bnet - the bayesian network +% new_evidence - optional, if specified - evidence to be incorporated [cell(1,n)] +% max_over - optional, if specified determines the variable elimination order [1:n] +% +% OUTPUT: +% mpe - the MPE assignmet for the net variables (or [] if no satisfying assignment) +% ll - log assignment probability. +% +% Notes: +% 1. Adapted from '@var_elim_inf_engine\marginal_nodes' for MPE by Ron Zohar, 8/7/01 +% 2. Only discrete potentials are supported at this time. +% 3. Complexity: O(nw*) where n is the number of nodes and w* is the induced tree width. +% 4. Implementation based on: +% - R. Dechter, "Bucket Elimination: A Unifying Framework for Probabilistic Inference", +% UA1 96, pp. 211-219. + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +n = length(bnet.dag); +evidence = cell(1,n); +if (nargin<2) + new_evidence = evidence; +end + +onodes = find(~isemptycell(new_evidence)); % observed nodes +hnodes = find(isemptycell(new_evidence)); % hidden nodes +pot_type = determine_pot_type(bnet, onodes); + +if pot_type ~= 'd' + error('only disrete potentials supported at this time') +end + +for i=1:n + fam = family(bnet.dag, i); + CPT{i} = convert_to_pot(bnet.CPD{bnet.equiv_class(i)}, pot_type, fam(:), evidence); +end + +% handle observed nodes: set impossible cases' probability to zero +% rather than prun matrix (this makes backtracking easier) + +for ii=onodes + lIdx = 1:ns(ii); + lIdx = setdiff(lIdx, new_evidence{ii}); + + sCPT=struct(CPT{ii}); % violate object privacy + + sargs = ''; + for jj=1:(length(sCPT.domain)-1) + sargs = [sargs, ':,']; + end + for jj=lIdx + eval(['sCPT.T(', sargs, num2str(jj), ')=0;']); + end + CPT{ii}=dpot(sCPT.domain, sCPT.sizes, sCPT.T); +end + +B = cell(1,n); +for b=1:n + B{b} = mk_initial_pot(pot_type, [], [], [], []); +end + +if (nargin<3) + max_over = (1:n); +end +order = max_over; % no attempt to optimize this + + +% Initialize the buckets with the CPDs assigned to them +for i=1:n + b = bucket_num(domain_pot(CPT{i}), order); + B{b} = multiply_pots(B{b}, CPT{i}); +end + +% Do backward phase +max_over = max_over(length(max_over):-1:1); % reverse +maximize = 1; +for i=max_over(1:end-1) + % max-ing over variable i which occurs in bucket j + j = bucket_num(i, order); + rest = mysetdiff(domain_pot(B{j}), i); + %temp = marginalize_pot_max(B{j}, rest); + temp = marginalize_pot(B{j}, rest, maximize); + b = bucket_num(domain_pot(temp), order); + % fprintf('maxing over bucket %d (var %d), putting result into bucket %d\n', j, i, b); + sB=struct(B{b}); % violate object privacy + if ~isempty(sB.domain) + B{b} = multiply_pots(B{b}, temp); + else + B{b} = temp; + end +end +result = B{1}; +marginal = pot_to_marginal(result); +[prob, mpe] = max(marginal.T); + +% handle impossible cases +if ~(prob>0) + mpe = []; + ll = -inf; + %warning('evidence has zero probability') + return +end + +ll = log(prob); + +% Do forward phase +for ii=2:n + marginal = pot_to_marginal(B{ii}); + mpeidx = []; + for jj=order(1:length(mpe)) + %assert(ismember(jj, marginal.domain)) %%% bug + temp = find_equiv_posns(jj, marginal.domain); + mpeidx = [mpeidx, temp] ; + if isempty(temp) + mpeidx = [mpeidx, Inf] ; + end + end + [mpeidxsorted sortedtompe] = sort(mpeidx) ; + + % maximize the matrix obtained from assigning values from previous buckets. + % this is done by building a string and using eval. + + kk=1; + sargs = '('; + for jj=1:length(marginal.domain) + if (jj~=1) + sargs = [sargs, ',']; + end + if (mpeidxsorted(kk)==jj) + sargs = [sargs, num2str(mpe(sortedtompe(kk)))]; + if (kk<length(mpe)) + kk = kk+1 ; + end + else + sargs = [sargs, ':']; + end + end + sargs = [sargs, ')'] ; + eval(['[val, loc] = max(marginal.T', sargs, ');']) + mpe = [mpe loc]; +end +[I,J] = sort(order); +mpe = mpe(J); + +mpe = num2cell(mpe); + +%%%%%%%%% + +function b = bucket_num(domain, order) + +b = max(find_equiv_posns(domain, order)); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/marginal_nodes.m b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/marginal_nodes.m new file mode 100644 index 00000000..98551cb0 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/marginal_nodes.m @@ -0,0 +1,79 @@ +function [marginal, loglik] = marginal_nodes(engine, query, add_ev) +% MARGINAL_NODES Compute the marginal on the specified query nodes (var_elim) +% [marginal, loglik] = marginal_nodes(engine, query) + +if nargin < 3, add_ev = 0; end + +assert(length(query)>=1); + +evidence = engine.evidence; + +bnet = bnet_from_engine(engine); +ns = bnet.node_sizes; +n = length(bnet.dag); + +onodes = find(~isemptycell(evidence)); +hnodes = find(isemptycell(evidence)); +pot_type = determine_pot_type(bnet, onodes); + +% Fold the evidence into the CPTs - this could be done in 'enter_evidence' +CPT = cell(1,n); +for i=1:n + fam = family(bnet.dag, i); + CPT{i} = convert_to_pot(bnet.CPD{bnet.equiv_class(i)}, pot_type, fam(:), evidence); +end + + + +sum_over = mysetdiff(1:n, query); +order = [query sum_over]; % no attempt to optimize this + +% Initialize the buckets with the product of the CPTs assigned to them +B = cell(1,n+1); +for b=1:n+1 + B{b} = mk_initial_pot(pot_type, [], [], [], []); +end +for i=1:n + b = bucket_num(domain_pot(CPT{i}), order); + B{b} = multiply_pots(B{b}, CPT{i}); +end + +% Do the marginalization +sum_over = sum_over(length(sum_over):-1:1); % reverse +for i=sum_over(:)' + % summing over variable i which occurs in bucket j + j = bucket_num(i, order); + rest = mysetdiff(domain_pot(B{j}), i); + % minka + if ~isempty(rest) + temp = marginalize_pot(B{j}, rest); + b = bucket_num(domain_pot(temp), order); + %fprintf('summing over bucket %d (var %d), putting result into bucket %d\n', j, i, b); + B{b} = multiply_pots(B{b}, temp); + end +end + +% Combine all the remaining buckets into one +result = B{1}; +for i=2:length(query) + if ~isempty(domain_pot(B{i})) + result = multiply_pots(result, B{i}); + end +end +[result, loglik] = normalize_pot(result); + + +marginal = pot_to_marginal(result); +% minka: from jtree_inf_engine +if add_ev + bnet = bnet_from_engine(engine); + %marginal = add_ev_to_dmarginal(marginal, engine.evidence, bnet.node_sizes); + marginal = add_evidence_to_gmarginal(marginal, engine.evidence, bnet.node_sizes, bnet.cnodes); +end + +%%%%%%%%% + +function b = bucket_num(domain, order) + +b = max(find_equiv_posns(domain, order)); + diff --git a/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/var_elim_inf_engine.m b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/var_elim_inf_engine.m new file mode 100644 index 00000000..dd3c940a --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/@var_elim_inf_engine/var_elim_inf_engine.m @@ -0,0 +1,15 @@ +function engine = var_elim_inf_engine(bnet, varargin) +% VAR_ELIM_INF_ENGINE Variable elimination inference engine +% engine = var_elim_inf_engine(bnet) +% +% For details on variable elimination, see +% - R. Dechter, "Bucket Elimination: A Unifying Framework for Probabilistic Inference", UA1 96, pp. 211-219. +% - Z. Li and B. D'Ambrosio, "Efficient inference in Bayes networks as a combinatorial +% optimization problem", Intl. J. Approximate Reasoning, 11(1):55-81, 1994 +% - R. McEliece and S. M. Aji, "The Generalized Distributive Law", IEEE Trans. Inform. Theory, 46(2), 2000 + + +% This is where we will store the results between enter_evidence and marginal_nodes +engine.evidence = []; + +engine = class(engine, 'var_elim_inf_engine', inf_engine(bnet)); diff --git a/sourcecodes/bnt-master/BNT/inference/static/CVS/Entries b/sourcecodes/bnt-master/BNT/inference/static/CVS/Entries new file mode 100644 index 00000000..2108bb8c --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/CVS/Entries @@ -0,0 +1,2 @@ +/dummy/1.1.1.1/Sat Jan 18 22:22:46 2003// +D diff --git a/sourcecodes/bnt-master/BNT/inference/static/CVS/Entries.Log b/sourcecodes/bnt-master/BNT/inference/static/CVS/Entries.Log new file mode 100644 index 00000000..844f5ce7 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/CVS/Entries.Log @@ -0,0 +1,17 @@ +A D/@belprop_fg_inf_engine//// +A D/@belprop_inf_engine//// +A D/@belprop_mrf2_inf_engine//// +A D/@cond_gauss_inf_engine//// +A D/@enumerative_inf_engine//// +A D/@gaussian_inf_engine//// +A D/@gibbs_sampling_inf_engine//// +A D/@global_joint_inf_engine//// +A D/@jtree_inf_engine//// +A D/@jtree_limid_inf_engine//// +A D/@jtree_mnet_inf_engine//// +A D/@jtree_sparse_inf_engine//// +A D/@likelihood_weighting_inf_engine//// +A D/@pearl_inf_engine//// +A D/@quickscore_inf_engine//// +A D/@stab_cond_gauss_inf_engine//// +A D/@var_elim_inf_engine//// diff --git a/sourcecodes/bnt-master/BNT/inference/static/CVS/Repository b/sourcecodes/bnt-master/BNT/inference/static/CVS/Repository new file mode 100644 index 00000000..347cab89 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/CVS/Repository @@ -0,0 +1 @@ +FullBNT/BNT/inference/static diff --git a/sourcecodes/bnt-master/BNT/inference/static/CVS/Root b/sourcecodes/bnt-master/BNT/inference/static/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/BNT/inference/static/dummy b/sourcecodes/bnt-master/BNT/inference/static/dummy new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/sourcecodes/bnt-master/BNT/inference/static/dummy |
