File Coverage

blib/lib/Algorithm/LSH.pm
Criterion Covered Total %
statement 39 90 43.3
branch 2 6 33.3
condition 3 11 27.2
subroutine 10 18 55.5
pod 9 9 100.0
total 63 134 47.0


line stmt bran cond sub pod time code
1             package Algorithm::LSH;
2 3     3   1307 use strict;
  3         5  
  3         92  
3 3     3   13 use warnings;
  3         4  
  3         76  
4 3     3   15 use base qw(Algorithm::LSH::Base);
  3         3  
  3         1822  
5 3     3   1800 use Algorithm::LSH::Bucket;
  3         6  
  3         30  
6 3     3   2667 use UNIVERSAL::require;
  3         4714  
  3         29  
7 3     3   81 use Scalar::Util qw(blessed);
  3         6  
  3         304  
8 3     3   14 use Carp;
  3         7  
  3         134  
9 3     3   3177 use Storable qw( retrieve store );
  3         10961  
  3         2277  
10              
11             our $VERSION = '0.00001_01';
12              
13             __PACKAGE__->mk_accessors($_) for qw( hash bucket storage );
14              
15             sub new {
16 4     4 1 56 my $class = shift;
17 4         42 my $self = $class->SUPER::new(@_);
18 4         20 $self->_setup(@_);
19 4         34 return $self;
20             }
21              
22             sub insert {
23 0     0 1 0 my $self = shift;
24 0         0 my ( $label, $vector ) = @_;
25 0         0 my $hashed_arrayref = $self->hash->do_hashing($vector);
26 0         0 $self->bucket->insert( $label, $vector, $hashed_arrayref );
27             }
28              
29             sub nn {
30 0     0 1 0 my $self = shift;
31 0         0 my $nn = $self->nearest_neighbours(@_);
32 0         0 return $nn;
33             }
34              
35             sub nearest_neighbours {
36 0     0 1 0 my $self = shift;
37 0         0 my $vector = shift;
38 0         0 my $without_self = shift;
39 0         0 my $neighbours = $self->neighbours( $vector, $without_self );
40 0         0 my $nn = $self->nearest( $vector, $neighbours );
41 0         0 return $nn;
42             }
43              
44             sub neighbours {
45 0     0 1 0 my $self = shift;
46 0         0 my $vector = shift;
47 0         0 my $without_self = shift;
48 0         0 my $hashed_arrayref = $self->hash->do_hashing($vector);
49 0         0 my $neighbours =
50             $self->bucket->select( $vector, $hashed_arrayref, $without_self );
51 0         0 return $neighbours;
52             }
53              
54             sub nearest {
55 0     0 1 0 my $self = shift;
56 0         0 my $vector = shift;
57 0         0 my $neighbours = shift;
58 0         0 my %nearest;
59 0         0 for (@$neighbours) {
60 0         0 my ( $n_label, $n_vector ) = each %$_;
61 0         0 my $dist = $self->distance( $vector, $n_vector );
62 0 0 0     0 if ( ! defined $nearest{distance} || $dist < $nearest{distance} ) {
63 0         0 $nearest{label} = $n_label;
64 0         0 $nearest{vector} = $n_vector;
65 0         0 $nearest{distance} = $dist;
66             }
67             }
68 0         0 return \%nearest;
69             }
70              
71             sub distance {
72 0     0 1 0 my $self = shift;
73 0         0 my $vector_1 = shift;
74 0         0 my $vector_2 = shift;
75 0         0 my $sum;
76 0         0 for my $i ( 0 .. @{$vector_1} - 1 ) {
  0         0  
77 0         0 my $d = ( $vector_1->[$i] - $vector_2->[$i] )**2;
78 0         0 $sum += $d;
79             }
80 0         0 my $distance = sqrt($sum);
81 0         0 return $distance;
82             }
83              
84             sub save {
85 0     0 1 0 my $self = shift;
86 0   0     0 my $file_path = shift || './save.bin';
87 0         0 $self->storage->save($file_path);
88             }
89              
90             sub load {
91 0     0 1 0 my $self = shift;
92 0   0     0 my $file_path = shift || './save.bin';
93 0         0 my $data = $self->storage->load($file_path);
94 0         0 my $class = blessed $data->hash;
95 0         0 $class->use;
96 0         0 for ( keys %$data ) {
97 0         0 $self->$_( $data->$_ );
98             }
99             }
100              
101             sub _setup {
102 4     4   9 my $self = shift;
103              
104             # param check
105 4         26 $self->_check_parameters;
106              
107             # dynamic load (hash class)
108 4         46 my $hash_class = delete $self->{hash_class};
109 4   100     31 $hash_class ||= 'Algorithm::LSH::Hash::Hamming';
110 4 50       39 $hash_class->require or croak $@;
111 4         260 $self->hash( $hash_class->new( context => $self, @_ ) );
112              
113             # dynamic loading (storage class)
114 4         31 my $storage_class = delete $self->{storage_class};
115 4   50     29 $storage_class ||= 'Algorithm::LSH::Storage::Storable';
116 4 50       49 $storage_class->require or croak $@;
117 4         115 $self->storage( $storage_class->new( context => $self, @_ ) );
118              
119             # bucket class
120 4         53 $self->bucket( Algorithm::LSH::Bucket->new( context => $self, @_ ) );
121             }
122              
123             1;
124             __END__