function [bnet, loglik] = propagate_dbn(bnet, obs_nodes, vals)
% PROPOGATE_DBN Use the Boyen-Koller algorithm to do inference.
% [bnet, loglik] = propogate_dbn(bnet, obs_nodes, obs_vals)
%
% If bnet.filter_only = 1, we do filtering, else smoothing.
% This is the DBN equivalent of the forwards-backwards algorithm.

T = length(vals);

alpha = cell(1,T);
beta = cell(1,T);
post = cell(1,T);
scale = ones(1,T);

% post1{c} contains the posterior on clique c in the jtree for slice 1 alone
% post{t}{c} contains the posterior on clique c in the jtree for slices t and t+1
% alpha{t}{c} contains the filtered posterior on cluster c at time t

beta = [];
t = 1;
[alpha{t}, scale(t), post1] = init_belief_state(bnet, obs_nodes{t}, vals{t});
for t=2:T
  [alpha{t}, scale(t), post{t-1}] = update_belief_state(bnet, alpha{t-1}, ...
      obs_nodes{t}, vals{t}, obs_nodes{t-1}, vals{t-1}, t);
end
if ~bnet.filter_only
  t=T;
  beta{t} = back_init_belief_state(bnet, scale(t), obs_nodes{t});
  for t=T-1:-1:1
    beta{t} = back_update_belief_state(bnet, beta{t+1}, scale(t), ...
	obs_nodes{t}, vals{t}, obs_nodes{t+1}, vals{t+1});
    post{t} = combine_fwd_back(bnet, alpha{t}, beta{t+1}, t, ...
	obs_nodes{t}, vals{t}, obs_nodes{t+1}, vals{t+1});
  end
end

bnet.dbn.alpha = alpha;
bnet.dbn.beta = beta;
bnet.dbn.scale = scale;
bnet.dbn.post = post;
bnet.dbn.post1 = post1;

if any(scale==0)
  loglik = -inf;
else
  loglik = -sum(log(scale));
end
