mkRGB・sf・python による解析関数の複素数値分布の表示

現在のコンピュータ パワーを活用して解析関数がどのような形をしているのかをコンピュータ画面上にカラー表示します。

kkRGB.exe を使って複素数値の四次元分布をカラー表示させます。解析関数の複素数値分布は sfpython を使って計算させます。コンピュータ パワーを活用して sin(z) などの解析関数がどんな複素数値分布をしているのか見ていきます。

できましたら、皆様も御自分のコンピュータ上で計算させながら、自分で関数の種類や値域を設定し、複素数分布を計算させ、mkRGB.exe を使って表示させながら読んでいかれることを希望します。そのほうが面白いはずです。sf や mkRGB.exe はこちらからダウンロードできます。python は Enthought パッケージが、こちらからダウンロードできます。

mkRGB

コンピュータの RGB 表示をを活用して、二次元平面上に複素数変面上での複素数分布を表示させることを提案します。下に 0+0i を中心とする複素平面上の複素数値と、RGB ピクセルの対応させ方を表す「複素数値 kkRGB 地図」を示します。

    複素数値 kkRGB 地図

mkRGB.exe は sf 複素行列変数ファイルを変換して、kkRGB 図として表示させるプログラムです。100 x 200 sf 複素数行列ファイル名を引数に与えたとき、mkRGB.exe は 100 pixel 幅で 200 pixel 高さの二次元画面に表示します。個々の pixel は sf 複素行列変数の i,j 複素数値を「複素数値 kkRGB 地図」に従って RGB の色に変換し、横 i pixel, 縦 j pixel の位置に表示させます。

複素数変面上での複素数分布のデータは四次元データになります。複素関数を紙の上の図形して表示するためには、実数値の分布と虚数値の分布の二つに分けて表示する必要がありました。実数値と虚数に分けてしまうと位相の変化が分かりにくくなってしまいます。 結局、複素関数値が複素平面状でどのように分布しているのか、どのように位相が回転しているのか明確にイメージできないままでした。

mkRGB.exe を使うことで、一つの kkRGB 図に複素数値の分布を表示させることができます。解析関数の複素数値分布を直感的に把握できる形式で表示できます。

mkRGB.exe はこちらに置いてある sf12b.zip の中にあります。解凍してお使いください。

sf による複素数値分布 sf 行列変数ファイルの作成

mkRGB に与える sf 複素行列変数ファイルは sf または python で作ります。

sf による sf 複素行列変数ファイルの生成は sf の二重ループによって行列を生成することで行います。100x100 の sf 行列変数ファイルは、以下のような具合に作れます。

//@@
/s
xLeft @= -1.0
Δx @= 2.0
yUpper @= 1.0
Δy @= 2.0
N@=100
temp=<< xLeft+Δx/(2N),N, Δx/N @ x, _j|\
    << yUpper-Δy/(2N),N, -Δy/N @ y, _k|\
        !sin( (x+y i)**2 )
    >>
>>
//@@@

python まで勉強してられないときには、10 倍の計算時間が必要ですが、sf で解析関数の複素行列変数ファイルを作成してください。

python による複素数値分布 sf 行列変数ファイルの作成

python を使えば、sf よりも高速に sf 行列変数ファイルを作成できます。zeta 関数など、より広い範囲の解析関数を対象とできます。

下のような sf 複素数値行列変数ファイルを作るモジュールを使います。カレント ディレクトリに dpAnltc.py を作り、下のブロックの python code をコピー&ペーストして下さい。sfVal.py が必要となるのでこちらからダウンロードください。

# type dpAnltc.py
from scipy import reshape, zeros, log, arange, Complex64
import sfVal

def dumpFnctn(fAg,xNag=100, yNag=100, xLeftAg = -1.5, xRightAg=1.5, yUpAg = 1.5, yDownAg = -1.5):
    matrix=reshape( zeros(xNag*yNag, Complex64), (yNag,xNag) )

    for (real,n) in zip(arange(xLeftAg+(xRightAg-xLeftAg)/(2*xNag)
                              ,xRightAg,(xRightAg-xLeftAg)/xNag),range(xNag)):
        for (image,m) in zip(arange(yUpAg-(yUpAg-yDownAg)/(2*yNag)
                                   ,yDownAg,-(yUpAg-yDownAg)/yNag),range(yNag)):
            #print 'sAg:', (real,image), ' m:',m, " n:",n," ",matrix[m,n]
            matrix[m,n] = fAg(real + image*1j)
        print n
    sfVal.putSf(matrix, 'mtCplx')

def dumpLogFnctn(fAg,xNag=100, yNag=100, xLeftAg = -1.5, xRightAg=1.5, yUpAg = 1.5, yDownAg = -1.5):
    matrix=reshape( zeros(xNag*yNag, Complex64), (yNag,xNag) )

    for (real,n) in zip(arange(xLeftAg+(xRightAg-xLeftAg)/(2*xNag)
                              ,xRightAg,(xRightAg-xLeftAg)/xNag),range(xNag)):
        for (image,m) in zip(arange(yUpAg-(yUpAg-yDownAg)/(2*yNag)
                                   ,yDownAg,-(yUpAg-yDownAg)/yNag),range(yNag)):
            #print 'sAg:', (real,image), ' m:',m, " n:",n," ",matrix[m,n]
            zetaAt =  fAg(real + image*1j)
            absAt = abs(zetaAt)
            logAt = log(1+absAt)
            matrix[m,n] = logAt * zetaAt / absAt
        print n
    sfVal.putSf(matrix, 'mtCplx')

