そうだPythonを勉強したいのだ(Pure Python List編)

http://d.hatena.ne.jp/yukichanko/20110216/1297900684

の続きです。Cで書いた(と言うか、前からあった)ので、次はPython化します。

ここでは、PythonのPureリストを使って実装して、次回、NumPy化します。

よしっ、んでは、Pythonらしくプログラミングするか。。。。(10秒後)。。。マンドクセー。
EmacsでCtrl-3。左にCのコード、右にPythonのコードを置いて、1対1対応にしましたw

以下、CじゃなくてPythonだったから簡単だったこと、を書いていきます。

リストの初期化が楽

Cだと何げに面倒臭い。

void set_delta(double* dx) {
  int i;
  for (i = 0; i < NX; i++) dx[i] = DX;
}

と言うのを、Pythonだと

dx = [Const.DX] * Const.NX

と1行で書ける。この辺の簡潔さは、LL最高ーと言いたくなる。

後は。。。とコードを見なおしたけど、特にPythonらしいところがなかった。数値解析の場合、Cでも十分に簡潔に書けますからね。最初の準備のところだけ、少し差が出るぐらいです。

Cの関数を呼ぶのがめちゃ楽

Pythonてどうやって時間測るの? 何となくos.timeとかってモジュールがありそうだよね。調べるか。。。(10秒後)。。。マンドクセー、となったので、Cの時間測定関数を直接呼ぶことに。

    • utility.h
void get_current_time_by_sec(double* time);
void get_use_memory_size_from_mac(long int* mem);
    • utility.c
void get_current_time_by_sec(double* time) {
  struct rusage t;
  struct timeval tv;
  getrusage(RUSAGE_SELF, &t);
  tv = t.ru_utime;
  *time = tv.tv_sec + (double)tv.tv_usec*1e-6;
}

として、

gcc -dynamiclib -m32 -o $@ $

と、共有ライブラリを作る。

あとは、Pythonの中から、

import ctypes

resource = ctypes.CDLL('utility.dylib')
tstart = ctypes.c_double()
resource.get_current_time_by_sec(ctypes.byref(tstart))
print tstart.value

とするだけでおk. おいおい、超簡単じゃねぇか。ラッパ関数を書かなくてもいいし、SWIGを使わなくても、呼ぶだけなら簡単にできる。

注意1: 当初のバージョンでは、値を戻り値で返していたのだが、どうにもintでしか返ってこない。もちろん、res_typeは指定しており、c_doubleで返すようになっているのだけど、Pythonには、int型のオブジェクトでしか返ってこなかった。理由がわからなかったので、とりあえずポインタ経由に。

注意2: おそらくPythonのバージョンによるのだと思いますが、今、私が使っているPython2.6.5では、64ビットのオブジェクトをロードすることが出来ませんでした。そのため、上の共有ライブラリを作るところで、gccに-m32オプションをつけて、32ビットのオブジェクトにしています。

結果

当然ですが、Pythonの惨敗です。手元のMBP1コアで、

言語 CPU Time Memory
C 0.91sec(1.0) 416KB
Python(Pure List) 72.9sec(80.1) 3.29MB

でした。ま、予想通り。次は、NumPyで行ってみまっす。

https://github.com/mizutomo/FDTD-1D

参考