Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stan/math/prim/fun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
#include <stan/math/prim/fun/hypergeometric_2F2.hpp>
#include <stan/math/prim/fun/hypergeometric_3F2.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq_helper.hpp>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually want to include this in prim/fun.hpp? Not fully sure what the implications of leaving it out would be

#include <stan/math/prim/fun/hypot.hpp>
#include <stan/math/prim/fun/identity_matrix.hpp>
#include <stan/math/prim/fun/i_times.hpp>
Expand Down
7 changes: 4 additions & 3 deletions stan/math/prim/fun/hypergeometric_2F1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <stan/math/prim/fun/pow.hpp>
#include <stan/math/prim/fun/sqrt.hpp>
#include <stan/math/prim/fun/square.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq_helper.hpp>
#include <boost/optional.hpp>

namespace stan {
Expand Down Expand Up @@ -187,7 +187,7 @@ inline return_type_t<Ta1, Ta2, Tb, Tz> hypergeometric_2F1(const Ta1& a1,

a_args << a1, a2;
b_args << b;
return hypergeometric_pFq(a_args, b_args, z);
return internal::hypergeometric_pFq_helper(a_args, b_args, z);
} catch (const std::exception& e) {
// Apply Euler's hypergeometric transformation if function
// will not converge with current arguments
Expand All @@ -200,7 +200,8 @@ inline return_type_t<Ta1, Ta2, Tb, Tz> hypergeometric_2F1(const Ta1& a1,

a_args << a1_t, a2_t;
b_args << b_t;
return hypergeometric_pFq(a_args, b_args, z_t) / pow(1 - z, a2);
return internal::hypergeometric_pFq_helper(a_args, b_args, z_t)
/ pow(1 - z, a2);
}
}
} // namespace math
Expand Down
17 changes: 12 additions & 5 deletions stan/math/prim/fun/hypergeometric_pFq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err/check_not_nan.hpp>
#include <stan/math/prim/err/check_finite.hpp>
#include <stan/math/prim/fun/to_array_1d.hpp>
#include <stan/math/prim/fun/to_row_vector.hpp>
#include <boost/math/special_functions/hypergeometric_pFq.hpp>
#include <stan/math/prim/fun/hypergeometric_1F0.hpp>
#include <stan/math/prim/fun/hypergeometric_2F1.hpp>
#include <stan/math/prim/fun/hypergeometric_pFq_helper.hpp>

namespace stan {
namespace math {

/**
* Returns the generalized hypergeometric function applied to the
* input arguments:
Expand All @@ -29,6 +31,13 @@ return_type_t<Ta, Tb, Tz> hypergeometric_pFq(const Ta& a, const Tb& b,
const Tz& z) {
plain_type_t<Ta> a_ref = a;
plain_type_t<Tb> b_ref = b;

if (a_ref.size() == 1 && b_ref.size() == 0) {
return hypergeometric_1F0(a_ref[0], z);
} else if (a_ref.size() == 2 && b_ref.size() == 1) {
return hypergeometric_2F1(a_ref[0], a_ref[1], b_ref[0], z);
}

check_finite("hypergeometric_pFq", "a", a_ref);
check_finite("hypergeometric_pFq", "b", b_ref);
check_finite("hypergeometric_pFq", "z", z);
Expand All @@ -50,9 +59,7 @@ return_type_t<Ta, Tb, Tz> hypergeometric_pFq(const Ta& a, const Tb& b,
throw std::domain_error(msg.str());
}

return boost::math::hypergeometric_pFq(
std::vector<double>(a_ref.data(), a_ref.data() + a_ref.size()),
std::vector<double>(b_ref.data(), b_ref.data() + b_ref.size()), z);
return internal::hypergeometric_pFq_helper(a_ref, b_ref, z);
}
} // namespace math
} // namespace stan
Expand Down
32 changes: 32 additions & 0 deletions stan/math/prim/fun/hypergeometric_pFq_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_PFQ_HELPER_HPP
#define STAN_MATH_PRIM_FUN_HYPERGEOMETRIC_PFQ_HELPER_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/to_array_1d.hpp>
#include <boost/math/special_functions/hypergeometric_pFq.hpp>

namespace stan {
namespace math {
namespace internal {
/**
* Implementation for calculating the generalized hypergeometric function
* \f$_pF_q(a_1,...,a_p;b_1,...,b_q;z)\f$.
*
* This is declared separatel to avoid circular dependencies between the
* various hypergeometric functions.
*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs docs for template parameters

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @andrjohns this just needs to docs for the template parameters then it is good to go. I can do that if you don't have the time

* @param[in] a Vector of 'a' arguments to function
* @param[in] b Vector of 'b' arguments to function
* @param[in] z Scalar z argument
* @return Generalized hypergeometric function
*/
template <typename Ta, typename Tb, typename Tz,
require_all_vector_st<std::is_arithmetic, Ta, Tb>* = nullptr,
require_arithmetic_t<Tz>* = nullptr>
inline double hypergeometric_pFq_helper(const Ta& a, const Tb& b, const Tz& z) {
return boost::math::hypergeometric_pFq(to_array_1d(a), to_array_1d(b), z);
}
} // namespace internal
} // namespace math
} // namespace stan
#endif