どちらの関数も、最初の引数に求めたい解析関数を指定します。二番目に行列の行サイズを指定します。kkRGB 表示の横 pixel 数と同じです。三番目に行列の列サイズを指定します。kkRGB 表示の縦 pixel 数と同じです。計算させる値息は複素平面の四角形です。四番目に四角形の左端の実数値を指定します。五番目に四角形の右端の実数値を指定します。六番目に四角形の上端の虚数値を実数値で指定します。七番目に四角形の下端の虚数値を実数値で指定します。下のような具合です

//@@
from scipy.special import sin
from dpAnltc import *
dumpFnctn(lambda z:sin(z**2), 300,300,-1.0,1.0, 1.0, -1.0)
//@@@
指定された関数の mtCplx.val という名前の複素数値 sf 行列ファイルを生成します。 それを使って mkRGB mtCplx -max:0.5 などと kkRGB 表示させます。

デフォルト引数のパラメータが設定されています。デフォルトでは 300 dot x 300 dot の pixel 数で [-1.5,1.5] x[1.5,-1.5] の領域の複素数分布を計算します。

解析関数とは

関数 f(z) が解析関数であるとき、f(z) は複素平面を定義域とし、また値粋とします関数です。z ∈ Complex & f(z) ∈ Complex です。解析関数 f(z) は特異点を除いて複素平面での微分が可能です。f(z) の微分を計算するとき Δz→0 のさせかたは実数関数のときより多くなります。そして解析関数 f(z) は

limit  (f(z0+Δz) - f(z0) )/Δz
Δz→0

具体例を考えます。sin(z) を 1+2i の位置で微分して見ます

//@@
# 実数軸の方向で Δz→0 操作を行う
z0 = 1+2i
N @= 6
θ @= 0
r  @=0.1

<<1,N,1@j|\
    r = r/10
    Δz @= r!exp(iθ)
    z@= z0 + Δz

    ( !sin(z0+ Δz) - !sin(z0) )/Δz
>>
//@@@
< 2.01686-3.06164i, 2.03114-3.05288i,   2.03256-3.052i, 2.03271-3.05191i
                                    ,  2.03272-3.0519i,  2.03272-3.0519i >

//@@
# 虚数軸の方向で Δz→0 操作を行う
z0 = 1+2i
N @= 6
θ @= `π / 2
r  @=0.1

<<1,N,1@j|\
    r = r/10
    Δz @= r!exp(iθ)
    z@= z0 + Δz

    ( !sin(z0+ Δz) - !sin(z0) )/Δz
>>
//@@@
< 2.04255-3.06778i,  2.0337-3.05348i, 2.03282-3.05206i, 2.03273-3.05191i
                                    ,  2.03272-3.0519i,  2.03272-3.0519i >
//@@
# 右斜め上から Δz→0 操作を行う
z0 = 1+2i
N @= 6
θ @= `π / 3
r  @=0.1

<<1,N,1@j|\
    r = r/10
    Δz @= r!exp(iθ)
    z@= z0 + Δz

    ( !sin(z0+ Δz) - !sin(z0) )/Δz
>>
//@@@
< 2.03327-3.07056i, 2.03278-3.05376i, 2.03273-3.05208i, 2.03272-3.05192i
                                    ,  2.03272-3.0519i,  2.03272-3.0519i >

!cos(1+2i)
< 2.03272-3.0519i >

解析関数が複素平面上で微分可能であることは、結構強い制限です。制限によって解析関数の美しい構造が導かれます。

∂f(z).real/∂z.real  ==  ∂f(z).image/∂z.image = 
∂f(z).image/∂z.real == -∂f(z).real/∂z.image = 
∂f.real(x,y)/∂x - ∂f.image(x,y)/∂y == 0
∂f.image(x,y)/∂y - ∂f.real(x,y)/∂x == 0

逆に特異点を含む二点間の積分路の差は常に一定です。解析関数の二点間の積分路の値は、特異点によって決まってしまうとも言えます。詳細は数多くの web page 教科書を参照ください。

sf での数値実験を!

解析関数の勉強をするとき、上の解析関数の微分で行ったような数値実験を行うことをすすめます。sf を使えば二点間の数値積分なぞ簡単に行えます。数値実験をしながら解析関数を勉強をしていくことで、数式だけを追っていくときよりも、より深く理解できます。無用な誤解をせずに済みます。

sf 変数ファイル フォーマット

