Подтвердить что ты не робот

Обнаружение бесконечного цикла в программе brainfuck

Я написал простой brainfuck интерпретатор в языке MATLAB script. Он управляется случайными программами bf для выполнения (как часть проекта генетического алгоритма). Проблема, с которой я сталкиваюсь, заключается в том, что программа оказывается бесконечной петлей в большом количестве случаев, и, следовательно, GA застревает в точке.
Итак, мне нужен механизм для обнаружения бесконечных циклов и избежать выполнения этого кода в bf.
Один очевидный (тривиальный) случай - когда у меня есть

[]

Я могу обнаружить это и отказаться от запуска этой программы.
Для нетривиальных случаев я понял, что основная идея заключается в том, чтобы определить, как одна итерация цикла меняет текущую ячейку. Если изменение отрицательное, мы в конечном итоге достигнем 0, так что это конечная петля. В противном случае, если изменение неотрицательно, это бесконечный цикл.
Реализация этого легко для случая одного цикла, но с вложенными циклами он становится очень сложным. Например, (в дальнейшем (1) относится к содержимому ячейки 1 и т.д.)

++++ Put 4 in 1st cell (1)
>+++ Put 3 in (2)
<[   While( (1) is non zero)
    --   Decrease (1) by 2
    >[   While( (2) is non zero)
        -    Decrement (2)
        <+   Increment (1) 
    >]   
    (2) would be 0 at this point
    +++  Increase (2) by 3 making (2) = 3
<]   (1) was decreased by 2 and then increased by 3, so net effect is increment

и, следовательно, код работает и продолжается. Однако наивная проверка числа + и - сделанных на ячейке 1, будет сказать, что число - больше, поэтому не будет обнаруживать бесконечный цикл.
Может ли кто-нибудь подумать о хорошем алгоритме для обнаружения бесконечных циклов, учитывая произвольное вложение произвольного числа циклов в bf?

EDIT: Я знаю, что проблема с остановкой в ​​общем случае неразрешима, но я не был уверен, не было ли особых случаев исключения. Как, может быть, Matlab может функционировать как машина Super Turing, способная определить остановку программы bf. Я мог бы быть ужасно ошибаюсь, но если так, я хотел бы точно знать, как и почему.

ВТОРАЯ РЕДАКТИРОВКА: Я написал то, что я называю бесконечным детектором цикла. Вероятно, он пропускает некоторые крайние случаи (или, что менее вероятно, каким-то образом избегает мимины мистера Тьюринга), но, похоже, работает для меня на данный момент. В псевдокодном виде здесь говорится:

subroutine bfexec(bfprogram)
begin
    Looping through the bfprogram,
        If(current character is '[')
            Find the corresponding ']'
            Store the code between the two brackets in, say, 'subprog'
            Save the value of the current cell in oldval
            Call bfexec recursively with subprog
            Save the value of the current cell in newval
            If(newval >= oldval)
                Raise an 'infinite loop' error and exit
            EndIf
        /* Do other character processings */
        EndIf
    EndLoop
end
4b9b3361

Ответ 1

Когда я использовал линейное генетическое программирование, я просто использовал верхнюю границу для количества инструкций, которые одна программа могла выполнять за всю свою жизнь. Я думаю, что это разумно двумя способами: я все равно не могу решить проблему остановки, и программы, которые занимают слишком много времени для вычисления, не заслуживают большего времени.

Ответ 3

Скажем, вы писали программу, которая могла бы определить, будет ли эта программа работать в бесконечном цикле. Скажем, для простоты, что эта программа была написана в мозгу, чтобы анализировать программы мозгового искусства (хотя это не является предварительным условием следующего доказательства, потому что любой язык может эмулировать мозговое увлечение и мозговой укол, может подражать любому языку).

Теперь скажем, что вы расширяете программу проверки, чтобы создать новую программу. Эта новая программа немедленно выходит из строя, когда ее входные петли бесконечно и циклически завершаются, когда его вход выходит в какой-то момент.

Если вы введете эту новую программу в себя, какими будут результаты?

Если эта программа выполняется навсегда при запуске, то по ее собственному определению она должна немедленно выйти при запуске с самим собой в качестве ввода. И наоборот. Программа проверки не может существовать, потому что ее само существование подразумевает противоречие.

Как уже упоминалось ранее, вы, по сути, пересказываете знаменитую проблему с остановкой: http://en.wikipedia.org/wiki/Halting_problem

Под ред. Я хочу пояснить, что вышеупомянутая защита не является моей собственной, но по существу является знаменитым доказательством, которое Алан Тьюринг дал еще в 1936 году.

Ответ 4

Состояние в bf - это один массив символов.

Если бы я был вами, я бы взял хэш состояния интерпретатора bf на каждом "]" (или один раз в rand (1, 100) "]" s *) и утвердил, что набор хэшей уникален.

Во втором (или более) времени я вижу определенный хеш, я сохраняю все состояние в стороне.

В третьем (или более) времени я вижу определенный хеш, я сравниваю все состояние с сохраненным (ыми) и если есть совпадение, я ухожу.

В каждой команде ввода ('.', IIRC) я reset сохраненные состояния и список хэшей.

Оптимизация - это только хэш-часть затронутого состояния.

Я не решил проблему с остановкой - я обнаруживаю бесконечные циклы во время запуска программы.

* rand должен сделать проверку независимо от периода цикла

Ответ 5

Бесконечный цикл не может быть обнаружен, но вы можете определить, занимает ли программа слишком много времени.

Внедрить тайм-аут, увеличивая счетчик каждый раз, когда вы запускаете команду (например, <, >, +, -). Когда счетчик достигает некоторого большого количества, которое вы установили по наблюдению, вы можете сказать, что для выполнения вашей программы требуется очень много времени. Для вашей цели "очень длинный" и бесконечный - достаточно хорошее приближение.

Ответ 6

Как уже упоминалось, это проблема остановки. Но в вашем случае может быть решение: проблема с остановкой рассматривается в отношении машины Тьюринга, которая имеет неограниченную память.

Если вы знаете, что у вас есть верхний предел памяти (например, вы знаете, что не используете более 10 ячеек памяти), вы можете выполнить свою программу и остановить ее. Идея состоит в том, что вычислительное пространство ограничивает время вычисления (поскольку вы не можете писать более одной ячейки за один шаг). После того, как вы выполнили столько шагов, сколько сможете иметь разные конфигурации памяти, вы можете сломаться. Например. если у вас есть 3 ячейки, с 256 условиями, вы можете иметь не более 3 ^ 256 разных состояний, и поэтому вы можете остановиться после выполнения этого множества шагов. Но будьте осторожны, есть неявные ячейки, такие как указатель инструкции и регистры. Вы делаете это еще короче, если вы сохраняете каждую конфигурацию состояния, и как только вы обнаружите тот, который у вас уже есть, у вас есть бесконечный цикл. Этот подход определенно намного лучше во время выполнения, но для этого требуется гораздо больше места (здесь он может быть подходящим для хэш-конфигураций).

Ответ 7

Это не проблема с остановкой, однако все же нецелесообразно пытаться обнаружить остановку даже в такой ограниченной машине, как 1000-битная машина BF.

Рассмотрим эту программу:

+[->[>]+<[-<]+]

Эта программа не будет повторяться до тех пор, пока она не заполнит всю память, которая за 1000 ячеек займет около 10-300 лет.

Ответ 8

Сверху моей головы (и я могу ошибаться), я бы подумал, что было бы немного сложно определить, имеет ли программа бесконечный цикл без фактического выполнения самой программы.

Поскольку условное выполнение частей программы зависит от состояния выполнения программы, будет сложно узнать конкретное состояние программы без фактического выполнения программы.

Если вы не требуете выполнения программы с бесконечным циклом, вы можете попробовать выполнить счетчик "инструкции" и выполнить только конечное количество инструкций. Таким образом, если программа имеет бесконечный цикл, интерпретатор может завершить программу, которая застревает в бесконечном цикле.

Ответ 9

Если я правильно помню, доказательство проблемы остановки было справедливо только для некоторых крайних случаев, которые включали самосознание. Однако все же тривиально показать практический пример того, почему вы не можете создать бесконечный детектор цикла.

Рассмотрим Последняя теорема Ферма. Легко создать программу, которая выполняет итерацию через каждое число (или в этом случае 3 числа) и определяет, является ли это контрпримером к теореме. Если это так, оно останавливается, в противном случае оно продолжается.

Итак, если у вас есть бесконечный детектор цикла, он должен быть в состоянии доказать эту теорему и многие другие (возможно, все остальные, если их можно свести к поиску контрпримеров).

В общем, любая программа, которая включает итерацию через числа и только остановку при некотором условии, потребует общего доказательства теоремы, чтобы доказать, что это условие может быть выполнено. И это самый простой случай петли.