Skip to content

Commit

Permalink
Merge pull request #210 from p2t2/DEV2.2.1
Browse files Browse the repository at this point in the history
Dev2.2.1
  • Loading branch information
Michael Reposa committed Jun 13, 2014
2 parents 4683974 + 74000db commit cc6d42c
Show file tree
Hide file tree
Showing 35 changed files with 2,825 additions and 155 deletions.
3 changes: 1 addition & 2 deletions Figaro/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ Bundle-ManifestVersion: 2
Bundle-Name: Figaro
Bundle-SymbolicName: com.cra.figaro
Bundle-Version: 2.2.0
Bundle-ClassPath: .,
lib/jsci-core.jar
Export-Package: com.cra.figaro.algorithm,
com.cra.figaro.algorithm.decision,
com.cra.figaro.algorithm.decision.index,
Expand All @@ -22,6 +20,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.scala-lang.scala-library,
org.scala-lang.scala-actors,
org.scala-lang.scala-reflect
Import-Package: org.apache.commons.math3.distribution;version="3.3.0"



2 changes: 1 addition & 1 deletion Figaro/figaro_build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=2.2.0.0
version=2.2.1.0
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ trait Anytime extends Algorithm {
/**
* Optional function to run when the algorithm is stopped (not killed). Used in samplers to update lazy values
*/
def stopUpdate(): Unit = {}
def stopUpdate(): Unit = { }

/**
* A class representing the actor running the algorithm.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ trait AnytimeProbQuery extends ProbQueryAlgorithm with Anytime {
protected def doExpectation[T](target: Element[T], function: T => Double): Double = {
runner ! Handle(ComputeExpectation(target, function))
receive {
case Expectation(result) => result
case Expectation(result) =>
result
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,12 @@ object ProbFactor {
}

private def parameterizedGetProbs[T](select: ParameterizedSelect[T]): List[Double] = {
val selectVar = Variable(select)
val probs = select.parameter.expectedValue.toList
probs
val outcomes = select.outcomes
val map = select.parameter.MAPValue
for {
xvalue <- Variable(select).range
index = outcomes.indexOf(xvalue.value)
} yield map(index)
}

private def makeFactors[T](select: AtomicSelect[T]): List[Factor[Double]] = {
Expand Down Expand Up @@ -567,14 +570,14 @@ object ProbFactor {
private def makeFactors(flip: ParameterizedFlip): List[Factor[Double]] = {
val flipVar = Variable(flip)
val factor = new Factor[Double](List(flipVar))
val prob = flip.parameter.expectedValue
val prob = flip.parameter.MAPValue
val i = flipVar.range.indexOf(Regular(true))
factor.set(List(i), prob)
factor.set(List(1 - i), 1.0 - prob)
List(factor)
}

private def concreteFactors[T](elem: Element[T]): List[Factor[Double]] =
def concreteFactors[T](elem: Element[T]): List[Factor[Double]] =
elem match {
case f: ParameterizedFlip => makeFactors(f)
case s: ParameterizedSelect[_] => makeFactors(s)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class SufficientStatisticsVariableElimination(
*/
def getFactors(neededElements: List[Element[_]], targetElements: List[Element[_]], upper: Boolean = false): List[Factor[(Double, mutable.Map[Parameter[_], Seq[Double]])]] = {
val allElements = neededElements.filter(p => p.isInstanceOf[Parameter[_]] == false)

if (debug) {
println("Elements appearing in factors and their ranges:")
for { element <- allElements } {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* ExpectationMaximization.scala
* Expectation maximization algorithm.
* Expectation maximization algorithm using variable elimination as the inference algorithm.
*
* Created By: Michael Howard (mhoward@cra.com)
* Creation Date: Jun 1, 2013
Expand Down Expand Up @@ -50,13 +50,13 @@ class ExpectationMaximization(universe: Universe, targetParameters: Parameter[_]
/*
* Obtain an estimate of sufficient statistics from expectation step
*/
//println("EM iteration " + iteration)
val sufficientStatistics = doExpectationStep()
doMaximizationStep(sufficientStatistics)
}
}

protected def doExpectationStep(): Map[Parameter[_], Seq[Double]] = {

val algorithm = SufficientStatisticsVariableElimination(paramMap)(universe)
algorithm.start
val result = algorithm.getSufficientStatisticsForAllParameters
Expand All @@ -67,7 +67,7 @@ class ExpectationMaximization(universe: Universe, targetParameters: Parameter[_]

protected def doMaximizationStep(parameterMapping: Map[Parameter[_], Seq[Double]]): Unit = {

for (p <- targetParameters) {
for (p <- targetParameters) yield {
p.maximize(parameterMapping(p))
}
}
Expand All @@ -87,19 +87,39 @@ class ExpectationMaximization(universe: Universe, targetParameters: Parameter[_]
protected def doKill(): Unit = {}
}

/**
* @deprecated
*/
object ExpectationMaximization {

/**
* An expectation maximization algorithm which will run for the default of 10 iterations
*
* @deprecated
*/
def apply(p: Parameter[_]*)(implicit universe: Universe) =
new ExpectationMaximization(universe, p: _*)(10)

/**
* An expectation maximization algorithm which will run for the number of iterations specified
*
* @deprecated
*/
def apply(iterations: Int, p: Parameter[_]*)(implicit universe: Universe) =
new ExpectationMaximization(universe, p: _*)(iterations)

}

object EMWithVE {
/**
* An expectation maximization algorithm which will run for the default of 10 iterations
*/
def apply(p: Parameter[_]*)(implicit universe: Universe) =
new ExpectationMaximization(universe, p: _*)(10)

/**
* An expectation maximization algorithm which will run for the number of iterations specified
*/
def apply(iterations: Int, p: Parameter[_]*)(implicit universe: Universe) =
new ExpectationMaximization(universe, p: _*)(iterations)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* GeneralizedEM.scala
* Expectation maximization algorithm using any ProbQueryAlgorithm as the inference algorithm.
*
* Created By: Michael Howard (mhoward@cra.com)
* Creation Date: Jun 1, 2013
*
* Copyright 2013 Avrom J. Pfeffer and Charles River Analytics, Inc.
* See http://www.cra.com or email figaro@cra.com for information.
*
* See http://www.github.com/p2t2/figaro for a copy of the software license.
*/

package com.cra.figaro.algorithm.learning

import com.cra.figaro.language._
import com.cra.figaro.algorithm.{Algorithm, ParameterLearner, ProbQueryAlgorithm, OneTime}
import com.cra.figaro.algorithm.factored.beliefpropagation.BeliefPropagation
import com.cra.figaro.algorithm.sampling.{Importance, MetropolisHastings, ProposalScheme}

/*
* @param inferenceAlgorithmConstructor
*/

class GeneralizedEM(inferenceAlgorithmConstructor: Seq[Element[_]] => Universe => ProbQueryAlgorithm with OneTime, universe: Universe, targetParameters: Parameter[_]*)(val numberOfIterations: Int) extends Algorithm with ParameterLearner {
/*
* Start the algorithm. After it returns, the algorithm must be ready to provide answers.
*/

protected def doStart(): Unit = {
em()
}

protected def em(): Unit = {
for (iteration <- 1 to numberOfIterations) {
/*
* Obtain an estimate of sufficient statistics from expectation step
*/

val sufficientStatistics = doExpectationStep()
doMaximizationStep(sufficientStatistics)
}
}

protected def doExpectationStep(): Map[Parameter[_], Seq[Double]] = {
val inferenceTargets =
universe.activeElements.filter(_.isInstanceOf[Parameterized[_]]).map(_.asInstanceOf[Parameterized[_]])
val algorithm = inferenceAlgorithmConstructor(inferenceTargets)(universe)
algorithm.start()

var result: Map[Parameter[_], Seq[Double]] = Map()

for { parameter <- targetParameters } {
var stats = parameter.zeroSufficientStatistics
for {
target <- inferenceTargets
if target.parameter == parameter
} {
val t: Parameterized[target.Value] = target.asInstanceOf[Parameterized[target.Value]]
val distribution: Stream[(Double, target.Value)] = algorithm.distribution(t)
val newStats = t.distributionToStatistics(distribution)
stats = (stats.zip(newStats)).map(pair => pair._1 + pair._2)
}
result += parameter -> stats
}
algorithm.kill()
result
}

protected def doMaximizationStep(parameterMapping: Map[Parameter[_], Seq[Double]]): Unit = {
for (p <- targetParameters) yield {
p.maximize(parameterMapping(p))
}
}

/*
* Stop the algorithm from computing. The algorithm is still ready to provide answers after it returns.
*/
protected def doStop(): Unit = {}

/*
* Resume the computation of the algorithm, if it has been stopped.
*/

protected def doResume(): Unit = {}

/*
* Kill the algorithm so that it is inactive. It will no longer be able to provide answers.
*/

protected def doKill(): Unit = {}
}

object EMWithBP {
private def makeBP(numIterations: Int, targets: Seq[Element[_]])(universe: Universe) = {
BeliefPropagation(numIterations, targets:_*)(universe)
}

/**
* An expectation maximization algorithm which will run for the default of 10 iterations
*/
def apply(p: Parameter[_]*)(implicit universe: Universe) =
new GeneralizedEM((targets: Seq[Element[_]]) => (universe: Universe) => makeBP(10, targets)(universe), universe, p: _*)(10)

/**
* An expectation maximization algorithm which will run for the number of iterations specified
*/
def apply(emIterations: Int, bpIterations: Int, p: Parameter[_]*)(implicit universe: Universe) =
new GeneralizedEM((targets: Seq[Element[_]]) => (universe: Universe) => makeBP(bpIterations, targets)(universe), universe, p: _*)(emIterations)
}

object EMWithImportance {
private def makeImportance(numParticles: Int, targets: Seq[Element[_]])(universe: Universe) = {
Importance(numParticles, targets:_*)(universe)
}

/**
* An expectation maximization algorithm using importance sampling for inference
*
* @param emIterations number of iterations of the EM algorithm
* @param importanceParticles number of particles of the importance sampling algorithm
*/
def apply(emIterations: Int, importanceParticles: Int, p: Parameter[_]*)(implicit universe: Universe) =
new GeneralizedEM((targets: Seq[Element[_]]) => (universe: Universe) => makeImportance(importanceParticles, targets)(universe), universe, p: _*)(emIterations)
}

object EMWithMH {
private def makeMH(numParticles: Int, proposalScheme: ProposalScheme, targets: Seq[Element[_]])(universe: Universe) = {
MetropolisHastings(numParticles, proposalScheme, targets:_*)(universe)
}

/**
* An expectation maximization algorithm using Metropolis Hastings for inference.
*
* @param emIterations number of iterations of the EM algorithm
* @param mhParticles number of particles of the MH algorithm
*/
def apply(emIterations: Int, mhParticles: Int, p: Parameter[_]*)(implicit universe: Universe) =
new GeneralizedEM((targets: Seq[Element[_]]) => (universe: Universe) => makeMH(mhParticles, ProposalScheme.default(universe), targets)(universe), universe, p: _*)(emIterations)

/**
* An expectation maximization algorithm using Metropolis Hastings for inference.
*
* @param emIterations number of iterations of the EM algorithm
* @param mhParticles number of particles of the MH algorithm
*/
def apply(emIterations: Int, mhParticles: Int, proposalScheme: ProposalScheme, p: Parameter[_]*)(implicit universe: Universe) =
new GeneralizedEM((targets: Seq[Element[_]]) => (universe: Universe) => makeMH(mhParticles, proposalScheme, targets)(universe), universe, p: _*)(emIterations)
}
Loading

0 comments on commit cc6d42c

Please sign in to comment.