繁体   English   中英

解决停机问题比人们想象的要容易吗?

[英]Is solving the halting problem easier than people think?

尽管一般情况是不可判定的,但许多人仍然解决了足以满足日常使用的等价问题。

在科恩关于计算机病毒的博士论文中,他展示了病毒扫描如何等同于停机问题,但我们的整个行业都围绕着这一挑战展开。

我也看过微软的终结者项目——http://research.microsoft.com/Terminator/

这让我问 - 停止问题是否被高估了 - 我们需要担心一般情况吗?

类型会随着时间的推移变得图灵完备吗——依赖类型似乎是一个很好的发展?

或者,换个角度看,我们会开始使用非图灵完备语言来获得 static 分析的好处吗?

解决停机问题比人们想象的要容易吗?

我认为这和人们想象的一样困难。

随着时间的推移,类型会变得完整吗?

亲爱的,他们已经是了!

依赖类型似乎是一个很好的发展?

非常如此。

我认为非图灵完备但可证明的语言可能会有所增长。 很长一段时间以来,SQL 都属于这一类(现在不再是),但这并没有真正削弱它的实用性。 我认为这样的系统肯定有一席之地。

哇,这是一个令人困惑的问题。

首先:停机问题不是实际意义上的“问题”,而是“需要解决的问题”。 它更像是关于数学本质的陈述,类似于哥德尔的不完全性定理。

第二:构建一个完美的病毒扫描程序是棘手的(因为它相当于停机问题)正是“围绕这一挑战建立了整个行业”的原因。 如果能设计出完美的病毒扫描算法,那只需要有人做一次,就不需要行业了。 故事结束。

第三:使用图灵完备的语言并不能消除“静态分析的好处”——它仅仅意味着静态分析存在局限性。 没关系——无论如何,我们所做的几乎所有事情都是有限制的。

最后:如果停机问题可以以任何方式“解决”,那肯定会“比人们想象的更容易”,因为图灵证明它是无法解决的。 从数学的角度来看,一般情况是唯一相关的情况。 具体情况是工程问题。

有很多程序可以解决停机问题,其中很多程序很有用。

如果您有一个编译器会告诉您“暂停”、“不暂停”或“不知道”,那么它可以告诉您程序的哪个部分导致了“暂停”或“不知道”的情况. 如果你真的想要一个绝对停止或没有停止的程序,那么你会修复那些“不知道”的单元,就像我们摆脱编译器警告一样。 我想我们都会惊讶于尝试解决这个通常不可能的问题被证明是有用的频率。

作为一名日常程序员,我认为继续沿着解决停止式问题的道路走下去是值得的,即使你只是接近这个极限而从未达到它。 正如您所指出的,病毒扫描被证明是有价值的。 谷歌搜索并不假装是“为 Y 找到最好的 X”的绝对答案,但它也非常有用。 如果我释放了一种新型病毒(muwahaha),这是否会创建一个更大的解决方案集,或者只是针对现有的问题区域? 不考虑技术上的差异,有的会务实地开发并收取后续“检测和清除”服务的费用。

我期待为您的其他问题提供真正的科学答案...

顺便说一句,我认为模板的图灵完整性表明暂停被高估了。 大多数语言保证它们的编译器会停止; 不是那么 C++。 这会削弱 C++ 作为一门语言吗? 我不这么认为; 它有很多缺陷,但并不总是停止的编译不是其中之一。

停止问题只有在一般情况下才真正有趣,因为如果停止问题是可判定的,那么所有其他不可判定的问题也可以通过归约来判定。

所以,我对这个问题的看法是,不,在重要的情况下这并不容易。 也就是说,在现实世界中,这可能没什么大不了的。

另见: http ://en.wikipedia.org/wiki/Halting_problem#Importance_and_consequences

我不知道人们认为它有多难,所以我不能说它是否更容易。 但是,您的观察是正确的,问题的不可判定性(通常)并不意味着该问题的所有实例都是不可判定的。 例如,我可以很容易地告诉你,像while false do something这样的程序会终止(假设 while 和 false 的语义很明显)。

您提到的终结者项目之类的项目显然存在(在某些情况下甚至可能有效),因此很明显并非所有项目都是无望的。 还有一个竞赛(我相信每年),用于证明重写系统终止的工具,这基本上是一种计算模型。 但在很多情况下,终止是很难证明的。

看待它的最简单方法可能是将不可判定性视为问题实例化复杂性的最大值。 每个实例化都在这个最大值的微不足道的范围内,并且随着最大值的增加,您通常会发现实例化平均起来也更难。

一个问题不可判定的事实并不意味着它不有趣:相反! 所以是的,我们没有一个有效和统一的程序来解决所有程序的终止(以及许多其他关于软件的问题)这一事实并不意味着不值得寻找部分解决方案。 从某种意义上说,这就是我们需要软件工程的原因:因为我们不能仅仅将任务委托给计算机。

但是,您的问题的标题有点误导。 我同意 DrPizza 的观点:终止问题与人们想象的一样困难。 此外,我们不必担心一般情况这一事实并不意味着终止问题被高估了:值得寻找部分解决方案,因为我们知道一般解决方案很难。

最后,关于依赖类型和子递归语言的问题,虽然部分相关,但确实是不同的问题,我不确定将它们混合在一起有什么意义。

基于 x86 仿真器的模拟停止判定器显示 Strachey(1965) P 是非停止的

一个不可能的计划:Strachey(1965)
计算机杂志,第 7 卷,第 4 期,1965 年 1 月,第 313 页,

这是对软件工程语言中提供的停止问题的关键新见解的解释。 使用软件工程术语解释技术计算机科学术语。 不需要了解停机问题。

它基于在 x86utm 操作系统中执行的完全可操作的软件。 创建 x86utm 操作系统(基于优秀的开源 x86 仿真器)是为了在 C/x86 的更高抽象级别上研究停止问题证明反例的细节。

这个一般原则驳斥了传统的停止问题证明
每个正确模拟其输入直到它正确预测该模拟输入永远不会达到其最终状态的模拟暂停决策器,正确地拒绝该输入为非暂停。

从纯软件工程的角度来看,需要 T(Strachey_P) 才能正确预测其输入的正确且完整的 x86 仿真永远不会到达该输入的“ret”指令。

当我说模拟停止决策器 T 正确地确定其输入永远不会到达其“返回”语句时,基于 T 可以看到 Strachey_P 使用相同的参数调用自身,没有提供足够的详细信息来正确理解我一定是正确的。 这些详细信息在 x86 级别提供。

typedef void (*ptr)();
// rec routine P
//   §L :if T[P] go to L
//     Return §
void Strachey_P()
{
  L: if (T(Strachey_P)) goto L;
  return;
}
 
int main()
{
  Output("Input_Halts = ", T(Strachey_P));
}

_Strachey_P()
[000012a6](01)  55         push ebp
[000012a7](02)  8bec       mov ebp,esp
[000012a9](05)  68a6120000 push 000012a6
[000012ae](05)  e833fcffff call 00000ee6
[000012b3](03)  83c404     add esp,+04
[000012b6](02)  85c0       test eax,eax
[000012b8](02)  7402       jz 000012bc
[000012ba](02)  ebed       jmp 000012a9
[000012bc](01)  5d         pop ebp
[000012bd](01)  c3         ret
Size in bytes:(0024) [000012bd]

_main()
[00001346](01)  55         push ebp
[00001347](02)  8bec       mov ebp,esp
[00001349](05)  68a6120000 push 000012a6
[0000134e](05)  e893fbffff call 00000ee6
[00001353](03)  83c404     add esp,+04
[00001356](01)  50         push eax
[00001357](05)  6817050000 push 00000517
[0000135c](05)  e805f2ffff call 00000566
[00001361](03)  83c408     add esp,+08
[00001364](02)  33c0       xor eax,eax
[00001366](01)  5d         pop ebp
[00001367](01)  c3         ret
Size in bytes:(0034) [00001367]

 machine   stack     stack     machine    assembly
 address   address   data      code       language
 ========  ========  ========  =========  =============
[00001346][0010221b][00000000] 55         push ebp
[00001347][0010221b][00000000] 8bec       mov ebp,esp
[00001349][00102217][000012a6] 68a6120000 push 000012a6
[0000134e][00102213][00001353] e893fbffff call 00000ee6

T: Begin Simulation   Execution Trace Stored at:1122c7
Address_of_T:ee6
[000012a6][001122b7][001122bb] 55         push ebp
[000012a7][001122b7][001122bb] 8bec       mov ebp,esp
[000012a9][001122b3][000012a6] 68a6120000 push 000012a6
[000012ae][001122af][000012b3] e833fcffff call 00000ee6
T: Infinitely Recursive Simulation Detected Simulation Stopped

T 知道它自己的机器地址,在此基础上它可以很容易地检查它存储的 Strachey_P 的 execution_trace(见上文)以确定:
(a) Strachey_P 使用与调用 T 相同的参数调用 T。
(b) Strachey_P 中的任何指令都无法逃脱这种无限递归的仿真。
(c) T 在其对 T 的调用被仿真并报告非停止之前中止其对 Strachey_P 的仿真。

[00001353][0010221b][00000000] 83c404     add esp,+04
[00001356][00102217][00000000] 50         push eax
[00001357][00102213][00000517] 6817050000 push 00000517
[0000135c][00102213][00000517] e805f2ffff call 00000566
Input_Halts = 0
[00001361][0010221b][00000000] 83c408     add esp,+08
[00001364][0010221b][00000000] 33c0       xor eax,eax
[00001366][0010221f][00000018] 5d         pop ebp
[00001367][00102223][00000000] c3         ret
Number of Instructions Executed(538) == 8 Pages ...

停止基于软件工程被驳斥的问题证明

这是对软件工程语言中提供的停止问题的可能新见解的解释。 使用软件工程术语解释技术计算机科学术语。 不需要了解停机问题。

它基于在 x86utm 操作系统中执行的完全可操作的软件。 创建 x86utm 操作系统(使用优秀的开源 x86 仿真器)是为了在 C/x86 的更高抽象级别上研究停止问题证明反例的细节。

当计算通过到达其最后一条指令完成所有步骤时,它被称为正常终止。 如下所示,P 本质上是在无限递归中调用 H,并在此基础上被 H 拒绝为非停止。

typedef void (*ptr)();
int H(ptr p, ptr i); // simulating halt decider

void P(ptr x) 
{
  int Halt_Status = H(x, x); 
  if (Halt_Status) 
    HERE: goto HERE; 
  return; 
} 

int main() 
{ 
  Output("Input_Halts = ", H(P, P)); 
}

当模拟暂停判定器 H(P,P) 模拟其输入时,我们可以看到:
(1) 从 P() 调用函数 H()。
(2) 对 H() 使用相同的参数。
(3) 在调用 H(P,P) 之前 P 中没有任何指令。

当 H(P,P) 模拟其输入时,模拟的 P 调用 H(P,P) 再次模拟自己。 H 认识到 P 指定了永远不会结束的无限嵌套模拟,中止了对 P 的模拟并拒绝 P 为非停止。

在可计算性理论中,停机问题是根据对任意计算机程序的描述和输入来确定程序是完成运行还是永远继续运行的问题。 Alan Turing 在 1936 年证明,不可能存在解决所有可能的程序输入对的停止问题的通用算法。

对于任何可能确定程序是否停止的程序 H,一个“病态”程序 P,用一些输入调用,可以将它自己的源和它的输入传递给 H,然后专门做与 H 预测 P 将做的相反的事情。 不存在处理这种情况的 H。 https://en.wikipedia.org/wiki/Halting_problem

如上所述,H 和 P 实现了彼此之间的确切病理关系。 因为 H(P,P) 确实处理了这种情况,所以上述停止问题不可判定输入模板已被驳斥。

当这个停止决定原则被理解为正确时:停止决定者必须根据这些输入实际指定的实际行为计算从其输入到接受或拒绝状态的映射。

