Skip to content

Commit

Permalink
- changed package path to: "probability.probdsl"
Browse files Browse the repository at this point in the history
- build probdsl on monadic defered distribution,
  scalaz monads and embeddedmonads
- update all examples to work with changes
  • Loading branch information
urso committed Sep 10, 2010
1 parent 9fddd92 commit 375bed0
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 182 deletions.
6 changes: 3 additions & 3 deletions examples/Alarm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* ----------------------------------------------------------------------------
*/
object Alarm {
import probability.EmbeddedProbability._
import probability.probdsl._

//first we want to encode the events
case class Burglary(s:Boolean)
Expand Down Expand Up @@ -72,7 +72,7 @@ object Alarm {
def mary(a:Alarm) = mkProb( if(a.s) 0.7 else 0.01, Mary )

//compute the joint probability:
val p = prob[State] {
val p = normalizedProb[State] {
val b = burglary
val e = earthquake
val a = alarm(b,e)
Expand Down Expand Up @@ -103,7 +103,7 @@ object Alarm {

// do conditional filtering directly
guard( john(a).s && mary(a).s )
Some(b)
b
})
}
}
Expand Down
8 changes: 4 additions & 4 deletions examples/Diagnosis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*
*/
object Diagnosis {
import probability.EmbeddedProbability._
import probability.probdsl._

sealed abstract class Status
case class Ill() extends Status
Expand All @@ -51,13 +51,13 @@ object Diagnosis {
def pTest(d:Status) = flip(if (d == Ill()) PFalseNegative else 1.0 - PFalsePositive,
Negative(), Positive())

// compute P(I|T=Positive):
// compute P(I|T=Positive) using bayes rule:
def run = {
println("P(I|T=Positive) = ")
println(normalizedProb[Status] {
val i = pDisease
guard( Positive() == pTest(i) )
Some(i)
guard( Positive() == pTest(i) ) // equivalent to: if (Positive() == pTest(i)) single(i) else stop
i
})
}

Expand Down
4 changes: 2 additions & 2 deletions examples/DrugTest.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

object DrugTest {
import probability.EmbeddedProbability._
import probability.probdsl._

sealed abstract class Status
object User extends Status { override def toString = "User" }
Expand All @@ -13,7 +13,7 @@ object DrugTest {
val PosIfUser = 0.99
val PosIfClean = 0.01

val drugTest = prob[(Status, TestResult)] {
val drugTest = normalizedProb[(Status, TestResult)] {
val s = flip(0.001, User, Clean)
val t = flip(if (s == User) PosIfUser else PosIfClean, Positive, Negative)
(s, t)
Expand Down
6 changes: 3 additions & 3 deletions examples/MontyHall.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
*/
object MontyHall {
import probability.EmbeddedProbability._
import probability.probdsl._

// first we want to encode our state.
//
Expand Down Expand Up @@ -96,8 +96,8 @@ object MontyHall {

// print some results
def run = {
println("stay:\n" + prob { testWinner(stay(firstRound)) } + "\n")
println("switch:\n" + prob { testWinner(switchDoor(firstRound)) })
println("stay:\n" + normalizedProb { testWinner(stay(firstRound)) } + "\n")
println("switch:\n" + normalizedProb { testWinner(switchDoor(firstRound)) })
}

}
Expand Down
33 changes: 14 additions & 19 deletions examples/SpamPlan.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@
*/
object SpamPlan {
import probability._
import probability.EmbeddedProbability._
import probdsl._

sealed abstract class Classification
case class Spam() extends Classification { override def toString = "Spam" }
case class Ham() extends Classification { override def toString = "Ham" }

val S = List(Spam(), Ham())

private val uniformClasses : Distribution[Classification] = prob { uniform(S) }
private val uniformClasses : Distribution[Classification] = normalizedProb[Classification] { uniform(S) }

// trait every spam database must implement.
// Will additionally mix in functions for computing probabilities
Expand Down Expand Up @@ -135,24 +135,16 @@ object SpamPlan {

def pHasWord(word:String, t:Classification) = {
guard(pWord(word, t))
Some(t)
t
}

// P(S | W == word) = < P(W == word | S) * P_prior(S)) >
def pHasWord(word:String, prior:Distribution[Classification] = prob(pMsgType)) = {
def pHasWord(word:String, prior:Distribution[Classification] = normalizedProb[Classification](pMsgType)) = {
var t = dist(prior)
guard(pWord(word, t))
Some(t)
t
}

// P(S | W1 == word1, W2 == word2, ... )
// = < P(S|W1) * P(S|W2) * ... >
def pHasWords(words:Iterator[String], prior:Distribution[Classification] = prob(pMsgType)) = {
val clazz:Option[Classification] = dist(prior.map { Some(_) })
words.foldLeft(clazz) { (optT, word) =>
optT flatMap (pHasWord(word, _))
}
}
def characteristic(f: Distribution[Classification] => Distribution[Classification]) = {
f(uniformClasses)
}
Expand Down Expand Up @@ -225,22 +217,25 @@ object SpamPlan {
def bayesianClassifier_(db:SpamFeaturesDB,
words:Iterator[String],
max:Int = 15,
prior:Distribution[Classification] = null) = {
prior:Distribution[Classification] = null) :
(Distribution[Classification],Int) = {
val prior_ : Distribution[Classification] = (if(prior == null)
prob{db.pMsgType}
normalizedProb{db.pMsgType}
else prior)

val classifiers = db.findClassifiers(words,max).toList
val p = classifiers.map { c => prob[Option[Classification]] {
val p = classifiers.map { c => prob[Classification] {
// compute < P_uni(S|Wi) * P_prior(S) >
// and lift into Option type for doing bayesian inference (invalid cases
// are None and valid cases Some(class)
val t = dist(prior_);
if (t == dist(c)) Some(t) else None
}}.reduceLeft { (da, db) => prob[Option[Classification]] {
guard(t == dist(c))
t
}}.reduceLeft { (da, db) => normalizedProb[Option[Classification]] {
// multiply all probabilities (naive bayesian part)
val t = dist(da)
if (t == dist(db)) t else None
guard (t == dist(db))
t
}}

(Probability.normalize(p), // normalize is always the last step when doing
Expand Down
39 changes: 18 additions & 21 deletions examples/Test1.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@


object Test1 {
import probability.EmbeddedProbability._
import probability.probdsl._

def test = prob[Boolean] {
flip(0.5)
Expand All @@ -16,7 +16,7 @@ object Test1 {
def die = uniform[Int](Array(1,2,3,4,5,6))
def coin = flip(0.5)

def test3 = prob[(Int,Int)] {
def test3 = normalizedProb[(Int,Int)] {
val d1 = die
val d2 = die
(d1, d2)
Expand All @@ -33,46 +33,43 @@ object Test1 {
d._1 + d._2
}

def test6 = collecting[Int](loopK(100000)) {
def test6 = collect[Int](loopK(100000)) {
val d1 = die
val d2 = die
d1 + d2
}

//run test for 30 seconds
def test7 = collecting[Int](loopMaxMs(1000 * 30)) {
/*//run test for 30 seconds*/
def test7 = collect[Int](loopMaxMs(1000 * 30)) {
val d1 = die
val d2 = die
d1 + d2
}

def test8 = pickValue( runProbabilistic[(Int, Int)] {
(die, die)
})

def test9 = pickValue( runProbabilistic[Int] {
def test8 = normalizedProb[Int] {
die + die
})
}.pick

def test10 = prob[String] {
def test9 = normalizedProb[String] {
if (coin) "head" else "tail"
}

def test11 = prob[Option[String]] {
// truth table
def test10 = prob[String] {
(coin, coin) match {
case (true, true) => Some ("heads")
case (false, false) => Some ("tails")
case (_, _) => None
case (true, true) => single("heads")
case (false, false) => single("tails")
case (_, _) => stop
}
}

def test12 = normalizedProb[String] {
// truth table with normalization
def test11 = normalizedProb[String] {
(coin, coin) match {
case (true, true) => Some ("heads")
case (false, false) => Some ("tails")
case (_, _) => None
case (true, true) => single("heads")
case (false, false) => single("tails")
case (_, _) => stop
}
}

}

102 changes: 102 additions & 0 deletions src/main/scala/probability/probdsl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package probability

import scala.util.continuations._
import scalaz._
import Monad.monad

import embeddedmonads._

object DeferedDistributionPure extends Pure[DeferedDistribution] {
def pure[A](a: => A) = defered.single[A](a)
}

object DeferedDistributionBind extends Bind[DeferedDistribution] {
def bind[A,B](a: DeferedDistribution[A], f: A => DeferedDistribution[B]) =
a flatMap f
}

private object EmbeddedDistribution extends EmbeddedMonad[DeferedDistribution]()(
monad[DeferedDistribution](DeferedDistributionBind, DeferedDistributionPure))

object probdsl {
import EmbeddedDistribution._

def runProb[C](ctx: => Any @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]])
: DeferedDistribution[C] =
runMonad[C](ctx)

def prob[C](ctx: => Any @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]])
: Distribution[Option[C]] =
runProb[C](ctx).reify

def normalizedProb[C](ctx: => Any @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]])
: Distribution[C] =
runProb[C](ctx).normalizedProb

def sampleOne[C](ctx: => Any @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]])
: Option[C] =
runProb[C](ctx).pick

def collect[C](pred: () => Boolean)
(ctx: => Any @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]])
: Distribution[Option[C]] =
runProb[C](ctx).collect(pred)

def normalizedCollect[C](pred: () => Boolean)
(ctx: => Any @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]])
: Distribution[C] =
runProb[C](ctx).normalizedCollect(pred)

def loopK(k:Int) : (() => Boolean) = defered.loopK(k)

def loopMaxMs(k:Long) : (() => Boolean) = defered.loopMaxMs(k)

def flip[A](x:Double, a:A, b:A) : A @ cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
defered.flip[A](x,a,b).value

def flip(x:Double) : Boolean @ cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
flip[Boolean](x, true, false)

def uniform[A](d:Iterable[A]) : A @ cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
defered.uniform(d).value

def linear[A](d:Iterable[A]) : A @ cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
defered.linear(d).value

def single[A](a:A) : A @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
defered.single(a).value

def dist[A](d:Distribution[A]) : A @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
defered.dist[A](d).value

def dist[A](d:Iterable[(Double, A)]) : A @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
dist[A](Distribution(d))

def dist[A](d:(Double,A)*) : A @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] =
dist[A](Distribution(d))

def guard(b:Boolean) : Unit @cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] = if (!b) {
shift { k: (Unit => DeferedDistribution[Any]) =>
defered.pnull[Any]
}
}

def stop : Unit @ cpsParam[DeferedDistribution[Any],
DeferedDistribution[Any]] = guard(false)
}

Loading

0 comments on commit 375bed0

Please sign in to comment.