kkRGB.exe の引数に与える sf 複素行列ファイル変数は単なるテキスト・ファイルです。sf での計算式の対象とするために定義されました。sf や sfVal.py の puSf(.) 関数で出力させれば、自動的に sf 複素行列ファイル変数のフォーマットで出力されます。 でも、このフォーマットを満たせば、他のプログラムから sf 複素行列ファイル変数を作り mkRGB.exe に kkRGB 表示させることも可能です。

このフォーマットを説明します。下に 5 x 2 の複素行列の sf ファイルの中身を例示します。

type mt.val
% BaseComplexDoubleMatrix 5,  2
< -1.010875342582172e+065 +4.234147225207233e+064i, 1.657203572139946e+064 -5.008606545684682e+064i >
< -2.254936183883746e+064 +2.884564265820551e+064i, 6.588785106281863e+064 +1.81483395600486e+065i >
< -3.307555463112328e+065 -1.96425291809001e+065i, 7.105114280752834e+064 -1.428343444730398e+064i >
< 8.538161848811448e+065 -2.761038788587805e+065i, -5.173337738213509e+063 +5.368918136753312e+064i >
< 1.08593238674481e+065 +1.128163816105048e+064i, -3.698440760957881e+065 -1.867966326505306e+065i >

最初の行の「% BaseComplexDoubleMatrix」は複素行列を示す文字列であり、そのまま出力してやらねばなりません。次の「5, 2」は、このファイルが 5 x 2 行列であることを宣言しています。スペースの入れ方は自由ですが 「,」を忘れないで下さい

二行目からが行列データです。行列の一行データを書き出して、最後に改行が追加されます。

< -1.010875342582172e+065 +4.234147225207233e+064i, 1.657203572139946e+064 -5.008606545684682e+064i >

この各行の < スペース コンマや > の記号や数値文字列の長さは同じフォーマットにする必要があります。次の規則を守って行データを文字列に変換してください。

以上のフォーマットを守って sf 複素行列ファイル作るならば、どんなプログラムによって長方形の複素数値分布データを作っても mkRGB.exe で表示させられます。

解析関数の kkRGB 表示

以下では解析関数の概要は知っているものとして、具体的な解析関数の複素数値の分布、位相回転の様子を kkRGB 表示する事で見ていきます。知ってるつもりの基本関数でも意外な性質が見えてきます。

多項式

まず最も単純である多項式の複素数値分布を見てみましょう。z^2 と z^5+2*z^4+3*z^3+4*z^2+5*z+6 の二つの多項式です。

z^2, z^-2

//@@
/s
xLeft @= -1.0
Δx @= 2.0
yUpper @= 1.0
Δy @= 2.0
N@=100
temp=<< xLeft+Δx/(2N),N, Δx/N @ x, _j|\
    << yUpper-Δy/(2N),N, -Δy/N @ y, _k|\
        z @= x+y i
#       下の行の関数形を変えてやることで任意の複素関数の値分布を計算できる
        z^2
    >>
>>
//@@@
//@@
from dpAnltc import *
dumpFnctn(lambda z:z**2, 300,300,-1.0,1.0, 1.0, -1.0)
//@@@

この dumpFnctn(.) python 関数は z^2 の複素数分布データを mtCplx.val の名前の sf 行列変数ファイルに入れています。それを下のように mkRGB で表示させます。

mkRGB mtCplx -max?
Maximum:1.98669 Column:0 Row:0

mkRGB mtCplx -max:0.1 -limit:5

-max:0.1 オプションはアナログ RGB 表示の最大値を mtCplx 行列の最大値の 0.1 倍にすることを意味します。三色の RGB を連続して混ぜ合わせるアナログ RGB 表示領域と、橙色/黄色/緑色/空色の四色のみの組み合わせで表示するデジタル RGB 領域の境界が 1.98669 * 0.1 == 0.19867 であることを意味します。-limit: オプションはデジタル RGB 表示領域と白領域との境界値を -max: 値からの倍率で設定します。この場合は 0.19867*5 == 0.99335 が、その境界における絶対値になっています。

左側の kkRGB 図形は z^2 の複素数値分布を示します。kkRGB 表示をさせているとき r キーを押すと、ピクセル値を 1/z で計算しなおした図形を描かせた右側の kkRGB 図形に換えます。右側の reversed kkRGB 図は 1/z^2 == z^-2 の複素数分布だとも言えます。

0+0i を中心に定義域を一周すると z^2 の位相は二回転、即ち 4π 回転することが解ります。z^2 は 0+0i を最小とし、そこからの距離が大きくなるほど関数値の絶対値も大きくなることが分かります。解析関数の複素数値分布の概要を kkRGB 図から読み取るとき、四色で表示されるデジタル RGB 領域が一番役立ちます。境界が明確だからです。-max: -limit: オプションの値を設定しなおしてやる事で、より細かく関数値の分布を調べられます。

z^5+2z^4+3z^3+4z^2+5z+6

z^2 よりも複雑な、重根ではない五次の多項式 z^5+2z^4+3z^3+4z^2+5z+6 の複素数値分布を求めます。

//@@
from dpAnltc import *
dumpFnctn(lambda z:z**5+2*z**4+3*z**3+4*z**2+5*z+6, 300,300,-3.0,3.0, 3.0, -3.0)
//@@@

