From 41737b7046f0d7482aa3c97bd9ec5e67c0b67f0e Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Sat, 15 Feb 2020 16:37:56 +0000 Subject: [PATCH 01/10] Add discrete_range_cdf, discrete_range_lcdf and discrete_range_lccdf --- stan/math/prim/prob.hpp | 5 ++ .../prim/prob/discrete_range_ccdf_log.hpp | 20 +++++ stan/math/prim/prob/discrete_range_cdf.hpp | 81 +++++++++++++++++++ .../math/prim/prob/discrete_range_cdf_log.hpp | 20 +++++ stan/math/prim/prob/discrete_range_lccdf.hpp | 81 +++++++++++++++++++ stan/math/prim/prob/discrete_range_lcdf.hpp | 81 +++++++++++++++++++ .../discrete_range_ccdf_log_test.hpp | 65 +++++++++++++++ .../discrete_range_cdf_log_test.hpp | 63 +++++++++++++++ .../discrete_range_cdf_test.hpp | 61 ++++++++++++++ .../prob/discrete_range_ccdf_log_test.cpp | 15 ++++ .../prim/prob/discrete_range_cdf_log_test.cpp | 15 ++++ 11 files changed, 507 insertions(+) create mode 100644 stan/math/prim/prob/discrete_range_ccdf_log.hpp create mode 100644 stan/math/prim/prob/discrete_range_cdf.hpp create mode 100644 stan/math/prim/prob/discrete_range_cdf_log.hpp create mode 100644 stan/math/prim/prob/discrete_range_lccdf.hpp create mode 100644 stan/math/prim/prob/discrete_range_lcdf.hpp create mode 100644 test/prob/discrete_range/discrete_range_ccdf_log_test.hpp create mode 100644 test/prob/discrete_range/discrete_range_cdf_log_test.hpp create mode 100644 test/prob/discrete_range/discrete_range_cdf_test.hpp create mode 100644 test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp create mode 100644 test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp diff --git a/stan/math/prim/prob.hpp b/stan/math/prim/prob.hpp index 6aad4c64441..e58a2e7769c 100644 --- a/stan/math/prim/prob.hpp +++ b/stan/math/prim/prob.hpp @@ -75,6 +75,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include diff --git a/stan/math/prim/prob/discrete_range_ccdf_log.hpp b/stan/math/prim/prob/discrete_range_ccdf_log.hpp new file mode 100644 index 00000000000..efc4d2d1bcf --- /dev/null +++ b/stan/math/prim/prob/discrete_range_ccdf_log.hpp @@ -0,0 +1,20 @@ +#ifndef STAN_MATH_PRIM_PROB_DISCRETE_RANGE_CCDF_LOG_HPP +#define STAN_MATH_PRIM_PROB_DISCRETE_RANGE_CCDF_LOG_HPP + +#include + +namespace stan { +namespace math { + +/** \ingroup prob_dists + * @deprecated use discrete_range_lccdf + */ +template +double discrete_range_ccdf_log(const T_y& y, const T_lower& lower, + const T_upper& upper) { + return discrete_range_lccdf(y, lower, upper); +} + +} // namespace math +} // namespace stan +#endif diff --git a/stan/math/prim/prob/discrete_range_cdf.hpp b/stan/math/prim/prob/discrete_range_cdf.hpp new file mode 100644 index 00000000000..1550e42d7db --- /dev/null +++ b/stan/math/prim/prob/discrete_range_cdf.hpp @@ -0,0 +1,81 @@ +#ifndef STAN_MATH_PRIM_PROB_DISCRETE_RANGE_CDF_HPP +#define STAN_MATH_PRIM_PROB_DISCRETE_RANGE_CDF_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** \ingroup prob_dists + * Return the CDF of a discrete range distribution for the given y, + * lower and upper bounds (all integers). + * + * `y`, `lower` and `upper` can each be a scalar or a one-dimensional container. + * Any container arguments must be the same size. + * + * @tparam T_y type of scalar, either int or std::vector + * @tparam T_lower type of lower bound, either int or std::vector + * @tparam T_upper type of upper bound, either int or std::vector + * + * @param y integer random variable + * @param lower integer lower bound + * @param upper integer upper bound + * @return The CDF evaluated at the specified arguments. If containers are + * supplied, returns the product of the CDFs. + * @throw std::domain_error if upper is smaller than lower. + * @throw std::invalid_argument if non-scalar arguments are of different + * sizes. + */ +template +double discrete_range_cdf(const T_y& y, const T_lower& lower, + const T_upper& upper) { + static const char* function = "discrete_range_cdf"; + + if (size_zero(y, lower, upper)) { + return 1.0; + } + + check_not_nan(function, "Random variable", y); + check_consistent_sizes(function, "Lower bound parameter", lower, + "Upper bound parameter", upper); + check_greater_or_equal(function, "Upper bound parameter", upper, lower); + + scalar_seq_view y_vec(y); + scalar_seq_view lower_vec(lower); + scalar_seq_view upper_vec(upper); + size_t size_y_lower = max_size(y, lower); + size_t N = max_size(y, lower, upper); + + for (size_t n = 0; n < N; ++n) { + const double y_dbl = value_of(y_vec[n]); + if (y_dbl < value_of(lower_vec[n])) { + return 0; + } + if (y_dbl > value_of(upper_vec[n])) { + return 1; + } + } + + double cdf(1.0); + for (size_t n = 0; n < N; n++) { + const double y_dbl = value_of(y_vec[n]); + const double lower_dbl = value_of(lower_vec[n]); + const double upper_dbl = value_of(upper_vec[n]); + + cdf *= (y_dbl - lower_dbl + 1) / (upper_dbl - lower_dbl + 1); + } + + return cdf; +} + +} // namespace math +} // namespace stan +#endif diff --git a/stan/math/prim/prob/discrete_range_cdf_log.hpp b/stan/math/prim/prob/discrete_range_cdf_log.hpp new file mode 100644 index 00000000000..91e631446b9 --- /dev/null +++ b/stan/math/prim/prob/discrete_range_cdf_log.hpp @@ -0,0 +1,20 @@ +#ifndef STAN_MATH_PRIM_PROB_DISCRETE_RANGE_CDF_LOG_HPP +#define STAN_MATH_PRIM_PROB_DISCRETE_RANGE_CDF_LOG_HPP + +#include + +namespace stan { +namespace math { + +/** \ingroup prob_dists + * @deprecated use discrete_range_lcdf + */ +template +double discrete_range_cdf_log(const T_y& y, const T_lower& lower, + const T_upper& upper) { + return discrete_range_lcdf(y, lower, upper); +} + +} // namespace math +} // namespace stan +#endif diff --git a/stan/math/prim/prob/discrete_range_lccdf.hpp b/stan/math/prim/prob/discrete_range_lccdf.hpp new file mode 100644 index 00000000000..0907b653c43 --- /dev/null +++ b/stan/math/prim/prob/discrete_range_lccdf.hpp @@ -0,0 +1,81 @@ +#ifndef STAN_MATH_PRIM_PROB_DISCRETE_RANGE_LCCDF_HPP +#define STAN_MATH_PRIM_PROB_DISCRETE_RANGE_LCCDF_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** \ingroup prob_dists + * Return the log CCDF of a discrete range distribution for the given y, + * lower and upper bounds (all integers). + * + * `y`, `lower` and `upper` can each be a scalar or a one-dimensional container. + * Any container arguments must be the same size. + * + * @tparam T_y type of scalar, either int or std::vector + * @tparam T_lower type of lower bound, either int or std::vector + * @tparam T_upper type of upper bound, either int or std::vector + * + * @param y integer random variable + * @param lower integer lower bound + * @param upper integer upper bound + * @return The log CCDF evaluated at the specified arguments. If containers are + * supplied, returns the sum of the log CCDFs. + * @throw std::domain_error if upper is smaller than lower. + * @throw std::invalid_argument if non-scalar arguments are of different + * sizes. + */ +template +double discrete_range_lccdf(const T_y& y, const T_lower& lower, + const T_upper& upper) { + static const char* function = "discrete_range_lccdf"; + + if (size_zero(y, lower, upper)) { + return 0.0; + } + + check_not_nan(function, "Random variable", y); + check_consistent_sizes(function, "Lower bound parameter", lower, + "Upper bound parameter", upper); + check_greater_or_equal(function, "Upper bound parameter", upper, lower); + + scalar_seq_view y_vec(y); + scalar_seq_view lower_vec(lower); + scalar_seq_view upper_vec(upper); + size_t size_y_lower = max_size(y, lower); + size_t N = max_size(y, lower, upper); + + for (size_t n = 0; n < N; ++n) { + const double y_dbl = value_of(y_vec[n]); + if (y_dbl < value_of(lower_vec[n])) { + return 0; + } + if (y_dbl > value_of(upper_vec[n])) { + return LOG_ZERO; + } + } + + double ccdf(0.0); + for (size_t n = 0; n < N; n++) { + const double y_dbl = value_of(y_vec[n]); + const double lower_dbl = value_of(lower_vec[n]); + const double upper_dbl = value_of(upper_vec[n]); + + ccdf += log(upper_dbl - y_dbl) - log(upper_dbl - lower_dbl + 1); + } + + return ccdf; +} + +} // namespace math +} // namespace stan +#endif diff --git a/stan/math/prim/prob/discrete_range_lcdf.hpp b/stan/math/prim/prob/discrete_range_lcdf.hpp new file mode 100644 index 00000000000..16cf3b29746 --- /dev/null +++ b/stan/math/prim/prob/discrete_range_lcdf.hpp @@ -0,0 +1,81 @@ +#ifndef STAN_MATH_PRIM_PROB_DISCRETE_RANGE_LCDF_HPP +#define STAN_MATH_PRIM_PROB_DISCRETE_RANGE_LCDF_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace stan { +namespace math { + +/** \ingroup prob_dists + * Return the log CDF of a discrete range distribution for the given y, + * lower and upper bounds (all integers). + * + * `y`, `lower` and `upper` can each be a scalar or a one-dimensional container. + * Any container arguments must be the same size. + * + * @tparam T_y type of scalar, either int or std::vector + * @tparam T_lower type of lower bound, either int or std::vector + * @tparam T_upper type of upper bound, either int or std::vector + * + * @param y integer random variable + * @param lower integer lower bound + * @param upper integer upper bound + * @return The log CDF evaluated at the specified arguments. If containers are + * supplied, returns the sum of the log CDFs. + * @throw std::domain_error if upper is smaller than lower. + * @throw std::invalid_argument if non-scalar arguments are of different + * sizes. + */ +template +double discrete_range_lcdf(const T_y& y, const T_lower& lower, + const T_upper& upper) { + static const char* function = "discrete_range_lcdf"; + + if (size_zero(y, lower, upper)) { + return 0.0; + } + + check_not_nan(function, "Random variable", y); + check_consistent_sizes(function, "Lower bound parameter", lower, + "Upper bound parameter", upper); + check_greater_or_equal(function, "Upper bound parameter", upper, lower); + + scalar_seq_view y_vec(y); + scalar_seq_view lower_vec(lower); + scalar_seq_view upper_vec(upper); + size_t size_y_lower = max_size(y, lower); + size_t N = max_size(y, lower, upper); + + for (size_t n = 0; n < N; ++n) { + const double y_dbl = value_of(y_vec[n]); + if (y_dbl < value_of(lower_vec[n])) { + return LOG_ZERO; + } + if (y_dbl > value_of(upper_vec[n])) { + return 0; + } + } + + double cdf(0.0); + for (size_t n = 0; n < N; n++) { + const double y_dbl = value_of(y_vec[n]); + const double lower_dbl = value_of(lower_vec[n]); + const double upper_dbl = value_of(upper_vec[n]); + + cdf += log(y_dbl - lower_dbl + 1) - log(upper_dbl - lower_dbl + 1); + } + + return cdf; +} + +} // namespace math +} // namespace stan +#endif diff --git a/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp b/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp new file mode 100644 index 00000000000..32e38840fb8 --- /dev/null +++ b/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp @@ -0,0 +1,65 @@ +// Arguments: Ints, Ints, Ints +#include + +using stan::math::var; +using std::vector; + +class AgradCcdfLogDiscreteRange : public AgradCcdfLogTest { + public: + void valid_values(vector>& parameters, + vector& ccdf_log) { + vector param(3); + + param[0] = 3; // y + param[1] = 1; // lower + param[2] = 5; // upper + parameters.push_back(param); + ccdf_log.push_back(-0.916290731874154995573); // expected ccdf_log + + param[0] = 9; // y + param[1] = 5; // lower + param[2] = 15; // upper + parameters.push_back(param); + ccdf_log.push_back(-0.606135803570315601085); // expected ccdf_log + + param[0] = 0; // y + param[1] = -4; // lower + param[2] = 5; // upper + parameters.push_back(param); + ccdf_log.push_back(-0.693147180559945286227); // expected ccdf_log + } + + void invalid_values(vector& /*index*/, vector& /*value*/) { + // y + + // lower + + // upper + } + + bool has_lower_bound() { return false; } + + bool has_upper_bound() { return false; } + + template + stan::return_type_t ccdf_log(const T_y& y, + const T_lower& lower, + const T_upper& upper, + const T3&, const T4&, + const T5&) { + return stan::math::discrete_range_lccdf(y, lower, upper); + } + + template + stan::return_type_t ccdf_log_function( + const T_y& y, const T_lower& lower, const T_upper& upper, const T3&, + const T4&, const T5&) { + if (y < lower || y > upper) { + return stan::math::LOG_ZERO; + } + + return log((upper - y) / (upper - lower + 1)); + } +}; diff --git a/test/prob/discrete_range/discrete_range_cdf_log_test.hpp b/test/prob/discrete_range/discrete_range_cdf_log_test.hpp new file mode 100644 index 00000000000..059fd3d2c3b --- /dev/null +++ b/test/prob/discrete_range/discrete_range_cdf_log_test.hpp @@ -0,0 +1,63 @@ +// Arguments: Ints, Ints, Ints +#include + +using stan::math::var; +using std::numeric_limits; +using std::vector; + +class AgradCdfLogDiscreteRange : public AgradCdfLogTest { + public: + void valid_values(vector>& parameters, + vector& cdf_log) { + vector param(3); + + param[0] = 3; // y + param[1] = 1; // lower + param[2] = 5; // upper + parameters.push_back(param); + cdf_log.push_back(-0.510825623765990721736); // expected cdf_log + + param[0] = 9; // y + param[1] = 5; // lower + param[2] = 15; // upper + parameters.push_back(param); + cdf_log.push_back(-0.788457360364270165576); // expected cdf_log + + param[0] = 0; // y + param[1] = -4; // lower + param[2] = 5; // upper + parameters.push_back(param); + cdf_log.push_back(-0.693147180559945286227); // expected cdf_log + } + + void invalid_values(vector& /*index*/, vector& /*value*/) { + // y + + // lower + + // upper + } + + bool has_lower_bound() { return false; } + + bool has_upper_bound() { return false; } + + template + double cdf_log(const T_y& y, const T_lower& lower, const T_upper& upper, + const T3&, const T4&, const T5&) { + return stan::math::discrete_range_lcdf(y, lower, upper); + } + + template + double cdf_log_function(const T_y& y, const T_lower& lower, + const T_upper& upper, const T3&, const T4&, + const T5&) { + if (y < lower || y > upper) { + return stan::math::LOG_ZERO; + } + + return log((y - lower + 1.0) / (upper - lower + 1.0)); + } +}; diff --git a/test/prob/discrete_range/discrete_range_cdf_test.hpp b/test/prob/discrete_range/discrete_range_cdf_test.hpp new file mode 100644 index 00000000000..697d049909d --- /dev/null +++ b/test/prob/discrete_range/discrete_range_cdf_test.hpp @@ -0,0 +1,61 @@ +// Arguments: Ints, Ints, Ints +#include + +using stan::math::var; +using std::numeric_limits; +using std::vector; + +class AgradCdfDiscreteRange : public AgradCdfTest { + public: + void valid_values(vector>& parameters, vector& cdf) { + vector param(3); + + param[0] = 3; // y + param[1] = 1; // lower + param[2] = 5; // upper + parameters.push_back(param); + cdf.push_back(0.6); // expected cdf + + param[0] = 9; // y + param[1] = 5; // lower + param[2] = 15; // upper + parameters.push_back(param); + cdf.push_back(0.454545454545454530315); // expected cdf + + param[0] = 0; // y + param[1] = -4; // lower + param[2] = 5; // upper + parameters.push_back(param); + cdf.push_back(0.5); // expected cdf + } + + void invalid_values(vector& /*index*/, vector& /*value*/) { + // y + + // lower + + // upper + } + + bool has_lower_bound() { return false; } + + bool has_upper_bound() { return false; } + + template + double cdf(const T_y& y, const T_lower& lower, const T_upper& upper, + const T3&, const T4&, const T5&) { + return stan::math::discrete_range_cdf(y, lower, upper); + } + + template + double cdf_function(const T_y& y, const T_lower& lower, const T_upper& upper, + const T3&, const T4&, const T5&) { + if (y < lower || y > upper) { + return 0; + } + + return (y - lower + 1.0) / (upper - lower + 1.0); + } +}; diff --git a/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp new file mode 100644 index 00000000000..fffc8c3cd0b --- /dev/null +++ b/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp @@ -0,0 +1,15 @@ +#include +#include + +TEST(ProbDiscreteRange, cdf_log_matches_lccdf) { + using stan::math::discrete_range_ccdf_log; + using stan::math::discrete_range_lccdf; + int y = 1; + int lower = 0; + int upper = 9; + + EXPECT_FLOAT_EQ((discrete_range_lccdf(y, lower, upper)), + (discrete_range_ccdf_log(y, lower, upper))); + EXPECT_FLOAT_EQ((discrete_range_lccdf(y, lower, upper)), + (discrete_range_ccdf_log(y, lower, upper))); +} diff --git a/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp new file mode 100644 index 00000000000..91e5976e04d --- /dev/null +++ b/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp @@ -0,0 +1,15 @@ +#include +#include + +TEST(ProbDiscreteRange, cdf_log_matches_lcdf) { + using stan::math::discrete_range_cdf_log; + using stan::math::discrete_range_lcdf; + int y = 1; + int lower = 0; + int upper = 9; + + EXPECT_FLOAT_EQ((discrete_range_lcdf(y, lower, upper)), + (discrete_range_cdf_log(y, lower, upper))); + EXPECT_FLOAT_EQ((discrete_range_lcdf(y, lower, upper)), + (discrete_range_cdf_log(y, lower, upper))); +} From ebad00e28ea9741547a7b608af9697c427cd4c5c Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Wed, 19 Feb 2020 09:09:53 +0000 Subject: [PATCH 02/10] Simplify values in tests --- test/prob/discrete_range/discrete_range_ccdf_log_test.hpp | 6 +++--- test/prob/discrete_range/discrete_range_cdf_log_test.hpp | 6 +++--- test/prob/discrete_range/discrete_range_cdf_test.hpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp b/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp index 32e38840fb8..ebdf201079f 100644 --- a/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp +++ b/test/prob/discrete_range/discrete_range_ccdf_log_test.hpp @@ -14,19 +14,19 @@ class AgradCcdfLogDiscreteRange : public AgradCcdfLogTest { param[1] = 1; // lower param[2] = 5; // upper parameters.push_back(param); - ccdf_log.push_back(-0.916290731874154995573); // expected ccdf_log + ccdf_log.push_back(log(2.0 / 5)); // expected ccdf_log param[0] = 9; // y param[1] = 5; // lower param[2] = 15; // upper parameters.push_back(param); - ccdf_log.push_back(-0.606135803570315601085); // expected ccdf_log + ccdf_log.push_back(log(6.0 / 11)); // expected ccdf_log param[0] = 0; // y param[1] = -4; // lower param[2] = 5; // upper parameters.push_back(param); - ccdf_log.push_back(-0.693147180559945286227); // expected ccdf_log + ccdf_log.push_back(log(5.0 / 10)); // expected ccdf_log } void invalid_values(vector& /*index*/, vector& /*value*/) { diff --git a/test/prob/discrete_range/discrete_range_cdf_log_test.hpp b/test/prob/discrete_range/discrete_range_cdf_log_test.hpp index 059fd3d2c3b..426564cf56f 100644 --- a/test/prob/discrete_range/discrete_range_cdf_log_test.hpp +++ b/test/prob/discrete_range/discrete_range_cdf_log_test.hpp @@ -15,19 +15,19 @@ class AgradCdfLogDiscreteRange : public AgradCdfLogTest { param[1] = 1; // lower param[2] = 5; // upper parameters.push_back(param); - cdf_log.push_back(-0.510825623765990721736); // expected cdf_log + cdf_log.push_back(log(3.0 / 5)); // expected cdf_log param[0] = 9; // y param[1] = 5; // lower param[2] = 15; // upper parameters.push_back(param); - cdf_log.push_back(-0.788457360364270165576); // expected cdf_log + cdf_log.push_back(log(5.0 / 11)); // expected cdf_log param[0] = 0; // y param[1] = -4; // lower param[2] = 5; // upper parameters.push_back(param); - cdf_log.push_back(-0.693147180559945286227); // expected cdf_log + cdf_log.push_back(log(5.0 / 10)); // expected cdf_log } void invalid_values(vector& /*index*/, vector& /*value*/) { diff --git a/test/prob/discrete_range/discrete_range_cdf_test.hpp b/test/prob/discrete_range/discrete_range_cdf_test.hpp index 697d049909d..c0d74b41c51 100644 --- a/test/prob/discrete_range/discrete_range_cdf_test.hpp +++ b/test/prob/discrete_range/discrete_range_cdf_test.hpp @@ -14,19 +14,19 @@ class AgradCdfDiscreteRange : public AgradCdfTest { param[1] = 1; // lower param[2] = 5; // upper parameters.push_back(param); - cdf.push_back(0.6); // expected cdf + cdf.push_back(3.0 / 5); // expected cdf param[0] = 9; // y param[1] = 5; // lower param[2] = 15; // upper parameters.push_back(param); - cdf.push_back(0.454545454545454530315); // expected cdf + cdf.push_back(5.0 / 11); // expected cdf param[0] = 0; // y param[1] = -4; // lower param[2] = 5; // upper parameters.push_back(param); - cdf.push_back(0.5); // expected cdf + cdf.push_back(5.0 / 10); // expected cdf } void invalid_values(vector& /*index*/, vector& /*value*/) { From a35873a314f808daeab9499c3988f88e22e125bc Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Wed, 19 Feb 2020 09:24:26 +0000 Subject: [PATCH 03/10] Exploit the fact that all arguments are ints --- stan/math/prim/prob/discrete_range_cdf.hpp | 20 +++++++------------- stan/math/prim/prob/discrete_range_lccdf.hpp | 20 +++++++------------- stan/math/prim/prob/discrete_range_lcdf.hpp | 20 +++++++------------- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/stan/math/prim/prob/discrete_range_cdf.hpp b/stan/math/prim/prob/discrete_range_cdf.hpp index 1550e42d7db..f94e639b459 100644 --- a/stan/math/prim/prob/discrete_range_cdf.hpp +++ b/stan/math/prim/prob/discrete_range_cdf.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace stan { @@ -38,12 +37,10 @@ template double discrete_range_cdf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_cdf"; - if (size_zero(y, lower, upper)) { - return 1.0; + return 1; } - check_not_nan(function, "Random variable", y); check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); @@ -51,28 +48,25 @@ double discrete_range_cdf(const T_y& y, const T_lower& lower, scalar_seq_view y_vec(y); scalar_seq_view lower_vec(lower); scalar_seq_view upper_vec(upper); - size_t size_y_lower = max_size(y, lower); size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const double y_dbl = value_of(y_vec[n]); - if (y_dbl < value_of(lower_vec[n])) { + const int y_dbl = y_vec[n]; + if (y_dbl < lower_vec[n]) { return 0; } - if (y_dbl > value_of(upper_vec[n])) { + if (y_dbl > upper_vec[n]) { return 1; } } double cdf(1.0); for (size_t n = 0; n < N; n++) { - const double y_dbl = value_of(y_vec[n]); - const double lower_dbl = value_of(lower_vec[n]); - const double upper_dbl = value_of(upper_vec[n]); - + const double y_dbl = y_vec[n]; + const double lower_dbl = lower_vec[n]; + const double upper_dbl = upper_vec[n]; cdf *= (y_dbl - lower_dbl + 1) / (upper_dbl - lower_dbl + 1); } - return cdf; } diff --git a/stan/math/prim/prob/discrete_range_lccdf.hpp b/stan/math/prim/prob/discrete_range_lccdf.hpp index 0907b653c43..0512688a448 100644 --- a/stan/math/prim/prob/discrete_range_lccdf.hpp +++ b/stan/math/prim/prob/discrete_range_lccdf.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace stan { @@ -38,12 +37,10 @@ template double discrete_range_lccdf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_lccdf"; - if (size_zero(y, lower, upper)) { - return 0.0; + return 0; } - check_not_nan(function, "Random variable", y); check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); @@ -51,28 +48,25 @@ double discrete_range_lccdf(const T_y& y, const T_lower& lower, scalar_seq_view y_vec(y); scalar_seq_view lower_vec(lower); scalar_seq_view upper_vec(upper); - size_t size_y_lower = max_size(y, lower); size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const double y_dbl = value_of(y_vec[n]); - if (y_dbl < value_of(lower_vec[n])) { + const int y_dbl = y_vec[n]; + if (y_dbl < lower_vec[n]) { return 0; } - if (y_dbl > value_of(upper_vec[n])) { + if (y_dbl > upper_vec[n]) { return LOG_ZERO; } } double ccdf(0.0); for (size_t n = 0; n < N; n++) { - const double y_dbl = value_of(y_vec[n]); - const double lower_dbl = value_of(lower_vec[n]); - const double upper_dbl = value_of(upper_vec[n]); - + const int y_dbl = y_vec[n]; + const int lower_dbl = lower_vec[n]; + const int upper_dbl = upper_vec[n]; ccdf += log(upper_dbl - y_dbl) - log(upper_dbl - lower_dbl + 1); } - return ccdf; } diff --git a/stan/math/prim/prob/discrete_range_lcdf.hpp b/stan/math/prim/prob/discrete_range_lcdf.hpp index 16cf3b29746..0cfce741d4e 100644 --- a/stan/math/prim/prob/discrete_range_lcdf.hpp +++ b/stan/math/prim/prob/discrete_range_lcdf.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace stan { @@ -38,12 +37,10 @@ template double discrete_range_lcdf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_lcdf"; - if (size_zero(y, lower, upper)) { - return 0.0; + return 0; } - check_not_nan(function, "Random variable", y); check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); @@ -51,28 +48,25 @@ double discrete_range_lcdf(const T_y& y, const T_lower& lower, scalar_seq_view y_vec(y); scalar_seq_view lower_vec(lower); scalar_seq_view upper_vec(upper); - size_t size_y_lower = max_size(y, lower); size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const double y_dbl = value_of(y_vec[n]); - if (y_dbl < value_of(lower_vec[n])) { + const int y_dbl = y_vec[n]; + if (y_dbl < lower_vec[n]) { return LOG_ZERO; } - if (y_dbl > value_of(upper_vec[n])) { + if (y_dbl > upper_vec[n]) { return 0; } } double cdf(0.0); for (size_t n = 0; n < N; n++) { - const double y_dbl = value_of(y_vec[n]); - const double lower_dbl = value_of(lower_vec[n]); - const double upper_dbl = value_of(upper_vec[n]); - + const int y_dbl = y_vec[n]; + const int lower_dbl = lower_vec[n]; + const int upper_dbl = upper_vec[n]; cdf += log(y_dbl - lower_dbl + 1) - log(upper_dbl - lower_dbl + 1); } - return cdf; } From c329bab5866c9b6b75a9a82f3edf23958c212d95 Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Wed, 19 Feb 2020 15:55:19 +0000 Subject: [PATCH 04/10] Add tests for boundaries --- .../prob/discrete_range_ccdf_log_test.cpp | 29 ++++++++++++++----- .../prim/prob/discrete_range_cdf_log_test.cpp | 28 +++++++++++++----- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp index fffc8c3cd0b..9ed68e2cadf 100644 --- a/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp +++ b/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp @@ -4,12 +4,25 @@ TEST(ProbDiscreteRange, cdf_log_matches_lccdf) { using stan::math::discrete_range_ccdf_log; using stan::math::discrete_range_lccdf; - int y = 1; - int lower = 0; - int upper = 9; - - EXPECT_FLOAT_EQ((discrete_range_lccdf(y, lower, upper)), - (discrete_range_ccdf_log(y, lower, upper))); - EXPECT_FLOAT_EQ((discrete_range_lccdf(y, lower, upper)), - (discrete_range_ccdf_log(y, lower, upper))); + + for (int lower = 0; lower < 5; ++lower) { + for (int upper = lower; upper < 5; ++upper) { + for (int y = lower; y <= upper; ++y) { + EXPECT_FLOAT_EQ((discrete_range_lccdf(y, lower, upper)), + (discrete_range_ccdf_log(y, lower, upper))); + EXPECT_FLOAT_EQ((discrete_range_lccdf(y, lower, upper)), + (discrete_range_ccdf_log(y, lower, upper))); + } + } + } +} + +TEST(ProbDiscreteRange, lccdf_boundaries) { + using stan::math::discrete_range_lccdf; + int lower = 1; + int upper = 5; + + EXPECT_FLOAT_EQ(std::log(4.0 / 5), discrete_range_lccdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lccdf(upper, lower, upper)); } diff --git a/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp index 91e5976e04d..e676316608f 100644 --- a/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp +++ b/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp @@ -4,12 +4,24 @@ TEST(ProbDiscreteRange, cdf_log_matches_lcdf) { using stan::math::discrete_range_cdf_log; using stan::math::discrete_range_lcdf; - int y = 1; - int lower = 0; - int upper = 9; - - EXPECT_FLOAT_EQ((discrete_range_lcdf(y, lower, upper)), - (discrete_range_cdf_log(y, lower, upper))); - EXPECT_FLOAT_EQ((discrete_range_lcdf(y, lower, upper)), - (discrete_range_cdf_log(y, lower, upper))); + + for (int lower = 0; lower < 5; ++lower) { + for (int upper = lower; upper < 5; ++upper) { + for (int y = lower; y <= upper; ++y) { + EXPECT_FLOAT_EQ((discrete_range_lcdf(y, lower, upper)), + (discrete_range_cdf_log(y, lower, upper))); + EXPECT_FLOAT_EQ((discrete_range_lcdf(y, lower, upper)), + (discrete_range_cdf_log(y, lower, upper))); + } + } + } +} + +TEST(ProbDiscreteRange, lcdf_boundaries) { + using stan::math::discrete_range_lcdf; + int lower = 1; + int upper = 5; + + EXPECT_FLOAT_EQ(std::log(1.0 / 5), discrete_range_lcdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper, lower, upper)); } From 58ebbf84d00a8372316456bf05e24e5cb13337df Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Fri, 21 Feb 2020 21:00:43 +0000 Subject: [PATCH 05/10] Add tests for out of support values --- .../prob/discrete_range_ccdf_log_test.cpp | 10 ++++++++++ .../prim/prob/discrete_range_cdf_log_test.cpp | 10 ++++++++++ .../prim/prob/discrete_range_cdf_test.cpp | 20 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 test/unit/math/prim/prob/discrete_range_cdf_test.cpp diff --git a/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp index 9ed68e2cadf..e4e8d900aba 100644 --- a/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp +++ b/test/unit/math/prim/prob/discrete_range_ccdf_log_test.cpp @@ -26,3 +26,13 @@ TEST(ProbDiscreteRange, lccdf_boundaries) { EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, discrete_range_lccdf(upper, lower, upper)); } + +TEST(ProbDiscreteRange, lccdf_out_of_support) { + using stan::math::discrete_range_lccdf; + int lower = 1; + int upper = 5; + + EXPECT_FLOAT_EQ(0.0, discrete_range_lccdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lccdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp index e676316608f..3c796f29070 100644 --- a/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp +++ b/test/unit/math/prim/prob/discrete_range_cdf_log_test.cpp @@ -25,3 +25,13 @@ TEST(ProbDiscreteRange, lcdf_boundaries) { EXPECT_FLOAT_EQ(std::log(1.0 / 5), discrete_range_lcdf(lower, lower, upper)); EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper, lower, upper)); } + +TEST(ProbDiscreteRange, lcdf_out_of_support) { + using stan::math::discrete_range_lcdf; + int lower = 1; + int upper = 5; + + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lcdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(0.0, discrete_range_lcdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/prim/prob/discrete_range_cdf_test.cpp b/test/unit/math/prim/prob/discrete_range_cdf_test.cpp new file mode 100644 index 00000000000..e5c251210d6 --- /dev/null +++ b/test/unit/math/prim/prob/discrete_range_cdf_test.cpp @@ -0,0 +1,20 @@ +#include +#include + +TEST(ProbDiscreteRange, cdf_boundaries) { + using stan::math::discrete_range_cdf; + int lower = 1; + int upper = 5; + + EXPECT_FLOAT_EQ(1.0 / 5, discrete_range_cdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(5.0 / 5, discrete_range_cdf(upper, lower, upper)); +} + +TEST(ProbDiscreteRange, cdf_out_of_support) { + using stan::math::discrete_range_cdf; + int lower = 1; + int upper = 5; + + EXPECT_FLOAT_EQ(0.0, discrete_range_cdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(1.0, discrete_range_cdf(upper + 1, lower, upper)); +} From 680b4ad2d8769de8cb423d1b4e6a75722dad9926 Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Wed, 26 Feb 2020 09:21:17 +0000 Subject: [PATCH 06/10] Add rev and fwd tests for boundary conditions --- stan/math/prim/prob/discrete_range_cdf.hpp | 9 ++++---- stan/math/prim/prob/discrete_range_lccdf.hpp | 9 ++++---- stan/math/prim/prob/discrete_range_lcdf.hpp | 9 ++++---- .../fwd/prob/discrete_range_ccdf_log_test.cpp | 22 +++++++++++++++++++ .../fwd/prob/discrete_range_cdf_log_test.cpp | 21 ++++++++++++++++++ .../math/fwd/prob/discrete_range_cdf_test.cpp | 20 +++++++++++++++++ .../rev/prob/discrete_range_ccdf_log_test.cpp | 22 +++++++++++++++++++ .../rev/prob/discrete_range_cdf_log_test.cpp | 21 ++++++++++++++++++ .../math/rev/prob/discrete_range_cdf_test.cpp | 20 +++++++++++++++++ 9 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp create mode 100644 test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp create mode 100644 test/unit/math/fwd/prob/discrete_range_cdf_test.cpp create mode 100644 test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp create mode 100644 test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp create mode 100644 test/unit/math/rev/prob/discrete_range_cdf_test.cpp diff --git a/stan/math/prim/prob/discrete_range_cdf.hpp b/stan/math/prim/prob/discrete_range_cdf.hpp index f94e639b459..455df64622a 100644 --- a/stan/math/prim/prob/discrete_range_cdf.hpp +++ b/stan/math/prim/prob/discrete_range_cdf.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace stan { @@ -51,7 +52,7 @@ double discrete_range_cdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = y_vec[n]; + const int y_dbl = value_of(y_vec[n]); if (y_dbl < lower_vec[n]) { return 0; } @@ -62,9 +63,9 @@ double discrete_range_cdf(const T_y& y, const T_lower& lower, double cdf(1.0); for (size_t n = 0; n < N; n++) { - const double y_dbl = y_vec[n]; - const double lower_dbl = lower_vec[n]; - const double upper_dbl = upper_vec[n]; + const double y_dbl = value_of(y_vec[n]); + const double lower_dbl = value_of(lower_vec[n]); + const double upper_dbl = value_of(upper_vec[n]); cdf *= (y_dbl - lower_dbl + 1) / (upper_dbl - lower_dbl + 1); } return cdf; diff --git a/stan/math/prim/prob/discrete_range_lccdf.hpp b/stan/math/prim/prob/discrete_range_lccdf.hpp index 0512688a448..1a598eeb80e 100644 --- a/stan/math/prim/prob/discrete_range_lccdf.hpp +++ b/stan/math/prim/prob/discrete_range_lccdf.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace stan { @@ -51,7 +52,7 @@ double discrete_range_lccdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = y_vec[n]; + const int y_dbl = valude_of(y_vec[n]); if (y_dbl < lower_vec[n]) { return 0; } @@ -62,9 +63,9 @@ double discrete_range_lccdf(const T_y& y, const T_lower& lower, double ccdf(0.0); for (size_t n = 0; n < N; n++) { - const int y_dbl = y_vec[n]; - const int lower_dbl = lower_vec[n]; - const int upper_dbl = upper_vec[n]; + const int y_dbl = value_of(y_vec[n]); + const int lower_dbl = value_of(lower_vec[n]); + const int upper_dbl = value_of(upper_vec[n]); ccdf += log(upper_dbl - y_dbl) - log(upper_dbl - lower_dbl + 1); } return ccdf; diff --git a/stan/math/prim/prob/discrete_range_lcdf.hpp b/stan/math/prim/prob/discrete_range_lcdf.hpp index 0cfce741d4e..26fc8bbcef9 100644 --- a/stan/math/prim/prob/discrete_range_lcdf.hpp +++ b/stan/math/prim/prob/discrete_range_lcdf.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace stan { @@ -51,7 +52,7 @@ double discrete_range_lcdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = y_vec[n]; + const int y_dbl = value_of(y_vec[n]); if (y_dbl < lower_vec[n]) { return LOG_ZERO; } @@ -62,9 +63,9 @@ double discrete_range_lcdf(const T_y& y, const T_lower& lower, double cdf(0.0); for (size_t n = 0; n < N; n++) { - const int y_dbl = y_vec[n]; - const int lower_dbl = lower_vec[n]; - const int upper_dbl = upper_vec[n]; + const int y_dbl = value_of(y_vec[n]); + const int lower_dbl = value_of(lower_vec[n]); + const int upper_dbl = value_of(upper_vec[n]); cdf += log(y_dbl - lower_dbl + 1) - log(upper_dbl - lower_dbl + 1); } return cdf; diff --git a/test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp new file mode 100644 index 00000000000..91509b9fb3c --- /dev/null +++ b/test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp @@ -0,0 +1,22 @@ +#include +#include + +TEST(FwdProbDiscreteRange, lccdf_boundaries) { + using stan::math::discrete_range_lccdf; + stan::math::fvar lower(1); + stan::math::fvar upper(5); + + EXPECT_FLOAT_EQ(std::log(4.0 / 5), discrete_range_lccdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lccdf(upper, lower, upper)); +} + +TEST(FwdProbDiscreteRange, lccdf_out_of_support) { + using stan::math::discrete_range_lccdf; + stan::math::fvar lower(1); + stan::math::fvar upper(5); + + EXPECT_FLOAT_EQ(0, discrete_range_lccdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lccdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp new file mode 100644 index 00000000000..4f95843276e --- /dev/null +++ b/test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp @@ -0,0 +1,21 @@ +#include +#include + +TEST(FwdProbDiscreteRange, lcdf_boundaries) { + using stan::math::discrete_range_lcdf; + stan::math::fvar lower(1); + stan::math::fvar upper(5); + + EXPECT_FLOAT_EQ(std::log(1.0 / 5), discrete_range_lcdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper, lower, upper)); +} + +TEST(FwdProbDiscreteRange, lcdf_out_of_support) { + using stan::math::discrete_range_lcdf; + stan::math::fvar lower(1); + stan::math::fvar upper(5); + + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lcdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/fwd/prob/discrete_range_cdf_test.cpp b/test/unit/math/fwd/prob/discrete_range_cdf_test.cpp new file mode 100644 index 00000000000..16eb531901b --- /dev/null +++ b/test/unit/math/fwd/prob/discrete_range_cdf_test.cpp @@ -0,0 +1,20 @@ +#include +#include + +TEST(FwdProbDiscreteRange, cdf_boundaries) { + using stan::math::discrete_range_cdf; + stan::math::fvar lower(1); + stan::math::fvar upper(5); + + EXPECT_FLOAT_EQ(1.0 / 5, discrete_range_cdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper, lower, upper)); +} + +TEST(FwdProbDiscreteRange, out_of_support) { + using stan::math::discrete_range_cdf; + stan::math::fvar lower(1); + stan::math::fvar upper(5); + + EXPECT_FLOAT_EQ(0, discrete_range_cdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp new file mode 100644 index 00000000000..06d62088cd8 --- /dev/null +++ b/test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp @@ -0,0 +1,22 @@ +#include +#include + +TEST(RevProbDiscreteRange, lccdf_boundaries) { + using stan::math::discrete_range_lccdf; + stan::math::var lower(1); + stan::math::var upper(5); + + EXPECT_FLOAT_EQ(std::log(4.0 / 5), discrete_range_lccdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lccdf(upper, lower, upper)); +} + +TEST(RevProbDiscreteRange, lccdf_out_of_support) { + using stan::math::discrete_range_lccdf; + stan::math::var lower(1); + stan::math::var upper(5); + + EXPECT_FLOAT_EQ(0, discrete_range_lccdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lccdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp new file mode 100644 index 00000000000..3e6dbc8802c --- /dev/null +++ b/test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp @@ -0,0 +1,21 @@ +#include +#include + +TEST(RevProbDiscreteRange, lcdf_boundaries) { + using stan::math::discrete_range_lcdf; + stan::math::var lower(1); + stan::math::var upper(5); + + EXPECT_FLOAT_EQ(std::log(1.0 / 5), discrete_range_lcdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper, lower, upper)); +} + +TEST(RevProbDiscreteRange, lcdf_out_of_support) { + using stan::math::discrete_range_lcdf; + stan::math::var lower(1); + stan::math::var upper(5); + + EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, + discrete_range_lcdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper + 1, lower, upper)); +} diff --git a/test/unit/math/rev/prob/discrete_range_cdf_test.cpp b/test/unit/math/rev/prob/discrete_range_cdf_test.cpp new file mode 100644 index 00000000000..092baf91321 --- /dev/null +++ b/test/unit/math/rev/prob/discrete_range_cdf_test.cpp @@ -0,0 +1,20 @@ +#include +#include + +TEST(RevProbDiscreteRange, cdf_boundaries) { + using stan::math::discrete_range_cdf; + stan::math::var lower(1); + stan::math::var upper(5); + + EXPECT_FLOAT_EQ(1.0 / 5, discrete_range_cdf(lower, lower, upper)); + EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper, lower, upper)); +} + +TEST(RevProbDiscreteRange, out_of_support) { + using stan::math::discrete_range_cdf; + stan::math::var lower(1); + stan::math::var upper(5); + + EXPECT_FLOAT_EQ(0, discrete_range_cdf(lower - 1, lower, upper)); + EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper + 1, lower, upper)); +} From 093501fe0f851967d19f6fade0143f2c06476779 Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Wed, 26 Feb 2020 11:12:35 +0000 Subject: [PATCH 07/10] Fix typo --- stan/math/prim/prob/discrete_range_lccdf.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stan/math/prim/prob/discrete_range_lccdf.hpp b/stan/math/prim/prob/discrete_range_lccdf.hpp index 1a598eeb80e..3875ccde7c3 100644 --- a/stan/math/prim/prob/discrete_range_lccdf.hpp +++ b/stan/math/prim/prob/discrete_range_lccdf.hpp @@ -52,7 +52,7 @@ double discrete_range_lccdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = valude_of(y_vec[n]); + const int y_dbl = value_of(y_vec[n]); if (y_dbl < lower_vec[n]) { return 0; } From 0bc6f24913c6f49e2f46d55368856e435a917a58 Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Wed, 26 Feb 2020 20:26:49 +0000 Subject: [PATCH 08/10] Revert addition of rev/fwd tests and use of value_of --- stan/math/prim/prob/discrete_range_cdf.hpp | 9 ++++---- stan/math/prim/prob/discrete_range_lccdf.hpp | 9 ++++---- stan/math/prim/prob/discrete_range_lcdf.hpp | 9 ++++---- .../fwd/prob/discrete_range_ccdf_log_test.cpp | 22 ------------------- .../fwd/prob/discrete_range_cdf_log_test.cpp | 21 ------------------ .../math/fwd/prob/discrete_range_cdf_test.cpp | 20 ----------------- .../rev/prob/discrete_range_ccdf_log_test.cpp | 22 ------------------- .../rev/prob/discrete_range_cdf_log_test.cpp | 21 ------------------ .../math/rev/prob/discrete_range_cdf_test.cpp | 20 ----------------- 9 files changed, 12 insertions(+), 141 deletions(-) delete mode 100644 test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp delete mode 100644 test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp delete mode 100644 test/unit/math/fwd/prob/discrete_range_cdf_test.cpp delete mode 100644 test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp delete mode 100644 test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp delete mode 100644 test/unit/math/rev/prob/discrete_range_cdf_test.cpp diff --git a/stan/math/prim/prob/discrete_range_cdf.hpp b/stan/math/prim/prob/discrete_range_cdf.hpp index 455df64622a..f94e639b459 100644 --- a/stan/math/prim/prob/discrete_range_cdf.hpp +++ b/stan/math/prim/prob/discrete_range_cdf.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace stan { @@ -52,7 +51,7 @@ double discrete_range_cdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = value_of(y_vec[n]); + const int y_dbl = y_vec[n]; if (y_dbl < lower_vec[n]) { return 0; } @@ -63,9 +62,9 @@ double discrete_range_cdf(const T_y& y, const T_lower& lower, double cdf(1.0); for (size_t n = 0; n < N; n++) { - const double y_dbl = value_of(y_vec[n]); - const double lower_dbl = value_of(lower_vec[n]); - const double upper_dbl = value_of(upper_vec[n]); + const double y_dbl = y_vec[n]; + const double lower_dbl = lower_vec[n]; + const double upper_dbl = upper_vec[n]; cdf *= (y_dbl - lower_dbl + 1) / (upper_dbl - lower_dbl + 1); } return cdf; diff --git a/stan/math/prim/prob/discrete_range_lccdf.hpp b/stan/math/prim/prob/discrete_range_lccdf.hpp index 3875ccde7c3..0512688a448 100644 --- a/stan/math/prim/prob/discrete_range_lccdf.hpp +++ b/stan/math/prim/prob/discrete_range_lccdf.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace stan { @@ -52,7 +51,7 @@ double discrete_range_lccdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = value_of(y_vec[n]); + const int y_dbl = y_vec[n]; if (y_dbl < lower_vec[n]) { return 0; } @@ -63,9 +62,9 @@ double discrete_range_lccdf(const T_y& y, const T_lower& lower, double ccdf(0.0); for (size_t n = 0; n < N; n++) { - const int y_dbl = value_of(y_vec[n]); - const int lower_dbl = value_of(lower_vec[n]); - const int upper_dbl = value_of(upper_vec[n]); + const int y_dbl = y_vec[n]; + const int lower_dbl = lower_vec[n]; + const int upper_dbl = upper_vec[n]; ccdf += log(upper_dbl - y_dbl) - log(upper_dbl - lower_dbl + 1); } return ccdf; diff --git a/stan/math/prim/prob/discrete_range_lcdf.hpp b/stan/math/prim/prob/discrete_range_lcdf.hpp index 26fc8bbcef9..0cfce741d4e 100644 --- a/stan/math/prim/prob/discrete_range_lcdf.hpp +++ b/stan/math/prim/prob/discrete_range_lcdf.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace stan { @@ -52,7 +51,7 @@ double discrete_range_lcdf(const T_y& y, const T_lower& lower, size_t N = max_size(y, lower, upper); for (size_t n = 0; n < N; ++n) { - const int y_dbl = value_of(y_vec[n]); + const int y_dbl = y_vec[n]; if (y_dbl < lower_vec[n]) { return LOG_ZERO; } @@ -63,9 +62,9 @@ double discrete_range_lcdf(const T_y& y, const T_lower& lower, double cdf(0.0); for (size_t n = 0; n < N; n++) { - const int y_dbl = value_of(y_vec[n]); - const int lower_dbl = value_of(lower_vec[n]); - const int upper_dbl = value_of(upper_vec[n]); + const int y_dbl = y_vec[n]; + const int lower_dbl = lower_vec[n]; + const int upper_dbl = upper_vec[n]; cdf += log(y_dbl - lower_dbl + 1) - log(upper_dbl - lower_dbl + 1); } return cdf; diff --git a/test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp deleted file mode 100644 index 91509b9fb3c..00000000000 --- a/test/unit/math/fwd/prob/discrete_range_ccdf_log_test.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -TEST(FwdProbDiscreteRange, lccdf_boundaries) { - using stan::math::discrete_range_lccdf; - stan::math::fvar lower(1); - stan::math::fvar upper(5); - - EXPECT_FLOAT_EQ(std::log(4.0 / 5), discrete_range_lccdf(lower, lower, upper)); - EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, - discrete_range_lccdf(upper, lower, upper)); -} - -TEST(FwdProbDiscreteRange, lccdf_out_of_support) { - using stan::math::discrete_range_lccdf; - stan::math::fvar lower(1); - stan::math::fvar upper(5); - - EXPECT_FLOAT_EQ(0, discrete_range_lccdf(lower - 1, lower, upper)); - EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, - discrete_range_lccdf(upper + 1, lower, upper)); -} diff --git a/test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp deleted file mode 100644 index 4f95843276e..00000000000 --- a/test/unit/math/fwd/prob/discrete_range_cdf_log_test.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -TEST(FwdProbDiscreteRange, lcdf_boundaries) { - using stan::math::discrete_range_lcdf; - stan::math::fvar lower(1); - stan::math::fvar upper(5); - - EXPECT_FLOAT_EQ(std::log(1.0 / 5), discrete_range_lcdf(lower, lower, upper)); - EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper, lower, upper)); -} - -TEST(FwdProbDiscreteRange, lcdf_out_of_support) { - using stan::math::discrete_range_lcdf; - stan::math::fvar lower(1); - stan::math::fvar upper(5); - - EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, - discrete_range_lcdf(lower - 1, lower, upper)); - EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper + 1, lower, upper)); -} diff --git a/test/unit/math/fwd/prob/discrete_range_cdf_test.cpp b/test/unit/math/fwd/prob/discrete_range_cdf_test.cpp deleted file mode 100644 index 16eb531901b..00000000000 --- a/test/unit/math/fwd/prob/discrete_range_cdf_test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -TEST(FwdProbDiscreteRange, cdf_boundaries) { - using stan::math::discrete_range_cdf; - stan::math::fvar lower(1); - stan::math::fvar upper(5); - - EXPECT_FLOAT_EQ(1.0 / 5, discrete_range_cdf(lower, lower, upper)); - EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper, lower, upper)); -} - -TEST(FwdProbDiscreteRange, out_of_support) { - using stan::math::discrete_range_cdf; - stan::math::fvar lower(1); - stan::math::fvar upper(5); - - EXPECT_FLOAT_EQ(0, discrete_range_cdf(lower - 1, lower, upper)); - EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper + 1, lower, upper)); -} diff --git a/test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp b/test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp deleted file mode 100644 index 06d62088cd8..00000000000 --- a/test/unit/math/rev/prob/discrete_range_ccdf_log_test.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -TEST(RevProbDiscreteRange, lccdf_boundaries) { - using stan::math::discrete_range_lccdf; - stan::math::var lower(1); - stan::math::var upper(5); - - EXPECT_FLOAT_EQ(std::log(4.0 / 5), discrete_range_lccdf(lower, lower, upper)); - EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, - discrete_range_lccdf(upper, lower, upper)); -} - -TEST(RevProbDiscreteRange, lccdf_out_of_support) { - using stan::math::discrete_range_lccdf; - stan::math::var lower(1); - stan::math::var upper(5); - - EXPECT_FLOAT_EQ(0, discrete_range_lccdf(lower - 1, lower, upper)); - EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, - discrete_range_lccdf(upper + 1, lower, upper)); -} diff --git a/test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp b/test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp deleted file mode 100644 index 3e6dbc8802c..00000000000 --- a/test/unit/math/rev/prob/discrete_range_cdf_log_test.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -TEST(RevProbDiscreteRange, lcdf_boundaries) { - using stan::math::discrete_range_lcdf; - stan::math::var lower(1); - stan::math::var upper(5); - - EXPECT_FLOAT_EQ(std::log(1.0 / 5), discrete_range_lcdf(lower, lower, upper)); - EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper, lower, upper)); -} - -TEST(RevProbDiscreteRange, lcdf_out_of_support) { - using stan::math::discrete_range_lcdf; - stan::math::var lower(1); - stan::math::var upper(5); - - EXPECT_FLOAT_EQ(stan::math::LOG_ZERO, - discrete_range_lcdf(lower - 1, lower, upper)); - EXPECT_FLOAT_EQ(0, discrete_range_lcdf(upper + 1, lower, upper)); -} diff --git a/test/unit/math/rev/prob/discrete_range_cdf_test.cpp b/test/unit/math/rev/prob/discrete_range_cdf_test.cpp deleted file mode 100644 index 092baf91321..00000000000 --- a/test/unit/math/rev/prob/discrete_range_cdf_test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -TEST(RevProbDiscreteRange, cdf_boundaries) { - using stan::math::discrete_range_cdf; - stan::math::var lower(1); - stan::math::var upper(5); - - EXPECT_FLOAT_EQ(1.0 / 5, discrete_range_cdf(lower, lower, upper)); - EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper, lower, upper)); -} - -TEST(RevProbDiscreteRange, out_of_support) { - using stan::math::discrete_range_cdf; - stan::math::var lower(1); - stan::math::var upper(5); - - EXPECT_FLOAT_EQ(0, discrete_range_cdf(lower - 1, lower, upper)); - EXPECT_FLOAT_EQ(1, discrete_range_cdf(upper + 1, lower, upper)); -} From f0e9e51eabef8a5c988b0322356f3bf27fa44d45 Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Fri, 28 Feb 2020 16:12:15 +0000 Subject: [PATCH 09/10] Template parameters on function calls can be inferred --- stan/math/prim/prob/discrete_range_ccdf_log.hpp | 2 +- stan/math/prim/prob/discrete_range_cdf_log.hpp | 2 +- stan/math/prim/prob/discrete_range_log.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stan/math/prim/prob/discrete_range_ccdf_log.hpp b/stan/math/prim/prob/discrete_range_ccdf_log.hpp index efc4d2d1bcf..324192e8c72 100644 --- a/stan/math/prim/prob/discrete_range_ccdf_log.hpp +++ b/stan/math/prim/prob/discrete_range_ccdf_log.hpp @@ -12,7 +12,7 @@ namespace math { template double discrete_range_ccdf_log(const T_y& y, const T_lower& lower, const T_upper& upper) { - return discrete_range_lccdf(y, lower, upper); + return discrete_range_lccdf(y, lower, upper); } } // namespace math diff --git a/stan/math/prim/prob/discrete_range_cdf_log.hpp b/stan/math/prim/prob/discrete_range_cdf_log.hpp index 91e631446b9..c21d7e17014 100644 --- a/stan/math/prim/prob/discrete_range_cdf_log.hpp +++ b/stan/math/prim/prob/discrete_range_cdf_log.hpp @@ -12,7 +12,7 @@ namespace math { template double discrete_range_cdf_log(const T_y& y, const T_lower& lower, const T_upper& upper) { - return discrete_range_lcdf(y, lower, upper); + return discrete_range_lcdf(y, lower, upper); } } // namespace math diff --git a/stan/math/prim/prob/discrete_range_log.hpp b/stan/math/prim/prob/discrete_range_log.hpp index 2c47f84eaa2..bee68587ae1 100644 --- a/stan/math/prim/prob/discrete_range_log.hpp +++ b/stan/math/prim/prob/discrete_range_log.hpp @@ -21,7 +21,7 @@ double discrete_range_log(const T_y& y, const T_lower& lower, template inline double discrete_range_log(const T_y& y, const T_lower& lower, const T_upper& upper) { - return discrete_range_lpmf(y, lower, upper); + return discrete_range_lpmf(y, lower, upper); } } // namespace math From 54ad239af70aecbd43f1a0b2ec8c687add007dd6 Mon Sep 17 00:00:00 2001 From: Marco Colombo Date: Fri, 28 Feb 2020 16:15:58 +0000 Subject: [PATCH 10/10] Move size_zero checks after other consistency checks --- stan/math/prim/prob/discrete_range_cdf.hpp | 8 ++++---- stan/math/prim/prob/discrete_range_lccdf.hpp | 8 ++++---- stan/math/prim/prob/discrete_range_lcdf.hpp | 8 ++++---- stan/math/prim/prob/discrete_range_lpmf.hpp | 8 +++----- stan/math/prim/prob/discrete_range_rng.hpp | 4 +--- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/stan/math/prim/prob/discrete_range_cdf.hpp b/stan/math/prim/prob/discrete_range_cdf.hpp index f94e639b459..9a54ec2c00d 100644 --- a/stan/math/prim/prob/discrete_range_cdf.hpp +++ b/stan/math/prim/prob/discrete_range_cdf.hpp @@ -37,14 +37,14 @@ template double discrete_range_cdf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_cdf"; - if (size_zero(y, lower, upper)) { - return 1; - } - check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); + if (size_zero(y, lower, upper)) { + return 1; + } + scalar_seq_view y_vec(y); scalar_seq_view lower_vec(lower); scalar_seq_view upper_vec(upper); diff --git a/stan/math/prim/prob/discrete_range_lccdf.hpp b/stan/math/prim/prob/discrete_range_lccdf.hpp index 0512688a448..6f2d002b9b8 100644 --- a/stan/math/prim/prob/discrete_range_lccdf.hpp +++ b/stan/math/prim/prob/discrete_range_lccdf.hpp @@ -37,14 +37,14 @@ template double discrete_range_lccdf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_lccdf"; - if (size_zero(y, lower, upper)) { - return 0; - } - check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); + if (size_zero(y, lower, upper)) { + return 0; + } + scalar_seq_view y_vec(y); scalar_seq_view lower_vec(lower); scalar_seq_view upper_vec(upper); diff --git a/stan/math/prim/prob/discrete_range_lcdf.hpp b/stan/math/prim/prob/discrete_range_lcdf.hpp index 0cfce741d4e..88de348c5e5 100644 --- a/stan/math/prim/prob/discrete_range_lcdf.hpp +++ b/stan/math/prim/prob/discrete_range_lcdf.hpp @@ -37,14 +37,14 @@ template double discrete_range_lcdf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_lcdf"; - if (size_zero(y, lower, upper)) { - return 0; - } - check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); + if (size_zero(y, lower, upper)) { + return 0; + } + scalar_seq_view y_vec(y); scalar_seq_view lower_vec(lower); scalar_seq_view upper_vec(upper); diff --git a/stan/math/prim/prob/discrete_range_lpmf.hpp b/stan/math/prim/prob/discrete_range_lpmf.hpp index 28adbf64a63..c691e5cde65 100644 --- a/stan/math/prim/prob/discrete_range_lpmf.hpp +++ b/stan/math/prim/prob/discrete_range_lpmf.hpp @@ -46,16 +46,14 @@ double discrete_range_lpmf(const T_y& y, const T_lower& lower, const T_upper& upper) { static const char* function = "discrete_range_lpmf"; using std::log; - - if (size_zero(y, lower, upper)) { - return 0.0; - } - check_not_nan(function, "Random variable", y); check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower); + if (size_zero(y, lower, upper)) { + return 0.0; + } if (!include_summand::value) { return 0.0; } diff --git a/stan/math/prim/prob/discrete_range_rng.hpp b/stan/math/prim/prob/discrete_range_rng.hpp index 9d2a5f56e3a..4348694ece9 100644 --- a/stan/math/prim/prob/discrete_range_rng.hpp +++ b/stan/math/prim/prob/discrete_range_rng.hpp @@ -33,11 +33,9 @@ namespace math { template inline typename VectorBuilder::type discrete_range_rng(const T_lower& lower, const T_upper& upper, RNG& rng) { + static const char* function = "discrete_range_rng"; using boost::random::uniform_int_distribution; using boost::variate_generator; - - static const char* function = "discrete_range_rng"; - check_consistent_sizes(function, "Lower bound parameter", lower, "Upper bound parameter", upper); check_greater_or_equal(function, "Upper bound parameter", upper, lower);