「直属系列落ち」というオプション

ゼルコバの木では本人(基準ノード)の(もっとも遠い)先祖の直系血族とその配偶者の集合を標準家系図と呼んでいる.系図全体をこのような標準家系図(系列)の合成とみなすというのがゼルコバの木の基本的な立ち位置だ.ある先祖ノードの標準家系図は系列であり,先祖ノードの数だけ系列が存在する.この意味で系列の位置関係を決定することがゼルコバの木の課題であると言える.これを系列再配置問題と呼ぶ.

各系列において標準家系図の基準ノードに相当する人名を系列優先ノードとする.人名は複数の先祖を持つ場合があり,また他系列のノードと婚姻関係を持つことがあるので,同じ人名が複数の系列の中に登場する場合がある.もし二つの系列の間にこのような重複する人名が存在しないとすれば,その二つの系列には何のつながりもない.

通常は全体図に含まれるほとんどの系列は何らかの繋がりを少なくとも他の系列に一つは持っている.始系列(基準ノードの標準家系図)を除く(孤立していない)すべての系列の優先ノードはこのような重複人名カードの中から選択される.このような重複するカード(多重カード)を図面上から消去して多重ゼロの状態にすることが系図作成の目標であり,系図の品質を評価する最大の基準である.

系列優先ノードは複数の系列と関係を持っている可能性はあるが,それらのうち始系列にもっとも近いものを選択してその系列の主系列とし,その系列を(主系列の)従系列とする.系列を節点とし,系列の主従関係を枝とするグラフが木になることは容易に示すことができる.(ただしここではグラフは連結であることを仮定する)

系列再配置の基本は系列を主系列の近傍に配置すること,主系列に出現する系列優先実ノードと従系列に出現する仮ノードの世代を一致させることの2点だが,それだけでは多重を解消することはできない.場合によっては優先ノードを切り替える必要が生じることもある.

多重カードを解消するための配置を決定するという問題はとても難しく,当初はいわゆる日本的職人芸(Japanese craftmanship)で解決しようとしていたのだが,どうしても埒が明かないということが分かったので,方向転換し,もう少し「数学的」に考えることにした.

その結果,①オブジェクトの移動には垂直と水平の2方向があり,これらは独立に操作できること(なぜなら「直交」しているから),②多重に関係するのは垂直方向の操作だけであることが分かった.さらに,比較的最近になってから③重婚同類グラフが循環することが多重の原因であり,重婚同類循環が存在する場合にはどんなことをしても多重を解消できないということが明らかになった.

重婚同類グラフ検定はグラフの静的な検査なのでメインループに入る前の予備検定でストレートに計算を完了することができる.従って,系列再配置は水平方向の調整を行うだけのものになった.水平方向の移動では2つのことが起きる.一つは系列間の衝突であり,もう一つは乖離だ.

このような問題の最適解を得る方法は知られていないので,基本的には漸近法を適用して解を求めるしかない.これを行っているのが,ApproximationとSolveBondedTribeCollisionという2つの関数だ.前者は系列間の乖離の解消を担当し,後者は衝突の回避を図るものだが,両者は互いに競合するので最終的に静定するまでループする.

さて,今日は「直属系列落ち」とは何か?というところから始めなくてはならない.一方では「ここでは直属系列落ちを許容する」がONとなっているのに,他方では「直属系列落ちを無視する」がOFFという矛盾した状態になっている.そもそも「直属系列」とは何か?これは昨日調べたように,①HASNOMINORであるか,ないし②BOTTOMEMPTYでかつ,HASNOMINOR以外の下位系列を持たないような系列と定義される.ここで,HASNOMINORとは「始系列を除き下位系列を持たない系列」,BOTTOMEMPTYとは「最下段世代枠が空で最下段世代に消去された系列優先仮ノードが存在する系列」である.

つまり,主系列にごく近い直参旗本のような系列と考えてよい.従って,これらの系列は主系列の近傍に配置されるべきというのが「直属系列」の趣旨であるように思われる.一方BONDEDTRIBE(束縛系列)という概念がある.これは「すべての下位系列と交叉しかつ上位系列と交叉している系列」とされるので,おそらく主系列(および自系列の下流系)との位置関係が確定した系列と考えてよいだろう.ただし,IsBondedTribeでは(BONDEDTRIBE | MAGARIHOSEI | SPOUSESENZO)を返しているので,もう少し広い概念だ.束縛系列の反対概念が自由系列で IsFreeTribeBox は !IsBondedTribeに等しい.

