Support for other distribution, e.g. Normal, Poisson
beloglazov opened this issue · comments
It's just an enhancement suggestion: it would be nice to have support for other distributions in addition to the uniform distribution, such as the normal and Poisson distributions.
Thanks for you great work!
I'm trying to implement Knuth's algorithm for generating Poisson samples (http://en.wikipedia.org/wiki/Poisson_distribution#Generating_Poisson-distributed_random_variables) and came up with the following:
def poissonSample(lambda: Double): Rng[Int] = {
val L = math.exp(-lambda)
@annotation.tailrec
def loop(p: Double, k: Int): Rng[Int] = {
for {
u <- choosedouble(0, 1)
} yield {
if (p > L) loop(p * u, k + 1)
else k
}
}
loop(1.0, 0).map(_ - 1)
}
This doesn't compile, as the internal call to loop
is expected to return Int
instead of Rng[Int]
. I'm really a beginner in functional programming, and can't figure out at the moment how to solve this. I'd be happy to get any suggestions. Thanks!
Try:
def poissonSample(lambda: Double): Rng[Int] = {
val L = math.exp(-lambda)
@annotation.tailrec
def loop(p: Double, k: Int): Rng[Int] = {
choosedouble(0, 1).flatMap { u =>
if (p > L) loop(p * u, k + 1)
else Rng.constant(k)
}
}
loop(1.0, 0).map(_ - 1)
}
Thanks! That fixed the type issue. However, loop
is not tail-recursive:
[error] could not optimize @tailrec annotated method loop: it contains a recursive call not in tail position
[error] choosedouble(0, 1).flatMap(u =>
Is there any way to make it tail-recursive?
If you are interested, here is an implementation of the Box-Muller method for generating normally distributed numbers:
def normalSample(mean: Double, variance: Double): Rng[Double] = {
// Box–Muller method
choosedouble(0, 1).fill(2) map { u =>
val z = math.sqrt(-2 * math.log(u(0))) * math.cos(2 * math.Pi * u(1))
mean + math.sqrt(variance) * z
}
}
@beloglazov I don't think it needs to be tail recursive. Rng will take care of that for you internally.
@markhibberd Great, thanks for letting me know! I need to dig more into the Rng implementation to understand that.