I have to write a little BST (binary search tree) class in Dafny.
I begin with Dafny then write a class and an insert method was the easiest part.
I tried multiple time to write a recursive predicate which can check if the tree passed as argument is a BST (without balancing condition, a simple binary tree following the rule left.value < node.value && right.value > node.value).
I found in another StackOverflow post a way to do it passing a function in a predicate and the main recursives check are in the function but it doesn't seem to work.
The error is basically 'A pre-condition for this call might not hold'.
Here is the code:
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);
}
}
I also tried to do it entirely in the predicate but the recursive check seems to doesn't work anyway.
Any idea to get recursion check instead of loop check in a predicate?
Thanks for reading.
Edit:
Following James's answer i modified my code
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);
}
But same problem occurs in requires and ensures statement, I now check if all value at left side are lesser and all at right side are greater but this error occurs again
A postcondition might not hold on this return path.
And if I comment out the ensures statement I get the following error:
A precondition for this call might not hold.
All constructives ideas and dafny tips will be read with attention.
Thanks.
There are several issues with your code.
(1) What is the purpose of the TreeADT class? In Dafny, classes are usually used to represent mutable objects, but your class has no fields or mutator methods, and you use a datatype to hold the data, so you can just get rid of the class altogether.
(2) Your definition of isBST is wrong. Here is an example:
method UhOh()
ensures isBST(Node(Node(Nil, 3, Node(Nil, 7, Nil)), 5, Nil))
{}
This tree is not a binary search tree because 7 is greater than 5 but 7 is in the left subtree of 5. But your definition allows this tree.
(3) The concrete problem you are running into is that Dafny cannot prove that the variable t in Main is a binary search tree. I see you have that postcondition of insert commented out. Why? You will need that postcondition.
I'm also not sure what you meant by "passing a function in a predicate". You have a useless (though harmless) wrapper predicate isBST. In Dafny, the word predicate is nothing but an abbreviation for a function whose return type is bool.
Your edited code looks much better. Now these two additional postconditions to insert are enough to finish the proof:
ensures forall x :: treeMin(x, tree) && x < value ==> treeMin(x, toAdd)
ensures forall x :: treeMax(x, tree) && x > value ==> treeMax(x, toAdd)
After adding few assert statements you can see what dafny is unable to verify.
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 is unable to verify added assert holds. Way to think about why dafny is unable to verify is it looks abstractly all method with given pre and post conditions forgetting implementation. insert method precondition is input is valid binary search tree and postcondition is output is valid binary tree. So insert method which always return below tree for example is valid implementation.
Now it is not hard to see why treeMax or treeMin will not hold when temp is always Tree(Tree(Nil, 1, Nil), 3, Tree(Nil, 5, Nil)).
Looking back bigger issue is there is no link between input tree and output tree provided by ensures.
Related
I am having trouble sorting data after a Firebase query. In my database, there is a collection of bikes, and each bike has a condition: Excellent, Great, Good, Fair, Poor, or Totaled. I would like to sort by condition so the start of the list is Excellent and the bottom is Totaled. I am then putting this in a ListView.
My Firebase structure:
My Firebase structure
My query: FirebaseFirestore.instance.collection('bikes').snapshots();
I tried following this post's guidance, but to no avail. My very simple test below to sort by title length doesn't seem to sort anything (I'm passing the sorting to a function since sorting is only when the user clicks a button).
AsyncSnapshot<QuerySnapshot<Object?>> sortSnapshot(
AsyncSnapshot<QuerySnapshot<Object?>> snapshot) {
if (sortList == true) {
snapshot.data!.docs.sort((a, b) => a['Name'].length.compareTo(b['Name'].length));
}
return snapshot;
}
I don't think the sorting part is your problem here. The following code sorts the items by length of Name using the same approach you provided above, and then sorts by condition:
void main() {
final conditions = {
'Excellent': 0,
'Great': 1,
'Good': 2,
'Fair': 3,
'Poor': 4,
'Totaled': 5,
};
final docs = [
{'Name': 'Argon', 'Condition': 'Great'},
{'Name': 'Baum', 'Condition': 'Good'},
{'Name': 'Canyon', 'Condition': 'Excellent'},
{'Name': 'Davidson', 'Condition': 'Totaled'},
{'Name': 'Erickson', 'Condition': 'Fair'},
{'Name': 'Focus', 'Condition': 'Poor'},
];
docs.sort((a, b) => a['Name']!.length.compareTo(b['Name']!.length));
print(docs);
docs.sort((a, b) =>
conditions[a['Condition']]!.compareTo(conditions[b['Condition']]!));
print(docs);
}
I think a more likely explanation for what is happening, is you are not updating the UI by calling setState or something along those lines. Or maybe your sortList variable is assigned to false. Or maybe you aren't correctly registering the function as a callback to the aforementioned button press. There really isn't enough context here to say for certain, but I really don't think your sorting code is the problem here.
Edit. After looking at it a bit more. Why are you passing around and trying to update an AsyncSnapshot object? The documentation suggests that this class is immutable. I presume calling .data on this object generates the data every time you call the method, rather than returning a mutable reference (otherwise the class could not possibly be immutable).
Essentially what I think you will need to do is save snapshot.data!.docs to a variable, and sort and return that, rather than returning back the AsyncSnapshot.
SOLUTION:
For anyone stumbling across this in the future: mmcdon20's answer was correct. It turns out the AsyncSnapshot is indeed immutable. I didn't get any warnings or errors when trying to sort it (which is sort of annoying), but it makes sense. It couldn't be changed, so it wasn't changing.
Anyways, I ended up modifying my sorting function as follows:
My query: FirebaseFirestore.instance.collection('bikes').snapshots();
Extraction of mutable List to sort:
var snapList = snapshot.data!.docs.toList(); // <-- Mutable List object
var posts = sortSnapshot(snapList); // <-- Function that sorts
My sorting function:
List<QueryDocumentSnapshot<Object?>> sortSnapshot(
List<QueryDocumentSnapshot<Object?>> snapList) {
if (sortString == 'Sort by: Distance') {
// Grab lat/lon
// Do distance calculation via Haversine formula
// Sort by distance
} else if (sortString == 'Sort by: Condition') {
snapList.sort((a, b) => compareCondition(a['Condition'], b['Condition']));
}
return snapList;
}
I haven't implemented the sorting by Distance yet, but you get the idea. For sorting by condition, here's my comparator:
int compareCondition(String a, String b) {
// Order: Excellent, Great, Good, Fair, Poor, Totaled
if (a == b) return 0;
switch (a) {
case "Excellent":
return -1;
case "Great":
if (b == 'Excellent') return 1;
return -1;
case "Good":
if ((b == 'Excellent') || (b == 'Great')) return 1;
return -1;
case "Fair":
if ((b == 'Excellent') || (b == 'Great') || (b == 'Great')) return 1;
return -1;
case "Poor":
if ((b == 'Excellent') ||
(b == 'Great') ||
(b == 'Great') ||
(b == 'Fair')) return 1;
return -1;
case "Totaled":
if ((b == 'Excellent') ||
(b == 'Great') ||
(b == 'Great') ||
(b == 'Fair') ||
(b == 'Poor')) return 1;
return -1;
}
return -1;
}
This properly sorts the list, and I can then use my posts List object to generate my ListTiles in my ListView.
Thanks mmcdon20 and hopes this helps someone out someday!
Say I have two structs that define a linked list:
....
....
type node struct {
item interface{}
next *node
}
type LinkedList struct {
first *node
N int
}
...
...
and I want to compare the value of the type of the underlying node, say, in a find function where we check if k == node.item such that:
func (l *LinkedList) find (key interface{}) bool {
result := false
if !l.isEmpty() {
for x:= l.first; x != nil; x = x.next {
if x.item == key {
result = true
break
}
}
return result
}
this will not work for the expected find function because the underlying types are different, hence the func will always return false. We can confirm this upon reflecting the type:
fmt.Println(reflect.TypeOf(key), reflect.TypeOf(x.item))
>>> string, *main.node
Tried workarounds?
I've tried asserting the type but alas this does not work and panics
tmp := x.item.(string)
>>>panic: interface conversion: interface {} is *main.node, not string
This case is the same for using fmt.Sprintf(x.item)
I'm a bit stumped as to where to go from here. Is there a way to do this?
Inserting item to linked list
The following snippet should clarify how insertion is handled
func (l *LinkedList) insertFirst(item interface{}) {
var first *node = new(node)
oldfirst := l.first
first.item = item
first.next = oldfirst
l.first = first
l.N++
}
.....
//which gets called somewhere like
var n *node = new(node)
n.item = item
l.insertFirst(n)
.....wait no theres the error!
----------
burak-serdar you are 100% correct that I am inserting the node in the node!
The interface comparison in find() is a valid comparison and it will work if the type of the key and the type of the value stored in the node are the same. However, evidence points to you adding a node in place of a value.
Say I have this struct:
type Foo struct {
Bar *string `json:"bar"`
Baz *int64 `json:"baz,omitempty"`
Qux *string `json:"qux"`
Quux string `json:"quux"`
}
After unmarshalling the json, I check for nil like so:
switch {
case f.Bar == nil:
return errors.New("Missing 'bar'")
case f.Baz == nil:
f.Baz = 42
case f.Qux == nil:
return errors.New("Missing 'qux'")
}
(or through a series of if statements, etc...)
I understand that I can put all the nil comparisons in one comma separated case, but each nil check will have differing returns.
My question: is there a less verbose way of doing the nil checks?
A question to you: how less verbose you want to get? Because you want to do different things on different conditions (different fields being nil). Your code contains these different things and the different conditions. Beyond that what's "redundant" in your code are just the switch and case keywords. You want to leave them out? Because the rest is not "redundant", they are required.
Also note that in Go cases do not fall through even without a break (unlike in other languages), so in your above example if f.Baz is nil, you will set it to 42 and f.Qux will not be checked (so no error will be returned), but if f.Baz is non-nil and f.Qux is nil, an error will be returned. I know it's just an example, but this is something to keep in mind. You should handle errors first if you use a switch! Or use if statements and then the error will be detected and returned regardless of the order of field checks.
Your code with switch is clean and efficient. If you want to make it less verbose, readability (and performance) will suffer.
You may use a helper function which checks if a pointer value is nil:
func n(i interface{}) bool {
v := reflect.ValueOf(i)
return v.Kind() == reflect.Ptr && v.IsNil()
}
And using it:
func check(f *Foo) error {
switch {
case n(f.Bar):
return errors.New("Missing 'bar'")
case n(f.Qux):
return errors.New("Missing 'qux'")
case n(f.Baz):
x := int64(42)
f.Baz = &x
}
return nil
}
Or using if statements:
func check2(f *Foo) error {
if n(f.Bar) {
return errors.New("Missing 'bar'")
}
if n(f.Qux) {
return errors.New("Missing 'qux'")
}
if n(f.Baz) {
x := int64(42)
f.Baz = &x
}
return nil
}
Try these on the Go Playground.
I'm trying to implement a delete() method to a list (no HEAD ref)
I find out that I can modify the parameter to a struct.
func (l *LinkedList) Delete(n *Node) {
if n.next == nil {
n = nil
} else {
current := &n
*n = *n.next
*current = nil
}
}
The "else" part works fine, but deleting the last node does not modify the list
Tried using
*n = nil
But then I have the compile error.
cannot use nil as type Node in assignment
Code complete in this playground:
http://play.golang.org/p/Dhzyd7QHEw
You're just doing it wrong. I mean classic element removal from single linked list. Right way:
func (l *LinkedList) Delete(n *Node) {
// if we want to delete the head element - just move the head pointer
if l.head == n {
l.head = n.next
return
}
// otherwise find previous element to the one we are deleting
current := l.head
for current != nil && current.next != n {
current = current.next
}
// and move that previous element next pointer to the next element
if current != nil {
current.next = n.next
}
}
https://play.golang.org/p/_NlJw_fPWQD
So what was wrong in your example? In your Delete function you are receiving a pointer to some node. This pointer is local to your function, it's like a local variable. It doesn't matter if you assign nil to a local variable inside your function. Outside - no one will see such assignments. What you want to do - is to change the next pointer of the previous list item. This way the item will no longer be in the list. GC will remove the actual allocated memory.
UPDATE:
Since go pointers are "real" pointers, this can be implemented without special case for the head removal, by using an additional level of indirection, as suggested by Linus in his famous TED talk (and earlier in slashdot Q&A - see "favorite hack" question):
func (l *LinkedList) Delete(n *Node) {
// initialize indirect with the address of a head pointer
indirect := &(l.head)
// until indirect has address of a pointer to the node we're deleting
for *indirect != n {
// check that it's not the end of the list
if (*indirect).next == nil {
// the node we're tryign to delete is not in the list
return
}
// set indirect to the address of the next pointer
indirect = &(*indirect).next
}
// indirect has address of a pointer we need to modify to delete the node
*indirect = n.next
}
https://play.golang.org/p/hDy3hB5LUME
IMO two levels of inderection is harder to understand than a simple special case for deleting the head element, but Linus is not exactly an ordinary developer like myself :)
I have to copy certain elements from a std::map into a vector.
It should work like in this loop:
typedef int First;
typedef void* Second;
std::map<First, Second> map;
// fill map
std::vector<Second> mVec;
for (std::map<First, Second>::const_iterator it = map.begin(); it != map.end(); ++it) {
if (it->first % 2 == 0) {
mVec.push_back (it->second);
}
}
Since I'd like to avoid using any functors, but use boost::lambda instead, I tried using std::copy, but can't get it right.
std::copy (map.begin(), map.end(), std::back_inserter(mVec)
bind(&std::map<int, void*>::value_type::first, _1) % 2 == 0);
I'm new to lambda expressions, and I can't figure it out how to use them correctly.
I didn't get any useful results on Google or StackOverflow either.
This question is similar
What you would need in STL would be a transform_if algorithm. Then you would have to write:
transform_if (mymap.begin(), mymap.end(),
back_inserter(myvec),
bind(&std::map<First, Second>::value_type::second, _1) ,
(bind(&std::map<First, Second>::value_type::first, _1) % 2) == 0 );
The code for transform_if is taken from this unrelated question and it is:
template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction f,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = f(*first);
}
return result;
}
I think there is no other way to perform both steps (transform and conditional copy) at once using STL algorithms.
You can use boost range adaptors to achieve that.
using namespace boost::adaptors;
boost::copy( map | filtered( [] (const pair<First,Second> &p)->bool {return p.first % 2 == 0;})
| transformed( [] (const pair<First,Second> &p) {return p.second;}),
std::back_inserter(mVec));