断言和集合基数

时间:2020-07-31 20:42:51

标签: dafny

  • 为什么以下断言失败?
  • 此外,如果我取消注释ASSERT 0(第22行),为什么所有的断言都起作用?
function CountFactors(i:nat): nat
  requires i >= 1;
{
  var a := set b | 1 <= b <= i && i % b == 0;
  |a|
}
function CountFactorsSet(i:nat): set<nat>
  requires i >= 1;
{
  var a := set b | 1 <= b <= i && i % b == 0;
  a
}
method CountFactorsMethod(i:nat) returns (a: set<nat>)
  requires i >= 1;
{
  a := set b | 1 <= b <= i && i % b == 0;
}
method Main()
{
  var r:= CountFactorsMethod(2);
  print(r);
  // assert CountFactorsSet(2) == {1, 2}; // ASSERT 0
  assert CountFactors(2) == 2; // ASSERT 1
}

这里是link to the code。我正在使用Dafny 2.3.0.10506

1 个答案:

答案 0 :(得分:2)

在Dafny中使用集(或图或序列)时,这是一个非常常见的问题。这个问题归结为所谓的集合的“扩展相等”。

在数学上,如果两组元素相同,则它们相等。也就是说,(使用伪Dafny语法):

A == B   <==>   (forall x :: x in A <==> x in B)

这为证明两步相等的集合提供了非常强大的推理原理。取A的任意元素并显示在B中,然后取B的任意元素并显示在A中。

不幸的是,从自动推理的角度来看,这是一项相当昂贵的任务。如果Dafny试图通过该规则证明每个集合与它可以想到的每个其他集合相等,那就太慢了。

Dafny遵循以下经验法则:

除非达芬妮在程序中断言它们相等,否则我将不会尝试通过扩展性证明两个集合相等。

这通过限制Dafny考虑证明的套数彼此相等来保持验证性能。

因此,当您assert CountFactorsSet(2) == {1, 2};时,您授予Dafny权限以关于集CountFactorsSet(2)的扩展推理,事实证明足以解决此问题。


顺便说一句,在大型程序中,如果您从不重复两次设定的理解,那么您的运气会更好。取而代之的是,总是像这样将理解包在函数中。

function CountFactorsSet(i:nat): set<nat>
  requires i >= 1;
{
  set b | 1 <= b <= i && i % b == 0
}
function CountFactors(i:nat): nat
  requires i >= 1;
{
  |CountFactorsSet(i)|
}

通过使用函数而不是直接理解,可以使Dafny的生活变得更加轻松,因为对应用到同一参数的函数的两次出现相等是“显而易见的”,而对Dafny而言,这两次出现并不“显而易见”相同理解的不同句法出现是相等的。

事实证明,在您的示例中这无关紧要,但我只是想警告您,以防您计划在理解方面做更多工作。

相关问题