この dumpFnctn(.) python 関数は z^2 の複素数分布データを mtCplx.val の名前の sf 行列変数ファイルに入れています。それを下のように mkRGB で表示させます。

mkRGB mtCplx -max?
Maximum:1874.06 Column:0 Row:299

mkRGB mtCplx -max:0.01

右側の kkRGB リバース図の白い点が根のある位置です。このゼロ点の周りで位相が一回転していることが分かります。左側の kkRGB 図より、この多項式を 0+0j から 3 程度離れた領域からみると、位相が 10 回転しており z^5 に近くなってきていることも解ります。

実根の位置を 0+0i にする

上の五次多項式の実根を 0+0i の位置に移してやります。根の位置の変化に伴って位相回転がどのように変化するかを見てみましょう。

//@@
from dpAnltc import *
dumpFnctn(lambda z:(z**4 + 0.5082*z**3 + 2.242*z**2 + 0.6556*z + 4.022)*z
        , 300,300,-3.0,3.0, 3.0, -3.0)
//@@@
mkRGB mtCplx -max:0.01

z の非整数べき乗の解析関数

z の非整数乗の関数では、原点の周りで位相が整数回転できません。多価関数となります。

z^ (1/2)

z^(1/2) の複素数分布を kkRGB 表示します。デフォルト パラメータを使うので 300 dot x 300 dot の pixel 数で [-1.5,1.5] x[1.5,-1.5] の領域の複素数分布を計算します。

//@@
from dpAnltc import *
dumpFnctn(lambda z:z**0.5)
//@@@
mkRGB mtCplx -max?
Maximum:1.45405 Column:0 Row:0

mkRGB mtCplx

複素平面上で原点を中心に 1/2 回転しています。 左側のノーマル kkRGB 図で、負の実数軸で位相が不連続になっています。リーマン面です。関数は多価関数となります。らせん状に積み重なっています。

リーマン面が負の実軸になっているのは多価関数の計算上の都合です。

z^3.3

z^3 から少しずらして z^3.3 の kkRGB 図を描かせます。
//@@
from dpAnltc import *
dumpFnctn(lambda z:z**3.3)
//@@@
mkRGB mtCplx -max?
Maximum:11.8308 Column:0 Row:299

mkRGB mtCplx -max:0.1

z^3 と良く似た kkRGB 図になります。原点の周りの位相回転が 3 回転より 0.3 回転だけ増えます。位相の不連続点が出てしまいます。負の実数軸が、この不連続点として表示されています。リーマン面です。z^3.3 は多価関数になってしまいました。

定数の z べき乗の解析関数

e^z

exp(z) == e^z の複素数値分布を見てみましょう。定義域を広げて、関数値の変化の様子をより分かり安くします。

