前方視界不良という状態が続いている

前方視界不良という状態が続いている.五里霧中というほどのものではないが,かなり見通しが悪くなっている.どういう状態に持って行こうとしているのか,それをはっきりさせる必要がある.最終目標は,すべてのフェーズでつねに完全な参照管理が確立しているという状態,暫定的にはCLEARTABLEフェーズでは例外も認められるが,最終的にはその壁も崩されなくてはならない.UNDOの前後で崩れていないことは必須だ.系統並び替えに入る時点でトポロジーに関わるような操作はすべて完了していなくてはならない.

完全な参照管理とは,参照リスト管理がきちんと動作していること,参照カウントが正しく管理されていること,特にオブジェクトのデストラクタの中で整合性が維持されることが求められる.もう一つ重要なポイントは,①UNDO処理,②参照管理のいずれか,ないし両方が未サポートの場合でも正しく動作しなくてはならないという点だ.

今日の訪問者数は午後8時現在で700人を突破している.この統計が正しいとすれば,これまでのレコードになりそうだが,なぜそんなに急増しているのか?その理由が分からない.Googleアナリティクスには反映されていないので,真偽のほども不明だ.

EraseTreeViewの入口では整合しているのだが,描画リストのクリーンアップで不良が発生する.⇒いや,違う.CheckDataLinkではこの参照エラーは検出できない.CheckNringCountを仕掛けたら入口ですでに不良が発生していた.⇒やはり,UNDOだ.問題はバックアップイメージの復元を行うUndoRestoreにあると言ってよい.UndoRestoreでは,UndoCopyでオブジェクトからの参照を一旦すべてクリアしてから,イメージを復元し,その後,CountupReferenceで参照カウントの再計算を実施している.

とんでもないミスを冒していた.仮修正でコメントもなしに止めていた行があった.復活させたら動作するようになった.多分,これで完全になったという訳ではないとは思われるが… 参照処理はもう少し徹底した修正が必要と思われるが,別のエラーが出てきたので,先にそちらを片付けることにする.⇒再現できなくなってしまった.

われ 男の子 意気の子 名の子 剣の子

昨日はプチ宴会でお休み.今日が仕事始めだ.通常なら100本くらい入ってくるメールが今日はたったの2本しかなかった.昨日はそれでもまだ30本くらいはあったのだが… 昨日は飲み会(と言っても飲めるのはほとんどわたしだけ)から帰ったあと,Your Daily Epsilon of Math を投稿した.三日坊主で終わるのか,365本まで投稿して皆勤賞をもらえるかどうかは今のところ分からないが.まぁ,続けられるだけやってみよう.高校の卒業アルバムを弟が発掘してくれていたので,持ち帰った.わたしにも「少年時代」というのがあったのだ!アルバムの余白の寄せ書きの中にわたしの手で書いたこんな短歌が挿入されていた.

われ 男の子 意気の子 名の子 剣の子
詩の子 恋の子 ああ,もだえの子

誰の歌だろう?わたしが書いたのだろうか?確かに,この気分はわたしのものだが,わたしのボキャブラリの中には「剣の子」というのはなかったような気もする.気になって部屋に戻ってから調べたら,与謝野鉄幹の歌だった.確かに,これを読むとわたし自身の中に(父親から引き継いだ)「明治」のフレーバーが残っているのを感じる.

https://www.facebook.com/age.baba.5/posts/pfbid02RVMSuXJXTro94cRXvQ2j6NRJqVW8Nwtmf3Kurm8UnAgAD89xVu89jLk6vAYuBhA6l

▲極小反例307.ZELを開いて,再現リストの項目5の手順でUndoProcess→ UndoRestore→ UNDONODE::UndoCopy→ UNDOBASE::UndoCopyを実行後に置いたCheckDataLinkでカード参照番号の重複エラーが検出される.⇒動作確認のために動作をアレンジしている箇所があったが,外しても同じ.UndoRestoreはループ中の動作なので,一時的な不整合が生じる可能性は考えられるが,UndoProcessの出口でも同じエラーが発生する.

この2つのカードリンクはオブジェクトとしては別物で,PDB[48]に入っているのは「47」というカード,PDB[7937]に入っているのは「16129」というカードだ.参照番号はいずれも48.しかし,ファイルを開いたときのカード数は307点しかないのだから,7937などという場所に有効なカードが存在すること自体間違っているのではないだろうか?⇒いや,名前でハッシングしているので,リンクはテーブル上では離散的な配置になっているから,あり得ないことではない.⇒実際「16129」というカードは存在する.

ファイルオープン時にはこのカードは一覧表の先頭にある.参照番号は7937だ.「47」というカードの参照番号は48で,テーブルの末尾にある.ここまでは問題ないようだ.⇒いや,これは一度基準ソートした結果の場合だ.起動時では「16129」はテーブル先頭から5番目の位置にある.また,「47」は下から5番目だ.⇒基準ソートでは,この順序が逆転しているだけで,位置的には正しい.つまり,「47」が上から5番目,「16129」は下から5番目だ.

Undoでこの順序は元に戻るが,参照番号が変化してしまっている.「47」は7937に,「16129」は48に入れ替わっている.どうも,この最初のUndoがデタラメな動作になっているような感じだ.参照番号は確かにソート→Undoになっているが,中身の順序がバラバラに壊れている.Renumberというのは必須の動作だったのだろうか?⇒いや,ちょっと混乱しているかも.参照番号は離散値ではあるが,整列している(起動時は降順)が,名前順にはなっていない.頭の方を拾い出すと,

8113, 24421, 8021, 32561, 16129, 7811, 7793

のようになっている.末尾の並びは,下から,

23, 31, 35, 41, 47, 61, 71, 83, 16469

だ.ソートは問題なく動作している.Undoも正しく動作している.従って,ここまでの動作には問題はない.カードの一括削除の対象に入っているのかどうかが問題だ.「47」は残っている.参照番号は7937.「16129」は削除されている.どうも,このカード削除の動作がおかしい.カード削除によって参照番号の入れ替えが発生しているように思われる.元々の状態は,「47」が#48,「16129」が#7937だ.

別の不良が見つかった.最初にソート→Undoという手順を省いて,いきなり一括削除→ Undoでは順序の問題は発生しないが,「被参照カウント不一致」が大量発生する.こちらのバグの方が易しそうに思われるので,先にこちらを片付けておくことにしよう.このエラーはEraseTreeView→ ~NAMEBOX→ CleanSlot→ clearSlotで発生する.

NODULE::slottypeという関数は少し書き換えているので動作確認が必要だ.nodule::CheckSansyoCountという検査関数はNリング上のすべてのノードの参照カウントをチェックする.この関数の中で参照ではないと判断されたリンクが参照リストに記載されている可能性があるので検出できるようにしたところ,TRIBEBOXの参照リストにTRIBELIST→ TRIBEBOXという接続リンクが入っているのが見つかった.

TRIBEBOX *starttribeは「基準ノードの属する始系列への参照」となっている.TRIBELISTはNLISTの派生クラスであり,LISTNODEクラスのオブジェクトのリストということになっている.NLIST→ LIST→ DATALISTの継承関係があるが,listtopは「リスト先頭ノード接続用スロット」となっている.つまり,TRIBELSITの先頭TRIBEBOXはlisttopに接続しているはずだ.いや,starttribeというのはこれとはまた別のスロットだろう.これは結局,TRIBELISTでは先頭TRIBEBOXが接続され,かつ,そのオブジェクトへの参照も保持している,つまり,同じ値を持つ複数のスロットがあるということではないだろうか?

このような重複リンクは合法であり,それを禁止するとかなり窮屈な仕様になってしまうような気もするが,DATALIST::listtopが接続であるとすれば,むしろ,アンカー接続として地の部分にスロットを設けた方がよかったのではないだろうか?これはかなり厄介な外科手術になってしまう可能性があるので,ここではパスするしかない.ベタ参照にしてしまうと管理上いろいろと厄介な話も持ち上がってきそうな気がする…

参照リストのリストノードは参照元リンクと参照元のスロット位置が入っている.従って,重複リンクのいずれかを誤認しているという訳ではないが,スロット番号だけでは接続用であるか参照用であるのかを判定することはできない.いや,そんなことはない.やはり,今の場合「スロットタイプ不整合」が成立しているのではないか?DATALISTsTOPLIST=1であり,TRIBELISTsSTARTTRIBE=2のはずだから,TRIBELIST[2]は参照でなくてはならないはずだ…

スロット2というのは,LIST::LISTsBOTTOMに相当する.従って,スロット2は接続ではなく,参照でなくてはならない.slottypeが間違っているのだろうか?⇒@20221229で「枝番号と親番号が一致しない場合を許容する」という仕様変更を行っているので,参照を接続と誤認する事態が発生しているように思われる.⇒この変更は,「参照カウント不一致」を伴う「UndoCopyで参照元ノードリスト不記載」に対処したものと思われるが,やはり問題がありそうだ.

slottypeの変更を破棄し,オリジナルに復帰することにした.これで,このエラーは発生しなくなったが,slottypeの変更が必要になった時点まで巻き戻さなくてはならない.その前に,また別のエラーが出ているのでそちらを先に片付けることにする.

▲ブロック削除→ Undo→ Redoで「被参照カウントの残留」が発生する.⇒UndoProcess→ ~CARDLINK→~noduleで起きている.#1612のCARDLINKだ.おそらく,削除範囲に含まれるカードだろう.残留カウントは2.nodule::TakeSansyoでは,参照カウントが残っている場合には,nodule::takeSansyoで除去できるようになっているのだが,補修できなかったようだ.

それ以前に最初のUndoを実行した時点でnodule:ReferenceControlの参照リストx参照カウント 不一致が発生している.これはまずいのではないか?⇒UndoProcessの出口でTopologicalSortを実行する直前ですでに被参照カウント不一致が量産されている.すべてMARGLINKだ.⇒参照リストの長さの方が,参照カウントより2以上小さいという状態になっている.これらはおそらくUndoによって復活したリンクだろう.参照カウントは強制的に調整していたのではないだろうか?いや,そもそも,この値は一致しないということもあるのではないか?

フェイスブックに日替わりでDaily Epsilonの問題を投稿するのを日課とする

Facebookの数学物理etcグループにAMSのYour Daily Epsilon of Mathの日替わりの問題を毎日投稿することにした.投稿しておけば,誰かが回答を付けてくれるだろうという虫のいい算段だ.昨日の初回投稿には,数分後にレスが付いた!問題のレベルはほぼ高校数学の範囲内だが,わたしには手の出ないようなものもあるので,大いに助かる.毎日勤勉に投稿できるかどうかは保証の限りではないが,まぁ,飽きるまでは続けてみたい.多少なりとも認知症予防の効果は期待できそうだ.

年越し蕎麦とお節の差し入れが届いた

姉からの年越し蕎麦とお節の差し入れが届いた.清酒の小瓶も付いている.灯油のストックもあるし,2方面の窓を,①ぷちぷち,②二重カーテン,③毛布/寝袋の三重層で断熱した.入口のドアの上のガラスにもプチプチを貼っているので,今年初めてほぼ完全な防寒の備えができた.姉から年末恒例の余ったカレンダーの横流しもいつか来なくなり,ダイソーで書き込みのできるカレンダーを買っていたが,今年はAMS(American Mathematics Society)から「Your Daily Epsilon of Math 2023」というのを取り寄せた.日替わりの諺の代わりに,小さな数学の問題が毎日提出される.(答えはその「日付」ということになっているので,考える前に回答できてしまうから,心配はいらない)

なんとか,今のバグをクリアして新年を迎えたいものだが,その前にあっけなく年を越してしまいそうだ.UNDOのからんだかなり難しい障害だが,ある意味でいよいよ年来の懸案を片付けるときが来ているのではないか?という気もする.年来の懸案とは,「完全な参照管理を確立すること」,言い換えれば,「超クリーンなシステムを構築すること」である.「超クリーンなシステム」は完全にコントロールされ,いかなる不安定要因も含まないような決定姓が保証されなくてはならない.現行プログラムはかなりのレベルまでそれに近いものになっているが,まだ「カオス的」な部分を残している.

ユーザとのやり取りでグラフのトポロジーが変化するようなデータ操作が行われたときには,系統並び替えを実行しなくてはならないが,このようなときにはフェーズを一旦INITIALIZED(=CHAOTICSTATE)に落として,INITIALIZED→ TOPOLOGICALSORT→ CLEARTABLEのように遷移し,画面要素をClearTableで初期化したあと,本番の系統並び替え処理を実行する.INITIALIZEDではCOUPLING::TopologicalSortでTREEVIEW::InitTreeViewとEraseTreeViewで描画要素のクリーンアップが実行されているので,CLEARTABLEフェーズでは参照エラーは無視されることになっている.このようなアナーキーな状態を払拭し,すべてのフェーズがシームレスに接続することが我々のプログラミングの最終目標であると言える.特にUNDOはこのような操作に関し,完全に透明でなくてはならないと考えられる

CARDLINK::CheckCardDataLinkで「カード参照番号の重複」というのが起きている.CheckCardDataLinkは副作用のある検査ルーチンで,SaveFamilyBase→ InitLinkTableで使われている.⇒CheckCardDataLinkとCheckMargDataLinkに引数testを設けて切り分けるようにした.

▲再現手順5の2回目のUndoで,UndoProcess→ TopologicalSort→ ClearTableの入口に置いた検査ルーチンで大量のエラーが検出される.特に,CheckDataLink→ CheckMargLinkの中でgetoyanumを実行して,結婚リンク中の子どもの参照番号から逆引きしたカードリンク不在が発生している.⇒基準ソート時に実行しているRenumberを停止してみたが,状況は変わらない.⇒TOPOLOGY::topologicalSortの入口ですでに,この状態になっている.ということは,UNDOSYSTEM::UndoProcess自体に欠陥があるということになる.

#3196のCARDLINKをUndoするところだ.参照番号は@1565.このノードは削除されていない実ノードと思われるが,更新を受けているようで,UndoRestoreが実行されている.UndoProcessのループ内で実行しているのは,基本的にUndoRestoreだけなので,これを調べなくてはならない.⇒UNDONODE::UndoCopyの中で不良が発生している.⇒@1565というリンクがテーブルの中でダブってしまうという不良だ.なぜ,そんなことが起きているのか?


「参照カウント不一致」は未解決だった

解決したと思っていた「参照カウント不一致」がまだ収まっていない.⇒どうも昨日の修正でバグを作り込んでしまったようだ.2022-12-29のバックアップでは再現手順による障害は発生しない.どうしたらよいか?⇒2022-12-29では,NODULE::slottypeの判定に従来の論理が使われている.まず,これを適用してみよう.⇒ダメだ.UndoCopyで参照元ノードリスト不記載が出てしまう.⇒2022-12-29-1の版ではすでに不良が発生している.どうしたらよいだろう?昨日の修正はかなり大規模なものだが,もう一度やり直しするしかない.⇒やってみよう.

NODULE::slottypeを修正版と差し替えたが問題なく動作している.「選択カードリストのカウント不一致」では停止しない,「並び替えではリンクテーブルは操作しない@20221228」でエラーを無視する修正を入れた他は,2022-12-29版のままだ.いや,確かに昨日のログでも,『これで一応「参照カウント不一致」エラーは発生しないようになった』とあり,一応落着していることが確認されている.ここでバックアップしておくのが賢明だろう.複数のパターンでテストしているので,再現手順を記録しておこう.

  1. 起動→ 基準ノードの@23を削除→ Undo で「被参照カウント不一致」
  2. 基準ソート→Undo→Redo→Undo
  3. カード一括削除→ 基準ソート→Undo→ Undo→ Redo→ Redo→ Undoで「被参照カウント不一致」
  4. 2回以上全削除を繰り返し,それらをすべてUndoした状態でそれに交叉する領域を一括削除する⇒SetUndoListで (object->UndoNumber && object->UndoNumber > UndoNumber)というエラーが起きる
  5. 基準ソート→ Undo→ 一括削除→ 基準ソート→Undo→ Undo⇒ClearTable→ ResetParentPageでSetOyapageのエラー

上記リストの1, 2のテストはパスしたが,3でエラーが起きた.TopologicalSort→ ClearTable→ ResetParentPage→ SetOyapageで(cardbase.oyanums[oya->getoyanum(j)] != oya->margbase.refnum)というエラーになった.⇒テスト3を単独実行しただけでは再現しない.テスト2→ テスト3で再現できる.つまり,基準ソート→ Undo→ 一括削除→ 基準ソート→Undo→ Undoで再現する.⇒これもリストに追加しておこう.テスト5のエラーは,UndoProcess内では発生していないので,ここでは一旦無視して先に進むことにする.

▲上記テスト5でUndoボタン押下→Undo処理から戻って,VBでGetNewTableを実行してKAKEIZU::makerecordの中で,「夫妻参照番号不整合」というのが発生した.この結婚の夫参照番号5845は,引数で与えられた参照番号395と一致しない.⇒リンクベースのOTTOには正しい値が入っているのだが,静的情報のottoが間違っている.makerecordはKAKEIZUクラスの関数なので,静的情報を返すという仕様になっているのだろう… 外部にはリンクは渡せないので,インタフェースはすべて静的情報に基づくものになるというのは間違いではないとは思われるが,静的情報とリンクデータをどこで同期させているのかが問題だ.

検査ルーチンを作っておく必要がある⇒CARDLINK:CheckCardDataLinkというテストルーチンがある.⇒このエラーはCheckCardDataLinkで検出できる.LINKTABLE:CheckDataLinkという包括テストルーチンがある.COUPLING:InitLinkTableではこのテストを通している.InitLinkTableはOpenFamilyBaseから呼び出される.

LINKTABLE::CheckDataLinkはMARGLINKとCARDLINKの検査を行っているが,CheckMargDataLinkではMakeCouplingの呼び出しで,副作用のある検査になっている.この関数の是非に付いては別途調べる必要があるが,一旦止めておこう.⇒引数で判別できるようにした.

▲ClearTableの出口に仕掛けたCheckDataLink→ CheckMargLinkで,夫と妻がどちらも空という結婚リンクが検出された.もし,検査ルーチンが誤動作しているのでなければ,これはかなり問題だ.どうもこのような結婚リンクが複数あるように思われる.

手順を間違えたのだろうか?今度は別のエラーが出た.ClearTable->ResetParentPage->setParentPageで(hubo->getrefnum() != cardbase.carddata.oyanum)というエラーになった.

CheckMargLinkの中でもMakeCouplingという実関数が呼び出されている.引数でパスできるようにしておこう.⇒LINKTABLE:CheckDataLinkの中から呼び出されているkodomosuという関数ではMarriageOrderingが実行されているが,この関数ではDeleteMarriageが実行されることがある.⇒どうも,CheckDataLinkにはまだ実動作が含まれているようだ.ClearTableの冒頭でCheckDataLinkを実行すると,「無効な結婚リンク」が47件も発生してしまう.

 

「参照カウント不一致」エラーは一応解決

