初めての Pull Request

GitBucket に3件ほど Pull Request を送っておいた。OSS への Contribute は久々な気がする。
Scalatra 知らないし、Scala は書籍持っているけど、ほとんど経験ない、とかいう状態だけどなんとかなるものだな。

#86 Add encoding detection

Shift-JIS で書かれたファイルをレポジトリに入れると表示がおかしい、ということで、エンコーディングの自動認識+変換。
コードを見ると、UTF-8 決め打ちでバイト列から文字列に変換していたので、juniversalchardet を使ってエンコーディングを認識して変換するようにしただけ。

#87 Specify ContentType

なぜか、IE だとまったく表示されない問題の対策。
最初、さっぱり分かんなかったんだけど、間に WEBrick で作った proxy はさんで、ヘッダを確認して判明。リクエストの Accept ヘッダに application/x-shockwave-flash があって、text/html がないとレスポンスの Content-Type が application/x-shockwave-flash になっとる。なんだこれ?
とりあえず、明示的に Content-Type を指定するように変更。
しかし、IE の Accept ヘッダが変。

Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*

image/pjpeg ってなんだ?

#88 Support i18n

国際化の仕組みいれただけ。あとはメッセージリソース作って、テンプレートを書き換えれば多言語対応出来るはず。
個人的には必要ないんだけど、UI が英語なだけで拒否反応示す人もいるからねぇ。

call by/pass by

まぁ、Java のメソッド呼び出しを call by reference とは言わんでしょうなぁ。
ちなみに、PythonJava の場合とほぼ同じだけど、Tutorial で call by value だと書いてある。

arguments are passed using call by value (where the value is always an object reference, not the value of the object)

で、FAQ では pass by assignment とか書いてあったり。

Remember that arguments are passed by assignment in Python.

Rayleigh分布のあれ

きむらさんがすっきりしないようなので、シミュレーションしてみた。

  • スケールパラメータ 5*sqrt(2) *1で、Layleigh分布*2 の乱数 t を496回生成。
  • n - 1 <= t < n の場合に、n週目発見の欠陥としてカウント
  • 各週の発見欠陥数から K_i を計算

ということを1,000回実施して、K_i の平均と標準偏差を計算。

import random
import math

NUM_TRIAL = 1000
TOTAL_DEFECTS = 496
ESTIMATED_TM = 5
T_MAX = 10

def mean(seq):
    return sum(seq) / len(seq)

def std(seq):
    m = mean(seq)
    return math.sqrt(sum((x - m) ** 2 for x in seq) / len(seq))

def trial(total_defects, e_tm, t_max):
    counts = [0 for _ in xrange(t_max)]
    scale = e_tm * math.sqrt(2)
    for _ in xrange(total_defects):
        t = random.weibullvariate(scale, 2)
        idx = int(t)
        if idx < t_max:
            counts[idx] += 1
    k_estimates = []
    for i, c in enumerate(counts, 1):
        k = 1.0 * e_tm * e_tm / i * math.exp(0.5 * i * i / e_tm / e_tm) * c
        k_estimates.append(k)
    return { 'counts': counts, 'k_estimates': k_estimates }

def main():
    k_all = [[] for _ in xrange(T_MAX)]

    for _ in xrange(NUM_TRIAL):
        result = trial(TOTAL_DEFECTS, ESTIMATED_TM, T_MAX)
        for i, c in enumerate(result['k_estimates']):
            k_all[i].append(c)

    for i, k in enumerate(k_all, 1):
        print i, mean(k), std(k)

if __name__ == '__main__':
    main()

実行結果

1 251.352105149 79.4676230281
2 376.753701049 69.2076414754
3 432.474818805 62.0288908122
4 470.504307734 58.1793029766
5 490.379167544 60.2312676994
6 507.273800261 61.3508169168
7 526.239623696 68.082631596
8 543.75572901 72.5164253587
9 552.920371528 84.6362785681
10 576.050813473 95.2159227826

