Class: Flann::Index

Inherits:
Object
  • Object
show all
Defined in:
lib/flann/index.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(index_dataset = nil, dtype: :float64, parameters: Flann::Parameters::DEFAULT) {|@parameters| ... } ⇒ Index

Constructor takes a block where we set each of the parameters. We need to be careful to do this since we’re using the C API and not C++; so everything important needs to be initialized or there could be a segfault. For reasonable default definitions, see:

Yields:



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/flann/index.rb', line 48

def initialize index_dataset = nil, dtype: :float64, parameters: Flann::Parameters::DEFAULT
  @dataset        = index_dataset
  #require 'pry'
  #binding.pry if @dataset.nil?
  @dtype          = (!index_dataset.nil? && index_dataset.is_a?(NMatrix)) ? index_dataset.dtype : dtype
  @index_ptr      = nil

  @parameters_ptr, @parameters = Flann::handle_parameters(parameters)

  yield @parameters if block_given?
end

Instance Attribute Details

#datasetObject

Returns the value of attribute dataset.



59
60
61
# File 'lib/flann/index.rb', line 59

def dataset
  @dataset
end

#dtypeObject (readonly)

Returns the value of attribute dtype.



59
60
61
# File 'lib/flann/index.rb', line 59

def dtype
  @dtype
end

#index_ptrObject (readonly)

Returns the value of attribute index_ptr.



59
60
61
# File 'lib/flann/index.rb', line 59

def index_ptr
  @index_ptr
end

#parametersObject (readonly)

Returns the value of attribute parameters.



59
60
61
# File 'lib/flann/index.rb', line 59

def parameters
  @parameters
end

#parameters_ptrObject (readonly)

Returns the value of attribute parameters_ptr.



59
60
61
# File 'lib/flann/index.rb', line 59

def parameters_ptr
  @parameters_ptr
end

Instance Method Details

#build!Object

Build an index



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/flann/index.rb', line 68

def build!
  raise("no dataset specified") if dataset.nil?
  c_type   = Flann::dtype_to_c(dtype)
  c_method = "flann_build_index_#{c_type}".to_sym
  speedup_float_ptr = FFI::MemoryPointer.new(:float)
  @index_ptr = Flann.send(c_method, FFI::Pointer.new_from_nmatrix(dataset), dataset.shape[0], dataset.shape[1], speedup_float_ptr, parameters_ptr)
  if index_ptr.address == 0
    require 'pry'
    binding.pry
    raise("failed to allocate index_ptr")
  end


  # Return the speedup
  speedup_float_ptr.read_float
end

#free!(parameters = {}) ⇒ Object

Free an index



152
153
154
155
156
157
158
159
# File 'lib/flann/index.rb', line 152

def free! parameters = {}
  parameters = Parameters.new(Flann::Parameters::DEFAULT.merge(parameters))
  c_method = "flann_free_index_#{Flann::dtype_to_c(dtype)}".to_sym
  parameters_ptr, parameters = Flann::handle_parameters(parameters)
  Flann.send(c_method, index_ptr, parameters_ptr)
  @index_ptr = nil
  self
end

#load!(filename) ⇒ Object

Load an index from a file (with the dataset already known!).

FIXME: This needs to free the previous dataset first.



144
145
146
147
148
149
# File 'lib/flann/index.rb', line 144

def load! filename
  c_method = "flann_load_index_#{Flann::dtype_to_c(dtype)}".to_sym

  @index_ptr = Flann.send(c_method, filename, FFI::Pointer.new_from_nmatrix(dataset), dataset.shape[0], dataset.shape[1])
  self
end

#nearest_neighbors(testset, k, parameters = {}) ⇒ Object

Get the nearest neighbors based on this index. Forces a build of the index if one hasn’t been done yet.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/flann/index.rb', line 86

def nearest_neighbors testset, k, parameters = {}
  parameters = Parameters.new(Flann::Parameters::DEFAULT.merge(parameters))

  self.build! if index_ptr.nil?

  parameters_ptr, parameters = Flann::handle_parameters(parameters)
  result_size = testset.shape[0] * k

  c_type = Flann::dtype_to_c(dataset.dtype)
  c_method = "flann_find_nearest_neighbors_index_#{c_type}".to_sym
  indices_int_ptr, distances_t_ptr = Flann::allocate_results_space(result_size, c_type)

  Flann.send c_method, index_ptr,
                       FFI::Pointer.new_from_nmatrix(testset),
                       testset.shape[0],
                       indices_int_ptr, distances_t_ptr,
                       k,
                       parameters_ptr


  [indices_int_ptr.read_array_of_int(result_size),
   c_type == :double ? distances_t_ptr.read_array_of_double(result_size) : distances_t_ptr.read_array_of_float(result_size)]
end

#radius_search(query, radius, max_k = nil, parameters = {}) ⇒ Object

Perform a radius search on a single query point



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/flann/index.rb', line 111

def radius_search query, radius, max_k=nil, parameters = {}
  max_k    ||= dataset.shape[0]
  parameters = Parameters.new(Flann::Parameters::DEFAULT.merge(parameters))

  self.build! if index_ptr.nil?
  parameters_ptr, parameters = Flann::handle_parameters(parameters)

  c_type = Flann::dtype_to_c(dataset.dtype)
  c_method = "flann_radius_search_#{c_type}".to_sym
  indices_int_ptr, distances_t_ptr = Flann::allocate_results_space(max_k, c_type)

  Flann.send(c_method, index_ptr, FFI::Pointer.new_from_nmatrix(query), indices_int_ptr, distances_t_ptr, max_k, radius, parameters_ptr)

  # Return results: two arrays, one of indices and one of distances.
  indices   = indices_int_ptr.read_array_of_int(max_k)
  distances = c_type == :double ? distances_t_ptr.read_array_of_double(max_k) : distances_t_ptr.read_array_of_float(max_k)

  # Stop where indices == -1
  cutoff = indices.find_index(-1)
  cutoff.nil? ? [indices, distances] : [indices[0...cutoff], distances[0...cutoff]]
end

#save(filename) ⇒ Object

Save an index to a file (without the dataset).

Raises:

  • (IOError)


134
135
136
137
138
139
# File 'lib/flann/index.rb', line 134

def save filename
  raise(IOError, "Cannot write an unbuilt index") if index_ptr.nil?     # FIXME: This should probably have its own exception type.
  c_method = "flann_save_index_#{Flann::dtype_to_c(dtype)}".to_sym
  Flann.send(c_method, index_ptr, filename)
  self
end