git-svn-id: https://bucket.mit.edu/svn/nilm/nilmdb@11380 ddd99763-3ecb-0310-9145-efcb8ce7c51ftags/bxinterval-return
@@ -581,7 +581,6 @@ RedBlackEntry * RedBlackTree::DeleteNode(RedBlackTreeNode * z){ | |||
/**/ | |||
/***********************************************************************/ | |||
/* | |||
TemplateStack<RedBlackTreeNode *> * RedBlackTree::Enumerate(int low, | |||
int high) { | |||
TemplateStack<RedBlackTreeNode *> * enumResultStack = | |||
@@ -604,4 +603,3 @@ TemplateStack<RedBlackTreeNode *> * RedBlackTree::Enumerate(int low, | |||
} | |||
return(enumResultStack); | |||
} | |||
*/ |
@@ -221,7 +221,10 @@ class IntervalSet(object): | |||
Removes an interval from the set. Must exist exactly | |||
as provided -- cannot remove a subset of an existing interval.""" | |||
self.tree.delete(rbtree.RBNode(other)) | |||
i = self.tree.find(other.start, other.end) | |||
if i is None: | |||
raise IntervalError("interval " + str(other) + " not in tree") | |||
self.tree.delete(i) | |||
return self | |||
def __add__(self, other): | |||
@@ -240,16 +243,16 @@ class IntervalSet(object): | |||
out = IntervalSet() | |||
if not isinstance(other, IntervalSet): | |||
other = [ other ] | |||
for x in other: | |||
for i in self.intersection(x): | |||
for i in self.intersection(other): | |||
out.tree.insert(rbtree.RBNode(i)) | |||
else: | |||
for x in other: | |||
for i in self.intersection(x): | |||
out.tree.insert(rbtree.RBNode(i)) | |||
return out | |||
def intersection(self, interval): | |||
### PROBABLY WRONG | |||
""" | |||
Compute a sequence of intervals that correspond to the | |||
intersection between `self` and the provided interval. | |||
@@ -261,11 +264,10 @@ class IntervalSet(object): | |||
""" | |||
if not isinstance(interval, Interval): | |||
raise TypeError("bad type") | |||
node = self.tree.find_left(interval.start, interval.end) | |||
for n in self.tree.inorder(node): | |||
for n in self.tree.intersect(interval.start, interval.end): | |||
i = n.obj | |||
if i: | |||
if i.start > interval.start and i.end < interval.end: | |||
if i.start >= interval.start and i.end <= interval.end: | |||
yield i | |||
elif i.start > interval.end: | |||
break | |||
@@ -286,7 +286,9 @@ class RBTree(object): | |||
def render_dot(self, title = "RBTree"): | |||
"""Render the entire RBTree as a dot graph""" | |||
return "digraph rbtree {\n" + self.__render_dot_node(self.root) + "}\n"; | |||
return ("digraph rbtree {\n" | |||
+ self.__render_dot_node(self.root.left) | |||
+ "}\n"); | |||
def render_dot_live(self, title = "RBTree"): | |||
"""Render the entire RBTree as a dot graph, live GTK view""" | |||
@@ -295,7 +297,9 @@ class RBTree(object): | |||
sys.path.append("/usr/share/xdot") | |||
import xdot | |||
xdot.Pen.highlighted = lambda pen: pen | |||
s = "digraph rbtree {\n" + self.__render_dot_node(self.root) + "}\n"; | |||
s = ("digraph rbtree {\n" | |||
+ self.__render_dot_node(self.root) | |||
+ "}\n"); | |||
window = xdot.DotWindow() | |||
window.set_dotcode(s) | |||
window.set_title(title + " - any key to close") | |||
@@ -309,13 +313,13 @@ class RBTree(object): | |||
# Walking, searching | |||
def __iter__(self): | |||
return self.inorder(self.root) | |||
return self.inorder(self.root.left) | |||
def inorder(self, x = None): | |||
"""Generator that performs an inorder walk for the tree | |||
starting at RBNode x""" | |||
if x is None: | |||
x = self.root | |||
x = self.root.left | |||
while x.left is not self.nil: | |||
x = x.left | |||
while x is not self.nil: | |||
@@ -327,7 +331,7 @@ class RBTree(object): | |||
Also returns the largest node less than or equal to key, | |||
and the smallest node greater or equal to than key.""" | |||
if x is None: | |||
x = self.root | |||
x = self.root.left | |||
largest = self.nil | |||
smallest = self.nil | |||
while x is not self.nil: | |||
@@ -364,3 +368,25 @@ class RBTree(object): | |||
"""Find node with the largest key <= (start,end), or None""" | |||
y = self.__find_all(start, end, x)[2] | |||
return y if y is not self.nil else None | |||
# Intersections | |||
def intersect(self, start, end): | |||
"""Generator that returns nodes that overlap the given | |||
(start,end) range, for the tree rooted at RBNode x. | |||
NOTE: this assumes non-overlapping intervals.""" | |||
# Start with the leftmost node before the starting point | |||
n = self.find_left(start, start) | |||
# If we didn't find one, look for the leftmode node before the | |||
# ending point instead. | |||
if n is None: | |||
n = self.find_left(end, end) | |||
# If we still didn't find it, there are no intervals that intersect. | |||
if n is None: | |||
return none | |||
# Now yield this node and all successors until their endpoints | |||
if False: | |||
yield | |||
return |
@@ -2,7 +2,7 @@ | |||
# note: the value doesn't matter, that's why they're empty here | |||
nocapture= | |||
nologcapture= # comment to see cherrypy logs on failure | |||
#with-coverage= | |||
with-coverage= | |||
cover-inclusive= | |||
cover-package=nilmdb | |||
cover-erase= | |||
@@ -12,8 +12,8 @@ stop= | |||
verbosity=2 | |||
#tests=tests/test_cmdline.py | |||
#tests=tests/test_layout.py | |||
tests=tests/test_rbtree.py | |||
#tests=tests/test_interval.py | |||
#tests=tests/test_rbtree.py | |||
tests=tests/test_interval.py | |||
#tests=tests/test_client.py | |||
#tests=tests/test_timestamper.py | |||
#tests=tests/test_serializer.py | |||
@@ -200,6 +200,10 @@ class TestInterval: | |||
makeset(" [-----] ") == | |||
makeset(" [--] ")) | |||
assert(makeset(" [--] [--]") & | |||
makeset(" [------] ") == | |||
makeset(" [-] [-] ")) | |||
assert(makeset(" [---]") & | |||
makeset(" [--] ") == | |||
makeset(" ")) | |||
@@ -265,9 +269,10 @@ class TestIntervalDB: | |||
class TestIntervalTree: | |||
#@unittest.skip("needs GTK") | |||
def test_interval_tree(self): | |||
import random | |||
random.seed(1234) | |||
# make a set of 500 intervals | |||
iset = IntervalSet() | |||
j = 500 | |||
@@ -280,8 +285,13 @@ class TestIntervalTree: | |||
if random.randint(0,1): | |||
iset -= Interval(i, i+1) | |||
# try removing an interval that doesn't exist | |||
with assert_raises(IntervalError): | |||
iset -= Interval(1234,5678) | |||
# show the graph | |||
iset.tree.render_dot_live() | |||
if False: | |||
iset.tree.render_dot_live() | |||
class TestIntervalSpeed: | |||
@unittest.skip("this is slow") | |||
@@ -11,6 +11,8 @@ from nilmdb.rbtree import RBTree, RBNode | |||
from test_helpers import * | |||
import unittest | |||
render = False | |||
class TestRBTree: | |||
def test_rbtree(self): | |||
rb = RBTree() | |||
@@ -22,7 +24,6 @@ class TestRBTree: | |||
# Verify that the dot isn't too big. | |||
assert(len(s.splitlines()) < 30) | |||
#@unittest.skip("needs GTK") | |||
def test_rbtree_big(self): | |||
import random | |||
random.seed(1234) | |||
@@ -34,7 +35,8 @@ class TestRBTree: | |||
rb.insert(RBNode(None, i, i+1)) | |||
# show the graph | |||
rb.render_dot_live("in-order insert") | |||
if render: | |||
rb.render_dot_live("in-order insert") | |||
# remove about half of them | |||
for i in random.sample(xrange(j),j): | |||
@@ -42,7 +44,8 @@ class TestRBTree: | |||
rb.delete(rb.find(i, i+1)) | |||
# show the graph | |||
rb.render_dot_live("in-order insert, random delete") | |||
if render: | |||
rb.render_dot_live("in-order insert, random delete") | |||
# make a set of 500 intervals, inserted at random | |||
rb = RBTree() | |||
@@ -51,7 +54,8 @@ class TestRBTree: | |||
rb.insert(RBNode(None, i, i+1)) | |||
# show the graph | |||
rb.render_dot_live("random insert") | |||
if render: | |||
rb.render_dot_live("random insert") | |||
# remove about half of them | |||
for i in random.sample(xrange(j),j): | |||
@@ -59,11 +63,13 @@ class TestRBTree: | |||
rb.delete(rb.find(i, i+1)) | |||
# show the graph | |||
rb.render_dot_live("random insert, random delete") | |||
if render: | |||
rb.render_dot_live("random insert, random delete") | |||
# in-order insert of 250 more | |||
for i in xrange(250): | |||
rb.insert(RBNode(None, i+500, i+501)) | |||
# show the graph | |||
rb.render_dot_live("random insert, random delete, in-order insert") | |||
if render: | |||
rb.render_dot_live("random insert, random delete, in-order insert") |