Net::Rshはrootでないと動かん

昔からkondaraで使ってたrshスクリプトをSOAP対応にしてもう少し使いやすくしたいと思ったんだが、、、

kondaraってSOAP::Liteモジュールが入らんし、5.8のコンパイルも通らん。しかもsshも入ってないので、Net::SSHもつかえん。

ただ、Net::SSHがあるってことはNet::Rshもあるかなあと探したらNet::Rshを発見。

こいつを使ってperlスクリプトを書いてみた。

書いてみたけどなぜか動かん。何故ー?と小一時間悩んだ結果

Net::Rsh - perl client for Rsh protocol - search.cpan.org

Rsh protocol requires that the program be run as root or that the program be setuid to root

うげ、これじゃ使えねぇとか思いつつrootで実行したらあっさり動いた。

結局、perlスクリプトでsystem関数使うのもアレなので、

my $cmd = "rsh $host $rsh_cmd";

open my($fh), "|-", "$cmd" or die $!;

while(<$fh>){
    print;
}

とかやったけど、|-とか-|とかちゃんと理解してないので調べないといけないゾ。

みんなのpythonが届いた

Higher-order Perlの4章を読み終わった。iteratorの章だが100ページ近くあってなかなかの読み応えでちょっと読み疲れた。

ProductName Higher-Order Perl: Transforming Programs with Programs
Mark Jason Dominus
Morgan Kaufmann / 5574円 ( 2005-03-28 )


さぁ、5章だと思ったら、みんなのpythonが届いた。

ProductName みんなのPython
柴田 淳
ソフトバンククリエイティブ / ?円 ( 2006-08-22 )


うーん読む暇をみつけないといけないが、haskellのあとだなぁ。

Error.pm

Inline::Java使っていてjavaのtry-catchってコンパイラに強制されてる感が強くてやだけど構文自体は読みやすくてよいよなと思ってたらperlでもtry-catch構文風なものが使えるようになるモジュールがあるそうだ。

qootas.org/blog - Perlにおけるtry catch

perl についてくるモジュール Error.pm を使うとこんな感じで書けます。

下の記事もわかりやすい。

perl.com: Object Oriented Exception Handling in Perl

The main goal of this article is to discuss in detail about exception handling in Perl and how to implement it using Error.pm. On our way, we'll be touching upon the advantages of using exception-handling over traditional error-handling mechanisms, exception handling with eval {}, problems with eval {} and the functionalities available in Fatal.pm. But by and large, our focus we'll be on using Error.pm for exception handling.

Inline::JavaでCDKのニ次元構造立ち上げをperlから

_in house_でケモインフォ関連のプログラミングをするのに、二次元構造の立ち上げツール(またはライブラリ)と、構造描画ツールは必須だが、いまのとこCDKを使うという選択肢しかない。

実用PerlプログラミングにInline::Javaを使うとjavaのコードをperlに組み込めると書いてあったので、CDKを組み込んでみたヨ。

ProductName 実用 Perlプログラミング 第2版
Simon Cozens
オライリージャパン / 3360円 ( 2006-03-01 )


まぁ、要するに、
Q.そこまでしてperlで処理したいのか?
A. もちろんですヨ、奥さん
ということなんだが。

さて、インストールはj2sdkの場所を指定しないといけないのでcpan -iだとこける。そのため地道に、buildディレクトリで再インストール。

$ cd .cpan/build/Inline-Java-0.51
$ perl Makefile.PL J2SDK=/usr/java/jdk1.5.0_08/
$ make java
$ make
$ make test
$ make install

ただ、make javaで

:入力ファイルの操作のうち、未チェックまたは安全ではないものがあります。
注:詳細については、-Xlint:unchecked オプションを指定して再コンパイルしてください。

とかいう警告が出るが、testは通るのでまぁ気にしないということで。

で、コードを書いてみる。

参考にしたjavaのコード

:::java use Inline Java => <<'END_OF_JAVA_CODE' ; import java.io.StringWriter; import java.io.IOException; import org.openscience.cdk.Molecule; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.io.MDLWriter; import org.openscience.cdk.smiles.SmilesParser; import org.openscience.cdk.layout.StructureDiagramGenerator; import org.openscience.cdk.tools.HydrogenAdder;

class smi2mol{

    public smi2mol(){
    }

    public String convert(String smi){
    Molecule mol = null;

    try {
        SmilesParser sp = new SmilesParser();
        mol = sp.parseSmiles(smi);
    }catch (Exception ise){
        ise.printStackTrace();
    }

    StringWriter w = null;
    MDLWriter  mw = null;

    try {
        w = new StringWriter();
        mw = new MDLWriter(w);
    } catch (Exception e) {
        e.printStackTrace();
    }

    HydrogenAdder ha = new HydrogenAdder();
    try{
        ha.addExplicitHydrogensToSatisfyValency(mol);
    } catch (Exception e){
        e.printStackTrace();
    }

    StructureDiagramGenerator sdg = new StructureDiagramGenerator();
        try{
        sdg.setMolecule(mol);
        sdg.generateCoordinates();
        mol = sdg.getMolecule();
        mw.write(mol);  
    } catch (Exception e){
        e.printStackTrace();
    }

    return w.toString();
    }
}

END_OF_JAVA_CODE

my $alu = new smi2mol();    
my $smiles_string = shift;
print $alu->convert($smiles_string);

実行してみる

::: sh $ perl test.pl "C(=O)O"

  CDK

  5  4  0  0  0  0  0  0  0  0999 V2000
    1.2990   -0.7500    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.0000    0.0000    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
    2.5981   -0.0000    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
    1.2990   -2.2500    0.0000 H   0  0  0  0  0  0  0  0  0  0  0  0
    3.8971   -0.7500    0.0000 H   0  0  0  0  0  0  0  0  0  0  0  0
  2  1  2  0  0  0  0 
  3  1  1  0  0  0  0 
  1  4  1  0  0  0  0 
  3  5  1  0  0  0  0 
M  END

水素が付加されて、座標も計算されたMOLファイルが出力される。

javaって例外を返す可能性がある場合try,catch構文入れないと強制的にエラーになるのね。try,catch構文は読みやすいけど、強制されんのはちょっとやだナァと。単にフォーマットをコンバートするだけのコードなのに結構長くなっちゃったし。

::: perl use CDK; use Chemistry::Mol;

my $mol = CDK::smi2sdf($molecule);
print $mol;

みたいにモジュールにしてuseして使えばCDKを意識しなくてよくなる。

RSPerl

Statistics::R なんかいまいちとか言って、もっぱらRのヒストリファイルをいじってバッチ用に書き換えて使う日々が続いてたが、何を思ったのか、突然RSPerlを使いたくなったのでインストールしてみた。

まずは、Rのインストールから。rpmで楽々。

$ rpm -qa | grep R-
R-devel-2.3.1-1.fc5
R-2.3.1-1.fc5

RSPerlもコマンド一発で楽チン。

$ R CMD INSTALL  --configure-args='--with-in-perl' RSPerl_0.91-0.tar.gz

環境変数の設定スクリプトがあるので、/etc/profileに書いておく

$ vi /etc/profile
#for RSPerl
source /usr/lib/R/library/RSPerl/scripts/RSPerl.bsh

これで、OK。

でRSPerlのいいところは

  • 配列をリファレンスで渡せる(Statics::Rとは違う)
  • AUTOLOADでRの関数を呼び出せる。R::plotとかできる

ので、結構便利だ。

でもマトリックスとかデータフレームの扱いがちょっとめんどくさいのと、Rを起動するために、 &R::initR("--silent") とかやらないといけないのと、$r->plotとかやりたいのにR::plotと書かなきゃいけないので、長いコードだとごちゃごちゃしてきて見通しが悪くなる。

結局Rでバッチのほうがコードが読みやすかったりとか。やっぱRpyか。昨日ソフトのインストールに来てた業者の人も最近pythonの案件増えてますよ~とか言ってたし。

ProductName みんなのPython
柴田 淳
ソフトバンククリエイティブ / ?円 ( 2006-08-22 )


うー、欲しくなってきた。

続 perlでフィボナッチ

昨日に引き続き3章を読み進めていたら、フィボナッチ数をキャッシュで高速化する例が。

ProductName Higher-Order Perl: Transforming Programs with Programs
Mark Jason Dominus
Morgan Kaufmann / 6402円 ( 2005-03-28 )


コードはこんな感じで、割と普通な。

my %cache;

sub fib{
    my $n = shift;
    unless (exists $cache{$n}){
    if($n < 2){
        $cache{$n} = 1;
    }else{   
        $cache{$n} = fib($n-1) + fib($n-2);
    }
    }
    return $cache{$n};
}

さて、昨日のタプルを使ったコードとどっちが速いのか比べてみた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/perl

use strict;
use warnings;
use Benchmark qw(cmpthese);

sub fibStep {
    my $n = shift;
    return [$n->[1], $n->[0] + $n->[1]];
}

sub fibPair {
    my ($n, $fs, $fp) = @_;
    return [0,1] if ($n == 0);
    return $fs->($fp->($n-1,$fs,$fp))
}

sub fastFib {
    my $n = shift;
    my $fs = \&fibStep;
    my $fp = \&fibPair;
    my $fib_num = $fp->($n,$fs,$fp);
    return $fib_num->[0];
}

my %cache;

sub fib{
    my $n = shift;
    unless (exists $cache{$n}){
    if($n < 2){
        $cache{$n} = 1;
    }else{   
        $cache{$n} = fib($n-1) + fib($n-2);
    }
    }
    return $cache{$n};
}

my $number = 50;
my $count = 10000000;

my $fibcache = \&fib;
my $fibfast = \&fib;

cmpthese($count, {
        'Cache' => $fibcache->($number),
        'Fast' => $fibfast->($number)
    });

とりあえず1000万回まわしてみたけどそれでもwarningがでるので、この際無視。

./fib.pl 
            (warning: too few iterations for a reliable count)
            (warning: too few iterations for a reliable count)
            Rate  Fast Cache
Fast  38461538/s    --  -27%
Cache 52631579/s   37%    --

キャッシュしたほうが速いというのがイマイチ理解できん。何でじゃろか?

haskellでフィボナッチ そしてPerlで書いてみた

普通のhaskellプログラミングを読み終えて、なんか次に読むものないかなと探していたら、webarchiveに面白そうなページがあることを知ったので、ダウンロードして読んでます。

3回目の講義資料に、タプルを使って高速にフィボナッチ数を計算する話があったので、なんでそうなるのかを理解するために手で書き下してみた。

普通に書くとこんな感じ(fib)。

fact :: Int -> Int
fact n
  | n == 0  = 1
  | n > 0   = fact (n-1) * n

書き下すと、計算量があっという間に増えていくことがわかる。

fib 5
=> fib 3 + fib 4
=> (fib 1 + fib 2) + (fib 2 + fib 3)
=> (fib1 + (fib 0 + fib 1)) + ((fib 0 + fib 1) + (fib 1 + fib 2))
=> (fib1 + (fib 0 + fib 1)) + ((fib 0 + fib 1) + (fib 1 + (fib 0 + fib 1)))

タプルを使った例(fastfib)

フィボナッチ数列を効率良く計算する方法を考えよう.前に見たとおり,フィボナッチ数列の各項は,その前の二つの項の和である.逆に言えば,二つの連続した項の値が与えられれば,次の項を計算するのは簡単なのだ.

fibStep :: (Int, Int) -> (Int, Int)
fibStep (u, v) = (v, u+v)

fibPair :: Int -> (Int, Int)
fibPair n
  | n == 0    = (0, 1)
  | otherwise = fibStep (fibPair (n-1))

fastFib :: Int -> Int
fastFib = fst . fibPair

コードを眺めただけではなんで速くなるのか実感がわかなかったので、書き下してみる。

fastFib 5
=> fst (fibPair 5)
=> fst (fibStep (fibPair 4))
=> fst (fibStep fibStep (fibPair 3))
=> fst (fibStep fibStep fibStep (fibPair 2))
=> fst (fibStep fibStep fibStep fibStep (fibPair 1))
=> fst (fibStep fibStep fibStep fibStep fibStep (fibPair 0))
=> fst (fibStep fibStep fibStep fibStep fibStep (0, 1))
=> fst (fibStep fibStep fibStep fibStep (1, 1))
=> fst (fibStep fibStep fibStep (1, 2))
=> fst (fibStep fibStep (2, 3))
=> fst (fibStep (3, 5))
=> fst (5, 7)
=> 5

をを、タプルにすることで、計算量が減ってます、自分で展開していくとなるほどとよくわかる。

さて、最近Higher-order Perlを読んでいる僕としては、これをperlで書いてみたくなるわけである。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/perl

use strict;
use warnings;

sub fibStep {
    my $n = shift;
    return [$n->[1], $n->[0] + $n->[1]];
}

sub fibPair {
    my ($n, $fs, $fp) = @_;
    return [0,1] if ($n == 0);
    return $fs->($fp->($n-1,$fs,$fp))
}

sub fastFib {
    my $n = shift;
    my $fs = \&fibStep;
    my $fp = \&fibPair;
    my $fib_num = $fp->($n,$fs,$fp);
    return $fib_num->[0];
}

my $number = shift;
print fastFib($number)

サブルーチンのリファレンスを引数にとらないといけないのがhaskellと異なるとこかな。あとは書いてて思ったのは関数の型を書くとプログラムの流れが理解しやすいナァと。

実行すると一瞬で計算が終わる(速い!)

