Compare commits
2 Commits
nilmdb-1.6
...
bxinterval
Author | SHA1 | Date | |
---|---|---|---|
9b9f392d43 | |||
3c441de498 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.coverage
|
||||
*.pyc
|
@@ -1,605 +0,0 @@
|
||||
|
||||
|
||||
|
||||
// The RedBlackEntry class is an Abstract Base Class. This means that no
|
||||
// instance of the RedBlackEntry class can exist. Only classes which
|
||||
// inherit from the RedBlackEntry class can exist. Furthermore any class
|
||||
// which inherits from the RedBlackEntry class must define the member
|
||||
// function GetKey(). The Print() member function does not have to
|
||||
// be defined because a default definition exists.
|
||||
//
|
||||
// The GetKey() function should return an integer key for that entry.
|
||||
// The key for an entry should never change otherwise bad things might occur.
|
||||
|
||||
class RedBlackEntry {
|
||||
public:
|
||||
RedBlackEntry();
|
||||
virtual ~RedBlackEntry();
|
||||
virtual int GetKey() const = 0;
|
||||
virtual void Print() const;
|
||||
};
|
||||
|
||||
class RedBlackTreeNode {
|
||||
friend class RedBlackTree;
|
||||
public:
|
||||
void Print(RedBlackTreeNode*,
|
||||
RedBlackTreeNode*) const;
|
||||
RedBlackTreeNode();
|
||||
RedBlackTreeNode(RedBlackEntry *);
|
||||
RedBlackEntry * GetEntry() const;
|
||||
~RedBlackTreeNode();
|
||||
protected:
|
||||
RedBlackEntry * storedEntry;
|
||||
int key;
|
||||
int red; /* if red=0 then the node is black */
|
||||
RedBlackTreeNode * left;
|
||||
RedBlackTreeNode * right;
|
||||
RedBlackTreeNode * parent;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RedBlackTree {
|
||||
public:
|
||||
RedBlackTree();
|
||||
~RedBlackTree();
|
||||
void Print() const;
|
||||
RedBlackEntry * DeleteNode(RedBlackTreeNode *);
|
||||
RedBlackTreeNode * Insert(RedBlackEntry *);
|
||||
RedBlackTreeNode * GetPredecessorOf(RedBlackTreeNode *) const;
|
||||
RedBlackTreeNode * GetSuccessorOf(RedBlackTreeNode *) const;
|
||||
RedBlackTreeNode * Search(int key);
|
||||
TemplateStack<RedBlackTreeNode *> * Enumerate(int low, int high) ;
|
||||
void CheckAssumptions() const;
|
||||
protected:
|
||||
/* A sentinel is used for root and for nil. These sentinels are */
|
||||
/* created when RedBlackTreeCreate is caled. root->left should always */
|
||||
/* point to the node which is the root of the tree. nil points to a */
|
||||
/* node which should always be black but has aribtrary children and */
|
||||
/* parent and no key or info. The point of using these sentinels is so */
|
||||
/* that the root and nil nodes do not require special cases in the code */
|
||||
RedBlackTreeNode * root;
|
||||
RedBlackTreeNode * nil;
|
||||
void LeftRotate(RedBlackTreeNode *);
|
||||
void RightRotate(RedBlackTreeNode *);
|
||||
void TreeInsertHelp(RedBlackTreeNode *);
|
||||
void TreePrintHelper(RedBlackTreeNode *) const;
|
||||
void FixUpMaxHigh(RedBlackTreeNode *);
|
||||
void DeleteFixUp(RedBlackTreeNode *);
|
||||
};
|
||||
|
||||
const int MIN_INT=-MAX_INT;
|
||||
|
||||
RedBlackTreeNode::RedBlackTreeNode(){
|
||||
};
|
||||
|
||||
RedBlackTreeNode::RedBlackTreeNode(RedBlackEntry * newEntry)
|
||||
: storedEntry (newEntry) , key(newEntry->GetKey()) {
|
||||
};
|
||||
|
||||
RedBlackTreeNode::~RedBlackTreeNode(){
|
||||
};
|
||||
|
||||
RedBlackEntry * RedBlackTreeNode::GetEntry() const {return storedEntry;}
|
||||
|
||||
RedBlackEntry::RedBlackEntry(){
|
||||
};
|
||||
RedBlackEntry::~RedBlackEntry(){
|
||||
};
|
||||
void RedBlackEntry::Print() const {
|
||||
cout << "No Print Method defined. Using Default: " << GetKey() << endl;
|
||||
}
|
||||
|
||||
RedBlackTree::RedBlackTree()
|
||||
{
|
||||
nil = new RedBlackTreeNode;
|
||||
nil->left = nil->right = nil->parent = nil;
|
||||
nil->red = 0;
|
||||
nil->key = MIN_INT;
|
||||
nil->storedEntry = NULL;
|
||||
|
||||
root = new RedBlackTreeNode;
|
||||
root->parent = root->left = root->right = nil;
|
||||
root->key = MAX_INT;
|
||||
root->red=0;
|
||||
root->storedEntry = NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: LeftRotate */
|
||||
/**/
|
||||
/* INPUTS: the node to rotate on */
|
||||
/**/
|
||||
/* OUTPUT: None */
|
||||
/**/
|
||||
/* Modifies Input: this, x */
|
||||
/**/
|
||||
/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
|
||||
/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
|
||||
/* makes the parent of x be to the left of x, x the parent of */
|
||||
/* its parent before the rotation and fixes other pointers */
|
||||
/* accordingly. */
|
||||
/***********************************************************************/
|
||||
|
||||
void RedBlackTree::LeftRotate(RedBlackTreeNode* x) {
|
||||
RedBlackTreeNode* y;
|
||||
|
||||
/* I originally wrote this function to use the sentinel for */
|
||||
/* nil to avoid checking for nil. However this introduces a */
|
||||
/* very subtle bug because sometimes this function modifies */
|
||||
/* the parent pointer of nil. This can be a problem if a */
|
||||
/* function which calls LeftRotate also uses the nil sentinel */
|
||||
/* and expects the nil sentinel's parent pointer to be unchanged */
|
||||
/* after calling this function. For example, when DeleteFixUP */
|
||||
/* calls LeftRotate it expects the parent pointer of nil to be */
|
||||
/* unchanged. */
|
||||
|
||||
y=x->right;
|
||||
x->right=y->left;
|
||||
|
||||
if (y->left != nil) y->left->parent=x; /* used to use sentinel here */
|
||||
/* and do an unconditional assignment instead of testing for nil */
|
||||
|
||||
y->parent=x->parent;
|
||||
|
||||
/* instead of checking if x->parent is the root as in the book, we */
|
||||
/* count on the root sentinel to implicitly take care of this case */
|
||||
if( x == x->parent->left) {
|
||||
x->parent->left=y;
|
||||
} else {
|
||||
x->parent->right=y;
|
||||
}
|
||||
y->left=x;
|
||||
x->parent=y;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: RighttRotate */
|
||||
/**/
|
||||
/* INPUTS: node to rotate on */
|
||||
/**/
|
||||
/* OUTPUT: None */
|
||||
/**/
|
||||
/* Modifies Input?: this, y */
|
||||
/**/
|
||||
/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
|
||||
/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
|
||||
/* makes the parent of x be to the left of x, x the parent of */
|
||||
/* its parent before the rotation and fixes other pointers */
|
||||
/* accordingly. */
|
||||
/***********************************************************************/
|
||||
|
||||
void RedBlackTree::RightRotate(RedBlackTreeNode* y) {
|
||||
RedBlackTreeNode* x;
|
||||
|
||||
/* I originally wrote this function to use the sentinel for */
|
||||
/* nil to avoid checking for nil. However this introduces a */
|
||||
/* very subtle bug because sometimes this function modifies */
|
||||
/* the parent pointer of nil. This can be a problem if a */
|
||||
/* function which calls LeftRotate also uses the nil sentinel */
|
||||
/* and expects the nil sentinel's parent pointer to be unchanged */
|
||||
/* after calling this function. For example, when DeleteFixUP */
|
||||
/* calls LeftRotate it expects the parent pointer of nil to be */
|
||||
/* unchanged. */
|
||||
|
||||
x=y->left;
|
||||
y->left=x->right;
|
||||
|
||||
if (nil != x->right) x->right->parent=y; /*used to use sentinel here */
|
||||
/* and do an unconditional assignment instead of testing for nil */
|
||||
|
||||
/* instead of checking if x->parent is the root as in the book, we */
|
||||
/* count on the root sentinel to implicitly take care of this case */
|
||||
x->parent=y->parent;
|
||||
if( y == y->parent->left) {
|
||||
y->parent->left=x;
|
||||
} else {
|
||||
y->parent->right=x;
|
||||
}
|
||||
x->right=y;
|
||||
y->parent=x;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: TreeInsertHelp */
|
||||
/**/
|
||||
/* INPUTS: z is the node to insert */
|
||||
/**/
|
||||
/* OUTPUT: none */
|
||||
/**/
|
||||
/* Modifies Input: this, z */
|
||||
/**/
|
||||
/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */
|
||||
/* using the algorithm described in _Introduction_To_Algorithms_ */
|
||||
/* by Cormen et al. This funciton is only intended to be called */
|
||||
/* by the Insert function and not by the user */
|
||||
/***********************************************************************/
|
||||
|
||||
void RedBlackTree::TreeInsertHelp(RedBlackTreeNode* z) {
|
||||
/* This function should only be called by RedBlackTree::Insert */
|
||||
RedBlackTreeNode* x;
|
||||
RedBlackTreeNode* y;
|
||||
|
||||
z->left=z->right=nil;
|
||||
y=root;
|
||||
x=root->left;
|
||||
while( x != nil) {
|
||||
y=x;
|
||||
if ( x->key > z->key) {
|
||||
x=x->left;
|
||||
} else { /* x->key <= z->key */
|
||||
x=x->right;
|
||||
}
|
||||
}
|
||||
z->parent=y;
|
||||
if ( (y == root) ||
|
||||
(y->key > z->key) ) {
|
||||
y->left=z;
|
||||
} else {
|
||||
y->right=z;
|
||||
}
|
||||
}
|
||||
|
||||
/* Before calling InsertNode the node x should have its key set */
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: InsertNode */
|
||||
/**/
|
||||
/* INPUTS: newEntry is the entry to insert*/
|
||||
/**/
|
||||
/* OUTPUT: This function returns a pointer to the newly inserted node */
|
||||
/* which is guarunteed to be valid until this node is deleted. */
|
||||
/* What this means is if another data structure stores this */
|
||||
/* pointer then the tree does not need to be searched when this */
|
||||
/* is to be deleted. */
|
||||
/**/
|
||||
/* Modifies Input: tree */
|
||||
/**/
|
||||
/* EFFECTS: Creates a node node which contains the appropriate key and */
|
||||
/* info pointers and inserts it into the tree. */
|
||||
/***********************************************************************/
|
||||
/* jim */
|
||||
RedBlackTreeNode * RedBlackTree::Insert(RedBlackEntry * newEntry)
|
||||
{
|
||||
RedBlackTreeNode * y;
|
||||
RedBlackTreeNode * x;
|
||||
RedBlackTreeNode * newNode;
|
||||
|
||||
x = new RedBlackTreeNode(newEntry);
|
||||
TreeInsertHelp(x);
|
||||
newNode = x;
|
||||
x->red=1;
|
||||
while(x->parent->red) { /* use sentinel instead of checking for root */
|
||||
if (x->parent == x->parent->parent->left) {
|
||||
y=x->parent->parent->right;
|
||||
if (y->red) {
|
||||
x->parent->red=0;
|
||||
y->red=0;
|
||||
x->parent->parent->red=1;
|
||||
x=x->parent->parent;
|
||||
} else {
|
||||
if (x == x->parent->right) {
|
||||
x=x->parent;
|
||||
LeftRotate(x);
|
||||
}
|
||||
x->parent->red=0;
|
||||
x->parent->parent->red=1;
|
||||
RightRotate(x->parent->parent);
|
||||
}
|
||||
} else { /* case for x->parent == x->parent->parent->right */
|
||||
/* this part is just like the section above with */
|
||||
/* left and right interchanged */
|
||||
y=x->parent->parent->left;
|
||||
if (y->red) {
|
||||
x->parent->red=0;
|
||||
y->red=0;
|
||||
x->parent->parent->red=1;
|
||||
x=x->parent->parent;
|
||||
} else {
|
||||
if (x == x->parent->left) {
|
||||
x=x->parent;
|
||||
RightRotate(x);
|
||||
}
|
||||
x->parent->red=0;
|
||||
x->parent->parent->red=1;
|
||||
LeftRotate(x->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
root->left->red=0;
|
||||
return(newNode);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: GetSuccessorOf */
|
||||
/**/
|
||||
/* INPUTS: x is the node we want the succesor of */
|
||||
/**/
|
||||
/* OUTPUT: This function returns the successor of x or NULL if no */
|
||||
/* successor exists. */
|
||||
/**/
|
||||
/* Modifies Input: none */
|
||||
/**/
|
||||
/* Note: uses the algorithm in _Introduction_To_Algorithms_ */
|
||||
/***********************************************************************/
|
||||
|
||||
RedBlackTreeNode * RedBlackTree::GetSuccessorOf(RedBlackTreeNode * x) const
|
||||
{
|
||||
RedBlackTreeNode* y;
|
||||
|
||||
if (nil != (y = x->right)) { /* assignment to y is intentional */
|
||||
while(y->left != nil) { /* returns the minium of the right subtree of x */
|
||||
y=y->left;
|
||||
}
|
||||
return(y);
|
||||
} else {
|
||||
y=x->parent;
|
||||
while(x == y->right) { /* sentinel used instead of checking for nil */
|
||||
x=y;
|
||||
y=y->parent;
|
||||
}
|
||||
if (y == root) return(nil);
|
||||
return(y);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: GetPredecessorOf */
|
||||
/**/
|
||||
/* INPUTS: x is the node to get predecessor of */
|
||||
/**/
|
||||
/* OUTPUT: This function returns the predecessor of x or NULL if no */
|
||||
/* predecessor exists. */
|
||||
/**/
|
||||
/* Modifies Input: none */
|
||||
/**/
|
||||
/* Note: uses the algorithm in _Introduction_To_Algorithms_ */
|
||||
/***********************************************************************/
|
||||
|
||||
RedBlackTreeNode * RedBlackTree::GetPredecessorOf(RedBlackTreeNode * x) const {
|
||||
RedBlackTreeNode* y;
|
||||
|
||||
if (nil != (y = x->left)) { /* assignment to y is intentional */
|
||||
while(y->right != nil) { /* returns the maximum of the left subtree of x */
|
||||
y=y->right;
|
||||
}
|
||||
return(y);
|
||||
} else {
|
||||
y=x->parent;
|
||||
while(x == y->left) {
|
||||
if (y == root) return(nil);
|
||||
x=y;
|
||||
y=y->parent;
|
||||
}
|
||||
return(y);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: Print */
|
||||
/**/
|
||||
/* INPUTS: none */
|
||||
/**/
|
||||
/* OUTPUT: none */
|
||||
/**/
|
||||
/* EFFECTS: This function recursively prints the nodes of the tree */
|
||||
/* inorder. */
|
||||
/**/
|
||||
/* Modifies Input: none */
|
||||
/**/
|
||||
/* Note: This function should only be called from ITTreePrint */
|
||||
/***********************************************************************/
|
||||
|
||||
void RedBlackTreeNode::Print(RedBlackTreeNode * nil,
|
||||
RedBlackTreeNode * root) const {
|
||||
storedEntry->Print();
|
||||
printf(", key=%i ",key);
|
||||
printf(" l->key=");
|
||||
if( left == nil) printf("NULL"); else printf("%i",left->key);
|
||||
printf(" r->key=");
|
||||
if( right == nil) printf("NULL"); else printf("%i",right->key);
|
||||
printf(" p->key=");
|
||||
if( parent == root) printf("NULL"); else printf("%i",parent->key);
|
||||
printf(" red=%i\n",red);
|
||||
}
|
||||
|
||||
void RedBlackTree::TreePrintHelper( RedBlackTreeNode* x) const {
|
||||
|
||||
if (x != nil) {
|
||||
TreePrintHelper(x->left);
|
||||
x->Print(nil,root);
|
||||
TreePrintHelper(x->right);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: Print */
|
||||
/**/
|
||||
/* INPUTS: none */
|
||||
/**/
|
||||
/* OUTPUT: none */
|
||||
/**/
|
||||
/* EFFECT: This function recursively prints the nodes of the tree */
|
||||
/* inorder. */
|
||||
/**/
|
||||
/* Modifies Input: none */
|
||||
/**/
|
||||
/***********************************************************************/
|
||||
|
||||
void RedBlackTree::Print() const {
|
||||
TreePrintHelper(root->left);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: DeleteFixUp */
|
||||
/**/
|
||||
/* INPUTS: x is the child of the spliced */
|
||||
/* out node in DeleteNode. */
|
||||
/**/
|
||||
/* OUTPUT: none */
|
||||
/**/
|
||||
/* EFFECT: Performs rotations and changes colors to restore red-black */
|
||||
/* properties after a node is deleted */
|
||||
/**/
|
||||
/* Modifies Input: this, x */
|
||||
/**/
|
||||
/* The algorithm from this function is from _Introduction_To_Algorithms_ */
|
||||
/***********************************************************************/
|
||||
|
||||
void RedBlackTree::DeleteFixUp(RedBlackTreeNode* x) {
|
||||
RedBlackTreeNode * w;
|
||||
RedBlackTreeNode * rootLeft = root->left;
|
||||
|
||||
while( (!x->red) && (rootLeft != x)) {
|
||||
if (x == x->parent->left) {
|
||||
|
||||
//
|
||||
w=x->parent->right;
|
||||
if (w->red) {
|
||||
w->red=0;
|
||||
x->parent->red=1;
|
||||
LeftRotate(x->parent);
|
||||
w=x->parent->right;
|
||||
}
|
||||
if ( (!w->right->red) && (!w->left->red) ) {
|
||||
w->red=1;
|
||||
x=x->parent;
|
||||
} else {
|
||||
if (!w->right->red) {
|
||||
w->left->red=0;
|
||||
w->red=1;
|
||||
RightRotate(w);
|
||||
w=x->parent->right;
|
||||
}
|
||||
w->red=x->parent->red;
|
||||
x->parent->red=0;
|
||||
w->right->red=0;
|
||||
LeftRotate(x->parent);
|
||||
x=rootLeft; /* this is to exit while loop */
|
||||
}
|
||||
//
|
||||
|
||||
} else { /* the code below is has left and right switched from above */
|
||||
w=x->parent->left;
|
||||
if (w->red) {
|
||||
w->red=0;
|
||||
x->parent->red=1;
|
||||
RightRotate(x->parent);
|
||||
w=x->parent->left;
|
||||
}
|
||||
if ( (!w->right->red) && (!w->left->red) ) {
|
||||
w->red=1;
|
||||
x=x->parent;
|
||||
} else {
|
||||
if (!w->left->red) {
|
||||
w->right->red=0;
|
||||
w->red=1;
|
||||
LeftRotate(w);
|
||||
w=x->parent->left;
|
||||
}
|
||||
w->red=x->parent->red;
|
||||
x->parent->red=0;
|
||||
w->left->red=0;
|
||||
RightRotate(x->parent);
|
||||
x=rootLeft; /* this is to exit while loop */
|
||||
}
|
||||
}
|
||||
}
|
||||
x->red=0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: DeleteNode */
|
||||
/**/
|
||||
/* INPUTS: tree is the tree to delete node z from */
|
||||
/**/
|
||||
/* OUTPUT: returns the RedBlackEntry stored at deleted node */
|
||||
/**/
|
||||
/* EFFECT: Deletes z from tree and but don't call destructor */
|
||||
/**/
|
||||
/* Modifies Input: z */
|
||||
/**/
|
||||
/* The algorithm from this function is from _Introduction_To_Algorithms_ */
|
||||
/***********************************************************************/
|
||||
|
||||
RedBlackEntry * RedBlackTree::DeleteNode(RedBlackTreeNode * z){
|
||||
RedBlackTreeNode* y;
|
||||
RedBlackTreeNode* x;
|
||||
RedBlackEntry * returnValue = z->storedEntry;
|
||||
|
||||
y= ((z->left == nil) || (z->right == nil)) ? z : GetSuccessorOf(z);
|
||||
x= (y->left == nil) ? y->right : y->left;
|
||||
if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */
|
||||
root->left=x;
|
||||
} else {
|
||||
if (y == y->parent->left) {
|
||||
y->parent->left=x;
|
||||
} else {
|
||||
y->parent->right=x;
|
||||
}
|
||||
}
|
||||
if (y != z) { /* y should not be nil in this case */
|
||||
|
||||
/* y is the node to splice out and x is its child */
|
||||
|
||||
y->left=z->left;
|
||||
y->right=z->right;
|
||||
y->parent=z->parent;
|
||||
z->left->parent=z->right->parent=y;
|
||||
if (z == z->parent->left) {
|
||||
z->parent->left=y;
|
||||
} else {
|
||||
z->parent->right=y;
|
||||
}
|
||||
if (!(y->red)) {
|
||||
y->red = z->red;
|
||||
DeleteFixUp(x);
|
||||
} else
|
||||
y->red = z->red;
|
||||
delete z;
|
||||
} else {
|
||||
if (!(y->red)) DeleteFixUp(x);
|
||||
delete y;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* FUNCTION: Enumerate */
|
||||
/**/
|
||||
/* INPUTS: tree is the tree to look for keys between [low,high] */
|
||||
/**/
|
||||
/* OUTPUT: stack containing pointers to the nodes between [low,high] */
|
||||
/**/
|
||||
/* Modifies Input: none */
|
||||
/**/
|
||||
/* EFFECT: Returns a stack containing pointers to nodes containing */
|
||||
/* keys which in [low,high]/ */
|
||||
/**/
|
||||
/***********************************************************************/
|
||||
|
||||
TemplateStack<RedBlackTreeNode *> * RedBlackTree::Enumerate(int low,
|
||||
int high) {
|
||||
TemplateStack<RedBlackTreeNode *> * enumResultStack =
|
||||
new TemplateStack<RedBlackTreeNode *>(4);
|
||||
|
||||
RedBlackTreeNode* x=root->left;
|
||||
RedBlackTreeNode* lastBest=NULL;
|
||||
|
||||
while(nil != x) {
|
||||
if ( x->key > high ) {
|
||||
x=x->left;
|
||||
} else {
|
||||
lastBest=x;
|
||||
x=x->right;
|
||||
}
|
||||
}
|
||||
while ( (lastBest) && (low <= lastBest->key) ) {
|
||||
enumResultStack->Push(lastBest);
|
||||
lastBest=GetPredecessorOf(lastBest);
|
||||
}
|
||||
return(enumResultStack);
|
||||
}
|
@@ -1,26 +1,7 @@
|
||||
# cython: profile=False
|
||||
# This is from bx-python 554:07aca5a9f6fc (BSD licensed), modified to
|
||||
# store interval ranges as doubles rather than 32-bit integers.
|
||||
|
||||
"""
|
||||
Data structure for performing intersect queries on a set of intervals which
|
||||
preserves all information about the intervals (unlike bitset projection methods).
|
||||
|
||||
:Authors: James Taylor (james@jamestaylor.org),
|
||||
Ian Schenk (ian.schenck@gmail.com),
|
||||
Brent Pedersen (bpederse@gmail.com)
|
||||
"""
|
||||
|
||||
# Historical note:
|
||||
# This module original contained an implementation based on sorted endpoints
|
||||
# and a binary search, using an idea from Scott Schwartz and Piotr Berman.
|
||||
# Later an interval tree implementation was implemented by Ian for Galaxy's
|
||||
# join tool (see `bx.intervals.operations.quicksect.py`). This was then
|
||||
# converted to Cython by Brent, who also added support for
|
||||
# upstream/downstream/neighbor queries. This was modified by James to
|
||||
# handle half-open intervals strictly, to maintain sort order, and to
|
||||
# implement the same interface as the original Intersecter.
|
||||
|
||||
# This is based on bxintersect in bx-python 554:07aca5a9f6fc (BSD licensed);
|
||||
# modified to store interval ranges as doubles rather than 32-bit integers,
|
||||
# use fully closed intervals, support deletion, etc.
|
||||
#cython: cdivision=True
|
||||
|
||||
import operator
|
||||
@@ -194,76 +175,6 @@ cdef class IntervalNode:
|
||||
self.cright._intersect( start, end, results )
|
||||
|
||||
|
||||
cdef void _seek_left(IntervalNode self, double position, list results, int n, double max_dist):
|
||||
# we know we can bail in these 2 cases.
|
||||
if self.maxend + max_dist < position:
|
||||
return
|
||||
if self.minstart > position:
|
||||
return
|
||||
|
||||
# the ordering of these 3 blocks makes it so the results are
|
||||
# ordered nearest to farest from the query position
|
||||
if self.cright is not EmptyNode:
|
||||
self.cright._seek_left(position, results, n, max_dist)
|
||||
|
||||
if -1 < position - self.end < max_dist:
|
||||
results.append(self.interval)
|
||||
|
||||
# TODO: can these conditionals be more stringent?
|
||||
if self.cleft is not EmptyNode:
|
||||
self.cleft._seek_left(position, results, n, max_dist)
|
||||
|
||||
|
||||
|
||||
cdef void _seek_right(IntervalNode self, double position, list results, int n, double max_dist):
|
||||
# we know we can bail in these 2 cases.
|
||||
if self.maxend < position: return
|
||||
if self.minstart - max_dist > position: return
|
||||
|
||||
#print "SEEK_RIGHT:",self, self.cleft, self.maxend, self.minstart, position
|
||||
|
||||
# the ordering of these 3 blocks makes it so the results are
|
||||
# ordered nearest to farest from the query position
|
||||
if self.cleft is not EmptyNode:
|
||||
self.cleft._seek_right(position, results, n, max_dist)
|
||||
|
||||
if -1 < self.start - position < max_dist:
|
||||
results.append(self.interval)
|
||||
|
||||
if self.cright is not EmptyNode:
|
||||
self.cright._seek_right(position, results, n, max_dist)
|
||||
|
||||
|
||||
cpdef left(self, position, int n=1, double max_dist=2500):
|
||||
"""
|
||||
find n features with a start > than `position`
|
||||
f: a Interval object (or anything with an `end` attribute)
|
||||
n: the number of features to return
|
||||
max_dist: the maximum distance to look before giving up.
|
||||
"""
|
||||
cdef list results = []
|
||||
# use start - 1 becuase .left() assumes strictly left-of
|
||||
self._seek_left( position - 1, results, n, max_dist )
|
||||
if len(results) == n: return results
|
||||
r = results
|
||||
r.sort(key=operator.attrgetter('end'), reverse=True)
|
||||
return r[:n]
|
||||
|
||||
cpdef right(self, position, int n=1, double max_dist=2500):
|
||||
"""
|
||||
find n features with a end < than position
|
||||
f: a Interval object (or anything with a `start` attribute)
|
||||
n: the number of features to return
|
||||
max_dist: the maximum distance to look before giving up.
|
||||
"""
|
||||
cdef list results = []
|
||||
# use end + 1 becuase .right() assumes strictly right-of
|
||||
self._seek_right(position + 1, results, n, max_dist)
|
||||
if len(results) == n: return results
|
||||
r = results
|
||||
r.sort(key=operator.attrgetter('start'))
|
||||
return r[:n]
|
||||
|
||||
def traverse(self):
|
||||
if self.cleft is not EmptyNode:
|
||||
for node in self.cleft.traverse():
|
||||
@@ -392,6 +303,7 @@ cdef class IntervalTree:
|
||||
|
||||
# ---- Position based interfaces -----------------------------------------
|
||||
|
||||
## KEEP
|
||||
def insert( self, double start, double end, object value=None ):
|
||||
"""
|
||||
Insert the interval [start,end) associated with value `value`.
|
||||
@@ -401,8 +313,14 @@ cdef class IntervalTree:
|
||||
else:
|
||||
self.root = self.root.insert( start, end, value )
|
||||
|
||||
add = insert
|
||||
|
||||
def delete( self, double start, double end, object value=None ):
|
||||
"""
|
||||
Delete the interval [start,end) associated with value `value`.
|
||||
"""
|
||||
if self.root is None:
|
||||
self.root = IntervalNode( start, end, value )
|
||||
else:
|
||||
self.root = self.root.insert( start, end, value )
|
||||
|
||||
def find( self, start, end ):
|
||||
"""
|
||||
@@ -412,26 +330,9 @@ cdef class IntervalTree:
|
||||
return []
|
||||
return self.root.find( start, end )
|
||||
|
||||
def before( self, position, num_intervals=1, max_dist=2500 ):
|
||||
"""
|
||||
Find `num_intervals` intervals that lie before `position` and are no
|
||||
further than `max_dist` positions away
|
||||
"""
|
||||
if self.root is None:
|
||||
return []
|
||||
return self.root.left( position, num_intervals, max_dist )
|
||||
|
||||
def after( self, position, num_intervals=1, max_dist=2500 ):
|
||||
"""
|
||||
Find `num_intervals` intervals that lie after `position` and are no
|
||||
further than `max_dist` positions away
|
||||
"""
|
||||
if self.root is None:
|
||||
return []
|
||||
return self.root.right( position, num_intervals, max_dist )
|
||||
|
||||
# ---- Interval-like object based interfaces -----------------------------
|
||||
|
||||
## KEEP
|
||||
def insert_interval( self, interval ):
|
||||
"""
|
||||
Insert an "interval" like object (one with at least start and end
|
||||
@@ -439,50 +340,6 @@ cdef class IntervalTree:
|
||||
"""
|
||||
self.insert( interval.start, interval.end, interval )
|
||||
|
||||
add_interval = insert_interval
|
||||
|
||||
def before_interval( self, interval, num_intervals=1, max_dist=2500 ):
|
||||
"""
|
||||
Find `num_intervals` intervals that lie completely before `interval`
|
||||
and are no further than `max_dist` positions away
|
||||
"""
|
||||
if self.root is None:
|
||||
return []
|
||||
return self.root.left( interval.start, num_intervals, max_dist )
|
||||
|
||||
def after_interval( self, interval, num_intervals=1, max_dist=2500 ):
|
||||
"""
|
||||
Find `num_intervals` intervals that lie completely after `interval` and
|
||||
are no further than `max_dist` positions away
|
||||
"""
|
||||
if self.root is None:
|
||||
return []
|
||||
return self.root.right( interval.end, num_intervals, max_dist )
|
||||
|
||||
def upstream_of_interval( self, interval, num_intervals=1, max_dist=2500 ):
|
||||
"""
|
||||
Find `num_intervals` intervals that lie completely upstream of
|
||||
`interval` and are no further than `max_dist` positions away
|
||||
"""
|
||||
if self.root is None:
|
||||
return []
|
||||
if interval.strand == -1 or interval.strand == "-":
|
||||
return self.root.right( interval.end, num_intervals, max_dist )
|
||||
else:
|
||||
return self.root.left( interval.start, num_intervals, max_dist )
|
||||
|
||||
def downstream_of_interval( self, interval, num_intervals=1, max_dist=2500 ):
|
||||
"""
|
||||
Find `num_intervals` intervals that lie completely downstream of
|
||||
`interval` and are no further than `max_dist` positions away
|
||||
"""
|
||||
if self.root is None:
|
||||
return []
|
||||
if interval.strand == -1 or interval.strand == "-":
|
||||
return self.root.left( interval.start, num_intervals, max_dist )
|
||||
else:
|
||||
return self.root.right( interval.end, num_intervals, max_dist )
|
||||
|
||||
def traverse(self):
|
||||
"""
|
||||
iterator that traverses the tree
|
||||
|
@@ -18,7 +18,9 @@ Intervals are closed, ie. they include timestamps [start, end]
|
||||
# Fourth version is an optimized rb-tree that stores interval starts
|
||||
# and ends directly in the tree, like bxinterval did.
|
||||
|
||||
import rbtree
|
||||
# Fifth version is back to modified bxintersect...
|
||||
|
||||
import bxintersect
|
||||
|
||||
class IntervalError(Exception):
|
||||
"""Error due to interval overlap, etc"""
|
||||
@@ -128,7 +130,7 @@ class IntervalSet(object):
|
||||
"""
|
||||
'source' is an Interval or IntervalSet to add.
|
||||
"""
|
||||
self.tree = rbtree.RBTree()
|
||||
self.tree = bxinterval.IntervalTree()
|
||||
if source is not None:
|
||||
self += source
|
||||
|
||||
@@ -210,7 +212,7 @@ class IntervalSet(object):
|
||||
if self.intersects(other):
|
||||
raise IntervalError("Tried to add overlapping interval "
|
||||
"to this set")
|
||||
self.tree.insert(rbtree.RBNode(other))
|
||||
self.tree.insert_interval(other)
|
||||
else:
|
||||
for x in other:
|
||||
self.__iadd__(x)
|
||||
|
Reference in New Issue
Block a user