File indexing completed on 2025-01-18 09:39:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #ifndef BOOST_MATH_QUADRATURE_TANH_SINH_HPP
0030 #define BOOST_MATH_QUADRATURE_TANH_SINH_HPP
0031
0032 #include <cmath>
0033 #include <limits>
0034 #include <memory>
0035 #include <boost/math/quadrature/detail/tanh_sinh_detail.hpp>
0036
0037 namespace boost{ namespace math{ namespace quadrature {
0038
0039 template<class Real, class Policy = policies::policy<> >
0040 class tanh_sinh
0041 {
0042 public:
0043 tanh_sinh(size_t max_refinements = 15, const Real& min_complement = tools::min_value<Real>() * 4)
0044 : m_imp(std::make_shared<detail::tanh_sinh_detail<Real, Policy>>(max_refinements, min_complement)) {}
0045
0046 template<class F>
0047 auto integrate(const F f, Real a, Real b, Real tolerance = tools::root_epsilon<Real>(), Real* error = nullptr, Real* L1 = nullptr, std::size_t* levels = nullptr) const ->decltype(std::declval<F>()(std::declval<Real>()));
0048 template<class F>
0049 auto integrate(const F f, Real a, Real b, Real tolerance = tools::root_epsilon<Real>(), Real* error = nullptr, Real* L1 = nullptr, std::size_t* levels = nullptr) const ->decltype(std::declval<F>()(std::declval<Real>(), std::declval<Real>()));
0050
0051 template<class F>
0052 auto integrate(const F f, Real tolerance = tools::root_epsilon<Real>(), Real* error = nullptr, Real* L1 = nullptr, std::size_t* levels = nullptr) const ->decltype(std::declval<F>()(std::declval<Real>()));
0053 template<class F>
0054 auto integrate(const F f, Real tolerance = tools::root_epsilon<Real>(), Real* error = nullptr, Real* L1 = nullptr, std::size_t* levels = nullptr) const ->decltype(std::declval<F>()(std::declval<Real>(), std::declval<Real>()));
0055
0056 private:
0057 std::shared_ptr<detail::tanh_sinh_detail<Real, Policy>> m_imp;
0058 };
0059
0060 template<class Real, class Policy>
0061 template<class F>
0062 auto tanh_sinh<Real, Policy>::integrate(const F f, Real a, Real b, Real tolerance, Real* error, Real* L1, std::size_t* levels) const ->decltype(std::declval<F>()(std::declval<Real>()))
0063 {
0064 BOOST_MATH_STD_USING
0065 using boost::math::constants::half;
0066 using boost::math::quadrature::detail::tanh_sinh_detail;
0067
0068 static const char* function = "tanh_sinh<%1%>::integrate";
0069
0070 typedef decltype(std::declval<F>()(std::declval<Real>())) result_type;
0071 static_assert(!std::is_integral<result_type>::value,
0072 "The return type cannot be integral, it must be either a real or complex floating point type.");
0073 if (!(boost::math::isnan)(a) && !(boost::math::isnan)(b))
0074 {
0075
0076
0077 if ((a <= -tools::max_value<Real>()) && (b >= tools::max_value<Real>()))
0078 {
0079 auto u = [&](const Real& t, const Real& tc)->result_type
0080 {
0081 Real t_sq = t*t;
0082 Real inv;
0083 if (t > 0.5f)
0084 inv = 1 / ((2 - tc) * tc);
0085 else if(t < -0.5)
0086 inv = 1 / ((2 + tc) * -tc);
0087 else
0088 inv = 1 / (1 - t_sq);
0089 return f(t*inv)*(1 + t_sq)*inv*inv;
0090 };
0091 Real limit = sqrt(tools::min_value<Real>()) * 4;
0092 return m_imp->integrate(u, error, L1, function, limit, limit, tolerance, levels);
0093 }
0094
0095
0096 if ((boost::math::isfinite)(a) && (b >= tools::max_value<Real>()))
0097 {
0098 auto u = [&](const Real& t, const Real& tc)->result_type
0099 {
0100 Real z, arg;
0101 if (t > -0.5f)
0102 z = 1 / (t + 1);
0103 else
0104 z = -1 / tc;
0105 if (t < 0.5)
0106 arg = 2 * z + a - 1;
0107 else
0108 arg = a + tc / (2 - tc);
0109 return f(arg)*z*z;
0110 };
0111 Real left_limit = sqrt(tools::min_value<Real>()) * 4;
0112 result_type Q = Real(2) * m_imp->integrate(u, error, L1, function, left_limit, tools::min_value<Real>(), tolerance, levels);
0113 if (L1)
0114 {
0115 *L1 *= 2;
0116 }
0117 if (error)
0118 {
0119 *error *= 2;
0120 }
0121
0122 return Q;
0123 }
0124
0125 if ((boost::math::isfinite)(b) && (a <= -tools::max_value<Real>()))
0126 {
0127 auto v = [&](const Real& t, const Real& tc)->result_type
0128 {
0129 Real z;
0130 if (t > -0.5)
0131 z = 1 / (t + 1);
0132 else
0133 z = -1 / tc;
0134 Real arg;
0135 if (t < 0.5)
0136 arg = 2 * z - 1;
0137 else
0138 arg = tc / (2 - tc);
0139 return f(b - arg) * z * z;
0140 };
0141
0142 Real left_limit = sqrt(tools::min_value<Real>()) * 4;
0143 result_type Q = Real(2) * m_imp->integrate(v, error, L1, function, left_limit, tools::min_value<Real>(), tolerance, levels);
0144 if (L1)
0145 {
0146 *L1 *= 2;
0147 }
0148 if (error)
0149 {
0150 *error *= 2;
0151 }
0152 return Q;
0153 }
0154
0155 if ((boost::math::isfinite)(a) && (boost::math::isfinite)(b))
0156 {
0157 if (a == b)
0158 {
0159 return result_type(0);
0160 }
0161 if (b < a)
0162 {
0163 return -this->integrate(f, b, a, tolerance, error, L1, levels);
0164 }
0165 Real avg = (a + b)*half<Real>();
0166 Real diff = (b - a)*half<Real>();
0167 Real avg_over_diff_m1 = a / diff;
0168 Real avg_over_diff_p1 = b / diff;
0169 bool have_small_left = fabs(a) < 0.5f;
0170 bool have_small_right = fabs(b) < 0.5f;
0171 Real left_min_complement = float_next(avg_over_diff_m1) - avg_over_diff_m1;
0172 Real min_complement_limit = (std::max)(tools::min_value<Real>(), float_next(Real(tools::min_value<Real>() / diff)));
0173 if (left_min_complement < min_complement_limit)
0174 left_min_complement = min_complement_limit;
0175 Real right_min_complement = avg_over_diff_p1 - float_prior(avg_over_diff_p1);
0176 if (right_min_complement < min_complement_limit)
0177 right_min_complement = min_complement_limit;
0178
0179
0180
0181
0182
0183
0184
0185
0186 BOOST_MATH_ASSERT((left_min_complement * diff + a) > a);
0187 BOOST_MATH_ASSERT((b - right_min_complement * diff) < b);
0188 auto u = [&](Real z, Real zc)->result_type
0189 {
0190 Real position;
0191 if (z < -0.5)
0192 {
0193 if(have_small_left)
0194 return f(diff * (avg_over_diff_m1 - zc));
0195 position = a - diff * zc;
0196 }
0197 else if (z > 0.5)
0198 {
0199 if(have_small_right)
0200 return f(diff * (avg_over_diff_p1 - zc));
0201 position = b - diff * zc;
0202 }
0203 else
0204 position = avg + diff*z;
0205 BOOST_MATH_ASSERT(position != a);
0206 BOOST_MATH_ASSERT(position != b);
0207 return f(position);
0208 };
0209 result_type Q = diff*m_imp->integrate(u, error, L1, function, left_min_complement, right_min_complement, tolerance, levels);
0210
0211 if (L1)
0212 {
0213 *L1 *= diff;
0214 }
0215 if (error)
0216 {
0217 *error *= diff;
0218 }
0219 return Q;
0220 }
0221 }
0222 return policies::raise_domain_error(function, "The domain of integration is not sensible; please check the bounds.", a, Policy());
0223 }
0224
0225 template<class Real, class Policy>
0226 template<class F>
0227 auto tanh_sinh<Real, Policy>::integrate(const F f, Real a, Real b, Real tolerance, Real* error, Real* L1, std::size_t* levels) const ->decltype(std::declval<F>()(std::declval<Real>(), std::declval<Real>()))
0228 {
0229 BOOST_MATH_STD_USING
0230 using boost::math::constants::half;
0231 using boost::math::quadrature::detail::tanh_sinh_detail;
0232
0233 static const char* function = "tanh_sinh<%1%>::integrate";
0234
0235 if ((boost::math::isfinite)(a) && (boost::math::isfinite)(b))
0236 {
0237 if (b <= a)
0238 {
0239 return policies::raise_domain_error(function, "Arguments to integrate are in wrong order; integration over [a,b] must have b > a.", a, Policy());
0240 }
0241 auto u = [&](Real z, Real zc)->Real
0242 {
0243 if (z < 0)
0244 return f((a - b) * zc / 2 + a, (b - a) * zc / 2);
0245 else
0246 return f((a - b) * zc / 2 + b, (b - a) * zc / 2);
0247 };
0248 Real diff = (b - a)*half<Real>();
0249 Real left_min_complement = tools::min_value<Real>() * 4;
0250 Real right_min_complement = tools::min_value<Real>() * 4;
0251 Real Q = diff*m_imp->integrate(u, error, L1, function, left_min_complement, right_min_complement, tolerance, levels);
0252
0253 if (L1)
0254 {
0255 *L1 *= diff;
0256 }
0257 if (error)
0258 {
0259 *error *= diff;
0260 }
0261 return Q;
0262 }
0263 return policies::raise_domain_error(function, "The domain of integration is not sensible; please check the bounds.", a, Policy());
0264 }
0265
0266 template<class Real, class Policy>
0267 template<class F>
0268 auto tanh_sinh<Real, Policy>::integrate(const F f, Real tolerance, Real* error, Real* L1, std::size_t* levels) const ->decltype(std::declval<F>()(std::declval<Real>()))
0269 {
0270 using boost::math::quadrature::detail::tanh_sinh_detail;
0271 static const char* function = "tanh_sinh<%1%>::integrate";
0272 Real min_complement = tools::epsilon<Real>();
0273 return m_imp->integrate([&](const Real& arg, const Real&) { return f(arg); }, error, L1, function, min_complement, min_complement, tolerance, levels);
0274 }
0275
0276 template<class Real, class Policy>
0277 template<class F>
0278 auto tanh_sinh<Real, Policy>::integrate(const F f, Real tolerance, Real* error, Real* L1, std::size_t* levels) const ->decltype(std::declval<F>()(std::declval<Real>(), std::declval<Real>()))
0279 {
0280 using boost::math::quadrature::detail::tanh_sinh_detail;
0281 static const char* function = "tanh_sinh<%1%>::integrate";
0282 Real min_complement = tools::min_value<Real>() * 4;
0283 return m_imp->integrate(f, error, L1, function, min_complement, min_complement, tolerance, levels);
0284 }
0285
0286 }
0287 }
0288 }
0289 #endif