Λ値が周期桁数と完全一致するようになった

ユーザがR値を変更して,離散対数を求めることが一応できるようになった.ここまでやったのだから,Rをテキストボックスから数値ボックスに変えるところまでやってしまおう.現在ユーザが設定可能なパラメータは4つあり,すべて数値ボックスになっている.数値ボックスの利点は,①UpDownボタンが使えること,②数値が確定するまでイベントが発生しないというところだ.特に①は使い勝手にかなり影響するので,実用性を重んじるなら必須だろう.

離散対数にはまだあまり本格的に足を突っ込んでいないので,そこまでやるか?という感もあるが,踏み出した足を引っ込める訳にもゆかない.数値ボックスの弱点は最大でもInt64の範囲の値しかとれないという点だが,今のところはそれで十分だろう.Rには現在pRtextという名前が付いている.これまではRの他にもαR,γRのという類似項目があったのだが,今回これらとは縁が切れたので別の名前で呼ぶことにしよう.とりあえず,valueRとしてみよう.

Rの設定値がγを超えても何の変化もない.⇒γ値を超えられないようにした方がよい.⇒対処した.

周期#がゼロとなるのは,ψα=φ(γ)となる場合に限られているのではないだろうか?これは横数列が(固定部を除き)0の並びになっている場合である.もちろん,(φ,#)=0である.⇒周期がゼロとなるのは,対象数αが除数(法)γで割り切れることを意味する.ただし,これはかならずしも α ≡ 0 mod γ を意味しない.α^ψ ≡ 0 mod γ となるような整数 ψ が存在すれば,周期数列桁#はかならずゼロになる.

周期数列桁#=0 の場合は,Λ値は不定であるとする.Λはφ(γ)の約数なので,除数ゼロとなってしまうからだ.また,Λは α^ψ ≡ 1 mod γとなるような最小ψ値と定義されているので,もし,Λ=0となることを許せば α^0 ≡ 1 mod γ がつねに成立してしまうので,Λ値は0しか取れないということになってしまうためである.

リターンキーを押しただけではR値は確定しない.Rは値が適合しない場合を許容しているためだ.ψの変化を見ていれば,Rが適合しているかどうかは判定可能だが,見落とした場合適合しているのか否かが分からなくなる.無効な値であることを何らかの方法で示す必要がある.一番確かなのは背景色を変えることではないだろうか?⇒実装した.とてもわかり易くなった.R値がグレー表示されている場合は,無効値である.このような場合にはコントロールパネルの「update」を押すことでノーマルな値に書き換えられる.

★Λ値は剰余数列が固定部をもつとき,そのときのみ不定になる.これは(α,γ)<>1であることと同値である.⇒この命題は間違っている.Λ不定≡(α,γ)<>1ではあるが,このような場合でも固定部0となるケースはある.α=182, γ=250では(182, 250)=2だが,固定部0:#4.従って,Λ値が不定であることと(α,γ)<>1は同値であるとしなくてはならない.⇒最終的にはΛ値不定というのは周期桁#=0の場合に限られることになった.それ以外ではつねに#=Λとなる.

psiの文字列をΛに一括変換した.113個が変換された.⇒変換しきれなかった項目が3つ残っていた.ついでにtotをφに変換した.61個あった.2005年のEFAではU-length function という用語と ψ値が並列に使われている.ようやくEFAからテイクオフできたのではないか?

ΦないしΛの約数列を参考表示する.⇒φ(γ)の約数リストを画面に表示するようにした.Λ値をその横に表示するようにしているので,Λがφ(γ)の約数であることが明瞭に示されるようになった.

ΛがΦの約数であることをべき剰余検定に応用できないだろうか?つまり,そのことを使って周期数列をより効率的に生成することはできないだろうか?しかし,Φ=γ-1になるときの#は#=Φとなるので,どっちみちγ-1の計算を実行するしかないのだが… 剰余数列をリストアップするのではなく,Λ数を取得するだけなら,Φを使うのは意味があるだろう.意味のない数ではないので,Φの約数リストを出力してみよう.φ(γ)として表示するようにした.Λが空欄になっている場合でも{φ(γ)}には#値は必ず入っている.従って,Λ=#とすることには合理性があると思われるのだが,べき剰余を直接計算して#を求めるのとは別の何らかの手段でΛを獲得することができなくてはならない.

手がかりになるのは(α, γ)値だが,これをどう適用すればよいのか?適用可能なのか?の手掛かりがつかめない.#がゼロという場合もある.このような場合には約数列{φ(γ)}の中に0は入っていないので,不定となることはやむを得ないと考えられるが,それ以外では#=Λでよいはずだ.(α, γ)がゼロでない場合には,αとγをこの値で割って既約にすることができる.このようにしても,既約のα’,γ’の対から生成される{φ(γ’)}の項は,すべて{φ(γ)}の中に含まれていると見られるので,既約対を用いれば,多少は問題を小さくすることはできそうだ.γが素数の場合は別として,γが大きな合成数である場合には,φ(γ)の約数だけをΛの候補とすることで計算を効率化できる可能性は十分あると思う.

Λ関数の引数でφを渡しているが,内部で再計算しているので不要だ.確かにループでαを変えながら複数回実行しているところはあるので,事前に計算しておいた方が有利だが,渡し方を間違える可能性があるので,冗長でも内部で計算した方がよい.⇒対処した.

現行のΛ関数はφ(γ)の約数をΛの候補として見ているが,R=1の場合しかチェックしていない.R=0になる場合,および固定部がある場合に対応する必要がある.

(α, γ)が1でないときは,互い素となるまでGCMでγを割り込んでゆくという方法が効果があるかもしれない.gcm=1ならば従来の方法で解けるので,得られたΛが共通パラメータとして通用する.⇒できた!完璧だ!おそらくこれは今回のセッションで得られた最大の収穫だ.⇒多分,証明はそれほど難しくないと思う.一度正しい命題が発見されれば,その証明は後から付いて来る.

α=77, γ=76のとき,Λ関数で停止した.α=76, γ=76,α=39, γ=76,α=31, γ=30でも.⇒逆手順になっていた.既約操作を実施した後で,互いに素のチェックをやっていた.

#=0の場合を除き完全にΛと#が一致するようになった.#=0ということは循環がないということなので,ある意味当然である.たとえば,α=17, γ=17など割り切れる場合にはそのような現象が起こる.

離散対数を求める問題

現在,3つの剰余値にR, αR,γRのようなラベルを付けているが,Rとそれ以外の剰余を区別するために,別の文字を割り当てることにする.αR,γR はいずれも数列の周期を表す数字なので,λを用いることにする.λは物理学では波長の意味で使われているので連想が効くのではないかと思う.一旦バックアップを取ってから修正に入ることにしよう.

記号文字の割当てに関してはこれで完璧ではないかと思う.これらはほとんど英文字一文字なので一括変換してすべてのテキスト出力を同期させておきたい.かなり大掛かりな修正になるが,整理してしまった方がよいと思う.⇒作業に入る前に記号の割当てについてもう少し考えてみよう.ψという文字は心理学では超能力を表し,量子力学では波動関数を表す.数学ではフィボナッチ数列の逆数和として使われている.

この意味ではψを剰余数列という波動を示す関数とみなすというのは外れていないとは思われるが,周期であるという点に注目すればむしろ,波長λの方が適切であるような気もする.この場合,αR,γRなどは位相と見るのが順当である.位相には,β,φ,ψが使われることが多い.この意味ではψ(α),ψ(γ)のような使い方が考えられる.未決の懸案事項として,#=ψとするかどうか?という問題があるが,とりあえず,n→α,e→γ,K→Θ,B→βのみ確定としてフィックスしてしまうことにする.

関数内部で同名の記号をローカル変数として使っている場合がある.→nはグローバル変数ではないのだから,差し支えないはずだ.n/Nで269個あった.コンパイルエラーは1件に留まる.b/Bは145個.k/Kは2件しかなかった.本当だろうか?⇒丸残りになっていた.205個出た.γはeとして使われる場合がある.しかし,eはイベントハンドラの引数にも現れるので注意が必要だ.ψ→Λも実行することにする.ψα,ψγも片付けてしまうことにしよう.パネル出力は別として,ほぼ仕上がったのではないかと思う.あとはこれをツールとして活用するというフェーズに入ることになるが,あえて取り上げるとすれば,「離散対数を求める」問題を実装するというのがある.

離散対数というのは,剰余Rに対して決まるγ値のことで,いまのところどうやってそれを求めればよいのか?というアイディアはまとまっていない.しかし,グループでしきりにこの話題が取り上げられているので,いま,ここでそれに対応するというのもありではないかという気がする.少し方式を考えてみることにしよう.Rとγの関係は,

α^γ÷Θ=Q…R つまり,α^γ≡R mod Θ

であるから,α^γ-R≡0 mod Θ を満たすγを求めるという問題になる.αとΘは固定であるから,マトリックスΘのΨαの行でRの位置を求めることに等しい.Rは複数位置に存在し得るので,最小のΨγを見つけることになるだろう.ただし,Matrix(Θ).rows(Ψα)上にRが存在しないという場合もあり得る.(R<Θ)ただし,Θを素数に限定すればかならずγを得ることはできる.⇒いや,できない場合もある.たとえば,α=138, Θ=241のとき,Ψα=138だが,この行はΛ=80で剰余数列の長さは80しかないから,この数列に乗らないRはいくらでもある.

一般には「n を整数として既約剰余類群 G = (Z/nZ)× が巡回群であると仮定」することになっているようだ.「そのような n は 2, 4 および素数冪 q と 2 q の形に書けるものに限られる」とされる.この条件は群Gが原始根を持つ場合と一致するということのようだ.たとえば,α=3,Θ=17は原始根3を持っている.このときの離散対数は指数(index)と呼ばれることもある.離散対数の定義は以下のようなものだ.

G を位数 n の有限巡回群とする。b を G の生成元とすれば、G の任意の元 g は、適当な整数 k を用いて g = b^k の形に書ける。さらに、g を表現する二つの整数 k1, k2 は必ず n を法として合同である。したがって、g に n を法とする k の合同類を対応させることにより log_b:G→Z/nZ なる函数を定義することができる.この函数は準同型写像であり,bを底とする離散対数と呼ばれる.

従って,この問題に入り込むには,まず群が巡回群であるか否かを判定するところから始めなくてはならない.

B進表記を10進表記に変換する機能が壊れている.(動作しない)⇒イベントハンドラは残っていたが,ハンドルが消えていた.⇒復活できたが,他にもこのようなところはあるだろうか?⇒一通りチェックした限りでは大丈夫なようだ.

『群 G が巡回群となるかどうかを見るには G の単項生成部分群で G 自身に一致するものがあるかどうかを調べるだけで十分である』

「巡回群とは,だた一つの元で生成される群(単項生成群)のことである」から,これは巡回群の定義そのものである.

「位数 n の群が巡回群となるための必要十分条件は、n の任意の約数 d に対して位数 d の部分群をちょうど一つ持つこと」

これを我々の言語に翻訳すると,位数Λの剰余数列がΛの任意の約数dに対して位数dの剰余数列を持つことのようになる.⇒どうもまったく意味不明だ.いずれにしても,我々はまだ,Λの約数のようなものをチェックしてみたことがない.しかし,いまの場合はφ(Θ)=Λなので,φ(Θ)=の約数を見ることになる.まだやってみたことはないかもしれないが,このアプローチは我々の方法とかけ離れたものではない.原理はよくわからないが,Rからγを逆算ないし探索するというのはそれほど難しくないと思われるので,とりあえず実装してみることにしよう.

‘System.ArgumentOutOfRangeException’ という例外が発生している.⇒Θに61という値を代入しただけで発生している.この数には限らない.もっと小さくても起きる.⇒DispInvertFuncの中で起きている.⇒DispNotationで起きている.⇒notation.Textに空文字列を書き込んだだけでエラーになっている.⇒Kinai.vbをデザインモードで開けなくなっている.⇒プロジェクトのフォルダ名を変更しようとしたら,別のプロセスがこのフォルダを使っているというメッセージが出た.食事後(落ちていた)にバックアップした版に戻っても同じ.もう一つ前のバックアップ久留島喜内 2023-06-17-4は開けた.⇒この版では障害は発生しない.ここから再開することにする.

WinMergeをインストールしてフォルダを比較してみた.Handles notation.TextChangedを追加しただけだ.⇒DispInvertFuncの中からClearInverseが呼び出され,それがトリガーになってnotation_TextChangedが呼び出されるというループになっていた.passflagを立てて回避するようにした.⇒念のため,ここでバックアップを取っておこう.⇒離散対数計算はざっくり動作するようになった.

パラメータの記号はほぼ固まったことになっているのだが,もう一度考えてみたい.現行では,Nをαとし,Bをβ,KをΘ,eをγとしているが,αβγという三つ組を考えるとすれば,むしろ,NBKではないだろうか?なぜかというと,B進の1/Nの循環節の長さを剰余数列としてみようとすると,β→N,N→Kのようになり,NBKが三つ巴の関係になっているように見えるからだ.このことから考えると,ΘをBとするようなローテーションもあり得るように思われる.群論ではKはnと呼ばれていて,主観的にも相互転換しやすい方がよいような気がする.

現在γと呼ばれているものはΨγと同種のインデックスの仲間と考えられるので,αやβとはカテゴリが違うと考えられる.従って,この値はむしろψと呼んだ方が適切であるかもしれない.ψの用途は位相・角度・電束などとなっており,γよりベターであるような気がする.#や@にはまだ名前は付いていないが,Λの仲間と思われる.γをまず,ψに変更し,ついでΘをγに変えることにする.

行ヘッダ・列ヘッダを整備する

厄介な問題が出てきた.パネルに出しているαR,γRとマトリックス上のデータが一致しない.原因ははっきりしている.横数列の周期がΘではなく,Θ-1になっているためだ.Θ-1というより,正確に言えばφ(Θ)だ.φ(Θ)の剰余を表示するようにすれば正しく対応できるようになるとは思われるが,そうなると,大きなマトリックスを出す意味が失われてしまう.考えられる方法としては,列ヘッダを2行にして①γの生値と②γ mod φ(Θ) を併記することではないだろうか?そうすると,実際のデータは3行目から始まることになる.

同様のことは行ヘッダに付いても言えるかもしれない.行ヘッダに数字を表示できるようにするにはどうすればよいのか?

https://dobon.net/vb/dotnet/datagridview/drawrownumber.html

①CallPaintingイベントハンドラを使う,②RowPostPaintイベントハンドラを使う,

https://atmarkit.itmedia.co.jp/fdotnet/dotnettips/506dgvlinenum/dgvlinenum.html

https://atmarkit.itmedia.co.jp/ait/articles/0610/27/news141.html

列ヘッダにはγ値が表示されているので,その下の行に γ mod φ(Θ)を出すようにしてみよう.⇒わかり易くなった.この行だけ色付けしてみよう.行ヘッダに関しては現状のままでよい.こんな感じになった.これなら間違いないだろう.この値はγRに対応しているので,γRのテキストボックスの色もグレーにしておこう.

image

いや,逆にパネルの色に合わせて行をカーキで塗りつぶしてみよう.少し派手めだが,この程度露骨な方がわかり易いと思う.この行を固定できるとさらによいのだが… ⇒やり方はある.Frozenという属性をTrueにすればよい.最左の第一列も同じ色で塗り潰しておこう.完璧だ.

image

これでマトリックスとパネルを完全に結びつけることができた.あとは行ヘッダを出すだけだ.⇒出た!

.RowHeadersVisible = True
.RowHeadersWidthSizeMode =
DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders

しかし,セル幅がムダに広くなっている.⇒どうもかなり具合が悪い.

.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToFirstHeader

という設定が取り敢えず,一番まともに近いものになるが,二桁以上の数字になると一部が掛けてしまう.AutoSizeToAllHeadersとすればこのようなことは避けられるが,今度は列ヘッダを選択しても列選択できなくなる.これは行ヘッダ幅とテーブルの左上セルの幅が一致しなくなるためだ.⇒多少見苦しいところは残るが,いまのところ,AutoSizeToFirstHeader よりましな方法がない.

行ヘッダにはマトリックスに表示された範囲の整数値を生で表示したいと思っているのだが,問題がある.マトリックスというのはΘだけで決定されるものであり,α値の如何に依らない.これはγ値についても言えることだが,γ値はすべての検定で1から始まる値なので,特に断らなくてもよいように思われる.テーブルの位置決めにはαRとγRが参照されているので,まるきり無関係という訳ではないが,αやγnは剰余であり,生値は参照されていない.⇒行ヘッダはむしろ非表示という方が分かり易いのではないだろうか?現行では下図のようになっている.

image

これはΘ=244のマトリックスで,αR=123,γR=122だ.これで見ると,マトリックスの左上点は(107,106)ということになるから生値ではないが,シフトした値が出ていることは間違いない.ただし,どうもまだ正しく動作しているようには見えない.どうもマトリックスの計算が間違っているようだ.α=119,γ=121,Θ=244のとき,R=119のはずだが,マトリックス上にこの値が見当たらない.α=119,γ=96,Θ=89のとき,αR=30,γR=33,R=52はマトリックス上にある.マトリックスの左上点が(1,1)の場合は動作しているのではないだろうか?

いずれにしても行番号をヘッダ部に表示することは諦めた方がよい.むしろ,列ヘッダと同様にヘッダ用の列を別途追加するようにした方がよい.その方が安全だ.

行選択→列選択のとき,行選択を解除しないで十文字に選択できるとよいのだが… 列ヘッダでなくコントロールキーを押しながらドラッグして拡張選択する方法で十文字に選択することはできる.またシフトキーを押しながら先頭行のセルを選択すると矩形領域が選択され,その右下セルがRの位置になる.⇒列ヘッダをクリックすると列選択モードに切り替わるが,それを廃止して,列ヘッダのクリック→列のセルを拡張選択するようにした方がよい.⇒対応修正した.

まだ,合わない.α=125,γ=124,Θ=244のとき,αR=125,γR=123でR=149だが,125の行に149という数字は見当たらない.ただし,cycle={125,9,149,81,121,241,113,217,41,1}となっているので,マトリックスの方が間違っているのではないか?マトリックスサイズを36×36から64×64に変えたら乗ってきた.確かにこのテーブルは正しい.⇒γRの値がおかしい.φ(Θ)=120でγRが123というのはあり得ない.⇒以下のような調整を行っている.

If tot < Θ – 1 Then eR = eR + tot
If eR = 0 Then eR = Θ – 1

これが間違っているのではないだろうか?とりあえず,両方止めてみた.今度は一致している.ただし,上記の数字と合っていない.上ではR=149となっているが,R=81だ.正しい答えは81だ.あるいは手順が異なっているのか?テーブルを読み損なっていたか?

image

列を1個追加してα値を表示するように改修したところだが,この値は実際には剰余を取ってからの値であり,既存マトリックスの第一列目とまったく同じなので表示する意味がない.⇒列ヘッダと同じように通し番号にしてみよう.

image

この方がよい.この番号はおそらく生値なので巨大数になる可能性もあるが,仕方ないだろう.一応これで仕上がったのではないかと思う.一度バックアップを取っておこう.TestMatrixにも対応しておく必要がある.TestMatrixではマトリックスは生成しないが,テーブルはフルサイズで構築することになっている.当然,左上セルはつねに(1, 1)だ.

TestMatrixではダンプは出さない方がよい.時間が掛かり過ぎる.また,カーソルが砂時計にならないのはなぜだろう?⇒テスト完了したら,出力コンソールに何かしらメッセージを出した方がよい.⇒対処した.

ダメだ.まだ数字が合っていない.α=125,γ=110,Θ=244,φ(Θ)=120 のとき,αR=125,γR=110 で R=1 のところ,クロスポイントには217とある.cycle={125,9,149,81,121,241,113,217,41,1}なので,R=1 も 217 も候補には入ってくるが… 正しい答えは R=1 だ.ということはγRが間違っていることになる.周期は10でφ(Θ)の約数になっているのだから,φ(Θ)で mod を取るというので間違いないと思われるのだが… γR=94が列の先頭になっている.このときの値は81であっているのだが,その次の数字が217で外れている.つまり,第一列目の選択に問題があるか,ないし,第一列目の評価に問題がある.

周期はそれぞれの行によって異なるので,同期を取るためにはφ(Θ)で分割する必要がある.つねに,φ(Θ)の倍数が第一列に来るようにすればよいのだが,それでは大きなテーブルに対応できない.どうすればよいか?最初の糸口が見つかるまで空回しするしかないのではないか?たとえば,α=125の場合,γ=94ならば,R=81, γ=95ならR=121,96で241,… このマトリックスの値はテーブルから引いているものなので,テーブルが間違っているのだろうか?⇒確かにそのようだ.各項ごとにべきを再計算しなくてはならない.コストは掛かるが仕方ないだろう.

列ヘッダをクリックしてその列を全選択するという操作は簡単に実装できたが,多少使い勝手上の問題がある.単純な拡張選択になっているため,別の列を選択すると複数列が選択状態になってしまう.これはあまり芳しくない.すでに選択されている場合には選択を落とすという動作も考えられるが,この場合の問題はその列全体を落とすと,行選択されている場合に欠落セルが出る可能性がある.現在選択されている行を取り出すことは可能だろうか?SelectedRowsというパラメータはあるようだ.⇒できた.自由に列選択ができるようになった.これで十分だ.

αやγに大きい数字を入れると,インデックスが1から始まるようになる.つまり,巻き戻しされてしまう.これでよいのだろうか?⇒マトリックスのインデックス行/列に現れる数値はインデックスであり,生値ではない.つまり,表示されているのはαRとγRであり,それらが見える範囲が表示されているというに過ぎない.従って,これらのヘッダ行ないしヘッダ列にはΘないし,φ(Θ)を超える値が現れることはない.

いや,その説明は間違っている.どちらも通番として表示されているのでΘやφ(Θ)を超えることはある.これは便宜上そうしているだけであって,αやγの生値を表示しているものではないことに注意する必要がある.⇒αやγの数字が大きいか小さいかには関係ない.インデックス行/列に表示されるのは,αRやγRであり,これらの値が小さければ1から始まるようになる.ただし,マトリックスの連続性を強調するために,インデックス行/列に表示される数字そのものの剰余は取らず,通番に見えるように表示している.

列ヘッダとインデックス行はまったく同じ内容に見える.列ヘッダは不要なのではないか?あるいは,逆にインデックス行は通番ではなくインデックス表示した方がましかもしれない.その方がわかり易くなると思う.⇒剰余の式が間違っていた.括弧が落ちていた.⇒修正して違いがはっきり見えるようになった.横数列の周期はΦ=φ(Θ)であり,この値はΘよりずっと小さくなる場合もある.γRはこの値を超えない.

どうも,まだ合っていないところがある.α=130,γ=115,Θ=244,φ(Θ)=120でαR=130,γR=115,R=172のとき,stripeと縦数列が一致しない.stripeの中に115が出てこない.⇒このリストはGetResidueStripeで生成されているが,ModPowの演算で除数がΘのままになっている.⇒Φに変えてみた.115は出ているが,まだマトリックスと一致しない.⇒stripeに表示されるのはR値であり,当然Θが除数でなくてはならないから,この修正は間違っている.R=172が記載されていないのだから,stripeの誤りと考えられる.

⇒stripeの出力は完全に正しい.マトリックスの読み方が間違っている.インデックス行に表示されている値はインデックスであり,剰余Rではない.つまり,カーキ色の行/列は剰余数列データには含まれない!⇒cycle出力もチェックしておこう.⇒完全に合っている.cycleの桁数はstripeよりずっと小さいが,周期的に繰り返されていることが確認できる.これらのテキスト出力の長さには最大MaxOutput=10000という制限があるが,実用上は特に問題にならないだろう.これでマトリックスは完成したのではないかと思う.

GetResiduCycleにはバグが残っている

BuildPowerGridでエラーが起きている.まだ,修正が完結していない.BuildPowerGridでは,範囲を限定したマトリックスを操作するようになっているが,BuildMatrixの対応修正が完了していない.まず,左上点を指定して範囲限定のマトリックスを生成できるようにする必要がある.左上点の計算はBuildPowerGridから借用してきているので,あとはそれを使ってマトリックスをシフトするだけだ.⇒一応数字は出てきた.

▲行ヘッダをクリックしたら,ヘッダ列に1という数字の並びが出現した.行ヘッダには数字は表示されないものと思い込んでいたのだが… 何か設定があるのだろうか?しかも,すべての行に1が表示されてしまうというのはどういうことだろう.

