2014/05/25(日)Perl Data Language 基礎編 #02 「行列の演算とバッド値」

PDLの関数を見る前に行列の演算です。

ドキュメントは以下の通り。

  • PDL::Core(メソッド、型変換のための関数、PDLの生成、型変換、スレッドなど)
  • PDL::BadValues(PDLにおけるバッド値サポートの議論)

バッド値は欠損値に使うのが良さそう。バッド値があるとバッドフラグがついて、さらにバッドフラグがついたピドル(PDLの変数のこと)で演算したりするとバッドフラグが伝染するみたい。ちなみに他の文字列(nyan)はバッド値がつくのか疑問に思ったので試したけど、ちゃんと'bad'や'BAD'と区別してバッドフラグはつかないようになっている模様。

他の注意点は行列同士の積は「x」を使うことぐらい。

統計についてまとめていく前にコア関数をまとめて、主要なドキュメントをまとめて、グラフ描画についてまとめます。

#!/usr/bin/env perl

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

my $a = pdl [
    [ 1, 2 ],
    [ 3, 4 ]
];

my $b = pdl [
    [ 5 ],
    [ 6 ]
];

say "$a: $a";
say "$b: $b";

say "$a x $b";
say $a x $b; # 行列の積は*でなくてxを使う

my $d = $a;
$d = $d ** 3; # 3乗

say "$d($a^3): $d";
say "$a: $a"; # $a には影響しない

my $e = pdl [
    [ 'inf',    2    ],
    [ 'nan', ' -inf' ]
];

my $f = pdl [
    [ '-inf',  'bad'   ],
    [  3    ,  'nyan' ]
];

say "$e: $e";
say "$f: $f";

say "$e + $f:";
say $e + $f;

say "バッドフラグ";
say PDL->new(3)->badflag;
say PDL->new('bad')->badflag;
eval { PDL->new('nyan')->badflag; };
print $@ if $@;
my $g = pdl [ 'nyan' ];
say $g->badflag;
say p $g;

実行結果↓

$a: 
[
 [1 2]
 [3 4]
]

$b: 
[
 [5]
 [6]
]

$a x $b

[
 [17]
 [39]
]

$d($a^3): 
[
 [ 1  8]
 [27 64]
]

$a: 
[
 [1 2]
 [3 4]
]

$e: 
[
 [ inf    2]
 [ nan -inf]
]

$f: 
[
 [-inf    0]
 [   3    0]
]

$e + $f:

[
 [-nan    2]
 [ nan -inf]
]

バッドフラグ
0
1
PDL::Core::new_pdl_from_string: found disallowed character(s) 'nyan' in nyan at core.pl line 50.
0
PDL {
    Data     : [0]
    Type     : double
    Shape    : [1]
    Nelem    : 1
    Min      : 0
    Max      : 0
    Badflag  : No
    Has Bads : No
}

2014/05/25(日)Perl Data Language 基礎編 #01 「PDLのインストール」

統計検定に向けて「Perlで統計」をまとめていきます。(の予定でしたが、思いのほかPDLが大きいライブラリだったのでまずはPDLをまとめていきます)

PDL(Perl Data Language)は、科学技術計算とその結果の描画のためのPerl拡張です。PDLは速くて、IDL(科学技術計算でよく使われるデータ分析用プログラミング言語)やMATLABと匹敵するか、それらより速い(often outperforming)です。PDLによって、画像などの多次元データも効率よく格納できて素早く操作できます。$a = $b + $c で $b と $c が大きいデータ集合 (たとえば 2048x2048 画像) でもほんの一瞬で結果を得られます。PDL変数(piddleと呼ばれる)は基本的なデータ型の広範囲をサポートし、たとえば $x は何次元のデータでも入ります(おそらくメモリが許す限り)。@x に格納しない理由は、「メモリ」と「スピード」のためです。(ドキュメントより)

インストールは以下の通り。

cpanm Data::Printer
cpanm Data::Printer::Filter::PDL

今回はとりあえず動かすところま'で。

#!/usr/bin/env perl

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

my $piddle = pdl [1,0,0,1];
say $piddle;

say "Data::Printer::Filter::PDL で表示:";
p $piddle;
print "\n";

print "要素数:" . $piddle->nelem . "\n";
say $piddle->info("メモリ消費量:%M");

print "\n";


my $piddle2 = pdl [ [ 1 .. 3 ], [ 3 .. 5 ] ];
say $piddle2;

say "Data::Printer::Filter::PDL で表示:";
p $piddle2;
print "\n";

print "要素数:" . $piddle2->nelem . "\n";
say $piddle2->info("メモリ消費量:%M");

実行結果:
pdl

次回はPDLの関数を見て、次々回でモジュールまとめていく感じでいこうかな。

追記!割りとガチで使う場合は GSL(GNU Scientific Library)をインストールしておきましょう。パッケージ管理システムがAPTの場合は「sudo apt-get install libgsl0-dev」でOK!GSLのインストールより先にPDLをインストールしてしまった場合は、「cpanm PDL --reinstall」でPDLを再インストールしましょう。

2014/05/01(木)1文字フォントの作り方(無料)

💩 (うんこ)を表示できるフォント(うんこフォント)を作ったので作り方を軽くまとめておきます。

用意するハードウェア

  • スキャナー(デジタルでフォントを描く場合はなくてもOK)

最初に用意するソフトウェア

  • Gimp
  • Inkscape

