エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

不完全性定理(6)

前回の「」に以下の機能を追加することにします。

  • 」では任意の長さの自然数を扱うことができる

プログラミング言語Cでも配列を使うことで実現できるので必要ない(メモリー不足にはならないとしているので任意の長さの配列を使うことができる)のですが、最初からできることにしておきます。

不完全性定理とはなにか 完全版 ゲーデルとチューリング 天才はなにを証明したのか (ブルーバックス B 2277)』を調べる前に「プログラミング言語不完全性定理」について ChatGPT で調べてみました。

プログラミング言語不完全性定理

入力:   h(n) = 1 を論理式で書くとどうなりますか

結果:

関数   h(n) の定義に基づくと、  h(n) = 1 とは 自然数   n が「」のコードであり、そのコードを実行したときに停止する ことを意味します。

これを論理式で書くと、次のように表現できます:
  
h(n) = 1 \iff \text{「Cω」のコードとして \( n \) が構文的に正しい} \land \text{「Cω」のコード \( n \) を実行すると停止する}

論理式の要素

1.   n が「」のコードであること

  • これは「  n 自然数として有効な『』のコードである」という意味です。これを   \text{is_code}(n) と書きます。

2. 」のコード   n を実行すると停止すること

  • これは「  n をコードとして解釈し実行したときに有限時間内に停止する」という意味です。これを   \text{halts}(n) と書きます。

論理式の結論

以上をまとめると、  h(n) = 1 は次のような論理式で書けます:

  
h(n) = 1 \iff \text{is_code}(n) \land \text{halts}(n)

補足

  •   \text{is_code}(n) :   n が「」のコードとして構文的に正しいことを示す述語。
  •   \text{halts}(n) : コード   n を実行したときに停止することを示す述語。

この   \text{halts}(n) が停止性問題(Halting Problem)に関係する述語であり、これを計算可能な形で定義することが一般には不可能であるため、関数   h の実現が理論的に不可能であることにつながります。

論理式で書くことができたかどうかよくわからないので、以下のように入力しました。

入力:   \text{halts}(n) は「すべてのループの実行回数とすべての関数呼び出しの実行回数の合計が有限」と言い換えることはできますか

結果:

はい、 \text{halts}(n) を「すべてのループの実行回数とすべての関数呼び出しの実行回数の合計が有限」と言い換えることは可能です。この言い換えは、停止性問題の性質を正しく表しています。

理由

停止性問題の本質は、「プログラムが有限の手順で終了するかどうか」を判定することです。この条件を満たすためには、以下の2点を確認する必要があります:

1. ループ:

  • プログラム内のすべてのループ(例えば、`for` や `while`)が有限回で終了する必要があります。
  • ループの無限実行は、プログラムの停止を妨げる主要な要因です。

2. 関数呼び出し:

  • プログラムが呼び出すすべての関数が有限回の処理で終了する必要があります。
  • 再帰的な関数呼び出しや関数の無限ループも停止を妨げます。

これら2つを合わせると、「プログラムのすべてのループと関数呼び出しが有限回で終了する場合、そのプログラムは停止する」と言えます。

言い換えとしての表現

この観点から、 \text{halts}(n) を次のように言い換えることができます:

  • 形式的な言い換え:

 
  \text{halts}(n) \iff \text{「プログラム \( n \) におけるすべてのループの実行回数とすべての関数呼び出しの実行回数の合計が有限である」}

  • 非形式的な言い換え:

プログラム   n の実行が無限に続かず、最終的に停止すること。

注意点

この言い換えは停止性問題の性質を直感的に捉えたものですが、停止性問題の本質的な難しさを解消するわけではありません。具体的には次の点が重要です:

1. 実行回数を事前に知るのは困難

  • あるプログラム   n におけるすべてのループや関数呼び出しの実行回数が有限かどうかを決定することは一般には不可能です(チューリング機械の停止性問題に帰着します)。

2. 停止性問題の非決定可能性

  • 停止性問題は一般に非決定可能であり、「すべてのループや関数呼び出しの実行回数が有限か」を判定する述語自体が計算可能ではありません。

したがって、この言い換えは停止性の性質を分かりやすく表現する助けにはなりますが、それを使って停止性問題を解決することはできません。

論理式で書くことはできると言えます。確認のためさらに以下を入力してみました。これは停止しないことを証明するにはループが実行される回数を調べる必要があると思われるためです。

入力: 無限ループは停止しないことを証明してください

結果:

無限ループが停止しないことは、その定義から明らかです。以下で論理的に説明します。

無限ループの定義

無限ループとは、終了条件が満たされないまま、あるいはループの構造自体が終了条件を持たないために、無限に繰り返し実行される処理を指します。

一般的な無限ループの構造は次のようになります:

1. 条件付きループ:

   while (true) { /* 処理 */ }

ここでは、ループの終了条件が常に `true` であるため、終了することがありません。

2. 条件が変化しないループ:

   while (x != 0) { /* 処理 */ }

ここで、`x` の値がループ内部で変更されない場合、条件 `x != 0` が常に `true` のままになり、ループは終了しません。

停止しないことの証明

無限ループが停止しないことを形式的に証明するには、「停止する」という仮定が矛盾を生むことを示す背理法を用いることができます。

1. 停止するという仮定

無限ループが停止すると仮定します。これは、ループの実行回数が有限であることを意味します。

2. 実行回数の有限性との矛盾

無限ループの定義において、次の2つが満たされます:

  • ループの条件が永遠に真であり続ける(終了条件が存在しない、または満たされない)。
  • 実行回数に上限がない(無限回繰り返される)。

したがって、「無限ループが停止する」という仮定は「無限の反復が有限回で終了する」と言っているのと等しくなり、これは矛盾です。

3. 結論

矛盾が生じたため、「無限ループが停止する」という仮定は誤りであるとわかります。よって、無限ループは停止しません。

形式的な論理記述

無限ループが停止しないことを数理論理的に記述する場合、次のように書けます:

1. 無限ループを表すプログラムを  P とする。
2. プログラムが停止するとは、ある有限のステップ数  t が存在し、プログラムがそのステップ数以内に終了することである。

無限ループの定義から、任意の有限の  t に対して次が成り立ちます:

\neg \exists t \, (\text{Program \( P \) halts within \( t \) steps})

これは、「無限ループが停止しない」ということを論理的に表しています。

補足

無限ループが停止しないことは、その動作をシミュレーションするだけでも観察可能です。しかし、停止性問題全体を考慮すると、特定のプログラムが無限ループに陥るかどうかを事前に判定することは一般には不可能です(停止性問題の非決定可能性)。

不完全性定理とはなにか 完全版 ゲーデルとチューリング 天才はなにを証明したのか (ブルーバックス B 2277)』では真であり証明できない論理式があると書かれています。このシステムでそのようなものがあるかどうかを調べるため、以下のように入力しました。

入力:  h(n_g) = 1 が真なのか偽なのかわかりますか

結果:

 h(n_g) = 1 が真か偽かを判定することは不可能です。これが停止性問題の非決定可能性によるものであり、自己参照的な構造を含む  h  n_g のような状況では矛盾が生じます。以下でその理由を詳細に説明します。

1.  n_g の定義

 n_g は自己参照的なプログラム  g のコード(自然数表現)とします。 g(n) の挙動は次のように定義されています:


g(n) =
\begin{cases}
\text{無限ループする} & \text{もし \( h(n) = 1 \)} \\
\text{停止する} & \text{もし \( h(n) \neq 1 \)}
\end{cases}

2.  h(n_g) を判定しようとすると矛盾が生じる

 h(n_g) = 1 と仮定した場合と  h(n_g) \neq 1 と仮定した場合をそれぞれ考えます。

ケース 1:  h(n_g) = 1 と仮定する
  •  h(n_g) = 1 であるなら、定義により  g(n_g) は無限ループします。
  • しかし、 h(n_g) = 1 は「 g(n_g) が停止する」と主張しているため、矛盾が生じます。
ケース 2:  h(n_g) \neq 1 と仮定する
  •  h(n_g) \neq 1 であるなら、定義により  g(n_g) は停止します。
  • しかし、 h(n_g) \neq 1 は「 g(n_g) が停止しない」と主張しているため、矛盾が生じます。

3. 結論:  h(n_g) = 1 を判定できない

この自己矛盾から、「 h(n_g) = 1 が真か偽かを判定することはできない」ことがわかります。これは、停止性問題の非決定可能性を直接示しています。

停止性問題の核心

この例は、停止性問題が計算理論的に決定不可能である理由を端的に示しています。関数  h を使って停止性を判定しようとすると、自己参照が生じ、論理的矛盾が発生するため、停止性を一般的に判定する  h のような関数は存在し得ません。

このシステムではたぶんできないので、条件を変えてみます。

入力: プログラミング言語の機能を制限すれば   h(n_g) = 1 が真なのか偽なのかわかりますか

結果:

プログラミング言語の機能を制限することで、特定の条件下で   h(n_g) = 1 が真なのか偽なのかを判定できる場合があります。ただし、その判定可能性は言語の制限の程度に依存します。以下に詳しく説明します。

1. プログラミング言語を制限する例

停止性問題の決定不可能性は、チューリング完全プログラミング言語における特性です。したがって、言語が以下のように制限されている場合には、停止性が判定可能になる場合があります:

a. 再帰や無限ループを禁止
  • プログラムに再帰関数や無限ループ (`while (true)`) を記述できないようにする。
  • 例として、単純な有限の命令セットのみを許すプログラム(例:ループ回数が静的に決まる)を考えます。

この場合、すべてのプログラムの実行が有限であるため、  h(n_g) = 1 かどうかを常に判定可能です。言語の性質上、無限ループが生じないからです。

b. 実行時間やステップ数に上限を設定
  • プログラムに「最大ステップ数」や「最大計算時間」の上限を課す。
  • この制限下では、停止するかどうかをプログラムのシミュレーションによって決定できます。停止しなければ「時間切れ」と判定すればよいためです。

ただし、これは「時間切れ」を停止性の代替条件とするものであり、停止性問題そのものを完全に解決しているわけではありません。

2. 言語制限と   h(n_g) の判定可能性

  h(n_g) = 1 を判定可能にするためには、以下の条件を満たす必要があります:

1. 言語の表現力が有限であること

  • プログラムが計算可能なすべての処理を記述できる(チューリング完全である)場合、停止性問題の決定不可能性から、一般には   h(n_g) = 1 を判定できません。
  • 表現力を有限に制限した場合(例:すべてのループが有限回数で終了するなど)、停止性が判定可能になります。

2. プログラムの挙動が静的解析可能であること

  • プログラムの停止性をコードの構造や仕様から解析的に判断できる場合(例:すべてのループ回数が静的に計算可能)、  h(n_g) = 1 を判定できます。

3. 具体例

制限された言語での例
  • ループ回数が明示的に固定されている場合
  for (int i = 0; i < 10; i++) { /* 処理 */ }

この場合、ループが必ず終了するため、停止性が保証されます。したがって、  h(n_g) を判定できます。

  • 無条件で無限ループを含む場合
  while (true) { /* 処理 */ }

この場合、停止しないことが静的に判定できます。

チューリング完全な言語の例

次のようなプログラムでは、静的解析では停止性を判断できません:

int f(int x) {
    if (x == 0) return 1;
    else return f(x - 1) + f(x - 2);
}

入力によって計算が停止するかどうかが動的に変わるため、  h(n_g) を一般的に判定することはできません。

4. 結論

プログラミング言語の機能を制限すれば、特定のケースで   h(n_g) = 1 の判定が可能です。しかし、これにはトレードオフがあります:

  • 言語の表現力が制限され、汎用的な計算能力を失う(チューリング完全ではなくなる)。
  • チューリング完全な言語であれば、自己参照構造を含むプログラムの停止性問題は解決できない。

したがって、言語を制限することで停止性を判定可能にすることはできますが、それは汎用的なプログラミング言語としての能力を犠牲にすることを意味します。

条件についてはよくわからなかったので『不完全性定理とはなにか 完全版 ゲーデルとチューリング 天才はなにを証明したのか (ブルーバックス B 2277)』を見ていきたいと思います。