faiss 0.2.6 → 0.2.7

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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/faiss/extconf.rb +1 -1
  4. data/lib/faiss/version.rb +1 -1
  5. data/lib/faiss.rb +2 -2
  6. data/vendor/faiss/faiss/AutoTune.cpp +15 -4
  7. data/vendor/faiss/faiss/AutoTune.h +0 -1
  8. data/vendor/faiss/faiss/Clustering.cpp +1 -5
  9. data/vendor/faiss/faiss/Clustering.h +0 -2
  10. data/vendor/faiss/faiss/IVFlib.h +0 -2
  11. data/vendor/faiss/faiss/Index.h +1 -2
  12. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +17 -3
  13. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +10 -1
  14. data/vendor/faiss/faiss/IndexBinary.h +0 -1
  15. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +2 -1
  16. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -0
  17. data/vendor/faiss/faiss/IndexBinaryHash.cpp +1 -3
  18. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +273 -48
  19. data/vendor/faiss/faiss/IndexBinaryIVF.h +18 -11
  20. data/vendor/faiss/faiss/IndexFastScan.cpp +13 -10
  21. data/vendor/faiss/faiss/IndexFastScan.h +5 -1
  22. data/vendor/faiss/faiss/IndexFlat.cpp +16 -3
  23. data/vendor/faiss/faiss/IndexFlat.h +1 -1
  24. data/vendor/faiss/faiss/IndexFlatCodes.cpp +5 -0
  25. data/vendor/faiss/faiss/IndexFlatCodes.h +7 -2
  26. data/vendor/faiss/faiss/IndexHNSW.cpp +3 -6
  27. data/vendor/faiss/faiss/IndexHNSW.h +0 -1
  28. data/vendor/faiss/faiss/IndexIDMap.cpp +4 -4
  29. data/vendor/faiss/faiss/IndexIDMap.h +0 -2
  30. data/vendor/faiss/faiss/IndexIVF.cpp +155 -129
  31. data/vendor/faiss/faiss/IndexIVF.h +121 -61
  32. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +2 -2
  33. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +12 -11
  34. data/vendor/faiss/faiss/IndexIVFFastScan.h +6 -1
  35. data/vendor/faiss/faiss/IndexIVFPQ.cpp +221 -165
  36. data/vendor/faiss/faiss/IndexIVFPQ.h +1 -0
  37. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +6 -1
  38. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +0 -2
  39. data/vendor/faiss/faiss/IndexNNDescent.cpp +1 -2
  40. data/vendor/faiss/faiss/IndexNNDescent.h +0 -1
  41. data/vendor/faiss/faiss/IndexNSG.cpp +1 -2
  42. data/vendor/faiss/faiss/IndexPQ.cpp +7 -9
  43. data/vendor/faiss/faiss/IndexRefine.cpp +1 -1
  44. data/vendor/faiss/faiss/IndexReplicas.cpp +3 -4
  45. data/vendor/faiss/faiss/IndexReplicas.h +0 -1
  46. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +8 -1
  47. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +7 -0
  48. data/vendor/faiss/faiss/IndexShards.cpp +26 -109
  49. data/vendor/faiss/faiss/IndexShards.h +2 -3
  50. data/vendor/faiss/faiss/IndexShardsIVF.cpp +246 -0
  51. data/vendor/faiss/faiss/IndexShardsIVF.h +42 -0
  52. data/vendor/faiss/faiss/MetaIndexes.cpp +86 -0
  53. data/vendor/faiss/faiss/MetaIndexes.h +29 -0
  54. data/vendor/faiss/faiss/MetricType.h +14 -0
  55. data/vendor/faiss/faiss/VectorTransform.cpp +8 -10
  56. data/vendor/faiss/faiss/VectorTransform.h +1 -3
  57. data/vendor/faiss/faiss/clone_index.cpp +232 -18
  58. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +25 -3
  59. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +7 -0
  60. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +78 -0
  61. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +20 -6
  62. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +7 -1
  63. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +21 -7
  64. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +7 -0
  65. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +7 -0
  66. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +10 -3
  67. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +7 -1
  68. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +11 -3
  69. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +25 -2
  70. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +76 -29
  71. data/vendor/faiss/faiss/gpu/GpuCloner.h +2 -2
  72. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +14 -13
  73. data/vendor/faiss/faiss/gpu/GpuDistance.h +18 -6
  74. data/vendor/faiss/faiss/gpu/GpuIndex.h +23 -21
  75. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +10 -10
  76. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -12
  77. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +29 -50
  78. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +3 -3
  79. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +8 -8
  80. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +4 -4
  81. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +2 -5
  82. data/vendor/faiss/faiss/gpu/impl/RemapIndices.cpp +9 -7
  83. data/vendor/faiss/faiss/gpu/impl/RemapIndices.h +4 -4
  84. data/vendor/faiss/faiss/gpu/perf/IndexWrapper-inl.h +2 -2
  85. data/vendor/faiss/faiss/gpu/perf/IndexWrapper.h +1 -1
  86. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +55 -6
  87. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +20 -6
  88. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +95 -25
  89. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +67 -16
  90. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +4 -4
  91. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +7 -7
  92. data/vendor/faiss/faiss/gpu/test/TestUtils.h +4 -4
  93. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +1 -1
  94. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +6 -0
  95. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +0 -7
  96. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +9 -9
  97. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +1 -1
  98. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +2 -7
  99. data/vendor/faiss/faiss/impl/CodePacker.cpp +67 -0
  100. data/vendor/faiss/faiss/impl/CodePacker.h +71 -0
  101. data/vendor/faiss/faiss/impl/DistanceComputer.h +0 -2
  102. data/vendor/faiss/faiss/impl/HNSW.cpp +3 -7
  103. data/vendor/faiss/faiss/impl/HNSW.h +6 -9
  104. data/vendor/faiss/faiss/impl/IDSelector.cpp +1 -1
  105. data/vendor/faiss/faiss/impl/IDSelector.h +39 -1
  106. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +62 -51
  107. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +11 -12
  108. data/vendor/faiss/faiss/impl/NNDescent.cpp +3 -9
  109. data/vendor/faiss/faiss/impl/NNDescent.h +10 -10
  110. data/vendor/faiss/faiss/impl/NSG.cpp +1 -6
  111. data/vendor/faiss/faiss/impl/NSG.h +4 -7
  112. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +1 -15
  113. data/vendor/faiss/faiss/impl/PolysemousTraining.h +11 -10
  114. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +0 -7
  115. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +25 -12
  116. data/vendor/faiss/faiss/impl/ProductQuantizer.h +2 -4
  117. data/vendor/faiss/faiss/impl/Quantizer.h +6 -3
  118. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +796 -174
  119. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +16 -8
  120. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +3 -5
  121. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +4 -4
  122. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +3 -3
  123. data/vendor/faiss/faiss/impl/ThreadedIndex.h +4 -4
  124. data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +291 -0
  125. data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +74 -0
  126. data/vendor/faiss/faiss/impl/code_distance/code_distance.h +123 -0
  127. data/vendor/faiss/faiss/impl/code_distance/code_distance_avx512.h +102 -0
  128. data/vendor/faiss/faiss/impl/index_read.cpp +13 -10
  129. data/vendor/faiss/faiss/impl/index_write.cpp +3 -4
  130. data/vendor/faiss/faiss/impl/kmeans1d.cpp +0 -1
  131. data/vendor/faiss/faiss/impl/kmeans1d.h +3 -3
  132. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -1
  133. data/vendor/faiss/faiss/impl/platform_macros.h +61 -0
  134. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +48 -4
  135. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +18 -4
  136. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +2 -2
  137. data/vendor/faiss/faiss/index_factory.cpp +8 -10
  138. data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +29 -12
  139. data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +8 -2
  140. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  141. data/vendor/faiss/faiss/invlists/DirectMap.h +2 -4
  142. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +118 -18
  143. data/vendor/faiss/faiss/invlists/InvertedLists.h +44 -4
  144. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +3 -3
  145. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +1 -1
  146. data/vendor/faiss/faiss/python/python_callbacks.cpp +1 -1
  147. data/vendor/faiss/faiss/python/python_callbacks.h +1 -1
  148. data/vendor/faiss/faiss/utils/AlignedTable.h +3 -1
  149. data/vendor/faiss/faiss/utils/Heap.cpp +139 -3
  150. data/vendor/faiss/faiss/utils/Heap.h +35 -1
  151. data/vendor/faiss/faiss/utils/approx_topk/approx_topk.h +84 -0
  152. data/vendor/faiss/faiss/utils/approx_topk/avx2-inl.h +196 -0
  153. data/vendor/faiss/faiss/utils/approx_topk/generic.h +138 -0
  154. data/vendor/faiss/faiss/utils/approx_topk/mode.h +34 -0
  155. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +367 -0
  156. data/vendor/faiss/faiss/utils/distances.cpp +61 -7
  157. data/vendor/faiss/faiss/utils/distances.h +11 -0
  158. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +346 -0
  159. data/vendor/faiss/faiss/utils/distances_fused/avx512.h +36 -0
  160. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +42 -0
  161. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +40 -0
  162. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +352 -0
  163. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.h +32 -0
  164. data/vendor/faiss/faiss/utils/distances_simd.cpp +515 -327
  165. data/vendor/faiss/faiss/utils/extra_distances-inl.h +17 -1
  166. data/vendor/faiss/faiss/utils/extra_distances.cpp +37 -8
  167. data/vendor/faiss/faiss/utils/extra_distances.h +2 -1
  168. data/vendor/faiss/faiss/utils/fp16-fp16c.h +7 -0
  169. data/vendor/faiss/faiss/utils/fp16-inl.h +7 -0
  170. data/vendor/faiss/faiss/utils/fp16.h +7 -0
  171. data/vendor/faiss/faiss/utils/hamming-inl.h +0 -456
  172. data/vendor/faiss/faiss/utils/hamming.cpp +104 -120
  173. data/vendor/faiss/faiss/utils/hamming.h +21 -10
  174. data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +535 -0
  175. data/vendor/faiss/faiss/utils/hamming_distance/common.h +48 -0
  176. data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +519 -0
  177. data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +26 -0
  178. data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +614 -0
  179. data/vendor/faiss/faiss/utils/partitioning.cpp +21 -25
  180. data/vendor/faiss/faiss/utils/simdlib_avx2.h +344 -3
  181. data/vendor/faiss/faiss/utils/simdlib_emulated.h +390 -0
  182. data/vendor/faiss/faiss/utils/simdlib_neon.h +655 -130
  183. data/vendor/faiss/faiss/utils/sorting.cpp +692 -0
  184. data/vendor/faiss/faiss/utils/sorting.h +71 -0
  185. data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +165 -0
  186. data/vendor/faiss/faiss/utils/utils.cpp +4 -176
  187. data/vendor/faiss/faiss/utils/utils.h +2 -9
  188. metadata +29 -3
  189. data/vendor/faiss/faiss/gpu/GpuClonerOptions.cpp +0 -26
