理系学生日記

おまえはいつまで学生気分なのか

多くなったシミュレーションパラメータの処理方法を考えてみた

動機

シミュレーションするとき、何種類かのパラメータをいくつか変えて行いたいときがよくある。

$ ./sim --num 300,400,500,600 -ber 1e-5,1e-4,1e-3

今まで何も考えず、簡単化するとこんな感じのスクリプトを組んでたのだけれど、パラメータが多くなってくるとfor文のネストがいちじるしく多くなってぶっころしたくなった。for文はもうおなかいっぱい。みんなどうやってるんだろう。

foreach my $num (@num) {
  foreach my $ber (@ber) {
    system( './sim-written-another-lang $num $ber' ) for (1..$cnt) 
  }
}

for文をつくらないようにするにはどうしたらいいんだろうと考えて、シミュレーションパラメータは全部ハッシュにして渡すことにした。こんな感じのハッシュをやまほどつくる。

$p1 = { 
        num   => 300, 
        ber   => 1e-5,
        frate => 0.001, # default failure rate
      };
$p2 = {
        num   => 400,
        ber   => 1e-5,
        frate => 0.001, # default failure rate
      };        

で、そういうハッシュでパラメータを関数に渡すとfor文がネストせずに幸せ。

exe_sim( $_ ) for ($p1, $p2);

問題

というわけで問題は、こういう感じのarrayrefを含むハッシュから、arrayrefを含まない複数のhashref配列を山ほどこさえて、幸せになるためにはどうしたらいいか。

%paramset = (
   num   => [300,400,500,600],
   ber   => [1e-5,1e-4,1e-3],
   frate => 1e-5,
);

書いてみた

arrayrefだけとりあえず展開してみる。deep copyしたのは、shallow copyだと単にdumpしたとき気持ち悪かったからであって、あんま意味はないかもしれない。ちなみに、汎用性はない悪寒がする。

sub expand_hash {
    my (@hashes) = @_;
    my ($original, @newhash) = (0);

    my @newhash;
    foreach my $href (@hashes) {
	my $expand = 0;
	for my $key ( keys %$href ) {
	    if( ref( $href->{$key} ) eq 'ARRAY' ){
		push @newhash,
		     map { { %{ dclone( $href ) }, $key => $_ } } @{ $href->{$key} };
		$expand = 1;
                last;
	    }
	}
        unless( $expand ) {
	    push @newhash, $href;
            $original++;
        }
    }
    return $original == @hashes? @hashes : expand_hash( @newhash );
}

実験

use Data::Dumper;
my @hashrefs = expand_hash( { a => [1,2,3], b => 3, c => [4,5] } );
print Dumper( \@hashrefs );

実験結果

忌むべき車輪の再発明のような気がしないでもない。

$VAR1 = [
          {
            'c' => 4,
            'a' => 1,
            'b' => 3
          },
          {
            'c' => 4,
            'a' => 2,
            'b' => 3
          },
          {
            'c' => 4,
            'a' => 3,
            'b' => 3
          },
          {
            'c' => 5,
            'a' => 1,
            'b' => 3
          },
          {
            'c' => 5,
            'a' => 2,
            'b' => 3
          },
          {
            'c' => 5,
            'a' => 3,
            'b' => 3
          }
        ];

オチ

ていうかこれって単に順列の応用であって、ほぼ間違いなく(しかも性能のきわめて悪い)車輪の再発明でしょうほんとうにあ(ry