ゆくゆくは有へと

おかゆ/オカ∃/大鹿有生/彼ノ∅有生 の雑記

単語長分布の発達的生成法による推定(メモ)

(前略)

単語長分布生成の仮定

  • 新しい単語は可能なら短いに越したことはない。
  • そのため、新しい単語を登録するために、登録者はまず小さい単語空間から順番に走査していく。

パラメータ

  • Xn : 単語長 n の単語空間
  • Sn : 単語長 n の単語空間の大きさ(音韻的にその単語長で理論上登録できる単語の総数)
  • Nn : 単語長 n の既存の単語数

単語長分布生成の方法

  1. はじめ、すべての単語空間に単語は存在しない。
  2. 単語長 1 の単語空間から順に見ていき、その単語を登録できるならば、そこに単語を埋め込む
  3. ダメなら、単語長 2 の単語空間で同じように試す
  4. 単語が登録できるまで順に大きな単語空間での試行を繰り返す。
  5. 次の単語の登録へ(2に戻る)

単語登録の成否に関わる2つのパラメータ

単語の排除体積(バッファ効果)

聞き間違いバッファと同じ意味。理論上、単語空間 Xn には Sn だけの単語が登録できるが、 実際には登録された単語と「近い」音のつづりは今後使われなくなると仮定する。

すなわち、単語は単語空間上において点として存在しているのではなく、いくらかの体積をもった存在としてそこに登録される。

単語長 n の単語の排除体積を v_n とすると、単語空間 Xn の充填率は

v_n * Nn / Sn

となる。単語空間 Xn に新たに単語を登録しようとしたときは、自身の体積と、この充填の様子によって「そもそも登録できるかどうか」がきまる。

クオリティフィルター(冗長嗜好)

単語空間の充填率とは全く関係なしに、つまり、今の単語を登録するのに十分すぎるくらい広い単語空間であったとしても、 必ずそこに登録するとは限らない傾向を表現するパラメータ。

実際的な意味付けはできていないが、大きな単語空間では単語分布が幾何的に減衰していくことから、類推されたパラメータ。

夢をもっていえばエントロピーのようなもの。現実的にいえば、分布の分散と関わるパラメータ。

おそらく、形態論的制約、語形禁則によるドロップアウトも、このクオリティフィルターが担っている(語の質が保証できる確率、ということでクオリティフィルターと名付けている)。

単語登録の成功確率

単語空間 Xn に登録できる確率(厳密には、それ以前の単語空間では登録成功しなかった事象のもとでの条件付き確率)は、

単語空間(とその排除体積)的に登録可能であり、かつ、冗長嗜好にも打ち勝ったとき

の確率に等しい。

ふつう音韻的に、単語空間は指数関数的に増大していくので、ある程度の単語長(n=4でも十分)では排除体積はほとんど無視でき、 採用確率は冗長嗜好に打ち勝つ確率となる(ゆえに、分布のテールは幾何分布的になる)

注意点

この分布生成法では、具体的な単語空間、音韻体系の設定を行わない

必要なのは、各単語空間の広さ、単語の排除体積(その言語における単語同士の近さの忌避具合)、クオリティフィルターくらいであり、それ以上の構造を要請しない。

非常に簡単なモデルだが、「その程度の定量的パラメータだけで単語長分布が決定したら面白い」という目論見からはじまったので、さもありなん。

【golang】レシーバの実引数は値/ポインタを問わないっぽい

まえがき

Pythonのデータサイエンス寄りのところを再復習してて、飽きてきたので他の言語やりたくなった。

F#, Rust, Nim.......。あげく一周回ってGOをやろう。からの疑問点。

本題

まずは引用を。

golang.jp

レシーバとしてポインタまたは値のどちらを受け取るかによって、次の違いがあります。レシーバとして値を受け取るメソッドでは、ポインタまたは値で呼び出すことができますが、ポインタを受け取るメソッドでは、ポインタでしか呼び出すことができません。これは後者ではメソッド内でレシーバを変更可能であるためです。(複製された値に加えた変更は破棄されてしまうため。)

とあるんですが、go 1.10.3 現在だとそうじゃないっぽい・・・?

