CheckAxisLineStraightで例外が発生

最近の修正をフィックス.

  1. MAXREPEATCOUNTを廃止する@20210315 8箇所
  2. MakingLookUpは系統並び替えで一度だけ実行する@20210227 11箇所

源氏物語全系譜7.ZELの全体図 #4 明石中宮で被参照カウントの残留が起きている.TribeRelocationのフェーズAFTERMARGSAMEGENEでTribeGhostNameを実行しているところだ.障害はNAMEBOX:ExtractBox2LDRsubで対象ノードを削除するところで起きている.その後,CheckAxisLineStraightで例外が発生する.TREEVIEW:GetBaseBoxが空を返している.まず,この障害を先に見ておこう.

CheckAxisLineStraightでは「血統軸線図で軸線上の描画要素が垂直線上にあることを確認」している.TREEVIEW::GetBaseBoxはTREEVIEWが管理している基準ノードの仮ノードbaseboxを返す関数で,この値を設定しているのはTREEVIEW::SetBaseBoxだ.値は設定されているが,その後このリンクはExtractBox2LDRsubの中で削除されている.TREEVIEW::CleanSansyoでは参照解除した後,SelectBaseBoxで取り直しを実施しているのだが… ⇒実際,この時点では値は再設定されているのだが…どこかでリセットされている.再設定されてはいるが,値は削除対象リンクと同じだ.

TREEVIEW::SelectBaseBoxでは基準カードの仮ノードが無効になっている場合には取り直しするようになっているが,まだこの時点では活きているためだ.すでにNAMEBOXのデストラクタが発動された状態になっているので,disposingを見るようにしておこう.⇒解決した.この修正で上記の非参照カウントの残留も発生しないようになった.

上記サンプルの#6 玉鬘でAFTERMARGSAMEGENEフェーズのループが停止しなくなった.TOPOLOGY::EstablishMajorTribeChainが収束しない.EstablishMajorTribeChainでは系列木グラフを連結成分に分解しているが,3成分に分離した状態から脱出できない.分離している系列は以下の2つだ.

  1. TRIBEBOX #16586 先祖=#12539 中将のお許(髭黒付)(0)[34] 優先=#19098 髭黒(3)→#10720 髭黒(0) →主系列#15210:※3 type=BTW右接続関係
  2. TRIBEBOX #16599 先祖=#12556 木工の君(0)[35] 優先=#19115 髭黒(4)→#10720 髭黒(0) →主系列#15210:※3 type=BTW右接続関係

どちらも髭黒が系列優先ノードになっている.ループを強制脱出して描画まで進むことはできる.最終出力ではすべての系列の参照関係は解決している.2つの系列の共通の優先実ノードである髭黒(0)では当初「系列優先実ノードの絶対/物理世代番号不一致」が発生しているが,その後解消しているようだ.それでは何が原因で「物理コネクション不在」になっているのか?系列接続種別が途中でどちらも逆婚姻関係に切り替わっている.参照先も髭黒(2) →主系列#16307:右大臣(明石)に変わる.最終的には髭黒(0) を左手本人とするBTWが成立する.髭黒(0) を左手本人とするBTWには以下がある.

  1. rightbox=MARGBOX #8100:#11026 髭黒の前の北の方(0)+#18238 髭黒(1)→#18252 真木柱(2)
  2. rightbox=MARGBOX #8020:#12539 中将のお許(髭黒付)(0)+#19098 髭黒(3)→
  3. rightbox=MARGBOX #8276:#12556 木工の君(0)+#19115 髭黒(4)→

なぜだろう?AFTERMARGSAMEGENEフェーズではこれらの結婚に対するBTWは試されていない.MainExperiment→ ReduceMultiCard→ FindDoublyBlessedOneでは多重カードを持つ人名リンクを対象にそのノードが配偶者となっている結婚枠を総当りでチェックしているので漏れがないが,TRIBEBOX::BetweenTwoWomenでは制約条件が多いため外れている.現行方針は,AFTERMARGSAMEGENEで①すべての系列の物理コネクションを確立する,②多重不可避を除くすべてのノードで絶対世代番号と物理世代番号が一致する配置を確定する,というものになっているので,少なくとも系列優先ノードの関わるBTWはこのフェーズの中で決めてしまう必要がある.

AFTERMARGSAMEGENEのループで実行しているBetweenTwoWomenを廃止して,系列優先ノードに限定してFindDoublyBlessedOneを使ってみることにしよう.⇒いや,むしろ,EstablishMajorTribeChainにそれを組み込んだ方がよいのではないか?⇒TRIBEBOX:addTribeTreeGraphでHasPhysicalConnectionに失敗したとき,系列優先ノードのBTWを試みるようにした.⇒これにより,TRIBEBOX #16586 先祖=#12539 中将のお許(髭黒付)(0)[6] 優先=#19098 髭黒(3)→#8697 玉鬘(0) →主系列#15210:※3 type=BTW左接続関係を確立できた.しかも,これ一発ですべての障害が解決した.

このサンプルでは髭黒が多重になって,多重が6件発生しているが,髭黒(2)と(3)は同世代なので仮ノード消去できるように見える.なぜ,それができないのかを見ておこう.髭黒の仮ノードは7個あるが,可視ノードはNAMEBOX #18950 髭黒(2)と#19098 髭黒(3)だけだ.髭黒(3)は配偶者だが,BTWの左手本人になっている.髭黒(2)は消去された仮ノードの実ノードで同時にTYW枠本人でもある.TYWをLDRに転換するという関数はあったはずだが… ⇒NAMEBOX::ExtractBox2LDRsubでそれをやっている.ExtractBox2LDRはeraseGhostからしか呼び出されていない.TYW枠を吸収するという処理もあったのではないか?

TOPOLOGY::CheckAbsorbMarriageは一度も実行されていない.⇒クラスタ循環がある場合には実行を抑制している.⇒クラスタ循環がある場合もCheckAbsorbMarriageを実行するようにした.これで髭黒の多重は消えて,多重5件という最小値まで削減することができた.これ以外のパターンで多重カードが5件以上になるケースがかなりある.これは避けられないのだろうか?

▲同上サンプルの#56 今上で停止した.TRIBEBOX:CheckAbsoluteGeneで(prime->IsValidNameBox() && !primary->breakup)が起きている.(primary->getnodegene() == prime->getFloor())の場合はその直前でゼロ復帰しているので,系列優先仮ノードの絶対世代番号と物理世代番号が一致していないことを意味する.系列優先仮ノードがbreakupでないということは,そのノードがクラスタ循環でパージされた結婚に関わっていないということを意味するので,本来なら一致していなくてはならないのだが…

エラーを無視して続行すると,EstablishMajorTribeChainで停止しない状態になる.障害が起きているのは,TRIBEBOX #15140 先祖=#10448 二条太政大臣(0)[1] 優先=#9547 今上(0) で始系列だ.これはかなりおかしい.TRIBELIST::SetAbsolutePotentialでは,「絶対世代番号系と物理世代番号系を一致させる」としているのだが,一致していない.SetAbsolutePotentialは以下の3箇所から呼び出されている.

  1. AdjustTribeGeneration(void) (TRIBELIST)
  2. HeapTribeBoxes(bool symmetry) (TRIBELIST)
  3. SetTribeMaxGene(char * caller) (TRIBELIST)

SetTribeMaxGeneはGoDownStreamの出口で呼び出されている.また,TribeRelocationのステージ【1】系列相対世代番号を正規化するの段でNormalizeRelativeGenerationにより「系列相対世代番号を正規化する」ところでも実行される.また,ShiftDirectAbsoluteの中からも実行される.ShiftDirectAbsoluteの中からも実行されている.系統の最古世代先祖の絶対世代番号が1になっている.これはかなりおかしい.

絶対世代番号は0発進のはずだ.最古世代先祖として#10448 二条太政大臣(0)が選択されているが,明らかにこれは間違いだ.CARDLINK:#2922 @211※2[0]かないし,CARDLINK:#1473 @50※3[0]でなくてはならない.ということは,TRIBELIST::GetTheEldestが間違っているということになる.

水洗トイレが壊れてしまった 浮玉が上がっているのに水が止まらない

床に就く直前だったのですでに朦朧としていたが,工具類を引っ張り出して無我夢中に取り組むうち何とか水栓を止めて分解するところまではできたので,あとはそのままにしてぐたっと寝込んだ.

IMG_20210317_232343

カインズに行けば多分パーツを見つけることができるとは思うが,このところ昼夜が逆転しているので,しばらくは昼間表に出られない.ともかく,(よほど太物でない限り)シャワーで流せることだけは確認してある.(もともとこのトイレにはトイペーというものは置かれていない.シャワーでお尻を洗うとき,ついでに便器も洗うというだけだ)

多重カードが最小値の5ではなく,7になってしまう原因がわかった.TribeRelocationに続くメインループTRIBELIST::MainExprerimentで打ち切っていたためだ.多重カード数が下限と推定される値に達したときには処理を打ち切ってループから脱出するようになっていた.推定下限値にはこれまでsameGeneCyclesが当てられてきたが,現行ではTOPOLOGY::Inevitables「多重不可避カード数」が適用されている.これらの値は(源氏7をサンプルとしたときの)多重カードの最小値より大きいため,最小値まで削減される前に終了してしまっている.

この脱出条件を止めると,処理は多重カード数が静定するまで続行するので,最小値が確実に実現されるようになる.実際,このように手配した後では,「重婚クラスタ循環を子ノード側で切断」する場合も「親ノード側で切断」した場合も同じ結果になる.つまり,重婚クラスタ循環を切断するためのカットセットは必ずしも一意ではないが,最終出力としては同じ結果が得られると言える.これで重婚クラスタ循環が存在する場合を含めて,つねに最適結果を出力することができるようになった.別の言葉を使って言えば,「系図作図問題の原理的な完全解」を得ることができた,つまり,「系図作図問題が初めて原理的に解かれた」と言える.(思えば長い道程だった…)

軸線図がおかしい.#1 光源氏の軸線図が紫の上で止まってしまう.光にはまだ他の子どもがいる.もっと長い軸線があるはずなのだが… どうしたのだろう?軸線図はすでに仕上がっているはずだったのだが…

軸線図処理は2つのパートからなっている.①TOPOLOGY:FindJikusenAncestorはDECOMPOSITIONフェーズで系列分解処理TribeDecompositionの中から呼び出されて「軸線最長鎖」を決定し,②TOPOLOGY::CallBuildShaftLineは,TribeRelocationの中からBUILDCENTERLINEフェーズで呼び出されて.軸線グラフから血統軸線を構築する.①では最初に直系血族グラフを生成し,このグラフからGetLongestChainで軸線最長鎖を切り出している.

直系血族グラフの生成は単純な処理なので間違いないと思われるが,GetLongestChainでは明らかにやり損なっている.GetLongestChainでは最初にGetHasseDiagramを呼び出して枝グラフからハッセ図を生成している.このグラフをインポートしてみよう.

image

この図から見ると,最長で8世代に渡る軸線が存在する.先祖ノードは※3,末裔ノードは若宮(匂宮の)だ.これから軸線を切り出すのは容易であるように思われるのだが… この後,MakeAntiChainListで反鎖リストと呼ばれるものを生成する.反鎖リストは同世代ノードリストとも呼ばれ,同世代ノードを成分とする成分分解リストである.反鎖リストもCSV形式でエクスポートできる.90度回転させるとこんな図になる.

image

GetLongestChainの最終出力である軸線最長鎖は間違っていない.FindJikusenAncestorの最終出力も正しい.先祖ノード:CARDLINK:#1473 @50※3[0] 末裔ノード:CARDLINK:#1482 @51若宮(匂宮の)[0]となっている.結局,CallBuildShaftLineでやり損なっているということになる.CallBuildShaftLineは重婚クラスタ検定の前に実施される.この後の重婚クラスタ検定で軸線が崩されている可能性が高い.軸線が成功するためには,紫の上の下に明石中宮が来なくてはならないのだが,実際の出力でその辺りがどうなっているのかを見てみよう.

image

明石中宮は世代的には紫の上(0)の下の世代に配置されているが,紫の上のもう一つのカードである紫の上(1)に連結されている.これを紫の上(0)の直下に持ってこなくてはならない.確かにこれは難しい問題だ.結婚枠(子ども枠)は親(のいずれか)の直下に配置されることになっている.明石中宮の親は光源氏+紫の上であり,その意味では光源氏の直下か,ないしその配偶者である紫の上(1)の直下しか居場所はない.紫の上(0)は光源氏の娘(養女)ではあってもその配偶者ではないからだ.

軸線を描画するためにこの原則を曲げることは可能だろうか?光源氏→ 紫の上で止まるより,光源氏→ 明石中宮→ 匂宮→ 若宮 (匂宮の)の方が長い.実際,光源氏の軸線を考えるなら,その方が妥当だろう.つまり,光源氏→ 紫の上という関係を軸線から外して考える必要がある.しかし,光源氏→ 紫の上が親子関係(養親子関係を含む)にあること自体が問題という訳ではない.そもそも光源氏+紫の上→明石中宮という関係そのものが養親子関係だ.

軸線に反映する親子関係を実親子関係に限定するという割り切り方もあるのではないか?いや,それもやや疑問だ.光源氏→ 紫の上を実親子関係,光源氏+紫の上→明石中宮を実親子関係としても同じ問題が発生する.一番わかり易いのは,重婚クラスタ検定を経た後の「正則系図」上で軸線を考えるということではないだろうか?多系列にまたがる軸線というのを描画できるだろうか?現状では少し難しいように思われる.

現行枠組みを維持したまま,軸線図検定で光源氏→ 紫の上という親子関係をパージするというのがもっとも望ましいのだが… 重婚クラスタ検定を系列分解より前に実施することは可能だろうか?重婚クラスタ検定で用いているのは,①婚姻関係と②親子関係だけであり,系列という概念は持ち込まれていないはずだ.重婚クラスタ検定を先行実施できれば,「正則系図(絶対世代番号を付与されたハッセ図)」上で軸線を考えるということも可能になるのではないだろうか?不可能ではないような気がするので挑戦してみよう.

重婚グラフ検定はBuildSameGeneMarriageGraphとGetHasseDiagramという2つのパートに分かれていて,TRIBERELOCATIONとSAMEGENEMARRIAGEという2つのフェーズにまたがる大きな処理だが,一つにまとめることができる.これをまず,関数化しておこう.⇒TOPOLOGY::CheckWeddingClusterとしてみた.⇒まったく問題なさそうだ.少し面白くなってきた.⇒ダメだ.反例が出てしまった.桐壷院でソートしたら,EstablishMajorTribeChainで収束しないようになってしまった.⇒これは改修する前の版でも起きる.まず,このバグを取らなくてはならない.

▲源氏物語全系譜7.ZELを#1041 桐壷院でソートして,AFTERMARGSAMEGENEフェーズでTOPOLOGY:EstablishMajorTribeChainが収束しない.主系列が決定できないのは,TRIBEBOX #189411 先祖=#183114 三位中将(0)[27] 優先=#192114 夕顔(2)→#190999 夕顔(1)だ.系列接続種別は婚姻関係,系列優先仮ノードの夕顔(2)は消去された仮ノード属性を持ち,始系列の一院系列所属の優先実ノードの夕顔(1)は実ノード属性を持っている.何の問題もないように見えるのだが…

実ノードの絶対世代番号が物理世代番号と一致しないという理由だ.

甘いものが無性に欲しくなって

即席のドーナツを作ってみた.小麦粉+ベーキングパウダを水で溶いて熱した油の中にポトンと落としただけ.速攻3分でできあがり.ただし,画像をアップロードするのに2日掛かった.

ドーナッツ

重婚クラスタ循環は多重カードが発生する原因だが,循環に関係するクラスタに属するすべてのノードが関わっているという訳ではない.むしろ,循環を解消するためにパージされた婚姻グラフの枝,つまり結婚当事者ノードに関わりがある.循環の発生している重婚クラスタに属するノードにはCARDLINK::samecycle属性が付与されているが,それを代替するものとして,breakup属性を導入し,循環を解消するために削除された婚姻枝の結婚枠とその当事者ノード付与するようにした.{samemcycle} ⊃ {breakaup}でbreakup属性の方がより範囲が狭い.つまり,焦点深度が深い.CARDLINK::samecycleは廃止した.

TOPOLOGY::BuildSameGeneMarriageGraphのステージ【13】重婚グラフの循環が止まるまで枝を除去するの段では,「重婚クラスタ循環が存在するとき,親子枝の親ノードの配偶者の配偶者関係を切断」していたが,ターゲットを「親子枝の子ノード」に切り替えてみた.サンプルの源氏物語全系譜7.ZELでは,この親子枝は光源氏→夕霧に該当し,これまでは親の光源氏をクラスタから切断するという処理になっていたところを,子ノードの夕霧で切断するという操作に切り替えた.この結果,多重カードは現行の7から5まで削減することができた.修正前の多重カードは以下の7点だが,▲マークの付いた,源典侍と真木柱は修正後の版では多重になることを免れている.

  1. @5紫の上(若紫)[5]
  2. @57女三宮[4]
  3. @100源典侍[4] ▲
  4. @101朧月夜[4]
  5. @103空蝉[4]
  6. @104藤壷の宮[4]
  7. @144真木柱[6] ▲

これで見る限り,修正後の版の方が高品質であるように思われるが,親ノードと子ノードのどちらを切断する方が有利かはケースバイケースであり,本来ならその優劣を計量して決定すべきところだが,多重カードの出現数はコンテキストに依存して決定されるため,この時点では確定することができない.実際,「子ノードで切断」する方式の場合,削除される枝数は以下のようにむしろ増加している.下記▲は「親ノードで切断」には含まれない循環/削除枝.

  1. 削除枝:直系血族配偶者 MARGBOX #8260:#8612 光源氏(0)+#17138 紫の上(若紫)(1)→#8663 明石中宮(0)
  2. 循環枝:【2】⇒【2】 【CARDLINK:#1095 @8夕霧[0]】⇒【CARDLINK:#1032 @1光源氏[0]】
  3. 削除枝:重婚配偶者 MARGBOX #6916:#17276 落葉の宮(1)+#9938 柏木(0)→ ▲
  4. 循環枝:【2】⇒【2】 【CARDLINK:#1032 @1光源氏[0]】⇒【CARDLINK:#1041 @2桐壷院[0]】▲
  5. 削除枝:重婚配偶者 MARGBOX #8548:#17672 柏木(1)+#17686 女三宮(2)→#17700 薫(2)
  6. 削除枝:重婚配偶者 MARGBOX #7252:#10601 伊予介(0)+#18368 空蝉(2)→
  7. 削除枝:重婚配偶者 MARGBOX #7076:#9887 致仕太政大臣(0)+#17571 夕顔(1)→#17585 玉鬘(1)
  8. 削除枝:重婚配偶者 MARGBOX #7092:#9887 致仕太政大臣(0)+#17600 源典侍(2)→
  9. 削除枝:重婚配偶者 MARGBOX #7380:#9309 朱雀院(0)+#17339 朧月夜(1)→
  10. 削除枝:重婚配偶者 MARGBOX #8292:#8629 桐壷院(0)+#17389 藤壷の宮(1)→#17403 冷泉院(3)

直系血族婚はあらかじめ除去されているので循環枝に含まれていないが,それを含めれば,修正前の方式では循環を解消するために2箇所の切断が必要であり,修正後の方式では切断は3箇所に増加,パージされる婚姻関係(削除枝)は前者が7であるのに対し,後者では8に増加している(しかし,多重カード数は後者の方が少ない).

HasPhysicalConnectionで系列優先実ノードの絶対世代番号と物理世代番号の一致を求めるように修正した.HasPhysicalConnectionはDoesMajorTribePathExistとaddTribeTreeGraphから呼び出されている.DoesMajorTribePathExistはIsConnectedとSetMinorTribe,TribePrimaryCandidateで使われている.addTribeTreeGraphはEstablishMajorTribeChainから実行される.この修正により,源氏物語全系譜7.ZEL #1 光源氏で起きていた「絶対世代番号と物理世代番号の不一致」は解消した.

多重カードは5枚.多分これは最少多重カードになっていると思う.ZT BASICではグラフ検証系を使えないため,9件の多重カードが残る.最近の修正をフィックスしておこう.

  1. CARDLINK:samecycleを廃止する@20210315 12箇所
  2. MAXREPEATCOUNTを廃止する@20210315 8箇所
  3. MakingLookUpは系統並び替えで一度だけ実行する@20210227 廃止 10箇所
  4. TESTABSOLUTEGENERATION 3箇所
  5. 仮修正 2箇所,OBSOLETE 1箇所

Version 2.2.0.029 Release 2021-03-17を所内リリースした.⇒ダメだ.多重カードが7に戻ってしまった.修正フィックス前の版でも同じ.⇒ZELKOVA 2021-03-15-2まで戻れば復活する.WinMergeでファイルを比較してみたが有意差は見つからなかった.この版とZELKOVA 2021-03-16の相違点はグラフ関係の関数を移動していることと「MAXREPEATCOUNTを廃止する」修正がまだ入っていないくらいだ.その他TribeRelocation.cppには細かい差異があるが,一瞥しただけでは致命的なものは見つからなかった.

ともかく,この版に戻って出直すしかない.まず,この版で「CARDLINK:samecycleを廃止する@20210315」と「重婚クラスタ循環を子ノード側で切断する@20210315」をフィックスしておこう.⇒後者はSPECIFICATIONとして温存しておいた方がよい.この版でリリース版を起こしておくことにする.その前にZT BASICで動作することを確認しておこう.⇒OKだ.改めて,「MAXREPEATCOUNTを廃止する」を入れておこう.

重婚クラスタ検定論理の修正

TOPOLOGY::BuildSameGeneMarriageGraphを修正して,ステージ【3】婚姻関係にある2つの人名を連結する枝をグラフに追加するの段で「直系血族婚関係を重婚クラスタグラフからあらかじめ排除する」ようにした.また,重婚クラスタ循環が存在するとき,親子枝の親ノードPの配偶者の配偶者関係を切断する処理で,配偶者Aの配偶者Bとの関係が配偶者Bの唯一の結婚の場合には切断しないように修正した.

これはこの切断によって配偶者Bが孤立してしまうことを防止するためである.この関係を切断しなくても,クラスタの世代分割には支障はない.配偶者Bは配偶者Aとともに親ノードPのクラスタに移籍するようになるからだ.これで,少なくとも大臣(葵)系列と蔵人の少将 (夕顔)系列で発生していた,「絶対世代番号と物理世代番号の不一致」は解消したが,まだ複数の「絶対世代番号不一致」が残っている.

image

この中には,先帝系列,※6系列,※7系列,按察の大納言(若紫)系列が含まれているが,問題は系列優先ノードとその他のノードとの位置関係にある.このブロックの中心は先帝系列でその優先ノードの紫の上(若紫)が光源氏との直系血族婚関係にあるため多重出現していることが関係しているのではないか?だとすれば,どうすればよいか?

系列優先ノードでsamecycle属性を持っているノードが14点,breakup属性を持っているノードが4点ある.samecycleは循環の発生している重婚クラスタに属するノードで,breakupは循環を解消するために削除された婚姻枝の当事者ノードだ.breakupノードは一般にsamecycleノードでもあるが,紫の上(若紫)は上記修正により,重婚クラスタ検定に入る前に直系血族婚関係で除去されているため,breakup属性しか持っていない.breakup属性を持つ優先仮ノードには以下がある.

  1. TRIBEBOX #15205 先祖=#8765 一院(0)[1] 優先=#8612 光源氏(0) 始系列
  2. TRIBEBOX #15349 先祖=#10533 先帝(0)[4] 優先=#50277 紫の上(若紫)(3)→#17138 紫の上(若紫)(1)
  3. TRIBEBOX #15593 先祖=#10516 衛門督(箒木)(0)[15] 優先=#18334 空蝉(1)→#10346 空蝉(0)
  4. TRIBEBOX #16087 先祖=#10414 三位中将(0)[28] 優先=#18734 夕顔(2)→#8612 光源氏(0)

このグラフのクラスタ図を見てみよう.

image

※6系列と※7系列が中務宮と同じ世代まで下がっているところが特徴的だ.※3と並ぶ※2系列は実際の出力では左端に移動しているが,高さは変わらない.実際の系図出力は下図のようになっている.

image

系図全体の世代高さは同じ9世代だが,クラスタ図には冗長なところが存在しない.どこでこの差異が発生しているのかを突き止めなくてはならない.紫の上のカードは2つ出ている.紫の上(0)は葵の上の直下の子ども枠内で絶対世代番号と物理世代番号は一致している.紫の上(1)はその一つ上の世代,光源氏の結婚枠内で絶対世代番号5に対し,物理世代番号は4になっている.

クラスタ図上には人名カードの重複は存在しないから,クラスタ図上では絶対世代番号5の位置にあり,他の場所から参照される場合もその位置で参照されているはずだ.先帝系列の優先ノードを紫の上と決定したときの選択に誤りがあるのではないだろうか?つまり,クラスタ上で決定した位置に配置されるべきノードを選択すべきだったのではないだろうか?⇒少なくとも系列優先実ノードの絶対世代番号≠物理世代番号であることが決定因であることは間違いなさそうだ.

クラスタ図を用いて絶対世代番号を決定した後の処理

重婚クラスタ検定でクラスタ図を用いて絶対世代番号を決定した後の処理を見直す必要がある.ここでは2つのことを実施している.①絶対世代番号を用いて各描画要素の配置を決定すること,②系列間の参照関係を確立し,物理的なコネクションを確保すること.①は主にTRIBELIST::ShiftDirectAbsoluteとAdjustTribeGenerationによって実行され,②はTOPOLOGY::EstablishMajorTribeChainが担当する.

①の状態を検査するためにTREEVIEW::TestAbsoluteGenerationを復活させた.系列参照関係はすでにMAKEUPTREEフェーズで基本的には確立しているが,物理的なコネクションを構成するためにTRIBEBOX::TribeGhostNameとBetweenTwoWomenが発動される.また,これらの処理によって描画要素の垂直位置関係に矛盾を解決するためにCheckTribeVerticalPositionが用いられる.

重婚クラスタ循環がない図面ではこれらの道具立てで十分処理できるのだが,問題は源氏のように重婚クラスタが無数に存在するような図面の場合だ.このような図面に多重カードが発生することは避けられないが,それを極小化するためには,絶対世代番号を用いた配置とそれからの逸脱をコントロールする必要がある.どうすればよいか?

まず,重婚クラスタグラフからハッセ図を生成するときに除去された削除枝(結婚)を追跡できるようにしておこう.一度バックアップに戻って出直すことにする.

カード巡回パネルの仕様を変更

カード巡回パネルの仕様を変更して,巡回対象テーブルを検索テーブルから選択テーブルに変えることにする.⇒改修した.また,左右カーソルキーでカード巡回パネルのスピンボタンを代用できるようにした.左右カーソルキーでカード巡回パネルが出ていない場合でも,選択されたカード領域を巡回することができる.これは結構便利かもしれない.

▲部分図で選択カード0のとき,全体図に戻って選択カード1となり,一覧表では選択状態になっているが,系図画面では選択が落ちている.⇒再現できない.

源氏物語全系譜7.ZEL全体図#1 光源氏で「先祖ノード絶対世代番号不一致」が以下で発生している.

  1. #10533 先帝(0)
  2. #10618 大臣(葵)
  3. #10992 ※6(0)
  4. #11349 按察の大納言(若紫)
  5. #11536 ※7(0)

AFTERMARGSAMEGENEフェーズでShiftDirectAbsoluteとAdjustTribeGenerationを実行した直後には世代不一致は起きていない.その後に実行される①CheckTribeVerticalPosition,②TribeGhostName,③BetweenTwoWomenのうち,①は世代調整のために不可欠なので温存し,②と③はメインループに入ってから遅延しょりすることにした.また,リトライではAFTERMARGSAMEGENEの入口まで戻って,ShiftDirectAbsoluteとAdjustTribeGenerationを再実行するようにした.これで#10618 大臣(葵)を除くすべての「先祖ノード絶対世代番号不一致」が解消した.

大臣(葵)の世代不一致は六条御息所の重婚に起因するもので,配偶者である前春宮と光源氏が異世代とならざるを得ないことから不可避と認定される.

image

このサンプルでは多重が9件発生しているが,除去された循環枝数9と一致している.この中には本人ポジションを持たない不可避多重カード6件が含まれる.これはほぼ「究極の多重カード最小図面」と呼んで差し支えないのではないかと思う.

▲上記サンプルで※3系列と先帝系列で「主系列の付け替え」が反復発生している.※3系列では優先ノードが#17897 桐壷の更衣(1)⇔#17865 明石の上(1)で行ったり来たりになっている.先帝系列では,#17963 真木柱(2)と#17949 髭黒(1)の間で往復運動している.どちらも主系列は一院系列で結果的には主系列には変更はない.この切り替えはEstablishMajorTribeChainで起きている.

Windows 10 バージョン 2004のインストールに失敗した

PCがやけに重くなっている感じがしたので,Windows 10 バージョン 2004のインストールを試みた.ダウンロードにも相当な時間が掛かったが何とか完了し,インストールに入ったが遅々として進まないので寝てしまった.朝起きたら「更新したプログラムを構成しています 25%」の状態で足踏みしている.30分放置してもまったく進まないので電源を落として再起動した.ネットでチェックすると,バージョン 2004のインストールには相当問題があるようだ.

image

再起動すると「コンピュータに対する変更を元に戻しています」の画面になったが,そのあとは通常通り使えるようになった.OSのバージョンは1909に戻っている.「更新を7日間一時停止」しておくのが一番無難かもしれない.最近の修正をフィックスしておこう.

  1. SIMPLENODEのdownwardとupwardを廃止@20210303 2箇所
  2. 選択はカードの有効無効と無関係@20210305 4箇所
  3. クラスタ検定に結婚を持たない終端ノードを含める@20210306 1箇所
  4. 主選択カードの仕様変更@20210307 2箇所
  5. カード選択とカード移動を切り離す20210306 7箇所
  6. 仮修正 2箇所,暫定修正 6箇所,#if 0 8箇所,

カード履歴ボタンではセンタリングしなくてもよいのではないか?現参照カードにはHOMEキーでいつでもジャンプできる.⇒だとすれば,カード履歴で単選択に戻るのではなく,選択領域を維持したまま現参照カードだけ切り替えるという仕様の方が筋が通るのではないか?⇒カード履歴ではJumpNewCardSingleで単選択に落としている.カード履歴でカード画面のタブが切り替わるのもよくない.⇒カード履歴では意図的にタブを復元している.JUMPTBLには以下の記録が格納されている.

  1. refn As Integer ‘現参照カード(基準ノード)参照番号
  2. tabn As Integer ‘カード画面タブ番号
  3. page As Integer ‘結婚ページ番号
  4. oyap As Integer ‘父母ページ番号
  5. entry As Integer ‘部分図エントリ番号
  6. previewmode As Short ‘プレビューモード
  7. keizuparm As mKeizuParm ‘系図描画パラメータ

つまり,可能な限りそのときの状態を復元させるという意図がある.一種のUNDOのような効果を狙っていたものと思われる.少しやり過ぎではないかという感もある… カード移動によって無闇にタブが切り替わらない方がよいという場合もあると思うのだが… タブの切り替え,結婚ページ,父母ページの切り替えなどは一時停止してしばらく運用してみることにする.これで,上下矢印キー,カード画面のスピンボタン,カード履歴ボタンの動作は現参照カードを移動するだけというシンプルなものになった.これでよいのではないかと思う.

逆に,矢印キー,スピンボタン,履歴ボタンが押されたときはカード巡回パネルは閉じた方がよいと思う.現行では履歴ボタンでは閉じるようになっているが,スピンボタンは巡回パネルのスピンボタンの動作になっている.また,矢印キーではやや意味不明の動作になる.⇒矢印キーでは巡回パネルを閉じるようにした.カード画面のスピンボタンが巡回パネルの動作になるというのも少し分かりづらいところはあるが,弊害はあまりないと思われるので現行のままとする.

系図画面の空白部をクリックして無選択にならない.⇒表示が更新されていない.mGetSelectListでは0を返している.UpdateSelectionは実行されている.⇒処理の重複を回避するために削り過ぎてしまった.UpdateSelectionの中でClearSelectionを実行することは必須だ.

選択→センタリングという動作そのものはよいと思うが,少し動作し過ぎの感じがする.カードが見えている場合はそこまでやらなくてよい.⇒CallCenteringMoveでは,*selectchangeがオンの場合はカードがフレーム内のときはジャンプしないようになっている.ただし,ACTION_HOMEKEYではつねに現参照カードにジャンプする.⇒CZelkovaCtrl3::CenteringCardの動作をACTION_CENTERに戻した.動作的にはこれでよいと思う.ただし,一覧表上で拡張選択(複数選択)した場合には現参照カードが見えるようにすべきだ.

呼び出し側ではそのような動作になっているが,ActionCenteringには引数で参照番号を渡していないため,どこかで齟齬が起きている.⇒TREEVIEW::CallCenteringMoveで*selectchangeが入っていないため,「中央点不動ズーム」の動作になっている.⇒タイミングが合っていない.センタリングはCardGridView_CurrentCellChangedで実行されるが,selectchangeに値が入るのはDataGridView_MouseUpでSelectionProcが実行されたときだ.この順序関係を変えることはできないので,ACTION_CENTERの場合は,selectchangeを無視してセンタリングを実行するようにするしかない.⇒修正した.これで完全に現参照カードを追尾できるようになった.

源氏物語全系譜6.1.ZEL 全体図#1 光源氏で一覧表で複数選択→親族図に切り替えで被参照カウントの残留が発生した.NAMEBOX:Dispose→ RetrieveGhost→ DeleteLongTailで発生している.MARGBOX[24]からの参照だ.MARGBOXsANCHORスロットでanchor2という変数だ.「アンカー参照の控え,アンカー付け替え時の参照削除用:人名枠への単純参照」というコメントが付いている.NAMEBOXにはNAMEsDUMMYというスロットがあり,dummyboxという名前が付いている.この障害は選択操作と無関係に発生する.

NAMEBOX::Disposeでcheckをオンにすると,これまで停止していなかったところで止まるようになる.⇒checkで停止するようになっていた.紛らわしいので廃止しておこう.

dummyboxはすでに空になっているが,現物は残っている.dummyboxは参照ではなく接続なので,おそらくフロート状態になっているのだろう.障害が起きているのはNAMEBOX #96515 中姫君(4)で,ダミー枠はMARGBOX #96525だ.⇒いや,読み損なっていた.障害ノードはNAMEBOX #86655 中姫君(3)で,dummyboxは活きているので簡単に参照解除できる.⇒解決.

同上の操作でNAMEBOX::getDrawSizeの「親族範囲外カード」エラーが複数出ている.LINEAGEの値は7でZELKOVATREEのとき,カードのkindredが10>7であるためだ.10というのはSTRANGERSなので明らかに「親族範囲外カード」であるように思われる.ただし,これはTREEVIEW::EraseTreeViewで起きているので,検査対象とはなならない.少なくともCHAOTICSTATE以下では無視してよいだろう.

同上サンプルの親族図の系図画面上で複数選択→ 部分図に遷移しようとしてMARGBOX::MostLeftで停止した.(ML && ML->group() != group())というエラーだ.結婚枠とその中の人名枠の所属系列が異なるというエラーだ.選択操作とは無関係に発生する.この障害もやはり,EraseTreeViewで発生している.上記と同様無視でよいだろう.

いい感じになってきた.選択操作に関してはほぼ満点と言ってよい.

検索ボックスでテキストを全選択して削除でカード削除になるのはまずい.⇒これはおそらくDELキーがカード削除コマンドになっているためではないかと思われる.このため,キーイベントが発生する前にコマンドが実行されてしまっている.KeyDownSubではCtrl+DELでカード編集:カード削除となっていて,「@2017-09-09 修飾なしの削除キーでカード削除を実行する × 弊害がある」としているのだが… ⇒まず,カード削除コマンドのショートカットをCtrl+DELに変えてみよう.

検索ボックスでDELキーを押すと,MDIForm_KeyDown→ KeyDownSubを通るようになるが,該当項目がないのでパスしてテキストのクリアが実行される.また,系図画面にフォーカスがあるときには,ZView_KeyDownが起動され,ここでは「修飾なしの削除キーでカード削除 」が実行される.これでよいのではないだろうか?カード画面上のテキストボックスでも普通にDELキーが使える.

検索ボックスで検索条件不一致で検索テキストが削除されるというのはあまりよい仕様ではない.また,テキストがクリアされた後,カーソルがボックスの中央というのも違和感がある.⇒検索入力ボックスのAlignmentはLeftになっている.このAlignmentはテキストボックス内の位置ではなく,ボックス全体がツールバーの中で右寄せか左寄せかという設定になっている.MDIParent.Designer.vbで「Me.検索入力ボックス.TextAlign=System.Drawing.ContentAlignment.MiddleLeft」としてみたが,変化しない.というか,不一致でテキストがクリアされると見ていたが,違うようだ.

「マッチするカードはありません」のパネルを閉じてもテキストボックスには残っている.ただし,ボックス内にカーソルを置くと突然消えて,カーソルがボックスの中央に表示された状態になる.しかし,カーソルを移動すると消えていた文字がまた復活する.検索入力ボックスのイベントハンドラは「検索入力ボックス_TextChanged」だけだ.ボックス内にカーソルを置いただけではこのイベントは発生しない.⇒よくわからないが,ここではこういうものだとしておこう.

検索ボックスの右にある虫メガネは選択領域があるときには,巡回パネルの右スピンボタンと同じ動作になっていて,カードを巡回するようになっているが,インジケータ行が変化していない.⇒SearchBoxSearchにUpdateSelectionを追加してインジケータ行も連動するようになったが,動作的にはかなり問題がある.選択領域と検索領域を混用するというのはやはりまずいのではないか?

検索領域は検索結果の巡回にのみ使用するように限定すべきだと思う.確かに選択領域を巡回できる手段があるというのも悪いアイディアではないが,混乱の元になる.検索結果は新たな検索が実施されるまでは温存され,いつでもカード巡回パネルないし検索ボタンで巡回できるというのはよいと思う.従って,選択領域を検索領域にコピーするという操作は基本的に不要ないし有害であると思われる.

選択領域→ 検索領域のコピーはmGetSearchListで実施している.この関数をmGetSearchListから呼び出すというのはとりあえず停止しよう.また,検索結果を選択領域に組み込むというのも廃止すべきだろう.いや,検索領域を選択領域に落とすというのは結構有用性があるのではないか?だとすれば,検索結果をストレートに選択領域に転換するというのが一番わかり易いと思う.

ただし,次検索で巡回するのは検索領域であり,選択領域ではないから,たとえば検索解除しても次検索は可能ということになる.検索領域から選択領域へのコピーはMakeSearchSelectionで実施している.この関数ではSendSelectionで選択領域を送っているので,系図画面には反映されているが,一覧表が更新されていない.⇒MakeSearchSelectionでUpdateSelectionを実行するようにした.

