Agent-almanac add-rcpp-integration
git clone https://github.com/pjt222/agent-almanac
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/es/skills/add-rcpp-integration" ~/.claude/skills/pjt222-agent-almanac-add-rcpp-integration-47a21e && rm -rf "$T"
i18n/es/skills/add-rcpp-integration/SKILL.mdAñadir Integración con Rcpp
Integrar código C++ en un paquete R usando Rcpp para operaciones críticas de rendimiento.
Cuándo Usar
- La función R es demasiado lenta y la elaboración de perfiles confirma un cuello de botella
- Se necesita interactuar con bibliotecas C/C++ existentes
- Implementar algoritmos que se benefician del código compilado (bucles, recursión)
- Añadir RcppArmadillo para operaciones de álgebra lineal
Entradas
- Obligatorio: Paquete R existente
- Obligatorio: Función R a reemplazar o complementar con C++
- Opcional: Biblioteca C++ externa con la que interactuar
- Opcional: Si usar RcppArmadillo (predeterminado: Rcpp simple)
Procedimiento
Paso 1: Configurar la Infraestructura de Rcpp
usethis::use_rcpp()
Esto:
- Crea el directorio
src/ - Añade
a LinkingTo e Imports en DESCRIPTIONRcpp - Crea
conR/packagename-package.R
y@useDynLib@importFrom Rcpp sourceCpp - Actualiza
para los archivos compilados.gitignore
Para RcppArmadillo:
usethis::use_rcpp_armadillo()
Esperado: Directorio
src/ creado, DESCRIPTION actualizado con Rcpp en LinkingTo e Imports, y R/packagename-package.R contiene la directiva @useDynLib.
En caso de fallo: Si
usethis::use_rcpp() falla, crear manualmente src/, añadir LinkingTo: Rcpp e Imports: Rcpp a DESCRIPTION, y añadir #' @useDynLib packagename, .registration = TRUE y #' @importFrom Rcpp sourceCpp al archivo de documentación a nivel de paquete.
Paso 2: Escribir la Función C++
Crear
src/my_function.cpp:
#include <Rcpp.h> using namespace Rcpp; //' Compute cumulative sum efficiently //' //' @param x A numeric vector //' @return A numeric vector of cumulative sums //' @export // [[Rcpp::export]] NumericVector cumsum_cpp(NumericVector x) { int n = x.size(); NumericVector out(n); out[0] = x[0]; for (int i = 1; i < n; i++) { out[i] = out[i - 1] + x[i]; } return out; }
Para RcppArmadillo:
#include <RcppArmadillo.h> // [[Rcpp::depends(RcppArmadillo)]] //' Matrix multiplication using Armadillo //' //' @param A A numeric matrix //' @param B A numeric matrix //' @return The matrix product A * B //' @export // [[Rcpp::export]] arma::mat mat_mult(const arma::mat& A, const arma::mat& B) { return A * B; }
Esperado: Archivo fuente C++ en
src/my_function.cpp con anotación // [[Rcpp::export]] válida y comentarios de documentación estilo roxygen //'.
En caso de fallo: Verificar que el archivo usa
#include <Rcpp.h> (o <RcppArmadillo.h> para Armadillo), que la anotación de exportación está en su propia línea directamente encima de la firma de la función, y que los tipos de retorno se corresponden con tipos válidos de Rcpp.
Paso 3: Generar RcppExports
Rcpp::compileAttributes() devtools::document()
Esperado:
R/RcppExports.R y src/RcppExports.cpp generados automáticamente.
En caso de fallo: Revisar los errores de sintaxis C++. Asegurarse de que la etiqueta
// [[Rcpp::export]] está presente encima de cada función exportada.
Paso 4: Verificar la Compilación
devtools::load_all()
Esperado: El paquete compila y carga sin errores.
En caso de fallo: Revisar la salida del compilador para detectar errores. Problemas frecuentes:
- Cabeceras de sistema faltantes: Instalar las bibliotecas de desarrollo
- Errores de sintaxis: Los mensajes del compilador C++ apuntan a la línea
- Falta el atributo
para RcppArmadilloRcpp::depends
Paso 5: Escribir Pruebas para el Código Compilado
test_that("cumsum_cpp matches base R", { x <- c(1, 2, 3, 4, 5) expect_equal(cumsum_cpp(x), cumsum(x)) }) test_that("cumsum_cpp handles edge cases", { expect_equal(cumsum_cpp(numeric(0)), numeric(0)) expect_equal(cumsum_cpp(c(NA_real_, 1)), c(NA_real_, NA_real_)) })
Esperado: Las pruebas pasan, confirmando que la función C++ produce resultados idénticos al equivalente R y gestiona los casos límite (vectores vacíos, valores NA) correctamente.
En caso de fallo: Si las pruebas fallan con la gestión de NA, añadir comprobaciones explícitas de NA en el código C++ usando
NumericVector::is_na(). Si las pruebas fallan con entrada vacía, añadir una cláusula de guarda para vectores de longitud cero al inicio de la función.
Paso 6: Añadir Script de Limpieza
Crear
src/Makevars:
PKG_CXXFLAGS = -O2
Crear
cleanup en la raíz del paquete (para CRAN):
#!/bin/sh rm -f src/*.o src/*.so src/*.dll
Hacer ejecutable:
chmod +x cleanup
Esperado:
src/Makevars establece los indicadores del compilador y el script cleanup elimina los objetos compilados. Ambos archivos existen en el nivel raíz del paquete.
En caso de fallo: Verificar que
cleanup tiene permisos de ejecución (chmod +x cleanup) y que Makevars usa tabulaciones (no espacios) para la sangría si se añaden reglas estilo Makefile.
Paso 7: Actualizar .Rbuildignore
Asegurarse de que los artefactos compilados se gestionan correctamente:
^src/.*\.o$ ^src/.*\.so$ ^src/.*\.dll$
Esperado: Los patrones de
.Rbuildignore evitan que los archivos objeto compilados se incluyan en el tarball del paquete, preservando los archivos fuente y Makevars.
En caso de fallo: Ejecutar
devtools::check() y buscar NOTEs sobre archivos inesperados en src/. Ajustar los patrones de .Rbuildignore para excluir solo los archivos .o, .so y .dll.
Validación
-
compila sin advertenciasdevtools::load_all() - La función compilada produce resultados correctos
- Las pruebas pasan para casos límite (NA, vacío, entradas grandes)
-
pasa sin advertencias de compilaciónR CMD check - Los archivos RcppExports están generados y confirmados
- La mejora de rendimiento se confirma con benchmarks
Errores Comunes
- Olvidar
: Hay que regenerar RcppExports tras modificar archivos C++compileAttributes() - Desbordamiento de enteros: Usar
en lugar dedouble
para valores numéricos grandesint - Gestión de memoria: Rcpp gestiona la memoria automáticamente para los tipos Rcpp; no usar
manualmentedelete - Gestión de NA: C++ no conoce los NA de R. Comprobar con
Rcpp::NumericVector::is_na() - Portabilidad entre plataformas: Evitar características C++ específicas de una plataforma. Probar en Windows, macOS y Linux.
- Falta
: La documentación a nivel de paquete debe incluir@useDynLib@useDynLib packagename, .registration = TRUE
Habilidades Relacionadas
- configuración del paquete antes de añadir Rcppcreate-r-package
- probar las funciones compiladaswrite-testthat-tests
- CI debe tener la cadena de herramientas C++setup-github-actions-ci
- los paquetes compilados necesitan verificaciones adicionales de CRANsubmit-to-cran