*エントリ集合演算について [#e6d7a0af] アリス「ねぇ、ボブ。」~ ボブ「どうしたんだい、アリス?」~ アリス「華和梨のエントリ集合演算を使ってみたら、使う前と文(単語)の呼ばれる確率が変わっちゃったんだけど。」~ ボブ「HAHAHA! しょうがないなあ、アリスは。じゃあ、ボクがエントリ集合演算について解説してあげるよ。」~ アリス「さすがボブね!」 *目次 [#ccdebfc4] #contents *エントリ集合演算の基礎 [#b1c1027a] まず、以下のような置換子を含まないエントリ定義が存在するとします。 野菜: きゅうり, なす, スイカ, トマト 果物: りんご, みかん, なし, スイカ, トマト **和集合演算'+' [#s0627fbe] 和集合演算'+'では、演算子'+'の左辺のエントリに登録されている文の集合と右辺のエントリに登録されている文の集合のいずれかに含まれる文の集合からランダムに一つの文が選ばれます。~ 「野菜」、「果物」のエントリに対して、${野菜 + 果物}というエントリ集合演算を実施することを考えます。~ 演算子'+'の左辺のエントリに登録されている文と右辺のエントリに登録されている文は 左辺=「野菜」エントリに登録されている「きゅうり」、「なす」、「スイカ」、「トマト」 右辺=「果物」エントリに登録されている「りんご」、「みかん」、「なし」、「スイカ」、「トマト」 なので、${野菜 + 果物}の結果は、「野菜」エントリと「果物」エントリのいずれかに含まれる文の集合、すなわち、 きゅうり, なす, スイカ, トマト, りんご, みかん、なし の7つの文からなる集合から一つの文が等確率なランダムに選ばれます。「果物」と「野菜」の両方のエントリに含まれているからといって「スイカ」や「トマト」が選択される確率が2倍になったりはしないことに注意してください。~ 実際に3万回実施してみた結果は下記の通り。7つのエントリがほぼ1/7の確率ずつに選ばれているのがわかります。 |文|回数| |きゅうり|4168回| |なす|4415回| |スイカ|4290回| |トマト|4297回| |りんご|4246回| |みかん|4243回| |なし|4341回| ちなみに、出てくる文の候補は同じことであっても、 野菜か果物: ${野菜}, ${果物} のエントリ呼び出しを実施したときと、${野菜 + 果物}のエントリ呼び出しを実施したときでは個々の文の出てくる確率が変わることに注意してください。~ これは、${野菜か果物}では、${野菜}か${果物}が1/2ずつの確率で選ばれてから、${野菜}なり${果物}なりが評価されるためです。このため、「野菜」エントリと「果物」エントリに含まれる文の数の差により、「野菜」エントリに登録されている「きゅうり」、「なす」の出現頻度は、「果物」エントリに登録されている「りんご」、「みかん」、「なし」より高くなり、さらに、「野菜」エントリにも「果物」エントリにも登録されている「スイカ」や「トマト」の出現頻度は著しく大きくなります。~ 実際にやってみた結果は以下の通り。 |文|回数| |きゅうり|3690回| |なす|3747回| |スイカ|6797回| |トマト|6774回| |りんご|2995回| |みかん|2970回| |なし|3027回| ~ **差集合演算'-' [#n49393b6] 差集合演算'-'では、演算子'-'の左辺のエントリに登録されている文の集合のうち、右辺の登録されている文の集合には含まれていない文の集合からランダムに一つの文が選ばれます。~ 「野菜」、「果物」のエントリに対して、${野菜 - 果物}というエントリ集合演算を実施することを考えます。~ 演算子'-'の左辺のエントリに登録されている文と右辺のエントリに登録されている文は 左辺=「野菜」エントリに登録されている「きゅうり」、「なす」、「スイカ」、「トマト」 右辺=「果物」エントリに登録されている「りんご」、「みかん」、「なし」、「スイカ」、「トマト」 なので、${野菜 - 果物}の結果は、「野菜」エントリに登録されていて、かつ、「果物」エントリには登録されていない文の集合、すなわち、 きゅうり, なす の2つの文から一つが等確率なランダムに選ばれます。実際に3万回実施してみた結果は下記の通り。「きゅうり」と「なす」がほぼ50%ずつの確率で選ばれます。 |文|回数| |きゅうり|15036回| |なす|14964回| ~ **積集合演算'&' [#aafdb5ef] 積集合演算'&'では、演算子'&'の左辺のエントリに登録されている文の集合と右辺のエントリに登録されている文の集合の両方に含まれる文の集合からランダムに一つの文が選ばれます。~ 「野菜」、「果物」のエントリに対して、${野菜 & 果物}というエントリ集合演算を実施することを考えます。演算子'+'の左辺のエントリに登録されている文と右辺のエントリに登録されている文は 左辺=「野菜」エントリに登録されている「きゅうり」、「なす」、「スイカ」、「トマト」 右辺=「果物」エントリに登録されている「りんご」、「みかん」、「なし」、「スイカ」、「トマト」 なので、${野菜 & 果物}の結果は、「野菜」エントリと「果物」エントリの両方に含まれる文の集合、すなわち、 スイカ、トマト の2つの文から一つが等確率なランダムに選ばれます。実際に3万回実施してみた結果は下記の通り。「スイカ」と「トマト」がほぼ50%ずつの確率で選ばれます。 |文|回数| |スイカ|15077回| |トマト|14293回| ~ **複数のエントリ集合演算子からなる式 [#h39ca56d] エントリ集合演算の演算子の左辺や右辺にはエントリ名だけでなく、エントリ集合演算の式を記述することができます。たとえば、 果物: きゅうり, なす, スイカ, トマト 野菜: りんご, みかん, スイカ, トマト 主食: 米, パン 野菜: きゅうり, なす, スイカ, トマト 果物: りんご, みかん, なし, スイカ, トマト ナス属: なす, トマト というエントリが存在する場合、${主食 + 野菜 & 果物}というエントリ集合演算の式を記述することができます。~ このとき、普通の算数の式で掛け算が足し算や引き算に優先するように、エントリ集合演算でも、'&'演算は'+'演算や'-'演算よりも先に実施されます。たとえば、${主食 + 野菜 & 果物}の場合、まず、"野菜 & 果物"を実施してから、"主食 + "野菜 & 果物"の結果"を実施します。~ この優先順位に関する詳しい話については華和梨のドキュメントを見ておいてください。 というエントリが存在する場合、${野菜 - 果物 & ナス属}というようなエントリ集合演算の式を記述することができます。~ このとき、普通の算数の式で掛け算が足し算や引き算に優先するように、エントリ集合演算でも、'&'演算は'+'演算や'-'演算よりも先に実施されます。たとえば、${野菜 - 果物 & ナス属}の場合、以下のようになります。 ***1.「果物 & ナス属」を実施する。 [#ga78b483] エントリ集合演算子"&"の左辺と右辺に登録されている文はそれぞれ以下の通り。 左辺=「果物」エントリに登録されている「りんご」、「みかん」、「なし」、「スイカ」、「トマト」 右辺=「ナス属」エントリに登録されている「なす」、「トマト」 したがって、このエントリ集合演算の結果できる文の集合は左辺と右辺の両方の文の集合に含まれている トマト になります。 ***2. 「野菜 - 「果物 & ナス属」の結果」を実施する。 [#g3193795] 次に、「野菜」エントリに登録されている文の集合と「果物 & ナス属」の結果の文の集合の差集合演算"-"を実施します。 左辺=「野菜」エントリに登録されている「きゅうり」、「なす」、「スイカ」、「トマト」 右辺=「果物 & ナス属」のエントリ集合演算結果である「トマト」 したがって、このエントリ集合演算の結果できる集合は、左辺の文の集合の中で右辺の文の集合に含まれていない きゅうり、なす、スイカ の集合になります。3万回実施してみた結果は以下の通り。 |文|回数| |きゅうり|10106回| |なす|9916回| |スイカ|9978回| ~ >次からが本題 *置換子を含むエントリに対するエントリ集合演算 [#a5ebfb10] エントリに登録されている文が置換子(${ほげ}などのエントリ呼び出しのこと)を含む場合には以下の規則が適用されます。 -"${柑橘類}"などのように単独のエントリ呼び出しからなる文は、それをさらに展開する。その展開先がやっぱり単独のエントリ呼び出しからなる場合には同じように展開を続ける。 -"${状態}バナナ"などのように置換子を含む文は展開しない。 というわけで、たとえば、 うにゅう族: うにゅう, ${うにゅう以外}, ${カラー}うにゅう カラー: 黒, どどめ色, レインボー, 白 うにゅう以外: ただきち, うにゃん というエントリが存在していて、これがエントリ集合演算の左辺や右辺に出てくる場合、「${うにゅう以外}」はエントリが展開されて「ただきち」、「うにゃん」という2つの文として扱われ、「${カラー}うにゅう」は「${カラー}うにゅう」として解釈され、結果、 うにゅう, ただきち, うにゃん, ${カラー}うにゅう という文の集合として扱われます。~ これにより、以下の2つの事象が発生することに注意してください。 **文の出現確率に関する事象 [#ua3e40e1] うにゅう族: うにゅう, ${うにゅう以外}, ${カラー}うにゅう カラー: 黒, どどめ色, レインボー, 白 うにゅう以外: ただきち, うにゃん さくら側: さくら, 双葉, エミリ というエントリ群が存在したとき、${さくら側 + うにゅう族}というエントリ集合演算を実施した場合、その実施結果として、 うにゅう, ただきち, うにゃん, ${カラー}うにゅう, さくら, 双葉, エミリ という7つの文の集合となります。~ 結果、黒うにゅう、どどめ色うにゅう、レインボーうにゅう、白うにゅうの4つがエントリ集合演算として出てくるとき、それは、最初に、「うにゅう, ただきち, うにゃん, ${カラー}うにゅう, さくら, 双葉, エミリ」の集合から「${カラー}うにゅう」が選択された上で、さらに、「黒うにゅう, どどめ色うにゅう, レインボーうにゅう, 白うにゅう」の中から一つが選ばれた結果としての出力であるので、その出現確率は他の「うにゅう, ただきち, うにゃん, さくら, 双葉, エミリ」の6体に比べて1/4に落ちてしまいます。~ 実際にやってみた結果も以下の通り。 |文|回数| |うにゅう|4307回| |ただきち|4316回| |うにゃん|4287回| |黒うにゅう|1135回| |白うにゅう|1039回| |どどめ色うにゅう|1021回| |レインボーうにゅう|1086回| |さくら|4238回| |エミリ|4240回| |双葉|4331回| というわけで、同じ置換子を含む文でも、ただ一つの置換子から成り立っている文かそうでないかによって扱われ方が異なるのです。 **演算対象に関する事象 [#x4293439] うにゅう族: うにゅう, ${うにゅう以外}, ${カラー}うにゅう カラー: 黒, どどめ色, レインボー, 白 うにゅう以外: ただきち, うにゃん 特別なうにゅう: 白うにゅう, 黒うにゅう というエントリ群が存在したとき、${うにゅう族 - 特別なうにゅう}というエントリ集合演算を実施した場合を考えます。~ このとき、"-"演算子の左辺と右辺の文の集合は以下のようになります。 左辺=うにゅう, ただきち, うにゃん, ${カラー}うにゅう 右辺=白うにゅう, 黒うにゅう これらの文の集合に対する差集合演算の結果は、 うにゅう, ただきち, うにゃん, ${カラー}うにゅう となります。この中で、「${カラー}うにゅう」という文は、その展開結果に「特別なうにゅう」エントリに含まれる「黒うにゅう」や「白うにゅう」といった文が含まれます。~ つまり、「特別なうにゅう」エントリに含まれる文であるはずの「白うにゅう」や「黒うにゅう」が${うにゅう族 - 特別なうにゅう}のエントリ集合演算の結果として出力されてしまいます。 |文|回数| |うにゅう|7523回| |ただきち|7420回| |うにゃん|7479回| |どどめ色うにゅう|1901回| |レインボーうにゅう|1875回| |白うにゅう|1912回| |黒うにゅう|1890回| とまあ、この通り。 同じことは、積集合演算でも言えるので、${うにゅう族 & 特別なうにゅう}とやっても、左辺と右辺の展開結果に共通するものはない、ということになり、${うにゅう族 & 特別なうにゅう}というエントリ集合演算はその結果として何も返してはきません。 *ところで3万回とかってどうやって試したんだよ! [#v70f4c5f] こうやりました。 テスト実施: $(呼出回数テスト テスト 30000) テスト: ${野菜 + 果物} 野菜: きゅうり, なす, スイカ, トマト 果物: りんご, みかん, なし, スイカ, トマト =kis function 呼出回数テスト $( .cleartree テスト結果; loop $@arg[2] $( .setstr @tmp ${$@arg[1]}; .inc テスト結果.${@tmp}; ); .clear @テスト結果表示; .listtree @テスト結果表示 テスト結果; foreach @i @テスト結果表示 $( .echo ${@i}":"${${@i}}"回\n"; ); ); =end *コメント [#ibb7e2b5] #comment