/*
* File: SamplingImportanceResamplingParticleFilter.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Dec 15, 2009, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.statistics.bayesian;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.math.ProbabilityUtil;
import gov.sandia.cognition.statistics.DataDistribution;
import gov.sandia.cognition.util.DefaultWeightedValue;
import java.util.ArrayList;
/**
* An implementation of the standard Sampling Importance Resampling
* particle filter.
* @author Kevin R. Dixon
* @since 3.0
* @param <ObservationType>
* Type of observations handled by the algorithm.
* @param <ParameterType>
* Type of parameters to infer.
*/
@PublicationReference(
author={
"M. Sanjeev Arulampalam",
"Simon Maskell",
"Neil Gordon",
"Tim Clapp"
},
title="A Tutorial on Particle Filters for Online Nonlinear/Non-Gaussian Bayesian Tracking",
type=PublicationType.Journal,
publication="IEEE Transactions on Signal Processing, Vol. 50, No. 2",
year=2002,
pages={174,188},
url="http://people.cs.ubc.ca/~murphyk/Software/Kalman/ParticleFilterTutorial.pdf"
)
public class SamplingImportanceResamplingParticleFilter<ObservationType,ParameterType>
extends AbstractParticleFilter<ObservationType,ParameterType>
{
/**
* Percentage of effective particles, below which we resample.
*/
protected double particlePctThreadhold;
/**
* Creates a new instance of SamplingImportanceResamplingParticleFilter
*/
public SamplingImportanceResamplingParticleFilter()
{
super();
}
/**
* Getter for particlePctThreadhold
* @return
* Number of effective particles, below which we resample.
*/
public double getParticlePctThreadhold()
{
return this.particlePctThreadhold;
}
/**
* Setter for particlePctThreadhold
* @param particlePctThreadhold
* Number of effective particles, below which we resample.
*/
public void setParticlePctThreadhold(
double particlePctThreadhold)
{
ProbabilityUtil.assertIsProbability(particlePctThreadhold);
this.particlePctThreadhold = particlePctThreadhold;
}
@Override
public void update(
DataDistribution<ParameterType> particles,
ObservationType value)
{
// Sample from the existing weighted particles.
ArrayList<? extends ParameterType> sampledParticles =
particles.sample( this.random, this.numParticles );
// Weight the samples by the observation likelihood.
ArrayList<DefaultWeightedValue<ParameterType>> updatedParticles =
new ArrayList<DefaultWeightedValue<ParameterType>>( this.numParticles );
double weightSum = 0.0;
for( ParameterType sampledParticle : sampledParticles )
{
ParameterType updatedParticle =
this.getUpdater().update( sampledParticle );
double previousWeight = particles.get(sampledParticle);
double weight = previousWeight * Math.exp(
this.getUpdater().computeLogLikelihood( updatedParticle, value) );
weightSum += weight;
updatedParticles.add( new DefaultWeightedValue<ParameterType>(
updatedParticle, weight ) );
}
// Normalize the weights and add them back into the PMF.
particles.clear();
for( DefaultWeightedValue<ParameterType> updatedParticle : updatedParticles )
{
final double weight = updatedParticle.getWeight();
particles.set( updatedParticle.getValue(), weight/weightSum );
}
// Now make sure we've got enough effective particles.
double particlePct =
this.computeEffectiveParticles(particles) / this.getNumParticles();
if( particlePct < this.getParticlePctThreadhold() )
{
// Sample from the current belief (this will be close to degenerate)
sampledParticles = particles.sample(this.random, this.numParticles);
final double uniformWeight = 1.0/this.numParticles;
particles.clear();
// Resample new particles from the existing ones but assign
// uniform weight.
for( ParameterType sampledParticle : sampledParticles )
{
ParameterType resampledParticle =
this.getUpdater().update( sampledParticle );
particles.set( resampledParticle, uniformWeight );
}
}
}
}