All Downloads are FREE. Search and download functionalities are using the official Maven repository.

smile.math.special.Beta Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2010-2020 Haifeng Li. All rights reserved.
 *
 * Smile 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 3 of
 * the License, or (at your option) any later version.
 *
 * Smile 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 Smile.  If not, see .
 ******************************************************************************/

package smile.math.special;

import static java.lang.Math.*;
import static smile.math.special.Gamma.lgamma;

/**
 * The beta function, also called the Euler integral of the first kind.
 * 

*

 *     B(x, y) = 01 tx-1 (1-t)y-1dt
 * 
* for x, y > 0 and the integration is over [0, 1]. * The beta function is symmetric, i.e. B(x, y) = B(y, x). * * @author Haifeng Li */ public class Beta { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Beta.class); /** Utility classes should not have public constructors. */ private Beta() { } /** * A small number close to the smallest representable floating point number. */ private static final double FPMIN = 1e-300; /** * Beta function, also called the Euler integral of the first kind. * The beta function is symmetric, i.e. B(x,y)==B(y,x). */ public static double beta(double x, double y) { return exp(lgamma(x) + lgamma(y) - lgamma(x + y)); } /** * Regularized Incomplete Beta function. * Continued Fraction approximation (see Numerical recipies for details) */ public static double regularizedIncompleteBetaFunction(double alpha, double beta, double x) { // This function is often used to calculate p-value of model fitting. // Due to floating error, the model may provide a x that could be slightly // greater than 1 or less than 0. We allow tiny slack here to avoid brute exception. final double EPS = 1E-8; if (x < 0.0 && abs(x) < EPS) { return 0.0; } if (x > 1.0 && abs(x - 1.0) < EPS) { return 1.0; } if (x < 0.0 || x > 1.0) { throw new IllegalArgumentException("Invalid x: " + x); } double ibeta = 0.0; if (x == 0.0) { ibeta = 0.0; } else { if (x == 1.0) { ibeta = 1.0; } else { // Term before continued fraction ibeta = exp(lgamma(alpha + beta) - lgamma(alpha) - lgamma(beta) + alpha * log(x) + beta * log(1.0D - x)); // Continued fraction if (x < (alpha + 1.0) / (alpha + beta + 2.0)) { ibeta = ibeta * incompleteFractionSummation(alpha, beta, x) / alpha; } else { // Use symmetry relationship ibeta = 1.0 - ibeta * incompleteFractionSummation(beta, alpha, 1.0 - x) / beta; } } } return ibeta; } /** * Incomplete fraction summation used in the method regularizedIncompleteBeta * using a modified Lentz's method. */ private static double incompleteFractionSummation(double alpha, double beta, double x) { final int MAXITER = 500; final double EPS = 3.0E-7; double aplusb = alpha + beta; double aplus1 = alpha + 1.0; double aminus1 = alpha - 1.0; double c = 1.0; double d = 1.0 - aplusb * x / aplus1; if (abs(d) < FPMIN) { d = FPMIN; } d = 1.0 / d; double h = d; double aa = 0.0; double del = 0.0; int i = 1, i2 = 0; boolean test = true; while (test) { i2 = 2 * i; aa = i * (beta - i) * x / ((aminus1 + i2) * (alpha + i2)); d = 1.0 + aa * d; if (abs(d) < FPMIN) { d = FPMIN; } c = 1.0 + aa / c; if (abs(c) < FPMIN) { c = FPMIN; } d = 1.0 / d; h *= d * c; aa = -(alpha + i) * (aplusb + i) * x / ((alpha + i2) * (aplus1 + i2)); d = 1.0 + aa * d; if (abs(d) < FPMIN) { d = FPMIN; } c = 1.0 + aa / c; if (abs(c) < FPMIN) { c = FPMIN; } d = 1.0 / d; del = d * c; h *= del; i++; if (abs(del - 1.0) < EPS) { test = false; } if (i > MAXITER) { test = false; logger.error("Beta.incompleteFractionSummation: Maximum number of iterations wes exceeded"); } } return h; } /** * Inverse of regularized incomplete beta function. */ public static double inverseRegularizedIncompleteBetaFunction(double alpha, double beta, double p) { final double EPS = 1.0E-8; double pp, t, u, err, x, al, h, w, afac; double a1 = alpha - 1.; double b1 = beta - 1.; if (p <= 0.0) { return 0.0; } if (p >= 1.0) { return 1.0; } if (alpha >= 1. && beta >= 1.) { pp = (p < 0.5) ? p : 1. - p; t = sqrt(-2. * log(pp)); x = (2.30753 + t * 0.27061) / (1. + t * (0.99229 + t * 0.04481)) - t; if (p < 0.5) { x = -x; } al = (x * x - 3.) / 6.; h = 2. / (1. / (2. * alpha - 1.) + 1. / (2. * beta - 1.)); w = (x * sqrt(al + h) / h) - (1. / (2. * beta - 1) - 1. / (2. * alpha - 1.)) * (al + 5. / 6. - 2. / (3. * h)); x = alpha / (alpha + beta * exp(2. * w)); } else { double lna = log(alpha / (alpha + beta)); double lnb = log(beta / (alpha + beta)); t = exp(alpha * lna) / alpha; u = exp(beta * lnb) / beta; w = t + u; if (p < t / w) { x = pow(alpha * w * p, 1. / alpha); } else { x = 1. - pow(beta * w * (1. - p), 1. / beta); } } afac = -lgamma(alpha) - lgamma(beta) + lgamma(alpha + beta); for (int j = 0; j < 10; j++) { if (x == 0. || x == 1.) { return x; } err = regularizedIncompleteBetaFunction(alpha, beta, x) - p; t = exp(a1 * log(x) + b1 * log(1. - x) + afac); u = err / t; x -= (t = u / (1. - 0.5 * min(1., u * (a1 / x - b1 / (1. - x))))); if (x <= 0.) { x = 0.5 * (x + t); } if (x >= 1.) { x = 0.5 * (x + t + 1.); } if (abs(t) < EPS * x && j > 0) { break; } } return x; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy