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

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を開くことができた.カード番号のはみ出しは解消した.ただし,三極検定でループカウントオーバーが発生している.

修正のフィックスでバグを作り込むとは

デバッグ作業が少し進み始めた.バグというのはとんでもないところに潜んでいるものだ.「デバッグにはいかなる予断も許されない」

UNDOBASE::SetUndoList→ で(!copynode->shadow)が発生

GetNewCard→ MakeNewCardで引数のrefnumが0のときは,mCreateCardで新規カードを作っている.mCreateCard→ CreateCard→ FAMILYTREE::getNewCard→ UNDOSYSTEM:CommandStart→ UNDOBASE::CommandStart→ BackupPointData→ SetUndoList→ で(!copynode->shadow)が発生している.⇒「生成したばかりでshadowを持つはずがない@20170823」というブロックが削除され,代わりに「1行削除@20220423」が入っている.この日付は2022-04-23だが,この修正は実際には2022-04-26-1で初めて入っている.この辺りのログを読んでみよう.

2022-04-29のログはそのものずばり,「UNDOBASE::SetUndoList で(!copynode->shadow)により停止した」となっている.⇒この記事では対処されていない.問題がメモリ不足の問題にすり替わっている.⇒2022-04-27で「UNDOに関する修正をフィックス」している.おそらく,ここで誤ったものと思われる.「UNDOのShadowをfreeblock化@20220423」2箇所 に該当するのではないか?

「UNDOのShadowをfreeblock化@20220423」というのがある.この日付が20220423となっているので,整合している.この定義はFIXED@20220426でフィックスされている.#ifndefのマクロで#elseが活きなくてはならないところを誤って削ってしまったのだろう.⇒復活させた.修正のフィックスでバグを作り込んでしまっていた.⇒別のエラーが出るようになった.

UNDOBASE::CommandEndでUndoCurptrが空になった.⇒PergeZenpoChainで空にしている.UNDOBASE::CommandEndは戻り値としてlongを返しているが,この値は初期値0のままで使われていない.⇒「ringTopが空のときはつねにPergeZenpoChainを実行する@20170515」となっているため,PergeZenpoChainが実行されている.UNDOSYSTEM::CommandEndには「UndoCurptrが空となる場合があり得る?@20220418」というコメントが付いている.この関数は外部で致命的エラーが発生したときには,fatalerrorを返している.

PergeZenpoChainでは,Undoチェーンの後方ノードが空,つまり,UndoCurptrが末尾ノードである場合は,UndoChain,UndoCurptr,UndoNumberをリセットしている.また,UndoCurptr=UndoChainの場合(UndoCurptrが先頭ノードの場合)も同様動作となる.従って,UndoCurptrが空となるのはノーマルな状態であると考えられる.

if (lret >= 0 && !UndoCurptr) STOP; あり得る@20220418 となっていたのだが,同日付であり得ないに変わっている.⇒lretにUndoNumberを格納してチェックを回避するように修正した.⇒どこかでハングしている.強制ブレーク→続行しようとして,以下のような見たこともないパネルが出た.

image

デバッグの中止もできない.どうも,このエラーは「Attempting to get the view from an adapter in state TextDocDataAvailable」はかなり始末が悪そうだ.ネット上にも情報はあるが,あまり役に立たない… デバッガに関係するものであるような気がするが…

PHASEがINITIALIZINGのままになっている.どこかで横道に逸れてしまっているのだろうか?エラーが発生しているのだろうか?CZelkovaCtrl3::TopologicalSortで-1017を返している.この値はCallSortLineageの戻り値だ.ERR_AUTOCORECTEDDATA(自動補正されたデータ:保存が必要)という通知だ.InitializeDisplayではUpdateFlagをオンにして対応しているが,Currefnumに0を格納しているため,動作がおかしくなっているのではないか?

Z.BaseRefnumには1が入っていて,GetRecordNumberでレコード番号を取り出そうとしているが,0が戻ってくる.Z.mSendRequest(4) ‘基準ノードの参照番号を請求する @@2016-10-22 というのがあるので,これで取り出してみてはどうか?⇒対処した.これで描画できるようになった.⇒この修正でGetNewCard→ MakeNewCard→ mCreateCard を通らなくなってしまったので,UNDOが掛からないようになっている.暫定修正を入れてもう一度動作確認してみよう.CommandEndの動作にはまだ少し疑問がある.

  1. (UndoCount <= 2)のときは,なぜUndoCurptrを繋ぎ変えてUndoChainに戻しているのか?
  2. なぜ,UndoCurptr->ringTopは空になっているのか?

FAMILYTREE::getNewCardは-10018を返している.⇒このエラーコードは「カード登録数がカードリンクテーブルのサイズを超えた」の意味だ.しかし,UNDOBASE::CommandEndにはアプリケーションの処理結果は一切入ってこない.⇒一手間かかってしまうが,アプリの処理結果をCommandEndに渡すようにしておいた方がよいのではないか?処理が失敗したときには,そのコマンドは破棄されるというのが当然の動作になるのではないかと思う.⇒一度バックアップを取ってから取り組むことにしよう.⇒ZELKOVA 2022-12-24 Aとして保全した.

「CommandEndに処理結果を渡す@20221224」で修正しておこう.⇒処理により,戻り値が結構あいまいな場合があるので,ケースバイケースで導入するものとし,今回はMAKENEWCARDにのみ限定適用とする.⇒PergeZenpoChainを実行して0復帰するようにした.UndoCurptr, UndoCount, UndoNumberはすべて初期化されている.

CommandEnd(DELCARD)では負値を返している.CommandEnd(DELALLCARD),CommandEnd(MERGECARDS)も同じ.これは別途チェックしておく必要がある.⇒UNDOBASE:CommandEndでは特に何もしていない.現行ではUndoNumberを返すようになっている.UNDOSYSTEM::CommandEndではTopologicalSortの結果を返すようになっている.致命的エラーが発生したときには,fatalerrorで復帰する.

UNDOSYSTEM::CommandEndで0復帰すると,画面が表示されない.なぜだろう?⇒GetNewCardで新規ファイルに失敗しただけで何も表示されないというのはかなりおかしい.⇒画面の更新はRefreshSubで実行されるが,更新のダブりを抑制するためのRefreshFlagはデータベースの読み込みが完了するまでは落ちない.このため,事実上UndoStatusの実行時にしか画面は更新されないようになっているが,これまでの論理ではZ.mUndoStatusがゼロの場合には画面の更新は実行されなかった.⇒UNDOSTAT.UPDATEDIAGRAM) <> 0 の場合はつねにZView.RefreshSubを呼び出すように修正した.

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

▼MAXUNDOCOUNTに達したときの動作を確認する

Undoでテーブルが更新されていない.⇒UndoStatusに組み込んで動作するようになったが,呼び出し頻度が高過ぎる.⇒CardUndoRedoから呼び出すのが適切だ.⇒もともとこの位置から呼び出していた.

▲カードを1点づつ5点削除したあと,Undoを2回反復して,UndoProcessでUndoNumberの不一致 (UndoCurptr-> UndoNumber != UndoNumber)が発生.前者が7,後者が8.また,Undoで最初の50点まで戻れなくなる.

一覧画面が毎回同じ場所・サイズで開く.前回の場所を覚えていない.⇒現在位置は覚えているが,ファイルを閉じると忘れてしまうようだ.⇒ダブルクリックでオープンしたときは,DockingWindowFunc(False) が実行され,このときのウィンドウ位置を記憶するという動作になっている.⇒暫定的にこの動作を止めて任意の場所で開けるようになった.

▲テーブルをクリックしてCardTable_MouseClickが起動しない.⇒MouseClickというイベントが見当たらない.MouseDownというのはある.⇒MouseDownでも入ってこない.

▲CardGridView_CurrentCellChanged→EditTableEnd→…FAMILYTREE:GetCardBaseで(PHASE < DRAWSTAGE) で停止した.



MiniTool Partition Wizard でOSドライブの移行を試みる

アクセス解析プラグイン Site Kit でようやく詳細情報が出てきた.これで見ると,テント村の来訪者のプロフィールをまったく誤解していたようだ.STATISTICSで見ると最近の一日の来訪者は200人くらいになっているが,そのほとんどは検索エンジン経由で,URLでストレートにジャンプしてくるケースはごくわずかしかない.その検索ワードも,①regsvr32とか,②タイプ初期化子が例外をスローしました,③blend for visual studio, ④xoops 開発 終了など,ごく特殊なキーワードばかり.このようなキーワードについての記事を書いている訳ではないので,読んでもほとんど役に立っていないと思う.そんなことであれば,もう少し詳しい解説記事を書いた方がよいくらいだが,この辺りに関してはわたしもあまり専門的な知識を持ち合わせていない…

メール受信専用に使っているBlackHawkがメモリ不足で動作が悪いので,ディスククリーンアップの記事を探していたら,MiniTool Partition Wizard というのを見つけた.OSドライブを丸ごと引っ越しさせるという機能を持っている.ダウンロードに時間が掛かりそうなので,povo1.0の24時間使い放題220円を使ったが,ディスク容量不足で途中で中断してしまった.ただし,プログラムの本体はインストールされているようで,立ち上がってきた.無料評価版だが,果たして安全にOSドライブの移行が実行可能なのだろうか?失敗すればとんでもないことになる虞がある.⇒そもそも,それをやると移行先ディスクのデータはすべて消去される.もしやるとすれば移行先ドライブを空っぽにしてからでないと始められない.このドライブは238GBだが,うち,31GBが使用済みになっている.USBメモリに移せない容量ではないが…

このBlackHawkというマシンはかなり脆弱で外付けHDを接続できなかったのではないだろうか?確かにそのようだ.画面が不安定になって,おそらくどこかでクラッシュしてしまうだろう.⇒32GBのUSBメモリは装着できた.ここに一旦すべてのデータを退避させてみよう.残り時間20分となっているので,それほどの時間は掛からない.本体のMiniTool Partition Wizard と一緒にMiniTool ShadowMakerという別製品もインストールするようになっていたので,多分メモリ不足は後者のダウンロードで起きたのだろう.製品として購入すると8200円掛かる.⇒やってみよう.移行先ドライグを指定後,以下のパネルが出た.

image

よくわからないが,GPTでは2TB以上のドライブが扱える,UEFIというのはブートモードでWindows 11はUEFIにのみ対応という話なので,多分関係ないと思う.⇒移行した後,BIOSで起動ドライブを設定しなくてはならない.これができないとお釈迦になってしまう.試しておいた方がよいのではないか?⇒Windowsキー→設定→回復→今すぐ再起動→…→オプションの選択→トラブルシューティング→詳細オプション→UEFIファームウェアの設定→再起動→BIOS設定画面が起動という手順で起動できる.電源オンの直後にF2,ないしDelキーを押すということになっている.F2かDelかどちらかわからないがBIOS設定画面に出た.

移行先のSDDドライブはGPTディスクになっているようだ.⇒やはり,購入しないとOS移行はサポートされないようだ.8200円というのは買い切りではなく,年額だ.このソフトはかなりグレードが高いのでそれだけの価値はあると思うが… ここで8千円出費したら年が越せなくなるのではないか?そもそも,このマシンがあと1年持つのかさえ分からないというのに… とりあえず,ここは保留とするしかなさそうだ…

▲「メモリ描画環境用のメモリが不足しているため,生描画に切り替えます」が出て,モノクロに切り替えた後,倍率などを変えると同じメッセージが出て,生描画に戻ってしまう.

▲現行版では「氏名を表示」のみになっているのに,2行出ている.これはどういう設定になっているのか?

Collatz12146.ZELを開いて,例外が発生する.「ucrtbased.pdbは読み込まれていません」が出力画面に表示される.

image

続行で”Buffer too small”のエラーが起きる.

image

再試行でucrtbased.dllで停止するが,トレースはできない.⇒この障害は事前に大きめのファイルを2つ開いた後の読み込みで起きる.この後,「一部データに…修復されました」を表示してVBに制御が戻っているが,SetSingleSelection中にTREEVIEW::CheckSelectListのエラーが出る.selectcardlistのカウント1と現物カウント0で不一致が生じている.また,UNDOBASE::SetUndoListでcopynode->shadowが空で停止する.⇒この後,dp空で例外が発生するため,修正した.⇒ダメだ.”Buffer too small”がパスできなくなってしまった.⇒上で読み込めたというのは,「偶々」だったのだろうか?⇒コマンドライン引数で渡すようにしたら開けた.

見たことのないエラーが出た.

DataWarehouse ホストへの要求に失敗しました: ‘Invalid task token: 88802e77-79a6-4e8c-a1d0-60b392b93d34’

コマンドライン引数渡しも効果なかった.結局同じだ.

!ひどいバグがあった.CARDLINK::CheckCardLinkのダンプ文に一つ余分な引数が入っていた.⇒解決

SetSingleSelection中にTREEVIEW::CheckSelectListのエラーが出る.selectcardlistのカウント1と現物カウント0で不一致が生じている.⇒SetSingleSelectionは単選択を強制する関数なのだから,選択1でなくてはならないが,Currefnumがゼロとなっているため,選択されたカードが存在しない状態になっている.まず,これを一致させる必要がある.⇒対処した.⇒データベースのオープン関数ZView.Zelkova1.Openの戻り値をCurrefnumに格納する処理が落ちている.⇒修正した.⇒これで動作するようになった.

上記の「copynode->shadowが空で停止」も発生しないようになったが,なぜここでエラーが起きていたのかは別途調べておく必要がある.

GetNewCard→ MakeNewCardで引数のrefnumが0のときは,mCreateCardで新規カードを作っている.mCreateCard→ CreateCard→ FAMILYTREE::getNewCard→ UNDOSYSTEM::CommandStart→ UNDOBASE::CommandStart→ BackupPointData→ SetUndoList→ でエラーが発生している.この時点ではまだ新規カードは生成されていない.MAKENEWCARDではまず,partialmapを引数にSetUndoListが実行される.

アクセス解析ツールがようやく動き始めた

インストールしたアクセス解析ツールがようやく動き始めた.現在トータルユーザ36という表示が出ている.うちダイレクトアクセスは2人,それ以外はすべてOrganic Search,つまり検索エンジン経由ということになる.国別ではUSAから1人アクセスがあるようだ.テント村のサイドバーに出しているSTATISTICSでは今日の来訪者101,アクテイブ来訪者24となっているので,数字にはかなり開きがある.Site Kitの使い方はまだよくわからないので,調整が必要なのかもしれないが…

揚陸地点は決まった.ZELKOVA 再開発 2022-12-12,ここから始めるしかない.この版では人名テーブルと結婚テーブルのサイズはいずれも0x2000=8192となっている.

▲初期起動時,TREEVIEW::Refresh→…NAMEBOX::getGeneration中に(coordinate() == ABSOLUTE)で停止する.続行で新規ファイルになってしまう.この一行をコメントアウトすればファイルを開くことができる.DEBUG_NEVERというマクロはSTOPマクロを実行しているだけなので,動作に差の出る理由がよくわからない.

Refreshが呼び出されているということはすでに絶対座標系に切り替わっているはずなので,この位置でgetGenerationが呼び出されていることに問題があるように思われる.これは,「確定世代番号を導入する@20201121」という修正に関わるもので,Bobject::setabsoluteの中で,_generation = GetGeneration()が実行されている.ただし,GetGeneration関数の中で_generationを返しているので,この動作にはやや疑問がある.また,GetGenerationという関数があちこちで重複定義されている点も疑問だ.以下のクラスで再定義されている.

  1. GENEBOX
  2. PAIRBOX
  3. MARGBOX
  4. TRIBEBOX
  5. NAMEBOX
  6. TREEVIEW 相対座標系ではつねに0を返す
  7. TITLEBOX 相対座標系ではつねに0を返す

その理由はこの関数が仮想関数になっているためだろう.仮想関数にする必要があるのかどうか?というのがそもそも疑問だ._generation に値を代入しているのは,Bobject::setabsoluteだけで,この関数の中ではGetGenerationが呼び出されている.⇒MakeAbsoluteではSetAbsoluteを実行後にCOORDINATE = ABSOLUTEを実行しているので,これで問題ないのではないか?

getGenerationという関数は「常用世代番号」を返すことになっている.この関数をPrintParameterの中から呼び出しているところに問題があるのではないか?PrintParameterという関数は人名枠の中に付加情報として各種パラメータをプリントするための関数であり,絶対座標系以外では使われることはないのではないだろうか?

Collatz12146.ZELを開こうとすると,「登録リンク数が上限の8192を超えました」というエラーが二度発生したあと,「夫・妻リンクともに不在」が多量発生し,CARDLINK::CheckCardLink sc=3840 不正親番号の補正が実行された後,”Buffer too small”という例外が発生する.

image

今度は「データ不整合がありましたが…」を出したあと,描画できた.

image

ただし,以下のような複数の障害が発生している.

TREEVIEW::CheckSelectList

UNDOBASE::SetUndoList

UNDOBASE::UndoCopy

UNDONODE::Dispose

特にUNDOでポインタ空が発生しているというのは致命的だ.データ数は8192点まで削減されている.

image

まず,テーブルサイズを倍増(→16384)させて動作するかどうかを見てみよう.⇒リンカーでエラーになってしまった.

LINK : fatal error LNK1248: イメージ サイズ (823DC000) が最大許容サイズ (80000000) を超えています

「Win32 では1プロセスあたりのユーザーメモリ空間は 2GB」で0x80000000はその上限と思われる.これはWin32の制約なので,どうすることもできない.ちなみに現在の構成プロパティは,スタックサイズ2147483648,ヒープサイズ1073741824,ヒープコミットサイズ1048576に設定されている.現行では「テーブルサイズを2のべき乗にする@20220316」というオプションになっているので,8192点を超えることはできないということになってしまうのだが,「テーブルサイズを2のべき乗にする」というのはどういう効果があるのか?

いや,少なくともこの版では実効性はないようだ.ということは任意の値が取れるということなので,もう少し増やしてみよう.最終版では人名テーブル12300,結婚テーブル10300となっているが,この辺りがギリギリの範囲なのではないだろうか?

サイトにデータ解析ツールを組み込んでみた

サイトにデータ解析ツールを組み込んでみた.Google アナリティクスのアカウントを取得し,Site KitというプラグインをWordPressにインストールした.設定は簡単に終わったが,「データを収集中」という表示から抜けてこない.最初の表示が出るまでに最長48時間掛かるということになっているので,多分,問題なく動作しているのだとは思うが…

「サイトのユーザエクスペリエンスを測定」というカテゴリで,一つだけ確定している値がある.Largest Contentful Paintという項目で 4.4秒 「悪い」 という評価が出ている.読み込みに時間がかかり過ぎという意味だ.Total Blocking Time(ページの読み込み完了からクリック可能になるまでの待ち時間)は 60ミリ秒で「良い」という評価をもらった.過去に遡ることはできないはずなのだが,「過去7日間」に絞っても状態は変わらない.Googleの過去ログをすべて再解析しているのだろうか?もし,それができたらかなりおもしろいが…

バックアップドライブの整理は遅々として進まない.昨日仕掛けたファイル転送は夜通し掛かってもまだ,73%というところだ.コラッツ解析ツールに関してはある程度状況はつかめたので,ゼルコバの木の状況を確認しておこう.現在開発機にインストールされているバージョンはV2.2.2.008 R2022-04-26,このソースを押さえておく必要がある.デスクトップ上にはコラッツツールのプロジェクトフォルダはあるが,ゼルコバの木のフォルダはない.D:開発用ドライブにあるZELKOVAというフォルダが最終版と思われるが,この版は2.2.2.009 R2022-04-29でこちらの方が少し新しい.

ログ上では2022-05-03の「あきらめてここで打ち切るか,何か対策を考えるか?それが問題だ」というのが最終日付だ.やっていたのは,「CollatzTest 4000.ADLの極小反例サンプル抽出」という作業だが,このあと興味が「経済循環マトリックス」の方に移ってしまっているので,おそらく打ち切りになってしまったのだろう.何件か障害が発生している.Dドライブの最終バックアップは2022-05-06だ.問題は「メモリ不足」だが,解決できなかったようだ.「極小反例サンプル抽出」というのがどういうものであるかはわかったが,どういう障害が起きていたのかはまだつかめていない.

2022/05/01に①UNDOでShadowが空というエラーが起きている,②Collatz4000-12243.ZELでループカウントオーバーという2つの障害が記録されている.「極小反例サンプル抽出」の対象となっているのは②の問題だ.「極小反例サンプル抽出」というのは時間コストが掛かる処理なので,いくつかの機能を暫定的に停止しているところがある.5月3日付けのログは

「そもそも,バージョンが戻ってしまっている.というか,最終版がバックアップされていない.最終バックアップは2022-05-01-2で,これには2022/05/01のログの修正のすべては反映されていない.「BUNSFILEのバッファは常設とする@20220430」は入っているが,UNDOの修正は入っていないように思われる.ここからやり直すしかない.一度仮眠してデバッグを再開するときには,必ずバックアップを取るようにしないと失敗する…」

で終わっている.最終バックアップは5月6日という日付になっているので,この辺りはクリアされているのだろうか?いずれにせよ,ゼルコバの木に関してはここから進むしかないのではないだろうか?ZELKOVA 2022-05-03のバックアップはBAD, BAD2, BAD3, BAD4, NOGOODとなっていて,悪戦苦闘している状況が伺える.2022-05-06というのはおそらく,事後に形式的にバックアップしただけのものと思われるので,問題は解決していないと考えるしかないのではないか?

ここはもう腹を決めてここから再出発するしかないのではないだろうか?実際,現況は大海原で難破して漂流しているのに等しいと思った方がよい.⇒既定の開発用フォルダ ZELKOVA を ZELKOVA 2022-05-08にリネームしてここを再開発地点とすることにする.⇒どうも,この版はVS2017で開発されていた模様だ.すでにVS2019に移行済みだったはずだが,何らかの理由でVS2017に戻っているのではないだろうか?

image

確かに,VS2017なら問題なく開ける.とりあえず,バージョン番号を変えておこう.Version 2.2.2.000 Release 2022-12-21.⇒なぜだろう?バージョン番号など微細な修正を加えただけなのに,「アプリケーションはブレークモードになっています」で停止してしまった.

System.TypeInitializationException
   HResult=0x80131534
   Message=’ZelkovaTree.Program’ のタイプ初期化子が例外をスローしました。
   Source=<例外のソースを評価できません>
   スタック トレース:
<例外のスタック トレースを評価できません>

