annoy-rb 0.4.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/README.md +31 -6
- data/ext/annoy/annoyext.cpp +12 -9
- data/ext/annoy/annoyext.hpp +288 -284
- data/ext/annoy/extconf.rb +1 -1
- data/lib/annoy/version.rb +1 -1
- data/lib/annoy-rb.rb +3 -0
- data/lib/annoy.rb +16 -5
- data/sig/annoy.rbs +75 -1
- metadata +5 -11
- data/.github/workflows/build.yml +0 -20
- data/.gitignore +0 -21
- data/.rspec +0 -3
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -10
- data/Rakefile +0 -15
- data/Steepfile +0 -20
- data/annoy-rb.gemspec +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 504bef50c398d29e30123e694558cbbb9edc5c3958f457ce3b5622e51467decf
|
4
|
+
data.tar.gz: 39965aeddd097635ccdd9e926d2a1b349c294c41a44c2cc5f729c5bc5431d99e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56dfefa366db41856aebc90c23ccbd775bbc0eaf354e80f87568049ff05b039ce07e875da2be6a4e5730415f255d8e972800326a597ce073056803508de1291c
|
7
|
+
data.tar.gz: 353473a64ffcae0beb9f0d4af7eb6fac85404f3103ad325ece10d7a59813b5eb778e98195d16801036fc167a118d408e4cfd58825c954db077c0234927faf3d2
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
## 0.6.1
|
2
|
+
|
3
|
+
- Refactor codes and configs with RuboCop and clang-format.
|
4
|
+
|
5
|
+
## 0.6.0
|
6
|
+
- Add `dtype` argument to initialize method to specify the data type of vector element.
|
7
|
+
If you want to load a search index created with the Python bindings, specify 'float32' to the dtype argument.
|
8
|
+
|
9
|
+
```
|
10
|
+
require 'annoy'
|
11
|
+
|
12
|
+
f = 40
|
13
|
+
t = Annoy::AnnoyIndex.new(n_features: f, metric: 'angular', dtype: 'float32')
|
14
|
+
t.load('index_with_python_bindings.ann')
|
15
|
+
```
|
16
|
+
|
17
|
+
- Change the data type of item index from int to int32_t.
|
18
|
+
- Update type declarations and documentations.
|
19
|
+
- Introduce conventional commits.
|
20
|
+
|
21
|
+
## 0.5.0
|
22
|
+
### Breaking change
|
23
|
+
- Remove `-march=native` and `-DANNOYLIB_MULTITHREADED_BUILD` from CXXFLAGS.
|
24
|
+
For example, the installation command to reproduce the same build as the previous version is as follows:
|
25
|
+
|
26
|
+
```
|
27
|
+
$ gem install annoy-rb -- --with-cxxflags=-march=native -DANNOYLIB_MULTITHREADED_BUILD
|
28
|
+
```
|
29
|
+
|
30
|
+
```
|
31
|
+
$ bundle config --local build.annoy-rb "--with-cxxflags=-march=native -DANNOYLIB_MULTITHREADED_BUILD"
|
32
|
+
$ bundle install
|
33
|
+
```
|
34
|
+
|
1
35
|
## 0.4.0
|
2
36
|
- Add dummy constructor call at memory allocation of binding class to prevent occuring segment fault on GC when initialize method is failed.
|
3
37
|
|
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
#
|
1
|
+
# annoy-rb
|
2
2
|
|
3
3
|
[![Build Status](https://github.com/yoshoku/annoy.rb/workflows/build/badge.svg)](https://github.com/yoshoku/annoy.rb/actions?query=workflow%3Abuild)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/annoy-rb.svg)](https://badge.fury.io/rb/annoy-rb)
|
5
5
|
[![License](https://img.shields.io/badge/License-Apache%202.0-yellowgreen.svg)](https://github.com/yoshoku/annoy.rb/blob/main/LICENSE.txt)
|
6
|
-
[![Documentation](
|
6
|
+
[![Documentation](https://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/annoy.rb/doc/)
|
7
7
|
|
8
|
-
|
8
|
+
annoy-rb provides Ruby bindings for the [Annoy (Approximate Nearest Neighbors Oh Yeah)](https://github.com/spotify/annoy).
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
@@ -23,11 +23,24 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
$ gem install annoy-rb
|
25
25
|
|
26
|
-
Note:
|
26
|
+
Note: annoy-rb does not require the installation of another external library.
|
27
|
+
In addition, annoy-rb does not give any optimization options when building native extensions.
|
28
|
+
If necessary, add optimization options yourself during installation, as follows;
|
29
|
+
|
30
|
+
```
|
31
|
+
$ bundle config --local build.annoy-rb "--with-cxxflags=-march=native"
|
32
|
+
$ bundle install
|
33
|
+
```
|
34
|
+
|
35
|
+
Or:
|
36
|
+
|
37
|
+
```
|
38
|
+
$ gem install annoy-rb -- --with-cxxflags=-march=native
|
39
|
+
```
|
27
40
|
|
28
41
|
## Documentation
|
29
42
|
|
30
|
-
* [
|
43
|
+
* [annoy-rb API Documentation](https://yoshoku.github.io/annoy.rb/doc/)
|
31
44
|
|
32
45
|
## Usage
|
33
46
|
|
@@ -50,6 +63,18 @@ u.load('test.ann')
|
|
50
63
|
p u.get_nns_by_item(0, 100) # will find the 100 nearest neighbors.
|
51
64
|
```
|
52
65
|
|
66
|
+
With the default argument, annoy-rb uses double precision floating point type for the data type of vector element.
|
67
|
+
On the other hand, the [Python bindings of Annoy](https://pypi.org/project/annoy/) use single precision floating point type.
|
68
|
+
If you want to load a search index created with the Python bindings, specify 'float32' to the dtype argument.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
require 'annoy'
|
72
|
+
|
73
|
+
f = 40
|
74
|
+
t = Annoy::AnnoyIndex.new(n_features: f, metric: 'angular', dtype: 'float32')
|
75
|
+
t.load('index_with_python_bindings.ann')
|
76
|
+
```
|
77
|
+
|
53
78
|
## License
|
54
79
|
|
55
80
|
The gem is available as open source under the terms of the [Apache-2.0 License](https://www.apache.org/licenses/LICENSE-2.0).
|
@@ -58,4 +83,4 @@ The gem is available as open source under the terms of the [Apache-2.0 License](
|
|
58
83
|
|
59
84
|
Bug reports and pull requests are welcome on GitHub at https://github.com/yoshoku/annoy.rb.
|
60
85
|
This project is intended to be a safe, welcoming space for collaboration,
|
61
|
-
and contributors are expected to adhere to the [
|
86
|
+
and contributors are expected to adhere to the [Contributor Covenant](https://contributor-covenant.org) code of conduct.
|
data/ext/annoy/annoyext.cpp
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/**
|
2
2
|
* Annoy.rb is a Ruby binding for the Annoy (Approximate Nearest Neighbors Oh Yeah).
|
3
3
|
*
|
4
|
-
* Copyright (c) 2020 Atsushi Tatsuma
|
4
|
+
* Copyright (c) 2020-2022 Atsushi Tatsuma
|
5
5
|
*
|
6
6
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
* you may not use this file except in compliance with the License.
|
@@ -18,13 +18,16 @@
|
|
18
18
|
|
19
19
|
#include "annoyext.hpp"
|
20
20
|
|
21
|
-
extern "C"
|
22
|
-
void Init_annoyext(void)
|
23
|
-
{
|
21
|
+
extern "C" void Init_annoyext(void) {
|
24
22
|
VALUE rb_mAnnoy = rb_define_module("Annoy");
|
25
|
-
RbAnnoyIndex<AnnoyIndexAngular
|
26
|
-
RbAnnoyIndex<AnnoyIndexDotProduct
|
27
|
-
RbAnnoyIndex<AnnoyIndexHamming
|
28
|
-
RbAnnoyIndex<AnnoyIndexEuclidean
|
29
|
-
RbAnnoyIndex<AnnoyIndexManhattan
|
23
|
+
RbAnnoyIndex<AnnoyIndexAngular<double>, double>::define_class(rb_mAnnoy, "AnnoyIndexAngular");
|
24
|
+
RbAnnoyIndex<AnnoyIndexDotProduct<double>, double>::define_class(rb_mAnnoy, "AnnoyIndexDotProduct");
|
25
|
+
RbAnnoyIndex<AnnoyIndexHamming<uint64_t>, uint64_t>::define_class(rb_mAnnoy, "AnnoyIndexHamming");
|
26
|
+
RbAnnoyIndex<AnnoyIndexEuclidean<double>, double>::define_class(rb_mAnnoy, "AnnoyIndexEuclidean");
|
27
|
+
RbAnnoyIndex<AnnoyIndexManhattan<double>, double>::define_class(rb_mAnnoy, "AnnoyIndexManhattan");
|
28
|
+
|
29
|
+
RbAnnoyIndex<AnnoyIndexAngular<float>, float>::define_class(rb_mAnnoy, "AnnoyIndexAngularFloat32");
|
30
|
+
RbAnnoyIndex<AnnoyIndexDotProduct<float>, float>::define_class(rb_mAnnoy, "AnnoyIndexDotProductFloat32");
|
31
|
+
RbAnnoyIndex<AnnoyIndexEuclidean<float>, float>::define_class(rb_mAnnoy, "AnnoyIndexEuclideanFloat32");
|
32
|
+
RbAnnoyIndex<AnnoyIndexManhattan<float>, float>::define_class(rb_mAnnoy, "AnnoyIndexManhattanFloat32");
|
30
33
|
}
|
data/ext/annoy/annoyext.hpp
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/**
|
2
2
|
* Annoy.rb is a Ruby binding for the Annoy (Approximate Nearest Neighbors Oh Yeah).
|
3
3
|
*
|
4
|
-
* Copyright (c) 2020 Atsushi Tatsuma
|
4
|
+
* Copyright (c) 2020-2022 Atsushi Tatsuma
|
5
5
|
*
|
6
6
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
* you may not use this file except in compliance with the License.
|
@@ -22,301 +22,304 @@
|
|
22
22
|
#include <typeinfo>
|
23
23
|
|
24
24
|
#include <ruby.h>
|
25
|
+
|
25
26
|
#include <annoylib.h>
|
26
27
|
#include <kissrandom.h>
|
27
28
|
|
28
29
|
#ifdef ANNOYLIB_MULTITHREADED_BUILD
|
29
|
-
|
30
|
+
typedef AnnoyIndexMultiThreadedBuildPolicy AnnoyIndexThreadedBuildPolicy;
|
30
31
|
#else
|
31
|
-
|
32
|
+
typedef AnnoyIndexSingleThreadedBuildPolicy AnnoyIndexThreadedBuildPolicy;
|
32
33
|
#endif
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
free(error);
|
119
|
-
ruby_xfree(vec);
|
120
|
-
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
121
|
-
return Qfalse;
|
122
|
-
}
|
123
|
-
|
124
|
-
ruby_xfree(vec);
|
125
|
-
return Qtrue;
|
126
|
-
};
|
127
|
-
|
128
|
-
static VALUE _annoy_index_build(VALUE self, VALUE _n_trees, VALUE _n_jobs) {
|
129
|
-
const int n_trees = NUM2INT(_n_trees);
|
130
|
-
const int n_jobs = NUM2INT(_n_jobs);
|
131
|
-
char* error;
|
132
|
-
if (!get_annoy_index(self)->build(n_trees, n_jobs, &error)) {
|
133
|
-
VALUE error_str = rb_str_new_cstr(error);
|
134
|
-
free(error);
|
135
|
-
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
136
|
-
return Qfalse;
|
137
|
-
}
|
138
|
-
return Qtrue;
|
139
|
-
};
|
140
|
-
|
141
|
-
static VALUE _annoy_index_save(VALUE self, VALUE _filename, VALUE _prefault) {
|
142
|
-
const char* filename = StringValuePtr(_filename);
|
143
|
-
const bool prefault = _prefault == Qtrue ? true : false;
|
144
|
-
char* error;
|
145
|
-
if (!get_annoy_index(self)->save(filename, prefault, &error)) {
|
146
|
-
VALUE error_str = rb_str_new_cstr(error);
|
147
|
-
free(error);
|
148
|
-
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
149
|
-
return Qfalse;
|
150
|
-
}
|
151
|
-
RB_GC_GUARD(_filename);
|
152
|
-
return Qtrue;
|
153
|
-
};
|
154
|
-
|
155
|
-
static VALUE _annoy_index_load(VALUE self, VALUE _filename, VALUE _prefault) {
|
156
|
-
const char* filename = StringValuePtr(_filename);
|
157
|
-
const bool prefault = _prefault == Qtrue ? true : false;
|
158
|
-
char* error;
|
159
|
-
if (!get_annoy_index(self)->load(filename, prefault, &error)) {
|
160
|
-
VALUE error_str = rb_str_new_cstr(error);
|
161
|
-
free(error);
|
162
|
-
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
163
|
-
return Qfalse;
|
164
|
-
}
|
165
|
-
RB_GC_GUARD(_filename);
|
166
|
-
return Qtrue;
|
167
|
-
};
|
168
|
-
|
169
|
-
static VALUE _annoy_index_unload(VALUE self) {
|
170
|
-
get_annoy_index(self)->unload();
|
171
|
-
return Qnil;
|
172
|
-
};
|
173
|
-
|
174
|
-
static VALUE _annoy_index_get_nns_by_item(VALUE self, VALUE _idx, VALUE _n_neighbors, VALUE _search_k, VALUE _include_distances) {
|
175
|
-
const int idx = NUM2INT(_idx);
|
176
|
-
const int n_neighbors = NUM2INT(_n_neighbors);
|
177
|
-
const int search_k = NUM2INT(_search_k);
|
178
|
-
const bool include_distances = _include_distances == Qtrue ? true : false;
|
179
|
-
std::vector<int> neighbors;
|
180
|
-
std::vector<F> distances;
|
181
|
-
|
182
|
-
get_annoy_index(self)->get_nns_by_item(idx, n_neighbors, search_k, &neighbors, include_distances ? &distances : NULL);
|
183
|
-
|
184
|
-
const int sz_neighbors = neighbors.size();
|
185
|
-
VALUE neighbors_arr = rb_ary_new2(sz_neighbors);
|
186
|
-
|
187
|
-
for (int i = 0; i < sz_neighbors; i++) {
|
188
|
-
rb_ary_store(neighbors_arr, i, INT2NUM(neighbors[i]));
|
189
|
-
}
|
190
|
-
|
191
|
-
if (include_distances) {
|
192
|
-
const int sz_distances = distances.size();
|
193
|
-
VALUE distances_arr = rb_ary_new2(sz_distances);
|
194
|
-
for (int i = 0; i < sz_distances; i++) {
|
195
|
-
rb_ary_store(distances_arr, i, typeid(F) == typeid(double) ? DBL2NUM(distances[i]) : UINT2NUM(distances[i]));
|
196
|
-
}
|
197
|
-
VALUE res = rb_ary_new2(2);
|
198
|
-
rb_ary_store(res, 0, neighbors_arr);
|
199
|
-
rb_ary_store(res, 1, distances_arr);
|
200
|
-
return res;
|
201
|
-
}
|
202
|
-
|
203
|
-
return neighbors_arr;
|
204
|
-
};
|
205
|
-
|
206
|
-
static VALUE _annoy_index_get_nns_by_vector(VALUE self, VALUE _vec, VALUE _n_neighbors, VALUE _search_k, VALUE _include_distances) {
|
207
|
-
const int n_dims = get_annoy_index(self)->get_f();
|
208
|
-
|
209
|
-
if (!RB_TYPE_P(_vec, T_ARRAY)) {
|
210
|
-
rb_raise(rb_eArgError, "Expect item vector to be Array.");
|
211
|
-
return Qfalse;
|
212
|
-
}
|
213
|
-
|
214
|
-
if (n_dims != RARRAY_LEN(_vec)) {
|
215
|
-
rb_raise(rb_eArgError, "Array size does not match to index dimensionality.");
|
216
|
-
return Qfalse;
|
217
|
-
}
|
218
|
-
|
219
|
-
F* vec = (F*)ruby_xmalloc(n_dims * sizeof(F));
|
220
|
-
for (int i = 0; i < n_dims; i++) {
|
221
|
-
vec[i] = typeid(F) == typeid(double) ? NUM2DBL(rb_ary_entry(_vec, i)) : NUM2UINT(rb_ary_entry(_vec, i));
|
222
|
-
}
|
223
|
-
|
224
|
-
const int n_neighbors = NUM2INT(_n_neighbors);
|
225
|
-
const int search_k = NUM2INT(_search_k);
|
226
|
-
const bool include_distances = _include_distances == Qtrue ? true : false;
|
227
|
-
std::vector<int> neighbors;
|
228
|
-
std::vector<F> distances;
|
229
|
-
|
230
|
-
get_annoy_index(self)->get_nns_by_vector(vec, n_neighbors, search_k, &neighbors, include_distances ? &distances : NULL);
|
231
|
-
|
35
|
+
// clang-format off
|
36
|
+
template<typename F> using AnnoyIndexAngular = AnnoyIndex<int32_t, F, Angular, Kiss64Random, AnnoyIndexThreadedBuildPolicy>;
|
37
|
+
template<typename F> using AnnoyIndexDotProduct = AnnoyIndex<int32_t, F, DotProduct, Kiss64Random, AnnoyIndexThreadedBuildPolicy>;
|
38
|
+
template<typename F> using AnnoyIndexHamming = AnnoyIndex<int32_t, F, Hamming, Kiss64Random, AnnoyIndexThreadedBuildPolicy>;
|
39
|
+
template<typename F> using AnnoyIndexEuclidean = AnnoyIndex<int32_t, F, Euclidean, Kiss64Random, AnnoyIndexThreadedBuildPolicy>;
|
40
|
+
template<typename F> using AnnoyIndexManhattan = AnnoyIndex<int32_t, F, Manhattan, Kiss64Random, AnnoyIndexThreadedBuildPolicy>;
|
41
|
+
// clang-format on
|
42
|
+
|
43
|
+
template <class T, typename F> class RbAnnoyIndex {
|
44
|
+
public:
|
45
|
+
static VALUE annoy_index_alloc(VALUE self) {
|
46
|
+
T* ptr = (T*)ruby_xmalloc(sizeof(T));
|
47
|
+
new (ptr) T();
|
48
|
+
return TypedData_Wrap_Struct(self, &annoy_index_type, ptr);
|
49
|
+
};
|
50
|
+
|
51
|
+
static void annoy_index_free(void* ptr) {
|
52
|
+
((T*)ptr)->~AnnoyIndex();
|
53
|
+
ruby_xfree(ptr);
|
54
|
+
};
|
55
|
+
|
56
|
+
static size_t annoy_index_size(const void* ptr) { return sizeof(*((T*)ptr)); };
|
57
|
+
|
58
|
+
static T* get_annoy_index(VALUE self) {
|
59
|
+
T* ptr;
|
60
|
+
TypedData_Get_Struct(self, T, &annoy_index_type, ptr);
|
61
|
+
return ptr;
|
62
|
+
};
|
63
|
+
|
64
|
+
static VALUE define_class(VALUE rb_mAnnoy, const char* class_name) {
|
65
|
+
VALUE rb_cAnnoyIndex = rb_define_class_under(rb_mAnnoy, class_name, rb_cObject);
|
66
|
+
rb_define_alloc_func(rb_cAnnoyIndex, annoy_index_alloc);
|
67
|
+
rb_define_method(rb_cAnnoyIndex, "initialize", RUBY_METHOD_FUNC(_annoy_index_init), 1);
|
68
|
+
rb_define_method(rb_cAnnoyIndex, "add_item", RUBY_METHOD_FUNC(_annoy_index_add_item), 2);
|
69
|
+
rb_define_method(rb_cAnnoyIndex, "build", RUBY_METHOD_FUNC(_annoy_index_build), 2);
|
70
|
+
rb_define_method(rb_cAnnoyIndex, "save", RUBY_METHOD_FUNC(_annoy_index_save), 2);
|
71
|
+
rb_define_method(rb_cAnnoyIndex, "load", RUBY_METHOD_FUNC(_annoy_index_load), 2);
|
72
|
+
rb_define_method(rb_cAnnoyIndex, "unload", RUBY_METHOD_FUNC(_annoy_index_unload), 0);
|
73
|
+
rb_define_method(rb_cAnnoyIndex, "get_nns_by_item", RUBY_METHOD_FUNC(_annoy_index_get_nns_by_item), 4);
|
74
|
+
rb_define_method(rb_cAnnoyIndex, "get_nns_by_vector", RUBY_METHOD_FUNC(_annoy_index_get_nns_by_vector), 4);
|
75
|
+
rb_define_method(rb_cAnnoyIndex, "get_item", RUBY_METHOD_FUNC(_annoy_index_get_item), 1);
|
76
|
+
rb_define_method(rb_cAnnoyIndex, "get_distance", RUBY_METHOD_FUNC(_annoy_index_get_distance), 2);
|
77
|
+
rb_define_method(rb_cAnnoyIndex, "get_n_items", RUBY_METHOD_FUNC(_annoy_index_get_n_items), 0);
|
78
|
+
rb_define_method(rb_cAnnoyIndex, "get_n_trees", RUBY_METHOD_FUNC(_annoy_index_get_n_trees), 0);
|
79
|
+
rb_define_method(rb_cAnnoyIndex, "on_disk_build", RUBY_METHOD_FUNC(_annoy_index_on_disk_build), 1);
|
80
|
+
rb_define_method(rb_cAnnoyIndex, "set_seed", RUBY_METHOD_FUNC(_annoy_index_set_seed), 1);
|
81
|
+
rb_define_method(rb_cAnnoyIndex, "verbose", RUBY_METHOD_FUNC(_annoy_index_verbose), 1);
|
82
|
+
rb_define_method(rb_cAnnoyIndex, "get_f", RUBY_METHOD_FUNC(_annoy_index_get_f), 0);
|
83
|
+
return rb_cAnnoyIndex;
|
84
|
+
};
|
85
|
+
|
86
|
+
private:
|
87
|
+
static const rb_data_type_t annoy_index_type;
|
88
|
+
|
89
|
+
static VALUE _annoy_index_init(VALUE self, VALUE _n_dims) {
|
90
|
+
const int n_dims = NUM2INT(_n_dims);
|
91
|
+
T* ptr = get_annoy_index(self);
|
92
|
+
new (ptr) T(n_dims);
|
93
|
+
return Qnil;
|
94
|
+
};
|
95
|
+
|
96
|
+
static VALUE _annoy_index_add_item(VALUE self, VALUE _idx, VALUE arr) {
|
97
|
+
const int32_t idx = (int32_t)NUM2INT(_idx);
|
98
|
+
const int n_dims = get_annoy_index(self)->get_f();
|
99
|
+
|
100
|
+
if (!RB_TYPE_P(arr, T_ARRAY)) {
|
101
|
+
rb_raise(rb_eArgError, "Expect item vector to be Array.");
|
102
|
+
return Qfalse;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (n_dims != RARRAY_LEN(arr)) {
|
106
|
+
rb_raise(rb_eArgError, "Array size does not match to index dimensionality.");
|
107
|
+
return Qfalse;
|
108
|
+
}
|
109
|
+
|
110
|
+
F* vec = (F*)ruby_xmalloc(n_dims * sizeof(F));
|
111
|
+
for (int i = 0; i < n_dims; i++) {
|
112
|
+
vec[i] = typeid(F) == typeid(double) ? NUM2DBL(rb_ary_entry(arr, i)) : NUM2UINT(rb_ary_entry(arr, i));
|
113
|
+
}
|
114
|
+
|
115
|
+
char* error;
|
116
|
+
if (!get_annoy_index(self)->add_item(idx, vec, &error)) {
|
117
|
+
VALUE error_str = rb_str_new_cstr(error);
|
118
|
+
free(error);
|
232
119
|
ruby_xfree(vec);
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
120
|
+
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
121
|
+
return Qfalse;
|
122
|
+
}
|
123
|
+
|
124
|
+
ruby_xfree(vec);
|
125
|
+
return Qtrue;
|
126
|
+
};
|
127
|
+
|
128
|
+
static VALUE _annoy_index_build(VALUE self, VALUE _n_trees, VALUE _n_jobs) {
|
129
|
+
const int n_trees = NUM2INT(_n_trees);
|
130
|
+
const int n_jobs = NUM2INT(_n_jobs);
|
131
|
+
char* error;
|
132
|
+
if (!get_annoy_index(self)->build(n_trees, n_jobs, &error)) {
|
133
|
+
VALUE error_str = rb_str_new_cstr(error);
|
134
|
+
free(error);
|
135
|
+
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
136
|
+
return Qfalse;
|
137
|
+
}
|
138
|
+
return Qtrue;
|
139
|
+
};
|
140
|
+
|
141
|
+
static VALUE _annoy_index_save(VALUE self, VALUE _filename, VALUE _prefault) {
|
142
|
+
const char* filename = StringValuePtr(_filename);
|
143
|
+
const bool prefault = _prefault == Qtrue ? true : false;
|
144
|
+
char* error;
|
145
|
+
if (!get_annoy_index(self)->save(filename, prefault, &error)) {
|
146
|
+
VALUE error_str = rb_str_new_cstr(error);
|
147
|
+
free(error);
|
148
|
+
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
149
|
+
return Qfalse;
|
150
|
+
}
|
151
|
+
RB_GC_GUARD(_filename);
|
152
|
+
return Qtrue;
|
153
|
+
};
|
154
|
+
|
155
|
+
static VALUE _annoy_index_load(VALUE self, VALUE _filename, VALUE _prefault) {
|
156
|
+
const char* filename = StringValuePtr(_filename);
|
157
|
+
const bool prefault = _prefault == Qtrue ? true : false;
|
158
|
+
char* error;
|
159
|
+
if (!get_annoy_index(self)->load(filename, prefault, &error)) {
|
160
|
+
VALUE error_str = rb_str_new_cstr(error);
|
161
|
+
free(error);
|
162
|
+
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
163
|
+
return Qfalse;
|
164
|
+
}
|
165
|
+
RB_GC_GUARD(_filename);
|
166
|
+
return Qtrue;
|
167
|
+
};
|
168
|
+
|
169
|
+
static VALUE _annoy_index_unload(VALUE self) {
|
170
|
+
get_annoy_index(self)->unload();
|
171
|
+
return Qnil;
|
172
|
+
};
|
173
|
+
|
174
|
+
static VALUE _annoy_index_get_nns_by_item(VALUE self, VALUE _idx, VALUE _n_neighbors, VALUE _search_k,
|
175
|
+
VALUE _include_distances) {
|
176
|
+
const int32_t idx = (int32_t)NUM2INT(_idx);
|
177
|
+
const int n_neighbors = NUM2INT(_n_neighbors);
|
178
|
+
const int search_k = NUM2INT(_search_k);
|
179
|
+
const bool include_distances = _include_distances == Qtrue ? true : false;
|
180
|
+
std::vector<int32_t> neighbors;
|
181
|
+
std::vector<F> distances;
|
182
|
+
|
183
|
+
get_annoy_index(self)->get_nns_by_item(idx, n_neighbors, search_k, &neighbors, include_distances ? &distances : NULL);
|
184
|
+
|
185
|
+
const int sz_neighbors = neighbors.size();
|
186
|
+
VALUE neighbors_arr = rb_ary_new2(sz_neighbors);
|
187
|
+
|
188
|
+
for (int i = 0; i < sz_neighbors; i++) {
|
189
|
+
rb_ary_store(neighbors_arr, i, INT2NUM((int)(neighbors[i])));
|
190
|
+
}
|
191
|
+
|
192
|
+
if (include_distances) {
|
193
|
+
const int sz_distances = distances.size();
|
194
|
+
VALUE distances_arr = rb_ary_new2(sz_distances);
|
195
|
+
for (int i = 0; i < sz_distances; i++) {
|
196
|
+
rb_ary_store(distances_arr, i, typeid(F) == typeid(double) ? DBL2NUM(distances[i]) : UINT2NUM(distances[i]));
|
239
197
|
}
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
const char* filename = StringValuePtr(_filename);
|
291
|
-
char* error;
|
292
|
-
if (!get_annoy_index(self)->on_disk_build(filename, &error)) {
|
293
|
-
VALUE error_str = rb_str_new_cstr(error);
|
294
|
-
free(error);
|
295
|
-
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
296
|
-
return Qfalse;
|
198
|
+
VALUE res = rb_ary_new2(2);
|
199
|
+
rb_ary_store(res, 0, neighbors_arr);
|
200
|
+
rb_ary_store(res, 1, distances_arr);
|
201
|
+
return res;
|
202
|
+
}
|
203
|
+
|
204
|
+
return neighbors_arr;
|
205
|
+
};
|
206
|
+
|
207
|
+
static VALUE _annoy_index_get_nns_by_vector(VALUE self, VALUE _vec, VALUE _n_neighbors, VALUE _search_k,
|
208
|
+
VALUE _include_distances) {
|
209
|
+
const int n_dims = get_annoy_index(self)->get_f();
|
210
|
+
|
211
|
+
if (!RB_TYPE_P(_vec, T_ARRAY)) {
|
212
|
+
rb_raise(rb_eArgError, "Expect item vector to be Array.");
|
213
|
+
return Qfalse;
|
214
|
+
}
|
215
|
+
|
216
|
+
if (n_dims != RARRAY_LEN(_vec)) {
|
217
|
+
rb_raise(rb_eArgError, "Array size does not match to index dimensionality.");
|
218
|
+
return Qfalse;
|
219
|
+
}
|
220
|
+
|
221
|
+
F* vec = (F*)ruby_xmalloc(n_dims * sizeof(F));
|
222
|
+
for (int i = 0; i < n_dims; i++) {
|
223
|
+
vec[i] = typeid(F) == typeid(double) ? NUM2DBL(rb_ary_entry(_vec, i)) : NUM2UINT(rb_ary_entry(_vec, i));
|
224
|
+
}
|
225
|
+
|
226
|
+
const int n_neighbors = NUM2INT(_n_neighbors);
|
227
|
+
const int search_k = NUM2INT(_search_k);
|
228
|
+
const bool include_distances = _include_distances == Qtrue ? true : false;
|
229
|
+
std::vector<int32_t> neighbors;
|
230
|
+
std::vector<F> distances;
|
231
|
+
|
232
|
+
get_annoy_index(self)->get_nns_by_vector(vec, n_neighbors, search_k, &neighbors, include_distances ? &distances : NULL);
|
233
|
+
|
234
|
+
ruby_xfree(vec);
|
235
|
+
|
236
|
+
const int sz_neighbors = neighbors.size();
|
237
|
+
VALUE neighbors_arr = rb_ary_new2(sz_neighbors);
|
238
|
+
|
239
|
+
for (int i = 0; i < sz_neighbors; i++) {
|
240
|
+
rb_ary_store(neighbors_arr, i, INT2NUM((int)(neighbors[i])));
|
241
|
+
}
|
242
|
+
|
243
|
+
if (include_distances) {
|
244
|
+
const int sz_distances = distances.size();
|
245
|
+
VALUE distances_arr = rb_ary_new2(sz_distances);
|
246
|
+
for (int i = 0; i < sz_distances; i++) {
|
247
|
+
rb_ary_store(distances_arr, i, typeid(F) == typeid(double) ? DBL2NUM(distances[i]) : UINT2NUM(distances[i]));
|
297
248
|
}
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
}
|
249
|
+
VALUE res = rb_ary_new2(2);
|
250
|
+
rb_ary_store(res, 0, neighbors_arr);
|
251
|
+
rb_ary_store(res, 1, distances_arr);
|
252
|
+
return res;
|
253
|
+
}
|
254
|
+
|
255
|
+
return neighbors_arr;
|
256
|
+
};
|
257
|
+
|
258
|
+
static VALUE _annoy_index_get_item(VALUE self, VALUE _idx) {
|
259
|
+
const int32_t idx = (int32_t)NUM2INT(_idx);
|
260
|
+
const int n_dims = get_annoy_index(self)->get_f();
|
261
|
+
F* vec = (F*)ruby_xmalloc(n_dims * sizeof(F));
|
262
|
+
VALUE arr = rb_ary_new2(n_dims);
|
263
|
+
|
264
|
+
get_annoy_index(self)->get_item(idx, vec);
|
265
|
+
|
266
|
+
for (int i = 0; i < n_dims; i++) {
|
267
|
+
rb_ary_store(arr, i, typeid(F) == typeid(double) ? DBL2NUM(vec[i]) : UINT2NUM(vec[i]));
|
268
|
+
}
|
269
|
+
|
270
|
+
ruby_xfree(vec);
|
271
|
+
return arr;
|
272
|
+
};
|
273
|
+
|
274
|
+
static VALUE _annoy_index_get_distance(VALUE self, VALUE _i, VALUE _j) {
|
275
|
+
const int32_t i = (int32_t)NUM2INT(_i);
|
276
|
+
const int32_t j = (int32_t)NUM2INT(_j);
|
277
|
+
const F dist = get_annoy_index(self)->get_distance(i, j);
|
278
|
+
return typeid(F) == typeid(double) ? DBL2NUM(dist) : UINT2NUM(dist);
|
279
|
+
};
|
280
|
+
|
281
|
+
static VALUE _annoy_index_get_n_items(VALUE self) {
|
282
|
+
const int32_t n_items = get_annoy_index(self)->get_n_items();
|
283
|
+
return INT2NUM(n_items);
|
284
|
+
};
|
285
|
+
|
286
|
+
static VALUE _annoy_index_get_n_trees(VALUE self) {
|
287
|
+
const int32_t n_trees = get_annoy_index(self)->get_n_trees();
|
288
|
+
return INT2NUM(n_trees);
|
289
|
+
};
|
290
|
+
|
291
|
+
static VALUE _annoy_index_on_disk_build(VALUE self, VALUE _filename) {
|
292
|
+
const char* filename = StringValuePtr(_filename);
|
293
|
+
char* error;
|
294
|
+
if (!get_annoy_index(self)->on_disk_build(filename, &error)) {
|
295
|
+
VALUE error_str = rb_str_new_cstr(error);
|
296
|
+
free(error);
|
297
|
+
rb_raise(rb_eRuntimeError, "%s", StringValuePtr(error_str));
|
298
|
+
return Qfalse;
|
299
|
+
}
|
300
|
+
RB_GC_GUARD(_filename);
|
301
|
+
return Qtrue;
|
302
|
+
};
|
303
|
+
|
304
|
+
static VALUE _annoy_index_set_seed(VALUE self, VALUE _seed) {
|
305
|
+
const int seed = NUM2INT(_seed);
|
306
|
+
get_annoy_index(self)->set_seed(seed);
|
307
|
+
return Qnil;
|
308
|
+
};
|
309
|
+
|
310
|
+
static VALUE _annoy_index_verbose(VALUE self, VALUE _flag) {
|
311
|
+
const bool flag = _flag == Qtrue ? true : false;
|
312
|
+
get_annoy_index(self)->verbose(flag);
|
313
|
+
return Qnil;
|
314
|
+
};
|
315
|
+
|
316
|
+
static VALUE _annoy_index_get_f(VALUE self) {
|
317
|
+
const int32_t f = get_annoy_index(self)->get_f();
|
318
|
+
return INT2NUM(f);
|
319
|
+
};
|
318
320
|
};
|
319
321
|
|
322
|
+
// clang-format off
|
320
323
|
template<class T, typename F>
|
321
324
|
const rb_data_type_t RbAnnoyIndex<T, F>::annoy_index_type = {
|
322
325
|
"RbAnnoyIndex",
|
@@ -329,5 +332,6 @@ const rb_data_type_t RbAnnoyIndex<T, F>::annoy_index_type = {
|
|
329
332
|
NULL,
|
330
333
|
RUBY_TYPED_FREE_IMMEDIATELY
|
331
334
|
};
|
335
|
+
// clang-format on
|
332
336
|
|
333
337
|
#endif /* ANNOYEXT_HPP */
|
data/ext/annoy/extconf.rb
CHANGED
data/lib/annoy/version.rb
CHANGED
data/lib/annoy-rb.rb
ADDED
data/lib/annoy.rb
CHANGED
@@ -30,30 +30,40 @@ module Annoy
|
|
30
30
|
# @return [String]
|
31
31
|
attr_reader :metric
|
32
32
|
|
33
|
+
# Returns the data type of feature.
|
34
|
+
# @return [String]
|
35
|
+
attr_reader :dtype
|
36
|
+
|
33
37
|
# Create a new search index.
|
34
38
|
#
|
35
39
|
# @param n_features [Integer] The number of features (dimensions) of stored vector.
|
36
40
|
# @param metric [String] The distance metric between vectors ('angular', 'dot', 'hamming', 'euclidean', or 'manhattan').
|
37
|
-
|
41
|
+
# @param dtype [String] The data type of features ('float64' and 'float32').
|
42
|
+
# If metric is given 'hamming', 'uint64' is automatically assigned to this argument.
|
43
|
+
def initialize(n_features:, metric: 'angular', dtype: 'float64') # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
38
44
|
raise ArgumentError, 'Expect n_features to be Integer.' unless n_features.is_a?(Numeric)
|
39
45
|
|
40
46
|
@n_features = n_features.to_i
|
41
47
|
@metric = metric
|
48
|
+
@dtype = dtype
|
42
49
|
|
50
|
+
# rubocop:disable Layout/LineLength
|
43
51
|
@index = case @metric
|
44
52
|
when 'angular'
|
45
|
-
AnnoyIndexAngular.new(@n_features)
|
53
|
+
@dtype == 'float64' ? AnnoyIndexAngular.new(@n_features) : AnnoyIndexAngularFloat32.new(@n_features)
|
46
54
|
when 'dot'
|
47
|
-
AnnoyIndexDotProduct.new(@n_features)
|
55
|
+
@dtype == 'float64' ? AnnoyIndexDotProduct.new(@n_features) : AnnoyIndexDotProductFloat32.new(@n_features)
|
48
56
|
when 'hamming'
|
57
|
+
@dtype = 'uint64'
|
49
58
|
AnnoyIndexHamming.new(@n_features)
|
50
59
|
when 'euclidean'
|
51
|
-
AnnoyIndexEuclidean.new(@n_features)
|
60
|
+
@dtype == 'float64' ? AnnoyIndexEuclidean.new(@n_features) : AnnoyIndexEuclideanFloat32.new(@n_features)
|
52
61
|
when 'manhattan'
|
53
|
-
AnnoyIndexManhattan.new(@n_features)
|
62
|
+
@dtype == 'float64' ? AnnoyIndexManhattan.new(@n_features) : AnnoyIndexManhattanFloat32.new(@n_features)
|
54
63
|
else
|
55
64
|
raise ArgumentError, "No such metric: #{@metric}."
|
56
65
|
end
|
66
|
+
# rubocop:enable Layout/LineLength
|
57
67
|
end
|
58
68
|
|
59
69
|
# Add item to be indexed.
|
@@ -69,6 +79,7 @@ module Annoy
|
|
69
79
|
#
|
70
80
|
# @param n_trees [Integer] The number of trees. More trees gives higher search precision.
|
71
81
|
# @param n_jobs [Integer] The number of threads used to build the trees. If -1 is given, uses all available CPU cores.
|
82
|
+
# This parameter is enabled only if "-DANNOYLIB_MULTITHREADED_BUILD" is specified on gem installation.
|
72
83
|
# @return [Boolean]
|
73
84
|
def build(n_trees, n_jobs: -1)
|
74
85
|
@index.build(n_trees, n_jobs)
|
data/sig/annoy.rbs
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Annoy
|
2
2
|
VERSION: String
|
3
|
+
ANNOY_VERSION: String
|
3
4
|
|
4
5
|
class AnnoyIndex
|
5
6
|
attr_reader n_features: Integer
|
6
7
|
attr_reader metric: String
|
8
|
+
attr_reader dtype: String
|
7
9
|
|
8
|
-
def initialize: (n_features: Integer n_features, ?metric: String metric) -> void
|
10
|
+
def initialize: (n_features: Integer n_features, ?metric: String metric, ?dtype: String dtype) -> void
|
9
11
|
def add_item: (Integer i, Array[Float | Integer] v) -> bool
|
10
12
|
def build: (Integer n_trees, ?n_jobs: Integer n_jobs) -> bool
|
11
13
|
def save: (String filename, ?prefault: bool prefault) -> bool
|
@@ -40,6 +42,24 @@ module Annoy
|
|
40
42
|
def seed: (Integer s) -> nil
|
41
43
|
end
|
42
44
|
|
45
|
+
class AnnoyIndexAngularFloat32
|
46
|
+
def initialize: (Integer n_features) -> void
|
47
|
+
def add_item: (Integer i, Array[Float] v) -> bool
|
48
|
+
def build: (Integer n_trees, Integer n_jobs) -> bool
|
49
|
+
def save: (String filename, bool prefault) -> bool
|
50
|
+
def load: (String filename, bool prefault) -> bool
|
51
|
+
def unload: () -> bool
|
52
|
+
def get_nns_by_item: (Integer i, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
53
|
+
def get_nns_by_vector: (Array[Float] v, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
54
|
+
def get_item: (Integer i) -> Array[Float]
|
55
|
+
def get_distance: (Integer i, Integer j) -> Float
|
56
|
+
def n_items: () -> Integer
|
57
|
+
def n_trees: () -> Integer
|
58
|
+
def on_disk_build: (String filename) -> bool
|
59
|
+
def verbose: (bool flag) -> nil
|
60
|
+
def seed: (Integer s) -> nil
|
61
|
+
end
|
62
|
+
|
43
63
|
class AnnoyIndexDotProduct
|
44
64
|
def initialize: (Integer n_features) -> void
|
45
65
|
def add_item: (Integer i, Array[Float] v) -> bool
|
@@ -58,6 +78,24 @@ module Annoy
|
|
58
78
|
def seed: (Integer s) -> nil
|
59
79
|
end
|
60
80
|
|
81
|
+
class AnnoyIndexDotProductFloat32
|
82
|
+
def initialize: (Integer n_features) -> void
|
83
|
+
def add_item: (Integer i, Array[Float] v) -> bool
|
84
|
+
def build: (Integer n_trees, Integer n_jobs) -> bool
|
85
|
+
def save: (String filename, bool prefault) -> bool
|
86
|
+
def load: (String filename, bool prefault) -> bool
|
87
|
+
def unload: () -> bool
|
88
|
+
def get_nns_by_item: (Integer i, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
89
|
+
def get_nns_by_vector: (Array[Float] v, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
90
|
+
def get_item: (Integer i) -> Array[Float]
|
91
|
+
def get_distance: (Integer i, Integer j) -> Float
|
92
|
+
def n_items: () -> Integer
|
93
|
+
def n_trees: () -> Integer
|
94
|
+
def on_disk_build: (String filename) -> bool
|
95
|
+
def verbose: (bool flag) -> nil
|
96
|
+
def seed: (Integer s) -> nil
|
97
|
+
end
|
98
|
+
|
61
99
|
class AnnoyIndexHamming
|
62
100
|
def initialize: (Integer n_features) -> void
|
63
101
|
def add_item: (Integer i, Array[Integer] v) -> bool
|
@@ -94,6 +132,24 @@ module Annoy
|
|
94
132
|
def seed: (Integer s) -> nil
|
95
133
|
end
|
96
134
|
|
135
|
+
class AnnoyIndexEuclideanFloat32
|
136
|
+
def initialize: (Integer n_features) -> void
|
137
|
+
def add_item: (Integer i, Array[Float] v) -> bool
|
138
|
+
def build: (Integer n_trees, Integer n_jobs) -> bool
|
139
|
+
def save: (String filename, bool prefault) -> bool
|
140
|
+
def load: (String filename, bool prefault) -> bool
|
141
|
+
def unload: () -> bool
|
142
|
+
def get_nns_by_item: (Integer i, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
143
|
+
def get_nns_by_vector: (Array[Float] v, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
144
|
+
def get_item: (Integer i) -> Array[Float]
|
145
|
+
def get_distance: (Integer i, Integer j) -> Float
|
146
|
+
def n_items: () -> Integer
|
147
|
+
def n_trees: () -> Integer
|
148
|
+
def on_disk_build: (String filename) -> bool
|
149
|
+
def verbose: (bool flag) -> nil
|
150
|
+
def seed: (Integer s) -> nil
|
151
|
+
end
|
152
|
+
|
97
153
|
class AnnoyIndexManhattan
|
98
154
|
def initialize: (Integer n_features) -> void
|
99
155
|
def add_item: (Integer i, Array[Float] v) -> bool
|
@@ -111,4 +167,22 @@ module Annoy
|
|
111
167
|
def verbose: (bool flag) -> nil
|
112
168
|
def seed: (Integer s) -> nil
|
113
169
|
end
|
170
|
+
|
171
|
+
class AnnoyIndexManhattanFloat32
|
172
|
+
def initialize: (Integer n_features) -> void
|
173
|
+
def add_item: (Integer i, Array[Float] v) -> bool
|
174
|
+
def build: (Integer n_trees, Integer n_jobs) -> bool
|
175
|
+
def save: (String filename, bool prefault) -> bool
|
176
|
+
def load: (String filename, bool prefault) -> bool
|
177
|
+
def unload: () -> bool
|
178
|
+
def get_nns_by_item: (Integer i, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
179
|
+
def get_nns_by_vector: (Array[Float] v, Integer n, Integer search_k, (true | false) include_distances) -> ([Array[Integer], Array[Float]] | Array[Integer])
|
180
|
+
def get_item: (Integer i) -> Array[Float]
|
181
|
+
def get_distance: (Integer i, Integer j) -> Float
|
182
|
+
def n_items: () -> Integer
|
183
|
+
def n_trees: () -> Integer
|
184
|
+
def on_disk_build: (String filename) -> bool
|
185
|
+
def verbose: (bool flag) -> nil
|
186
|
+
def seed: (Integer s) -> nil
|
187
|
+
end
|
114
188
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: annoy-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yoshoku
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Annoy.rb provides Ruby bindings for the Annoy (Approximate Nearest Neighbors
|
14
14
|
Oh Yeah).
|
@@ -19,17 +19,9 @@ extensions:
|
|
19
19
|
- ext/annoy/extconf.rb
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
|
-
- ".github/workflows/build.yml"
|
23
|
-
- ".gitignore"
|
24
|
-
- ".rspec"
|
25
22
|
- CHANGELOG.md
|
26
|
-
- CODE_OF_CONDUCT.md
|
27
|
-
- Gemfile
|
28
23
|
- LICENSE.txt
|
29
24
|
- README.md
|
30
|
-
- Rakefile
|
31
|
-
- Steepfile
|
32
|
-
- annoy-rb.gemspec
|
33
25
|
- ext/annoy/annoyext.cpp
|
34
26
|
- ext/annoy/annoyext.hpp
|
35
27
|
- ext/annoy/extconf.rb
|
@@ -37,6 +29,7 @@ files:
|
|
37
29
|
- ext/annoy/src/annoylib.h
|
38
30
|
- ext/annoy/src/kissrandom.h
|
39
31
|
- ext/annoy/src/mman.h
|
32
|
+
- lib/annoy-rb.rb
|
40
33
|
- lib/annoy.rb
|
41
34
|
- lib/annoy/version.rb
|
42
35
|
- sig/annoy.rbs
|
@@ -48,6 +41,7 @@ metadata:
|
|
48
41
|
source_code_uri: https://github.com/yoshoku/annoy.rb
|
49
42
|
changelog_uri: https://github.com/yoshoku/annoy.rb/blob/main/CHANGELOG.md
|
50
43
|
documentation_uri: https://yoshoku.github.io/annoy.rb/doc/
|
44
|
+
rubygems_mfa_required: 'true'
|
51
45
|
post_install_message:
|
52
46
|
rdoc_options: []
|
53
47
|
require_paths:
|
@@ -63,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
57
|
- !ruby/object:Gem::Version
|
64
58
|
version: '0'
|
65
59
|
requirements: []
|
66
|
-
rubygems_version: 3.2.
|
60
|
+
rubygems_version: 3.2.33
|
67
61
|
signing_key:
|
68
62
|
specification_version: 4
|
69
63
|
summary: Ruby bindings for the Annoy (Approximate Nearest Neighbors Oh Yeah).
|
data/.github/workflows/build.yml
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
name: build
|
2
|
-
|
3
|
-
on: [push, pull_request]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
build:
|
7
|
-
runs-on: ubuntu-latest
|
8
|
-
strategy:
|
9
|
-
fail-fast: false
|
10
|
-
matrix:
|
11
|
-
ruby: [ '2.6', '2.7', '3.0' ]
|
12
|
-
steps:
|
13
|
-
- uses: actions/checkout@v2
|
14
|
-
- name: Set upt Ruby ${{ matrix.ruby }}
|
15
|
-
uses: ruby/setup-ruby@v1
|
16
|
-
with:
|
17
|
-
ruby-version: ${{ matrix.ruby }}
|
18
|
-
bundler-cache: true
|
19
|
-
- name: Build and test with Rake
|
20
|
-
run: bundle exec rake
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/CODE_OF_CONDUCT.md
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
2
|
-
|
3
|
-
## Our Pledge
|
4
|
-
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
-
orientation.
|
11
|
-
|
12
|
-
## Our Standards
|
13
|
-
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
15
|
-
include:
|
16
|
-
|
17
|
-
* Using welcoming and inclusive language
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
19
|
-
* Gracefully accepting constructive criticism
|
20
|
-
* Focusing on what is best for the community
|
21
|
-
* Showing empathy towards other community members
|
22
|
-
|
23
|
-
Examples of unacceptable behavior by participants include:
|
24
|
-
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
-
advances
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
-
* Public or private harassment
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
30
|
-
address, without explicit permission
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
-
professional setting
|
33
|
-
|
34
|
-
## Our Responsibilities
|
35
|
-
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
38
|
-
response to any instances of unacceptable behavior.
|
39
|
-
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
-
threatening, offensive, or harmful.
|
45
|
-
|
46
|
-
## Scope
|
47
|
-
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
-
when an individual is representing the project or its community. Examples of
|
50
|
-
representing a project or community include using an official project e-mail
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
53
|
-
further defined and clarified by project maintainers.
|
54
|
-
|
55
|
-
## Enforcement
|
56
|
-
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
-
reported by contacting the project team at yoshoku@outlook.com. All
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
63
|
-
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
66
|
-
members of the project's leadership.
|
67
|
-
|
68
|
-
## Attribution
|
69
|
-
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
-
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
-
|
73
|
-
[homepage]: https://contributor-covenant.org
|
74
|
-
[version]: https://contributor-covenant.org/version/1/4/
|
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'bundler/gem_tasks'
|
2
|
-
require 'rspec/core/rake_task'
|
3
|
-
|
4
|
-
RSpec::Core::RakeTask.new(:spec)
|
5
|
-
|
6
|
-
require 'rake/extensiontask'
|
7
|
-
|
8
|
-
task :build => :compile
|
9
|
-
|
10
|
-
Rake::ExtensionTask.new('annoyext') do |ext|
|
11
|
-
ext.ext_dir = 'ext/annoy'
|
12
|
-
ext.lib_dir = 'lib/annoy'
|
13
|
-
end
|
14
|
-
|
15
|
-
task :default => [:clobber, :compile, :spec]
|
data/Steepfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
target :lib do
|
2
|
-
signature "sig"
|
3
|
-
|
4
|
-
check "lib" # Directory name
|
5
|
-
# check "Gemfile" # File name
|
6
|
-
# check "app/models/**/*.rb" # Glob
|
7
|
-
# # ignore "lib/templates/*.rb"
|
8
|
-
#
|
9
|
-
# # library "pathname", "set" # Standard libraries
|
10
|
-
# # library "strong_json" # Gems
|
11
|
-
end
|
12
|
-
|
13
|
-
# target :spec do
|
14
|
-
# signature "sig", "sig-private"
|
15
|
-
#
|
16
|
-
# check "spec"
|
17
|
-
#
|
18
|
-
# # library "pathname", "set" # Standard libraries
|
19
|
-
# # library "rspec"
|
20
|
-
# end
|
data/annoy-rb.gemspec
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require_relative 'lib/annoy/version'
|
2
|
-
|
3
|
-
Gem::Specification.new do |spec|
|
4
|
-
spec.name = 'annoy-rb'
|
5
|
-
spec.version = Annoy::VERSION
|
6
|
-
spec.authors = ['yoshoku']
|
7
|
-
spec.email = ['yoshoku@outlook.com']
|
8
|
-
|
9
|
-
spec.summary = 'Ruby bindings for the Annoy (Approximate Nearest Neighbors Oh Yeah).'
|
10
|
-
spec.description = 'Annoy.rb provides Ruby bindings for the Annoy (Approximate Nearest Neighbors Oh Yeah).'
|
11
|
-
spec.homepage = 'https://github.com/yoshoku/annoy.rb'
|
12
|
-
spec.license = 'Apache-2.0'
|
13
|
-
|
14
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
15
|
-
spec.metadata['source_code_uri'] = spec.homepage
|
16
|
-
spec.metadata['changelog_uri'] = 'https://github.com/yoshoku/annoy.rb/blob/main/CHANGELOG.md'
|
17
|
-
spec.metadata['documentation_uri'] = 'https://yoshoku.github.io/annoy.rb/doc/'
|
18
|
-
|
19
|
-
# Specify which files should be added to the gem when it is released.
|
20
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
22
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
-
end
|
24
|
-
spec.bindir = 'exe'
|
25
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
-
spec.require_paths = ['lib']
|
27
|
-
spec.extensions = ['ext/annoy/extconf.rb']
|
28
|
-
end
|