wolffd@0: function [engine, ll, niter] = enter_evidence(engine, evidence, varargin) wolffd@0: % ENTER_EVIDENCE Propagate evidence using belief propagation wolffd@0: % [engine, ll, niter] = enter_evidence(engine, evidence, ...) wolffd@0: % wolffd@0: % The log-likelihood is not computed; ll = 0. wolffd@0: % niter contains the number of iterations used wolffd@0: % wolffd@0: % The following optional arguments can be specified in the form of name/value pairs: wolffd@0: % [default value in brackets] wolffd@0: % wolffd@0: % maximize - 1 means use max-product, 0 means use sum-product [0] wolffd@0: % wolffd@0: % e.g., engine = enter_evidence(engine, ev, 'maximize', 1) wolffd@0: wolffd@0: ll = 0; wolffd@0: maximize = 0; wolffd@0: wolffd@0: if nargin >= 3 wolffd@0: args = varargin; wolffd@0: nargs = length(args); wolffd@0: for i=1:2:nargs wolffd@0: switch args{i}, wolffd@0: case 'maximize', maximize = args{i+1}; wolffd@0: otherwise, wolffd@0: error(['invalid argument name ' args{i}]); wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: verbose = 0; wolffd@0: wolffd@0: ns = engine.fgraph.node_sizes; wolffd@0: onodes = find(~isemptycell(evidence)); wolffd@0: hnodes = find(isemptycell(evidence)); wolffd@0: cnodes = engine.fgraph.cnodes; wolffd@0: pot_type = determine_pot_type(engine.fgraph, onodes); wolffd@0: wolffd@0: % prime each local kernel with evidence (if any) wolffd@0: nfactors = engine.fgraph.nfactors; wolffd@0: nvars = engine.fgraph.nvars; wolffd@0: factors = cell(1,nfactors); wolffd@0: for f=1:nfactors wolffd@0: K = engine.fgraph.factors{engine.fgraph.equiv_class(f)}; wolffd@0: factors{f} = convert_to_pot(K, pot_type, engine.fgraph.dom{f}(:), evidence); wolffd@0: end wolffd@0: wolffd@0: % initialise msgs wolffd@0: msg_var_to_fac = cell(nvars, nfactors); wolffd@0: for x=1:nvars wolffd@0: for f=engine.fgraph.dep{x} wolffd@0: msg_var_to_fac{x,f} = mk_initial_pot(pot_type, x, ns, cnodes, onodes); wolffd@0: end wolffd@0: end wolffd@0: msg_fac_to_var = cell(nfactors, nvars); wolffd@0: dom = cell(1, nfactors); wolffd@0: for f=1:nfactors wolffd@0: %hdom{f} = myintersect(engine.fgraph.dom{f}, hnodes); wolffd@0: dom{f} = engine.fgraph.dom{f}(:)'; wolffd@0: for x=dom{f} wolffd@0: msg_fac_to_var{f,x} = mk_initial_pot(pot_type, x, ns, cnodes, onodes); wolffd@0: %msg_fac_to_var{f,x} = marginalize_pot(factors{f}, x); wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: wolffd@0: wolffd@0: converged = 0; wolffd@0: iter = 1; wolffd@0: var_prod = cell(1, nvars); wolffd@0: fac_prod = cell(1, nfactors); wolffd@0: wolffd@0: while ~converged & (iter <= engine.max_iter) wolffd@0: if verbose, fprintf('iter %d\n', iter); end wolffd@0: wolffd@0: % absorb wolffd@0: old_var_prod = var_prod; wolffd@0: for x=1:nvars wolffd@0: var_prod{x} = mk_initial_pot(pot_type, x, ns, cnodes, onodes); wolffd@0: for f=engine.fgraph.dep{x} wolffd@0: var_prod{x} = multiply_by_pot(var_prod{x}, msg_fac_to_var{f,x}); wolffd@0: end wolffd@0: end wolffd@0: for f=1:nfactors wolffd@0: fac_prod{f} = mk_initial_pot(pot_type, dom{f}, ns, cnodes, onodes); wolffd@0: for x=dom{f} wolffd@0: fac_prod{f} = multiply_by_pot(fac_prod{f}, msg_var_to_fac{x,f}); wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % send msgs to neighbors wolffd@0: old_msg_var_to_fac = msg_var_to_fac; wolffd@0: old_msg_fac_to_var = msg_fac_to_var; wolffd@0: converged = 1; wolffd@0: for x=1:nvars wolffd@0: %if verbose, disp(['var ' num2str(x) ' sending to fac ' num2str(engine.fgraph.dep{x})]); end wolffd@0: for f=engine.fgraph.dep{x} wolffd@0: temp = divide_by_pot(var_prod{x}, old_msg_fac_to_var{f,x}); wolffd@0: msg_var_to_fac{x,f} = normalize_pot(temp); wolffd@0: if ~approxeq_pot(msg_var_to_fac{x,f}, old_msg_var_to_fac{x,f}, engine.tol), converged = 0; end wolffd@0: end wolffd@0: end wolffd@0: for f=1:nfactors wolffd@0: %if verbose, disp(['fac ' num2str(f) ' sending to var ' num2str(dom{f})]); end wolffd@0: for x=dom{f} wolffd@0: temp = divide_by_pot(fac_prod{f}, old_msg_var_to_fac{x,f}); wolffd@0: temp2 = multiply_by_pot(factors{f}, temp); wolffd@0: temp3 = marginalize_pot(temp2, x, maximize); wolffd@0: msg_fac_to_var{f,x} = normalize_pot(temp3); wolffd@0: if ~approxeq_pot(msg_fac_to_var{f,x}, old_msg_fac_to_var{f,x}, engine.tol), converged = 0; end wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: if iter==1 wolffd@0: converged = 0; wolffd@0: end wolffd@0: iter = iter + 1; wolffd@0: end wolffd@0: wolffd@0: niter = iter - 1; wolffd@0: engine.niter = niter; wolffd@0: wolffd@0: for x=1:nvars wolffd@0: engine.marginal_nodes{x} = normalize_pot(var_prod{x}); wolffd@0: end wolffd@0: wolffd@0: