Rcpp中调用stats::constrOptim传入自定义函数出现编译报错
错误原因
你遇到的编译错误核心是类型不匹配:R的stats::constrOptim接收的目标函数必须是R可识别的Function类型对象,你直接传入C原生函数指针subject_function,Rcpp的类型转换系统没有对应规则把C函数指针转换为R可识别的函数对象,因此触发了类型转换阶段的报错,也就是你看到的is_convertible.h中的"function returning a function"错误。你传入R原生函数时,取到的本身就是Rcpp::Function类型实例,类型匹配因此不会报错。
可行解决方法
方案1:最小改动适配(推荐)
你已经通过// [[Rcpp::export]]将subject_function导出为R可调用的函数,只需要在调用constrOptim前,从R环境中获取该导出函数的Rcpp::Function实例即可,同时可以直接提取返回结果中的par对象返回,修改后的C++代码如下:
// [[Rcpp::depends(RcppArmadillo)]] // [[Rcpp::depends(RcppProgress)]] #define RCPP_ARMADILLO_RETURN_VEC_AS_VECTOR #include <RcppArmadillo.h> #include <string> #include <progress.hpp> using namespace arma; // [[Rcpp::export]] double subject_function(const vec &weights, const mat &predictions, const vec &truth) { vec pred = predictions * weights; vec loss_vec = arma::pow(pred - truth, 2); return arma::mean(loss_vec); } // [[Rcpp::export]] arma::vec constr_optim_rcpp(const vec &weights, const mat &predictions, const vec &truth, const mat &ui, const vec &ci) { Rcpp::Environment stats_pkg = Rcpp::Environment::namespace_env("stats"); Rcpp::Function constrOptim = stats_pkg["constrOptim"]; // 核心修改:获取已导出到R环境的损失函数实例 Rcpp::Environment global_env = Rcpp::Environment::global_env(); Rcpp::Function subject_fun = global_env["subject_function"]; // 调用优化函数,直接提取par返回 Rcpp::List optim_res = constrOptim( weights, subject_fun, R_NilValue, Rcpp::Named("ui", ui), Rcpp::Named("ci", ci), Rcpp::Named("method", "Nelder-Mead"), Rcpp::Named("predictions", predictions), Rcpp::Named("truth", truth) ); return Rcpp::as<arma::vec>(optim_res["par"]); }
R端调用示例:
Rcpp::sourceCpp("development/batch_reprex.cpp") A <- matrix(1:6, ncol = 2) weights <- c(0.5, 0.5) truth <- c(3, 3, 3) # 构造约束 positivity <- diag(ncol(A)) convexity <- rep(1, ncol(A)) constr_left <- rbind(convexity, positivity) constr_right <- c(1, rep(0, ncol(A))) # 直接调用封装函数即可拿到par结果 constr_optim_rcpp(weights, A, truth, constr_left, constr_right - 1e-12)
注:如果你的代码是写在R包内而非全局环境,只需要将获取函数的环境从
global_env替换为你包的命名空间即可,比如Rcpp::Environment::namespace_env("你的包名")。
方案2:纯C++层面优化(性能更高)
如果对性能要求较高,不想在迭代过程中反复进行R和C的交互,可以直接使用C的约束优化库ensmallen,它原生支持Armadillo数据结构,可以完全在C++层面完成约束优化,不需要调用R的constrOptim,性能提升非常明显。
内容的提问来源于stack exchange,提问作者BerriJ
相关产品推荐
相关产品推荐

