華和梨のエントリ集合演算
長いよ。
華和梨のエントリ集合演算は便利だけど、どうもコレを使うと単語の出現確率がコレを使わない場合と異なってくるっぽいので調べてみた。
結果としては、エントリ集合演算を実施するとき、エントリ集合演算の項として出てくるエントリ(たとえば、${hoge + fuga}なら、hogeとfuga)が要素として1つのエントリ呼び出しのみからなる文(たとえば、${foo}とか${buzz})を含む場合、そのエントリを1つのエントリ呼び出しのみからなる文でなくなるまで再帰的に展開してからエントリ集合演算を実施するらしい。
例えば、
テスト: ${testA + testB} testA: ${testC}, ${testD}${testE} testB: さくら, エミリ testC: 双葉, まゆら testD: 青, 黒, どどめ色 testE: うにゅう, ただきち
というエントリがあった場合、testAとtestBがそれぞれ
testA ┬―${testC}┬―→ 双葉 │ └―→ まゆら └―――――――→ ${testD}${testE} testB ┬―――――――→ さくら └―――――――→ エミリ
と展開されて、エントリ集合演算の結果、双葉、ただきち、${testD}${testE}、さくら、エミリの5つの要素からなる集合となって、この中から等確率で1つの要素が選ばれているらしい。
この結果、${テスト}というエントリ呼び出しを実施したとき、双葉、ただきち、さくら、エミリの4人が出てくる確率はそれぞれ20%ずつだけど、${testD}${testE}の文の展開結果として出てくる青うにゅうや黒ただきちなどが出てくる確率は、その組み合わせパターン6種類の合計で20%、個々の単語では約3.7%になるということに。
実際、この${テスト}を3万回エントリ呼び出しした時に出てきた単語の回数は以下の通り。
双葉 | 5965回 |
まゆら | 6115回 |
エミリ | 5988回 |
さくら | 6015回 |
黒うにゅう | 999回 |
黒ただきち | 1008回 |
青うにゅう | 965回 |
青ただきち | 940回 |
どどめ色うにゅう | 1017回 |
どどめ色ただきち | 988回 |
理論的には、双葉、まゆら、エミリ、さくらが6000回、黒うにゅうたちが個々1000回なので、ほぼ理論値通りの結果となっている。
考えてみれば、
テスト: ${testA + testB} testA: ${testC}, ${testD}${testE} testB: "布団がふっとんだ", "シャベルがしゃべる" testC: "ねこがねころぶ" testD: "となりの家に囲いができたってねぇ。", "となりの家に塀ができたってねぇ" testE: "へー。", "かっこいー!"
とかだったら、「布団がふっとんだ」や「シャベルがしゃべる」や「猫がねころぶ」と「となりの家に囲いができたってねぇ。へー。」系統の全体が等確率で出て欲しいのだから当たり前のことなのかも知れない。
おまけ
差集合の演算(-)
エントリ演算は項の展開が終わった時点で実施するので、減算や乗算では注意しないと消したつもりのエントリが出てくることも。
テスト: ${testX - testY} testX: ${testS}, ${testT}${testU} testY: さくら, 黒うにゅう testS: さくら, エミリ testT: 黒, 青 testU: うにゅう, ただきち
とか実施した場合、testXとtestYは
testX ┬―${testS}┬―→ さくら │ └―→ エミリ └―――――――→ ${testT}${testU} testB ┬――――――――→ さくら └――――――――→ 黒うにゅう
と展開されてエントリ集合演算が実施されるので、${テスト2}のエントリ呼び出し結果に${testY}に含まれているはずの「黒うにゅう」が出てきてしまいます。実際に3万回、${テスト2}のエントリ呼び出しを実施してみた結果は以下の通り。
エミリ | 15063回 |
青うにゅう | 3686回 |
青ただきち | 3726回 |
黒ただきち | 3741回 |
黒うにゅう | 3784回 |
エミリの頻度がほぼ50%となるのはエントリ集合演算の結果としてできるエントリ集合の項がエミリ、${testD}${testE}のみとなるから。
積集合の演算(&)
ちなみに乗算も同じなので気をつけないと、出したい項が出てこないなんてことにも。
テスト: ${testM & testN} testM: ${testO}${testP} testN: 黒うにゅう testO: 黒, 青 testP: うにゅう, ただきち
なんてやろうものなら、testMの項の展開結果は${testO}${testP}だけなので、${テスト}のエントリ呼び出しを実施しても黒うにゅうどころか何も出てこないということに。
和集合の演算(+)
和集合の演算でも、
テスト: ${testH + testI} testH: ${testJ}${testK} testI: 黒うにゅう testJ: 黒, 青 testK: うにゅう, ただきち
とかやると、${testI}に含まれる黒うにゅうと${testJ}${testK}の展開結果として出てくる黒うにゅうは別枠扱いになるので、黒うにゅうばかり出てくるようになるので注意。実際に3万回ためした結果は
黒うにゅう | 18735回 |
黒ただきち | 3757回 |
青うにゅう | 3708回 |
青ただきち | 3800回 |
この通り。
とまあ、ここまで調べてから華和梨のドキュメントの「KAWARI Phase8 : KIS Programming Reference」の「2.3. エントリ呼び出し」のところに
エントリ集合演算呼び出しでは、 エントリの持つ文の集合を使って集合演算を行い、 結果として残った文からランダムで1つを選び、 その文を評価した結果を出力する。なお、エントリの持つ文に前述の「純粋仮想単語」が存在した場合、 そのエントリ呼び出しが指定する先のエントリも合わせて展開する。
とちゃんと書いてあるのを発見したわけでorz