内部例外 1:
FileLoadException: ファイルまたはアセンブリ ‘ZelkovaGC3.dll’、またはその依存関係の 1 つが読み込めませんでした。このコマンドを処理するにはメモリ リソースが足りません。 (HRESULT からの例外:0x80070008)

クリーンビルドしたら動作するようになった.⇒53直系血族図.ZELというサンプルを開いて例外が出た.アクセス違反が発生している.

image

NAMEBOX::DrawFooterLineの中で(vpos == MAXMDB)で停止している.vposの値は10299,

MAXMDB=MAXMARGTABLESIZE-1 MAXMARGTABLESIZE=10300

まったく見たこともないエラーパネルまで出てきた.

image

エラーを無視して続行する.53直系血族図.ZELというファイルは点数1931でそれほど大きなサンプルではない.上記のエラーが影響しているのだろうか?先祖ノードとその直下のノードが孤立してしまう.

image

Collatz12146.ZELを開こうとしたら,うんともすんとも言わなくなってしまった.BUG3000-1906.ZEL(1906点)は開けたが配置が悪い.

image

この版よりは,現在インストール済の版の方がよほどましだ.

image

インストール版のソースを探して,そこから開始することにしよう.2022-04-27という版が一番まともな動作になっているようなので,ここまで戻ることにする.とは言え,ここでもいくつかのエラーは出ているが… いずれにせよ,これより後の版を追いかけても泥沼に入ることは避けられないので,できるだけ乾いた土地にスタートラインを置いた方がよいと思う.とりあえず,この版をデバッグしてある程度の安定版を構築することにしよう.この版では上記53直系血族図.ZEL,BUG3000-1906.ZEL,Collatz12146.ZELの3ファイルを開くことができる.

コラッツ木生成ツールの仕様は変遷している

コラッツ木生成ツールは仕様が変遷しているので,どの版をベースとして進めるかを決めておかなくてはならない.2022-03-10という版は「三本桜の復活」という方向に向かう途上と考えられるが,2022/04/05で方向転換して「銀河系の再構築」に切り替えている.この辺りから「コラッツ中核木」という言葉が使われ始めている.

実際,アプリのボタンにもCoreという語が用いられているのだが,この「中核木」というのは,完全木なのか?仮想木(長子木)なのか?⇒中核木=長子木でよい.やはり「長子木」と呼んだ方が直観的で間違いないような気がする.もう一つ分かりづらいのが「完全木」だ.「完全木は1を含む」という記述もあり,「中核木から1を除外した部分木は完全正則木の条件を満たす」という記述も見られる.整理しておこう.

  1. コラッツ一般木:すべての奇数を含むコラッツ木(偶数を除外)
  2. コラッツ仮想木:コラッツ数(長子ノード)のみを含むコラッツ木
  3. コラッツ完全木:3倍数を含まないコラッツ木→ユニバーサルアドレス

仮想木=中核木であり,仮想木から1を除いたものを長子木とする.(長子木は完全正則である)長子ノードとはコラッツ一般木上の兄弟ノードのうちの最右ノードであり,コラッツ仮想木はコラッツ一般木の縮約グラフである.長子ノード(1を含む)はコラッツ数と呼ばれる.ただし,「コラッツ数」を「完全木上のノード」としているところもある.これはSultanのコラッツ数の定義と一致する.2022/03/29「素数pとその倍数を除去したコラッツ完全木」には,以下のような記述がある.

前提:ある任意の素数Pより小さい素数はすべてコラッツ数である
帰結:素数Pより大きい素数で最小のものをP’とするとき,素数P’はコラッツ数である

これは数学的帰納法を証明に適用しようとする試みだが,望みはあるだろうか?※ともかく,コラッツツールの最終版を見て,どこまで進んでいたのかを確認しておこう.この版はV3.0.3となっているが,もう少し新しい版がある.CollatzCoreTree 2022-04-16 というのがとりあえず最新版のようだ.ただし,バージョン番号はV3.0.3で変わりない.

