function bnet = schedule_marginals(bnet, marginal)
% SCHEDULE_MARGINALS Specify what marginals we will want to compute using jtree or BK.
% bnet = schedule_marginals(bnet, marginals)
%
% With the jtree algorithm, we can compute the marginal on any set of nodes which occur together
% in some clique. To ensure that there is a clique which contains each marginal you want to
% compute, we can add extra edges to the moral graph before triangulating it.
% e.g., suppose you want to compute the marginals on {1,5} and {2,3,4}.
% You can proceed as follows.
%
%   bnet = schedule_marginals(bnet, {[1 5], [2 3 4]} );
%   bnet = enter_evidence(...)
%   m1 = marginal_nodes(bnet, [1 5])
%   m2 = marginal_nodes(bnet, [2 3 4])
%
% If bnet is a DBN, marginals{i} refers to nodes in slices 1 and possibly also 2.
% The actual time slice can be specified when you call MARGINAL_NODES.

% An alternative method, which does not require (explicitely) adding extra edges, is described in
%   H. Xu, "Computing marginals for arbitrary subsets from marginal representation in
%       Markov trees", Artificial Intelligence, 1995, 74:177-189.
% This has been implemented in MARGINAL_IMPLICIT.

num_marginals = length(marginal);
bnet.desired_marginal = marginal; % this is how the jtree knows what extra edges to add

switch bnet.algo
  case {'hmm', 'lds'}
    check_marginals_span_less_than_two_slices(marginal, ss);
  case 'jtree',
    bnet.jtree = mk_jtree(bnet);
  case 'bk',
    check_marginals_span_less_than_two_slices(marginal, ss);
    bnet = mk_jtree_dbn(bnet);
  otherwise,
    error(['unrecognized algo ' bnet.algo]);
end

%%%%%%%%

function check_marginals_span_less_than_two_slices(marginal, ss)

for i=1:length(marginal)
  nodes = marginal{i};
  if max(nodes)-min(nodes) > 2*ss
    error(['cant compute marginal on ' num2str(nodes)]);
  end
end
