何かを書き留める何か

数学や読んだ本について書く何かです。最近は社会人として生き残りの術を学ぶ日々です。

コミュニティへの貢献としての査読・校正

来月2017年12月16日に埼玉県さいたま市大宮区で「Python Boot Camp in 埼玉」が開催される。 私はTAとして参加する。

そこで、第82回Python mini Hack-a-thonにおいて、 Boot Campでテキストとして用いられる「Python Boot Camp Text」を一通り読んだ。 目的は予習及び直すべき箇所があれば指摘しようと思ったからである。

pyhack.connpass.com

今回の成果は次のPull Requestとしてまとまった。

いずれも、言語仕様に関連した細々とした指摘である。 しかし、イテラブルとシーケンスは混同しがちな概念であったり(シーケンスはイテラブルであるが、イテラブルはシーケンスとは限らない)、 普段、型としてはあまり意識しない辞書のビューオブジェクト、 シーケンス型に対するインデックスによるアクセス(__getitem__)とスライスの違いなどありがちなものである。

過去の技術書の査読の経験が少し活用できた1日であった。 前の職場でも今の職場でも誤植を見つけるのがうまいといわれるので、他の人よりもそういうを見つけるのが得意なのかもしれない。 先天性のものか、学部・修士と数学書を読んだ影響なのか、どちらだろうか。

TAは修士の時にプログラミング演習以来である。 プログラミング演習では学部生に教えるのではなく、考えさせるように指導を受けた。 Boot Campなので何も知らない人に何もない状態で考えてもらうのは中々難しいかもしれないが、Boot Campが終わったあとも続けてプログラミングが学べるように手助けを行っていきたい。

みんなのPython勉強会 #30 に参加しました

祝! 30回目の勉強会

去る2017年11月8日に「みんなのPython勉強会 #30」が麹町のクリーク・アンド・リバー社にて行われた。

startpython.connpass.com

みんなのPython勉強会は古参のPython入門本「Pythonスタートブック」の筆者と読者の出会いがきっかけで生まれた勉強会である。 ずっと存在は知っていたが、今回のテーマがPython本であったので、参加を決めた。

地図を見ながら迷うって一体と思いつつ無事到着。

Introduction

@tsjshgさんによる「みんなのPython勉強会」の設立の由来などの説明と来月行われる「Pythonオープンサイエンスシンポジウム in つくば」の紹介があった。 飲み会のノリで始まった勉強会がこんなにも長く続くのはすごいことである。

「いちばんやさしいPythonの学び方の作り方」

@takanoryさんによる「いちばんやさしいPythonの教本」の紹介と執筆時に心がけたこと、プログラミングの学び方の発表があった。

gitpitch.com

「オレ凄えって思うことが大事」という言葉が印象に残った。

Pythonエンジニアファーストブック」

speakerdeck.com

@checkpointさんによる「Pythonエンジニアファーストブック」の紹介とWeb開発についての発表があった。 仕事でも実践で使えるように書いた、というのが心強い言葉である。

「Jupyterで始めるPython実践入門」

@nobolis_さんとdrillerさんのPythonとの出会いについての発表があった。 前半2つの発表は本の紹介のウエイトが大きかったが、お二方の発表はPython未経験者がどのようにPythonに触れていったのかという話であった。 お二方は本職がプログラマではなく、必要に駆られて始めたそうである(なのに本が書けるとはすごい)。

パネルディスカッション

@takanoryさん, @checkpointさんに @iktakahiroさんを加えてパネルディスカッションが行われた。

僕はPythonのバージョンとDjangoのバージョンをどのように追従するべきかという質問(のような何か)をした。 答えとしては、自ら音頭を取ってやろう!やらなきゃ!と思うようになった。

懇親会

ビールサーバーとピザがでるという豪華な懇親会であった。 僕自身はお酒が苦手であるのでウーロン茶とピザを堪能した。 ありがとうございます。

感想

執筆した本の紹介そのものはふんふんと適当に流していたが、どのようなことを考えて本を書いたのか、何に気を付けて書いたのか、という話はきちんと聞こうと頑張った。 初心者本は難しいと口にしながらそれに挑んだ筆者たちはすごい。

また、プログラミング言語の学び方というテーマでは発表者の多くが実際に手を動かす派であった。 対立(?)する派閥は言語仕様から入る派であるが、@nobolis_さんから「はやおさんは言語から入る派ですよね」とおっしゃっていただいた。 確かに、「Pythonチュートリアル」から「Python文法詳解」、「Effective Python」と読んで学んでいった。 これは学部や修士課程で恩師から「難しいけれどもきちんとした本を読んだほうが結局早い」という言葉を受けてその通りに行動しているのではと思う。 C言語ならばK&R、Javaならば「プログラミング言語Java」、読んではいないものの「プログラミング言語Ruby」や「プログラミング言語PHP」から入ろうとした。 理論と実践が伴うと最強になれると信じて私は理論から入るのである。

パネルディスカッションで機械学習にともなう数学の学び方の質問があった。

