package aima.core.probability.bayes.approx; import java.util.LinkedHashMap; import java.util.Map; import java.util.Random; import aima.core.probability.CategoricalDistribution; import aima.core.probability.RandomVariable; import aima.core.probability.bayes.BayesianNetwork; import aima.core.probability.proposition.AssignmentProposition; import aima.core.probability.util.ProbUtil; import aima.core.probability.util.ProbabilityTable; import aima.core.util.JavaRandomizer; import aima.core.util.Randomizer; import aima.core.util.datastructure.Pair; /** * Artificial Intelligence A Modern Approach (3rd Edition): page 534.<br> * <br> * * <pre> * function LIKELIHOOD-WEIGHTING(X, e, bn, N) returns an estimate of <b>P</b>(X|e) * inputs: X, the query variable * e, observed values for variables E * bn, a Bayesian network specifying joint distribution <b>P</b>(X<sub>1</sub>,...,X<sub>n</sub>) * N, the total number of samples to be generated * local variables: W, a vector of weighted counts for each value of X, initially zero * * for j = 1 to N do * <b>x</b>,w <- WEIGHTED-SAMPLE(bn,e) * W[x] <- W[x] + w where x is the value of X in <b>x</b> * return NORMALIZE(W) * -------------------------------------------------------------------------------------- * function WEIGHTED-SAMPLE(bn, e) returns an event and a weight * * w <- 1; <b>x</b> <- an event with n elements initialized from e * foreach variable X<sub>i</sub> in X<sub>1</sub>,...,X<sub>n</sub> do * if X<sub>i</sub> is an evidence variable with value x<sub>i</sub> in e * then w <- w * P(X<sub>i</sub> = x<sub>i</sub> | parents(X<sub>i</sub>)) * else <b>x</b>[i] <- a random sample from <b>P</b>(X<sub>i</sub> | parents(X<sub>i</sub>)) * return <b>x</b>, w * </pre> * * Figure 14.15 The likelihood-weighting algorithm for inference in Bayesian * networks. In WEIGHTED-SAMPLE, each nonevidence variable is sampled according * to the conditional distribution given the values already sampled for the * variable's parents, while a weight is accumulated based on the likelihood for * each evidence variable.<br> * <br> * <b>Note:</b> The implementation has been extended to handle queries with * multiple variables. <br> * * @author Ciaran O'Reilly * @author Ravi Mohan */ public class LikelihoodWeighting implements BayesSampleInference { private Randomizer randomizer = null; public LikelihoodWeighting() { this(new JavaRandomizer(new Random())); } public LikelihoodWeighting(Randomizer r) { this.randomizer = r; } // function LIKELIHOOD-WEIGHTING(X, e, bn, N) returns an estimate of // <b>P</b>(X|e) /** * The LIKELIHOOD-WEIGHTING algorithm in Figure 14.15. For answering queries * given evidence in a Bayesian Network. * * @param X * the query variables * @param e * observed values for variables E * @param bn * a Bayesian network specifying joint distribution * <b>P</b>(X<sub>1</sub>,...,X<sub>n</sub>) * @param N * the total number of samples to be generated * @return an estimate of <b>P</b>(X|e) */ public CategoricalDistribution likelihoodWeighting(RandomVariable[] X, AssignmentProposition[] e, BayesianNetwork bn, int N) { // local variables: W, a vector of weighted counts for each value of X, // initially zero double[] W = new double[ProbUtil .expectedSizeOfCategoricalDistribution(X)]; // for j = 1 to N do for (int j = 0; j < N; j++) { // <b>x</b>,w <- WEIGHTED-SAMPLE(bn,e) Pair<Map<RandomVariable, Object>, Double> x_w = weightedSample(bn, e); // W[x] <- W[x] + w where x is the value of X in <b>x</b> W[ProbUtil.indexOf(X, x_w.getFirst())] += x_w.getSecond(); } // return NORMALIZE(W) return new ProbabilityTable(W, X).normalize(); } // function WEIGHTED-SAMPLE(bn, e) returns an event and a weight /** * The WEIGHTED-SAMPLE function in Figure 14.15. * * @param e * observed values for variables E * @param bn * a Bayesian network specifying joint distribution * <b>P</b>(X<sub>1</sub>,...,X<sub>n</sub>) * @return return <b>x</b>, w - an event with its associated weight. */ public Pair<Map<RandomVariable, Object>, Double> weightedSample( BayesianNetwork bn, AssignmentProposition[] e) { // w <- 1; double w = 1.0; // <b>x</b> <- an event with n elements initialized from e Map<RandomVariable, Object> x = new LinkedHashMap<RandomVariable, Object>(); for (AssignmentProposition ap : e) { x.put(ap.getTermVariable(), ap.getValue()); } // foreach variable X<sub>i</sub> in X<sub>1</sub>,...,X<sub>n</sub> do for (RandomVariable Xi : bn.getVariablesInTopologicalOrder()) { // if X<sub>i</sub> is an evidence variable with value x<sub>i</sub> // in e if (x.containsKey(Xi)) { // then w <- w * P(X<sub>i</sub> = x<sub>i</sub> | // parents(X<sub>i</sub>)) w *= bn.getNode(Xi) .getCPD() .getValue( ProbUtil.getEventValuesForXiGivenParents( bn.getNode(Xi), x)); } else { // else <b>x</b>[i] <- a random sample from // <b>P</b>(X<sub>i</sub> | parents(X<sub>i</sub>)) x.put(Xi, ProbUtil.randomSample(bn.getNode(Xi), x, randomizer)); } } // return <b>x</b>, w return new Pair<Map<RandomVariable, Object>, Double>(x, w); } // // START-BayesSampleInference @Override public CategoricalDistribution ask(final RandomVariable[] X, final AssignmentProposition[] observedEvidence, final BayesianNetwork bn, int N) { return likelihoodWeighting(X, observedEvidence, bn, N); } // END-BayesSampleInference // }