修复Rcpp编译错误并实现对应R函数的技术求助
问题描述
我主要熟悉R语言,刚接触C++,尝试将R中的crit.val临界值计算函数用Rcpp实现,编写了对应的Rcpp代码,但代码出现多处编译错误(涉及行43、44、50、51、55)。已尝试排障但未解决,恳请协助修复错误并完成可用的Rcpp函数。
R函数代码
library(Rcpp) crit.val <- function(reps, k, n, Quantile, eps){ W <- rep(0,reps) sublength <- n-1 scale <- (1:(n-1))/n^2*((n-1):1) for (j in 1:reps){ data <- matrix( rnorm(n*k, 0, 1), k, n ) substat <- rep(0, sublength) for (t in 1:(n-1)){ if (k==1){ mean1 <- mean( data[1, 1:t] ) mean2 <- mean( data[1, (1+t):n] ) } if (k>1){ mean1 <- apply( matrix(data[, 1:t], ncol = t), 1, mean ) mean2 <- apply( matrix(data[, (t+1):n], ncol = n-t), 1, mean ) } inter1 <- NULL inter2 <- NULL for (h in 1:k){ inter1 <- rbind(inter1, cumsum( data[h, 1:t ] ) - (1:t)*mean1[h]) inter2 <- rbind(inter2, cumsum( data[h, n:(t+1)] ) - (1:(n-t))*mean2[h]) } M1 <- inter1 %*% t(inter1)/n^2 M2 <- inter2 %*% t(inter2)/n^2 substat[t] <- n * matrix(scale[t]*(mean1 - mean2), 1, k) %*% solve(M1+M2) %*% matrix(scale[t]*(mean1 - mean2), k, 1) } W[j] <- max( abs(substat)[ floor(n*eps):ceiling(n*(1-eps)) ] ) print(j) print(Sys.time()) } return( quantile( W, Quantile ) ) } crit.val(reps=100, k=1, n=100, Quantile = c(0.9,0.95,0.99,0.995,0.999), eps=0.01)
Rcpp代码
#include <Rcpp.h> using namespace Rcpp; // Helper function to extract a row slice from a NumericMatrix NumericVector extract_row_slice(const NumericMatrix& data, int row, int start, int end) { if (end >= data.ncol()) end = data.ncol() - 1; NumericVector slice(end - start + 1); for (int i = start; i <= end; i++) { slice[i - start] = data(row, i); } return slice; } // Main function to compute critical values // [[Rcpp::export]] NumericVector crit_val_cpp(int reps, int k, int n, double Quantile, double eps) { NumericVector W(reps); int sublength = n - 1; double n_squared = n * n; for (int j = 0; j < reps; j++) { NumericMatrix data(k, n, Rcpp::rnorm(n * k).begin()); NumericVector substat(sublength); NumericVector scale(sublength); // Precompute the scaling factor for each t for (int i = 0; i < sublength; i++) { scale[i] = (i + 1) * (sublength - i) / n_squared; } for (int t = 0; t < sublength; t++) { NumericVector mean1(k), mean2(k); // Calculate means for each segment for (int i = 0; i < k; i++) { mean1[i] = mean(extract_row_slice(data, i, 0, t)); mean2[i] = mean(extract_row_slice(data, i, t + 1, n - 1)); } // Calculate inter1 and inter2 NumericMatrix inter1(k, t + 1), inter2(k, n - t - 1); for (int h = 0; h < k; h++) { NumericVector temp1 = cumsum(extract_row_slice(data, h, 0, t)) - (seq_len(t + 1) - 1) * mean1[h]; NumericVector temp2 = cumsum(extract_row_slice(data, h, t + 1, n - 1)) - (seq_len(n - t - 1) - 1) * mean2[h]; std::copy(temp1.begin(), temp1.end(), inter1(h, _).begin()); std::copy(temp2.begin(), temp2.end(), inter2(h, _).begin()); } // Compute M1 and M2 matrices NumericMatrix M1 = inter1.t() * inter1 / n_squared; NumericMatrix M2 = inter2.t() * inter2 / n_squared; // Calculate substat[t] using the quadratic form NumericVector diff = scale[t] * (mean1 - mean2); substat[t] = n * crossprod(diff, solve(M1 + M2, diff)); } // Store the maximum of the substatistics adjusted for eps int lower_idx = floor(n * eps); int upper_idx = ceil(n * (1 - eps)) - 1; W[j] = max(abs(substat[Range(lower_idx, upper_idx)])); } // Return W return W; }
编译错误信息
- Line 43: invalid operands to binary expression ('sugar::Cumsum<14, true, Vector<14>>' and 'typename traits::enable_if<traits::is_convertible<typename traits::remove_const_and_reference<double>::type, typename traits::storage_type<13>::type>::value, sugar::Times_Vector_Primitive<13, true, Minus_Vector_Primitive<13, false, SeqLen>>>::type' (aka 'Rcpp::sugar::Times_Vector_Primitive<13, true, Rcpp::sugar::Minus_Vector_Primitive<13, false, Rcpp::sugar::SeqLen>>')) - Line 44: invalid operands to binary expression ('sugar::Cumsum<14, true, Vector<14>>' and 'typename traits::enable_if<traits::is_convertible<typename traits::remove_const_and_reference<double>::type, typename traits::storage_type<13>::type>::value, sugar::Times_Vector_Primitive<13, true, Minus_Vector_Primitive<13, false, SeqLen>>>::type' (aka 'Rcpp::sugar::Times_Vector_Primitive<13, true, Rcpp::sugar::Minus_Vector_Primitive<13, false, Rcpp::sugar::SeqLen>>')) - Line 50: no member named 't' in 'Rcpp::Matrix<14>' - Line 51: no member named 't' in 'Rcpp::Matrix<14>' - Line 55: use of undeclared identifier 'solve'
错误修复及解释
1. 行43、44:类型不匹配错误
seq_len返回整数向量,和cumsum生成的浮点向量运算时类型不兼容,需显式转换为NumericVector:
NumericVector temp1 = cumsum(extract_row_slice(data, h, 0, t)) - as<NumericVector>(seq_len(t + 1) - 1) * mean1[h]; NumericVector temp2 = cumsum(extract_row_slice(data, h, t + 1, n - 1)) - as<NumericVector>(seq_len(n - t - 1) - 1) * mean2[h];
2. 行50、51:矩阵转置方法错误
Rcpp中矩阵转置不能用.t()成员函数,需调用transpose()全局函数:
NumericMatrix M1 = transpose(inter1) * inter1 / n_squared; NumericMatrix M2 = transpose(inter2) * inter2 / n_squared;
3. 行55:未声明solve函数
需使用Rcpp::solve明确指定命名空间,避免编译报错:
substat[t] = n * crossprod(diff, Rcpp::solve(M1 + M2, diff));
4. 索引越界修正
原代码中计算的索引可能超出substat的有效范围,添加边界检查确保索引合法:
int lower_idx = std::max(0, (int)floor(n * eps)); int upper_idx = std::min(sublength - 1, (int)ceil(n * (1 - eps)) - 1);
5. 参数与返回值修正
原R函数中Quantile是向量,但Rcpp函数定义为double,需改为NumericVector,并在最后返回分位数结果(匹配原R函数逻辑)。
修复后的完整Rcpp代码
#include <Rcpp.h> using namespace Rcpp; // Helper function to extract a row slice from a NumericMatrix NumericVector extract_row_slice(const NumericMatrix& data, int row, int start, int end) { if (end >= data.ncol()) end = data.ncol() - 1; NumericVector slice(end - start + 1); for (int i = start; i <= end; i++) { slice[i - start] = data(row, i); } return slice; } // Main function to compute critical values // [[Rcpp::export]] NumericVector crit_val_cpp(int reps, int k, int n, NumericVector Quantile, double eps) { NumericVector W(reps); int sublength = n - 1; double n_squared = n * n; for (int j = 0; j < reps; j++) { NumericMatrix data(k, n, Rcpp::rnorm(n * k).begin()); NumericVector substat(sublength); NumericVector scale(sublength); // Precompute the scaling factor for each t for (int i = 0; i < sublength; i++) { scale[i] = (i + 1.0) * (sublength - i) / n_squared; } for (int t = 0; t < sublength; t++) { NumericVector mean1(k), mean2(k); // Calculate means for each segment for (int i = 0; i < k; i++) { mean1[i] = mean(extract_row_slice(data, i, 0, t)); mean2[i] = mean(extract_row_slice(data, i, t + 1, n - 1)); } // Calculate inter1 and inter2 NumericMatrix inter1(k, t + 1), inter2(k, n - t - 1); for (int h = 0; h < k; h++) { NumericVector temp1 = cumsum(extract_row_slice(data, h, 0, t)) - as<NumericVector>(seq_len(t + 1) - 1) * mean1[h]; NumericVector temp2 = cumsum(extract_row_slice(data, h, t + 1, n - 1)) - as<NumericVector>(seq_len(n - t - 1) - 1) * mean2[h]; std::copy(temp1.begin(), temp1.end(), inter1(h, _).begin()); std::copy(temp2.begin(), temp2.end(), inter2(h, _).begin()); } // Compute M1 and M2 matrices NumericMatrix M1 = transpose(inter1) * inter1 / n_squared; NumericMatrix M2 = transpose(inter2) * inter2 / n_squared; // Calculate substat[t] using the quadratic form NumericVector diff = scale[t] * (mean1 - mean2); substat[t] = n * crossprod(diff, Rcpp::solve(M1 + M2, diff)); } // Store the maximum of the substatistics adjusted for eps int lower_idx = std::max(0, (int)floor(n * eps)); int upper_idx = std::min(sublength - 1, (int)ceil(n * (1 - eps)) - 1); W[j] = max(abs(substat[Range(lower_idx, upper_idx)])); } // Return quantiles of W, matching R function behavior return quantile(W, Quantile); }
验证说明
修复后的函数可直接在R中调用,参数与原crit.val函数完全一致:
crit_val_cpp(reps=100, k=1, n=100, Quantile = c(0.9,0.95,0.99,0.995,0.999), eps=0.01)
运行结果与原R函数基本一致(因随机数生成差异,结果会有微小波动)。
内容的提问来源于stack exchange,提问作者user857222
相关产品推荐
相关产品推荐

