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-Gaussian distribution.
* <p>
* For each observed value the log-likelihood is computed from the Poisson-Gaussian distribution (a Poisson convolved
* with a Gaussian). The mean of the Poisson distribution is set using the expected value generated by the provided
* function. The 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.
* The sum uses a non-normalised Poisson-Gaussian distribution for speed (see
* {@link PoissonGaussianFunction#pseudoLikelihood(double)} ).
*/
public class PoissonGaussianLikelihoodWrapper extends LikelihoodWrapper
{
private PoissonGaussianFunction p0, p1;
final private boolean usePicard = false;
/**
* 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
* @param a
* The initial parameters for the function
* @param k
* The observed values
* @param n
* The number of observed values
* @param alpha
* Inverse gain of the EMCCD chip
* @param s
* The Gaussian standard deviation
*/
public PoissonGaussianLikelihoodWrapper(NonLinearFunction f, double[] a, double[] k, int n, double alpha, double s)
{
super(f, a, k, n);
// We have two functions: One for no poisson counts and one for poisson counts.
// They differ in their normalisation.
p0 = PoissonGaussianFunction.createWithStandardDeviation(alpha, 0, s);
p0.setUsePicardApproximation(usePicard);
p1 = PoissonGaussianFunction.createWithStandardDeviation(alpha, 1, s);
p1.setUsePicardApproximation(usePicard);
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodWrapper#computeLikelihood()
*/
public double computeLikelihood()
{
// Compute the negative log-likelihood to be minimised
double ll = 0;
for (int i = 0; i < n; i++)
{
final double e = f.eval(i);
if (e <= 0)
// Use the function with the non-Poisson normalisation
ll -= p0.logProbability(data[i], e);
else
ll -= p1.logProbability(data[i], e);
}
return ll;
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodWrapper#computeLikelihood(int)
*/
public double computeLikelihood(int i)
{
final double e = f.eval(i);
if (e <= 0)
return p0.logProbability(data[i], e);
return p1.logProbability(data[i], e);
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodWrapper#canComputeGradient()
*/
@Override
public boolean canComputeGradient()
{
return false;
}
}