首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Dafny谓词isBinarySearchTree

Dafny谓词isBinarySearchTree
EN

Stack Overflow用户
提问于 2021-11-09 13:58:20
回答 2查看 203关注 0票数 0

我必须用Dafny写一个BST (二进制搜索树)类。

我从Dafny开始,然后编写一个类,插入方法是最简单的部分。

我多次尝试编写递归谓词,该谓词可以检查作为参数传递的树是否为BST (没有平衡条件,遵循规则left.value < node.value && right.value >node.value的简单二叉树)。

我在另一个StackOverflow post中找到了一种方法来实现它,在谓词中传递函数,主递归检查在函数中,但它似乎不起作用。

该错误基本上是“此调用的预条件可能不成立”。

以下是代码:

代码语言:javascript
复制
datatype Tree = Nil | Node(left: Tree, value: int, right: Tree)

class TreeADT{  

    function isBST(tree: Tree): bool
        decreases tree
    {
        match tree
        case Nil => true
        case Node(_,_,_) =>
            (tree.left == Nil || tree.left.value < tree.value) 
            && (tree.right == Nil || tree.right.value > tree.value) 
            && isBST(tree.left) && isBST(tree.right)
    }

    predicate isBinarySearchTree(tree: Tree)
    {
        isBST(tree)
    }
    
    method insert(tree: Tree, value: int) returns (toAdd: Tree) //maybe remove
        requires isBinarySearchTree(tree) 
        decreases tree;
        // ensures isBinarySearchTree(toAdd) //same error appear here
    {
        if(tree == Nil) {return Node(Nil, value, Nil);}
        else{
            if(value == tree.value) {return tree;}
            var temp: Tree;
            if(value < tree.value){
                temp := insert(tree.left, value);
                toAdd := Node(temp, tree.value, tree.right);
            }else{
                temp := insert(tree.right, value);
                toAdd := Node(tree.left, tree.value, temp);
            }
            return toAdd;
        }
            
    }

    method printOrderedTree(tree:Tree)
        decreases tree
    {
        if tree == Nil {}
        else { 
            printOrderedTree(tree.left); 
            print tree.value, ", "; 
            printOrderedTree(tree.right);
        }
    }


    method Main() {
        var t := insert(Nil, 5);
        var u := insert(t, 2); // error on pre-condition here
        print t, "\n";
        print u, "\n";
        printOrderedTree(u);
        var b:bool := isBST(u);
    }
}

我还试图完全在谓词中完成,但递归检查似乎无论如何都不起作用。

在谓词中得到递归检查而不是循环检查,有什么想法吗?

感谢您的阅读。

编辑:

按照James的回答,我修改了我的代码

代码语言:javascript
复制
datatype Tree = Nil | Node(left: Tree, value: int, right: Tree)

predicate isBinarySearchTree(tree: Tree)
    decreases tree
{
    match tree
    case Nil => true
    case Node(_,_,_) =>
        (tree.left == Nil || tree.left.value < tree.value) 
        && (tree.right == Nil || tree.right.value > tree.value) 
        && isBinarySearchTree(tree.left) && isBinarySearchTree(tree.right)
        && treeMin(tree.value, tree.right) && treeMax(tree.value, tree.left)
}

predicate treeMax(max: int, tree: Tree)
    decreases tree
{
    match tree
    case Nil => true
    case Node(left,v,right) => (max > v) && treeMax(max, left) && treeMax(max, right)
}

predicate treeMin(min: int, tree:Tree)
    decreases tree
{
    match tree
    case Nil => true
    case Node(left,v,right) => (min < v) && treeMin(min, left) && treeMin(min, right)
}

method insert(tree: Tree, value: int) returns (toAdd: Tree) //maybe remove
    requires isBinarySearchTree(tree) 
    decreases tree;
    ensures isBinarySearchTree(toAdd)
{
    if(tree == Nil) {return Node(Nil, value, Nil);}
    else{
        if(value == tree.value) {return tree;}
        var temp: Tree;
        if(value < tree.value){
            temp := insert(tree.left, value);
            toAdd := Node(temp, tree.value, tree.right);
        }else{
            temp := insert(tree.right, value);
            toAdd := Node(tree.left, tree.value, temp);
        }
        return toAdd;
    }
        
}

method printOrderedTree(tree:Tree)
    decreases tree
{
    if tree == Nil {}
    else { 
        printOrderedTree(tree.left); 
        print tree.value, ", "; 
        printOrderedTree(tree.right);
    }
}


method Main() {
    var t := insert(Nil, 5);
    var u := insert(t, 2);
    print t, "\n";
    print u, "\n";
    u := insert(u, 1);
    u := insert(u, 3);
    u := insert(u, 7);
    u := insert(u, 6);
    u := insert(u, 4);
    printOrderedTree(u);
}

但是,在requires语句中也会出现同样的问题,我现在检查左侧的所有值是否较小,而右侧的值是否都更大,但此错误再次发生。

代码语言:javascript
复制
A postcondition might not hold on this return path.

如果我注释掉了ensures语句,就会得到以下错误:

代码语言:javascript
复制
A precondition for this call might not hold.

所有的构造,想法和愚蠢的提示将被仔细阅读。

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-09 18:44:28

您的代码有几个问题。

(1) TreeADT类的用途是什么?在Dafny中,类通常用于表示可变对象,但是您的类没有字段或mutator方法,您可以使用datatype来保存数据,这样就可以完全摆脱类。

(2)你对isBST的定义是错误的。下面是一个示例:

代码语言:javascript
复制
method UhOh()
  ensures isBST(Node(Node(Nil, 3, Node(Nil, 7, Nil)), 5, Nil))
{}

这棵树不是二进位搜索树,因为7大于5,但7在5的左边子树中。但是你的定义允许这棵树。

(3)您遇到的具体问题是,Dafny无法证明t中的变量Main是二进制搜索树。我看你把insert的后置条件注释掉了。为什么?你需要那个后置条件。

我也不知道您所说的“在谓词中传递函数”是什么意思。您有一个无用的(尽管无害)包装谓词isBST。在Dafny中,单词predicate只不过是返回类型为boolfunction的缩写。

您编辑的代码看起来好多了。现在,insert的这两个附加的后置条件就足以完成这个证明了:

代码语言:javascript
复制
ensures forall x :: treeMin(x, tree) && x < value ==> treeMin(x, toAdd)
ensures forall x :: treeMax(x, tree) && x > value ==> treeMax(x, toAdd)
票数 1
EN

Stack Overflow用户

发布于 2021-11-12 04:53:00

添加了几个assert语句之后,您可以看到dafny无法验证什么。

代码语言:javascript
复制
   if (value < tree.value) {
        temp := insert(tree.left, value);
        toAdd := Node(temp, tree.value, tree.right);
        assert treeMax(tree.value, temp);
    }
    else {
        temp := insert(tree.right, value);
        toAdd := Node(tree.left, tree.value, temp);
        assert treeMin(tree.value, temp);
    }

达夫尼无法验证添加的断言持有。思考dafny无法验证的原因是,它抽象地看起来所有的方法都有给定的前后条件,忘记了实现。insert方法的前提条件是输入是有效二叉树,后置条件是输出有效二叉树。因此,插入方法,它总是返回树下面,例如,是有效的实现。

现在不难理解为什么treeMaxtreeMin在temp总是Tree(Tree(Nil, 1, Nil), 3, Tree(Nil, 5, Nil))时不起作用。

回顾过去,更大的问题是ensures提供的输入树和输出树之间没有联系。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69899477

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档