メビウス関数
数論入門とか組み合わせ論入門とかを読んでゆくと、メビウス関数というものがメビウスの反転公式とともに出てくるのですが、書いてあることがちゃお付録のおまじないブック並みに意味不明で、やる気を無くします。
http://kids.nifty.com/cs/kuchikomi/kids_bbs/list/aid_omajinai-love-01/1.htm
- メビウス関数の定義
- メビウスの反転公式
このメビウス関数
を使うと、
のとき、
となる。
以下で、やる気を出して考えてみることにします。
整数の素因数分解と分割
整数をより小さな単位に分解するとき、
- 素因数分解(積による分解)
- 分割 (和による分解)
の二つが考えられます。
分割の方は、オイラーの分割恒等式などで出てくるように、べき級数 () の母関数というものを利用してべき指数の和の問題として解くことができます。
これと同じように、母関数に指数的な級数 (ディリクレ級数 ) をとることで、積の問題を解くことができ、これからメビウス関数と反転公式が出てきます。
ここで、ディリクレ級数の形が分数になっていて、ちょっとイライラするのですが、元々は と
のように似た者同士でしたが、収束性を考えると、前者は
で収束しますが、後者は
と負数でないと収束しないので、それならば初めから負数と思って、分母に置くことが考えられます。ディレクレが老婆心をだしてそうしてくれたと思うと、許してやろうという気にもなります。
さて、オイラー積を考えて、全ての素数に関する積をとると、
と、素因数分解のすべての組み合わせが出るので、全正整数に関する和となってゼータ関数が出てきます。
ところで、最初の積の逆数をとると、素数のダブりが許されない積になるのですべての整数は出てきません。また掛け算回数の偶奇性によって符号も変わることになります。これが丁度メビウス関数の定義に相当しています。つまり、
となります。
そうして、これらの式の左辺が丁度逆数の関係になっているので、右辺の級数同士も逆数になっているはずです。すると、ゼータ関数の逆関数は、メビウス関数が係数となったディリクレ級数であることが分かります。つまり、
となります。
また、一般のディリクレ級数
に対して、
すなわち、
の関係が成り立つとすると、
より、対応する指数の項を比較して、
となります。一方、逆関数の式からは、
となるので、対応する指数の項の比較から、
または、
が求まります。
以上により、母関数の方法によりメビウスの反転公式が示されました。
結局、分割の問題も、基本対称関数と同次対称関数の関係も、母関数とその逆関数の積およびそれらの級数展開の積の関係から求められており、同じ論理構造を持っていることが分かります。
Fortran でメビウス関数を使ってゼータ関数の逆数を求める
メビウス関数の求め方ですが、どの求め方が良いのかよく分からないので、
で求めます。これがメビウス関数になることは、1の n 乗根の図を描いて考えると示せます。複素数の和ですが虚部は消えるので、 を使って実数だけで、
と書きかえられます。n が大きくなると結構重い計算になります。本来は、乗法的関数なのでもっと簡単に計算できるはずですが・・・めんどくさいので力づくでw
R4.7.24 追記: 素朴計算法
fortran66.hatenablog.com
ソース・プログラム
module m_moebius implicit none real, parameter :: pi = 4 * atan(1.0) contains pure elemental integer function igcd(ia, ib) integer, value :: ia, ib igcd = ia do if (ib == 0) exit igcd = ib ib = mod(ia, ib) ia = igcd end do end function igcd pure elemental integer function moebius(n) integer, intent(in) :: n integer :: k real :: x x = 0.0 do k = 1, n if (igcd(k, n) == 1) x = x + cos(2 * pi * k / n) end do moebius = nint(x) end function moebius end module m_moebius program zeta use m_moebius implicit none integer, allocatable :: m(:), moe(:) integer :: i, n real :: x, s ! zeta(2) = pi^2/6 x = 0.0 s = 0.0 do i = 1, 10000 x = x + moebius(i) / real(i)**2 s = s + 1.0 / real(i)**2 end do print *, x, 6.0 / pi**2, s, pi**2 / 6 print *, 'zeta(2)^-1 * zeta(2) =', x * s print * ! zeta(3) = Apery's constant x = 0.0 s = 0.0 do i = 1, 1000 x = x + moebius(i) / real(i)**3 s = s + 1.0 / real(i)**3 end do print *, x, 1.0 / 1.20205690, s, 1.20205690 print *, 'zeta(3)^-1 * zeta(3) =', x * s end program zeta