( UPDATE : лучше формируются вопрос ставятся здесь в качестве комментариев к общепринятом ответу ниже , показывает , что этот вопрос не является четко определенным)
Классическое доказательство невозможности проблемы остановки зависит от демонстрации противоречия при попытке применить алгоритм обнаружения остановки к себе в качестве входных данных. Смотрите фон ниже для получения дополнительной информации.
Продемонстрированное противоречие применимо из-за парадокса самоссылки (например, предложение «Это предложение не соответствует действительности»). Но если мы строго запрещаем такие ссылки на себя (т.е. принимаем тот факт, что такие ссылки не могут быть остановлены), с каким результатом мы останемся? Решается ли проблема остановки для оставшегося набора машин, которые не ссылаются на саму себя, или нет?
Вопросы это:
Если мы рассмотрим подмножество всех возможных машин Тьюринга, которые не имеют самоссылки (то есть не принимают их в качестве входных данных), что мы знаем о проблеме остановки для этого подмножества?
ОБНОВИТЬ
Возможно, лучшая формулировка того, что мне нужно, это лучшее понимание того, что определяет разрешимый набор. Я пытался выделить классическое доказательство неразрешимости, потому что оно не добавляет никакой информации о неразрешимости, за исключением случаев, когда вы запускаете HALT для себя.
Предпосылки: Предполагая, что существует противоречие, что существует машина Тьюринга которая может определить вход M, который является кодированием для машины Тьюринга и X , независимо от того, останавливается ли M ( X ) . Затем рассмотрим машину Тьюринга K, которая принимает M и X и использует Q, чтобы решить, останавливается ли M ( X ) или нет, а затем делает обратное, то есть K останавливается, если M ( X ) не останавливается, и не останавливается, если М ( Х )привалы. Тогда демонстрирует противоречие, так как K должен остановиться, если он не останавливается, и не останавливается, когда он останавливается.
Мотивация: коллега работает над формальной проверкой программных систем (особенно, когда система уже проверена на уровне исходного кода, и мы хотим подтвердить ее для ее скомпилированной версии, чтобы нейтрализовать проблемы компилятора), и в его случае он заботится о специальный набор встроенных управляющих программ, для которых мы точно знаем, что они не будут ссылаться на себя. Один из аспектов проверки, которую он хочет выполнить, заключается в том, будет ли гарантировано, что скомпилированная программа остановится, если будет доказано, что входной исходный код завершается.
ОБНОВИТЬ
Основываясь на комментариях, приведенных ниже, я проясняю значение несамостоятельных машин Тьюринга.
Цель состоит в том, чтобы определить его как множество, которое не приводит к противоречию, поставленному в доказательстве (см. «Предпосылки» выше). Это может быть определено следующим образом:
Предполагая, что существует машина Тьюринга которая решает проблему остановки для набора машины Тьюринга S , тогда S не является самоссылкой относительно Q, если она исключает все машины, которые вызывают Q на S (прямо или косвенно). (Понятно, что это означает, что Q не может быть членом S. )
Чтобы уточнить, что имеется в виду, косвенно вызывая на S :
Вызов на S обозначается машиной Тьюринга Q с набором состояний и определенными возможными начальными входами на ленте (соответствующими любому члену S ), причем голова изначально находится в начале этого входа. Машина W вызывает Q на S «косвенно», если существует (конечная) последовательность шагов, которые W предпримет, чтобы сделать свою конфигурацию «гомоморфной» начальной конфигурации Q ( S ) .
ОБНОВЛЕНИЕ 2
Из ответа ниже, утверждающего, что бесконечно много машин Тьюринга выполняют одну и ту же задачу, и поэтому не является уникальным, мы изменим приведенное выше определение, сказав, что Q - это не одна машина Тьюринга, а (бесконечный) набор вычислений всех машин та же функция (HALT), где HALT - это функция, которая определяет, останавливается ли машина Тьюринга на конкретном входе.
ОБНОВЛЕНИЕ 3
Определение гомоморфизма машины Тьюринга:
TM A гомоморфен TM B, если граф переходов A гомоморфен графу переходов B, в стандартном смысле гомоморфизмов графов с помеченными узлами AND ребер. Граф переходов (V, E) ТМ таков, что V = состояния, E = дуги перехода между состояниями. Каждая дуга помечена символом (S, W, D), S = символом, считываемым с ленты, и W = символом, который должен быть записан на нее, и D = направление, в котором движется шоу головы.
источник
Ответы:
Я думаю, что потребуется немного больше работы, чтобы добраться до «четко определенного» вопроса. В частности, это проблематично:
Одна проблема состоит в том, что существует бесконечно много машин Тьюринга, которые вычисляют одну и ту же функцию. В стандартном аргументе диагонализации я могу просто заменить подпрограмму Q другим решающим фактором для HALT, поскольку их бесконечно много. Или функция, которая вычислимо эквивалентна HALT. Так что мне не совсем понятно, как определить ваше понятие «косвенный вызов».
Другой вопрос: для каких наборов машин Тьюринга разрешима проблема остановки? Здесь есть множество ответов: TM с ограниченным ресурсом (например, использовать только пространство f (n), где f - некоторая конкретная вычислимая функция), TM, которые операционно ограничены каким-то конкретным способом (например, считывающая головка перемещается только в одну сторону) и т. Д. Но другой интересный вопрос заключается в том, является ли членство в этом ограниченном наборе разрешимым, или вам нужно ограничить себя «обещанием проблем», когда вы гарантируете только правильный ответ на некотором «обещанном» подмножестве входных данных, но не проверяете членство.
источник
Если я правильно понимаю вашу мотивацию, похоже, что это проблема «правильности компиляции», а не проблема «ограниченной остановки». У вас есть свойство (завершение), которое вы доказали для некоторой программы Prog исходного уровня, которую вы хотите затем распространить на скомпилированный код, чтобы получить то же свойство скомпилированного (Prog) . Но компилятор может (в общем) делать произвольные глупые вещи, такие как реализация среды выполнения с полным лечением (скажем, JVM), компилирование вашей завершающей программы в байт-код JVM, а затем выгрузка исполняемого файла, запускающего JVM, и подача его скомпилированным байт-кодом.
На практике , возможно, вполне возможно использовать имеющиеся у вас неявные знания о том, как работает ваш компилятор, для реализации некоторой процедуры проверки, которая в значительной степени доказывает правильность скомпилированных программ при наличии правильных исходных программ (действительно, многие инструменты автоматической проверки для программ используют неявные знания алгоритма к коду "компилятор" в мозгах программистов). Однако, в общем, вы, вероятно, смотрите на проблему корректности компилятора. Насколько я понимаю, есть два классических способа сделать это.
Один вариант заключается в том, чтобы иметь компилятор, который принимает в качестве входных данных программу Prog и завершение проверки (Prog), а вывод - компилирование (Prog) и завершение (компилирование (Prog)) - последний может быть проверен дважды, независимо от компилятор. Я считаю, что классическим документом по этому вопросу является Necula and Lee's . Дизайн и реализация сертифицирующего компилятора .
В качестве альтернативы, вы можете доказать факт о функции compiles () - всякий раз, когда compiles () дает завершающий ввод, он производит завершающий вывод. Доступным введением в этот подход к правильности компиляции является статья Ксавье Лероя CACM « Формальная проверка реалистичного компилятора» .
(PS Я надеюсь, что этот ответ полезен - я признаю, что он немного отличается от вопроса, который вы задали, поэтому дайте мне знать, если я зашла в тупик и / или повторяю что-то, что вы уже знаете.)
источник