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 typename T_return = return_type_t<Ta, Tb, Tz>,
21 typename ArrayAT = Eigen::Array<scalar_type_t<Ta>, 3, 1>,
22 typename ArrayBT = Eigen::Array<scalar_type_t<Ta>, 3, 1>,
23 require_all_vector_t<Ta, Tb>* = nullptr,
24 require_stan_scalar_t<Tz>* = nullptr>
25T_return hypergeometric_3F2_infsum(const Ta& a, const Tb& b, const Tz& z,
26 double precision = 1e-6,
27 int max_steps = 1e5) {
28 ArrayAT a_array = as_array_or_scalar(a);
29 ArrayBT b_array = append_row(as_array_or_scalar(b), 1.0);
30 check_3F2_converges("hypergeometric_3F2", a_array[0], a_array[1], a_array[2],
31 b_array[0], b_array[1], z);
32
33 T_return t_acc = 1.0;
34 T_return log_t = 0.0;
35 T_return log_z = log(fabs(z));
36 Eigen::ArrayXi a_signs = sign(value_of_rec(a_array));
37 Eigen::ArrayXi b_signs = sign(value_of_rec(b_array));
38 plain_type_t<decltype(a_array)> apk = a_array;
39 plain_type_t<decltype(b_array)> bpk = b_array;
40 int z_sign = sign(value_of_rec(z));
41 int t_sign = z_sign * a_signs.prod() * b_signs.prod();
42
43 int k = 0;
44 while (k <= max_steps && log_t >= log(precision)) {
45 // Replace zero values with 1 prior to taking the log so that we accumulate
46 // 0.0 rather than -inf
47 const auto& abs_apk = math::fabs((apk == 0).select(1.0, apk));
48 const auto& abs_bpk = math::fabs((bpk == 0).select(1.0, bpk));
49 T_return p = sum(log(abs_apk)) - sum(log(abs_bpk));
50 if (p == NEGATIVE_INFTY) {
51 return t_acc;
52 }
53
54 log_t += p + log_z;
55 t_acc += t_sign * exp(log_t);
56
57 if (is_inf(t_acc)) {
58 throw_domain_error("hypergeometric_3F2", "sum (output)", t_acc,
59 "overflow hypergeometric function did not converge.");
60 }
61 k++;
62 apk.array() += 1.0;
63 bpk.array() += 1.0;
64 a_signs = sign(value_of_rec(apk));
65 b_signs = sign(value_of_rec(bpk));
66 t_sign = a_signs.prod() * b_signs.prod() * t_sign;
67 }
68 if (k == max_steps) {
69 throw_domain_error("hypergeometric_3F2", "k (internal counter)", max_steps,
70 "exceeded iterations, hypergeometric function did not ",
71 "converge.");
72 }
73 return t_acc;
74}
75} // namespace internal
76
115template <typename Ta, typename Tb, typename Tz,
117 require_stan_scalar_t<Tz>* = nullptr>
118auto hypergeometric_3F2(const Ta& a, const Tb& b, const Tz& z) {
119 check_3F2_converges("hypergeometric_3F2", a[0], a[1], a[2], b[0], b[1], z);
120 // Boost's pFq throws convergence errors in some cases, fallback to naive
121 // infinite-sum approach (tests pass for these)
122 if (z == 1.0 && (sum(b) - sum(a)) < 0.0) {
124 }
125 return hypergeometric_pFq(to_vector(a), to_vector(b), z);
126}
127
144template <typename Ta, typename Tb, typename Tz,
146auto hypergeometric_3F2(const std::initializer_list<Ta>& a,
147 const std::initializer_list<Tb>& b, const Tz& z) {
148 return hypergeometric_3F2(std::vector<Ta>(a), std::vector<Tb>(b), z);
149}
150
151} // namespace math
152} // namespace stan
153#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.
require_all_t< is_vector< std::decay_t< Types > >... > require_all_vector_t
Require all of the types satisfy is_vector.
T_return 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:15
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.
fvar< T > sum(const std::vector< fvar< T > > &m)
Return the sum of the entries of the specified standard vector.
Definition sum.hpp:22
FvarT hypergeometric_pFq(const Ta &a, const Tb &b, const Tz &z)
Returns the generalized hypergeometric (pFq) function applied to the input arguments.
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:15
fvar< T > exp(const fvar< T > &x)
Definition exp.hpp:13
typename plain_type< T >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
Definition fvar.hpp:9