@@ -27,6 +27,8 @@ module Control.Monad.Bayes.Population
27
27
resampleSystematic ,
28
28
stratified ,
29
29
resampleStratified ,
30
+ onlyBelowEffectiveSampleSize ,
31
+ effectiveSampleSize ,
30
32
extractEvidence ,
31
33
pushEvidence ,
32
34
proper ,
@@ -210,6 +212,32 @@ resampleMultinomial ::
210
212
Population m a
211
213
resampleMultinomial = resampleGeneric multinomial
212
214
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
+ -}
233
+ effectiveSampleSize :: Functor m => Population m a -> m Double
234
+ effectiveSampleSize = fmap (effectiveSampleSizeKish . map (exp . ln . snd )) . runPopulation
235
+ where
236
+ effectiveSampleSizeKish :: [Double ] -> Double
237
+ effectiveSampleSizeKish weights = square (Data.List. sum weights) / Data.List. sum (square <$> weights)
238
+ square :: Double -> Double
239
+ square x = x * x
240
+
213
241
-- | Separate the sum of weights into the 'Weighted' transformer.
214
242
-- Weights are normalized after this operation.
215
243
extractEvidence ::
0 commit comments