UNDOにからんで「参照カウント不一致」という不良が出ている.参照とは,オブジェクトへのリンクを格納したスロットを言う.ゼルコバの木では処理効率の観点からリンクには生ポインタを使っているので,リンク先のオブジェクトの削除などで無効になったリンクにアクセスしようとすると,致命的な事故が発生することになるので,システムを安定運用するためには超厳密な参照管理が必須である.このために参照カウントというパラメータを保持しているが,現行システムにはそれを管理するためのREFERENCECONTROLという機構が組み込まれている.従って,このエラーの発生は決して許されない極めて深刻な障害と言える.

動作確認のために入れた仮修正によって別の障害が発生している.基準ソートを実行して,TOPOLOGY::ClearTableで結婚リンクの参照番号と親番号の不一致が起きている.⇒仕様的には結婚リンクの参照番号と親番号が一致するというのは仕様ではないはずだが,事実上そうなっていることは確かだろう.⇒暫定的にエラーで停止しないようにした.

スロットの接続種別を取り出すNODULE::slottypeで,親番号とスロット番号が一致しない場合でも,親参照が一致していればSLOT_LINKを返すように暫定修正して,参照カウント不一致は発生しないようになったが,いろいろ問題がある.

  1. ほとんどの場合はこれで問題なかったとしても,同じオブジェクトが接続しながら参照されているような場合を排除できない
  2. リンクテーブル内のリンクはすべて接続であるとして処理されるべきではないか?つまり,対象オブジェクトごとに個別対応する必要があるのではないか?
  3. 親番号とスロット番号の不一致は不良とみなされるべきであり,イメージをリストアした時点で対処されなくてはならないのでは?処理する場所はCountupReferenceでもよいのかもしれないが…
  4. カードリンクと結婚リンクはUNDOSYSTEM::RestoreShadowでInsertLinkされる.ただし,これは現物オブジェクトがEXISTINGでない場合に限られる.つまり,Nring上で延命している場合にのみ適用される
  5. UNDONODE::CountupReferenceとUndoCopyの2箇所で参照の復元を実施している.これは必要なのか?これらはいずれもUNDOSYSTEM:UndoRestoreの内部で呼ばれている.どちらかのみでよいような気もする.UNDOBASE:UndoRestoreでも同様処理になっている.⇒いや,やっていることは真逆だ.UndoCopyでは対象オブジェクトのすべての参照を解除している.逆にCountupReferenceは参照設定を実施している.この動作は正しいと思われる.

▲基準ソート→Undo→Redoの後,まとめて全削除→UndoしてUNDOSYSTEM::UndoProcessでRebuildCardListしたとき,(previous != treeview->selectcardlist->count)になった.previousは1で実カウントは77.⇒これはエラーではなくむしろノーマルな動作のように思われる.カード削除の前に戻ったとき,削除対象カードが選択状態になっているという方が正しい.従って,ここでは不一致をエラーとしないというのでよいと思われる.⇒いや,このエラーのタイミングでは選択リストはすでに復元されているはずなので,それと一致しないというのはおかしいのではないか?

全削除コマンドが実行されたとき,どのタイミングで選択カードリストが保全されたかが問題だ.コマンド実行後に更新されたオブジェクトがあれば上書き保全するということもやっているのではないか?カードの全削除は単点削除の反復として実装されているはずだから,削除完了時に1点選択の状態になっていてもおかしくない.⇒これはそれほど大きな問題ではないので保留とし,エラーで停止しないようにしておこう.

さて,これで一応「参照カウント不一致」エラーは発生しないようになったが,まだ,もう少し問題が残っている.対象リンクが参照でない場合(接続の場合),CountupReferenceでは何もしていないが,「親番号とスロット番号の不一致」が起こっているのではないか?⇒UNDONODE::CountupReferenceで「親番と枝番の不一致」が起きた場合には強制的に調整するようにした.

まだ,「参照カウント不一致」が収まっていない.UndoRedo→ TopologicalSort→ EraseTreeViewで起きている.基準ソート→Undo→Redo→Undoで起きる.⇒親ノードに接続している場合は,つねに接続リンクとして扱う以外ないということになった.

「オブジェクトが接続している親ノードからは参照されない」

というルールを公理化することができれば,これでもよいのだが… 果たしてそう断言できるだろうか?実質的にはこれに反するケースというのはおそらく存在しないのではないかとは思われるのだが… 安全のためには,やはり,オブジェクトの種別を特定して対応を変えるしかないような気がする.⇒人名テーブルと結婚テーブルについては,IsReferenceを使わないよう対処した.それ以外は既存論理で対応する.

ここで一度バックアップを取っておこう.レコード番号には,①リンクテーブルのレコード番号,②lookupテーブルのレコード番号の二種がある.これらを峻別しなくてはならない.特に①はprivateとし,外部からアクセスできないようにする必要がある.⇒maxrecnumとmaxrefnumは元々privateになっている.一旦破棄された一昨日の修正をログに従って復旧してみよう.⇒ZELKOVA 2022-12-27 BADというバックアップがあるので,参照しながら進めよう.

  1. maxrecnumをrecordcountにリネーム→有効レコードカウント
  2. recordcountは lookup テーブルの count に等しい
  3. maxrecordを新設し,最大(リンク)レコード番号を格納する
  4. recordcountの更新時に,maxrecordも更新する.
  5. maxrecordは単調に増加するものとし,(基準ソート時以外では)テーブルは縮小されない
  6. getmaxrecnではmaxrecordを返す
  7. maxrecordのアクセス関数をmaxRecordとする
  8. _maxrecnをリネームしてrecordCountとする
  9. getmaxrecnを廃止して,maxRecordに統一する

ダメだ!また,被参照カウント不一致が出てしまった.基準ソート→ Undo→ Redo→ Undo→ 一括削除→ Undoという手順だ.出ている時点は同じだが,今度はNAMEBOXのデストラクタで起きている.被参照カウントの残留も発生する.⇒CHECKREMAINSANSYOは一時止めておこう.⇒起動→ ルートノード削除→ Undoで再現する.これまで出ていなかったので,上の修正で作り込まれたものと思われる.⇒修正を一部戻してテストしてみたが同じだ.もう一度バックアップに戻るしかない.⇒いや,ダメだ.バックアップでも障害は起きている.

TREEVIEW::EraseTreeViewの入口ですでに不良は発生している.⇒UNDONODE::UndoCopy→ UNDOBASE::UndoCopyで起きているが,UndoCopyでは単にイメージを上書きしているだけなので,そうなることは避けられない.その部分はCountupReferenceで補正しているのだが,どうもそれだけではカバーできないということのようだ.最初の障害は#1540のCARDLINKで起きる.参照カウント不一致が起きているのは#80のMARGLINKだ.この結婚の夫が#1540で削除された@35のカードと思われる.⇒いや,読み違えている.

削除されたのは@23#1522のカードで,同時に#74のMARGLINKも削除されている.この2つは<再生>されているが,MARGLINK内の夫ないし子ノードのリンクは修復されていないようだ.

今日の来訪者数が568人になっている

こ,これはなんだ!?今日の来訪者数が568になっている.まだ,午後5時台だ.何が起きたのだろう?普段は行っても200を超えるくらいだ…

image

いま,見ると6時14分現在で625人に昇る.もし,これが本当なら,1日1000人も達成不可能な目標ではなくなる.にわかには信じ難い… 悪いことではないとは思うが… Googleアナリティックスの数字を見てみよう.こちらには,特に顕著な変化は現れていない.

image

All users=186という数字があるが,これは過去を含めたトータルの数字で山のピークでも40人だ.2つの統計の数字がかけ離れ過ぎているので,どちらも信頼できないという感じ… Googleアナリティックスにはコードを埋め込むという設定の仕方もあるようなので,いつかヒマになったらやってみることにしよう.

UNDOで「被参照カウント不一致」というエラーが出ている.CheckNringCountという検査ルーチンをベタ貼りして追跡し,UNDOSYSTEM::UndoRestoreが原因であることは(ほぼ)突き止めたが,まだ現場を押さえきれていない.

dump(char*)という関数の使い方を間違えていた.ほとんどのクラスではdump(char*)ではprintshortという関数の戻り値を返している.しかし,dumpで期待されているのは,引数のchar*にテキストを格納して復帰する動作である.⇒修正しなくてはならない.とんでもないしくじりがあったものだ… ⇒関係する箇所をすべて修正した.

参照カウント不一致がCountupReferenceによって引き起こされていることはほぼ間違いない.障害を起こしているのは,CARDTABLEとMARGTABLEと見られる.奇妙なのは,これらのテーブルに格納されているリンクはすべて接続であるはずなのに,参照とみなされているという点だ.⇒親番号が変化してしまっているためだ.基準ソートは実行しているが,カード並び替えではlookupを対象とする操作であり,リンクテーブルは操作していないはずなのだが… どこで変化してしまっているのだろう?SWOで追いかけてみよう.

snum=74のMARGLINKのpnumは1だが,snum=10のMARGTABLEのスロット9に入っている.ファイルはロードして基準ソートしただけなので,このオブジェクトは現物であると推定される.UndoRestoreの中でMARGTABLEがUndoCopyされた時点で不一致が生じている.つまり,Shadowのイメージではスロット10のオブジェクトのpnumが1ということになる.⇒確かに現物とイメージではまったく異なる内容になっている.現物ではスロット9には#129の結婚リンクが入っているが,イメージでは#74だ.前者は#1621→#2386で,後者は#1522→#1747だ.⇒NameNarabekaeの中でNAMESORT::SetNodeLinkというのをやっている.⇒いや,違う.「まず重みで昇順に並び替えを実施」した後に実施しているRenumberで書き換わっているようだ.しかし,これを実施しないとテーブルの整合性が崩れてしまう… この続きは明日やろう.


「不正 UndoNumber」に対処

昨日のログでは「保留」としていた「不正 UndoNumber」に対処.

複数カードの削除を2回以上実行した後,Undoで最初の状態まで戻り,そこで再度複数カードを削除すると,SetUndoListで(object->UndoNumber > UndoNumber)という「不正UndoNumber」エラーが発生する.⇒object->UndoNumber が0になっていれば,このエラーは発生しないので,PergeZenpoChainで前方コマンドチェーンをカットするときに,始末しておけばよいのではないか?

オブジェクトへのリンクはUNDONODE::addressにベタ参照として入っている.UNDONODEのデストラクタでaddress->UndoNumberをリセットしてやればよいのではないだろうか?⇒実オブジェクトはShadowチェーンを構成している.⇒Shadowはオブジェクトのバックアップされたイメージだ.この中にはバックアップ時のUndoNumberも含まれている.従って,ここでUndoNumberをリセットしても,オブジェクトのUndoNumberはつねに正当な値を保持していると言える.⇒対処した.

▲setmaxrefnumで最終レコード番号をmaxrefnumに代入している.⇒最終レコード番号=maxrefnumという決め付けは危険だ.⇒setmaxrefnumがつねに危険という訳ではない.引数で「レコード番号」を渡しているケースを拾い出す必要がある.maxrefnumはリンクを生成するか,削除した場合以外には変化しないと考えられるから,これらのケースに漏れ落ちがなければ,それ以外の場所でmaxrefnumを更新する必要はない.まず,setmaxrefnumで同じ値を設定しようとしたときに停止するようにしてみよう.⇒さっぱりヒットしない.おそらく,処理の冒頭でmaxrefnumを初期化しているのだろう.

テーブルで行選択してカード削除しようとすると,対象カードが変化してしまう.⇒カード画面でカード番号欄が4桁しか見えないため,数字が隠れてしまう.⇒カード削除パネルに出てくるカード番号が間違っている.カード画面の主選択カードは正しい.⇒操作を間違えていた.「番号列セル」のクリックでは選択状態は変わらず,「現参照カード」のみ変化する.「現参照カード」というのは,カード画面上に表示されたカードだ.これまではこれを「主選択カード」と呼んできたが,「選択操作」と独立に操作できるようになっていることを忘れていた.というか,そうなっていることを知らなかった!

newlinkでもレコード番号をmaxrefnumに格納している.⇒setmaxrefnumの参照箇所は15箇所ある.結婚リンクの場合,MARGTABLE::makenewlinkでは親のスロット番号をそのまま参照番号としている.CARDTABLE::makelinkでも実質,レコード番号をセットしている.COUPLING::InitLinkTableでは,参照番号をレコード番号とみなしてテーブルを構築lしている.従って,参照番号=レコード番号が本則であると考えるべきである.ただし,参照番号は論理番号であり,レコード番号は物理番号であるから,つねに両者が一致していると仮定すべきではない.実際,ファイルロード時には参照番号の付け替えは行われていないから,古いファイルの中には一致していないものが多数あると考えるべきだ.少し,整理する必要がある.

