Windows 11 にアップグレードした

いきなりだが,面倒くさいのでWindows 11に移行することにした.画面の外観は,けばけばしたところが一掃されてわたし好みに近いものになった上,とりあえず通常の作業で支障を来たすようなこともなさそうだという見極めも付いたので,ともかくしばらくこれで運用することにした.大量のファイルコピーで以前より少し遅くなったような感じはする.エクスプローラで詳細モードで表示したときの行間が広くなっているのは気に入らないが,まぁ,しばらく使っていれば慣れるだろう.え,もちろん「ウィジェット」はオフになってますよ.

三極検定は個別系列内の要素の配置を決定する処理で,①結婚枠の吊り位置の調整,②結婚枠の衝突の回避,③要素間の距離を詰めてコンパクト化の3つの処理から構成される.水平セグメント検定と呼んでいるのは,この3番目のコンパクト化に関わるものだが,レイアウトを崩さずにコンパクト化するためにはあるまとまった要素のグループを同時に移動する必要があり,かなり技巧的なものにならざるを得ない.テスト回数3000のサンプルで起きている不良は水平セグメント検定の誤動作によるものと考えられるが,これを追跡するのはかなり難しい.

これまで使えていたSUW(ShowUnderWear)というデバッグ用のツールが使えない状態になっている上,巨大サンプルに対応してメモリ使用量を削減するために,水平セグメント検定で個別系列ごとに確保していた作業域をシステム全体で1個にしてしまっているため,セグメント番号による色分け表示というのもできない状態になっている.SUWというのはある種の例外処理で,プログラム実行中のどのタイミングでも(書きかけの)図面を画面に描画することができるという強力なツールだったのだが…SUWでは特定の系列を描画対象に指定することができるようになっていたはずなので,まだ工夫すれば何とかなる可能性がある.まず,それを追求してみよう.

コラッツ特注版ではメモリを節約するために,MAXIMALGRAPHのsegments配列とloosebox配列を外部に追い出して静的変数としているが,MAXIMALGRAPH自体は個別系列で保持するようになっている.しかし,MAXIMALGRAPHオブジェクトはセグメント検定中しか参照されていないはずだから,システムに1個あれば十分なのではないだろうか?少なくとも当面はセグメント検定を広域化するという構想は持っていないので,徹底してしまった方がわかり易いと思う.修正してみよう.⇒いや,やはりそこまでやるのはやり過ぎかもしれない.事後にsegmentcntなどを参照する場合がある.これらは個別系列で保持するしかない.⇒いや,そういう箇所は多くはない.というより,むしろ積極的にそうした方がよい.この修正に関わる箇所には以下がある.

  1. TRIBELIST::IsTribeComplete
  2. NAMEBOX::Group
  3. NAMEBOX::Group
  4. MARGBOX::clear
  5. NAMEBOX::Clear
  6. NAMEBOX::CLEAR
  7. TOPOLOGY::checkRIG
  8. Bobject::initialize
  9. Bobject::SetBranch

これらの箇所でセグメントを操作するのはむしろ危険だ.MAXIMALGRAPHを共有した上で,ReleaseSegmentを実行しないようにすれば描画時にもアクセスすることができるだろう.ReleaseSegmentの呼び出しは,①TRIBEBOX::HorizontalSegmentの出口,②TRIBEBOX::CheckMaximalSegmentの出口(単独で呼ばれた場合),③TRIBEBOX::CheckMaximalCompaction,④MAXIMALGRAPH::clearSegmentの4箇所ある.④は必須だが,①,②,③は止めることができる.

この修正をやってみて気付いたことがある.MAXIMALGRAPHを共有するということは,広域検定を実装するという方向に向かっているのではないかという点だ.三極検定は基本的に系列単位の処理なので,いきなりそれを広域化するというのは現実的ではないが,「共有」という語が「広域」を含意していることは明らかである.これで,セグメントのカラー表示はできるようになったが,SUWが動かないのでは始まらない.

どうも,どこか壊してしまったようだ.急に動かなくなってしまった.⇒TableSort.cppを差し替えて動作するようになった.TOPOLOGY::MakeLeastWindowで実行しているTRIBELIST::HeapTribeBoxesを関数の冒頭で実行するようにして,画面が表示できるようになった.理由はよく分からないが,これで良しとしておこう.SUWとセグメントのカラー表示が復活したので,デバッグを再開する.さて,どうやって追いかけたらいいだろう?

少し動作がおかしい.VS2027を管理者モードで起動しても立ち上がってこない.管理者モードでなければ起動できる.おかしなことに,タスクマネージャを開いているときには,管理者モードでも起動できるという動作になっている.管理者モードでないと不都合な場面というのはそれほどないので,運用的にはさほど不便ということもないような気はするが,管理者モードでないとデバッグ中にゼルコバの木のテーマを登録したりなどのこともできなくなる.タスクバーのアイコン→ 右クリック→ Visual Studio 2017→ 右クリック → プロパティ→ 詳細設定→ 管理者として実行をオンにして,ワンクリックで起動できるようになった.

SUWはまだ動いていない.HeapTribeBoxesの前にstackTribeGeneを実行することで描画できるようになった.stackTribeGeneは系列内部の描画要素を系列世代枠の集約する関数,HeapTribeBoxesはその計算を元に系列枠全体の矩形領域を計算し,それを集約して系図枠全体の矩形領域を計算するものだ.これで見ると,どんなことになっているのかをはっきりつかむことができる.

image

左端の孤立点は1だと思っていたが,違う.5, 5461,  85の3人兄弟だ.

image

1にはこの他に,1365, 21, 341 の合わせて6人の子どもがいる.このうち,1365,21 は3倍数なので,子孫につながるのは,341,5,5461,85の4つだけだ.このうちの3つは左端で孤立しているので,右側には1系統しかないことになる.上の図でおかしいのは,3人兄弟のうちの真ん中の5461の下に垂線がないことだ.実際,カード画面で見ても5461は子どもを持っていない.しかし,上記したように5461は3倍数ではないので,子孫がいなくてはならない.

ADLファイルで見ると,そもそも 5461 というカードの登録がない.15461というカードはある.⇒見落としていた.1の子どもの位置にある.ただし,5461を親とするレコードがない.これはかなりおかしい.つまり,ADLの出力自体に誤りがある.5には13,213,3,3413,53,853 の 6人の子どもがいる.85は,113,1813,453,7253 の4人の子がある.このADL出力の誤りを見つけなくてはならない.

明らかにGetTheNumberの論理には誤りがある.⇒いや,違う.5461はテストの対象となる奇数そのものだ.従って,5461が終端ノードであることは間違いない.もし,5461→1というパスがあるのなら,1に5461が直結しているのは間違いではない.実際,5461*3+1 = 16384 = 2^14だ.従って,ADLデータは間違っていない.確かにこの不良は結婚枠を一律中吊りにしていることに関係していることは間違いない.⇒中吊りを強制しないモードで走らせてみたが収束しない.

TC(Test Count)4000のサンプルでは中吊りの場合と同等の回数(loopcnt=32)で収束している.どうもこのTC3000というのは何か特殊なサンプルになっているのだろうか?この計算自体が収束しないある種の散逸構造的なトラップに陥っているのだろうか?

大きいサンプルの描画で不良が出ている

検証テストが出力する大きいサンプルの描画で不良が出ている.

コラッツ木ツールからZTを直接起動して,ImportEndで停止する.

image

このエラーはデバッグモードでは起きない.⇒Nリング上の特定のノードを検索するデバッグ用のコードが残っていた.

テスト回数4000では三極検定のループを34周で抜けているが,テスト回数3000では抜けられない.⇒どうもこれは,三極検定の欠陥が露呈したものであるような気がする.errcntは周回するごとに単調に減少してゆくが,ある点まで来るとまた跳ね上がってしまうという動作を繰り返している.以前はこれに加えて,ルートノード直下の結婚枠が結婚点不一致のとき,CheckMargBoxを実行しても移動量がゼロにならないという事象があったが,いまは再現できない状態になっている.

このサンプル自体が特殊なものになっているという感じもする.後で再試する必要があるので,このサンプルを取り分けておこう.⇒「CollatzTest.X.ADL」としておいた.

コラッツ木というのは紛れもなく「単純な木」なので,これが解けないとなると身も蓋もない.⇒中間の状態が見たいので,SUWを仕掛けてみたが,まったく描画できない.この三極検定はMainExprerimentの手前のTribeRelocationで実行しているので,TribeRelocationをまるごと止めてみたところ,ともかく描画することはできた.

image

ただし,この図を見るとどうもMainExprerimentの中では三極検定をやっていないように見える.CompleteTribeBoxは,①TRIBELIST::CheckCompleteList,②TRIBEBOX::StackTribeGeneから呼び出される.⇒MainExprerimentの中ではStackTribeGeneさえ呼び出されていない.⇒⇒出た!

image

出たのはよいが,少し形状が違い過ぎる.多分これは間違っているのだと思う.衝突検定が入っていないのではないだろうか?⇒正しく動作するためには,少なくともTREEVIEW::GetMaxMoveを実行する必要があるようだ.⇒この関数はTribeRelocationで実行される前にTREEVIEW:SetDispParmの中からすでに2回呼び出されている.

ここで更新されているのは,maxloopcountとMAXLOOPCOUNTの2つだけと思われる.これらの値はそれぞれ,20→2261,128→2261のようにかなり大きく変化している.maxloopcountは計算用の内部変数なので,外部に影響するのはMAXLOOPCOUNTの値だけだ.この値が急増するのは,この値がカード数と結婚数よりも大きい数になっているためだ.テスト回数3000のサンプルではこの値が1680になっている.

変動しているのは,ルート直下の結婚枠の幅だ.本来の配置なら30000くらいの幅があるはずのところが,313まで縮退し,また膨張するという運動を繰り返している.これでは収束するはずがない.⇒水平セグメント検定で失敗している.この解析はかなり難しいかもしれない…

検証テストカウント3200のADLサンプルでハングする

コラッツ木検定ツールとゼルコバの木が完全連動するようになったので,効率的にテストできるようになったが,検証テストでテストカウント3200を指定したときにハングしてしまうという問題が出ている.出力されたADLファイルを見ると,ノード数は3827で,ゼルコバの木のカード数上限の7000まではまだまだある.テストカウント3000では多少時間は掛かるが問題なく描画できているので,原因を突き止めておく必要がある.⇒極大セグメント検定でハングしているようだ.

いや,極大セグメント検定からは抜けているが,三極検定でループしている模様だ.CompleteはTRUEになっているが,perfectがFALSEのままになっている.ループカウントオーバーというのは見ているが,ループを一周するのに相当時間が掛かっているようだ.ループカウントが3646を超えるとレッドラインオーバーが発生するが,それまでに日が暮れてしまいそうだ.REDLINE=10に変更し,強制的にブレークするようにして描画まで進んだが,まだ,どこかで詰まっているところがある.画面の半分しか描画できないだけでなく,タイトルバーをつかんでウィンドウをドラッグすることもできない.

image

いや,まだ,計算は完了していない.画面は以下のように変わった.

image

しかし,制御はまだ戻ってきていない.水平スプリットの検査に手間取っているようだ.⇒スプリット検査を止めたら抜けてきたが,画面は上と変わりない.左上隅に小さな集落がある他は,広い範囲にごく短いヤブが生い茂った状態だ.系統が2分解し,ノード1を先祖ノードとする始系列ともうひとつの系列に分かれている.後者の先祖ノードは#1825のようだ.#1825の親は#1369だが,カードで見ると親なしになっている.#1369の親は#1027で子どもは#7301だけになっている.

結局,#1369→#1825という親子関係が失われているということになる.ゼルコバの木のダンプで見ると,このサンプルのカード数は5045,結婚数は3645.この数は上で「ADLファイルを見ると,ノード数は3827」としているのよりも少ない.ソースコードを見ると,最大カード数は0x2000=8192,最大結婚数も同じ8192だ.MAXCHILD=12となっているが,12人より子どもが大きいときには複数の結婚ページを使うことができたはずだ.MAXMARRIAGE 32となっているので,384人までの子どもを持つことができるはず…実際問題として,もっとも子どもが多いのは1の6人,いや,5にも6人の子どもがいる.

「ADLファイルを見ると,ノード数は3827」というのは,ADLファイルの行数が3827という意味であり,この数は結婚数と一致していなくてはならない.しかし,実際には3645というのだから,182個も少ない.これもかなりおかしい.結婚が切れているとしたらその子どもはすべて親なし,つまり先祖ノードになってしまうから,系列がその数だけ発生しなくてはならないと考えられるのだが…ともかく,ADLから変換したCSVを保全してチェックしてみることにしよう.⇒CSVでは

#1825,男,1825,,,,,,,,,,,,,,,,1,1,1,#1369,,1
#7301,男,7301,,,,,,,,,,,,,,,,1,1,1,#1369,,2

のようなレコードがあり,#1369→#1825という親子関係は活きている.#1369のもう一人の子どもである#1825は問題なく繋がっている.どういうことだろう?世代数には上限はなかったはずだが…始系列はmin=0, max=115とあるので,世代数では116世代ということになる.いや,この数字も奇妙だ.コラッツツールの画面ではTree height は96になっている.この数字が正しいとすれば,どこかで連結を誤っていることになる.このテストでは1~6399の奇数を検定したとなっている.

Total odd number count: 3200 というのは疑問のある数字だ.確かにテストされた奇数のカウントは3200だが,Total odd number には木に含まれるノード数を表示すべきではないか?いや,同じノードが何度も重複出現するため,それをこの場でカウントするのは無理だ.⇒Total odd number countを Tested odd number count に変更した.

問題のレコードは少なくともVBからはDLLに送信されている.TREEVIEW::sendUpdateDataではこのレコードを受信して処理している.LINKTABLE::ImportEndでは1825は父1369を持っている.⇒いや,違う.1825はImportEndでMakeMarriagePageに失敗している.⇒LINKTABLE::MakeMarriagePageの中で「上流で循環」が発生している.1825の曽祖父である1541の親が本来289のところ1825になっている.少なくともADL上ではこの間違いは起こっていない.CSVにもこの誤りはない.従って,インポート処理中の誤りと推定される.

どこかで誤動作しているのだろうか?LINKTABLE::ImportEndの2周目でこの値が入ってくる.⇒いや,違う.もっと前だ.ImportTableFuncで送信した1825の2番目の子ども9733のレコードを処理するところで誤動作している.LINKTABLE::GetRefnumが9733の参照番号を求めているのに対し,1541が返されている.上記したように,カードテーブルのサイズ上限は8192なのでそれを超える値に対し,ハッシュした代替値が返されたのだろう.⇒VB側でMAXPDB=7000になっていた.ただし,これは多分動作には影響していないと思う.おそらく,この後に本物の1541が登場し,その位置に座ってしまったのではないか?

どうも,この不良は手順が悪いためではないかという気がする.TREEVIEW::sendUpdateDataでは,breakNumberでは名前から参照番号を取り出しているが,この関数から呼び出しているGetRefnumでは,ハッシュ化を実行している.しかし,この参照番号はその場では登録されず,事後にまとめて処理されているため,ハッシュの衝突が発生しないので,重複登録が容易に発生する状況になっている.これを安全に実施するためには,breakNumberの中でカード登録を行うしかないのではないか?⇒対処した.これで一応画面は表示できたが,目を覆うような惨めな結果になった.

image

特にひどいのは,ルートノード1だ.画面の一番下にどこにもつながらない状態で孤立している.縦書きに戻してみよう.⇒三極検定のループカウント上限を10に設定した状態では上と同じ図面になってしまうが,上限を100まで上げたところ,ループカウント32で抜けてきた.

image

形状は以前「蝙蝠」と呼んでいたものとほぼ同型だ.カード数は5045点.カード数上限は8192となっているので,もう少し大きくしてみよう.テストカウント4000を試してみる.⇒三極検定のループカウント33で抜けてきた.カード数は6365になった.最大枝数は8,樹高は96.

image

前にテストカウント3000というサンプルを取っているので,取り直ししてみよう.⇒なぜだろう?レッドラインオーバーになってしまった.

image

障害の原因が左端に孤立したルートノード1であることは明らかだ.なぜ,こんなことが起きているのだろう?結婚枠をカラー表示してみると下図のようになる.

image

コラッツ特注版では結婚枠はつねに中吊りしているのだから,全体を左シフトして最上層の結婚枠中央に1が来るようにすればよいだけと思われるのだが… なぜそれができないのだろう?いや,もしかすると「結婚点の一致」という操作を止めていたかも…⇒試験的に止めていたこともあるが,戻している.CheckMargPointで毎回移動が発生している.移動量は変動があるが,つねに正で48960などの大きな数値だ.

修正をフィックスしてリリース版を起こした

修正をフィックスしてリリース版を起こしたが,ZELのアイコンをダブルクリックしてファイルを開いたとき,「基準ノード不在」が発生するという事象が残っている.開発環境でデバッグモードでコマンドライン起動できるようになっているが,そこではこのような事象は発生していない.つまり,リリース版とデバッグモードの動作が異なるものになっている.⇒リリースモードでコマンドラインを実行してみればよいのではないか?⇒おかしい,現象が再現しなくなった.⇒確かに,一つ修正を入れてからリビルドしているはずだが,すでに解消しているようだ.

コマンドラインで隣接リストのCSVがオープンできるとしたら,ダブルクリックでそうできてもよい.ただし,そのためにはCSVという拡張子をZELに登録しなくてはならない.CSVファイルは一般にはエクセルなどの表計算がデフォルトアプリになっているので,それを横取りするというのも多少問題がある.むしろ,隣接リスト専用の拡張子を決めてゼルコバの木で登録するようにした方がよいのではないか?現行ではゼルコバの木形式エクスポートも隣接リストも同じ拡張子CSVを使っているが,これも問題だ.*.ADLとしてみよう.ADLはActivities of Daily Livingで「日常生活動作」という意味だ.これには,移動・排泄・食事・更衣・洗面・入浴などの日常の生活動作が含まれる.わたしの関心のもっぱらの傾向からすると適切な拡張子であるような気がする.

このファイルが出力できるのは今のところコラッツ木生成ツールだけだが,隣接リストはテキストエディタでも簡単に作れるので,まぁ,よいのではないだろうか?⇒だいぶわかり易くなった.⇒アプリインストール時に*.ADLを登録するようにした.これでADLファイルをダブルクリックしてもコラッツ木が表示できるようになった.

ADLファイルはもともとCSVファイルだが,インポートしたときに内部的に一度ZEL形式のCSVフォーマット形式に変換し,それをインポートするという動作になっている.このため,ファイルを読み込んだあと,タイトルに表示される名前がこの一時ファイルの名前になっている.これはかなりおもしろくない.書き換えることは可能だろうか?⇒一時ファイルの名前を単純にADLファイル名の後ろに”.CSV”を追加するだけにした.これなら表示されてもそれほど不自然ではないと思う.

開発環境でリリースモードで走らせると空白画面になる.本来は新規カードが1枚表示されていなくてはならないところだ.⇒いや,コマンドライン引数を渡さないようにすれば,デバッグモードでも同じ動作になる.どこか壊してしまったのだろうか?⇒コマンドライン起動の処理を一箇所に統合するために相当書き換えを行っているが,コマンドライン引数なしの場合の処理を落としていた.

いい感じになってきた.ほとんど「最強のコラッツツール」と言ってよいと思う.*.ADLのアイコンをダブルクリックするだけでゼルコバの木が立ち上がってくるというのもうれしい.このツールには5つの機能があり,それぞれ一般木と仮想木を扱えるようになっているから,5×2=10種のファイルが出力されることになる.まずは,これらの出力ファイルを一通りチェックしておこう.

ゼルコバの木が立ち上がっているのに,タスクバーにアイコンが出てこない.代わりに何か白い枠のようなものが出ている.EXEのアイコンとMDIウィンドウのアイコンは出ている…タスクバーに古いバージョンのアイコンが残っていたためだ.⇒問題なさそうだ.

A面の出力は問題ないと思う.左が一般木,右が仮想木だ

image image

▲コントロールキー+リールでズームができるようにしたい.また,ズームボタンは押し続けていると段々速くなるようになっているようだが,初期の動作ももう少し速くてよい.

アドレス変換でエラーが出た.分岐枝リストは「1. 1. 2. 1. 1. 1. 1. 1. 1. 2. 1. 1. 1. 2. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 2. 1. 1. 1. 3. 1. 1. 2. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 2. 1. 1. 1. 1. 1. 2:1」でコラッツ数列が「53261」から出力したものだ.⇒一見したところどこも問題ないように見えるのだが… ⇒一般木でテストしていたためだ.現行では一般木では拡張アドレスをサポートしていない.というか,一般木の場合のアドレスはつねに実アドレスになるから,拡張アドレスという概念はない.また,そのアドレスコードの示す経路中に3倍数が入っていれば,そこでアドレスコードはカットされる.

一般木上では「53261」のアドレスコードは「1. 3. 1. 1. 2. 2. 1. 1. 2. 1. 1. 1. 2. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 2. 1. 1. 1. 1. 1. 1. 1. 1. 1. 2. 1. 1. 1. 4. 1. 1. 2. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 2. 1. 1. 1. 1. 1. 2. 2」のようになる.長さは同じ60だ.ADLファイルの名前に木の種別を入れておいた方がよいのではないか?一文字でよいと思うが,一般木をG,仮想木をV,完全木をFとしてみよう.⇒しかし,今の誤操作はコラッツツール上のもので,ADLファイルとは関わりがない.⇒現行では仮想木に切り替えると出力枠の背景色がブルーになる.分岐枝リストのフレームも同色に切り替えた方がよいのではないか?

悪いアイディアではないが,効果は限定的だ.コラッツ数列のリスト出力を転用してアドレス変換することが多いが,リストに残っているのが,どちらのモードで出力されたものかは判別できない.⇒とりあえずは,現行のままとしておこう.ファイル名にモード種別を追加するという修正は入れておいた方がよいと思う.

幹線木の関係がおかしい.一般木も仮想木もコラッツ番号と合っていない.⇒サンプリングが悪いのではないか?多分相応していない組み合わせになっているのだと思う.サンプルを取り直した方がよい.23637という数字をターゲットとして取り直してみる.⇒問題なさそうだ.

image

コラッツ数列とアドレス→ノード番号は逆順になっていて,幹線木の軸はアドレス→ノード番号の系列と完全に一致している.これでB面4機能のうちの3つの出力が確認できた.あとは検証テストだけだ.2^3という範囲で1~15までの奇数を含む最小のコラッツ木を出力してみた.

image

終端ノードは一般木では3, 9, 15の3つあるが,仮想木では3はコラッツ数なのでパスの中間の位置に出現する.表示されているノード数は一般木が12で,仮想木は10だ.13と53は仮想木上には表示されない.53は範囲外だからよいとしても,13は[1, 15]の区間に入るので,表示されてもよいのではないか?拡張アドレスコードを使えば非コラッツ数の位置を示すことができるのだから,表示できないというのはおかしい.

13は3の兄弟ノードだから,5の下に来るべきだ.53も同じく3の兄弟だ.コラッツ数列取得で確認すると,13には「1. 1:1」というアドレスが割り当てられている.やや,53でも「1. 1:1」が出力されている.これはおかしい.一般木で見ると5の子ども枠には,{3, 13, 53, 213,…}が入っている.従って,3:={1. 1:0},13:={1. 1:1},53:={1. 1:2},でなくてはならないと思うのだが…実際,アドレス→ノード番号にこれらのコードを与えてノード番号を出力すると,{1. 1:1}→13,{1. 1:2}→53,{1. 1:3}→213が出力される.従って,アドレス→ノード番号は正しく動作していると言ってよいと思う.明らかにコラッツ数列取得処理はどこかで間違えている.

あれ?!今度は正しく動作している.読み間違えた,というか,どこかで操作を間違えたのか?このツールはあちこち操作するところが多いので勘違いを起こし易いかもしれない…ともかく,Get Collatz sequenceとAddress to numberが完全に逆演算になっているというところが肝心なところだ.この2つが正しく動作していれば,検証テストは自ずと正しく動作するはずなのだが…CSVに変換する前のADLの中身をテキストエディタで調べてみよう.一般木の方は,

1    5
11    7
13    17
17    11
23    15
35    23
5    13    3    53
53    35
7    9

のようになっている.これは正しい.仮想木を見てみよう.

1    5
11    7
17    11
23    15
3    17    35
35    23
5    3
7    9

確かにこれは,ゼルコバの木の描画と一致している.つまり,ADLの出力に欠落があるということになる.検証テストの出力は,コラッツ数列ではなくアドレスノード番号で出力していたような気がするのだが,違うだろうか?⇒確かに,そうなっている.NumberStreamに書き込んでいる場所で,かならずVerifyStreamに書き込むようにしていれば同期は取れるはずだ.NumberStreaming,TruncatedStreaming,VerifyStreamingはかならず排他的になっていなくてはならないのだが,どこかで崩れているということはないだろうか?

VeriVerifyStreamへの書き込みは2箇所でいずれもGetTheNumberの中だ.⇒おかしい.NumberStreamへの書き込みとVerifyStreamへの書き込みの位置は完全に一致している.そもそも,検査の対象から弾かれているという可能性が高い.⇒確かにその通りだ.コラッツ数しか対象としていない.⇒修正を入れてみたが,相当おかしな結果になった.⇒いや,間違えていた.Odd numberに大きな数字が入っていた.1から始めるようにしたら,カード数は11点になった.

テスト区間は[1, 15]でその間の奇数はすべて出力されている.53という数は入っていないが,この数は区間外であり,それがなくても連結性は保たれている.これでようやく正しく動作するようになった.区間を設定するのに2のべき乗を使っているというのはちょっと使い勝手が悪い.もう少し細かい範囲で調整したい.2のべき乗を使ったのは,大きい数字を入力するのが面倒だったからだが,やはり整数で指定するようにするべきだった.⇒これはやはり変更した方がよいと思う.⇒できた!

テストカウントを16で走らせてみた.

image

区間は1~31でカード数は53,1~31までの奇数はすべて入っている.1から一番遠いノードは27で距離は41ある.仮想木ではカード数は51で2枚少ない.この2つの図面を合併(追加読み込み)して,共通部分を取って部分図とすれば,一般木と仮想木がどのように交差しているかを見ることもできるだろう.テストカウントは巨大数になるので,かなり大きなテキストボックスが必要になる.Odd numberと同寸では画面に収めるのが難しい.

image

なんとか収まった!

image

これで大体仕上がったのではないかと思う.⇒テストカウント4000のコラッツ木を試してみたが,ハング状態になって抜けてこない.3000くらいまでは難なく描画できていたのだが… ゼルコバの木の上限は多分7000だったと思うので,仮に上限をオーバーしてもそこまでのグラフは描画できなくてはならないのだが… 計算自体は数秒で完了している…3000まではそこそこの時間で描画できるが,3200になるとほとんどハングしている.下図はテストカウント3000,ノード数4720のコラッツ幽霊木だ.前は「蝙蝠に見える」と言っていたのだが,点数が増えると,むしろ「炎」のような感じになってきた.

image

ゼルコバの木はだいぶ前に「Zelkova tree 2022」に改名しているが,まだどこかに「Zelkova-tree 2021」というのが残っているようだ.⇒AssemblyInfo.vbというファイルに入っている.このファイルはシステムが自動的に作っているものだと思うが…

なぜだろう.今回はテストカウント40000でカード数7000というADLが難なく開けた.考えられるのはカード数が不足しているため,グラフがぶつぶつの非連結になったため,却って速く描画できているのではないか?という感じだが…このグラフの木の高さは129だが,実際の描画はもっと低い木になっている.木というより,ヤブになってしまっている.実際,こんな図面になっている.

image

コラッツ木生成ツールから直接ゼルコバの木を起動する

コラッツ木生成ツールからゼルコバの木を直接起動することができるようになった.かなり楽しい.

最初にUPした動画は34MBで,アップロード時にエラーになったので,Windows 10のムービーメーカーで画質を落として(電子メール用として)保存したら,5MBになった.WordPressはデフォルトでは30MBが上限になっているようだ.ただし,後でメディアライブラリをチェックしてみたら,ファイルはアップロードされていた(アップロードされているかもしれないという注意は出ていた).まぁ,それほど高画質の映像が必要な訳ではないので,これで十分だろう.スマホで撮影するのではなく,画面をそのままキャプチャできればよいのだが… ⇒多分,探せばフリーソフトで,あるとは思う.

アプリ終了するとき,「データは更新されています.保存しますか?」は不要⇒コラッツ特注版では基本的に保存機能はサポートされないのだから,このメッセージを出す必要はない.コラッツ木生成ツールからゼルコバの木を起動した場合,毎回新しいEXEが立ち上がるので,画面を閉じるたびにメッセージが出るのはうるさい.⇒対処した.

ゼルコバの木のデバッグモードでコマンドライン起動するような仕掛けを組み込んだ辺りから,何か,具合が悪くなっている.カスペルスキーが毎回複数の「脅威」を検出してくる.どういうタイミングなのかはわからないが,ユーザーフォルダのAppDataの中にEXEが複製ないし生成されていて,それをカスペルスキーが「脅威」として検出するという事象だ.デバッグしようとしているEXEとそのPDBをVSが取り分けて実行しているということは考えられるが,毎回暗号化した一時フォルダに格納しているので,おそらく除外リストに登録しても効果がないのではないかと思う.⇒除外リストでフォルダが指定できればよいのだが…

ともかく,VS2017を修復インストールしてみよう.以前にも似たようなことはあったが,そのときは修復で収まっていた.

アドレス変換でアドレスコードが間違っているためエラーになったときにも,エクスポートパネルが表示される.⇒対処した.

▲エクスポートパネルからゼルコバの木を立ち上げたとき,系図画面の位置を覚えていない.⇒外付けモニターで閉じた場合は記憶されている.いや,今度は覚えていた.⇒また,戻ってしまった.この配置はドッキングモードの位置とサイズに似ている.

分岐枝リスト空の状態でAddress to numberを実行し,ZTをオープンして「インデックスが範囲を超えています」というエラーになった.⇒「分岐枝リスト空」という状態はノード1を意味している.出力フレームには「1」が表示されているので,動作的にはこれで正しいはずだ.しかし,CollatzNumber.csvの中身は空になっている.幹線木でも同じエラーになる.⇒分岐枝リストが空の場合は無処理でループから離脱している.ダンプリストへの出力はループの外で実行しているため,「1」が表示されているが,CSVファイルへの出力はループ内で実施しているため,無動作になっている.⇒対処した.

▲IDEをクローズボックスで閉じようとして例外が発生した.このパネルは前にも出ている.

image

コマンドライン引数を与えてデバッグする

コラッツ木生成ツールとゼルコバの木が一体化し一つのアプリのように連動するようになった.これはとても重要な一歩だが,あちこちで不具合も見られる.ともかく,このような使い方をすることに決めた以上使えるようにしなくてはならない.一つづつ潰してゆくことにしよう.

まず,系統並び替えの入口で基準ノード番号が0になっているという点から見てゆくことにする.これは結局,基準ノード番号の初期値が未定ということを意味していると考えられる.

通常系図データファイルには基準番号が保存されているので,それを取り出せば済むことだが,インポートした場合にはどこでそれを決めたらよいのだろう?⇒CSVファイルをファイル→隣接リストのインポートで読み込んだ場合には問題なく動作している.つまり,コラッツ木検定から直接ゼルコバの木を起動した場合にだけ起きる不具合だ.ノーマルなインポート手順と比較してどこか抜けているのだろう.

コラッツ木検定からゼルコバの木を直接オープンする場合はコマンドラインで引数が渡される.このようなコマンドラインからの起動は,「ファイルオープンテスト」でも行われているが,特に問題は起きていないように思われる.MDIForm_Loadの出口でコマンドラインを処理していところで,OpenFileProc(, OPENMOD.FULLIMPORT)の戻り値をCurrefnumに格納するようにした.

小さいサンプルでは問題は起きていないが,高さ60くらいになるとスクロールバーと実際の図面が合わなくなる.しかし,ズームなどの操作で画面を更新した後は,問題なく描画できる.⇒ズームアウトで縮小表示すると正常描画されるが,拡大方向ではまだおかしな図形が出てくる.人名枠は表示されても名前が出なかったり,一部の枠線が描画されなかったり.クリッピングの問題である可能性は高いような気がする.「再描画」を実行しても変化しない.⇒ウィンドウサイズを変えると正常に戻る.何かもう一つアクションが足りていないように思われる.

おかしい.リリース版に戻したらまた「基準ノード不在」が出るようになった.ツールの動作にもおかしいところがある.アプリを開発環境から起動して,インポートを実行した後,アプリを終了しても開発環境に制御が戻ってこない.また,エクスポートパネルはTopMostで実行しているのに,アプリ終了できてしまうというのもおかしい.⇒メインフォームをTopMostにしていたためだ.しかし,修正してもアプリ終了で制御が戻らないという現象は変わらない.

エクスポートパネルをHideで閉じていたので,Closeに変更したが,変化しない.FormClosedイベントは処理されているのだが…FormClosedの中で明示的にEndを実行することで正常終了できた.

基準ノード不在はOpenFileProcを実行する前に発生している.しかも,その後,OpenFileProcは2度呼び出されている.最初はmode=0,つぎにmode=2で呼び出される.mode=0はOPENMOD.ORDINARYだ.どこから呼び出されているのだろう?⇒TREEVIEW::GetScrollValueではフェーズがDRAWSTAGEのときはTopologicalSortを呼び出すようになっているが,CHAOTICSTATE未満では呼び出さないようにした.これで初期起動のときTopologicalSort呼び出しが重複するのは回避できるようになったが,今度はインポートのとき.TREEVIEW::GetViewSizeでbasenum=0で停止するようになった.この辺りはDLLを並行してデバッグできないと手も足も出ない.

.NETアプリとDLLを同時にデバッグするということは可能だろうか?しかも,一方はVS2019で他方はVS2017だ.2つのプロジェクトを完全に合体させて一つのソリューションに仕立てるということも場合によっては不可能ではないとは思われるが… .NETアプリは別として,EXEをコマンドプロンプトから起動してデバッグすることは可能なのではないか?⇒VBのプロパティ→デバッグ→開始オプション→コマンドライン引数で引数を渡すことができる.これは便利だ!これでコマンドライン起動時も完璧にデバッグできる.

上記のGetViewSizeのエラーは,GetScrollValueの中で起きている.このエラーを無視しても動作上特に問題は見られないので,入口でゼロ復帰するようにしておく.OpenFileProcが2度呼びされるというのは,MDIParentのロード時に,OpenTestでない場合にはInitFileを実行しているためだ.この処理は,ZELファイルのアイコンをダブルクリックで起動した場合に必要となるため,省くという訳にはゆかない.OpenTestはコマンドライン引数にディレクトリが入っているので識別できるが,ダブルクリックの場合には拡張子を見るしかない.

インポートの場合はInitFileを実行しないようにしてOpenFileProcの二度呼びは回避できるようになったが,結果はなお悪い.51725のコラッツ数列で5点のチェーンになるはずが,後ろ半分が千切れている.InitFileの中には何か必要な処理が入っているようだ.⇒副作用としては新規カードを一枚初期表示するというだけのなので,ここのところを詰めるのは後回しにしておこう.

画面外の部分が描画できないという問題は,インポートだけでなく,ダブルクリック起動の場合にも起きている.かなり厄介な問題だ.しかし,メニューコマンドからのインポートや保存したZELファイルのオープンなら問題なく開けているので,何か些細な漏れがあるものと思われるのだが…⇒何か,画面が暗幕のようなもので遮られているような感じだ.初期表示されていない部分をスクロールで見えるようにして,マウスドラッグで拡張選択しようとしても選択枠線を描画することができない.しかし,描画できている領域から始めると選択矩形をドラッグに従って描画できる.しかも,このとき「不可視領域」までの選択矩形が入り込んだ途端,すべての図形が見えるようになる.謎としか言えない.

