Bio-EnsEMBL

 view release on metacpan or  search on metacpan

lib/Bio/EnsEMBL/Utils/Tree/Interval/Immutable.pm  view on Meta::CPAN

      last;
    }
    if ($interval->is_left_of($node->x_center)) {
      foreach my $s_beg (@{$node->s_center_beg}) {
	last unless $interval->intersects($s_beg);
	push @{$result}, $s_beg;
      }
      $node = $node->left;
    } else {
      foreach my $s_end (@{$node->s_center_end}) {
	last unless $interval->intersects($s_end);
	push @{$result}, $s_end;
      }
      $node = $node->right;
    }
  }

  return sort_by_begin(uniq($result));
}

sub _query_point {
  my ($self, $node, $point, $result) = @_;

  return $result unless $node;

  # if x is less than x_center, the leftmost set of intervals, S_left, is considered
  if ($point <= $node->x_center) {
    # if x is less than x_center, we know that all intervals in S_center end after x,
    # or they could not also overlap x_center. Therefore, we need only find those intervals
    # in S_center that begin before x. We can consult the lists of S_center that have already
    # been constructed. Since we only care about the interval beginnings in this scenario,
    # we can consult the list sorted by beginnings.
    # Suppose we find the closest number no greater than x in this list. All ranges from the
    # beginning of the list to that found point overlap x because they begin before x and end
    # after x (as we know because they overlap x_center which is larger than x).
    # Thus, we can simply start enumerating intervals in the list until the startpoint value exceeds x.
    foreach my $s_beg (@{$node->s_center_beg}) {
      last if $s_beg->is_right_of($point);
      push @{$result}, $s_beg;
    }

    # since x < x_center, we also consider the leftmost set of intervals
    return $self->_query_point($node->left, $point, $result);
  } else {
    # if x is greater than x_center, we know that all intervals in S_center must begin before x,
    # so we find those intervals that end after x using the list sorted by interval endings.
    foreach my $s_end (@{$node->s_center_end}) {
      last if $s_end->is_left_of($point);
      push @{$result}, $s_end;
    }
    
    # since x > x_center, we also consider the rightmost set of intervals
    return $self->_query_point($node->right, $point, $result);
  }
  
  return sort_by_begin(uniq($result));
}

# This corresponds to the left branch of the range search, once we find a node, whose
# midpoint is contained in the query interval. All intervals in the left subtree of that node
# are guaranteed to intersect with the query, if they have an endpoint greater or equal than
# the start of the query interval. Basically, this means that every time we branch to the left
# in the binary search, we need to add the whole right subtree to the result set.

sub _range_query_left {
  my ($self, $node, $interval, $result) = @_;
  
  while ($node) {
    if ($interval->contains($node->x_center)) {
      push @{$result}, @{$node->s_center_beg};
      if ($node->right) {
	# in-order traversal of the right subtree to add all its intervals
	$self->_in_order_traversal($node->right, $result);
      }
      $node = $node->left;
    } else {
      foreach my $seg_end (@{$node->s_center_end}) {
	last if $seg_end->is_left_of($interval);
	push @{$result}, $seg_end;
      }
      $node = $node->right;
    }
  }
}

# This corresponds to the right branch of the range search, once we find a node, whose
# midpoint is contained in the query interval. All intervals in the right subtree of that node
# are guaranteed to intersect with the query, if they have an endpoint smaller or equal than
# the end of the query interval. Basically, this means that every time we branch to the right
# in the binary search, we need to add the whole left subtree to the result set.

sub _range_query_right {
  my ($self, $node, $interval, $result) = @_;

  while ($node) {
    if ($interval->contains($node->x_center)) {
      push @{$result}, @{$node->s_center_beg};
      if ($node->left) {
	# in-order traversal of the left subtree to add all its intervals
	$self->_in_order_traversal($node->left, $result);
      }
      $node = $node->right;
    } else {
      foreach my $seg_beg (@{$node->s_center_beg}) {
	last if $seg_beg->is_right_of($interval);
	push @{$result}, $seg_beg;
      }
      $node = $node->left;
    }
  }
}

sub in_order_traversal {
  my ($self) = @_;

  my $result = [];
  $self->_in_order_traversal($self->root, $result);

  return $result;
}

sub _in_order_traversal {
  my ($self, $node, $result) = @_;

  return unless $node;
  $result ||= [];

  $self->_in_order_traversal($node->left, $result);
  push @{$result}, @{$node->s_center_beg};
  $self->_in_order_traversal($node->right, $result);
}

sub _divide_intervals {
  my ($self, $intervals, $sorted) = @_;

  return undef unless scalar @{$intervals};

  my $sorted_intervals;
  if ($sorted) {
      $sorted_intervals = $intervals;
  } else {
      $sorted_intervals = sort_by_begin($intervals);
  }

  my $x_center = $self->_center_sorted($sorted_intervals);
  my ($s_center, $s_left, $s_right) = ([], [], []);
  
  foreach my $sorted_interval (@{$sorted_intervals}) {



( run in 0.655 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )