aboutsummaryrefslogtreecommitdiffhomepage
path: root/hol-light/TacticRecording/dltree.ml
diff options
context:
space:
mode:
Diffstat (limited to 'hol-light/TacticRecording/dltree.ml')
-rw-r--r--hol-light/TacticRecording/dltree.ml268
1 files changed, 268 insertions, 0 deletions
diff --git a/hol-light/TacticRecording/dltree.ml b/hol-light/TacticRecording/dltree.ml
new file mode 100644
index 00000000..e97ecd0b
--- /dev/null
+++ b/hol-light/TacticRecording/dltree.ml
@@ -0,0 +1,268 @@
+(* ========================================================================== *)
+(* DYNAMIC LOOKUP TREES (HOL Zero) *)
+(* - Library support for data storage in dynamic indexed binary trees *)
+(* *)
+(* By Mark Adams *)
+(* Copyright (c) Proof Technologies Ltd, 2008-2011 *)
+(* ========================================================================== *)
+
+
+module Dltree : Dltree_sig = struct
+
+
+(* This module provides library support for operations on dynamic lookup *)
+(* trees - self-balancing binary trees that store information on nodes *)
+(* ordered according to an index under '(<)'-comparison. *)
+
+(* This is implemented as Andersson trees (also called AA trees), that stay *)
+(* balanced within a factor of 2 - i.e. the maximum distance from root to *)
+(* leaf is no more than twice the minimum distance. This has a fairly simple *)
+(* implementation and yet is one of the most efficient forms of self- *)
+(* balancing trees. *)
+
+
+(* dltree datatype *)
+
+(* The 'dltree' datatype is a binary lookup tree datatype, where an index and *)
+(* item are held at each node, and leaves hold no information. Comparison *)
+(* between indexes is done using the polymorphic '(<)' total order relation. *)
+
+(* An integer is also held at each node and is used to keep the tree balanced *)
+(* as items are inserted/removed. This integer represents the distance from *)
+(* the node to the left-most leaf descendant of the node. Thus every left- *)
+(* branch node holds a value 1 less than its parent, and a node with a leaf *)
+(* as its left branch holds value 1. Every right-branch holds an integer *)
+(* either equal to its parent's or 1 less, and must be strictly less than its *)
+(* grandparent's. Thus the integer at a node also represents an upper bound *)
+(* of half the distance from the node to its rightmost leaf descendant, and *)
+(* thus an upper bound of half the distance from the node to any descendant. *)
+
+(* The tree is kept balanced by adjusting nodes' integers and left and right *)
+(* branches as the tree is updated. This is done by the 'skew' and 'split' *)
+(* operations. The number of nodes that need to be considered in this *)
+(* process is at most O(log n). Note that reference types are used for a *)
+(* node's branches, to save on unnecessary garbage collection that would *)
+(* otherwise result in rebuilding all ancestor nodes of all adjusted nodes *)
+(* each time a tree is updated. *)
+
+type ('a,'b) dltree0 =
+ Node of (int * ('a * 'b) * ('a,'b) dltree * ('a,'b) dltree)
+ | Leaf
+
+and ('a,'b) dltree = ('a,'b) dltree0 ref;;
+
+
+(* dltree_empty : unit -> ('a,'b) dltree *)
+(* *)
+(* Returns a fresh empty dltree. *)
+
+let dltree_empty () = ref Leaf;;
+
+
+(* dltree_reempty : ('a,'b) dltree -> unit *)
+(* *)
+(* Empties a given dltree. *)
+
+let dltree_reempty tr = (tr := Leaf);;
+
+
+(* dltree_elems : ('a,'b) dltree -> ('a * 'b) list *)
+(* *)
+(* This converts the information held in a given lookup tree into an index- *)
+(* ordered association list. *)
+
+let rec dltree_elems0 tr0 xys0 =
+ match !tr0 with
+ Node (_,xy0,tr1,tr2) -> dltree_elems0 tr1 (xy0::(dltree_elems0 tr2 xys0))
+ | Leaf -> xys0;;
+
+let dltree_elems tr = dltree_elems0 tr [];;
+
+
+(* Node destructors *)
+
+let dest_node tr0 =
+ match !tr0 with
+ Node info -> info
+ | Leaf -> failwith "dest_node: ?";;
+
+let level tr0 =
+ match !tr0 with
+ Node (l,_,_,_) -> l
+ | Leaf -> 0;;
+
+let left_branch tr0 =
+ match !tr0 with
+ Node (_,_,tr1,_) -> tr1
+ | Leaf -> failwith "left_branch: No left branch";;
+
+let right_branch tr0 =
+ match !tr0 with
+ Node (_,_,_,tr2) -> tr2
+ | Leaf -> failwith "right_branch: No right branch";;
+
+let rec leftmost_elem x tr0 =
+ match !tr0 with
+ Node (_,x0,tr1,_) -> leftmost_elem x0 tr1
+ | Leaf -> x;;
+
+let rec rightmost_elem x tr0 =
+ match !tr0 with
+ Node (_,x0,_,tr2) -> rightmost_elem x0 tr2
+ | Leaf -> x;;
+
+
+(* Tests *)
+
+let is_leaf tr0 =
+ match !tr0 with
+ Leaf -> true
+ | _ -> false;;
+
+let is_node tr0 =
+ match !tr0 with
+ Node _ -> true
+ | _ -> false;;
+
+
+(* skew *)
+
+let skew tr0 =
+ if (is_leaf tr0) or (is_leaf (left_branch tr0))
+ then ()
+ else if (level (left_branch tr0) = level tr0)
+ then let (l0,xy0,tr1,tr2) = dest_node tr0 in
+ let (l1,xy1,tr11,tr12) = dest_node tr1 in
+ (tr0 := Node (l1, xy1, tr11, ref (Node (l0,xy0,tr12,tr2))))
+ else ();;
+
+
+(* split *)
+
+let split tr0 =
+ if (is_leaf tr0) or (is_leaf (right_branch tr0))
+ then ()
+ else if (level (right_branch (right_branch tr0)) = level tr0)
+ then let (l0,xy0,tr1,tr2) = dest_node tr0 in
+ let (l2,xy2,tr21,tr22) = dest_node tr2 in
+ (tr0 := Node (l2 + 1, xy2, ref (Node (l0,xy0,tr1,tr21)), tr22))
+ else ();;
+
+
+(* dltree_insert : 'a * 'b -> ('a,'b) dltree -> unit *)
+(* *)
+(* This inserts the supplied single indexed item into a given lookup tree. *)
+(* Fails if the tree already contains an entry for the supplied index. *)
+
+let rec dltree_insert ((x,_) as xy) tr0 =
+ match !tr0 with
+ Node (_,(x0,_),tr1,tr2)
+ -> ((if (x < x0)
+ then (* Put into left branch *)
+ dltree_insert xy tr1
+ else if (x0 < x)
+ then (* Put into right branch *)
+ dltree_insert xy tr2
+ else (* Element already in tree *)
+ failwith "dltree_insert: Already in tree");
+ (* Rebalance from the node *)
+ skew tr0;
+ split tr0)
+ | Leaf
+ -> (* Put element here *)
+ (tr0 := Node (1, xy, ref Leaf, ref Leaf));;
+
+
+(* dltree_remove : 'a -> ('a,'b) dltree -> unit *)
+(* *)
+(* This removes the entry at the supplied index in a given lookup tree. *)
+(* Fails if the tree does not contain an entry for the supplied index. *)
+
+let decrease_level tr0 =
+ let (l0,xy0,tr1,tr2) = dest_node tr0 in
+ let n = 1 + min (level tr1) (level tr2) in
+ if (n < l0) && (is_node tr2)
+ then (tr0 := Node (n,xy0,tr1,tr2);
+ if (is_node tr2)
+ then let (l2,xy2,tr21,tr22) = dest_node tr2 in
+ if (n < level tr2)
+ then (tr2 := Node (n,xy2,tr21,tr22))
+ else ()
+ else ())
+ else ();;
+
+let rec dltree_remove x tr0 =
+ match !tr0 with
+ Node (l0,((x0,_) as xy0),tr1,tr2)
+ -> ((if (x < x0)
+ then (* Element should be in left branch *)
+ dltree_remove x tr1
+ else if (x0 < x)
+ then (* Element should be in right branch *)
+ dltree_remove x tr2
+ else (* Node holds element to be removed *)
+ if (is_leaf tr1) && (is_leaf tr2)
+ then (tr0 := Leaf)
+ else if (is_leaf tr1)
+ then let (x2,_) as xy2 = leftmost_elem xy0 tr2 in
+ (dltree_remove x2 tr2;
+ tr0 := Node (l0,xy2,tr1,tr2))
+ else let (x1,_) as xy1 = rightmost_elem xy0 tr1 in
+ (dltree_remove x1 tr1;
+ tr0 := Node (l0,xy1,tr1,tr2)));
+ (if (is_node tr0)
+ then (decrease_level tr0;
+ skew tr0;
+ skew tr2;
+ (if (is_node tr2) then skew (right_branch tr2)
+ else ());
+ split tr0;
+ split tr2)
+ else ()))
+ | Leaf
+ -> (* Element not in tree *)
+ failwith "dltree_remove: Not in tree";;
+
+
+(* dltree_elem : 'a -> ('a,'b) dltree -> 'a * 'b *)
+(* *)
+(* This returns the index and item held at the supplied index in a given *)
+(* lookup tree. Fails if the tree has no entry for the supplied index. *)
+
+let rec dltree_elem x0 tr =
+ match !tr with
+ Node (_, ((x,_) as xy), tr1, tr2)
+ -> if (x0 < x)
+ then dltree_elem x0 tr1
+ else if (x < x0)
+ then dltree_elem x0 tr2
+ else xy
+ | Leaf -> failwith "dltree_elem: Not in tree";;
+
+
+(* dltree_lookup : 'a -> ('a,'b) dltree -> 'b *)
+(* *)
+(* This returns the item held at the supplied index in a given lookup tree. *)
+
+let rec dltree_lookup x0 tr =
+ let (_,y) = try dltree_elem x0 tr
+ with Failure _ -> failwith "dltree_lookup: Not in tree" in
+ y;;
+
+
+(* dltree_mem : 'a -> ('a,'b) dltree -> bool *)
+(* *)
+(* This returns "true" iff the supplied index occurs in a given lookup tree. *)
+
+let rec dltree_mem x0 tr =
+ match !tr with
+ Node (_,(x,_),tr1,tr2)
+ -> if (x0 < x)
+ then dltree_mem x0 tr1
+ else if (x < x0)
+ then dltree_mem x0 tr2
+ else true
+ | Leaf -> false;;
+
+
+end;;