CheckSamePointの戻値の仕様を変更する

「端点共有束全体を移動する@20210105」オプションをフィックスしてから進むことにしよう.7箇所ある.仮修正が19箇所.

源氏物語全系譜6.1.ZELの全体図を#3 桐壷の更衣でソートしてPAIRBOX::RepairCommonEndPointの出口でCheckSamePointエラーが出る.「端点共有で始点不一致」が起きている.障害はPAIRBOX:#234599:#199072 明石の尼君(1)→#188661(0)とPAIRBOX:#234457:#198879 先帝の后宮(1)→#188559(0)で起きている.両者の区間は前者が(-207, -117),後者が(4066, 3989)のようにかけ離れているので,最初の判定が間違っていたか,ないし関係するノードのいずれかが大きく移動しているものと思われる.

このエラーはTOPOLOGY::CheckPairEndPoint→ PAIRBOX:RepairCommonEndPointで起きている.RepairCommonEndPointの目的は「対象ノード対の端点共有状態を検査し再構成する」なので,それに失敗していると考えるしかない.RepairPairBoxで修復を試みているが,変化していない模様だ.

CheckSamePointの従来の仕様では,エラーがあるかないかを示すだけのブール値を返していたが,仕様を変更して障害の詳細な要因を返すようにした.これらのビット定数はコード内から日本語でアクセスすることができる.障害をダンプするときにも,数値だけでなく名前まで表示できるようにした.

  1. 無効なノード対 disable状態のノード対
  2. 長さゼロのノード対 長さゼロのノード対は無視する
  3. ノーマルなノード対 ノーマルなノード対(端点共有束を含む)
  4. 実仮ノード不在 ノードないし仮ノードが取得できない → 不良
  5. ノード対不一致  仮ノードの参照するノード対と現物が一致しない → 不良
  6. カードリンク不一致 仮ノードと実ノードで参照する人名リンクが一致しない → 不良
  7. NOCOMMON属性不整合 実ノードとノード対でNOCOMMON属性が整合しない → 不良
  8. 直列リスト上にない非共有対 非端点共有ノード対でBundledTopが間違った値を返している → 不良
  9. 非共有対でsamepoint 直列リスト上の非端点共有ノード対がsamepointの値を持っている → 不良
  10. 最大区間ノード対の逆転 端点共有リストの先頭ノード対が最大区間ノード対でない → 順位入れ替え
  11. 危険対を端点共有 始点終点が同一座標で逆転するノード対を端点共有 → 端点共有解除
  12. NOCOMMONGOODSON NOCOMMONGOODSONで端点共有代表でない → 端点共有解除
  13. NOCOMMONで非共有代表 実ノードがgoodsonであるノード対は最大区間でなくては共有不可 → 端点共有解除
  14. samepoint不良 端点共有ノード対のsamepointが代表ノード対と一致しないかゼロ → 端点共有解除
  15. 共有端点不一致 端点共有ノード対で座標不一致 → 端点共有解除
  16. 左端点共有で種別不一致 左端点共有でsamepointが一致しない → 端点共有解除
  17. 右端点共有で種別不一致 右端点共有でsamepointが一致しない → 端点共有解除
  18. 端点共有で始点不一致 始点共有で始点が一致していない → 端点共有解除
  19. 端点共有で終点不一致 終点共有で終点が一致していない → 端点共有解除
  20. 端点一致でsamepointゼロ 端点共有可能なノード対のsamepointがゼロ → 端点共有
  21. 端点共有でsamepointゼロ 端点共有束上のノード対でsamepointがゼロ → 端点共有
  22. 直列リストノード対の衝突 直列リスト(同一チャンネル)上のノード対区間で交叉している → チャンネル移動(連結)
  23. 端点共有解除 シンメトリ婚/危険対の端点共有を解除する → チャンネル移動(単体)

CheckSamePointで「端点一致でsamepointゼロ」というエラー

源氏物語全系譜6.1.ZELの全体図を#127 摂政太政大臣でソートしてPAIRBOX:repairCommonEndPointの出口でGENELIST:CheckPairBoxの不良ノード対エラーにより停止.CheckSamePointで「端点一致でsamepointゼロ」というエラーが起きている.問題のノード対はPAIRBOX:#49223:#23382 蛍兵部卿宮の前の北の方(1)→#13126 蛍兵部卿宮の前の北の方(0).

PAIRBOX:#49223:#23382 蛍兵部卿宮の前の北の方(1)→#13126(0)と#49237:#23394 致仕太政大臣の北の方(1)→#13143(0)が端点共有と認定されているが,CheckCommonEndPointでは端点共有なしを返している.つまり,CheckCommonEndPointとCheckSamePointの基準が異なる.⇒CheckSamePointのロジックから,PAIRLIST::searchCommonPairという関数を作り,CheckCommonEndPointから呼び出すようにした.

系統並び替えの出口検査でCheckPairListのエラーが検出される.サンプルは源氏物語全系譜6.1.ZELの全体図 #1 光源氏.CheckPairBoxCollisionで障害が発生している.ノード対の衝突が5件発生している.この障害はHeapTribeBoxesを実行することで発生している.たとえば,PAIRBOX:#55361:#23947 八宮の北の方の母(1)→#14452(0)とPAIRBOX:#55518:#24194 受領(1)→#15438(0)が衝突している.

これは当然あり得ない.受領はまるきり離れた別系統のノードだ.これは,HeapTribeBoxesの中で独立系列をMoveRectRightで前詰めしているために起きている.ノード対管理は全域的に実施されているため,別系統のノード対とも数字的には衝突が起きる可能性はある.区間計算で用いている数字は,あらかじめ計算されてノード対の矩形領域に格納されているものが使われているためだ.

HeapTribeBoxesの実行後に再計算するか,ないし直接値を計算するしかない.衝突はPAIRLIST::VerifyPairBox→ CheckNormalizedSectionで検出されているので,この関数では値を直接計算するようにしておこう.⇒だいぶ正確に動作するようになってきたようだ.

同上サンプルを#2 桐壷院でソートして,CheckCommonEndPointで停止した.PAIRLIST::searchCommonPairとCheckCommonEndPointの判定が相反している.⇒searchCommonPairでは計算誤差を見ているのに対し,CheckCommonEndPointでは厳密値を適用しているためだ.⇒対処した.これでエラーは解消したが,別のエラーが発生している.

同上サンプルを開いて,PAIRBOX::MoveSamePointで停止する.この関数は対象ノード,移動先ノードともに直列リスト上のノードと仮定している.⇒searchCommonPairで端点共有の中まで探していた.

同上サンプルを#12 桐壷の更衣の母でソートして,TRIBELIST:MakePairListCleanでループカウントオーバーになった.PAIRBOX:#53758:#23537 致仕太政大臣の北の方(1)→#13143(0)の補修を反復しているようだ.衝突の相手方は毎回変化している.どうも補修が循環してしまっているように思われる.⇒#156006 ノード対:四宮(桐壷院の)(1)→(0)が割り込んで,致仕太政大臣の北の方を共有端点から追い出しているようだ.判定ではAfordableChannelが使われている.⇒checkNormalizedSectionで正規化していない区間を使っていた.

同上サンプルの#13 春宮でTOPOLOGY::CheckPairListのループカウントオーバーが起きた.PAIRBOX::CalcPairBoxで最大区間ノード対の逆転を解決が反復されている.PAIRBOX:#54628:#23016 致仕太政大臣の北の方(1)→#13143(0)とPAIRBOX:#54614:#23004 蛍兵部卿宮の前の北の方(1)→#13126(0)の入れ替えが実施されている.蛍兵部卿宮の前の北の方は同じチャンネルの葵の上のノード対と衝突して一旦チャンネルを追い出され,その後もう一度端点共有でこのチャンネルに戻るという動作を繰り返している.

端点共有ノード対とそうでないノード対の衝突では非共有ノード対側で処理するようにしてエラーは一応解消したが,端点共有同士の衝突という可能性もあり,むしろ,端点共有ノード対を移動する場合は端点共有束全体を移動するようにすべきだろう.チャンネル移動はPAIRBOX::MoveChannelToで実施している.

あらたまの年も新たに去年の月

image

今年はいよいよどっからもカレンダーが来ない… まぁ,いっか.コロナ時代だ!一旦ここまでの修正をフィックスしてから作業に掛かることにしよう.仕掛りのオプションには以下がある.

  1. DecidePrimaryNodeを書き換え@20201226 1箇所
  2. mergeUpperSegmentで移動禁止@20201227 1箇所
  3. 最大区間ノード対を端点共有の先頭に置く@20210101 25箇所

源氏物語全系譜6.1.ZELの全体図を#18 左兵衛督で開いて,PAIRBOX::CheckPairBoxで不良ノード対エラーで停止.「最大区間ノード対の逆転」が起きている.PAIRBOX:#84668:#23457 弘徽殿大后(1)→#12718 (0) と#50680:#23481 致仕太政大臣の北の方(1)→#13143(0)だ.NAMEBOX::makePairBoxではノード対を生成するだけで,端点共有の調整までは実施していない.ただし,端点共有はチェックされていて,端点共有束には追加されている.PAIRBOX:CalcPairBoxではNOCOMMONの場合には調整しているが,すべての場合をカバーしていない.ここで調整しておくべきだろう.

源氏物語全系譜6.1.ZELの傍系血族図を#5 紫の上(若紫)でソートしてLIST::nextで(PHASE > INITIALSTATE)という理由で停止した.系統並び替えでTribeRelocation→MakePairListCleanを実行しているところだ.PAIRLIST::SearchSamePointPairの中で起きている.この関数は「端点を共有するノード対を探す」ためのものだが,探しているノード対リストに属していないノード対をピックアップしてきたように思われる.IsBindablePairの中で書き換わっているのではないだろうか?

IsBindablePairの中でPAIRBOX::CalcPairBoxが実行され,「最大区間ノード対の逆転を解決」によってリストが再編されている.このため,直列リスト上にあったPAIRBOX:#35362:#21617 雲井の雁(1)→#12378(0)が端点共有リストの下位に移ってしまっている.IsBindablePairの中でPAIRBOX::CalcPairBoxが実行されること自体問題だが,最大区間先頭の調整が遅れていることも問題だ.いや,この動作はPAIRLIST::RepairPairBoxGenerationの中で起きているので,状態がある程度流動的になるのは避けられないのではないか?

IsBindablePairの中でCalcPairBoxを実行しないことでこのエラーは解消したが,雲井の雁と玉鬘の端点共有が崩れてしまっている.なぜか?⇒明石中宮と雲井の雁が同一チャンネルに入ったため,玉鬘が加わる余地がなくなったためと考えられる.(最終出力では明石中宮と雲井の雁は同一チャンネルにはなっていない… )最適解を求めるとすれば,玉鬘と雲井の雁の端点共有を成立させた上で,明石中宮は別チャンネルに移るというのが正解と思われるが,そこまでの動作にはなっていない.これで見ると,最優先すべき条件は端点共有であるということが分かる.

▲源氏物語全系譜6.1.ZELの全体図を#127 摂政太政大臣でソートしてPAIRBOX:repairCommonEndPointの出口でGENELIST:CheckPairBoxの不良ノード対エラーにより停止.CheckSamePointで「端点一致でsamepointゼロ」というエラーが起きている.問題のノード対はPAIRBOX:#49223:#23382 蛍兵部卿宮の前の北の方(1)→#13126 蛍兵部卿宮の前の北の方(0).

ノード対の「端点共有で始点不一致」エラー

多重カードを削減する基本的な方法は二つのカードを連結線で接続して片方のカードを削除することだ.このような連結線のうち,親から出て子どもに入るように見える親子連結線の水平部分をノード対と呼んでいる.これはノード対の両端に同一人名のカード(一方は可視,他方は不可視)が接続していることによる.ノード対の処理はZTシステムのコンポーネントの中でももっとも基本的なパートとなっている.

これらの水平連結線を交叉しない範囲でできるだけ簡潔に描画するというのはかなり難しい課題で,達成目標はベストエフォート(できる限り)ということになっているのだが,どうもあまりできがよくないので見直す必要が出てきた.おおまかな方針を決定し,すでに実装も進んでいるので,バグを潰しながら整理してゆくことにする.

NAMEBOX::makePairBoxでCheckSamePointの「端点共有で始点不一致」エラー.障害ノード対は#1226:#1099 雲井の雁(1)→#587 雲井の雁(0)と#1225:#1098 玉鬘(1)→#419 玉鬘(0)だ.⇒解決済

源氏物語全系譜6.1.ZELの傍系血族図の基準ノードを#13 春宮から#1光源氏に変えて,系統並び替えの冒頭でノード対リストのcancelを実行中,PAIRBOXの削除で参照カウントが負になった.⇒系統並び替えしなくても,アプリ終了だけで再現できる.⇒完全参照リスト管理をオンにしてテストしてみよう.⇒nodule::CheckSansyoで被参照カウント不一致が多発している.#34442 ノード対:蛍兵部卿宮の前の北の方(1)→(0)で参照元ノードリスト不記載,#34134 ノード対:玉鬘(1)→(0)でも同じエラーが発生している.これらは起動時にすでに発生している.LIST::bottomlistへの書き込みだ.PAIRLIST:swapで直接書き込んでいるためだろう.Bottomlist関数を使うようにした.

同上サンプルの全体図:#5 紫の上(若紫)でソートしてMakePairListCleanでループカウントオーバーになった.「最大区間ノード対の逆転」がPAIRBOX:#1492439:#1462069 致仕太政大臣の北の方(1)→#2449 (0)で起きている.親族図:傍系血族図 基準ノード=#5 紫の上(若紫)を開くと,NAMEBOX::makePairBoxでCheckPairBoxのエラーで停止する.⇒エラーを無視して描画は可能.全体図は問題なく開けた.紫の上の全体図を開いて,基準ノードを変えずに反復ソートしたら,3回目でMakePairListCleanの障害が出た.これは初期化が不完全ということを意味している.かなりまずい.

まず,先に最大区間ノード対の逆転がなぜ止まらないのかを見ておこう.PAIRBOX 蛍兵部卿宮の前の北の方(1)→(0)と競合しているが,これを端点共有と認定しているところが誤りだ.(3434, 3293)と(3434, 3293)で向きが逆になっている.⇒PAIRLIST::takeoutで共有解除,PAIRBOX::RepairCommonEndPointとPAIRBOX::MoveSamePointで共有を設定している.CheckCommonEndPointが間違った値を返している.⇒比較対象の矩形領域を正規化していなかった.

これで問題は解決したが,系統並び替えを反復すると動作が変化するというのはとてもまずいので,シューティングしておかなくてはならない.正規化すれば正しく動作するのだから,正規化しなくても動いているというのは,「たまたま」動いていただけと解釈するしかない.しかし,何がどうなっているとそのような動作になるのかを解析するのは難しい.類似のバグがまだ潜んでいる可能性はある.複数のバグが競合して動いたり動かなかったりということもありそうだ.⇒系統並び替えの冒頭で描画要素を完全にクリーンアップすることでソートを反復しても動作には変化が見られないようになった.

その上でCheckCommonEndPointの修正(比較対象矩形領域の正規化)を行うと,連結線のもつれはほぼ完全に消えた.これまでは端点共有と通常ノード対の区間交叉がかなり見られたが,一見したところ見当たらなくなった.EraseTreeViewで行っている描画要素のクリーンアップは多少時間コストは掛かるが,これを実行しておけば間違いはない.

類似した関数にInitTreeViewというのがあり,修正履歴では「InitCoupling>InitTreeViewを廃止@20201208 余分な処理になっている → FIXED@20201209」となっているので,多分使わなくてよいのではないかと思う.この関数は,現在,①FAMILYTREE:callSendCard,②FAMILYTREE::getNewCardで使われている.

「InitTreeViewをCOUPLINGのコンストラクタに移動@20170731」というコメントもあるが,COUPLING()では「ここではTREEVIEWの初期化は実行しない@20170804」となっている.⇒タイトル枠を初期化しているのが気になるが,各種フラグのリセットなどをやっているので,実行しておいた方がよいと思う.

▲源氏物語全系譜6.1.ZELの全体図を#18 左兵衛督でソートしてNAMEBOX::makePairBox→ PAIRBOX::CheckPairBoxエラーが出た.

春宮の傍系血族図で端点共有の始点不一致

SUPPORTSIMPLEGRAPHオフのバージョンで,源氏物語全系譜6.1.ZELの傍系血族図を#13 春宮で開いて,repairCommonEndPointで停止した.CheckSamePointでエラーが出ている.「端点共有で始点不一致」が起きている.repairCommonEndPointではPAIRBOX:#1237:#1120 藤壷の宮(2)→(0)を端点共有リストに移動しているが,最初から対象を間違えている.⇒いや,違う.これは誤差の累積だ.

この端点共有束には藤壷の宮と承香殿女御が入っている.区間は(4299, 1364)と(4302, 1680)だ.この結果,端点共有束としての区間は(4302, 1680)となり,明石の上の(4305, 1496)も誤差の範囲で一致する.これを避けるための唯一の方法は,端点共有リストの先頭につねに最大区間のノード対を置くようにすることだろう.それにはどうしたらよいか?

問題は区間を比較するとき,端点共有の場合は「正規化区間」というのを使っている点にある.正規化区間というのは言ってみれば「最大区間」と同じだが,誤差を含んでいるため許容誤差を3として±3以上の誤差を許容してしまうことになる.これをまず,廃止する必要がある.

#90 雲井の雁の出口検査で水平スプリット

#90 雲井の雁で出口検査で水平スプリットを検出 TRIBEBOX #1082 :先祖 #843 ※218でスプリットが生じている

TRIBELIST::DetectHorizontalSplitではこのスプリットを検出できない.DetectSplitの対象となるのは,FreeTribeBoxと呼ばれる束縛されていない系列に限定されている.⇒これを暫定的に無差別に検査を実行するようにしても状態は変わらない.この仮修正の下で,「系列間衝突が発生で移動量ゼロ」という事象が起きているので見ておこう.

TRIBEBOX::DetectSplitでERR_CROSSINTRIBESを返しているが,MoveLeftUptoLimitは移動量ゼロを返している.障害が起きているのは,RIBEBOX: #1058 先祖=#427 一院(0)だ.T1=#1070 [系列枠]:先祖=大臣(橋姫)とT2=#1062 [系列枠]:先祖=先帝の衝突が検出されているのだが… TRIBEBOX::CheckConflictでは水平交叉量を返しているが,エラーコードを返す場合もある.また,この関数を呼び出しているTRIBEBOX::DetectSplitでは,「厳密値を適用する@20180729」という決定がなされている.

今の場合は交叉量は1なので許容誤差範囲と推定されるのだが… 2018年当時のログを読み直してみるとこの項目に直接言及した記述はないが,「checkBondedTribeCollision 束縛系列ないし下位系列を持たない系列を対象とする.対象系列枠の主系列およびその下流系列(つまり系列ブロック)と対象系列との衝突検定を実施する 下位系列を持たない場合は系列ブロック核のみを検査する 厳密値を適用する 」とある.

「衝突検定はすべて厳密値を適用するものとし,実動作が完了してから丸めるものとする」というコメントもあるので,この方針に従ったものだろう.ただし,TRIBEBOX::DetectSplitでは交叉量ではなく,エラーコードを返しているので丸めようがない.TRIBEBOX::DetectSplitで誤差を見るようにしておこう.⇒「系列間衝突が発生で移動量ゼロ」エラーは解消した.⇒おかしい.系列枠リストから※218系列が消えてしまっているように見える.第14位にいるはずなのだが…

いや,そもそも当初は96系列あったはずなのに,64系列になっている.32個もどこかに消えてしまっている.⇒MakeUpTreeの出口近く(系列グループ(系統)を構成するの段)ではすでにそのカウントだ.96の中には単身先祖系列で抹消されるものもあるから,カウントが減少するのは不思議ではないが… ※218が先祖となる系列は消えている.⇒※218は一院系列に取り込まれている.つまり,これは系列内スプリットだ.@58 大宮と@68桃園式部卿宮の間が開いている点が問題になる.

image

一院系列のTRIBEBOX::CheckGeneSplitでスプリットが検出されていない.⇒CheckGeneSplitとInvestigateHSplitsで微妙に動作が異なる点が問題だ.InvestigateHSplitsでは許容範囲としてmax(Metrix.nfontW, Metrix.marghgap)という値を使い,これを1ふかした定規で区間検査を行っている.いま,marghgapは12という値が適用されているので,delta=13となっている.上の図でイエローの帯の幅は13で,これはほぼ結婚枠間のギャップに等しい.

CheckGeneSplitでは結婚枠矩形領域を集積するとき,結婚枠間ギャップを加味した値を取っている上に,さらに計算誤差を回避するためとして+1しているため,大宮の入っているボックスと桃園式部卿の入っているボックスは接触していると認定されている.⇒InvestigateHSplitsの許容範囲を拡げてこの矛盾を回避することも可能だが,CheckGeneSplitの検査を厳格にして,1単位でも移動するように修正した.

基準ノード#121 明石の尼君で開いて,TRIBEBOX:DecidePrimaryNodeで系列優先実ノード不在が起きる.⇒障害が起きているのはTRIBEBOX: #1064 先祖=#635 先帝(0)[0] 優先=紫の上(若紫)だ.TRIBEBOX::DecidePrimaryNodeの書き換えがまだ完結していない.現行ではほとんどをGetAlternativePrimeNodeに委ねるという論理になっているが,やり過ぎだ.すでにGoDownStreamでほぼ確定している条件があるのだから,それを活かすようにしなくてはならない.

もっともシンプルな解決として,優先ノードの持つ仮ノードリストの中で自系列に属するノードがあれば,それを優先仮ノードとし,他系列で自系列の下位系列に属さないものがあれば,優先実ノードとするというロジックを組み込んだ.基本的にはこれでよいのではないかと思う.

#18 左兵衛督で「系列間衝突が発生で移動量ゼロ」が起きた.ERR_CROSSINTRIBESが起きている.交叉量は18あるので無視できる値ではない.衝突はTRIBEBOX: #1058 先祖=#661 摂政太政大臣(0)と#1064 先祖=#507 ※3(0)の間で起きている.どちらも一院系列の従系列だ.関数MoveLeftUptoLimitで,ERR_CROSSINTRIBES,ERR_SPLITINTRIBES,ERR_WRONGSENZOORDERのケースを処理している.検査対象は始系列の#1056 先祖=#791 右大臣(明石)(0)だ.これはかなりおかしい.⇒仮修正がそのまま残っていた.

源氏の全体図テストが通った!

image

身を捨ててこそ浮かぶ瀬もあれ

野菜のストックがしおれかけて来たとき,水を掛けたり,水栽培したりして延命させることができるが,それでもしおれっ放しで戻らないときは,野菜が浸るまで水を注いでやるとよい.野菜が水に浮いてくるまでじゃぶじゃぶに水を入れてやると翌日には完全に復活している.

image

水をたっぷり張って野菜が謂わば無重力状態のように水中に浮いているようにするというのが肝心なところだ.捨身,身を捨てるということもときには必要なときがある.

SUPPORTSIMPLEGRAPHオフ,「基準ノードの配偶者の配偶者側で展開する@20201230」オフのバージョンで源氏物語全系譜6.1.ZELの全体図を#57 女三宮で開いてい,MARGBOX::GetUpperNodeで親ノード不正エラーが発生する.障害ノードはMARGBOX:#401:#1262 女三宮(1)+#1263 柏木(1)→で,親ノードの位置にNAMEBOX:#1267 小宰相の君(1)が現れている.これはかなりおかしい.

image

相互関係を確認するためにインストール済の別アプリで開いてみた.どう見てもこの結婚枠の上位に来るようなノードではない.TribeRelocationの【7.2】完全木検定:すべての系列を完全系列として正準化するステージでMakePairListClean中に起きている.NAMEBOX:GetGoldenCoupleでZTYW婚を削除するタイミングで発生している.削除対象のZTYW婚はMARGBOX:#2006:#1262 女三宮(1)+#1263 柏木(1)→#1265 按察の君(薫付)(1)だ.

削除対象のZTYW婚の本人ノードは按察の君ではなくて,薫 #1204だ.按察の君と小宰相の君はいずれも薫の配偶者で道連れでZTYW婚に連れ出されたものだ.手順の中では本人の薫の仮ノードは削除されているが,配偶者が取り残されて孤立している.⇒ZTYW婚を始末する完結したルーチンRestoreErasedYoungWifeがあるので,それと差し替えることにしよう.これで問題は解決したが,まだ不具合が残っている.

MARGBOX::RestoreErasedYoungWife→ NAMEBOX:RestoreExtractBox→ RetrieveGhost→ RestoreYoungWife→ RestoreExtractBoxで処理後の位置関係の検査で不一致が出ている.⇒検査の意味が不明.抽出枠を復元したとき,親の結婚枠の位置とサイズが不変であることを仮定しているようだが… この論理は廃止でよい.

▲#90 雲井の雁で出口検査で水平スプリットを検出.#91 左衛門督(寄生)でも発生.確かに#218 ※系列でスプリットが生じている.

image

検査ルーチンが実動作している可能性があるので,まず,それを見てみよう.検査ルーチンは動作にまったく影響していないようだ.このスプリットはAccidentalCollision→DetectHorizontalSplitでは検出されていない.2018-07-13の決定で「HORIZONTALORDERフェーズまではAccidentalCollisionを実行しない」となっている.InvestigateHSplitsはこのスプリットを検出できるが,この関数は描画ステージ(絶対座標系)でなければ動作しないため,適用できない.また,適用したとしても,系統並び替えの出口でHeapTribeBoxesが実行されるまでは,系統間の距離が定まっていないので検査しても意味がない.

▲#121 明石の尼君で系列優先実ノード不在が出た.#150 ※,#169 中務宮でも起きる.

系列接続問題を「人間関係の解析」から「図形の配置問題」に転換する

ZTシステムの作図法の基本は,系図を系列に分解しそれらの相互位置関係を定めることにある.系列とは先祖ノードの直系血族とその配偶者の集合であり,自ずと木を構成するから系列単体を描画するというのは初歩的な課題だが,入り組んだ系列の相互関係を定めるというのは必ずしも容易ではない.この部分に関してはこれまでにも何度も試行錯誤的な作り替えを実施してきた.このような試行錯誤に終止符を打つために提案されたEstablishMajorTribeChainが廃止されたのは2019/02/04だ.系列優先ノードの選択基準を緩和するという方向に動き始めたのはこの頃からと思われる.緩和の方向性は最終的には,系列の接続関係を「人間関係の解析」から「図形の配置問題」に転換するという方向を目指していたのではないかと思う.この方向性はまだ完結したとは言えないが,大幅に緩いものになってきていることは確かだ.

SUPPORTSIMPLEGRAPHオフのシステムで源氏物語全系譜6.1.ZELの全体図を#4 明石中宮で開いてTribeRelocationの【5.2】重婚同類グラフ検定の事後処理を行なうステージでLIST::nextで停止した.前にこのエラーが発生したときには,対象リストを取り違えているという論理ミスがあったが,今回はどうなっているのだろう?

今回は事前にplist->find(pbox)を試しているにも関わらず発生している.このエラーが発生する一つ前に,「ノード対世代不一致」というのが起きて,PairBoxGeneChangeが実行されている.この関数の中でノード対が削除される場合がある.いや,そもそもエラーは(!find(listnod))ではなく,(PHASE > INITIALSTATE)という理由だ.

明らかにPAIRLIST #1443のbottomlistの値が間違っている.⇒PairBoxGeneChangeの実行で不良が発生している.NAMEBOX:RetrieveGhostでノード対を破棄したときに起きているようだ.⇒plist->deleteElement(pairbox, true);で発生している.PAIRLISTはdeleteElementを持っていない.⇒PAIRLIST::dataCountDownでリスト終端ノードが端点共有である場合を見落としていた.

