2007-03-27 [長年日記]
■なぜこの方程式は解けないか?
この題名だけから、ガロアを想像できる人はきっと数学が好きなんだろう。
ガロアの生前の不幸と、死後に認められることになるその業績から、今では「不滅の名」となっていることも、きっと知っているだろう。
……そうではない人向けには、サブタイトルの方がキャッチーな様に感じる。
読んでみて、想定している(であろう)読者層と、タイトルにギャップがあった。サブタイトルの方が、むしろ相応しかったのではないか?
ともあれ、筆者はガロアに大きな関心を寄せている。偏愛といってもいいぐらい。
9章あるうちの1章が、まるまるガロアの人生を詳細に浮かび上がらせることに使われている。
そして、その前の章で書かれるのはアーベル――ガロアに負けず劣らず不幸な人生を歩み、そして死後業績が認められた今一人の数学者――の人生。
アーベルからガロアへと連なる成果のうち、もっとも理解しやすいであろう命題が、タイトルになっている。
5次以上の方程式は一般に解法(解の公式)を持たない*1
というものである。
正確にはこれはアーベルが明らかにしたもので、ガロアが明らかにしたのはその一歩先、「解ける方程式はどのような形式でなければならないか?」ということ。
そこでは対称性――シンメトリーが大きな役割を果たしている。
それがサブタイトルになっている。
まず、シンメトリーが自然やパズル、絵画や音楽の中でどの様に見いだされるか、次に人間はどのようにシンメトリーを捉えるのかが書かれる。
その次に、数学における方程式の扱われ方、成果が書かれる。
2次方程式の解法――解の公式を憶えさせられた記憶を持っているだろう。
3次方程式、4次方程式までは解の公式が導き出される。
実はそこまででも幾人かの運命的な数学者のドラマがある。もっとも本書を通してみると、アーベルやガロアのいわば前座に見えてしまうのだが。
数学者たちの苦悩はそこから長くに渡り続いた。
そして綺羅星のごとくアーベルやガロアが数学史に登場する*2わけだが、実は方程式の解についてはそれよりもずっと昔に、ある1つの証明が与えられている。
n次の方程式はn個の解を持つ
である。
ちょっと整理すると、「n個の解を持つと言えるが、けれども解けるとは限らない」ということの証明をアーベルやガロアがやってのけたのだ。
そんな話で終わってしまったら、この本はここまで厚くはならない。
それにそもそも筆者がこうまでガロアに魅了されたとはとうてい思えない。
この本の主題は、その過程でガロアが見いだした「群」という概念の素晴らしさ、凄さを伝える、というものであろう。
そしてそれを伝えることで、ガロアがどれほどの非凡な才能を持っていたか、どれほどの「発想の飛躍」を成し遂げたのかを描き出したいのだろう。
事実「群」についての説明がなされたのち本書の内容は、科学・数学の恐ろしく広い範囲を跳び回る。
ユークリッドの「原論」から非ユークリッド幾何学へ。
ニュートンの「プリンキピア」に始まり、特殊相対性理論から一般相対性理論、量子論・クォークの説明からひも理論・超対称性へ。
生物学から心理学、音楽からカノンへ。
対称性というキィワードを武器に、それらの間を縦横無尽に駆け回り、なぎ払っていく。
あまりに話題を広く取りすぎていてその様は若干あざとい感もある。1つの原理からなる論が全てを説明してしまう、というイメージは一種似非科学的でもあり「ちょっと話広げすぎじゃないか?」とも感じる。
が、そうは言いつつも痛快で蠱惑的なことは否定できない。
夭折した悲劇の数学者が切り開いた、「群」という沃野。その広がりを楽しむもよし。
逆に、これほどの成果を成し遂げた数学者のその人生に、歴史の不可思議さを感じるもよし。
追記
書き忘れた。
この本は、アーベルやガロアによる証明の理解にはつながらない。
群に関しても、雰囲気に触れることはできるだろうが、そこまで。
数学史の本、といった雰囲気であって、数学の本じゃない。
「学習したい」人向けに書かれたものではないので、まぁ当然といえば当然。
追記 2012/05/01
ちゃんと数学的に学習したい人向けには、
をお奨めする。
発売前だけど断言してお奨めできる(なぜってレビュワーなので)。
1章を読んだ時点でこれはすごい本だと確信できた。
乞うご期待。
■ちゃんと
書評になっているか?
■Vista風タスクバーポップアップ
未使用。
Alt+Tab を Vista風にするツールもあったけど、XPだとやっぱり根本的に「もたつく」感じがしたのだよなぁ。
こちらについてはメリットをさほど感じないので試すつもりはないけど、一応メモ。
■凄いバカなプログラムを作ろう に参加
凄い&バカなプログラムを作ろう企画。
きしだのはてな - 凄いバカなプログラムを作ろう
に乗ってみた。要Java1.4以上。
方針は「データをソートしない」。
public class Untitled1 { static String[] nullMessage; static String[] emptyMessage; static { int maxOfHashCode = Boolean.valueOf(Boolean.TRUE.hashCode()>Boolean.FALSE.hashCode()).hashCode(); nullMessage = new String[maxOfHashCode+1]; nullMessage[Boolean.TRUE.hashCode()] = "nullです"; emptyMessage = new String[maxOfHashCode+1]; emptyMessage[Boolean.TRUE.hashCode()] = "空です"; } public static void main(String[] args) { print(null); print(new int[]{}); print(new int[]{5}); print(new int[]{3, 2}); print(new int[]{14, 13, 71, 2, 24, 19}); } static void print(int[] inputs) { String nullOrEmptyMessage; boolean b = (nullOrEmptyMessage = nullMessage[Boolean.valueOf(inputs==null).hashCode()])==null && (nullOrEmptyMessage = emptyMessage[Boolean.valueOf(inputs.length==0).hashCode()])==null && (nullOrEmptyMessage=print(inputs, Integer.MIN_VALUE))==""; System.out.print(nullOrEmptyMessage); System.out.println(); } /*minimumと同じ数があったら標準出力に書き出す その影で「minimumよりも大きくてかつ一番小さい数」を探す 「minimumよりも大きい数」がなければ再帰終了*/ static String print(int[] inputs, int minimum) { int nextminimum=Integer.MAX_VALUE; for (int i = 0; i<inputs.length; i++) { boolean b = (inputs[i]==minimum && _print("" + minimum + " ")) || (inputs[i]>minimum && inputs[i]<=nextminimum && (nextminimum=inputs[i])!=inputs[i]); } boolean ref = (minimum != nextminimum && print(inputs, nextminimum)!=""); return ""; } /*Syste.out.printのラッパー。返り値がbooleanなだけ*/ static boolean _print(String s) { System.out.print(s); return false; } }
■バカな点を自分で解説。
冒頭のstaticな配列と初期化子。
"nullです"と"空です"というメッセージを出すためだけに配列を使う。
Boolean.valueOf(Boolean.TRUE.hashCode()>Boolean.FALSE.hashCode()).hashCode();
Boolean.valueOfの中身の Boolean.TRUE.hashCode()>Boolean.FALSE.hashCode() は、Boolean.TRUE と Boolean.FALSE の hasCode() を比較。Boolean.TRUE.hashCode()の方が大きければ true に、小さければ false になる。
それを Boolean.valueOf(boolean) に渡して hashCode() を取ると、Boolean.TRUE.hashCode() と Boolean.FALSE.hashCode() の大きい方になる。
Math.max(Boolean.TRUE.hashCode(), Boolean.FALSE.hashCode()) で済むんだけどあえてバカさを狙う。
nullMessage[Boolean.TRUE.hashCode()] = "nullです";
で nullMessage[Boolean.TRUE.hashCode()] のところだけ代入しておく。nullMessage[Boolean.FALSE.hashCode()] はnullのまま。
printメソッドの中身。
boolean の変数を用意して、&& と || を使って条件分岐。
inputs がnull, 空の時だけ、nullOrEmptyMessageに文字が入って、次の行で標準出力に書き出す。
配列に値が入っているときはnullOrEmptyMessageは空文字。print(int[], int)の返り値が必ず空文字だから。
配列に値が入っているときは print(int[], int) の中で、小さい方から順に標準出力に書き出すというバカさ。各行の末尾に要らない空白が入っているし。
再帰を使っているけど、最初と最後の呼び出しが必ず無駄になるというバカさも持っている。
で、最後に改行を出す、と。
追記
そうそう。
Boolean.valueOf(inputs==null).hashCode()
を
Boolean.valueOf(""+(inputs==null)).hashCode()
と書き直せば1.3以前でもOK。さすがに見づらいので止めたけど(にしても、なんでBoolean.valueOf(boolean)が無かったんだ??)。