Skip to content

Commit

Permalink
Checkpoint: working on a binary search tree specificaion
Browse files Browse the repository at this point in the history
  • Loading branch information
yav committed Oct 15, 2024
1 parent 7c0a52c commit 97366ef
Show file tree
Hide file tree
Showing 5 changed files with 410 additions and 0 deletions.
165 changes: 165 additions & 0 deletions src/examples/bst/bst_map.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@

#include "bst_map.h"
#include "bst_map_cn.h"


#if 0
/* Allocate a new singleton node */
struct MapNode *newNode(KEY key, VALUE value)
/*@
requires
true;
ensures
take node = Owned<struct MapNode>(return);
node.key == key;
node.value == value;
is_null(node.smaller);
is_null(node.larger);
@*/
{
struct MapNode *node = malloc_MapNode();
node->key = key;
node->value = value;
node->smaller = NULL;
node->larger = NULL;
return node;
}
#endif

#if 0
// Demonstrates a recursive traversal of a tree.
size_t count(struct MapNode const *node)
/*@
requires
take before = BST(node);
ensures
take after = BST(node);
before == after;
@*/
{
if (node == NULL) return 0;
return (size_t)1 + count(node->smaller) + count(node->larger);
}
#endif


#if 1
// A no-op function, just shows hows to traverse a tree with a loop.
void traverse(struct MapNode *node)
/*@
requires
take start = BST(node, anyKey());
ensures
take end = BST(node, anyKey());
// start == end;
@*/
{
struct MapNode *cur = node;

/*@ split_case is_null(cur); @*/
while (cur)
/*@
inv
{node} unchanged;
take focus = BSTFocus(node,cur,anyKey());
// start == unfocus(focus);
let cur_prev = cur;
@*/
{
cur = cur->smaller;
/*@ apply GoSmaller(node,cur_prev,anyKey()); @*/
}
}
#endif


#if 0
struct MapNode *findLeast(struct MapNode *p)
/*@
requires
take tree = BST(p);
ensures
take final_tree = BST(p);
tree == final_tree;
@*/
{
struct MapNode *parent = NULL;
struct MapNode *cur = p;
while(cur != NULL)
/*@
inv
{p} unchanged;
take front = BSTUpTo(cur,parent);
@*/
{
parent = cur;
cur = p->smaller;

}
return parent;
}
#endif


#if 0
/* Look for a node and its parent */
struct MapNode *findParent(struct MapNode **node, KEY key)
{
struct MapNode *parent = NULL;
struct MapNode *cur = *node;
while (cur != NULL)
{
KEY k = cur->key;
if (k == key) { *node = cur; return parent; }
parent = cur;
cur = k < key? cur->larger : cur->smaller;
}
*node = cur;
return parent;
}
#endif


#if 0
/* Create an empty set */
struct Map map_empty()
/*@ @*/
{
return (struct Map) { .root = NULL };
}
#endif

#if 0
/* Lookup a value in a map */
bool map_lookup(struct Map map, KEY key, VALUE *value) {
struct MapNode *search = map.root;
findParent(&search, key);
if (search == NULL) { return false; }
*value = search->value;
return true;
}
#endif

#if 0
/* Insert an element into a map. Overwrites previous if already present. */
void map_insert(struct Map *map, KEY key, VALUE value) {
struct MapNode *search = map->root;
struct MapNode *parent = findParent(&search, key);
if (search != NULL) {
search->value = value;
return;
}

if (parent == NULL) {
map->root = newNode(key,value);
return;
}

struct MapNode *new_node = newNode(key,value);
if (parent->key < key) {
parent->larger = new_node;
} else {
parent->smaller = new_node;
}
}
#endif
29 changes: 29 additions & 0 deletions src/examples/bst/bst_map.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef SET_H
#define SET_H
/* A set defined as binary search tree */

#include <stdbool.h>

#define KEY int
#define VALUE long

struct MapNode {
KEY key;
int ignore;
VALUE value;
struct MapNode *smaller;
struct MapNode *larger;
};

struct MapNode* malloc_MapNode();


struct Map {
struct MapNode *root;
};

struct Map map_empty();
bool map_lookup(struct Map map, KEY key, VALUE *value);


#endif // SET_H
10 changes: 10 additions & 0 deletions src/examples/bst/bst_map_cn.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <stdlib.h>
#include <assert.h>

#include "bst_map_cn.h"

