Collatz12146.ZELをようやく安定的に開くことができるようになった.ただし,開くまでには相当な時間が掛かっている.どこがネックになっているのか,シューティングしたいところだが,それはもう少し落ち着いてからの課題としておこう.
巨大ファイルでメモリ不足が発生しないようになったのは,MAXPDBxMAXMDBという巨大配列の使用を一時的に止めたことが効いているのではないかと思う.DTおよびKTという名前のshort型の2元配列で,親等計算に使われている.とりあえず,親等を計算する必要はないので当面は停止で問題ない.親等計算は結構時間を消費するので,オプションで止められるようにしておいた方がよいかもしれない.
Collatz12146.ZELでは三極検定レッドラインオーバーが発生している.
上図では小さ過ぎて見えないが,図面の左上隅に#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.⇒これは上記の「保留」に関わる修正ミスだ.