Automatic Differentiation
 
Loading...
Searching...
No Matches
integrate_1d_double_exponential.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUNCTOR_INTEGRATE_1D_DOUBLE_EXPONENTIAL_HPP
2#define STAN_MATH_PRIM_FUNCTOR_INTEGRATE_1D_DOUBLE_EXPONENTIAL_HPP
3
8#include <boost/math/quadrature/exp_sinh.hpp>
9#include <boost/math/quadrature/sinh_sinh.hpp>
10#include <boost/math/quadrature/tanh_sinh.hpp>
11#include <algorithm>
12#include <cmath>
13#include <cstddef>
14#include <ostream>
15
16namespace stan {
17namespace math {
18
27
80template <typename F>
81inline double integrate_de(const F& f, double a, double b,
82 double relative_tolerance, double absolute_tolerance,
83 int max_refinements) {
84 static constexpr const char* function = "integrate_1d_double_exponential";
85 double error1 = 0.0;
86 double error2 = 0.0;
87 double L1 = 0.0;
88 double L2 = 0.0;
89 size_t levels = 0;
90
91 const size_t mr
92 = max_refinements < 0 ? 0u : static_cast<size_t>(max_refinements);
93
94 auto one_integral_convergence_check
95 = [&](double e, double rel_tol, double abs_tol, double L) {
96 const double threshold = std::max(rel_tol * L, abs_tol);
97 if (e > threshold) {
98 [e]() STAN_COLD_PATH {
100 function, "error estimate of integral", e, "",
101 " exceeds max(relative_tolerance * L1, absolute_tolerance)");
102 }();
103 }
104 };
105 auto two_integral_convergence_check = [&](double e1, double e2,
106 double rel_tol, double abs_tol,
107 double La, double Lb) {
108 const double threshold_a = std::max(rel_tol * La, abs_tol);
109 const double threshold_b = std::max(rel_tol * Lb, abs_tol);
110 if (e1 > threshold_a) {
111 [e1]() STAN_COLD_PATH {
113 function, "error estimate of integral below zero", e1, "",
114 " exceeds max(relative_tolerance * L1, absolute_tolerance) for "
115 "the lower piece of the split");
116 }();
117 }
118 if (e2 > threshold_b) {
119 [e2]() STAN_COLD_PATH {
121 function, "error estimate of integral above zero", e2, "",
122 " exceeds max(relative_tolerance * L1, absolute_tolerance) for "
123 "the upper piece of the split");
124 }();
125 }
126 };
127
128 // If a or b is infinite, set xc to NaN (see docs above)
129 auto f_wrap = [&f](double x) { return f(x, NOT_A_NUMBER); };
130 if (std::isinf(a) && std::isinf(b)) {
131 boost::math::quadrature::sinh_sinh<double> integrator(mr);
132 double Q = integrator.integrate(f_wrap, relative_tolerance, &error1, &L1,
133 &levels);
134 one_integral_convergence_check(error1, relative_tolerance,
135 absolute_tolerance, L1);
136 return Q;
137 } else if (std::isinf(a)) {
138 boost::math::quadrature::exp_sinh<double> integrator(mr);
139 // If the integral crosses zero, break it into two (advice from the
140 // Boost implementation).
141 if (b <= 0.0) {
142 double Q = integrator.integrate(f_wrap, a, b, relative_tolerance, &error1,
143 &L1, &levels);
144 one_integral_convergence_check(error1, relative_tolerance,
145 absolute_tolerance, L1);
146 return Q;
147 } else {
148 boost::math::quadrature::tanh_sinh<double> integrator_right(mr);
149 double Q = integrator.integrate(f_wrap, a, 0.0, relative_tolerance,
150 &error1, &L1, &levels)
151 + integrator_right.integrate(
152 f_wrap, 0.0, b, relative_tolerance, &error2, &L2, &levels);
153 two_integral_convergence_check(error1, error2, relative_tolerance,
154 absolute_tolerance, L1, L2);
155 return Q;
156 }
157 } else if (std::isinf(b)) {
158 boost::math::quadrature::exp_sinh<double> integrator(mr);
159 if (a >= 0.0) {
160 double Q = integrator.integrate(f_wrap, a, b, relative_tolerance, &error1,
161 &L1, &levels);
162 one_integral_convergence_check(error1, relative_tolerance,
163 absolute_tolerance, L1);
164 return Q;
165 } else {
166 boost::math::quadrature::tanh_sinh<double> integrator_left(mr);
167 double Q = integrator_left.integrate(f_wrap, a, 0, relative_tolerance,
168 &error1, &L1, &levels)
169 + integrator.integrate(f_wrap, relative_tolerance, &error2,
170 &L2, &levels);
171 two_integral_convergence_check(error1, error2, relative_tolerance,
172 absolute_tolerance, L1, L2);
173 return Q;
174 }
175 } else {
176 auto f_wrap = [&f](double x, double xc) { return f(x, xc); };
177 boost::math::quadrature::tanh_sinh<double> integrator(mr);
178 if (a < 0.0 && b > 0.0) {
179 double Q = integrator.integrate(f_wrap, a, 0.0, relative_tolerance,
180 &error1, &L1, &levels)
181 + integrator.integrate(f_wrap, 0.0, b, relative_tolerance,
182 &error2, &L2, &levels);
183 two_integral_convergence_check(error1, error2, relative_tolerance,
184 absolute_tolerance, L1, L2);
185 return Q;
186 } else {
187 double Q = integrator.integrate(f_wrap, a, b, relative_tolerance, &error1,
188 &L1, &levels);
189 one_integral_convergence_check(error1, relative_tolerance,
190 absolute_tolerance, L1);
191 return Q;
192 }
193 }
194}
195
214template <typename F, typename... Args,
215 require_all_st_arithmetic<Args...>* = nullptr>
217 const F& f, double a, double b, double relative_tolerance,
218 double absolute_tolerance, int max_refinements, std::ostream* msgs,
219 const Args&... args) {
220 static constexpr const char* function = "integrate_1d_double_exponential";
221 check_less_or_equal(function, "lower limit", a, b);
222 check_nonnegative(function, "max_refinements", max_refinements);
223 check_nonnegative(function, "absolute_tolerance", absolute_tolerance);
224 if (unlikely(a == b)) {
225 if (std::isinf(a)) {
226 throw_domain_error(function, "Integration endpoints are both", a, "", "");
227 }
228 return 0.0;
229 } else {
230 return integrate_de(
231 [&](auto&& x, auto&& xc) { return f(x, xc, msgs, args...); }, a, b,
232 relative_tolerance, absolute_tolerance, max_refinements);
233 }
234}
235
266template <typename F, typename... Args,
267 require_all_st_arithmetic<Args...>* = nullptr>
268inline double integrate_1d_double_exponential(const F& f, double a, double b,
269 std::ostream* msgs,
270 const Args&... args) {
272 f, a, b, std::sqrt(EPSILON), 0.0,
274}
275
276} // namespace math
277} // namespace stan
278
279#endif
#define STAN_COLD_PATH
#define unlikely(x)
require_all_t< std::is_arithmetic< scalar_type_t< std::decay_t< Types > > >... > require_all_st_arithmetic
Require all of the scalar types satisfy std::is_arithmetic.
void check_less_or_equal(const char *function, const char *name, const T_y &y, const T_high &high, Idxs... idxs)
Throw an exception if y is not less than high.
static constexpr double NOT_A_NUMBER
(Quiet) not-a-number value.
Definition constants.hpp:56
void check_nonnegative(const char *function, const char *name, const T_y &y)
Check if y is non-negative.
static constexpr double EPSILON
Smallest positive value.
Definition constants.hpp:41
static constexpr double e()
Return the base of the natural logarithm.
Definition constants.hpp:20
return_type_t< T_a, T_b, Args... > integrate_1d_double_exponential_tol(const F &f, const T_a &a, const T_b &b, double relative_tolerance, double absolute_tolerance, int max_refinements, std::ostream *msgs, const Args &... args)
Return the integral of f from a to b using adaptive double-exponential quadrature,...
double integrate_1d_double_exponential(const F &f, double a, double b, std::ostream *msgs, const Args &... args)
Compute the integral of the single variable function f from a to b using adaptive double-exponential ...
void throw_domain_error(const char *function, const char *name, const T &y, const char *msg1, const char *msg2)
Throw a domain error with a consistently formatted message.
double integrate_de(const F &f, double a, double b, double relative_tolerance, double absolute_tolerance, int max_refinements)
Integrate a single variable function f from a to b using Boost's adaptive double-exponential quadratu...
constexpr int INTEGRATE_1D_DOUBLE_EXPONENTIAL_MAX_REFINEMENTS
Default maximum refinement count used by integrate_1d_double_exponential when the user does not pass ...
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
bool isinf(const stan::math::var &a)
Return 1 if the specified argument is positive infinity or negative infinity and 0 otherwise.
Definition std_isinf.hpp:16