リーマンゼータ関数とリーマン予想

当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

1859年にドイツの数学者ベルンハルト・リーマン(Bernhard Riemann)によって提唱されたリーマン予想は現代 (2019年5月8日時点) でも解決に至っていない、数学の難問中の難問です。リーマン予想の意味を理解するためには、まずリーマンゼータ関数について理解する必要があります。この記事では、Python でリーマンゼータ関数を実装して「リーマン予想とは何か?」を解説します。

リーマンゼータ関数

解析的整数論において重要な位置を占めるリーマンゼータ関数(Riemann zeta function)は
 \[\zeta(s)=\sum_{n=1}^{\infty}\frac{1}{n^s}\quad (\mathrm{Re}(s)\gt 1)\tag{1}\]
によって定義されます。Scipy にはリーマンゼータ関数を計算する scipy.special.zeta() が用意されていますが、定義 (1) の $s$ に相当する引数に正の実数しか渡せないので、応用範囲が限定的です。
 
この記事では mpmath に組み込まれている mpmath.zeta() を使うことにします。mpmath は Scipy や Sympy のバックグラウンドではたらく任意精度演算パッケージです。mpmath.zeta() は解析接続によって $s=1$ をのぞく複素数全域で定義されたゼータ関数を計算できます。

mpmath.zeta(s, a=1, derivative=0)

a=1 を指定すると(デフォルトで 1 になっています)、リーマンのゼータ関数を計算します。
 
ゼータ関数は $0$ を除く偶数点 $s=2n$ で収束します。
 \[\begin{align*}&\zeta(2)=-\frac{\pi^2}{2}=1.6449\\[6pt]&\zeta(4)=-\frac{\pi^2}{90}=1.0823\\[6pt]&\zeta(6)=-\frac{\pi^2}{945}=1.0173\end{align*}\]
mpmath.zeta() を使って確認してみましょう。

# PYTHON_RIEMANN_ZETA

# In[1]

# s=2nにおけるゼータ関数の値

import mpmath
mpmath.mp.dps = 25
mpmath.mp.pretty = True

# ζ(2),ζ(4),ζ(6)
z2 = mpmath.zeta(2, 1)
z4 = mpmath.zeta(4, 1)
z6 = mpmath.zeta(6, 1)

# 計算結果を小数点以下8桁まで表示
print("ζ(2): {}".format(z2))
print("ζ(4): {}".format(z4))
print("ζ(6): {}".format(z6))

# ζ(2): 1.644934066848226436472415
# ζ(4): 1.082323233711138191516004
# ζ(6): 1.017343061984449139714518

$s=1$ はリーマンゼータ関数の極なので、mpmath.zeta(1, 1) はエラーを返します。$s=2n+1$ における値も計算しておきます。

# In[2]

# s=2n+1におけるゼータ関数の値

# ζ(3),ζ(5),ζ(7)
z3 = mpmath.zeta(3, 1)
z5 = mpmath.zeta(5, 1)
z7 = mpmath.zeta(7, 1)

# 計算結果を小数点以下8桁まで表示
print("ζ(3): {}".format(z3))
print("ζ(5): {}".format(z5))
print("ζ(7): {}".format(z7))

# ζ(3): 1.202056903159594285399738
# ζ(5): 1.036927755143369926331365
# ζ(7): 1.008349277381922826839798

リーマン予想

リーマンゼータ関数の $s=-2n\ (n\gt 0)$ は自明な零点とよばれます。
mpmath.zeta() に零点での値を計算させてみましょう。

# In[3]

# 自明な零点の計算

# ζ(-2),ζ(-4),ζ(-6)
zm2 = mpmath.zeta(-2)
zm4 = mpmath.zeta(-4)
zm6 = mpmath.zeta(-6)

print("ζ(-2): {}".format(zm2))
print("ζ(-4): {}".format(zm4))
print("ζ(-6): {}".format(zm6))

# ζ(-2): 0.0
# ζ(-4): 0.0
# ζ(-6): 0.0

ちなみに、自明な零点以外の零点を非自明な零点とよびますが、
「非自明な零点はすべて $s=1/2+ti$ の上にあるよ」
というのが、かの有名な リーマン予想 です ($i$ は虚部、$t$ は任意の実数パラメータ) 。直線 $s=1/2+ti$ のことをクリティカル・ライン (critical line) といいます。
 
非自明な零点がどのあたりにあるのか、Matplotlib でグラフを描いて調べてみましょう。横軸にはクリティカル・ライン、縦軸にはリーマンゼータ関数の絶対値 $|\zeta(s)|$ をとります。

# In[4]

# 非自明な零点の探索

import matplotlib.pyplot as plt

x = []
absz = []

t = range(0, 5000)

for q in t:
    s = 0.5 + 0.01 * t[q] * 1j
    x.append(0.01 * t[q])
    absz.append(abs(mpmath.zeta(s)))

# リーマンゼータ関数のグラフを描画
fig = plt.figure(figsize = (6, 6))
ax = fig.add_subplot(111)
ax.set_title("Absolute value of Riemann zeta Function", size = 14)
ax.grid()
ax.set_xlim(0, 40)
ax.set_ylim(-1, 4)
ax.set_xlabel("Critical Line", size = 14, labelpad = 10)
ax.set_ylabel("|ζ(s)|", size = 14, labelpad = 10)
ax.plot(x, absz, color = "darkblue")

Python リーマンゼータ関数の非自明な零点の探索
クリティカル・ライン上で $|\zeta(s)|$ が $0$ になっている点が非自明な零点です。詳しい計算によると、原点に最も近い非自明な零点は $s=1/2\pm (14.13…)i$ であることが知られています。

コメント

  1. あとりえこばと より:

    【AI連載小説】科学とコードの交差点(44)「リーマンゼータ関数」
     
    自習室で、開誠、明信、美純はリーマンゼータ関数についての学習に没頭していました。三人は真剣な面持ちでノートに数式やグラフを描きながら、基本的な概念から学んでいました。
     
    開誠:「リーマンゼータ関数は数学の中でも非常に重要な関数だ。素数の分布や解析接続、数論など、幅広い分野で使われている」
    美純:「そうだね。リーマンゼータ関数は複素数全体で定義されていて、特に実部が1/2のときに特異な性質を持つのね」
    明信:「リーマンゼータ関数の特異点が素数の分布とどう関連しているのか、それが気になるな」
    開誠:「そうだ。リーマンゼータ関数は無限の素数に関する情報を含んでいるとされている」

    三人はリーマンゼータ関数の定義から始め、特異点や関連する数学的な概念について議論しました。
     
    美純:「特に、リーマンゼータ関数の特異点がプライムナンバー定理と関連していることが興味深いなあ」
    開誠:「そうだ。実際、リーマンゼータ関数の特異点の位置が素数の分布と対応していることが示されている」
    明信:「なるほど、リーマンゼータ関数は数学の奥深さに触れるだけでなく、素数の謎にも迫るような感じだな」

    三人はリーマンゼータ関数の数学的な背景や応用について熱心に話し合い、難解なトピックにも関わらず、興味津々の表情で学習を進めていました。
     
    美純:「複素平面上でのゼータ関数のゼロ点にも注目しないといけないよね」
    明信:「確かに、ゼータ関数のゼロ点が重要な情報を持っている。リーマン予想もその一部だ」
    開誠:「リーマン予想は未だに解明されていないが、その真偽が証明されれば、数学の多くの分野に革命をもたらすだろうな」