faiss 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 439ff96f613cd71e2a32197194d3814cf5ea516bd31489fdc2bd7a98747ec8ff
4
- data.tar.gz: b2eaf07886acc74aaee4e6f1956a8c09f1d76da0ebaca14b6d4f3e889d728ef7
3
+ metadata.gz: 46b01025b31b0b052236ffb42c9d046de719f2c6ffbdff50299e51f339def739
4
+ data.tar.gz: 1d50d77f839ad49dd6827776dca2f7eeea25eb333ccac6d86077a4366a085065
5
5
  SHA512:
6
- metadata.gz: 03d9a8aa01c86c176437adfab3038b91eb9b9991b2446f4b442114fac8e16133f213eec779d8bdedf80f13c643e96ec2ae39cfa9e1de4313148d53efa565d5c8
7
- data.tar.gz: aa3ef7993a7411cbd480134e054528f069931c57ec55a8dd74c33642fa9debf203507f5744fa1ad178c04d142ac6efd482d63e6df1ced32e890fedd1def73769
6
+ metadata.gz: ffd3ca8a5726dacc053da5c489f19212399c780fd41048793ebd9785716e934ac3e158a5a1fa09c11723fa12ab172d65166bb12216f245dd01864cef83b4608f
7
+ data.tar.gz: c485d9b425913d52f3a53c7e229dffa04fe1535de151b2abb5ac2e09a56d4ba4cfcfd8838846eab5b9a18c898115f56fa107640c210001b69ea8fd8a7eac8428
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.5.3 (2026-02-12)
2
+
3
+ - Added `IndexIDMap2` class
4
+ - Added `remove_ids` method
5
+ - Added `reconstruct_batch` and `reconstruct_n` methods
6
+ - Fixed error when searching frozen indexes
7
+ - Fixed memory leak with frozen exceptions
8
+
9
+ ## 0.5.2 (2026-01-02)
10
+
11
+ - Fixed error with Rice 4.8
12
+
1
13
  ## 0.5.1 (2025-12-20)
2
14
 
3
15
  - Updated Faiss to 1.13.2
data/LICENSE.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  MIT License
2
2
 
3
3
  Copyright (c) Facebook, Inc. and its affiliates.
4
- Copyright (c) 2020-2025 Andrew Kane
4
+ Copyright (c) 2020-2026 Andrew Kane
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
data/ext/faiss/index.cpp CHANGED
@@ -1,4 +1,6 @@
1
+ #include <algorithm>
1
2
  #include <string>
3
+ #include <vector>
2
4
 
3
5
  #include <faiss/AutoTune.h>
4
6
  #include <faiss/Index.h>
@@ -31,13 +33,9 @@ namespace Rice::detail {
31
33
 
32
34
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
33
35
 
34
- Convertible is_convertible(VALUE value) { return Convertible::Cast; }
36
+ double is_convertible(VALUE value) { return Convertible::Exact; }
35
37
 
36
38
  faiss::MetricType convert(VALUE x) {
37
- if (x == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
38
- return this->arg_->defaultValue<faiss::MetricType>();
39
- }
40
-
41
39
  auto s = Object(x).to_s().str();
42
40
  if (s == "inner_product") {
43
41
  return faiss::METRIC_INNER_PRODUCT;
@@ -64,7 +62,7 @@ namespace Rice::detail {
64
62
 
65
63
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
66
64
 
67
- Convertible is_convertible(VALUE value) { return Convertible::Cast; }
65
+ double is_convertible(VALUE value) { return Convertible::Exact; }
68
66
 
69
67
  faiss::ScalarQuantizer::QuantizerType convert(VALUE x) {
70
68
  auto s = Object(x).to_s().str();
@@ -112,7 +110,7 @@ void init_index(Rice::Module& m) {
112
110
  .define_method(
113
111
  "train",
114
112
  [](Rice::Object rb_self, numo::SFloat objects) {
115
- rb_check_frozen(rb_self.value());
113
+ check_frozen(rb_self);
116
114
 
117
115
  auto &self = *Rice::Data_Object<faiss::Index>{rb_self};
118
116
  auto n = check_shape(objects, self.d);
@@ -121,7 +119,7 @@ void init_index(Rice::Module& m) {
121
119
  .define_method(
122
120
  "add",
123
121
  [](Rice::Object rb_self, numo::SFloat objects) {
124
- rb_check_frozen(rb_self.value());
122
+ check_frozen(rb_self);
125
123
 
126
124
  auto &self = *Rice::Data_Object<faiss::Index>{rb_self};
127
125
  auto n = check_shape(objects, self.d);
@@ -130,7 +128,7 @@ void init_index(Rice::Module& m) {
130
128
  .define_method(
131
129
  "add_with_ids",
132
130
  [](Rice::Object rb_self, numo::SFloat objects, numo::Int64 ids) {
133
- rb_check_frozen(rb_self.value());
131
+ check_frozen(rb_self);
134
132
 
135
133
  auto &self = *Rice::Data_Object<faiss::Index>{rb_self};
136
134
  auto n = check_shape(objects, self.d);
@@ -139,6 +137,19 @@ void init_index(Rice::Module& m) {
139
137
  }
140
138
  self.add_with_ids(n, objects.read_ptr(), ids.read_ptr());
141
139
  })
140
+ .define_method(
141
+ "remove_ids",
142
+ [](Rice::Object rb_self, numo::Int64 ids) {
143
+ check_frozen(rb_self);
144
+
145
+ auto &self = *Rice::Data_Object<faiss::Index>{rb_self};
146
+ if (ids.ndim() != 1) {
147
+ throw Rice::Exception(rb_eArgError, "expected ids to be 1d array");
148
+ }
149
+ auto n = ids.shape()[0];
150
+ faiss::IDSelectorBatch sel(n, ids.read_ptr());
151
+ return self.remove_ids(sel);
152
+ })
142
153
  .define_method(
143
154
  "search",
144
155
  [](Rice::Object rb_self, numo::SFloat objects, size_t k) {
@@ -149,9 +160,18 @@ void init_index(Rice::Module& m) {
149
160
  auto labels = numo::Int64({n, k});
150
161
 
151
162
  if (rb_self.is_frozen()) {
163
+ // Don't mess with Ruby-owned memory while the GVL is released
164
+ auto objects_ptr = objects.read_ptr();
165
+ std::vector<float> objects_vec(objects_ptr, objects_ptr + n * self.d);
166
+ std::vector<float> distances_vec(n * k);
167
+ std::vector<int64_t> labels_vec(n * k);
168
+
152
169
  Rice::detail::no_gvl([&] {
153
- self.search(n, objects.read_ptr(), k, distances.write_ptr(), labels.write_ptr());
170
+ self.search(n, objects_vec.data(), k, distances_vec.data(), labels_vec.data());
154
171
  });
172
+
173
+ std::copy(distances_vec.begin(), distances_vec.end(), distances.write_ptr());
174
+ std::copy(labels_vec.begin(), labels_vec.end(), labels.write_ptr());
155
175
  } else {
156
176
  self.search(n, objects.read_ptr(), k, distances.write_ptr(), labels.write_ptr());
157
177
  }
@@ -164,7 +184,7 @@ void init_index(Rice::Module& m) {
164
184
  .define_method(
165
185
  "nprobe=",
166
186
  [](Rice::Object rb_self, double val) {
167
- rb_check_frozen(rb_self.value());
187
+ check_frozen(rb_self);
168
188
 
169
189
  auto &self = *Rice::Data_Object<faiss::Index>{rb_self};
170
190
  faiss::ParameterSpace().set_index_parameter(&self, "nprobe", val);
@@ -177,6 +197,34 @@ void init_index(Rice::Module& m) {
177
197
  self.reconstruct(key, recons.write_ptr());
178
198
  return recons;
179
199
  })
200
+ .define_method(
201
+ "reconstruct_batch",
202
+ [](faiss::Index &self, numo::Int64 ids) {
203
+ if (ids.ndim() != 1) {
204
+ throw Rice::Exception(rb_eArgError, "expected ids to be 1d array");
205
+ }
206
+ auto n = static_cast<std::size_t>(ids.shape()[0]);
207
+ auto d = static_cast<std::size_t>(self.d);
208
+ auto recons = numo::SFloat({n, d});
209
+ self.reconstruct_batch(n, ids.read_ptr(), recons.write_ptr());
210
+ return recons;
211
+ })
212
+ .define_method(
213
+ "reconstruct_n",
214
+ [](faiss::Index &self, int64_t i0, int64_t ni) {
215
+ if (ni < 0) {
216
+ throw Rice::Exception(rb_eArgError, "expected n to be non-negative");
217
+ }
218
+ // second condition written this way to avoid overflow
219
+ if (i0 < 0 || i0 > self.ntotal - ni) {
220
+ throw Rice::Exception(rb_eIndexError, "index out of range");
221
+ }
222
+ auto d = static_cast<std::size_t>(self.d);
223
+ auto n = static_cast<std::size_t>(ni);
224
+ auto recons = numo::SFloat({n, d});
225
+ self.reconstruct_n(i0, ni, recons.write_ptr());
226
+ return recons;
227
+ })
180
228
  .define_method(
181
229
  "save",
182
230
  [](faiss::Index &self, Rice::String fname) {
@@ -195,10 +243,12 @@ void init_index(Rice::Module& m) {
195
243
  .define_constructor(Rice::Constructor<faiss::IndexFlatIP, int64_t>());
196
244
 
197
245
  Rice::define_class_under<faiss::IndexHNSWFlat, faiss::Index>(m, "IndexHNSWFlat")
198
- .define_constructor(Rice::Constructor<faiss::IndexHNSWFlat, int, int, faiss::MetricType>(), Rice::Arg("_d"), Rice::Arg("_M"), Rice::Arg("_metric") = faiss::METRIC_L2);
246
+ .define_constructor(Rice::Constructor<faiss::IndexHNSWFlat, int, int>())
247
+ .define_constructor(Rice::Constructor<faiss::IndexHNSWFlat, int, int, faiss::MetricType>());
199
248
 
200
249
  Rice::define_class_under<faiss::IndexIVFFlat, faiss::Index>(m, "IndexIVFFlat")
201
- .define_constructor(Rice::Constructor<faiss::IndexIVFFlat, faiss::Index*, size_t, size_t, faiss::MetricType>(), Rice::Arg("_quantizer"), Rice::Arg("_d"), Rice::Arg("_nlist"), Rice::Arg("_metric") = faiss::METRIC_L2);
250
+ .define_constructor(Rice::Constructor<faiss::IndexIVFFlat, faiss::Index*, size_t, size_t>())
251
+ .define_constructor(Rice::Constructor<faiss::IndexIVFFlat, faiss::Index*, size_t, size_t, faiss::MetricType>());
202
252
 
203
253
  Rice::define_class_under<faiss::IndexLSH, faiss::Index>(m, "IndexLSH")
204
254
  .define_constructor(Rice::Constructor<faiss::IndexLSH, int64_t, int>());
@@ -213,7 +263,8 @@ void init_index(Rice::Module& m) {
213
263
  .define_constructor(Rice::Constructor<faiss::IndexIVFScalarQuantizer, faiss::Index*, size_t, size_t, faiss::ScalarQuantizer::QuantizerType>());
214
264
 
215
265
  Rice::define_class_under<faiss::IndexIVFPQ, faiss::Index>(m, "IndexIVFPQ")
216
- .define_constructor(Rice::Constructor<faiss::IndexIVFPQ, faiss::Index*, size_t, size_t, size_t, size_t, faiss::MetricType>(), Rice::Arg("_quantizer"), Rice::Arg("_d"), Rice::Arg("_nlist"), Rice::Arg("_M"), Rice::Arg("_nbits_per_idx"), Rice::Arg("_metric") = faiss::METRIC_L2);
266
+ .define_constructor(Rice::Constructor<faiss::IndexIVFPQ, faiss::Index*, size_t, size_t, size_t, size_t>())
267
+ .define_constructor(Rice::Constructor<faiss::IndexIVFPQ, faiss::Index*, size_t, size_t, size_t, size_t, faiss::MetricType>());
217
268
 
218
269
  Rice::define_class_under<faiss::IndexIVFPQR, faiss::Index>(m, "IndexIVFPQR")
219
270
  .define_constructor(Rice::Constructor<faiss::IndexIVFPQR, faiss::Index*, size_t, size_t, size_t, size_t, size_t, size_t>());
@@ -228,4 +279,7 @@ void init_index(Rice::Module& m) {
228
279
 
229
280
  Rice::define_class_under<faiss::IndexIDMap, faiss::Index>(m, "IndexIDMap")
230
281
  .define_constructor(Rice::Constructor<faiss::IndexIDMap, faiss::Index*>());
282
+
283
+ Rice::define_class_under<faiss::IndexIDMap2, faiss::Index>(m, "IndexIDMap2")
284
+ .define_constructor(Rice::Constructor<faiss::IndexIDMap2, faiss::Index*>());
231
285
  }
@@ -1,3 +1,6 @@
1
+ #include <algorithm>
2
+ #include <vector>
3
+
1
4
  #include <faiss/IndexBinary.h>
2
5
  #include <faiss/IndexBinaryFlat.h>
3
6
  #include <faiss/IndexBinaryIVF.h>
@@ -28,7 +31,7 @@ void init_index_binary(Rice::Module& m) {
28
31
  .define_method(
29
32
  "train",
30
33
  [](Rice::Object rb_self, numo::UInt8 objects) {
31
- rb_check_frozen(rb_self.value());
34
+ check_frozen(rb_self);
32
35
 
33
36
  auto &self = *Rice::Data_Object<faiss::IndexBinary>{rb_self};
34
37
  auto n = check_shape(objects, self.d / 8);
@@ -37,12 +40,25 @@ void init_index_binary(Rice::Module& m) {
37
40
  .define_method(
38
41
  "add",
39
42
  [](Rice::Object rb_self, numo::UInt8 objects) {
40
- rb_check_frozen(rb_self.value());
43
+ check_frozen(rb_self);
41
44
 
42
45
  auto &self = *Rice::Data_Object<faiss::IndexBinary>{rb_self};
43
46
  auto n = check_shape(objects, self.d / 8);
44
47
  self.add(n, objects.read_ptr());
45
48
  })
49
+ .define_method(
50
+ "remove_ids",
51
+ [](Rice::Object rb_self, numo::Int64 ids) {
52
+ check_frozen(rb_self);
53
+
54
+ auto &self = *Rice::Data_Object<faiss::IndexBinary>{rb_self};
55
+ if (ids.ndim() != 1) {
56
+ throw Rice::Exception(rb_eArgError, "expected ids to be 1d array");
57
+ }
58
+ auto n = ids.shape()[0];
59
+ faiss::IDSelectorBatch sel(n, ids.read_ptr());
60
+ return self.remove_ids(sel);
61
+ })
46
62
  .define_method(
47
63
  "search",
48
64
  [](Rice::Object rb_self, numo::UInt8 objects, size_t k) {
@@ -53,9 +69,18 @@ void init_index_binary(Rice::Module& m) {
53
69
  auto labels = numo::Int64({n, k});
54
70
 
55
71
  if (rb_self.is_frozen()) {
72
+ // Don't mess with Ruby-owned memory while the GVL is released
73
+ auto objects_ptr = objects.read_ptr();
74
+ std::vector<uint8_t> objects_vec(objects_ptr, objects_ptr + n * (self.d / 8));
75
+ std::vector<int32_t> distances_vec(n * k);
76
+ std::vector<int64_t> labels_vec(n * k);
77
+
56
78
  Rice::detail::no_gvl([&] {
57
- self.search(n, objects.read_ptr(), k, distances.write_ptr(), labels.write_ptr());
79
+ self.search(n, objects_vec.data(), k, distances_vec.data(), labels_vec.data());
58
80
  });
81
+
82
+ std::copy(distances_vec.begin(), distances_vec.end(), distances.write_ptr());
83
+ std::copy(labels_vec.begin(), labels_vec.end(), labels.write_ptr());
59
84
  } else {
60
85
  self.search(n, objects.read_ptr(), k, distances.write_ptr(), labels.write_ptr());
61
86
  }
@@ -65,6 +90,30 @@ void init_index_binary(Rice::Module& m) {
65
90
  ret.push(std::move(labels), false);
66
91
  return ret;
67
92
  })
93
+ .define_method(
94
+ "reconstruct",
95
+ [](faiss::IndexBinary &self, int64_t key) {
96
+ auto d = static_cast<std::size_t>(self.d / 8);
97
+ auto recons = numo::UInt8({d});
98
+ self.reconstruct(key, recons.write_ptr());
99
+ return recons;
100
+ })
101
+ .define_method(
102
+ "reconstruct_n",
103
+ [](faiss::IndexBinary &self, int64_t i0, int64_t ni) {
104
+ if (ni < 0) {
105
+ throw Rice::Exception(rb_eArgError, "expected n to be non-negative");
106
+ }
107
+ // second condition written this way to avoid overflow
108
+ if (i0 < 0 || i0 > self.ntotal - ni) {
109
+ throw Rice::Exception(rb_eIndexError, "index out of range");
110
+ }
111
+ auto d = static_cast<std::size_t>(self.d / 8);
112
+ auto n = static_cast<std::size_t>(ni);
113
+ auto recons = numo::UInt8({n, d});
114
+ self.reconstruct_n(i0, ni, recons.write_ptr());
115
+ return recons;
116
+ })
68
117
  .define_method(
69
118
  "save",
70
119
  [](faiss::IndexBinary &self, Rice::String fname) {
data/ext/faiss/kmeans.cpp CHANGED
@@ -1,3 +1,5 @@
1
+ #include <algorithm>
2
+
1
3
  #include <faiss/Clustering.h>
2
4
  #include <faiss/IndexFlat.h>
3
5
  #include <rice/rice.hpp>
@@ -27,7 +29,7 @@ void init_kmeans(Rice::Module& m) {
27
29
  "centroids",
28
30
  [](faiss::Clustering &self) {
29
31
  auto centroids = numo::SFloat({self.k, self.d});
30
- memcpy(centroids.write_ptr(), self.centroids.data(), self.centroids.size() * sizeof(float));
32
+ std::copy(self.centroids.begin(), self.centroids.end(), centroids.write_ptr());
31
33
  return centroids;
32
34
  })
33
35
  .define_method(
data/ext/faiss/numo.hpp CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Numo.hpp v0.2.1
2
+ * Numo.hpp v0.3.1
3
3
  * https://github.com/ankane/numo.hpp
4
4
  * BSD-2-Clause License
5
5
  */
@@ -38,7 +38,7 @@ public:
38
38
  }
39
39
 
40
40
  bool is_contiguous() const {
41
- return nary_check_contiguous(this->_value) == Qtrue;
41
+ return Rice::detail::protect(nary_check_contiguous, this->_value) == Qtrue;
42
42
  }
43
43
 
44
44
  operator Rice::Object() const {
@@ -46,26 +46,28 @@ public:
46
46
  }
47
47
 
48
48
  const void* read_ptr() {
49
- if (!is_contiguous()) {
50
- this->_value = nary_dup(this->_value);
51
- }
52
- return nary_get_pointer_for_read(this->_value) + nary_get_offset(this->_value);
49
+ return Rice::detail::protect([&]() {
50
+ if (!nary_check_contiguous(this->_value)) {
51
+ this->_value = nary_dup(this->_value);
52
+ }
53
+ return nary_get_pointer_for_read(this->_value) + nary_get_offset(this->_value);
54
+ });
53
55
  }
54
56
 
55
57
  void* write_ptr() {
56
- return nary_get_pointer_for_write(this->_value);
58
+ return Rice::detail::protect(nary_get_pointer_for_write, this->_value);
57
59
  }
58
60
 
59
61
  protected:
60
62
  NArray() { }
61
63
 
62
64
  void construct_value(VALUE dtype, VALUE v) {
63
- this->_value = rb_funcall(dtype, rb_intern("cast"), 1, v);
65
+ this->_value = Rice::detail::protect(rb_funcall, dtype, rb_intern("cast"), 1, v);
64
66
  }
65
67
 
66
68
  void construct_shape(VALUE dtype, std::initializer_list<size_t> shape) {
67
69
  // rb_narray_new doesn't modify shape, but not marked as const
68
- this->_value = rb_narray_new(dtype, shape.size(), const_cast<size_t*>(shape.begin()));
70
+ this->_value = Rice::detail::protect(rb_narray_new, dtype, shape.size(), const_cast<size_t*>(shape.begin()));
69
71
  }
70
72
 
71
73
  VALUE _value;
@@ -460,12 +462,12 @@ public:
460
462
 
461
463
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
462
464
 
463
- Convertible is_convertible(VALUE value) {
465
+ double is_convertible(VALUE value) {
464
466
  switch (rb_type(value)) {
465
467
  case RUBY_T_DATA:
466
468
  return Data_Type<numo::NArray>::is_descendant(value) ? Convertible::Exact : Convertible::None;
467
469
  case RUBY_T_ARRAY:
468
- return Convertible::Cast;
470
+ return Convertible::Exact;
469
471
  default:
470
472
  return Convertible::None;
471
473
  }
@@ -506,12 +508,12 @@ public:
506
508
 
507
509
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
508
510
 
509
- Convertible is_convertible(VALUE value) {
511
+ double is_convertible(VALUE value) {
510
512
  switch (rb_type(value)) {
511
513
  case RUBY_T_DATA:
512
514
  return Data_Type<numo::SFloat>::is_descendant(value) ? Convertible::Exact : Convertible::None;
513
515
  case RUBY_T_ARRAY:
514
- return Convertible::Cast;
516
+ return Convertible::Exact;
515
517
  default:
516
518
  return Convertible::None;
517
519
  }
@@ -552,12 +554,12 @@ public:
552
554
 
553
555
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
554
556
 
555
- Convertible is_convertible(VALUE value) {
557
+ double is_convertible(VALUE value) {
556
558
  switch (rb_type(value)) {
557
559
  case RUBY_T_DATA:
558
560
  return Data_Type<numo::DFloat>::is_descendant(value) ? Convertible::Exact : Convertible::None;
559
561
  case RUBY_T_ARRAY:
560
- return Convertible::Cast;
562
+ return Convertible::Exact;
561
563
  default:
562
564
  return Convertible::None;
563
565
  }
@@ -598,12 +600,12 @@ public:
598
600
 
599
601
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
600
602
 
601
- Convertible is_convertible(VALUE value) {
603
+ double is_convertible(VALUE value) {
602
604
  switch (rb_type(value)) {
603
605
  case RUBY_T_DATA:
604
606
  return Data_Type<numo::Int8>::is_descendant(value) ? Convertible::Exact : Convertible::None;
605
607
  case RUBY_T_ARRAY:
606
- return Convertible::Cast;
608
+ return Convertible::Exact;
607
609
  default:
608
610
  return Convertible::None;
609
611
  }
@@ -644,12 +646,12 @@ public:
644
646
 
645
647
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
646
648
 
647
- Convertible is_convertible(VALUE value) {
649
+ double is_convertible(VALUE value) {
648
650
  switch (rb_type(value)) {
649
651
  case RUBY_T_DATA:
650
652
  return Data_Type<numo::Int16>::is_descendant(value) ? Convertible::Exact : Convertible::None;
651
653
  case RUBY_T_ARRAY:
652
- return Convertible::Cast;
654
+ return Convertible::Exact;
653
655
  default:
654
656
  return Convertible::None;
655
657
  }
@@ -690,12 +692,12 @@ public:
690
692
 
691
693
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
692
694
 
693
- Convertible is_convertible(VALUE value) {
695
+ double is_convertible(VALUE value) {
694
696
  switch (rb_type(value)) {
695
697
  case RUBY_T_DATA:
696
698
  return Data_Type<numo::Int32>::is_descendant(value) ? Convertible::Exact : Convertible::None;
697
699
  case RUBY_T_ARRAY:
698
- return Convertible::Cast;
700
+ return Convertible::Exact;
699
701
  default:
700
702
  return Convertible::None;
701
703
  }
@@ -736,12 +738,12 @@ public:
736
738
 
737
739
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
738
740
 
739
- Convertible is_convertible(VALUE value) {
741
+ double is_convertible(VALUE value) {
740
742
  switch (rb_type(value)) {
741
743
  case RUBY_T_DATA:
742
744
  return Data_Type<numo::Int64>::is_descendant(value) ? Convertible::Exact : Convertible::None;
743
745
  case RUBY_T_ARRAY:
744
- return Convertible::Cast;
746
+ return Convertible::Exact;
745
747
  default:
746
748
  return Convertible::None;
747
749
  }
@@ -782,12 +784,12 @@ public:
782
784
 
783
785
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
784
786
 
785
- Convertible is_convertible(VALUE value) {
787
+ double is_convertible(VALUE value) {
786
788
  switch (rb_type(value)) {
787
789
  case RUBY_T_DATA:
788
790
  return Data_Type<numo::UInt8>::is_descendant(value) ? Convertible::Exact : Convertible::None;
789
791
  case RUBY_T_ARRAY:
790
- return Convertible::Cast;
792
+ return Convertible::Exact;
791
793
  default:
792
794
  return Convertible::None;
793
795
  }
@@ -828,12 +830,12 @@ public:
828
830
 
829
831
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
830
832
 
831
- Convertible is_convertible(VALUE value) {
833
+ double is_convertible(VALUE value) {
832
834
  switch (rb_type(value)) {
833
835
  case RUBY_T_DATA:
834
836
  return Data_Type<numo::UInt16>::is_descendant(value) ? Convertible::Exact : Convertible::None;
835
837
  case RUBY_T_ARRAY:
836
- return Convertible::Cast;
838
+ return Convertible::Exact;
837
839
  default:
838
840
  return Convertible::None;
839
841
  }
@@ -874,12 +876,12 @@ public:
874
876
 
875
877
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
876
878
 
877
- Convertible is_convertible(VALUE value) {
879
+ double is_convertible(VALUE value) {
878
880
  switch (rb_type(value)) {
879
881
  case RUBY_T_DATA:
880
882
  return Data_Type<numo::UInt32>::is_descendant(value) ? Convertible::Exact : Convertible::None;
881
883
  case RUBY_T_ARRAY:
882
- return Convertible::Cast;
884
+ return Convertible::Exact;
883
885
  default:
884
886
  return Convertible::None;
885
887
  }
@@ -920,12 +922,12 @@ public:
920
922
 
921
923
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
922
924
 
923
- Convertible is_convertible(VALUE value) {
925
+ double is_convertible(VALUE value) {
924
926
  switch (rb_type(value)) {
925
927
  case RUBY_T_DATA:
926
928
  return Data_Type<numo::UInt64>::is_descendant(value) ? Convertible::Exact : Convertible::None;
927
929
  case RUBY_T_ARRAY:
928
- return Convertible::Cast;
930
+ return Convertible::Exact;
929
931
  default:
930
932
  return Convertible::None;
931
933
  }
@@ -966,12 +968,12 @@ public:
966
968
 
967
969
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
968
970
 
969
- Convertible is_convertible(VALUE value) {
971
+ double is_convertible(VALUE value) {
970
972
  switch (rb_type(value)) {
971
973
  case RUBY_T_DATA:
972
974
  return Data_Type<numo::SComplex>::is_descendant(value) ? Convertible::Exact : Convertible::None;
973
975
  case RUBY_T_ARRAY:
974
- return Convertible::Cast;
976
+ return Convertible::Exact;
975
977
  default:
976
978
  return Convertible::None;
977
979
  }
@@ -1012,12 +1014,12 @@ public:
1012
1014
 
1013
1015
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
1014
1016
 
1015
- Convertible is_convertible(VALUE value) {
1017
+ double is_convertible(VALUE value) {
1016
1018
  switch (rb_type(value)) {
1017
1019
  case RUBY_T_DATA:
1018
1020
  return Data_Type<numo::DComplex>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1019
1021
  case RUBY_T_ARRAY:
1020
- return Convertible::Cast;
1022
+ return Convertible::Exact;
1021
1023
  default:
1022
1024
  return Convertible::None;
1023
1025
  }
@@ -1058,12 +1060,12 @@ public:
1058
1060
 
1059
1061
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
1060
1062
 
1061
- Convertible is_convertible(VALUE value) {
1063
+ double is_convertible(VALUE value) {
1062
1064
  switch (rb_type(value)) {
1063
1065
  case RUBY_T_DATA:
1064
1066
  return Data_Type<numo::Bit>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1065
1067
  case RUBY_T_ARRAY:
1066
- return Convertible::Cast;
1068
+ return Convertible::Exact;
1067
1069
  default:
1068
1070
  return Convertible::None;
1069
1071
  }
@@ -1104,12 +1106,12 @@ public:
1104
1106
 
1105
1107
  explicit From_Ruby(Arg* arg) : arg_(arg) { }
1106
1108
 
1107
- Convertible is_convertible(VALUE value) {
1109
+ double is_convertible(VALUE value) {
1108
1110
  switch (rb_type(value)) {
1109
1111
  case RUBY_T_DATA:
1110
1112
  return Data_Type<numo::RObject>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1111
1113
  case RUBY_T_ARRAY:
1112
- return Convertible::Cast;
1114
+ return Convertible::Exact;
1113
1115
  default:
1114
1116
  return Convertible::None;
1115
1117
  }
data/ext/faiss/utils.cpp CHANGED
@@ -14,3 +14,8 @@ size_t check_shape(const numo::NArray& objects, size_t k) {
14
14
  }
15
15
  return shape[0];
16
16
  }
17
+
18
+ void check_frozen(Rice::Object obj) {
19
+ // use protect to avoid skipping destructors and leaking memory
20
+ Rice::detail::protect(rb_check_frozen, obj.value());
21
+ }
data/ext/faiss/utils.h CHANGED
@@ -3,3 +3,5 @@
3
3
  #include "numo.hpp"
4
4
 
5
5
  size_t check_shape(const numo::NArray& objects, size_t k);
6
+
7
+ void check_frozen(Rice::Object obj);
data/lib/faiss/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Faiss
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faiss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '4.7'
18
+ version: '4.8'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '4.7'
25
+ version: '4.8'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: numo-narray
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -407,7 +407,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
407
407
  - !ruby/object:Gem::Version
408
408
  version: '0'
409
409
  requirements: []
410
- rubygems_version: 3.6.9
410
+ rubygems_version: 4.0.3
411
411
  specification_version: 4
412
412
  summary: Efficient similarity search and clustering for Ruby
413
413
  test_files: []