これですよ,これ,これが見たかったんだ!

すでにノーリターンポイントを超えてしまっているのでこのまま驀進するしかない.どこに向かって?崖っぷちに出るまでかな?

PAIRLIST::putbottomではdatacountを更新していない 

LIST::putbottomにはdatacountの更新が入っている.それだけではなく,この関数では繋いでいるスロットも間違っているようだ.この関数は引数を2つ持っているが,2番目の引数commonは共有端点ノード対を示しているはずだ.だとすれば増設スロットに接続しなくてはならないのに,スロットゼロに接続している.⇒この関数の後半部,commonが空でない場合はまったく使われていない.⇒関数の仕様を変更して,後半部を完全に抹消した方がよい.⇒対処した

▲端点共有→繋ぎ替えの動作を確認する

端点共有ノード対は接続チェーンを構成しているので,リストと呼ぶべきだが,慣用的に端点共有束という言い方をしているので,これに統一することにする.「束」と呼んでいるのは連結線がダブって1本に束ねられているように見えることから名付けたものと思われる.離散数学でいう束※とは関係ない.※⇒任意の2つの要素が唯一の上限と唯一の下限を持つような半順序集合を束と呼ぶ

端点共有ノード対の操作は,そこで完結している限りオブジェクトの削除や解体とは関わりがないが,増設スロットをどう操作しているか?という点に興味がある.PAIRBOX::setsamepointで「端点共有なし」以外の値を設定しているのは,PAIRBOX::SetSamePointとPAIRBOX:repairCommonEndPoint,PAIRLIST::puttail,NAMEBOX:makePairBoxしかない.SetSamePointはMoveSamePointとmakePairBoxから呼び出されている.

puttailはMoveCommonChannelToから呼び出されて,端点共有束のチャンネル移動を実施している.MoveCommonChannelToから呼び出されるcutoutはdeleteElementでノード対をノード対リストから切断しているが,後続する端点共有束もノード対と一緒に移動するため,dataCount()でカウントダウンしている.つまり,nodl_floatでは端点共有束をリストとしては扱っていないことになる.実際にそうなっているのかどうかを確認してみよう.⇒いや,MoveCommonChannelToは現行では使われていない.これは紛らわしいので抹消しておこう.⇒PAIRLIST::cutout,puttailも廃止される.

MoveSamePointではRemoveとReConnectを使って繋ぎ替えを実施している.RemoveではdeleteElementでフロート化した後,後続端点共有ノード対を前方に繋ぎ替え,後続リストノードは後続端点共有ノード対に繋ぎ替えている.ノード対リストからの切断はすべてdeleteElementで実行されるので実質nodl_floatが実行されている.nodule::nodl_floatの説明には,

増設スロットに接続されている子ノードXは対象ノードが接続されていたスロットに接続され,スロットゼロの子ノードZはノードXのスロットゼロチェーン末尾に移動する.子ノードXが空の場合はノードZを
対象ノードが接続されていたスロットに接続する.

とあるので,deleteElementの後に実行しているReConnectは不用である.ReConnectの説明では「Reconnectではそのノードの元の接続先については何も操作していない.通常はnodl_floatで切断してからReconnectを実行する.」とあり,むしろnodl_floatに任せた方が安全なのではないか?一度バックアップを取ってから書き換えを試みる.

その前にEXTRA_ANCHORをEXTRASLOTにリネームしておこう.この増設スロットはスロットゼロに近いもので,アンカーとして用いられることはおそらくないものと考えられる.⇒18箇所あった.

ZTシステム構成図7.ZELを#223 anod[]で開いてGENEBOX:getFloorで停止した.直接基本世代枠リストのインデックス(1発進)がゼロになっている.⇒最初#223で開いて,#202 NODULEでソートすると再現できる.ということは,系統並び替えを実行するときの初期化が不十分ということになる.

障害は系統並び替えの冒頭の基本世代枠リストのcancel中に起きている.フェーズはTOPOLOGICALSORTだ.ゼロが返るというのは,そのノードがリストに含まれていないことを意味する.この世代枠は削除処理中(disposing)でリスト上には存続しているが,おそらくリスト先頭要素でtop()から検索したのでは見つからないのだろう.リスト上に存在しない場合には0ではなくFARFUTUREを返すようにしておこう.

全体図テストに掛けてみたが,このサンプルではRemoveの対象が端点共有ノード対でactionが偽というパターンは出てこない.ただし,actionが真というのはあり,このときはリストに2点登録されているのに,deleteElementでリストが空になってしまう.ただし,datacountは1になっている.この動作はおかしいので追いかけてみよう.

#1 couplingを開いて終了で再現できる.このケースではリストにはPAIRBOX #33492, #33479, #32917 の3点が登録されていて,#33492と#33479は端点共有束を構成しているが,#33492の削除で#33479もリストから消えてしまう.

PAIRLIST::Removeではかなり技巧的なことをやっている.増設スロットが終了処理中に抹消されてしまうことから防禦するために,冒頭でこのスロットを空にしてからdeleteないしnodl_floatを実行している.このオブジェクトは事後にReConnectされるので最終的にはノーマルな状態に戻っているようだが… ⇒対応修正して25行のコードがわずか1行で済むようになった.これですよ,これ,これが見たかったんだ!

#82 SIMPLEGRAPHでソートしてLIST::nextでリスト末尾不整合のエラーが起きた.PAIRLIST::Removeに仕掛けたcheckdatacountがエラーを出している.MakePairListClean→ … → RetrieveGhost→ Removeというフローだ.RetrieveGhostはノード対を1個抹消するだけの関数だが,これ1本で475行もあるという十分大きな関数だ.

PAIRLISTは分岐のあるリストなので何をもってリスト末尾とするか?で議論があるような気がする.PAIRLIST::nextは端点共有を含むすべての要素を巡回できるので,この順序で末尾というのが順当な定義と思われるが,直列リスト末尾という考え方もあり得ないことはない.それにしても,リスト要素がまだ10個もあるのにリスト末尾が空というのはどこかで間違えているのだろう.

PAIRLISTはdataCountDownを持っていない.これはかなりおかしいのではないか?PAIRLIST::dataCountDownを作らなくても,nodule *preceding(nodule *)という関数を作れば対応できる可能性はある.多分この関数は仮想関数にする必要があるのではないかと思われるが…DATALISTはnodule*preceding(nodule*)を持っているので試してみよう.⇒preceding仮想関数は実装できたが,問題がある.

確かにすべてのノードに全順序を与えて,その末尾をボトムとするというのは合理的だが,現行論理の中にはおそらくそれに対応していないものがあるのではないかつまり,端点共有ではないノード対をリストに追加しようとしたときの接続先がボトムになっている.どうすればよいか?端点共有というのは例外であり,通常のノード対は直列リスト上にあるので,ボトムと言えばそちらの方が正解のような気もするが…

PAIRLISTではリスト上の次ノードを取り出すためにnextとnextboxという2つの関数を使い分けている.nextはリスト上のすべての要素を巡回する関数,nextboxは基本クラスのnextを呼び出すだけの直列リスト専用関数だ.nextboxをnextとしていれば,多分なにもしなくても動作していた可能性はあるが,余計なことをしてしまったものだ.この名前を入れ替えるのはかなり難しい.通常はリネームするとコンパイルエラーが出るのでどこを修正すればよいのかが分かるが,nextは基本クラスの関数なのでそれがなくてもエラーにはならない…

現行の動作は直列リスト型で動作している.⇒問題はそこではない.端点共有が存在する場合には,直列リスト上にないノードが直列リスト上に現れるという問題だ.dataCountDownはLISTのメンバー関数なのでそこまでは手が回らない.そのノードが末尾ノードのときにはprecedingで上位ノードを取り出しているが,この関数を曲げて後方にある端点共有ノードを引っ張り出すというのはあまりに強引だ.ここは素直にPAIRLIST::dataCountDownを導入すべきだろう.

「PAIRLISTにdataCountDownを導入@20201122」というコメントがあるが,どこにもその形跡はない.20201203にフィックスしたことになっているが,内容的に同じなので割愛したのかもしれない.⇒できた.LISTがbottomlistを書き換えてしまうので事前にチェックし,直列リスト上にあることを確認するためにIsOntheListを使った.

コメントを残す

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

CAPTCHA