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   32310 use 5.006;
  1         3  
  1         30  
4 1     1   4 use strict;
  1         1  
  1         35  
5 1     1   4 use warnings;
  1         5  
  1         221  
6             our $VERSION = '0.10';
7             #use utf8;
8              
9             sub new {
10 6     6 1 3250 my $class = shift;
11             # uncoverable condition false
12 6 100 66     63 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       17  
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 89577 my ($self, $a, $b) = @_;
23              
24 24         70 my ($amin, $amax, $bmin, $bmax) = (0, $#$a, 0, $#$b);
25              
26 24   100     227 while ($amin <= $amax and $bmin <= $bmax and $a->[$amin] eq $b->[$bmin]) {
      100        
27 13         14 $amin++;
28 13         57 $bmin++;
29             }
30 24   100     155 while ($amin <= $amax and $bmin <= $bmax and $a->[$amax] eq $b->[$bmax]) {
      100        
31 7         8 $amax--;
32 7         23 $bmax--;
33             }
34              
35 24         32 my $bMatches;
36 24         51 unshift @{ $bMatches->{$b->[$_]} },$_ for $bmin..$bmax;
  119         269  
37              
38 24         43 my $matchVector = [];
39 24         29 my $thresh = [];
40 24         32 my $links = [];
41              
42 24         25 my ( $i, $ai, $j, $k );
43 24         73 for ( $i = $amin ; $i <= $amax ; $i++ ) {
44 139         118 $ai = $a->[$i];
45 139 100       240 if ( exists( $bMatches->{$ai} ) ) {
46 95         75 for $j ( @{ $bMatches->{$ai} } ) {
  95         149  
47 112 100 100     316 if ( !@$thresh || $j > $thresh->[-1] ) {
48 83         86 $k = $#$thresh+1;
49 83         93 $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         33 $k = 0;
57 29         24 my $index;
58             my $found;
59 29         37 my $high = $#$thresh;
60 29         58 while ( $k <= $high ) {
61 1     1   445 use integer;
  1         7  
  1         4  
62 48         50 $index = ( $high + $k ) / 2;
63             #$index = int(( $high + $k ) / 2); # without 'use integer'
64 48         50 $found = $thresh->[$index];
65              
66 48 100       88 if ( $j == $found ) { $k = undef; last; }
  6 100       10  
  6         11  
67 16         29 elsif ( $j > $found ) { $k = $index + 1; }
68 26         49 else { $high = $index - 1; }
69             }
70             # now insertion point is in $k.
71 29 100       62 $thresh->[$k] = $j if (defined $k); # overwrite next larger
72             }
73 112 100       164 if (defined $k) {
74 106 100       344 $links->[$k] = [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ];
75             }
76             }
77             }
78             }
79 24 100       55 if (@$thresh) {
80 14         45 for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) {
81 83         190 unshift @$matchVector,[$link->[1],$link->[2]];
82             }
83             }
84 24         188 return [ map([$_ => $_], 0 .. ($bmin-1)),
85             @$matchVector,
86             map([++$amax => $_], ($bmax+1) .. $#$b) ];
87             }
88              
89             1;
90              
91             __END__