なぜRustを用いるのか
従来、計算物理学の分野では、Fortran、C/C++、Python、Julia、MATLABといったプログラミング言語が広く利用されてきました。これらの言語にはそれぞれ長所があり、特にPythonは科学技術計算におけるエコシステムが非常に充実しています。
AI agent を用いてコードの作成や修正を補助する時代には、言語選択の基準が少し変わります。人間がすべてのコードを手で書きやすいかだけでなく、人間が読みやすいか、生成されたコードを検査しやすいか、誤った変更をコンパイラやテストで早く止められるかが重要になります。
本書でRustを採用する理由は、AI agent がRustコードを常に正しく生成できるからではありません。むしろ、Rustの型システム、所有権、借用、明示的な可変性、Cargo、cargo testが、生成されたコードを検査するための強い足場になるからです。
AI agent 時代におけるRustの利点
1. 生成コードをコンパイラで制約できる
計算物理のコードでは、配列、状態変数、乱数生成器、作業用バッファ、出力データなど、多くのデータを扱います。これらのデータをいつ変更してよいのか、どこで共有してよいのかが曖昧になると、非常に追跡しにくいバグが生じます。
C/C++では、aliasing、メモリの寿命、可変な共有、データ競合に起因する問題が、実行時のまれな条件で初めて現れることがあります。Rustでは、所有権、借用、ライフタイム、Send / Sync などの仕組みにより、この種の問題の多くをコンパイル時に検査できます。
これは、AI agent が生成したコードを無制限に信用するのではなく、コンパイラとテストによるハーネスの中で扱うという意味で重要です。cargo checkで型や借用の問題を早く見つけ、cargo testで小さい計算部品を検証し、git diffで変更内容を確認する、という流れを作りやすくなります。
ただし、コンパイルが通ることは、物理的・数値的に正しいことを意味しません。数式、単位、境界条件、刻み幅、乱数 seed、保存量、収束性などは、読者自身が問題設定に立ち返って検証する必要があります。
2. 見た目の複雑さはレビュー不能性ではない
Rustのコードは、PythonやJuliaのコードに比べて複雑に見えることがあります。型、参照、mut、Result、エラー処理、モジュール境界など、数値計算の式そのもの以外の記述が多いためです。
しかし、その多くはコンパイラに渡す制約や、コードの意図を明示するための情報です。ロジックを追うときは、まず物理量の更新、ループ、境界条件、保存する値に注目し、型注釈やエラー処理の定型部分を一旦脇に置くことができます。むしろ、どの値が可変か、どこで所有権が移るか、どの失敗を扱うかが明示されているため、曖昧なコードよりもレビューしやすい場面があります。
AI agent を使う場合は、レビューの補助も依頼できます。例えば、「この関数を疑似コードにして」「物理量の更新ロジックだけを抜き出して」「この Result はどの失敗を表しているか説明して」と指示すれば、Rust特有の記述とアルゴリズム本体を分けて確認できます。
3. 学習コストの意味が変わる
Rustは、学習コストが高い言語として知られてきました。所有権、借用、ライフタイム、トレイトなどは、他の多くの手続き型言語にはない概念です。従来は、細かい記法やコンパイラエラーへの対応そのものが、Rustを使う上で大きな負担になりがちでした。
しかし、AI agent を用いる開発では、コードを最初から最後まで人間が手で書くことだけが中心ではありません。定型的な構造、入出力、テストの雛形、エラー処理、モジュール分割などは、AI agent に任せることができます。その分、人間は、物理モデル、数値計算法、境界条件、検証方法、結果の解釈に集中しやすくなります。
このとき、Rustの厳しさは単なる欠点ではなくなります。コンパイラが細かい誤りを指摘し、AI agent が修正案を出し、人間が物理・数値計算として妥当かを判断する、という分担が作りやすいからです。
4. エコシステム不足の見方も変わる
Pythonの科学計算エコシステムは、NumPy、SciPy、Matplotlib、pandasなどを中心に非常に成熟しています。一方、Rustの科学技術計算エコシステムは発展途上であり、特定の数値計算アルゴリズムや専門分野に特化したクレートが存在しない場合もあります。
これは現実的な課題です。ただし、AI agent を用いると、薄い wrapper、入出力コード、テスト、保存済みデータからのプロットなどは、以前よりも短い時間で用意しやすくなります。すべての機能が既にクレートとして揃っているからRustを使うのではなく、不足している部分を検査可能な形で補いやすいことが重要になります。
従来の言語との関係
Rustは、既存の言語をすべて置き換えるものではありません。目的に応じて、以下のような違いがあります。
- Fortran:数値計算やHPCの分野で長い実績があり、既存の数値ライブラリ資産に強みがあります。一方で、テンソルネットワークのように複雑なデータ構造、抽象化、テスト分割、依存関係管理を伴うアルゴリズムでは、設計や保守の負担が大きくなりやすい面があります。
- C/C++:高速な実行が可能で、既存資産も豊富です。一方で、メモリ管理、aliasing、未定義動作、データ競合などの問題をプログラマが慎重に管理する必要があります。
- Python:探索的な解析、可視化、既存ライブラリの利用に非常に強い言語です。一方、言語単体の実行速度や静的検査には限界があり、高速化が必要な箇所はC、Fortran、Rustなどで実装された外部ライブラリに依存することが多くなります。
- Julia:高水準な記述と高い実行性能を両立しようとする言語で、数値計算のプロトタイピングにも適しています。一方、Rustのように所有権や借用を用いてメモリ共有やデータ競合をコンパイル時に厳密に制約する設計ではありません。
本書では、Rustを「最も簡単に書ける言語」としてではなく、計算コードを安全に育て、AI agent の出力を検査し、再現可能な形で残しやすい言語として扱います。
Rustの具体的な強み
安全性とパフォーマンスの両立
Rustは、所有権システムによりコンパイル時にメモリ安全性を保証しつつ、C/C++に近い実行性能を目指せる言語です。ガベージコレクタに依存しないため、実行中の予期しにくい停止を避けやすく、長時間実行する計算や性能が重要な計算に向いています。
データ競合のない並列処理
現代の計算物理学では、マルチコアCPUやGPUといった並列計算資源の活用が重要です。Rustの型システムは、スレッド間で共有してよいデータと共有してはいけないデータをコンパイル時に検査します。
例えば、データ並列ライブラリであるRayonを利用すると、イテレータを並列化しながら、データ競合を起こしにくい形でコードを書くことができます。
Cargoによる再現可能な開発環境
Rustでは、cargo newによるプロジェクト作成、cargo addによる依存関係の追加、cargo buildによるビルド、cargo testによるテスト実行といった一連の作業が、cargoという単一のツールで完結します。
科学技術計算では、どの依存関係で、どの入力条件で、どのコードを実行したのかを後から確認できることが重要です。Cargo.tomlとCargo.lockにより依存関係を管理し、テストと実行コマンドを残すことで、計算の再現性を高められます。
他言語との連携
Rustからは、Fortran、C、C++で実装された既存の数値計算ライブラリを呼び出すこともできます。過去の資産をすべて捨てるのではなく、必要に応じて利用できる点も実用上の利点です。
使い分け
Rustにも向き不向きはあります。学習コストは依然として存在しますし、Pythonほど科学計算ライブラリが網羅的に揃っているわけではありません。
本書では、Rustで計算を行い、表形式データはCSV、多次元配列や大きなデータはHDF5やNumPy形式、実行条件はmetadataとして保存し、プロットは保存済みデータから作成する流れを基本にします。この方法では、入力パラメータ、乱数 seed、実行条件、出力ファイルを明示的に残せるため、結果の再現性や検証がしやすくなります。入出力やプロット用の定型的なコードは、AI agent に自然言語で指示して任せることができます。
迅速なデータ分析、使い捨てのスクリプト、既存Pythonライブラリに強く依存した解析では、PythonやJuliaを使う方が自然な場合もあります。一方でRustは、長時間実行する計算、性能やメモリ効率が重要な計算、並列化したい計算、長期的に保守したい計算コードで特に有用です。
まとめ
Rustは、安全性、パフォーマンス、並列処理、再現可能な開発環境という点で、計算物理学にとって魅力的な選択肢です。AI agent 時代には、さらに、生成コードをコンパイラとテストのハーネスの中で扱えることが重要になります。
AI agent は、コードを速く書く助けにはなりますが、物理的・数値的な正しさを自動的に保証するものではありません。本書では、Rustの厳密な仕組みを利用しながら、読者自身が問題設定、実装、検証、結果の解釈を行えるようになることを目指します。