重婚クラスタ循環の世代分割問題をクリア

重婚クラスタ循環を世代分割するという課題を原理的にクリアして,そのブラッシュアップを進めているが,BuildSameGeneMarriageGraphで無限ループするようになってしまった.どこかでミスっているのだが,どこで失敗しているのか特定できない.やむを得ず昨日の修正を一旦破棄して,2021-01-28の始業時バックアップに戻ることにする.昨日はまったくログを取っていないので,修正手順を再現しながらステップを追って点検してみよう.⇒バックアップはとりあえず動いている.ここからもう一度出直すことにしよう.先に進む前にまず,足元を固めるために,仕掛りになっている部分をフィックスしてしまった方がよいと思う.以下のような懸案事項がある.

  1. SIMPLEGRAPHのattributeを廃止@20201105 抽象グラフ検証系でオブジェクトではない一般データを扱えるようにするための修正だが,方針を変えて,attributeとncidを併用する方式に切り替える必要がある
  2. グラフのattributeはこれまで有意に使用されていなかったが,「多重枝」を扱う必要があり,有向グラフと無向グラフを峻別する必要も出てきたのでより重要性が増している 自己ループという属性もある
  3. SIMPLEEDGEの持っている(一部)属性をアプリに開放し,アプリが自由に使える領域に指定する 逆にグラフ検証系ではこの「ユーザパラメータ」は操作しない
  4. SIMPLEGRAPHクラスを基本クラスと応用クラスに再編する 前にUNDOシステムで行った改編と同様趣旨の修正を行い,SIMPLEGRAPHの抽象度を高める
  5. adjustGenerationRangeを停止する@20210117 動作的にはこの関数をNOPにしても問題は生じていない これが正しいとすれば,系列枠クラスのいくつかのパラメータを廃止してadjustGenerationRangeを完全に破棄すべきだろう
  6. 不可避の多重カード数と重婚クラスタ循環を分解するために除去される最小枝数が完全に一致するという予測が出てきた
  7. 重婚クラスタ循環が存在する場合と存在しない場合の論理を統合する
  8. 右手配偶者が左手本人で停止しない@20210108

結構クリティカルな修正だが,まずこれらを片付けてから前に進むのがよい.その前に上記を除く仕掛りを現状でフィックスしておこう.

  1. 重婚クラスタ循環を解決する@20210127 1箇所
  2. sameGeneCyclesを無視する@20210127 3箇所
  3. 仮修正 4箇所,暫定

まず項目1から始めよう.この修正は簡単なので,オプションを廃止し,コードを直接修正することにする.⇒しかし,これには昨日の「initializeではSIMPLEGRAPH:attributeを更新しない@20210128」が関係するので,まず,この修正を入れておいた方が安全だ.attributeはオブジェクト生成時に指定するか,ないしsetAttributeで明示的に設定するかのいずれかに限定するというのがこの修正だ.この修正は8箇所ある.⇒修正した.この修正はこのままフィックスする.⇒これでグラフ検証系で非モノデータを扱える準備ができた.

項目2 ⇒これは昨日の修正「無向グラフでは並行枝を登録しない@20210128」に関わりがあるので,後回し.項目3,ユーザに解放する領域(ユーザ変数)とは以下を言う.

  1. nodule *reffer;    // 参照ノード1
  2. nodule *reff2;    // 参照ノード2
  3. int usable;        // 有効な枝
  4. int nouse;            // 切断された枝
  5. int circular;        // 循環する枝(閉路上の枝)
  6. int selfloop;        // 自己ループ枝

これらはユーザが独自に定義して自由使用できる変数とし,アクセス関数は設けない.ただし,selfloopはグラフ処理系でも判断できるので,グラフ関数で設定した方がよいかもしれない.SELFLOOPGRAPHというグラフ属性を追加したので,selfloopはSELFLOOPGRAPH属性を持つグラフに対してのみ許すとした方がよいと思う.circularを閉路上の枝と定義すれば,グラフ処理系で操作する対象となるが,この変数は必ずしも閉路上の枝にかならず設定されるというものではないので,やはりアプリ側で管理するとした方がよい.現行ではおおよそそのような棲み分けになっていると思われるが,項目4を実施すればはっきりするだろう.

その前に昨日の修正「無向グラフでは並行枝を登録しない@20210128」を片付けておこう.⇒修正はSIMPLEGRAPH::addとfindedgeの2箇所だけだ.⇒問題なく動作している.現行では有向グラフを使っているのはTribeTreeGraph(系列木枝グラフ)だけのようだ.しかし,多重グラフ2も有向グラフのはずなので,設定してみよう.まずい.どこかで問題のある修正を入れてしまっているようだ.重婚同類=0 多重=10になってしまっている.上記の「無向グラフでは並行枝を登録しない@20210128」という修正だ.⇒初歩的な論理ミスがあった.

多重グラフ1(婚姻関係グラフ)で「ループフリーグラフで自己ループ枝の登録は不可」というエラーが出ている.婚姻グラフでは単身婚を自己ループとして登録している.この枝を弾いても動作にはほとんど影響は出ていないものと見られるが,単身婚以外の結婚を持たないノードの子ども世代とこのノードの親ノードの世代で重婚クラスタ循環が起きる可能性はゼロとは言えないので,このグラフが自己ループを持つのを認めることにしておこう.

系列木グラフでも同様のエラーが出ている.系列木グラフでは始系列を自己ループで登録している.これはこれでよいのではないだろうか?系列木グラフにもSELFLOOPGRAPH属性を与えておくことにしよう.グラフが大分精密に操作できるようになってきた.項目6の「不可避の多重カード数と重婚クラスタ循環を分解するために除去される最小枝数の一致」という予測を確認するためには昨日の修正を入れてみる必要がある.「多重婚配偶者は切り離す@20210128」という修正だ.⇒どうもこの修正はまだ収束していないようだ.

TestInevitableMultiZeroに入って,TestStronglyConnectedで停止してしまう.BuildSameGeneMarriageGraphのループでTestStronglyConnectedでなくなるまでループしても同じ結果になる.これは,BuildSameGeneMarriageGraphの出口で循環を停止するために除去した枝を戻しているために起きているが,除去される枝はすべて循環の原因となる親子枝であり,この循環は婚姻関係グラフで障害ノードを切り離すカットセット枝をすべて除去しているのだから,循環枝を戻しても再び循環が起きることはないはずなのだが…

コード的には「多重婚配偶者は切り離す」という論理を追加しない方がシンプルであり,ある意味でこれで十分だとは思われるのだが,なぜエラーが発生するのかその理由だけは調べる必要がある.BuildSameGeneMarriageGraphのループのボトムでRetrieveRemovedEdgeを実行すると,今度はループが停止しなくなる.循環枝は9本で,多重配偶者を3件処理している.

  1. card=CARDLINK:#410 @3桐壷の更衣[0] wife=#408 桐壷院 @2
  2. card=CARDLINK:#554 @75葵の上[0] wife=#406 光源氏 @1
  3. card=CARDLINK:#656 @126源氏宮[0] wife=#488 朱雀院 @42

この後,【CARDLINK:#406 @1光源氏[0]】⇒【CARDLINK:#414 @5紫の上(若紫)[0]】の循環枝の処理に失敗してループしている.この親子枝はすでに一度処理されているものなのだが,なぜかぶり返している.光源氏は循環枝の親としてすでに2回登場しているので,光源氏の配偶者はすべて光源氏のブロックに移動しているはずなのだが,紫の上は光源氏の配偶者であると同時に養女でもあるので,配偶者として移動してもそのブロック内で自己ループになるということは考えられる.しかし,だとすれば,この手法を使わない場合でも同様のことが起きなくてはならないのだが,そうならないのはなぜか?

いや,逆に言うと,既定の方式でなぜ問題が解けているのか?という方が疑問だ.既定の方式では光源氏と紫の上は同じクラスタに残るはずであり,そのクラスタでもう一度自己ループが発生してもおかしくないのだが… できるものなら,この重婚クラスタ図をZTを使って表示してみたいのだが… 重婚クラスタ図は原理的に系統図とまったく同じなので,接続関係をZTに渡すことができれば描画は容易にできるはずだ.一つのアプリで2つの系図を同時に開くことができればそれも可能だが,現状では直ちには応じることはできない.

一覧表形式にして出力することは不可能だろうか?かなり面倒くさそうだが,不可能ではないと思う.CSVで出力できれば別アプリで開くこともできる.やってみる価値はあるとは思われるが,そのためにはかなりの準備が必要だ.いや,思ったより簡単なのではないか?重婚クラスタ図には親子関係しかないので,系図データとしてはかなり単純なものになるはずだ.この図面のノードはクラスタでそれに親子関係を与えたものがクラスタ図になる.ただし,この図面ではそのクラスタに含まれる結婚までは分からない.それをチェックするだけなら,むしろ既存のダンプルーチンで十分だ.

とりあえず,重婚クラスタグラフの連結成分リストをダンプすればよいのではないか?ループ出口では重婚クラスタグラフの連結成分リストは空になっている.むしろ,婚姻関係グラフの連結成分リストを見た方が早い.⇒光源氏と葵の上は同じクラスタ,紫の上,藤壷の宮などは孤立ノードになっている.以下のようなクラスタが存在する.

  1. 桐壷院,桐壷の更衣
  2. 朱雀院,源氏宮
  3. 式部卿宮,紫の上の母
  4. 明石入道,明石の尼君
  5. 紅梅,真木柱,蛍兵部卿宮
  6. 光源氏,葵の上
  7. 摂政太政大臣,大宮
  8. 柏木,落葉の宮,夕霧,雲井の雁
  9. 按察大納言(桐壷),桐壷の更衣の母
  10. 今上,明石中宮
  11. 匂宮,中姫君,匂宮の北の方,浮舟,薫,女二宮
  12. 冷泉院,秋好中宮,王女御,弘徽殿女御,冷泉院の御息所
  13. 按察の大納言(若紫),北山の尼君
  14. 先帝,先帝の后宮[0]
  15. 春宮,春宮の女御,麗景殿女御
  16. 二宮,二宮の北の方

意外に細分割されている.光源氏+紫の上の関係が切断されるのは,葵の上→夕霧という親子関係から,葵の上の配偶者光源氏の配偶関係が切断されることによって初めて発生する.従って,葵の上→夕霧という関係が存在していなければ同じ障害が発生する可能性はあるように思われる.従って,選別的に切断するのであれば,「多重婚配偶者」ではなく,むしろ「親子関係にある配偶者」ないし,「直系血族関係にある配偶者」を切断しなくてはならないということになるはずだ.

直系血族関係をチェックする既存関数としてIsAncestorOf,IsMyParentがある.前者は主語の下流系を探索し,後者は上流系を探索するもので,組み合わせればよさそうだが,前者はすべての人名リンクを探索しているので今の場合には適切ではない.後者は無効カードを除外しているが,特殊な場面で使うことを予定しているため応用できない.新たに一つ作ってみよう.⇒CARDLINK::IsMyAncestorという関数を新設した.IsAncestorOfとは逆に上流方向を探索するものになったが,紫の上を「直系血族配偶者を発見」として検出できている.

IsAncestorOfは現在使われていない関数だが,TestInevitableMultiZeroのすぐ下にあったところから推測して,重婚クラスタ検定の中で使う意図で開発されたものと思われる.クラスタの親子関係接続による循環を検査すればこと足りるということになって放置されていたのだろう.一応これで解決を得たが,このアルゴリズムで完全と言えるかどうか?については,確信が持てない.一番確実なのは,配偶者→配偶者の配偶者の枝をカットするのではなく,本人周辺の枝をカットして孤立ノードにしてしまうというのが一番確実なのかもしれないが…

祖父が孫と関係するなどのこともあり得るので,親子関係だけでは十分ではないということだけは確実だ.現行論理でも直系血族間で婚姻関係があれば,必ずクラスタ循環が発生するから検出は可能だが,現行のやり方では解けない場合が出てくる可能性がある.循環は垂直性の循環なのでそのどこを切っても循環は一応止まるが,解決にはなっていない.そのようなことが起こり得るということは上の例からも明らかだ.

現行では親ノードの配偶者をカットしているが,むしろ子どもの配偶者をチェックすべきではないだろうか?この方が確実にカットできるような気がする.親ノードの配偶者を周辺で切り取り,子ノードの直系血族配偶者をカットというのがわかり易いような気がする.⇒実装した.多分これが正解だと思う.循環枝を1本処理した段階で一度ループから離脱して検定を再実行するようにして,処理された循環枝3,削除された枝6に変化した.出力にも少し変化が現れた.

image

多重になっているのは,光源氏,藤壷の宮,柏木の3件だ.これらのカードが多重になっている原因は,光源氏の場合,紫の上が養女であるという直系血族との婚姻,藤壷の宮の場合は桐壷院・光源氏という親子との三角関係(俗に言う親子丼),柏木のケースは配偶者の落葉の宮と女三宮がいずれも重婚者,つまりダブル三角関係という同情の余地もない情況だ.図面も以前出ていたものとは大分トポロジーが変わっているが,今回の方がよりわかり易くなっているのではないかと思う.多分これが重婚クラスタ循環問題についての最終解となるだろう.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA