function [bnet, ll] = propagate_jtree(bnet, soft_nodes, soft_vals)
% PROPOGATE_JTREE Use the join tree algorithm to do inference.
% [bnet, ll] = propogate_jtree(bnet, soft_nodes, soft_vals)

if nargin < 2
  soft_nodes = [];
  soft_vals = [];
end

bnet = mk_ev_specific_pot(bnet, bnet.jtree.nodes_assigned_to_clique);

for i=1:length(soft_nodes)
  v = soft_nodes(i);
  c = bnet.jtree.cl_containing_family(v);
  pot = mk_table(v, bnet.node_sizes(v));
  pot.T = soft_vals{i};
  bnet.jtree.clpot{c} = multiply_by_potential(bnet.jtree.clpot{c}, pot);
end

% Multiply in user-specified clique potentials for undirected components
for i=1:length(bnet.cliques)
  c = find_clique(bnet.jtree, bnet.cliques{i});
  bnet.jtree.clpot{c} = multiply_by_potential(bnet.jtree.clpot{c}, bnet.clpot{i});
end

bnet = collect_evidence(bnet);

if bnet.maximize
  bnet = traceback(bnet);
else
  if ~bnet.is_dbn | ~bnet.filter_only
    bnet = distribute_evidence(bnet);
  else
    fprintf('warning: filtering with the jtree algorithm may give wrong marginals\n');
    % the reason is that a node may be contained in a clique which contains "future" evidence
  end
  
end

num_cliques = length(bnet.jtree.cliques);
lik = zeros(1, num_cliques);
for i=1:num_cliques
  [bnet.jtree.clpot{i}, lik(i)] = normalize_potential(bnet.jtree.clpot{i});
end


lik = lik + (lik==0)*eps;
ll = max(log(lik));
%ll = min(log(lik));
% When doing exact inference, any potential can be used to compute the likelihood.
% But when using a variational approximation, we only get a lower bound.
% Hence we take the tightest lower bound.
