/* * GeneralisedGaussLaguerreQuadrature.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; /** * Approximate the integral from min to +INF of x^alpha * e^-Bx * f(x) by generalised Gauss-Riemann quadrature * * Adapted from Numerical Recipes */ public class GeneralisedGaussLaguerreQuadrature implements Integral { private double B; private double alpha; final private int noPoints; final private double[] abscissae; final private double[] coefficients; public GeneralisedGaussLaguerreQuadrature(double B, double alpha, int noPoints){ this.B = B; this.alpha = alpha; this.noPoints = noPoints; abscissae = new double[noPoints]; coefficients = new double[noPoints]; setupArrays(); } public GeneralisedGaussLaguerreQuadrature(int noPoints){ this.noPoints = noPoints; abscissae = new double[noPoints]; coefficients = new double[noPoints]; } public void setB(double B){ this.B = B; setupArrays(); } public void setAlpha(double alpha){ this.alpha = alpha; setupArrays(); } public void setAlphaAndB(double alpha, double B){ this.alpha = alpha; this.B = B; setupArrays(); } private void setupArrays(){ final int maxIterations = 10; final double eps = 1E-14; double z = 0; double p1=0, p2=0, p3=0, pp=0; for(int i=0; i<noPoints; i++){ if(i==0){ z = (1.0+alpha)*(3.0+0.92*alpha)/(1.0+2.4*noPoints+1.8*alpha); } else if (i==1){ z += (15.0+6.25*alpha)/(1.0+0.9*alpha+2.5*noPoints); } else { double ai = i-1; z += ((1.0+2.55*ai)/(1.9*ai) + 1.26*ai*alpha/(1.0+3.5*ai))*(z-abscissae[i-2])/(1.0+0.3*alpha); } boolean failed = true; for(int its = 0 ; its<maxIterations; its++){ p1 = 1.0; p2 = 0.0; for(int j=0; j<noPoints; j++){ p3 = p2; p2 = p1; p1 = ((2*j+1+alpha-z)*p2-(j+alpha)*p3)/(j+1); } pp = (noPoints*p1-(noPoints+alpha)*p2)/z; double z1=z; z=z1-p1/pp; if(Math.abs(z-z1) <= eps){ failed = false; break; } } if(failed){ throw new RuntimeException("Too many iterations"); } abscissae[i] = z; coefficients[i] = -Math.exp(GammaFunction.lnGamma(alpha+noPoints) - GammaFunction.lnGamma((double)noPoints))/ (pp*noPoints*p2); } } public double integrate(UnivariateFunction f, double min, double max) { if(max!=Double.POSITIVE_INFINITY){ throw new RuntimeException("Gauss-Laguerre quadrature is for integration with an infinite upper limit"); } else{ return integrate(f, min); } } public double logIntegrate(UnivariateFunction f, double min, double max) { if(max!=Double.POSITIVE_INFINITY){ throw new RuntimeException("Gauss-Laguerre quadrature is for integration with an infinite upper limit"); } else{ return logIntegrate(f, min); } } public double integrate(UnivariateFunction f, double min){ double integral = 0; for(int i=0; i<noPoints; i++){ integral += coefficients[i]*f.evaluate(abscissae[i]/B + min); } integral *= 1/Math.pow(B, alpha+1); return integral; } public double logIntegrate(UnivariateFunction f, double min){ try { double logIntegral = Double.NEGATIVE_INFINITY; for (int i = 0; i < noPoints; i++) { logIntegral = LogTricks.logSum(logIntegral, Math.log(coefficients[i]) + ((UnivariateFunction.AbstractLogEvaluatableUnivariateFunction)f) .logEvaluate(min + abscissae[i] / B)); } logIntegral += -(alpha + 1) * Math.log(B); return logIntegral; } catch(ClassCastException e){ throw new RuntimeException(f.toString()+" has no logEvaluate method"); } } }