α=7, γ=2, Θ=13という設定で,GetResidueCycleで停止した.j=13,R=10で周期が検出され,j=j+1でループを抜けようとして j > maxとなった.この関数はPsiFunctionから呼び出されている.cycle(0)=7でcycle(1)=10だ.GetResidueCycleの戻り値は周期だが,cycle(12)=7となっているのを見落としているのではないか?2023-06-13に「φ(Θ)剰余数列周期の公倍数である」という発見があり,このときにGetResidueCycleと類似のGetResidueStripeという関数を新設しているが,この辺りはまだ十分バグが取れていないのではないだろうか?

この時期より前の版に戻って同じ障害が発生するかどうかを見てみよう.GetResidueStripeは元々はMakeStripePatternという関数だ.また,GetResiduCycleはBuildMatrixをお手本にして新規に作られたものと思われる.従って,まだバグが残っている可能性は十分あると見なくてはならない.GetResiduCycle→GetResidueCycleとリネームしておこう(eが落ちていた).GetResiduCycleを修正して,cycle(0)に格納されている初期値を参照するようにした.

ValueChangedでPrimeK.Checked <> primeで停止した.⇒PrimeK.Checkedを設定している場所がない.どうも一行誤って消してしまったようだ.IsPrimeという関数も内部でTotientFuncを呼んでいるが,比較的小さな素数に関するテストを事前に実行して効率化しているので,こちらを使うべきだ.(いましばらくは並列実行して検算する必要があるとしても)⇒仕掛りの箇所には何か目印(『暫定』など)を付けて置かないと忘れてしまう.

ダメだ.どこを間違えたのだろう.すべてのセルが1になってしまった.MT(i, 1) = BigInteger.ModPow(RowTop + i – 1, ColumnTop, Θ)の式が間違っている.ColumnTop – 1から始めていたので,指数がすべて0になってしまっていた.しかし,これでも間違っている.古い版の論理は正しく動作している.確かに横数列の周期はΘ-1になるので,それを加味しなくてはならないのだが… どうすればよいのだろう?

Θの上限→MAXARRAYSIZE=268435455

画面はエラーを出した状態で止まっている.BuildPowerGrid内だ.

image

α=123456, Θ=1234567890123456,γ=2,eR = 352731702317570.⇒この関数の中では全ての変数をIntegerとして扱っている.⇒ViewGridは行も列もIntegerの範囲に制限されている.kだけInt64に変更しておいた.⇒二次元配列Tの上限はMAXARRAYSIZEではなく,MAXSQUARESIZEに変更されている.⇒対処したが,まだ別のところでエラーが起きている.TestMatrix内だ.TestMatrixでは異種文字数カウント用にworkという配列を使っているが,ここでオーバーフローが起きている.workはサイズΘで生成しているので,間に合っているはずだが,テーブルTへのアクセスでレンジオーバーになっているのだろう.MAXSQUARESIZEの範囲に限定しなくてはならない.

とりあえず,エラーなしで動作するようになったが,Θ=123456789という順当なサンプルで尋常でない時間が掛かっている.TestMatrixにはいくつもループが入っていて,それぞれがどうしようもないくらい時間が掛かる.いずれにせよ,BuildMatrixには現実的な上限を設けるしかないと思う.MAXSQUARESIZE=&H7FFFでよいのではないだろうか?⇒関数レベルではなく,BuildMatrixないしTestMatrixのコマンドレベルで弾くようにした.Θ自体にも制限を掛けることにしよう.Θの上限はMAXARRAYSIZE=268435455とする.

もうひとつやることがある.マトリックスは本体では基本的に参照されず,ユーザの比較の便のためにだけ表示されているものなので,Θのすべての範囲のテーブルを作る必要はない.本来はべき剰余マトリックスの構造を確認するために,ある程度広い範囲で計算を実施する必要性があったが,横数列・縦数列ともにΘ以下の周期を持つということが確立されたので,もはや無闇に大きなテーブルを作ることは意味がなくなった.

MatrixTestでは全域テーブルが必要だが,それもΘの範囲内で十分なので,それ以上のテーブルを生成する必要はない.BuildMatrixでΘの範囲を超えたマトリックスが要求された場合にのみ大きいテーブルを作ればよい.⇒いや,現状そういう作りになっているのではないか?⇒指定された列数・行数がΘに満たない場合には,Θのフルサイズでテーブルを生成している.この部分は廃止されてよいと思う.

MatrixTestではΘxφの範囲のテストを実施しているが,廃止することにする.しかし,これを廃止してもTestMatrixは相当重い.異種文字数のカウントに相当な時間が掛かっている.BuildMatrixはツールとして常用する部分なので,ここではTestMatrixを実施しないようにする.また,TestMatrixコマンドではΘの範囲をもっと制限した方がよい.

▲BuildMatrixで行/列がΘより小さいときはΘまで拡張するという措置を廃止したところ,BuildPowerGridでエラーになった.topn=25150,leftn=26997で範囲外になっている.生成するテーブル自体オフセットを加味したものになっていなくてはならない.

パラメータの受け渡しが簡単にできるようにMatrixというクラスを新設し,BuildMatrixとTestMatrix,DumpMatrixをこのクラスに移した.⇒移植は簡単にできたが,マトリックスに何も表示されない.Matrixにまだ何も書き込んでいなかった.⇒大体できた.マトリックスも表示されるようになった.⇒まだ,エラーが出ている.

image

初期起動にやけに時間が掛かっている

初期起動にやけに時間が掛かっている.いつまで経っても砂時計のままだ.⇒Θの既定値に大きな値,1234567890123456 が入っていた.テスト用に設定したものがそのままになっていたのだろう.それにしても,抜けて来られないというのは問題だ.PowerResidueFunc で「除数上限オーバー」が発生している.エラーコード

ERROR_POWERRESIDUEFUNC_OVERFLOW

を定義して,その後の処理をパスするようにした.

