Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 1426 ibeta derivs large args #1433

Merged
merged 22 commits into from
Jun 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b465d12
More robust regularized ibeta derivatives and negative binomial cdfs
betanalpha Apr 26, 2015
eece634
Working for doubles, namespace issues for higher-order
betanalpha Apr 26, 2015
7ef2c9f
Substantially more robust regularized incomplete beta derivatives
betanalpha Apr 29, 2015
cfa4dc7
Fixed incorrect function name
betanalpha Apr 29, 2015
7e8db1c
Included what you use - test headers now passes
betanalpha Apr 29, 2015
64a453a
removed more cpplint warnings
syclik May 4, 2015
6b61d1e
Added more stability for large values of second argument, test
betanalpha May 5, 2015
08e8dea
Merge branch 'feature/issue-1426-ibeta_derivs_large_args' of https://…
betanalpha May 5, 2015
a71514a
cpplint warnings
syclik May 5, 2015
fded172
Merge branch 'feature/issue-1441-math-namespace' into feature/issue-1…
syclik May 9, 2015
4281233
1426: changing function names
syclik May 9, 2015
46132e5
splitting out inc_beta derivatives
syclik May 11, 2015
4ae4f5e
basic doc
syclik May 22, 2015
cb6de77
Doc for inc_beta derivatives
betanalpha May 23, 2015
c38b669
updating doc for ibeta deriv
syclik May 27, 2015
4e98ace
Merge branch 'develop' into feature/issue-1426-ibeta_derivs_large_args
syclik May 27, 2015
4411139
fixing includes
syclik May 27, 2015
5deae91
Merge branch 'develop' into feature/issue-1426-ibeta_derivs_large_args
syclik Jun 1, 2015
e101fb2
1426: my bad -- mismatched curly brace
syclik Jun 1, 2015
1c63764
1426: fixing merge problem
syclik Jun 1, 2015
836d335
1426: fixing merge problem
syclik Jun 1, 2015
229c283
1426: last bit of renaming
syclik Jun 1, 2015
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
3 changes: 3 additions & 0 deletions src/stan/math/prim/scal/fun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <stan/math/prim/scal/fun/identity_free.hpp>
#include <stan/math/prim/scal/fun/if_else.hpp>
#include <stan/math/prim/scal/fun/inc_beta.hpp>
#include <stan/math/prim/scal/fun/inc_beta_dda.hpp>
#include <stan/math/prim/scal/fun/inc_beta_ddb.hpp>
#include <stan/math/prim/scal/fun/inc_beta_ddz.hpp>
#include <stan/math/prim/scal/fun/int_step.hpp>
#include <stan/math/prim/scal/fun/inv.hpp>
#include <stan/math/prim/scal/fun/inv_cloglog.hpp>
Expand Down
94 changes: 94 additions & 0 deletions src/stan/math/prim/scal/fun/inc_beta_dda.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_INC_BETA_DDA_HPP
#define STAN_MATH_PRIM_SCAL_FUN_INC_BETA_DDA_HPP

#include <stan/math/prim/scal/fun/inc_beta.hpp>
#include <stan/math/prim/scal/fun/inc_beta_ddb.hpp>
#include <cmath>

namespace stan {
namespace math {

template <typename T>
T inc_beta_ddb(T a, T b, T z,
T digamma_b, T digamma_ab);

/**
* Returns the partial derivative of the regularized
* incomplete beta function, I_{z}(a, b) with respect to a.
* The power series used to compute the deriative tends to
* converge slowly when a and b are large, especially if z
* approaches 1. The implementation will throw an exception
* if the series have not converged within 100,000 iterations.
* The current implementation has been tested for values
* of a and b up to 12500 and z = 0.999.
*
* @tparam T scalar types of arguments
* @param a a
* @param b b
* @param z upper bound of the integral
* @param digamma_a value of digamma(a)
* @param digamma_ab value of digamma(b)
* @return partial derivative of the incomplete beta with respect to a
*
* @pre a >= 0
* @pre b >= 0
* @pre 0 <= z <= 1
*/
template <typename T>
T inc_beta_dda(T a, T b, T z,
T digamma_a, T digamma_ab) {
using std::log;

if (b > a)
if ((0.1 < z && z <= 0.75 && b > 500)
|| (0.01 < z && z <= 0.1 && b > 2500)
|| (0.001 < z && z <= 0.01 && b > 1e5))
return -inc_beta_ddb(b, a, 1 - z, digamma_a, digamma_ab);

if (z > 0.75 && a < 500)
return -inc_beta_ddb(b, a, 1 - z, digamma_a, digamma_ab);
if (z > 0.9 && a < 2500)
return -inc_beta_ddb(b, a, 1 - z, digamma_a, digamma_ab);
if (z > 0.99 && a < 1e5)
return -inc_beta_ddb(b, a, 1 - z, digamma_a, digamma_ab);
if (z > 0.999)
return -inc_beta_ddb(b, a, 1 - z, digamma_a, digamma_ab);

double threshold = 1e-10;

digamma_a += 1.0 / a; // Need digamma(a + 1), not digamma(a);

// Common prefactor to regularize numerator and denomentator
T prefactor = (a + 1) / (a + b);
prefactor = prefactor * prefactor * prefactor;

T sum_numer = (digamma_ab - digamma_a) * prefactor;
T sum_denom = prefactor;

T summand = prefactor * z * (a + b) / (a + 1);

T k = 1;
digamma_ab += 1.0 / (a + b);
digamma_a += 1.0 / (a + 1);

while (fabs(summand) > threshold) {
sum_numer += (digamma_ab - digamma_a) * summand;
sum_denom += summand;

summand *= (1 + (a + b) / k) * (1 + k) / (1 + (a + 1) / k);
digamma_ab += 1.0 / (a + b + k);
digamma_a += 1.0 / (a + 1 + k);
++k;
summand *= z / k;

if (k > 1e5)
throw std::domain_error("stan::math::inc_beta_dda did "
"not converge within 100000 iterations");
}
return inc_beta(a, b, z) * (log(z) + sum_numer / sum_denom);
}

} // math
} // stan