①getmaxrecnではつねにテーブルサイズを返している.②テーブルは一般にはスパースであると考えられるが,最大レコード番号がカウントされていない.③maxrecnum(以前のmaxrecn)はlookupテーブルのレコードカウントであり,②の最大レコード番号ではない.④maxrecnumをrecordcountとリネームし,maxrecordという変数を新設して,ここに②の最大レコード番号を格納する.⑤getmaxrecnでは④のmaxrecordを返すようにする.⑥recordcountをメンテナンスする関数の中で,maxrecordを更新する.

▲delrecnを廃止する@20221226をフィックス,longtableのaddを使う@20221226をフィックス

maxrecordは単調に増加するものとし,テーブルの縮小は行わない.maxrecordの参照関数をmaxRecordとする._maxrecnをリネームしてrecordCountとする.MakingLookUpは17箇所から呼び出されている.UNDOではUndoEndとUndoProcessでMakingLookUpを実行しているので,DEFINEUNDOSYSTEMは多くの場合,省略できるのではないか?CommandStartFlagがオンの場合はすべてパスするようにしてみよう.

▲BUG3000-1906.ZELを開いて,1906-543=1363点を削除→基準ソート→UndoでTREEVIEW::CheckSelectListのエラーが発生した.selectcardlist->countと実カウントの不一致1が起きている.⇒何かやり損なったのだろうか?再描画が掛かってこない.どうも,バックアップに戻って作り直しするしかなさそうだ.修正手順を記録しながら進めることにする.最初にまずいくつかの過去の修正をフィックスしておこう.ただし,定義文はコメントとして残しておく.

  1. delrecnを廃止する@20221226をフィックス
  2. longtableのaddを使う@20221226をフィックス
  3. getmaxrecnを廃止@20221226をフィックス
  4. setmaxrefnumでレコード番号を禁止@20221227をフィックス

やはり,ダメだ.CheckSelectListのエラーが発生するほか,Undo→ Undo→ Redo→ Redo→ Undoで,参照カウント 不一致が大量に発生する.ここまでは単純に修正をフィックスしただけなので,バックアップに戻っても同じだと思う.このままシューティングするしかない.もう少し小さなサンプルでテストすることにする.極小反例307.ZEL(66点)でやってみよう.⇒再現する.手順は,①カードを大量一括削除,②基準ソート,③Undo→ Undo→ Redo→ Redo→ Undoだ.

テーブル並び替えの時点では選択カードは1点という状態になっている.最初のUndoでCheckSelectListのエラーになる.selectcardlist->countは1だが,selectflagはすべて落ちている.そもそも,UNDOでは選択状態を保全していたのだろうか?⇒保全している.いや,selectcardlistそのものは保全していないが,カードの保持するselectflagから復元している.⇒どうも,かなりおかしい.lookup.countが307もある.いや,この時点ではそれで正しい.

元々の論理ではUNDO時には,選択はすべて解除するということになっていたものと思われる.ただし,冒頭でカウントをリセットする処理が(意図的に外されていたため)不整合が発生していたものと思われる.いろいろな意味でUNDO時に選択状態を維持するというのは無理があると思われるので,「UNDO時はつねに無選択状態」ということにしたい.⇒いや,selectflagから復元するという方式で動作しているようだ.これでもよいのではないか?

UNDO中はつねにカードリンクが保持するselectflagからselectcardlistを復元できるので,基本的に選択状態は維持可能と思われる.ただし,これは選択状態が復元できるという意味ではない.選択領域全体をキープしようとしたら,コマンドのたびにすべてのカードリンクをバックアップしなくてはならなくなってしまう.それはおよそ不可能だ.

「被参照カウント不一致」の問題に移ろう.これはかなり,手強いと思う.再現手順は,基準ソート→Undo→Redo→Undoだ.その後は,RedoでもUndoでも同じになる.手順から見ると,Redoで壊しているように思われるのだが… 障害が発生しているのはCARDLINKとMARGLINKで,これらはバックアップとは無縁のように思われるのだが… ⇒いや,2回目のUndoで起きているようだ.UNDOコマンドのリングを巡回処理中に不良が起きている.ここで実行されているのは,RestoreShadowとUndoRestoreくらいだが… ⇒UndoRestoreが元凶だ.

Collatz12146.ZELを開けるようになった

Collatz12146.ZELをようやく安定的に開くことができるようになった.ただし,開くまでには相当な時間が掛かっている.どこがネックになっているのか,シューティングしたいところだが,それはもう少し落ち着いてからの課題としておこう.

巨大ファイルでメモリ不足が発生しないようになったのは,MAXPDBxMAXMDBという巨大配列の使用を一時的に止めたことが効いているのではないかと思う.DTおよびKTという名前のshort型の2元配列で,親等計算に使われている.とりあえず,親等を計算する必要はないので当面は停止で問題ない.親等計算は結構時間を消費するので,オプションで止められるようにしておいた方がよいかもしれない.

Collatz12146.ZELでは三極検定レッドラインオーバーが発生している.

image

上図では小さ過ぎて見えないが,図面の左上隅に#1のカードが取り残されている.その他にも何点か隔離された点が残っているが,おそらく,これらがレッドラインオーバーの原因になっているものと思われる.極小反例抽出というのは,この問題をシューティングする目的で始まったのだろう.⇒極小反例サンプルのコレクションがある.極小反例 371.zelが多分最小と思われるので,試しに開いてみよう.⇒開けてしまう.反例になっていない.⇒この問題は後からやることにしよう.

CARDTABLEとMARGTABLEにはRenumberという関数がある.これが使えるのではないだろうか?⇒NAMESORT::NameNarabekaeには元々その処理が入っている.基準ソート(参照番号による並び替え)では,PDBとMDBのRenumberを実行している.ただし,現行の「特注版」では基準ソートの代わりに番外として「カード番号によるソート」が実行されているため,適用されていない.⇒参照番号とカード番号はまったく同一なので,「特注版」として特に別扱いする理由はないような気がする.オプションを止めてみよう.⇒うまく行ったようだ.