なんだが、週によって全然違う分布を示すようなので、スライドのように K_i の平均や標準偏差計算しても意味ないんじゃ無いですかね。

*1:こうすれば tm=5 になる

*2:つまり形状パラメータ2の Weibull 分布

結局正規分布

まず、スライド35ページのf(t)の式で表されるのは、ある単位時間内で発見される欠陥数の期待値ですよね*1
で、f(1), f(2), ... のそれぞれは正規分布に従った分布になるはず(中心極限定理のため)。これは簡単なプログラムで確かめられる。

import math
import random

number_of_defects = 1000
trial_count = 1000
counts = [0 for _ in xrange(number_of_defects + 1)]
min_value = 0.1
max_value = 0.2

for _ in xrange(trial_count):
    cnt = 0
    for _ in xrange(number_of_defects):
        t = random.weibullvariate(1, 2)
        if min_value <= t < max_value:
            cnt += 1
    counts[cnt] += 1

for n, cnt in enumerate(counts):
    if cnt > 0: print n, cnt

で、69ページの式に従えば、当然各 K_i も正規分布に従う。なので、K_i の平均値と標準偏差から K の信頼水準を求めているのではないかと。
まぁ、i によらず、K_i の標準偏差が一緒なのかとか、K の信頼水準をそのまま f(t) の信頼水準に適用していいのか、といったあたりがよくわかりませんが。

*1:というかこの式、確率密度関数じゃないよね、f(t)は確率じゃないし

split

調べてみると、プログラミング言語によって、split の細かい挙動が異なるのであった。

Perl, Ruby の場合

% ruby -e 'p "a-b--c-".split /-/'  
["a", "b", "", "c"]

% ruby -e 'p "a-b--c-".split /-/, -1'
["a", "b", "", "c", ""]

% ruby -e 'p "a-b--c-".split /(-)/'
["a", "-", "b", "-", "", "-", "c", "-"]

% ruby -e 'p "abc".split //'
["a", "b", "c"]
% perl -MData::Dumper -e 'print Dumper([split /-/, "a-b--c-"])'
$VAR1 = [
          'a',
          'b',
          '',
          'c'
        ];

% perl -MData::Dumper -e 'print Dumper([split /-/, "a-b--c-", -1])'
$VAR1 = [
          'a',
          'b',
          '',
          'c',
          ''
        ];

% perl -MData::Dumper -e 'print Dumper([split /(-)/, "a-b--c-"])' 
$VAR1 = [
          'a',
          '-',
          'b',
          '-',
          '',
          '-',
          'c',
          '-'
        ];

% perl -MData::Dumper -e 'print Dumper([split //, "abc"])' 
$VAR1 = [
          'a',
          'b',
          'c'
        ];

PerlRuby は同じ動き。

  • 分割の結果、空文字となった末尾の要素は削除
    • 分割数に負数を指定すると削除されない
  • 正規表現にキャプチャがある場合は、キャプチャされた内容が戻り値に格納
  • 空の正規表現の場合は文字ごとに分割

Python の場合

% python -c 'import re; print repr(re.split("-", "a-b--c-"))'
['a', 'b', '', 'c', '']

% python -c 'import re; print repr(re.split("(-)", "a-b--c-"))'
['a', '-', 'b', '-', '', '-', 'c', '-', '']

% python -c 'import re; print repr(re.split("", "abc"))'
['abc']
  • 末尾の空文字は削除されない
  • 正規表現にキャプチャがある場合の動作は Perl, Ruby と同様
  • 空の正規表現の場合は分割されない

Java の場合

Groovy というか、Java の仕様。

% groovy -e 'println("a-b--c-".split(/-/))'
[a, b, , c]

% groovy -e 'println("a-b--c-".split(/(-)/, -1))'
[a, b, , c, ]

% groovy -e 'println("a-b--c-".split(/(-)/))'
[a, b, , c]

% groovy -e 'println("abc".split(""))'    
[, a, b, c]

% groovy -e 'println("abc".split("", -1))'
[, a, b, c, ]
  • 末尾の空文字は削除される
    • 分割数に負数を指定すると削除されない
  • 正規表現にキャプチャがあっても関係なし
  • 空の正規表現を指定すると文字ごとに分割
    • 先頭と末尾に空文字が入る
    • 分割数の指定がないと末尾の空文字は削除

JavaScript の場合

Java に標準で組み込まれている Rhino を使ってみる。

% jrunscript -e 'println("a-b--c-".split(/-/).toSource())'      
["a", "b", "", "c", ""]

% jrunscript -e 'println("a-b--c-".split(/(-)/).toSource())'
["a", "-", "b", "-", "", "-", "c", "-", ""]

% jrunscript -e 'println("abc".split(new RegExp()).toSource())'
["a", "b", "c"]
  • 末尾の空文字は削除されない
  • 正規表現にキャプチャがある場合の動作 Perl, Ruby と同様
  • 空の正規表現を指定した場合は文字ごとに分割(Perl, Ruby と同様)

末尾にデリミタが来る場合なんかを考えると分割数を常に指定しておいたほうが無難かなぁ。
しかし、末尾の空文字を削除するのは何なんだろな。

著作権

面白い。
早川マップは Google Maps を使用したものがある模様。

ユーザーは、マップ情報(画像イメージを含みます。)に表示された著作権、商標またはその他の財産権に関する注意書きを削除または変更(その方法の如何を問いません。)することはできません。

とのことだが、早川マップには Google Maps著作権表示は見当たらない。早川さんが個別に Google(およびゼンリンなどデータの提供元)の許可を個別に得ていない限りは、単純に利用規約違反だ。
もし、許可を得ていないのであれば、著作権を守れ、と言っている当の著作物が実は利用規約違反により実現されているわけで、大変興味深い。
なお、国土地理院のデータに関しては

?国、地方公共団体及び行政関係機関の皆様へ?
国土地理院では、当面の間、東北地方太平洋沖地震災害に関連する測量成果については、出典を明示することで申請を省略して複製・使用することを許可いたします。
具体的には「国土地理院提供」などと明記してください。
なお、災害に関連しないものについては、従来通り申請が必要です。また、独立行政法人等で行政関係機関に該当するか不明な場合は、下記「問い合わせ窓口」にお問い合わせください。

とのことなので、問題無さげ。

宣言その2

kinaba さんの tweet から。

Cの型宣言、年に一回くらい流行る「英語で読む」という方法が、簡単なものをわざと難しく見せているように思えて好きになれないのです。(その方針の是非はさておき)使う時の構文と宣言の構文が似るようにという方針で設計されてるのだからそう読んだ方が素直では。

別の言い方をすると、"a ptr to func returning ptr to func returning char" だと判明して何か嬉しいでしょうか。それは一体なんなのか。それは「デリファレンスして0引数適用してデリファレンスしてint適用したらcharになる物体」(続

続) ですし、それは char (*(*fp)(void))(int); という宣言にまさにその通りのことが書いてある。

なるほど。const/volatile は置いておいて、英語にしたところで微妙なのはそのとおりな気がする。
じゃ、ま、S式にしてみる。

void (*signal(int, void (*)(int)))(int)
(declare
 :identifier 'signal
 :type (function
        :return (pointer
                 (function 
                  :return 'void
                  :args '(int)))
        :args (list 'int
                    (pointer
                     (function
                      :return 'void
                      :args '(int))))))
double (*(*(*f)(double))(double))(double)
(declare
 :identifier f
 :type (function
        :return (pointer
                 (function
                  :return (pointer
                           (function
                            :return 'double
                            :args '(double)))
                  :args '(double)))
        :args '(double)))

あぁ、うん。どうだろね。