F3を押すと巡回パネルが閉じてしまうが,開いたままでよいのではないか?⇒KeyDownSubで閉じている.F3キーの場合は開けたままとしてみよう.

検索条件をキープされているはずだが,入っていない.SearchStringは検索文字列リストに追加しているだけだ.CopySearchConditionがMakeSearchSelectionから呼び出されているが,これはZ.SCの内容を検索パネルのパラメータにコピーするものだ.検索ボックスではZ.SCを使っていないのではないか?QuickSearchでは事後にZ.SCを構成しているが,MakeSearchSelection実行後なので間に合わない.⇒先行してZ.SCを構成するようにした.

クィック検索では姓名を1文字列としているが,姓と名前に分離する必要がある.スペースを区切り文字としてSplitで分割するようにした.

キーワード「大納言」で検索し,結果を新規部分図として部分図に切り替えようとして,TOPOLOGY::BuildSameGeneMarriageGraphで停止した.多重グラフ2の枝リストが空になっている.しかし,これはすべてのノードが孤立ノードの場合なら,あり得ることだ.ダンプだけで停止しないようにした.

カード一覧表をクリック→カード選択でカード画面が変化しない

カード一覧表をクリック→カード選択でカード画面が変化しない.矢印キー,カード画面のスピンボタンでは変化する.系図画面上のクリック→カード選択でも変化する.一覧表の最左セル(インジケータ列)のクリックなら変化する.⇒CardGridView_CurrentCellChangedでCardBox.GetNewCardを実行するように修正.CurrentCellChangedではマウスアップイベントとの重複動作を避けるためにSelectionProcないしSendSelectionを実行しないように修正している.

今後は,カード画面上に表示されるカードを現参照カードと呼ぶことにする.現参照カードは三図面(全体図・親族図・部分図)共通でカード選択操作によって指定されるが,↑↓キーないし,カード画面上のスピンボタン(カード番号の差左右に配置)を操作することで選択状態に変化を与えずに移動することができる.つまり,現参照カードと選択カードは独立の状態として管理される.現参照カードは一覧表の最左列をクリックするか,ないし人名カードのカード番号欄にカード番号を記入→ENTERで直接変更することもできる.

カード一覧表の最左列のクリックで現参照カードを切り替えたとき,一覧画面上のカラー表示行が更新されない.⇒CardGridView_CurrentCellChangedでインジケータ移動を処理しているブロックでChangeRowColorを実行するようにした.

一覧表の表示範囲が系図画面上のカードのとき,系図画面上に現参照カードが存在しない場合には,インジケータは消えていなくてはならないのにそうなっていない.人名カード上のスピンボタンでカード移動した場合にはそのような動作になる.カード履歴で移動した場合も一手遅れてそのような状態になる.

図面種別を切り替えたときには現参照カードがレコードに含まれているか否かをチェックしなくてはならない.また,含まれていた場合にも行が変化している可能性がある.以前はKindredMapSubの中でGetNewTableを実行していたが,現行では「図面種別変更では必ず系統並び替えが実行されるのでここでは不要」としているため,この関数内では検査ができない.同様のことは一覧表の表示範囲を切り替えたときにも起こり得るので,GetNewTableの中で検査した方がよい.

GetNewTableではUpdateSelectionを実行しているので,この中で検査できるのではないか?⇒一番確実なのはUpdateIndicatorでチェックすることだろう.いや,UpdateIndicatorの中から実行されるSetCurrentCellでは現参照用カードのレコードが存在しない場合にはインジケータをリセットしているのだが… UpdateSelectionに渡している引数が悪い.BuildNewTableの戻り値を使っているが,間違いだ.

現参照番号を渡すようにした.カード履歴で移動のときには,Z.SelectedRefnumをUpdateSelectionに渡している.SelectedRefnumは検索などのときにも使用される作業変数なので,適切ではない.Currefnumを使うべきだろう.⇒大体整理されたのではないかと思う.

親族呼称図.ZELの全体図で基準ノードの#46 義父(舅)→婿を削除しようとして,NAMEBOX::Disposeで停止した.その後,系統並び替えで多重グラフ2の節点リストが空で停止した.SIMPLEGRAPH:GetHasseDiagramで「基準ノードが空」エラーが起きる.基準ノード以外のカードの削除では特に問題は発生しない.多重グラフ1の連結成分リストには含まれている.

15  #7743 k COMPLIST 7743 {2}[0]<15> <15>CARDLINK:#629 @48妻の祖父→孫娘の婿[0] <15>CARDLINK:#638 @49妻の祖母→孫娘の婿[0]

ただし,このクラスタは親子関係を持っていないため,多重グラフ2には算入されていない.⇒多重グラフ2は親子関係による枝グラフとして生成されているが,親子関係を持っていないノードもグラフに含める必要がある.⇒最初に多重グラフ1の連結成分リストを転記して多重グラフ2の節点リストを構成しておくようにした.これでどんな多系統図でも扱えるようになったのではないか?

image

「カード削除」によって系列優先ノードが削除されることは普通に起こり得るので,OnDeleteCard中はNAMEBOX::Disposeで停止しないとしておくことにする.

同上サンプルの部分図基準ノード=#45 妻→夫の基準ノードを削除した後の動作が悪い.UNDOで戻ったとき系図画面で現参照カードの枠が消えている.他のカードをクリックするとその枠が逆に表示される.⇒UNDOを実行したとき,画面を更新する前に枠を削除していないのだろう.UNDOを実行したときには必ず系統並び替えが実行されるので,その時点でフラグをリセットする必要がある.

いや,それはやっている.どこかで余分な動作が入っているのではないか?⇒TREEVIEW::DrawControlでは冒頭で選択枠を非表示とし,出口で選択枠を再表示しているが,dispselectしか見ていなかった.DispSelectBoxは選択枠と現参照カード枠の両方を処理しているので,dispprimeを見る必要がある.⇒動作するようになった.

一覧画面上で選択操作した場合には,従来のように現参照カードにジャンプできるようにした方がよい.これまではCardBox.GetNewCardでセンタリングするようになっていたのだが,インジケータなどによる移動でもGetNewCardになるので,センタリングする場合としない場合を切り分けなくてはならない.可能だろうか?

DataGridView_MouseUpではSelectionProc()を呼び出しているが,これもどちらの場合も含んでいる.矢印キーによる移動とカード画面のスピンボタンによる移動ではSpinUpDownを呼び出している.この関数の中でもGetNewCardを使っているので,GetNewCardの外でセンタリングするようにすればよいのではないか?

以前はSelectionProcの中でCenteringCardSubを実行していたのだが… CardGridView_CurrentCellChangedの中ではインジケータ列のクリックとそうでない場合の2箇所でGetNewCardを実行している.インジケータ列のクリックでない場合にはセンタリングを実行するようにした.

HOMEキーも予定したような動作になっている.これで選択操作と現参照カードの操作はほぼ完全に整理が付いたのではないかと思う.これと類似した機能として,検索時のカード巡回とカード巡回パネルによる選択領域のカード巡回がある.チェックしておこう.

一覧表とカード画面は巡回パネルと同期しているが,系図画面のジャンプが止まっている.この操作ではGetNewCardは呼び出されていない.代わりにMakeNewCardを実行している.SetSelectCardで「カード巡回パネルのカードを更新」しているが,この中でCenteringCardSubを実行している.なぜ利かないのだろう?

一覧表でカード選択→ カード巡回パネルで「巡回の対象となる(複数の)カードがありません」のエラーが出る.このエラーはZ.SearchCountの場合に発生する.カード巡回の対象はZ.DeleteTableではなく,Z.SearchTableなので,それを転記する必要がある.TakeSearchSelectionでそれをやっているが,現在のところ止めてある.MakeSearchSelectionというその逆関数もある.

