package gdsc.smlm.function; import org.apache.commons.math3.special.Gamma; import org.apache.commons.math3.util.FastMath; /*----------------------------------------------------------------------------- * GDSC SMLM Software * * Copyright (C) 2017 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. *---------------------------------------------------------------------------*/ /** * Computes likelihood values for a Poisson function */ public class PoissonCalculator { /** * Get the Poisson log likelihood of value x given the mean. The mean must be strictly positive. x must be positive. * * @param u * the mean * @param x * the x * @return the log likelihood */ public static double logLikelihood(double u, double x) { // Unlikely so skip this ... //if (x == 0) // return -u; return x * Math.log(u) - u - logFactorial(x); } private static double logFactorial(double k) { if (k <= 1) return 0.0; return Gamma.logGamma(k + 1); } /** * Get the Poisson log likelihood of value x given the mean. The mean must be strictly positive. x must be positive. * * @param u * the mean * @param x * the x * @return the log likelihood */ public static double logLikelihood(double[] u, double[] x) { double ll = 0.0; for (int i = u.length; i-- > 0;) ll += logLikelihood(u[i], x[i]); return ll; } /** * Get the Poisson likelihood of value x given the mean. The mean must be strictly positive. x must be positive. * * @param u * the mean * @param x * the x * @return the likelihood */ public static double likelihood(double u, double x) { //return Math.pow(u, x) * FastMath.exp(-u) / factorial(x); return FastMath.exp(logLikelihood(u, x)); } /** * Get the Poisson likelihood of value x given the mean. The mean must be strictly positive. x must be positive. * * @param u * the mean * @param x * the x * @return the likelihood */ public static double likelihood(double[] u, double[] x) { return FastMath.exp(logLikelihood(u, x)); } /** * Get the Poisson maximum log likelihood of value x given the mean is value x. x must be positive. * * @param x * the x * @return the log likelihood */ public static double maximumLogLikelihood(double x) { return (x > 0.0) ? logLikelihood(x, x) : 0.0; } /** * Get the Poisson maximum log likelihood of value x given the mean is value x. x must be positive. * * @param x * the x * @return the log likelihood */ public static double maximumLogLikelihood(double[] x) { double ll = 0.0; for (int i = x.length; i-- > 0;) ll += maximumLogLikelihood(x[i]); return ll; } /** * Get the Poisson maximum likelihood of value x given the mean is value x. x must be positive. * * @param x * the x * @return the likelihood */ public static double maximumLikelihood(double x) { return (x > 0.0) ? likelihood(x, x) : 1; } /** * Get the Poisson maximum likelihood of value x given the mean is value x. x must be positive. * * @param x * the x * @return the likelihood */ public static double maximumLikelihood(double[] x) { return FastMath.exp(maximumLogLikelihood(x)); } /** * Get the Poisson log likelihood ratio of value x given the mean. The mean must be strictly positive. x must be * positive. * * @param u * the mean * @param x * the x * @return the log likelihood ratio */ public static double logLikelihoodRatio(double[] u, double[] x) { // From https://en.wikipedia.org/wiki/Likelihood-ratio_test#Use: // LLR = -2 * [ ln(likelihood for alternative model) - ln(likelihood for null model)] // The model with more parameters (here alternative) will always fit at least as well— // i.e., have the same or greater log-likelihood—than the model with fewer parameters // (here null) double ll = 0.0; for (int i = u.length; i-- > 0;) { //ll += logLikelihood(u[i], x[i]) - maximumLogLikelihood(x[i]); if (x[i] > 0.0) { //ll += (x[i] * Math.log(u[i]) - u[i]) - (x[i] * Math.log(x[i]) - x[i]); //ll += x[i] * Math.log(u[i]) - u[i] - x[i] * Math.log(x[i]) + x[i]; //ll += x[i] * (Math.log(u[i]) - Math.log(x[i])) - u[i] + x[i]; ll += x[i] * Math.log(u[i] / x[i]) - u[i] + x[i]; } else { ll -= u[i]; } } return -2.0 * ll; } }