/*
* Hyperexponential.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.math.distributions;
import dr.math.UnivariateFunction;
/**
* GeneralizedIntegerGammaDistribution distribution.
* @author Marc A. Suchard
*/
public class GeneralizedIntegerGammaDistribution implements Distribution {
private int shape1, shape2;
private double rate1, rate2;
private double[] A = null;
private double[] B = null;
public GeneralizedIntegerGammaDistribution(int shape1, int shape2, double rate1, double rate2) {
this.shape1 = shape1;
this.shape2 = shape2;
this.rate1 = rate1;
this.rate2 = rate2;
}
@Override
public double logPdf(double x) {
throw new RuntimeException("Not yet implemented");
}
@Override
public double cdf(double x) {
throw new RuntimeException("Not yet implemented");
}
@Override
public double quantile(double y) {
throw new RuntimeException("Not yet implemented");
}
@Override
public double mean() {
throw new RuntimeException("Not yet implemented");
}
@Override
public double variance() {
throw new RuntimeException("Not yet implemented");
}
@Override
public UnivariateFunction getProbabilityDensityFunction() {
throw new RuntimeException("Not yet implemented");
}
public double generatingFunction(double s) {
return Math.pow(rate1 / (rate1 + s), shape1) * Math.pow(rate2 / (rate2 + s), shape2);
}
// http://www.ism.ac.jp/editsec/aism/pdf/034_3_0591.pdf
public double generatingFunctionPartialFraction(double s) {
if (A == null) {
computeCoefficients();
}
double sum = 0.0;
for (int i = 1; i <= shape1; ++i) {
sum += A[i] / Math.pow(rate1 + s, i);
}
for (int i = 1; i <= shape2; ++i) {
sum += B[i] / Math.pow(rate2 + s, i);
}
return sum;
}
private void computeCoefficients() {
A = new double[shape1 + 1];
B = new double[shape2 + 1];
final double lambdaFactor = Math.pow(rate1, shape1) * Math.pow(rate2, shape2);
int sign = 1;
double factorial = 1.0;
for (int i = 1; i <= shape1; ++i) {
if (i > 1 && (shape2 + i - 2) > 1) {
factorial *= shape2 + i - 2;
factorial /= i - 1;
}
// System.err.println("A[" + (shape1 - i + 1) + "]: " + factorial);
A[shape1 - i + 1] = factorial * sign * lambdaFactor / Math.pow(rate2 - rate1, shape2 + i - 1);
sign *= -1;
}
sign = 1;
factorial = 1.0;
for (int i = 1; i <= shape2; ++i) {
if (i > 1 && (shape1 + i - 2) > 1) {
factorial *= shape1 + i - 2;
factorial /= i - 1;
}
// System.err.println("B[" + (shape2 - i + 1) + "]: " + factorial);
B[shape2 - i + 1] = factorial * sign * lambdaFactor / Math.pow(rate1 - rate2, shape1 + i - 1);
sign *= -1;
}
}
public double pdf(double x) {
if (A == null) {
computeCoefficients();
}
final double expRate1X = Math.exp(-rate1 * x);
final double expRate2X = Math.exp(-rate2 * x);
double sum = 0.0;
double power = 1.0;
int factorial = 1;
for (int i = 1; i <= shape1; ++i) {
sum += A[i] * power * expRate1X / factorial;
power *= x; // x^{i - 1}
factorial *= i; // (i - 1)!
}
power = 1.0;
factorial = 1;
for (int i = 1; i <= shape2; ++i) {
sum += B[i] * power * expRate2X / factorial;
power *= x; // x^{i - 1}
factorial *= i; // (i - 1)!
}
return sum;
}
public static double pdf(double x, int shape1, int shape2, double rate1, double rate2) {
return new GeneralizedIntegerGammaDistribution(shape1, shape2, rate1, rate2).pdf(x);
}
// https://en.wikipedia.org/wiki/Generalized_integer_gamma_distribution
// https://en.wikipedia.org/wiki/Generalized_integer_gamma_distribution
// http://arxiv.org/pdf/math/0408189v1.pdf
// http://www.math.utep.edu/Faculty/moschopoulos/Publications/1985-The_Distribution_of_the_Sum_of_Independent_Gamma_Random_Variables.pdf
// partial fractions, inverse Fourier transform
// http://stats.stackexchange.com/questions/72479/general-sum-of-gamma-distributions
}