flann 1.8.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +36 -0
- data/LICENSE.txt +10 -0
- data/Manifest.txt +12 -0
- data/Rakefile +111 -0
- data/flann.gemspec +59 -0
- data/lib/flann.rb +293 -0
- data/lib/flann/index.rb +162 -0
- data/lib/flann/version.rb +37 -0
- data/spec/flann_spec.rb +104 -0
- data/spec/index_spec.rb +114 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/test.dataset +65536 -0
- metadata +144 -0
data/lib/flann/index.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# Copyright 2014 John O. Woods (john.o.woods@gmail.com), West Virginia
|
2
|
+
# University's Applied Space Exploration Lab, and West Virginia Robotic
|
3
|
+
# Technology Center. All rights reserved.
|
4
|
+
#
|
5
|
+
# THE BSD LICENSE
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions
|
9
|
+
# are met:
|
10
|
+
#
|
11
|
+
# 1. Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
class FFI::Pointer
|
29
|
+
class << self
|
30
|
+
def new_from_nmatrix nm
|
31
|
+
raise(StorageError, "dense storage expected") unless nm.dense?
|
32
|
+
c_type = Flann::dtype_to_c(nm.dtype)
|
33
|
+
c_type = :uchar if c_type == :byte
|
34
|
+
::FFI::Pointer.new(c_type, nm.data_pointer).tap { |p| p.autorelease = false }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Flann
|
40
|
+
class Index
|
41
|
+
|
42
|
+
# Constructor takes a block where we set each of the parameters. We need to be careful to do this since
|
43
|
+
# we're using the C API and not C++; so everything important needs to be initialized or there could be
|
44
|
+
# a segfault. For reasonable default definitions, see:
|
45
|
+
#
|
46
|
+
# * https://github.com/mariusmuja/flann/tree/master/src/cpp/flann/algorithms
|
47
|
+
#
|
48
|
+
def initialize index_dataset = nil, dtype: :float64, parameters: Flann::Parameters::DEFAULT
|
49
|
+
@dataset = index_dataset
|
50
|
+
#require 'pry'
|
51
|
+
#binding.pry if @dataset.nil?
|
52
|
+
@dtype = (!index_dataset.nil? && index_dataset.is_a?(NMatrix)) ? index_dataset.dtype : dtype
|
53
|
+
@index_ptr = nil
|
54
|
+
|
55
|
+
@parameters_ptr, @parameters = Flann::handle_parameters(parameters)
|
56
|
+
|
57
|
+
yield @parameters if block_given?
|
58
|
+
end
|
59
|
+
attr_reader :dtype, :dataset, :parameters, :parameters_ptr, :index_ptr
|
60
|
+
|
61
|
+
# Assign a new dataset. Requires that the old index be freed.
|
62
|
+
def dataset= index_dataset
|
63
|
+
free!
|
64
|
+
@dataset = index_dataset
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build an index
|
68
|
+
def build!
|
69
|
+
raise("no dataset specified") if dataset.nil?
|
70
|
+
c_type = Flann::dtype_to_c(dtype)
|
71
|
+
c_method = "flann_build_index_#{c_type}".to_sym
|
72
|
+
speedup_float_ptr = FFI::MemoryPointer.new(:float)
|
73
|
+
@index_ptr = Flann.send(c_method, FFI::Pointer.new_from_nmatrix(dataset), dataset.shape[0], dataset.shape[1], speedup_float_ptr, parameters_ptr)
|
74
|
+
if index_ptr.address == 0
|
75
|
+
require 'pry'
|
76
|
+
binding.pry
|
77
|
+
raise("failed to allocate index_ptr")
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# Return the speedup
|
82
|
+
speedup_float_ptr.read_float
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get the nearest neighbors based on this index. Forces a build of the index if one hasn't been done yet.
|
86
|
+
def nearest_neighbors testset, k, parameters = {}
|
87
|
+
parameters = Parameters.new(Flann::Parameters::DEFAULT.merge(parameters))
|
88
|
+
|
89
|
+
self.build! if index_ptr.nil?
|
90
|
+
|
91
|
+
parameters_ptr, parameters = Flann::handle_parameters(parameters)
|
92
|
+
result_size = testset.shape[0] * k
|
93
|
+
|
94
|
+
c_type = Flann::dtype_to_c(dataset.dtype)
|
95
|
+
c_method = "flann_find_nearest_neighbors_index_#{c_type}".to_sym
|
96
|
+
indices_int_ptr, distances_t_ptr = Flann::allocate_results_space(result_size, c_type)
|
97
|
+
|
98
|
+
Flann.send c_method, index_ptr,
|
99
|
+
FFI::Pointer.new_from_nmatrix(testset),
|
100
|
+
testset.shape[0],
|
101
|
+
indices_int_ptr, distances_t_ptr,
|
102
|
+
k,
|
103
|
+
parameters_ptr
|
104
|
+
|
105
|
+
|
106
|
+
[indices_int_ptr.read_array_of_int(result_size),
|
107
|
+
c_type == :double ? distances_t_ptr.read_array_of_double(result_size) : distances_t_ptr.read_array_of_float(result_size)]
|
108
|
+
end
|
109
|
+
|
110
|
+
# Perform a radius search on a single query point
|
111
|
+
def radius_search query, radius, max_k=nil, parameters = {}
|
112
|
+
max_k ||= dataset.shape[0]
|
113
|
+
parameters = Parameters.new(Flann::Parameters::DEFAULT.merge(parameters))
|
114
|
+
|
115
|
+
self.build! if index_ptr.nil?
|
116
|
+
parameters_ptr, parameters = Flann::handle_parameters(parameters)
|
117
|
+
|
118
|
+
c_type = Flann::dtype_to_c(dataset.dtype)
|
119
|
+
c_method = "flann_radius_search_#{c_type}".to_sym
|
120
|
+
indices_int_ptr, distances_t_ptr = Flann::allocate_results_space(max_k, c_type)
|
121
|
+
|
122
|
+
Flann.send(c_method, index_ptr, FFI::Pointer.new_from_nmatrix(query), indices_int_ptr, distances_t_ptr, max_k, radius, parameters_ptr)
|
123
|
+
|
124
|
+
# Return results: two arrays, one of indices and one of distances.
|
125
|
+
indices = indices_int_ptr.read_array_of_int(max_k)
|
126
|
+
distances = c_type == :double ? distances_t_ptr.read_array_of_double(max_k) : distances_t_ptr.read_array_of_float(max_k)
|
127
|
+
|
128
|
+
# Stop where indices == -1
|
129
|
+
cutoff = indices.find_index(-1)
|
130
|
+
cutoff.nil? ? [indices, distances] : [indices[0...cutoff], distances[0...cutoff]]
|
131
|
+
end
|
132
|
+
|
133
|
+
# Save an index to a file (without the dataset).
|
134
|
+
def save filename
|
135
|
+
raise(IOError, "Cannot write an unbuilt index") if index_ptr.nil? # FIXME: This should probably have its own exception type.
|
136
|
+
c_method = "flann_save_index_#{Flann::dtype_to_c(dtype)}".to_sym
|
137
|
+
Flann.send(c_method, index_ptr, filename)
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
# Load an index from a file (with the dataset already known!).
|
142
|
+
#
|
143
|
+
# FIXME: This needs to free the previous dataset first.
|
144
|
+
def load! filename
|
145
|
+
c_method = "flann_load_index_#{Flann::dtype_to_c(dtype)}".to_sym
|
146
|
+
|
147
|
+
@index_ptr = Flann.send(c_method, filename, FFI::Pointer.new_from_nmatrix(dataset), dataset.shape[0], dataset.shape[1])
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
# Free an index
|
152
|
+
def free! parameters = {}
|
153
|
+
parameters = Parameters.new(Flann::Parameters::DEFAULT.merge(parameters))
|
154
|
+
c_method = "flann_free_index_#{Flann::dtype_to_c(dtype)}".to_sym
|
155
|
+
parameters_ptr, parameters = Flann::handle_parameters(parameters)
|
156
|
+
Flann.send(c_method, index_ptr, parameters_ptr)
|
157
|
+
@index_ptr = nil
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright 2014 John O. Woods (john.o.woods@gmail.com), West Virginia
|
2
|
+
# University's Applied Space Exploration Lab, and West Virginia Robotic
|
3
|
+
# Technology Center. All rights reserved.
|
4
|
+
#
|
5
|
+
# THE BSD LICENSE
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions
|
9
|
+
# are met:
|
10
|
+
#
|
11
|
+
# 1. Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
module Flann
|
29
|
+
module VERSION
|
30
|
+
MAJOR = 1
|
31
|
+
MINOR = 8
|
32
|
+
TINY = 4
|
33
|
+
MINISCULE = 2
|
34
|
+
|
35
|
+
STRING = [MAJOR, MINOR, TINY, MINISCULE].compact.join('.')
|
36
|
+
end
|
37
|
+
end
|
data/spec/flann_spec.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright 2014 John O. Woods (john.o.woods@gmail.com), West Virginia
|
2
|
+
# University's Applied Space Exploration Lab, and West Virginia Robotic
|
3
|
+
# Technology Center. All rights reserved.
|
4
|
+
#
|
5
|
+
# THE BSD LICENSE
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions
|
9
|
+
# are met:
|
10
|
+
#
|
11
|
+
# 1. Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
require File.dirname(__FILE__) + "/spec_helper.rb"
|
29
|
+
|
30
|
+
describe Flann do
|
31
|
+
|
32
|
+
it "::VERSION::STRING matches #define FLANN_VERSION_ in config.h" do
|
33
|
+
found = false
|
34
|
+
File.open(File.dirname(__FILE__) + "/../../cpp/flann/config.h", "r") do |f|
|
35
|
+
while line = f.gets
|
36
|
+
next unless line =~ /#[\s]*define[\s]+FLANN_VERSION_[\s]+"\d.\d.\d"/
|
37
|
+
fields = line.split
|
38
|
+
found = true
|
39
|
+
expect(fields.last[1...-1]).to eq(Flann::VERSION::STRING.split('.')[0...-1].join('.'))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
raise("could not find version string in config.h") unless found
|
44
|
+
end
|
45
|
+
|
46
|
+
it "works on the example given in the manual" do
|
47
|
+
dataset = NMatrix.random([10000,128])
|
48
|
+
testset = NMatrix.random([1000,128])
|
49
|
+
|
50
|
+
index = Flann::Index.new(dataset) do |params|
|
51
|
+
params[:algorithm] = :kmeans
|
52
|
+
params[:branching] = 32
|
53
|
+
params[:iterations] = 7
|
54
|
+
params[:checks] = 16
|
55
|
+
end
|
56
|
+
speedup = index.build! # this is optional
|
57
|
+
|
58
|
+
results, distances = index.nearest_neighbors(testset, 5)
|
59
|
+
|
60
|
+
# Skip saving, as that's tested elsewhere, and I don't feel like cleaning up.
|
61
|
+
# index.save "my_index.save"
|
62
|
+
|
63
|
+
# Alternatively, without an index:
|
64
|
+
results, distances = Flann.nearest_neighbors(dataset, testset, 5,
|
65
|
+
algorithm: :kmeans, branching: 32,
|
66
|
+
iterations: 7, checks: 16)
|
67
|
+
end
|
68
|
+
|
69
|
+
context "#set_distance_type!" do
|
70
|
+
it "sets the distance functor without error" do
|
71
|
+
Flann.set_distance_type! :euclidean
|
72
|
+
|
73
|
+
# Version check needed before attempting get_distance_type
|
74
|
+
if Flann.respond_to?(:flann_get_distance_type)
|
75
|
+
d = Flann.get_distance_type
|
76
|
+
expect(d).to eq(:euclidean)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
[:byte, :int32, :float32, :float64].each do |dtype|
|
82
|
+
before :each do
|
83
|
+
scale = [:byte, :int32, :int64].include?(dtype) ? 255 : 1.0
|
84
|
+
@dataset = NMatrix.random([1000,128], dtype: dtype, scale: scale)
|
85
|
+
@testset = NMatrix.random([100,128], dtype: dtype, scale: scale)
|
86
|
+
end
|
87
|
+
|
88
|
+
context "#nearest_neighbors" do
|
89
|
+
it "computes the nearest neighbors without an index" do
|
90
|
+
Flann.nearest_neighbors @dataset, @testset, 5
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "#cluster" do
|
95
|
+
it "calls flann_compute_cluster_centers_... properly" do
|
96
|
+
Flann.cluster(@dataset, 5)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
end
|
data/spec/index_spec.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright 2014 John O. Woods (john.o.woods@gmail.com), West Virginia
|
2
|
+
# University's Applied Space Exploration Lab, and West Virginia Robotic
|
3
|
+
# Technology Center. All rights reserved.
|
4
|
+
#
|
5
|
+
# THE BSD LICENSE
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions
|
9
|
+
# are met:
|
10
|
+
#
|
11
|
+
# 1. Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
require File.dirname(__FILE__) + "/spec_helper.rb"
|
29
|
+
|
30
|
+
|
31
|
+
describe Flann::Index do
|
32
|
+
[:byte, :int32, :float32, :float64].each do |dtype|
|
33
|
+
context dtype.inspect do
|
34
|
+
before :each do
|
35
|
+
scale = [:byte, :int32, :int64].include?(dtype) ? 255 : 1.0
|
36
|
+
|
37
|
+
@dataset = NMatrix.random([1000,128], dtype: dtype, scale: scale)
|
38
|
+
@testset = NMatrix.random([100,128], dtype: dtype, scale: scale)
|
39
|
+
@index = Flann::Index.new(@dataset) do |t|
|
40
|
+
t[:algorithm] = :kdtree
|
41
|
+
t[:trees] = 4
|
42
|
+
end
|
43
|
+
@index.build!
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
context "#nearest_neighbors" do
|
48
|
+
it "runs without error" do
|
49
|
+
@index.nearest_neighbors @testset, 5
|
50
|
+
end
|
51
|
+
|
52
|
+
if dtype == :float32
|
53
|
+
it "runs a :kdtree_single search correctly" do
|
54
|
+
@dataset = read_dataset "test.dataset"
|
55
|
+
@testset = @dataset[0,:*].clone
|
56
|
+
@index = Flann::Index.new(@dataset) do |t|
|
57
|
+
t[:algorithm] = :kdtree_single
|
58
|
+
end
|
59
|
+
@index.build!
|
60
|
+
indices, distances = @index.nearest_neighbors @testset, 11
|
61
|
+
#expect(indices).to eq([0,1,256,257,2,512,258,513,514,3,768])
|
62
|
+
expect(indices[0]).to eq(0)
|
63
|
+
expect(indices[1..2].sort).to eq([1,256])
|
64
|
+
expect(indices[3]).to eq(257)
|
65
|
+
expect(indices[4..5].sort).to eq([2,512])
|
66
|
+
expect(indices[6..7].sort).to eq([258,513])
|
67
|
+
expect(indices[8]).to eq(514)
|
68
|
+
expect(indices[9..10].sort).to eq([3,768])
|
69
|
+
|
70
|
+
expect(distances[0]).to be_within(1E-16).of(0.0)
|
71
|
+
expect(distances[1]).to be_within(1E-4).of(2.614689)
|
72
|
+
expect(distances[2]).to be_within(1E-4).of(2.614689)
|
73
|
+
expect(distances[3]).to be_within(1E-4).of(5.229378)
|
74
|
+
expect(distances[4]).to be_within(1E-4).of(10.465225)
|
75
|
+
expect(distances[5]).to be_within(1E-4).of(10.465225)
|
76
|
+
expect(distances[6]).to be_within(1E-4).of(13.079914)
|
77
|
+
expect(distances[7]).to be_within(1E-4).of(13.079914)
|
78
|
+
expect(distances[8]).to be_within(1E-4).of(20.93045)
|
79
|
+
expect(distances[9]).to be_within(1E-4).of(23.541904)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
context "#radius_search" do
|
86
|
+
it "runs without error" do
|
87
|
+
query = NMatrix.random([1,128])
|
88
|
+
@index.radius_search query, 0.4
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
context "#save" do
|
94
|
+
it "saves an index to a file which can be loaded again" do
|
95
|
+
FileUtils.rm("temp_index.save_file", :force => true)
|
96
|
+
@index.save("temp_index.save_file")
|
97
|
+
|
98
|
+
raise(IOError, "save failed") unless File.exists?("temp_index.save_file")
|
99
|
+
|
100
|
+
post_index = Flann::Index.new(@dataset)
|
101
|
+
post_index.load!("temp_index.save_file")
|
102
|
+
FileUtils.rm("temp_index.save_file", :force => true)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
context "#free!" do
|
108
|
+
it "frees an index" do
|
109
|
+
@index.free!
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright 2014 John O. Woods (john.o.woods@gmail.com), West Virginia
|
2
|
+
# University's Applied Space Exploration Lab, and West Virginia Robotic
|
3
|
+
# Technology Center. All rights reserved.
|
4
|
+
#
|
5
|
+
# THE BSD LICENSE
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions
|
9
|
+
# are met:
|
10
|
+
#
|
11
|
+
# 1. Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
require 'rspec'
|
29
|
+
require 'rspec/longrun'
|
30
|
+
|
31
|
+
require "./lib/flann"
|
32
|
+
|
33
|
+
# Helper function for reading a test dataset so we can test nearest neighbors
|
34
|
+
# and radius search and such.
|
35
|
+
def read_dataset filename
|
36
|
+
Dir.chdir("spec") do
|
37
|
+
f = File.new(filename, 'r')
|
38
|
+
n = NMatrix.new([65536, 3], dtype: :float32)
|
39
|
+
i = 0
|
40
|
+
while line = f.gets
|
41
|
+
line.chomp!
|
42
|
+
fields = line.split
|
43
|
+
n[i,:*] = fields.map { |field| field.to_f }
|
44
|
+
|
45
|
+
i += 1
|
46
|
+
end
|
47
|
+
|
48
|
+
n
|
49
|
+
end
|
50
|
+
end
|