diff options
| author | ziejd2 | 2017-09-28 15:04:40 -0500 |
|---|---|---|
| committer | ziejd2 | 2017-09-28 15:04:40 -0500 |
| commit | 8070dc963753142bb86c4ed698d91fd623ed28e7 (patch) | |
| tree | d0f6dd8fc46a49b819aa55c1a90faa14d8448883 /sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine | |
| parent | 7cc31810d53176e805532b2789955f4eedbce6bb (diff) | |
| download | BNW-8070dc963753142bb86c4ed698d91fd623ed28e7.tar.gz | |
BNW using Octave instead of Matlab.
This version of BNW should perform the same as the original version. The only difference is that it uses Octave instead of Matlab when running BayesNet Toolbox during parameter learning. I am calling this BNW_1.02. It can be accessed at: compbio.uthsc.edu/BNW_1.02
Diffstat (limited to 'sourcecodes/bnt-master/BNT/inference/dynamic/@cbk_inf_engine')
14 files changed, 724 insertions, 0 deletions
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))); + |