「除数上限オーバー」はΘがMAXARRAYSIZEを超えたときに発生する.これは物理的に配列が構成できないため避けることはできないが,このとき,φ(Θ)などは計算値が表示されているのに,ψや(φ(Θ), #)などは表示されていない.#の値が出ているのは消し忘れか?fixedとketaは同時に消去しているので,どこかで更新しているのだろう.⇒表示されている123は既定値だ.処理に入る前に消去しておいた方がよい.⇒ClearParameterを止めてあった.理由は不明.

クリアされるようになったが,φ(Θ)の計算くらいはできるのではないだろうか?⇒DispParameterの中で表示するようにした.

MAXARRAYSIZEを&H7FFFFFFFまで上げてみたら,PsiFunctionでエラーになってしまった.配列を生成するところでエラーが発生する.やはり,7FFFFFFF=28ビットが限界のようだ.暗号の世界などでは512ビットなどというのが普通なので,到底およびもつかない.

▲BuildMatrixは誤っていないか?⇒点検してみよう.⇒それ以前に,BuildMatrixをΘ=1234567890123456で実行してエラーで停止した.⇒二次元配列はMAXARRAYSIZEまで取れない.MAXSQUARESIZEという定数を導入して制限を掛けるようにした.T(i, j) = T(i, j – 1) * T(i, 1) Mod Θでもエラーになるので,掛ける前にmodを取るようにした.

▲α=123472,γ=2,Θ=38, β=20のとき,Ξは一見レピュニットになっているように見えるが,インジケータは立っていない.

▲異種文字数/剰余数列周期をマトリックスに表示する

▲Θ=1234567890123456, α=Θ=1234567890123456,γ=2で例外が発生した.

image

φ(Θ)は剰余数列周期の公倍数である

α^γ%Θ=Rで,マトリックス上の(αR行,γR列)の値がRと一致するはずだが,合わない.確かに.剰余計算は合っているが,γがΘを超えた後のγRの計算がおかしい.一つ多過ぎるのか,小さ過ぎるのか?Θが8のとき,γR=1でR=1となり,すでに合っていない.γ=7=Θ-1までは合っている.⇒どうも,かなりまずいことになってきた.完全な設計ミスだ.γRという値はまったく当てにならない.ということは,stripeの表示も間違っているということだろうか?⇒確かに間違っている.stripeはPsiFunctionでやっているように単独列として独自計算して出せば正しい数列になるとは思われるが,それとテーブルを対照させる「インデックス」はどう計算すればよいのだろう?

Θが素数の場合は,明らかにΘ-1という周期が横数列で発生する.従って,今の計算方式でも通用する.それ以外の場合にはまったく不明とするしかないのではないか?ということは,いま生成しているマトリックスも素数以外の場合には間違ったパターンが出力されているということになる.かなり困ったことになった.どうすればよいのだろう?BuildMatrixで表示されるテーブルそのものは多分間違ってはいないと思われる.問題はそれにどうアクセスするか?ということだ.つまり,テーブルの列インデックスをどのような形式で与えるか?行インデックスは現行通り,αRが適用できるはずだ.

  1. 行インデックス,cycleに関しては現行通り
  2. stripeは独自計算ルーチンを導入する
  3. 列インデックス,つまりγRは参考値とし,Θが素数でない場合には薄墨表示とする.

とりあえず,この3点で修正を入れてみよう.⇒GetResidueStripeという関数を新設した.ところが,すでに既設のMakeStripePatternという関数があった.ただし,この関数ではべき%(K-1)という計算を事前に実行している.明らかにこれは誤りだ.対処した.一応これで解決したことにしておこう.BuildMatrixのテーブルはつねにΘxΘで生成されているので問題ないだろう.いや,それが誤りではないか?テーブルは指定サイズで生成されている.テーブルの左上セルはつねに(1,1)になっている.マトリックスではこれをシフトして使っているのではないか?確かにそのようだ.

▲α=123472,γ=2,Θ=38, β=20のとき,Ξは一見レピュニットになっているように見えるが,インジケータは立っていない.なぜか?⇒テキストボックスには1000文字までの1が入っている.

行をインデックス化する方法が一つある.すべての行の周期の公倍数を求め,その剰余を取れば正しい列が指定できる.ただし,このインデックスは各行の固定部より上でなくては適用できない.ともかく,テーブルに周期=異種文字列数を出しておく必要がある.⇒CycleとDropという配列は存在する.これらの値はPowerResidueFuncで計算されたものをResidueFuncProで格納している.ValueChangedPro,TestMatrixとdivisor.ValueChangedでこれらの配列を初期化している.PsiFunctionではこの配列を参照してψ値を決定している.GetResiduCycleでもこの配列を初期化している.この2つの使い方はまったく違うので混同するのはよくない.ともかく,この値をDumpMatrixで出力してみよう.

MatrixTestを実行してどこかで例外が発生した.⇒DumpMatrix内だ.⇒配列の範囲外にアクセスしていた.

重要なことを発見した.剰余数列の周期を決めているのはφ(α)ではなく,φ(Θ)だ.φ(Θ)を取れば,素数でない場合もドンピシャで値が確定する.言い換えれば,φ(Θ)は剰余数列周期の公倍数である.別の言葉で言えば,#ないしψ値はφ(Θ)の約数である.⇒実装してみたが,まったく問題なく動作している.EFAはこのことにまったく触れていないので,おそらく気付いていなかったのだろう.乗法剰余群の位数として知られる値がφ(Θ)の約数であることに触れた記事は読んだ記憶がない.

φ(Θ)が剰余数列周期の公倍数であるとすればγRはその剰余になるはずだから,Θが素数であるとかないとかの留保なしにインデックスを決定できるようになると思う.やってみよう.⇒完全に一致している.これでべき剰余数列の周期は完全に押さえられたと思う.⇒いや,まだ完結していないようだ.α=123458,γ=30,Θ=8のとき,φ(Θ)=4でγR=2だが,stripeがマトリックスと一致しない.Cycle={1,0,2,0,2,0,2,0,}でこれらの項の公倍数は2だから,φ(Θ)=4はその公倍数と言える.

不一致が発生する理由は固定部の存在であると思われる.この固定部の部分を除外すれば,完全にφ(Θ)の周期に乗るのではないか?いや,どこから初めてもそれほど違わないような気もするが…Drop={0,3,0,2,0,3,0,0,}なので,最小限3のオフセットが必要になるのではないか?どういう計算をしても γ mode φ(Θ)は2にしかならないが,インデックス2の縦数列に入っている値は固定部に含まれるため,その後は発生しなくなる数列であるので,不一致が生じると考えられる.Θの2倍のマトリックスを表示してその右半分にアクセスするようなインデックスを出力すれば安全だが,それもやり過ぎのような気がする.

一番安全なのは,γR+φ(Θ)を表示することではないだろうか?つまり,γR={γR mod φ(Θ)}+φ(Θ)ということになる.従って,マトリックスの全容を見たいのであれば,Θ+φ(Θ)のマトリックスを拡げる必要があるということになるだろう.これでよいのではないかと思う.φ(Θ)=Θ-1の場合には加算しなくてもそのままの値が使えるはずだが… このためには,φ(Θ)=Θ-1であることと,dropが存在しないことが同値であることを証明する必要がある.また,dropが発生する場合,その値はφ(Θ)を超えないことも証明されなくてはならない.ともあれ,これで一件落着なのではないかと思う.#=ψの等式も#=0の場合を除いて,完全に一致するようになった.これも#=0のときのψ値を0と定義すればよいというだけの話なので,ψ値はつねに決定可能ということになる.

α,Θ,Rの値が与えられたとき,γ値を逆算できるだろうか?もし,これができれば離散対数問題と呼ばれる課題を解いたことになる.原理的にはそれほど難しい話ではない.αとΘからαRが決まるので,αRのcycleを生成し,その中でRを検索すればよいというだけの話だ.cycleのサイズはたかだか,φ(Θ)x2あればよいと考えられる.離散対数問題の対象はおそらく巡回群に限定されていたと思うので,固定部のことは考慮しなくてもよいとすれば,φ(Θ)で済む可能性もある.

ΘはInt64と定義されているので10進で19桁を超えることはできないが,その範囲なら何とか計算できるのではないかと思う.

▲Θに16桁の数字を与えてエラーになった.

image

Θ=1234567890123456,α=123500, γ=33で起きた.エラーはGetResiduCycleで起きているようだ.

ψがφを割り切るというのは定理ではない

Getψ関数の仕様を再考する必要がある.ψ数はnとKによって決まるが,ψ数が決定できない場合もある.ψ数が得られる条件はNのべき剰余数列の中(終端)に1が現れることだが,剰余数列に1が入らない場合はいくらでもある.このようなときに,ψ数の定義に従って,nに対応したKの最小の値を決定するというのがGetψ関数の役割だが,その動作にはかなり疑問がある.①選ばれるKが極端に小さい.ほとんどは1, 2, 3, 5 のいずれかだ.②設定値ですでにψ数が確定しているのに,ボタンを押されるとより小さい値を探して提示するという動作になっている.

適合するKを1から探すのではなく,直近のK'<Kを求めるというのが適当ではないだろうか?逆に+Kの方を探すということも考えられるが,小さい方を探すというのが自然だろう.どのようなNに対しても,K=1, 2, 3, 5のいずれかは必ずψ値を与えると言えるだろうか?これは予想問題として立てておいてもよいかもしれない.

PsiFunctionはその中で表示出力している.⇒いや,Kの値を変えたときにValueChangedイベントが発生しているのだろう.⇒passflagを使って出力を抑制するようにした.

ψ数が求められる条件として「NとKが互いに素」というのが適用されている.これは正しいと言えるか?⇒EFAの定義表にもそう書いてあるので間違いないだろう.

N=10, K=1234567でハングしてしまった.⇒MakeStripePatternで手間取っている.文字列の長さを制限していないので無闇に長いテキストを生成しようとしている.⇒MaxOutput=10000で打ち切るようにした.⇒動作するようになった.

ψ(n, K)という関数は元々循環小数に関する議論の中で提案されたものであり,そこではu-length functionと呼ばれている.u-lengthとはnの循環節の長さであり,@と表記されている値である.従って,EFAの記述が正しいとすれば,u-length=ψ(n,B)で計算できなくてはならない.n=123, B=10のとき,@=5でnU=99999となる.このとき, N=10, K=123で剰余数列を計算すると#=5となって@の値と一致する.ただし,ψ値は不定のままだ.

n*U(b,n) = r*(by(b,n)-1)のような関係式が提示されている.U(b,n)は「循環単位」と呼ばれる整数値で現行ツールのUと一致する.上式の左辺はnUと呼んでいるものに他ならないから,この値が右辺式のように分解できるかどうかを確かめなくてはならない.

Nの入力値がMAX_INT64を超えているとき,黙って元の値に戻している.⇒パーツが上限を超える値を拒否しているためではないか?

EFAに記載された事例を検討してみよう.

… given n=21, you easily find out the remainder sequence {1,10,16,13,4,19,1,..}, while u-length function y(10,21)=6, U(10,21)=47619 and r=1. However if you take U=47619*x and r=x, then the equation holds for any x.

n=21, B=10とすると,U=47619, nU=999999 で @=6.r=1 であるかどうかは画面では分からない.⇒ nB=n%B という値も表示されてよいかもしれない.多分 r=n%Bのはずだ.一方,n=10, K=21という設定では,#=6で cycle={10,16,13,4,19,1,10,}が表示される.ただし,ψは空欄になっている.つまり,nにある値を設定し,KとBに同じ値を代入すると,上の状況を再現できる.いや,違う.べき剰余画面では B→n, n→K のように設定しなくてはならない.

この2つの逆向きの計算を一画面に同時に表示することはできるだろうか?nが除数Kに向かうところが難解なところだ.パラメータの名前が誤解を招き易い.Bはbaseで自明だが,nは対象数,Kは固定の除数のイメージがあり,Kをnとみなすこと自体に抵抗がある.KをΘで置き換えてみよう.小文字のθは角度として普遍的に使われているが,大文字のΘはあまり使われていない.この文字を選んだ理由は割り算記号÷に少し似ていないこともないという理由だ.Ξが111を90度回転させたものと似ているというのと似たような理由だ.

そうなるとnの方にもギリシャ文字を割り当てた方がよさそうな感じになってくる.どうせなら,Bをβとし,nをαとしてみてはどうだろう?αとβは同格なので互いに入れ替え可能というイメージになる.べき剰余と逆数の循環小数を連通させるというのがこの検定の最大の目的であり,それにそうとすればこの辺りを明確にする必要がある.α/βではなく,A/Bというのでもそれほど悪くはないような気はする.そうなると,指数のeもギリシャ文字でεではないだろうか?QとRは英字で残ってしまうが,仕方ないだろう.今後はこの記法に従って記述することにする.

εには固定のイメージがあるので使いづらい.α,βの次の文字γを割り当てることにしよう.γはstripeに関係する.縦数列はまだあまり深く調べられていないので,これから発展する領域と考えられるので,α, βと同格の文字を割り当てておくのは適当だと思う.

2つ問題がある.(1)α=21, β=10とするとU=47619, αU=999999で6桁なので@=6, また,αとβを入れ替えてα=10とし,Θ=21とすると,#=6, cycle={10,16,13,4,19,1}となって,上の記述と合っているが,ψの値が不定になっている.(2)U=47619*x and r=x, then the equation holds for any x という問題.

ここでGet ψを実行すると,Θは11に代わり,ψ=2が表示される.これはどちらかが間違っているかないし,異なる定義によっていることになる.ψ関数(u-length function)の定義に戻ってみよう.

Given mutually prime numbers n and b, there exist nonnegative integer x<n and positive integers y and z such that z=x*b^y \n…x, that reads n divides x*b^y, the quotient z, and the remainder x, in other words, n*z+x=x*b^y. A set of {x,y,z} exists infinitely. u-length function y(b,n) is defined as the minimum such number y, as well recursion unit U(b,n) as the minimum such number z.

今の事例では,n=21, b=10, z=47619, y=6 のはずだが,合っていることを確認しよう. 21・47619+x=10^6・x → (10^6-1)x=999999\x=21・47619=999999 ∴ x=1 確かに数値的には合っているようだ.ψ(b,n)の値はそのような関係式を満足する最小のyとされているのだから,ここではψ値は確定している.現行ツールでψ値をどのように決定しているかを見てみよう.⇒PsiFunctionでは,φ(α)の約数からψを割り出している.今φ(α)=4なので,約数列は{1,2,4}

10^1%21=10, 10^2%21=10, 16, 10^4%21=4でR=1が出てこない.なるほど,理由はわかった.ψがφの約数であるというのは正しいが,ψ=φの場合があることを見落としている.これを入れれば多分解けるはずだ.いや,間違いだ.φ=4は計算には入っている.ψがφの約数であるという推論が間違っているのではないだろうか?いや,これは定理ということになっている.

P1(T):For any natural number n>2 on b-base decimal system, the value of u-length function y(b,n)>0 always divides the value of Euler’s totient function f(n), i.e., gcd(f(n),y(b,n)) = y(b,n). If n is a prime, then y(b,n) divides n-1.

どうもこれが間違いの元ではないだろうか?Wolfram MathWorldのMultiplicable Orderの項目によると,10^6≡1 mod 7なので,ord_7(10)=6となっている.φ(10)=4なので,ψ=6はφ=4を割り切ることはできない.確かに現行プログラムではこのような場合には「互いに素でPSI検出不能」というメッセージを出している.

https://mathworld.wolfram.com/MultiplicativeOrder.html

応急的にαのすべてのべきをテストするように修正して動作するようになった.この論理はもし,cycle数列が手元にあれば,もっと高速化することができる.マトリックスの一行だけを出力する手立てはあるだろうか?⇒周期数列はDispResidueCycleで表示している.この関数はResidueFuncProから呼び出されているが,この数列を得るためにはPowerResidueFuncを実施することが必須だ.PsiFunctionは剰余演算とは独立に実行できなくてはならないから,独自にcycleを取得できるようにするべきだろう.これはBuildMatrixでやっていることの一部を切り出すことに当たる.⇒GetResiduCycleという関数を作った.これでψ値の計算にはFactoringが不用になり,無茶苦茶高速化された.

やはり,ψがφを割り切るというのは完全な誤りであるように思われる.α=29でΘ=59のとき,φ=28でψは29になる.剰余数列は下記のようなものになっている.

{29,15,22,48,35,12,53,3,28,45,7,26,46,36,41,9,
25,17,21,19,20,49,5,27,16,51,4,57,1,29,}

αは29で素数だから,φは当然28になる.このとき,ψ値は29でφよりも大きい数になっているから,当然φを割り切ることはできない.Θがαよりも小さいときにはもしかするとψがφを割り切るということが成立しているのかもしれないが…いずれにせよ,何らかの条件がなければ成立しないものと思われる.⇒非常に重要なことを発見した.これは以前にどこかに書いたことがあるような気がするが,αとUはある基数Bの進数システム上で「逆元」であると言える.下図を見ると,このことが疑問の余地なく確認できる.

image

いや,逆元と言うからには,a ✕ a^-1=1となることを証明しなくてはならない.確かにそんな簡単なものではない.123 x 813 = 99999だ.これを見て言えることは,99999を単元とみなすことができれば,確かにこの2つの下図は互いの逆数であると言えるだろう.仮に999…999のような形のすべての数を単位元とみなすとしても,999…999の約数とならない数はいくらでもあるはずだ.Wolfframのページには下のような表が掲載されている.この程度のものは出力できるようにしておきたい.

Multiplicative Order

image

▲Get ψはほとんど不用になった.

道具箱から複数の画面を開けるようにする.ないし,出力画面を道具箱に移す.⇒完全に2つの(等サイズの)ウィンドウに分割した.

image

これしかない.タブにしてもよいのだが,そうすると出力画面とパネルを同時に見ることができない.出力画面は不用なときには閉じてアイコン化しておくことができる.道具箱を閉じるとアプリ終了する.

原始根マークが間違っているようだ.α=123488でΘ=5のとき,αにマークが付いているが,cycleは0#0で3.と表示されているだけだ.そもそもcycleの表示がおかしくなっている.どこか壊してしまったのだろうか?cycleを表示しているのはDispResidueCycleだ.この関数に渡されるdropとperiodが間違っているのだろう.おかしい.こんどは正しく表示されている.開始時点のα=123456,Θ=7に戻ってやり直ししてみよう.途中で巨大なレピュニット数が出現しているのが関係しているのかもしれない.6498桁もある数をダンプするというのが無茶だ.MakeRecursionUnitでも巨大数をダンプしている.

現在MakeRecursionUnitではMAXTEXTLENGTH=32767を上限としているが,さすがに大き過ぎるのではないか?MaxOutput=10000に落とした.だいぶ楽になった.

Θ=8でαを変えていたら,α202の辺りでハングしてしまった.kinaiは3つ走っている.VS19も2つ走っている.⇒制御が戻ってきた.イベントが滞留してこなすのに時間が掛かっていたためだ.

▲cycleは重複しない文字列でよい.(末尾の1文字は余分)桁数#分だけ出せばよい.

cycleのdropと1/αのfixedに記号を与える.⇒使える余白がないので,現状のままとする.無名の値を参照するときには [3#12],[0@23]などのように表記して区間に関係する値であることを暗示すればよい.

そろそろ外部に持ち出せる雰囲気になって

まだ,午前9時前(AM08:55)だというのに,こんなキチガイじみた数字が出ている.このペースでカウントが伸びれば,日付が変わるころには確実に1000人を超えることになるだろう.

image

何か異変が起こったという感じなのだが…

そろそろ外部に持ち出せる雰囲気になってきたので,試しにEXEをVAIOにコピーして走らせてみたのだが,ウィンドウ枠が縦長過ぎてスクリーンに収まらない.対策を色々考えてみたが,画面の一番下のブロックを切り出して独立のコントロールパネルのようなもの仕立てるという結論になった.このパネルには主に5種の検定を実行するためのボタンがあるが,一般ユーザにはあまり関心がない部分と思われるので,却って使い易くなるのではないかと思う.このパネル上のボタンで有用なのは右端に置いてある,①Get φ,②Update,③Build Matrixの3つのボタンでできればこのボタンはメイン画面に置きたいところなのだが… まぁ,手元にリモコンを置いて操作するような感じになるのではないかと思う.ともかくやってみよう.⇒大体動作するようになった.

image

InvertTestで画面出力が出ない.⇒解消した.

Updateボタンでマトリックスが開き,BuildMatrixは無動作になっている.⇒修正した.

Ξの判定が間違っている.N=12347のとき,Ξは 0111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111…

のような数になるが,nUは09999999999999999999999999999999999999999999999999
999999999999999 のように先頭にゼロが付いた数になっている.Uは 809, 913, 339, 272, 697, 821, 333, 117, 356, 442, 860, 613, 914, 311, 168, 704, 948, 570, 502, 956, 183, 688, 345, 347, 047, 865, 878, 351, 016, 441, 240, 787, 235, 765, 773, 062, … のような 10進で6173桁の数で,それを12347倍したものがnUだから,5桁上がるとして6178桁になるはずだ.nUの先頭に入っている0というのは何かの間違いではないだろうか?

nUの数字列はConvertNum2Stringで生成されている.ToBCDはこんな巨大数を処理しきれないので,MaxKetaSuで打ち切っているが,バイト配列の先頭に0が入って,{0,9,9,9,…}のような内容になっている.数値をテキストに変換する場合には頭から割り込んできているはずだから,桁数が上限を超えていても処理できなくてはならない.⇒どうも怪しくなってきた.ToBCDでは対象数Nを頭からBで割り込んだ数を配列に格納し,それを逆順にした配列を返している.配列に格納されているのはN%Bの剰余Rだ.確かにこれはBで割った商を求めているのではなく,Bを進数に変換したときのバイト列を取っているのだから,正当な操作と言えるだろう.多分これしか方法はないものと思われる.

つまり,一度頭から尻尾までさばかなければ皿には盛り付けできないということだろう.ということは桁数がオーバーフローした時点でご破算にしなくてはならない.ToBCDでは上限がMAXTEXTLENGTH=32767だ.これでは到底歯が立たない.というか,そもそも整数値と桁数を混同しているように見える.ToBCDではともかく末尾桁まで計算しなくてはならないのだから,その限界を正確に見極める必要がある.ToBCDでは最初から作業配列のサイズを

Dim arraysize As BigInteger = MaxKetaSu

でMaxKetaSu = 1000で固定している.これはかなりまずい.作業用配列サイズをMAXARRAYSIZEまで拡大してみた.桁数は6178なので完全に処理できる.Ξの計算ではテキスト化したnUではなく,nUの生値を使っているはずだから,この判定は正しいと言える.また,出力されたレピュニット数11111…も末尾までさばいた値から生成したものだから正しいと言える.表示桁数は1000桁になっているが,これはこれで十分だろう.ToBCDでオーバーフローした場合には,デバッグコンソールにメッセージを出してブレークするようになっているが,エラー復帰するようにした方がよい.間違った値が表示されると却って混乱の元になる.エラーコードを返すようにした.

UコードはNが6桁辺りで限界になってしまうが,桁数で1万桁台でも表示不能となっている.もう少し拡げることは可能なのではないか?MakeRecursionUnitはMaxOutput=10000が上限になっている.上限をMAXARRAYSIZEに代えてみた.問題なく動作している.ただし.桁数が3万を超えると流石に重くなってくる.MAXTEXTLENGTH4 = 32767を上限としてみよう.⇒まぁ.そこそこの動きになった.

テキストボックスの名前の付け替えを行った.一応収束した.また,ClearParameterという関数を作ってValueChangedの冒頭で呼び出すようにした.これはすべてのテキストボックスを一旦クリアするためのものだ.これで更新されていないボックスが浮き出しになる.また,InvertFuncの冒頭でClearInverseを実行するようにした.

SeedTestではcycleとstripeを更新してない.また,PrimeTestではInvertFuncを呼び出しているが,パラメータはまったく更新していない.InvertTestでも同じだ.以前は動いていたような気がするのだが…

N=12347のとき,Updateボタンを押して例外が発生する.ClearInverseで例外が発生している.なぜだろう?notation.Text = “”というコードで例外が置きている.ただし,初回は問題なくパスしている.⇒パーツを作り直したら収まった.⇒原因は不明

PrimeTestではBの値が変化する以外なにも表示されない.動作はしているのだが,テキストが長過ぎて格納できないのだろう.いや,切り詰める処理は入っている.Uをテキストに変換したときの長さは6169で,テキストボックスの上限は32767だから十分入る大きさだ.⇒消去してから描画までの時間が長過ぎるためだ.描画した直後に消去されるような流れになっている.DispInvertFuncの冒頭でクリアするようにして見えるようになった.ただし,Bの因数リストとB進表記は空欄のままだ.⇒PrimeTestClickの中でDispNotationを実行するようにした.これでボックスBの中身はすべて出力されるようになった.

InvertTestにも同じ問題がある.⇒DispInvertFuncの中で実行した方が分かり易い.stripeはKを変えない限り一定だがNを変えればcycleは変化しなくてはならない.まずこれを見てみよう.⇒DispResidueCycleで出力されている.DispResidueCycleはResidueFuncProから呼び出される.呼び出しているのは,①ValueChangedPro,②modulo3.Click,③GoButton,④TestMatrixの4箇所だ.SeedTestではFactoringとInvertFuncは実行しているが,剰余計算はやっていない.modulo3というのは,現在ReisueTestと呼んでいるものだ.⇒名前を付け替えた.③のGoButtonはすでに廃止されている.

SeedTestのどこかでやけくそ時間が掛かっている.どこかでコントロールを失っている感じだ.カーソルは砂時計のままなので処理は完了していないのだが,ブレークで止められない.N=1234567.いや,処理は明らかにすでに終わっている.カーソルが戻っていないだけと思われる.⇒UseWaitCursorがオンになっていた.⇒ResidueTestとSeedTestではValueChangedProを実行するようにした.これでもれなく表示が更新されるようになった.いや,まだだいぶ落ちているような気がする.ResidueTestでは,1/nやUが更新されていない.ResidueTestでは逆数計算をやっていないからだ.これはそれでよいのではないか?

InvertTestを実行後の状態がおかしい.N=12347, B=10で因子が1,2,3,5 表記がDLHとなっている.前の状態が残ったままになっている.PrimeTestも同じだ.⇒Passflagが立った状態で値を戻しているためだ.passflagをリセット後に値を戻すようにした.

これで大体収まったのではないかと思う.

▲Getψ関数はψ値を確定するためのKを探索するルーチンだが,動作に不審がある.たとえば,N=12358でK=27のときψ=3で確定しているにも関わらず,Getψでk=3にジャンプするというのはおかしい.

▲各種の検定の結果をテーブルに出力する.マトリックスの異種文字数を出す.最初の項目は将来的課題とする.二番目は対処する.

▲出力文字数は制限しない(テキストボックスの容量まで)

nU/(B-1)という値にΞという名前を与える

現行ではnU/(B-1)の値にrepというラベルを付けているが,この数値はつねにレピュニットになるとは限らないので,正確とは言えない.多少うるさいが,直接nU/(B-1)と表記しておいた方が間違いがないのではないか?合わせて,rep値がレピュニッであるか否かを示すインジケータも表示しておきたい.昨日からEFAの読み直しを始めているが,レピュニット値を得られるか否かはnの素因数分解に深く関係している.

ある数rがレピュニットであることをどのように判定すればよいだろう?レピュニットはBに依存するので計算にはBが現れなくてはならない.r=(B^e-1)/(B-1)だから,r*(B-1)+1してB^eに戻せるかどうかを試してみればよいのではないか?いまの場合,eは未知だから,X=r*(B-1)+1として,B^log(X)=Xとなることを確認すればよい.いや,これは間違いだ.B^(logX/logB)=Xだ.Bを底とする対数を直接求めることは可能だろうか?x=logX / lobBを計算してやればよい.⇒できた!かなりわかり易くなった.⇒ダメだ.誤動作している.

n=29, B=5のとき,r=11111111111111がレピュニットでないと判定されている.doubleの計算なので誤差が出てしまっているのだろうか?x=13.999999999999998という値だ.CTypeで変換しているが切り捨てになっているのではないだろうか?⇒そのようだ.Math.Round関数を使うようにしてみた.Roundの引数で四捨五入を行う小数位を指定できるが,15とした場合には落ちてしまう.15桁目は8で,14桁目までは9が入っている.引数を14として動作したので,これでよいことにする.整数値で検算しているので問題ないはずだ.

ダメだ.n=73, B=29でr=11111111111111111111111111111111111111111111111111

1111111111111111111111 の数字をレピュニットでないと判定している.71.999999999999986を71にまるめている.⇒第二引数を12まで落としてみた.これで(B^e-1)/(B-1)の値を完全に検査できる.この値には何か名前が付いていただろうか?この値は結構重要度が高いので,何かギリシャ文字を与えてもよいのではないだろうか?⇒φ,ψときて,次はχではないか?しかし,文字面ではxと同じになってしまう.upsilonというのもある.nUの約数なのでΥもおもしろいと思うのだが,見た目がYになってしまう.Ξは横棒だが,一が3つ並んだ形状に見えるので,これを使ってみよう.つまり,上で「nU/(B-1)」と表記した値だ.Ξ=nU/(B-1)ということになる.⇒直感的で悪くないと思う.

このインジケータをチェックすると,nとBが互いに素であることと,Ξ値がレピュニット数であることは完全に同値であることが確認できる.これは大きな収穫だ.ダニエル・デジオジーとの対話の中で数字和(digit sum)の話が出てくる.どこか場所があれば出してみたいのだが… 数字根(digital root)というのもある.これは数字和を一つの数とみなしてその数字和を求め,のような操作を繰り返して一桁になったときの数字だ.nのB進表記を出すところでダンプ出力として出しておくことにしよう.DispInvertFunc→DispNotationで表示している.

Bを変えたとき,Bの因数とB進表記が変化しない.⇒対処した.

Bを変えたとき,何も外部出力されない.⇒暫定修正としてBottomLineを呼び出すようにした.

DispInvertFunc で循環節を重複して生成しているようだ.

DispInvertFunc→MakeRecurringDecimal→※→DispParametor2
DispInvertFunc | Inverse.Click→DispInvert→※

文字列の生成はMakeRecurringDecimalに統一し,DispInvertの中から呼び出せばよいのでは?いや,DispInvertFunc → DispInvertの呼び出しはDUMPNUMSTRINGの限られているから止めてよい.従って,

DispInvertFunc→MakeRecurringDecimal→※→DispParametor2
Inverse.Click→DispInvert→※

のようになる.つまり,DispInvertの論理をMakeRecurringDecimalの呼び出しに変えればよいのではないか?というか,DispInvertを廃止して,Inverse.Click→DispInvert→DispInvertFuncでもよいような気がするが… いや,そもそも,Inverse.Click→DispInvertFunc は実行されている.Inverse.ClickではDispInvertFuncの後に,DispInvertとDispRecurringDecimalを実行している.DispRecurringDecimalは出力画面に「循環小数」などの情報を出力している.これはDispInvertFunc に取り込んでしまった方が早い.⇒DispInvertは廃止した.

nRの計算が間違っているような気がする.K=14のとき,nR=14という値が表示されている.しかし,nRはn%KなのだからnR<14でなくてはならない.nRはKの剰余だが,少しだけ違うところがある.nR=0のときには,nR=Kとなるように調整してあるところが味噌だ.これによって,マトリックスの行番号とnRが一致するようになっている.eRの場合も同様の調整が入っている.2023-06-07のログによれば,

「たとえば,K=4のとき,e=3, 6, 9ではeRは0になるが,マトリックスの指標としてみる場合には0という数字は現れないので,eR=0 → eR=K-1のように換算する必要がある.nR=0にも同様の問題はあるが,行の場合は行ヘッダが表示されないので,剰余が1列目に表示されているが,それが0になっているので,特に手当しなくても問題ないようには見える.⇒縦軸は番号Nとみなすべきだから,やはりゼロは適当ではないと思う.eRの場合と同様0→Kのように読み替えるべきだ.」

のようになっている.驚くべきことは,nRと数字根は完全に一致する.ただし,すべてのKについてそれが成り立っている訳ではない.

上の修正の影響と思われるが,Kを変更してもnRが変化しなくなってしまった.いや,処理は抜けていないようだが,描画されないような状態になっている.何かタイミング的な問題があるのだろうか?Nが小さい範囲では問題は起きない.⇒ChangeCursorが入っていないため,処理が続いているのが見えていないことが原因と思われる.⇒対処した.

「nRと数字根は完全に一致」しているように見えたのだが,まったく起きなくなってしまった.少なくともK=45では一致していたと思うのだが…対象の数字を一桁小さくしたら一致するようになった.確かに数字根の計算には逆数演算が必要というか,そのカテゴリに含まれるが,逆数方面は上限がタイトなので動作しない場合があるのではないか?

べき乗の計算値やB進表記などをBottomLineで表示しているが,あまりよくないと思う.BottomLineは処理中に繰り返し呼び出されるので無駄な処理が入り過ぎる.DispParametor2に移してみよう.ダンプに紛れてしまうので読みづらい.ValueChangedの末尾に置いてみよう.

数字根がnRと一致する条件がわかった.K=B-1だ.つまり,B=10のときK=9の剰余はBの数字根と一致する.B=10,K=45では一部一致する場合もあるが,不一致となる場合もある.また,次のようなことも言える.「KがB-1の倍数のときは,B^x%Kは一定値を取る.」いや,一定にならない場合もある.たとえば,B=10でK=27では{1, 10, 19}の3つの値に分離する.しかし,K=36なら一定だ.おそらくBの因数をp1*p2*…として,(B-1)*p1*p2…などであれば一定になるのではないだろうか?Kの素因数分解も必要かも知れない.B(B-1)というのも気になる数字だ.循環節の書式を下記のように変更した.

A: 0.005|4347826086956521739130

とても読み易くなった.

Kを変えてもe%K-1が変化しない.stripeは変化している.⇒e<Kならば値は変化しないと思う.e>Kになれば変化するようになる.剰余演算ではつねにこのようなことが起こる.つまり,Kより小さい値は剰余演算ではほとんど意味がない.⇒というか,Kの範囲内でしか通用しない.

Bを変化させたとき,Bの因数と表記が変化しない.Bの素因数を表示しているのはDispNotationだけだ.DispNotationを呼んでいるのはValueChangedProだけだ.⇒base2.ValueChangedイベントでDispNotationを呼び出すようにした.

Nを変更して(n,K)が更新されない.この値を更新しているのは,DispModPowだけだ.⇒いや,呼び出されているし,更新もされている.1や7などの数字で色も地味なので見落とされていただけだ.

▲横数列が尽数列になっても,原始根マークが付かない.K=11のとき,ψ=K-1のときのみインジケータが点灯する.