//@@
from scipy.special import exp
from dpAnltc import *
#dumpLogFnctn(lambda z:exp(z),300,300,-5.0,5.0,5.0,-5.0)
dumpFnctn(lambda z:exp(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:145.96 Column:91 Row:299

mkRGB mtCplx -max:0.01

exp(z) は、虚数軸方向に対しては位相が変わるだけで絶対値が変化しないことが分かります。正の実数軸方向に移動すると、その絶対値は exp の指数カープで増加していくことも分かります。

5^z

!exp(1) = 2.71828 の z べき乗を 5 の z べき乗にして複素数値の分布を見てみます。
//@@
from dpAnltc import *
dumpFnctn(lambda z:5**z,300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:3042.29 Column:69 Row:299

mkRGB mtCplx -max:0.01

exp(z)より大きく変化するようになりますが、虚数軸方向に対しては位相が変わるだけで絶対値が変化しないことは同じです。正の実数軸方向に移動すると、その絶対値は 指数カープで増加していくことも同じです。

(3+4i)^z

複素定数の z べき乗したときの複素数値の分布を見てみます。
//@@
from dpAnltc import *
dumpFnctn(lambda z:(3+4j)**z,300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:309090 Column:299 Row:299

mkRGB mtCplx -max:0.01

絶対値が一定となる等高線が傾くことが分かります。

その他の z べき乗解析関数

z^z

嫌がらせとさえ思える z^z の複素数値分布を見てみましょう。皆様は z^z がどのような位相変化をしているか、z^z が複素平面上でどのような複素数値分布をしているか、それぞれイメージできますでしょうか。

//@@
from dpAnltc import *
dumpLogFnctn(lambda z:z**z,300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:8.00403 Column:149 Row:299

mkRGB mtCplx -max:0.01

右側に行くにつれて急激に絶対値が大きくなる関数であることが一目で分かります。

境界値設定を 10 倍にしてやって、上の kkRGB 図で値が大きくなりすぎて白くなっている部分の位相変化を見えるようにしてみます。

mkRGB mtCplx -max:0.01

実数軸上で 0+0i の左側に小さなこぶががあります。その部分の絶対値の様子をグラフにして見ます。

!abs(mtCplx[149,*])
gdsp

このこぶの部分だけに限定して kkRGB 図を拡大しましょう。実数:[-1,0] 虚数[0.5,-0.5] の上下、左右を 1/10 にまで絞った領域での複素数分布を見てみます。この領域では変動が小さいので log をとらずに計算させます。

//@@
from dpAnltc import *
dumpFnctn(lambda z:z**z,300,300,-1.0,0., 0.5,-0.5)
//@@@
mkRGB mtCplx -max?
Maximum:1.43713 Column:149 Row:189

mkRGB mtCplx

リーマン面は -1.0+0i から 0+0i の範囲だけではありません。-2+0i から 0+0i に kkRGB 図を拡大してみます。

//@@
from dpAnltc import *
dumpFnctn(lambda z:z**z,300,300,-2.0,-0.0, 1.0,-1.0)
//@@@
mkRGB mtCplx

リーマン面での位相変化から、その切り口での多価関数の様子をイメージできます。上の kkRGB 図からは [-1+0i , 0+0i] の区間でチューブの断面のようになっている z^z 解析関数の断面がイメージできます。[-2+0i , -1+0i] の区間でも、別のチューブ断面構造が存在します。上下の離れ具合は [-1+0i , 0+0i] のときより小さくなっています。

この断面のチューブを解析接続して複素平面全体に広げてやることで z^2 の複素数値分布をイメージできます。z^z は二価関数でしょう。正の実数軸(橙色と黄色の境界)、負の実数軸(空色と緑色の境界)では、二価の関数で構成されるチューブが互いに接触して一価の関数となりそうです。そのチューブの曲がり具合は kkRGB 図の等位相面で分かります。

e^(z^2)

exp(z^2) 即ち多項式と exp() を組み合わせた解析関数の複素数値分布を見てみましょう。

//@@
from scipy.special import exp
from dpAnltc import *
dumpLogFnctn(lambda z:exp(z**2),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:24.8333 Column:149 Row:0

mkRGB mtCplx -max:0.05

絶対値は左右対称で 0+0i から左右離れるにしたがって急激に大きくなります。上下にも対称です。0+0i から上下に離れるにしたがって急激に小さくなります。

上下だけではなく、左右にも共役です。この共役性は下のように数値計算でも確認できます。

z@=1+2i, !exp(z^2)
< -0.032543-0.037679i >
z@=-1+2i, !exp(z^2)
< -0.032543+0.037679i >
z@=1-2i, !exp(z^2)
< -0.032543+0.037679i >

ちなみにエラー関数は exp(-z^2) == 1/exp(z^2) です。ですから、上の二つの kkRGB 図の左右を入れ替えてやれば、エラー関数の複素数分布とも見なせます。

三角関数

様々な三角関数の複素数分布を見てみましょう。

sin(z)

最初に sin(z) の複素数分布を見てみましょう。
//@@
from scipy.special import sin
from dpAnltc import *
dumpFnctn(lambda z:sin(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:72.9835 Column:0 Row:8

mkRGB mtCplx -max:0.01

上下方向に移動したとき、絶対値が急激に増加することが分かります。左右に移動したときは sin 関数と同様な位相変化をすることも分かります。絶対値の等高線は横一直線が少しだけ波打っていることが見てとれます。

cos(z)

cos(z) の複素数分布は sin(z) とどのように異なるでしょうか。
//@@
from scipy.special import cos
from dpAnltc import *
dumpFnctn(lambda z:cos(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:72.9835 Column:0 Row:55

mkRGB mtCplx -max:0.01

複素平面まで拡張したときでも、sin と cos の違いは位相変化が π/2 ずれていることが違うだけのようです。

tan(z)

tan(z) の複素数分布を見てみましょう。
//@@
from scipy.special import tan
from dpAnltc import *
dumpFnctn(lambda z:tan(z),300,300,-5.0,5.0,5.0,-5.0)
#dumpLogFnctn(lambda z:tan(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:58.1213 Column:149 Row:291

mkRGB mtCplx -max:0.01

極は実数軸上にのみ存在するようです。sin/cos 関数のときと異なり、上側/下側それぞれで real part が正/負だけに限定されます。x 軸方向に移動させたとき tan(x) は複素平面でも πの周期性を持つことが見られます。

上下に移動しても tan(z) はあまり変動しないようです。境界値を 5 倍大きく設定した、下の kkRGB 図より、上下方向に垂直に移動させるとき一定の値に収束するのが解ります。

mkRGB mtCplx -max:0.05

下のグラフより、上の kkRGB 図より上下方向の値の変化の仕方がより詳細にイメージできます。

!abs(mtCplx[*,149])
gdsp
!image(mtCplx[*,149])
gdsp

cot(z)

cot(z) は tan(z) と、どんな違いとなるのか見てみましょう。

//@@
from scipy.special import sin, cos
from dpAnltc import *
dumpFnctn(lambda z:cos(z)/sin(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:53.5738 Column:149 Row:244

mkRGB mtCplx -max:0.01

複素数の範囲でも、 cot(z) は tan(z) と実数軸方向に π/2 だけ位相がずれたものであると解ります。

三角関数の逆関数

三角関数の逆関数の複素数値分布を調べます。

asin(z)

asin(z) の複素数値分布を見てみましょう。

//@@
from cmath import asin
from dpAnltc import *
dumpFnctn(lambda z:asin(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:2.77423 Column:150 Row:0

mkRGB mtCplx -max:0.8

実数軸の -1+0i より左側と、 1+0i より右側にリーマン面が出てきました。リーマン面の始まる位置での変化をより詳しく見るため,実数:[-1.5,1.5] 虚数:[1.5,-1.5] に領域を狭めます。

//@@
from cmath import asin
from dpAnltc import *
dumpFnctn(lambda z:asin(z),300,300,-1.5,1.5,1.5,-1.5)
//@@@
mkRGB mtCplx -max?
Maximum:1.83602 Column:149 Row:0

mkRGB mtCplx
mkRGB mtCplx -max:0.8

sin(z) == 0 となる z は n π (n==0,±1,±2,...) ですから、asin(0+0i) が n π の値を取る多価関数となることは理解できますが、左右のリーマン面とどのように n π の点が繋がるのか私にはイメージできません。皆様はどうでしょうか。

acos(z)

acos(z) と asin(z) との違いはどんなものでしょうか。

//@@
from cmath import acos
from dpAnltc import *
dumpFnctn(lambda z:acos(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:3.8843 Column:149 Row:0

mkRGB mtCplx -max:0.8

asin(z) とは異なり左右が対称ではなくなりました。その理由を探るため、-max: をデフォルトの 1 にして kkRGB 画面全部を境界領域以内に表示させます。

mkRGB mtCplx

acos の左右の対称性がないのは、どうも接続の仕方によるもののように思えます。

atan(z)

atna(z) の複素数分布を見てみましょう。

//@@
from cmath import atan
from dpAnltc import *
dumpFnctn(lambda z:atan(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:2.51925 Column:119 Row:149

mkRGB mtCplx -max:0.8

虚数軸上 i から上側に、また -i から下側にリーマン面が出ています。

ちなみに、ここの一番下に matlab を使った atan(z) のカラー位相/絶対値表示図形があります。等高線を補ってやらないと解りにくいカラー表示です。kkRGB のほうが優れていると主張します。

ハイパボリック関数

様々なハイパボリック関数の複素数分布を見てみましょう。

sinh(z), cosh(z)

最初に sinh(z)/cosh(z) の複素数分布を見てみましょう。
//@@
from scipy.special import sinh
from dpAnltc import *
dumpFnctn(lambda z:sinh(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:72.9835 Column:8 Row:0

mkRGB mtCplx -max:0.01
//@@
from scipy.special import cosh
from dpAnltc import *
dumpFnctn(lambda z:cosh(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:72.9835 Column:55 Row:0

mkRGB mtCplx -max:0.01

sinh(z)/cosh(z) は sin(z)/cosh(z) を π/2 だけ回転させたものであることが良く分かります。

真正特異点

真正特異点の周りでの位相変化/絶対値変化の様子を見てみましょう。

exp(1/z)

exp(1/z) は 0+0i を真正特異点とする解析関数です。この複素数値分布を見てみましょう。log を取っても変化が大きすぎるので、実数:[-1.0,1.0] 虚数:[1.0,-1.0] の領域に狭めます。

//@@
from scipy.special import exp
from dpAnltc import *
dumpLogFnctn(lambda z:exp(1/z),300,300,-1.0,1.0,1.0,-1.0)
//@@@
mkRGB mtCplx -max?
Maximum:1.39371e+065 Column:149 Row:150

mkRGB mtCplx -max:0.05

変化を解りやすくするため、スレッショルドを 1/5 だけ小さくした kkRGB 図も作っておきます。

mkRGB mtCplx -max:0.01

0+0i の周りで位相が急激に変化しています。でもリーマン面は存在しないようです。

sin(1/z)

0+0i を真正特異点とする sin(1/z) の複素数分布を見てみましょう。
//@@
from scipy.special import sin
from dpAnltc import *
dumpLogFnctn(lambda z:sin(1/z),300,300,-1.0,1.0,1.0,-1.0)
//@@@
mkRGB mtCplx -max?
Maximum:149.307 Column:149 Row:149

mkRGB mtCplx -max:0.01

絶対値の分布が上下/左右に対称です。上下/左右に共役な関係にあることも解ります。exp(1/z) よりも対称性が明確です。

定義域を、実数:[-5.0,5.0] 虚数:[5.0,-5.0] の領域に広げてみます。

//@@
from scipy.special import sin
from dpAnltc import *
dumpLogFnctn(lambda z:sin(1/z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:29.3069 Column:149 Row:149

mkRGB mtCplx -max:0.01

特異点は 0+0i だけのようです。右側の reversed kkkRGB 図より実数軸上に二つのゼロ点があることに気づかされます。良く見れば、前の kkRGB 図でもゼロ点が存在していました。

より狭い定義域、実数:[-0.1.0.1] 虚数:[0.1,-0.1] ではどうでしょうか。

//@@
from scipy.special import sin
#from cmath import sin
from dpAnltc import *
dumpLogFnctn(lambda z:sin(1/z),300,300,-0.1,0.1,0.1,-0.1)
//@@@
mkRGB mtCplx -max?
Maximum:576.23 Column:147 Row:149

mkRGB mtCplx -max:0.01

この kkRGB 図から、位相に付いてはどんなに拡大しても相似な対称性を持つようです。

ゼロ点が 0+0i の周囲に無限個ある事も分かります。先に二個のゼロ点だけが見えたのは、他のゼロ点は値域を広く取ったために表示分解能が低くかったためです。

この kkRGB 図で、正の実数軸上にある白っぽい線は計算がオーバーフローしてできた線です。log で圧縮した後で 576 の値が出てきていることから、オーバーフローが有りそうだと推測されます。

その他の関数

その他の解析関数の複素数分布を見てみましょう。

log(z) 関数

log(z) の複素数値分布を見てみましょう。

//@@
from scipy.special import log
from dpAnltc import *
dumpFnctn(lambda z:log(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:4.4269 Column:149 Row:149

mkRGB mtCplx

負の実数軸にリーマン面が現れています。log(z) == log(abs(z)) + i arg(z) による螺旋状の多価関数から、部分的に切り出した図になっています。純虚数値の線が -1+0i と 1+0i を通る円になっていることが良く分かります。1+0i が一次のゼロ点であることも分かります。1+0i の周りで 360度位相が回転しています。

スレッショルドを少し下げてやると等高線が現れてくるので、値と位相の変化がより分かりやすくなります。

mkRGB mtCplx -max:0.7

Γ(z) 関数

Γ(z) 関数の複素数値分布を見てみましょう。

//@@
from scipy.special import gamma
from dpAnltc import *
dumpLogFnctn(lambda z:gamma(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:3.78046 Column:149 Row:149

mkRGB mtCplx -max:0.5

右側に行くにつれて急速に絶対値が増えることが分かります。上下に進んでいくにつれて絶対値が 0 に近づいていることも解ります。0+0i, -1+0i, -2+0i, -3+0i,... に一次の極があることが分かります。

ζ(z)関数

最後に ζ(z) 関数の複素数値分布を kkRGB 図で表して見ます。ただし python の ζ(z) 関数は実数でしか定義されていません。複素数での ζ 関数が備わっていないので、ζ 関数ルーチンを作るところから始めます。

ζ(s) 関数とは

ζ(s) 関数とは下の式で定義される関数です
             1     1     1            1
ζ(s)≡ 1 + --- + --- + --- + .... + --- + ....  ------(ζ:1)式
            2^s   3^s   4^s          n^s

ζ(s) 関数は素数分布と関連付けられます。下のように 「1/(1-1/p^s) ただし p は素数」は次の等比級数で表せます。

       1              1     1     1      1    
   ---------- == 1 + --- + --- + --- + ---- + 
    1 - 1/2^s        2^1   4^s   8^s   16^s   

       1              1     1     1      1    
   ---------- == 1 + --- + --- + ---- + ---- + 
    1 - 1/3^s        3^1   9^s   27^s   81^s   

       1              1     1       1       1    
   ---------- == 1 + --- + ---- + ----- + ----- + 
    1 - 1/5^s        5^1   25^s   125^s   625^s   
                     1
ζ(s)  ==   Π    --------
          p∈素数  1-1/p^s

ζ(s) には素数分布など自然数の性質が凝縮しているとされ、多くの数学者がその性質を追求しています。

ζ(s) 関数の計算

ζ(s) を交代級数に変形した ζ'(s) のほうが収束が早くなります。こちらの方が数値計算で値を求め易い式です。

              1     1     1            1
ζ'(s)≡ 1 - --- + --- - --- + .... + --- + ....
             2^s   3^s   4^s          n^s

ζ(s) と ζ'(s) は下の関係があるので、収束が早い ζ'(s) を使って ζ(s) の値を求ます。

              1     1     1            1
ζ'(s)≡ 1 - --- + --- - --- + .... + --- + ....
             2^s   3^s   4^s          n^s

                 1     1     1            1                 1     1         
ζ'(s) == ( 1 + --- + --- + --- + .... + --- + ....) - 2(+ --- + --- + .... )
                2^s   3^s   4^s          n^s               2^s   4^s        
                                 1     1     1            1 
       == ζ(s)  - 2 2^(-s)(1 + --- + --- + --- + .... + --- + .... +)
                                2^s   3^s   4^s          n^s
       == (1-2 2^(-s))ζ(s)

       == (1-2^(1-s))ζ(s)

ζ(s) == ζ'(s)/(1-2^(1-s)) ------- (ζ:2)式

下のように ζ`(s) を定義すると

ζ`(s) ≡ s(s-1)/2π^(-s/2)Γ(s/2)ζ(s)
ζ(s) == π^(-0.5+s)  Γ((1-s)/2)/Γ(s/2) ζ(1-s)  ------- (ζ:3)式

Γ(s) は 0+0i の所で発散します。それより右側の s.real が 0.5 以上の右半平面での ζ(s) 関数値を ζ'(s)/(1-2^(1-s)) から計算します。x が 0.5 より小さい左半平面での ζ(s) 値は、上の (ζ:3)式を使って、Γ(s) 関数と ζ(s) 右半平面の値より求めます。

具体的には、下の python code で複素数値まで含めた ζ(s) 値を計算します。実数部分が 0.5 以上のときは (ζ:2)式 より ζ(z) を計算します。0.5より小さい時は (ζ:2)式と(ζ:3)式を津かつて ζ(z) を計算します。

#type kZeta.py
from scipy.special import gamma, zetac, log
from scipy import *
import sfVal
def _less5zeta(s):
    pi = 3.141592653589793
    return  pi**(-0.5+s)*gamma((1-s)/2)/gamma(s/2)*myZeta(1-s)
def myZeta(s):
    _sizeN = 100
    if (s.real <= 0.5):
        return _less5zeta(s)
    if (s.real <= 0.6):
        _sizeN = 1000000
    if (s.real <= 0.7):
        _sizeN = 100000
    if (s.real <= 0.8):
        _sizeN = 20000
    if (s.real <= 0.9):
        _sizeN = 6000
    if (s.real <= 1.0):
        _sizeN = 2200
    if (s.real <= 1.1):
        _sizeN = 1000
    if (s.real <= 1.2):
        _sizeN = 550
    if (s.real <= 1.3):
        _sizeN = 320
    if (s.real <= 1.4):
        _sizeN = 140

    return sum([(-1)**(x+1) * x**(-s) for x in range(1,_sizeN)])/(1-2**(1-s))

1000000, 100000, 20000, ... の数値は ζ'(s) の計算値が三桁目までの精度を持つような級数の長さを下の計算より求めて決めました。

1/1000000^0.5
< 0.001 >
1/100000^ 0.6
< 0.001 >
1/20000 ^ 0.7
< 0.000975616 >
1/6000 ^  0.8
< 0.000949465 >
1/2200 ^  0.9
< 0.00098134 >
1/1000 ^  1.0
< 0.001 >
1/550 ^   1.1
< 0.000967389 >
1/320 ^   1.2
< 0.000985871 >
1/210 ^   1.3
< 0.000957447 >
1/140 ^   1.4
< 0.000989511 >
1/100 ^   1.5
< 0.001 >

ζ(s) 関数の kkRGB 表示

上の kZeta.py にある myZeta(z) python 関数を使って、ζ(z) の複素数値分布を kkRGB 表示させます

//@@
from kZeta import myZeta
from dpAnltc import *
dumpLogFnctn(lambda z:myZeta(z),300,300,-5.0,5.0,5.0,-5.0)
//@@@
mkRGB mtCplx -max?
Maximum:3.78508 Column:149 Row:180

mkRGB mtCplx -max:0.2

上の kkRGB 図で 0.5 + y i の直線上に小さな髭上の括れがあるのは、計算誤差の所為です。ここで反転させて計算させているため、誤差がはっきりと出てしまっています。

この kkRGB 図より、この領域では絶対値の分布は右肩上がりで、 1+0i の位置にポールが存在するのが分かります。この周辺, 実数:[0.5. 1.5] 虚数:[0.5,-0.5] の狭い領域を見てみましょう。

//@@
from kZeta import myZeta
from dpAnltc import *
dumpLogFnctn(lambda z:myZeta(z),300,300,0.5,1.5,0.5,-0.5)
//@@@
mkRGB mtCplx -max?
Maximum:6.05877 Column:149 Row:150

mkRGB mtCplx -max:0.2

特に目だった特徴は有りません。単純な一次の極のようです。ただ、白丸が見られないので、極の立ち上がり方が狭い範囲で急峻であることが分かります。

今度は ζ(z) 関数をもっと広い領域で見てみましょう。上下に対称なのは明らかなので、実数:[-38.5. 1.5] 虚数:[38.5,-1.5] の領域とします。kkRGB 図も 500 x 500 ドットの大きな物にします

//@@
from kZeta import myZeta
from dpAnltc import *
dumpLogFnctn(lambda z:myZeta(z),500,500,-38.5,1.5,38.5,-1.5)
//@@@
mkRGB mtCplx -max?
Maximum:75.8355 Column:0 Row:0

mkRGB mtCplx -max:0.05

左上の部分で絶対値が最大となります。その位置で log 圧縮した後の値で 75.8855 の値をとります。実際の ζ(z) 関数値は結構大きな値です。

負の実数軸上 -2+0i, -4+0i, -6+0i ... に自明なゼロ点が未ら利ます。また実数軸が 1/2 の直線上のゼロ点 0.5+14.134725i, 0.5+21.022040i,0.5+25.010856 がみられます。たった六個のゼロ点しかみえませんが、規則性を感じられるゼロ点の配置幅の変化の仕方です。

ちなみに、Wolfram のここで、やはり ζ(z) 関数の複素数値分布画像を見られます。でも、実数部分と虚数部分の二つの三次元俯瞰図で表現しているため、良く分からない画像となっています。kkRGB のほうが、ずっと ζ(z) の複素数分布を直感的に掴める表示であることが良く分かります。


ホーム・ページに戻ります