ibeta_inverse.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 940 行 · 第 1/3 页

HPP
940
字号
//  Copyright John Maddock 2006.//  Copyright Paul A. Bristow 2007//  Use, modification and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP#ifdef _MSC_VER#pragma once#endif#include <boost/math/special_functions/beta.hpp>#include <boost/math/special_functions/erf.hpp>#include <boost/math/tools/roots.hpp>#include <boost/math/special_functions/detail/t_distribution_inv.hpp>namespace boost{ namespace math{ namespace detail{//// Helper object used by root finding// code to convert eta to x.//template <class T>struct temme_root_finder{   temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {}   std::tr1::tuple<T, T> operator()(T x)   {      BOOST_MATH_STD_USING // ADL of std names      T y = 1 - x;      if(y == 0)      {         T big = tools::max_value<T>() / 4;         return std::tr1::make_tuple(-big, -big);      }      if(x == 0)      {         T big = tools::max_value<T>() / 4;         return std::tr1::make_tuple(-big, big);      }      T f = log(x) + a * log(y) + t;      T f1 = (1 / x) - (a / (y));      return std::tr1::make_tuple(f, f1);   }private:   T t, a;};//// See:// "Asymptotic Inversion of the Incomplete Beta Function"// N.M. Temme// Journal of Computation and Applied Mathematics 41 (1992) 145-157.// Section 2.//template <class T, class Policy>T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol){   BOOST_MATH_STD_USING // ADL of std names   const T r2 = sqrt(T(2));   //   // get the first approximation for eta from the inverse   // error function (Eq: 2.9 and 2.10).   //   T eta0 = boost::math::erfc_inv(2 * z, pol);   eta0 /= -sqrt(a / 2);   T terms[4] = { eta0 };   T workspace[7];   //   // calculate powers:   //   T B = b - a;   T B_2 = B * B;   T B_3 = B_2 * B;   //   // Calculate correction terms:   //   // See eq following 2.15:   workspace[0] = -B * r2 / 2;   workspace[1] = (1 - 2 * B) / 8;   workspace[2] = -(B * r2 / 48);   workspace[3] = T(-1) / 192;   workspace[4] = -B * r2 / 3840;   terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);   // Eq Following 2.17:   workspace[0] = B * r2 * (3 * B - 2) / 12;   workspace[1] = (20 * B_2 - 12 * B + 1) / 128;   workspace[2] = B * r2 * (20 * B - 1) / 960;   workspace[3] = (16 * B_2 + 30 * B - 15) / 4608;   workspace[4] = B * r2 * (21 * B + 32) / 53760;   workspace[5] = (-32 * B_2 + 63) / 368640;   workspace[6] = -B * r2 * (120 * B + 17) / 25804480;   terms[2] = tools::evaluate_polynomial(workspace, eta0, 7);   // Eq Following 2.17:   workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480;   workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216;   workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760;   workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640;   terms[3] = tools::evaluate_polynomial(workspace, eta0, 4);   //   // Bring them together to get a final estimate for eta:   //   T eta = tools::evaluate_polynomial(terms, 1/a, 4);   //   // now we need to convert eta to x, by solving the appropriate   // quadratic equation:   //   T eta_2 = eta * eta;   T c = -exp(-eta_2 / 2);   T x;   if(eta_2 == 0)      x = 0.5;   else      x = (1 + eta * sqrt((1 + c) / eta_2)) / 2;   BOOST_ASSERT(x >= 0);   BOOST_ASSERT(x <= 1);   BOOST_ASSERT(eta * (x - 0.5) >= 0);#ifdef BOOST_INSTRUMENT   std::cout << "Estimating x with Temme method 1: " << x << std::endl;#endif   return x;}//// See:// "Asymptotic Inversion of the Incomplete Beta Function"// N.M. Temme// Journal of Computation and Applied Mathematics 41 (1992) 145-157.// Section 3.//template <class T, class Policy>T temme_method_2_ibeta_inverse(T /*a*/, T /*b*/, T z, T r, T theta, const Policy& pol){   BOOST_MATH_STD_USING // ADL of std names   //   // Get first estimate for eta, see Eq 3.9 and 3.10,   // but note there is a typo in Eq 3.10:   //   T eta0 = boost::math::erfc_inv(2 * z, pol);   eta0 /= -sqrt(r / 2);   T s = sin(theta);   T c = cos(theta);   //   // Now we need to purturb eta0 to get eta, which we do by   // evaluating the polynomial in 1/r at the bottom of page 151,   // to do this we first need the error terms e1, e2 e3   // which we'll fill into the array "terms".  Since these   // terms are themselves polynomials, we'll need another   // array "workspace" to calculate those...   //   T terms[4] = { eta0 };   T workspace[6];   //   // some powers of sin(theta)cos(theta) that we'll need later:   //   T sc = s * c;   T sc_2 = sc * sc;   T sc_3 = sc_2 * sc;   T sc_4 = sc_2 * sc_2;   T sc_5 = sc_2 * sc_3;   T sc_6 = sc_3 * sc_3;   T sc_7 = sc_4 * sc_3;   //   // Calculate e1 and put it in terms[1], see the middle of page 151:   //   workspace[0] = (2 * s * s - 1) / (3 * s * c);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 };   workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 };   workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 };   workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 };   workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5);   terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);   //   // Now evaluate e2 and put it in terms[2]:   //   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 };   workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 };   workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 };   workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 };   workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6);   terms[2] = tools::evaluate_polynomial(workspace, eta0, 4);   //   // And e3, and put it in terms[3]:   //   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 };   workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 };   workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6);   static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 };   workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7);   terms[3] = tools::evaluate_polynomial(workspace, eta0, 3);   //   // Bring the correction terms together to evaluate eta,   // this is the last equation on page 151:   //   T eta = tools::evaluate_polynomial(terms, 1/r, 4);   //   // Now that we have eta we need to back solve for x,   // we seek the value of x that gives eta in Eq 3.2.   // The two methods used are described in section 5.   //   // Begin by defining a few variables we'll need later:   //   T x;   T s_2 = s * s;   T c_2 = c * c;   T alpha = c / s;   alpha *= alpha;   T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2);   //   // Temme doesn't specify what value to switch on here,   // but this seems to work pretty well:   //   if(fabs(eta) < 0.7)   {      //      // Small eta use the expansion Temme gives in the second equation      // of section 5, it's a polynomial in eta:      //      workspace[0] = s * s;      workspace[1] = s * c;      workspace[2] = (1 - 2 * workspace[0]) / 3;      static const BOOST_MATH_INT_TABLE_TYPE(T, int) co12[] = { 1, -13, 13 };      workspace[3] = tools::evaluate_polynomial(co12, workspace[0], 3) / (36 * s * c);      static const BOOST_MATH_INT_TABLE_TYPE(T, int) co13[] = { 1, 21, -69, 46 };      workspace[4] = tools::evaluate_polynomial(co13, workspace[0], 4) / (270 * workspace[0] * c * c);      x = tools::evaluate_polynomial(workspace, eta, 5);#ifdef BOOST_INSTRUMENT      std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;#endif   }   else   {      //      // If eta is large we need to solve Eq 3.2 more directly,      // begin by getting an initial approximation for x from      // the last equation on page 155, this is a polynomial in u:      //      T u = exp(lu);      workspace[0] = u;      workspace[1] = alpha;      workspace[2] = 0;      workspace[3] = 3 * alpha * (3 * alpha + 1) / 6;      workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24;      workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120;      x = tools::evaluate_polynomial(workspace, u, 6);      //      // At this point we may or may not have the right answer, Eq-3.2 has      // two solutions for x for any given eta, however the mapping in 3.2      // is 1:1 with the sign of eta and x-sin^2(theta) being the same.      // So we can check if we have the right root of 3.2, and if not      // switch x for 1-x.  This transformation is motivated by the fact      // that the distribution is *almost* symetric so 1-x will be in the right      // ball park for the solution:      //      if((x - s_2) * eta < 0)         x = 1 - x;#ifdef BOOST_INSTRUMENT      std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;#endif   }   //   // The final step is a few Newton-Raphson iterations to   // clean up our approximation for x, this is pretty cheap   // in general, and very cheap compared to an incomplete beta   // evaluation.  The limits set on x come from the observation   // that the sign of eta and x-sin^2(theta) are the same.   //   T lower, upper;   if(eta < 0)   {      lower = 0;      upper = s_2;   }   else   {      lower = s_2;      upper = 1;   }   //   // If our initial approximation is out of bounds then bisect:   //   if((x < lower) || (x > upper))      x = (lower+upper) / 2;   //   // And iterate:   //   x = tools::newton_raphson_iterate(      temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2);   return x;}//// See:// "Asymptotic Inversion of the Incomplete Beta Function"// N.M. Temme// Journal of Computation and Applied Mathematics 41 (1992) 145-157.// Section 4.//template <class T, class Policy>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?