テーブルサイズを16384まで拡大してCollatz12146.ZELを読み込んでみた.系統並び替えだけで16分掛かっている.テーブルのロードでもその位掛かるので,トータルでは20~30分くらい掛かっているのではないだろうか?パフォーマンスに関してはもっと後で取り組むことになるが,getnewRefnumの仮修正はフィックスしておいた方がよい.getnewRefnumのオリジナルバージョンではmaxrefnumの次の番号を返すようになっているが,暫定的に空スロットを見つけてその番号を返すようにしている.一般にはこちらの仕様の方が適していると考えられるので修正を戻しておくことにしよう.ただし,maxrefnumがテーブルサイズを超えた場合には,任意の空スロット番号を返すということにする.⇒いや,emptyrecn自体そういう作りになっている.

この関数はテーブルフルになった場合にはエラーコードを返しているのだが,それに対応するようになっているだろうか?⇒一応対処した.emptyrecnとgetnewRefnumの最大の違いはテーブルサイズオーバーのとき,エラーパネルを出すか出さないか?だ.emptyrecnでは,「%sデータベースの容量%d件を超えています.\nこれ以上%sリンクを追加することはできません.」のようなメッセージが表示される.これが頻発するというのは望ましくない.⇒emptyrecnに引数を一つ追加して切り分けるようにした.⇒いや,コンパイルが通らない.BASETABLEはテンプレートクラスなので,ヘッダファイルの中で初期化できない.

そもそも,このBASETABLE::emptyrecn自体間違っているのではないか?この関数は冒頭,max = getmaxrecn()で最大レコード番号を取り出しているが,現行ではgetmaxrecnはtablesizeを返すようになっている.従って,(max < tablesize)はつねに偽となり,つねに空スロットの探索という動作になってしまう.これはここで予定している動作になっていないのではないか?maxrecnというメンバー変数もある.この値はメンテナンスされているのだろうか?

_maxrecnという参照関数でアクセスするようになっている.この値は,MakingLookUpで更新される.また,delrecnという変数も持っているが,これはもう廃止してもよいのではないだろうか?また,incmaxrecn,decmaxrecnという関数も使われている.今度はCollatz3900-6165.ZELでテストしてみよう.このファイルのサイズはCollatz12146.ZELの半分くらいだ(6165点).⇒時間は掛かるが問題なく開けた.三極検定では30回ループを回している.

BASETABLE::getmaxrecnがつねにtablesizeを返しているとすると,getmaxrecnを呼び出しているところでは,つねにテーブルサイズ分のリンクをチェックしていることになる.これはあまりにタイムロスが大き過ぎる.lookupテーブルには前詰めしたリンクが入っているはずだ X.基本的にレコード単位にアクセスするときは,このテーブル(lookup)を使っているはずだが,全テーブルに直接アクセスしているところも無数にあるに違いない.lookupを使うためにはMakingLookUpが実行されている必要がある.getmaxrecnの呼び出しは194箇所もある.

とりあえず,delrecnを廃止しておこう.今度はBUG3000-1906.ZELを開いてみた(1906点).そこそこの時間で開けた.系統並び替えの所要時間は34秒.このサンプルはどうやって作ったのか分からないが,最小番号は15で,ルートは35になっている.

▲一覧画面を開いたとき,必ずカード番号の降順で初期表示されるのはなぜか?また,起動時には元の画面を復元してもらいたい.

一度バックアップを取ってから始めよう.lookupというのは,longtable型のオブジェクトで,テーブルサイズはMAXPDBに固定されている.結婚テーブルもlookupを持っているが,サイズ調整はしていない.通常,longtableには参照番号などの整数値が格納されるが,lookupの場合にはテーブルのインデックス(1発進)が入っている.この値はMakingLookUpで常時メンテナンスする必要がある.⇒チェックすれば死亡していることは確認できる… longtableにCountという参照関数を追加してcountを取り出せるようにしておこう.

lookupにアクセスしているところでは,getmaxrecnを使うのを止めて,この関数を使うことができる.⇒いや,MakingLookUpでlookup.countをmaxrecnumに格納しているので,この値を直接取り出すことにする.lookupは59箇所から参照されている.lookupを参照する関数として,getlinkとgetrefnumがある.テーブル並び替えはlookupを対象に実行されている.つまり,リンクテーブルは操作されない.

▲setmaxrefnumで最終レコード番号をmaxrefnumに代入している.⇒最終レコード番号=maxrefnumという決め付けは危険だ.

▲CommandStart~CommandEndではlookupは使用不可(MakingLookUpが実行されていない)⇒これは,フラグを見れば確認できるだろう.

▲getrecn(refnum)という関数は,リンクテーブルでアクセスした方が効率がよいが,ヒットしない場合はlookupを使った方が無駄が少ない.

効率にはほとんど影響しないが,多少なりコードを読みやすくするために,longtableにaddという関数を追加しておこう.

▲上記サンプルでツリーの裾の方をまとめて1304点全削除したところ,SetUndoListで (object->UndoNumber && object->UndoNumber > UndoNumber)というエラーになった.object->UndoNumberは3, UndoNumberは1.その前に複数のカード削除とUndo/Redoを実行している.この全削除はUndoで振り出しに戻ったところでやっているので,前方チェーンはすべて削除されているはずなのだが… オブジェクトのUndoNumberがリセットされていなかったのだろうか?⇒同じエラーが無数に起こるので,一旦終了する.

オブジェクトの輪切りを反復しても再現しない.おそらく,先行実行されたカード削除に関係するオブジェクトで削除対象ではないオブジェクトが存在し,Undoで復活した図面ではそのときに設定したUndoNumberが残っていたのではないだろうか?そのようなことは起こり得るように思われる.⇒UndoNumberを上書きしてやればそれまでだが,それではUndoNumberを導入した意味がなくなってしまうのではないか?⇒再現手順を確立しておこう.⇒少なくとも2回以上全削除を繰り返し,それらをすべてUndoした状態でそれに関係した領域をまとめて全削除すると発生する.⇒かなり難しいので一時保留としておこう.

同上サンプルで,ルートから底辺までの帯状の領域222点を全削除して,SetUndoListの出口で(object->UndoNumber != UndoCurptr->UndoNumber)が出た.object->UndoNumberは0,UndoCurptr->UndoNumberは1.CommandStart→ BackupPointData→ SetUndoListで発生している.objectはPARTIALNAME.⇒これは上記の「保留」に関わる修正ミスだ.

ようやく作業がルーチンで回り始めた

ようやく作業がルーチンで回り始めた.こうなれば,もう怖いものなしだ.今回作業再開の目的は一義的には「Sultanの論文の検証」だが,その前に「コラッツ木生成ツールの再構築」と「ゼルコバの木の増強」に取り組まなくてはならない.現在,ゼルコバの木は「コラッツ特注版」というかなり変則的な方向に進んでいるが,この方向性をむしろ「本則」として標準化する必要がある.

コラッツ木は単純な木であり,これを最大限・最高速で処理できるようにすることは,一般の系図を扱う上での前提であると考える.ゼルコバの木はこれまで,最大1000点というスケールの領域を扱ってきたが,これを機会に1万点を超えるデータを扱えるように仕立て直したい.かなりハードルは高いが,やっておく必要がある.

カードを2点削除した後で,Undoを2回行うと,UndoNumberの不一致が発生する. (UndoCurptr-> UndoNumber != UndoNumber)が起きている.UndoCurptr-> UndoNumber=1, UndoNumber=2だ.このエラーは初回だけで,その後の Redo,Undoでは収まってしまう.

UndoNumberという値は,①UNDOBASE,②UNDOCOMMAND,③noduleの各クラスで保持されている.UndoNumberは「重複バックアップの回避用」.UNDOBASE::MakeNewCommandでシステムとチェーンのUndoNumberの同期がなされている.SetUndoListではバックアップの対象となるオブジェクトに現UndoNumberが格納される.

UNDOBASE::CommandEndでは出口でUndoNumberの調整が行われる.⇒UndoStartでコマンドを開始する時点で,前方のコマンドチェーンがパージされる.このとき同期が一時的に崩れる場合がある.UndoCurptrが変更された場合には,つねにUndoNumberを更新する必要があるのではないか?UndoCurptrは以下で切り替えが発生する.

  1. UndoBase::UndoProcessの出口
  2. UndoSystem::UndoProcessの出口
  3. PergeZenpoChainの出口
  4. UNDOBASE::MakeNewCommandの出口
  5. UNDOBASE::CommandEndの出口で(UndoCount <= 2)のとき

UndoBase::UndoProcessは実質的には(ほぼ)使われていない.UndoBase::CommandEndで例外がキャッチされた場合にのみ,強制的にUNDOを実行して復帰するような作りになっているが,これが実行された試しはないと考えられる.

MAXUNDOCOUNT=5のとき,最大4コマンドまでしか保持できない.なぜか?⇒MakeNewCommandで(UndoCount >= MAXUNDOCOUNT)で打ち切っているためではないか?等号を外せば,MAXUNDOCOUNTまで作れるはずだ.⇒これでよい.

ここで一旦バックアップを取っておこう.

一覧画面の列ラベルをクリックしたときのテーブル並び替えが実行できないのはなぜか?⇒いや,動いている.セル項目をテキストしてソートしているので期待したような結果にならなかったためではないか?⇒カード番号は数値としてソートしているのに正しい並びになっている.見間違えだったのだろうか?まぁ,ともかく,これでよしとしよう.

少なくとも今当面の目的では,①カード番号,②氏名,③所属,④肩書きだけは数値としてソートしたい.⇒特注版の「数値で並び替え@20221225」オプションとして処理しておく.⇒うまく行った!

NAMESORT::NameNarabekaeのcheckがオンになっているとき,STOP文で止まらない(場合がある)のはなぜか?⇒ブレークポイントを置けば停止する.⇒STOP try {__asm { int 3} } catch (…){}を{ int 0}に書き換えたら毎回停止するようになった.

コラッツ木生成ツールから出力される隣接リストファイル(ADL)では,氏名欄にそのノードの値である巨大整数が入っている.カード番号はテーブルの範囲内であれば,その値をそのまま採用する場合もあるが,通常はオーバーフローしてしまうため,ハッシュして小さな数に変換している.ここで使っているハッシュ関数は単純なもので,すべてのビットが1であるようなある桁数の整数とANDを取っているだけだ.テーブルサイズを2のべき乗にしていたのはこのような事情による.

テーブルサイズが小さくなった場合はどういうことになるのか?現行では,0x1FFFという定数に固定されている.この値はテーブルサイズによって伸縮されるべきだと思う.カード番号のデータ型はlongなので,最大でもその範囲を超えることはできないが,テーブルサイズ AND FFFFFFFF まで使えるのではないだろうか?

▲発行されたカード番号が実際のテーブルサイズより大きくなる場合がある.テーブルサイズが1000のとき,最大#1097というカードが存在する.登録データはきっかり1000点だ.つまり,1000より小さい領域に97個分の穴が開いているということになるのだが… 実用的にはこれでも特に問題はないとも言えるが,参照番号はテーブルのレコード番号と一致するのがベストであるという観点からすれば,見直しの余地はあるのではないだろうか?⇒やってみることにしよう.

多少厄介なので,一度バックアップを取っておいた方がよいかもしれない.⇒どうも見ているところが違うようだ.カード番号はLINKTABLE::GetRefnumで決めていると思っていたが,通っていない.いや,いまテストしているのはADLファイルではなく,ZELファイルだ.⇒テーブルサイズを6000に拡大して読み込んだら,カード番号も振り直しされている.ただし,最大6000を超えるカードが97点ある.どこで振り直しをやっているのだろう?

カード番号が決定しないとテーブルは構成できない… COUPLING:InitLinkTable辺りでやっているのではないだろうか?⇒確かにそのようだ.参照番号が空スロットならばそこを使い,空いていないときは,空スロットを探してそこに居を定める論理になっている.BASETABLE:newlinkでは,まず指定番号のスロットが空いていればリンクを生成してそこにリンクする.空いていない場合は,makenewlinkを使って空スロットを探し,そこにリンクを(newlinkを使って)生成する.

しかし,この方式なら参照番号がテーブルサイズを超えることはないように思われるのだが… makenewlinkには2つのバージョンがあり,emptyrecnを使うパターンとgetnewRefnumを使うパターンがある.後者はmaxrefnumをインクリメントした番号を返すので増長してゆく可能性がある.⇒getnewRefnumの代わりにemptyrecnを使うようにしてみたが,効果なかった.⇒現行方式では参照番号の振り直しまでは実行していないので,テーブルサイズより大きなカード番号の存在は不可避である.⇒参照番号の振り直しというのがどこかにあったのではないか?

▲テーブル並び替えで系統並び替えが実行される.

テーブルサイズ8192(0x2000)でテストしてみた.最大で8289というカードがある.8289-8192=97でこの場合もはみ出しているカードのオーダーは同じだ.⇒MAXPDB=12300, MAXMDB=10300でCollatz12146.ZELを開くことができた.カード番号のはみ出しは解消した.ただし,三極検定でループカウントオーバーが発生している.