これも「難しいけれどもきちんとした本を読んだほうが結局早い」の一例である。 線型代数は佐武先生の「線型代数学」か斎藤先生の「線型代数入門」を読むべきで、世間一般の線型代数の本は斎藤先生の本を簡略化したものに過ぎないという偏見があるのだが、 機械学習にこれらの本は大げさすぎるだろうか...。

微積分学は「解析概論」か「解析入門」かなあ...とか、位相空間は大人しく「現代数学概論II」の前半、ルベーグ積分伊藤清三先生のを、確率論は伊藤清先生の...と思いつつ「Extremal combinatorics」をパラパラ眺める生活をしている。

最後は話がそれてしまったが、面白い勉強会で参加してとてもよかった。 来月のつくばの会は何とか理由をでっちあげて参加してみたい。でもつくばは遠いなあ。

UUID version 4は衝突するのか?

UUID4が衝突するのか心配で食事も満足にできず夜も寝ることができません

UUID(Universally Unique Identifier)とは汎用識別子であり、 ISO/IEC 11578:1996や、 IETFRFC 4122で仕様が公開されている。

UUID 4の構造

RFC 4122ではいくつかバージョンが定められているが、そのうちバージョン4は122ビットの乱数から生成される。

実際は、UUIDのフォーマット

0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          time_low                             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       time_mid                |         time_hi_and_version   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         node (2-5)                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

の中でタイムスタンプやクロックシーケンス、ノードの値をすべて真の乱数か疑似乱数で埋めたものがUUIDバージョン4である。

Pythonでは簡単にUUID 4を生成することができる。

import uuid

i = uuid.uuid4()
print("time_low:", i.time_low)
print("time_mid:", i.time_mid)
print("time_hi_and_version:", i.time_hi_version)
print("clk_seq_hi_res:", i.clock_seq_hi_variant)
print("clk_seq_low:", i.clock_seq_low)
print("node:", i.node)

実行結果は以下の通りになる。

time_low: 3924201199
time_mid: 64286
time_hi_and_version: 20234
clk_seq_hi_res: 161
clk_seq_low: 137
node: 160669060093137

UUID 4は衝突するのか?

UUID 4を識別子として使うならば、当然それらが被らない、衝突しないことが期待される。 今回は  N 個のUUID 4が生成された場合に衝突する確率を見積もるのが目的である。

 N \geq 2^{122} + 1の場合

UUID 4を 2^{122} + 1個以上生成した場合、UUID 4の全パターンは 2^{122}であるので、確率1で衝突する。 このような論法を鳩の巣原理という。 鳩の巣原理は一見単純ながら面白い定理を証明できたりするのだが本題から外れるので割愛する。

以降、  N 2^{122}以下の自然数を考える。

 N \le 2^{122}の場合

衝突する確率を直接求めるのではなく、余事象である衝突しない確率を考える。 まず、2個のUUID 4を生成してその2つが衝突しない確率は \frac{2^{122}-1}{2^{122}}である。 次に3個目のUUID 4を生成していずれの生成したUUID 4と衝突しない確率は \frac{2^{122}-2}{2^{122}}である。 この論法を繰り返すと、 N 個のUUID 4が衝突しない確率 p_{0}として次の式を得る。

\begin{align*} p_0 = \prod^{N-1}_{k=1}\left(1-\frac{k}{2^{122}}\right). \end{align*}

よって、 N 個のUUID 4が生成された場合に衝突する確率 pは次の式となる。

\begin{align*} p = 1 - \prod^{N-1}_{k=1}\left(1-\frac{k}{2^{122}}\right). \end{align*}

めでたし、めでたし。

確率の評価

衝突する確率を計算できたとは言え、これでは計算が大変である。 そこで、適当な不等式で評価してみよう。

補題: 任意の実数 tにおいて 1 + t \leq e^{t}が成り立つ。

証明:  f(t) = e^{t} - (1 + t)として微分して増減を調べる。

この不等式を使って衝突する確率を評価してみる。

\begin{align*} p \geq 1 - \prod^{N-1}_{k=1}\left(e^{-\frac{k}{2^{122}}}\right). \end{align*}

指数法則より、

\begin{align*} p \geq 1 - e^{\left(\sum^{N-1}_{k=1} -\frac{k}{2^{122}}\right)}. \end{align*}

みんな大好き \sumの計算をすると、

\begin{align*} p \geq 1 - e^{-\frac{N(N-1)}{2\times 2^{122}}}. \end{align*}

これで衝突する確率を下から押さえることができた。

例えば、 N = 10^{10}とすると、 p \geq 9.4 \times 10^{-18} となり、非常に小さい値となる。

本当は指数函数多項式で上から押さえたいのだが、よい方法がない。

結論

UUID 4が衝突する確率は非常に小さく、杞憂である。 ただし、これはあくまでも数学的な話であり、例えば乱数のシードを固定した、UUIDを間違えて使いまわしてしまった場合は衝突する。 また、衝突する確率は0ではないので、絶対に衝突が許されない場合は別の方法を考える必要がある。