@@ -26,6 +26,8 @@ module Control.Monad.Bayes.Population
26
26
resampleSystematic ,
27
27
stratified ,
28
28
resampleStratified ,
29
+ onlyBelowEffectiveSampleSize ,
30
+ effectiveSampleSize ,
29
31
extractEvidence ,
30
32
pushEvidence ,
31
33
proper ,
@@ -206,6 +208,31 @@ resampleMultinomial ::
206
208
PopulationT m a
207
209
resampleMultinomial = resampleGeneric multinomial
208
210
211
+ -- | Only use the given resampler when the effective sample size is below a certain threshold
212
+ onlyBelowEffectiveSampleSize ::
213
+ (MonadDistribution m ) =>
214
+ -- | The threshold under which the effective sample size must fall before the resampler is used.
215
+ -- For example, this may be half of the number of particles.
216
+ Double ->
217
+ -- | The resampler to user under the threshold
218
+ ((MonadDistribution m ) => PopulationT m a -> PopulationT m a ) ->
219
+ -- | The new resampler
220
+ (PopulationT m a -> PopulationT m a )
221
+ onlyBelowEffectiveSampleSize threshold resampler pop = do
222
+ ess <- lift $ effectiveSampleSize pop
223
+ if ess < threshold then resampler pop else pop
224
+
225
+ -- | Compute the effective sample size of a population from the weights.
226
+ --
227
+ -- See https://en.wikipedia.org/wiki/Design_effect#Effective_sample_size
228
+ effectiveSampleSize :: (Functor m ) => PopulationT m a -> m Double
229
+ effectiveSampleSize = fmap (effectiveSampleSizeKish . map (exp . ln . snd )) . runPopulationT
230
+ where
231
+ effectiveSampleSizeKish :: [Double ] -> Double
232
+ effectiveSampleSizeKish weights = square (Data.List. sum weights) / Data.List. sum (square <$> weights)
233
+ square :: Double -> Double
234
+ square x = x * x
235
+
209
236
-- | Separate the sum of weights into the 'WeightedT' transformer.
210
237
-- Weights are normalized after this operation.
211
238
extractEvidence ::
0 commit comments