# -*- coding: utf-8 -*-
import numpy as np
from .base import Resampler
from ..types.numeric import Probability
from ..types.particle import Particles
[docs]class SystematicResampler(Resampler):
[docs] def resample(self, particles):
"""Resample the particles
Parameters
----------
particles : list of :class:`~.Particle`
The particles to be resampled according to their weight
Returns
-------
particles : list of :class:`~.Particle`
The resampled particles
"""
if not isinstance(particles, Particles):
particles = Particles(particle_list=particles)
n_particles = len(particles)
weight = Probability(1/n_particles)
log_weights = np.array([weight.log_value for weight in particles.weight])
weight_order = np.argsort(log_weights, kind='stable')
max_log_value = log_weights[weight_order[-1]]
with np.errstate(divide='ignore'):
cdf = np.log(np.cumsum(np.exp(log_weights[weight_order] - max_log_value)))
cdf += max_log_value
# Pick random starting point
u_i = np.random.uniform(0, 1 / n_particles)
# Cycle through the cumulative distribution and copy the particle
# that pushed the score over the current value
u_j = u_i + (1 / n_particles) * np.arange(n_particles)
index = weight_order[np.searchsorted(cdf, np.log(u_j))]
new_particles = Particles(state_vector=particles.state_vector[:, index],
weight=[weight]*n_particles,
parent=Particles(state_vector=particles.state_vector[:, index],
weight=particles.weight[index]))
return new_particles