フォント(SVGファイル)作成手順↓

  1. 紙に文字を書く
  2. スキャナーで読み込む(300dpiぐらい)
  3. Gimpで2値化(白と黒に分けること)
  4. 気に入らないところがあればGimpで編集
  5. bmpファイルで保存
  6. Inkscapeを起動
  7. 「ファイル」→「ドキュメントの設定」→「カスタムサイズ」で正方形にする(1000px x 1000pxぐらい)
  8. bmpファイルをドラッグ・アンド・ドロップしてInkscapeで読み込み(埋め込み)
  9. 「パス」→「ビットマップをトレース」→「OK」ボタンを押す
  10. 「テキスト」→「SVG フォントエディタ」→「新規」ボタンを押す
  11. 「フォント 1」をクリックして「ファミリ名」を適当なフォント名(うんこフォントなら「Unko」とか)にする
  12. 「グリフ」タブをクリック→「グリフを追加」ボタンを押す
  13. 「グリフ 1」の「マッチング文字列」に作りたいフォントの文字を入力
  14. 「選択オブジェクトから曲線を取得」ボタンを押す
  15. 「プレビューテキスト」に作りたいフォントの文字を入力して描いたフォントが反映されているか確認
  16. 「ファイル」→「名前を付けて保存」でファイルの種類はInkscape SVGのままで保存

Inkscapeの操作は自作フォントの作り方|windowsで無料で作成!How to make Font in Inkscape.It's completely free.が詳しいです。

SVGファイルから eot, ttf, woff ファイル作成手順(難易度高め)

  1. Linuxで「sudo apt-get install npm」する(パッケージ管理システムによって少し変わる)
  2. さらに「npm install -g svg2ttf」する
  3. 「svg2ttf from.svg to.ttf」でttfファイルを作成(もちろん適切なファイル名で)
  4. WOFFコンバータでttfファイルからwoffファイルとeotファイルを作成!(終了)

紙にかいた文字は↓ですが、線はもっと太くしたほうがいいです。 うんこ

↑のように線が細いと、小さく表示したときに文字が見えなくなるのでGimpでかなり太くしないといけなくなります。 unko

ファイルサイズは woff, eot, ttf で2,000から3,000 バイトぐらいになりました。

2014/03/21(金)Lingua::JA::KanjiTable - Perlで常用漢字表と人名用漢字表を扱う

https://metacpan.org/pod/Lingua::JA::KanjiTable

常用漢字表だけでも個人的には嬉しいのですが、人名用漢字表も用意してあるので妥当な名かのチェックもできます。戸籍法 第50条と戸籍法施行規則 第60条によると、子の名には常用漢字表の漢字と人名用漢字表の漢字と片仮名と平仮名が使えるようなので、以下のコードで名の妥当性をチェックできます。(名は Mock::Person::JP で出力)

#!/usr/bin/env perl
 
use strict;
use warnings;
use utf8;
use Lingua::JA::KanjiTable;
 
my @name_list = qw/希砂妃 みのる 菜奈世
勇凪 ソラ 未佑 茶流 怜実 紫翠 夢里/;
 
for my $name (@name_list)
{
    $name =~ /^p{InMei}+$/
        ? print "validn"
        : print "invalidn"
        ;
}
 
sub InMei
{
    return <<"END";
+Lingua::JA::KanjiTable::InJoyoKanji
+Lingua::JA::KanjiTable::InJinmeiyoKanji
3005
3041t3096
309D
309E
30A1t30FA
30FCt30FE
END
}

2014/03/08(土)PerlでServer-Sent Events

サーバからPUSHされたイベントを受け取るやつ。(http://www.w3.org/TR/eventsource/

Server-sent Event

最初リアルタイムで反映されなくて試行錯誤していたのですが、nginxの設定を変えたらリアルタイムで反映されるようになりました。(http://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx

コードは下の通りで「plackup」とかで立ち上げられます。

#!/usr/bin/env perl

use strict;
use warnings;
use AnyEvent;
use Time::Piece;
use HTTP::ServerEvent;

my $AFTER    = 1;
my $INTERVAL = 1;
my $DURATION = 60 * 30; # 秒

my $html = do { local $/; <DATA> };

my $app = sub {
    my $env = shift;

    if ($env->{PATH_INFO} ne '/sse/events')
    {
        return [ 200, ['Content-Type', 'text/html'], [$html] ];
    }

    if ( ! $env->{"psgi.streaming"} )
    {
        my $err= "Server does not support streaming responses";
        return [ 500, ['Content-Type', 'text/plain'], [$err] ];
    }

    return sub {
        my $responder = shift;
        my $writer    = $responder->([ 200, [ 'Content-Type' => 'text/event-stream; charset=UTF-8' ] ]);

        my $cnt = 0;

        my $t; $t = AnyEvent->timer(
            after    => $AFTER,
            interval => $INTERVAL,
            cb       => sub {
                my $now = localtime->strftime('%Y-%m-%d %H:%M:%S');

                my $event = HTTP::ServerEvent->as_string(
                    id   => ++$cnt,
                    data => $now,
                );

                $writer->write($event);

                undef $t if $cnt > $DURATION;
            }
        );
    };
};

__DATA__
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Server-Sent Events</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
</head>

<body>
  <h1>Server-Sent Events</h1>
  <div id="msg"></div>
  <script>
    var eventSource = new EventSource('/sse/events');
    var msg = $("#msg");

    eventSource.onmessage = function(e)
    {
        console.log("message");
        console.log(e.data);

        msg.prepend("<p>" + e.data + "</p>");
    };

    eventSource.onopen = function(e)
    {
        console.log("open");
    };

    eventSource.onerror = function(e)
    {
        console.log("error");
    };
  </script>
</body>