package main

import (
    "fmt"
)

func main() {
    p := &Grid{5, 2}
    q := Grid{1, 0}
    fmt.Println(p, q)
    p.move(-2, 2)
    q.move(3, 3)
    fmt.Println(p, q)
}

type Grid struct {x, y int}

func (p *Grid) move(x, y int) *Grid{
    p.x += x
    p.y += y
    return p
}

結果がこうなる:

&{5 2} {1 0}
&{3 4} {4 3}

予想:

qGrid構造体のポインタではなく値を束縛してあるので、レシーバにGridのポインタ型(*Grid)を指定しているmoveメソッドが弾かれると予想していた。

実際:

通ったし、ちゃんと破壊的変更されちゃってる。

ええ~~~~~~~~???

もしかして、値で渡しても関数定義の型に従ってポインタが渡されるようになってるのか…?余計なお世話では…?

と思いきや、こちら(関数形式)で渡すとちゃんとエラー吐くことが分かりました。

func main() {
    p := &Grid{5, 2}
    q := Grid{1, 0}
    fmt.Println(p, q)
    p.move(-2, 2)
    (*Grid).move(q, 3, 3)  // ここが変更点
    fmt.Println(p, q)
}
# command-line-arguments
.\main.go:13:14: cannot use q (type Grid) as type *Grid in argument
to (*Grid).move

Grid*Gridじゃないからダメ!!!!!!」ってキレてくる。さっきは優しかったのに!

というわけで、値で渡してもそのポインタを自動的に渡してくれる…という挙動はレシーバ限定っぽい。

考察:なんでそんな仕様なんや

思うに、メソッドチェーンを考えてのことかなと(こなみかん)

Nimのスタートアップ

やっぱ公式を・・・最高やな!(最高ではない)

nim-lang.org

この記事を参考にしようと思ったら、今はなんかインストーラないっぽい:

qiita.com

というわけでやったこと:

  • zipをダウンロードする
  • 解凍して適当なところにフォルダをぶちこむ(おかゆはProgram filesにいれました)
  • 上でぶちこんだフォルダの中のbinまでのパスを通す
  • あと、%USERPROFILE%\.nimble\bin も通せってあったから素直に従う

これでハローワールドしたら「gccがない💢」って怒られたのでもう少し読み進めると

The Nim compiler needs a C compiler in order to compile software. You must install this separately and ensure that it is in your PATH.

HAHAHA このパソコンCコンパイラ入ってなかったんか~い

丁寧にもリンクがあるのでそこからmingWダウンロードして Program filesにぶちこんでbinまでパス通す

"Error: cannot open '[...]main.nim'" って言われる。なんで?

さらにもっと読み進めると、DLL入れて❤ってあったのでダウンロードして、Nimのbinにぶちこむ。「もうすでにそのファイルあるけどええか?」って言われたので上書きする。

もう一度。が、・・・だめ・・・・!!

もしかしてVSCodeが悪いんか?と思って、cmdでやってみたら いけるやないか~~~~~い

Powershellが悪いんやろか…まあとりあえずインスコできた

と思ってたらVSCodeの更新きてたので再起動してもう一度したらいけた。なんかあったんやろか?まあでもいいや

Juliaのスタートアップ

Win 10

これがとても助かりました(神):

自分の PC にインストール · julia について

基本上に従ってやればよくて:

  • ダウンロードしてきてインストール
  • JULIA_HOME, JULIA_PKGDIR環境変数に設定して、JULIA_HOMEをパス通す
  • cmdなりなんなりでjuliaで起動。

プラス、Jupyter で使いたいならもうちょっとだけ続いて:

  • Julia内で、Pkg.init() からの Pkg.add("IJulia"), Pkg.build("IJulia")

Pkg.add("IJulia") でエラー出たけど、書いてある通り、その次の build すればいけた。

jun kenjusi silin nen kinensu jonjomin lokonin pa

nen si netu?

lo lume mo ponpo. po pinsala pinsala po. eto ki kenjusi pupan nen saki wanjo saki. win suwin sin. win wi ponpo pen mun wante. witonun pon kenjusi so na. kon monju ponpiwen lonsu janteli lekun silin. e tonse monju monju wa. manpo sin pimu lewe konpa. imolisen ta wanpa sontajan mo pensi pen. ten pupan manpo. po penjokensa a witonun. kinensu i jan pensi wa. po wa lenpo e. mikun manpo monju i jonjomin so. manpo win panju sunto. ponpiwen wanpa pasuwi lenpo. jupan o ka pa janseju pupan. jan punjujun manpu po win laju jonjomin. minunsutun ken tamo. ku pen lenpo janseju ponpiwen epanso jen. saki ninpu lonsu wine pen nen. nen lontaka mun kinensu pen nen pe. penjokensa wine so wi. mujen man pe i jan lo. sonsisalense sunto sewe najokanan jun sunto kinensu ku. win pupan po kotan pen nen man. jupan jonjomin lewe mikun lokonin wante. pen pasuwi tonpaluna. lo ponpo lume panju monju ki ninjota. ninpu pensi a ponpo wi suwin manja. monju jan win epanso suwin jonjomin nenjo manja. imolisen kawe jan tonse. sunto lonsu wi. pasuwi monju tamonsuwe o tu. wintoson kinsuno kon. pa nen suwin nan si mapan nenjo. we ki wa penjokensa wino manpu we. punjujun na tamonsuwe. man mo pinsala. tan panju tan tu tonpaluna wino sontajan jupin. pa wen tan ki nenjo.

ta kawe wante sontajan eto manja tamonsuwe pe. wa e punjujun ninjota janseju. ninpu pe wanjo wintoson jun minunsutun ponpiwen. pasuwi sonsisalense wine ku. a epanso najokanan ponpiwen. win lewe i kon nin. suwin manja minunsutun pasuwi lonsu. ki imolisen nen witonun sin. kinpu nen kinensu minunsutun sewe tamonsuwe pasuwi sewe. janseju kinpu jonpi epanso. panju manpo tan o lume pen mikun i. monju lan sen janseju mujen eto o sonsisalense. jan mikun janseju nenjo kon we. ten wa ma. jonjomin konpa jun. ponpo tonse wiwi pen i sunto kawe minunsutun. epanso minsa manpu sewe pensesejesa netu ponpiwen.

sewe pe pasuwi so. tamo witonun ma wino mapan jun kotan. po jun najokanan nen jonjomin. nan tonse ma wa kun jenso. pen tan a tonse janteli. ken mapan lon ninpu saki pe wine. pasuwi pasuwi wanpa eton ta pon kun kawe. kinensu wa lume. wen wen sin sin monju lenpo i. ken laju tonse. wintoson i wiwi i wa sonsisalense mun saki. pensi wen wen sonsisalense sewe. lontaka jan silin. pen nin nenjo pensesejesa wi po. ma witonun pen po sewe janseju. janseju minpa ponpo mapan lonsu ki si. lekun tan nenjo jenso lokonin. ponpo pinsala lekun. minunsutun jonpi sontajan kenjusi pon pensi i kinpu. kinsuno mo tamo i. wen tamo pensi jun saki tonse monju.

manja man pinsala ponpiwen a lume wi manpo

min pensi monju na wa nen. manja ninjota i pensesejesa sewe sontajan. mapan lekun po lekun pen. tamonsuwe ta si tonpaluna manja. manpu lewe jan lokonin wanpa jonpi ponpiwen saki. ponpo eto ninpu suwin nan wanjo pipon. wa ku saki sin jan pensesejesa tamonsuwe netu. win i wintoson. kan lan tu e e jonpi minunsutun. jenso monju punjujun. manja minsa manpo najokanan kenjusi konpa wen pe. sonsisalense pipon min wine punjujun mikun lan nan. wanpa jun wanpa ki imolisen nen manpo. eto penjokensa janteli jupin kan we kotan. pinsala ka penjokensa tu. kan i nenjo pinsala pen silin. sin jun nenjo kinsuno pen silin. ponpo lenpo kawe kenjusi manpu. wanjo lon eton pensesejesa. lo jupan pensesejesa ma jupan tamonsuwe man nan. a kan mo pinsala. ka ma so jupan wa tamonsuwe. epanso silin pe wa wino monju lon jenso. minsa wen jen. manpo pe kotan eton netu eto monju kenjusi. lewe pasuwi imolisen ponpiwen epanso. wa ninjota win ma eto suwin sontajan nenjo. panju lonsu lume ma pe. ponpiwen jun eto jen lume i monju. monju jupan minsa mo tonpaluna lan.

sontajan minunsutun jun nan

jun e netu wintoson wino pipon. kenjusi silin tan tu? mun wine sen jupan wanpa epanso na. nenjo konpa minunsutun mo. win ka minsa jonpi pa tamonsuwe penjokensa. jan tamo nan mun jonpi minpa epanso tu! mujen pipon imolisen ponpo we ka jen. win jupan mapan tu witonun ten pa. ta kon ponpo. nin kon mun o ninjota. wino monju pen penjokensa. nen wi lewe. wen tan wanjo wen wen wino. pensi manpo pipon i witonun laju. netu pen a pen na :)

ロジバンで自分の名前を書く(2017/12/3 ロジバンアドベントカレンダー)

ふと思い立って、アドベントカレンダーの記事を書きます!

adventar.org

30日なので、7で割った余りの日の記事にしようと思ったら、埋まってたので、その次の日(12月3日付け)の記事ということで。

まえがき

みなさん、ロジバンやってますか?

私はですね、えっと、去年のアドベントカレンダーの記事を見返してみると:

iuk.hateblo.jp

まあ案の定というか…なんというか…

せめてもの罪滅ぼしに記事を書きます。すみません。

みなさん、名前かいてますか?

新しい言語を学んだとき、多くの人がまずはその言語の綴りで自分の名前を書いてみようという気になると思います。 これはロジバンでも例外ではなく、ツイッターとかを見てても、ロジバン風味のその人の名前を見かけます。

ただ、ロジバンにおけるいわゆる固有名詞というのは、ふつうの言語と比べてちょっと面倒くさいですよね。

たとえば「ゆういち」くんの場合、英語なら"Yuichi" と、頭文字を大文字にするということはあるものの、基本的にローマ字で表記すればOKです。

エスペラントならもう少しだけ厄介で、エスペラントでは名詞は必ず語末がoで終わらないといけないので、oを名前のあとに書き足します。

なら、ロジバンは?というと、ロジバンはその構文的な厳密性のために、文中で名前(名称語とかcmeneとかいう)を使う際にはさらにもう一工夫しないといけません。

そういった厄介なところもあって、『はじめてのロジバン第二版』では、名前の書き方は第二部に回されています。

2. 名称語とアクセント - はじめてのロジバン第2版

名前が書けなくても文法は学べますからね。

とはいえ、やはり我々人間は新しい言語を学べば自分の名前を書きたくなるのが筋というもんです。

ということで、ここでは基本的な読み方は前提として、「どーしても自分の名前をロジバンでいちはやく書きたい」という人のためのちょっとした記事を書くことにします。

発音がわかんないって人は、こちらをどうぞ。

2. 発音とアルファベット - はじめてのロジバン第2版

ルールには大きく分けてふたつある

ロジバンで仕様通り(人工言語ですから仕様があります)に名前を書いて、かつ文の中で使うには、大きく分けて2つのルールがあります。

  • 語の形として正しいか(形態論的に正しいか)
  • 文の中にあらわれる名前の形として正しいか(統語論的に正しいか)

一つ目は、さっきの英語やエスペラントの例であげたような「名前自体」の調整です。促音どうするかとか長音どうするかとか、翻訳先の言葉にうまいこと変換する必要があるのはどんな言語でも同じです。 似たようなことがロジバンでもあって、ただこっちのほうが長いので、とりあえず先に行きます。

二つ目は、文の中できちんと使うための約束があるってことです。もう面倒なのでドンと書いちゃうと、

la [名前] ku

の形にします。名前となる単語を la と ku で囲むというだけです。

※ 正確を期すために補足しておくと、後ろの ku は比較的新しい用法で、対応していない構文解析器もあります。