#endif
89 changes: 89 additions & 0 deletions src/stan/math/prim/scal/fun/inc_beta_ddb.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_INC_BETA_DDB_HPP
#define STAN_MATH_PRIM_SCAL_FUN_INC_BETA_DDB_HPP

#include <stan/math/prim/scal/fun/inc_beta.hpp>
#include <stan/math/prim/scal/fun/inc_beta_dda.hpp>
#include <cmath>

namespace stan {
namespace math {

template <typename T>
T inc_beta_dda(T a, T b, T z,
T digamma_a, T digamma_ab);

/**
* Returns the partial derivative of the regularized
* incomplete beta function, I_{z}(a, b) with respect to b.
* The power series used to compute the deriative tends to
* converge slowly when a and b are large, especailly if z
* approaches 1. The implementation will throw an exception
* if the series have not converged within 100,000 iterations.
* The current implementation has been tested for values
* of a and b up to 12500 and z = 0.999.
*
* @tparam T scalar types of arguments
* @param a a
* @param b b
* @param z upper bound of the integral
* @param digamma_a value of digamma(a)
* @param digamma_ab value of digamma(b)
* @return partial derivative of the incomplete beta with respect to b
*
* @pre a >= 0
* @pre b >= 0
* @pre 0 <= z <= 1
*/
template <typename T>
T inc_beta_ddb(T a, T b, T z,
T digamma_b, T digamma_ab) {
using std::log;

if (b > a)
if ((0.1 < z && z <= 0.75 && b > 500)
|| (0.01 < z && z <= 0.1 && b > 2500)
|| (0.001 < z && z <= 0.01 && b > 1e5))
return -inc_beta_dda(b, a, 1 - z, digamma_b, digamma_ab);

if ((z > 0.75 && a < 500)
|| (z > 0.9 && a < 2500)
|| (z > 0.99 && a < 1e5)
|| (z > 0.999))
return -inc_beta_dda(b, a, 1 - z, digamma_b, digamma_ab);

double threshold = 1e-10;

// Common prefactor to regularize numerator and denomentator
T prefactor = (a + 1) / (a + b);
prefactor = prefactor * prefactor * prefactor;

T sum_numer = digamma_ab * prefactor;
T sum_denom = prefactor;

T summand = prefactor * z * (a + b) / (a + 1);

T k = 1;
digamma_ab += 1.0 / (a + b);

while (fabs(summand) > threshold) {
sum_numer += digamma_ab * summand;
sum_denom += summand;

summand *= (1 + (a + b) / k) * (1 + k) / (1 + (a + 1) / k);
digamma_ab += 1.0 / (a + b + k);
++k;
summand *= z / k;

if (k > 1e5)
throw std::domain_error("stan::math::inc_beta_ddb did "
"not converge within 100000 iterations");
}

return inc_beta(a, b, z)
* (log(1 - z) - digamma_b + sum_numer / sum_denom);
}

} // math
} // stan

#endif
44 changes: 44 additions & 0 deletions src/stan/math/prim/scal/fun/inc_beta_ddz.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef STAN_MATH_PRIM_SCAL_FUN_INC_BETA_DERIVATIVES_HPP
#define STAN_MATH_PRIM_SCAL_FUN_INC_BETA_DERIVATIVES_HPP

#include <stan/math/prim/scal/fun/lgamma.hpp>
#include <stan/math/prim/scal/fun/inc_beta.hpp>
#include <boost/math/special_functions/beta.hpp>
#include <cmath>

namespace stan {
namespace math {


/**
* Returns the partial derivative of the regularized
* incomplete beta function, I_{z}(a, b) with respect to z.
*
* @tparam T scalar types of arguments
* @param a a
* @param b b
* @param z upper bound of the integral
* @return partial derivative of the incomplete beta with respect to z
*
* @pre a > 0
* @pre b > 0
* @pre 0 < z <= 1
*/
template <typename T>
T inc_beta_ddz(T a, T b, T z) {
using std::exp;
using std::log;
return exp((b - 1) * log(1 - z) + (a - 1) * log(z)
+ lgamma(a + b) - lgamma(a) - lgamma(b));
}

template <>
double inc_beta_ddz(double a, double b, double z) {
using boost::math::ibeta_derivative;
return ibeta_derivative(a, b, z);
}

} // math
} // stan

#endif
Loading