ブレインの停止問題を部分的に解決する***


9

停止問題を解決するには、プログラムの説明が表示され、プログラムが終了するかどうかを判断する必要があります。すべてのプログラムに対してこれを行うことはできません。(brainf ***のような)プログラムの場合:

>

それは明らかに停止し、次のようなプログラムの場合:

+[]

それは明らかにしません。あなたの課題は、可能な限り多くのプログラムの停止問題を「解決」することです。これらのプログラムは.またはを使用,せず、入力も出力もありません。プログラムの説明が表示され、「停止」、「停止しない」、または「不明」のいずれかを出力する必要があります。プログラムが「停止」または「停止しない」を出力する場合、入力プログラムは解決されています。ここにいくつかの要件があります。

  1. それは少なくとも無限の量のプログラムを解かなければならない。
  2. それが解決するすべてのプログラムについて、そのソリューションは正しい必要があります。
  3. 上記の3つの選択肢から1つだけを出力できます。
  4. 実行中のコンピュータには無限の時間とメモリがあるため、XKCD 1266は機能しません(テープは無制限です)。
  5. 外部リソースはありません。
  6. 停止の問題を実際に解決できるプログラミング言語を使用することはできません。

プログラムである文字列を受け取り、必要に応じてその抽象構文ツリーを生成する非コード側プログラムがある場合があります。これは実際にはスコアリングではありませんが、あるプログラムが別のプログラムよりも優れているかどうかを判断する方法に注意してください。

  1. プログラムAがBが解決しない無限の数のプログラムを解決するが、Bが解決するプログラムが有限であるか、Aが解決しない場合、Aが自動的に勝ちます。
  2. それ以外の場合は、文字数が最も少ないプログラムが優先されます。空白やコメントは数えないので、コードを難読化しないでください。

ヒント:タイマーは機能しません。いつでもTと指定されたマシンにはNがあり、それより長いプログラムはすべてT時間以上かかる必要があることがわかります。これは、タイマーは有限数のプログラムの解を達成することしかできないことを意味し、上記からわかるように、有限数のプログラムを解いても役に立ちません。


3
採点システムが機能するとは思いません。ソリューションが与えられれば、次のようにしてより良いものを構築するのは簡単です:ソリューションSが「不明」を出力するプログラムPを見つけ、入力Pに正しい答えを出力する新しいソリューションを作成します。の>最後に追加されたs(これらはPが停止した場合に停止するため)、および他のすべての入力でSの回答を出力 この新しいソリューションを解きS.よりも無限に多くの問題
cardboard_box

ただし、これらはソリューションを追加しませんでした。たとえば、元のPは「最後のものが>である場合、それを無視します」とだけ言うことができます。次に、あなたのことは冗長になります。
PyRulez 2014年

そうです。まず、Sと同じように答えます>が、プログラムの終了後はsを無視するソリューションS 'を作成します。次に、Sが「不明」と答えるプログラムPを見つけ、次にPで正しく答える新しいソリューションを作成します。>sが追加され、それ以外の場合はS 'の答えを示します。S 'は>sを無視するため、任意の数の>sが追加されたP もS'によって解決されません。
cardboard_box

3
「少なくとも無限の量のプログラム」?もっと解くためのボーナスはありますか?;-)
Jonathan Van Matre 2014年

1
明らかに参照実装に従っていないため、他のすべての実装の違いを明確にする必要があります:セルサイズ、アンダーフローとオーバーフローでの動作、テープが両方向で無限であるか、片方向のみであるか、および1つだけである場合あなたはそれを通過しようとします。最も厳密に指定された言語ではありません...
ピーターテイラー14年

回答:


8

Python、ゴルフのスパゲッティコード

まあ。

def will_it_halt(instructions):
    tape_length = 1
    LOOP_BOUND = 1000
    registry = [0] * tape_length
    pos = 0

    jumpbacks = []
    reached_states = set()

    pos_instructions = 0
    while True:
        letter = instructions[pos_instructions]
        if letter == "+":
            registry[pos] = (registry[pos] + 1) % 256
        elif letter == "-":
            registry[pos] = (registry[pos] - 1) % 256
        elif letter == ">":
            pos += 1
            if pos >= tape_length:
                registry += [0]*tape_length
                tape_length = len(registry)
        elif letter == "<":
            pos -= 1
            if pos <= 0:
                registry = [0]*tape_length+registry
                tape_length = len(registry)
                pos += tape_length
        elif letter == "[":
            if registry[pos] == 0:
                nests = 1
                while nests:
                    pos_instructions += 1
                    if instructions[pos_instructions] == "[": nests += 1
                    elif instructions[pos_instructions] == "]": nests -= 1

                if jumpbacks == []:
                    reached_states.clear()

            else:
                jumpbacks.append(pos_instructions-1)

        elif letter == "]":
            stripped_registry = [str(x) for x in registry if x != 0]
            translated_pos = pos - (len(registry) - len(stripped_registry))
            state = (translated_pos, pos_instructions, ".".join(stripped_registry))
            if state in reached_states: return "Does not halt"
            elif len(reached_states) > LOOP_BOUND: return "Unknown"
            else:
                reached_states.add(state)
                pos_instructions = jumpbacks.pop()
        pos_instructions += 1
        if pos_instructions >= len(instructions): break
    return "Halts"

