web-dev-qa-db-ja.com

停止の問題は正確には何ですか?

プログラミングに関連する停止の問題について人々が尋ねるときはいつでも、人々は「ループを1つだけ追加すると、停止するプログラムを手に入れ、したがってタスクを自動化できない

理にかなっています。プログラムに無限ループがある場合、プログラムの実行中に、プログラムがまだ入力を処理しているかどうか、またはプログラムが無限にループしているかどうかを知る方法はありません。

しかし、これの一部は直観に反するようです。ソースコードを入力として受け取る停止問題ソルバーを作成していたとしたらどうでしょう。 rascher@localhost$ ./haltingSolver source.c

私のコード(source.c)が次のようになっている場合:

for (;;) {  /* infinite loop */  }

私のプログラムがこれを見るのはかなり簡単なようです。 「ループを見て、条件を見てください。条件がリテラルのみに基づいていて、変数がない場合は、常にループの結果がわかります。変数がある場合(while(x <10)など)は、これらの変数は常に変更されます。変更されない場合は、ループの結果が常にわかります。」

確かに、これらのチェックは簡単ではありません(ポインタ演算など)が、不可能ではないようです。例えば:

int x = 0
while (x < 10) {}

検出される可能性があります。と一緒に-自明ではありませんが:

int x = 0
while (x < 10)
{
   x++;
   if (x == 10)
   {
      x = 0
   }
}

では、ユーザー入力はどうですか?それがキッカーであり、それがプログラムを予測不可能にするものです。

int x = 0;
while (x < 10) 
{
   scanf("%d", &x); /* ignoring infinite scanf loop oddities */
}

これで私のプログラムは次のように言うことができます。「ユーザーが10以上を入力すると、プログラムは停止します。他のすべての入力では、再びループします。」

つまり、何百もの入力がある場合でも、1つがプログラムが停止する条件をリストできる必要があります。確かに、私がプログラムを書くとき、私は常に誰かがそれを終了する能力を持っていることを確認しています!結果として得られる条件のリストが作成するのが簡単だと言っているわけではありませんが、私には不可能ではないようです。ユーザーからの入力を取得し、それらを使用してポインターインデックスを計算することなどができますが、プログラムが確実に終了するように条件の数を増やすだけで、それらを列挙することは不可能になりません。

それで、停止の問題は正確には何ですか?無限ループを検出する問題を記述できないという考えについて、私は何を理解していませんか?または、なぜ「ループ」がよく引用される例なのでしょうか。

[〜#〜]更新[〜#〜]

では、質問を少し変えてみましょう。コンピュータに当てはまる停止の問題は何ですか?そして、いくつかのコメントに応答します。

プログラムは「任意の入力」を処理できなければならない、と多くの人が言っています。しかし、コンピュータでは、任意の入力はありません。 1バイトのデータしか入力しない場合は、2 ^ 8の入力しかありません。したがって、例として:

int c = getchar()

switch (c) {
   case 'q':
      /* quit the program */
}

突然、私はすべての可能性を説明しました。 cのビットパターンが0x71の場合、1つの処理を実行します。他のすべてのパターンでは、他のパターンを実行します。リソースが有限であるため、任意の文字列入力を受け入れるプログラムでも、実際には「任意」ではありません。つまり、「任意」の理論が適用されますが、実際には1対1ではありません。

引用された他の例はこれです:

while (n != 1)
    if (n & 1 == 1) 
        n = 3 * n + 1;
    else 
        n /= 2;

Nが32ビット整数の場合...これが停止するかどうかを視覚的に伝えることができます。

この編集は何も求めていないと思いますが、私が見た中で最も説得力のある例は これ です:

プログラムが停止することを決定する魔法のプログラム/メソッドがあると仮定します。

public bool DeterminesHalt(string filename, string[] args){
    //runs whatever program you tell it do, passing any args
    //returns true if the program halts, false if it doesn't
}

次に、次のような小さなコードを記述したとします。

public static void Main(string[] args){
    string filename = Console.ReadLine(); //read in file to run from user
    if(DeterminesHalt(filename, args))
        for(;;);
    else
        return;
}

したがって、この例では、魔法の停止方法とは正反対のプログラムを記述できます。特定のプログラムが停止すると何らかの方法で判断した場合は、無限ループにジャンプします。そうでなければ、プログラムが無限ループにあると判断した場合、プログラムを終了します。

繰り返しますが、意図的に無限ループを含むプログラムを記述した場合、「停止の問題を解決する」ことは一種のモットーではありませんか。

52
poundifdef

編集(元の回答よりはるかに遅い):MarkCCの Good Math、Bad Math は最近、具体的な例を示したホールティング問題の excellent議論 を書きました。

停止問題は基本的に、任意のプログラムが最終的に停止するかどうかを確認できるかどうかを尋ねる正式な方法です。

言い換えれば、program(input)が最終的に停止する場合はtrueを返し、停止しない場合はfalseを返す、停止Oracle、HaltingOracle(program、input)と呼ばれるプログラムを作成できますか?

答えは:いいえ、できません。

Halting問題への入力が関連しているかどうか、またはニシンが関連しているかどうかに関する質問のフォローアップ:はい、入力は重要です。また、「任意」の方が正しい場所で「無限」が使用されているのを見ると、混乱が生じるようです。

実際の例:あなたがQAのポジションで働いていて、停止するチェッカープログラム(別名Oracle)を書いて、 arbitrary開発チームが作成したプログラム(D)、およびエンドユーザー(I)が提供するarbitrary入力、プログラムD入力Iが与えられると、最終的に停止します。

キューマネージャーの声:「ほらほら、間抜けなユーザーは、どんなガベージを入力しても、サーバータスクが無限ループに陥ることがないようにしましょう。 、コードモンキー!」

これは素晴らしいアイデアのようですよね?サーバーをハングさせたくないですか?

停止の問題があなたに言っているのは、あなたが解決できない課題を手渡されているということです。代わりに、この特定のケースでは、しきい値時間を超えて実行され、それらを取り消す準備ができているタスクを計画する必要があります。

Markは入力の代わりにコードを使用して問題を説明します。

def Deciever(i):
  Oracle = i[0]
  in = i[1]
  if Oracle(Deceiver, i):
    while True:
      continue
  else:
    return i

コメントでの私の議論では、悪意のある入力操作の経路をたどって、解決できない問題を強制しました。マークの例ははるかに洗練されており、停止しているOracleを使用して自分自身を打ち負かしています。

したがって、Deceiverへの入力は、実際には2つの要素のリストです。最初の要素は、Oracleを停止する提案です。 2番目は別の入力です。停止キラーはオラクルに尋ねます:「私は入力iのために停止すると思いますか?」。 Oracleが「はい、停止します」と言った場合、プログラムは無限ループに入ります。オラクルが「いいえ、停止しません」と言った場合、停止します。オラクルが何を言っても、それは間違っています。

別の言い方をすると、不正行為、入力の再フォーマット、数え切れないほど/数えきれないほどの無限、またはその他の注意散漫なしに、マークはOracleプログラムを停止させる任意のに勝つことができるコードを書きました。 Oracleが停止するかどうかの質問に答えるDeceiverを書くことはできません。

元の答え:

偉大なものから Wikipedia

計算可能性理論では、停止問題は次のように述べることができる決定問題です。プログラムの説明と有限入力を与えられて、その入力を与えられて、プログラムが実行を終了するか、永久に実行するかを決定します。

アランチューリングは、1936年に、すべての可能なプログラムと入力のペアの停止問題を解決する一般的なアルゴリズムは存在できないことを証明しました。停止の問題はチューリングマシンでは決定できないと言います。 Copeland(2004)は、実際の用語の停止問題をMartin Davisに帰します。

重要なポイントの1つは、プログラムまたは入力を制御できないことです。あなたはそれらを渡され、質問に答えるのはあなた次第です。

チューリングマシンは、計算能力の効果的なモデルの基礎であることにも注意してください。別の言い方をすると、現代のコンピューター言語で行うすべてのことを、これらの典型的なチューリングマシンにマッピングすることができます。その結果、停止の問題は、有用な現代の言語では決定できません。

51
Bob Cross

停止の問題を解決するには、任意のプログラムが任意の入力に対してを停止するかどうかを判断できるアルゴリズムを開発する必要があります。 。

40
dsimcha

これは、停止の問題が決定不可能であることの証明の簡単な説明です。

プログラムが停止したかどうかを計算するプログラムHがあるとします。 Hは2つのパラメーターを受け取ります。最初のパラメーターはプログラムの説明Pで、2番目のパラメーターは入力Iです。Hは、Pが入力Iで停止した場合にtrueを返し、それ以外の場合はfalseを返します。

次に、別のプログラムp3の説明を入力として受け取るプログラムp2を記述します。 p2はH(p3、p3)を呼び出し、Hがtrueを返した場合はループし、そうでない場合は停止します。

P2(p2)を実行するとどうなりますか?

それはループし、同時に停止しなければならず、宇宙を爆発させます。

29
Graphics Noob

これはよく打ちのめされて、実際には poeticproof のスタイルで書かれています ルイス・キャロル Geoffrey PullumによるSeuss博士(彼は Language Log の名声)。

面白いもの。ここに味があります:

これが私が使用するトリックです-そしてそれは簡単です。
Qと呼ぶ手順を定義します。
これは、成功を止めるというPの予測を使用します
ひどい論理的混乱を引き起こします。

...

Pがどのように実行しても、Qはそれをすくいます。
QはPの出力を使用して、Pを愚かに見せています。
Pが何を言っても、Qを予測することはできません。
Pは、間違っている場合は正しい、真の場合は間違っている!

21
Doug McClean

ウィキペディアに 停止問題 のOKの証明があります。

正確に言うと、ループに何らかの手法を適用するだけでは不十分な理由として、次のプログラム(疑似コード)を考えてみます。

int main()
{
  //Unbounded length integer
  Number i = 3;

  while(true)
  {
    //example: GetUniquePositiveDivisiors(6) = [1, 2, 3], ...(5) = 1, ...(10) = 1, 2, 5, etc.
    Number[] divisiors = GetUniquePositiveDivisiors(i);
    Number sum = 0;
    foreach(Number divisor in divisiors) sum += divisor;

    if(sum == i) break;

    i+=2;
  }
}

このコードが停止した場合はtrueを返し、それ以外の場合はfalseを返すアプローチを考えられますか?

慎重に考える

偶然にもフィールズメダルをめぐって深刻な争いになっている場合は、上記のコードの代わりに これらの問題 のコードを想像してみてください。

9
Kevin Montrose

「ループを1つだけ追加すると、停止プログラムが作成されるため、タスクを自動化できません。」

停止問題の適用を一般化することについて誰かが言っているように聞こえます。終了を証明できる特定のループがたくさんあります。幅広いクラスのプログラムの終了チェックを実行できる調査が存在します。たとえばCoqでは、終了を証明できるプログラムに限定されます。マイクロソフトには、プログラムが終了することを証明するためにさまざまな近似を使用するターミネーターと呼ばれる研究プロジェクトがあります。

ただし、停止の問題はおもちゃの例だけではありません。これらはすべてのプログラムで機能するわけではないため、どちらも一般的な「停止の問題」を解決しません。

問題は、停止問題が、プログラムを実行せずに終了するかどうかを知る方法がないプログラムが存在することを示しています。つまり、停止するかどうかを決定することは決してできません。

(Haskellで)停止する場合と停止しない場合があるプログラムの例:

collatz 1 = ()
collatz !n | odd n     = collatz (3 * n + 1)
           | otherwise = collatz (n `div` 2)

またはよりアクセシブルなもの:

while (n != 1)
    if (n & 1 == 1) 
        n = 3 * n + 1;
    else 
        n /= 2;

すべての整数が1以上の場合、このプログラムは停止しますか?まあ、これまでのところはうまくいきましたが、すべての整数で停止するという定理はありません。 Lothar Collat​​z による予想があるため、1937年まで遡りますが、証明はありません。

7
Edward KMETT

チューリングのすばらしい例は自己参照でした-そこにIS別のプログラムを調べて、それが停止するかどうかを判断できるプログラムがあるとします。停止プログラムチェッカーITSELFを停止プログラムに送りますチェッカー-それは何をすべきですか?

5
n8wrl

サブポイント「人々は「1つのループを追加しただけでは停止プログラムがあり、したがってタスクを自動化できない」で応答する」を参照して、次の詳細を追加します。

任意のプログラムが停止するかどうかをアルゴリズムで計算できないと言っている投稿は、チューリングマシンにとって完全に正しいものです。

問題は、すべてのプログラムがチューリングマシンを必要とするわけではないということです。これらは、概念的に「より弱い」マシンで計算できるプログラムです。たとえば、正規表現は、入力時に常に停止する有限状態マシンによって完全に具体化できます。いいですね。

人々が「ループを1つ追加する」と言うとき、彼らは、プログラムが十分に複雑である場合、チューリングマシンを必要とし、したがって(アイデアとしての)停止問題が適用されるという考えを表現しようとしていると思います。

これは質問に少し正接するかもしれませんが、質問の詳細を考えると、これは指摘する価値があったと思います。 :)

5
agorenst

ここに停止の問題が決して解決できないプログラムがあります。

プログラムが停止することを決定する魔法のプログラム/メソッドがあると仮定します。

public bool DeterminesHalt(string filename, string[] args){
    //runs whatever program you tell it do, passing any args
    //returns true if the program halts, false if it doesn't
}

次に、次のような小さなコードを記述したとします。

public static void Main(string[] args){
    string filename = Console.ReadLine(); //read in file to run from user
    if(DeterminesHalt(filename, args))
        for(;;);
    else
        return;
}

したがって、この例では、魔法の停止方法とはまったく逆のプログラムを作成できます。特定のプログラムが停止すると何らかの方法で判断した場合は、無限ループに入ります。そうでなければ、プログラムが無限ループにあると判断した場合、プログラムを終了します。

入力チェックをいくつ実行しても、作成されたすべてのプログラムが停止したかどうかを判断するための可能な解決策はありません。

4
ahawker

これまでに多くの興味深い具体例/アナログがあります。背景をさらに深く読みたい場合は、チャールズペッツオールドによるチューリングのオリジナルペーパー The Annotated Turing に関する優れた本があります。

関連する、横並びで、ウェブ上には本当にきちんとしたエッセイがあります 誰がより大きな数に名前を付けることができますか? これは、チューリングマシンとアッカーマン関数を磨きます。

3
Don Wakefield

これは 停止中の犬の問題 の変形ですが、犬の代わりにプログラムを使用し、吠えずに停止します。

2
Firas Assaad

すでに良い答えはたくさんありますが、理論と実用性の選択的な混合の一種で、停止問題が実際に解決可能であるという事実に誰も対処したことはありません。

まず第一に、停止問題は基本的に、任意の2番目のプログラムを受け取り、2次プログラムが任意の入力で停止するかどうかを決定するプログラムを作成するタスクです。つまり、「はい、このプログラムはこの入力で停止します」または「いいえ、停止しません」と言います。そして実際には、チューリングマシンでの一般的なケース(他の人々はすでにこの証拠を提供しているようです)では解決できません。本当の問題は、何かを実行することで停止するかどうかを確認することができる(停止するまで待つ)が、実行することで停止しないかどうかを実際に確認できないことです(永遠に待ち続けるだけです)。

これは、定義上、メモリの量が無限であるため、状態が無限にあるチューリングマシンの問題です。ただし、私たちのコンピュータには限られた量のメモリしかありません。コンピュータには非常に多くのビットしかありません。したがって、プログラムの実行中に見た以前のすべての状態(ビット構成)を何らかの方法で追跡できれば、チェッカーが無限ループに陥らないことを保証できます。二次プログラムが最終的に停止する場合は、「はい、このプログラムはこの入力で停止します」と言います。停止する前に同じビット構成が2回表示される場合は、「いいえ、それはできません」とわかります。技術的にはそれほど重要ではないかもしれませんが、私たちが直面している本当に「難しい」問題は、理論上は実際よりも難しいことが多いことを知っておくのは良いことです。

2
Ambuoroko

別の観点からの証明

Mov、add、jmpなどの命令が含まれているが、inもoutもないCPUがあるとします。そして、記憶を得た。他のCPUとは異なり、これにはparaRegと呼ばれる別のレジスタがあります。このレジスターはファイルのようなもので、無制限のコンテンツをそこに移動し、サイズを取得し、途中でシークし、コンテンツから一部のコンテンツを削除することができます。

始める前に、いくつかの単語を定義しましょう。 programは一連の命令であり、文字列です。プログラムを実行する前に、parameter(文字列)を保持するparaRegを除くすべてのレジスタとメモリをゼロにクリアしてから、プログラムをメモリ位置ゼロに配置し、IPレジスタをゼロに設定します。 プロセスは、プログラムの実行中です。

これで、停止の問題は次のように述べることができます:proObjと呼ばれる任意のプログラムが与えられた場合(パラメーターpara0を取る場合、その最初の行に命令を追加します:mov paraReg、para0)、proObjをパラメータと、0に設定されたparaRegでproObjが実行を開始したときにproObjが停止するかどうかを決定できますか?

P1と呼ばれるそのようなプログラムを入手したとします。次に、パラメーターpara0を取るp2と呼ばれる別のプログラムを作成できます。 p1を介して、コンテンツがpara0、パラメーターがpara0のプログラムが停止するかどうかを判断できます(この方法で行います。最初の行が[mov paraReg、para0]で、残りがpara0であるプログラムを作成します。このプログラムにpro0という名前を付けます。次に、paraRegをpro0に設定してp1を呼び出します。)停止する場合は、p2を無限ループに入れ、そうでない場合はp2を停止させます。

P2をparaRegに入れてp2を実行すると、プロセスは停止しますか?停止した場合、p2の定義から、p2をparaRegに入れてp2を実行したときに、停止してはなりません。同様に、停止しない場合は、p2をparaRegに入れてp2を実行すると、停止するはずです。次に、p2がなく、p1がないと言えます。

2
zhengyitian

簡単なケースをいくつか挙げました。

それでは、残りのすべてのケースについて考えてみましょう。

可能なシナリオの数は無数にあり、それらすべてをリストする必要があります。

もちろん、一般化することはできません。

ここで停止の問題が発生します。どのように一般化しますか?

1
Tom Hubbard

プログラムはどのように Collat​​z予想 を解決しますか?

1
Adrian Panasiuk

Programming Pearls から、Jon Bentley著

4.6問題

5。このプログラムは、入力xが正の整数のときに終了することを証明します。

while x != 1 do
    if even(x)
        x = x/2
    else
        x = 3*x +1
1

停止問題の重要性は、問題自体の重要性にありません。逆に、自動化されたテストはソフトウェアエンジニアリングではほとんど実用的ではありません(プログラムが停止することを証明しても、それが正しいであることは証明されません。いずれにしても、仮定のアルゴリズムは特定の有限の一方、実際のソフトウェア開発者はall可能な有限入力のテストに関心があります)。

むしろ、停止問題は最初に証明されたものの1つでしたndecidable、つまり、一般的なケースで機能するアルゴリズムが存在しないことを意味します。言い換えると、チューリングは70年以上前に、コンピュータが解決できない問題がいくつかあることを証明しました。

0
Todd Owen

さらに別の例。最近、ひょうの数と呼ばれるものに遭遇しました。これらの番号は、これらのルールでシーケンスを形成します

f(n) is odd  -  f(n+1) = 3*f(n)+1
f(n) is even -  f(n+1) = f(n)/2

現在、すべての開始点は最終的に1に到達し、4,2,1,4,2,1,4,2,1...を繰り返すと想定されていますが、これについての証拠はありません。したがって、現在、雹のシーケンスに入力されたときに数値が終了するかどうかを判断する唯一の方法は、1に到達するまで実際に計算することです。

これは、[〜#〜] i [〜#〜]が停止の問題をどのように理解するかへの鍵です。私がそれを理解する方法は、あなたができないことです確かにあなたが実際にプログラムを実行しない限りプログラムが停止する/しないことを知っています。ですから、あなたが書いたプログラムが、停止の問題への答え確かにを与える可能性があるなら、実際にプログラムを実行する必要があります。

0
Mike Cooper

これを読むことをお勧めします: http://en.wikipedia.org/wiki/Halting_problem 、特に http://en.wikipedia.org/wiki/Halting_problem#Sketch_of_proof =この問題をアルゴリズム的な方法で解決できない理由を理解するため。

0
Artyom

コードの任意の部分をチェックし、それが停止するかどうかを通知できるアルゴリズムを作成するとします。

確認するアルゴリズム自体を指定します。

0
John Smith

問題の正確な定義は、次のことを行うプログラムを作成する必要があることです。-任意のプログラムを取得-プログラムへの任意の有限入力を与えられてプログラムが停止するかどうかを決定

しかし、これは本当に高い水準です。停止の問題には多くの部分的な解決策がありますが、一般的な解決策はありません。さらに悪いことに、停止の問題を部分的に解決するプログラムを見つけることさえ難しいことが知られています。

停止問題に関するBBC h2g2記事

停止の問題を本当に解決した場合は、rentacoder.comなどのサイトで作業できます。数か月前、停止の問題を解決するための契約を申し出たATuringというユーザーからの投稿がありました。 :)

0
James Thompson

自分の芝生を刈っていない人の芝生を刈っている男の話を考えて、自分の芝生を刈っているのかどうかを自問するのが役立つかもしれません。

0