我们对可证明正确的程序了解什么?


37

计算机程序的复杂性不断提高,计算机在社会中的地位日益重要,这使我想知道为什么我们仍然不集体使用编程语言,而您必须使用编程语言来正式证明代码可以正常工作。

我相信该术语是“认证编译器”(我在这里找到了它):一种编译一种编程语言的编译器,在该语言中,不仅必须编写代码,而且还必须声明代码规范并证明代码符合该规范。规范(或使用自动证明者这样做)。

在互联网上搜索时,我仅发现使用非常简单的编程语言的项目或尝试适应现代编程语言的失败项目。这引出我的问题:

是否有任何认证的编译器实现了成熟的编程语言,还是这很难/从理论上讲是不可能的?

此外,我还没有看到任何涉及可证明程序的复杂性类,例如“由图灵机确定的所有语言的类(存在证明该图灵机停止的证据)”,我将其称为ProvableR作为模拟到R,该组递归语言。

我可以看到学习这样的复杂类的优点:例如,对于ProvableR停机问题是可判定的(I甚至猜想ProvableRE在明显的方式定义的。将可以决定的最大语言类别)。另外,我怀疑我们是否会排除任何实用的程序:当您无法证明程序终止时,谁会使用该程序?

所以我的第二个问题是:

我们对复杂性类了解多少,这些复杂性类要求其包含的语言具有可证明的某些属性?


1
编译器可以枚举长度i的所有可能证明,让i从1到无穷大,直到找到证明程序停止的证明。如果我们要求可证明的编译器输入停止,那么编译器将始终找到该证明。由于无法确定停止问题,所以我们必须得出结论,有一些程序停止了,但是没有证据表明存在该问题。关键点在于,程序无法找到证据是否存在,不是程序无法找到证据是否存在。
Alex 10 Brink

3
我认为您应该将它们分开。它们是具有不同答案的不同问题。
Mark Reitblatt 2011年

4
关于第一个问题,有影响力的论文是“社会过程以及定理和程序的证明”,portal.acm.org/citation.cfm?id=359106
Colin

1
程序验证无法确定。因此,一个问题是说什么构成一个好的解决方案。见cstheory.stackexchange.com/questions/4016/...
拉杜·格里戈里

2
@科林:该论文因其对证明的分析而值得一读,但其预测却被伪造了。如今,我们已经证明了正确的编译器,操作系统内核,垃圾收集器和数据库,而它们都是不可能的。逃避批评的诀窍是避免对形式化证明的低级细节进行人工验证,而是使用机器对证明进行验证,然后使用人工来验证证明检查器。Noam对类型理论的引用是最先进的,因为类型理论是功能性的,这使命令式程序陷入了困境。
Neel Krishnaswami

Answers:


28

“验证编译器”通常意味着略有不同:它意味着您有一个编译器,可以证明它发出的机器代码正确地实现了高级语义。也就是说,这证明没有编译器错误。人们提供给编译器的程序仍然可能是错误的,但是编译器将生成错误程序的正确机器代码版本。这些方面最大的成功案例是经过CompCert验证的编译器,它是适用于大部分C语言的编译器。

Compcert编译器本身是具有正确性证明的程序(在Coq中完成),该程序保证如果它为程序生成代码,则将是正确的(关于CompCert设计人员使用的Assembly&C的操作语义)。用机器检查这些东西的工作量很大。通常,正确性证明的大小是您要验证的程序大小的1倍至100倍。编写经过机器检查的程序和证明是您必须学习的一项新技能,尽管这取决于能否同时做到这点,但这不是像平常一样的数学或编程。感觉就像是您从头开始,就像再次成为新手程序员一样。

但是,对此没有特殊的理论障碍。遵循这些原则的唯一事情是Blum Size定理,对于所有程序全部使用的语言,您都可以找到一种通用递归语言的程序,当使用全部语言进行编程时,该递归语言至少会成倍增大。理解这种结果的方式是,总语言不仅编码程序,而且编码终止证明。因此,您可以拥有带有长期终止证明的简短程序。但是,实际上这并不重要,因为我们只会编写带有可管理终止证明的程序。

编辑:戴乐要求对最后一点做一些阐述。

这主要是一个务实的主张,基于这样一个事实,即如果您可以理解某个程序为什么运行,那么该原因不太可能是数百万个页面的巨大不变性。(我使用的最长不变式只有几页,而且男孩确实会使审阅者发牢骚!这也是可以理解的,因为不变式是程序除去所有有助于人们理解的叙述的原因。)

但是也有一些理论上的原因。基本上,我们不知道有多少方法可以系统地发明其正确性证明很长的程序。主要方法是(1)采取证明正确性的逻辑;(2)找到无法在该逻辑中直接表示的属性(一致性证明是典型的来源);以及(3)找到一个程序,该程序的正确性正确性证明依赖于不可表达财产的一系列可表达后果。因为(2)是不可表达的,所以这意味着每个可表示结果的证明都必须独立完成,这使您无法确定正确性证明的大小。作为一个简单的示例,请注意,在具有父关系的一阶逻辑中,您不能表达祖先关系。kk)是可表示的,对于每个固定。因此,通过提供一个程序来使用某个祖先的属性达到某个深度(例如100),可以在FOL中强制正确性证明将这些属性的证明包含一百倍。k