@@ -24,9 +24,6 @@
24
24
  #include <sys/stat.h>
25
25
  #include <sys/types.h>
26
26
 
27
- #ifdef __SSE__
28
- #endif
29
-
30
27
  #include <faiss/Index2Layer.h>
31
28
  #include <faiss/IndexFlat.h>
32
29
  #include <faiss/IndexIVFPQ.h>
@@ -35,6 +32,7 @@
35
32
  #include <faiss/utils/Heap.h>
36
33
  #include <faiss/utils/distances.h>
37
34
  #include <faiss/utils/random.h>
35
+ #include <faiss/utils/sorting.h>
38
36
 
39
37
  extern "C" {
40
38
 
@@ -58,7 +56,6 @@ int sgemm_(
58
56
 
59
57
  namespace faiss {
60
58
 
61
- using idx_t = Index::idx_t;
62
59
  using MinimaxHeap = HNSW::MinimaxHeap;
63
60
  using storage_idx_t = HNSW::storage_idx_t;
64
61
  using NodeDistFarther = HNSW::NodeDistFarther;
@@ -101,7 +98,7 @@ struct NegativeDistanceComputer : DistanceComputer {
101
98
  };
102
99
 
103
100
  DistanceComputer* storage_distance_computer(const Index* storage) {
104
- if (storage->metric_type == METRIC_INNER_PRODUCT) {
101
+ if (is_similarity_metric(storage->metric_type)) {
105
102
  return new NegativeDistanceComputer(storage->get_distance_computer());
106
103
  } else {
107
104
  return storage->get_distance_computer();
@@ -349,7 +346,7 @@ void IndexHNSW::search(
349
346
  InterruptCallback::check();
350
347
  }
351
348
 
352
- if (metric_type == METRIC_INNER_PRODUCT) {
349
+ if (is_similarity_metric(metric_type)) {
353
350
  // we need to revert the negated distances
354
351
  for (size_t i = 0; i < k * n; i++) {
355
352
  distances[i] = -distances[i];
@@ -22,7 +22,6 @@ namespace faiss {
22
22
  struct IndexHNSW;
23
23
 
24
24
  struct ReconstructFromNeighbors {
25
- typedef Index::idx_t idx_t;
26
25
  typedef HNSW::storage_idx_t storage_idx_t;
27
26
 
28
27
  const IndexHNSW& index;
@@ -64,7 +64,7 @@ template <typename IndexT>
64
64
  void IndexIDMapTemplate<IndexT>::add_with_ids(
65
65
  idx_t n,
66
66
  const typename IndexT::component_t* x,
67
- const typename IndexT::idx_t* xids) {
67
+ const idx_t* xids) {
68
68
  index->add(n, x);
69
69
  for (idx_t i = 0; i < n; i++)
70
70
  id_map.push_back(xids[i]);
@@ -77,7 +77,7 @@ void IndexIDMapTemplate<IndexT>::search(
77
77
  const typename IndexT::component_t* x,
78
78
  idx_t k,
79
79
  typename IndexT::distance_t* distances,
80
- typename IndexT::idx_t* labels,
80
+ idx_t* labels,
81
81
  const SearchParameters* params) const {
82
82
  FAISS_THROW_IF_NOT_MSG(
83
83
  !params, "search params not supported for this index");
@@ -91,7 +91,7 @@ void IndexIDMapTemplate<IndexT>::search(
91
91
 
92
92
  template <typename IndexT>
93
93
  void IndexIDMapTemplate<IndexT>::range_search(
94
- typename IndexT::idx_t n,
94
+ idx_t n,
95
95
  const typename IndexT::component_t* x,
96
96
  typename IndexT::distance_t radius,
97
97
  RangeSearchResult* result,
@@ -182,7 +182,7 @@ template <typename IndexT>
182
182
  void IndexIDMap2Template<IndexT>::add_with_ids(
183
183
  idx_t n,
184
184
  const typename IndexT::component_t* x,
185
- const typename IndexT::idx_t* xids) {
185
+ const idx_t* xids) {
186
186
  size_t prev_ntotal = this->ntotal;
187
187
  IndexIDMapTemplate<IndexT>::add_with_ids(n, x, xids);
188
188
  for (size_t i = prev_ntotal; i < this->ntotal; i++) {
@@ -18,7 +18,6 @@ namespace faiss {
18
18
  /** Index that translates search results to ids */
19
19
  template <typename IndexT>
20
20
  struct IndexIDMapTemplate : IndexT {
21
- using idx_t = typename IndexT::idx_t;
22
21
  using component_t = typename IndexT::component_t;
23
22
  using distance_t = typename IndexT::distance_t;
24
23
 
@@ -74,7 +73,6 @@ using IndexBinaryIDMap = IndexIDMapTemplate<IndexBinary>;
74
73
  * implementation via a 2-way index */
75
74
  template <typename IndexT>
76
75
  struct IndexIDMap2Template : IndexIDMapTemplate<IndexT> {
77
- using idx_t = typename IndexT::idx_t;
78
76
  using component_t = typename IndexT::component_t;
79
77
  using distance_t = typename IndexT::distance_t;
80
78
 
@@ -10,11 +10,13 @@
10
10
  #include <faiss/IndexIVF.h>
11
11
 
12
12
  #include <omp.h>
13
+ #include <cstdint>
13
14
  #include <mutex>
14
15
 
15
16
  #include <algorithm>
16
17
  #include <cinttypes>
17
18
  #include <cstdio>
19
+ #include <limits>
18
20
  #include <memory>
19
21
 
20
22
  #include <faiss/utils/hamming.h>
@@ -22,6 +24,7 @@
22
24
 
23
25
  #include <faiss/IndexFlat.h>
24
26
  #include <faiss/impl/AuxIndexStructures.h>
27
+ #include <faiss/impl/CodePacker.h>
25
28
  #include <faiss/impl/FaissAssert.h>
26
29
  #include <faiss/impl/IDSelector.h>
27
30
 
@@ -35,27 +38,19 @@ using ScopedCodes = InvertedLists::ScopedCodes;
35
38
  ******************************************/
36
39
 
37
40
  Level1Quantizer::Level1Quantizer(Index* quantizer, size_t nlist)
38
- : quantizer(quantizer),
39
- nlist(nlist),
40
- quantizer_trains_alone(0),
41
- own_fields(false),
42
- clustering_index(nullptr) {
41
+ : quantizer(quantizer), nlist(nlist) {
43
42
  // here we set a low # iterations because this is typically used
44
43
  // for large clusterings (nb this is not used for the MultiIndex,
45
44
  // for which quantizer_trains_alone = true)
46
45
  cp.niter = 10;
47
46
  }
48
47
 
49
- Level1Quantizer::Level1Quantizer()
50
- : quantizer(nullptr),
51
- nlist(0),
52
- quantizer_trains_alone(0),
53
- own_fields(false),
54
- clustering_index(nullptr) {}
48
+ Level1Quantizer::Level1Quantizer() {}
55
49
 
56
50
  Level1Quantizer::~Level1Quantizer() {
57
- if (own_fields)
51
+ if (own_fields) {
58
52
  delete quantizer;
53
+ }
59
54
  }
60
55
 
61
56
  void Level1Quantizer::train_q1(
@@ -131,7 +126,7 @@ size_t Level1Quantizer::coarse_code_size() const {
131
126
  return nbyte;
132
127
  }
133
128
 
134
- void Level1Quantizer::encode_listno(Index::idx_t list_no, uint8_t* code) const {
129
+ void Level1Quantizer::encode_listno(idx_t list_no, uint8_t* code) const {
135
130
  // little endian
136
131
  size_t nl = nlist - 1;
137
132
  while (nl > 0) {
@@ -141,7 +136,7 @@ void Level1Quantizer::encode_listno(Index::idx_t list_no, uint8_t* code) const {
141
136
  }
142
137
  }
143
138
 
144
- Index::idx_t Level1Quantizer::decode_listno(const uint8_t* code) const {
139
+ idx_t Level1Quantizer::decode_listno(const uint8_t* code) const {
145
140
  size_t nl = nlist - 1;
146
141
  int64_t list_no = 0;
147
142
  int nbit = 0;
@@ -165,13 +160,10 @@ IndexIVF::IndexIVF(
165
160
  size_t code_size,
166
161
  MetricType metric)
167
162
  : Index(d, metric),
168
- Level1Quantizer(quantizer, nlist),
163
+ IndexIVFInterface(quantizer, nlist),
169
164
  invlists(new ArrayInvertedLists(nlist, code_size)),
170
165
  own_invlists(true),
171
- code_size(code_size),
172
- nprobe(1),
173
- max_codes(0),
174
- parallel_mode(0) {
166
+ code_size(code_size) {
175
167
  FAISS_THROW_IF_NOT(d == quantizer->d);
176
168
  is_trained = quantizer->is_trained && (quantizer->ntotal == nlist);
177
169
  // Spherical by default if the metric is inner_product
@@ -180,13 +172,7 @@ IndexIVF::IndexIVF(
180
172
  }
181
173
  }
182
174
 
183
- IndexIVF::IndexIVF()
184
- : invlists(nullptr),
185
- own_invlists(false),
186
- code_size(0),
187
- nprobe(1),
188
- max_codes(0),
189
- parallel_mode(0) {}
175
+ IndexIVF::IndexIVF() {}
190
176
 
191
177
  void IndexIVF::add(idx_t n, const float* x) {
192
178
  add_with_ids(n, x, nullptr);
@@ -412,6 +398,7 @@ void IndexIVF::search_preassigned(
412
398
  nprobe = std::min((idx_t)nlist, nprobe);
413
399
  FAISS_THROW_IF_NOT(nprobe > 0);
414
400
 
401
+ const idx_t unlimited_list_size = std::numeric_limits<idx_t>::max();
415
402
  idx_t max_codes = params ? params->max_codes : this->max_codes;
416
403
  IDSelector* sel = params ? params->sel : nullptr;
417
404
  const IDSelectorRange* selr = dynamic_cast<const IDSelectorRange*>(sel);
@@ -427,6 +414,10 @@ void IndexIVF::search_preassigned(
427
414
  !(sel && store_pairs),
428
415
  "selector and store_pairs cannot be combined");
429
416
 
417
+ FAISS_THROW_IF_NOT_MSG(
418
+ !invlists->use_iterator || (max_codes == 0 && store_pairs == false),
419
+ "iterable inverted lists don't support max_codes and store_pairs");
420
+
430
421
  size_t nlistv = 0, ndis = 0, nheap = 0;
431
422
 
432
423
  using HeapForIP = CMin<float, idx_t>;
@@ -439,6 +430,14 @@ void IndexIVF::search_preassigned(
439
430
  int pmode = this->parallel_mode & ~PARALLEL_MODE_NO_HEAP_INIT;
440
431
  bool do_heap_init = !(this->parallel_mode & PARALLEL_MODE_NO_HEAP_INIT);
441
432
 
433
+ FAISS_THROW_IF_NOT_MSG(
434
+ max_codes == 0 || pmode == 0 || pmode == 3,
435
+ "max_codes supported only for parallel_mode = 0 or 3");
436
+
437
+ if (max_codes == 0) {
438
+ max_codes = unlimited_list_size;
439
+ }
440
+
442
441
  bool do_parallel = omp_get_max_threads() >= 2 &&
443
442
  (pmode == 0 ? false
444
443
  : pmode == 3 ? n > 1
@@ -457,7 +456,7 @@ void IndexIVF::search_preassigned(
457
456
  * that are in common between the two
458
457
  ******************************************************/
459
458
 
460
- // intialize + reorder a result heap
459
+ // initialize + reorder a result heap
461
460
 
462
461
  auto init_result = [&](float* simi, idx_t* idxi) {
463
462
  if (!do_heap_init)
@@ -495,7 +494,8 @@ void IndexIVF::search_preassigned(
495
494
  auto scan_one_list = [&](idx_t key,
496
495
  float coarse_dis_i,
497
496
  float* simi,
498
- idx_t* idxi) {
497
+ idx_t* idxi,
498
+ idx_t list_size_max) {
499
499
  if (key < 0) {
500
500
  // not enough centroids for multiprobe
501
501
  return (size_t)0;
@@ -506,10 +506,8 @@ void IndexIVF::search_preassigned(
506
506
  key,
507
507
  nlist);
508
508
 
509
- size_t list_size = invlists->list_size(key);
510
-
511
509
  // don't waste time on empty lists
512
- if (list_size == 0) {
510
+ if (invlists->is_empty(key)) {
513
511
  return (size_t)0;
514
512
  }
515
513
 
@@ -518,32 +516,51 @@ void IndexIVF::search_preassigned(
518
516
  nlistv++;
519
517
 
520
518
  try {
521
- InvertedLists::ScopedCodes scodes(invlists, key);
522
- const uint8_t* codes = scodes.get();
519
+ if (invlists->use_iterator) {
520
+ size_t list_size = 0;
523
521
 
524
- std::unique_ptr<InvertedLists::ScopedIds> sids;
525
- const Index::idx_t* ids = nullptr;
522
+ std::unique_ptr<InvertedListsIterator> it(
523
+ invlists->get_iterator(key));
526
524
 
527
- if (!store_pairs) {
528
- sids.reset(new InvertedLists::ScopedIds(invlists, key));
529
- ids = sids->get();
530
- }
525
+ nheap += scanner->iterate_codes(
526
+ it.get(), simi, idxi, k, list_size);
531
527
 
532
- if (selr) { // IDSelectorRange
533
- // restrict search to a section of the inverted list
534
- size_t jmin, jmax;
535
- selr->find_sorted_ids_bounds(list_size, ids, &jmin, &jmax);
536
- list_size = jmax - jmin;
537
- if (list_size == 0) {
538
- return (size_t)0;
528
+ return list_size;
529
+ } else {
530
+ size_t list_size = invlists->list_size(key);
531
+ if (list_size > list_size_max) {
532
+ list_size = list_size_max;
539
533
  }
540
- codes += jmin * code_size;
541
- ids += jmin;
542
- }
543
534
 
544
- nheap += scanner->scan_codes(
545
- list_size, codes, ids, simi, idxi, k);
535
+ InvertedLists::ScopedCodes scodes(invlists, key);
536
+ const uint8_t* codes = scodes.get();
537
+
538
+ std::unique_ptr<InvertedLists::ScopedIds> sids;
539
+ const idx_t* ids = nullptr;
546
540
 
541
+ if (!store_pairs) {
542
+ sids.reset(new InvertedLists::ScopedIds(invlists, key));
543
+ ids = sids->get();
544
+ }
545
+
546
+ if (selr) { // IDSelectorRange
547
+ // restrict search to a section of the inverted list
548
+ size_t jmin, jmax;
549
+ selr->find_sorted_ids_bounds(
550
+ list_size, ids, &jmin, &jmax);
551
+ list_size = jmax - jmin;
552
+ if (list_size == 0) {
553
+ return (size_t)0;
554
+ }
555
+ codes += jmin * code_size;
556
+ ids += jmin;
557
+ }
558
+
559
+ nheap += scanner->scan_codes(
560
+ list_size, codes, ids, simi, idxi, k);
561
+
562
+ return list_size;
563
+ }
547
564
  } catch (const std::exception& e) {
548
565
  std::lock_guard<std::mutex> lock(exception_mutex);
549
566
  exception_string =
@@ -551,8 +568,6 @@ void IndexIVF::search_preassigned(
551
568
  interrupt = true;
552
569
  return size_t(0);
553
570
  }
554
-
555
- return list_size;
556
571
  };
557
572
 
558
573
  /****************************************************
@@ -581,9 +596,9 @@ void IndexIVF::search_preassigned(
581
596
  keys[i * nprobe + ik],
582
597
  coarse_dis[i * nprobe + ik],
583
598
  simi,
584
- idxi);
585
-
586
- if (max_codes && nscan >= max_codes) {
599
+ idxi,
600
+ max_codes - nscan);
601
+ if (nscan >= max_codes) {
587
602
  break;
588
603
  }
589
604
  }
@@ -610,7 +625,8 @@ void IndexIVF::search_preassigned(
610
625
  keys[i * nprobe + ik],
611
626
  coarse_dis[i * nprobe + ik],
612
627
  local_dis.data(),
613
- local_idx.data());
628
+ local_idx.data(),
629
+ unlimited_list_size);
614
630
 
615
631
  // can't do the test on max_codes
616
632
  }
@@ -651,7 +667,8 @@ void IndexIVF::search_preassigned(
651
667
  keys[ij],
652
668
  coarse_dis[ij],
653
669
  local_dis.data(),
654
- local_idx.data());
670
+ local_idx.data(),
671
+ unlimited_list_size);
655
672
  #pragma omp critical
656
673
  {
657
674
  add_local_results(
@@ -744,6 +761,10 @@ void IndexIVF::range_search_preassigned(
744
761
  idx_t max_codes = params ? params->max_codes : this->max_codes;
745
762
  IDSelector* sel = params ? params->sel : nullptr;
746
763
 
764
+ FAISS_THROW_IF_NOT_MSG(
765
+ !invlists->use_iterator || (max_codes == 0 && store_pairs == false),
766
+ "iterable inverted lists don't support max_codes and store_pairs");
767
+
747
768
  size_t nlistv = 0, ndis = 0;
748
769
 
749
770
  bool interrupt = false;
@@ -780,21 +801,30 @@ void IndexIVF::range_search_preassigned(
780
801
  key,
781
802
  ik,
782
803
  nlist);
783
- const size_t list_size = invlists->list_size(key);
784
804
 
785
- if (list_size == 0)
805
+ if (invlists->is_empty(key)) {
786
806
  return;
807
+ }
787
808
 
788
809
  try {
789
- InvertedLists::ScopedCodes scodes(invlists, key);
790
- InvertedLists::ScopedIds ids(invlists, key);
791
-
810
+ size_t list_size = 0;
792
811
  scanner->set_list(key, coarse_dis[i * nprobe + ik]);
812
+ if (invlists->use_iterator) {
813
+ std::unique_ptr<InvertedListsIterator> it(
814
+ invlists->get_iterator(key));
815
+
816
+ scanner->iterate_codes_range(
817
+ it.get(), radius, qres, list_size);
818
+ } else {
819
+ InvertedLists::ScopedCodes scodes(invlists, key);
820
+ InvertedLists::ScopedIds ids(invlists, key);
821
+ list_size = invlists->list_size(key);
822
+
823
+ scanner->scan_codes_range(
824
+ list_size, scodes.get(), ids.get(), radius, qres);
825
+ }
793
826
  nlistv++;
794
827
  ndis += list_size;
795
- scanner->scan_codes_range(
796
- list_size, scodes.get(), ids.get(), radius, qres);
797
-
798
828
  } catch (const std::exception& e) {
799
829
  std::lock_guard<std::mutex> lock(exception_mutex);
800
830
  exception_string =
@@ -1086,6 +1116,10 @@ void IndexIVF::merge_from(Index& otherIndex, idx_t add_id) {
1086
1116
  other->ntotal = 0;
1087
1117
  }
1088
1118
 
1119
+ CodePacker* IndexIVF::get_CodePacker() const {
1120
+ return new CodePackerFlat(code_size);
1121
+ }
1122
+
1089
1123
  void IndexIVF::replace_invlists(InvertedLists* il, bool own) {
1090
1124
  if (own_invlists) {
1091
1125
  delete invlists;
@@ -1104,71 +1138,11 @@ void IndexIVF::replace_invlists(InvertedLists* il, bool own) {
1104
1138
 
1105
1139
  void IndexIVF::copy_subset_to(
1106
1140
  IndexIVF& other,
1107
- int subset_type,
1141
+ InvertedLists::subset_type_t subset_type,
1108
1142
  idx_t a1,
1109
1143
  idx_t a2) const {
1110
- FAISS_THROW_IF_NOT(nlist == other.nlist);
1111
- FAISS_THROW_IF_NOT(code_size == other.code_size);
1112
- FAISS_THROW_IF_NOT(other.direct_map.no());
1113
- FAISS_THROW_IF_NOT_FMT(
1114
- subset_type == 0 || subset_type == 1 || subset_type == 2,
1115
- "subset type %d not implemented",
1116
- subset_type);
1117
-
1118
- size_t accu_n = 0;
1119
- size_t accu_a1 = 0;
1120
- size_t accu_a2 = 0;
1121
-
1122
- InvertedLists* oivf = other.invlists;
1123
-
1124
- for (idx_t list_no = 0; list_no < nlist; list_no++) {
1125
- size_t n = invlists->list_size(list_no);
1126
- ScopedIds ids_in(invlists, list_no);
1127
-
1128
- if (subset_type == 0) {
1129
- for (idx_t i = 0; i < n; i++) {
1130
- idx_t id = ids_in[i];
1131
- if (a1 <= id && id < a2) {
1132
- oivf->add_entry(
1133
- list_no,
1134
- invlists->get_single_id(list_no, i),
1135
- ScopedCodes(invlists, list_no, i).get());
1136
- other.ntotal++;
1137
- }
1138
- }
1139
- } else if (subset_type == 1) {
1140
- for (idx_t i = 0; i < n; i++) {
1141
- idx_t id = ids_in[i];
1142
- if (id % a1 == a2) {
1143
- oivf->add_entry(
1144
- list_no,
1145
- invlists->get_single_id(list_no, i),
1146
- ScopedCodes(invlists, list_no, i).get());
1147
- other.ntotal++;
1148
- }
1149
- }
1150
- } else if (subset_type == 2) {
1151
- // see what is allocated to a1 and to a2
1152
- size_t next_accu_n = accu_n + n;
1153
- size_t next_accu_a1 = next_accu_n * a1 / ntotal;
1154
- size_t i1 = next_accu_a1 - accu_a1;
1155
- size_t next_accu_a2 = next_accu_n * a2 / ntotal;
1156
- size_t i2 = next_accu_a2 - accu_a2;
1157
-
1158
- for (idx_t i = i1; i < i2; i++) {
1159
- oivf->add_entry(
1160
- list_no,
1161
- invlists->get_single_id(list_no, i),
1162
- ScopedCodes(invlists, list_no, i).get());
1163
- }
1164
-
1165
- other.ntotal += i2 - i1;
1166
- accu_a1 = next_accu_a1;
1167
- accu_a2 = next_accu_a2;
1168
- }
1169
- accu_n += n;
1170
- }
1171
- FAISS_ASSERT(accu_n == ntotal);
1144
+ other.ntotal +=
1145
+ invlists->copy_subset_to(*other.invlists, subset_type, a1, a2);
1172
1146
  }
1173
1147
 
1174
1148
  IndexIVF::~IndexIVF() {
@@ -1233,6 +1207,39 @@ size_t InvertedListScanner::scan_codes(
1233
1207
  return nup;
1234
1208
  }
1235
1209
 
1210
+ size_t InvertedListScanner::iterate_codes(
1211
+ InvertedListsIterator* it,
1212
+ float* simi,
1213
+ idx_t* idxi,
1214
+ size_t k,
1215
+ size_t& list_size) const {
1216
+ size_t nup = 0;
1217
+ list_size = 0;
1218
+
1219
+ if (!keep_max) {
1220
+ for (; it->is_available(); it->next()) {
1221
+ auto id_and_codes = it->get_id_and_codes();
1222
+ float dis = distance_to_code(id_and_codes.second);
1223
+ if (dis < simi[0]) {
1224
+ maxheap_replace_top(k, simi, idxi, dis, id_and_codes.first);
1225
+ nup++;
1226
+ }
1227
+ list_size++;
1228
+ }
1229
+ } else {
1230
+ for (; it->is_available(); it->next()) {
1231
+ auto id_and_codes = it->get_id_and_codes();
1232
+ float dis = distance_to_code(id_and_codes.second);
1233
+ if (dis > simi[0]) {
1234
+ minheap_replace_top(k, simi, idxi, dis, id_and_codes.first);
1235
+ nup++;
1236
+ }
1237
+ list_size++;
1238
+ }
1239
+ }
1240
+ return nup;
1241
+ }
1242
+
1236
1243
  void InvertedListScanner::scan_codes_range(
1237
1244
  size_t list_size,
1238
1245
  const uint8_t* codes,
@@ -1252,4 +1259,23 @@ void InvertedListScanner::scan_codes_range(
1252
1259
  }
1253
1260
  }
1254
1261
 
1262
+ void InvertedListScanner::iterate_codes_range(
1263
+ InvertedListsIterator* it,
1264
+ float radius,
1265
+ RangeQueryResult& res,
1266
+ size_t& list_size) const {
1267
+ list_size = 0;
1268
+ for (; it->is_available(); it->next()) {
1269
+ auto id_and_codes = it->get_id_and_codes();
1270
+ float dis = distance_to_code(id_and_codes.second);
1271
+ bool keep = !keep_max
1272
+ ? dis < radius
1273
+ : dis > radius; // TODO templatize to remove this test
1274
+ if (keep) {
1275
+ res.add(dis, id_and_codes.first);
1276
+ }
1277
+ list_size++;
1278
+ }
1279
+ }
1280
+
1255
1281
  } // namespace faiss