ngt 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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