众所周知,程序的正确模拟(或 TM 描述)准确地测量了该程序的实际行为:

然后(根据逻辑必要性)这正确地实现了停止判定原则:正确模拟其输入直到它正确预测该模拟输入永远不会正常终止的每个模拟停止判定器,正确地拒绝该输入作为非停止。

因为 H 是一个 Pure Pure Pure 函数,所以它似乎实现了一个可计算函数,因此是图灵可计算的。

停止的问题证明包含一个致命的缺陷

这是对软件工程语言中提供的停止问题的可能新见解的解释。 使用软件工程术语解释技术计算机科学术语。 不需要了解停机问题。

当传统的“病态”输入(与停止决策器决定的任何事情相反)是模拟停止决策器的第一个参数时,则该输入变为可确定为指定无限递归模拟。

本文基于在 x86utm 操作系统中执行的完全可操作的软件。 创建 x86utm 操作系统(基于优秀的开源 x86 仿真器)是为了在 C/x86 的更高抽象级别上研究停止问题证明反例的细节。

typedef void (*ptr)();
int H(ptr p, ptr i); // simulating halt decider

// P does the opposite of whatever H decides 
void P(ptr x) 
{
  int Halt_Status = H(x, x); 
  if (Halt_Status)    // if H(P,P) reports that its input halts
    HERE: goto HERE;  // P loops and never halts
  return;             // else P halts
} 

int main() 
{ 
  Output("Input_Halts = ", H(P, P)); 
}

//
// The above code is from Halt7.c in the 
// the linked Visual Studio project 
//

// This H(P,P) specifies the direct execution of P(P) 
// which obviously never stops running
int H(ptr x, ptr y)
{
  x(y);  
}

上述 H 和 P 彼此之间存在这种停止问题的关系。

对于可能确定程序是否停止的任何程序 H,使用某些输入调用的“病态”程序 P 可以将其自己的源及其输入传递给H。https://en.wikipedia.org/wiki/Halting_problem

停止:定义为到达最后一条指令(AKA 最终状态)并停止。

当一个 H 被定义为正确地确定上述 P(P) 的直接执行永远不会到达它的“返回”指令(AKA 最终状态)时,传统的停止问题证明被驳斥了。

所有暂停决策器都旨在预测其输入的行为,而无需实际执行这些输入,因为暂停决策器本身必须始终暂停。 用于确定上述 P(P) 永不停止的方法是对正确检测无限递归的类似方法的轻微改编。

当匹配正确的非暂停行为模式时,模拟暂停决定器 (SHD) 中止其模拟并返回 0。暂停并不意味着停止运行,暂停仅意味着到达最后一条指令并停止运行。

因为我们可以看到从 H 直接执行 P(P) 永远不会到达 P 的最后一条“返回”指令,我们知道 H 对 P 的完全或部分模拟永远不会到达 P 的最后一条指令。知道 P 是非停止的。

完整的停机决定系统(Visual Studio Project)

在 Microsoft Visual Studio Community 2017 下编译

这是直接从链接项目的 Halt7.c 剪切和粘贴的。 我刚刚从 SE 下载了这个项目。 它是完全可操作的代码,可识别无限递归行为模式的改编版本。

void P(ptr x) 
{
  int Halt_Status = H(x, x); 
  if (Halt_Status) 
    HERE: goto HERE; 
  return; 
} 


int main() 
{ 
//PH(PH); 
//Output("Heap_PTR:", Heap_PTR);
  Output("Input_Halts = ", H(P, P));  
//Output("Input_Halts = ", H1(P, P));  
//Output("Input_Halts = ", HH(P, P));  
//Output((char*)"Input_Halts = ", H((u32)P, (u32)P));  
//Output((char*)"Input_Halts = ", H(P, P));  
//Output((char*)"Input_Halts = ", HH(PH, PH));  
//Output((char*)"Input_Halts = ", H((ptr)Add3, (ptr)8));  
//Output((char*)"Input_Halts = ", H(Infinite_Recursion, (ptr)0x777));  
//Output((char*)"Input_Halts = ", H(PR, (ptr)0x777));  
} 
 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM