3 See the NOTICE file distributed with
this work
for additional information
4 regarding copyright ownership.
6 Licensed under the Apache License, Version 2.0 (the
"License");
7 you may not use
this file except in compliance with the License.
8 You may obtain a copy of the License at
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an
"AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License
for the specific language governing permissions and
16 limitations under the License.
22 Please email comments or questions to the
public Ensembl
23 developers list at <http:
25 Questions may also be sent to the Ensembl help desk at
36 Represents a node in the
mutable interval tree pure perl implementation.
42 package Bio::EnsEMBL::Utils::Tree::Interval::Mutable::Node;
46 use Scalar::Util qw(looks_like_number weaken);
47 use List::Util qw(max);
56 The tree to which the node belongs
58 Description : Constructor. Creates a
new mutable tree instance node
59 associated with the given interval
68 my $class = ref($caller) || $caller;
70 my ($tree, $interval) = @_;
71 throw 'Node constructor takes (tree, interval) as arguments'
72 unless $tree and $interval;
74 my $self = bless({ tree => $tree,
75 intervals => [ $interval ], # the array of all records with the same key
76 key => $interval->start,
77 max => $interval->end,
81 right => undef }, $class);
89 Example : my $tree = $node->root;
90 Description : Returns the tree to which the node belongs
104 Example : my $key = $node->key;
105 Description : Returns the key associated with the node
114 $self->{key} = shift
if( @_ );
122 Example : my $intervals = $node->intervals;
123 Description : Returns the intervals associated with the node
131 return shift->{intervals};
137 Description : Add an interval to the node
's set of intervals
145 push @{shift->{intervals}}, shift;
151 Description : Return the parent of the node in the tree
161 $self->{parent} = shift;
162 weaken($self->{parent});
165 return $self->{parent};
171 Description : Return the height of the node
172 Returntype : scalar, positive or 0
180 $self->{height} = shift if( @_ );
182 return $self->{height};
188 Description : Return the node's left child
197 $self->{left} = shift
if( @_ );
199 return $self->{left};
205 Description : Return the node
's right child
206 Returntype : Bio::EnsEMBL::Utils::Tree::Interval::Mutable::Node
214 $self->{right} = shift if( @_ );
216 return $self->{right};
221 Arg [1] : Bio::EnsEMBL::Utils::Interval
222 The interval to search for overlaps in the tree
223 Description : Search the node and its successors for overlapping
224 intervals with the query
225 Returntype : Arrayref of Bio::EnsEMBL::Utils::Interval
234 # if interval is to the right of the rightmost point of any interval in this node and
235 # all its children, there won't be any matches
236 return []
if $i->start > $self->{max};
240 # search left subtree
241 if ($self->left and $self->left->{max} >= $i->start) {
246 push @{$results}, @{$self->_overlapping_intervals($i)};
248 # if interval is to the left of the start of this interval, then
249 # it can't be in any child to the right
250 return $results
if $i->end < $self->key;
252 # search right subtree
253 push @{$results}, @{$self->right->search($i)}
if $self->right;
260 Arg [1] : scalar, $key
261 The key to search the node
for
262 Description : Searches
for a node by a
'key' value
270 my ($self, $key) = @_;
272 if ($self->key == $key) {
274 } elsif ($key < $self->key) {
285 The interval to insert
286 Description : Insert an interval in the node or in its successors
296 if ($i->start < $self->key) {
297 # insert into left subtree
298 unless (defined $self->left) {
300 $self->left->parent($self);
302 $self->left->insert($i);
305 # insert into right subtree
306 unless (defined $self->right) {
308 $self->right->parent($self);
310 $self->right->insert($i);
314 # update max value if needed
315 $self->{max} = $i->
end if $self->{max} < $i->end;
317 # update node's height
318 $self->_update_height;
320 # rebalance to ensure O(logn) time operations
327 The node to remove from the tree
328 Description : Remove a node from the tree
336 my ($self, $node) = @_;
340 my $parent = $self->
parent;
342 if ($node->key < $self->key) {
343 # node to be removed is in left subtree
344 return $self->left->remove($node)
if $self->left;
346 } elsif ($node->key > $self->key) {
347 # node to be removed is in right subtree
348 return $self->right->remove($node)
if $self->right;
351 if ($self->left and $self->right) {
352 # node has two children
353 my $lowest = $self->right->_lowest;
354 $self->key($lowest->key);
355 $self->{intervals} = $lowest->{intervals};
356 return $self->right->remove($self);
357 } elsif ($parent->left == $self) {
358 # one child or no child case on left side
360 $parent->left($self->right);
361 $self->right->parent($parent);
363 $parent->left($self->left);
364 $self->left->parent($parent)
if $self->left
366 $parent->_update_parents_max;
367 $parent->_update_height;
372 } elsif ($parent->right == $self) {
373 # one child or no child case on right side
375 $parent->right($self->right);
376 $self->right->parent($parent);
378 $parent->right($self->left);
379 $self->left->parent($parent)
if $self->left;
381 $parent->_update_parents_max;
382 $parent->_update_height;
390 =head1 PRIVATE METHODS
394 Not a method since code could invoke method on undefined instances, e.g. _rebalance
401 return -1 unless $node;
402 return $node->height;
407 Returns the
'smallest' node in the tree
414 return $self unless $self->left;
415 return $self->left->_lowest;
421 my $high = $self->{intervals}[0]->end;
422 map { $high = $_->end
if $high < $_->end } @{$self->{intervals}};
430 $self->height(List::Util::max $self->left?$self->left->height:0, $self->right?$self->right->height:0 + 1);
433 sub _update_parents_max {
435 # updates the max value of all the parents after inserting into already existing node, as well as
436 # removing the node completely or removing the record of an already existing node. Starts with
437 # the parent of an affected node and bubbles up to root
438 my $high = $self->_highest_end;
439 if ($self->left and $self->right) {
440 $self->{max} = max $self->left->{max}, $self->right-{max}, $high;
441 } elsif ($self->left and !$self->right) {
442 $self->{max} = max $self->left->{max}, $high;
443 } elsif (!$self->left and $self->right) {
444 $self->{max} = max $self->right->{max}, $high;
446 $self->{max} = $high;
449 $self->parent->_update_parents_max
if $self->parent;
454 Rebalances the tree
if the height value between two nodes of the same parent is greater than two.
455 There are 4 cases that can happen:
460 y T4 Right Rotate (z) x z
461 / \ - - - - - - - - -> / \ / \
469 y T4 Left Rotate (y) x T4 Right Rotate(z) y z
470 / \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
471 T1 x y T3 T1 T2 T3 T4
478 T1 y Left Rotate(z) z x
479 / \ - - - - - - - -> / \ / \
487 T1 y Right Rotate (y) T1 x Left Rotate(z) z y
488 / \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
489 x T4 T2 y T1 T2 T3 T4
498 my ($left, $right) = ($self->left, $self->right);
500 if (_height($left) - _height($right) >= 2) {
501 if (_height($left->left) >= _height($left->right)) {
503 $self->_right_rotate;
504 $self->_update_max_right_rotate;
508 $self->_right_rotate;
509 $self->_update_max_right_rotate;
511 } elsif (_height($right) - _height($left) >= 2) {
512 if (_height($right->right) >= _height($right->left)) {
515 $self->_update_max_left_rotate;
518 $right->_right_rotate;
520 $self->_update_max_left_rotate;
528 my $right = $self->right;
530 $right->parent($self->parent);
531 unless (defined $right->parent) {
532 $self->tree->root($right);
534 if ($right->parent->left == $self) {
535 $right->parent->left($right);
536 } elsif ($right->parent->right == $self) {
537 $right->parent->right($right);
541 $self->right($right->left);
542 $self->right->parent($self)
if $self->right;
545 $self->parent($right);
547 $self->_update_height;
548 $right->_update_height;
552 sub _update_max_left_rotate { # handles Right-Right
case and Right-Left
case in rebalancing AVL tree
555 # update max of left sibling (x in first case, y in second)
556 my $parent = $self->parent;
557 my $parent_right = $parent->right;
559 my $parent_right_high = $parent_right->_highest_end;
560 if (!$parent_right->left and $parent_right->right) {
561 $parent_right->{max} = max $parent_right_high, $parent_right->right->{max};
562 } elsif ($parent_right->left and !$parent_right->right) {
563 $parent_right->{max} = max $parent_right_high, $parent_right->left->{max};
564 } elsif (!$parent_right->left and !$parent_right->right) {
565 $parent_right->{max} = $parent_right_high;
567 $parent_right->{max} = max $parent_right_high, $parent_right->left->{max}, $parent_right->right->{max};
571 # update max of itself (z)
572 my $high = $self->_highest_end;
573 if (!$self->left and $self->right) {
574 $self->{max} = max $high, $self->right->{max};
575 } elsif ($self->left and !$self->right) {
576 $self->{max} = max $high, $self->left->{max};
577 } elsif (!$self->left and !$self->right) {
578 $self->{max} = $high;
580 $self->{max} = max $high, $self->left->{max}, $self->right->{max};
583 # update max of parent (y in first case, x in second)
584 $parent->{max} = max $parent->left?$parent->left->{max}:0, $parent->right?$parent->right->{max}:0, $parent->_highest_end
592 my $left = $self->left;
594 $left->parent($self->parent);
595 unless (defined $left->parent) {
596 $self->tree->root($left);
598 if ($left->parent->left == $self) {
599 $left->parent->left($left);
600 } elsif ($left->parent->right == $self) {
601 $left->parent->right($left);
605 $self->left($left->right);
606 $self->left->parent($self)
if $self->left;
609 $self->parent($left);
611 $self->_update_height;
612 $left->_update_height;
615 sub _update_max_right_rotate { # handles Left-Left
case and Left-Right
case after rebalancing AVL tree
618 # update max of left sibling (x in first case, y in second)
619 my $parent = $self->parent;
620 my $parent_left = $parent->left;
622 my $parent_left_high = $parent_left->_highest_end;
623 if (!$parent_left->left and $parent_left->right) {
624 $parent_left->{max} = max $parent_left_high, $parent_left->right->{max};
625 } elsif ($parent_left->left and !$parent_left->right) {
626 $parent_left->{max} = max $parent_left_high, $parent_left->left->{max};
627 } elsif (!$parent_left->left and !$parent_left->right) {
628 $parent_left->{max} = $parent_left_high;
630 $parent_left->{max} = max $parent_left_high, $parent_left->left->{max}, $parent_left->right->{max};
634 # update max of itself (z)
635 my $high = $self->_highest_end;
636 if (!$self->left and $self->right) {
637 $self->{max} = max $high, $self->right->{max};
638 } elsif ($self->left and !$self->right) {
639 $self->{max} = max $high, $self->left->{max};
640 } elsif (!$self->left and !$self->right) {
641 $self->{max} = $high;
643 $self->{max} = max $high, $self->left->{max}, $self->right->{max};
646 # update max of parent (y in first case, x in second)
647 $parent->{max} = max $parent->left?$parent->left->{max}:0, $parent->right?$parent->right->{max}:0, $parent->_highest_end
651 sub _overlapping_intervals {
655 if ($self->key <= $i->end and $i->start <= $self->_highest_end) {
656 # node's interval overlap: check individual intervals
657 map { push @{$results}, $_
if $i->start <= $_->end } @{$self->{intervals}}