File Coverage

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


line stmt bran cond sub pod time code
1             package LCS::Tiny;
2              
3 1     1   38219 use 5.006;
  1         4  
  1         31  
4 1     1   5 use strict;
  1         1  
  1         37  
5 1     1   4 use warnings;
  1         6  
  1         282  
6             our $VERSION = '0.09';
7             #use utf8;
8              
9             sub new {
10 6     6 1 2512 my $class = shift;
11             # uncoverable condition false
12 6 100 66     51 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       14  
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 96666 my ($self, $a, $b) = @_;
23              
24 24         63 my ($amin, $amax, $bmin, $bmax) = (0, $#$a, 0, $#$b);
25              
26 24   100     219 while ($amin <= $amax and $bmin <= $bmax and $a->[$amin] eq $b->[$bmin]) {
      100        
27 13         21 $amin++;
28 13         53 $bmin++;
29             }
30 24   100     159 while ($amin <= $amax and $bmin <= $bmax and $a->[$amax] eq $b->[$bmax]) {
      100        
31 7         9 $amax--;
32 7         27 $bmax--;
33             }
34              
35 24         29 my $bMatches;
36 24         61 unshift @{ $bMatches->{$b->[$_]} },$_ for $bmin..$bmax;
  119         283  
37              
38 24         48 my $matchVector = [];
39 24         30 my $thresh = [];
40 24         28 my $links = [];
41              
42 24         28 my ( $i, $ai, $j, $k );
43 24         79 for ( $i = $amin ; $i <= $amax ; $i++ ) {
44 139         143 $ai = $a->[$i];
45 139 100       258 if ( exists( $bMatches->{$ai} ) ) {
46 95         79 for $j ( @{ $bMatches->{$ai} } ) {
  95         151  
47 112 100 100     312 if ( !@$thresh || $j > $thresh->[-1] ) {
48 83         75 $k = $#$thresh+1;
49 83         110 $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         27 $k = 0;
57 29         23 my $index;
58             my $found;
59 29         25 my $high = $#$thresh;
60 29         51 while ( $k <= $high ) {
61 1     1   474 use integer;
  1         8  
  1         5  
62 48         38 $index = ( $high + $k ) / 2;
63             #$index = int(( $high + $k ) / 2); # without 'use integer'
64 48         46 $found = $thresh->[$index];
65              
66 48 100       78 if ( $j == $found ) { $k = undef; last; }
  6 100       7  
  6         7  
67 16         25 elsif ( $j > $found ) { $k = $index + 1; }
68 26         43 else { $high = $index - 1; }
69             }
70             # now insertion point is in $k.
71 29 100       54 $thresh->[$k] = $j if (defined $k); # overwrite next larger
72             }
73 112 100       162 if (defined $k) {
74 106 100       391 $links->[$k] = [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ];
75             }
76             }
77             }
78             }
79 24 100       49 if (@$thresh) {
80 14         48 for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) {
81 83         180 unshift @$matchVector,[$link->[1],$link->[2]];
82             }
83             }
84 24         195 return [ map([$_ => $_], 0 .. ($bmin-1)),
85             @$matchVector,
86             map([++$amax => $_], ($bmax+1) .. $#$b) ];
87             }
88              
89             1;
90              
91             __END__