什么是不变式?


130

这个词似乎在许多上下文中得到了使用。我能想到的最好的是,它们表示一个不变的变量。这不是什么常量/最终形式(该死的Java!)。


也许他们应该把它称为不变的?
约翰尼

Answers:


189

不变量比变量更“概念上”。通常,它是程序状态的始终为真的属性。可以确保保持不变的函数或方法被称为保持不变。

例如,二叉搜索树可能具有不变性,即对于每个节点,节点左孩子的关键字小于节点自己的关键字。为该树正确编写的插入函数将保持不变。

如您所知,这不是可以存储在变量中的东西:它更多是关于程序的语句。通过确定程序应维护哪种不变量,然后查看代码以确保其实际维护那些不变量,可以避免代码中的逻辑错误。


1
如果在Wikipedia链接中包含Cero的答案,那么这个很好的例子会更好。
ablarg

2
父母的年龄大于其亲生子女的年龄。周围的环境将发生变化,但不变性不会发生变化。例如,可能是史密斯一家有两个孩子。或者可能在任何哺乳动物的其他物种中。上下文改变了,但是不变性没有改变。
trueadjustr

1
“ ...程序状态的属性始终为真...”-@jacob baskin-写得很好,并为此表示感谢。
twknab

“ ...程序状态的一个属性始终为真...”-我同意它写得很好,但可能会引起误解。首先,我将其理解为布尔值true,但是我很确定它的意思是“ ...始终不变”(但也许只是因为英语不是我的母语)
dev-null

29

您知道在逻辑中的特定位置始终是真实的,并且可以在调试时检查出问题出在哪里,这是一个条件。


17

我通常从算法或结构的角度看待它们。

例如,您可以声明一个循环不变式-在每次迭代的开始或结束时始终为true。也就是说,如果您的循环应该处理从一个堆栈到另一个堆栈的一组对象,则可以说| stack1 | + | stack2 | = c,位于循环的顶部或底部。

如果不变检查失败,则表明出现了问题。在此示例中,这可能意味着您忘记将处理后的元素压入最终堆栈等。


17

维基百科的魔力:不变式(计算机科学)

在计算机科学中,一个谓词(如果为真)将在整个特定操作序列中保持为真,称为该序列的不变式。


2
链接?技术术语?读?WTF?;)虽然,认真,良好的链接,但一点点总结将是不错的。
垃圾工

10

如该行所述:

在计算机科学中,一个谓词(如果为真)将在整个特定操作序列中保持为真,称为该序列的不变式。

为了更好地理解这一希望,C ++中的此示例将有所帮助。

考虑一个场景,您必须获取一些值并在名为as的变量中获取它们的总数,count然后将其添加到称为as的变量中sum

不变的(再次它更像是一个概念):

// invariant:
// we have read count grades so far, and
// sum is the sum of the first count grades

上面的代码是这样的,

int count=0;
double sum=0,x=0;
while (cin >> x) {
++count;
sum+=x;
}

上面的代码做什么?

1)从中读取输入cin并将其放入x

2)成功读取一次后,递增countsum = sum + x

3)重复1-2,直到读取停止(即ctrl + D)

循环不变式:

不变量必须为True ALWAYS。因此,最初,您仅以此开始代码

while(cin>>x){
  }

该循环从标准输入读取数据并存储在x中。好,好。但是因为我们的不变式的第一部分没有被跟随(或保持为真),所以不变式变为假。

// we have read count grades so far, and

如何保持不变性为真?

简单!增量计数。

这样++count;会很好!现在我们的代码变成这样,

while(cin>>x){
 ++count; 
 }

即使是现在我们不变的(必须是TRUE一个概念)是假的,因为现在我们没有满足的第二部分我们不变的。

// sum is the sum of the first count grades

那么现在该怎么办?

添加xsum并将其存储在sumsum+=x),下一次 cin>>x将读取一个新值X。

现在我们的代码变成这样,

while(cin>>x){
 ++count; 
 sum+=x;
 }

让我们检查

代码是否匹配我们的不变式

// invariant:
// we have read count grades so far, and
// sum is the sum of the first count grades

码:

while(cin>>x){
 ++count; 
 sum+=x;
 }

啊!。现在,循环不变式始终为True ,代码可以正常工作。

上面的示例取材于Andrew-koening和Barbara-E 的《Accelerated C ++》一书



2

从本质上讲,不变式在编写简洁的代码方面非常有用,因为从概念上了解代码中应包含哪些不变式您可以轻松决定如何组织代码以实现这些目标。如ealier所述,它们在调试中也很有用,因为检查不变量是否被维护通常是查看您尝试执行的任何操作是否实际上在执行您想要的操作的好方法。


2

它通常是在某些数学运算下不会改变的数量。一个例子是一个标量,它不旋转下改变。例如,在磁共振成像中,通过旋转不变量来表征组织性质很有用,因为理想情况下,其估计不依赖于扫描仪中人体的方向。


2

这个答案是给我5岁的孩子的。不要将不变量视为常数或固定数值。但是可以。但是,不仅如此。

相反,不变性类似于各种实体之间的固定关系。例如,与您的亲生父母相比,您的年龄将始终小于其年龄。您的年龄和父母的年龄都会随着时间的推移而变化,但是我上面提到的关系是不变的。

不变量也可以是数值常数。例如,的值pi是圆的周长与其直径之间的不变比率。不论圆圈大小,该比例始终为pi


1

在执行任何实例方法之前和之后,数据字段(实例变量)之间的ADT不变物种关系必须始终为真。


0

Java并发实践一书中有一个很好的例子,说明了不变性及其重要性

尽管以Java为中心,但是该示例描述了一些代码,这些代码负责计算提供的整数的因数。示例代码尝试缓存提供的最后一个数字以及为提高性能而计算出的因素。在这种情况下,示例代码中没有考虑一个不变变量,这使该代码易于在并发场景中出现竞争条件。

在此处输入图片说明


0

这里的所有答案都很好,但我觉得我可以进一步阐明这件事:

从语言的角度来看,不变是指永远不变的东西。尽管该概念实际上来自数学,但与归纳相结合时,它是最受欢迎的证明技术之一。

这就是证明的方式,如果您可以找到处于初始状态的不变量,并且该不变量持续存在,而不管对该状态进行任何[合法]转换,那么您就可以证明,如果某个状态不具有此状态,不变,则无论将什么转换顺序应用于初始状态,它都永远不会发生。

现在,以前的思维方式(再次与归纳相结合)使得判断计算机软件的逻辑成为可能。当执行进入循环时,这一点尤其重要,在循环中可以使用不变式来证明某个循环将产生某种结果,或者它永远不会以某种方式改变程序的状态。

当使用不变式作为循环逻辑的谓词时,称为循环不变式。可以在循环外使用它,但是对于循环来说,它确实很重要,因为您经常有很多可能性,或者无限多种可能性。

请注意,我使用“谓词”一词是计算机软件的逻辑,而不是证明。那是因为尽管在数学中不变性可以用作证明,但它永远无法证明计算机软件在执行时会产生预期的效果,这是因为该软件是在许多抽象之上执行的,这是无法证明的他们将产生预期的结果(例如,考虑硬件抽象)。

最后,虽然理论上和严格地预测软件逻辑仅对医疗和军事应用等高关键应用很重要。在调试时,仍然可以使用不变式来帮助典型的程序员。它可以用来知道某个位置的程序失败,因为该程序无法维护某个不变式-无论如何,我们中的许多人在使用它时都没有考虑到它。

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.