💭

C++ ライブラリ libsparseir の開発記録(C++への移植編)

に公開

前置き

この記事は sparse-ir と呼ばれる Python, Julia で書かれたライブラリを C++ に移植した libsparseir の開発で得た知見を共有するために執筆されました.

sparse-ir に関して

sparse-ir は有限温度の量子多体系計算で使用される虚時間プロパゲーター(グリーン関数など)を効率的に処理するためのライブラリです.詳細は例えば下記の文献を参照してください.

本記事では物理学に関する解説は一切せず,sparse-ir を単に計算物理に関するソフトウェアとしてみなします.

作業・移植の背景

C++ への移植の動機は以下のようなものだったと記憶しています.

  • 独立に存在している既存の Python 実装 sparse-ir,Julia 実装 SparseIR.jl を両方メンテナンスするコストを下げる
  • Fortran ユーザ,C++ ユーザへの対応
  • 別の C++ ライブラリとの連携

本記事では C++ への移植の是非については議論しません.また,特定の言語から C++ への移行を積極的に提案するものではありません. 結果論ではありますが,C++に移行しさまざまな言語に対してサポートすることは多くの工数と覚悟・辛さが必要ということが実感できました.

例えば Hiroshi Shinaoka さんによる C++を使った数値計算ライブラリの整備で辛かったこと がとても参考になります.

作業開始

執筆者は Hiroshi Shinaoka さん(以下,品岡さん)の指示のもと Slack または Element (というチャットツール)でコミュニケーションを取りながら C++ への移植の作業を進めました.

作業は今の1年前(2024 年の10月ごろ)から始まりました.週に1日(急いでいる時は2日)ほどの工数使って作業を進めました.大雑把に下記の取り決めで移植を始めました.

  • 移植元のコードベースは SparseIR.jl の v1 系
  • C++11 の規格でコンパイルできること
  • ヘッダーオンリーで開発
  • 行列・線形代数に関するライブラリは Eigen を使う

ヘッダーオンリーにする理由は libsparseir が依存している C++11 library for double-double tuwien-cms/libxprec と同様にHeader-only modeで配布できたら嬉しいよねというモチベーションがあった気がします.ただ,機能をつけるにつれてコンパイルの時間がどんどん増えていったのでヘッダーオンリーにする案は消えていきました.

Julia から C++ への移植の方針

Julia パッケージ SparseIR.jl はいくつかの .jl ファイルを順番にインクルードする構成になっています:

"""
Intermediate representation (IR) for many-body propagators.
"""
module SparseIR

# <中略>

include("_linalg.jl")
include("_roots.jl")
include("_specfuncs.jl")
using ._LinAlg: tsvd

include("freq.jl")
include("abstract.jl")
include("svd.jl")
include("gauss.jl")
include("poly.jl")
include("kernel.jl")
include("sve.jl")
include("basis.jl")
include("augment.jl")
include("sampling.jl")
include("dlr.jl")
include("basis_set.jl")

# <中略>

end # module

原理的には,移植の際には,対応する .jl ファイルを .hpp にしてその中身を順番に移植していけば完成することになります.概ねそのようになりました.後述しますが,SparseIR.jl は単体テストが充実しており,実装の src/xxx.jl に対応する test/xxx.jl があるのでそれも移植を進めるにあたって役に立ちました.

GitHub Issue, GitHub Actions を使った開発

GitHub Issue を使って開発を進めました. xxx.jl を移植する という Issue を立てて,それに対するPR(Pull Request)を作り作業をしました.PR のコメントで closes #<Issue 番号> とコメントしておくとPRがマージされたら対応する Issue がクローズされます.わざわざいうほどでもないかもしれませんが,計算物理学の文脈だと Git/GitHub を使った開発はまだ浸透していないように見受けられたので書いておきました.また,PR が発行した時に,GitHub Actions による自動テストを実施し,テストが通ったら自動マージするようにしていました.

Cursor によるコーディング支援

近年ではLLM(大規模言語モデル)を用いたコーディングが盛んですが,libsparseir も実はその流行に乗っかって開発を進めていました.2024 年当時は Cursor というのがあるらしいという空気感でした.コードベースは学術的なものであること,SparseIR.jl 自体がすでに公開されている状態のものでしたので,機密情報を学習されるというようなリスクを考える必要はありませんでした.この機会に使ってみよう・なるべくサボろう楽をしようということで Cursor を導入しました.Cursor はコードの補完が優秀で今でも愛用しています.また,コンパイルエラーが出ればエラーメッセージをChatに貼り付けて相談する機能がC++での開発に役に立ちました.

Cursor 上で移植に使ったプロンプトは比較的シンプルで "<test/ファイル名.jl> を移植して" のようにしてテストコードを移植させました.そのあと,ロジックが入っている "src/ファイル名.jlを移植して" で移植させました.もちろん手動でコードを書くこともしました.

C++ で辛いのはコンパイルエラーの読解です.テンプレート関係のエラーは読み解くのが大変です.CursorにはエラーメッセージをChatに貼り付ける機能がありますのでその機能を使ってひたすらコンパイルが通るまで,「直せ」だの「助けて」だのを繰り返し対話しました.おかげで(?)EigenのTensor の使い方やshared_ptr の活用, CMakeLists.txt の書くためには大変重宝しました.

モデルは Claude-3-5-Sonnet を使っていました.また ChatGPT の o1 をAPIキーを使って叩くこともしていました.普段は前者を使っており,どうしてもコンパイルできず困った時に o1 を使っていました.また,試験的に Web アプリの ChatGPT 上でもコードを生成させてました.プロンプトに使うコードを貼り付けるために https://uithub.com/ というサービスを利用しました.これは GitHub で管理しているソースファイルをシンプルなテキストにしてくれるサービスで githubgu に置換すれば利用できるようになっています.当時はこれにお世話になっていました.

なんだかんだで(予定していた期間の)半年ほど経って,C++ 実装を作ることができました.むしろ Cursor のおかげで予定していた期間で作れました.LLM の支援がなかったら C++ が苦手だった執筆者は途方に暮れてたことは間違いありません.また,元実装に単体テストがあったことも大きかったです.幸い,sparse-ir のアルゴリズムには乱数に依存するものはなく,決定的でした.Julia のコードから出た数値結果と C++ のそれを比較することで,物理学に対する知見が浅い執筆者でも,デバッグすることができました.テストがある,それは偉大なり.

余談ですが,Cursor, Claude Code などのサービスを使ってるとコンパイル,テストを通すために,当該のエラーを引き起こす実装を削ることがあります.削ったことを忘れて作業できた!と報告する時がちらほらあるので注意してください.

Q: 人間はいらないのか? A: 要る.

人間がいらないかというとそういうわけでもなく,複雑で込み入ったアルゴリズムの実装,セグメンテーションフォルトによる実行時エラーの解決,計算ロジックの最適化には人間同士の議論で解決する必要がありました.C++ のスキルは品岡さんの方が上なのでエラーの解決の上でとても助かりました.議論の多くは非同期のチャットで行いました.現代的なソフトウェア開発の手法の導入に積極的な姿勢も互いのコミュニケーションを進める上で役に立っていると感じています.

2025 年現在,別プロジェクトで C から Julia, Rust への vibe coding をさせてます.AI は複雑なコードの読解は得意で外堀を埋めるのは得意です.一方で,内部である重要な計算物理特有の細かい実装まで含めた移植は機械的に難しいと感じています.ある種のハミルトニアンの実装をするタスクは結構サボってしまいます.ドメイン知識を持っている人(=ここでは物理をわかっている人)の存在は必須だと考えます.これは見方を変えるとコーディングが得意じゃなくてもLLMの力を借りれば研究者の生産性は大きく向上すると言えるでしょう.まだ,AIエージェントを触ったことがない方はこの機会に是非試してみてはいかがでしょうか.

Discussion