aima.core.probability.bayes.exact.EliminationAsk Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aima-core Show documentation
Show all versions of aima-core Show documentation
AIMA-Java Core Algorithms from the book Artificial Intelligence a Modern Approach 3rd Ed.
The newest version!
package aima.core.probability.bayes.exact;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import aima.core.probability.CategoricalDistribution;
import aima.core.probability.Factor;
import aima.core.probability.RandomVariable;
import aima.core.probability.bayes.BayesInference;
import aima.core.probability.bayes.BayesianNetwork;
import aima.core.probability.bayes.FiniteNode;
import aima.core.probability.bayes.Node;
import aima.core.probability.proposition.AssignmentProposition;
import aima.core.probability.util.ProbabilityTable;
/**
* Artificial Intelligence A Modern Approach (3rd Edition): Figure 14.11, page
* 528.
*
*
*
* function ELIMINATION-ASK(X, e, bn) returns a distribution over X
* inputs: X, the query variable
* e, observed values for variables E
* bn, a Bayesian network specifying joint distribution P(X1, ..., Xn)
*
* factors <- []
* for each var in ORDER(bn.VARS) do
* factors <- [MAKE-FACTOR(var, e) | factors]
* if var is hidden variable the factors <- SUM-OUT(var, factors)
* return NORMALIZE(POINTWISE-PRODUCT(factors))
*
*
* Figure 14.11 The variable elimination algorithm for inference in Bayesian
* networks.
*
* Note: The implementation has been extended to handle queries with
* multiple variables.
*
* @author Ciaran O'Reilly
*/
public class EliminationAsk implements BayesInference {
//
private static final ProbabilityTable _identity = new ProbabilityTable(
new double[] { 1.0 });
public EliminationAsk() {
}
// function ELIMINATION-ASK(X, e, bn) returns a distribution over X
/**
* The ELIMINATION-ASK algorithm in Figure 14.11.
*
* @param X
* the query variables.
* @param e
* observed values for variables E.
* @param bn
* a Bayes net with variables {X} ∪ E ∪ Y /* Y = hidden
* variables //
* @return a distribution over the query variables.
*/
public CategoricalDistribution eliminationAsk(final RandomVariable[] X,
final AssignmentProposition[] e, final BayesianNetwork bn) {
Set hidden = new HashSet();
List VARS = new ArrayList();
calculateVariables(X, e, bn, hidden, VARS);
// factors <- []
List factors = new ArrayList();
// for each var in ORDER(bn.VARS) do
for (RandomVariable var : order(bn, VARS)) {
// factors <- [MAKE-FACTOR(var, e) | factors]
factors.add(0, makeFactor(var, e, bn));
// if var is hidden variable then factors <- SUM-OUT(var, factors)
if (hidden.contains(var)) {
factors = sumOut(var, factors, bn);
}
}
// return NORMALIZE(POINTWISE-PRODUCT(factors))
Factor product = pointwiseProduct(factors);
// Note: Want to ensure the order of the product matches the
// query variables
return ((ProbabilityTable) product.pointwiseProductPOS(_identity, X))
.normalize();
}
//
// START-BayesInference
public CategoricalDistribution ask(final RandomVariable[] X,
final AssignmentProposition[] observedEvidence,
final BayesianNetwork bn) {
return this.eliminationAsk(X, observedEvidence, bn);
}
// END-BayesInference
//
//
// PROTECTED METHODS
//
/**
* Note:Override this method for a more efficient implementation as
* outlined in AIMA3e pgs. 527-28. Calculate the hidden variables from the
* Bayesian Network. The default implementation does not perform any of
* these.
*
* Two calcuations to be performed here in order to optimize iteration over
* the Bayesian Network:
* 1. Calculate the hidden variables to be enumerated over. An optimization
* (AIMA3e pg. 528) is to remove 'every variable that is not an ancestor of
* a query variable or evidence variable as it is irrelevant to the query'
* (i.e. sums to 1). 2. The subset of variables from the Bayesian Network to
* be retained after irrelevant hidden variables have been removed.
*
* @param X
* the query variables.
* @param e
* observed values for variables E.
* @param bn
* a Bayes net with variables {X} ∪ E ∪ Y /* Y = hidden
* variables //
* @param hidden
* to be populated with the relevant hidden variables Y.
* @param bnVARS
* to be populated with the subset of the random variables
* comprising the Bayesian Network with any irrelevant hidden
* variables removed.
*/
protected void calculateVariables(final RandomVariable[] X,
final AssignmentProposition[] e, final BayesianNetwork bn,
Set hidden, Collection bnVARS) {
bnVARS.addAll(bn.getVariablesInTopologicalOrder());
hidden.addAll(bnVARS);
for (RandomVariable x : X) {
hidden.remove(x);
}
for (AssignmentProposition ap : e) {
hidden.removeAll(ap.getScope());
}
return;
}
/**
* Note:Override this method for a more efficient implementation as
* outlined in AIMA3e pgs. 527-28. The default implementation does not
* perform any of these.
*
* @param bn
* the Bayesian Network over which the query is being made. Note,
* is necessary to provide this in order to be able to determine
* the dependencies between variables.
* @param vars
* a subset of the RandomVariables making up the Bayesian
* Network, with any irrelevant hidden variables alreay removed.
* @return a possibly opimal ordering for the random variables to be
* iterated over by the algorithm. For example, one fairly effective
* ordering is a greedy one: eliminate whichever variable minimizes
* the size of the next factor to be constructed.
*/
protected List order(BayesianNetwork bn,
Collection vars) {
// Note: Trivial Approach:
// For simplicity just return in the reverse order received,
// i.e. received will be the default topological order for
// the Bayesian Network and we want to ensure the network
// is iterated from bottom up to ensure when hidden variables
// are come across all the factors dependent on them have
// been seen so far.
List order = new ArrayList(vars);
Collections.reverse(order);
return order;
}
//
// PRIVATE METHODS
//
private Factor makeFactor(RandomVariable var, AssignmentProposition[] e,
BayesianNetwork bn) {
Node n = bn.getNode(var);
if (!(n instanceof FiniteNode)) {
throw new IllegalArgumentException(
"Elimination-Ask only works with finite Nodes.");
}
FiniteNode fn = (FiniteNode) n;
List evidence = new ArrayList();
for (AssignmentProposition ap : e) {
if (fn.getCPT().contains(ap.getTermVariable())) {
evidence.add(ap);
}
}
return fn.getCPT().getFactorFor(
evidence.toArray(new AssignmentProposition[evidence.size()]));
}
private List sumOut(RandomVariable var, List factors,
BayesianNetwork bn) {
List summedOutFactors = new ArrayList();
List toMultiply = new ArrayList();
for (Factor f : factors) {
if (f.contains(var)) {
toMultiply.add(f);
} else {
// This factor does not contain the variable
// so no need to sum out - see AIMA3e pg. 527.
summedOutFactors.add(f);
}
}
summedOutFactors.add(pointwiseProduct(toMultiply).sumOut(var));
return summedOutFactors;
}
private Factor pointwiseProduct(List factors) {
Factor product = factors.get(0);
for (int i = 1; i < factors.size(); i++) {
product = product.pointwiseProduct(factors.get(i));
}
return product;
}
}