You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Dafny中证明有序唯一键序列的KeySet长度与序列长度相等

问题:Dafny中无法证明KeySet长度等于序列长度

我在Dafny中实现了一个已验证的SortedMap,它由(键,值)对组成的序列构成,其中键是排序后的唯一整数。但无法证明KeySet的长度必须等于该序列的长度,错误信息如下:

this is the postcondition that could not be proved
  |
7 |   ensures |KeySet(sorted_seq)| == |sorted_seq|

简化后的代码:

predicate SortedSeq(sequence: seq<(int, int)>) {
  forall i, j | 0 <= i < j < |sequence| :: sequence[i].0 < sequence[j].0
}

function KeySet(sorted_seq: seq<(int, int)>): set<int>
  requires SortedSeq(sorted_seq)
  ensures |KeySet(sorted_seq)| == |sorted_seq|
{
  set i | i in sorted_seq :: i.0
}


method Main()
{
  var s: seq<(int,int)> := [(1, 2), (30, 40), (50, 50)];
  print KeySet(s);
}

问题原因

SortedSeq谓词保证了序列中的键严格递增,因此所有键必然唯一。但Dafny的自动验证器无法直接从集合推导的语法中,关联出“严格递增的键对应集合中元素个数等于序列长度”这一结论。集合推导式set i | i in sorted_seq :: i.0的唯一性需要显式的推理支持。

解决方法

可以通过以下两种方式让Dafny完成证明:

方法1:添加辅助引理

先证明满足SortedSeq的序列中所有键都是唯一的,再用这个引理来支持KeySet的后置条件:

predicate SortedSeq(sequence: seq<(int, int)>) {
  forall i, j | 0 <= i < j < |sequence| :: sequence[i].0 < sequence[j].0
}

lemma KeysUnique(sequence: seq<(int, int)>)
  requires SortedSeq(sequence)
  ensures forall i, j | 0 <= i < j < |sequence| :: sequence[i].0 != sequence[j].0
{
  // 由SortedSeq的严格递增直接可得键唯一,Dafny能自动验证这个引理
}

function KeySet(sorted_seq: seq<(int, int)>): set<int>
  requires SortedSeq(sorted_seq)
  ensures |KeySet(sorted_seq)| == |sorted_seq|
{
  set i | i in sorted_seq :: i.0
}
{
  KeysUnique(sorted_seq);
}

方法2:递归定义KeySet

改用递归方式构建键集合,同时维护“集合大小等于当前处理的序列长度”的不变量,这样Dafny更容易跟踪:

predicate SortedSeq(sequence: seq<(int, int)>) {
  forall i, j | 0 <= i < j < |sequence| :: sequence[i].0 < sequence[j].0
}

function KeySet(sorted_seq: seq<(int, int)>): set<int>
  requires SortedSeq(sorted_seq)
  ensures |KeySet(sorted_seq)| == |sorted_seq|
{
  if sorted_seq == [] then
    {}
  else
    KeySet(sorted_seq[0..|sorted_seq|-1]) + {sorted_seq[|sorted_seq|-1].0}
}
{
  if sorted_seq == [] {
    assert |KeySet(sorted_seq)| == 0 == |sorted_seq|;
  } else {
    var prev := sorted_seq[0..|sorted_seq|-1];
    var lastKey := sorted_seq[|sorted_seq|-1].0;
    assert forall k in KeySet(prev) :: k < lastKey;
    assert lastKey !in KeySet(prev);
    assert |KeySet(sorted_seq)| == |KeySet(prev)| + 1 == |prev| + 1 == |sorted_seq|;
  }
}

内容的提问来源于stack exchange,提问作者Carl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 16:46:18