ngt 0.4.0 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 056e77fc31169b9c0402c1460eebe72aa3a40ec105d3b7974dcef2b5846c6ed5
4
- data.tar.gz: cf99943c13969f7529a6b4371d38f139479bb24015a68382a091bb7446d25a1f
3
+ metadata.gz: a8a99eccfae3fd0f09f5566ec99d240049e34a4a5ddff73ef26333bad6070932
4
+ data.tar.gz: ea4dae9eee921e69078ca04eb76c67ceb8c3f00ba368b6c76809a8f98b39478e
5
5
  SHA512:
6
- metadata.gz: d5a0a3760d14a415e1c16adec206063fd60f3bc0957ccf470e3b588bae4f331d9f9ab7ab80da117e44e25ae6a384d8873228856582f8da6804cce8b72c696188
7
- data.tar.gz: 0e78ecd9a477c76a2f77c3ae2242a6886e02daf6ce8c6af99b9e1a50745a38b4f51a91472a936611b383db3f1e176798d4472393250c4d2cd334d8692ddd58ff
6
+ metadata.gz: 67f096ab1115949bba0606db499790ee6168fada1f06f7b9b46a1631c3f7f2311f9babbdd374afc0dea5dbba5d9a44721f7d8d8a61882c73bc44c043c3f5c258
7
+ data.tar.gz: 4b44ba3724255e3deb15a52be30a7856ef76f2c47ad5be75a2f9535561058f3dc3dc12a682063054d812f581a266ae423f819ded4fd7c6d1e827c27ca4006595
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.4.2 (2023-07-24)
2
+
3
+ - Fixed error with `dup` and `clone`
4
+
5
+ ## 0.4.1 (2022-12-08)
6
+
7
+ - Added support for `:float16` object type
8
+ - Fixed error with `object` method
9
+
1
10
  ## 0.4.0 (2022-06-14)
2
11
 
3
12
  - Updated NGT to 1.14.6
data/lib/ngt/ffi.rb CHANGED
@@ -36,8 +36,10 @@ module Ngt
36
36
  attach_function :ngt_set_property_edge_size_for_creation, %i[pointer int16_t pointer], :bool
37
37
  attach_function :ngt_set_property_edge_size_for_search, %i[pointer int16_t pointer], :bool
38
38
  attach_function :ngt_is_property_object_type_float, %i[int32_t], :bool
39
+ attach_function :ngt_is_property_object_type_float16, %i[int32_t], :bool
39
40
  attach_function :ngt_get_property_object_type, %i[pointer pointer], :int32_t
40
41
  attach_function :ngt_set_property_object_type_float, %i[pointer pointer], :bool
42
+ attach_function :ngt_set_property_object_type_float16, %i[pointer pointer], :bool
41
43
  attach_function :ngt_set_property_object_type_integer, %i[pointer pointer], :bool
42
44
  attach_function :ngt_set_property_distance_type_l1, %i[pointer pointer], :bool
43
45
  attach_function :ngt_set_property_distance_type_l2, %i[pointer pointer], :bool
@@ -67,11 +69,21 @@ module Ngt
67
69
  attach_function :ngt_get_property_distance_type, %i[pointer pointer], :distance_type
68
70
  attach_function :ngt_create_error_object, %i[], :pointer
69
71
  attach_function :ngt_get_error_string, %i[pointer], :string
72
+ attach_function :ngt_clear_error_string, %i[pointer], :void
70
73
  attach_function :ngt_destroy_error_object, %i[pointer], :void
71
74
  attach_function :ngt_create_optimizer, %i[bool pointer], :pointer
72
75
  attach_function :ngt_optimizer_adjust_search_coefficients, %i[pointer string pointer], :bool
73
76
  attach_function :ngt_optimizer_execute, %i[pointer string string pointer], :bool
74
77
  attach_function :ngt_optimizer_set, %i[pointer int int int float float float float double double pointer], :bool
75
78
  attach_function :ngt_destroy_optimizer, %i[pointer], :void
79
+
80
+ def self.add_finalizer(pointer, method)
81
+ ObjectSpace.define_finalizer(pointer, finalize(pointer.to_i, method))
82
+ end
83
+
84
+ def self.finalize(addr, method)
85
+ # must use proc instead of stabby lambda
86
+ proc { FFI.send(method, ::FFI::Pointer.new(:pointer, addr)) }
87
+ end
76
88
  end
