2014/05/27(火)Perl Data Language 基礎編 #07 「多次元ピドルから配列リファレンスへの変換、ベクトル走査、atとsclrの違い、topdl」

スライスの前にまとめておくべきことがあったのでまとめておきましょう。

atとsclrの違いは、sclrは何次元のピドルでもとにかく最初の値を返すこと。atだと場所の指定と次元が食い違うと死にます。

topdlはPDLを使ったモジュールで使えそうな関数。デフォルトではエクスポートされない点だけ注意。

とりあえずコードと実行結果を見るのが確実で手っ取り早い、というわけでいつも通りコードと実行結果を載っけます。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL;
use DDP filters => { -external => [ 'PDL' ] };

my $piddle = pdl [ [1,2,3], [4,5,6] ];
say $piddle;

say "unpdl で多次元ピドルを配列リファレンスへ:";
my $arrayref = $piddle->unpdl;
say p $arrayref;
print @{ $arrayref->[0] };
print @{ $arrayref->[1] };
print "\n\n";

my $vector = pdl [ 7,8,9 ];

say "listindices メソッドで走査:";
for my $i ($vector->listindices)
{
    say $vector->at($i);
}
print "\n";

say "list メソッドで走査:";
for my $elem ($vector->list)
{
    say $elem;
}
print "\n";

say "at(0,0)";
say $piddle->at(0,0);
print "\n";

say "at(0)";
eval { $piddle->at(0) };
say "エラー発生" if $@;
print "\n";

say "sclr";
say $piddle->sclr;
PDL->sclr({ Check => 'warn' });
say $piddle->sclr;
PDL->sclr({ Check => 'barf' });
eval { $piddle->sclr };
say "エラー発生" if $@;
PDL->sclr({ Check => 0 });
say $piddle->sclr . "(Check => 0 なのでエラーは発生しなくなる)";
print "\n";

say "topdl(pdlであることを確実にする)";
say p PDL::Core::topdl 7;
say p PDL::Core::topdl $piddle;
say p pdl $piddle;

実行結果↓

[
 [1 2 3]
 [4 5 6]
]

unpdl で多次元ピドルを配列リファレンスへ:
 [
    [0] [
        [0] 1,
        [1] 2,
        [2] 3
    ],
    [1] [
        [0] 4,
        [1] 5,
        [2] 6
    ]
]
123456

listindices メソッドで走査:
7
8
9

list メソッドで走査:
7
8
9

at(0,0)
1

at(0)
エラー発生

sclr
1
multielement piddle in 'sclr' call at unpdl.pl line 47.
1
エラー発生
1(Check => 0 なのでエラーは発生しなくなる)

topdl(pdlであることを確実にする)
PDL {
    Data     : 7
    Type     : double
    Shape    : Empty[0]
    Nelem    : 1
    Min      : 7
    Max      : 7
    Badflag  : No
    Has Bads : No
}
PDL {
    Data     : [
                [1 2 3]
                [4 5 6]
               ]
    Type     : double
    Shape    : [3 2]
    Nelem    : 6
    Min      : 1
    Max      : 6
    Badflag  : No
    Has Bads : No
}
PDL {
    Data     : [
                [1 2 3]
                [4 5 6]
               ]
    Type     : double
    Shape    : [3 2]
    Nelem    : 6
    Min      : 1
    Max      : 6
    Badflag  : No
    Has Bads : No
}

ピドルを渡すときのpdlとtopdlの違いが実行結果からは分からないのでベンチマークをとってみました。pdlにピドルを渡すと新たなコピーが作られるのに対してtopdlはリファレンスを返すので、その分だけ少し速いという結果になっていると考えられます。

#!/usr/bin/env perl

use strict;
use warnings;
use Benchmark;
use PDL;

my $piddle = pdl [ [1,2,3], [4,5,6] ];

Benchmark::cmpthese(-1, {
      'pdl' => sub {   pdl $piddle },
    'topdl' => sub { topdl $piddle },
});

ベンチマークの結果↓

         Rate   pdl topdl
pdl   19997/s    --  -15%
topdl 23643/s   18%    --