コラッツ完全木検定と呼ぶことにする

画面要素が確定していよいよコラッツ中核木に掛かるという段階だが,もう少しだけ考えてみたい.ゼルコバの木コラッツ特注版は基本的に保存機能を持たないビューアとしてリリースするつもりなので,画面にコラッツ木を表示するためには毎回CSVファイルをインポートしなくてはならない.出力される5種のCSVファイルにはそれぞれ固有の名前が付せられているが,中核木と一般木を区別することができないのはかなり不便かもしれない.これを避けるために,たとえばCollatzTree.CSVであれば,CollatzTree.Core.CSVなどのようなサフィックスを付けることが考えられる.これは大した手間ではないのでやっておこう.

Truncated treeというのも少し意味不明なので,Stem Treeという名称に変更することにする.日本語でも幹線木という呼び方をしているので,この方が実態に即しているのではないかと思う.trucated treeをstem treeと呼ぶことにすると,今度はStem treeとCore treeの混線が生じる可能性がある.この意味では,やはり,Core Treeではなく,Complete Treeの方がよいのではないか?ラベル上の問題なので後回しでもよいところだが,どういう印象になるか確認してみたいので,修正してみよう.「コラッツ完全木検定」というのが製品の正式名称だ.

もう一つ,Collatz sequenceの出力は倒立木として表示したい.これはルートである1が最下段になるような図式だが,コラッツ数列を模式化した場合には1が最下部になるような図になることが多いためだ.Collatz sequenceの出力とAddress to numberの出力が完全に同じになるというのはあまりおもしろくない.やはりこの2つは完全な逆演算になっていなくてはおかしい.あとは,branch order sequence が tree address=tree locationに他ならないという説明を加えるだけでシステムの全構図を把握できるだろう.

いや,locationという用語を用いないで,最初からaddressでもよいのではないか?IP addressという用語はすでに十分浸透しているので,そこから類推できると思う.⇒Collatz sequenceの出力を倒立木として表示するという修正は簡単に終わった.いよいよ本線の修正に入る.3倍数を取り除くというのは難しくないので,それほど掛からないのではないかと思う.古いロジックは参考にはなるが読解の妨げになるので,除去してしまうことになるだろう.CompleteTree

▲GetPageCountでエラーが出る

▲完全正則で左右対称なのに吊り位置にずれが出る.

少しややこしい問題が出てきた.コラッツ木生成を完全木対応に書き直すのは容易にできた.コラッツ数列の場合は開始ノードを奇数Nとすると,Nがどのような値であれ,1に至る経路は必ず存在する.この経路上には3倍数は登場しない.従って,コラッツ数列取得では完全木モードと一般木モードの動作は一致する.うまり,同じ関数で処理できる.しかし,その逆演算は必ずしも可能ではない.

たとえば,3倍数15のアドレスは一般木上では1.3.1.1.1と表示されるが,完全木上には15というノードは存在しない.銀河系ではこのような状況をどう始末してきたのか?銀河系ではコラッツ数列取得に限り,仮想木と一般木を併置する形式になっている.15の場合であれば,以下の2つの経路が提示される.

15 23(1) 35(1) 3(2) 5(1) 1(1)
15 23[1] 35[1] 53[1] 5[3] 1[1]

枝番号変換ないし幹線木図では上の2者のうち前者だけが採用され,純仮想木としての計算を実行する.やはり,これしかないのではないだろうか?仮想木上でアドレス(1.1.2.1.1)を適用すると,15が表示される.ただし,これは15が仮想木上の実ノードであるためであり,つねにこの逆演算が可能という訳ではない.たとえば,N=45の場合,

11 17(1) 3(1) 5(1) 1(1)
45 17[2] 13[1] 5[2] 1[1]

が併置されるが,仮想木上のアドレス 1.1.1.1で枝番号変換を実施すると,結果は45ではなく,11が表示される.完全木にもこれに類似した仕組みを導入するしかないが,仮想木の場合には,45と11の関係は比較的はっきりしている.11は45の兄弟ノードのうちの長子であるので一意に決定することができる.しかし,完全木には3倍数以外のすべての兄弟ノードが含まれているので,代替ノードを指定するというのもかなりあいまいなものになる.考えられる対応策としては,直近の兄ノードを指定のような感じだが,場合によっては兄がいない場合も考えられる.

代替案としては,たとえば,親の子ども枠の中に現れる3倍数の順序で決めるということも考えられなくはない.たとえば,最初の3倍数であれば0,2番目であれば-1,5番目であれば-4のような負の枝番号を与えるということが考えられる.このような標識があれば,そのコードから厳密なノード番号を割り出すことも不可能ではない.ただし,このような0以下の枝番号は完全木のアドレスコードの終端に現れることはあっても,中間には出現しない.仮にこのようなコードを使うとすれば,3倍数用の枝番号は0発進よりは-1から始めた方がよいかもしれない.

しかし,完全木モードで完全木の経路を扱っているところに一般木経路が潜り込むというのもあまり芳しくないような気がする.むしろ割り切って枝番号0を与えるというのでもよいのではないか?たとえば,上の45の例で言えば,下記のようになる.

45 17(0) 13(1) 5(2) 1(1)
45 17[2] 13[1] 5[2] 1[1]

完全木上では17→45という枝は存在しないことを17(0)で示している.アドレスコードでは1.2.1.0となるが,最後の0は評価できないので,親ノードの17で止まることになると思われる.これは已むを得ないのではないだろうか?仮想木経路と完全木経路の相違点は,前者では一般木経路から大きく迂回するような経路があり得るのに対し,完全木の場合は終端との接続ポイントを除けば一般木と完全木の経路は完全一致するという点だ.しかも,このようなことが起こるのは3倍数に限定されているのだから,割とわかり易いのではないだろうか?大体これでよいのではないかと思う.コラッツ数列取得処理ではほぼ一般木の論理がそのまま使えると考えてよいだろう.

しかし,3倍数に関しては負の枝番号を与えるというのもそれほど悪いアイディアというものでもない.仮にこれが導入されると,コラッツ木上のすべての奇数にユニークなアドレスを与えることができるようになるからだ.これは悪くないのではないか?確かにやってみる価値はあるような気がする.ただし,一つだけ問題がある.コラッツ完全木が完全正則木であるとすれば,本来そこに含まれないノードのアドレスを与えたとき,どのような図面が描画されるのだろう?

  1. コラッツ木生成では本来の完全正則木しか描画されない
  2. コラッツ数列取得と枝番号変換処理で出力されるコラッツ木はチェーンであり,その終端に1個3倍数を追加してもあまり問題ではない
  3. 幹線木図ではどうなるか?幹線と言っているのは,上記のチェーンであり,それらに枝数分の葉を追加しただけのものだから,問題はない.幹線木図の終端ノードはつねに単独で枝を持たないのだから,それが3倍数であっても特に問題ない
  4. 検証テストはどうなるか?検証テストはコラッツ数列取得と枝番号変換処理を組み合わせたものであり,この両者が動作すれば動作可能なはずだ.対象ノードから3倍数を除去した部分だけテストしてもよいが,もし可能なら全点テストする方がよい.多分それは可能だと思う.

これで,3倍数を間引かないで全点テストできる可能性がでてきた.この方が望ましいと思う.ただし,論理が多少込み入ったものになることは避けられない…アドレスを以下のように表記することは可能だ

1.2.3.4.5-6

この方式なら枝番号に負値を与える必要もない.最後の-6を負値と解釈してもよいが,その意味するところは「親ノードの6番目の3倍数」ということになる.1, 2, 3などの(正の)数は3倍数でないノードだけを数えた枝番号,-6は3倍数だけを数えたときの枝番号ということになる.

ただし,Splitという関数はこのような複合的な書式を扱えないかもしれない.どこかでそういうことをやった記憶はあるのだが…PythonやC#にはあるようだ.VBのSplit関数にはこの機能はないが,Replaceを使って文字列を置換して区切り文字を統一するという方法がある.ただし,どこに「-」記号が入ってくるか分からないので,やはり,別途調べるしかないかもしれない…⇒昔C++でやっていた.どこかからコピペしてきたものと思われるが,list<string> split(string str, string delim)という関数を使っている.

list<string> split(string str, string delim)
{
     list<string> result;
     int cutAt;
     while ((cutAt = str.find_first_of(delim)) != (int)str.npos ){
         if (cutAt > 0) { result.push_back(str.substr(0, cutAt)); }
         str = str.substr(cutAt + 1);
     }
     if (str.length() > 0){ result.push_back(str); }
    return result;
}

アドレスコード的には上記の方式がスマートだが,こだわらなければ下記が最短だ.

1.2.3.4.5.-6

これなら現行論理でも簡単に分離できるし,数の正負を見るだけで判定できる.これでよいことにしよう.これで行けるとすれば,次のような方法も考えられる.UI的には上記方式で行うものとし,内部で「-」を[.-]に変換した上で通常のようにSplitすればよい.これが一番スマートなのではないか?しかし,ユーザの混乱を避けるという意味からすれば,やはり,区切り文字は「.」に限定し,数字の正負で判定というのが正しいような気もする.(説明もこの方が簡単だ)まず,コラッツ数列取得から始めよう.3倍数は終端にしか現れないから,完全木と一般木で同じ論理の使い回しができるのではないか?

とりあえず,コラッツ数列取得はできた.次は枝番号→番号変換だ.⇒いや,まだできていない.一般木の枝番号を使っている.やはり関数を分けた方がよいのではないか?⇒一つの関数で間に合いそうだ.枝番→番号変換まではできた.幹線図はどうか?⇒大体終わった.検証テストも動作している.ただし,3倍数の一部の脱落が起きている.どうも隣接リストの操作に不備があるように思われる.あるいは,コラッツ数列と枝番号の受け渡しに問題があるのかもしれないが…

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA