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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4cdefee51cf2cd6e8eef8bccf558de5f70007625815817312c4f6a5c0ada3fb
4
- data.tar.gz: 327b8c21596c7e7688dfa318095d4cbf9253d93e74a72703ce14f3c5d81d0590
3
+ metadata.gz: 504bef50c398d29e30123e694558cbbb9edc5c3958f457ce3b5622e51467decf
4
+ data.tar.gz: 39965aeddd097635ccdd9e926d2a1b349c294c41a44c2cc5f729c5bc5431d99e
5
5
  SHA512:
6
- metadata.gz: 52bc21959f96e2e33e8bebe6f585311d15614015093a6b2a354e9d736e6343a90c60350a9ee0039387226490a7e613b1622c61ff998d5cb1a4ad3df7533f4960
7
- data.tar.gz: 9b34a4e7416dbc50fa1626764a84eea4921c93ef5d59833c2f176f96519a52f8a009a41460f5e097ac86acebfc67478b79ea6dfe759682b87cafc4a41f0ec8fc
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
- # Annoy.rb
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](http://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/annoy.rb/doc/)
6
+ [![Documentation](https://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/annoy.rb/doc/)
7
7
 
8
- Annoy.rb provides Ruby bindings for the [Annoy (Approximate Nearest Neighbors Oh Yeah)](https://github.com/spotify/annoy).
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: Annoy.rb does not require the installation of another external library.
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
- * [Annoy.rb API Documentation](https://yoshoku.github.io/annoy.rb/doc/)
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 [code of conduct](https://github.com/yoshoku/annoy.rb/blob/main/CODE_OF_CONDUCT.md).
86
+ and contributors are expected to adhere to the [Contributor Covenant](https://contributor-covenant.org) code of conduct.
@@ -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, double>::define_class(rb_mAnnoy, "AnnoyIndexAngular");
26
- RbAnnoyIndex<AnnoyIndexDotProduct, double>::define_class(rb_mAnnoy, "AnnoyIndexDotProduct");
27
- RbAnnoyIndex<AnnoyIndexHamming, uint64_t>::define_class(rb_mAnnoy, "AnnoyIndexHamming");
28
- RbAnnoyIndex<AnnoyIndexEuclidean, double>::define_class(rb_mAnnoy, "AnnoyIndexEuclidean");
29
- RbAnnoyIndex<AnnoyIndexManhattan, double>::define_class(rb_mAnnoy, "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
  }
@@ -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
- typedef AnnoyIndexMultiThreadedBuildPolicy AnnoyIndexThreadedBuildPolicy;
30
+ typedef AnnoyIndexMultiThreadedBuildPolicy AnnoyIndexThreadedBuildPolicy;
30
31
  #else
31
- typedef AnnoyIndexSingleThreadedBuildPolicy AnnoyIndexThreadedBuildPolicy;
32
+ typedef AnnoyIndexSingleThreadedBuildPolicy AnnoyIndexThreadedBuildPolicy;
32
33
  #endif
33
34
 
34
- typedef AnnoyIndex<int, double, Angular, Kiss64Random, AnnoyIndexThreadedBuildPolicy> AnnoyIndexAngular;
35
- typedef AnnoyIndex<int, double, DotProduct, Kiss64Random, AnnoyIndexThreadedBuildPolicy> AnnoyIndexDotProduct;
36
- typedef AnnoyIndex<int, uint64_t, Hamming, Kiss64Random, AnnoyIndexThreadedBuildPolicy> AnnoyIndexHamming;
37
- typedef AnnoyIndex<int, double, Euclidean, Kiss64Random, AnnoyIndexThreadedBuildPolicy> AnnoyIndexEuclidean;
38
- typedef AnnoyIndex<int, double, Manhattan, Kiss64Random, AnnoyIndexThreadedBuildPolicy> AnnoyIndexManhattan;
39
-
40
- template<class T, typename F> class RbAnnoyIndex
41
- {
42
- public:
43
- static VALUE annoy_index_alloc(VALUE self) {
44
- T* ptr = (T*)ruby_xmalloc(sizeof(T));
45
- new (ptr) T();
46
- return TypedData_Wrap_Struct(self, &annoy_index_type, ptr);
47
- };
48
-
49
- static void annoy_index_free(void* ptr) {
50
- ((T*)ptr)->~AnnoyIndex();
51
- ruby_xfree(ptr);
52
- };
53
-
54
- static size_t annoy_index_size(const void* ptr) {
55
- return sizeof(*((T*)ptr));
56
- };
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 int idx = 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);
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
- const int sz_neighbors = neighbors.size();
235
- VALUE neighbors_arr = rb_ary_new2(sz_neighbors);
236
-
237
- for (int i = 0; i < sz_neighbors; i++) {
238
- rb_ary_store(neighbors_arr, i, INT2NUM(neighbors[i]));
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
- if (include_distances) {
242
- const int sz_distances = distances.size();
243
- VALUE distances_arr = rb_ary_new2(sz_distances);
244
- for (int i = 0; i < sz_distances; i++) {
245
- rb_ary_store(distances_arr, i, typeid(F) == typeid(double) ? DBL2NUM(distances[i]) : UINT2NUM(distances[i]));
246
- }
247
- VALUE res = rb_ary_new2(2);
248
- rb_ary_store(res, 0, neighbors_arr);
249
- rb_ary_store(res, 1, distances_arr);
250
- return res;
251
- }
252
-
253
- return neighbors_arr;
254
- };
255
-
256
- static VALUE _annoy_index_get_item(VALUE self, VALUE _idx) {
257
- const int idx = NUM2INT(_idx);
258
- const int n_dims = get_annoy_index(self)->get_f();
259
- F* vec = (F*)ruby_xmalloc(n_dims * sizeof(F));
260
- VALUE arr = rb_ary_new2(n_dims);
261
-
262
- get_annoy_index(self)->get_item(idx, vec);
263
-
264
- for (int i = 0; i < n_dims; i++) {
265
- rb_ary_store(arr, i, typeid(F) == typeid(double) ? DBL2NUM(vec[i]) : UINT2NUM(vec[i]));
266
- }
267
-
268
- ruby_xfree(vec);
269
- return arr;
270
- };
271
-
272
- static VALUE _annoy_index_get_distance(VALUE self, VALUE _i, VALUE _j) {
273
- const int i = NUM2INT(_i);
274
- const int j = NUM2INT(_j);
275
- const F dist = get_annoy_index(self)->get_distance(i, j);
276
- return typeid(F) == typeid(double) ? DBL2NUM(dist) : UINT2NUM(dist);
277
- };
278
-
279
- static VALUE _annoy_index_get_n_items(VALUE self) {
280
- const int32_t n_items = get_annoy_index(self)->get_n_items();
281
- return INT2NUM(n_items);
282
- };
283
-
284
- static VALUE _annoy_index_get_n_trees(VALUE self) {
285
- const int32_t n_trees = get_annoy_index(self)->get_n_trees();
286
- return INT2NUM(n_trees);
287
- };
288
-
289
- static VALUE _annoy_index_on_disk_build(VALUE self, VALUE _filename) {
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
- RB_GC_GUARD(_filename);
299
- return Qtrue;
300
- };
301
-
302
- static VALUE _annoy_index_set_seed(VALUE self, VALUE _seed) {
303
- const int seed = NUM2INT(_seed);
304
- get_annoy_index(self)->set_seed(seed);
305
- return Qnil;
306
- };
307
-
308
- static VALUE _annoy_index_verbose(VALUE self, VALUE _flag) {
309
- const bool flag = _flag == Qtrue ? true : false;
310
- get_annoy_index(self)->verbose(flag);
311
- return Qnil;
312
- };
313
-
314
- static VALUE _annoy_index_get_f(VALUE self) {
315
- const int32_t f = get_annoy_index(self)->get_f();
316
- return INT2NUM(f);
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
@@ -2,7 +2,7 @@ require 'mkmf'
2
2
 
3
3
  abort 'libstdc++ is not found.' unless have_library('stdc++')
4
4
 
5
- $CXXFLAGS << " -std=c++14 -march=native -DANNOYLIB_MULTITHREADED_BUILD"
5
+ $CXXFLAGS << " -std=c++14"
6
6
  $INCFLAGS << " -I$(srcdir)/src"
7
7
  $VPATH << "$(srcdir)/src"
8
8
 
data/lib/annoy/version.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  # Annoy.rb is a Ruby wrapper for Annoy (Approximate Nearest Neighbors Oh Yeah).
4
4
  module Annoy
5
5
  # The version of Annoy.rb you are using.
6
- VERSION = '0.4.0'
6
+ VERSION = '0.6.1'
7
7
 
8
8
  # The version of Annoy included with gem.
9
9
  ANNOY_VERSION = '1.17.0'
data/lib/annoy-rb.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'annoy'
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
- def initialize(n_features:, metric: 'angular')
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.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: 2021-08-06 00:00:00.000000000 Z
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.22
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).
@@ -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
@@ -1,21 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
- *.bundle
10
- *.so
11
- *.o
12
- *.a
13
- mkmf.log
14
-
15
- # rspec failure tracking
16
- .rspec_status
17
-
18
- *.swp
19
- *.dat
20
- tags
21
- .DS_Store
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
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
@@ -1,10 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in annoy.gemspec
4
- gemspec
5
-
6
- gem 'rake', '~> 13.0'
7
- gem 'rake-compiler', '~> 1.1'
8
- gem 'rspec', '~> 3.0'
9
- gem 'rbs', '~> 1.2'
10
- gem 'steep', '~> 0.44'
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