問題のかなり強力な解決策:bfコードを実行するだけです。テープの長さは任意に長く、個々のセルは256で折り返すと想定します。すべてのループの終わりに、セットでテープの状態を保存します。状態は形式です(テープ上の私たちの位置、指示上の私たちの位置、先行する0が取り除かれたテープの外観)。

同じ状態を2回保存すると、無限ループのどこかにいるため、プログラムは停止しません。1,000以上の州を保存している場合は、損失を削減し、不明を返します。ループを抜けたら、大きなループになっていないかどうかを確認します。そうでない場合は、以前の状態が二度と表示されることはありません(少なくとも、命令の位置は常に異なります)。これにより、状態のセットをクリアできます。

これにより、ループが1,000回の反復より長くないBFプログラムや、ループで1,000回の反復の前に状態を繰り返す多くのプログラムが正確に判断されます。ただし、すべてではありません。「{100万+がここにある} [-]> + [+-]」のようなものは最終的に状態を繰り返しますが、[-]ループは最初に1,000回の繰り返しを通過します。

いくつかの例:

>+>->+>-

ループがないため、最後に到達して停止します。

+[+]

ループは256回の反復後に終了するため、ループは最後に到達して停止します。

+[+-]

最終的に状態(0,5、 "1")を繰り返すため、停止しません。

+[->+]

これは状態を繰り返しませんが、ループが終了することはないため、「不明」と出力されます。しかし、プログラムはここで詐欺のようなものです。テープに位置を保存する代わりに、元のレジストリとストリップされたレジストリの間にオフセットを追加します。ループがテープをいくつかのスペースだけ平行移動する場合、それは(ライフグライダーのように)テープを無期限に平行移動し続けるので、停止しないと言えます。

+[>+]

翻訳しない、状態を繰り返さない、不明と出力する。

+++++++++++[-]

これは停止しますが、LOOP_BOUNDが10の場合は「不明」と出力されます。

これをよりスマートにする方法はいくつかあります。LOOP_BOUNDを増やして、未知数の数を減らすことは明らかです。ネストされたループをよりスマートに処理できます。BB番号とループのサイズを工夫して、何かが停止するかどうかをより適切に検出できるかもしれませんが、CSでもPythonでもまだそれを行うには不十分です。


2

GolfScript(23文字、無限正解)

'[]'&!
# 0 if there are brackets, so Unknown
# 1 if there are no brackets, so no looping, so definitely halts
'UnknownHalts'7/=

1
無限の正解を言うことは、要件であったため不要です。
PyRulez 2014年

2
規則の乱用... Lol
Isiah Meadows

1

Awk

2つの例からの電力の小さな拡張。プログラムにループがまったく含まれておらず、したがって決定も含まれていない場合でも、プログラムは停止することが明らかに決定されています。プログラムの有効性を想定しているので、角かっこはバランスが取れていると想定しているため、角かっこのどちらか一方を検索するだけで済みます。

BEGIN{RS=""}
!/\[/{print "Halts"; exit}
END{print "Unknown"}

2番目の場合、最初にループが実行されるかどうかをチェックする必要があるため、ループの前の直線コードをシミュレートする必要があります。次に、ループが同じセルに戻り(つまり、>sの数が<ループ内のs の数に等しい)、このセルでincsまたはdecsを実行しない場合(つまり、バランスのとれた位置バランスのプレフィックスの場合)ループ本体のインスタンスが存在しない+、または-次の前<または>後、細胞)は非修飾されます。この部分の実装には、さらに時間がかかる場合があります。ああ、待って、ループが実行されるかどうかを確認する最初の部分では、これと同じアイデアを使用して、ループ前のプログラムでバランスのとれたサフィックスを検索し、+or -(アンバランス)があると主張できます。


0

ハスケル

これは本当に簡単な答えの例です。回答に自由に含めてください(回答に複数のテストを含めることをお勧めします。)

main=do
    p<-getLine
    if take 3 p == "+[]"
        then putStr "Does not halt"
        else putStr "Unknown"

基本的には、最初にループがあるかどうかを調べます。その正確なループが最初に発生しない場合は、あきらめるだけです。でも動作しません++[]。ただし、無限の数のプログラムを解決します。解決するときは常に正しいです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.