Dafny框架系统问题:原地翻转二叉树验证失败求助
Dafny验证原地翻转二叉树的modify clause问题
Dafny的框架系统存在诸多易踩坑点。我正尝试验证原地翻转二叉树问题,分别以对象方法和独立函数两种方式实现。但独立函数的递归调用始终被提示违反上下文的modify clause,我已尽可能将相关内容添加到modify clause中仍无法解决,我认为归纳法应足够支撑验证,特此寻求解决方法。
相关代码
/** * 原地翻转二叉树问题 * Definition for a binary tree node. */ class TreeNode { var val: int; var left: TreeNode?; var right: TreeNode?; ghost var repr: set<TreeNode>; constructor(val: int, left: TreeNode?, right: TreeNode?) requires left != null ==> left.Valid() requires right != null ==> right.Valid() requires left != null && right != null ==> left.repr !! right.repr ensures this.val == val ensures this.left == left ensures this.right == right ensures left != null ==> this !in left.repr ensures right != null ==> this !in right.repr ensures Valid() { this.val := val; this.left := left; this.right := right; var leftRepr := if left != null then {left}+left.repr else {}; var rightRepr := if right != null then {right}+right.repr else {}; this.repr := {this} + leftRepr + rightRepr; } predicate Valid() reads this, repr decreases repr { this in repr && (this.left != null ==> (this.left in repr && this !in this.left.repr && this.left.repr < repr && this.left.Valid() )) && (this.right != null ==> (this.right in repr && this !in this.right.repr && this.right.repr < repr && this.right.Valid())) && (this.left != null && this.right != null ==> this.left.repr !! this.right.repr) } } method invertBinaryTree(root: TreeNode?) returns (newRoot: TreeNode?) modifies {root} + (if root != null && root.left != null then {root.left} else {}) + (if root != null && root.right != null then {root.right} else {}) requires root != null ==> root.Valid() ensures root != null ==> newRoot == root && newRoot.right == old(root.left) && root.left == old(root.right) ensures root == null ==> newRoot == null ensures root != null ==> newRoot != null && newRoot.repr == root.repr && newRoot.Valid() decreases if root == null then {} else root.repr { if root != null { assert root in root.repr; assert root.Valid(); var leftChild := null; if root.left != null { assert root.left != null; assert root.left.repr < root.repr; assert root.left.Valid(); leftChild := invertBinaryTree(root.left); } var rightChild := root.right; if root.right != null { assert root.right.Valid(); rightChild := invertBinaryTree(root.right); } root.right := leftChild; root.left := rightChild; return root; }else{ return null; } }
问题分析与修复
核心问题
当前方法的modifies子句仅声明了修改当前节点、直接左子节点和直接右子节点,但递归调用时,子树的所有节点都会被修改(递归会逐层翻转子树的左右节点)。Dafny的框架检查要求modifies必须覆盖所有可能被修改的对象集合,因此当前的modifies范围不足以覆盖递归过程中修改的子树节点,导致违反错误。
修复步骤
修改modifies子句:利用
TreeNode的repr幽灵变量(该变量已包含当前节点及其所有子节点),将modifies范围改为:modifies if root != null then root.repr else {}这样就能覆盖递归过程中所有会被修改的节点。
简化冗余断言:原代码中的部分断言可被Dafny自动推导,无需手动添加,简化后代码更简洁。
修复后的完整方法代码
method invertBinaryTree(root: TreeNode?) returns (newRoot: TreeNode?) modifies if root != null then root.repr else {} requires root != null ==> root.Valid() ensures root != null ==> newRoot == root && newRoot.right == old(root.left) && root.left == old(root.right) ensures root == null ==> newRoot == null ensures root != null ==> newRoot != null && newRoot.repr == root.repr && newRoot.Valid() decreases if root == null then {} else root.repr { if root != null { var leftChild := invertBinaryTree(root.left); var rightChild := invertBinaryTree(root.right); root.right := leftChild; root.left := rightChild; return root; }else{ return null; } }
验证逻辑说明
modifies root.repr直接覆盖了当前树的所有节点,满足递归时修改子树节点的框架要求。decreases root.repr通过集合大小的递减保证递归终止,符合Dafny的终止检查规则。ensures条件中的newRoot.repr == root.repr确保翻转操作不会改变树的节点集合,只是调整了节点间的引用关系,这也和Valid()谓词的要求一致。
内容的提问来源于stack exchange,提问作者Hath995
相关产品推荐
相关产品推荐

