Package aima.core.probability.bayes.model

Source Code of aima.core.probability.bayes.model.FiniteBayesModel

package aima.core.probability.bayes.model;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import aima.core.probability.CategoricalDistribution;
import aima.core.probability.FiniteProbabilityModel;
import aima.core.probability.ProbabilityModel;
import aima.core.probability.RandomVariable;
import aima.core.probability.bayes.BayesInference;
import aima.core.probability.bayes.BayesianNetwork;
import aima.core.probability.bayes.exact.EnumerationAsk;
import aima.core.probability.proposition.AssignmentProposition;
import aima.core.probability.proposition.ConjunctiveProposition;
import aima.core.probability.proposition.Proposition;
import aima.core.probability.util.ProbUtil;
import aima.core.probability.util.ProbabilityTable;

/**
* Very simple implementation of the FiniteProbabilityModel API using a Bayesian
* Network, consisting of FiniteNodes, to represent the underlying model.<br>
* <br>
* <b>Note:</b> The implementation currently doesn't take advantage of the use
* of evidence values when calculating posterior values using the provided
* Bayesian Inference implementation (e.g enumerationAsk). Instead it simply
* creates a joint distribution over the scope of the propositions (i.e. using
* the inference implementation with just query variables corresponding to the
* scope of the propositions) and then iterates over this to get the appropriate
* probability values. A smarter version, in the general case, would need to
* dynamically create deterministic nodes to represent the outcome of logical
* and derived propositions (e.g. conjuncts and summations over variables) in
* order to be able to correctly calculate using evidence values.
*
* @author Ciaran O'Reilly
*/
public class FiniteBayesModel implements FiniteProbabilityModel {

  private BayesianNetwork bayesNet = null;
  private Set<RandomVariable> representation = new LinkedHashSet<RandomVariable>();
  private BayesInference bayesInference = null;

  public FiniteBayesModel(BayesianNetwork bn) {
    this(bn, new EnumerationAsk());
  }

  public FiniteBayesModel(BayesianNetwork bn, BayesInference bi) {
    if (null == bn) {
      throw new IllegalArgumentException(
          "Bayesian Network describing the model must be specified.");
    }
    this.bayesNet = bn;
    this.representation.addAll(bn.getVariablesInTopologicalOrder());
    setBayesInference(bi);
  }

  public BayesInference getBayesInference() {
    return bayesInference;
  }

  public void setBayesInference(BayesInference bi) {
    this.bayesInference = bi;
  }

  //
  // START-ProbabilityModel
  public boolean isValid() {
    // Handle rounding
    return Math.abs(1 - prior(representation
        .toArray(new Proposition[representation.size()]))) <= ProbabilityModel.DEFAULT_ROUNDING_THRESHOLD;
  }

  public double prior(Proposition... phi) {
    // Calculating the prior, therefore no relevant evidence
    // just query over the scope of proposition phi in order
    // to get a joint distribution for these
    final Proposition conjunct = ProbUtil.constructConjunction(phi);
    RandomVariable[] X = conjunct.getScope().toArray(
        new RandomVariable[conjunct.getScope().size()]);
    CategoricalDistribution d = bayesInference.ask(X,
        new AssignmentProposition[0], bayesNet);

    // Then calculate the probability of the propositions phi
    // be seeing where they hold.
    final double[] probSum = new double[1];
    CategoricalDistribution.Iterator di = new CategoricalDistribution.Iterator() {
      public void iterate(Map<RandomVariable, Object> possibleWorld,
          double probability) {
        if (conjunct.holds(possibleWorld)) {
          probSum[0] += probability;
        }
      }
    };
    d.iterateOver(di);

    return probSum[0];
  }

  public double posterior(Proposition phi, Proposition... evidence) {

    Proposition conjEvidence = ProbUtil.constructConjunction(evidence);

    // P(A | B) = P(A AND B)/P(B) - (13.3 AIMA3e)
    Proposition aAndB = new ConjunctiveProposition(phi, conjEvidence);
    double probabilityOfEvidence = prior(conjEvidence);
    if (0 != probabilityOfEvidence) {
      return prior(aAndB) / probabilityOfEvidence;
    }

    return 0;
  }

  public Set<RandomVariable> getRepresentation() {
    return representation;
  }

  // END-ProbabilityModel
  //

  //
  // START-FiniteProbabilityModel
  public CategoricalDistribution priorDistribution(Proposition... phi) {
    return jointDistribution(phi);
  }

  public CategoricalDistribution posteriorDistribution(Proposition phi,
      Proposition... evidence) {

    Proposition conjEvidence = ProbUtil.constructConjunction(evidence);

    // P(A | B) = P(A AND B)/P(B) - (13.3 AIMA3e)
    CategoricalDistribution dAandB = jointDistribution(phi, conjEvidence);
    CategoricalDistribution dEvidence = jointDistribution(conjEvidence);

    CategoricalDistribution rVal = dAandB.divideBy(dEvidence);
    // Note: Need to ensure normalize() is called
    // in order to handle the case where an approximate
    // algorithm is used (i.e. won't evenly divide
    // as will have calculated on separate approximate
    // runs). However, this should only be done
    // if the all of the evidences scope are bound (if not
    // you are returning in essence a set of conditional
    // distributions, which you do not want normalized).
    boolean unboundEvidence = false;
    for (Proposition e : evidence) {
      if (e.getUnboundScope().size() > 0) {
        unboundEvidence = true;
        break;
      }
    }
    if (!unboundEvidence) {
      rVal.normalize();
    }

    return rVal;
  }

  public CategoricalDistribution jointDistribution(
      Proposition... propositions) {
    ProbabilityTable d = null;
    final Proposition conjProp = ProbUtil
        .constructConjunction(propositions);
    final LinkedHashSet<RandomVariable> vars = new LinkedHashSet<RandomVariable>(
        conjProp.getUnboundScope());

    if (vars.size() > 0) {
      RandomVariable[] distVars = new RandomVariable[vars.size()];
      int i = 0;
      for (RandomVariable rv : vars) {
        distVars[i] = rv;
        i++;
      }

      final ProbabilityTable ud = new ProbabilityTable(distVars);
      final Object[] values = new Object[vars.size()];

      CategoricalDistribution.Iterator di = new CategoricalDistribution.Iterator() {

        public void iterate(Map<RandomVariable, Object> possibleWorld,
            double probability) {
          if (conjProp.holds(possibleWorld)) {
            int i = 0;
            for (RandomVariable rv : vars) {
              values[i] = possibleWorld.get(rv);
              i++;
            }
            int dIdx = ud.getIndex(values);
            ud.setValue(dIdx, ud.getValues()[dIdx] + probability);
          }
        }
      };

      RandomVariable[] X = conjProp.getScope().toArray(
          new RandomVariable[conjProp.getScope().size()]);
      bayesInference.ask(X, new AssignmentProposition[0], bayesNet)
          .iterateOver(di);

      d = ud;
    } else {
      // No Unbound Variables, therefore just return
      // the singular probability related to the proposition.
      d = new ProbabilityTable();
      d.setValue(0, prior(propositions));
    }
    return d;
  }

  // END-FiniteProbabilityModel
  //
}
TOP

Related Classes of aima.core.probability.bayes.model.FiniteBayesModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.