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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/ngt/ffi.rb +12 -0
- data/lib/ngt/index.rb +37 -17
- data/lib/ngt/optimizer.rb +3 -10
- data/lib/ngt/utils.rb +4 -1
- data/lib/ngt/version.rb +1 -1
- data/lib/ngt.rb +4 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8a99eccfae3fd0f09f5566ec99d240049e34a4a5ddff73ef26333bad6070932
|
4
|
+
data.tar.gz: ea4dae9eee921e69078ca04eb76c67ceb8c3f00ba368b6c76809a8f98b39478e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67f096ab1115949bba0606db499790ee6168fada1f06f7b9b46a1631c3f7f2311f9babbdd374afc0dea5dbba5d9a44721f7d8d8a61882c73bc44c043c3f5c258
|
7
|
+
data.tar.gz: 4b44ba3724255e3deb15a52be30a7856ef76f2c47ad5be75a2f9535561058f3dc3dc12a682063054d812f581a266ae423f819ded4fd7c6d1e827c27ca4006595
|
data/CHANGELOG.md
CHANGED
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)
|
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
|
-
|
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,
|
86
|
+
res = ffi(:ngt_get_object_as_float, object_space, id)
|
74
87
|
res.read_array_of_float(dimensions)
|
75
|
-
|
76
|
-
res = ffi(:ngt_get_object_as_integer,
|
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
|
-
|
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
|
-
|
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
data/lib/ngt.rb
CHANGED
@@ -5,10 +5,10 @@ require "ffi"
|
|
5
5
|
require "tmpdir"
|
6
6
|
|
7
7
|
# modules
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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.
|
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:
|
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.
|
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
|