何が問題なのか?それが問題だ.現状では「直属系列落ちを無視する@20181001」はOFFなので,!IsBondedTribeのとき,IsDirectSubTribeを検査している.無視と言いながら検査しているところもおかしいが,!IsBondedTribeのときIsDirectSubTribeとは何を意味しているのかを調べてみよう.この条件を書き下ろすと次のようになる.

!(BONDEDTRIBE | MAGARIHOSEI | SPOUSESENZO) && (MAGARIHOSEI | BOTTOMEMPTY | SPOUSESENZO | HASNOMINOR)

これは結局,

(!BONDEDTRIBE & !MAGARIHOSEI & !SPOUSESENZO) & (MAGARIHOSEI | BOTTOMEMPTY | SPOUSESENZO | HASNOMINOR)

だから,MAGARIHOSEI とSPOUSESENZO の項は消えて,

!BONDEDTRIBE & (BOTTOMEMPTY | HASNOMINOR)

のようになると考えられる.(BOTTOMEMPTY | HASNOMINOR)は直属系列の定義にやや近いので,これは(広義の)直属系列でかつ(狭義の)束縛系列でないものと読める.しかし,にも関わらずここでは停止していないので,一体何がこのパスを通過しているのか分からなくなってしまう.⇒(事実上)何も通っていない.SolveBondedTribeCollisionでは冒頭でCheckAllBondedTribeを実行した後,エラーなしでゼロ復帰している.つまり,SolveBondedTribeCollisionはCheckAllBondedTribeを実行するだけのものになっている.

実際,CheckAllBondedTribeの中では自由系列がなくなるまでループを回している.ただし,自由系列が存在した場合には戻り値を返すので最初から自由系列は存在していなかったということになる…つまり,CheckAllBondedTribeが正しく動作することが保証されているのなら,SolveBondedTribeCollisionの後段は不要になるはずだ.さらに言えば,もしかすると,衝突検定を実施しているSolveTribeCollisionさえ不要になっている可能性がある.⇒いや,むしろ逆にSolveTribeCollisionの中からApproximationが呼び出されている.SolveTribeCollisionは自身を再帰実行しているので,この関数一つあればこと足りるのではないか?

どうもCheckAllBondedTribeは何もしていないように思われる.もし,それが本当ならおそらくSolveBondedTribeCollisionも不要になるはずだ.どうもその気配が濃厚になってきた.この処理を完全に止めたバージョンを作ってみよう.⇒とりあえず,問題なく動作している.20180717に「SolveBondedTribeCollisionを実行関数化する」という修正を行っている.この頃のログは残っているだろうか?「テント村」は2018年12月に開設されているのでそれよりも前の話だ.My Weblog Postsのバックアップでも2016-02-08から2018-12-14の間は空白になっている.確かにこれは正確にネットが止まっていた期間だ.

通常ブログが使えないときでも,自己宛てにメールを送ってログ代わりにしていたはずなのだが,メールサーバにアクセスできなければ,それもできない… それ以前からWindows Live Writerを使っているのだから,オフラインで下書きに保存くらいのことはできたのではないか?確かにその通りだ.下書きに残っている.2018-07-17のタイトルは「AccidentalCollisionを三検査関数で書き換える」だ.

「CheckHorizontalOrderを三検査関数で書き換えるというのはやはり無理があるとしても,AccidentalCollisionを三検査関数で書き換えることは不可能ではないと思われる.試してみることにしよう.」

三検査関数というのは,CheckAllBondedTribe,CheckAllCollision,DetectSplitだ.これらは検査用関数だが,それを実行関数に仕立てるということをやっている.「すべての束縛系列がブロック内で衝突していなければ,あとは自由系列ブロックの水平移動だけ」という立場から衝突検定をCheckBondedTribeCollisionに限定するという方針で,ある程度時間を短縮するという効果が出ている.「SolveBondedTribeCollisionを実行関数化する」というのはその一環として実施されたものだろう.

この頃は先祖並び自動オフというところに焦点があったようで,現在テストしているサンプルは先祖並び自動オンだから,これで動いたから安心とは言えない…現在のバージョンにはCheckBondedTribeCollisionという関数は残っていない.多分この関数をリネームしたものがSolveBondedTribeCollisionなのだろう.それをいま削除しようとしているのだが…おそらく,このときの修正は検査関数をそのままの位置で実行関数に格上げするようなやり方だったのではないだろうか?つまり,オリジナルの処理で漏れてしまうところを検査関数をある意味で強化することによって解決したということなのではないか?

