about summary refs log tree commit diff
path: root/sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine
diff options
context:
space:
mode:
Diffstat (limited to 'sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine')
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Entries8
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Repository1
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/CVS/Root1
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Entries4
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Repository1
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/CVS/Root1
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence.m59
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/enter_soft_evidence1.m94
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/Old/marginal_family.m38
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_evidence.m62
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/enter_soft_evidence.m11
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/ff_inf_engine.m44
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/filter_evidence.m48
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_family.m44
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/marginal_nodes.m20
-rw-r--r--sourcecodes/bnt-master/BNT/inference/dynamic/@ff_inf_engine/smooth_evidence.m89
16 files changed, 525 insertions, 0 deletions
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