Skip to content

Commit

Permalink
Merge pull request #463 from p2t2/DEV3.2.0
Browse files Browse the repository at this point in the history
Dev3.2.0
  • Loading branch information
mreposa committed Jun 1, 2015
2 parents c1a61e4 + 9e0dda9 commit 2b6d4f9
Show file tree
Hide file tree
Showing 30 changed files with 502 additions and 191 deletions.
2 changes: 1 addition & 1 deletion Figaro/META-INF/MANIFEST.MF
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Figaro
Bundle-SymbolicName: com.cra.figaro
Bundle-Version: 3.1.0
Bundle-Version: 3.2.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
@@ -1 +1 @@
version=3.1.0.0
version=3.2.0.0
@@ -1,13 +1,13 @@
/*
* DecisionVariableElimination.scala
* Variable elimination for Decisions algorithm.
*
*
* Created By: Brian Ruttenberg (bruttenberg@cra.com)
* Creation Date: Oct 1, 2012
*
*
* 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.
*/

Expand All @@ -28,7 +28,7 @@ import scala.language.existentials

/* Trait only extends for double utilities. User needs to provide another trait or convert utilities to double
* in order to use
*
*
*/
/**
* Trait for Decision based Variable Elimination. This implementation is hardcoded to use.
Expand All @@ -39,12 +39,12 @@ trait ProbabilisticVariableEliminationDecision extends VariableElimination[(Doub
*/
/* Implementations must define this */
def getUtilityNodes: List[Element[_]]

/**
* Semiring for Decisions uses a sum-product-utility semiring.
*/
override val semiring = SumProductUtilitySemiring()