mZelkova::mGetSearchListはTakeSearchSelectionと同等のことを実施している.Zelkova1_NodeClickではmZelkova::mGetSelectListから選択カードリストを取得して,mGetSearchListで検索リストに転記している.mGetSelectListの中でつねにmGetSearchListを実行する必要はないと考えられるので,停止しておこう.その代わり,カード巡回_ClickでZ.mGetSearchListを実行するようにしてみた.

これでカード巡回はできるようになったが,スピンボタンの押下で一覧表の選択が落ちてしまった.これはおかしい.⇒SetSelectCardでUpdateSelectionを実行していたところ,「カード巡回では選択領域を変化させない」という理由でUpdateIndicatorに変えたためだ.UpdateSelectionを単独で実行すると単選択になってしまう.

CZelkovaCtrl3::CenteringCardでは引数にカード参照番号が入っているが,実際の動作ではまったく参照されていない.実際には選択カードリストを見ているため,予定したような動作にならないので,ActionCenteringの引数をACTION_CENTERからACTION_HOMEKEYに変更した.CallCenteringMoveではACTION_HOMEKEYのときは現参照カードにジャンプするようになっているので,この方が実情と整合する.

カード巡回パネルが出ているときに選択状態を変えてもテーブルが更新されない.また,一覧表で選択操作を行うとカード巡回パネルが閉じてしまう.⇒上記ではmGetSelectListの中でmGetSearchListを実行しないとしているが,修正を戻して実行するようにした.また,一覧表上の選択操作でもカード巡回パネルを閉じないようにした.

インジケータ列のクリックで選択が落ちる場合がある.⇒特定のカードで落ちているような感じもする.なぜか,#15 五宮で落ちる.かなり不思議だ.⇒以下の条件が成立してCardGridView_CurrentCellChangedから離脱している.

EditRowIndex = CardGridView.CurrentCell.RowIndex

EditRowIndexが14になっている.EditTableFlagを見ていないためだ.

▲カードと連動をオフにするとカード切り替えがオンになるが,パネルを開いたときにカードと連動オフの場合はカード切り替えはオフになったまま.また,カード切り替えボタンを押してもカード画面の内容は更新されず,パネルを閉じて終了してしまう.

▲源氏物語全系譜6.1.ZELの全体図 #1 光源氏でカード番号でソートしようとして,非参照カウントの残留が発生した.EraseTreeViewからNAMEBOX::Dispose→ RetrieveGhostで起きている.なにかの拍子にカード番号の昇順ソートが掛かってしまった.しかも,その前に選択反転のようなことも起きている.

一覧表のインジケータを選択と独立に操作

終端ノードないし孤立ノードを選択して系統並び替えを実行すると,SIMPLEGRAPH::GetHasseDiagramで「基準ノードが空」というエラーが出ていたので,BuildSameGeneMarriageGraphのステージ【4】で「複数の親を持つ終端カードを節点とする自己ループを追加する」としていたところを,「結婚を持たない終端カードを節点とする自己ループを追加する」のように変更した.これにより,すべての有効なカードが重婚クラスタグラフに含まれるようになった.

これで選択操作と図面操作が切り離され,選択状態は図面をどう改変しても変化しないようになったが,厳密に言うとまだそれが残っているところがある.一覧画面とカード画面上でカード移動を実行すると選択は単選択状態に戻ってしまう.現行では①一覧画面・カード画面上でのカードの移動,②系図画面上でのセンタリング,③カード画面に表示されるカードは完全に連動している.選択状態を維持したままカード移動を実行するとしたら,どんな仕様になるのか?考えてみよう.

  1. 一覧画面上のインジケータが移動する
  2. カード画面に表示される主選択カードが変化する
  3. 系図画面はカードの移動によっては変化しない
  4. 系図画面で主選択カードにジャンプするにはHOMEキーを押す

ということになるのではないだろうか?カード検索を実行したときに表示される「カード巡回」パネルはやや上と類似した動作になっている.ただし,検索結果に含まれるカードはすべて選択状態になっているので,①選択されたカードを巡回する,②系図画面ではセンタリングが実行されるという相違点があるが,考え方としては近いものがある.上のような仕様が実装されることになれば,カード巡回パネルの操作でも系図画面は変化しないということになるのではないだろうか?この方が操作的には軽くなり,より使い易くなるのではないかと思う.

一番の問題点は項目1の「一覧画面上のインジケータが移動する」,つまり選択とインジケータの操作を完全に分離可能かどうか?という点にある.まず,この点を確認しておこう.⇒難しいかもしれない.一覧表のクリックとUP/DOWNキーの押下は同じイベントで処理されている.いや,先にキーイベントが発生しているから,切り分けることはできるのではないか?⇒可能だ.その前に,カード移動したときセンタリングしないようにしたときの操作性がどのように変化するかを見ておこう.

センタリングしないというのでよいのではないか?実際,部分図や親族図でカードが画面上に存在しない場合などもある.つまり,カード移動では系図画面は変化しないというのでよいと思う.ただし,カード画面と一覧画面はつねに連動するものとする.

もう一つ問題がある.仮に選択状態を変化させずにカード移動ができるようになったとしても,すべてのカードを巡回しないとそのカードに到達できないのではほとんど意味がない.カード画面ではカード番号を入力→ENTERでそのカードにジャンプできるが,それと同等のことが一覧画面でもできなくてはならない.一覧表の最左列つまり,インジケータが表示されている列のセルをクリックするとそこにジャンプできるようにすることは可能だろうか?

▲カード編集:カード巡回で「巡回の対象となるカードがありません」の表示が出る.一覧画面で複数カードを選択しているのだが…

▲プレビュー画面でズーム倍率を100%に切り替えたら,Zelkova1_MoveControlでAutoPosition.X < 0 Or AutoPosition.Y < 0というエラーが起きた.また,ズーム倍率25%でウィンドウ枠をドラッグしたら何重にも線が重なって画面が壊れた.ここでズームーボタンを押したら,倍率が595%になった.

親族図:直系血族図をカード一覧表:すべてのカードに切り替えて全点で62のところが,124点に増えてしまった.TREEVIEW:CheckSelectListでカウント不一致のエラーが出ている.選択カード数は1でselectflagのカウントはゼロ.

BuildNewTableでは,テーブルを一旦空にした後,再構築しているが,このとき,行の追加によりCurrentCellChangedイベントが発生→ CurrentCell.ColumnIndex = 0→最左列のクリックと誤認してGetNewCardを実行→ MakeNewCard→ 参照番号がゼロであるため,GetNewTable(True)で新しいテーブルが追加されるという動作になっている.⇒CardGridView_CurrentCellChangedでテーブル構築中は無動作で抜けるようにした.

基準ノードの行はシアン色で表示されているが,この行を含む複数行を選択した後,他の行をクリックすると,色が落ちてしまう.⇒しかし,起こる場合と起こらない場合がある.どうも行の並びと関係があるような気がする.⇒背景色設定を共通ルーチン化することで漏れを排除するようにした.⇒解決.

▲親族図と全体図で系統並び替えの基準ノードを共有しているように思われる.これらは独立ということになっていたのではないか?部分図の基準ノードは独立しているようだが… 確かにこの仕様はバランスが悪いような気もするが,実用的にはその方が適切である場合もあり得る.全体図でカードAを基準ノードにしているときに,親族図に移動する目的は,Aの親族図が見たいという場合が多いのではないか?このとき,まったく別のカードの親族図が出ていたとすると混乱する可能性がある.

しかし,現行では系統並び替えによっても選択領域は変化しないから,カードAが選択されていれば,そのまま系統並び替えを実行すればよいということになるのではないか?部分図のように親族図も独立の基準ノードを持つとした方が,仕様的には筋が通っていると思う.また,今回の「選択領域と提示カードの分離」という方向性にも合致している.

ただし,これを実装するにはファイルのフォーマットの変更が必要となるので,右から左という訳にはゆかない.同種の課題として,全体図・親族図・部分図で独立の環境パラメータ(親族種別など)を持つという懸案もある.これも保存ファイルのフォーマットに関わるので,もしやるとすれば同時に実現した方がよい.

この件は一時保留としてもう少し片付けることにしよう.一覧表のインジケータ行とカード画面に表示される提示カード(仮称)は完全に同期するようになったが,ここまで来ると系図画面にも出さないという訳にはゆかなくなる.提示カードは従来仕様の「主選択カード」に類似しているが,選択領域に含まれていないというところが大きな違いだ.

現行では主選択カードの取り出しには2つの方法がある.①系図画面で左ボタンアップ→TREEVIEW::LButtonUpで取得,②カード画面に人名カードを表示する際に,Z.mSetPrimarySelectionでカードの参照番号を送付.どちらの場合も最終的には人名カードが更新されるので,mSetPrimarySelectionがあれば間に合いそうだ.取得した値は,TREEVIEW::selectedcardとselectednameに格納されるので,とりあえず,それを流用することにしよう.

▲主点カードはカード画面上に表示されているカードと一致しなくてはならない.従って,一覧表の表示範囲が系図画面上のカードのとき,系図画面上にそのカードが存在しない場合には,インジケータは消えていなくてはならないのにそうなっていない.人名カード上のスピンボタンでカード移動した場合にはそのような動作になっている.カード履歴で移動した場合でも,一手遅れてそのような状態になっている.

▲親族呼称図.ZELの直系血族図で基準ノードの#46 義父(舅)→婿を削除しようとして,NAMEBOX::Disposeで停止した.その後,系統並び替えで多重グラフ2の節点リストが空で停止した.全体図でも類似の障害が発生する.このケースではSIMPLEGRAPH::GetHasseDiagramで「基準ノードが空」エラーが起きる.基準ノード以外のカードの削除では特に問題は発生しない.

系統並び替えを実行しても選択が落ちない

カード選択はユーザの主体的な行動であり,システム側からユーザに押し付けるものではない.カード選択操作の場面は,①系図画面上の選択,②一覧画面上での選択,③カード画面での移動,④編集コマンドによる選択がある.③ではつねに単選択になるが,それ以外は一般に複数カードの選択が可能だ.①で系図画面上のカードをクリックないし拡張選択した場合はOCXが選択/解除されたカードないし領域をDLL側に通知する.DLL側ではそれに従い,selectcardlist->tableを更新する.

②の場合,アプリ側ではZ.DeleteTableに選択領域を設定して,GCに送り,GCではそれをDLLに伝達する.DLL側ではDeleteTableの内容をTREEVIEW::selectcardlist->tableに転記する.④には全選択/選択反転がある.全選択では「有効なカード」がすべて選択され,選択の反転では「有効なカード」ー「選択されたカード」が選択状態になる.「有効なカード」とは一覧表表示範囲:系図画面上のカードに相当する.カードテーブル上のカード(CARDLINK)はselectcardlist->tableと同期するためのフラグselectflagを持っている.DLL側でselectcardlistの更新を行っている関数には以下がある.

  1. TREEVIEW::putSelectList ←CallPutSelectList
  2. TREEVIEW::selectAll ←CallSelectAll
  3. TREEVIEW::hitSelectNode ←TREEVIEW::LButtonUp
  4. TREEVIEW::selectNode ←TREEVIEW::LButtonUp
  5. TREEVIEW::getSelectList ←CallGetSelectList
  6. TOPOLOGY::RebuildCardList ←UNDOSYSTEM::UndoProcess,UNDOSYSTEM::CommandEnd

getSelectListはputSelectList の逆関数でアプリ側にselectcardlistの内容を返す関数だが,その前にカードテーブルをスキャンしてselectflagオンのカードをselectcardlist->tableに収集してから送付している.RebuildCardList はUNDOシステムで用いられる関数でカードのselectflagからselectcardlist->tableを復元している.系図画面で拡張選択したときの動作を見てみよう.初回だけは系図画面と一覧画面が同期していたが,後が続かない.なぜか?

LbuttonUpからselectcardlistを更新するところまでは問題ない.その後,Zelkova1_NodeClickが起動され,mZelkova::mGetSelectListを呼び出してZ.DeleteTableを更新している.Z.DeleteCountの値も正しい.一覧表の更新はUpdateSelectionで実行している.どうもどこかで選択が落とされている.ただし,Z.DeleteTableの中身は変化していない.

UpdateSelectionの中で落とされている.UpdateIndicatorで単選択に戻されている.動作不良の元凶はUpdateIndicatorだ.インジケータと呼んでいるのは,一覧表の最左列に表示される右矢印を意味している.選択操作に関連するが,インジケータの操作で単選択になってしまうというのはおかしい.UpdateIndicatorを実行しなければ,系図画面と一覧画面の選択状態は完全に同期している.

UpdateIndicatorから呼ばれるSetCurrentCellで単選択に落ちている.「現在のセルを変更すると DataGridView 選択範囲が変更される場合があります」ということのようだ.設定で回避できるのだろうか?現在の設定は以下のようになっている.

.SelectionMode = DataGridViewSelectionMode.FullRowSelect ‘つねに行全体を選択
.MultiSelect = True             ‘複数行の選択を許す
.AllowUserToDeleteRows = False
.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2

Selection Modes in the Windows Forms DataGridView Control によれば,「Note that changing the value of the CurrentCell property does not alter the current selection」となっているのだが…

UpdateSelectionでは以前は選択領域設定の前にUpdateIndicatorを実行していたのだが,「引数のカード参照番号が選択されていない場合がある@20180830」という理由で現在の位置に移動している.しかし,これでは完全に誤動作してしまうので,修正前の状態に戻すことにする.選択されていない参照番号を指定した場合には余分なカードが選択された状態になり,整合が取れなくなる可能性がある.CurrentCellを非選択にできるかどうかを調べてみよう.

問題なさそうだ.これで要求を満足する動作になった.複数選択動作でまだ一つだけ不十分な点がある.一覧表でインジケータの出ている行と,カード画面に表示されているカード,および系図画面で濃紺で表示されているカードは連動しているが,系図画面上で選択を落とす操作をしたときに濃紺で表示される「主選択カード」が消えてしまう場合がある.一覧表で操作した場合には問題ないように見える.

部分図で複数選択を実行して,getSelectListでCheckSelectListのエラーが起きた.getSelectListではカードテーブルからselectcardlistを作り直している.CheckSelectListでは有効カードのみをカウントしている.getSelectListでも同様処理するようにしてエラーは解消したが,有効でないカードの選択フラグはむしろ積極的に落とす必要がある.今度はTREEVIEW::hitSelectNodeで同様エラーが出た.

上記の修正は間違っている.「選択領域はカードの有効・無効とは無関係」というのがゼルコバの木の仕様だ.ただし,全選択と選択反転は有効カードのみが対象となる.⇒対処した.

図面種別を切り替えると系図画面が無選択状態になってしまう.系図画面の切り替えでは一度選択領域をリセットして,再描画する必要がある.系統並び替えの冒頭で実行されるTREEVIEW::InitTreeViewでsetSelcount(0)が実行されている.図面種別の切り替えでは必ず系統並び替えが必要になるから,ここでリセットされたのでは対処しようがない.GCに問い合わせできれば取得可能だが,上りインタフェースは存在しない.⇒InitTreeViewではsetSelcount(0)を実行しない代わりに,COUPLING::EraseFamilyTreeでリセットするようにした.

▲系統並び替えを実行して,GetHasseDiagramで「基準ノードが空」エラーが発生する.seedはFAMILYTREE::BaseLinkを含む成分リストで多重グラフ2の節点リストで探しているのだが… 通常の手順では発生しない.複数カードを選択し,そのうちの一つをCtrl+クリックで選択解除→ Ctrl+クリックで再選択してから系統並び替えで発生する.その後は図面種別の切り替えなどでも同じ事象が起きるようになる.

グラフをダンプしてみたが,確かに入っていない.ただし,これは上のような「手順」の問題ではなく,クラスタ図自体の問題だ.つまり,現行では終端ノードは世代番号の確定に関係がないという理由で省かれている.これは確かにまずいのではないだろうか?