tech
ハッカーの遺言状──竹内郁雄の徒然苔
第44回:複雑さを利用する?
元祖ハッカー、竹内郁雄先生による書き下ろし連載の第44回。今回のお題は「複雑さを利用する?」。
ハッカーは、今際の際(いまわのきわ)に何を思うのか──。ハッカーが、ハッカー人生を振り返って思うことは、これからハッカーに少しでも近づこうとする人にとって、貴重な「道しるべ」になるはずです(これまでの連載一覧)。
文:竹内 郁雄
カバー写真: Goto Aki
前回「複雑って何?」と題して、小難しい話を書いてしまった。複雑さについての話だからしょうがないとはいえ、やっぱり複雑で、小難しくなる。しかし、複雑さを忌避するのではなく、利用しようという逆転の発想もあり得るというのが今回の趣旨。
プログラムは書くことはもちろん、理解することすら困難なことはよく理解されていると思う。いいなぁ、「理解することが困難なことを理解する」。これこそAIの真骨頂。
で、私の思うところ、プログラミングの難しさは、その昔(多分、20世紀半ばに)数学者たちがよく言った「無限よりも巨大な有限のほうが難しい」という直観によってうまく言い当てられている。巨大な有限群の発見や、四色問題の証明はそのことを裏付けた。
19世紀に提唱された「平面上の地図は4色で塗り分けられる」という予想は四色問題として200年以上未解決問題だったが、1976年、アッペルとハーケンによって証明された。しかし、この証明、コンピュータプログラムによって行われたのである。これは数学史上初めてのことではないかと思う。プログラムによる証明となると、プログラムが正しいことの証明はどうするのかという疑問が起こる。その後、どんどん証明の改良が行われ、プログラムによる証明ということは変わらないが、もう「四色定理」が正しいことを疑う人はいなくなったらしい。
誰しも疑う余地がないものを証明と呼ぶはずだが、証明が複雑になるとそれが怪しくなるといういい例だ。みんながプログラムで証明すれば恐くない?
書かれたプログラムは、それ自身は静的な記述でしかないが、それが実際に意味を持つためには、プログラムの解釈系、つまりコンピュータが必要である。現在のデジタルコンピュータは典型的な離散系だ。メモリがギガとかテラの大きさになると、手に負えない巨大有限系の素質を十分に備えている。
カオスがもたらす「複雑系」は、ごく簡単な方程式系から、非常に複雑な振る舞いが発生することに由来している。しかし、この場合、記述もその解釈系も連続的、つまりアナログだ。
私は、勉強不足なので、チューリングマシンの理論から出てくるような、どこにも連続系が関与しない複雑度の理論(例えば、前回紹介したコルモゴロフやベネットの理論)と、カオスのように基本的に無限精度がないと意味のない、つまり連続系でないと意味のない複雑系の理論とのきちんとした関連を理解できていない。
実はチューリングは、チューリングマシンを超える計算機械をすでにイメージしていた。彼がOマシンと呼んだ、「オラクル(神託)」メカニズムを内包した計算機械だ。これは通常のチューリングマシンに、オラクルと、オラクルを読み取る装置を付加したものである。例えば、すべてのプログラム(当然、有限の長さであり、2進数で符号化できるので、自然数に対応させることができる)の停止性を表すオラクル、つまり0と1の間の2進数で表現された実数を考える。
停止性問題をごく簡単に説明しよう。プログラムがちゃんと停止して結果を出すことを、プログラムの停止性と呼ぶ。プログラムが停止性を持つかどうかを判定するプログラムはチューリングマシンの能力では書けない。これが計算不可能性の有名な定理だ。
2進小数のオラクルは、N 番目のプログラム(つまり、N の2進数として表現されるプログラム)が停止する場合は小数点以下N 桁目が1、しない場合は0となっている、長いプログラム、つまり、ある大きな番号以上のプログラムは停止しないということはあり得ないので、オラクルが有理数ということはあり得ない。計算不可能性の定理により、循環小数でもなく、チューリングマシンでは計算できない無理数である(複雑性の理論では、知恵の数Ωと呼ばれる)。
オラクル、つまり知恵の数Ωがたまたま与えられたとし、Ωを無限精度で読み取るメカニズムが存在すれば、チューリングマシンの停止問題は解けることになる。ここでも離散と連続の間の、微妙にして越え難い壁が見えてくる。もっとも、チューリングマシンの限界というのは、かなり厳格に規定された(まさにデジタルの)チューリングマシンのメカニズムに起因する。時間がアナログ進行する非同期な並列マシンを用意すると、チューリングマシンの計算可能性を超えるらしいので(※1)、チューリングマシンを超えるのは(それが制御可能かどうかは別として)実際的にも不可能でないと思われている。
いずれにせよ、連続系が関与していないために、プログラムは「眼鏡の倍率」をいろいろ変えて観察するという手法が成立しない。プログラムにも、カオスの初期値過敏性とよく似たことがある。例えば、私の過去のプログラミング(特にマイクロプログラミング)の経験では、一番予期しない動作違いを起こすバグは、プログラムの中の(表面上はエラーが検出されない)綴り誤りである。典型的には、レジスタ番号を間違えるとか、同じデータ型の変数名を取り違えるといった誤りは、コンパイラやアセンブラではエラーが検出しにくい。プログラムを注意深く見ても、誤りに気がつきにくい。
しかし、そのような「単純な」誤りはまったく予想しないような奇妙なプログラムの振る舞いをもたらす。これに対して、アルゴリズムの誤りや、(2とするところを3にしたような)数値の誤りバグは、常規を逸したような挙動にはあまり結び付かない。予想された軌道の範囲からそれほど大きく外れないことが多い(それが制御の道筋に影響する場合は別だが)。バグ原因の発見に苦労するのは、思い込みもあるので、むしろ単純ミスのほうである。
このようにプログラムの中の書き誤り、つまりバグは、プログラムの挙動に過敏な影響をもたらすが、それはカオスでいう初期値過敏性とは性格が異なるように思われる。相空間の中で軌跡が急速に離れていくというより、まるで違う空間の中に、つまり、プログラムを書いた本人には、たとえ、バグがあっても、そんな転び方はしないはずだという、まったく予想もしなかった新しい空間に、プログラムの挙動が転がってしまうのである。主観的な物云いであるが、実感としてそうなのだからしょうがない。
予想しなかったまったく別の空間へ、振る舞いが転がり込んでしまう。これが離散的記述であるプログラムに離散的な解釈系、つまりコンピュータが作用することによってもたらされる本質的な複雑さである。このようなことが起こったときのデバグは、非常に質の悪い逆問題を解くことにほかならない。秩序を壊すのは簡単だが、無邪気に壊されたものから、秩序を回復するのは(ジグソーパズルの例を出すまでもなく)きわめて困難である。
離散系の問題の難しさは、観察眼鏡の倍率を変える手法がうまく通用しないところにあると述べた。巨大でありながら、それを表す数の最下位ビットがいつまでも問題の対象になり続ける。その1ビットの差により、答えがイエスかノーか簡単に転ぶ。カオスの場合も、それと似ているのだが、その転び方が眼鏡の倍率に依存する。離散系の場合は、眼鏡の倍率に依存しない絶対的な基準がある。例えば、プログラムが止まるか止まらないか。正しいか、正しくないか。しかし、カオスの場合は、なんだかんだ言っても位相図のようなアナログ感覚のものが書けてしまう。とはいえ、このような直観が一般的に受け入れられるものなのかどうか、私には自信がない。
ここで、複雑(Complex)と単純(Simple)との関わりを、少々乱暴に仕切ってみよう。
工学では、複雑系という言葉が出現する以前から、複雑さを回避することが基本的な方法論だったと思う。つまり、なるべく単純なメカニズムを用いて、効用を得ようとする。その効用自身も単純な言葉で言い表すことができる。例えば、速く移動する。重いものを持ち上げて移動する、などなど。従来の工学では、単純な記述で書けない効用(目的、目標)はなかった。また、メカニズムも基本的に単純である。つまり、いくら部品が多くなっても、要素還元的であり、設計図面通りにすべての箇所が機能する。ある種の機械(新聞を印刷する輪転機がその例か?)では「どうして中間にこんな歯車が必要なの?」というものがあるようだが、それでもギリギリ、要素還元的である(と、機械屋でない私は)想像する。
これを一言で言えば、単純(S)から、単純(S)を生み出す、S-S型の方法である。コンピュータが出現する前の工学はことごとくこのタイプであったと言っても言い過ぎではないだろう。
工学のS-S型に対して、物理学に代表される多くの自然科学は、まず(人間にとっては)複雑な森羅万象、つまり、まず複雑系があり、それを理解するために人間がいろいろな指標、特性などを抽出し、単純な原理や理論へとマッピングしようとするタイプである。これを、複雑さ(C)から単純な指標(S)を得るという意味で、C-S型と呼ぼう。
宇宙の原理は単純であると信じて、観察される複雑な現象から単純なパラメタや指標を抽出してきた先人の偉大な努力は超敬服に値する。自然科学のみならず、経済学、社会学など、もともと存在している複雑なものの理解を求める学問はすべてそのような方法論に基づいているのだろう。複雑なものを、複雑さを削らないで記述してもちっとも嬉しくない。人間は複雑なものを複雑なままには理解できないために、CからSへのマッピングの過程で情報が欠落することは避けられないが、それはそれで問題なしとするのも重要なパラダイムだろう。私は以前の人工知能をこのC-S型に分類したい。なぜなら、人間の知能という複雑なものを、科学や工学の(それ自身、単純化の権化である)語彙の範囲で理解しようとしたからである。
これらの伝統的な方法論に対して、複雑系が話題になり始めたことから抬頭してきた方法論が、単純から複雑へ向かう、S-C型である。これは、単純な記述から、複雑なものを生み出すことがメインとなる方法論である。人工生命(※2)がその典型だろう。単純な模型から、複雑な挙動が生まれる現象を「発明」し、そのプロセスを実世界のモデリングに重ね合わせるというのが基本だと私は了解している。コンウェイのライフゲームはそのアイデアの基本をうまく表現している。人工生命によって、生物っぽい挙動をする「生物」がいる仮想世界がいくつも生成されるのだが、そのような可能性の示唆自身に意義があると考えるわけである。
S-C型に確固たる哲学があるのかと問い詰められると自信はないが、見て面白いのはS-C型である。複雑系の研究会などで、「こんな記述からこんな複雑な、あるいは奇妙な振る舞いが生じた。どうだ、面白いでしょう」(※3)みたいな感じの発表は、評価が真っ二つに分かれるかもしれないが、それがS-C型がS-C型である所以だと私は思う。一部の人工生命研究者のように、人工生命の方法論を娯楽や芸術の手段として利用しようする(していた?)のは、その点を正しく突いている。
こうなると、C-C型はないのだろうかとなる。こじつけた言い方をすれば、これは複雑なものを複雑なまま受け入れようという古代東洋思想、典型的にはTaoismに通ずる哲学ではなかろうか。人間は複雑なものを複雑なままで理解することはできないが、理解するという主知的な発想を捨てて、複雑なものをありのまま享受し、それを楽しむという、一種の悟りがあり得る。これは人間の精神衛生上、真っ当な対応だと思う。私は好きである。
このような乱暴な仕切りでも、ある種の概念整理ができた気分になる。さて、複雑なコンピュータプログラミングに関しては、上のどれにも当てはまらないタイプを割り当てるのが妥当だという気がする。遺言だから気楽なもので、「気がする」だけでいい。多少こじつけだが、これがS-C-S型、つまり、単純→複雑→単純というタイプである。外側だけを見ると、単純なものから、単純な(分かりやすい)効用を得るというS-S型なのだが、途中でC、つまり複雑系を経由する。
S-S型、つまり従来の還元的手法の工学では、単純な要素の線形組み合わせ、あるいは制御された組み合わせにより、人間にとってはっきりと分かる単純な効用、特性、指標を得てきた。前回の遺言状でほのめかしたが、工学でパラダイムシフトが起こっているとすれば、複雑系を経由して、なおかつ効用を得ようという考えが広まってきたことだと思う。例えば、マルチエージェントシステムにおいては、個々のエージェントは十分に単純な記述と振る舞いを持つ。それらが多数並列に動くと、振る舞いは制御可能域を超えた複雑さを持ち始める。しかしながら、システム全体から抽出される効用、特性、指標は分かりやいものを狙う。
ディープラーニングは、多層のニューラルネットワークを使う。何段もの中間層があり、そこでの挙動は大雑把には掴めるものの一体何が起こっているかは、「中間が難しい」の原理により、理解が困難である。典型的なS-C-S型だと思う。
S-S型ではなく、わざわざS-C-S型を選ぶメリットは何か? コンピュータ屋よりも機械系・制御系の人々がむしろ早く熱心に着目したといえる「自律分散系」においては、生体と同じような意味での複雑な組織体系を作ることによって、生体が特有に持つ自己安定性、自己修復性、自己組織性が得られることを最大のメリットと考えた。たしかに、生体のような複雑系にこれらの機能は「自然に」備わっているように見える。ただし、それが工学的に作り込めるものなのか、驚異的に長い超並列計算としての進化の結果──前回紹介したベネットの言う「遅い成長の原理」──によってしかもたらされないものなのかどうか、私にはよく分からない。
しかし、マルチエージェントやディープラーニングのようなものを持ち出さずとも、S-C-Sはコンピュータプログラミングの誕生とともに発生したと思う。つまり、コンピュータプログラムの内部的振る舞いはすでに複雑系の資格を十分に有しているからだ。
上に述べたように、コンピュータプログラムの複雑さは巨大な離散系の持つ複雑さである。しかし、依然としてプログラムに求められるのはプログラムの内部動作の複雑さに比べると圧倒的に単純な効用である。
コンピュータプログラミングが、S-C-S型である端的な例は、例えば数式処理による積分である。入力も出力もたいていの場合、それほど大きくないが、計算の途中に出てくる中途半端な式たちの大きさは、文字どおり半端ではない。
コンピュータネットワークは、プログラミングの枠組で考えると、なるべく単純な通信プロトコルという要素によって、非均質につながったコンピュータの間の1対1、1対N、N対Nなどの通信(これ自身は分かりやすい単純な効用)を保証しようという広義のプログラミングである。しかし、コンピュータネットワークのダイナミクスはそれこそ複雑系の典型例であり、人間が工学的に生み出した複雑系の真の代表例である。これもS-C-S型の典型である。身近な例では、ピタゴラスィッチもS-C-S型だろう。
写真1は3年ほど前、PCの入れ換えの機会に、意を決してPC類が収まっている私の部屋の押入れの中の配線を整理しようとしたときの一コマである。騒音防止のために、3、4台のPCを押入れに入れてあったのだが、その配線がすごいことになっていた。でもちゃんとPCは使えていたので、配線の複雑さはともかく、効用はあった。これもS-C-S型と呼べないことはなかろう。
プログラミングを分かりやすいものにしようという運動の出発点は、プログラムの内部動作をプログラマから隠蔽してしまおうという発想である。プログラムから、プログラムの内部動作と直接的に結び付いているものを、一つ一つ消していく。例えば、機械語からコンパイラへの移行で内部レジスタを見えなくする、gotoを言語からなくす、などなど。このような方法論は基本的には要素還元主義に基づくものであり、当然のことながら、それなりの成果を上げてきた。また、それで大方の問題が解決してしまうプログラムの類は実は少なくない。木構造階層はプログラミングの指導原理である。
ところが、プログラムが扱う対象が複雑になればなるほど、要素還元的なものですら、量的な爆発により、事実上、要素還元的でないものになる。私が昔から個人的なルールとしている(根拠のない)量と質の関係式によれば、量が2桁以上、つまり100倍以上違えば、それは質が「一つ」違う。プログラムが実現しているシステムにはこの意味で質が一つも二つも違う例がたくさん存在する。扱うデータ量が100倍、速度が100倍になれば、それは違う質のシステムに脱皮する。
単に量が増えるだけでも、そのような差が出てくるが、一般に、巨大になると同時に、巨大量を扱うためのカギとなる一様性や木構造的階層性が失われることが多い。一様なままであれば、小さなシステムのいわば相似拡大であるから、まだ取り扱いやすい。
私が1990年ごろ、当時の同僚たちとともに提唱したコネクティクス(Connectics、日本語では近傍系理論と呼んでいた)という概念がある。コネクティクスを一言で言うと、巨大で複雑なシステムも、それを成り立たせている要素は単純であり、かつ要素間の関係も単純であるが、それが集積すると、ねじれが積層して、要素還元的でないシステムが容易に出現するということを表す。重要なのは、積層するねじれが個々の要素や要素間の関係を見てもほとんど見えないことである。つまり、局所を見ても、複雑な全体につながるヒントが見えない。
最も単純な比喩でこのことをはっきりさせよう。位相多様体という概念がある。これは、近傍系からなる被覆(cover)である。と言われても困るかもしれないが、被覆については、小さい丸い端切れ(近傍)をたくさんオーバーラップさせて、ぬいぐるみを作ることをイメージするとよい。例えば、ある近傍とその周囲の近傍を見る限り、球面もドーナツもクラインの壷もみな同じである。つまり局所を見る限り、それらに構造的な差が見えない。しかし、全体を見るとあきらかに違う構造が出現する。つまり、要素や、要素間の関係だけでは記述できないものが大局的には存在するのである。
コネクティクスの例題はほかにもたくさんある。先人たちは数理社会学、グループダイナミクス、経済学、オートマタ、人工生命、などなど。コンピュータプログラミングの文脈ではコンピュータネットワークやエージェントプログラミングがコネクティクスそのものである。
それでは、コネクティクスは何を提唱したか。それは、全体と要素の中間に関する語彙をもっと増やそうという主張である。我々が何かを理解するということは、それに対して適切な共通言語を用意するということに(もちろん完全ではないが)ほぼ同義であろう。そう思って思い返すと、我々には巨大な数の要素からなるシステムの理解に必要な語彙があまりにも少ない。
要素還元的にうまくいっているシステムでは、中間階層にいろいろな名前付けや概念付けが行われている。つまり、階層的理解が、階層間の大きなギャップなしに達成できている。ところが、いわゆる複雑なシステムを語るために、我々は全体として見た特性を語る語彙と、個々の要素、個々の要素間の関係を語る語彙の2種類しか用意していないことが多い。つまり、関係がねじれながら積層している中間段階について語る語彙をほとんど持たない。
前回の遺言状に関して、昔のサッカー仲間の岩崎陸さんから、「サッカーの中盤も複雑なのでは?」という感想をいただいたが、まったく御意。サッカーの中盤についての語彙は、ボランチ、ダイヤモンドなど、大昔に比べて少しずつ増えてきているようだ。
複雑なシステムはもとより要素還元的な木構造的階層を持っていない、つまり「怪層構造」(heterarchical structure、「散層構造」とも言うが「怪層」は野崎昭弘先生の命名だと思う)を持っているので、そのようなうまい語彙を単純に生み出すことが難しい。しかし、数理社会学では点中心性(point centrality)とか、クリーク(clique)といった、単純な要素間の関係だけではないものを指す語彙がいくつかある。このようなものに類した言葉をもっとたくさん用意すべきなのだろう。
自然科学の発達の初期段階では、原理の探求の前に、博物学のような分類学が存在した。我々は自分たちの持っている方法論の道具がすでに十分なものであるかのような誤解をしているのではないか? 複雑系というこれまでの対象とはレベルの違うものを対象にしようというとき、博物学、分類学といった手法をもう一度見直して、我々の観察眼をもっと研ぎ澄ます必要があるのではないか? これがコネクティクスの主張した一番重要な論点であった。
これで難しいプログラミングが少しでも見通し良くなればよかったのだが……(※4)。(つづく)
※1:間違っていたらごめん。
※2:Artificial Life。1990年ごろ大いに研究された。
※3:まさに「創発」のことを言っている。「創発とは何か?」と問えば、途端に哲学的な課題になる。
※4:この記事が公表されてから気がついたのだが、「デザインパターン」はソフトウェアの世界では珍しい分類学的試みではあったと思う。語彙の整備として、とても重要な試みである。
竹内先生への質問や相談を広く受け付けますので、編集部、または担当編集の風穴まで、お気軽にお寄せください。(編集部)
変更履歴:
2017年07月15日:脚注4を追加しました。
SNSシェア