Skip to content

Commit

Permalink
Merge pull request #508 from p2t2/DEV3.3
Browse files Browse the repository at this point in the history
Dev3.3
  • Loading branch information
mreposa committed Jul 24, 2015
2 parents 07fc949 + b95b048 commit 2687f15
Show file tree
Hide file tree
Showing 46 changed files with 1,244 additions and 710 deletions.
2 changes: 1 addition & 1 deletion Figaro/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Figaro
Bundle-SymbolicName: com.cra.figaro
Bundle-Version: 3.2.1
Bundle-Version: 3.3.0
Export-Package: com.cra.figaro.algorithm,
com.cra.figaro.algorithm.decision,
com.cra.figaro.algorithm.decision.index,
Expand Down
2 changes: 1 addition & 1 deletion Figaro/figaro_build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=3.2.1.1
version=3.3.0.0
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ abstract class DecisionImportance[T, U] private (override val universe: Universe
// override doSample so can update the local utilities
override protected def doSample(): Unit = {
val s = sample()
universe.clearTemporaries()
totalWeight = logSum(s._1, totalWeight)
allWeightsSeen foreach (updateWeightSeenForTarget(s, _))
allUtilitiesSeen foreach (updateWeightSeenForTargetNoLog((math.exp(s._1) * utilitySum, s._2), _))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.cra.figaro.util._
import annotation.tailrec
import scala.collection.mutable.{ Map, Set }
import scala.language.postfixOps
import scala.util.control.TailCalls._

/**
* Trait of algorithms that perform variable elimination.
Expand Down Expand Up @@ -123,18 +124,32 @@ trait VariableElimination[T] extends FactoredAlgorithm[T] with OneTime {
}
}

// Wraps the TailRec class and returns the result
protected def eliminateInOrder(
order: List[Variable[_]],
factors: MultiSet[Factor[T]],
map: FactorMap[T]): MultiSet[Factor[T]] =
map: FactorMap[T]): MultiSet[Factor[T]] = {
callEliminateInOrder(order, factors, map).result
}

/*
* TailRec class turns a tail-recursive method into a while loop
* The result needs to be extracted explicitly
*/
private def callEliminateInOrder(
order: List[Variable[_]],
factors: MultiSet[Factor[T]],
map: FactorMap[T]): TailRec[MultiSet[Factor[T]]] = {
order match {
case Nil =>
factors
done(factors)
case first :: rest =>
eliminate(first, factors, map)
eliminateInOrder(rest, factors, map)
tailcall(callEliminateInOrder(rest, factors, map))
}

}


private[figaro] def ve(): Unit = {
//expand()
val (neededElements, _) = getNeededElements(starterElements, Int.MaxValue)
Expand Down Expand Up @@ -236,7 +251,7 @@ class ProbQueryVariableElimination(override val universe: Universe, targets: Ele
dist.toStream
}

/**
/**
* Computes the expectation of a given function for single target element.
*/
def computeExpectation[T](target: Element[T], function: T => Double): Double = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Filtering.scala
* Filtering algorithms.
* ParFiltering.scala
* A parallel version of Filtering.
*
* Created By: Avi Pfeffer (apfeffer@cra.com)
* Creation Date: Jan 1, 2009
* Created By: Lee Kellogg (lkellogg@cra.com)
* Creation Date: Jun 2, 2015
*
* Copyright 2013 Avrom J. Pfeffer and Charles River Analytics, Inc.
* Copyright 2015 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.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
/*
* ParParticleFilter.scala
* A parallel one-time particle filter.
*
* Created By: Lee Kellogg (lkellogg@cra.com)
* Creation Date: Jun 2, 2015
*
* Copyright 2015 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.filtering

import com.cra.figaro.language._
import scala.collection.parallel.ParSeq
import com.cra.figaro.algorithm.filtering.ParticleFilter.WeightedParticle
import com.cra.figaro.library.cache.PermanentCache
import com.cra.figaro.library.cache.Cache
import com.cra.figaro.algorithm.sampling.LikelihoodWeighter

/**
* A parallel one-time particle filter. Distributes the work of generating particles at each time step over a specified
Expand Down Expand Up @@ -42,7 +58,7 @@ class ParOneTimeParticleFilter(static: () => Universe, initial: () => Universe,
* @param windows the UniverseWindows to sample from
* @param weightedParticleCreator a function that generates a WeightedParticle, given a UniverseWindow and an index
*/
private def genParticles(windows: Seq[UniverseWindow], weightedParticleCreator: (UniverseWindow, Int) => WeightedParticle): Seq[WeightedParticle] = {
private def genParticles(windows: Seq[(UniverseWindow, LikelihoodWeighter)], weightedParticleCreator: ((UniverseWindow, LikelihoodWeighter), Int) => WeightedParticle): Seq[WeightedParticle] = {
val parWindows = windows.par
val particles = parWindows zip indices flatMap { case(window, (start, end)) =>
(start to end) map { i => weightedParticleCreator(window, i) }
Expand All @@ -58,13 +74,15 @@ class ParOneTimeParticleFilter(static: () => Universe, initial: () => Universe,

def run(): Unit = {
windows = genInitialWindows()
val particles = genParticles(windows, (w, _) => initialWeightedParticle(w.static, w.current))
val windowWithCaches = windows.map(w => (w, new LikelihoodWeighter(w.current, new PermanentCache(w.current))))
val particles = genParticles(windowWithCaches, (w, _) => initialWeightedParticle(w._1.static, w._1.current, w._2))
doTimeStep(particles)
}

def advanceTime(evidence: Seq[NamedEvidence[_]] = List()): Unit = {
val newWindows = advanceUniverseWindows(windows)
val particles = genParticles(newWindows, (w, i) => addWeightedParticle(evidence, i, w))
val newWindowsWithCaches = newWindows.map(w => (w, new LikelihoodWeighter(w.current, new PermanentCache(w.current))))
val particles = genParticles(newWindowsWithCaches, (w, i) => addWeightedParticle(evidence, i, w._1, w._2))
doTimeStep(particles)
windows = newWindows
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ package com.cra.figaro.algorithm.filtering
import com.cra.figaro.algorithm.sampling._
import com.cra.figaro.language._
import com.cra.figaro.util._
import com.cra.figaro.library.cache.PermanentCache
import com.cra.figaro.library.cache.Cache
import com.cra.figaro.algorithm.sampling.LikelihoodWeighter

/**
* An abstract class of particle filters.
Expand All @@ -35,7 +38,7 @@ import com.cra.figaro.util._
* @param transition The transition function that returns a new universe from a static and previous universe, respectively.
*/
trait ParticleFilter {

val numParticles: Int

/** The belief about the state of the system at the current point in time. */
Expand Down Expand Up @@ -76,22 +79,18 @@ trait ParticleFilter {
* TODO: previous state could be replaced by the static universe (or a universe window)
*/
protected def makeWeightedParticle(previousState: State, currentUniverse: Universe): ParticleFilter.WeightedParticle = {
Forward(currentUniverse)
// avoiding recursion

// satisfied if all conditioned elements are satisfied
val satisfied = currentUniverse.conditionedElements.forall { x => x.conditionSatisfied }

//multiply weights together in log space if satisfied
val weight =
if (satisfied) {
math.exp(currentUniverse.constrainedElements.foldLeft(0.0)((b,a) => b + a.constraintValue))
} else 0.0
protected def makeWeightedParticle(previousState: State, currentUniverse: Universe, lw: LikelihoodWeighter): ParticleFilter.WeightedParticle = {

val weight = try {
math.exp(lw.computeWeight(currentUniverse.activeElements))
} catch {
case Importance.Reject => 0.0
}

val snapshot = new Snapshot
snapshot.store(currentUniverse)
val state = new State(snapshot, previousState.static)
currentUniverse.clearTemporaries
(weight, state)
}

Expand All @@ -118,21 +117,21 @@ trait ParticleFilter {
logProbEvidence = logProbEvidence + scala.math.log(sum / numParticles)
}

protected def addWeightedParticle(evidence: Seq[NamedEvidence[_]], index: Int, universes: UniverseWindow): ParticleFilter.WeightedParticle = {
protected def addWeightedParticle(evidence: Seq[NamedEvidence[_]], index: Int, universes: UniverseWindow, lw: LikelihoodWeighter): ParticleFilter.WeightedParticle = {
val previousState = beliefState(index)
previousState.dynamic.restore(universes.previous)
previousState.static.restore(universes.static)
universes.current.assertEvidence(evidence)
val result = makeWeightedParticle(previousState, universes.current)
val result = makeWeightedParticle(previousState, universes.current, lw)
result
}

protected def initialWeightedParticle(static: Universe, current: Universe): ParticleFilter.WeightedParticle = {
protected def initialWeightedParticle(static: Universe, current: Universe, lw: LikelihoodWeighter): ParticleFilter.WeightedParticle = {
Forward(static)
val staticSnapshot = new Snapshot
staticSnapshot.store(static)
val state = new State(new Snapshot, staticSnapshot)
makeWeightedParticle(state, current)
makeWeightedParticle(state, current, lw)
}

/*
Expand All @@ -159,7 +158,7 @@ trait ParticleFilter {
logProbEvidence
}

/**
/**
* The computed probability of evidence.
*/
def probEvidence(): Double = {
Expand All @@ -179,10 +178,10 @@ trait ParticleFilter {
*/
class OneTimeParticleFilter(static: Universe = new Universe(), initial: Universe, transition: (Universe, Universe) => Universe, val numParticles: Int)
extends Filtering(static, initial, transition) with ParticleFilter with OneTimeFiltering {

var currentUniverse: Universe = initial
var previousUniverse: Universe = _

private def doTimeStep(weightedParticleCreator: Int => ParticleFilter.WeightedParticle) {
val weightedParticles = for { i <- 0 until numParticles } yield weightedParticleCreator(i)

Expand All @@ -196,17 +195,19 @@ class OneTimeParticleFilter(static: Universe = new Universe(), initial: Universe
* Begin the particle filter, determining the initial distribution.
*/
def run(): Unit = {
doTimeStep((i: Int) => initialWeightedParticle(static, currentUniverse))
val lw = new LikelihoodWeighter(currentUniverse, new PermanentCache(currentUniverse))
doTimeStep((i: Int) => initialWeightedParticle(static, currentUniverse, lw))
}

/**
* Advance the filtering one time step, conditioning on the given evidence at the new time point.
*/
def advanceTime(evidence: Seq[NamedEvidence[_]] = List()): Unit = {

val currentWindow = new UniverseWindow(previousUniverse, currentUniverse, static)
val newWindow = advanceUniverse(currentWindow, transition)
doTimeStep((i: Int) => addWeightedParticle(evidence, i, newWindow))
val lw = new LikelihoodWeighter(newWindow.current, new PermanentCache(newWindow.current))
doTimeStep((i: Int) => addWeightedParticle(evidence, i, newWindow, lw))
previousUniverse = newWindow.previous
currentUniverse = newWindow.current
}
Expand Down Expand Up @@ -256,14 +257,14 @@ object ParticleFilter {

/** Weighted particles, consisting of a weight and a state. */
type WeightedParticle = (Double, State)

/** Reference to parallel implementation. */
def par = ParParticleFilter

}

/**
* A class representing a single window in time, with a current universe, a previous universe,
* A class representing a single window in time, with a current universe, a previous universe,
* and a static universe.
*/
class UniverseWindow(val previous: Universe, val current: Universe, val static: Universe)
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class OneTimeElementSampler(target: Element[_], myNumSamples: Int)
doInitialize()
super.run()
update
universe.clearTemporaries
}
}

Expand Down
Loading

0 comments on commit 2687f15

Please sign in to comment.