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

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

[]

I можно обнаружить это и отказаться от запуска этой программы.
Для нетривиальных случаев я понял, что основная идея: определить, как одна итерация цикла изменяет текущую ячейку. Если изменение отрицательное, мы в конечном итоге достигнем 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 может функционировать как супер машина Тьюринга, способная определить остановку программы 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's processings */
        EndIf
    EndLoop
end

9 ответов


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


Алан Тьюринг хотел бы поговорить с вами.

http://en.wikipedia.org/wiki/Halting_problem


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

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

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

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

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

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


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

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

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

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

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

оптимизация заключается только в хэше части состояния, которая была затронута.

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

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


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

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


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

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


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

считайте эту программу:

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

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


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

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

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


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

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

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

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