77
89
  end
data/lib/ngt/index.rb CHANGED
@@ -9,10 +9,11 @@ module Ngt
9
9
  @path = path
10
10
 
11
11
  @error = FFI.ngt_create_error_object
12
+ FFI.add_finalizer(@error, :ngt_destroy_error_object)
13
+
12
14
  @property = ffi(:ngt_create_property)
15
+ FFI.add_finalizer(@property, :ngt_destroy_property)
13
16
  ffi(:ngt_get_property, @index, @property)
14
-
15
- ObjectSpace.define_finalizer(self, self.class.finalize(@error, @index, @property))
16
17
  end
17
18
 
18
19
  def dimensions
@@ -34,22 +35,34 @@ module Ngt
34
35
  def object_type
35
36
  @object_type ||= begin
36
37
  object_type = ffi(:ngt_get_property_object_type, @property)
37
- FFI.ngt_is_property_object_type_float(object_type) ? :float : :integer
38
+ if FFI.ngt_is_property_object_type_float(object_type)
39
+ :float
40
+ elsif FFI.ngt_is_property_object_type_float16(object_type)
41
+ :float16
42
+ else
43
+ :integer
44
+ end
38
45
  end
39
46
  end
40
47
 
41
48
  def insert(object)
42
- ffi(:ngt_insert_index, @index, c_object(object.to_a), dimensions)
49
+ object = object.to_a
50
+ ffi(:ngt_insert_index, @index, c_object(object), object.size)
43
51
  end
44
52
 
45
53
  def batch_insert(objects, num_threads: 8)
46
54
  if narray?(objects)
55
+ check_dimensions(objects.shape[1])
56
+
47
57
  objects = objects.cast_to(Numo::SFloat) unless objects.is_a?(Numo::SFloat)
48
58
  count = objects.shape[0]
49
59
  obj = ::FFI::MemoryPointer.new(:char, objects.byte_size)
50
60
  obj.write_bytes(objects.to_binary)
51
61
  else
52
62
  objects = objects.to_a
63
+ objects.each do |object|
64
+ check_dimensions(object.size)
65
+ end
53
66
  count = objects.size
54
67
  flat_objects = objects.flatten
55
68
  obj = ::FFI::MemoryPointer.new(:float, flat_objects.size)
@@ -70,11 +83,13 @@ module Ngt
70
83
 
71
84
  def object(id)
72
85
  if object_type == :float
73
- res = ffi(:ngt_get_object_as_float, @object_space, id)
86
+ res = ffi(:ngt_get_object_as_float, object_space, id)
74
87
  res.read_array_of_float(dimensions)
75
- else
76
- res = ffi(:ngt_get_object_as_integer, @object_space, id)
88
+ elsif object_type == :integer
89
+ res = ffi(:ngt_get_object_as_integer, object_space, id)
77
90
  res.read_array_of_uint8(dimensions)
91
+ else
92
+ raise Error, "Method not supported for this object type"
78
93
  end
79
94
  end
80
95
 
@@ -85,7 +100,8 @@ module Ngt
85
100
  def search(query, size: 20, epsilon: 0.1, radius: nil)
86
101
  radius ||= -1.0
87
102
  results = ffi(:ngt_create_empty_results)
88
- ffi(:ngt_search_index, @index, c_object(query.to_a), dimensions, size, epsilon, radius, results)
103
+ query = query.to_a
104
+ ffi(:ngt_search_index, @index, c_object(query), query.size, size, epsilon, radius, results)
89
105
  result_size = ffi(:ngt_get_result_size, results)
90
106
  ret = []
91
107
  result_size.times do |i|
@@ -125,6 +141,8 @@ module Ngt
125
141
  case object_type.to_s.downcase
126
142
  when "float"
127
143
  ffi(:ngt_set_property_object_type_float, property, error)
144
+ when "float16"
145
+ ffi(:ngt_set_property_object_type_float16, property, error)
128
146
  when "integer"
129
147
  ffi(:ngt_set_property_object_type_integer, property, error)
130
148
  else
@@ -160,6 +178,8 @@ module Ngt
160
178
  end
161
179
  end
162
180
 
181
+ FFI.add_finalizer(index, :ngt_close_index)
182
+
163
183
  super(index, path)
164
184
  ensure
165
185
  FFI.ngt_destroy_error_object(error) if error
@@ -180,15 +200,6 @@ module Ngt
180
200
  Utils.ffi(*args)
181
201
  end
182
202
 
183
- def self.finalize(error, index, property)
184
- # must use proc instead of stabby lambda
185
- proc do
186
- FFI.ngt_destroy_error_object(error)
187
- FFI.ngt_close_index(index)
188
- FFI.ngt_destroy_property(property)
189
- end
190
- end
191
-
192
203
  private
193
204
 
194
205
  def narray?(data)
@@ -196,9 +207,18 @@ module Ngt
196
207
  end
197
208
 
198
209
  def c_object(object)
210
+ check_dimensions(object.size)
199
211
  c_object = ::FFI::MemoryPointer.new(:double, object.size)
200
212
  c_object.write_array_of_double(object)
201
213
  c_object
202
214
  end
215
+
216
+ def check_dimensions(d)
217
+ raise ArgumentError, "Bad dimensions" if d != dimensions
218
+ end
219
+
220
+ def object_space
221
+ @object_space ||= ffi(:ngt_get_object_space, @index)
222
+ end
203
223
  end
204
224
  end
data/lib/ngt/optimizer.rb CHANGED
@@ -4,12 +4,13 @@ module Ngt
4
4
 
5
5
  def initialize(outgoing: 10, incoming: 120, queries: 100, low_accuracy_from: 0.3, low_accuracy_to: 0.5, high_accuracy_from: 0.8, high_accuracy_to: 0.9, gt_epsilon: 0.1, merge: 0.2)
6
6
  @error = FFI.ngt_create_error_object
7
+ FFI.add_finalizer(@error, :ngt_destroy_error_object)
8
+
7
9
  @optimizer = ffi(:ngt_create_optimizer, true)
10
+ FFI.add_finalizer(@optimizer, :ngt_destroy_optimizer)
8
11
 
9
12
  ffi(:ngt_optimizer_set, @optimizer, outgoing, incoming, queries, low_accuracy_from,
10
13
  low_accuracy_to, high_accuracy_from, high_accuracy_to, gt_epsilon, merge)
11
-
12
- ObjectSpace.define_finalizer(self, self.class.finalize(@optimizer, @error))
13
14
  end
14
15
 
15
16
  def execute(in_index_path, out_index_path)
@@ -20,14 +21,6 @@ module Ngt
20
21
  ffi(:ngt_optimizer_adjust_search_coefficients, @optimizer, path(index_path))
21
22
  end
22
23
 
23
- def self.finalize(optimizer, error)
24
- # must use proc instead of stabby lambda
25
- proc do
26
- FFI.ngt_destroy_optimizer(optimizer)
27
- FFI.ngt_destroy_error_object(error)
28
- end
29
- end
30
-
31
24
  private
32
25
 
33
26
  def path(obj)
data/lib/ngt/utils.rb CHANGED
@@ -4,7 +4,10 @@ module Ngt
4
4
  def self.ffi(method, *args)
5
5
  res = FFI.send(method, *args)
6
6
  message = FFI.ngt_get_error_string(args.last)
7
- raise Error, message unless message.empty?
7
+ unless message.empty?
8
+ FFI.ngt_clear_error_string(args.last)
9
+ raise Error, message
10
+ end
8
11
  res
9
12
  end
10
13
 
data/lib/ngt/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ngt
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.2"
3
3
  end
data/lib/ngt.rb CHANGED
@@ -5,10 +5,10 @@ require "ffi"
5
5
  require "tmpdir"
6
6
 
7
7
  # modules
8
- require "ngt/utils"
9
- require "ngt/index"
10
- require "ngt/optimizer"
11
- require "ngt/version"
8
+ require_relative "ngt/utils"
9
+ require_relative "ngt/index"
10
+ require_relative "ngt/optimizer"
11
+ require_relative "ngt/version"
12
12
 
13
13
  module Ngt
14
14
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ngt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-15 00:00:00.000000000 Z
11
+ date: 2023-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -71,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  - !ruby/object:Gem::Version
72
72
  version: '0'
73
73
  requirements: []
74
- rubygems_version: 3.3.7
74
+ rubygems_version: 3.4.10
75
75
  signing_key:
76
76
  specification_version: 4
77
77
  summary: High-speed approximate nearest neighbors for Ruby