Skip to content

Commit

Permalink
Merge pull request #555 from p2t2/DEV4.0
Browse files Browse the repository at this point in the history
Dev4.0
  • Loading branch information
mreposa committed Mar 14, 2016
2 parents 2687f15 + 0d17037 commit 290abb5
Show file tree
Hide file tree
Showing 377 changed files with 99,198 additions and 3,257 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.3.0
Bundle-Version: 4.0.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.3.0.0
version=4.0.0.0
Expand Up @@ -16,7 +16,6 @@ package com.cra.figaro.algorithm.decision
import com.cra.figaro.algorithm._
import com.cra.figaro.algorithm.factored._
import com.cra.figaro.algorithm.factored.factors._
import com.cra.figaro.algorithm.factored.factors.factory._
import com.cra.figaro.algorithm.sampling._
import com.cra.figaro.language._
import com.cra.figaro.library.decision._
Expand All @@ -25,6 +24,7 @@ import com.cra.figaro.algorithm.lazyfactored.Extended
import annotation.tailrec
import scala.collection.mutable.{ Map, Set }
import scala.language.existentials
import com.cra.figaro.algorithm.factored.factors.factory.Factory

/* Trait only extends for double utilities. User needs to provide another trait or convert utilities to double
* in order to use
Expand Down Expand Up @@ -71,13 +71,12 @@ trait ProbabilisticVariableEliminationDecision extends VariableElimination[(Doub
}
}

Factory.removeFactors()
val thisUniverseFactorsExceptUtil = neededElements flatMap (Factory.make(_))
val thisUniverseFactorsExceptUtil = neededElements flatMap (Factory.makeFactorsForElement(_))
// Make special utility factors for utility elements
val thisUniverseFactorsUtil = getUtilityNodes map (makeUtilFactor(_))

val dependentUniverseFactors =
for { (dependentUniverse, evidence) <- dependentUniverses } yield Factory.makeDependentFactor(universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))
for { (dependentUniverse, evidence) <- dependentUniverses } yield Factory.makeDependentFactor(Variable.cc, universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))

// Convert all non-utility factors from standard factors to decision factors, ie, factors are now tuples of (Double, _)
val thisUniverseFactorsExceptUtil_conv = thisUniverseFactorsExceptUtil.map(s => convert(s, false))
Expand Down
Expand Up @@ -23,12 +23,14 @@ import scala.collection._
import com.cra.figaro.algorithm.lazyfactored._
import scala.collection.immutable.Set
import com.cra.figaro.algorithm.UnsupportedAlgorithmException
import com.cra.figaro.algorithm.structured._
import com.cra.figaro.library.collection.MakeArray

/**
* Trait for algorithms that use factors.
*/
trait FactoredAlgorithm[T] extends Algorithm {

/**
* Get the elements that are needed by the query target variables and the evidence variables. Also compute the values
* of those variables to the given depth.
Expand Down Expand Up @@ -86,7 +88,8 @@ trait FactoredAlgorithm[T] extends Algorithm {
*
* */
val newlyNeededElements =
Element.closeUnderContingencies(starterElements.toSet).map((elem: Element[_]) => (elem, depth))
Element.closeUnderContingencies(starterElements.toSet ++ boundsInducingElements.toSet).map((elem: Element[_]) => (elem, depth))


@tailrec
def expandElements(curr: Set[(Element[_], Int)]): Unit = {
Expand All @@ -96,12 +99,13 @@ trait FactoredAlgorithm[T] extends Algorithm {
val (uni, set) = pair
val values = LazyValues(uni)
values.expandAll(set)
val currentlyExpanded = values.expandedElements.toSet
val currentDepths = currentlyExpanded.map(d => (d, values.expandedDepth(d).getOrElse(0)))
val others = currentDepths.flatMap(e => chaseDown(e._1, e._2, currentlyExpanded))
val filteredElements = others.filter(o => boundsInducingElements.contains(o._1))
val neededElements = filteredElements.flatMap(f => (f._1.elementsIAmContingentOn + f._1).map((_, f._2)))
neededElements
//val currentlyExpanded = values.expandedElements.toSet
//val currentDepths = currentlyExpanded.map(d => (d, values.expandedDepth(d).getOrElse(0)))
//val others = currentDepths.flatMap(e => chaseDown(e._1, e._2, currentlyExpanded))
//val filteredElements = others.filter(o => boundsInducingElements.contains(o._1))
//val neededElements = filteredElements.flatMap(f => (f._1.elementsIAmContingentOn + f._1).map((_, f._2)))
//neededElements
List()
})
expandElements(allNeededElements.toSet)
}
Expand All @@ -110,24 +114,21 @@ trait FactoredAlgorithm[T] extends Algorithm {

// We only include elements from other universes if they are specified in the starter elements.
val resultElements = values.expandedElements.toList ::: starterElements.filter(_.universe != universe)

/* We support non caching chains now using sampling
* resultElements.foreach(p => p match {
* case n: NonCachingChain[_,_] => throw new UnsupportedAlgorithmException(n)
* case _ =>
}* )
*
*/

// Only conditions and constraints produce distinct lower and upper bounds for *. So, if there are not such elements with * as one
// of their values, we don't need to compute bounds and can save computation.
val boundsNeeded = boundsInducingElements.exists(e => LazyValues(e.universe).storedValues(e).hasStar)
// We make sure to clear the variable cache now, once all values have been computed.
// This ensures that any created variables will be consistent with the computed values.
Variable.clearCache()

// Even though we just cleared the variables, we generate all the variables so we can create the factors
resultElements.foreach(Variable(_))

(resultElements, boundsNeeded)
}


/**
* All implementations of factored algorithms must specify a way to get the factors from the given universe and
* dependent universes.
Expand Down
Expand Up @@ -16,10 +16,12 @@ package com.cra.figaro.algorithm.factored
import com.cra.figaro.algorithm._
import com.cra.figaro.algorithm.learning._
import com.cra.figaro.language._
import com.cra.figaro.algorithm.factored.factors._
import scala.collection._
import scala.collection.mutable.{ Map, Set }
import scala.collection.mutable.{ Set }
import scala.collection.immutable.Map
import com.cra.figaro.util.MultiSet
import com.cra.figaro.algorithm.factored.factors._
import com.cra.figaro.algorithm.factored.factors.factory.Factory

/**
* Variable elimination for sufficient statistics factors.
Expand All @@ -44,25 +46,24 @@ class SufficientStatisticsVariableElimination(
* Clear the sufficient statistics factors used by this algorithm.
*/
private def removeFactors() {
statFactor.removeFactors
Variable.clearCache
}

/**
* 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]])]] = {
def getFactors(neededElements: List[Element[_]], targetElements: List[Element[_]], upper: Boolean = false): List[Factor[(Double, 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(","))
}
}

Factory.removeFactors()

val thisUniverseFactors = allElements flatMap (statFactor.make(_))
val dependentUniverseFactors =
for { (dependentUniverse, evidence) <- dependentUniverses } yield statFactor.makeDependentFactor(universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))
for { (dependentUniverse, evidence) <- dependentUniverses } yield statFactor.makeDependentFactor(Variable.cc, universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))

dependentUniverseFactors ::: thisUniverseFactors
}
Expand Down Expand Up @@ -94,8 +95,7 @@ class SufficientStatisticsVariableElimination(

val semiring = SufficientStatisticsSemiring(parameterMap)

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

Expand Down
Expand Up @@ -22,6 +22,8 @@ import annotation.tailrec
import scala.collection.mutable.{ Map, Set }
import scala.language.postfixOps
import scala.util.control.TailCalls._
import com.cra.figaro.algorithm.structured._
import com.cra.figaro.algorithm.factored.factors.factory.Factory

/**
* Trait of algorithms that perform variable elimination.
Expand Down Expand Up @@ -164,7 +166,8 @@ trait VariableElimination[T] extends FactoredAlgorithm[T] with OneTime {
println("*****************\nStarting factors\n")
allFactors.foreach((f: Factor[_]) => println(f.toReadableString))
}
val (_, order) = optionallyShowTiming(VariableElimination.eliminationOrder(allFactors, targetVariables), "Computing elimination order")
val (score, order) = optionallyShowTiming(VariableElimination.eliminationOrder(allFactors, targetVariables), "Computing elimination order")
if (debug) println("***************** Eliminition Score: " + score)
val factorsAfterElimination =
optionallyShowTiming(eliminateInOrder(order, HashMultiSet(allFactors: _*), initialFactorMap(allFactors)), "Elimination")
if (debug) println("*****************")
Expand Down Expand Up @@ -195,10 +198,9 @@ trait ProbabilisticVariableElimination extends VariableElimination[Double] {
println(Variable(element).id + "(" + element.name.string + "@" + element.hashCode + ")" + ": " + element + ": " + Variable(element).range.mkString(","))
}
}
Factory.removeFactors()
val thisUniverseFactors = allElements flatMap (Factory.make(_))
val thisUniverseFactors = allElements flatMap(Factory.makeFactorsForElement(_))
val dependentUniverseFactors =
for { (dependentUniverse, evidence) <- dependentUniverses } yield Factory.makeDependentFactor(universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))
for { (dependentUniverse, evidence) <- dependentUniverses } yield Factory.makeDependentFactor(Variable.cc, universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))
dependentUniverseFactors ::: thisUniverseFactors
}

Expand Down
Expand Up @@ -21,15 +21,14 @@ import com.cra.figaro.util._
import annotation.tailrec
import com.cra.figaro.algorithm.OneTimeProbQuery
import com.cra.figaro.algorithm.ProbQueryAlgorithm
import com.cra.figaro.algorithm.factored.factors._
import com.cra.figaro.algorithm.factored.factors.factory._
import com.cra.figaro.algorithm.factored._
import com.cra.figaro.algorithm.factored.factors._
import com.cra.figaro.algorithm.sampling.ProbEvidenceSampler
import com.cra.figaro.language.Element
import com.cra.figaro.language.Universe
import com.cra.figaro.language._
import com.cra.figaro.algorithm.lazyfactored.LazyValues
import com.cra.figaro.algorithm.lazyfactored.BoundedProbFactor
import scala.collection.mutable.Map
import com.cra.figaro.algorithm.factored.factors.factory.Factory

/**
* Trait for performing belief propagation.
Expand Down Expand Up @@ -204,9 +203,10 @@ trait ProbabilisticBeliefPropagation extends BeliefPropagation[Double] {
*/
def getFactors(neededElements: List[Element[_]], targetElements: List[Element[_]], upperBounds: Boolean = false): List[Factor[Double]] = {

val thisUniverseFactors = (neededElements flatMap (BoundedProbFactor.make(_, upperBounds))).filterNot(_.isEmpty)
//val thisUniverseFactors = (neededElements flatMap (BoundedProbFactor.make(_, upperBounds))).filterNot(_.isEmpty)
val thisUniverseFactors = (neededElements flatMap (Factory.makeFactorsForElement(_, upperBounds, true))).filterNot(_.isEmpty)
val dependentUniverseFactors =
for { (dependentUniverse, evidence) <- dependentUniverses } yield Factory.makeDependentFactor(universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))
for { (dependentUniverse, evidence) <- dependentUniverses } yield Factory.makeDependentFactor(Variable.cc, universe, dependentUniverse, dependentAlgorithm(dependentUniverse, evidence))
val factors = dependentUniverseFactors ::: thisUniverseFactors
// To prevent underflow, we do all computation in log space
factors.map(makeLogarithmic(_))
Expand Down
Expand Up @@ -15,7 +15,7 @@ package com.cra.figaro.algorithm.factored.factors

import com.cra.figaro.language._
import scala.collection._
import scala.collection.mutable.{ Set, Map }
import scala.collection.immutable.{ Set, Map }

/**
* Sum and product operations defined for sufficient statistics.
Expand All @@ -25,19 +25,19 @@ import scala.collection.mutable.{ Set, Map }
* Maximization determines the parameterMap automatically from the parameters.
*/
class SufficientStatisticsSemiring(parameterMap: immutable.Map[Parameter[_], Seq[Double]])
extends Semiring[(Double, mutable.Map[Parameter[_], Seq[Double]])] {
extends Semiring[(Double, immutable.Map[Parameter[_], Seq[Double]])] {

/**
* 0 probability and a vector of zeros for all parameters. The vector for a parameter
* must be of length equal to number of possible observations of the parameter.
*/
val zero = (0.0, mutable.Map(parameterMap.toSeq: _*))
val zero = (0.0, immutable.Map(parameterMap.toSeq: _*))

/**
* 1 probability and a vector of zeros for all parameters. The vector for a parameter
* must be of length equal to number of possible observations of the parameter.
*/
val one = (1.0, mutable.Map(parameterMap.toSeq: _*))
val one = (1.0, immutable.Map(parameterMap.toSeq: _*))

/**
* Probabilities are multiplied using standard multiplication.
Expand All @@ -57,22 +57,17 @@ class SufficientStatisticsSemiring(parameterMap: immutable.Map[Parameter[_], Seq
}

private def mapSum(xVector: (Double, Map[Parameter[_], Seq[Double]]), yVector: (Double, Map[Parameter[_], Seq[Double]])): Map[Parameter[_], Seq[Double]] = {
require(xVector._2.size == yVector._2.size)
val result: Map[Parameter[_], Seq[Double]] = Map()
for (x <- xVector._2.keys) {
result += x -> weightedComponentSum(xVector._2(x), yVector._2(x), xVector._1, yVector._1)
}
result
require(xVector._2.size == yVector._2.size)
Map() ++ {for (x <- xVector._2.keys) yield {
x -> weightedComponentSum(xVector._2(x), yVector._2(x), xVector._1, yVector._1)
}}
}

private def mapProduct(xVector: (Double, Map[Parameter[_], Seq[Double]]), yVector: (Double, Map[Parameter[_], Seq[Double]])): Map[Parameter[_], Seq[Double]] = {
val result: Map[Parameter[_], Seq[Double]] = Map()
private def mapProduct(xVector: (Double, Map[Parameter[_], Seq[Double]]), yVector: (Double, Map[Parameter[_], Seq[Double]])): Map[Parameter[_], Seq[Double]] = {
require(xVector._2.size == yVector._2.size)
for (x <- xVector._2.keys) {
result += x -> simpleComponentSum(xVector._2(x), yVector._2(x))
}
result

Map() ++ {for (x <- xVector._2.keys) yield {
x -> simpleComponentSum(xVector._2(x), yVector._2(x))
}}
}

private def simpleComponentSum(xVector: Seq[Double], yVector: Seq[Double]): Seq[Double] = {
Expand Down

0 comments on commit 290abb5

Please sign in to comment.