struct MapNode *malloc_MapNode() {
struct MapNode *result = malloc(sizeof(struct MapNode));
assert(result != NULL);
return result;
}
153 changes: 153 additions & 0 deletions src/examples/bst/bst_map_cn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#ifndef BST_MAP_CN_H
#define BST_MAP_CN_H

#include "bst_map.h"
#include "bst_sem_cn.h"

// Specialized `malloc`
extern struct MapNode *malloc_MapNode();
/*@
spec malloc_MapNode();
requires
true;
ensures
take v = Block<struct MapNode>(return);
@*/



/*@
// *****************************************************************************
// Consuming an entire tree
// *****************************************************************************
// Semantic data stored at a node
function (NodeData) getNodeData(struct MapNode node) {
{ key: node.key, value: node.value }
}
// A binary search tree, where all keys are in the given range.
predicate BST BST(pointer root, Interval range) {
if (is_null(root)) {
return Leaf {};
} else {
take node = Owned<struct MapNode>(root);
let data = getNodeData(node);
assert(inInterval(node.key, range));
let ranges = splitInterval(node.key, range);
take smaller = BST(node.smaller, ranges.lower);
take larger = BST(node.larger, ranges.upper);
return Node { data: data, smaller: smaller, larger: larger };
}
}
// *****************************************************************************
// Focusing on a node in the tree
// *****************************************************************************
type_synonym BSTFocus = {
// Indicates if we are at a node or a leaf.
boolean at_leaf,
// Rest of the tree
BST done,
// Focused node
struct MapNode node,
BST smaller,
BST larger
}
predicate BSTFocus BSTFocus(pointer root, pointer child, Interval range) {
if (is_null(child)) {
take tree = BST(root, range);
return { at_leaf: true, done: tree,
node: default<struct MapNode>,
smaller: default<BST>,
larger: default<BST> };
} else {
take node = Owned<struct MapNode>(child);
take result = BSTNodeUpTo(root, child, node, range);
let ranges = splitInterval(node.key,result.range);
take smaller = BST(node.smaller, ranges.lower);
take larger = BST(node.larger, ranges.upper);
return { at_leaf: false, done: result.tree, node: node,
smaller: smaller, larger: larger };
}
}
// Consume parts of the tree starting at `p` until we get to `c`.
// We do not consume `c`.
// `child` is the node stored at `c`.
predicate { BST tree, Interval range }
BSTNodeUpTo(pointer p, pointer c, struct MapNode child, Interval range) {
if (ptr_eq(p,c)) {
return { tree: Leaf {}, range: range };
} else {
take parent = Owned<struct MapNode>(p);
assert(inInterval(parent.key, range));
let ranges = splitInterval(parent.key, range);
take result = BSTNodeChildUpTo(c, child, parent, ranges);
return result;
}
}
// Starting at a parent with data `data` and children `smaller` and `larger`,
// we go toward `c`, guided by its value, `target`.
predicate { BST tree, Interval range }
BSTNodeChildUpTo(pointer c, struct MapNode target, struct MapNode parent, Intervals ranges) {
if (parent.key < target.key) {
take small = BST(parent.smaller, ranges.lower);
take large = BSTNodeUpTo(parent.larger, c, target, ranges.upper);
return { tree: Node { data: getNodeData(parent), smaller: small, larger: large.tree },
range: large.range };
} else {
if (parent.key > target.key) {
take small = BSTNodeUpTo(parent.smaller, c, target, ranges.lower);
take large = BST(parent.larger, ranges.upper);
return { tree: Node { data: getNodeData(parent), smaller: small.tree, larger: large },
range: small.range };
} else {
// We should never get here, but asserting `false` is not allowed
return default<{ BST tree, Interval range }>;
}}
}
function (BST) unfocus(BSTFocus focus) {
if (focus.at_leaf) {
focus.done
} else {
let node = focus.node;
let bst = Node { data: getNodeData(node),
smaller: focus.smaller,
larger: focus.larger
};
setKey(node.key, focus.done, bst)
}
}
lemma FocusUnfocus(pointer root, pointer cur, Interval range)
requires
take x = BSTFocus(root,cur,range);
ensures
take y = BST(root,range);
unfocus(x) == y;
lemma GoSmaller(pointer root, pointer cur, Interval range)
requires
!is_null(cur);
take focus = BSTFocus(root,cur,range);
ensures
take focus_smaller = BSTFocus(root,focus.node.smaller,range);
unfocus(focus) == unfocus(focus_smaller);
@*/
#endif
Loading

0 comments on commit 97366ef

Please sign in to comment.