Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reimplemented fresh-name generation for pretty-printing.
Using red-black trees code from Twelf.
- Loading branch information
Showing
6 changed files
with
318 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
(* From Twelf *) | ||
(* Red/Black Trees *) | ||
(* Author: Frank Pfenning *) | ||
|
||
functor RedBlackTree | ||
(type key' | ||
val compare : key' * key' -> order) | ||
:> TABLE where type key = key' = | ||
struct | ||
type key = key' | ||
type 'a entry = key * 'a | ||
|
||
datatype 'a dict = | ||
Empty (* considered black *) | ||
| Red of 'a entry * 'a dict * 'a dict | ||
| Black of 'a entry * 'a dict * 'a dict | ||
|
||
type 'a Table = 'a dict ref | ||
|
||
(* Representation Invariants *) | ||
(* | ||
1. The tree is ordered: for every node Red((key1,datum1), left, right) or | ||
Black ((key1,datum1), left, right), every key in left is less than | ||
key1 and every key in right is greater than key1. | ||
2. The children of a red node are black (color invariant). | ||
3. Every path from the root to a leaf has the same number of | ||
black nodes, called the black height of the tree. | ||
*) | ||
|
||
local | ||
|
||
fun lookup dict key = | ||
let | ||
fun lk (Empty) = NONE | ||
| lk (Red tree) = lk' tree | ||
| lk (Black tree) = lk' tree | ||
and lk' ((key1, datum1), left, right) = | ||
(case compare(key,key1) | ||
of EQUAL => SOME(datum1) | ||
| LESS => lk left | ||
| GREATER => lk right) | ||
in | ||
lk dict | ||
end | ||
|
||
(* val restore_right : 'a dict -> 'a dict *) | ||
(* | ||
restore_right (Black(e,l,r)) >=> dict | ||
where (1) Black(e,l,r) is ordered, | ||
(2) Black(e,l,r) has black height n, | ||
(3) color invariant may be violated at the root of r: | ||
one of its children might be red. | ||
and dict is a re-balanced red/black tree (satisfying all invariants) | ||
and same black height n. | ||
*) | ||
fun restore_right (Black(e, Red lt, Red (rt as (_,Red _,_)))) = | ||
Red(e, Black lt, Black rt) (* re-color *) | ||
| restore_right (Black(e, Red lt, Red (rt as (_,_,Red _)))) = | ||
Red(e, Black lt, Black rt) (* re-color *) | ||
| restore_right (Black(e, l, Red(re, Red(rle, rll, rlr), rr))) = | ||
(* l is black, deep rotate *) | ||
Black(rle, Red(e, l, rll), Red(re, rlr, rr)) | ||
| restore_right (Black(e, l, Red(re, rl, rr as Red _))) = | ||
(* l is black, shallow rotate *) | ||
Black(re, Red(e, l, rl), rr) | ||
| restore_right dict = dict | ||
|
||
(* restore_left is like restore_right, except *) | ||
(* the color invariant may be violated only at the root of left child *) | ||
fun restore_left (Black(e, Red (lt as (_,Red _,_)), Red rt)) = | ||
Red(e, Black lt, Black rt) (* re-color *) | ||
| restore_left (Black(e, Red (lt as (_,_,Red _)), Red rt)) = | ||
Red(e, Black lt, Black rt) (* re-color *) | ||
| restore_left (Black(e, Red(le, ll as Red _, lr), r)) = | ||
(* r is black, shallow rotate *) | ||
Black(le, ll, Red(e, lr, r)) | ||
| restore_left (Black(e, Red(le, ll, Red(lre, lrl, lrr)), r)) = | ||
(* r is black, deep rotate *) | ||
Black(lre, Red(le, ll, lrl), Red(e, lrr, r)) | ||
| restore_left dict = dict | ||
|
||
fun insert (dict, entry as (key,datum)) = | ||
let | ||
(* val ins : 'a dict -> 'a dict inserts entry *) | ||
(* ins (Red _) may violate color invariant at root *) | ||
(* ins (Black _) or ins (Empty) will be red/black tree *) | ||
(* ins preserves black height *) | ||
fun ins (Empty) = Red(entry, Empty, Empty) | ||
| ins (Red(entry1 as (key1, datum1), left, right)) = | ||
(case compare(key,key1) | ||
of EQUAL => Red(entry, left, right) | ||
| LESS => Red(entry1, ins left, right) | ||
| GREATER => Red(entry1, left, ins right)) | ||
| ins (Black(entry1 as (key1, datum1), left, right)) = | ||
(case compare(key,key1) | ||
of EQUAL => Black(entry, left, right) | ||
| LESS => restore_left (Black(entry1, ins left, right)) | ||
| GREATER => restore_right (Black(entry1, left, ins right))) | ||
in | ||
case ins dict | ||
of Red (t as (_, Red _, _)) => Black t (* re-color *) | ||
| Red (t as (_, _, Red _)) => Black t (* re-color *) | ||
| dict => dict | ||
end | ||
|
||
(* function below from .../smlnj-lib/Util/int-redblack-set.sml *) | ||
(* Need to check and improve some time *) | ||
(* Sun Mar 13 08:22:53 2005 -fp *) | ||
|
||
(* Remove an item. Returns true if old item found, false otherwise *) | ||
local | ||
exception NotFound | ||
datatype 'a zipper | ||
= TOP | ||
| LEFTB of ('a entry * 'a dict * 'a zipper) | ||
| LEFTR of ('a entry * 'a dict * 'a zipper) | ||
| RIGHTB of ('a dict * 'a entry * 'a zipper) | ||
| RIGHTR of ('a dict * 'a entry * 'a zipper) | ||
in | ||
fun delete t key = | ||
let | ||
fun zip (TOP, t) = t | ||
| zip (LEFTB(x, b, z), a) = zip(z, Black(x, a, b)) | ||
| zip (LEFTR(x, b, z), a) = zip(z, Red(x, a, b)) | ||
| zip (RIGHTB(a, x, z), b) = zip(z, Black(x, a, b)) | ||
| zip (RIGHTR(a, x, z), b) = zip(z, Red(x, a, b)) | ||
(* bbZip propagates a black deficit up the tree until either the top | ||
* is reached, or the deficit can be covered. It returns a boolean | ||
* that is true if there is still a deficit and the zipped tree. | ||
*) | ||
fun bbZip (TOP, t) = (true, t) | ||
| bbZip (LEFTB(x, Red(y, c, d), z), a) = (* case 1L *) | ||
bbZip (LEFTR(x, c, LEFTB(y, d, z)), a) | ||
| bbZip (LEFTB(x, Black(w, Red(y, c, d), e), z), a) = (* case 3L *) | ||
bbZip (LEFTB(x, Black(y, c, Red(w, d, e)), z), a) | ||
| bbZip (LEFTR(x, Black(w, Red(y, c, d), e), z), a) = (* case 3L *) | ||
bbZip (LEFTR(x, Black(y, c, Red(w, d, e)), z), a) | ||
| bbZip (LEFTB(x, Black(y, c, Red(w, d, e)), z), a) = (* case 4L *) | ||
(false, zip (z, Black(y, Black(x, a, c), Black(w, d, e)))) | ||
| bbZip (LEFTR(x, Black(y, c, Red(w, d, e)), z), a) = (* case 4L *) | ||
(false, zip (z, Red(y, Black(x, a, c), Black(w, d, e)))) | ||
| bbZip (LEFTR(x, Black(y, c, d), z), a) = (* case 2L *) | ||
(false, zip (z, Black(x, a, Red(y, c, d)))) | ||
| bbZip (LEFTB(x, Black(y, c, d), z), a) = (* case 2L *) | ||
bbZip (z, Black(x, a, Red(y, c, d))) | ||
| bbZip (RIGHTB(Red(y, c, d), x, z), b) = (* case 1R *) | ||
bbZip (RIGHTR(d, x, RIGHTB(c, y, z)), b) | ||
| bbZip (RIGHTR(Red(y, c, d), x, z), b) = (* case 1R *) | ||
bbZip (RIGHTR(d, x, RIGHTB(c, y, z)), b) | ||
| bbZip (RIGHTB(Black(y, Red(w, c, d), e), x, z), b) = (* case 3R *) | ||
bbZip (RIGHTB(Black(w, c, Red(y, d, e)), x, z), b) | ||
| bbZip (RIGHTR(Black(y, Red(w, c, d), e), x, z), b) = (* case 3R *) | ||
bbZip (RIGHTR(Black(w, c, Red(y, d, e)), x, z), b) | ||
| bbZip (RIGHTB(Black(y, c, Red(w, d, e)), x, z), b) = (* case 4R *) | ||
(false, zip (z, Black(y, c, Black(x, Red(w, d, e), b)))) | ||
| bbZip (RIGHTR(Black(y, c, Red(w, d, e)), x, z), b) = (* case 4R *) | ||
(false, zip (z, Red(y, c, Black(w, Red(w, d, e), b)))) | ||
| bbZip (RIGHTR(Black(y, c, d), x, z), b) = (* case 2R *) | ||
(false, zip (z, Black(x, Red(y, c, d), b))) | ||
| bbZip (RIGHTB(Black(y, c, d), x, z), b) = (* case 2R *) | ||
bbZip (z, Black(x, Red(y, c, d), b)) | ||
| bbZip (z, t) = (false, zip(z, t)) | ||
fun delMin (Red(y, Empty, b), z) = (y, (false, zip(z, b))) | ||
| delMin (Black(y, Empty, b), z) = (y, bbZip(z, b)) | ||
| delMin (Black(y, a, b), z) = delMin(a, LEFTB(y, b, z)) | ||
| delMin (Red(y, a, b), z) = delMin(a, LEFTR(y, b, z)) | ||
| delMin (Empty, _) = raise Match | ||
fun joinRed (Empty, Empty, z) = zip(z, Empty) | ||
| joinRed (a, b, z) = let | ||
val (x, (needB, b')) = delMin(b, TOP) | ||
in | ||
if needB | ||
then #2(bbZip(z, Red(x, a, b'))) | ||
else zip(z, Red(x, a, b')) | ||
end | ||
fun joinBlack (a, Empty, z) = #2(bbZip(z, a)) | ||
| joinBlack (Empty, b, z) = #2(bbZip(z, b)) | ||
| joinBlack (a, b, z) = let | ||
val (x, (needB, b')) = delMin(b, TOP) | ||
in | ||
if needB | ||
then #2(bbZip(z, Black(x, a, b'))) | ||
else zip(z, Black(x, a, b')) | ||
end | ||
fun del (Empty, z) = raise NotFound | ||
| del (Black(entry1 as (key1, datum1), a, b), z) = | ||
(case compare(key,key1) | ||
of EQUAL => joinBlack (a, b, z) | ||
| LESS => del (a, LEFTB(entry1, b, z)) | ||
| GREATER => del (b, RIGHTB(a, entry1, z))) | ||
| del (Red(entry1 as (key1, datum1), a, b), z) = | ||
(case compare(key,key1) | ||
of EQUAL => joinRed (a, b, z) | ||
| LESS => del (a, LEFTR(entry1, b, z)) | ||
| GREATER => del (b, RIGHTR(a, entry1, z))) | ||
in | ||
(del(t, TOP); true) handle NotFound => false | ||
end | ||
end (* local *) | ||
|
||
(* use non-imperative version? *) | ||
fun insertShadow (dict, entry as (key,datum)) = | ||
let val oldEntry = ref NONE (* : 'a entry option ref *) | ||
fun ins (Empty) = Red(entry, Empty, Empty) | ||
| ins (Red(entry1 as (key1, datum1), left, right)) = | ||
(case compare(key,key1) | ||
of EQUAL => (oldEntry := SOME(entry1); | ||
Red(entry, left, right)) | ||
| LESS => Red(entry1, ins left, right) | ||
| GREATER => Red(entry1, left, ins right)) | ||
| ins (Black(entry1 as (key1, datum1), left, right)) = | ||
(case compare(key,key1) | ||
of EQUAL => (oldEntry := SOME(entry1); | ||
Black(entry, left, right)) | ||
| LESS => restore_left (Black(entry1, ins left, right)) | ||
| GREATER => restore_right (Black(entry1, left, ins right))) | ||
in | ||
(oldEntry := NONE; | ||
((case ins dict | ||
of Red (t as (_, Red _, _)) => Black t (* re-color *) | ||
| Red (t as (_, _, Red _)) => Black t (* re-color *) | ||
| dict => dict), | ||
!oldEntry)) | ||
end | ||
|
||
fun app f dict = | ||
let fun ap (Empty) = () | ||
| ap (Red tree) = ap' tree | ||
| ap (Black tree) = ap' tree | ||
and ap' (entry1, left, right) = | ||
(ap left; f entry1; ap right) | ||
in | ||
ap dict | ||
end | ||
|
||
in | ||
fun new (n) = ref (Empty) (* ignore size hint *) | ||
val insert = (fn table => fn entry => (table := insert (!table, entry))) | ||
val insertShadow = | ||
(fn table => fn entry => | ||
let | ||
val (dict, oldEntry) = insertShadow (!table, entry) | ||
in | ||
(table := dict; oldEntry) | ||
end) | ||
val lookup = (fn table => fn key => lookup (!table) key) | ||
val delete = (fn table => fn key => (delete (!table) key; ())) | ||
val clear = (fn table => (table := Empty)) | ||
val app = (fn f => fn table => app f (!table)) | ||
end | ||
|
||
end; (* functor RedBlackTree *) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
(* From Twelf *) | ||
(* Hash Tables *) | ||
(* Author: Frank Pfenning *) | ||
(* Modified: Roberto Virga *) | ||
|
||
(* This provides a common interface to hash tables *) | ||
(* red/black trees and similar data structures *) | ||
|
||
signature TABLE = | ||
sig | ||
type key (* parameter *) | ||
type 'a entry = key * 'a | ||
|
||
type 'a Table | ||
val new : int -> 'a Table (* size hint for some implementations *) | ||
|
||
val insert : 'a Table -> 'a entry -> unit | ||
(* insert entry, return shadowed entry if there is one *) | ||
val insertShadow : 'a Table -> 'a entry -> ('a entry) option | ||
val lookup : 'a Table -> key -> 'a option | ||
val delete : 'a Table -> key -> unit | ||
val clear : 'a Table -> unit | ||
|
||
(* Apply function to all entries in unpredictable order *) | ||
val app : ('a entry -> unit) -> 'a Table -> unit | ||
|
||
end; (* signature TABLE *) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
(* From Twelf *) | ||
|
||
structure StringRedBlackTree = | ||
RedBlackTree (type key' = string | ||
val compare = String.compare) | ||
|
||
structure IntRedBlackTree = | ||
RedBlackTree (type key' = int | ||
val compare = Int.compare) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters