5
未解決問題議論
文献あり

「くどー問題」再び

394
2

くどー問題とその数値計算

Mathlogでくどーさんがとある数学の問題を記事にされています:

そろそろ誰かに解いてほしい自作問題(未解決)

私はこれを「くどー問題」と呼んでいます。問題の内容は上記記事を見ていただくのがよいと思いますが、一応引用させていただきます:

1からn(3)までの整数が書かれたカードが1枚ずつある。この時、以下の条件を満たしながらカードを1枚ずつ取り除いていくことを考える。

  1. どの時点においても「カードに書かれた数の3乗和」が「カードに書かれた数の和」で割り切れる
  2. 1nのカードは最後の2枚になるまで残す

この時、条件を満たしながらカードがなくなるまで取り除くことができるようなnは無数に存在するか?

くどーさんは条件を満たすnとして3,6を見つけています。またn10では条件を満たすnは存在しないことを数値計算で確かめてもらった記憶がある、と述べています。

これに関し私は以前数値計算を行いました: 「くどー問題」の数値計算

この記事では3n500の範囲で数値計算を行い条件を満たす数を探索しましたが、3,6以外見つけることはできませんでした。

今回はJuliaというコンピュータ言語を用いて3n5000までの範囲の殆どの数(※20個を除く)に関して検証を行いました。結果は以下です:

3n5000において3,6以外条件を満たす数はみつかっていない
(※そのうち20個のnに関しては条件を満たすか否か判明していない)

本記事ではこれに関して説明します。前回同様、今回も整数論的考察はないです。また前回の記事は読まなくても大丈夫です。

用語の定義

まず議論に必要な用語を定義します。

議論に必要な用語
  1. 以下nは最大のカードの番号を表す

  2. 以下mはカードを取り除く枚数を表す。取り除くことを以下「削除」と呼ぶ。各nに対しm1mn2 (mN)の値を取る

  3. 番号の削除の列を[a1,a2,a3,,am]のように四角カッコで表すことにする。ここでa1,,am2からn1のどれかの数字(重複はない)であり、左の数字から初期のカードの集合{1,2,,n}の対応する要素を削除していく。
    以下の条件を満たすとき[a1,a2,a3,,am]を「可能な削除列」と呼ぶことにする:

    [a1,a2,a3,,am]に含まれる数字を{1,2,,n}から削除した数字の集合をMとして、iMi3iMiで割り切れる。さらに1lmを満たすすべての整数lに対して[a1,,al]も同様の条件:「[a1,,al]に含まれる数字を{1,2,,n}から削除した数字の集合をMとして、iMi3iMiで割り切れる」を満たす

    例えばn=6の場合、可能な削除列は各mで以下のようになる:

    m可能な削除列
    1[3]
    2[3,4]
    3[3,4,5]
    4[3,4,5,2]

    n=6では削除の各段階で1通りしか可能な削除列が存在しないが、一般には複数存在する。

  4. Delete(n;m)を「n枚のカードからm枚を削除するときの可能な削除列の集合」とする。n=6,m=4なら上記のとおり
    Delete(6;4)={[3,4,5,2]}
    である。もっと非自明な例として、n=19,m=15の場合は
    Delete(19;15)={[15,4,5,6,7,8,9,10,11,12,13,14,16,2,18],[15,4,5,6,7,8,9,16,18,12,3,17,10,11,13],[15,4,5,6,7,8,9,16,18,12,3,17,10,11,14],[15,4,5,6,7,8,9,16,18,12,3,17,10,14,11],[15,4,5,6,7,8,9,16,18,12,10,17,3,11,13],[15,4,5,6,7,8,9,16,18,12,10,17,3,11,14],[15,4,5,6,7,8,9,16,18,12,10,17,3,14,11],[15,4,5,6,7,9,8,10,11,12,13,14,16,2,18],[15,4,5,6,7,9,8,16,18,12,3,17,10,11,13],[15,4,5,6,7,9,8,16,18,12,3,17,10,11,14],[15,4,5,6,7,9,8,16,18,12,3,17,10,14,11],[15,4,5,6,7,9,8,16,18,12,10,17,3,11,13],[15,4,5,6,7,9,8,16,18,12,10,17,3,11,14],[15,4,5,6,7,9,8,16,18,12,10,17,3,14,11]}
    である。

  5. Remain(n;m)を「n枚のカードからm枚を取り除いたときに可能な残りのカードの組み合わせの集合」とする。例えばn=19,m=15の場合
    Remain(19;15)={{1,3,17,19},{1,2,14,19},{1,2,13,19}}
    である(残ったカードに関してはその数字の並び方は重要ではないので集合の記号{}で表す)。

  6. |A|Aは有限集合)はAの要素の数を表す:|Delete(6;4)|=1, |Delete(19;15)|=14, |Remain(19;15)|=3

  7. mmax(n)を「あるnに対し|Remain(n,m)|1を満たす最大のm」とする(|Remain(n,1)|=0の場合mmax(n)=0とする)。例えば
    mmax(3)=1, mmax(4)=0, mmax(5)=0,mmax(6)=4,
    となる。これは「可能な削除列が存在する最大のm」である。mmax(n)=n2なら最後までカードを削除できる。

