File Coverage

blib/lib/Set/Similarity/BV.pm
Criterion Covered Total %
statement 66 66 100.0
branch 10 10 100.0
condition 10 12 91.6
subroutine 17 17 100.0
pod 7 7 100.0
total 110 112 99.1


line stmt bran cond sub pod time code
1             package Set::Similarity::BV;
2              
3 5     5   2780 use strict;
  5         9  
  5         156  
4 5     5   23 use warnings;
  5         8  
  5         237  
5              
6             our $VERSION = '0.05';
7              
8 5     5   36 use Carp 'croak';
  5         9  
  5         370  
9 5     5   3765 use Data::Dumper;
  5         31944  
  5         1030  
10              
11             our $width = int 0.999+log(~0)/log(2);
12              
13             sub new {
14 7     7 1 1513 my $class = shift;
15              
16             # uncoverable condition false
17 7 100 66     49 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       23  
18             }
19              
20             sub similarity {
21 44     44 1 6382 my ($self, $hex1, $hex2) = @_;
22              
23 44 100 100     219 return 1 if (!($hex1 || $hex2)); # both zero
24 36 100 100     243 return 0 unless ($hex1 && $hex2); # one is zero
25              
26             #return 1 if (!(hex($hex1) || hex($hex2))); # both zero
27             #return 0 unless (hex($hex1) && hex($hex2) ); # one is zero
28              
29 5     5   45 no warnings 'portable'; # for 0xffffffffffffffff
  5         11  
  5         660  
30              
31 24         80 return $self->from_integers(
32             $self->_integers($hex1),
33             $self->_integers($hex2),
34             );
35             }
36              
37              
38 1     1 1 324 sub from_integers { croak 'Method "from_integers" not implemented in subclass' }
39              
40             sub intersection {
41 30     30 1 38 my ($self,$v1,$v2) = @_;
42              
43 5     5   28 no warnings 'portable'; # for 0xffffffffffffffff
  5         9  
  5         989  
44              
45 30         78 my $bits = 0;
46 30         30 my $max1 = scalar(@{$v1}) - 1;
  30         50  
47 30         29 my $max2 = scalar(@{$v2}) - 1;
  30         30  
48              
49 30   66     152 for (my $i=0; ($i <= $max1) && ($i <= $max2); $i++) {
50 33         114 $bits += $self->bits([ ($v1->[$i] & $v2->[$i]) ]);
51             }
52 30         79 return $bits;
53             }
54              
55             sub _integers {
56 62     62   85 my ($self,$hex_string) = @_;
57              
58 62         110 my $chunk_size = int($width/4);
59 62         464 my @chunks = $hex_string =~ m/([0-9a-f]{1,$chunk_size})/gi;
60              
61 5     5   32 no warnings 'portable'; # for 0xffffffffffffffff
  5         8  
  5         553  
62 62         94 my $result = [];
63 62         95 for my $chunk (@chunks) {
64 71         63 push @{$result},hex($chunk);
  71         183  
65             }
66 62         241 return $result;
67             }
68              
69             sub bits {
70 87     87 1 104 my ($self,$array_of_integers) = @_;
71              
72 5     5   2968 use integer;
  5         49  
  5         20  
73 5     5   160 no warnings 'portable'; # for 0xffffffffffffffff
  5         8  
  5         991  
74              
75             # (bytesof($v) -1) * bitsofbyte = (8-1)*8 = 56 # for 64 bit
76             # (bytesof($v) -1) * bitsofbyte = (8-1)*8 = 56 # for 32 bit
77 87         104 my $final_shift = (($width/8) - 1) * 8;
78              
79 87         74 my $bits = 0;
80 87         64 for my $i (@{$array_of_integers}) {
  87         133  
81 95         90 my $v = $i; # don't use (and change) $i directly
82 95         97 $v = $v - (($v >> 1) & 0x5555555555555555);
83 95         101 $v = ($v & 0x3333333333333333) + (($v >> 2) & 0x3333333333333333);
84             # (bytesof($v) -1) * bitsofbyte = (8-1)*8 = 56 ----------------------vv
85 95         101 $v = (($v + ($v >> 4) & 0x0f0f0f0f0f0f0f0f) * 0x0101010101010101) >> $final_shift;
86 95         114 $bits += $v;
87             }
88              
89 87         322 return $bits;
90             }
91              
92             sub combined_length {
93 10     10 1 13 my ($self,$v1,$v2) = @_;
94              
95 10         24 return $self->bits($v1) + $self->bits($v2);
96             }
97              
98             sub min {
99 8 100   8 1 68 ($_[1] < $_[2])
100             ? $_[1] : $_[2];
101             }
102              
103             1;
104              
105             __END__