Claude CodeにPythonをRustに変えてもらった
はじめに
AtCoderのHeuristic Contestは気楽に書けるのでPythonで参加しているのだが、計算速度で有利なC++とかRustとか参加した方がいいのかな?と思うことがある。実際どのくらい違うのか、Claude Codeが流行っているっぽいので、自分で作ったPythonのコードをRustに変換してもらってみた。
Beam Searchのプログラム
今回はAHC049の問題を、Beam Searchで解いたコードを使った。271行のコードで、コンテスト時間内には間に合わなかったが100番台相当のスコアがでている。ファイルとしては1つなので、 ChatGPT にもお願いしてみると、何回かに分けてRustに変換してくれた。ただ、buildすると型の不一致のエラーが大量にでてきたのでそこで投げ出した。
Claude Codeで「@main.pyをRustに変換して」とお願いすると main.rs
と Cargo.toml
を出力した。次に「buildして」とお願いすると rustc
でコンパイルを開始、エラーがなくなるまで、修正とコンパイルを繰り返していた。「こんな修正したいけどいい?」と聞いてくるので、それを見ると借用でのエラーが多かったようである。
数回の修正確認が終わると「buildできたよ」と言ってきたので、サンプルの入力ファイルを使って動かしてみた。出力も問題なく、Python版の半分の時間で終わっていた。つまりビーム幅を広げることができるのだが、実はビーム幅を広げてもそんなにスコアが上がらない事は、Python版で実行時間を長くして確認済みである。
焼きなましのプログラム
Rustへの変換
速度が効いてくるのは焼きなましかなぁということで、上位のソースコードを参考にして、
焼きなましでの解法をPythonで作成した。コードの長さは173行で、こちらの方がすっきりしている。この段階で、自分で作ったBeams Searchよりも高い80番台相当のスコアをだした。
Claude Codeがmain.rs
と Cargo.toml
を出力したので、buildを依頼すると、今度は cargo
を使うことにしたらしく、 main.rs
を src
の下に移動させるなど、ディレクトリ構成を変えてきた。前と何が違ったのかはわからないが、気分屋なところがあるのだろうか?in
フォルダの下にあるサンプルの入力ファイルにも気づいたようで、buildが終わった後、そのファイルを使った試験まで提案してきた。賢い。
ただ、ここからが詰まってしまった。どうも実行時エラーが出ているらしく、入力読み込みのところの例外処理を一生懸命作成している。今回の入力は正しい入力なので、関係ないよな...と思いつつ手動で実行させてエラー箇所を確認すると、元のPythonファイルだと以下の場所でエラーがでていた。
path[src][src_idx], path[dst][dst_idx] = path[dst][dst_idx], path[src][src_idx]
よくあるswap処理で、path[src][src_idx]
とpath[dst][dst_idx]
を入れ替えている。何故かここをClaude Codeは、それぞれのリスト上の値を入れ替える処理に変換していた。
path[src].swap(src_idx, dst_idx);
path[dst].swap(dst_idx, src_idx);
手作業で修正しても大したことがない場所であるが、Claude Codeを試す意味をこめて、「150行目はリストそれぞれで値を入れ替えるのではなくて、path[src]とpath[dst]の要素を入れ替えるんだよ」と教えてみた。すると、以下のような正しいコードを提示してきた。
let temp = path[src][src_idx]
path[src][src_idx] = path[dst][dst_idx]
path[dst][dst_idx] = temp
人間相手だとしても「伝わるかな?」という気がしたが、きちんと理解してくれたらしい。また、近傍を導出する場所なので、巻き戻しで逆の処理をしているコードもあるのだが、そこも忘れずに修正してきた。賢い。指摘されたのが人間の場合は、Pythonのコードを読み直して間違いに気づいて修正するかと思うが、そのようにしたのか、指摘だけで修正したのかは不明である。
計算処理の最適化
それでは、Rustに変換してどのくらい速くなったのか確認するために、試行回数をカウントしてみた。結果は、Python版が約92万回なのに対して、Rust版は約52万回。Pythonの方が性能が良い...だめじゃん。
このままだとPythonがいいという結論になってしまうので、「計算処理時間を短くする方法を考えて」とClaudeに投げてみた。すると以下の方針と修正案が提示された。
- 焼きなましの温度の更新頻度を減らす
- 時刻取得回数が減るので、処理は軽くなりそうな気はする
- 距離の計算結果を事前計算しておく
- この問題では荷物間距離を使うが、この距離はマンハッタン処理なので、ただの足し算である。このため、あまり変わらない気はする。
どうかなぁ..と思いつつEnterを押して修正案を了承していると、「これで大きく減るはずだよ」と言って修正が完了した。特に距離計算の軽量化が効くはずと主張している。本当か?と思いつつサンプルの入力ファイルを使って動かしてみると約52万回。変わってない…。
修正完了時に、「他にもこんな方法があると思うよ」と言っていくつか方針もだしてきていた。その中でよさそうな「乱数生成を軽量なものに変更する」の実装をお願いしてみた。thread_rng
ではなく、SmallRng
を使う方法を提案してきた。修正案を了承した後、「buildしてみて」と言うと、Cargo.toml
の features への追加を忘れていてコンパイルできていなかった。ちょっと抜けているところが、人間くさいとこを感じてしまう。Claude Codeに修正してもらって動かすと、試行回数は386万回になった。結構速くなった。
おわりに
そんな感じで、Claude Codeで遊んでみた。動くコードという、確実な「仕様」を渡せているからかも知れないが、かなり良いコードを出してくれた。今回すべての修正を目視していたが、勝手にやってもらっても問題なさそうだった。機械だから当然かも知れないが、Pythonの random.randint(a,b)
はb
を含むとか間違いやすいところもきちんと変換していた。
一方でエラー修正ではまったり、最適化がちょっといまいちだったりする面もある。少し気になったのは、Pythonのコードで荷物の重さなどを保持するクラスBox
を使っていた。一方でRustにはヒープ上のデータを指すBox<T>
があり、紛らわしい。ChatGPTはBoxItem
へのクラス名の変更を提案してくれて、すごいなぁと思っていたが、Claude Codeはそのまま使っていた。何らかの理由でBox
をimport
する必要があれば提案してくるかもではあるが。
最近のLLM系AIを触ると少し人間っぽさを感じてしまうのはすごいと思う。今回は、「仕事は速いがちょっと抜けている生徒」という感触を持った。近いうちに完璧になってしまい、人間っぽさを感じなくなるのかも知れないが。そもそもの目的であった、今後Heuristic ContestにRustで参加するかは...Pythonが楽な面もあるので、ゆっくり考えたい。
Discussion