Nodeで動かして完結編

終わる終わる詐欺ではありません。アクエリアスと体当たり爆沈して終了です。

Haskell vs F#
↑のエントリを見て、↓の2つのエントリを書いた。今日はその完結編。
HaskellとF#の解読の練習とちょっとした疑問でRubyに移植してみた
Cに書き直して満足して終了

元エントリの中の人とゆかいな仲間達の間では道具選びの結論が出て、既にアルゴリズム改良にいそしんでいます。が、その裏で、未だにワタクシおなじみの言語で書き換えたらどうなるかを一人でやってます。器用貧乏のサガですね。

今日はコードをCoffeeScript(JavaScript)に直して、Node.jsで動かしてみました。おお。速い。

実行結果
$ node --version
v0.6.10
$ coffee --version
CoffeeScript version 1.2.0
$ coffee -c hoge.coffee
$ time node hoge.js
999.9999999999998
node hoge.js  8.26s user 0.08s system 100% cpu 8.289 total

おお!Haskellの15倍の処理時間(15倍遅い)!これは速いほう!!(過去エントリ参照(Ruby編, C編)
v8エンジンって結構優れてるんですね。

感想めいたもの

作りたいアプリケーションに合わせて道具を選びましょうという超当たり前の感想と、F#見直したわーくらいしかなくて、Cに書き直して満足して終了で書いたのと一緒w。

比較表
処理系と実装 Haskellを1とした場合 実処理時間(s)
C(llvm-gcc-4.2) 0.1 0.070
Haskell (7.4.1) 1.0 0.534
Ruby very slow(YARV 1.9.3p0) 54.2 28.935
Ruby slow(YARV 1.9.3p0) 26.8 14.296
Ruby very slow(JRuby 1.6.5.1) 58.3 31.139
Ruby slow(JRuby 1.6.5.1) 14.5 7.724
Ruby very slow(MacRuby 0.10) 331.0 176.73
Ruby slow(MacRuby 0.10) 24.1 12.855
Ruby (MacRuby 0.10) 並列化 18.2 9.729
JavaScript(Node.js 0.6.10) 15.5 8.289
CoffeeSctipt
induceBackwardVerySlow = (nodes, values) ->
  n = Math.floor(values.length / 2)
  nodes.map*1[0]

console.log(Math.max((value(i) for i in [1..ITERATION])...))

しかし、はてなダイアリーってCoffeeScriptシンタックスハイライト無いんだね…。なんかがっかりだなぁ。。。

コンパイル後のJavaScript
(function() {
  var ITERATION, i, induceBackwardVerySlow, last_values, test_tree, value;

  induceBackwardVerySlow = function(nodes, values) {
    var n;
    n = Math.floor(values.length / 2);
    return nodes.map(function(node) {
      return node.branches.map(function(branch) {
        return branch.p * values[n + branch.k] * node.df;
      }).reduce(function(a, b) {
        return a + b;
      });
    });
  };

  ITERATION = 1000;

  last_values = function(i) {
    var n, _results;
    _results = [];
    for (n = 0; n <= 200; n++) {
      _results.push(i);
    }
    return _results;
  };

  test_tree = function() {
    var _i, _results;
    return (function() {
      _results = [];
      for (_i = 0; _i <= 99; _i++){ _results.push(_i); }
      return _results;
    }).apply(this).map(function(i) {
      var _i, _results;
      return (function() {
        _results = [];
        for (var _i = -i; -i <= i ? _i <= i : _i >= i; -i <= i ? _i++ : _i--){ _results.push(_i); }
        return _results;
      }).apply(this).map(function(j) {
        return {
          df: 1.0,
          branches: [
            { 
              k: j - 1,
              p: 1.0 / 6.0
            }, {
              k: j,
              p: 2.0 / 3.0
            }, {
              k: j + 1,
              p: 1.0 / 6.0
            }
          ]
        };
      });
    });
  };

  value = function(i) {
    return test_tree().reverse().reduce(function(values, nodes) {
      return induceBackwardVerySlow(nodes, values);
    }, last_values(i))[0];
  };

  console.log(Math.max.apply(Math, (function() {
    var _results;
    _results = [];
    for (i = 1; 1 <= ITERATION ? i <= ITERATION : i >= ITERATION; 1 <= ITERATION ? i++ : i--) {
      _results.push(value(i));
    }
    return _results;
  })()));

}).call(this);

*1:node) -> node.branches.map((branch) -> branch.p * values[n + branch.k] * node.df ).reduce((a, b) -> a + b) ) ITERATION = 1000 last_values = (i) -> (i for n in [0..200]) test_tree = -> [0..99].map((i) -> [-i..i].map((j) -> { df: 1.0, branches: [{k: j - 1, p: 1.0 / 6.0}, {k: j , p: 2.0 / 3.0}, {k: j + 1, p: 1.0 / 6.0}] } ) ) value = (i) -> test_tree(). reverse(). reduce((values, nodes) -> induceBackwardVerySlow(nodes, values) , last_values(i