关于这一主题的复杂论述被称为“逆数学”,是需要证明一定定理的公理的研究。我对此了解不多,但是如果您向CS提出有关其应用的问题,我敢肯定,至少Timothy Chow,也许还有其他几个人,将能够告诉您一些有趣的事情。


1
您能否再详细说明一下“我们只会编写带有可管理的终止证明的程序”?
戴乐

感谢您的更新答案!您的回答确实打开了我的视野。实际上,我本人也从事“反数学”方面的工作,但我没有意识到您提到的联系。再次感谢!
戴乐

1
您所做编辑的重点在于以下事实,即我们几乎没有任何需要使用自然证明系统(例如Frege)中的长期证明的重言式候选人。造成这种情况的部分原因是,我们认识重言式的唯一方法是首先是重言式的,是因为我们心中有一个证明,而证明并没有那么长!
约书亚·格罗夫

22

我认为第一个问题的答案是,使用当前工具通常工作量过多。为了获得这种感觉,我建议尝试证明Coq中冒泡排序的正确性(或者,如果您希望挑战更多,请使用快速排序)。我认为期望程序员编写经过验证的程序是不合理的,只要证明这种基本算法的正确性既困难又费时。

这个问题类似于询问数学家为什么不编写可被证明检查者验证的形式证明吗?用正式的正确性证明编写程序意味着证明有关所编写代码的数学定理,并且对该问题的答案也适用于您的问题。

这并不意味着没有成功的经过验证的程序案例。我知道,有团体谁被证明的类似系统的正确性微软的虚拟机管理程序。一个相关的案例是Microsoft的经过验证的C编译器。但总的来说,当前的工具需要大量的开发工作(包括SE和HCI方面),才能对通用程序员(和数学家)有用。

关于Neel关于仅具有全部功能的语言的程序大小增长的答案的最后一段,实际上很容易证明更多(如果我理解正确的话)。可以合理地预期,任何编程语言的语法都将是ce,而不是全部可计算函数的集合,因此对于所有程序全部为总的任何编程语言来说,总共有可计算函数,任何程序都无法计算(任何大小的语言)。


AC0AC0-复杂度类完整,因此它包含了复杂度类中的所有问题并可以证明这些程序的整体性。在证明复杂性方面研究了证明与复杂性理论之间的关系,如果您有兴趣,请参阅SA Cook和P. Nguyen的最新著作“ 证明复杂性的逻辑基础 ”。(提供 2008年的草案。)因此,基本答案是对于许多类“ Provably C = C”。

PAϵ0TPA2FIΣ1

但是在我看来,这在程序验证上下文中没有多大意义,因为还有一些程序在扩展上计算相同的功能,但是我们无法证明这两个程序在计算相同的功能,即,这些程序在扩展上是相等的,但不相同故意地。(这类似于晨星和晚星。)此外,很容易修改给定的可证明的总体程序以得到理论上无法证明其总体的程序。


PnnP证明中的因式分解算法。(也有研究人员尝试使第一种方法尽可能自动化,但是检查程序有趣的非平凡属性在计算上是困难的,并且如果没有错误的肯定和否定,就无法完全验证。)


3
好答案!您提到一种方法是从证明中提取程序,例如,这可以在Coq中自动完成。一个相关的领域是证明挖掘,人们(通常在数学逻辑中工作)试图从给定的证明中提取信息。例如,在某些情况下,有可能自动找到经典给出的直觉证明。
Radu GRIGore 2011年

1
Π20PAHA

1
安德烈·鲍尔(Andrej Bauer)在他的博客上发表了一篇有趣的新文章,他在文章中证明了哥德尔(Codel)的《哥德尔的方言解释》
卡韦

18

您在第一个问题中提出的问题有时被称为“验证编译器”,几年前,Tony Hoare将其提供为计算研究的巨大挑战。在某种程度上,这已经存在并且在诸如Coq定理证明器之类的工具中得到了积极使用,这些工​​具通过类型理论和按类型命题原理(“ Curry-Howard ”)来组织问题。

编辑:只是想在“一定程度上”增加重点。这远未解决问题,但Coq的成功使人们希望这不是一个空想。


8
我要说的是,构建经过验证的软件就是1956年构建普通的旧软件的地方。很明显,软件将变得异常重要,并且已经有了重大的成功案例。但是,人们仍然缺少许多基本概念(例如,清楚地了解什么是过程和变量),并且从理论到实践的距离可能与通过在定理中编写代码来实现Lisp一样短。这是从事语言和验证工作的令人兴奋的时刻。
Neel Krishnaswami

12

检查程序是否正确的工具有时称为程序验证器。在这种情况下,“正确”通常意味着两件事:该程序从不产生某些输出(认为分段错误,NullPointerException等),并且该程序符合规范。

该代码和规范可能会达成共识,但仍然被认为是错误的。从某种意义上说,要求开发人员编写规格就像要求两个开发人员解决问题一样。如果两个实现都同意,那么您将更有把握地确定它们是可以的。但是,从另一个意义上讲,规范比第二种实现要好。由于该规范不需要高效甚至可执行,因此它可能更加简洁,因此更容易出错。