同上サンプルを開いて,TribeRelocationの【7.8】多重カードゼロを検査して変化なしなら検定打ち切りステージでTRIBEBOX:SetMinorTribeのエラーが発生した.DisConnectedGraphを強制モードで実行しているところだ.障害系列は#1120 先祖=#801 左大臣(梅枝)(0)で優先仮ノードはNAMEBOX:#1336 今上(2),関係は配偶者,優先実ノードは#415 明石中宮(0)で関係は養子,所属系列は#1056 先祖=#427 一院(0)の始系列だ.この接続関係は「逆婚姻関係」と呼ばれるものに相当する.DecideTribeTypeはPRIME_BTWLEFTを返している.確かに,今上(2)はDOUBLYBLESSED,明石中宮(0)はRIGHTHUSBANDだから,PRIME_BTWLEFTという判定は正しい.

ここの論理は,優先仮ノードが配偶者で系列種別が婚姻関係でも逆婚姻関係でもない場合で,この系列が始系列であった場合の代替ノードを探すというものになっているが,始系列でない場合は無動作なので当然配偶者のままになっているから,明らかにおかしい.また,始系列の場合は通常は基準ノードが最初から確定しているのだから,代替を探すということ自体かなり奇妙な感じがする.複数系統の場合にはこのようなことが起こり得るかもしれないが,いずれにしても,始系列以外でここで停止するというのは誤りだろう.

同上サンプルを#48 四宮(桐壷院の)で開いてTRIBEBOX:DecidePrimaryNodeで停止した.優先仮ノード不在エラーが起きている.障害が起きているのはTRIBEBOX: #1068 先祖=#811 大臣(橋姫)(0)で,優先ノードはCARDLINK:#546 @70浮舟[0].浮舟は仮ノードを4つ持っているが,うち3つは一院系列,他の一つは常陸介系列で,橋姫系列というのは存在しない.

浮舟の母は2つ結婚を持っている.相手は八宮と常陸介で,浮舟は両方に属しているがどちらも相手方の系列で展開されているのだろう.従って,大臣(橋姫)系列の優先ノードとなり得るのは浮舟の母だけだ.DecidePrimaryNodeではこの後,TRIBEBOX:GetAlternativePrimeNodeで代替候補の浮舟の母を見つけているので,問題はない.つまり,ここでは停止しなくてよい.

予想されていたことだが,非連結系列が出てしまった.

同上サンプルを#81 弘徽殿女御で開いて,TribeRelocation【11】系列包括矩形領域を集積して系統を並列配置するステージで非連結系列が発生した.「始系列参照パスが途切れている系列」が3件.

  1. #110566 先祖=#789 左大臣(真木柱)(0)[27] 優先=#653 左大臣の女御(0)→#425 冷泉院(0) →主系列#110502:摂政太政大臣 type=婚姻関係
  2. #110568 先祖=#853 宰相の娘(0)[28] 優先=#853 宰相の娘(0)→ #425 冷泉院(0) → 主系列#110502:摂政太政大臣 type=婚姻関係
  3. #110570 先祖=#857 中納言の娘(0)[29] 優先=#857 中納言の娘(0)→#425 冷泉院(0)→主系列#110502:摂政太政大臣 type=婚姻関係

少しおかしい.これら3系列はすべて摂政太政大臣系列を参照しているが,摂政太政大臣系列は始系列ではなかったのか?⇒Majortribeが設定されていないためのようだ.いや,設定されているが,TRIBEBOX:GetMajorTribeでNULLを返している.GetMajorTribeでは

  1. 始系列である場合
  2. 仮ノードがノード対を持っている場合
  3. 仮ノードがBTW右手本人の場合
  4. 仮ノードがBTW左手本人の場合
  5. 仮ノードがノード対参照先実ノードで系列種別が逆婚姻関係の場合

以外は有効な系列接続関係と認めていない.しかし,現行ではもっと多様な関係が許されている.これには,親子関係による接続が含まれていないし,配偶者→配偶者の参照も認められていない.これを以下のように整理した.

  1. 仮ノード:本人 x 実ノード:本人 → 親元関係
  2. 仮ノード:本人 x 実ノード:配偶者 → 婚姻関係
  3. 仮ノード:配偶者 x 実ノード:本人 → 逆婚姻関係
  4. 仮ノード:配偶者 x 実ノード:配偶者 → BTW左接続関係/BTW右接続関係

すべてこの区分で解決した.

▲同上サンプルを#94 明石の上で開いて,DecidePrimaryNodeを実行中,MARGBOX::GetUpperNodeで「親ノード不正」エラーが発生

抽象グラフ検証系を外したベーシックなシステムの動作を再確認する

抽象グラフ検証系を外したベーシックなシステムの動作を再確認しておこう.グラフ検証系はZTシステムの肝とも言うべき重婚同類循環検定で用いられている機構で,ZTシステムの必須コンポーネントではあるが,それなしでも通常の系図を描画することは可能であり,どのような系図もたとえそれが最適なものではなかったとしても少なくともエラーなしで描画できなくてはならない.グラフ検証系がベーシックシステム自体の不良をカバーするものであってはならない.

MakeUpTreeの中で系列優先ノードを決定するDecidePrimaryNodeを全面的に書き換えた.これはある意味で,系列接続関係の仕様を根底から修正するものになっている.従来仕様では,従系列の系列優先仮ノードとそれが参照する主系列の優先実ノードは大概の場合は異なるカードの人名枠であることが仮定されていたが,改訂DecidePrimaryNodeではこの制限を大幅に緩和して,仮ノードと実ノードが同一人名であることがむしろノーマルであるような仕様になっている.

要は2系列の接点となるノードが決定できれば,その接続関係は問わないという立ち位置にシフトした.実際,系列優先ノード決定の時点では接続関係が確定していない配偶者ポジションにある2つのノードを結合するということが行われている.この関係は最終的にはBTWによって解決されているが,従来論理ではこのような選択は不可能だった.つまり,接続関係は後付けてよいというポリシー変更がなされたと解釈してよい.