何が問題かと言えば,「コントロールサイズ」だろう.コントロールサイズは基本的に系図外枠サイズに一致しているはずなのだが…

▲ZTの実行中,開発環境を落とそうとしてフェーズエラーが発生した.

image

その後,プロジェクトを1/5アンロードしたところで例外が発生した.

image

System.ArgumentException: 値が有効な範囲にありません。
    場所 Microsoft.Internal.VisualStudio.Shell.Interop.IVsSolutionBuildOrderPrivate.GetBuildOrderList(Boolean fForceRecalculation, UInt32 cProjects, VsProjectBuildOrder[] pBuildOrder, UInt32& pValidationId)
    場所 Microsoft.VisualStudio.ErrorListPkg.Shims.TaskListBase.RecalculateProjectRank()
    場所 Microsoft.VisualStudio.ErrorListPkg.Shims.TaskListBase.OnEntriesChanged(Object sender, EntriesChangedEventArgs e)
    場所 Microsoft.VisualStudio.Text.Utilities.GuardedOperations.RaiseEvent[TArgs](Object sender, EventHandler`1 eventHandlers, TArgs args)
— 直前に例外がスローされた場所からのスタック トレースの終わり —
    場所 Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)

デバッグ中にシャットダウンしようとしたのが悪かったのかもしれない…⇒どうも,かなり状態が悪くなっている.VS2017が立ち上がらなくなってしまった.⇒シャットダウンして再起動で立ち上がった.カスペルスキーから2件の「脅威」を検出したという警告が出た.

image

「ユーザに損害を与える目的で悪用される可能性のある正規のソフトウェア」というのはこれまでも何度も出現しているが,今回のは捕獲された場所がマイクロソフトの管轄域であるというところが違う.いずれもZelkovaTree2022.exeで作成時刻は午前1時36分.開発用フォルダに残っているEXEはリリース版が23:00,デバッグ版が23:37でそれより後に作られている.捕獲場所には同じ時刻に作られたPDB(シンボルファイル)も入っている.「解決」ボタンで削除できないため,「駆除して再起動」になった.カスペルスキーはこれを「特別な駆除」と呼んでいる.再起動すると以下のパネルが表示された.

image

このパネルはいつも「特別な駆除」の後に出てくるようだ.これを閉じると,今度はカスペルスキーの完全スキャンが始まる.2TBの外付けHDDが接続したままなので丸一日掛かるかもしれない.カスペルスキーのスキャンはウィンドウを閉じてもバックグラウンドで実行を続けるので一旦閉じておこう.一応捕獲場所をチェックしておこう.⇒一つはフォルダごと削除されているが,もう一つはProjectAssemblyフォルダの中にPDBが残っていた.⇒障害が再現できるかどうかやってみた.デバッグを開始して,ZTがCSVをインポートした後,開発環境をクローズボックスで閉じるという操作だが,問題なく閉じることができた.

MDIForm_Loadでコマンドライン引数で実行するところの論理を少し整理して見通しよいものにしておきたい.できれば,すべてを一つのOpenFileProcの中で処理したいのだが…

▲OpenFileProcではMakeNewObjectで毎回Child配列を初期化しているが,不要なのではないか?ClearChildで間に合うはずだ.

初期表示された画面上のカードをクリックないし選択することでノーマルな状態になる.これはどういうことだろう?カードのクリックというのはOCXに入り,そこから折り返してVBに戻るという動作になっているはずだから,OCX側からの何かしらの応答が必要ということではないだろうか?再描画というのは逆にVBからOCXへの伝達になるので,何の効果もないのではないか?⇒系図画面上でクリックイベントを発生させれば,擬似的に動作するのではないか?

コラッツ木生成ツールから直接ゼルコバの木にエクスポートする

コラッツ木生成ツールから直接ゼルコバの木にエクスポートできるようになった.「隣接リストをエクスポート」オプションをオンにしておくと,メッセージパネルが開いて保存先のファイル名を表示するようになっている.このパネルにボタンを追加して『ゼルコバの木』を起動し,コラッツ木をその場で確認できるようにした.これはかなり楽しい.

image

しかし,これができるようになったために,いままで隠れていたボロが一挙に噴き出してきた.たとえば,59871のコラッツ数列生成では88点の系図が出力されるが,画面の大部分が真っ白になってしまう.アドレス変換ではこれを逆順に出力しただけのものだが,こちらは正常に表示されている.幹線木では262点のグラフになるが,やはり大部分は真っ白になっている.これは多分,横書きの問題ではないかと思われる.⇒いや,縦書きにしても同じ現象が起きる.これはかなりまずい.

どこかで描画領域の管理に失敗しているようだ.縦書きの場合,画面では最上層が表示されているのに,スクロールバーのノブはボトムの位置にある.スクロールバーを上に上げれば画面は真っ白になってしまう.しかし,アドレス変換では同じものが問題なく描画できているので,問題はゼルコバの木本体ではなく,インポート処理の部分にあるように思われる.データ自体はいずれの場合でも問題なく読み込まれているようだ.⇒いや,データ自体がおかしくなっている可能性がある.ZELで保存して再読み込みしても同じ現象が起きる.

いや,今度は読めた.何か操作を誤っているのだろうか?⇒少なくともアプリを一度落として再起動してやればZELファイルを読み込むことができる.インポートした直後に読み込んだ場合は,画面が更新されていないという感じだ.リリース版の動作を確認してみよう.今度はインポートしたときに,「基準ノード不在」というエラーが出るようになった.⇒アプリからZTを起動してインポートするのではなく,CSVをZTのインポートコマンドで読み込むようにすれば何の問題も起きない.⇒なぜだろう?完全に問題なく動作するようになった(「基準ノード不在」というエラーは残っている

縦書きでは問題は解消しているが,横書きのコラッツ数列ではまだ前方が白紙になる.⇒画面の描画領域の問題である可能性はある.確かに大きい図面だとメモリ描画環境でメモリ不足が生じて生描画に切り替わる場合がある.一度「画面に合わせてズーム」まで縮小するとその後は拡大しても描画上の問題は発生しなくなるようだ.メモリ描画環境の操作に関わりがあるような感じもする.少なくともデータ(読み込み)の問題ではない.⇒系統並び替えの入口で基準ノードが0になっている.



「拡張コラッツ問題」は一般には成立しない

前稿(2022/04/06)には,2つの式が記載されている.

ノード番号:={長子ノード番号}.{兄弟順位}      (1)
長子ノード番号:={親ノード番号}.{長子識別子}    (2)

これら2式が正しければ,

ノードN:={地番1}.{地番2}.{地番3}…{地番k}

のようなアドレスコードが可能となり,すべての自然数はその内部にコラッツ木の(暗号化された)アドレスコードを持っているということになると予測される.前稿ではこれら2式について,

『(1)式はNの4進数表記からデコードされ,(2)は3N+1の2進数表記によってデコードされる.3N+1という計算は3進表記した値を1左シフト(した上で1をプラスする,つまり1を右端に連結)することによって得られるから,「演算(代数的操作)」というよりは,「文字列操作」として(形式的に)実行可能であると推定される.』

としているが,果たしてそう言い切れるのだろうか?『(1)式はNの4進数表記からデコードされる』という部分は,3月3日付けのログ「コラッツ国の公用語は4進数である」で説明しているように,ほぼ確実であると言えるが,『(2)は3N+1の2進数表記によってデコードされる』とすれば,以下のような類似問題が成立することが予想される.

拡張コラッツ問題:kを任意の奇数(定数)であるとする.任意の自然数Nについて,Nが偶数ならば2で割り,奇数であればk倍して1を加える操作を反復すると,かならず1に帰着する

この問題は,Wikiの「コラッツの問題」というページの「類似の問題」という項目に以下のような形式で採り上げられている.

「任意の正の整数 n に対して

  • n が偶数の場合、n を 2 で割る
  • n が奇数の場合、n に 2m – 1 (m ≥ 1)をかけて 1 を足す

という操作を繰り返すと、有限回で 1 に到達する」

m=1の場合,この命題が成立することは容易に示すことができる.m=2の場合がコラッツ問題だが,m=3の場合,つまりk=5の場合には

13→ 66→ 33→ 166→ 83→ 416→ 208→ 104→ 52→ 26→ 13

のような反例が存在し,成立しない.つまり,「拡張コラッツ問題」は一般には成立しない.上記数列から偶数を除去すると,

13→ 33→ 83→ 13

これを5進で表示すると,23, 113, 313 となる.これらの数字に左シフト+1の操作を施すと,

231, 1131, 3131

のような5進数が得られる.これを10進表記すれば,66, 166, 416 だから,確かに循環している.これをどう解釈すればよいのだろう?少なくとも,k=5の場合には,(2)式のようなものは成立していないことは確かだろう.そもそもk>3の場合に,「長子木」のようなものが構成可能であるかどうかは,まったく自明ではない.というか,おそらく,k>3の場合には「長子木」のようなものは存在していないのではないだろうか?逆に言えば,長子木のようなものが構成可能であるのは,k=3の場合に限定されるのではないだろうか?いずれにしても,「長子木とは何か?」ということが追求されなくてはならないだろう.

Wikiには「コラッツ予想の他の形式」として,「ボトムアップ方式」という提案が記載されている.「ボトムアップ方式」というのは,いままさに我々がやっている方式そのもので,コラッツ写像の逆演算からボトムアップに木を構成しようとする試みである.この記事では21ステップまでのコラッツグラフのSVG画像↓が紹介されているが,この図版の数値は偶数を含むものであるため,かなり狭い領域しか表示できていない.「完全正則」という概念にも達していないため,証明にはまだほど遠い段階にあり,「予測」の域を脱していない.

image

拡張コラッツ問題で生成されるようなグラフを拡張コラッツ木ないし,k-コラッツ木と呼ぶことにしよう.上記で見たようにk-コラッツ木は必ずしも「木」にはならないが,そのトポロジーがどのようなものになるのかは興味がある.しかし,ここではこれ以上深入りしないで,先に進むことにする.さて,懸案の仮想木上の拡張アドレスコードに掛かることにしよう.本システムでは偶数は扱わないとしたので,非長子ノード用の書式を追加するだけだ.

区切り文字として「:」を追加する.完全木では区切り文字として,3倍数には「-」を割り当て,2倍数(偶数)を識別するために「*」を追加しているが,「:」と「-」は方式的にはかなり異なる.{x-y}は{x}-{y}であり,「-」で区切られた2つの枝番(XとYは親子関係)だが,{x:y}は全体で1個の一般木上の枝番(x:y)を示している(XとYは兄弟でXはコラッツ数列には表示されない).

B面ではMax branchesという値を表示している.拡張アドレスの場合はどういうことになるか?仮想木上にないノード(非長子ノード)の枝番は無視するしかないのではないか?というか,長兄ノードは仮想木上にあるので,その枝番を適用でよいと思う.というか,それしか方法がない.幸い非長子ノードはつねに終端に来るので問題ないだろう.⇒とりあえず,アドレス→番号変換は動作するようになった.

幹線木にも対応修正を入れておこう.幹線木をどう英訳するかでいろいろな候補が挙がっている.①Truncated tree, ②Stem tree,③Minimal regular tree などなど…Nを含む極小な正則木という意味では,③が一番正確であるような気もするのだが…Stem treeでも悪くないような気もする…幹線木というオプションが存在する意義自体がよくわからないという向きには,「極小正則木」という命名は説明になっているような気もする…⇒幹線木も動作している.あとは,コラッツ数列だけだ.

既存コードの出力は,仮想木上の経路だけで止まっている.たとえば,非長子ノードの19397では

4849    19397
227 (2)    3637 [2]
5 (3)    341 [3]
1 (1)    1 [4]

が出力される.左列が仮想木,右列が一般木だが,左列にはターゲットの19397は表示されていない.19397の仮想木上の経路は1. 3. 2:1で,アドレス変換では

1 [1]
5 [3]
227 (2:1)
19397

のように表示される.これを天地逆転したものが表示されるようにしなくてはならない.つまり,

19397
227 (2:1)
5 [3]
1 [1]

のようにならなくてはならない.⇒大体動作するようになった.

▲幹線木でアドレスに1. 2. 2. 2:1を設定すると,206277の代わりに825109という数字が出てくる.この数字は少なくともダンプ出力の中には見当たらない.successorという変数におかしな値が入ってくる.ループの中で余分なことをやっているようだ.幹線木ではDumpSuccessorsで実行している処理をループ中で重複実行していた.

隣接リストの内容をチェックしておこう.⇒アドレス変換はよいが,他の2つは間違っている.


どうもまだ方針がぐらついている

どうもまだ方針がぐらついている.完全木という構想を捨てて仮想木に絞り込んだ積りだが,完全木には完全木の優位性があり,仮想木にもそれなりの弱点がある.これは結局,「三本桜」という方針が正しかったということを意味するのではないか?というか,どこかでポイントを見失っているのではないだろうか?目標は何か?それをまず確定する必要がある.これまで得られた知見の中でもっとも重要なポイントはノード番号の4進数表記の中には,親から継承したDNAコードと枝番号が埋め込まれているという点だ.これをアドレスコードの流儀で書き下せば,

ノード番号:={親から継承したDNA}.{枝番号}

のようになる.つまり,ノード番号は遺伝情報と枝番を「.」によって連結したコード(テキスト)であると言える.親から継承したDNAは長子ノード番号に等しいので,

ノード番号:={長子ノード番号}.{兄弟順位}      (1)

{長子ノード番号}の中には親番号が埋め込まれていると推定されるので,仮にそれが

長子ノード番号:={親ノード番号}.{長子識別子}    (2)

のように分解可能であるとすれば,

ノード番号:={親ノード番号}.{長子識別子}.{兄弟順位}

のように表示可能であることになるから,{長子識別子}.{兄弟順位}を{地番}と置いて,

ノード番号:={親ノード番号}.{地番}

のようになり,これを再帰的に展開すれば,

ノードN:={地番1}.{地番2}.{地番3}…{地番k}

のように分節できる可能性がある.つまり,自然数Nをある適切な方法で暗号解読できれば,自然数Nを直接一般コラッツ木上のアドレスコード(ないしそれと等価なある表現形式)に変換できることが期待される.(1)式はNの4進数表記からデコードされ,(2)は3N+1の2進数表記によってデコードされる.3N+1という計算は3進表記した値を1左シフト(した上で1をプラスする,つまり1を右端に連結)することによって得られるから,「演算(代数的操作)」というよりは,「文字列操作」として(形式的に)実行可能であると推定される.このような解析を行う上で有効なフォーメーションとは何か?ということが問題になるが,ともかく,仮想木上で定義された汎用アドレスシステムの実装という仕掛りの作業を片付けておくことにしよう.

以前拡張アドレスコードを実装したときは完全木を対象としていたが,今回の仮想木上のアドレスコードの書式はそれとはやや異なるものになっている.前回の方式では1.2-1というアドレスコードでは

1 [1]→ 5 [2]→ 53 [-1]→ 141

のようなコラッツ数列が出力されていたが,今回方式で{1.2/1}とした場合には,

1 [1]→ 5 [2]→ 113(1)=453

のような動作になる.つまり,5の2番目の長子ノードである113は出力されず,直接非コラッツ数である453が出力されるようになる.既存論理で,453のコラッツ数列を求めると

113    453
5 (2)    85 [2]
1 (1)    1 [3]

が出力され,枝番号リストには{1. 2}が出力されるので,これをアドレス→番号変換すると113という答えが返ってくるため,デュアルな動作になっていない.これはもちろん,{1.2/1}→ 453→ {1.2/1}とならなくてはならない.従って,コラッツ数列取得では

453    453
5 (2/1)    85 [2]
1 (1)    1 [3]

が出力されなくてはならないだろう.この場合,区切り文字の「/」は以前提案されたように「:」とした方が(私の主観だが…)むしろわかり易いかもしれない.つまり,

453    453
5 (2:1)    85 [2]
1 (1)    1 [3]

のようになる.アドレス⇔番号変換ならば,{1.2:1}→ 453→ {1.2:1}となる.この方が読み易いような気がする.また,以前にも示唆しているところだが,本システムでは最終的に「偶数」は扱わないということにしたい.この制限によっても特に不都合が生じることはないと思う…既存コードでCore treeモードで検証テストを実行して出力される隣接リストはかなりあいまいなものになっている.つまり,望むような結果になっていない(と言うより間違っている).これは上記のような「辻褄の合っていないところ」が存在するためと考えられる.多分,これは上記のようなアドレスコードの導入によって改善されるはずだ.

「三本桜の復活」→「銀河系の再構築」

「三本桜の復活」を止めて,「銀河系の再構築」に方向転換した.一般的なアドレスコードは,コラッツ木のルートノード1からノードNまでの経路上の枝番号の並びを「.」で連結したテキストとして表記される.一般アドレスコードによって任意の自然数のコラッツ木上の位置を一意に決定することが可能だが,このアドレッシングには無効な枝番の並びが生じるという欠点がある.つまり,一般木上では3倍数が終端ノードとなってしまうため,完全正則木を構成することができない.

コラッツ木から3倍数を除去した完全木ではこのようなことが起きないので,完全正則な木を構成できる,つまり,任意のアドレスコードとノード番号に1対1の対応を付けることができるというのが「完全木」を導入した理由である.しかし,3倍数を除去することによって生じるコラッツ木上の空位とアドレスコードの対応は必ずしも自明ではない.仮想木の場合は仮想木上の位置とノード番号の関係は明確に定義されているのでむしろ対処し易いのではないか?と考えられたので急遽方向転換し,汎用アドレスコードを仮想木上で再定義することにした.完全木上のアドレスコードは以下のように定義されていた.

a.b.c….x-y*z a, b, c, … x, y, z は正の整数

a, b, c…, x は完全木上の枝番を示す1以上の整数で,a.b.c….x のような地番表示によって完全木上の任意のノードの位置を示すことができる.完全木は一般木から3倍数を除去したグラフであり,3倍数の位置を示すためには x-y のような構文が用いられる.これは3倍数Mが親ノードa.b.c….xのy番目の3倍数であることを示している.2倍数(偶数)を表記するためには,y*zの構文を用いる.これは,2倍数Eの親ノードをPとするとき,M=P*2^zの関係が成立することを意味している.完全木上のノードではない数を表記するために使われるx-y*zのような構文を「詳細付番」と呼んでいる.仮想木上のアドレスもこれに準ずる.

  1. コラッツ木上で共通の親を持つノードを兄弟ノードとし,兄弟ノードのうち最右に位置するノードを長子ノードとする 長子ノードはコラッツ数と呼ばれることもある
  2. 仮想コラッツ木はグラフの連結性を維持しながら,兄弟ノードを長子ノードに合併・縮約することによって得られる一般コラッツ木の簡約グラフである 仮想木上の(1を除く)すべてのノードは長子ノードである
  3. コラッツ木上のノードの位置を特定するためのアドレスコードは仮想木をベースとして定義される
  4. アドレスコードはルートノード1からノードNに至る経路上で経由する枝番号(兄弟順位)の並びを「.」で連結したテキストである
  5. ルートノード1を表記するアドレスコードは空文字列{}である
  6. ルートノード1以外の任意のノードNを表記するアドレスコードはつねに”1”で始まる アドレスコード{1}はノード5を示している
  7. 仮想木上に存在しないノード(非コラッツ数)には①非長子(奇数)ノード,②偶数ノードの2種がある 仮想木に非コラッツ数ノードを追加したグラフを拡張コラッツ木とする
  8. 非長子ノードUのアドレスは x/y のように表記する ここで,xはUの長兄ノードの枝番号(仮想木),yはUの属する兄弟枠の中の兄弟順位(一般木)である {x/y}は{x}というパスを含まない つまり,{x/y}で一つの「拡張木」上の枝番を表示する
  9. 偶数ノードEのアドレスは !z のように表記する ここで,Eの親ノードを奇数Nとするとき,E=N*2^zであるとする 奇数Nはコラッツ数である場合とそうでない場合がある {!z}で一つの「拡張木」上の枝番を表示する

たとえば,{1.2.3.4/2.!3} は 1[1]→ 5[2]→ 113[3]→ 4835[4]=6601841(2)→ 17604909*2^3→ 140839272 のようになる.コラッツ数列として表示すれば,

140839272→ 17604909→ 6601841→ 4835→ 113→ 5→ 1

である.既存ツールで17604909のコラッツ数列を求めると,以下が出力される.

4401227    17604909
6601841 (1)    6601841 [2]
4835 (4)    4951381 [1]
113 (3)    7253 [6]
5 (2)    85 [4]
1 (1)    1 [3]

この出力では,左列が仮想木,右列が一般木のコラッツ数列となっている.⇒なるほど,確かにこれが仮想木の欠点かもしれない.上記の拡張アドレスコードを使えば,次のような出力になる.

17604909 17604909
6601841 [1]    6601841 [2]
4835 (4)    4951381 [1]
113 (3)    7253 [6]
5 (2)    85 [4]
1 (1)    1 [3]

もし,ここで仮想木ではなく完全木を用いていれば,右列と左列は完全に一致していたはずだ.完全木上には3倍数が存在しないから,3倍数を通過点とするコラッツ経路は存在しない.従って,一般木と完全木はアドレッシングに関しては(3倍数を含めてもほぼ)完全に一致すると考えられる.確かにこれは完全木のかなり大きなアドバンテージであるように思われる.やはり,考察から完全木を(完全に)排除することはできないのではないか?必要なのは,むしろ完全木と仮想木がどのように対応しているかを見ることではないだろうか?それが解明できれば,一般木と仮想木の関係についても自ずから明らかになるのではないか?