package gdsc.smlm.function;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2014 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
/**
* This is a wrapper for any function to compute the negative log-likelihood assuming a Poisson-Gamma-Gaussian
* distribution.
* <p>
* For each observed value the log-likelihood is computed from the Poisson-Gamma-Gaussian distribution (a Poisson
* convolved with a Gamma distribution convolved with a Gaussian). The Poisson-Gamma distribution is derived
* analytically in the paper Maximilian H Ulbrich & Ehud Y Isacoff, Nature Methods - 4, 319 - 321 (2007) to explain the
* probability distribution of ADUs given a fixed photon level per pixel and set gain in an EM-CCD camera (The Poisson
* distribution models the photon count and the Gamma distribution models the EM-gain). This is then numerically
* convolved with a Gaussian distribution to model the read noise of the camera.
* <p>
* The distribution of Ulbrich & Isacoff has no analytical solution to the convolution with a Gaussian. However the
* convolution with a Gaussian has the most effect when the counts are low. The Poisson-Gamma-Gaussian can be
* approximated using the Poisson-Gamma and a partial convolution with a Gaussian at low counts. This method is provided
* as Python source code within the supplementary information of the paper Mortensen, et al (2010) Nature Methods 7,
* 377-383. This Java implementation is based on the Python code.
* <P>
* The mean of the Poisson distribution is set using the expected value generated by the provided function. The scale
* (EM-gain) for the Gamma distribution and standard deviation of the Gaussian is fixed and set in the constructor. The
* mean of the Gaussian is assumed to be zero.
* <p>
* The negative log-likelihood can be evaluated over the entire set of observed values or for a chosen observed value.
*/
public class PoissonGammaGaussianLikelihoodWrapper extends LikelihoodWrapper
{
final private PoissonGammaGaussianFunction p;
/**
* Initialise the function.
* <p>
* The input parameters must be the full parameters for the non-linear function. Only those parameters with gradient
* indices should be passed in to the functions to obtain the value (and gradient).
*
* @param f
* The function to be used to calculated the expected values (if modelling EMCCD data this should
* evaluate the value without the bias)
* @param a
* The initial parameters for the function
* @param k
* The observed values (if using EMCCD data the bias should be subtracted)
* @param n
* The number of observed values
* @param alpha
* Inverse gain of the EMCCD chip
* @param s
* The Gaussian standard deviation
*/
public PoissonGammaGaussianLikelihoodWrapper(NonLinearFunction f, double[] a, double[] k, int n, double alpha,
double s)
{
super(f, a, k, n);
p = new PoissonGammaGaussianFunction(alpha, s);
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodWrapper#computeLikelihood()
*/
public double computeLikelihood()
{
// Compute the negative log-likelihood
double ll = 0;
for (int i = 0; i < n; i++)
{
final double l = p.logLikelihood(data[i], f.eval(i));
if (l == Double.NEGATIVE_INFINITY)
{
return Double.POSITIVE_INFINITY;
}
ll -= l;
}
return ll;
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodWrapper#computeLikelihood(int)
*/
public double computeLikelihood(int i)
{
return -p.logLikelihood(data[i], f.eval(i));
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodWrapper#canComputeGradient()
*/
@Override
public boolean canComputeGradient()
{
return false;
}
}