🦋

オンライン整数列大辞典(OEIS)に数列を登録してみた!

に公開
10

今回の内容は2024年12月8日の JuliaLangJa 年末 LT 大会 2024 での発表内容となります。

https://julialangja.connpass.com/event/338390/

また,Julia Advent Calendar 2024の12日目の記事となります。

https://qiita.com/advent-calendar/2024/julia

はじめに

横山 明日希(@asunokibou)さんのXのポストで次のような問題がありました。

https://x.com/asunokibou/status/1858851048510947649

(1)の\fbox{ア}\fbox{キ}に異なる自然数を入れる場合を考えます。

まずは解の1組はちょっと考えるとわかります。

「他にあるのか?あるとしたら何組あるか?」が気になりました。

Julia言語で調べてみる。

まずは,いつものようにJulia言語で調べてみることにしました。

using Combinatorics

X = [i for i =1:9] |> x->permutations(x,7)
Y = []
for x ∈ X
    if sum(i/x[i] for i=1:7) == 7
        push!(Y,x)
    end
end
Y

49-element Vector{Any}:
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 8, 5, 4, 7]
[1, 2, 4, 3, 5, 8, 6]
[1, 2, 6, 8, 5, 3, 7]
[1, 2, 6, 8, 5, 9, 3]
[1, 2, 9, 3, 6, 4, 7]
[1, 2, 9, 3, 6, 8, 4]
[1, 2, 9, 4, 3, 6, 7]
[1, 2, 9, 6, 5, 3, 7]
[1, 2, 9, 8, 3, 4, 7]

[4, 8, 9, 2, 5, 3, 6]
[4, 8, 9, 3, 6, 2, 7]
[4, 8, 9, 6, 2, 3, 7]
[6, 1, 4, 3, 5, 8, 7]
[6, 1, 9, 8, 5, 3, 7]
[6, 3, 1, 8, 5, 9, 7]
[6, 4, 9, 2, 5, 3, 7]
[6, 4, 9, 8, 2, 3, 7]
[6, 8, 9, 2, 4, 3, 7]

49通りあるようです。1組確認してみます。

このあと,たむらいつる(@tsatie) さんが n=6 のときをチェックしてくれたのですが,何か合わないような報告でした。

https://x.com/tsatie/status/1859552651232309545

個数を変化させると面白そうだったので,n=1からn=9まで調べてみました。

using Combinatorics

function c(n)
    X = [i for i =1:9] |> x->permutations(x,n)
    Y = []
    for x ∈ X
        if sum(i/x[i] for i=1:n) == n
            push!(Y,x)
        end
    end
    Y |> length
end

for i = 1:9
    print("$(c(i)),")
end

1,1,3,6,15,38,49,29,1,

とでできました。数列が出てくるとオンライン整数列大辞典(OEIS)で調べたくなります。そして調べてみてると

どうもデータベースになさそうです。(無かったのは初めてです)ということで登録したくなったわけです。

オンライン整数列大辞典(OEIS)に登録

アカウントの作成

まずは,アカウントを作成しました。私の所属は私立の中高なので,その所属で登録することにしました。

シーケンスの登録

数列を登録し,Julia言語での構成も登録しました。

議論開始

すると,数列の説明の文章を直していると,Michel Marcusさんから

「数列はc(n)じゃなくてa(n)がいいよ。この数列はこれで終わり?有限?」

と質問がありました。そこで,数列をc(n)からa(n)に修正して

「シーケンスはc(n)からa(n)に変更しました。このシーケンスは有限ですが、拡張できます。現在、1桁の数字1から9までからn個の整数を選択し、それらを順列に並べることによって形成されています。しかし、これは代わりに1からmまでの数字を選択することで一般化できます。mの値ごとに、有限列が生成できると思います。」

と返しました。

三角形の行で読み取るシーケンス:T(n,k)への変更

今度は,Andrew Howroyd さんからいくつかの提案がありました。

  • 「ASCII文字のみにしてください。(特別な下付き文字/上付き文字ではありません)」

  • n=1...9からの制限が取り除かれれば、これははるかに良いだろうと考えます。それはどのように数字を変えますか?それ以外の場合は、n がシーケンスの長さであり、数字が 1..k. から選択される三角形 T(n,k) を作成します。 (これはあなたが持っているものに最も近いでしょう)

  • 例のセクションは醜いです。(結果のプレゼンテーションを無視することはできません)。プログラムから配列を出力するだけではありません。例:a(3) = 3の解は1/1 + 2/2 + 3/3 = 1/1 + 2/4 + 3/2 = 1/2 + 2/1 + 3/6 = 3です。目に優しいと思います。

なるほど,こうやっていろんな方が指摘してくれるのか。ありがたい!

function T(n,k)
    X = [i for i =1:n] |> x->permutations(x,k)
    Y = []
    for x ∈ X
        if sum(i/x[i] for i=1:k) == k
            push!(Y,x)
        end
    end
    Y |> length
end

for i = 1:9
    print("$(T(9,i)),")
end

1,1,3,6,15,38,49,29,1,

数列が違う!

このあと,Andrew Howroydさんから,びっくりする連絡が来ました。私の提示したシーケンスが合わないということでした。
私が提案したのは

「1,1,3,6,15,38,49,29,1,」

でしたが,

「1,1,3,6,16,40,54,30,1,」

でわないか?との指摘でした。

自分のコードを見直してみたのですが,

i/x[i]は誤差が出るのでは?と思って,i//x[i]として有理数で計算することにしました。

function T(n,k)
    X = [i for i =1:n] |> x->permutations(x,k)
    Y = []
    for x ∈ X
        if sum(i//x[i] for i=1:k) == k
            push!(Y,x)
        end
    end
    Y |> length
end

for i = 1:9
    print("$(T(9,i)),")
end

1,1,3,6,16,40,54,30,1,

確かに違っている。何が足りなかったかは後で検討することにして,まずは修正をしました。

修正するときに,「この数列だったら,すでにOEISに存在するのでは?」と思って,チェックしたのですが,このシーケンスも存在しなかったので,ちょっと安心しました。

DATAの修正,例示の作成

Andrew Howroyd さんが,DATAを三角形の行で読み取るシーケンスに直してくれたり,例示のテーブルを作ってくれたり,PARIのコードを書いてくれました。

n=10から13 まで拡張する

今度はAlois P. Heinz さんがT(n,k)n=10から13のときのシーケンスを調べてくれました。
私のPC(M1のMacBookPro)では,n=12あたりから時間がかかっていて,n=13は試してません。

ついに承認!

管理者のN. J. A. Sloaneさんから承認の連絡が2024/12/3にありました。やった!

コードの追加

この後,Chai Wah Wu さんがpythonのコードを追加してくれました。

A378322

今回登録したシーケンスの番号はA378322です。

https://oeis.org/A378322

やりとりをざっくり紹介してきましたが,編集履歴はこちらからみることができます。

https://oeis.org/history?seq=A378322&start=0

まとめ

シーケンスは何が違っていたのか?

i/x[i]i//x[i]でチェックしたのですが,ずれていたのは5つの順列でした。

using Combinatorics

X = [i for i =1:9] |> x->permutations(x,7)
Y = []
for x ∈ X
    if sum(i/x[i] for i=1:7) == 7
        push!(Y,x)
    end
end
Z = []
for x ∈ X
    if sum(i//x[i] for i=1:7) == 7
        push!(Z,x)
    end
end
set_Y = Set(Tuple.(Y))
set_Z = Set(Tuple.(Z))
difference = setdiff(set_Z, set_Y)

Set{NTuple{7, Int64}} with 5 elements:
(3, 1, 2, 8, 5, 9, 7)
(1, 4, 2, 8, 3, 9, 6)
(1, 2, 9, 8, 5, 3, 6)
(1, 3, 4, 2, 6, 8, 7)
(2, 1, 9, 8, 5, 4, 6)

和をとって,計算すると今回は無視できない誤差だったようです。

for x ∈ difference 
    println("有理数は$(sum(i//x[i] for i=1:7)),実数は$(sum(i/x[i] for i=1:7))")
end

有理数は7//1,実数は7.000000000000001
有理数は7//1,実数は7.000000000000001
有理数は7//1,実数は7.000000000000001
有理数は7//1,実数は6.999999999999999
有理数は7//1,実数は7.000000000000001

気づいたこと

Andrew Howroyd さんがテーブルを作ってくれました。(n=9まで)
n=13までテーブルを書いてみました。

T(n,k) k = 1..n
T(1,k) 1;
T(2,k) 1, 1;
T(3,k) 1, 1, 1;
T(4,k) 1, 1, 2, 1;
T(5,k) 1, 1, 2, 1, 1;
T(6,k) 1, 1, 3, 3, 4, 1;
T(7,k) 1, 1, 3, 3, 4, 1, 1;
T(8,k) 1, 1, 3, 5, 10, 11, 12, 1;
T(9,k) 1, 1, 3, 6, 16, 40, 54, 30, 1;
T(10,k) 1, 1, 3, 7, 25, 88, 184, 206, 102, 1;
T(11,k) 1, 1, 3, 7, 25, 88, 184, 206, 102, 1, 1;
T(12,k) 1, 1, 3, 13, 56, 244, 744, 1329, 1623, 746, 749, 1;
T(13,k) 1, 1, 3, 13, 56, 244, 744, 1329, 1623, 746, 749, 1, 1;

nが1変化するときにあまり変化がない(末尾に1を加えるだけ)となっているのは

  • n=1からn=2
  • n=2からn=3
  • n=4からn=5
  • n=6からn=7
  • n=10からn=11
  • n=12からn=13

の時です。変化した後のnが素数のようですね。そうすると,オイラーのトーシェント関数あたりが関係しているかもしれませんね。

今後について

やっぱり,数学的に個数を考えたいですね。漸化式や生成関数(母関数)が見つかると最高です!

Discussion

Y.K.Y.K.

記事読ませていただきました
三角数という言葉は既に存在します
https://ja.wikipedia.org/wiki/三角数
途中混同してしまったので別の呼び方に変えたほうが記事が読みやすいかもしれません

清水団清水団

ご指摘ありがとうございました。三角数という呼称はやめて「三角形の行で読み取るシーケンス(Triangle read by rows)」に変更しました。「パスカルの三角形」が有名ですよね。OEISではtablというキーワードで分類されています。

https://oeis.org/wiki/Keywords

Y.K.Y.K.

Triangle read by rowsすごくあっていていいと思います!
対応して頂きありがとうございました!

kzaukzaukzaukzau

Aをn次の置換行列
Bを(1,2,,,,n)を対角成分とするn次対角行列
P_kを(1,1,,1,0,0,0)を1がk個0がn-k個並べたn次対角行列、

Tr(P_kBAB^{-1}A^{-1})=k

を満たす、置換行列Aの個数/(n-k)!がこの記事の数列であるところまでは分かった。

清水団清水団

素晴らしい!
確認してみますね。
数式化されると大きい数へのアプローチも可能になります。
ありがとうございます。

kzaukzaukzaukzau

Xをすべての成分が1のベクトル、
〈,〉を内積
Eを単位行列

F(A)=〈P_kX,BAB^{-1}X〉

F(A)を定義すると

F(A)=F(E)

を満たす置換行列Aの個数/(n-k)!

でも同じ計算

kzaukzaukzaukzau

ちょっと長いけど、n次正方行列の行列式を使った公式を作れた。
a(i)をiがk以下でi,それ以上は0
T(i,j)= i=j なら1
i<j なら1
i>j なら-1
A(i,j,t)=T(i,j)exp(t a(i)/j)
A(i,j,t)をi,jを添字にn次正方行列に並べて、
行列式にいれると、求めている数列の(n-k)!倍がexp(kt)の係数に符号を除きなる。
ラプラス変換して、kでの留数を計算しても、係数を得られる。

外出中のため未検算

kzaukzaukzaukzau

朝はこれで行けると考えましたが、
条件を満たす、すべての置換σで

sgn(σ)\prod_i T(i,σ(i))

が等しい

なら行列式を置換で表す公式を用いて成り立つ議論でした。

nissynissy

探索してみたところ、k=14で11,13が同じとこばかりにいることに気づいたので

ということがわかりました。ここから、

もう一歩進めて、

一般化して、

また、ある程度仮置きした深いところでは

これらを枝刈りに使って、n=19まで求めました。(n\to\inftyも少し)

n\k 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
14 1 1 3 13 65 333 1238 3108 6015 9352 13003 5626 5627 1
15 1 1 3 16 86 518 2500 9452 27214 63396 128774 148399 182932 41035 1
16 1 1 3 19 102 673 3497 16120 55294 167643 435558 871666 1430445 835600 168452 1
17 1 1 3 19 102 673 3497 16120 55294 167643 435558 871666 1430445 835600 168452 1 1
18 1 1 3 23 131 939 5388 28216 118286 462406 1543940 4303791 10223610 12169300 5818790 940549 940552 1
19 1 1 3 23 131 939 5388 28216 118286 462406 1543940 4303791 10223610 12169300 5818790 940549 940552 1 1
\infty 1 1 3 44 3869 1439852

ミスってなければいいですが…

清水団清水団

ありがとうございます!素晴らしい!
OEISではn=13までなので,ぜひ,OEISに参加して拡張していただけるとありがたいです。
上記の絞り方を参考にして私も,確認してみます。