diff --git a/core/src/main/scala/dimwit/stats/IndependentDistributions.scala b/core/src/main/scala/dimwit/stats/IndependentDistributions.scala index 2132c49..6929598 100644 --- a/core/src/main/scala/dimwit/stats/IndependentDistributions.scala +++ b/core/src/main/scala/dimwit/stats/IndependentDistributions.scala @@ -216,12 +216,22 @@ class Exponential[T <: Tuple: Labels, V: IsFloating](val rate: Tensor[T, V]) ext ) stndExp / rate -class Poisson[T <: Tuple: Labels, V: IsInteger](val rate: Tensor[T, V]) extends IndependentDistribution[T, V]: +class Poisson[T <: Tuple: Labels, VSample: IsInteger, VRate: IsFloating](val rate: Tensor[T, VRate]) extends IndependentDistribution[T, VSample]: - override def elementWiseLogProb(x: Tensor[T, V]): Tensor[T, LogProb] = + override def elementWiseLogProb(x: Tensor[T, VSample]): Tensor[T, LogProb] = liftPyTensor(jstats.poisson.logpmf(x.jaxValue, mu = rate.jaxValue)) - override def sample(k: Random.Key): Tensor[T, V] = - liftPyTensor( - Jax.jrandom.poisson(k.jaxKey, lam = rate.jaxValue, shape = rate.shape.dimensions.toPythonProxy) + override def sample(k: Random.Key): Tensor[T, VSample] = + liftPyTensor(rate.shape, VType[VSample])( + Jax.jrandom.poisson(k.jaxKey, lam = rate.jaxValue, shape = rate.shape.dimensions.toPythonProxy, dtype = VType[VSample].dtype.jaxType) ) + +object Poisson: + + /** Create a Poisson distribution from a rate tensor, sampling as Int32 counts */ + def apply[T <: Tuple: Labels, VRate: IsFloating](rate: Tensor[T, VRate]): Poisson[T, Int32, VRate] = + new Poisson[T, Int32, VRate](rate) + + /** Create a Poisson distribution from a rate tensor, sampling counts of the given integer type */ + def apply[T <: Tuple: Labels, VSample: IsInteger, VRate: IsFloating](rate: Tensor[T, VRate], vtype: VType[VSample]): Poisson[T, VSample, VRate] = + new Poisson[T, VSample, VRate](rate) diff --git a/core/src/test/scala/dimwit/stats/DistributionSuite.scala b/core/src/test/scala/dimwit/stats/DistributionSuite.scala index ab0de81..cb280bd 100644 --- a/core/src/test/scala/dimwit/stats/DistributionSuite.scala +++ b/core/src/test/scala/dimwit/stats/DistributionSuite.scala @@ -401,7 +401,7 @@ class DistributionSuite extends DimwitTest: describe("Poisson"): it("logProbs matches JAX"): - val rate = Tensor(Shape(Axis[A] -> 3)).fromArray(Array(1, 3, 10)) + val rate = Tensor(Shape(Axis[A] -> 3)).fromArray(Array(1.0f, 3.0f, 10.0f)) val x = Tensor(Shape(Axis[A] -> 3)).fromArray(Array(1, 2, 8)) val dist = Poisson(rate) @@ -413,7 +413,7 @@ class DistributionSuite extends DimwitTest: it("sample means approximates rate"): val poisson = Poisson( - Tensor(Shape(Axis[A] -> 2)).fromArray(Array(1, 5)) + Tensor(Shape(Axis[A] -> 2)).fromArray(Array(1.0f, 5.0f)) ) val key = Random.Key(42) val samples = key.splitvmap(Axis[Samples] -> 10000)(k => poisson.sample(k))