BioPerl
view release on metacpan or search on metacpan
Bio/Search/Tiling/MapTileUtils.pm view on Meta::CPAN
@input{(0..$n-1)} = @{$_[0]};
my @active = (0..$n-1);
my @hold;
my @tiled_ints;
my @ret;
while (@active) {
my $tgt = $input{my $tgt_i = shift @active};
push @tiled_ints, $tgt_i;
my $tgt_not_disjoint = 1;
while ($tgt_not_disjoint) {
$tgt_not_disjoint = 0;
while (my $try_i = shift @active) {
my $try = $input{$try_i};
if ( !are_disjoint($tgt, $try) ) {
$tgt = min_covering_interval($tgt,$try);
push @tiled_ints, $try_i;
$tgt_not_disjoint = 1;
}
else {
push @hold, $try_i;
}
}
if (!$tgt_not_disjoint) {
push @ret, [ $tgt => [@tiled_ints] ];
@tiled_ints = ();
}
@active = @hold;
@hold = ();
}
}
return @ret;
}
=head2 decompose_interval
Title : decompose_interval
Usage : @decomposition = decompose_interval( \@overlappers )
Function: Calculate the disjoint decomposition of a set of
overlapping intervals, each annotated with a list of
covering intervals
Returns : array of arrayrefs of the form
( [[@interval] => [@indices_of_coverers]], ... )
Args : arrayref of intervals (arrayrefs like [$a0, $a1], with
Note : Each returned interval is associated with a list of indices of the
original intervals that cover that decomposition component
(scalar size of this list could be called the 'coverage coefficient')
Note : Coverage: each component of the decomp is completely contained
in the input intervals that overlap it, by construction.
Caveat : This routine expects the members of @overlappers to overlap,
but doesn't check this.
=cut
### what if the input intervals don't overlap?? They MUST overlap; that's
### what interval_tiling() is for.
sub decompose_interval {
return unless $_[0]; # no input
my @ints = @{$_[0]};
my (%flat,@flat);
### this is ok, but need to handle the case where a lh and rh endpoint
### coincide...
# decomposition --
# flatten:
# every lh endpoint generates (lh-1, lh)
# every rh endpoint generates (rh, rh+)
foreach (@ints) {
$flat{$$_[0]-1}++;
$flat{$$_[0]}++;
$flat{$$_[1]}++;
$flat{$$_[1]+1}++;
}
# sort, create singletons if nec.
my @a;
@a = sort {$a<=>$b} keys %flat;
# throw out first and last (meeting a boundary condition)
shift @a; pop @a;
# look for singletons
@flat = (shift @a, shift @a);
if ( $flat[1]-$flat[0] == 1 ) {
@flat = ($flat[0],$flat[0], $flat[1]);
}
while (my $a = shift @a) {
if ($a-$flat[-2]==2) {
push @flat, $flat[-1]; # create singleton interval
}
push @flat, $a;
}
if ($flat[-1]-$flat[-2]==1 and @flat % 2) {
push @flat, $flat[-1];
}
# component intervals are consecutive pairs
my @decomp;
while (my $a = shift @flat) {
push @decomp, [$a, shift @flat];
}
# for each component, return a list of the indices of the input intervals
# that cover the component.
my @coverage;
foreach my $i (0..$#decomp) {
foreach my $j (0..$#ints) {
unless (are_disjoint($decomp[$i], $ints[$j])) {
if (defined $coverage[$i]) {
push @{$coverage[$i]}, $j;
}
else {
$coverage[$i] = [$j];
}
}
}
}
return map { [$decomp[$_] => $coverage[$_]] } (0..$#decomp);
}
=head2 are_disjoint
Title : are_disjoint
Usage : are_disjoint( [$a0, $a1], [$b0, $b1] )
Function: Determine if two intervals are disjoint
Returns : True if the intervals are disjoint, false if they overlap
Args : array of two intervals
=cut
sub are_disjoint {
( run in 0.844 second using v1.01-cache-2.11-cpan-39bf76dae61 )