faiss 0.3.4 → 0.4.1

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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/ext/faiss/ext.cpp +2 -3
  4. data/ext/faiss/index.cpp +13 -14
  5. data/ext/faiss/index_binary.cpp +2 -0
  6. data/ext/faiss/kmeans.cpp +2 -0
  7. data/ext/faiss/pca_matrix.cpp +2 -0
  8. data/ext/faiss/product_quantizer.cpp +2 -0
  9. data/ext/faiss/utils.cpp +3 -0
  10. data/lib/faiss/version.rb +1 -1
  11. data/vendor/faiss/faiss/AutoTune.cpp +11 -8
  12. data/vendor/faiss/faiss/Clustering.cpp +0 -16
  13. data/vendor/faiss/faiss/IVFlib.cpp +213 -0
  14. data/vendor/faiss/faiss/IVFlib.h +42 -0
  15. data/vendor/faiss/faiss/Index.h +1 -1
  16. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -7
  17. data/vendor/faiss/faiss/IndexBinaryFlat.h +2 -1
  18. data/vendor/faiss/faiss/IndexFlatCodes.cpp +1 -1
  19. data/vendor/faiss/faiss/IndexFlatCodes.h +4 -2
  20. data/vendor/faiss/faiss/IndexHNSW.cpp +13 -20
  21. data/vendor/faiss/faiss/IndexHNSW.h +1 -1
  22. data/vendor/faiss/faiss/IndexIVF.cpp +20 -3
  23. data/vendor/faiss/faiss/IndexIVF.h +5 -2
  24. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +2 -1
  25. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +2 -1
  26. data/vendor/faiss/faiss/IndexIVFFlat.cpp +2 -1
  27. data/vendor/faiss/faiss/IndexIVFFlat.h +2 -1
  28. data/vendor/faiss/faiss/IndexIVFPQ.cpp +2 -1
  29. data/vendor/faiss/faiss/IndexIVFPQ.h +2 -1
  30. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +277 -0
  31. data/vendor/faiss/faiss/IndexIVFRaBitQ.h +70 -0
  32. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +2 -1
  33. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +2 -1
  34. data/vendor/faiss/faiss/IndexRaBitQ.cpp +148 -0
  35. data/vendor/faiss/faiss/IndexRaBitQ.h +65 -0
  36. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +2 -1
  37. data/vendor/faiss/faiss/IndexScalarQuantizer.h +2 -1
  38. data/vendor/faiss/faiss/clone_index.cpp +38 -3
  39. data/vendor/faiss/faiss/cppcontrib/factory_tools.cpp +19 -0
  40. data/vendor/faiss/faiss/cppcontrib/factory_tools.h +4 -11
  41. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +2 -1
  42. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +13 -3
  43. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +1 -1
  44. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +1 -1
  45. data/vendor/faiss/faiss/gpu/test/TestGpuIcmEncoder.cpp +112 -0
  46. data/vendor/faiss/faiss/impl/HNSW.cpp +35 -13
  47. data/vendor/faiss/faiss/impl/HNSW.h +5 -4
  48. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -1
  49. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +519 -0
  50. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +78 -0
  51. data/vendor/faiss/faiss/impl/ResultHandler.h +2 -2
  52. data/vendor/faiss/faiss/impl/code_distance/code_distance-sve.h +3 -4
  53. data/vendor/faiss/faiss/impl/index_read.cpp +220 -25
  54. data/vendor/faiss/faiss/impl/index_write.cpp +29 -0
  55. data/vendor/faiss/faiss/impl/io.h +2 -2
  56. data/vendor/faiss/faiss/impl/io_macros.h +2 -0
  57. data/vendor/faiss/faiss/impl/mapped_io.cpp +313 -0
  58. data/vendor/faiss/faiss/impl/mapped_io.h +51 -0
  59. data/vendor/faiss/faiss/impl/maybe_owned_vector.h +316 -0
  60. data/vendor/faiss/faiss/impl/platform_macros.h +7 -3
  61. data/vendor/faiss/faiss/impl/simd_result_handlers.h +1 -1
  62. data/vendor/faiss/faiss/impl/zerocopy_io.cpp +67 -0
  63. data/vendor/faiss/faiss/impl/zerocopy_io.h +32 -0
  64. data/vendor/faiss/faiss/index_factory.cpp +16 -5
  65. data/vendor/faiss/faiss/index_io.h +4 -0
  66. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -3
  67. data/vendor/faiss/faiss/invlists/InvertedLists.h +5 -3
  68. data/vendor/faiss/faiss/invlists/InvertedListsIOHook.cpp +3 -3
  69. data/vendor/faiss/faiss/python/python_callbacks.cpp +24 -0
  70. data/vendor/faiss/faiss/python/python_callbacks.h +22 -0
  71. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +30 -12
  72. data/vendor/faiss/faiss/utils/hamming.cpp +45 -21
  73. data/vendor/faiss/faiss/utils/hamming.h +7 -3
  74. data/vendor/faiss/faiss/utils/hamming_distance/avx512-inl.h +1 -1
  75. data/vendor/faiss/faiss/utils/utils.cpp +4 -4
  76. data/vendor/faiss/faiss/utils/utils.h +3 -3
  77. metadata +16 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc3446fb52271b6e55c4e0ba64cf7146d8bcff39316803e9e7fac68caa0b1d7d
4
- data.tar.gz: fb3bdc9c66b670413df99c0f1d914fd4861ccce30e11a1f959fb570d62d7dca0
3
+ metadata.gz: 94cc2ecdeb397dfce274b08f07006ec7d6d13290f4149d8fca0b9d1a3f2312c6
4
+ data.tar.gz: a32b28f7bc57f9bad918b0411855617951ce8013af7f1ca9dfc72978f5eb1f78
5
5
  SHA512:
6
- metadata.gz: b56a61bbe96f7aa628b0eb819b9404c6c48fba6f2c6cf3802d32fad52a8cbb1abbf97e09700c5d2b22faafef7ba2c5424839f7e98dacbb32d86a60c565c1b9f1
7
- data.tar.gz: dce96c87b15ee7708e1c08f5f7ab4d04c1fb2f4399d5d423cb1ab9de7099ffc0a1bb81a968fb527562bd3d42d1cd131e60fc80cff668de6fa8270c7a81dec8a5
6
+ metadata.gz: 317786c14bbd6803a8abd506881e7072dbd8bfaacce3968c8c26705de45f1840177f5fb3ce189b464e5f1bbffd07a277d6f454a977e1e2aef72bdfb7d7cd04a7
7
+ data.tar.gz: 4de11b05b094b18beaa0326e5d4bf2d7a71c1928b7bd7d12f28f430f7b40b023c6c7b7a4da73f74bc39b0be44c85677113597cf6b60ae4029a96bd11a41f706c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.4.1 (2025-06-18)
2
+
3
+ - Fixed error with Rice 4.6
4
+
5
+ ## 0.4.0 (2025-04-25)
6
+
7
+ - Updated Faiss to 1.11.0
8
+ - Dropped support for Ruby < 3.2
9
+
1
10
  ## 0.3.4 (2025-02-10)
2
11
 
3
12
  - Fixed error with Rice 4.5
data/ext/faiss/ext.cpp CHANGED
@@ -1,4 +1,4 @@
1
- #include "utils.h"
1
+ #include <rice/rice.hpp>
2
2
 
3
3
  void init_index(Rice::Module& m);
4
4
  void init_index_binary(Rice::Module& m);
@@ -7,8 +7,7 @@ void init_pca_matrix(Rice::Module& m);
7
7
  void init_product_quantizer(Rice::Module& m);
8
8
 
9
9
  extern "C"
