-
-
Notifications
You must be signed in to change notification settings - Fork 187
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
Vectorized unbounded continuous random number generators (Issue 45) #622
Changes from 7 commits
72eb950
fa7187b
270c96a
9a85e8c
ba6c624
275889c
d2281d1
427d316
8e83e4f
ee338ff
25daa7c
9bf8a0e
aa207eb
4517668
eff2de9
ddb60d9
47cdfc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,66 @@ | ||
#ifndef STAN_MATH_PRIM_SCAL_PROB_CAUCHY_RNG_HPP | ||
#define STAN_MATH_PRIM_SCAL_PROB_CAUCHY_RNG_HPP | ||
|
||
#include <boost/random/cauchy_distribution.hpp> | ||
#include <boost/random/variate_generator.hpp> | ||
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp> | ||
#include <stan/math/prim/scal/err/check_finite.hpp> | ||
#include <stan/math/prim/scal/err/check_not_nan.hpp> | ||
#include <stan/math/prim/scal/err/check_positive_finite.hpp> | ||
#include <stan/math/prim/scal/fun/constants.hpp> | ||
#include <stan/math/prim/scal/fun/log1p.hpp> | ||
#include <stan/math/prim/scal/fun/square.hpp> | ||
#include <stan/math/prim/scal/fun/value_of.hpp> | ||
#include <stan/math/prim/scal/meta/include_summand.hpp> | ||
#include <stan/math/prim/scal/meta/max_size.hpp> | ||
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp> | ||
#include <stan/math/prim/scal/meta/VectorBuilder.hpp> | ||
#include <boost/random/cauchy_distribution.hpp> | ||
#include <boost/random/variate_generator.hpp> | ||
#include <string> | ||
|
||
namespace stan { | ||
namespace math { | ||
|
||
/** | ||
* Return a pseudorandom Cauchy variate for the given location and scale | ||
* using the specified random number generator. | ||
* | ||
* mu and sigma can each be either scalars or vectors. All vector inputs | ||
* must be the same length. | ||
* | ||
* @tparam T_loc Type of location parameter | ||
* @tparam T_scale Type of scale parameter | ||
* @tparam RNG type of random number generator | ||
* @param mu location parameter | ||
* @param sigma positive scale parameter | ||
* @param mu (Sequence of) location parameter(s) | ||
* @param sigma (Sequence of) scale parameter(s) | ||
* @param rng random number generator | ||
* @return Cauchy random variate | ||
* @throw std::domain_error if mu is infinite or sigma is nonpositive | ||
* @throw std::invalid_argument if vector arguments are not the same length | ||
*/ | ||
template <class RNG> | ||
inline double | ||
cauchy_rng(double mu, | ||
double sigma, | ||
template <typename T_loc, typename T_scale, class RNG> | ||
inline typename VectorBuilder<true, double, T_loc, T_scale>::type | ||
cauchy_rng(const T_loc& mu, | ||
const T_scale& sigma, | ||
RNG& rng) { | ||
using boost::variate_generator; | ||
using boost::random::cauchy_distribution; | ||
|
||
static const std::string function = "cauchy_rng"; | ||
|
||
scalar_seq_view<T_loc> mu_vec(mu); | ||
scalar_seq_view<T_scale> sigma_vec(sigma); | ||
|
||
check_finite(function, "Location parameter", mu); | ||
check_positive_finite(function, "Scale parameter", sigma); | ||
check_consistent_sizes(function, | ||
"Location parameter", mu, | ||
"Scale Parameter", sigma); | ||
|
||
variate_generator<RNG&, cauchy_distribution<> > | ||
cauchy_rng(rng, cauchy_distribution<>(mu, sigma)); | ||
return cauchy_rng(); | ||
} | ||
size_t N = max_size(mu, sigma); | ||
|
||
VectorBuilder<true, double, T_loc, T_scale> output(N); | ||
|
||
for (size_t n = 0; n < N; n++) { | ||
variate_generator<RNG&, cauchy_distribution<> > | ||
cauchy_rng(rng, cauchy_distribution<>(mu_vec[n], sigma_vec[n])); | ||
output[n] = cauchy_rng(); | ||
} | ||
|
||
return output.data(); | ||
} | ||
} | ||
} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,69 @@ | ||
#ifndef STAN_MATH_PRIM_SCAL_PROB_DOUBLE_EXPONENTIAL_RNG_HPP | ||
#define STAN_MATH_PRIM_SCAL_PROB_DOUBLE_EXPONENTIAL_RNG_HPP | ||
|
||
#include <boost/random/uniform_01.hpp> | ||
#include <boost/random/variate_generator.hpp> | ||
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp> | ||
#include <stan/math/prim/scal/err/check_finite.hpp> | ||
#include <stan/math/prim/scal/err/check_not_nan.hpp> | ||
#include <stan/math/prim/scal/err/check_positive_finite.hpp> | ||
#include <stan/math/prim/scal/fun/value_of.hpp> | ||
#include <stan/math/prim/scal/fun/log1m.hpp> | ||
|
||
#include <stan/math/prim/scal/fun/constants.hpp> | ||
#include <stan/math/prim/scal/meta/include_summand.hpp> | ||
#include <stan/math/prim/scal/fun/sign.hpp> | ||
#include <stan/math/prim/scal/meta/max_size.hpp> | ||
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp> | ||
#include <stan/math/prim/scal/meta/VectorBuilder.hpp> | ||
#include <boost/random/uniform_01.hpp> | ||
#include <boost/random/variate_generator.hpp> | ||
#include <string> | ||
|
||
namespace stan { | ||
namespace math { | ||
|
||
/** | ||
* Return a pseudorandom double exponential variate with the given location | ||
* and scale using the specified random number generator. | ||
* | ||
* mu and sigma can each be either scalars or vectors. All vector inputs | ||
* must be the same length. | ||
* | ||
* @tparam T_loc Type of location parameter | ||
* @tparam T_scale Type of scale parameter | ||
* @tparam RNG class of random number generator | ||
* @param mu location parameter | ||
* @param sigma positive scale parameter | ||
* @param mu (Sequence of) location parameter(s) | ||
* @param sigma (Sequence of) scale parameter(s) | ||
* @param rng random number generator | ||
* @return double exponential random variate | ||
* @throw std::domain_error if mu is infinite or sigma is nonpositive | ||
* @throw std::invalid_argument if vector arguments are not the same length | ||
*/ | ||
template <class RNG> | ||
inline double | ||
double_exponential_rng(double mu, | ||
double sigma, | ||
template <typename T_loc, typename T_scale, class RNG> | ||
inline typename VectorBuilder<true, double, T_loc, T_scale>::type | ||
double_exponential_rng(const T_loc& mu, | ||
const T_scale& sigma, | ||
RNG& rng) { | ||
static const std::string function = "double_exponential_rng"; | ||
|
||
using boost::variate_generator; | ||
using boost::random::uniform_01; | ||
using std::log; | ||
using std::abs; | ||
|
||
scalar_seq_view<T_loc> mu_vec(mu); | ||
scalar_seq_view<T_scale> sigma_vec(sigma); | ||
|
||
check_finite(function, "Location parameter", mu); | ||
check_positive_finite(function, "Scale parameter", sigma); | ||
check_consistent_sizes(function, | ||
"Location parameter", mu, | ||
"Scale Parameter", sigma); | ||
|
||
size_t N = max_size(mu, sigma); | ||
|
||
VectorBuilder<true, double, T_loc, T_scale> output(N); | ||
|
||
variate_generator<RNG&, uniform_01<> > rng_unit_01(rng, uniform_01<>()); | ||
for (size_t n = 0; n < N; n++) { | ||
double laplaceRN = rng_unit_01(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional fix] What I was suggesting in the original comment was something like this
A slightly more efficient version would be
For For For I got there through the version here with algebra, but it turns out to be pretty close to the Wikipedia version, only using |
||
double a = (0.5 - laplaceRN > 0) ? 1.0 : -1.0; | ||
output[n] = mu_vec[n] - | ||
sigma_vec[n] * a * log1m(2 * abs(0.5 - laplaceRN)); | ||
} | ||
|
||
variate_generator<RNG&, uniform_01<> > | ||
rng_unit_01(rng, uniform_01<>()); | ||
double a = 0; | ||
double laplaceRN = rng_unit_01(); | ||
if (0.5 - laplaceRN > 0) | ||
a = 1.0; | ||
else if (0.5 - laplaceRN < 0) | ||
a = -1.0; | ||
return mu - sigma * a * log1m(2 * abs(0.5 - laplaceRN)); | ||
return output.data(); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,38 +3,70 @@ | |
|
||
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp> | ||
#include <stan/math/prim/scal/err/check_finite.hpp> | ||
#include <stan/math/prim/scal/err/check_not_nan.hpp> | ||
#include <stan/math/prim/scal/err/check_positive_finite.hpp> | ||
#include <stan/math/prim/scal/fun/constants.hpp> | ||
#include <stan/math/prim/scal/meta/length.hpp> | ||
#include <stan/math/prim/scal/meta/max_size.hpp> | ||
#include <stan/math/prim/scal/meta/VectorBuilder.hpp> | ||
#include <stan/math/prim/scal/prob/normal_rng.hpp> | ||
#include <stan/math/prim/scal/prob/exponential_rng.hpp> | ||
#include <stan/math/prim/scal/meta/include_summand.hpp> | ||
#include <stan/math/prim/scal/fun/value_of.hpp> | ||
#include <stan/math/prim/scal/prob/normal_rng.hpp> | ||
#include <boost/random/normal_distribution.hpp> | ||
#include <boost/random/variate_generator.hpp> | ||
#include <string> | ||
|
||
namespace stan { | ||
namespace math { | ||
|
||
template <class RNG> | ||
inline double | ||
exp_mod_normal_rng(double mu, | ||
double sigma, | ||
double lambda, | ||
/** | ||
* Return a pseudorandom Exponentially modified normal variate for the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional fix] I'd rather not capitalize anything other than proper names and names of distributions (not named after people) don't count. |
||
* given location, scale, and inverse scale using the specified random | ||
* number generator. | ||
* | ||
* mu, sigma, and lambda can each be either scalars or vectors. All vector | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't they be scalars, standard vectors, or Eigen vectors? |
||
* inputs must be the same length. | ||
* | ||
* @tparam T_loc Type of location parameter | ||
* @tparam T_scale Type of scale parameter | ||
* @tparam T_inv_scale Type of inverse scale parameter | ||
* @tparam RNG type of random number generator | ||
* @param mu (Sequence of) location parameter(s) | ||
* @param sigma (Sequence of) scale parameter(s) | ||
* @param lambda (Sequence of) inverse scale parameter(s) | ||
* @param rng random number generator | ||
* @return Exponentially modified normal random variate | ||
* @throw std::domain_error if mu is infinite, sigma is nonpositive, | ||
* or lambda is nonpositive | ||
* @throw std::invalid_argument if vector arguments are not the same length | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I think this should say "container arguments" where you have "vector arguments". |
||
*/ | ||
template <typename T_loc, typename T_scale, typename T_inv_scale, class RNG> | ||
inline | ||
typename VectorBuilder<true, double, T_loc, T_scale, T_inv_scale>::type | ||
exp_mod_normal_rng(const T_loc& mu, | ||
const T_scale& sigma, | ||
const T_inv_scale& lambda, | ||
RNG& rng) { | ||
static const std::string function = "exp_mod_normal_rng"; | ||
|
||
scalar_seq_view<T_loc> mu_vec(mu); | ||
scalar_seq_view<T_scale> sigma_vec(sigma); | ||
scalar_seq_view<T_inv_scale> lambda_vec(lambda); | ||
|
||
check_finite(function, "Location parameter", mu); | ||
check_positive_finite(function, "Inv_scale parameter", lambda); | ||
check_positive_finite(function, "Scale parameter", sigma); | ||
check_positive_finite(function, "Inv_scale parameter", lambda); | ||
check_consistent_sizes(function, | ||
"Location parameter", mu, | ||
"Scale Parameter", sigma, | ||
"Inv_scale Parameter", lambda); | ||
|
||
return normal_rng(mu, sigma, rng) | ||
+ exponential_rng(lambda, rng); | ||
} | ||
size_t N = max_size(mu, sigma, lambda); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional fix] I'd remove all the vertical space that's not absolutely necessary for readability. And that includes braces around for loops iwth single statements. Vertical space is precious! |
||
VectorBuilder<true, double, T_loc, T_scale, T_inv_scale> output(N); | ||
|
||
for (size_t n = 0; n < N; n++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional fix] we prefer |
||
output[n] = normal_rng(mu_vec[n], sigma_vec[n], rng) + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't going to be too much of an efficiency issue, but generally you don't want to call your public-facing functions internally because they're going to be doing redundant argument checks. It'll wind up creating more objects, too. Overally, though, this is probably OK like this and not worth optimizing now. |
||
exponential_rng(lambda_vec[n], rng); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional fix] I promised Sean not to require changes not legislated by cpplint, but I really think opertors should go on the following line for readability. You read code by scanning the structure down the left and it's lost with operators at theend of lines. |
||
} | ||
|
||
return output.data(); | ||
} | ||
} | ||
} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,50 +3,64 @@ | |
|
||
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp> | ||
#include <stan/math/prim/scal/err/check_finite.hpp> | ||
#include <stan/math/prim/scal/err/check_not_nan.hpp> | ||
#include <stan/math/prim/scal/err/check_positive.hpp> | ||
#include <stan/math/prim/scal/meta/length.hpp> | ||
#include <stan/math/prim/scal/err/check_positive_finite.hpp> | ||
#include <stan/math/prim/scal/meta/max_size.hpp> | ||
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp> | ||
#include <stan/math/prim/scal/meta/VectorBuilder.hpp> | ||
#include <stan/math/prim/scal/meta/return_type.hpp> | ||
#include <stan/math/prim/scal/fun/constants.hpp> | ||
#include <stan/math/prim/scal/meta/include_summand.hpp> | ||
#include <stan/math/prim/scal/fun/value_of.hpp> | ||
#include <boost/random/uniform_01.hpp> | ||
#include <boost/random/variate_generator.hpp> | ||
#include <string> | ||
|
||
namespace stan { | ||
namespace math { | ||
|
||
/** | ||
* Return a pseudorandom Gumbel variate with the given location and scale | ||
* using the specified random number generator. | ||
* | ||
* mu and sigma can each be either scalars or vectors. All vector inputs | ||
* must be the same length. | ||
* | ||
* @tparam T_loc Type of location parameter | ||
* @tparam T_scale Type of scale parameter | ||
* @tparam RNG type of random number generator | ||
* @param mu location parameter | ||
* @param beta positive scale parameter | ||
* @param mu (Sequence of) location parameter(s) | ||
* @param beta (Sequence of) scale parameter(s) | ||
* @param rng random number generator | ||
* @return Gumbel random variate | ||
* @throw std::domain_error if mu is infinite or beta is nonpositive. | ||
* @throw std::invalid_argument if vector arguments are not the same length | ||
*/ | ||
template <class RNG> | ||
inline double | ||
gumbel_rng(double mu, | ||
double beta, | ||
template <typename T_loc, typename T_scale, class RNG> | ||
inline typename VectorBuilder<true, double, T_loc, T_scale>::type | ||
gumbel_rng(const T_loc& mu, | ||
const T_scale& beta, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional fix] pack as many arguments onto a line as possible. Remember, vertical space is precious. (again, in Google style guide, not in cpplint) |
||
RNG& rng) { | ||
using boost::variate_generator; | ||
using boost::uniform_01; | ||
|
||
static const std::string function = "gumbel_rng"; | ||
|
||
check_finite(function, "Location parameter", mu); | ||
check_positive(function, "Scale parameter", beta); | ||
check_positive_finite(function, "Scale parameter", beta); | ||
check_consistent_sizes(function, | ||
"Location parameter", mu, | ||
"Scale Parameter", beta); | ||
|
||
variate_generator<RNG&, uniform_01<> > | ||
uniform01_rng(rng, uniform_01<>()); | ||
return mu - beta * std::log(-std::log(uniform01_rng())); | ||
} | ||
scalar_seq_view<T_loc> mu_vec(mu); | ||
scalar_seq_view<T_scale> beta_vec(beta); | ||
|
||
size_t N = max_size(mu, beta); | ||
|
||
VectorBuilder<true, double, T_loc, T_scale> output(N); | ||
|
||
variate_generator<RNG&, uniform_01<> > uniform01_rng(rng, uniform_01<>()); | ||
for (size_t n = 0; n < N; n++) { | ||
output[n] = mu_vec[n] - | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional] Same comments as last time on vertical space and operators. |
||
beta_vec[n] * std::log(-std::log(uniform01_rng())); | ||
} | ||
|
||
return output.data(); | ||
} | ||
} | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checks should go first before any work. In general, try to put exceptional/odd/edge-case branches first so that when you're by them, you can scan the main branch of the program together. Would you mind fixing this on all of these? Sorry for not catchign that earlier.