@@ -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,31 @@ 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
+ 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
+
213
240
-- | Separate the sum of weights into the 'Weighted' transformer.
214
241
-- Weights are normalized after this operation.
215
242
extractEvidence ::
0 commit comments