零線図の描き方





リーマン証明などで複素関数の零線図は非常に重要な研究手段となりました。これを描く方法を書きとめておくことにしました。

零線図は、複素関数のどこに零点があるかを計算しなければなりません。小さい値の近くで更に零に近い数を探す作業が必要になります。手動計算ではたいへんな手間が必要になります。そこで、ここはプログラム化して処理することにします。

そのプログラムは Mn.java. の中にありますが、それは taketa3.11 の Mn.java には入っていません。そこで、  Mn03.lzh (ここをクリック) を差し上げます。以前の Mn.java は別名で保管しておいたほうが良いでしょう。これを解凍すると、新しいMn.java と、graph.java と graph.html が出てきます。新しいMn.javaはtaketaフォルダに入れます。後のふたつは零線図を描くのに必要ですから、appletフォルダに入れておきます。新しい Mn.java には、main の外に reiten05, reiten06, jj02 というメソッドが入っています。零点計算のためには jj02 の中を書き換える必要があります。

書こうとしている複素関数の計算式を jj02 に書き込むのですが、今回は k(s) の零線図なので、すでに書き込まれているので変更は必要ありません。次にコンソール(DOS窓)を出してきて、Mn.javaを含むフォルダに移動します。このあたりのコンソールの使い方は、JavaやC言語と同じですから、各自学んでおいてください。コンソールに javac Mn.java と打ち込んで、実行を押すとコンパイルが始まります。これはすぐに終わります。次に Mn.java と打ち込むとなにやら動き始めます。今回は、k(s)の b=10 より上の部分で a=-5 から a=1 までの範囲で、どこに零点があるかを計算してくれます。精度は3桁程度ですから時間はかかりません。結果は reiten0.txt に書き込まれます。

計算が終わったことを確認して、reiten0.txtを開けてみます。すると、data という文字とたくさんの数字が見つかるはずです。これらはいじらずに、「全体をコピーする」をクリックし、全体をコピーします。次に、appletフォルダの中にあるgraph.java を開けて、その中にある 「dataの書き込み場所」の下にある空間にそのまま貼り付けます。空間は「data の書き込み場所」から「dataの書き込み終わり」までです。もし、すでに data[0][0]=1.5821414; のような文字が見えるなら、まずはすでにあるデータを消して、それから貼り付けます。


data05 の図
次に、applet のためのコンソールを出して、そこで javac graph.java と打ち込みます。次に appletフォルダの中にある graph.htmlを開けます。うまく開かないときは appletviewer を指定して開けてください。すると、右図のような絵が出てくるはずです。

(注   アプレットビューアーがうまく使えないときがあるようですが、javaフォルダのjdk\binの中に入っています。なければどこかで探してくる必要があります。)



Print Screen ボタンを押して、この画像をPCに取り込みます。そして、MSペイントのような画像ソフトを開いて、そこに貼り付け、いらないところを切り取って整形します。そして、名前を付けて保存します。ここではdata05.jpgという名前にしてあります。












これだけでは零線図にならないので、次にもう少し上の部分にある零線を描きます。Mn.java を開けると、65行目あたりに for (i・・・){ex[i]=0;} ex[0]=1;ex[1]=1;//ex[2]=3000000; と書かれた部分を見つけることができるはずです。

ex[0]=1;ex[1]=1; は ex数列が10を意味していることは判りますね。これがbの値を入れる数列です。今、10以上の範囲で零点を探しましたが、15以上を探してみましょう。15を表示するには ex[0]=1;ex[1]=1;ex[2]=5000000; としなければなりませんから、「 // 」という除外記号を消して、ex[2]=3000000; を ex[2]=5000000; に書き換えます。最後に Mn.java を全体として上書き保存します。あとはコンソールに戻って、java Mn.java , java Mn を実行すると、また reiten0.txt の中に新しいデータが書き込まれています。古い reiten0.txt を開けたままにしてあると、新しいデータが表示されないので、古いreiten0.txt は閉じたうえで、新しいデータを表示させます。


data06 の図
その新しいデータを graph.java の中にコピペして、appletコンソールで javac graph.java を実行し、また、graph.html を開けます。これも古いのが表示されるときは、いったん、古いgraph.html を消しておいてください。新しい graph.html の画像を Print Screen ボタンでPCに取り込みます。これをMSペイントに貼り付けます。「変形」の中にある「背景色を不透明にする」のチェックをはずすと、下絵が透けて見えるので、縦線・横線が完全に一致するように動かした上で、確定させます。

