File Coverage

blib/lib/LCS/Tiny.pm
Criterion Covered Total %
statement 55 55 100.0
branch 20 20 100.0
condition 17 18 100.0
subroutine 6 6 100.0
pod 2 2 100.0
total 100 101 100.0


line stmt bran cond sub pod time code
1             package LCS::Tiny;
2              
3 1     1   33942 use 5.006;
  1         3  
4 1     1   4 use strict;
  1         1  
  1         24  
5 1     1   4 use warnings;
  1         6  
  1         235  
6             our $VERSION = '0.11';
7             #use utf8;
8              
9             sub new {
10 6     6 1 2183 my $class = shift;
11             # uncoverable condition false
12 6 100 66     44 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       15  
13             }
14              
15             # Implemented according to
16              
17             # J. W. Hunt and T. G. Szymanski.
18             # A fast algorithm for computing longest common subsequences.
19             # Commun. ACM, 20(5):350-353, 1977.
20              
21             sub LCS {
22 24     24 1 79940 my ($self, $a, $b) = @_;
23              
24 24         46 my ($amin, $amax, $bmin, $bmax) = (0, $#$a, 0, $#$b);
25              
26 24   100     180 while ($amin <= $amax and $bmin <= $bmax and $a->[$amin] eq $b->[$bmin]) {
      100        
27 13         16 $amin++;
28 13         59 $bmin++;
29             }
30 24   100     124 while ($amin <= $amax and $bmin <= $bmax and $a->[$amax] eq $b->[$bmax]) {
      100        
31 7         6 $amax--;
32 7         25 $bmax--;
33             }
34              
35 24         22 my $bMatches;
36 24         57 unshift @{ $bMatches->{$b->[$_]} },$_ for $bmin..$bmax;
  119         246  
37              
38 24         38 my $matchVector = [];
39 24         25 my $thresh = [];
40 24         17 my $links = [];
41              
42 24         23 my ( $i, $ai, $j, $k );
43 24         47 for ( $i = $amin ; $i <= $amax ; $i++ ) {
44 139         111 $ai = $a->[$i];
45 139 100       245 if ( exists( $bMatches->{$ai} ) ) {
46 95         67 for $j ( @{ $bMatches->{$ai} } ) {
  95         121  
47 112 100 100     308 if ( !@$thresh || $j > $thresh->[-1] ) {
48 83         74 $k = $#$thresh+1;
49 83         83 $thresh->[$k] = $j;
50             }
51             #elsif ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) {
52             # $thresh->[$k] = $j;
53             #}
54             else {
55             # binary search for insertion point
56 29         22 $k = 0;
57 29         21 my $index;
58             my $found;
59 29         21 my $high = $#$thresh;
60 29         47 while ( $k <= $high ) {
61 1     1   491 use integer;
  1         9  
  1         4  
62 48         36 $index = ( $high + $k ) / 2;
63             #$index = int(( $high + $k ) / 2); # without 'use integer'
64 48         37 $found = $thresh->[$index];
65              
66 48 100       76 if ( $j == $found ) { $k = undef; last; }
  6 100       6  
  6         6  
67 16         24 elsif ( $j > $found ) { $k = $index + 1; }
68 26         40 else { $high = $index - 1; }
69             }
70             # now insertion point is in $k.
71 29 100       48 $thresh->[$k] = $j if (defined $k); # overwrite next larger
72             }
73 112 100       159 if (defined $k) {
74 106 100       304 $links->[$k] = [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ];
75             }
76             }
77             }
78             }
79 24 100       51 if (@$thresh) {
80 14         37 for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) {
81 83         170 unshift @$matchVector,[$link->[1],$link->[2]];
82             }
83             }
84 24         156 return [ map([$_ => $_], 0 .. ($bmin-1)),
85             @$matchVector,
86             map([++$amax => $_], ($bmax+1) .. $#$b) ];
87             }
88              
89             1;
90              
91             __END__