@@ -26,6 +26,8 @@ module Control.Monad.Bayes.Population
2626 resampleSystematic ,
2727 stratified ,
2828 resampleStratified ,
29+ onlyBelowEffectiveSampleSize ,
30+ effectiveSampleSize ,
2931 extractEvidence ,
3032 pushEvidence ,
3133 proper ,
@@ -206,6 +208,31 @@ resampleMultinomial ::
206208 PopulationT m a
207209resampleMultinomial = resampleGeneric multinomial
208210
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+
209236-- | Separate the sum of weights into the 'WeightedT' transformer.
210237-- Weights are normalized after this operation.
211238extractEvidence ::
0 commit comments