Symbolic Systems シンボリックシステムズ

組みこみ関数の使用

Mathematicaはver.7まできて、組み込み関数は性能向上は著しいものがある。関数によっては、任意精度(多倍長計算)でありながら、通常の計算ライブラリの速度に匹敵するものも存在する。自前でプログラム書く前に、まずは、すでに関数が存在するか確認することに時間を費やしても十分元がとれるはずである。

Do vs. Map

Mathemticaの世界へはFortranの世界から移ってきたユーザが多い。単に精度誤差がないというだけでMathematicaを使うのはもったない。

あまり複雑なことを考えなくとも、まずは、Do文(For文)をMapあるいはMapThreadに変えるだけで大幅な性能向上が得られる。以下には、そうした例をいくつか載せる。

(1)二次元配列の中から最大値を求める

2000*2000の整数乱数配列から最大値を探す。Doを使った普通の書き方では、約4.85秒時間がかかってる。一方、一度、二次元を一次元に平らにし(Flat)、そのリストから最大値を見つける関数Maxを使って求めた場合、約0.007秒。700倍の差がある。

一見、配列を平らにするような操作は無駄にみえるが、Mathematicaはこうした操作関数を最大限に最適化している。下記に示す他の例でもわかるように、全体を一度に操作するような関数、一見、遅そうに見える関数を使うと、実は、案外、効率いいことがわかる。

(2)リストの各要素に同じ関数を適用する

要素数10000のリストの各要素に対し関数f(未定義)を適用する。最初の例は、各要素を取り出し、関数fを適用し、再度、新しいリストをくみ上げている(AppendTo)。しかも、ここでは、副作用のないAppend関数ではなく、副作用あり(したがって速い)関数AppedToを使っている。それでも、約3秒の時間を要してる。

一方、Map関数を使った場合、約0.003秒。おおよそ1000倍の差が出る。

(3)配列要素に近傍の要素を加える

これは、配列プログラムの典型例である。この場合、自分自身{i,j}に対し、{i,j+1},{i+1,j},{i+1,j+1}番目の要素を加えてる。ただし、右下一行、一列分は被加算対象ではあるが、自分自身の値は使わないものとする。

1000*1000の整数配列で計算させて場合、通常の方法では約5秒。一方、{0,0},{0,1},{1,0},{1,1}だけずらしたこのサイズの配列を4枚用意し(RotateRight)、それらの要素をPlus関数で串刺しする(MapThread)方法をとった場合、約0.08秒。約60倍の性能差がでる。

しかも、ここでは、RotateRightの性質を考慮して、PadRightという関数で元配列の周囲に0を置くというオーバーヘッドを行っているにもかかわらず、これだけの性能差が生じた。

ここまでの実際の実行例はこちら

線形連立方程式

以下のような線形連立方程式

を解くのに、MathematicaではLinearSolve[]という関数を用いる。この関数は内部で内積計算を使っているため、内積計算を含むBLASライブラリーが加速されれば、結果的にLInearSolveも速くなる。

7000変数の連立方程式を例に、IntelMKLを使わなかった場合、16スレッドまで使った場合の 実行速度をプロットしたものが以下の図である。

16スレッドで約4倍の性能向上が見られる。

詳細は、こちらを参照のこと。

(c)2009.6 Symbolic Systems, Inc.