グラフ検証系を外したZTベーシックシステムで,源氏物語全系譜6.1.ZELの全体図を#1 光源氏で開いて,出口検査のCheckPerfectTreeで「結婚枠内兄弟ノードの衝突」が検出されている.実際,NAMEBOX #615 藤壷の宮(0)と#605 末摘花(0)の人名枠が交叉している.水平交叉量は6で計算誤差として許容できる範囲を超えている.しかし,エラーを無視して描画するとこの交叉は解消してノーマルな状態で描画されている.これは検査関数の中で使われているCheckBrotherOrderが検査モードで呼び出されているにも関わらず,実動作を伴うものになっているためと考えられる.これはそれ自体不良なので調べておこう.

MARGBOX::CheckBrotherOrderは実行関数としてMARGBOX:checkBrotherOrderを呼び出している.この関数から呼び出しているCheckBrotherCrushがモードに関わりなく移動を実行している.⇒対処した.次の問題はなぜ,このエラーがメインループで検出されなかったか?という点だ.⇒どうも,検査ルーチンの中に実動作を伴うものがあるように思われる.⇒原因はTRIBELIST::CheckMaximalSegmentにある.セグメント検定はTRIBEBOX::CheckMaximalSegmentによって系列単位に実行される.障害が起きているのは一院系列 #1056なので,ここだけ見ればよいだろう.いや,障害はどうも複合的なもののようだ.

TRIBELIST::CheckMaximalSegmentの単独実行では発現しない.それに加えてtribelist->IsTribeCompleteを実行する必要があるようだ.この2つは実行順序を問わず,どちらを先に実行した場合でも発現する※.TRIBEBOX::CheckMaximalSegmentから呼び出されるTRIBEBOX:CheckMaximalCompactionは検査モードというのを持っていないが,それから呼び出されるMaximalCompactionには検査モードがある.便宜的にCheckMaximalCompactionの引数が空の場合は実行モード,そうでないときは検査モードであるとしてみよう.⇒この修正は意味があるが,現在の障害には影響を与えない.

※藤壷の宮(0)と末摘花(0)の人名枠の交叉はTribeRelocationの出口ですでに存在している.ただし,交叉量は4で許容誤差の範囲内にある.下記のMoveNeutralによる移動は実際にはわずか1しか移動していないが,IsTribeCompleteの中でもCheckMaximalSegmentが実行されているため,移動量1の動作が複数回実行されることにより,傷口が6まで拡大して発現に至るという状況になっている.

MAXIMALGRAPH::mergeUpperSegmentでBobject::MoveNeutralが実行されていた.MaximalCompactionから呼び出されるCountUpLooseBeltは検査モードを持っていない.この関数は本来検査専用と考えられていたものと思われるが,CountUpLooseBeltからMoveNeutralまではかなりの段数がある.

CountUpLooseBelt→ TRIBEBOX::CountLooseBelt→ MAXIMALGRAPH:JoinUpperSegment→ MergeUpperSegment→ mergeUpperSegment→ Bobject::MoveNeutral

中間の各関数は本来検査専用で,検査/実行を区別していない.mergeUpperSegmentでは対象結婚枠がZTYW婚の場合に限り,隣接人名ノードを接触位置まで移動するという操作を行っている.この動作を廃止するというのも一つの考え方であるかもしれない.

この処理を停止したら,今度はMARGBOX::CheckMarchainで「結婚鎖拡張チェーン不正」というエラーが起きるようになってしまった.上記修正とは本来まったく無関係であるようなところだが… 上の修正が妥当であるか否かは別として,これはこれでまた別の障害と考えるべきだろう.まず,こちらを先に片付けることにする.

上記のような条件の下で,TribeRelocationの【9】先祖並び自動オフで系列枠を線形物理配置というステージの「ZTYW婚の適正配置を実施する」という段で,CheckZeroPositionを実行して「結婚鎖拡張チェーン不正」というエラーが発生している.結婚チェーン上に並んだ2つの結婚枠が同じ配偶者を持っているとき,後ろの結婚枠のsiblingsが前方結婚枠を指していないというエラーだ.実際には空が入っている.siblingsというのは,「前方にある同じ母の子ども枠への参照:チェーンを構成する」というものなので,確かにどこかで間違えているように思われる.

  1. MARGBOX:#1725:#409 光源氏(0)+#603 夕顔(0)→#419 玉鬘(0)
  2. MARGBOX:#343:#409 光源氏(0)+#603 夕顔(0)→

どちらも光源氏(0)+夕顔(0)の子ども枠で本人と配偶者が同じ結婚枠が子どもも1人しかいないのに2つあるという点が不審だが… 属性を見ると,前者はTOOYOUNGWIFE|ERASEDYOUNGWIFE,つまり,ZTYW婚,後者はERASEDZEROGHOST|GOODSIBLINGとなっている.つまり,「ZTYW本人を参照する仮ノードが存在する元の親枠」だ.

この2つの結婚枠は元々は一つのものだったのだから,「拡張子ども枠」のようなものでないことは明らかであり,siblingsを持っていないのも当然のように思われるが,このようなエラーはこれまで見たことがないような気がする.ZTYW婚というのはそれほどレアなものではないので,もっと頻発してもよさそうな気もするのだが…

最終的にはこのZTYW婚は消えてオリジナルのMARGBOX:#343だけが残り,玉鬘は夕顔の直下に配置されている.mergeUpperSegment→ Bobject::MoveNeutral の問題に戻ろう.下図で赤く塗りつぶしたところはZTYW婚で,この図面だけでもかなりの個数が使われている.

image

ZTYW婚の位置は不定なので,親ノードと同一セグメントにするのが難しいため,強制的に親ノードを隣接ノードの接触位置まで移動するという便法を取っているのだが,そのような強行手段(小細工)を取らなくても事実上問題は解決されているように思われる.この解法はひとまず保留として様子を見ることにしたい.しかし,これ以外でも検査モードで実動作が起きている可能性があるので,点検が必要だ.

予防措置としてTRIBEBOX::CheckMaximalSegment実行中はOnCheckMaximalSegmentが立っているので,このフラグがONのときは停止するようにしておこう.OnCheckMaximalSegmentを拡張してTRIBELIST::CheckMaximalSegmentの範囲まで広げておく.Bobject::MoveNeutral,Bobject::RelativeとBobject::originateでこのフラグをチェックするようにした.

すべてのオブジェクトの固有データ部を完全に殺菌(ゼロクリア)する

条件コンパイルをフィックスするときの手続きにミスがあったため,ファイルをクローズしたときのシステムのクリーンアップに失敗していたが,ようやく保健所の調理場検査にパスできる状態になった.理想的には存続するすべてのオブジェクトの固有データ部を完全に殺菌(ゼロクリア)してしまうことが望ましいが,一部環境パラメータを保持しているオブジェクトがあり,そのようなものに関しては別途措置が必要になる.環境パラメータと一般データを形式的に識別することはできないので個別のクラスで対応することになるが,保全の必要な環境パラメータであることを明示するためにこれらを一度ローカル変数に退避しておいて,処理的には全領域をゼロクリアするというのがわかり易いのではないかと思う.保全されるべき環境パラメータには以下がある.

  1. long BASETABLE::tablesize テーブルの物理サイズ
  2. HWND COUPLING::hwnd ウィンドウハンドル
  3. long DATALIST::datasize リスト要素のデータサイズ
  4. QUICKDB KAKEIZU::carddata, marriage
  5. CSize TREEVIEW::WindowSize 親ウィンドウサイズ,物理単位 CPoint WindowPost ノーマル画面で親フレームの左上点物理座標 CPoint PreviewPost プレビュー画面で親フレームの左上点物理座標

NODULE::signatureという変数は使われていないので廃止する.

ZTシステム構成図7.BAD2.ZELを開いて,LIST::nextで停止する.(!find(listnod))が起きている.TribeRelocationでSIMPLEGRAPH:BuildTightHasseDiagramを実行しているところだ.障害ノードは#2408 NODELISTでSIMPLENODE #14742の次の要素を求めているが,#14742がリスト上に存在しないというエラーになっている.このリストはかなり複雑な構造になっているが,該当要素は存在していないようだ.重婚同類検定では枝グラフを3つ使っている.

SIMPLEGRAPH::TightenHasseDiagramは主語のグラフの他,引数でもう一つのグラフtajugraph3への参照が渡されている.問題の箇所にはこの2つのグラフの節点リストを取り違えるというミスがあった.重婚グラフ検定の論理は一度総点検する必要がある.もし,複数のグラフを併用する必要があるのであれば,2つのグラフを引数で渡して,関数自体はクラスの静的関数とした方がよいと思う.一応現状で正しい論理が実装されているという仮定で修正を入れてみよう.以下の関数を改造した.

  1. BuildTightHasseDiagram
  2. TightenHasseDiagram
  3. sortComponentList

「完全参照リスト管理をサポートする」というオプションをOPTIONSからSPECIFICATIONに格上げし,REFERENCELISTCONTROLとリネームした.⇒裏オプションでも動作することを確認しておこう.⇒参照リスト管理は現在,黒子としての存在に留まり表では活動していない.

SUPPORTSIMPLEGRAPH「SIMPLEGRAPH抽象グラフ検証系をサポートする」というオプションで抽象グラフ検証系を止めてみる.⇒実装した.グラフ検証系なしでも思ったより動作している.ZTシステム構成図7.ZELは難なく開けた.ただし,一部の検査論理は停止している.抽象グラフ検証系でサポートしている機能には以下がある.

  1. GENEBOX::CheckInverseCycle 危険対枝グラフの循環検定
  2. TOPOLOGY::TestInevitableMultiZero 重婚同類グラフの循環検定
  3. TRIBELIST::ShiftDirectAbsolute 絶対世代番号に基づきカードシフト
  4. TOPOLOGY::FindJikusenAncestor 血糖軸線図のサポート
  5. TOPOLOGY::MakeLinearEdgeList 系列枠の全順序を決定する

SUPPORTSIMPLEGRAPHオフのバージョンで渋沢一族8.ZELの全体図を#211 大川平兵衛の息子で開こうとして,TRIBEBOX:GetAlternativePrimeNodeで停止した.系列優先ノードが決定できない.この系列は#2501 先祖 #950 渋沢 長登(宗安)で,最初は#1038 尾高 平九郎を優先ノードとする親元関係で決定していたはずなのだが,#956 渋沢 やへの婚姻関係に切り替わっている.

最初のGetAlternativePrimeNodeで切り替わり,2回目で失敗しているという構図だ.何が変わったというのだろう?⇒いや,変化していないために停止している.これはこのカードがTRIBEBOX:DecidePrimaryNodeでリジェクトされていることを意味する.つまり,DecidePrimaryNodeとGetAlternativePrimeNodeが相反している.⇒DecidePrimaryNodeに逆婚姻関係を導入して解決した.

どうもDecidePrimaryNodeのできが悪過ぎる.今度は源氏:明石中宮で停止した.この関数は全面的に書き換えた方がよい.この関数では現在の優先ノードのチェックだけを行い,不可のときは自分で代替候補を探すのではなく,GetAlternativePrimeNodeに任せるようにした方がよい.優先ノードチェックの要点は,①GetRealnodeで優先実ノードを確保できるかどうか?②主系列と従系列の基準ノードに対する位置関係,③系列種別が合っているかどうか,だけでよい.