実際に処理の流れを追うために-dオプションを付けて実行してsを連打すると、main::fibPairがどんどん実行されて$nが0になったところで今度はmain::fibStepが次々実行されていく様がわかる。

Higher-order Perlの5章にもフィボナッチ数列のことが書いてあるのだが、まだそこまで読み進めていない。(今3章突入したところ)

ProductName Higher-Order Perl: Transforming Programs with Programs
Mark Jason Dominus
Morgan Kaufmann / 5692円 ( 2005-03-28 )


ProductName ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門
青木 峰郎
ソフトバンククリエイティブ / ?円 ( 2006-06-01 )


haskellを勉強しながら、Higher-order Perlを読むと、色々新たな発見があって楽しい。

Sudoku

実家に帰ったら、婆さんが数独にはまってた。ボケ防止にいいらしい。ちょうどいいので、flashの数独をgoogleで適当に探してきてお気に入りに登録しておいてやったら喜ばれたヨ。まぁ、使うかどうかわからんけど。

ちょうど、Highr Order Perl読み始めたところだし、家に戻ってきて、数独ソルバでも書いてみるかと思ってたら、タイミングよくUno, dos, tres, quatro!にエントリが。

ProductName Higher-Order Perl: Transforming Programs with Programs
Mark Jason Dominus
Morgan Kaufmann / 6402円 ( 2005-03-28 )


バックトラック法ってのを使えばいいのねと自分で書いてみたのはマス目を一つ一つ移動してくコードだったんだけど、再帰深すぎるヨっていうエラーを吐いて終了。なんかダメダメだなぁ。他の人のを読んでみるとまだ埋まってないマス目を再帰で埋めていくべきだったことに気付いた。ちょっとこれに引っ張られたかなと反省。

まだ埋まってないマス目の配列と、過程として数字を置いたマス目の配列の二つを用意して、バックトラック法で解くというわけですな。

とか、わかった上で、三行数独ソルバを読むと、説明もついてるしよくわかった、素敵。

家のマシンで三行数独ソルバを実行してみるとこんな感じ。

 $ time perl sudoku.pl < sample
 825169734
 463857921
 917234658
 684712593
 759386142
 231495867
 548621379
 376948215
 192573486 #本当はココまで一行で出力

 real    0m1.439s
 user    0m1.436s
 sys     0m0.004s

プログラム・プロムナードにhaskellの数独ソルバが載ってたのでそれも実行してみた。ちゃんと理解しないといけないと思いつつ、今回はコピペ。ghciで計算させた。

 *Main> sudoku sample
 [8 2 5 1 6 9 7 3 4
 4 6 3 8 5 7 9 2 1
 9 1 7 2 3 4 6 5 8

 6 8 4 7 1 2 5 9 3
 7 5 9 3 8 6 1 4 2
 2 3 1 4 9 5 8 6 7
 5 4 8 6 2 1 3 7 9
 3 7 6 9 4 8 2 1 5
 1 9 2 5 7 3 4 8 6
 ]
 (0.28 secs, 26584692 bytes)

haskellもperlクイズみたいなのを誰かやってくれたら嬉しいナァ。とか。

Perlクイズを読み終えた

一ヶ月くらい前から暇をみてはPerlクイズを解いていたのだが、ここ2,3日は集中してすすめることができた。というわけで、本日終了。

最後のほうはパズルばかりでかなり手ごわいクイズが並んだが、一通りやり遂げた。

ProductName 結城浩のPerlクイズ
結城 浩
ソフトバンククリエイティブ / ?円 ( 2002-08 )


特に面白かったのはここらへん

初盤ではハッシュの操作とか正規表現なんかの問題が多かったが、特にソート関係は勉強になった。

あとは、「あらかじめ行数がわかっていなくてもランダムに行を表示する方法は特にイテレータ使ってる場合にランダムに一個選びたい場合にイイ。

chemichoっていうプログラムを書いていたときに、perlmolの部分構造マッチのメソッドがイテレータで、ヒット数を返すメソッドがなかったため、マッチした部分の中からランダムで一箇所選ぶためにわざわざ一回スキャンしてヒット数を調べてから、int(ヒット数*rand)番目を再度イテレータ使って取得するという二回同じイテレータをまわすプログラムだったという。

これって無駄だなと思っていたので、上のやり方はエレガントじゃ!と感動した。

perldoc perlvar

perlのコードを読んでると、たまに知らない変数が出てくることがあるが、$?とか$#みたいな記号のみで構成されているモノはgoogleでヒットさせにくくてイライラすることが多い

そんなときは

perldoc perlvar

で調べればいいということを知った。忘れるとアレなのでメモ。