package gdsc.smlm.function;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2016 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.
*---------------------------------------------------------------------------*/
import org.apache.commons.math3.distribution.PoissonDistribution;
import org.apache.commons.math3.special.Gamma;
import org.apache.commons.math3.util.FastMath;
/**
* Implements the probability density function for a Poisson distribution.
* <p>
* This is a simple implementation of the LikelihoodFunction interface.
*/
public class PoissonFunction implements LikelihoodFunction
{
/**
* The inverse of the EM-gain multiplication factor
*/
final double alpha;
/**
* Allow non-integer observed values
*/
final boolean nonInteger;
/**
* @param alpha
* The inverse of the EM-gain multiplication factor
* @param nonInteger
* Allow non-integer observed values
*/
public PoissonFunction(double alpha, boolean nonInteger)
{
this.alpha = Math.abs(alpha);
this.nonInteger = nonInteger;
}
/*
* (non-Javadoc)
*
* @see gdsc.smlm.function.LikelihoodFunction#likelihood(double, double)
*/
public double likelihood(double o, double e)
{
if (o < 0 || e <= 0)
return 0;
// convert to photons
e *= alpha;
o *= alpha;
// Allow non-integer observed value using the gamma function to provide a factorial for non-integer values
// PMF(l,k) = C * e^-l * l^k / gamma(k+1)
// log(PMF) = -l + k * log(l) - logGamma(k+1)
if (nonInteger)
{
//return (FastMath.exp(-e) * Math.pow(e, o) / factorial(o)) * alpha;
final double ll = -e + o * Math.log(e) - logFactorial(o);
return FastMath.exp(ll) * alpha;
}
//return new PoissonDistribution(e).probability((int) Math.round(o)) * alpha;
return new PoissonDistribution(e).probability((int) o) * alpha;
}
/**
* Return the log of the factorial for the given real number, using the gamma function
*
* @param k
* @return the log factorial
*/
public static double logFactorial(double k)
{
if (k <= 1)
return 0;
return Gamma.logGamma(k + 1);
}
/**
* Return the factorial for the given real number, using the gamma function
*
* @param k
* @return the factorial
*/
public static double factorial(double k)
{
if (k <= 1)
return 1;
return Gamma.gamma(k + 1);
}
}