@@ -27,6 +27,8 @@ module Control.Monad.Bayes.Population
2727 resampleSystematic ,
2828 stratified ,
2929 resampleStratified ,
30+ onlyBelowEffectiveSampleSize ,
31+ effectiveSampleSize ,
3032 extractEvidence ,
3133 pushEvidence ,
3234 proper ,
@@ -244,6 +246,31 @@ resampleMultinomial ::
244246 PopulationT m a
245247resampleMultinomial = resampleGeneric multinomial
246248
249+ -- | Only use the given resampler when the effective sample size is below a certain threshold
250+ onlyBelowEffectiveSampleSize ::
251+ (MonadDistribution m ) =>
252+ -- | The threshold under which the effective sample size must fall before the resampler is used.
253+ -- For example, this may be half of the number of particles.
254+ Double ->
255+ -- | The resampler to user under the threshold
256+ ((MonadDistribution m ) => PopulationT m a -> PopulationT m a ) ->
257+ -- | The new resampler
258+ (PopulationT m a -> PopulationT m a )
259+ onlyBelowEffectiveSampleSize threshold resampler pop = do
260+ ess <- lift $ effectiveSampleSize pop
261+ if ess < threshold then resampler pop else pop
262+
263+ -- | Compute the effective sample size of a population from the weights.
264+ --
265+ -- See https://en.wikipedia.org/wiki/Design_effect#Effective_sample_size
266+ effectiveSampleSize :: (Functor m ) => PopulationT m a -> m Double
267+ effectiveSampleSize = fmap (effectiveSampleSizeKish . map (exp . ln . snd )) . runPopulationT
268+ where
269+ effectiveSampleSizeKish :: [Double ] -> Double
270+ effectiveSampleSizeKish weights = square (Data.List. sum weights) / Data.List. sum (square <$> weights)
271+ square :: Double -> Double
272+ square x = x * x
273+
247274-- | Separate the sum of weights into the 'WeightedT' transformer.
248275-- Weights are normalized after this operation.
249276extractEvidence ::
0 commit comments