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

Я написал простой интерпретатор brainfuck на языке сценариев MATLAB. В него загружаются случайные программы bf для выполнения (как часть проекта генетического алгоритма). Проблема, с которой я сталкиваюсь, заключается в том, что в программе оказывается бесконечный цикл в значительном количестве случаев, и, следовательно, GA застревает в точке.
Итак, мне нужен механизм для обнаружения бесконечных циклов и предотвращения выполнения этого кода in 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?

РЕДАКТИРОВАТЬ: Я знаю, что проблема остановки в целом неразрешима, но я не был уверен, не существует ли особых исключений. Например, возможно, 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's processings */
        EndIf
    EndLoop
end

person sundar - Remember Monica    schedule 15.12.2008    source источник
comment
Matlab не может быть супер-тьюрингом, потому что он работает на машине Тьюринга (вашем компьютере). Поскольку состояние ограничено, подход к моментальным снимкам, подробно описанный Ауром Сарафом, должен работать, и хотя наихудший случай довольно плох, многие бесконечные циклы в BF должны быть обнаружены быстро.   -  person Nick Johnson    schedule 17.12.2008
comment
[] зацикливается бесконечно, только если значение под указателем не 0. Да, это было бы бесполезно, если бы оно использовалось в точке, где значение указателя может быть только 0 (например, в начале программы), но это не обязательно ошибка.   -  person Skilldrick    schedule 17.05.2010
comment
В любом случае, что такое супер машина Тьюринга ... Может быть, вы имеете в виду Stannett, M. 1990. X-Machines and the Halting Problem: Building a Super-Turing Machine. Formal Aspects of Computing, 2, 331-341.?   -  person DrBeco    schedule 06.04.2011
comment
Я думаю, у вас проблемы с предложением: Call bfexec recursively with subprog. Он может работать вечно, если найдет бесконечный цикл. Нет известного решения для этой проблемы с остановкой.   -  person DrBeco    schedule 06.04.2011
comment
Как ваш алгоритм не может ошибочно остановиться на + ›+‹ [›] Входе в этот цикл cell [0] = cell [1] = 1 и указатель = 0; поэтому oldval = 1. В конце первой итерации указатель = 1, newvalue = cell [1] = 1 и oldval ›= newval. Однако в еще одной итерации указатель = 2 и ячейка [2] = 0 (при условии, что все ячейки инициализированы на 0), таким образом, программа завершилась бы нормально, если бы ей было разрешено работать.   -  person Griffin    schedule 14.06.2016


Ответы (9)


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

person Svante    schedule 15.12.2008
comment
Я выбрал это в качестве ответа, поскольку он больше всего относился к моей ситуации. Я думаю, что я написал детектор бесконечного цикла, но он, вероятно, пропускает некоторые случаи (или, что менее вероятно, каким-то образом ускользает из тисков Тьюринга). Я опубликую этот код в вопросе в ближайшее время. - person sundar - Remember Monica; 22.12.2008
comment
Я все равно не могу решить проблему остановки, хорошее преуменьшение :) - person ; 24.12.2008
comment
Вы Желе? Запускаем программу, если она останавливается, то не бесконечно. Проблема? - person DampeS8N; 01.12.2010
comment
DampeS8N: Если он не остановится, он никогда не даст ответа и, следовательно, никогда не решит проблему. - person Svante; 02.12.2010
comment
+1 Тайм-аут может быть установлен в зависимости от сложности, количества строк и приоритета относительно контекста приложения в реальном времени, например, есть процессы, выполняющие моделирование большого взрыва, которое планируется запустить в течение нескольких лет на суперкомпьютере. - person Khaled.K; 10.03.2015

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

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

person dancavallaro    schedule 15.12.2008
comment
@dancavallaro, смеется. Заставил меня выплюнуть свой стакан, я так сильно смеялся. - person mmcdole; 15.12.2008
comment
Я столько раз видел это заблуждение ... Спасибо за исправление @NasBanov. - person mmgp; 18.12.2012
comment
@NasBanov Память, необходимая для вычислений для остановки LBA, больше, чем объем памяти, который у него есть. Следовательно, если более крупный LBA не моделирует меньший LBA, он все еще неразрешим. Помимо всего этого, это все еще непрактично решаемо. - person Cruncher; 04.09.2013
comment
@Cruncher, я не понимаю - о чем вы спорите? BF - это детерминированная машина с ограниченной памятью. Речь идет о практической реализации BF на другом языке, это не универсальная машина и не скована ограничениями BF VM. Относительно небольшой объем дополнительной памяти (~ память виртуальной машины) необходим для обнаружения бесконечного цикла. Так что да, то, о чем спрашивает ОП, возможно, и ответ данкавалларо, отклоняющий возможность, неверен. - person Nas Banov; 05.09.2013

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

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

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

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

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

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

person shsmurfy    schedule 15.12.2008
comment
Программа для мозгового траха считается полной по Тьюрингу, если у нее бесконечная память, бесконечно большие числа могут храниться в каждой ячейке или и то, и другое. - person ; 27.10.2011

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

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

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

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

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

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

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

* Rand делает проверку независимой от периода цикла.

person Aur Saraf    schedule 15.12.2008
comment
Из-за конечного состояния BF-программы это действительно сработает (хотя я думаю, вы сделали это более сложным, чем должно быть - просто хеш-состояние на каждом) и выйдите, если вы столкнулись с хешем раньше), и он в конечном итоге обнаружит любой бесконечный цикл, пока память ограничена. - person Nick Johnson; 17.12.2008
comment
Если бы я вышел из-под хеша, с которым встречался раньше, у меня был бы шанс остановиться на конечной программе. Хотя спорно, насколько реалистичен этот шанс, я не верю, что он может быть объявлен слишком малым, чтобы заботиться о нем без большого исследования. - person Aur Saraf; 21.12.2008

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

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

person Eugene Yokota    schedule 15.12.2008

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

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

person flolo    schedule 15.12.2008
comment
да. 3 ячейки, каждая с 256 состояниями, составляют 256 * 256 * 256 = 16777216, что не так уж много (для компьютера). - person dancavallaro; 15.12.2008
comment
Однако из-за того, что brainfuck использует такие простые конструкции, даже самые маленькие программы могут занимать от десятков до сотен ячеек. Например, умножение двух чисел в "Brainfuck" занимает около 30 ячеек. Любую интересную программу для мозгов было бы непрактично анализировать таким образом. - person shsmurfy; 15.12.2008
comment
@shsmurfy - Как умножаются? Умножение двух ячеек может быть выполнено с двумя временными ячейками. - person Chris Lutz; 27.04.2009

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

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

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

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

person Robert    schedule 04.11.2013

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

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

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

person coobird    schedule 15.12.2008

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

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

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

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

person Houshalter    schedule 10.03.2015
comment
Это действительно проницательный ответ, и я не уверен, почему он получил 0 голосов. - person bitconfused; 20.01.2019
comment
Ваше рассуждение о FLT неверно. Даже если бы у нас был детектор бесконечного цикла для обычного компьютера (а не бесконечный TM!), Мы не смогли бы решить FLT, потому что контрпримеры могут быть настолько большими, что не поместятся в памяти или на диске! В общем, проблема остановки неразрешима только для бесконечных машин. Мы можем написать алгоритм для решения проблемы остановки для таких компьютеров, как наш, с конечной памятью, которая будет завершена через некоторое конечное время. - person xrisk; 19.09.2019