考虑到这些警告,建议您查看Spec#程序验证程序


据我了解Spec#(及其扩展名Sing#),它使程序员能够静态地验证断言,但是它不需要程序员这样做,也不提供证明代码任意属性的能力。
Alex 10 Brink

原则上,可以将任意属性编码为fol断言。我不确定您希望该工具需要什么。您是否希望规格说明所有可能的输入的输出是什么?
Radu GRIGore 2011年

4

在一般情况下,不可能创建一种算法来确认算法是否等同于规范。这是一个非正式的证明:

几乎所有的编程语言都是图灵完备的。因此,由TM决定的任何语言也可以由以此语言编写的程序来决定。

Equivalence/TM

Equivalence/TMNonemptiness/TMEmptiness/TMEmptiness/TMEquivalence/TMEquivalence/TM也不能接受。因此,无论两台计算机是否等效,您都可以使用一种算法,但是不能确定它们是否等效,或者您没有给算法足够的时间。

但是,这仅适用于一般情况。您可以通过解决更为宽松的问题来决定规格是否等于程序。例如,您可能只检查了许多输入,或者说这两个程序是等效的,但存在一些不确定性。这就是软件测试的全部内容。

至于其余的问题:

注意:此部分已经过编辑以澄清。事实证明,我犯了我想避免的错误,对不起。

TrueRTrueRR

ProvableR=TrueRProvableRTrueRTrueRProvableRAϵTrueRAAAϵProvableR

非正式地,可以将其概括为:在证明一种语言之前,您不知道该语言是可以决定的。因此,如果在正式系统中您知道一种语言是可决定的,则该知识也可以用作证明。因此,您不能同时拥有一种语言既可确定又无法被证明的知识,因此这两个语句是互斥的。

RProvableRProvableRRR

@Kaveh最好地总结了这一点:可证明的总是在某些系统/理论中可证明的,并且通常与真理不符。

其他复杂性类别也是如此:要确定成员资格,您首先需要证明。这就是为什么我认为您的第二个问题过于笼统,因为它不仅包含复杂性理论,而且还包含计算理论,具体取决于您希望语言所具有的属性。


1
RProvableRΣ30Σ10

1
可证明的总是在某些系统/理论中可证明的,并且通常与真理不符。
卡韦

1
现在我看到,对于我的问题而言,有趣的是,应该谈论停止图灵机的集合,而不是确定语言的集合。
Alex 10 Brink

1
@Alex好吧,您需要某种谈论语言的方法,但是有很多方法。因此,如果您要谈论与某个有限对象(例如证明)相关的语言,则需要将自己限制为有限对象(如TM)可识别的语言。
Mark Reitblatt 2011年

2
R

3

以下经典专着几乎完全是您的第二个问题:

Hartmanis,J. 可行的计算和可证明的复杂性,CBMS-NSF应用数学区域会议系列,30.工业和应用数学协会(SIAM),宾夕法尼亚州费城,1978年。

{L(Mi)|Ti(n)T(n) is provable in F}MiTi(n)Min

T(n)nlog(n)g(n)1FTIME[T(n)]TIME[T(n)g(n)]

定理6.5:存在可计算的单调递增的时界,其中 -。F T I M E [ T n ] T I M E [ T n ]T(n)FTIME[T(n)]TIME[T(n)]

T(n)nlog(n)TIME[T(n)]={L(Mi)|F proves(j)[L(Mj)=L(Mi)Tj(n)T(n)]}

但是,对于太空,情况可以得到更好的控制:

s(n)nSPACE[s(n)]=FSPACE[s(n)]

SPACE[S(n)]=FSPACE[S(n)]S(n)ns(n)SPACE[S(n)]=SPACE[s(n)]


1

这个问题必须正确提出。例如,没有人想知道给定无限内存以及访问它的某种方式(可能是将基地址移动一定数量的操作)后,实际程序是否会完成。图灵定理在任何具体意义上都与程序正确性无关,并且将其视为程序验证障碍的人们正在混淆两个截然不同的事物。当工程师/程序员谈论程序的正确性时,他们想知道有限的属性。对于对某些事物是否可证明感兴趣的数学家来说,这也是正确的。戈德尔的来信http://vyodaiken.com/2009/08/28/godels-lost-letter/对此进行了详细解释。

即,这显然意味着,尽管Entscheidungsproblem问题的不确定性,数学家有关是或否问题的脑力劳动仍可以完全由机器代替。毕竟,仅需选择如此大的自然数,以至于当机器无法提供结果时,多考虑问题就没有意义了。

检查在实际计算机上执行的程序的巨大状态集并检测不良状态可能是不可行的,没有理论上的理由无法做到这一点。实际上,该领域已经取得了很大进展-例如,请参见http://www.cs.cornell.edu/gomes/papers/SATSolvers-KR-book-draft-07.pdf(感谢Neil Immerman的贡献)告诉我这件事

一个不同且更困难的问题是确切指定一个人想要一个程序具有正确的属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.