ngt 0.2.4 → 0.3.0
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 +7 -0
- data/README.md +7 -1
- data/lib/ngt/ffi.rb +10 -4
- data/lib/ngt/index.rb +87 -71
- data/lib/ngt/optimizer.rb +6 -1
- data/lib/ngt/version.rb +1 -1
- data/vendor/libngt.dylib +0 -0
- data/vendor/libngt.so +0 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6b9362e0da232f074b026b2545275061b9bac6e6124d6927e1bb7d798ac61e1
|
4
|
+
data.tar.gz: afa434689a718d77e944e12c8322258d6e5c064e99545f872c5d6cb1cffa614e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e676a72eda431ab954a1dcd77e6e7ae2ed843eb3bff1dcc8ae479b1c176a99bfaaa1dd27a6f79ef2f7eca0f6ceb6a35a5bf74a58b38cdda46b676aa0b5adc2d
|
7
|
+
data.tar.gz: ee1b5d27e178712b42ba9d5a6380e0c1d0ea9a9ac6e5941fca60fdd3a4e2ea5d9266f31dfdd79f117fe7fba08bbb92a21d93a363168ca36aa839d303c9e9deae
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -12,6 +12,12 @@ Add this line to your application’s Gemfile:
|
|
12
12
|
gem 'ngt'
|
13
13
|
```
|
14
14
|
|
15
|
+
On Mac, also install OpenMP:
|
16
|
+
|
17
|
+
```sh
|
18
|
+
brew install libomp
|
19
|
+
```
|
20
|
+
|
15
21
|
NGT is not available for Windows
|
16
22
|
|
17
23
|
## Getting Started
|
@@ -118,7 +124,7 @@ Ngt::Index.new(dimensions,
|
|
118
124
|
edge_size_for_creation: 10,
|
119
125
|
edge_size_for_search: 40,
|
120
126
|
object_type: :float, # :float, :integer
|
121
|
-
distance_type: :l2, # :l1, :l2, :hamming, :angle, :cosine,
|
127
|
+
distance_type: :l2, # :l1, :l2, :hamming, :angle, :cosine, :normalized_angle, :normalized_cosine, :jaccard
|
122
128
|
path: nil
|
123
129
|
)
|
124
130
|
```
|
data/lib/ngt/ffi.rb
CHANGED
@@ -15,8 +15,11 @@ module Ngt
|
|
15
15
|
:distance, :float
|
16
16
|
end
|
17
17
|
|
18
|
+
enum :distance_type, [:l1, :l2, :hamming, :angle, :cosine, :normalized_angle, :normalized_cosine, :jaccard]
|
19
|
+
|
18
20
|
attach_function :ngt_open_index, %i[string pointer], :pointer
|
19
21
|
attach_function :ngt_create_graph_and_tree, %i[string pointer pointer], :pointer
|
22
|
+
attach_function :ngt_create_graph_and_tree_in_memory, %i[pointer pointer], :pointer
|
20
23
|
attach_function :ngt_create_property, %i[pointer], :pointer
|
21
24
|
attach_function :ngt_save_index, %i[pointer string pointer], :bool
|
22
25
|
attach_function :ngt_get_property, %i[pointer pointer pointer], :bool
|
@@ -34,23 +37,26 @@ module Ngt
|
|
34
37
|
attach_function :ngt_set_property_distance_type_hamming, %i[pointer pointer], :bool
|
35
38
|
attach_function :ngt_set_property_distance_type_jaccard, %i[pointer pointer], :bool
|
36
39
|
attach_function :ngt_set_property_distance_type_cosine, %i[pointer pointer], :bool
|
37
|
-
attach_function :
|
38
|
-
attach_function :
|
39
|
-
attach_function :ngt_remove_index, %i[pointer int pointer], :bool
|
40
|
+
attach_function :ngt_set_property_distance_type_normalized_angle, %i[pointer pointer], :bool
|
41
|
+
attach_function :ngt_set_property_distance_type_normalized_cosine, %i[pointer pointer], :bool
|
40
42
|
attach_function :ngt_insert_index, %i[pointer pointer uint32 pointer], :int
|
41
43
|
attach_function :ngt_insert_index_as_float, %i[pointer pointer uint32 pointer], :int
|
42
44
|
attach_function :ngt_create_empty_results, %i[pointer], :pointer
|
43
45
|
attach_function :ngt_search_index, %i[pointer pointer int32 size_t float float pointer pointer], :bool
|
44
46
|
attach_function :ngt_get_result_size, %i[pointer pointer], :uint32
|
45
47
|
attach_function :ngt_get_result, %i[pointer uint32 pointer], ObjectDistance.by_value
|
48
|
+
attach_function :ngt_batch_insert_index, %i[pointer pointer uint32 pointer pointer], :bool
|
49
|
+
attach_function :ngt_create_index, %i[pointer uint32 pointer], :bool
|
50
|
+
attach_function :ngt_remove_index, %i[pointer int pointer], :bool
|
46
51
|
attach_function :ngt_get_object_space, %i[pointer pointer], :pointer
|
47
52
|
attach_function :ngt_get_object_as_float, %i[pointer int pointer], :pointer
|
48
53
|
attach_function :ngt_get_object_as_integer, %i[pointer int pointer], :pointer
|
54
|
+
attach_function :ngt_destroy_results, %i[pointer], :void
|
49
55
|
attach_function :ngt_destroy_property, %i[pointer], :void
|
50
56
|
attach_function :ngt_close_index, %i[pointer], :void
|
51
57
|
attach_function :ngt_get_property_edge_size_for_creation, %i[pointer pointer], :int16
|
52
58
|
attach_function :ngt_get_property_edge_size_for_search, %i[pointer pointer], :int16
|
53
|
-
attach_function :ngt_get_property_distance_type, %i[pointer pointer], :
|
59
|
+
attach_function :ngt_get_property_distance_type, %i[pointer pointer], :distance_type
|
54
60
|
attach_function :ngt_create_error_object, %i[], :pointer
|
55
61
|
attach_function :ngt_get_error_string, %i[pointer], :string
|
56
62
|
attach_function :ngt_destroy_error_object, %i[pointer], :void
|
data/lib/ngt/index.rb
CHANGED
@@ -2,34 +2,44 @@ module Ngt
|
|
2
2
|
class Index
|
3
3
|
include Utils
|
4
4
|
|
5
|
-
|
5
|
+
attr_reader :path
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(path)
|
7
|
+
def initialize(index, path)
|
8
|
+
@index = index
|
10
9
|
@path = path
|
10
|
+
|
11
11
|
@error = FFI.ngt_create_error_object
|
12
|
-
@
|
12
|
+
@property = ffi(:ngt_create_property)
|
13
|
+
ffi(:ngt_get_property, @index, @property)
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(@error, @index, @property))
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
@
|
19
|
-
|
20
|
-
@edge_size_for_search = ffi(:ngt_get_property_edge_size_for_search, property)
|
18
|
+
def dimensions
|
19
|
+
@dimensions ||= ffi(:ngt_get_property_dimension, @property)
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
@
|
24
|
-
|
22
|
+
def distance_type
|
23
|
+
@distance_type ||= ffi(:ngt_get_property_distance_type, @property)
|
24
|
+
end
|
25
25
|
|
26
|
-
|
26
|
+
def edge_size_for_creation
|
27
|
+
@edge_size_for_creation ||= ffi(:ngt_get_property_edge_size_for_creation, @property)
|
28
|
+
end
|
29
|
+
|
30
|
+
def edge_size_for_search
|
31
|
+
@edge_size_for_search ||= ffi(:ngt_get_property_edge_size_for_search, @property)
|
32
|
+
end
|
27
33
|
|
28
|
-
|
34
|
+
def object_type
|
35
|
+
@object_type ||= begin
|
36
|
+
object_type = ffi(:ngt_get_property_object_type, @property)
|
37
|
+
FFI.ngt_is_property_object_type_float(object_type) ? :float : :integer
|
38
|
+
end
|
29
39
|
end
|
30
40
|
|
31
41
|
def insert(object)
|
32
|
-
ffi(:ngt_insert_index, @index, c_object(object.to_a),
|
42
|
+
ffi(:ngt_insert_index, @index, c_object(object.to_a), dimensions)
|
33
43
|
end
|
34
44
|
|
35
45
|
def batch_insert(objects, num_threads: 8)
|
@@ -59,12 +69,12 @@ module Ngt
|
|
59
69
|
end
|
60
70
|
|
61
71
|
def object(id)
|
62
|
-
if float
|
72
|
+
if object_type == :float
|
63
73
|
res = ffi(:ngt_get_object_as_float, @object_space, id)
|
64
|
-
res.read_array_of_float(
|
74
|
+
res.read_array_of_float(dimensions)
|
65
75
|
else
|
66
76
|
res = ffi(:ngt_get_object_as_integer, @object_space, id)
|
67
|
-
res.read_array_of_uint8(
|
77
|
+
res.read_array_of_uint8(dimensions)
|
68
78
|
end
|
69
79
|
end
|
70
80
|
|
@@ -75,7 +85,7 @@ module Ngt
|
|
75
85
|
def search(query, size: 20, epsilon: 0.1, radius: nil)
|
76
86
|
radius ||= -1.0
|
77
87
|
results = ffi(:ngt_create_empty_results)
|
78
|
-
ffi(:ngt_search_index, @index, c_object(query.to_a),
|
88
|
+
ffi(:ngt_search_index, @index, c_object(query.to_a), dimensions, size, epsilon, radius, results)
|
79
89
|
result_size = ffi(:ngt_get_result_size, results)
|
80
90
|
ret = []
|
81
91
|
result_size.times do |i|
|
@@ -86,12 +96,14 @@ module Ngt
|
|
86
96
|
}
|
87
97
|
end
|
88
98
|
ret
|
99
|
+
ensure
|
100
|
+
FFI.ngt_destroy_results(results) if results
|
89
101
|
end
|
90
102
|
|
91
103
|
def save(path2 = nil, path: nil)
|
92
104
|
warn "[ngt] Passing path as an option is deprecated - use an argument instead" if path
|
93
|
-
path
|
94
|
-
ffi(:ngt_save_index, @index, path)
|
105
|
+
@path = path || path2 || @path || Dir.mktmpdir
|
106
|
+
ffi(:ngt_save_index, @index, @path)
|
95
107
|
end
|
96
108
|
|
97
109
|
def close
|
@@ -101,58 +113,65 @@ module Ngt
|
|
101
113
|
def self.new(dimensions, path: nil, edge_size_for_creation: 10,
|
102
114
|
edge_size_for_search: 40, object_type: :float, distance_type: :l2)
|
103
115
|
|
104
|
-
|
105
|
-
return super(path) if path && dimensions.nil?
|
116
|
+
error = FFI.ngt_create_error_object
|
106
117
|
|
107
|
-
# TODO remove in 0.
|
108
|
-
|
109
|
-
unless create
|
118
|
+
# TODO remove in 0.4.0
|
119
|
+
if !dimensions.is_a?(Integer) && !path
|
110
120
|
warn "[ngt] Passing a path to new is deprecated - use load instead"
|
111
|
-
|
121
|
+
path = dimensions
|
122
|
+
dimensions = nil
|
112
123
|
end
|
113
124
|
|
114
|
-
path
|
115
|
-
|
116
|
-
property = ffi(:ngt_create_property, error)
|
117
|
-
ffi(:ngt_set_property_dimension, property, dimensions, error)
|
118
|
-
ffi(:ngt_set_property_edge_size_for_creation, property, edge_size_for_creation, error)
|
119
|
-
ffi(:ngt_set_property_edge_size_for_search, property, edge_size_for_search, error)
|
120
|
-
|
121
|
-
case object_type.to_s.downcase
|
122
|
-
when "float"
|
123
|
-
ffi(:ngt_set_property_object_type_float, property, error)
|
124
|
-
when "integer"
|
125
|
-
ffi(:ngt_set_property_object_type_integer, property, error)
|
125
|
+
if path && dimensions.nil?
|
126
|
+
index = ffi(:ngt_open_index, path, error)
|
126
127
|
else
|
127
|
-
|
128
|
+
property = ffi(:ngt_create_property, error)
|
129
|
+
ffi(:ngt_set_property_dimension, property, dimensions, error)
|
130
|
+
ffi(:ngt_set_property_edge_size_for_creation, property, edge_size_for_creation, error)
|
131
|
+
ffi(:ngt_set_property_edge_size_for_search, property, edge_size_for_search, error)
|
132
|
+
|
133
|
+
case object_type.to_s.downcase
|
134
|
+
when "float"
|
135
|
+
ffi(:ngt_set_property_object_type_float, property, error)
|
136
|
+
when "integer"
|
137
|
+
ffi(:ngt_set_property_object_type_integer, property, error)
|
138
|
+
else
|
139
|
+
raise ArgumentError, "Unknown object type: #{object_type}"
|
140
|
+
end
|
141
|
+
|
142
|
+
case distance_type.to_s.downcase
|
143
|
+
when "l1"
|
144
|
+
ffi(:ngt_set_property_distance_type_l1, property, error)
|
145
|
+
when "l2"
|
146
|
+
ffi(:ngt_set_property_distance_type_l2, property, error)
|
147
|
+
when "angle"
|
148
|
+
ffi(:ngt_set_property_distance_type_angle, property, error)
|
149
|
+
when "hamming"
|
150
|
+
ffi(:ngt_set_property_distance_type_hamming, property, error)
|
151
|
+
when "jaccard"
|
152
|
+
ffi(:ngt_set_property_distance_type_jaccard, property, error)
|
153
|
+
when "cosine"
|
154
|
+
ffi(:ngt_set_property_distance_type_cosine, property, error)
|
155
|
+
when "normalized_angle"
|
156
|
+
ffi(:ngt_set_property_distance_type_normalized_angle, property, error)
|
157
|
+
when "normalized_cosine"
|
158
|
+
ffi(:ngt_set_property_distance_type_normalized_cosine, property, error)
|
159
|
+
else
|
160
|
+
raise ArgumentError, "Unknown distance type: #{distance_type}"
|
161
|
+
end
|
162
|
+
|
163
|
+
index =
|
164
|
+
if path
|
165
|
+
ffi(:ngt_create_graph_and_tree, path, property, error)
|
166
|
+
else
|
167
|
+
ffi(:ngt_create_graph_and_tree_in_memory, property, error)
|
168
|
+
end
|
128
169
|
end
|
129
170
|
|
130
|
-
|
131
|
-
when "l1"
|
132
|
-
ffi(:ngt_set_property_distance_type_l1, property, error)
|
133
|
-
when "l2"
|
134
|
-
ffi(:ngt_set_property_distance_type_l2, property, error)
|
135
|
-
when "angle"
|
136
|
-
ffi(:ngt_set_property_distance_type_angle, property, error)
|
137
|
-
when "hamming"
|
138
|
-
ffi(:ngt_set_property_distance_type_hamming, property, error)
|
139
|
-
when "jaccard"
|
140
|
-
ffi(:ngt_set_property_distance_type_jaccard, property, error)
|
141
|
-
when "cosine"
|
142
|
-
ffi(:ngt_set_property_distance_type_cosine, property, error)
|
143
|
-
else
|
144
|
-
raise ArgumentError, "Unknown distance type: #{distance_type}"
|
145
|
-
end
|
146
|
-
|
147
|
-
index = ffi(:ngt_create_graph_and_tree, path, property, error)
|
148
|
-
FFI.ngt_close_index(index)
|
149
|
-
index = nil
|
150
|
-
|
151
|
-
super(path)
|
171
|
+
super(index, path)
|
152
172
|
ensure
|
153
173
|
FFI.ngt_destroy_error_object(error) if error
|
154
174
|
FFI.ngt_destroy_property(property) if property
|
155
|
-
FFI.ngt_close_index(index) if index
|
156
175
|
end
|
157
176
|
|
158
177
|
def self.load(path)
|
@@ -169,11 +188,12 @@ module Ngt
|
|
169
188
|
Utils.ffi(*args)
|
170
189
|
end
|
171
190
|
|
172
|
-
def self.finalize(error)
|
191
|
+
def self.finalize(error, index, property)
|
173
192
|
# must use proc instead of stabby lambda
|
174
193
|
proc do
|
175
|
-
# TODO clean-up more objects
|
176
194
|
FFI.ngt_destroy_error_object(error)
|
195
|
+
FFI.ngt_close_index(index)
|
196
|
+
FFI.ngt_destroy_property(property)
|
177
197
|
end
|
178
198
|
end
|
179
199
|
|
@@ -183,10 +203,6 @@ module Ngt
|
|
183
203
|
defined?(Numo::NArray) && data.is_a?(Numo::NArray)
|
184
204
|
end
|
185
205
|
|
186
|
-
def float?
|
187
|
-
@float
|
188
|
-
end
|
189
|
-
|
190
206
|
def c_object(object)
|
191
207
|
c_object = ::FFI::MemoryPointer.new(:double, object.size)
|
192
208
|
c_object.write_array_of_double(object)
|
data/lib/ngt/optimizer.rb
CHANGED
data/lib/ngt/version.rb
CHANGED
data/vendor/libngt.dylib
CHANGED
Binary file
|
data/vendor/libngt.so
CHANGED
Binary file
|
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
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|