Agent-almanac add-rcpp-integration
install
source · Clone the upstream repo
git clone https://github.com/pjt222/agent-almanac
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/ja/skills/add-rcpp-integration" ~/.claude/skills/pjt222-agent-almanac-add-rcpp-integration-510b4a && rm -rf "$T"
manifest:
i18n/ja/skills/add-rcpp-integration/SKILL.mdsource content
Rcpp統合の追加
パフォーマンスが重要な処理にRcppを使用してRパッケージにC++コードを統合する。
使用タイミング
- プロファイリングでボトルネックが確認されたR関数が遅すぎる時
- 既存のC/C++ライブラリとのインターフェースが必要な時
- コンパイル済みコードが有利なアルゴリズムを実装する時(ループ、再帰)
- 線形代数演算にRcppArmadilloを追加する時
入力
- 必須: 既存のRパッケージ
- 必須: C++で置き換えるまたは補完するR関数
- 任意: インターフェースする外部C++ライブラリ
- 任意: RcppArmadilloを使用するかどうか(デフォルト:プレーンRcpp)
手順
ステップ1: Rcppインフラのセットアップ
usethis::use_rcpp()
これにより:
ディレクトリが作成されるsrc/- DESCRIPTIONのLinkingToとImportsに
が追加されるRcpp
にR/packagename-package.R
と@useDynLib
が作成される@importFrom Rcpp sourceCpp- コンパイル済みファイル用に
が更新される.gitignore
RcppArmadilloの場合:
usethis::use_rcpp_armadillo()
期待結果:
src/ディレクトリが作成される。DESCRIPTIONのLinkingToとImportsにRcppが追加される。R/packagename-package.Rに@useDynLibディレクティブが含まれる。
失敗時:
usethis::use_rcpp()が失敗する場合、手動でsrc/を作成し、DESCRIPTIONにLinkingTo: RcppとImports: Rcppを追加し、パッケージレベルのドキュメントファイルに#' @useDynLib packagename, .registration = TRUEと#' @importFrom Rcpp sourceCppを追加する。
ステップ2: C++関数の記述
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; }
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; }
期待結果:
src/my_function.cppに有効な// [[Rcpp::export]]アノテーションとroxygen形式の//'ドキュメントコメントを持つC++ソースファイルが存在する。
失敗時: ファイルが
#include <Rcpp.h>(Armadilloの場合は<RcppArmadillo.h>)を使用していること、エクスポートアノテーションが関数シグネチャの直上の独立した行にあること、戻り値の型が有効なRcpp型にマップされることを確認する。
ステップ3: RcppExportsの生成
Rcpp::compileAttributes() devtools::document()
期待結果:
R/RcppExports.Rとsrc/RcppExports.cppが自動的に生成される。
失敗時: C++の構文エラーを確認する。エクスポートされる各関数の上に
// [[Rcpp::export]]タグが存在することを確認する。
ステップ4: コンパイルの確認
devtools::load_all()
期待結果: パッケージがエラーなくコンパイルされて読み込まれる。
失敗時: コンパイラ出力のエラーを確認する。一般的な問題:
- システムヘッダの欠如:開発ライブラリをインストールする
- 構文エラー:C++コンパイラのメッセージが行を指示する
- RcppArmadilloの
属性の欠如Rcpp::depends
ステップ5: コンパイル済みコードのテスト
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_)) })
期待結果: テストがパスし、C++関数がR相当の結果と同一の結果を生成し、エッジケース(空のベクトル、NA値)を正しく処理することが確認される。
失敗時: NAの処理でテストが失敗する場合、C++コードで
NumericVector::is_na()を使用した明示的なNAチェックを追加する。空の入力でテストが失敗する場合、関数の先頭にゼロ長ベクトルに対するガード条件を追加する。
ステップ6: クリーンアップスクリプトの追加
src/Makevarsを作成する:
PKG_CXXFLAGS = -O2
パッケージルートに
cleanupを作成する(CRAN用):
#!/bin/sh rm -f src/*.o src/*.so src/*.dll
実行可能にする:
chmod +x cleanup
期待結果:
src/Makevarsがコンパイラフラグを設定し、cleanupスクリプトがコンパイル済みオブジェクトを削除する。両ファイルがパッケージルートレベルに存在する。
失敗時:
cleanupに実行権限があることを確認する(chmod +x cleanup)。Makefileスタイルのルールを追加する場合、Makevarsがインデントにスペースではなくタブを使用していることを確認する。
ステップ7: .Rbuildignoreの更新
コンパイル済みアーティファクトが処理されていることを確認する:
^src/.*\.o$ ^src/.*\.so$ ^src/.*\.dll$
期待結果:
.Rbuildignoreパターンが、ソースファイルとMakevarsを保持しながら、パッケージtarballにコンパイル済みオブジェクトファイルが含まれないようにする。
失敗時:
devtools::check()を実行してsrc/内の予期しないファイルに関するNOTEを確認する。.o、.so、.dllファイルのみを除外するように.Rbuildignoreパターンを調整する。
バリデーション
-
が警告なくコンパイルされるdevtools::load_all() - コンパイル済み関数が正しい結果を生成する
- エッジケースのテストがパスする(NA、空の入力、大きな入力)
-
がコンパイル警告なしでパスするR CMD check - RcppExportsファイルが生成されてコミットされている
- ベンチマークでパフォーマンス向上が確認される
よくある落とし穴
の忘れ: C++ファイルを変更した後はRcppExportsを再生成しなければならないcompileAttributes()- 整数オーバーフロー: 大きな数値には
ではなくint
を使用するdouble - メモリ管理: RcppはRcpp型のメモリを自動的に処理する;手動で
しないことdelete - NAの処理: C++はRのNAを認識しない。
でチェックするRcpp::NumericVector::is_na() - プラットフォームの移植性: プラットフォーム固有のC++機能を避ける。Windows、macOS、Linuxでテストする
の欠如: パッケージレベルのドキュメントには@useDynLib
が必要@useDynLib packagename, .registration = TRUE
関連スキル
- Rcpp追加前のパッケージセットアップcreate-r-package
- コンパイル済み関数のテストwrite-testthat-tests
- CIにはC++ツールチェーンが必要setup-github-actions-ci
- コンパイル済みパッケージはCRANの追加チェックが必要submit-to-cran