厳密には、ある有限長の文字列 x として表されるデータ列のある万能計算機 u におけるコルモゴロフ複雑性は以下の式で定義される:
ここで、p は計算機 u のためのプログラムであり、u(p) はそれを実行したときに出力される文字列である。l(p) はプログラムの長さを表す。ただし、プログラムは入力をもたず、つねに決まった出力を返すようなものとする。 ここで万能計算機とは万能チューリングマシンと同等の能力をもつ計算機を意味し、例えば C など通常のプログラム言語を解釈し実行するような処理系だと考えてよい。
コルモゴロフ複雑性を定めるためには、文字列に対する形式的な記述言語をまず指定しなければならない。 このような記述言語としては何かの具体的なプログラミング言語を選べばよい。 あるプログラム言語 L を固定したとき、 L のプログラム p が有限長の文字列 x を出力するなら、p は x の「記述」であるということにする。
このとき特に p として x 自身を明示的に含むような自明な記述がある。 例えば、上記の前者の文字列を標準出力に出力する Perl プログラムは、
のようになるだろう。 このようなプログラムの長さは明らかに x の長さよりもある定数分だけ長くなる。 しかし文字列に何かの構造が発見できれば、適切なアルゴリズムを用いることによってより短いプログラムを作れるかもしれない。 例えば次のPerlプログラムは上と同じ文字列を出力する。
print "01" x 30
このように記述言語 L における文字列 x のあらゆる記述のうちで最小の長さをもつ記述が見出せたとするなら、その長さが L における x のコルモゴロフ複雑性となる。
基本的な性質
自明な上限
前述の例で示されたように明示的に文字列 x をプログラムに含めることができるので、すべての x に対してそのコルモゴロフ複雑性 Ku(x) は x 自体の長さ |x| を定数分以上越えることはない。 すなわち、
定理: 任意の u に対して、ある定数 c が存在して、任意の x に対して、
が成り立つ。
記述言語による相対性
定義から明らかなように、コルモゴロフ複雑性は記述言語あるいは万能計算機に依存する。 しかし、ある万能計算機 u1 から別の万能計算機 u2 にプログラムを移植しても、コルモゴロフ複雑性はたかだか(u1 と u2 によって決まる) 定数分しか増えない。なぜなら2つの万能計算機は、必ずもう一方の計算機をエミュレートできるからである。 u2 上で u1を模倣するエミュレーションプログラム ε1,2 を作り、その上で u1 のためのプログラム p を動かせば、結果として u2 の上でプログラム p を動かせたことになる。 そしてこのエミュレーションプログラムはエミュレートするプログラムの大きさにかかわらずつねに一定である。 従って、 u2 上でのコルモゴロフ複雑性はたかだか l(p) + l(ε1,2) である。 逆の場合も同様にエミュレートができるので、すなわち、
定理: 任意の万能計算機 u1, u2 に対し、ある定数 c1,2 が存在して、任意の x に対し、
文字列 x が Ku(x) ≧ |x| となるなら x は「圧縮不能」であるという。 このような圧縮不能な文字列が存在するならどの程度存在するかを考えたい。 まず、簡単な基数 (濃度) についての考察から、ある長さの文字列 x すべての中には「圧縮不能」な文字列が少なくとも 1 つは存在していることがわかる。 なぜなら、長さ n のバイナリ列 (2 種類のアルファベットからなる文字列) は 2n 個存在するが、 それより短いバイナリ列は長さ 0 も含めて 2n - 1 しか存在しないからである。さらに同じ理由で、長さ n 以下の 2n+1 - 1 個のバイナリ列のうち、その半数より多い 2n が長さ n をもつのであるから、ある長さ以下のバイナリ列のうち圧縮不能な文字列は半数より多い。
一般に、圧縮不能の定義に自然数 c だけの余裕を入れ、Ku(x) ≧ |x| - c を満たすとした x を「c 圧縮不能」 という。 長さ n - c より短いバイナリ列の個数は、長さ n のバイナリ列と比べ、 (2n-c - 1) / 2n しかないので、 c 圧縮不能な文字列は全体の 1 - 1/2c より多い。 例えば、 c = 100 ビットだけ圧縮できるような文字列は、たかだか全体の 2-100 ∼ 10-30 しかない。
言い換えれば、任意の文字列 s を入力として整数 K(s) を出力するようなプログラムは存在しない。証明は背理法による。以下、あるプログラムを構成し、そのプログラムから出力される文字列が、そのプログラムよりも長いプログラムからでなければ出力され得ないという矛盾を導く。次のようなプログラムがあるとしよう:
function KolmogorovComplexity(strings)
これは文字列 s を入力とし K(s) を返却する。ここで次のようなプログラムを考える。
function GenerateComplexString(intn)
for i = 1 to 無限大:
for each 長さが丁度 i である string s の全集合に対して
if KolmogorovComplexity(s) >= nreturnsquit
このプログラムは KolmogorovComplexity() をサブルーチンとして呼び出す。このプログラムは長さが1から無限大に至るまでのありとあらゆる文字列を調べ、コルモゴロフ複雑性が少なくとも n 以上であるような文字列を見つけたらそれを返す。従って、任意の正の整数 n について、これはコルモゴロフ複雑性が少なくとも n 以上であるような文字列を生成する。このプログラム自身は固定的な長さを持つが、その長さを U と書こう。プログラム GenerateComplexString() に対する入力は整数 n だが、この大きさは n を表すのに必要なビット数で測ることとすると、これは log2(n) である。さて、ここで更に次のようなプログラムを考える:
function GenerateParadoxicalString()
return GenerateComplexString(n0)
この証明は背理法によるが、ここで現れる矛盾はベリーのパラドックスに似ている:「n を30字未満では表現できない最小の正の整数としよう」。他の証明方法として、K が計算不能であることを停止問題 H が計算不能であることに帰着して示すこともできる。K と H はチューリング同値である[1]。
関連する問題
データ圧縮の限界
(可逆な) 圧縮プログラムは与えられた文字列 x に関して、文字列 y を返す関数とみることができる。 ただし y は対応する展開プログラムで x に復元できなければならない。 よって、コルモゴロフ複雑性の定義から、展開プログラムの長さと y の長さの和は x のコルモゴロフ複雑性以上でなければならない。 この意味でコルモゴロフ複雑性はその文字列データに対する究極的な圧縮を限界づけている。
通常、圧縮プログラムでは y の長さは x よりも小さくなることが期待されるが、上述の圧縮不能な文字列の議論は圧縮プログラムに関しても成立するので、実際には圧縮できない x が少なくとも半数存在し、ほとんどは大きな圧縮ができない。 圧縮プログラムが我々が扱う多くの文字列を圧縮できるようにみえるのは、我々が実際に扱う文字列が、可能なすべての文字列と比べて極めて偏ったものにすぎないからである。
また、コルモゴロフ複雑性が計算不能であるという事実は、すべての文字列 x に対してコルモゴロフ複雑性がしめす究極の圧縮を実現するプログラムを作ることが原理的に不可能であるということを意味している。もしすべての文字列をコルモゴロフ複雑性まで圧縮するプログラムが存在すれば、その出力結果の長さを数えることでコルモゴロフ複雑性が計算できてしまい、上述の事実と矛盾するからである。
ランダム性
十分長い文字列において「圧縮不能」な文字列は、アルゴリズム化できるような何の規則性ももたないと考えられるので「ランダム」な文字列だとみなせるだろう。 コルモゴロフ複雑性を無限長の文字列に拡張したとき、圧縮できないような文字列は「アルゴリズム的にランダムな列」 (algorithmically random sequence) と呼ばれている。 正確には、与えられた無限列 x のすべての接頭部分列が c 圧縮不能であるような c が存在するとき、x はアルゴリズム的にランダムである。
殆どの文字列は、より「圧縮された」形では表現できないという意味で複雑である。しかしながら、文字列の長さがある閾値を超える場合、その文字列が複雑であることを形式的に証明することは出来ない、ということが言えてしまう。正確な定式化は以下の通り。まず、自然数を扱う特定の公理系 S を固定する。この公理系は次のことが出来る程度には強いものとする。即ち、S に含まれる式 FA を、文字列の複雑さに関する或る主張 A に関連付けることが出来る。この際、FAが S の公理から証明可能なら、これに対応する主張 A も真になるとする。この「定式化」に際しては、ゲーデル数化のような人工的な符号化を用いてもよいし、適用しようとする S をもっと明快に表現するような定式化を用いても良い。
定理:次の式(をS の中で定式化したもの)を公理系 S の中で証明できるように文字列 s を取れないような、定数 L(具体的な値は公理系と記述言語にのみ依存する) が存在する。
主張(X):任意の整数 n について、ある文字列 s が存在し、体系Sの中で式 「K(s)≧n」(がSの中で定式化できると仮定して)を証明できる。
S内の形式的証明全てを実効的に枚挙する何らかの手段を見つけることができる。
function NthProof(intn)
は入力として n を取り、適当な証明を出力する。この関数は全ての証明を枚挙する。その中には我々にとって差し当たり興味のない証明も混ざるだろう(NthProof()が枚挙する証明の中には例えば平方剰余の相互法則の証明、フェルマーの小定理の証明、フェルマーの最終定理の証明など、様々な既知の証明をS内の形式的言語に翻訳したものが現れるだろう)。この中の幾つかは K(s)≧n という形をした複雑性に関する式の証明である(s と n はS内の言語における定数)。さて、次のプログラムが存在する。
function NthProofProvesComplexityFormula(intn)
このプログラムは n 番目の証明が式 K(s)≧L を証明しているどうかを判定する。文字列 s と整数 L はそれぞれ以下のプログラムで計算可能である:
function StringNthProof(intn)
function ComplexityLowerBoundNthProof(intn)
ここで次のようなプログラムを考えよう。
function GenerateProvablyComplexString(intn)
for i = 1 to 無限大:
if NthProofProvesComplexityFormula(i) and ComplexityLowerBoundNthProof(i) >= nreturn StringNthProof(i)
quit
任意の n について、このプログラムは形式体系S内のありとあらゆる証明を調べ上げて、K(s)≧L(但しL ≧ n )を満たす文字列と証明を探し出そうとする。主張(X)によりこのプログラムは必ず停止する。このプログラムの長さを U としよう。
このとき、ある整数 n0 があって、U + log2(n0) + C < n0 を満たす。ここで C は、次のプログラムがGenerateProvablyComplexString()を呼び出す前後の固定的な長さである。
function GenerateProvablyParadoxicalString()
return GenerateProvablyComplexString(n0)
quit
プログラム GenerateProvablyParadoxicalString() は文字列 s を出力するが、このとき L が存在して K(s)≧L(但し L ≧ n0)を満たし、S内でこれを形式的に証明できる。特に K(s)≧n0 は真である。ところが、s は長さが U+log2(n0)+C であるプログラムでも生成できるので、その複雑性は n0 よりも小さい。これは矛盾である。よって主張(X)は成り立たないことが証明された。