画像処理ソフトはいろいろあるようですが、MSペイントはどのパソコンにも付いているはずです。もっとも、最新のMSペイントは使い勝手が悪いので、古いMSペイントを探してきて、それをコピーして使うことをお勧めします。ここでは、古いソフトを使ったという前提で説明してあります。







data07 の図
ex=15の描画が終わったら、次に ex=19 以上の描画に挑戦します。前と同じように、プログラムの ex[] 部分を変更し、 ex[0]=1;ex[1]=1;ex[2]=9000000; となるようにします。これで計算すると、reiten0.txtの中身が変更されますので、その新しいデータをgraph.javaに書き込み、コンソールで実行した後で、graph.htmlを開けます。それを前と同じ手順で貼り付けると右図のようになるはずです。a=0.5 より右側にある青の直線はゴミであることがあるので、ゴミならば消しておきます。

あとで見ても判るよう、「何の図か?、どこが零か、線の幅がどこくらいか、」を書き込んでおきます。


さらに上の範囲を計算すればいくらでも図を詳しくすることができます。あとは各自でやってください。これで実零線は完成です。









次に、虚零線を描きます。Mn.javaを開けて、虚零線用にいくつかの点を修正します。ひとつは、虚零線はa=5に到達するので、for(p2 ... 30 ...p2++) を for(p2 ... 50 ....p2++) に書き換えます。次に b=10 以上ということで、 ex[0]=1;ex[1]=1;//ex[2]=9000000; に戻します。「//」 はプログラムから除外するしるしです。


data08 の図
次に、graph.javaも一部書き換えます。虚零線は赤で示すことにしますので、graph.javaの終わりごろにある grf.setColor(Color.blue); という命令を grf.setColor(Color.red); にします。あとは、実零線のときと同じように、javac Mn.java , java Mn を実行します。データをgraph.javaに写して、javac graph.javaを実行し、graph.html の図を Print Screen でPCに取り込んで、先ほどの図に重ねます。

これを、b=15以上、b=19以上と繰り返して作業すると右図のような結果になります。

一部の赤線が途切れているのは、b=15と設定したのがやや高すぎたせいです。b=13くらいにして、再度計算するとこの部分を埋めることができます。ためしにやってみてください。








■      lt(s) と lu(s) の零線図を描く


k(s)以外も同じやり方で零線図を描くことになります。ためしに lt(s) と lu(s) の零線図を描いてみましょう。

lt(s)とlu(s)は リーマン証明から派生した公式 で解説してありますが、k(s)の関係式です。

lt(x) = 1 - 1/2^x + 1/3^x - 1/4^x + . . .
lu(x) = 1 + 1/3^x + 1/5^x + 1/7^x + 1/9^x + . . . .

という関数で、k(x)に良く似ていますね。

これをk(x)と関係付けた式に直すと

lt(x) = (2^x-2)/2^x * k(x)
lu(x) = (2^x-1)/2^x * k(x)

となります。

零線図なので、複素関数として考えるので、lt(s), lu(s) とします。

最初に、lt(s)の零線図にトライします。

はじめに、Mn.javaの中にあるjj02メソッドを開けます。この中にk(s)の計算式が書かれていますが、これをlt(s)に書き換えます。

すでに書かれているのは  Tk4.kr(aw,cw,p3); ですが、これに (2^s-2)/2^s を付け加えます。実際は、メモリーの種類を節約するために、k(s)/2^s を先に計算し、それに (2^s-2) を掛けます。sは数列として記録することになっているので、aw[][] などの複素数用の数列を使います。宣言部分はいじらないようにして、プログラム本体だけを次のように書き直してください。

lt_00 の図













次に、Mn.java の main に戻って、描画の範囲を確定させます。a軸方向の数字はhx[]に入っています。60行あたりにある hx[]が -5 になっていれば、そのままにしておきます。そうでなければ -5 に書き換えます。その結果  hx[0]=0;hx[1]=-5;  となっていればOKです。