以上からくどーさんの提示した問題は

mmax(n)=n2となるnは無限に存在するか?」

と言えます。

数値計算の概要

計算アルゴリズムは単純です。集合{1,2,,n}から要素を1つづつ取り除いて条件を満たすか確認し、Remain(n;m)を各mで逐一構成することでmmax(n)を計算します。

前回の記事ではすべてのDelete(n;m)を計算しました。しかしそれだと計算量が膨大になります(前章のDelete(19;15)Remain(19;15)を比較してみてください)。そこで今回は基本的にRemain(n;m)のみ計算し、そこに至るまでの経路(=Delete(n;m))は必要な場合だけ計算しました。 

結果

mmax(n)n依存性

まずmmax(n)nに対してプロットしてみます。

!FORMULA[100][1749414206][0]と!FORMULA[101][38042][0]の関係 mmaxnの関係

図1は各nに対するmmaxのグラフです。青の点がmmax(n)、緑の線はmmax(n)=n2のグラフです。この線に青点が乗れば、そのnは最後までカードを削除できる数字です。オレンジの上向き三角形は探索が終了していないnに対するmmaxの下限を示しています。つまりこれらのnではmmaxはこれより大きいことしか判明していません。

図1の詳細は下のリンクのグラフからアクセスすることができます:

インタラクティブなグラフ(図1)

このグラフは拡大・縮小することができ、かつ各データポイントにカーソルを重ねればそのデータの(n,mmax(n))が表示されます(計算の終わってないデータでは(n,inf(mmax(n)))が表示される)。

これらより以下がわかります:

  1. いまのところ3,6以外で条件を満たす数は見つかっていない。特に7n1331には条件を満たす数は存在しない
  2. 多くのnmmax0または2である。ある程度大きなnではmmaxnに対し0,0,2,2,0,0,2,2,のように0と2がそれぞれ2回づつ繰り返される傾向が見られる
  3. mmax(n)=n/2付近にmmaxが存在する一連のnが存在する。ある程度大きなnに対するmmaxは0付近またはn/2付近以上に存在し、「ギャップ」が見られる

これに関してコメントです:


  • 1.に関して

    7n5000の間では以下の20個のn(図1のオレンジ三角):

    1322,1456,1567,1586,1979,2203,2261,2522,2639,2882,3135,3266,3503,3535,3551,3699,3799,3815,4562,4928

    を除き、条件を満たす数字は存在しないことがわかっています。上記のnでは多くの削除のパターンが存在するため計算量が非常に大きくなり探索が完了していません。

  • 2.に関して

    以下にmmax=0,0,2,2,の繰り返しが起こる典型的な図を示します:

!FORMULA[134][-1207803673][0]の構造を持つ部分の拡大図 mmax=0,0,2,2,の構造を持つ部分の拡大図

このような周期的な変化は、nがある程度大きくなれば普遍的に現れます。よろしければインタラクティブな図を拡大して確認してみてください。

  • 3.に関して
  • mmax=n/2付近に存在するnは、|Remain(n;m)|およびDelete(n;m)も特徴的な性質を持ちます。これに関しては次章で述べます。
    ギャップに関しては、探索が終了していないnmmaxが0からn/2の中間付近の値を持つ可能性はあり、そうであればギャップはそれほど明確ではなくなります。しかしながら、探索の終了していないn|Remain(n;m)|があるmから指数的に大きくなり、経験的にはその場合n/2より有意に小さなmmaxをもつことはないです。なのでギャップの存在はロバストであるように思います。あくまで予想ではありますが。