「Approximationを廃止する@20180712」というコメントは残っているが,実際には存続している.SolveBondedTribeCollisionを停止すると今度はAccidentalCollision自身がほとんど何もしていないことになってしまう.確かに,この関数を止めても問題なく動いている.ことのついでにこの関数も廃止してみよう.⇒少し時間が掛かるが,渋沢の全体図テストをやってみることにしよう.⇒出口検査のCheckAllCollisionで停止した.さすがにこれは無理かもしれない.スプリットも発生している.AccidentalCollisionを復活させてSolveBondedTribeCollisionだけ停止というモードでテストしてみたが,やはり同じところで停止する.

基準ノード=214 穂積重樹だ.⇒SolveBondedTribeCollisionを復活させ,CheckAllBondedTribeだけを実行して復帰するように改造して同じエラーになった.つまり,SolveBondedTribeCollisionの後段は必要ということになる.反例は#214 穂積重樹だ.いや,その前にAccidentalCollisionが無動作になっていた.

SolveBondedTribeCollisionでCheckAllBondedTribeだけを実行するというバージョンを走らせて,基準ノード=300 三島美禰で停止した.CheckAllBondedTribeで初めて変異が発生した.基準ノード=302 堀切良平などでも同様の動作になるが,最終的には解決しているようだ.CheckAllBondedTribeで衝突はすべて解決しているのでSolveBondedTribeCollision後段の処理はまったく不要であるようにも思えるが,現状のままとしてバックアップに戻ることにしよう.

現在のインストール版V2.2.0.015は源氏を開いてエラーを出すので差し替えておこう.⇒V2.2.0.017_R20201115をリリースした.

「直属系列落ちを無視する@20181001」と「ここでは直属系列落ちを許容する@20181007」をとりあえずフィックスしておこう.SolveBondedTribeCollisionの去就についてはパフォーマンスの問題として別途取り組むこととする.「SELECTFOREFATHER」は先祖ノードのどちらが遠いかを判定する関数の仕様に関するもので,世代を比較するものと親等を比較するものがある.現行は世代比較になっているが,これを仕様としてSPECIFICATIONに移動.「WriteNonStopSampleListを一時停止@20161026」はファイルオープンテスト中にログをファイルに書き込むための関数.デバッグ用途なのでDEBUBタグに移動.

「衝突検定で計算誤差を許容する@20180930」→現状でフィックス.このプラグマではMAXKEISANGOSA という定数を使っている.現在,MAXKEISANGOSAは75箇所から参照されているが,一方で「厳密値を適用する」ないし「厳密値を返す」などとしているところが18箇所ある.厳密値を返すというところはおそらく,上位関数で判定しているためだろう.ただし,許容範囲に等号を含むか否かではぶれがある.

「NAMEBOX:Drawへ移動@20190131」→現状でフィックス.「MakeYokogakiBoxをパス@20180328」→現状でフィックス.MakeYokogakiBoxは横書きタイトルを描画する際の矩形領域を計算する関数で,タイトル枠には,①タイトル行,②作成者名,③作成日付,④コメントの4つのテキストボックスがあるが,コメント枠だけは別計算しているためMakeYokogakiBoxで計算しないという趣旨だ.

(配偶者の性別不問とした@20180201)→このオプションには問題がある.このプラグマは以下のようなコードを無効化している.

// 新規作成した父母の個人情報で性別情報が設定されていない場合があるので,ここで補充しておく.
if (Father) Father->sex = true;
if (Mother) Mother->sex = false;

前に延べた「親子関係を設定」しただけで女性が父になってしまうという現象はおそらく,これが原因になっていたものと思われる.この部分の論理はもう少し詳しく調べなくてはならない.ここでは,暫定的にOPTIONのタグに移動してデフォルトOFFとしておく.これでINCOMPLETEタグは一掃できたが,PENDINGに出戻ってきた項目が一つある.PUREBLOODSUPPORT(純血統図をサポートし上流が養親系だけの場合の下流検定の動作を保証する)というものだ.多分これは動作上必要な措置と考えられるので現状でFIXということになると思われるが,純血統図に関してはもう少し考えてみたい.

純血統図(親族図)では養親系を表示しないようにするということが考えられるからだ.現行では直系血族図を表示したとき,養親系も同時に表示されることになるが,純血統図とすると養親系を除外した血族図になるというイメージなのだが…⇒いや,現状でもそうなっているのではないか?実際,システム構成図はほとんど養親子関係しか存在しないため,純血統図を選ぶと基準カードだけになってしまう.つまり,動作している.何か勘違いしているか,あるいは別の問題があるのか?

いや,そもそもこのオプションは本当に必要なのか?システム構成図で見た限りではOFFでも特に問題なく動作しているように見える.

コメントを残す

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

CAPTCHA