Hey, so the rstan standalone functions thing is close but when Rcpp and Boost template metaprogramming come together it creates something uglier than I want to think about. Either I need to resolve some of that or get a workaround from the parser.
The problem is Rcpp generates code based on our current stan-dev/stan code that doesn’t quite match the explicit doubles instantiation. So the compiler skips our instantiation and then tries to use Rcpp’s traits with our templated function and that doesn’t work (boost::promote_args chokes on Rcpp’s input_parameter traits). If I put the templated version in it’s own namespace (“stan”) and I call it from the instantiation explicitly ( double f_rng(...) {return stan::f_rng<double....>(...); }
). Could someone familiar with the code generation (@Bob_Carpenter or @mitzimorris?) suggest how to make this change?
Alternatively, does someone understand off hand why hiding the templated function within a namespace is necessary within the following code? This code is as-generated except I hid the templated version in the namespace and called it from the instantiation (stan::f_rng
). The error you get otherwise is (so promote_args isn’t made to work with Rcpp or vice-versa, that makes sense):
In instantiation of ‘typename boost::math::tools::promote_args<T>::type f_rng(const T0__&, RNG&, std::ostream*) [with T0__ = Rcpp::ConstReferenceInputParameter<double>; RNG = Rcpp::ConstReferenceInputParameter<boost::random::additive_combine_engine<boost::random::linear_congruential_engine<unsigned int, 40014u, 0u, 2147483563u>, boost::random::linear_congruential_engine<unsigned int, 40692u, 0u, 2147483399u> >&>; typename boost::math::tools::promote_args<T>::type = Rcpp::ConstReferenceInputParameter<double>; std::ostream = std::basic_ostream<char>]’:
file2e5a2ea9e478.cpp:103:65: required from here
file2e5a2ea9e478.cpp:38:76: error: no matching function for call to ‘Rcpp::ConstReferenceInputParameter<double>::ConstReferenceInputParameter(double)’
fun_scalar_t__ DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
// Code generated by Stan version 2.17.0
// [[Rcpp::depends(rstan)]]
#include <exporter.h>
#include <RcppEigen.h>
#include <stan/model/standalone_functions_header.hpp>
#include <stan/model/model_header.hpp>
using std::istream;
using std::string;
using std::stringstream;
using std::vector;
using namespace stan::math;
typedef Eigen::Matrix<double,Eigen::Dynamic,1> vector_d;
typedef Eigen::Matrix<double,1,Eigen::Dynamic> row_vector_d;
typedef Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> matrix_d;
stan::io::program_reader prog_reader__() {
stan::io::program_reader reader;
reader.add_event(0, 0, "start", "unkown file name");
reader.add_event(8, 8, "end", "unkown file name");
return reader;
}
namespace stan {
template <typename T0__, class RNG>
typename boost::math::tools::promote_args<T0__>::type
f_rng(const T0__& mu, RNG& base_rng__, std::ostream* pstream__) {
typedef typename boost::math::tools::promote_args<T0__>::type fun_scalar_t__;
typedef fun_scalar_t__ fun_return_scalar_t__;
const static bool propto__ = true;
(void) propto__;
fun_scalar_t__ DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
(void) DUMMY_VAR__; // suppress unused var warning
int current_statement_begin__ = -1;
try {
{
current_statement_begin__ = 4;
fun_scalar_t__ x;
(void) x; // dummy to suppress unused var warning
stan::math::initialize(x, std::numeric_limits<double>::quiet_NaN());
stan::math::fill(x,DUMMY_VAR__);
stan::math::assign(x,normal_rng(mu,1, base_rng__));
current_statement_begin__ = 5;
return stan::math::promote_scalar<fun_return_scalar_t__>(x);
}
} catch (const std::exception& e) {
stan::lang::rethrow_located(e, current_statement_begin__, prog_reader__());
// Next line prevents compiler griping about no return
throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
}
}
struct f_rng_functor__ {
template <typename T0__, class RNG>
typename boost::math::tools::promote_args<T0__>::type
operator()(const T0__& mu, RNG& base_rng__, std::ostream* pstream__) const {
return f_rng(mu, base_rng__, pstream__);
}
};
}
// [[Rcpp::export]]
double
f_rng(const double& mu, boost::ecuyer1988& base_rng__, std::ostream* pstream__ = 0){
return stan::f_rng<double, boost::ecuyer1988>(mu, base_rng__, pstream__);
}
#include <Rcpp.h>
// __create_rng
boost::ecuyer1988 __create_rng(int seed);
RcppExport SEXP sourceCpp_1___create_rng(SEXP seedSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< int >::type seed(seedSEXP);
rcpp_result_gen = Rcpp::wrap(__create_rng(seed));
return rcpp_result_gen;
END_RCPP
}
// f_rng
double f_rng(const double& mu, boost::ecuyer1988& base_rng__, std::ostream* pstream__);
RcppExport SEXP sourceCpp_1_f_rng(SEXP muSEXP, SEXP base_rng__SEXP, SEXP pstream__SEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< const double& >::type mu(muSEXP);
Rcpp::traits::input_parameter< boost::ecuyer1988& >::type base_rng__(base_rng__SEXP);
Rcpp::traits::input_parameter< std::ostream* >::type pstream__(pstream__SEXP);
rcpp_result_gen = Rcpp::wrap(f_rng(mu, base_rng__, pstream__));
return rcpp_result_gen;
END_RCPP
}