line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Set::IntSpan::Partition;
|
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
112676
|
use 5.008000;
|
|
3
|
|
|
|
|
12
|
|
|
3
|
|
|
|
|
123
|
|
4
|
3
|
|
|
3
|
|
17
|
use strict;
|
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
109
|
|
5
|
3
|
|
|
3
|
|
16
|
use warnings;
|
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
111
|
|
6
|
3
|
|
|
3
|
|
16
|
use base qw(Exporter);
|
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
1370
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.02';
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw(
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
) ] );
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our @EXPORT = qw(
|
17
|
|
|
|
|
|
|
intspan_partition
|
18
|
|
|
|
|
|
|
intspan_partition_map
|
19
|
|
|
|
|
|
|
);
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub _uniq (@) {
|
22
|
0
|
|
|
0
|
|
|
my %h;
|
23
|
0
|
0
|
|
|
|
|
return map { $h{$_}++ == 0 ? $_ : () } @_;
|
|
0
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
}
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub _add {
|
27
|
0
|
|
|
0
|
|
|
my $rest = shift;
|
28
|
|
|
|
|
|
|
|
29
|
0
|
|
|
|
|
|
my @parts = map {
|
30
|
0
|
|
|
|
|
|
my $old = $_;
|
31
|
|
|
|
|
|
|
|
32
|
0
|
|
|
|
|
|
my $right = $rest->diff($old);
|
33
|
0
|
|
|
|
|
|
my $left = $old->diff($rest);
|
34
|
0
|
|
|
|
|
|
my $both = $old->intersect($rest);
|
35
|
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
|
$rest = $right;
|
37
|
|
|
|
|
|
|
|
38
|
0
|
|
|
|
|
|
grep { !$_->empty } $left, $both
|
|
0
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
} @_;
|
41
|
|
|
|
|
|
|
|
42
|
0
|
0
|
|
|
|
|
push @parts, $rest unless $rest->empty;
|
43
|
0
|
|
|
|
|
|
return @parts;
|
44
|
|
|
|
|
|
|
}
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub intspan_partition {
|
47
|
0
|
|
|
0
|
|
|
my @parts = ();
|
48
|
|
|
|
|
|
|
|
49
|
0
|
|
|
|
|
|
@parts = _add($_, @parts) for @_;
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# TODO: It's not really possible to get non-unique
|
52
|
|
|
|
|
|
|
# items into the list? But play it safe for now.
|
53
|
0
|
|
|
|
|
|
return _uniq @parts;
|
54
|
|
|
|
|
|
|
}
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub intspan_partition_map {
|
57
|
|
|
|
|
|
|
|
58
|
3
|
|
|
3
|
|
3200
|
use Heap::Simple qw//;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
use List::Util qw/min max/;
|
60
|
|
|
|
|
|
|
use List::MoreUtils qw/uniq/;
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
my $heap = Heap::Simple->new(order => sub {
|
63
|
|
|
|
|
|
|
my ($x, $y) = @_;
|
64
|
|
|
|
|
|
|
return 1 if $x->[0] < $y->[0];
|
65
|
|
|
|
|
|
|
return 0 if $x->[0] > $y->[0];
|
66
|
|
|
|
|
|
|
return 1 if $x->[1] < $y->[1];
|
67
|
|
|
|
|
|
|
return 0;
|
68
|
|
|
|
|
|
|
});
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
for (my $ix = 0; $ix < @_; ++$ix) {
|
71
|
|
|
|
|
|
|
my $obj = $_[$ix];
|
72
|
|
|
|
|
|
|
for ($obj->spans) {
|
73
|
|
|
|
|
|
|
$heap->insert([ $_->[0], $_->[1], [$ix] ]);
|
74
|
|
|
|
|
|
|
}
|
75
|
|
|
|
|
|
|
}
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
my @result;
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
while (1) {
|
80
|
|
|
|
|
|
|
my $x = $heap->extract_first;
|
81
|
|
|
|
|
|
|
my $y = $heap->extract_first;
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
last unless defined $x;
|
84
|
|
|
|
|
|
|
push @result, $x unless defined $y;
|
85
|
|
|
|
|
|
|
last unless defined $y;
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
if ($x->[1] < $y->[0]) {
|
88
|
|
|
|
|
|
|
push @result, $x;
|
89
|
|
|
|
|
|
|
$heap->insert($y);
|
90
|
|
|
|
|
|
|
next;
|
91
|
|
|
|
|
|
|
}
|
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
my $min = min($x->[1], $y->[0]);
|
94
|
|
|
|
|
|
|
my $max = max(min($y->[0], $x->[1]), min($x->[1], $y->[1]));
|
95
|
|
|
|
|
|
|
my $XandY = [ $min, $max, [ @{$x->[2]}, @{$y->[2]} ] ];
|
96
|
|
|
|
|
|
|
my $prefX = [ $x->[0], $XandY->[0] - 1, $x->[2] ];
|
97
|
|
|
|
|
|
|
my $suffX = [ $XandY->[1] + 1, $x->[1], $x->[2] ];
|
98
|
|
|
|
|
|
|
my $onlyY = [ $XandY->[1] + 1, $y->[1], $y->[2] ];
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
for ($prefX, $suffX, $onlyY, $XandY) {
|
101
|
|
|
|
|
|
|
next unless $_->[0] <= $_->[1];
|
102
|
|
|
|
|
|
|
$heap->insert($_);
|
103
|
|
|
|
|
|
|
}
|
104
|
|
|
|
|
|
|
}
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# group spans back into classes
|
107
|
|
|
|
|
|
|
my %group;
|
108
|
|
|
|
|
|
|
for my $item (@result) {
|
109
|
|
|
|
|
|
|
my $key = join ',', uniq sort @{ $item->[2] };
|
110
|
|
|
|
|
|
|
push @{ $group{$key} }, $item;
|
111
|
|
|
|
|
|
|
}
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
my %map;
|
114
|
|
|
|
|
|
|
while (my ($k, $v) = each %group) {
|
115
|
|
|
|
|
|
|
my $class = Set::IntSpan->new([map {
|
116
|
|
|
|
|
|
|
[ $_->[0], $_->[1] ]
|
117
|
|
|
|
|
|
|
} @$v]);
|
118
|
|
|
|
|
|
|
push @{ $map{$_} }, $class for uniq map { @{ $_->[2] } } @$v;
|
119
|
|
|
|
|
|
|
}
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
return %map;
|
122
|
|
|
|
|
|
|
}
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
1;
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
__END__
|