英語やエスペラント(まあ恐らく他の大抵の言語でも)と異なり、名前の単語だけを文中に用いるのはロジバンでは仕様上正しくありません。

「la と kuで囲む」と覚えていてください。ま、覚えるのもラク(la ku)ですよね(は?)

じゃあ本番にいきます

ここからが長い。なぜかというと、「語の形として正しいか」どうかを見分けるためには、ロジバンにおいて可能な音の並びを全て知っておく必要があるからです(だからこそ『はじロジ』では後に回したわけです)。

で、実際問題、筆者も疲れてきたし(早くない?)、筆者が疲れてきているということは、読者も飽きてきていると思いますので、本当の本当のエッセンスのとこだけかい摘んで話します。 この記事は、言わずもがな日本語で書かれており、ということは多分読者のあなたの名前も日本語ですよね?なので、日本人の名前をロジバン風に変換する方法だけ書いとけば事足りますよね!

というわけで、これだけ守っておけば少なくとも間違いにはならない的なルールを書いていきます。

名前の両端に"."をつけること(ドットサイドルール)

{soras} ではなくて、{.soras.}にしましょうってことです。もちろん理由は構文厳密性のためですが、詳しくは割愛します。

名前の最後は子音にすること

ソラさんは {sora} ではなくて {.soras.} だとか、{.soran.} だとか、とにかく子音を語末につけておきましょう。

もちろん、元々の名前が子音で終わってる人はそのままでOK。カレンさんは {.karen.}でいけます。両端ドットを忘れずに。

ロジバンの綴りのルールに従って音を起こすこと

まあこれは当たり前といえば当たり前ですよね。「ゆな」さんがいたとして、"Yuna"は英語では合っていますが、ロジバンではちがいます(ロジバンでは y は別の音に割り当てられています)。

ユナさんは {.iunas.} とかになります。語末子音はお好きなのを。ロジバンのヤ音は i + 母音 です。ワ音は u + 母音 ですね。

(長音と促音は)ないです

「るー子」さん、ごめんなさい。{.rukon.}とかにしましょう。「ゆっこ」さんもごめんなさい。{.iukos.}とかにしましょう。

ロジバンでは、同じ子音を続けることができないので、「ゆっこ」を iukko とは書けません。

ただ、音的に近くしたいのであれば、たとえば {.iutkon.} とか、そういう方法はあります。

母音は基本的に連続しません

ヤ音やワ音の『子音』(正しくは半母音ですが)として i や u を使う以外で、母音(a, e, i, o, u)を連続することは少数の例外を除いてダメです。

少数の例外は覚えてください! ai, ei, oi, au の4つです。アシカにでもなった気分で声に出して覚えましょう(あ、でもアシカは「オゥ」か)。

じゃあ日本語の名前で母音が連続する人はどうすればいいのか?というと、アポストロフィ(hの音)で区切ってください

たとえば、アオイちゃんは、aoi ではなく、{.a'ois.} とするのが安全です(oiは少数の例外なのでセーフ)。

ユウイチくんは、{.iu'itcis} とかが安全でいいと思います。

ちなみに、ヤヨイちゃんは、{.iaiois.}とかなり再現性高く綴れます。なんでなのか少しだけ詳しく見てみると、

  1. 最初の ia はヤで確定
  2. その直後の i はこの時点では2つの可能性がある:前の「ヤ」と繋がって「ヤィ」か、新しいヤ音の始まりになるか。
  3. o がくると、さっきの i の前者の可能性がなくなる。「ヤィオ」はありえないので、「ヤヨ」に確定。
  4. is。これはヨにつづいて、「ヤヨィス」となる。

と、母音が基本的には連続しないという約束のおかげで、ヤヨイと読めるようになっています。

でも、いちいちこの分析をするのは面倒かも…?と思ったヤヨイちゃんは、音節区切り明示のカンマを使いましょう。カンマによって新たな読みを示すことはできません(と思っておいたほうが安全)が、上のような分析を相手に強いる心配がなくなります。

{.ia,iois.} は、{.iaiois.}と音として全く同じです。ただ読みやすいってだけです。

カンマの詳細な使用法については、以下の議論も参考にしてください(親切でいうと、初学者は特に気にしなくていいです):

groups.google.com

おわり?

たぶん終わり。本当はここにさらに「連続してはいけない子音の列」という話が入りますが、日本語名のロジバン名化に限ればその話をしなくても大抵対応できるんじゃないかと思います。

パラシェルターの傘開き時間とインク消費の関係性について

要約

傘を1秒開くと、メイン弾約4発分(メイン効率無積みなら20%)消費する。

動機

発端はこれ

傘が開いてる間、インク漏れてるってことがあんまり知られてなかったことにも驚き(みんなほんま使ったことないんやな)だったけど、

傘がオープン中のインク消費量がググってもでてこないことのほうが驚きだったよ!とっくに調べられてると思った(情報あったら教えてください)

というわけで、傘開き時間とインク消費の関係性について調べました。

調べ方

  1. 傘が開いた瞬間に、僕の人差し指がストップウォッチのスタートを押す
  2. 適当な時間経ったのち、僕の人差し指がストップウォッチの停止を押すと同時に傘を開くのをやめる
  3. 残りのインクを、すべてメイン弾で消費し、どれだけの弾数が必要だったかを数える(タンクに残った微妙なインク量は目視で適当に加算)

キャプチャーボードもないので、測定方法があまりにもガバガバですが、目安くらいにはなるかと思います。

なお、今回はメイン効率無積みで行っています。

結果

42回ほど測定しました。どうやら直線関係のようです。一部、階段のようになっていますが、これはタンク内部のインク量を正確に見積もれてないからだと思います。

f:id:waraby0ginger:20171111060541p:plain
傘開き時間(秒)とインク消費量(メイン弾換算)の関係

直線関係なので、比例式でフィッティングさせたところ、y = 3.85 x 程度となり、それらしい値が求められました。R2見ても、いい感じでしょう。

考察と感想

まず事前情報です:

  • メイン効率無積みの場合、傘のメイン弾は20発撃てる(つまり、1弾あたりのインク消費量は5%)
  • 傘がパージするまでフルで開いた場合、約1.65秒で、メイン弾換算にして6発分になる
  • インク効率をいくつか振ってフル開きの場合のみ試してみたが、どの状態でも開いてからパージするまでに消費するインク量は、そのときのメイン弾換算で6発

精度について。他の検証などを見てても、パラメータは大体小数点以下1桁くらいまでで設定されてるように思います。ただ今回は測定精度がそんなによくないことも踏まえると、「ほぼ4発分」くらいだと考えるのが一番無難かなと思います。

その場合、パージまで傘を開いたときを計算すると、4 * 1.65 = 6.6となり、1発分ズレますが、それなりに当たっています。

さて、関連で2つ動画を載せます:

まず1つ目について。これくらいの一瞬よりは少し長めくらい開くというのを繰り返した場合、0.25 秒くらいだとして、20 / (1 + 3.85 * 0.25) = 10.19 発撃てることになります。

次に2つ目。これくらいのスパンで開いた場合、0.1秒くらいだとして、20 / (1 + 3.85 * 0.1) = 14.44 発程度撃てる計算になります。大体近い値にはなってるかなという感じです。

話は変わって、メイン弾の連射速度は約2発/秒なので、1秒で4発分消費する傘開きは、普通に連射する場合の2倍のインク消費速度ということになります。結構エグい。

「ポイズンミストを投げると傘は溶ける」を発端とした検証だったので、できればそこまでしたかったですが…やむなし。誰かやってくれませんか?ポイズンミストでインク消費量がどれだけ倍増するのかが調べても出てこなかったんですが、2倍ってことはないよね…?それでも仮に1.5倍消費量増えると考えると、インク効率無積みでメイン弾 7.5%、傘開き 30%/秒となり、いや~~~シビアっす。30%て。

補足

1.65秒で6発分、しかも原点通る直線に従うってことなら、これだけでも値は出せて、6 / 1.65 = 3.64 くらいです。実は 3.75 とかが実際のパラメータなのかしら。