Permalink
Browse files

add brute force ANN.

  • Loading branch information...
1 parent 271184b commit b49e1d11c15a369e85dbc87d25d3319d989dd34f @kuzuha committed Jan 2, 2012
Showing with 164 additions and 0 deletions.
  1. +63 −0 lib/Plann/ANN/BruteForce.pm
  2. +31 −0 lib/Plann/ANN/Entry.pm
  3. +6 −0 lib/Plann/Role/ANN.pm
  4. +48 −0 t/usual/ann/brute_force.t
  5. +16 −0 t/usual/ann/entry.t
@@ -0,0 +1,63 @@
+use 5.14.0;
+package Plann::ANN::BruteForce;
+use true;
+use Mouse;
+
+use Plann::ANN::Utils;
+
+with 'Plann::Role::ANN';
+
+=head1 Interface
+
+=head2 Constructors
+
+=head3 new
+
+Create a new Plann::ANN::BruteForce object.
+
+=head4 Parameters
+
+...
+
+=cut
+
+has 'entries' => (
+ traits => ['Array'],
+ is => 'ro',
+ isa => 'ArrayRef[Plann::ANN::Entry]',
+ default => sub { [] },
+ handles => { _train => 'push' },
+);
+
+=head2 Instance Methods
+
+=head3 train
+
+...
+
+=cut
+
+sub train { shift->_train(@_) }
+
+=head3 search
+
+...
+
+=cut
+
+sub search {
+ my $self = shift;
+ my ($matrix, $options) = @_;
+
+ my $res = [];
+ for my $entry (values $self->entries) {
+ my $distance = euclidean_distance(map {$_->[0]->[0]} $entry->vector, $matrix);
+
+ next if $options->{threshold} && $distance > $options->{threshold};
+ push $res, {
+ distance => $distance,
+ entry => $entry,
+ };
+ }
+ [sort { $a->{distance} <=> $b->{distance} } @$res];
+}
@@ -0,0 +1,31 @@
+use 5.14.0;
+package Plann::ANN::Entry;
+use true;
+use Mouse;
+
+use Plann::Subtypes;
+
+has 'vector' => (
+ is => 'ro',
+ isa => 'Matrix',
+ coerce => 1,
+ required => 1,
+);
+
+has 'parameters' => (
+ is => 'ro',
+ isa => 'HashRef',
+ default => sub { {} },
+);
+
+sub BUILDARGS {
+ my ($self, @args) = @_;
+ if (ref $args[0]) {
+ if (1 == scalar @args) {
+ @args = (vector => $args[0]);
+ } else {
+ @args = (vector => $args[0], parameters => $args[1]);
+ }
+ }
+ return {@args};
+}
@@ -0,0 +1,6 @@
+use 5.14.0;
+package Plann::Role::ANN;
+use true;
+use Mouse::Role;
+
+requires qw/search train/;
@@ -0,0 +1,48 @@
+use 5.14.0;
+use Test::Most tests => 4;
+
+use Plann::ANN::BruteForce;
+use Plann::ANN::Entry;
+
+my $ann = Plann::ANN::BruteForce->new;
+
+my @entries = (
+ Plann::ANN::Entry->new([1,2,3]),
+ Plann::ANN::Entry->new([2,3,4]),
+ Plann::ANN::Entry->new([100,200,300]),
+);
+
+my $expected = [
+ { entry => $entries[1], distance => 0 },
+ { entry => $entries[0], distance => 1.73205080756888 },
+ { entry => $entries[2], distance => 368.821094841388 },
+];
+
+$ann->train($_) for @entries;
+
+#
+# search
+#
+is_deeply(
+ $ann->search($entries[1]->vector),
+ $expected
+);
+
+#
+# search with threshold
+#
+pop $expected;
+is_deeply(
+ $ann->search($entries[1]->vector, { threshold => 2 }),
+ $expected
+);
+is_deeply(
+ $ann->search($entries[1]->vector, { threshold => 1.73205080756888 }),
+ $expected
+);
+
+pop $expected;
+is_deeply(
+ $ann->search($entries[1]->vector, { threshold => 1.73205080756887 }),
+ $expected
+);
View
@@ -0,0 +1,16 @@
+use 5.14.0;
+use Test::Most tests => 2;
+
+use Plann::ANN::Entry;
+
+my $entry;
+
+is_deeply(
+ Plann::ANN::Entry->new([1,2,3]),
+ Plann::ANN::Entry->new(vector => [1,2,3])
+);
+
+is_deeply(
+ Plann::ANN::Entry->new([1,2,3], { threshold => 10 }),
+ Plann::ANN::Entry->new(vector => [1,2,3], parameters => { threshold => 10 })
+);

0 comments on commit b49e1d1

Please sign in to comment.