Automatic Differentiation
 
Loading...
Searching...
No Matches
hypergeometric_3F2.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_3F2_HPP
2#define STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_3F2_HPP
3
15
16namespace stan {
17namespace math {
18namespace internal {
19template <typename Ta, typename Tb, typename Tz,
20 require_all_vector_t<Ta, Tb>* = nullptr,
21 require_stan_scalar_t<Tz>* = nullptr>
23 const Ta& a, const Tb& b, const Tz& z, double precision = 1e-6,
24 int max_steps = 1e5) {
25 using T_return = return_type_t<Ta, Tb, Tz>;
26 Eigen::Array<scalar_type_t<Ta>, 3, 1> a_array = as_array_or_scalar(a);
27 Eigen::Array<scalar_type_t<Tb>, 3, 1> b_array
29 check_3F2_converges("hypergeometric_3F2", a_array[0], a_array[1], a_array[2],
30 b_array[0], b_array[1], z);
31
32 T_return t_acc = 1.0;
33 T_return log_t = 0.0;
34 auto log_z = log(fabs(z));
35 Eigen::Array<int, 3, 1> a_signs = sign(value_of_rec(a_array));
36 Eigen::Array<int, 3, 1> b_signs = sign(value_of_rec(b_array));
37 int z_sign = sign(value_of_rec(z));
38 int t_sign = z_sign * a_signs.prod() * b_signs.prod();
39
40 int k = 0;
41 const double log_precision = log(precision);
42 while (k <= max_steps && log_t >= log_precision) {
43 // Replace zero values with 1 prior to taking the log so that we accumulate
44 // 0.0 rather than -inf
45 const auto& abs_apk = math::fabs((a_array == 0).select(1.0, a_array));
46 const auto& abs_bpk = math::fabs((b_array == 0).select(1.0, b_array));
47 auto p = sum(log(abs_apk)) - sum(log(abs_bpk));
48 if (p == NEGATIVE_INFTY) {
49 return t_acc;
50 }
51
52 log_t += p + log_z;
53 t_acc += t_sign * exp(log_t);
54
55 if (is_inf(t_acc)) {
56 throw_domain_error("hypergeometric_3F2", "sum (output)", t_acc,
57 "overflow hypergeometric function did not converge.");
58 }
59 k++;
60 a_array += 1.0;
61 b_array += 1.0;
62 a_signs = sign(value_of_rec(a_array));
63 b_signs = sign(value_of_rec(b_array));
64 t_sign = a_signs.prod() * b_signs.prod() * t_sign;
65 }
66 if (k == max_steps) {
67 throw_domain_error("hypergeometric_3F2", "k (internal counter)", max_steps,
68 "exceeded iterations, hypergeometric function did not ",
69 "converge.");
70 }
71 return t_acc;
72}
73} // namespace internal
74
113template <typename Ta, typename Tb, typename Tz,
115 require_stan_scalar_t<Tz>* = nullptr>
116inline auto hypergeometric_3F2(const Ta& a, const Tb& b, const Tz& z) {
117 check_3F2_converges("hypergeometric_3F2", a[0], a[1], a[2], b[0], b[1], z);
118 // Boost's pFq throws convergence errors in some cases, fallback to naive
119 // infinite-sum approach (tests pass for these)
120 if (z == 1.0 && (sum(b) - sum(a)) < 0.0) {
122 }
123 return hypergeometric_pFq(to_vector(a), to_vector(b), z);
124}
125
142template <typename Ta, typename Tb, typename Tz,
144inline auto hypergeometric_3F2(const std::initializer_list<Ta>& a,
145 const std::initializer_list<Tb>& b,
146 const Tz& z) {
147 return hypergeometric_3F2(std::vector<Ta>(a), std::vector<Tb>(b), z);
148}
149
150} // namespace math
151} // namespace stan
152#endif
select_< as_operation_cl_t< T_condition >, as_operation_cl_t< T_then >, as_operation_cl_t< T_else > > select(T_condition &&condition, T_then &&then, T_else &&els)
Selection operation on kernel generator expressions.
Definition select.hpp:148
auto append_row(Ta &&a, Tb &&b)
Stack the rows of the first argument on top of the second argument.
Definition append.hpp:183
auto to_vector(T_x &&x)
Returns input matrix reshaped into a vector.
Definition to_vector.hpp:21
require_all_t< is_stan_scalar< std::decay_t< Types > >... > require_all_stan_scalar_t
Require all of the types satisfy is_stan_scalar.
require_t< is_stan_scalar< std::decay_t< T > > > require_stan_scalar_t
Require type satisfies is_stan_scalar.
typename return_type< Ts... >::type return_type_t
Convenience type for the return type of the specified template parameters.
require_all_t< is_vector< std::decay_t< Types > >... > require_all_vector_t
Require all of the types satisfy is_vector.
return_type_t< Ta, Tb, Tz > hypergeometric_3F2_infsum(const Ta &a, const Tb &b, const Tz &z, double precision=1e-6, int max_steps=1e5)
double value_of_rec(const fvar< T > &v)
Return the value of the specified variable.
auto hypergeometric_3F2(const Ta &a, const Tb &b, const Tz &z)
Hypergeometric function (3F2).
void check_3F2_converges(const char *function, const T_a1 &a1, const T_a2 &a2, const T_a3 &a3, const T_b1 &b1, const T_b2 &b2, const T_z &z)
Check if the hypergeometric function (3F2) called with supplied arguments will converge,...
T as_array_or_scalar(T &&v)
Returns specified input value.
static constexpr double e()
Return the base of the natural logarithm.
Definition constants.hpp:20
auto sign(const T &x)
Returns signs of the arguments.
Definition sign.hpp:18
fvar< T > log(const fvar< T > &x)
Definition log.hpp:18
static constexpr double NEGATIVE_INFTY
Negative infinity.
Definition constants.hpp:51
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.
FvarT hypergeometric_pFq(const Ta &a, const Tb &b, const Tz &z)
Returns the generalized hypergeometric (pFq) function applied to the input arguments.
auto sum(const std::vector< T > &m)
Return the sum of the entries of the specified standard vector.
Definition sum.hpp:23
int is_inf(const fvar< T > &x)
Returns 1 if the input's value is infinite and 0 otherwise.
Definition is_inf.hpp:21
fvar< T > fabs(const fvar< T > &x)
Definition fabs.hpp:16
fvar< T > exp(const fvar< T > &x)
Definition exp.hpp:15
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...