10
- void Init_ext()
11
- {
10
+ void Init_ext() {
12
11
  auto m = Rice::define_module("Faiss");
13
12
 
14
13
  init_index(m);
data/ext/faiss/index.cpp CHANGED
@@ -1,3 +1,6 @@
1
+ #include <string>
2
+
3
+ #include <faiss/AutoTune.h>
1
4
  #include <faiss/Index.h>
2
5
  #include <faiss/IndexFlat.h>
3
6
  #include <faiss/IndexHNSW.h>
@@ -9,20 +12,20 @@
9
12
  #include <faiss/IndexIVFPQ.h>
10
13
  #include <faiss/IndexIVFPQR.h>
11
14
  #include <faiss/index_io.h>
12
- #include <faiss/AutoTune.h>
15
+ #include <rice/rice.hpp>
16
+ #include <rice/stl.hpp>
13
17
 
18
+ #include "numo.hpp"
14
19
  #include "utils.h"
15
20
 
16
21
  namespace Rice::detail {
17
22
  template<>
18
- struct Type<faiss::MetricType>
19
- {
23
+ struct Type<faiss::MetricType> {
20
24
  static bool verify() { return true; }
21
25
  };
22
26
 
23
27
  template<>
24
- class From_Ruby<faiss::MetricType>
25
- {
28
+ class From_Ruby<faiss::MetricType> {
26
29
  public:
27
30
  From_Ruby() = default;
28
31
 
@@ -30,8 +33,7 @@ namespace Rice::detail {
30
33
 
31
34
  Convertible is_convertible(VALUE value) { return Convertible::Cast; }
32
35
 
33
- faiss::MetricType convert(VALUE x)
34
- {
36
+ faiss::MetricType convert(VALUE x) {
35
37
  if (x == Qnil && this->arg_ && this->arg_->hasDefaultValue()) {
36
38
  return this->arg_->defaultValue<faiss::MetricType>();
37
39
  }
@@ -51,19 +53,16 @@ namespace Rice::detail {
51
53
  };
52
54
 
53
55
  template<>
54
- struct Type<faiss::ScalarQuantizer::QuantizerType>
55
- {
56
+ struct Type<faiss::ScalarQuantizer::QuantizerType> {
56
57
  static bool verify() { return true; }
57
58
  };
58
59
 
59
60
  template<>
60
- class From_Ruby<faiss::ScalarQuantizer::QuantizerType>
61
- {
61
+ class From_Ruby<faiss::ScalarQuantizer::QuantizerType> {
62
62
  public:
63
63
  Convertible is_convertible(VALUE value) { return Convertible::Cast; }
64
64
 
65
- faiss::ScalarQuantizer::QuantizerType convert(VALUE x)
66
- {
65
+ faiss::ScalarQuantizer::QuantizerType convert(VALUE x) {
67
66
  auto s = Object(x).to_s().str();
68
67
  if (s == "qt_8bit") {
69
68
  return faiss::ScalarQuantizer::QT_8bit;
@@ -84,7 +83,7 @@ namespace Rice::detail {
84
83
  }
85
84
  }
86
85
  };
87
- }
86
+ } // namespace Rice::detail
88
87
 
89
88
  void init_index(Rice::Module& m) {
90
89
  Rice::define_class_under<faiss::Index>(m, "Index")
@@ -3,7 +3,9 @@
3
3
  #include <faiss/IndexBinaryIVF.h>
4
4
  #include <faiss/index_factory.h>
5
5
  #include <faiss/index_io.h>
6
+ #include <rice/rice.hpp>
6
7
 
8
+ #include "numo.hpp"
7
9
  #include "utils.h"
8
10
 
9
11
  void init_index_binary(Rice::Module& m) {
data/ext/faiss/kmeans.cpp CHANGED
@@ -1,6 +1,8 @@
1
1
  #include <faiss/Clustering.h>
2
2
  #include <faiss/IndexFlat.h>
3
+ #include <rice/rice.hpp>
3
4
 
5
+ #include "numo.hpp"
4
6
  #include "utils.h"
5
7
 
6
8
  void init_kmeans(Rice::Module& m) {
@@ -1,5 +1,7 @@
1
1
  #include <faiss/VectorTransform.h>
2
+ #include <rice/rice.hpp>
2
3
 
4
+ #include "numo.hpp"
3
5
  #include "utils.h"
4
6
 
5
7
  void init_pca_matrix(Rice::Module& m) {
@@ -1,6 +1,8 @@
1
1
  #include <faiss/impl/ProductQuantizer.h>
2
2
  #include <faiss/index_io.h>
3
+ #include <rice/rice.hpp>
3
4
 
5
+ #include "numo.hpp"
4
6
  #include "utils.h"
5
7
 
6
8
  void init_product_quantizer(Rice::Module& m) {
data/ext/faiss/utils.cpp CHANGED
@@ -1,3 +1,6 @@
1
+ #include <rice/rice.hpp>
2
+
3
+ #include "numo.hpp"
1
4
  #include "utils.h"
2
5
 
3
6
  size_t check_shape(const numo::NArray& objects, size_t k) {
data/lib/faiss/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Faiss
2
- VERSION = "0.3.4"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -15,7 +15,6 @@
15
15
 
16
16
  #include <cinttypes>
17
17
  #include <cmath>
18
- #include <typeinfo>
19
18
 
20
19
  #include <faiss/impl/FaissAssert.h>
21
20
  #include <faiss/utils/random.h>
@@ -313,9 +312,6 @@ bool ParameterSpace::combination_ge(size_t c1, size_t c2) const {
313
312
  return true;
314
313
  }
315
314
 
316
- #define DC(classname) \
317
- const classname* ix = dynamic_cast<const classname*>(index)
318
-
319
315
  static void init_pq_ParameterRange(
320
316
  const ProductQuantizer& pq,
321
317
  ParameterRange& pr) {
@@ -339,6 +335,10 @@ ParameterRange& ParameterSpace::add_range(const std::string& name) {
339
335
  return parameter_ranges.back();
340
336
  }
341
337
 
338
+ // Do not use this macro if ix will be unused
339
+ #define DC(classname) \
340
+ const classname* ix = dynamic_cast<const classname*>(index)
341
+
342
342
  /// initialize with reasonable parameters for this type of index
343
343
  void ParameterSpace::initialize(const Index* index) {
344
344
  if (DC(IndexPreTransform)) {
@@ -394,7 +394,7 @@ void ParameterSpace::initialize(const Index* index) {
394
394
  std::numeric_limits<double>::infinity());
395
395
  }
396
396
  }
397
- if (DC(IndexIVFPQR)) {
397
+ if (dynamic_cast<const IndexIVFPQR*>(index)) {
398
398
  ParameterRange& pr = add_range("k_factor");
399
399
  for (int i = 0; i <= 6; i++) {
400
400
  pr.values.push_back(1 << i);
@@ -410,9 +410,6 @@ void ParameterSpace::initialize(const Index* index) {
410
410
 
411
411
  #undef DC
412
412
 
413
- // non-const version
414
- #define DC(classname) classname* ix = dynamic_cast<classname*>(index)
415
-
416
413
  /// set a combination of parameters on an index
417
414
  void ParameterSpace::set_index_parameters(Index* index, size_t cno) const {
418
415
  for (int i = 0; i < parameter_ranges.size(); i++) {
@@ -442,6 +439,10 @@ void ParameterSpace::set_index_parameters(
442
439
  }
443
440
  }
444
441
 
442
+ // non-const version
443
+ // Do not use this macro if ix will be unused
444
+ #define DC(classname) classname* ix = dynamic_cast<classname*>(index)
445
+
445
446
  void ParameterSpace::set_index_parameter(
446
447
  Index* index,
447
448
  const std::string& name,
@@ -574,6 +575,8 @@ void ParameterSpace::set_index_parameter(
574
575
  name.c_str());
575
576
  }
576
577
 
578
+ #undef DC
579
+
577
580
  void ParameterSpace::display() const {
578
581
  printf("ParameterSpace, %zd parameters, %zd combinations:\n",
579
582
  parameter_ranges.size(),
@@ -33,22 +33,6 @@ Clustering::Clustering(int d, int k) : d(d), k(k) {}
33
33
  Clustering::Clustering(int d, int k, const ClusteringParameters& cp)
34
34
  : ClusteringParameters(cp), d(d), k(k) {}
35
35
 
36
- static double imbalance_factor(int n, int k, int64_t* assign) {
37
- std::vector<int> hist(k, 0);
38
- for (int i = 0; i < n; i++)
39
- hist[assign[i]]++;
40
-
41
- double tot = 0, uf = 0;
42
-
43
- for (int i = 0; i < k; i++) {
44
- tot += hist[i];
45
- uf += hist[i] * (double)hist[i];
46
- }
47
- uf = uf * k / (tot * tot);
48
-
49
- return uf;
50
- }
51
-
52
36
  void Clustering::post_process_centroids() {
53
37
  if (spherical) {
54
38
  fvec_renorm_L2(d, k, centroids.data());
@@ -9,6 +9,7 @@
9
9
  #include <omp.h>
10
10
 
11
11
  #include <memory>
12
+ #include <numeric>
12
13
 
13
14
  #include <faiss/IndexAdditiveQuantizer.h>
14
15
  #include <faiss/IndexIVFAdditiveQuantizer.h>
@@ -16,7 +17,9 @@
16
17
  #include <faiss/IndexPreTransform.h>
17
18
  #include <faiss/IndexRefine.h>
18
19
  #include <faiss/MetaIndexes.h>
20
+ #include <faiss/clone_index.h>
19
21
  #include <faiss/impl/FaissAssert.h>
22
+ #include <faiss/index_io.h>
20
23
  #include <faiss/utils/distances.h>
21
24
  #include <faiss/utils/hamming.h>
22
25
  #include <faiss/utils/utils.h>
@@ -198,12 +201,32 @@ static void shift_and_add(
198
201
  memcpy(dst.data() + insert_point, src.data(), src.size() * sizeof(T));
199
202
  }
200
203
 
204
+ template <class T>
205
+ static void shift_and_add(
206
+ MaybeOwnedVector<T>& dst,
207
+ size_t remove,
208
+ const MaybeOwnedVector<T>& src) {
209
+ if (remove > 0)
210
+ memmove(dst.data(),
211
+ dst.data() + remove,
212
+ (dst.size() - remove) * sizeof(T));
213
+ size_t insert_point = dst.size() - remove;
214
+ dst.resize(insert_point + src.size());
215
+ memcpy(dst.data() + insert_point, src.data(), src.size() * sizeof(T));
216
+ }
217
+
201
218
  template <class T>
202
219
  static void remove_from_begin(std::vector<T>& v, size_t remove) {
203
220
  if (remove > 0)
204
221
  v.erase(v.begin(), v.begin() + remove);
205
222
  }
206
223
 
224
+ template <class T>
225
+ static void remove_from_begin(MaybeOwnedVector<T>& v, size_t remove) {
226
+ if (remove > 0)
227
+ v.erase(v.begin(), v.begin() + remove);
228
+ }
229
+
207
230
  void SlidingIndexWindow::step(const Index* sub_index, bool remove_oldest) {
208
231
  FAISS_THROW_IF_NOT_MSG(
209
232
  !remove_oldest || n_slice > 0,
@@ -519,5 +542,195 @@ void ivf_residual_add_from_flat_codes(
519
542
  index->ntotal += nb;
520
543
  }
521
544
 
545
+ int64_t DefaultShardingFunction::operator()(int64_t i, int64_t shard_count) {
546
+ return i % shard_count;
547
+ }
548
+
549
+ void handle_ivf(
550
+ faiss::IndexIVF* index,
551
+ int64_t shard_count,
552
+ const std::string& filename_template,
553
+ ShardingFunction* sharding_function,
554
+ bool generate_ids) {
555
+ std::vector<faiss::IndexIVF*> sharded_indexes(shard_count);
556
+ auto clone = static_cast<faiss::IndexIVF*>(faiss::clone_index(index));
557
+ clone->quantizer->reset();
558
+ for (int64_t i = 0; i < shard_count; i++) {
559
+ sharded_indexes[i] =
560
+ static_cast<faiss::IndexIVF*>(faiss::clone_index(clone));
561
+ if (generate_ids) {
562
+ // Assume the quantizer does not natively support add_with_ids.
563
+ sharded_indexes[i]->quantizer =
564
+ new IndexIDMap2(sharded_indexes[i]->quantizer);
565
+ }
566
+ }
567
+
568
+ // assign centroids to each sharded Index based on sharding_function, and
569
+ // add them to the quantizer of each sharded index
570
+ std::vector<std::vector<float>> sharded_centroids(shard_count);
571
+ std::vector<std::vector<idx_t>> xids(shard_count);
572
+ for (int64_t i = 0; i < index->quantizer->ntotal; i++) {
573
+ int64_t shard_id = (*sharding_function)(i, shard_count);
574
+ // Since the quantizer does not natively support add_with_ids, we simply
575
+ // generate them.
576
+ xids[shard_id].push_back(i);
577
+ float* reconstructed = new float[index->quantizer->d];
578
+ index->quantizer->reconstruct(i, reconstructed);
579
+ sharded_centroids[shard_id].insert(
580
+ sharded_centroids[shard_id].end(),
581
+ &reconstructed[0],
582
+ &reconstructed[index->quantizer->d]);
583
+ delete[] reconstructed;
584
+ }
585
+ for (int64_t i = 0; i < shard_count; i++) {
586
+ if (generate_ids) {
587
+ sharded_indexes[i]->quantizer->add_with_ids(
588
+ sharded_centroids[i].size() / index->quantizer->d,
589
+ sharded_centroids[i].data(),
590
+ xids[i].data());
591
+ } else {
592
+ sharded_indexes[i]->quantizer->add(
593
+ sharded_centroids[i].size() / index->quantizer->d,
594
+ sharded_centroids[i].data());
595
+ }
596
+ }
597
+
598
+ for (int64_t i = 0; i < shard_count; i++) {
599
+ char fname[256];
600
+ snprintf(fname, 256, filename_template.c_str(), i);
601
+ faiss::write_index(sharded_indexes[i], fname);
602
+ }
603
+
604
+ for (int64_t i = 0; i < shard_count; i++) {
605
+ delete sharded_indexes[i];
606
+ }
607
+ }
608
+
609
+ void handle_binary_ivf(
610
+ faiss::IndexBinaryIVF* index,
611
+ int64_t shard_count,
612
+ const std::string& filename_template,
613
+ ShardingFunction* sharding_function,
614
+ bool generate_ids) {
615
+ std::vector<faiss::IndexBinaryIVF*> sharded_indexes(shard_count);
616
+
617
+ auto clone = static_cast<faiss::IndexBinaryIVF*>(
618
+ faiss::clone_binary_index(index));
619
+ clone->quantizer->reset();
620
+
621
+ for (int64_t i = 0; i < shard_count; i++) {
622
+ sharded_indexes[i] = static_cast<faiss::IndexBinaryIVF*>(
623
+ faiss::clone_binary_index(clone));
624
+ if (generate_ids) {
625
+ // Assume the quantizer does not natively support add_with_ids.
626
+ sharded_indexes[i]->quantizer =
627
+ new IndexBinaryIDMap2(sharded_indexes[i]->quantizer);
628
+ }
629
+ }
630
+
631
+ // assign centroids to each sharded Index based on sharding_function, and
632
+ // add them to the quantizer of each sharded index
633
+ int64_t reconstruction_size = index->quantizer->d / 8;
634
+ std::vector<std::vector<uint8_t>> sharded_centroids(shard_count);
635
+ std::vector<std::vector<idx_t>> xids(shard_count);
636
+ for (int64_t i = 0; i < index->quantizer->ntotal; i++) {
637
+ int64_t shard_id = (*sharding_function)(i, shard_count);
638
+ // Since the quantizer does not natively support add_with_ids, we simply
639
+ // generate them.
640
+ xids[shard_id].push_back(i);
641
+ uint8_t* reconstructed = new uint8_t[reconstruction_size];
642
+ index->quantizer->reconstruct(i, reconstructed);
643
+ sharded_centroids[shard_id].insert(
644
+ sharded_centroids[shard_id].end(),
645
+ &reconstructed[0],
646
+ &reconstructed[reconstruction_size]);
647
+ delete[] reconstructed;
648
+ }
649
+ for (int64_t i = 0; i < shard_count; i++) {
650
+ if (generate_ids) {
651
+ sharded_indexes[i]->quantizer->add_with_ids(
652
+ sharded_centroids[i].size() / reconstruction_size,
653
+ sharded_centroids[i].data(),
654
+ xids[i].data());
655
+ } else {
656
+ sharded_indexes[i]->quantizer->add(
657
+ sharded_centroids[i].size() / reconstruction_size,
658
+ sharded_centroids[i].data());
659
+ }
660
+ }
661
+
662
+ for (int64_t i = 0; i < shard_count; i++) {
663
+ char fname[256];
664
+ snprintf(fname, 256, filename_template.c_str(), i);
665
+ faiss::write_index_binary(sharded_indexes[i], fname);
666
+ }
667
+
668
+ for (int64_t i = 0; i < shard_count; i++) {
669
+ delete sharded_indexes[i];
670
+ }
671
+ }
672
+
673
+ template <typename IndexType>
674
+ void sharding_helper(
675
+ IndexType* index,
676
+ int64_t shard_count,
677
+ const std::string& filename_template,
678
+ ShardingFunction* sharding_function,
679
+ bool generate_ids) {
680
+ FAISS_THROW_IF_MSG(index->quantizer->ntotal == 0, "No centroids to shard.");
681
+ FAISS_THROW_IF_MSG(
682
+ filename_template.find("%d") == std::string::npos,
683
+ "Invalid filename_template. Must contain format specifier for shard count.");
684
+
685
+ DefaultShardingFunction default_sharding_function;
686
+ if (sharding_function == nullptr) {
687
+ sharding_function = &default_sharding_function;
688
+ }
689
+
690
+ if (typeid(IndexType) == typeid(faiss::IndexIVF)) {
691
+ handle_ivf(
692
+ dynamic_cast<faiss::IndexIVF*>(index),
693
+ shard_count,
694
+ filename_template,
695
+ sharding_function,
696
+ generate_ids);
697
+ } else if (typeid(IndexType) == typeid(faiss::IndexBinaryIVF)) {
698
+ handle_binary_ivf(
699
+ dynamic_cast<faiss::IndexBinaryIVF*>(index),
700
+ shard_count,
701
+ filename_template,
702
+ sharding_function,
703
+ generate_ids);
704
+ }
705
+ }
706
+
707
+ void shard_ivf_index_centroids(
708
+ faiss::IndexIVF* index,
709
+ int64_t shard_count,
710
+ const std::string& filename_template,
711
+ ShardingFunction* sharding_function,
712
+ bool generate_ids) {
713
+ sharding_helper(
714
+ index,
715
+ shard_count,
716
+ filename_template,
717
+ sharding_function,
718
+ generate_ids);
719
+ }
720
+
721
+ void shard_binary_ivf_index_centroids(
722
+ faiss::IndexBinaryIVF* index,
723
+ int64_t shard_count,
724
+ const std::string& filename_template,
725
+ ShardingFunction* sharding_function,
726
+ bool generate_ids) {
727
+ sharding_helper(
728
+ index,
729
+ shard_count,
730
+ filename_template,
731
+ sharding_function,
732
+ generate_ids);
733
+ }
734
+
522
735
  } // namespace ivflib
523
736
  } // namespace faiss
@@ -14,6 +14,7 @@
14
14
  * IndexIVFs embedded within an IndexPreTransform.
15
15
  */
16
16
 
17
+ #include <faiss/IndexBinaryIVF.h>
17
18
  #include <faiss/IndexIVF.h>
18
19
  #include <vector>
19
20
 
@@ -167,6 +168,47 @@ void ivf_residual_add_from_flat_codes(
167
168
  const uint8_t* codes,
168
169
  int64_t code_size = -1);
169
170
 
171
+ struct ShardingFunction {
172
+ virtual int64_t operator()(int64_t i, int64_t shard_count) = 0;
173
+ virtual ~ShardingFunction() = default;
174
+ ShardingFunction() {}
175
+ ShardingFunction(const ShardingFunction&) = default;
176
+ ShardingFunction(ShardingFunction&&) = default;
177
+ ShardingFunction& operator=(const ShardingFunction&) = default;
178
+ ShardingFunction& operator=(ShardingFunction&&) = default;
179
+ };
180
+ struct DefaultShardingFunction : ShardingFunction {
181
+ int64_t operator()(int64_t i, int64_t shard_count) override;
182
+ };
183
+
184
+ /**
185
+ * Shards an IVF index centroids by the given sharding function, and writes
186
+ * the index to the path given by filename_generator. The centroids must already
187
+ * be added to the index quantizer.
188
+ *
189
+ * @param index The IVF index containing centroids to shard.
190
+ * @param shard_count Number of shards.
191
+ * @param filename_template Template for shard filenames.
192
+ * @param sharding_function The function to shard by. The default is ith vector
193
+ * mod shard_count.
194
+ * @param generate_ids Generates ids using IndexIDMap2. If true, ids will
195
+ * match the default ids in the unsharded index.
196
+ * @return The number of shards written.
197
+ */
198
+ void shard_ivf_index_centroids(
199
+ IndexIVF* index,
200
+ int64_t shard_count = 20,
201
+ const std::string& filename_template = "shard.%d.index",
202
+ ShardingFunction* sharding_function = nullptr,
203
+ bool generate_ids = false);
204
+
205
+ void shard_binary_ivf_index_centroids(
206
+ faiss::IndexBinaryIVF* index,
207
+ int64_t shard_count = 20,
208
+ const std::string& filename_template = "shard.%d.index",
209
+ ShardingFunction* sharding_function = nullptr,
210
+ bool generate_ids = false);
211
+
170
212
  } // namespace ivflib
171
213
  } // namespace faiss
172
214
 
@@ -17,7 +17,7 @@
17
17
  #include <typeinfo>
18
18
 
19
19
  #define FAISS_VERSION_MAJOR 1
20
- #define FAISS_VERSION_MINOR 10
20
+ #define FAISS_VERSION_MINOR 11
21
21
  #define FAISS_VERSION_PATCH 0
22
22
 
23
23
  // Macro to combine the version components into a single string
@@ -37,8 +37,8 @@ void IndexBinaryFlat::search(
37
37
  int32_t* distances,
38
38
  idx_t* labels,
39
39
  const SearchParameters* params) const {
40
- FAISS_THROW_IF_NOT_MSG(
41
- !params, "search params not supported for this index");
40
+ // Extract IDSelector from params if present
41
+ const IDSelector* sel = params ? params->sel : nullptr;
42
42
  FAISS_THROW_IF_NOT(k > 0);
43
43
 
44
44
  const idx_t block_size = query_batch_size;
@@ -60,7 +60,8 @@ void IndexBinaryFlat::search(
60
60
  ntotal,
61
61
  code_size,
62
62
  /* ordered = */ true,
63
- approx_topk_mode);
63
+ approx_topk_mode,
64
+ sel);
64
65
  } else {
65
66
  hammings_knn_mc(
66
67
  x + s * code_size,
@@ -70,7 +71,8 @@ void IndexBinaryFlat::search(
70
71
  k,
71
72
  code_size,
72
73
  distances + s * k,
73
- labels + s * k);
74
+ labels + s * k,
75
+ sel);
74
76
  }
75
77
  }
76
78
  }
@@ -107,9 +109,9 @@ void IndexBinaryFlat::range_search(
107
109
  int radius,
108
110
  RangeSearchResult* result,
109
111
  const SearchParameters* params) const {
110
- FAISS_THROW_IF_NOT_MSG(
111
- !params, "search params not supported for this index");
112
- hamming_range_search(x, xb.data(), n, ntotal, radius, code_size, result);
112
+ const IDSelector* sel = params ? params->sel : nullptr;
113
+ hamming_range_search(
114
+ x, xb.data(), n, ntotal, radius, code_size, result, sel);
113
115
  }
114
116
 
115
117
  } // namespace faiss
@@ -14,6 +14,7 @@
14
14
 
15
15
  #include <faiss/IndexBinary.h>
16
16
 
17
+ #include <faiss/impl/maybe_owned_vector.h>
17
18
  #include <faiss/utils/approx_topk/mode.h>
18
19
 
19
20
  namespace faiss {
@@ -21,7 +22,7 @@ namespace faiss {
21
22
  /** Index that stores the full vectors and performs exhaustive search. */
22
23
  struct IndexBinaryFlat : IndexBinary {
23
24
  /// database vectors, size ntotal * d / 8
24
- std::vector<uint8_t> xb;
25
+ MaybeOwnedVector<uint8_t> xb;
25
26
 
26
27
  /** Select between using a heap or counting to select the k smallest values
27
28
  * when scanning inverted lists.
@@ -110,7 +110,7 @@ CodePacker* IndexFlatCodes::get_CodePacker() const {
110
110
  }
111
111
 
112
112
  void IndexFlatCodes::permute_entries(const idx_t* perm) {
113
- std::vector<uint8_t> new_codes(codes.size());
113
+ MaybeOwnedVector<uint8_t> new_codes(codes.size());
114
114
 
115
115
  for (idx_t i = 0; i < ntotal; i++) {
116
116
  memcpy(new_codes.data() + i * code_size,
@@ -7,9 +7,11 @@
7
7
 
8
8
  #pragma once
9
9
 
10
+ #include <vector>
11
+
10
12
  #include <faiss/Index.h>
11
13
  #include <faiss/impl/DistanceComputer.h>
12
- #include <vector>
14
+ #include <faiss/impl/maybe_owned_vector.h>
13
15
 
14
16
  namespace faiss {
15
17
 
@@ -21,7 +23,7 @@ struct IndexFlatCodes : Index {
21
23
  size_t code_size;
22
24
 
23
25
  /// encoded dataset, size ntotal * code_size
24
- std::vector<uint8_t> codes;
26
+ MaybeOwnedVector<uint8_t> codes;
25
27
 
26
28
  IndexFlatCodes();
27
29