Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

j関数と正規化されたアイゼンシュタイン級数

正規化されたアイゼンシュタイン級数を以下で定義する。
 E_k(q) = 1 - \frac {2k} {B_k} \sigma_{k-1}(n) q^{n}
 B_kは以下で定義されるベルヌーイ数である。
 \frac {x} {e^{x} - 1} = \sum_{k=0}^{\infty} B_k \frac {x^{k}} {k!}
シグマはnの全ての約数dのべきの和を取る約数関数である。
 \sigma_{k}(n) = \sum_{d|n} d^{k}
次数の小さい方から例を書くと、
 E_4(q) = 1 + 240 \sum_{n=1}^{\infty} \sigma_3(n) q^{n}
 E_6(q) = 1 - 504 \sum_{n=1}^{\infty} \sigma_5(n) q^{n}
 E_8(q) = 1 + 480 \sum_{n=1}^{\infty} \sigma_7(n) q^{n}
 E_{10}(q) = 1 -264 \sum_{n=1}^{\infty} \sigma_9(n) q^{n}
 E_{12}(q) = 1 + \frac {65520} {691} \sum_{n=1}^{\infty} \sigma_{11}(n) q^{n}
 E_{14}(q) = 1 - 24 \sum_{n=1}^{\infty} \sigma_{13}(n) q^{n}

j関数を以下で定義します。
 j(q) = 1728 \frac {E_4(q)^{3}} {E_4(q)^{3} - E_6(q)^{2}}
このj関数は複素数体 \mathbb {C}上の関数ですが、
有限体 F_q(qは素数のべき)上の楕円曲線の j = 1728 \frac {4A^3} {4A^3 + 27B^2}と本質的に等しいです。
j関数の別の表現も知られています。
 j(q) = \frac {E_4(q)^{3}} {q \prod_{n=1}^{\infty}(1-q^{n})^{24}}
この証明にはモジュラー形式(Modular Form)の理論を使います。
どちらの形もj関数の係数を求めるのに使えそうですが、2番目の方を使うことにします。
コンピュータで計算する場合のアルゴリズムを考えてみます。
1) 1変数有限次多項式を実装する。
2) 正規化されたアイゼンシュタイン級数の指定最低次数までを返す関数を実装する。
3)  q \prod_{n=1}^{\infty}(1-q^{n})^{24}を正規化されたデルタ関数 \Delta(q)と呼ぶことにして(この名前はこのブログ内でのみ通用する用語です。)
正規化されたデルタ関数 の指定最低次数までを返す関数を実装します。
4)  \frac {1} {1-x} = 1 + x + x^{2} + ... + x^{k} のようにして分母の値を指定最低次数までの分子の値して返す関数を実装する。
5) j(q) q をqの指定次数まで計算してqのべきの係数を答えとします。

### rustで実装してみた

#[test]
fn j_invariant_test1() {
    assert_eq_str!(j_invariant1(&BigInt::from(2)), "196884 x^2 + 744 x + 1");
    assert_eq_str!(j_invariant1(&BigInt::from(3)), "21493760 x^3 + 196884 x^2 + 744 x + 1");
    assert_eq_str!(j_invariant1(&BigInt::from(4)), "864299970 x^4 + 21493760 x^3 + 196884 x^2 + 744 x + 1");
    assert_eq_str!(j_invariant1(&BigInt::from(5)), "20245856256 x^5 + 864299970 x^4 + 21493760 x^3 + 196884 x^2 + 744 x + 1");
}

デバッグビルドで5次の計算で30秒くらいかかりますが、なんとか実装できました。
かなり無駄な計算をしているので、最適化の余地は残っています。

ソースはこちらです。
GitHub - pebble8888/ellipticcurve


j-不変量 - Wikipedia