How do I check to see if a BST works in SML? - binary-search-tree

Heyo! I'm trying to construct a Binary Search Tree in SML, and I want to check to see if it correctly constructs a tree. I think the code I have is correct as it does compile without any errors, but without a function to check, I can't be sure. I have a provided checker in my textbook, but I don't know how to apply it to the Binary Search Tree. Here's my code:
datatype 'data tree =
Empty
| Node of 'data tree * 'data * 'data tree;
fun makeBST nil L = Empty
| makeBST (a::b) L =
let
fun insert Empty a = Node(Empty,a,Empty)
| insert (Node(left, root, right)) a =
if L(a, root) then
Node(insert left a, root, right)
else
Node(left, root, insert right a)
in
insert (makeBST b L) a
end;
And here is the checker code:
fun isintree x Empty = false
| isintree x (Node(left,y,right)) =
x = y orelse isintree x left orelse isintree x right;

That's not a very good checker, since it doesn't check the ordering of the tree, or that all the elements you added are in there, or that nothing you didn't add is there.
Let's start with verifying that the tree really is a search tree.
A binary tree is a search tree if and only if
it is empty, or
both its subtrees are search trees, and
all nodes in the left subtree are ordered before its element, and
all nodes in the right subtree are ordered after its element
In order to check whether a predicate holds for all nodes of a tree, we can use
fun all_tree Empty _ = true
| all_tree (Node (l, x, r)) pred = pred x
andalso all_tree l pred
andalso all_tree r pred
and then we can define
fun is_search_tree order Empty = true
| is_search_tree order (Node (l, x, r)) = is_search_tree order l
andalso is_search_tree order r
andalso all_tree l (fn y => order(y, x))
andalso all_tree r (fn y => order(x, y));
Next, we can check completeness by verifying that
All elements in the list are in the tree, and
all elements in the tree are in the list
Putting it all together:
(* This argument order makes this function more usable -
you're more likely to want to look up different values in
the same tree than the same value in different trees.*)
fun isintree Empty _ = false
| isintree (Node(left,y,right)) x =
x = y
orelse isintree left x
orelse isintree right x;
fun test_list order ls =
let val t = makeBST ls order
in
is_search_tree order t
andalso all_tree t (fn x => List.exists (fn y => x = y) ls)
andalso List.all (isintree t) ls
end;
Test:
- test_list op< [];
val it = true : bool
- test_list op< [1];
val it = true : bool
- test_list op< [1,2,3];
val it = true : bool
- test_list op< [3,2,1];
val it = true : bool
- test_list op> [1,2,3];
val it = true : bool
- test_list op< [1,1];
val it = false : bool
Oops. What happened?
- makeBST [1,1] op<;
val it = Node (Empty,1,Node (Empty,1,Empty)) : int tree
There are duplicates in the tree.
Fixing this left as an exercise.

After loading the program, you can try the following commands in REPL:
- val bst = makeBST [2,6,5,4,3] op <;
val bst = Node (Node (Empty,2,Empty),3,Node (Empty,4,Node #)) : int tree
- isintree 4 bst;
val it = true : bool
- isintree 5 bst;
val it = true : bool
- isintree 10 bst;
val it = false : bool

Related

What is the equivalent of propositional not equals?

I somewhat recently asked a question and resolved the issue with a some applications of the rewrite tactic. I then decided to look back at one of my other questions on code review asking for a review of my attempt to formalize Hilbert's (based on Euclid's) geometry.
From the first question, I learned there is a distinction between propositional equality and boolean equality and propositional equality. Looking back at the some of the axioms I wrote for the Hilbert plane, I utilized boolean equality extensively. Although I am not 100% sure, in light of the answer I received, I suspect that I don't want to use boolean equality.
For instance, take this axiom:
-- There exists 3 non-colinear points.
three_non_colinear_pts : (a : point ** b : point ** c : point **
(colinear a b c = False,
(a /= b) = True,
(b /= c) = True,
(a /= c) = True))
I tried rewriting it to not involve the = True:
-- There exists 3 non-colinear points.
three_non_colinear_pts : (a : point ** b : point ** c : point **
(colinear a b c = False,
(a /= b),
(b /= c),
(a /= c)))
All in all I took the code from my question on codereview removed the == and removed = True:
interface Plane line point where
-- Abstract notion for saying three points lie on the same line.
colinear : point -> point -> point -> Bool
coplanar : point -> point -> point -> Bool
contains : line -> point -> Bool
-- Intersection between two lines
intersects_at : line -> line -> point -> Bool
-- If two lines l and m contain a point a, they intersect at that point.
intersection_criterion : (l : line) ->
(m : line) ->
(a : point) ->
(contains l a = True) ->
(contains m a = True) ->
(intersects_at l m a = True)
-- If l and m intersect at a point a, then they both contain a.
intersection_result : (l : line) ->
(m : line) ->
(a : point) ->
(intersects_at l m a = True) ->
(contains l a = True, contains m a = True)
-- For any two distinct points there is a line that contains them.
line_contains_two_points : (a :point) ->
(b : point) ->
(a /= b) ->
(l : line ** (contains l a = True, contains l b = True ))
-- If two points are contained by l and m then l = m
two_pts_define_line : (l : line) ->
(m : line) ->
(a : point) ->
(b : point) ->
(a /= b) ->
contains l a = True ->
contains l b = True ->
contains m a = True ->
contains m b = True ->
(l = m)
same_line_same_pts : (l : line) ->
(m : line) ->
(a : point) ->
(b : point) ->
(l /= m) ->
contains l a = True ->
contains l b = True ->
contains m a = True ->
contains m b = True ->
(a = b)
-- There exists 3 non-colinear points.
three_non_colinear_pts : (a : point ** b : point ** c : point **
(colinear a b c = False,
(a /= b),
(b /= c),
(a /= c)))
-- Any line contains at least two points.
contain_two_pts : (l : line) ->
(a : point ** b : point **
(contains l a = True, contains l b = True))
-- If two lines intersect at a point and they are not identical, that is the o-
-- nly point they intersect at.
intersect_at_most_one_point : Plane line point =>
(l : line) -> (m : line) -> (a : point) -> (b : point) ->
(l /= m) ->
(intersects_at l m a = True) ->
(intersects_at l m b = True) ->
(a = b)
intersect_at_most_one_point l m a b l_not_m int_at_a int_at_b =
same_line_same_pts
l
m
a
b
l_not_m
(fst (intersection_result l m a int_at_a))
(fst (intersection_result l m b int_at_b))
(snd (intersection_result l m a int_at_a))
(snd (intersection_result l m b int_at_b))
This gives the error:
|
1 | interface Plane line point where
| ~~~~~~~~~~~~~~~~
When checking type of Main.line_contains_two_points:
Type mismatch between
Bool (Type of _ /= _)
and
Type (Expected type)
/home/dair/scratch/hilbert.idr:68:29:
|
68 | intersect_at_most_one_point : Plane line point =>
| ^
When checking type of Main.intersect_at_most_one_point:
No such variable Plane
So, it seems that /= works only for boolean. I have been unable to find a "propositional" /= like:
data (/=) : a -> b -> Type where
Does a propositional not equals exist? Or am I wrong about wanting to change from boolean to propositional equality?
The propositional equivalent to the boolean a /= b would be a = b -> Void. Void is a type with no constructors. So whenever you have a contra : Void, something has gone wrong. So a = b -> Void is to understand as: if you have an a = b, there is a contradiction. Usually written as Not (a = b), which is just a shorthand (Not a = a -> Void).
You're right to change to propositional equality. You might even change your boolean properties like contains : line -> point -> Bool to Contains : line -> point -> Type. Subsequently contains l p = True to Contains l p, and contains l p = False to Not (Contains l p).
That's a case of boolean blindness, i.e. with prf : contains l p = True, the only thing we know is that contains l p is True (and the compiler would need to take a look at contains to guess why it is True). On the other hand, with prf : Contains l p you have a constructed proof prf why the proposition Contains l p holds.

How can I go about creating distinct variables in Idris?

I am trying to reconstruct the axioms for Hilbert's geometry in Idris. I came up with the following code to represent his axioms:
interface (Eq point) => Plane line point where
colinear : point -> point -> point -> Bool
contains : line -> point -> point -> Bool
axiom1a : (a,b : point) -> (a /= b) = True -> (l : line ** (contains l a b = True))
axiom1b : contains l a b = True -> contains m a b = True -> l = m
axiom2 : (a : point ** (colinear a b c = False) && (a /= b) = True && (b /= c) = True && (a /= c) = True)
axiom3 : (l : line) -> (a ** (contains l a b = True))
axiom2 should read "There exists 3 distinct non-colinear points." I get the following error:
When checking type of Main.axiom2:
When checking argument P to type constructor Builtins.DPair:
Type mismatch between
Bool (Type of _ && _)
and
Type (Expected type)
If I remove && (a /= b) = True && (b /= c) = True && (a /= c) = True the code runs but then the qualification of "distinct" in the axiom is lost. Any help would be appreciated.
colinear a b c = False is a Type, not a Bool. Likewise for (a /= b) = True, (b /= c) = True, and (a /= c) = True.
Instead of using &&, you must use a "type-level &&", i.e. a tuple.
axiom2 : (a : point ** (colinear a b c = False, (a /= b) = True, (b /= c) = True, (a /= c) = True))
However, that would read "There exists a point a that is not colinear with any two other distinct points", which is not always the case. You could instead write this:
axiom2 : (a : point ** (b : point ** (c : point ** (colinear a b c = False, (a /= b) = True, (b /= c) = True, (a /= c) = True))))
That would read "There exist three distinct points that are not colinear". I'm not sure if it's possible to make that any nicer to look at, like (a, b, c : point ** ....

Changing a mutable field in OCaml

When I run the following code I get a syntax error, although as far as I can tell the syntax is correct. This attempts to implement a queue structure, where the function from_list converts a list to a queue with the corresponding values. I wrote str_of_int_q to print the contents of a queue. x and y are supposed to be two nodes, with x at the head and y at the tail.
;; open Assert
type 'a qnode = {v: 'a;
mutable next: 'a qnode option}
type 'a queue = {mutable head: 'a qnode option;
mutable tail: 'a qnode option}
let from_list (l: 'a list) : 'a queue =
let rec loop (l2: 'a list) (qu: 'a queue) =
begin match l2 with
| [] -> qu
| [x] -> let y = {v = x; next = None} in
qu.head <- Some y; qu.tail <- Some y;
qu
| h1::h2::t -> let y = qu.head in
let z = {v = h1; next = y} in
qu.head <- Some z;
qu
end
in loop l {head = None; tail = None}
let str_of_int_q (q: int queue) : string =
let rec loop (r: int qnode option) (s: string) : string =
begin match r with
| None -> s
| Some n -> loop n.next (s ^ (string_of_int n.v))
end
in loop q.head ""
let x = {v = 1; next = None}
let y = {v = 2; next = None}
x.next <- Some y;
let z = {head = Some x; tail = Some y}
;; print_endline (str_of_int_q z)
My error:
line 32, characters 7-9:
Error: Syntax error
Line 32 is the line x.next <- Some y; and characters 7-9 indicate the <-. But I'm storing into a mutable field an object of the appropriate type, so I don't see what's going wrong.
Top-level statements are separated by ;; in OCaml. However, ;; is optional before several keywords, such as let, open, type, etc. This is why you don't need ;; most of the time.
In your case, ;; is needed to disambiguate between let y = {v = 2; next = None} and x.next <- Some y. The latter is an expression and doesn't start with a special keyword, so OCaml doesn't know to insert an implicit ;; here.
See also http://ocaml.org/learn/tutorials/structure_of_ocaml_programs.html#The-disappearance-of.
As explained there, you can either do
let y = {v = 2; next = None}
;; x.next <- Some y
or
let y = {v = 2; next = None}
let () = x.next <- Some y
This latter solution works because by introducing a dummy binding we're starting our statement with let, which disambiguates again.
Note: I've also removed the trailing ; from your code. ; is actually an infix operator that combines two expressions (by throwing the result of the first one away and returning the result of the second one). This is not what you want here.

How to prove that the boolean inequality of a type with itself is uninhabited in Idris?

I was wondering how to prove that (So (not (y == y))) is an instance of Uninhabited, and I'm not sure how to go about it. Is it provable in Idris, or is not provable due to the possibility of a weird Eq implementation for y?
The Eq interface does not require an implementation to follow the normal laws of equality. But, we can define an extended LawfulEq interface which does:
%default total
is_reflexive : (t -> t -> Bool) -> Type
is_reflexive {t} rel = (x : t) -> rel x x = True
is_symmetric : (t -> t -> Bool) -> Type
is_symmetric {t} rel = (x : t) -> (y : t) -> rel x y = rel y x
is_transitive : (t -> t -> Bool) -> Type
is_transitive {t} rel = (x : t) -> (y : t) -> (z : t) -> rel x y = True -> rel x z = rel y z
interface Eq t => LawfulEq t where
eq_is_reflexive : is_reflexive {t} (==)
eq_is_symmetric : is_symmetric {t} (==)
eq_is_transitive : is_transitive {t} (==)
The result asked for in the question can be proved for type Bool:
so_false_is_void : So False -> Void
so_false_is_void Oh impossible
so_not_y_eq_y_is_void : (y : Bool) -> So (not (y == y)) -> Void
so_not_y_eq_y_is_void False = so_false_is_void
so_not_y_eq_y_is_void True = so_false_is_void
The result can be proved not true for the following Weird type:
data Weird = W
Eq Weird where
W == W = False
weird_so_not_y_eq_y : (y : Weird) -> So (not (y == y))
weird_so_not_y_eq_y W = Oh
The Weird (==) can be shown to be not reflexive, so an implementation of LawfulEq Weird is not possible:
weird_eq_not_reflexive : is_reflexive {t=Weird} (==) -> Void
weird_eq_not_reflexive is_reflexive_eq =
let w_eq_w_is_true = is_reflexive_eq W in
trueNotFalse $ trans (sym w_eq_w_is_true) (the (W == W = False) Refl)
Shersh is right: you can't. Implementations of (==) aren't guaranteed to be reflexive, so it might not be true.
You could restrict the type of y so that you are proving a property of a specific implementation of (==), but I suspect you want to use decEq and (=) instead of So and (==). It's easy to show Not (y = y) is uninhabited.

F# Code Optimization for Left Leaning Red Black Tree

I've been working on porting a C# implementation of a LLRBT to F# and I now have it running correctly. My question is how would I go about optimizing this?
Some ideas I have
Using a Discriminated Union for Node to remove the use of null
Remove getters and setters
you cant have a null attribute and a struct at the same time
Full source can be found here. C# code taken from Delay's Blog.
Current performance
F# Elapsed = 00:00:01.1379927 Height: 26, Count: 487837
C# Elapsed = 00:00:00.7975849 Height: 26, Count: 487837
module Erik
let Black = true
let Red = false
[<AllowNullLiteralAttribute>]
type Node(_key, _value, _left:Node, _right:Node, _color:bool) =
let mutable key = _key
let mutable value = _value
let mutable left = _left
let mutable right = _right
let mutable color = _color
let mutable siblings = 0
member this.Key with get() = key and set(x) = key <- x
member this.Value with get() = value and set(x) = value <- x
member this.Left with get() = left and set(x) = left <- x
member this.Right with get() = right and set(x) = right <- x
member this.Color with get() = color and set(x) = color <- x
member this.Siblings with get() = siblings and set(x) = siblings <- x
static member inline IsRed(node : Node) =
if node = null then
// "Virtual" leaf nodes are always black
false
else
node.Color = Red
static member inline Flip(node : Node) =
node.Color <- not node.Color
node.Right.Color <- not node.Right.Color
node.Left.Color <- not node.Left.Color
static member inline RotateLeft(node : Node) =
let x = node.Right
node.Right <- x.Left
x.Left <- node
x.Color <- node.Color
node.Color <- Red
x
static member inline RotateRight(node : Node) =
let x = node.Left
node.Left <- x.Right
x.Right <- node
x.Color <- node.Color
node.Color <- Red
x
static member inline MoveRedLeft(_node : Node) =
let mutable node = _node
Node.Flip(node)
if Node.IsRed(node.Right.Left) then
node.Right <- Node.RotateRight(node.Right)
node <- Node.RotateLeft(node)
Node.Flip(node)
if Node.IsRed(node.Right.Right) then
node.Right <- Node.RotateLeft(node.Right)
node
static member inline MoveRedRight(_node : Node) =
let mutable node = _node
Node.Flip(node)
if Node.IsRed(node.Left.Left) then
node <- Node.RotateRight(node)
Node.Flip(node)
node
static member DeleteMinimum(_node : Node) =
let mutable node = _node
if node.Left = null then
null
else
if not(Node.IsRed(node.Left)) && not(Node.IsRed(node.Left.Left)) then
node <- Node.MoveRedLeft(node)
node.Left <- Node.DeleteMinimum(node)
Node.FixUp(node)
static member FixUp(_node : Node) =
let mutable node = _node
if Node.IsRed(node.Right) then
node <- Node.RotateLeft(node)
if Node.IsRed(node.Left) && Node.IsRed(node.Left.Left) then
node <- Node.RotateRight(node)
if Node.IsRed(node.Left) && Node.IsRed(node.Right) then
Node.Flip(node)
if node.Left <> null && Node.IsRed(node.Left.Right) && not(Node.IsRed(node.Left.Left)) then
node.Left <- Node.RotateLeft(node.Left)
if Node.IsRed(node.Left) then
node <- Node.RotateRight(node)
node
type LeftLeaningRedBlackTree(?isMultiDictionary) =
let mutable root = null
let mutable count = 0
member this.IsMultiDictionary =
Option.isSome isMultiDictionary
member this.KeyAndValueComparison(leftKey, leftValue, rightKey, rightValue) =
let comparison = leftKey - rightKey
if comparison = 0 && this.IsMultiDictionary then
leftValue - rightValue
else
comparison
member this.Add(key, value) =
root <- this.add(root, key, value)
member private this.add(_node : Node, key, value) =
let mutable node = _node
if node = null then
count <- count + 1
new Node(key, value, null, null, Red)
else
if Node.IsRed(node.Left) && Node.IsRed(node.Right) then
Node.Flip(node)
let comparison = this.KeyAndValueComparison(key, value, node.Key, node.Value)
if comparison < 0 then
node.Left <- this.add(node.Left, key, value)
elif comparison > 0 then
node.Right <- this.add(node.Right, key, value)
else
if this.IsMultiDictionary then
node.Siblings <- node.Siblings + 1
count <- count + 1
else
node.Value <- value
if Node.IsRed(node.Right) then
node <- Node.RotateLeft(node)
if Node.IsRed(node.Left) && Node.IsRed(node.Left.Left) then
node <- Node.RotateRight(node)
node
I'm surprised there's such a perf difference, since this looks like a straightforward transliteration. I presume both are compiled in 'Release' mode? Did you run both separately (cold start), or if both versions in the same program, reverse the order of the two (e.g. warm cache)? Done any profiling (have a good profiler)? Compared memory consumption (even fsi.exe can help with that)?
(I don't see any obvious improvements to be had for this mutable data structure implementation.)
I wrote an immutable version and it's performing better than the above mutable one. I've only implemented insert so far. I'm still trying to figure out what the performance issues are.
type ILLRBT =
| Red of ILLRBT * int * ILLRBT
| Black of ILLRBT * int * ILLRBT
| Nil
let flip node =
let inline flip node =
match node with
| Red(l, v, r) -> Black(l, v, r)
| Black(l, v, r) -> Red(l, v, r)
| Nil -> Nil
match node with
| Red(l, v, r) -> Black(flip l, v, flip r)
| Black(l, v, r) -> Red(flip l, v, flip r)
| Nil -> Nil
let lRot = function
| Red(l, v, Red(l', v', r'))
| Red(l, v, Black(l', v', r')) -> Red(Red(l, v, l'), v', r')
| Black(l, v, Red(l', v', r'))
| Black(l, v, Black(l', v', r')) -> Black(Red(l, v, l'), v', r')
| _ -> Nil // could raise an error here
let rRot = function
| Red( Red(l', v', r'), v, r)
| Red(Black(l', v', r'), v, r) -> Red(l', v', Red(r', v, r))
| Black( Red(l', v', r'), v, r)
| Black(Black(l', v', r'), v, r) -> Black(l', v', Red(r', v, r))
| _ -> Nil // could raise an error here
let rec insert node value =
match node with
| Nil -> Red(Nil, value, Nil)
| n ->
n
|> function
| Red(Red(_), v, Red(_))
| Black(Red(_), v, Red(_)) as node -> flip node
| x -> x
|> function
| Red(l, v, r) when value < v -> Red(insert l value, v, r)
| Black(l, v, r) when value < v -> Black(insert l value, v, r)
| Red(l, v, r) when value > v -> Red(l, v, insert r value)
| Black(l, v, r) when value > v -> Black(l, v, insert r value)
| x -> x
|> function
| Red(l, v, Red(_))
| Black(l, v, Red(_)) as node -> lRot node
| x -> x
|> function
| Red(Red(Red(_),_,_), v, r)
| Black(Red(Red(_),_,_), v, r) as node -> rRot node
| x -> x
let rec iter node =
seq {
match node with
| Red(l, v, r)
| Black(l, v, r) ->
yield! iter l
yield v
yield! iter r
| Nil -> ()
}
If you're willing to consider an immutable implementation, you might want to look at Chris Okasaki's paper on red-black trees in a functional setting here.
My question is how would I go about optimizing this?
In the mutable case you should be able to get substantially better performance by using an array of Node structs rather than heap allocating each individual Node. In the immutable case you might try turning the red nodes into structs.