次に、b軸上の範囲を決めます。これはex[]に数字が入っています。今回は0以上ということで、for(p2...50...p2++){//p2 より下にある ex[]を書き直します。 ex[0]=-1;ex[1]=1; と書いて 0.1 以上と設定します。

あとはa軸上、どこまで計算するか指定しなければなりません。for(p2...50...p2++){//p2 の部分は「p2を50回繰り返せ」との命令です。60行あたりで、af[0]=-1;af[1]=2; と書かれているのは、横軸のずれる単位が af=0.2 という意味です。そして { } の枠の終わりのところに Tk.add(hx,af,hx); と書かれているのは、「hx[] 数列を 0.2 づつ増やしなさい」という命令です。これで、{ } の中での一回の計算が終わるごとに hxが0.2 増えることになります。hxは、最初が -5 ですから、次が -4.8, 次が -4.6 というふうに増加します。これが50回ですから、 5 になったら終わりになります。

それから、忘れてはならないのは、「//a,b は3カ所変更」のあとに書かれている 「//if(a[1]...」のブロックアウト記号「 // 」は消しておいて、「if(b[1]...)」には 「 // 」を書き込んでおかなければなりません。if(a[]... は実部計算用、if(b[]... は虚部計算用のプログラムが起動します。

なお、bf[] は零点近くの範囲をどのくらいの細かさで探すかを示す数列ですので、今のところいじる必要はありません。そのままにしておいてください。

あとは、先ほど計算したプログラムどおりで差し支えありません。全体を保存して、javac Mn.java, java Mn を実行すると、なにやら動き出して、結果が reiten0.txt に書き込まれます。私のPCでは答えを得るのに111秒もかかってしまいました。結構時間がかかりますね。

あとは先ほどと同じで、reiten0.txt の中身を graph.java にコピペします。そのとき、grf.setColor(Color.red); の red を blue に書き換えることを忘れないようにしてください。その上で、graph用のコンソールを出してきて、そこで javac graph.java を実行し、graph.html を appletviewer で開けると、lt(s)の 0 近辺の実部零線図が描かれるはずです。


lt_03 の図 右図のようになっていれば成功です。b=5 あたりにある青線は計算上のゴミですから、あとで消しておきます。



















次に、b=5 より上の範囲を計算します。そこで、ex[0]=0;ex[1]=5; と書き直して、再度、javac Mn.java, java Mn.java を実行します。結果をコピペして、画像を作り、それを先の図に重ねます。次に、b=8 より上を計算します。その結果も画像に重ねます。次々に重ねてゆくと次第に全体像が出来てきます。何度もやっているうちに、実部については、a=1 以上は値がないことがわかってきますので、実行範囲を30に変更しておきます。 for(p2...30...p2++){//p2


lt_04 の図 ある程度出来上がったら良しとしましょう。右図のようになっているはずです。

おそらく、やっている過程で、いくつかのミスが発生したのではないでしょうか。最初からうまくいくということはまれです。どこかに書き間違い、勘違いがあって、プログラムが動かなくなることが良くあります。じっくりと考えて、間違いのないように書かなければなりません。














lt_05 の図 次に、虚部の零線図を描きます。これも出来次第、実部の画像に重ねてゆきます。「if(a[1]...」をブロックアウトし、「if(b[1]...)」に 「 // 」を書き込みます。これで虚部用の計算プログラムになります。計算範囲を hx=-5 から hx=5 までとし、p2の30を50に書き直します。for(p2...50...p2++){//p2 となります。graph.java の中身も grf.setColor(Color.red); に書き換えます。

完成すると右図のようになっているはずです。ところどころで線が擦れていますが、間の範囲を指定して再計算し、画像を貼り付けると線がつながります。面倒なのでこのままにしておきますが、ご了承ください。

リーマン零点のところが、lt(s)でも零点になっていることがわかります。また、それ以外にも零点が発生していることがわかります。





■      lu(s) の零線図を描く


lu(s)の式は次のとおりです。

lu(x) = 1 + 1/3^x + 1/5^x + 1/7^x + 1/9^x + . . . .

lu(x) = (2^x-1)/2^x * k(x)




lu_01 の図 lt(s)と同じように、jj02メソッドの中身を書き換えます。

すでに、(2^s-2)が書き込まれているので、これを(2^s-1)に変更するだけです。lx[]数列はすでに1になるように設定されているので、Tk.sub(a,lx,d); に変更するだけです。あとは、javac Mn.java, java Mn と計算して、graph.java に貼り付け、出来た画像を重ねてゆくことになります。

実部計算用に if(a[1]... が動くようにしておくことと、graph.java の色を blue に変更しておくことを忘れないようにします。











lu_02 の図 実部が終わったら、虚部を計算し、ゴミは消して、全体を適当な大きさにまとめて出来上がります。

今回は、虚部だけでまとめておきました。


















lu_03 の図 実部と虚部を合わせると右図のようになります。

lt(s)と微妙に違っていますね。






















表紙に戻る  前のページへ  次のページへ