@@ -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 ,
@@ -210,6 +212,31 @@ resampleMultinomial ::
210212 Population m a
211213resampleMultinomial = resampleGeneric multinomial
212214
215+ -- | Only use the given resampler when the effective sample size is below a certain threshold
216+ onlyBelowEffectiveSampleSize ::
217+ MonadDistribution m =>
218+ -- | The threshold under which the effective sample size must fall before the resampler is used.
219+ -- For example, this may be half of the number of particles.
220+ Double ->
221+ -- | The resampler to user under the threshold
222+ (MonadDistribution m => Population m a -> Population m a ) ->
223+ -- | The new resampler
224+ (Population m a -> Population m a )
225+ onlyBelowEffectiveSampleSize threshold resampler pop = do
226+ ess <- lift $ effectiveSampleSize pop
227+ if ess < threshold then resampler pop else pop
228+
229+ -- | Compute the effective sample size of a population from the weights.
230+ --
231+ -- See https://en.wikipedia.org/wiki/Design_effect#Effective_sample_size
232+ effectiveSampleSize :: Functor m => Population m a -> m Double
233+ effectiveSampleSize = fmap (effectiveSampleSizeKish . map (exp . ln . snd )) . runPopulation
234+ where
235+ effectiveSampleSizeKish :: [Double ] -> Double
236+ effectiveSampleSizeKish weights = square (Data.List. sum weights) / Data.List. sum (square <$> weights)
237+ square :: Double -> Double
238+ square x = x * x
239+
213240-- | Separate the sum of weights into the 'Weighted' transformer.
214241-- Weights are normalized after this operation.
215242extractEvidence ::
0 commit comments