/**
* Makes a utility factor an element designated as a utility. This is factor of a tuple (Double, Double)
* where the first value is 1.0 and the second is a possible utility of the element.
Expand All @@ -60,14 +60,14 @@ trait ProbabilisticVariableEliminationDecision extends VariableElimination[(Doub
override def starterElements = getUtilityNodes ::: targetElements

/**
* Create the factors for decision factors. Each factor is hardcoded as a tuple of (Double, Double),
* where the first value is the probability and the second is the utility.
*/
* Create the factors for decision factors. Each factor is hardcoded as a tuple of (Double, Double),
* where the first value is the probability and the second is the utility.
*/
def getFactors(neededElements: List[Element[_]], targetElements: List[Element[_]], upper: Boolean = false): List[Factor[(Double, Double)]] = {
if (debug) {
println("Elements (other than utilities) appearing in factors and their ranges:")
for { element <- neededElements } {
println(Variable(element).id + "(" + element.name.string + "@" + element.hashCode + ")" + ": " + element + ": " + Variable(element).range.mkString(","))
for { element <- neededElements } {
println(Variable(element).id + "(" + element.name.string + "@" + element.hashCode + ")" + ": " + element + ": " + Variable(element).range.mkString(","))
}
}

Expand Down Expand Up @@ -99,7 +99,7 @@ trait ProbabilisticVariableEliminationDecision extends VariableElimination[(Doub
f.mapTo[(Double, Double)]((d: Double) => (d, 0.0), semiring.asInstanceOf[Semiring[(Double, Double)]])
} else {
if (f.variables.length > 1) throw new IllegalUtilityNodeException

val newF = f.mapTo[(Double, Double)]((d: Double) => (d, 0.0), semiring.asInstanceOf[Semiring[(Double, Double)]])
for {i <- 0 until f.variables(0).range.size} {
newF.set(List(i), (newF.get(List(i))._1, f.variables(0).range(i).asInstanceOf[Double]))
Expand All @@ -125,17 +125,17 @@ class ProbQueryVariableEliminationDecision[T, U](override val universe: Universe
lazy val queryTargets = List(target)

/**
* The variable elimination eliminates all variables except on all decision nodes and their parents.
* The variable elimination eliminates all variables except on all decision nodes and their parents.
* Thus the target elements is both the decision element and the parent element.
*/
val targetElements = List(target, target.args(0))
val targetElements = List(target, target.args(0))

def getUtilityNodes = utilityNodes

private var finalFactors: Factor[(Double, Double)] = Factory.defaultFactor[(Double, Double)](List(), List(), semiring)

/* Marginalizes the final factor using the semiring for decisions
*
*
*/
private def marginalizeToTarget(factor: Factor[(Double, Double)], target: Element[_]): Unit = {
val unnormalizedTargetFactor = factor.marginalizeTo(semiring, Variable(target))
Expand All @@ -148,13 +148,13 @@ class ProbQueryVariableEliminationDecision[T, U](override val universe: Universe
private def marginalize(resultFactor: Factor[(Double, Double)]) =
queryTargets foreach (marginalizeToTarget(resultFactor, _))

private def makeResultFactor(factorsAfterElimination: Set[Factor[(Double, Double)]]): Factor[(Double, Double)] = {
private def makeResultFactor(factorsAfterElimination: MultiSet[Factor[(Double, Double)]]): Factor[(Double, Double)] = {
// It is possible that there are no factors (this will happen if there are no decisions or utilities).
// Therefore, we start with the unit factor and use foldLeft, instead of simply reducing the factorsAfterElimination.
factorsAfterElimination.foldLeft(Factory.unit(semiring))(_.product(_))
}

def finish(factorsAfterElimination: Set[Factor[(Double, Double)]], eliminationOrder: List[Variable[_]]) =
def finish(factorsAfterElimination: MultiSet[Factor[(Double, Double)]], eliminationOrder: List[Variable[_]]) =
finalFactors = makeResultFactor(factorsAfterElimination)

/**
Expand All @@ -176,7 +176,7 @@ class ProbQueryVariableEliminationDecision[T, U](override val universe: Universe
(0.0 /: computeDistribution(target))(_ + get(_))
}

/**
/**
* Returns the computed utility of all parent/decision tuple values. For VE, these are not samples
* but the actual computed expected utility for all combinations of the parent and decision.
*/
Expand All @@ -194,14 +194,14 @@ class ProbQueryVariableEliminationDecision[T, U](override val universe: Universe
// find the variables of the parents.
val parentVariable = factor.variables.filterNot(_ == decisionVariable)(0)

// index of the decision variable
// index of the decision variable

val indexOfDecision = indices(factor.variables, decisionVariable)
val indexOfParent = indices(factor.variables, parentVariable)

for { indices <- factor.getIndices} {

/* for each index in the list of indices, strip out the decision variable index,
/* for each index in the list of indices, strip out the decision variable index,
* and retrieve the map entry for the parents. If the factor value is greater than
* what is currently stored in the strategy map, replace the decision with the new one from the factor
*/
Expand Down Expand Up @@ -257,7 +257,7 @@ object DecisionVariableElimination {
}
/**
* Create a decision variable elimination algorithm with the given decision variables and indicated utility
* nodes and using the given dependent universes in the current default universe. Use the given dependent
* nodes and using the given dependent universes in the current default universe. Use the given dependent
* algorithm function to determine the algorithm to use to compute probability of evidence in each dependent universe.
*/
def apply[T, U](
Expand Down
Expand Up @@ -73,7 +73,8 @@ trait FactoredAlgorithm[T] extends Algorithm {
if (depth >= 0) {
val includeThisElement = depth > LazyValues(element.universe).expandedDepth(element).getOrElse(-1)
// Keeping track of what's been chased so far avoids infinite recursion
val toChase = element.universe.directlyUsedBy(element).toSet ++ dependentUniverseCoparents.getOrElse(element, Set()) -- chasedSoFar
val related = element.universe.directlyUsedBy(element).toSet ++ dependentUniverseCoparents.getOrElse(element, Set())
val toChase = related.filter(!chasedSoFar.contains(_))
val rest = toChase.flatMap((elem: Element[_]) => chaseDown(elem, depth - 1, chasedSoFar ++ toChase))
if (includeThisElement) rest + ((element, depth)); else rest
} else Set()
Expand Down
@@ -1,13 +1,13 @@
/*
* MPEVariableElimination.scala
* Variable elimination algorithm for computing most probable explanation.
*
*
* Created By: Avi Pfeffer (apfeffer@cra.com)
* Creation Date: Jan 1, 2009
*
*
* 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.
*/

Expand All @@ -20,10 +20,11 @@ import com.cra.figaro.algorithm.factored.factors._
import com.cra.figaro.util
import scala.collection.mutable.{ Set, Map }
import com.cra.figaro.algorithm.lazyfactored._
import com.cra.figaro.util.MultiSet

/**
* Variable elimination algorithm to compute the most probable explanation.
*
*
* @param showTiming Produce timing information on steps of the algorithm
*/
class MPEVariableElimination(override val universe: Universe)(
Expand All @@ -33,12 +34,12 @@ class MPEVariableElimination(override val universe: Universe)(

override val comparator = Some((x: Double, y: Double) => x < y)
override val semiring = MaxProductSemiring()

/*
* We are trying to find a configuration of all the elements, so we must make them all starter elements for expansion.
*/
override val starterElements = universe.activeElements

/**
* Empty for MPE Algorithms.
*/
Expand All @@ -47,15 +48,15 @@ class MPEVariableElimination(override val universe: Universe)(
private val maximizers: Map[Variable[_], Any] = Map()

private def getMaximizer[T](variable: Variable[T]): T = maximizers(variable).asInstanceOf[variable.Value]

/*
* Convert factors to use MaxProduct
*/
override def getFactors(allElements: List[Element[_]], targetElements: List[Element[_]], upper: Boolean = false): List[Factor[Double]] = {
val factors = super.getFactors(allElements, targetElements, upper)
val factors = super.getFactors(allElements, targetElements, upper)
factors.map (_.mapTo(x => x, semiring))
}

def mostLikelyValue[T](target: Element[T]): T = getMaximizer(Variable(target))

private def backtrackOne[T](factor: Factor[_], variable: Variable[T]): Unit = {
Expand All @@ -64,7 +65,7 @@ class MPEVariableElimination(override val universe: Universe)(
maximizers += variable -> factor.get(indices)
}

def finish(factorsAfterElimination: Set[Factor[Double]], eliminationOrder: List[Variable[_]]): Unit =
def finish(factorsAfterElimination: MultiSet[Factor[Double]], eliminationOrder: List[Variable[_]]): Unit =
for { (variable, factor) <- eliminationOrder.reverse.zip(recordingFactors) } { backtrackOne(factor, variable) }
}

Expand Down
@@ -1,13 +1,13 @@
/*
* SufficientStatisticsVariableElimination.scala
* Variable elimination algorithm for sufficient statistics factors
*
*
* 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.
*/

Expand All @@ -19,12 +19,13 @@ import com.cra.figaro.language._
import com.cra.figaro.algorithm.factored.factors._
import scala.collection._
import scala.collection.mutable.{ Map, Set }
import com.cra.figaro.util.MultiSet

/**
* Variable elimination for sufficient statistics factors.
* Variable elimination for sufficient statistics factors.
* The final factor resulting from variable elimination contains a mapping of parameters to sufficient statistics vectors
* which can be used to maximize parameter values.
*
*
* @param parameterMap A map of parameters to their sufficient statistics.
*/
class SufficientStatisticsVariableElimination(
Expand All @@ -47,14 +48,14 @@ class SufficientStatisticsVariableElimination(
}

/**
* Particular implementations of probability of evidence algorithms must define the following method.
* Particular implementations of probability of evidence algorithms must define the following method.
*/
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 } {
println(Variable(element).id + "(" + element.name.string + "@" + element.hashCode + ")" + ": " + element + ": " + Variable(element).range.mkString(","))
for { element <- allElements } {
println(Variable(element).id + "(" + element.name.string + "@" + element.hashCode + ")" + ": " + element + ": " + Variable(element).range.mkString(","))
}
}

Expand All @@ -70,12 +71,12 @@ class SufficientStatisticsVariableElimination(
* Empty for this algorithm.
*/
val targetElements = List[Element[_]]()

override def starterElements = universe.conditionedElements ++ universe.constrainedElements

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

def finish(factorsAfterElimination: Set[Factor[(Double, Map[Parameter[_], Seq[Double]])]], eliminationOrder: List[Variable[_]]): Unit = {
def finish(factorsAfterElimination: MultiSet[Factor[(Double, Map[Parameter[_], Seq[Double]])]], eliminationOrder: List[Variable[_]]): Unit = {
// It is possible that there are no factors (this will happen if there is no evidence).
// Therefore, we start with the unit factor and use foldLeft, instead of simply reducing the factorsAfterElimination.
val finalFactor = factorsAfterElimination.foldLeft(Factory.unit(semiring))(_.product(_))
Expand All @@ -86,14 +87,14 @@ class SufficientStatisticsVariableElimination(
}

/**
* Returns a mapping of parameters to sufficient statistics resulting from
* Returns a mapping of parameters to sufficient statistics resulting from
* elimination of the factors.
*/
def getSufficientStatisticsForAllParameters = { result._2.toMap }

val semiring = SufficientStatisticsSemiring(parameterMap)

override def cleanUp() = {
override def cleanUp() = {
statFactor.removeFactors
super.cleanUp()
}
Expand Down

0 comments on commit 2b6d4f9

Please sign in to comment.