Skip to content

Commit d338ba8

Browse files
committed
Reduce error overhead
1 parent 3fb9218 commit d338ba8

2 files changed

Lines changed: 28 additions & 13 deletions

File tree

src/StanEstimators.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ RcppExport SEXP call_stan_(SEXP options_vector, SEXP ll_fun, SEXP grad_fun) {
1111
internal::grad_fun = Rcpp::Function(grad_fun);
1212
std::vector<std::string> options = Rcpp::as<std::vector<std::string>>(options_vector);
1313
int argc = 1 + options.size();
14-
const char* argv[argc];
14+
std::vector<const char*> argv(argc);
1515

1616
// Read in the name
1717
std::string name = "\0";
@@ -26,7 +26,7 @@ RcppExport SEXP call_stan_(SEXP options_vector, SEXP ll_fun, SEXP grad_fun) {
2626
argv[counter++] = options[i].c_str();
2727
}
2828
}
29-
return Rcpp::wrap(cmdstan::command(argc, argv));
29+
return Rcpp::wrap(cmdstan::command(argc, argv.data()));
3030
END_RCPP
3131
}
3232

src/include/estimator/estimator_ext_header.hpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
namespace internal {
1414
Rcpp::Function ll_fun("ls");
1515
Rcpp::Function grad_fun("ls");
16+
SEXP message_sym = Rf_install("message");
1617
}
1718

1819
template <typename F, typename T>
@@ -42,11 +43,15 @@ double r_function(const T& v,
4243
double lp = 0;
4344
auto v_cons = stan::math::lub_constrain<jacobian__>(v, lower_bounds, upper_bounds, lp);
4445
SEXP res = internal::ll_fun(v_cons);
45-
SEXP msgSEXP = Rf_getAttrib(res, Rf_install("message"));
46-
// If the result has a "message" attribute, it indicates an error in the user function
47-
if (msgSEXP != R_NilValue) {
48-
std::string msg = Rf_translateCharUTF8(STRING_ELT(msgSEXP, 0));
49-
throw std::domain_error("Error in user-defined function: " + msg);
46+
// Fast path: successful calls return a plain numeric scalar (REALSXP).
47+
// Only check attributes when the result is a list (VECSXP), which indicates
48+
// the user function returned a list (e.g., with a "message" on error).
49+
if (TYPEOF(res) == VECSXP) {
50+
SEXP msgSEXP = Rf_getAttrib(res, internal::message_sym);
51+
if (msgSEXP != R_NilValue) {
52+
std::string msg = Rf_translateCharUTF8(STRING_ELT(msgSEXP, 0));
53+
throw std::domain_error("Error in user-defined function: " + msg);
54+
}
5055
}
5156
return Rcpp::as<double>(res) + lp;
5257
}
@@ -75,14 +80,24 @@ stan::math::var r_function(const T& v,
7580
} else {
7681
arena_v = stan::math::lub_constrain<jacobian__>(v, lower_bounds, upper_bounds, lp);
7782
SEXP res = internal::grad_fun(arena_v.val());
78-
SEXP msgSEXP = Rf_getAttrib(res, Rf_install("message"));
79-
// If the result has a "message" attribute, it indicates an error in the user function
80-
if (msgSEXP != R_NilValue) {
81-
std::string msg = Rf_translateCharUTF8(STRING_ELT(msgSEXP, 0));
82-
throw std::domain_error("Error in user-defined gradient function: " + msg);
83+
// Fast path: successful gradient calls return a plain numeric vector.
84+
if (TYPEOF(res) == VECSXP) {
85+
SEXP msgSEXP = Rf_getAttrib(res, internal::message_sym);
86+
if (msgSEXP != R_NilValue) {
87+
std::string msg = Rf_translateCharUTF8(STRING_ELT(msgSEXP, 0));
88+
throw std::domain_error("Error in user-defined gradient function: " + msg);
89+
}
8390
}
8491
arena_grad = Rcpp::as<Eigen::VectorXd>(res);
85-
rtn = Rcpp::as<double>(internal::ll_fun(arena_v.val()));
92+
SEXP ll_res = internal::ll_fun(arena_v.val());
93+
if (TYPEOF(ll_res) == VECSXP) {
94+
SEXP msgSEXP = Rf_getAttrib(ll_res, internal::message_sym);
95+
if (msgSEXP != R_NilValue) {
96+
std::string msg = Rf_translateCharUTF8(STRING_ELT(msgSEXP, 0));
97+
throw std::domain_error("Error in user-defined function: " + msg);
98+
}
99+
}
100+
rtn = Rcpp::as<double>(ll_res);
86101
}
87102
return make_callback_var(
88103
rtn,

0 commit comments

Comments
 (0)