※すべての自然数からなるコラッツ全体木から2の倍数を縮約/除去したものをコラッツ一般木,3の倍数を縮約/除去したものをコラッツ完全木とすれば,コラッツ全体木から素数p以下のすべての素数の倍数を縮約/除去したグラフは連結な無限木を構成すると考えられる.このグラフのノードはすべてkより大きい素数のみからなる整数である.

動かしてみよう.⇒A面では正則木が出力される.デフォルト設定の ルート=1,枝数=4,樹高=5で,Max node count=1365を実行すると,カード数:373の3-正則木が出力された.どうもよくわからない.Max-branches=4で3-正則では数字が合わない.画面に表示されているMax node count=1365が何を意味しているのかもよくわからない.Core treeをオンにすると,342点の4-正則木が出力された.ただし,1の直下には5しかないので,厳密には正則木ではない.

Max node countには無効ノードカウント(void node count)が入っているため大きくなっているのだろう.有効ノードカウント(valid node count)と無効カウントを足すと,Max node countになっている.有効ノードカウントは出力データの有効カード数と一致している.Core tree(中核木)は長子木を指しているのだろう.この図版には3倍数が114点含まれている.(3倍数が長子ノードになる場合がある)

image

このグラフの樹高は実際には6になっているのに,設定が5というのもあまりうれしくない.それを除けば,大体のところは整合しているようだ.Core treeを指定しないときの出力が3-正則になっているというのはどういうことだろう.⇒core treeでないときでも,樹高は5になっているので,ルートは樹高に勘定されていないのだろう.つまり,ルートのみの木は樹高ゼロとみなしているものと思われる.core treeのオン・オフに関わりなくMax node count=1365になっているというのは,次数と樹高を指定したときの正則木のノード数を単純にカウントしてその範囲で計算を行っているものと思われるが,いまいち納得できない…

いずれにしても,この版では「完全木」という概念はまったく放棄されているように思われる.というか,「3倍数を除外する計算」を実装できなかったのではないだろうか?しかし,CollatzCompleteというプロジェクト名が使われていた時期もあるので,まったく試みたことがないというのではないはずだが… ⇒確かに,CollatzComplete 最終版 2022-04-03という版では,一般木,仮想木・完全木の3種が出力されるようになっている.ただし,この版では一般木と仮想木の出力が同じだ.つまり,仮想木出力は実際には実装されていなかったのではないか?⇒データを取り損なっていたかもしれない.仮想木の出力は一般木と同じではない.同じではないのはよいが,でき損なっているようだ.

image

このファイルを「隣接リストのインポート」で開くとエラーが出る.

image

一般木はまともに出力できている.

image

完全木の出力も問題ないようだ.

image

V3.0.0では仮想木の出力に失敗している.V3.0.3には完全木は実装されていないが,仮想木(中核木/長子木)の出力には成功している.この2つの版を組み合わせれば原理的には完全な「コラッツ三本桜」を実現できると考えられる.それをやるしかないのではないだろうか?よく読んでいないので本当のところはわからないが,Sultanは「完全木」の方から攻めているのではないだろうか?

我々の方法はベースに長子木があり,その上に一般木を展開していると考えられる.とは言っても,長子木を構築した上で一般木のノードを追加するという仕掛けにはなっていない.一般木を構築するための代数的基礎は一応確立しているが,長子木に関してはまだ不明のところが少し残っているのではなかったろうか?完全木の方が先に動作しているところから見ると,構成的には完全木の方が易しいのかもしれない.

だとすれば,Sultanがすでに問題を解いている可能性は十分ある.いずれにしても,まず当座の課題は「コラッツ三本桜」を実装することではないだろうか?それができていれば,Sultanの論文を読み進む上でもいろいろ役に立つのではないかと思う.もし,Sultanの論文の結論が正しいとすれば,少なくともそれを「追試」することにはなるだろう.