为什么不能证明程序?

时间:2009-01-25 00:32:14

标签: math theory proof axiom formal-verification

为什么计算机程序不能像数学陈述那样被证明?一个数学证明是建立在其他证明之上的,这些证据是从更多的证据和公理中建立起来的 - 我们认为这些真理是真实的。

计算机程序似乎没有这样的结构。如果您编写计算机程序,那么您如何能够获取以前经过验证的作品并使用它们来展示您的计划的真实性?你不能存在。此外,编程的公理是什么?该领域的原子真理?

我对上述内容没有很好的答案。但似乎软件无法被证明,因为它是艺术,而不是科学。你如何证明毕加索?

31 个答案:

答案 0 :(得分:76)

证明are计划。

Formal verification个程序是巨大的研究领域。 (例如,参见the group at Carnegie Mellon。)

许多复杂的程序已经过验证;例如,请参阅此kernel written in Haskell

答案 1 :(得分:30)

程序绝对可以被证明是正确的。糟糕的程序很难证明。为了做得更好,你必须进行程序和手头证明。

由于暂停问题,您无法自动证明。但是,您可以手动证明任意语句或语句序列的后置条件和前提条件。

您必须阅读Dijsktra的A Discipline of Programming

然后,你必须阅读Gries'The Science of Programming

然后你会知道如何证明程序是正确的。

答案 2 :(得分:15)

暂停问题仅表明存在无法验证的程序。一个更有趣,更实际的问题是什么类型的程序可以正式验证。也许任何人关心的程序都可以(在理论上)得到验证。 在实践中,到目前为止,只有非常小的程序被证明是正确的。

答案 3 :(得分:15)

对于那些提出不完整性的人来说只是一个小小的评论 - 所有公理系统并非如此,只有足够强大的系统。

换句话说,哥德尔证明了一个足以描述自身的公理系统必然是不完整的。然而,这并不意味着它无用,并且正如其他人所关联的那样,已经进行了各种程序证明尝试。

双重问题(编写检查证明的程序)也非常有趣。

答案 4 :(得分:14)

事实上,您可以编写可证明正确的程序。例如,微软已经创建了一个名为Spec#的C#语言扩展,其中包括一个自动化定理证明器。对于java,有ESC/java。我相信还有更多的例子。

编辑:显然不再开发规范#,但是the contract tools will become part of .NET 4.0

我看到一些海报在halting problemincompleteness theorems上挥手致意,这可能会妨碍程序的自动验证。这当然不是真的;这些问题只是告诉我们,编写无法证明是正确或不正确的程序是可能的。这并不妨碍我们构建 可证明正确的程序。

答案 5 :(得分:8)

如果你真的对这个话题感兴趣,那么我首先推荐David Gries的“编程科学”,这是一个关于这个主题的经典介绍性作品。

实际上可以在某种程度上证明程序是正确的。您可以编写前置条件和后置条件,然后证明给定满足前置条件的状态,执行后的结果状态将满足后置条件。

然而,它变得棘手,就是循环。对于这些,您还需要找到循环不变量并显示正确的终止,您需要在每个循环后剩余的最大迭代次数上找到上限函数。您还必须能够证明每次迭代循环后这至少减少一次。

一旦你掌握了所有这些程序,证明就是机械的。但不幸的是,没有办法自动派生循环的不变和绑定函数。人类的直觉足以应对具有小循环的琐碎案例,但实际上,复杂的程序很快变得难以处理。

答案 6 :(得分:5)

我不是来自数学背景,所以原谅我的无知,但“证明一个程序”是什么意思? 你在证明什么?正确吗?正确性是程序必须验证为“正确”的规范。但是这个规范是由人决定的,你如何验证这个规范是否正确?

在我看来,程序中存在漏洞,因为人类难以表达他们真正想要的东西。 alt text http://www.processdevelopers.com/images/PM_Build_Swing.gif

那你在证明什么?缺乏关注导致的错误?

答案 7 :(得分:5)

首先,你为什么说“程序无法证明”?

无论如何,“节目”是什么意思?

如果通过程序你意味着算法,你不知道Kruskal的吗? Dijkstra的? MST?普里姆的?二进制搜索?归并? DP?所有这些东西都有描述其行为的数学模型。

DESCRIBE。数学没有解释为什么它只是简单地描绘了如何。我无法向你证明太阳明天会在东方升起,但我可以向他们展示过去曾经做过这件事的数据。

你说: “如果你写了一个计算机程序,那你怎么能拿走以前经过验证的作品并用它们来展示你的程序的真实性?你不能不存在”

等待?你不能吗? http://en.wikipedia.org/wiki/Algorithm#Algorithmic_analysis

我无法向你展示“真相”我是一个程序,因为我无法向你展示语言的“真相”。两者都代表了我们对世界的经验性理解。不是“真相”。把所有的胡言乱语放在一边我可以在数学上向你证明,mergesort算法会对列表中的元素进行排序,其中O(nlogn)性能,Dijkstra将在加权图上找到最短路径,或者Euclid算法会找到最大的两个数字之间的公约数。在最后一个案例中,“我的计划中的真相”也许我会发现你是两个数字之间最大的常见除数,你不觉得吗?

通过递推方程,我可以描述您的Fibonacci程序是如何工作的。

现在,计算机编程是一门艺术吗?我当然认为是。和数学一样多。

答案 8 :(得分:4)

  

此外,编程的公理是什么?该领域的原子真理?

我已经开设了一门名为“基于合同的编程”课程(课程主页:http://www.daimi.au.dk/KBP2/)。这里我可以从课程(以及我采取的其他课程)中推断出

您必须正式(数学上)定义您的语言的语义。让我们想一个简单的编程语言;一个只有全局变量,int,int数组,算术,if-then-else,while,赋值和do-nothing [你可以使用任何主流语言的子集作为这个的“实现”]。

执行状态是对的列表(变量名,变量值)。读“{Q1} S1 {Q2}”为“执行语句S1将您从执行状态Q1带到状态Q2”。

一个公理将是"if both {Q1} S1 {Q2} and {Q2} S2 {Q3}, then {Q1} S1; S2 {Q3}"。也就是说,如果语句S1从状态Q1到Q2,而语句S2从Q2到Q3,则“S1; S2”(S1后跟S2)将从状态Q1带到状态Q3。

另一个公理是"if {Q1 && e != 0} S1 {Q2} and {Q1 && e == 0} S2 {Q2}, then {Q1} if e then S1 else S2 {Q2}"

现在,进行一些改进:{}中的Qn实际上是关于状态的陈述,而不是状态本身。

假设M(out,A1,A2)是一个语句,它执行两个已排序数组的合并并将结果存储到out中,并且我在下一个示例中使用的所有单词都是正式表达的(数学上)。然后"{sorted(A1) && sorted(A2)} A := M(A1, A2) {sorted(A) && permutationOf(A, A1 concatened with A2)}"是M正确实现合并算法的声明。

可以尝试通过使用上述公理来证明这一点(可能需要一些其他的。你可能需要一个循环,一个)。

我希望这能说明一些证明程序正确的样子。并相信我:即使对于看似简单的算法,也需要很多的工作才能证明它们是正确的。我知道,我读了很多次尝试; - )

[如果你读到这个:你的交接很好,所有其他导致我头疼的事情; - )]

答案 9 :(得分:3)

当然,他们可以像其他人一样发布。

证明一个非常小的子程序正确是一个很好的练习,恕我直言,编程相关学位课程的每个本科生都应该 来做。它让您深入了解如何使代码清晰,易于检查和维护。

然而,在现实世界中,它的实际应用有限。

首先,正如程序存在错误一样,数学证明也是如此。如何证明数学证明确实是正确的并且没有任何错误?你不能。而对于反例,任何数量的已发表的数学证明都会在其中发现错误,有时会在数年之后发现。

其次,如果没有“先验地”对程序应该做什么的明确定义,就无法证明程序是正确的。但任何程序应该做的明确定义都是一个程序。 (虽然它可能是某种规范语言的程序,但是你没有编译器。)因此,在你能证明程序是正确的之前,你必须首先拥有另一个程序是等效的并且事先已知是正确的。所以QED整个事情都是徒劳的。

我建议追踪布鲁克斯的经典“ No Silver Bullet ”一文。

答案 10 :(得分:2)

在这方面有很多研究......正如其他人所说的那样,程序语言中的结构很复杂,而且只有在尝试验证或证明任何给定的输入时才会变得更糟。

但是,许多语言允许规范,可接受的输入(前置条件),还允许指定最终结果(后置条件)。

此类语言包括:B,事件B,Ada,fortran。

当然,有许多工具旨在帮助我们证明程序的某些属性。例如,为了证明死锁自由,可以通过SPIN来处理他们的程序。

还有许多工具可以帮助我们检测逻辑错误。这可以通过静态分析(goanna,satabs)或实际执行代码(gnu valgrind?)来完成。

然而,从开始(规范),实现和部署开始,没有一个工具能够真正证明整个程序。 B方法很接近,但它的实现检查非常弱。 (它假定人类在将意识形态转化为实体时是​​无法实现的。)


作为旁注,当使用B方法时,您经常会发现自己从较小的公理中构建复杂的证明。 (这同样适用于其他详尽的定理证明)。

答案 11 :(得分:2)

您不仅可以证明程序,还可以让您的计算机从证明中构建程序。见Coq。因此,您甚至不必担心在实施过程中出错的可能性。

答案 12 :(得分:2)

这里没有提到的是B - Method这是一个基于正式方法的系统。它被用来开发巴黎地下的安全系统。 有一些工具可用于支持B和事件B的开发,特别是Rodin

答案 13 :(得分:2)

如果您正在寻找信心,那么证明程序的替代方法就是测试它们。这更容易理解,并且可以自动化。如上所述,它还允许在数学上不可能进行证明的程序类。

最重要的是,没有证据可以替代通过验收测试:*

  • 仅仅因为一个程序确实按照它所说的那样做,并不意味着它完成了用户想要它做的事情。

    • 除非,否则您可以证明其所说的内容就是用户所说的内容。

      • 然后你必须证明他们真正想要,因为作为一个用户,他们几乎肯定不知道他们想要什么。等.Reductio ad absurdum。

*更不用说单位,覆盖面,功能,整合和所有其他类型的测试。

希望这可以帮助你走上正轨。

答案 14 :(得分:2)

他们可以。作为一名大学新生,我花了很多很多时间做程序正确性证明。

在宏观尺度上不实用的原因是编写程序证明往往比编写程序困难得多。此外,今天的程序员倾向于构建系统,而不是编写函数或程序。

在微观范围内,我有时会针对个别功能进行心理测试,并倾向于组织我的代码以使其易于验证。

有一篇关于航天飞机软件的着名文章。他们做证明,或等同的东西。这是非常昂贵和耗时的。这种验证水平对他们来说可能是必要的,但对于任何类型的消费者或商业软件公司,使用现有技术,您将获得由竞争对手吃掉的午餐,竞争对手以1%的成本提供99.9%的解决方案。没有人会为MS Office支付5000美元,而这个MS Office稍微稳定一些。

答案 15 :(得分:1)

让我们假设一个纯函数式语言(即Haskell)。在这些语言中可以非常干净地考虑副作用。

证明程序产生正确的结果需要您指定:

  1. 数据类型和数学集之间的对应
  2. Haskell函数和数学函数之间的对应
  3. 一组公理,规定了你可以从其他人那里建立的功能,以及数学方面的相应结构。
  4. 这组规范称为指称语义。它们允许您证明使用数学的程序的原因。

    好消息是“程序结构”(上面的第3点)和“数学集的结构”非常相似(流行语是 topos ,或笛卡尔封闭类别),1 /你在数学方面做的证明很容易转移到程序化结构中2 /你编写的程序很容易在数学上正确显示。

答案 16 :(得分:1)

Godel's Theorems尽管如此......重点是什么?你想证明什么简单的“真理”?你想从这些真理中得到什么?虽然我可能会吃这些话......实用性在哪里?

答案 17 :(得分:1)

程序可以证明。如果你用新泽西州的标准ML(SML / NJ)这样的语言写它们,那就很容易了。

答案 18 :(得分:1)

你的声明很宽,所以它捕获了很多鱼。

底线是:一些程序绝对可以证明是正确的。所有程序都被证明是正确的。

这是一个微不足道的例子,请注意,这与当天破坏集理论的证据完全相同:创建一个可以确定自身是否正确的程序,如果它发现是< / em>正确,给出错误答案。

这是哥德尔的定理,简单明了。

但这不是问题,因为我们可以证明很多程序。

答案 19 :(得分:0)

大多数答案都集中在练习上,没关系:在练习中你不关心正式校对。但理论上是什么?

程序可以像数学陈述一样证明。但不是你的意思! 在任何足够强大的框架中,都有无法证明的数学陈述(和程序)!见here

答案 20 :(得分:0)

这里有太大的噪音,但无论如何我都会在风中喊叫......

“证明正确”在不同的语境中有不同的含义。在formal systems中,“证明正确”意味着公式可以从其他已证明的(或公理的)公式中推导出来。编程中的“证明正确”只是表示代码等同于正式规范。但是,您如何证明正式的规范是正确的?遗憾的是,除了通过测试之外,没有办法显示规范是无错误的,或解决任何现实世界的问题。

答案 21 :(得分:0)

仅仅是我的2美分,增加了那里有趣的东西。

在所有无法证明的程序中,最常见的是执行IO的程序(与世界或用户进行一些不可预测的交互)。甚至自动校样有时也会忘记“经过验证的”程序“在某些物理硬件上运行,而不是模型描述的理想程序。”

另一方面,数学证明并不关心世界。数学的一个反复出现的问题是它是否描述了真实的东西。每当发明像虚数或非欧几里德空间的新东西时,它就会被提升。然后问题被遗忘,因为这些新理论是如此好的工具。就像一个好的程序,它只是有效。

答案 22 :(得分:0)

我没有阅读所有的答案,但我看到它的方式,证明程序毫无意义,这就是为什么没有人这样做。

如果你有一个相对较小/中等的项目(例如,10K行代码),那么证据可能也是10k行,如果不是更长的话。

考虑一下,如果程序可能有错误,那么证明也可能存在“错误”。也许你需要证明证明!

另外需要考虑的是,程序非常正式和精确。你不能得到更严格和正式的,因为程序代码必须由一台非常愚蠢的机器执行。

虽然人们会阅读证据,但它们往往不如实际代码那么严格。

您唯一需要证明的是针对特定数据结构运行的低级算法(例如快速排序,插入二叉树等)。

这些事情有点复杂,它们工作的原因和/或它们是否会一直有效并不是很明显。它们也是所有其他软件的基本构建块。

答案 23 :(得分:0)

从一个不太抽象的观点来看,证明一些事情是将不确定性领域减少到一个经证实的空集。这是一厢情愿的想法,因为在现实世界中无法实现完美。

如果计算机程序的环境没有(或无法证实),那么它在现实世界中可以证明是正确的并且是失败的:

  • 必须证明操作系统内核,驱动程序和所有用户模式库以及同时执行的程序,包括其直接和间接的短期和长期副作用,

  • 硬件必须始终按预期运行(包括断电,水淹,地震,EMF干扰等),

  • 最终用户必须始终按预期行事(着名因素'X')。

自动纠错在各种硬件组件(RAM,磁盘,控制器等)中实现,但仍然发生硬件故障 - 在...... provably correct程序中产生级联错误和/或故障。

我甚至没有尝试关于最终用户创造力的结语......

因此,一个(正确)评分provably correct的程序并不意味着它在现实生活中是provably safe

这意味着,对于定义的研究中考虑的集合(它只能是现实世界的一个子集),此程序将按预期运行。

答案 24 :(得分:0)

正如其他人指出的那样,(某些)程序确实可以证明。

然而,实践中的一个问题是,您首先需要某种(即一个假设或定理)来证明。因此,为了证明某个程序的某些内容,您首先需要对其应该做的事情进行正式描述(例如,前后条件)。

换句话说,您需要一个正式的程序规范。但是,获得一个合理的(更不严格的正式)规范已经是软件开发中最难的事情之一。因此,通常很难证明有趣的关于(真实世界)程序的事情。

然而,有些事情可以(并且已经)更容易形式化(并且已经证实)。如果你至少可以证明你的程序不会崩溃,那已经是: - )。

BTW,一些编译器警告/错误基本上是(简单的)关于程序的证据。例如,Java编译器将证明您永远不会在代码中访问未初始化的变量(否则会给您编译错误)。

答案 25 :(得分:0)

我读了一下这个,但有两个问题。

首先,你无法证明一些称为正确性的抽象事物。如果事情设置得当,你可以证明两个正式系统是等价的。您可以证明程序实现了一组规范,并且最简单的方法是通过或多或少地构建证明和程序来实现这一点。因此,规范必须足够详细以提供证明的内容,并且因此规范实际上是一个程序。编写程序以满足目的的问题成为编写程序的正式详细规范以满足目的的问题,而这不一定是向前迈出的一步。

其次,程序很复杂。所以证明是正确的。如果你在编写程序时犯了错误,你肯定可以做一个证明。 Dijkstra和Gries告诉我,基本上,如果我是一个完美的数学家,我可以成为一名优秀的程序员。这里的价值在于证明和编程是两个有些不同的思维过程,至少根据我的经验,我犯了不同的错误。

根据我的经验,证明程序并非毫无用处。当我尝试做一些我可以正式描述的事情时,证明实现正确消除了许多难以发现的错误,主要是留下了愚蠢的错误,我可以在测试中轻松捕获。在一个必须生成极其无错误代码的项目中,它可以是一个有用的附件。它并不适合所有应用,它当然不是银弹。

答案 26 :(得分:0)

证明程序正确只能相对于程序的规范来完成;这是可能但昂贵/耗时

一些CASE系统生成的程序比其他程序更适合于证明 - 但同样,这依赖于规范的形式语义......

...所以你如何证明规范是正确的?对!有更多规格!

答案 27 :(得分:0)

如果程序具有明确定义的目标和初始假设(忽略Godel ......),则可以证明。找到所有素数x,对于6&lt; = x&lt; = 10,你的答案是7,这可以证明。我写了program that plays NIM(我写过的第一个Python程序),理论上计算机总是在游戏进入计算机可以获胜的状态后获胜。我无法证明它是真的,但它是真的(在数学上通过数字二进制和证明)我相信除非我在代码中出错。我是否犯了错误,不认真,有人能告诉我这个程序是否可以打败?

有一些数学定理已经被four color theorem等计算机代码“证明”了。但是有人反对,因为就像你说的那样,你能证明这个程序吗?

答案 28 :(得分:0)

  

此外,编程的公理是什么?该领域的原子真理?

操作码是“原子真理”吗?例如,看到......

mov ax,1

...程序员可能不断言为公理,除了硬件问题,执行此语句后,CPU的ax寄存器现在包含1

  

如果您编写了一个计算机程序,那么您如何使用以前经过验证的作品并使用它们来展示您的计划的真实性?

“之前的工作”可能是新程序运行的运行时环境。

新程序可以证明:除了正式的证据之外,它可以通过“检查”和各种形式的“测试”(包括“验收测试”)来证明。

  

你如何证明毕加索?

如果软件更像工业设计或工程而不是艺术,那么更好的问题可能是“你如何证明桥梁或飞机?”

答案 29 :(得分:0)

程序的某些部分可以被证明。例如,如果编译成功,则静态验证并保证类型安全的C#编译器。 但我怀疑你的问题的核心是证明一个程序正确执行。许多(我不敢说大多数)算法可以被证明是正确的,但由于以下原因,整个程序可能无法静态证明:

  • 验证需要遍历所有可能的分支(调用,ifs和interupts),这在高级程序代码中具有超立方时间复杂度(因此它永远不会在合理的时间内完成)。
  • 通过制作组件或使用反射,一些编程技术使得无法静态预测代码的执行(即,您不知道另一个程序员将​​如何使用您的库,并且编译器很难预测反射如何消费者将调用功能。

那些只是一些......

答案 30 :(得分:0)

阅读halting problem(这是关于证明程序是否完成的简单难度)。从根本上说,这个问题与哥德尔的不完备性定理有关。