Mathematica におけるコンパイラの効用

はじめに

Mathematica にコンパイル機能があることは昔からよく知られていますが、いま一つ使い方がわからず、あまり利用されていません。本稿では具体的な例 https://reference.wolfram.com/language/ref/Compile.html.ja 内[おもしろい例題]を参考に、コンパイルすると高速化 (この例の場合は約30倍に高速化) されることを示します。

基本事項の確認

コンパイラを知らない人はいないと思いますが、コンパイルの基本がメモリ参照を CPU 内メモリ (普通はレジスタ) に切り替えると理解している方は少ないかもしれません。メモリアクセス速度を低い順に並べると

ファイル << メインメモリ < CPUレジスタ

となります。Mathematica は通常、インタプリタとして機能し、変数が登場するたびにメインメモリへのアクセスが発生します。これに対し、コンパイラは変数を CPU レジスタに割り付けるために、参照速度が上がります。

なおコンパイルにおいて当該データが何バイト使用するか事前に知る必要があり、Mathematica のコンパイル関数 Compile では引数に必ず型を加えます。たとえば、{x,_Real} 「引数 xの型は実数」はその例です。

したがってコンパイルの対象変数は実行時、整数や実数等の数値でなければなりません。ただし、それらの変数が Sin 等の組み込み関数の引数あるいはリスト構造の一部であっても、コンパイルの効果はあります。

コンパイル関数 Compile の使い方

Sin[x] + x^2 - 1/(1+x) を本体に持つ関数 cf を定義します。

この関数の本体部分をコンパイルするには引数部分 {{x,_Real}} (二重括弧は複数の引数を想定) を含め、本体を Compile で囲みます。結果の CompileFunciton が代入された変数 cf は通常の関数名として使用できます:8cf[Pi] 。なお、引数が数値を仮定しているため、シンボル PiN によって強制的に数値化する必要はありません。

ここでコンパイルの効果をみるために、かなり不自然な関数 (同じ計算を100万回 繰り返す) を定義します。現在、Mathematica の Do 関数はかなり最適化されていますが、それでもコンパイルするのとしないとでは約10倍の速度差が出ることがわかります。

実例

以下の各小節に「原コード」と「コンパイル化コード」を挙げますが、その前に関数引数部分に関し、コンパイル化前と後の比較を行います。なお With は一時的な値を設定するのに使用し、Block のように内部の変数を局所化しません。つまり With 内で関数は大域的に定義されます。

比較1.

比較2.

比較3.

比較4.

比較5.

比較4.比較5.ではコンパイラオプション

が指定されています。

CompilationTarget はデフォルトでは C コードを想定します。ただし signedNoise のように計算よりリスト処理が中心の場合、Mathematica の仮想マシン用コード WVM を指定し、高速化します。

InlineExternalDefinitions を指定した場合、signedNoise 内で使用される外部関数 (たとえば dot 等) がインライン展開され、コンパイルされます。これによりコンパイルコードは長くなりますが、関数呼び出しが減る分、処理時間は高速化されます。

原コード

コンパイル化コード