Automatic Differentiation
 
Loading...
Searching...
No Matches
hypergeometric_pFq.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_PFQ_HPP
2#define STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_PFQ_HPP
3
9#include <boost/math/special_functions/hypergeometric_pFq.hpp>
10
11namespace stan {
12namespace math {
13
26template <typename Ta, typename Tb, typename Tz,
27 require_all_vector_st<std::is_arithmetic, Ta, Tb>* = nullptr,
28 require_arithmetic_t<Tz>* = nullptr>
29inline return_type_t<Ta, Tb, Tz> hypergeometric_pFq(Ta&& a, Tb&& b, Tz&& z) {
30 decltype(auto) a_ref = to_ref(std::forward<Ta>(a));
31 decltype(auto) b_ref = to_ref(std::forward<Tb>(b));
32 check_finite("hypergeometric_pFq", "a", a_ref);
33 check_finite("hypergeometric_pFq", "b", b_ref);
34 check_finite("hypergeometric_pFq", "z", z);
35 check_not_nan("hypergeometric_pFq", "a", a_ref);
36 check_not_nan("hypergeometric_pFq", "b", b_ref);
37 check_not_nan("hypergeometric_pFq", "z", z);
38
39 const bool condition_1 = (a_ref.size() > (b_ref.size() + 1)) && (z != 0);
40 const bool condition_2
41 = (a_ref.size() == (b_ref.size() + 1)) && (std::fabs(z) > 1);
42
43 if (condition_1 || condition_2) {
44 [&]() STAN_COLD_PATH {
45 std::stringstream msg;
46 msg << "hypergeometric function pFq does not meet convergence "
47 "conditions with given arguments. "
48 "a: "
49 << to_row_vector(a_ref) << ", "
50 << "b: " << to_row_vector(b_ref) << ", "
51 << "z: " << z;
52 throw std::domain_error(msg.str());
53 }();
54 }
55 // For plain vectors, we can use Eigen's Map to avoid unnecessary copies
56 using a_ref_t = decltype(a_ref);
57 using b_ref_t = decltype(b_ref);
58 constexpr bool is_a_plain_vec
59 = std::is_same_v<std::decay_t<a_ref_t>, plain_type_t<a_ref_t>>;
60 constexpr bool is_b_plain_vec
61 = std::is_same_v<std::decay_t<b_ref_t>, plain_type_t<b_ref_t>>;
62 if constexpr (is_a_plain_vec && is_b_plain_vec) {
63 // We use type erasure not do a hard copy here
64 using map_t = Eigen::Map<Eigen::VectorXd>;
65 auto map_a = map_t(const_cast<double*>(a_ref.data()), a_ref.size());
66 auto map_b = map_t(const_cast<double*>(b_ref.data()), b_ref.size());
67 return boost::math::hypergeometric_pFq(map_a, map_b, z);
68 } else {
69 // We need pointers to `a` and `b`'s data here so we hard evaluate.
70 decltype(auto) a_eval = eval(a_ref);
71 decltype(auto) b_eval = eval(b_ref);
72 return boost::math::hypergeometric_pFq(
73 std::vector<double>(a_eval.data(), a_eval.data() + a_eval.size()),
74 std::vector<double>(b_eval.data(), b_eval.data() + b_eval.size()), z);
75 }
76}
77} // namespace math
78} // namespace stan
79#endif
#define STAN_COLD_PATH
auto to_row_vector(T_x &&x)
Returns input matrix reshaped into a row vector.
typename return_type< Ts... >::type return_type_t
Convenience type for the return type of the specified template parameters.
T eval(T &&arg)
Inputs which have a plain_type equal to the own time are forwarded unmodified (for Eigen expressions ...
Definition eval.hpp:20
void check_finite(const char *function, const char *name, const T_y &y)
Return true if all values in y are finite.
void check_not_nan(const char *function, const char *name, const T_y &y)
Check if y is not NaN.
FvarT hypergeometric_pFq(Ta &&a, Tb &&b, Tz &&z)
Returns the generalized hypergeometric (pFq) function applied to the input arguments.
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
Definition to_ref.hpp:18
typename plain_type< std::decay_t< T > >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...