2.3.は何らかの理論的背景を持つと思うのですが、いまのところよくわかりません。

「カードの削除数」と「残りのカードの可能な組み合わせの数」の関係

次にm|Remain(n;m)|の関係を見てみます。すなわち各nにおける「カードの削除数」と「残りのカードの可能な組み合わせの数」との関係を調べてみます。

nがある程度大きい時、m vs |Remain(n;m)|は次の4つのパターンに分けられます:

  1. mmax=0,1,2,3程度で終わるため、|Remain(n;m)|m依存性を見る意味があまりない
  2. mmax=n/2付近にmmaxを持ち、|Remain(n;m)|はずっと1程度
  3. mmax=n/2の線より有意に大きいmmaxを持ち、|Remain(n;m)|はずっと1程度
  4. mmax=n/2の線より有意に大きいmmaxを持ち、|Remain(n;m)|はあるmまで1程度であり、その後指数的に大きくなる

1.は図1のmmax0に存在する点です。殆どのnはこれに分類されます。
2.の典型的なnは例えばn=4407mmax=2146)であり、m vs Remain(4407;m)をプロットすると次の図のようになります:
!FORMULA[177][-1046181974][0]における!FORMULA[178][38011][0] vs !FORMULA[179][-788139588][0] n=4407におけるm vs |Remain(n;m)|
図3のように殆どのmに対してRemain(4407,m)1、時に2になることがあり、そしてそのような小さい値を保ったまま最終的にゼロになります(※ゼロの点は示されていません。一番右側の点がmmax=2146)。

mmax=n/2より有意に大きなmmaxをもつnの場合、2.と同様にRemainが小さい値を保ったままゼロになる場合と、途中で指数的に大きくなる場合の2つに分けられます。3.は前者であり、例えばn=1035,1961はその例です。n=1961の図をプロットすると以下のようになります:
!FORMULA[191][-1048798002][0]における!FORMULA[192][38011][0] vs !FORMULA[193][-788139588][0] n=1961におけるm vs |Remain(n;m)|

これは図3と同様の振る舞いです。n=4407よりは|Remain|が2になる回数は多いですが、結局小さい値を保ったままゼロになります。

一方4.の例はn=703,735,799,839,935,1203,1379,3959,4255などです。この場合mmaxが指数関数的に増加したのちにゼロになるまでの振る舞いに違いがあります。そのうち典型的なn=703,1203,4255を図示します(y軸logプロットです):

!FORMULA[200][797621789][0]における!FORMULA[201][38011][0] vs !FORMULA[202][-788139588][0] (!FORMULA[203][38383][0]軸 log scale) n=703におけるm vs |Remain(n;m)| (y軸 log scale)
!FORMULA[204][-1049012243][0]における!FORMULA[205][38011][0] vs !FORMULA[206][-788139588][0] (!FORMULA[207][38383][0]軸 log scale) n=1203におけるm vs |Remain(n;m)| (y軸 log scale)
!FORMULA[208][-1046236813][0]における!FORMULA[209][38011][0] vs !FORMULA[210][-788139588][0] (!FORMULA[211][38383][0]軸 log scale) n=4255におけるm vs |Remain(n;m)| (y軸 log scale)

図5,6,7に対応するインタラクティブなグラフへのリンクも貼っておきます:

n=703では指数的増加ののちすぐにmmaxがゼロになります。n=1203では一度小さくなってからもしばらくある程度の値を保ち、そして最後は急激に小さくなってゼロになります。n=4255では指数増加する領域が2つあり、小さくなってからもある程度の値を保つ領域を経てゼロになります。

exponentの計算

ここで指数的増加のexponentを求めてみます。指数的増加を示す領域において2点をとりexponent bebmで振る舞う)を計算します。そのような領域が複数存在する場合はそれぞれの領域で別々にbを求めます。さらにα:=ebとすると、αmに対する|Remain(n;m)|の平均的な増加率:|Remain(n;m+1)|/|Remain(n;m)|の指標となります。 以下の表がb,αの計算結果です:

nregion(m1,|Remain(n;m1)|)(m2,|Remain(n;m2)|)bα703(100,53)(318,83938)0.033801.0349351(421,34262)(442,63172)0.029131.0302(445,35519)(469,57558)0.020111.0203(469,57558)(498,98108)0.018391.0191203(498,48)(560,393)0.033911.03439591(1810,27)(1868,89)0.020571.0212(2017,160)(2120,689)0.014181.01442551(1900,100)(2070,1373)0.015411.0162(2204,3108)(2382,33128)0.013291.013

b,αを求めるのに2点(m1,|Remain(n;m1))(m2,|Remain(n;m2))を用いています。"region"は指数的増加領域が複数ある場合の各領域を示しています。αの値より、指数増加領域ではmが1増えるとき|Remain(n;m)|は平均してだいたい1から3%程度増加することがわかります。

注意してほしいのは、この増加率は|Delete(n;m)|の増加率とは違うことです。前回の記事で調べたnの範囲(n500)では|Delete(n;m+1)|/|Delete(n;m)|は1.2から1.4程度でした。今回はちゃんと計算していませんが、n1000から5000くらいでもおそらく同じようなものだと思います。これが示しているのは、違うRemain(n;m)の要素の違う数字の削除が同じRemain(n;m+1)の要素をもたらすことがけっこうある、ということです。実際今回の数値計算においてRemain(n;m)の要素に対して削除作業をすると同じRemain(n;m+1)の要素に行き着くものが多くあるので、そのredundancyを取り除く作業をしています(「定義1」の4.と5.に示したRemain(19;15)Delete(19;15)を比較してみてください)。

Delete(n;m)m依存性

これは前回の計算でもわかっていたのですが、mmaxがある程度大きくなるようなnではDelete(n;m)は非常に特徴的な振る舞いをします。言葉で言うよりDelete(n;m)を見たほうが早いので、幾つか具体的に例を示してみます。まずn=19,59,119m=mmaxにおけるDelete(n;mmax)(の一部)を示します:

      - n=19, m=14(=mmax):
[15, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 2, 18] 
[15, 4, 5, 6, 7, 8, 9, 16, 18, 12, 3, 17, 10, 11, 13] 
[15, 4, 5, 6, 7, 8, 9, 16, 18, 12, 3, 17, 10, 11, 14]
[15, 4, 5, 6, 7, 8, 9, 16, 18, 12, 3, 17, 10, 14, 11]
[15, 4, 5, 6, 7, 8, 9, 16, 18, 12, 10, 17, 3, 11, 13]
[15, 4, 5, 6, 7, 8, 9, 16, 18, 12, 10, 17, 3, 11, 14]
[15, 4, 5, 6, 7, 8, 9, 16, 18, 12, 10, 17, 3, 14, 11]
[15, 4, 5, 6, 7, 9, 8, 10, 11, 12, 13, 14, 16, 2, 18]
[15, 4, 5, 6, 7, 9, 8, 16, 18, 12, 3, 17, 10, 11, 13]
[15, 4, 5, 6, 7, 9, 8, 16, 18, 12, 3, 17, 10, 11, 14]
[15, 4, 5, 6, 7, 9, 8, 16, 18, 12, 3, 17, 10, 14, 11]
[15, 4, 5, 6, 7, 9, 8, 16, 18, 12, 10, 17, 3, 11, 13]
[15, 4, 5, 6, 7, 9, 8, 16, 18, 12, 10, 17, 3, 11, 14]
[15, 4, 5, 6, 7, 9, 8, 16, 18, 12, 10, 17, 3, 14, 11]

 - n=59 m=21(=mmax)
[30, 29, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28] 
[30, 29, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 53] 
[30, 29, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 26, 28] 
[30, 29, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 26, 53] 
[30, 29, 10, 11, 52, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28] 
[30, 29, 10, 11, 52, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 38] 
[30, 29, 10, 11, 52, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 32, 58, 57, 56, 55] 
[30, 29, 10, 11, 52, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 54, 42, 57, 55, 44] 
[30, 29, 10, 11, 52, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 54, 42, 57, 55, 56] 
[30, 29, 10, 11, 52, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 54, 42, 57, 56, 43] 
...

- n=119, m=51(=mmax)
[60, 10, 11, 12, 13, ..., 56, 57, 58, 59] 
[60, 10, 11, 12, 13, ..., 56, 57, 58, 94] 
[60, 10, 11, 12, 13, ..., 37, 38, 39, 94, ..., 56, 57, 58, 40]
...
    

n=19ではすべてのDelete(n;mmax)n=59,119では一部のDelete(n;mmax)を示しました。これをみると

最初1つ(または2つ)の削除可能な数字があり、その次から連続した整数が並ぶ。最初に削除可能な数字はnが大きいとn/2に近い。

という特徴があることがわかります。

次にDelete(n;m)m依存性をmが小さな領域で見てみます。例えばmmaxn/2上に存在するnであるn=1239に関してこれを見てみると以下のようになります:
m=1:Delete(1239;1)={[620]}m=2:Delete(1239;2)={[620,31]}m=3:Delete(1239;3)={[620,31,32]}m=4:Delete(1239;4)={[620,31,32,33]}m=275:Delete(1239;275)={[620,31,32,33,,303,304]}m=276:Delete(1239;276)={[620,31,32,33,,303,304,305],[620,31,32,33,,303,304,1015]}
これも最初の削除可能な数字が6201239/2であり、次に31,32,...と続き、実にm=275まで連続した数字が並びます。しかもm=275までは可能な削除列は1つだけであり、m=276になって初めて2つ現れます。

これらの傾向はmmaxが大きくなるnに関してかなり普遍的に当てはまります。またこれはなんとなくなのですが、そのようなnは一桁目が97であることが多いように見えます(インタラクティブなグラフで確認してみてください)。

まとめ

くどーさんのご提案された問題: そろそろ誰かに解いてほしい自作問題(未解決) をJuliaによる数値計算により調べました。その結果以下の結果を得ました:

  • 3n5000の範囲でくどー条件を満たす数は見つからなかった(※20個だけ条件を満たすか判明していない数が存在する)
  • 多くのnmmaxは0または2。ある程度大きなnにおいて、mmax(n)nに対し0,0,2,2,0,0,2,2,...のように0と2がそれぞれ2回づつ繰り返される振る舞いをもつ
  • mmax(n)=n/2付近にmmaxをもつ一連のnが存在する。ある程度大きなnmmax0付近またはn/2付近以上に存在し、ギャップが見られる
  • ある程度mmax(n)が大きくなるnにおける|Remain(n;m)|mに対する振る舞いは、ずっと1のオーダーでそのままゼロになるか、またはあるmから指数的に大きくなるかの2つに大きく分類される。そのうち指数的に増加する場合、その指数的増加領域における|Remain(n;m+1)|/|Remain(n;m)|はだいたい1.01から1.03である。
  • mmaxが大きくなるnDelete(n;m)は、その要素の削除列を見ると、連続した整数が出現する。削除列の最初の数はnが大きい時ほぼn/2

これらの現象の理論的背景はいまのところわかりません。

くどーさんのオリジナルの問題「条件を満たしながらカードがなくなるまで取り除くことができるような𝑛は無数に存在するか?」ですが、これに関しても今のところ何も言えないです。数値計算でこれにアプローチするには、条件を満たすnを数多く求め、あるnまでで条件を満たす数の出現頻度を求めることが必要かと思います。また条件を満たす数の何らかのルールを見出すことが重要です。しかし今のところ3,6以外で条件を満たす数が求まっていないです。まずは6より大きな数で条件を満たすものを見つけるのが目標かと思います。ただ数値計算では、アルゴリズムに何らかの根本的な工夫をするか、または大規模計算機を使わないとこれ以上はなかなか厳しいかもしれません。

あと逆方向に探索することもできることを付記しておきます。これは{1,n}のカードの集合にカードを付け加えながら3乗和が1乗和で割り切れるか調べ、最終的に集合が1からnのカードすべてを持つかどうかを確認する探索法です。前回の記事ではこれを行ったのですが、非常に多くのパターンが現れるため数値計算が重くなりあまり有効ではありませんでした。ただ、前回は違う「付け加え」で結局同じ状態に行き着く場合の重複を除かずに計算していたので、これを取り除くと計算が軽くなるかもしれません。計算が非常に重くなるnに対しては、両方向から計算し、mn/2のところで両者を比較することで完全なカードの取り除きが可能か調べるのもよいかもしれません。

個人的な感想ですが、この問題が何らかの物理系と対応がつくと面白いように思います。テキトーな話ですが、「割り算の余り」と関係するといえば磁場中の量子系のエネルギー準位が思い浮かびます。Aharanov=Bohm効果、Diracの量子化条件のように、磁場中の半古典的な量子化条件では「割り切れる」ことが重要です。また量子ホール効果のエネルギー準位にも「余り」が登場します。しかしながら、1からnの3乗和が現れ、それを1乗和で割った余りがエネルギー準位や量子化条件等に現れるような物理系は存在するでしょうか...。

おしまい。

Appendix

Juliaのコード

Juliaは2012年に最初のバージョンがローンチされた比較的新しいコンピュータ言語ですjulia。Pythonと似通った言語でありながらCやfortranに匹敵するほど計算が高速であるという特徴を持ちます。Pythonを使える人ならJuliaもすぐに使えるようになると思います。

参考までに今回使用したコードをGistにアップロードしましたjulia_code。使い方を以下に説明します

コードおよびパラメータの設定に関する説明

本コードは与えられたnに対してRemain(n;m)を計算します。計算量が大きくなる場合を想定し、mにも範囲を設け、その範囲で計算して結果をファイルに出力します。そしてファイルから結果を読み出すことで計算を途中から再開できるようにしてあります。

本コードには5つのパラメータを入力する必要があります:

  1. n_threads: スレッド並列の並列数
  2. n: 本文のn(カードの枚数)
  3. mmin_file: 読み取りファイルのファイル名に記載されているmの最小値 (ファイルがない場合1にする)
  4. mmax_file: 読み取りファイルのファイル名に記載されているmの最大値 (ファイルがない場合1にする)
  5. mmax: 計算するmの最大値(※本文におけるmmaxとは関係ないことに注意)

1.はマシンの環境等に合わせて設定してください。2.5.は説明の必要はないと思います。
3.4.は説明が必要です。例えばn=703m1から100まで計算したいとします。初めて計算する場合
n_threads=4 ※これはご自身の環境に合わせて設定してください
n=703
mmin_file=1
mmax_file=1
mmax=100
とします。mmin_file=mmax_file=1とすると、ファイルからデータを読み出さず、最初から(m=1から)計算を行います。計算が終わると
KudoProb_n-703_mmin-1_mmax-100.dat
というファイルが作成されると思います。
この結果を用いてn=703m101から200まで計算したいとします。その場合は上記ファイル名の1と100をmmin_filemmax_fileに設定してください:
n_threads=4
n=703
mmin_file=1
mmax_file=100
mmax=200
このときコードはKudoProb_n-703_mmin-1_mmax-100.datからm=100における計算結果を読み出し、m=101から計算を開始し、m=200まで計算します。
設定したmmaxまでで計算が終了した場合(すなわち本文のmmaxがパラメータ名のmmaxよりも小さいとき)、ファイル名に"_finished"が添付されます。例えばn=1000の場合、mmax=1(※本文のmmax)なので
n_threads=4
n=1000
mmin_file=1
mmin_file=1
mmax=100
とすると計算はm=2までで終了します。このとき作成されるファイルは
KudoProb_n-1000_mmin-1_mmax-100_finished.dat
という名前になります。

アウトプットファイルの中身

アウトプットファイルはHDF5という形式で作成されます。Juliaでなくとも扱えるファイル形式かと思います。
juliaのREPLというインタラクティブなモードでファイルの構造を見てみます(n=27、最初に"using HDF5"というコマンドを実行しておく):

      julia> file_open = h5open("KudoProb_n-27_mmin-1_mmax-100_finished.dat","r")
🗂️ HDF5.File: (read-only) KudoProb_n-27_mmin-1_mmax-100_finished.dat
├─ 🔢 list_length_pos_list
└─ 🔢 m_final
    

list_length_pos_listには、各mに対する|Remain(n;m)|が記されています:

      julia> list_length_pos_list = read(file_open,"list_length_pos_list")
2×9 Matrix{Int64}:
1  2  3  4  5  6  7  8  9
1  1  1  2  1  1  1  1  0
    

データは行列の形で保存されており、1行目がm、2行目がそのmに対応する|Remain(n;m)|です。m_finalは初めて|Remain(n;m)|=0となるmであり、つまりはmmax+1です:

      julia> m_final = read(file_open,"m_final")
9
    

計算が終わらなかった場合は以下のような構造を持つファイルが出力されます:

      julia> file_open2=h5open("KudoProb_n-143_mmin-1_mmax-100.dat","r")
🗂️ HDF5.File: (read-only) KudoProb_n-143_mmin-1_mmax-100.dat
├─ 🔢 list_length_pos_list
├─ 🔢 m_final
└─ 🔢 pos_list
    

計算が終わらなかった場合はm_finalには入力したmmaxが代入されます。またこの場合、m=mmaxにおけるRemain(n;m)もpos_listという名前で保存されます。このファイルは時にかなり大きなサイズになるので(今回計算した範囲だと1GB程度になることもある)ご注意ください。

ソースファイルで修正を施すべき箇所

ソースファイルで変更するべき場所は2箇所(以下でDirectInput()を有効化した場合は144-152行目も)です。

1箇所目

166,167,168行のうち1つを有効化します(=どれかひとつだけコメントアウト記号#を外す)

  • DirectInput()を有効化した場合、インプットパラメータとしてソースファイル中の144-152行に記述されたものを読み取ります。よってこの場合144-152行のインプットパラメータを書き換えてください。
  • ArgInput()を有効化した場合、インプットパラメータをjuliaコマンドに与えられた値から読み取ります。juliaコマンドへ引数を渡すには以下のようにします:
      julia calc_KudoProb_parallel.jl (n_threadの値) (nの値) (mmin_fileの値) (mmax_fileの値) (mmaxの値)
    
  • StandardInput()をactivateした場合、インプットパラメータはコード実行時に標準入力から入力します。この場合、コードを実行してから指示に従ってこれらの値を入力してください。

多くのnに対して計算を行う場合はArgInput()を有効化し、juliaコマンドを様々なパラメータに対してシェルスクリプトに記述し、そのシェルスクリプトを実行するのがよいと思います(プロセス並列もできるし)。

2箇所目

170行目のpath_fileを設定します。この変数にデータファイルを保存するディレクトリを指定します。

基本的にはこれ以外の部分を変更する必要はないです。

その他注意

  1. スレッド並列化しています。でもそれほど速くはなりません(4スレッド、8スレッドでも倍の速さにはならない)。たぶんもっとよい並列化の方法があると思います。またGoogle Colaboratoryで計算していると時折segmentation faultにより計算がダウンします。おそらく並列化の影響だと思うのですがよくわかっていません(スタック領域の問題?)。Colaboratoryでも計算は他のマシンでのJuliaによる計算結果およびPythonでの計算結果を再現しているので信用できると思いますが、完全な保証はできませんのでご注意ください。
  2. 特定のnでは取り除きのパターンが非常に多くなり計算が大変重くなります。そのため保存ファイルの大きさが1GB近くになる場合があるのでご注意ください。
  3. リストの要素は基本Int16で扱っています。よって扱えるnの上限は2151=32,767ですのでご注意ください(1乗和・3乗和の計算では精度をInt64に変換しています)。Int32やInt64にすればもっと大きなnまで扱えますが、その場合使用メモリも保存されたデータファイルも大きくなります。
  4. ある意味重要)ソースコードは単純です。本質は"Kudo_prob_ver06Apr2024"という関数の12行目だけです。ある程度知識がある方は、ご自身で使いやすいように書き換えてもらうのがよいと思います。

参考文献

投稿日:2024428
更新日:2024430
OptHub AI Competition

この記事を高評価した人

高評価したユーザはいません

この記事に送られたバッジ

バッジはありません。
バッチを贈って投稿者を応援しよう

バッチを贈ると投稿者に現金やAmazonのギフトカードが還元されます。

投稿者

bisaitama
bisaitama
142
65086

コメント

他の人のコメント

コメントはありません。
読み込み中...
読み込み中
  1. くどー問題とその数値計算
  2. 用語の定義
  3. 数値計算の概要
  4. 結果
  5. mmax(n)n依存性
  6. 「カードの削除数」と「残りのカードの可能な組み合わせの数」の関係
  7. Delete(n;m)m依存性
  8. まとめ
  9. Appendix
  10. Juliaのコード
  11. コードおよびパラメータの設定に関する説明
  12. アウトプットファイルの中身
  13. ソースファイルで修正を施すべき箇所
  14. その他注意
  15. 参考文献