Dafny是否支持“施工证明”?

时间:2018-06-01 14:53:08

标签: proof dafny

假设我有一个计算某事的方法:

method Difference(a: nat, b: nat) returns (c: nat)
  ensures a + c == b || b + c == a
{
  ...
}

别介意现在的实施。如果我可以在Dafny中实现此方法,这意味着对于所有可能的参数 a b ,必须有一些返回值 c 满足后置条件。

换句话说,该方法的主体是建设性证明

forall a: nat, b: nat :: exists c: nat ::
  a + c == b || b + c == a

但是Dafny is not convinced

method Difference(a: nat, b: nat) returns (c: nat)
  ensures a + c == b || b + c == a
{
  c := if a > b then a - b else b - a;
}

method Main() {
  assert forall a: nat, b: nat :: exists c: nat ::  // error: assertion violation :(
    a + c == b || b + c == a;
}

有没有办法在Dafny中使用这种推理?

2 个答案:

答案 0 :(得分:2)

这样做的诀窍:将属性包装在谓词中,并在引理中证明exists,以便您可以使用assert提示验证者。

也许有一些方法可以在forall内提示。

predicate difference_property(a: nat, b: nat, c: nat)
{
    a + c == b || b + c == a
}

function difference(a: nat, b: nat): nat
{
    if a > b then a - b else b - a
}

lemma main(a: nat, b: nat)
    ensures exists c: nat :: difference_property(a, b, c)
{
    var c := difference(a, b);
    assert difference_property(a, b, c);
}

答案 1 :(得分:1)

对于存在被引理证明存在的情况,Valéry的答案是一个很好的伎俩。你也可以使用Dafny的forall 声明将这个技巧扩展为“forall内部的提示”,就像这样

forall a: nat, b: nat
    ensures exists c: nat :: difference_property(a, b, c)
{
    var c := difference(a, b);
    assert difference_property(a, b, c);
}

证明了forall 表达式

forall a: nat, b: nat :: 
    exists c: nat :: 
        difference_property(a, b, c)

对于Jason关于在证明中使用适当方法的其他问题,Dafny不支持这一点。实际上,我认为它是不合适的,因为方法可以对堆产生影响,例如。因此,一些证人的建构原则上可能依赖于分配状态甚至修改现有状态。将这种影响内化到逻辑中是可疑的,并且会改变达菲尼的本性。