断言、forall 和映射:通用量词不适用于映射
Assertion, forall, and maps: Universal quantifiers does not work with maps
在这个例子中,我只在一个映射中插入一个值,我试图断言这个映射中的任何两个键是相同的。但是断言失败。这是 link.
datatype HostState = HostState(counter:nat, vote: map<nat, set<nat>>)
predicate HostInit(s:HostState, counter: nat) {
var default: nat := 0;
&& s.counter == 1
&& |s.vote| == 1 && default in s.vote
}
lemma lemma_UniqueKey(){
var default: nat := 0;
assert forall s, counter :: HostInit(s, counter) ==>
(
// |s.vote| == 1 && default in s.vote // Pass
(forall t: nat, t': nat :: t in s.vote && t' in s.vote ==> t' == t) // Fail
// (forall t: nat :: t in s.vote) // Not even this works
);
}
仅当我使用 forall
遍历地图时断言才会失败。
关于为什么断言失败的任何线索?
不幸的是,Dafny 没有 built-in 理解 cardinality-one 和您提到的量化 属性 之间的关系。这是让 Dafny 相信这一事实的一种方法。
我们可以将推理分解为关于地图的通用引理。
lemma CardinalityOneMap<A,B>(m: map<A,B>)
requires |m| == 1
ensures forall x, y | x in m && y in m :: x == y
{
CardinalityOneSet(m.Keys);
}
这个引理只是说如果一个映射的基数为 1,那么它的所有键都是相等的。该证明在地图的键集上调用了关于集合的类似引理。
lemma CardinalityOneSet<A>(s: set<A>)
requires |s| == 1
ensures forall x, y | x in s && y in s :: x == y
{
var z :| z in s;
var s' := s - {z};
assert |s'| == 0; // this is enough for dafny to see s' is empty
}
这个引理是关于集合的相应事实。证明有点奇怪,并且依赖于(未记录,learned-by-fire)事实,即 Dafny 确实 理解一组基数 0 是空的。所以我们抓取 s
的“任意”元素 z
,然后构造集合 s - {z}
。然后我们提到这个新集合的基数,Dafny 突然注意到这个集合必须是空的,这意味着 s
必须只包含 z
,我们就完成了。
随着引理的证明,我们可以return你的代码。
lemma lemma_UniqueKey(){
var default: nat := 0;
forall s, counter | HostInit(s, counter)
ensures (forall t: nat, t': nat :: t in s.vote && t' in s.vote ==> t' == t)
{
CardinalityOneMap(s.vote);
}
assert forall s, counter :: HostInit(s, counter) ==>
(forall t: nat, t': nat :: t in s.vote && t' in s.vote ==> t' == t)
;
}
您想证明关于所有状态的断言。为此,我们需要在 s
上调用我们的引理 CardinalityOneMap
,但是 s
是通用量词下的一个变量,因此我们需要使用 forall
声明来做到这一点。在陈述之后,如果我们愿意,我们可以 re-assert 同样的事实,只是为了再次检查 Dafny 现在是否被说服了。
以下是一些可能相关的其他答案:
- Proving facts about cardinality of range sets
PS:很高兴看到您正在学习分布式系统课程!
在这个例子中,我只在一个映射中插入一个值,我试图断言这个映射中的任何两个键是相同的。但是断言失败。这是 link.
datatype HostState = HostState(counter:nat, vote: map<nat, set<nat>>)
predicate HostInit(s:HostState, counter: nat) {
var default: nat := 0;
&& s.counter == 1
&& |s.vote| == 1 && default in s.vote
}
lemma lemma_UniqueKey(){
var default: nat := 0;
assert forall s, counter :: HostInit(s, counter) ==>
(
// |s.vote| == 1 && default in s.vote // Pass
(forall t: nat, t': nat :: t in s.vote && t' in s.vote ==> t' == t) // Fail
// (forall t: nat :: t in s.vote) // Not even this works
);
}
仅当我使用 forall
遍历地图时断言才会失败。
关于为什么断言失败的任何线索?
不幸的是,Dafny 没有 built-in 理解 cardinality-one 和您提到的量化 属性 之间的关系。这是让 Dafny 相信这一事实的一种方法。
我们可以将推理分解为关于地图的通用引理。
lemma CardinalityOneMap<A,B>(m: map<A,B>)
requires |m| == 1
ensures forall x, y | x in m && y in m :: x == y
{
CardinalityOneSet(m.Keys);
}
这个引理只是说如果一个映射的基数为 1,那么它的所有键都是相等的。该证明在地图的键集上调用了关于集合的类似引理。
lemma CardinalityOneSet<A>(s: set<A>)
requires |s| == 1
ensures forall x, y | x in s && y in s :: x == y
{
var z :| z in s;
var s' := s - {z};
assert |s'| == 0; // this is enough for dafny to see s' is empty
}
这个引理是关于集合的相应事实。证明有点奇怪,并且依赖于(未记录,learned-by-fire)事实,即 Dafny 确实 理解一组基数 0 是空的。所以我们抓取 s
的“任意”元素 z
,然后构造集合 s - {z}
。然后我们提到这个新集合的基数,Dafny 突然注意到这个集合必须是空的,这意味着 s
必须只包含 z
,我们就完成了。
随着引理的证明,我们可以return你的代码。
lemma lemma_UniqueKey(){
var default: nat := 0;
forall s, counter | HostInit(s, counter)
ensures (forall t: nat, t': nat :: t in s.vote && t' in s.vote ==> t' == t)
{
CardinalityOneMap(s.vote);
}
assert forall s, counter :: HostInit(s, counter) ==>
(forall t: nat, t': nat :: t in s.vote && t' in s.vote ==> t' == t)
;
}
您想证明关于所有状态的断言。为此,我们需要在 s
上调用我们的引理 CardinalityOneMap
,但是 s
是通用量词下的一个变量,因此我们需要使用 forall
声明来做到这一点。在陈述之后,如果我们愿意,我们可以 re-assert 同样的事实,只是为了再次检查 Dafny 现在是否被说服了。
以下是一些可能相关的其他答案:
- Proving facts about cardinality of range sets
PS:很高兴看到您正在学习分布式系统课程!