faiss 0.5.2 → 0.6.0

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +1 -1
  4. data/ext/faiss/ext.cpp +1 -1
  5. data/ext/faiss/extconf.rb +5 -6
  6. data/ext/faiss/index_binary.cpp +76 -17
  7. data/ext/faiss/{index.cpp → index_rb.cpp} +108 -35
  8. data/ext/faiss/kmeans.cpp +12 -9
  9. data/ext/faiss/numo.hpp +11 -9
  10. data/ext/faiss/pca_matrix.cpp +10 -8
  11. data/ext/faiss/product_quantizer.cpp +14 -12
  12. data/ext/faiss/{utils.cpp → utils_rb.cpp} +10 -3
  13. data/ext/faiss/{utils.h → utils_rb.h} +6 -0
  14. data/lib/faiss/version.rb +1 -1
  15. data/lib/faiss.rb +1 -1
  16. data/vendor/faiss/faiss/AutoTune.cpp +130 -11
  17. data/vendor/faiss/faiss/AutoTune.h +14 -1
  18. data/vendor/faiss/faiss/Clustering.cpp +59 -10
  19. data/vendor/faiss/faiss/Clustering.h +12 -0
  20. data/vendor/faiss/faiss/IVFlib.cpp +31 -28
  21. data/vendor/faiss/faiss/Index.cpp +20 -8
  22. data/vendor/faiss/faiss/Index.h +25 -3
  23. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +19 -24
  24. data/vendor/faiss/faiss/IndexBinary.cpp +1 -0
  25. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +9 -4
  26. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +45 -11
  27. data/vendor/faiss/faiss/IndexFastScan.cpp +35 -22
  28. data/vendor/faiss/faiss/IndexFastScan.h +10 -1
  29. data/vendor/faiss/faiss/IndexFlat.cpp +193 -136
  30. data/vendor/faiss/faiss/IndexFlat.h +16 -1
  31. data/vendor/faiss/faiss/IndexFlatCodes.cpp +46 -22
  32. data/vendor/faiss/faiss/IndexFlatCodes.h +7 -1
  33. data/vendor/faiss/faiss/IndexHNSW.cpp +24 -50
  34. data/vendor/faiss/faiss/IndexHNSW.h +14 -12
  35. data/vendor/faiss/faiss/IndexIDMap.cpp +1 -1
  36. data/vendor/faiss/faiss/IndexIVF.cpp +76 -49
  37. data/vendor/faiss/faiss/IndexIVF.h +14 -4
  38. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +11 -8
  39. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +2 -2
  40. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +25 -14
  41. data/vendor/faiss/faiss/IndexIVFFastScan.h +26 -22
  42. data/vendor/faiss/faiss/IndexIVFFlat.cpp +10 -61
  43. data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +39 -111
  44. data/vendor/faiss/faiss/IndexIVFPQ.cpp +89 -147
  45. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +37 -5
  46. data/vendor/faiss/faiss/IndexIVFPQR.cpp +2 -1
  47. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +42 -30
  48. data/vendor/faiss/faiss/IndexIVFRaBitQ.h +2 -2
  49. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +246 -97
  50. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +32 -29
  51. data/vendor/faiss/faiss/IndexLSH.cpp +8 -6
  52. data/vendor/faiss/faiss/IndexLattice.cpp +29 -24
  53. data/vendor/faiss/faiss/IndexNNDescent.cpp +1 -0
  54. data/vendor/faiss/faiss/IndexNSG.cpp +2 -1
  55. data/vendor/faiss/faiss/IndexNSG.h +0 -2
  56. data/vendor/faiss/faiss/IndexNeuralNetCodec.cpp +1 -1
  57. data/vendor/faiss/faiss/IndexPQ.cpp +19 -10
  58. data/vendor/faiss/faiss/IndexRaBitQ.cpp +26 -13
  59. data/vendor/faiss/faiss/IndexRaBitQ.h +2 -2
  60. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +132 -78
  61. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +14 -12
  62. data/vendor/faiss/faiss/IndexRefine.cpp +0 -30
  63. data/vendor/faiss/faiss/IndexShards.cpp +3 -4
  64. data/vendor/faiss/faiss/MetricType.h +16 -0
  65. data/vendor/faiss/faiss/VectorTransform.cpp +120 -0
  66. data/vendor/faiss/faiss/VectorTransform.h +23 -0
  67. data/vendor/faiss/faiss/clone_index.cpp +7 -4
  68. data/vendor/faiss/faiss/{cppcontrib/factory_tools.cpp → factory_tools.cpp} +1 -1
  69. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +1 -1
  70. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +37 -11
  71. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -28
  72. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +367 -0
  73. data/vendor/faiss/faiss/impl/ClusteringInitialization.h +107 -0
  74. data/vendor/faiss/faiss/impl/CodePacker.cpp +4 -0
  75. data/vendor/faiss/faiss/impl/CodePacker.h +11 -3
  76. data/vendor/faiss/faiss/impl/CodePackerRaBitQ.cpp +83 -0
  77. data/vendor/faiss/faiss/impl/CodePackerRaBitQ.h +47 -0
  78. data/vendor/faiss/faiss/impl/FaissAssert.h +60 -2
  79. data/vendor/faiss/faiss/impl/HNSW.cpp +25 -34
  80. data/vendor/faiss/faiss/impl/HNSW.h +8 -6
  81. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +34 -27
  82. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -1
  83. data/vendor/faiss/faiss/impl/NSG.cpp +6 -5
  84. data/vendor/faiss/faiss/impl/NSG.h +17 -7
  85. data/vendor/faiss/faiss/impl/Panorama.cpp +53 -46
  86. data/vendor/faiss/faiss/impl/Panorama.h +22 -6
  87. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +16 -5
  88. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +70 -58
  89. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +92 -0
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.h +93 -31
  91. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +12 -28
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +3 -10
  93. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +15 -41
  94. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.h +0 -4
  95. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +14 -9
  96. data/vendor/faiss/faiss/impl/ResultHandler.h +131 -50
  97. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +67 -2358
  98. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +0 -2
  99. data/vendor/faiss/faiss/impl/VisitedTable.cpp +42 -0
  100. data/vendor/faiss/faiss/impl/VisitedTable.h +69 -0
  101. data/vendor/faiss/faiss/impl/expanded_scanners.h +158 -0
  102. data/vendor/faiss/faiss/impl/index_read.cpp +829 -471
  103. data/vendor/faiss/faiss/impl/index_read_utils.h +0 -1
  104. data/vendor/faiss/faiss/impl/index_write.cpp +17 -8
  105. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +47 -20
  106. data/vendor/faiss/faiss/impl/mapped_io.cpp +9 -2
  107. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +7 -2
  108. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +11 -3
  109. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +19 -13
  110. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +29 -21
  111. data/vendor/faiss/faiss/impl/{code_distance/code_distance-avx2.h → pq_code_distance/pq_code_distance-avx2.cpp} +42 -215
  112. data/vendor/faiss/faiss/impl/{code_distance/code_distance-avx512.h → pq_code_distance/pq_code_distance-avx512.cpp} +68 -107
  113. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +141 -0
  114. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +23 -0
  115. data/vendor/faiss/faiss/impl/{code_distance/code_distance-sve.h → pq_code_distance/pq_code_distance-sve.cpp} +57 -144
  116. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +9 -6
  117. data/vendor/faiss/faiss/impl/scalar_quantizer/codecs.h +121 -0
  118. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +136 -0
  119. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +280 -0
  120. data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +164 -0
  121. data/vendor/faiss/faiss/impl/scalar_quantizer/similarities.h +94 -0
  122. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +455 -0
  123. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +430 -0
  124. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +329 -0
  125. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +467 -0
  126. data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +203 -0
  127. data/vendor/faiss/faiss/impl/scalar_quantizer/training.h +42 -0
  128. data/vendor/faiss/faiss/impl/simd_dispatch.h +139 -0
  129. data/vendor/faiss/faiss/impl/simd_result_handlers.h +18 -18
  130. data/vendor/faiss/faiss/index_factory.cpp +35 -16
  131. data/vendor/faiss/faiss/index_io.h +29 -3
  132. data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +7 -4
  133. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +1 -1
  134. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +9 -19
  135. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +2 -0
  136. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +2 -1
  137. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +9 -1
  138. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +9 -0
  139. data/vendor/faiss/faiss/utils/Heap.cpp +46 -0
  140. data/vendor/faiss/faiss/utils/Heap.h +21 -0
  141. data/vendor/faiss/faiss/utils/NeuralNet.cpp +10 -7
  142. data/vendor/faiss/faiss/utils/distances.cpp +141 -23
  143. data/vendor/faiss/faiss/utils/distances.h +98 -0
  144. data/vendor/faiss/faiss/utils/distances_dispatch.h +170 -0
  145. data/vendor/faiss/faiss/utils/distances_simd.cpp +74 -3511
  146. data/vendor/faiss/faiss/utils/extra_distances-inl.h +164 -157
  147. data/vendor/faiss/faiss/utils/extra_distances.cpp +52 -95
  148. data/vendor/faiss/faiss/utils/extra_distances.h +47 -1
  149. data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +0 -1
  150. data/vendor/faiss/faiss/utils/partitioning.cpp +1 -1
  151. data/vendor/faiss/faiss/utils/pq_code_distance.h +251 -0
  152. data/vendor/faiss/faiss/utils/rabitq_simd.h +260 -0
  153. data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +150 -0
  154. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +568 -0
  155. data/vendor/faiss/faiss/utils/simd_impl/distances_autovec-inl.h +153 -0
  156. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +1185 -0
  157. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +1092 -0
  158. data/vendor/faiss/faiss/utils/simd_impl/distances_sse-inl.h +391 -0
  159. data/vendor/faiss/faiss/utils/simd_levels.cpp +322 -0
  160. data/vendor/faiss/faiss/utils/simd_levels.h +91 -0
  161. data/vendor/faiss/faiss/utils/simdlib_avx2.h +12 -1
  162. data/vendor/faiss/faiss/utils/simdlib_avx512.h +69 -0
  163. data/vendor/faiss/faiss/utils/simdlib_neon.h +6 -0
  164. data/vendor/faiss/faiss/utils/sorting.cpp +4 -4
  165. data/vendor/faiss/faiss/utils/utils.cpp +16 -9
  166. metadata +47 -18
  167. data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +0 -81
  168. data/vendor/faiss/faiss/impl/code_distance/code_distance.h +0 -186
  169. /data/vendor/faiss/faiss/{cppcontrib/factory_tools.h → factory_tools.h} +0 -0
@@ -12,6 +12,7 @@
12
12
 
13
13
  #include <faiss/impl/FaissException.h>
14
14
  #include <faiss/impl/platform_macros.h>
15
+ #include <cinttypes>
15
16
  #include <cstdio>
16
17
  #include <cstdlib>
17
18
  #include <string>
@@ -69,7 +70,7 @@
69
70
 
70
71
  #define FAISS_THROW_MSG(MSG) \
71
72
  do { \
72
- throw faiss::FaissException( \
73
+ throw ::faiss::FaissException( \
73
74
  MSG, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
74
75
  } while (false)
75
76
 
@@ -79,7 +80,7 @@
79
80
  int __size = snprintf(nullptr, 0, FMT, __VA_ARGS__); \
80
81
  __s.resize(__size + 1); \
81
82
  snprintf(&__s[0], __s.size(), FMT, __VA_ARGS__); \
82
- throw faiss::FaissException( \
83
+ throw ::faiss::FaissException( \
83
84
  __s, __PRETTY_FUNCTION__, __FILE__, __LINE__); \
84
85
  } while (false)
85
86
 
@@ -110,4 +111,61 @@
110
111
  } \
111
112
  } while (false)
112
113
 
114
+ ///
115
+ /// Safe arithmetic
116
+ ///
117
+
118
+ #include <limits>
119
+
120
+ namespace faiss {
121
+
122
+ /// Multiplication that throws on overflow instead of wrapping
123
+ inline size_t mul_no_overflow(size_t a, size_t b, const char* context) {
124
+ if (a != 0 && b > (std::numeric_limits<size_t>::max)() / a) {
125
+ FAISS_THROW_FMT("integer overflow in %s: %zu * %zu", context, a, b);
126
+ }
127
+ return a * b;
128
+ }
129
+
130
+ /// Addition that throws on overflow instead of wrapping
131
+ inline size_t add_no_overflow(size_t a, size_t b, const char* context) {
132
+ if (a > (std::numeric_limits<size_t>::max)() - b) {
133
+ FAISS_THROW_FMT("integer overflow in %s: %zu + %zu", context, a, b);
134
+ }
135
+ return a + b;
136
+ }
137
+
138
+ } // namespace faiss
139
+
140
+ ///
141
+ /// Bounds checking
142
+ ///
143
+
144
+ /// Check that val is in half-open range [lo, hi). Throws with the
145
+ /// stringified expression, its value, and the bounds on failure.
146
+ #define FAISS_CHECK_RANGE(val, lo, hi) \
147
+ FAISS_THROW_IF_NOT_FMT( \
148
+ (int64_t)(val) >= (int64_t)(lo) && (int64_t)(val) < (int64_t)(hi), \
149
+ "%s (= %" PRId64 ") out of range [%" PRId64 ", %" PRId64 ")", \
150
+ #val, \
151
+ (int64_t)(val), \
152
+ (int64_t)(lo), \
153
+ (int64_t)(hi))
154
+
155
+ /// Debug-only variant of FAISS_CHECK_RANGE. Aborts in debug builds
156
+ /// (when NDEBUG is not defined); compiled out in release builds to
157
+ /// avoid overhead in hot paths.
158
+ #ifndef NDEBUG
159
+ #define FAISS_CHECK_RANGE_DEBUG(val, lo, hi) \
160
+ FAISS_ASSERT_FMT( \
161
+ (int64_t)(val) >= (int64_t)(lo) && (int64_t)(val) < (int64_t)(hi), \
162
+ "%s (= %" PRId64 ") out of range [%" PRId64 ", %" PRId64 ")", \
163
+ #val, \
164
+ (int64_t)(val), \
165
+ (int64_t)(lo), \
166
+ (int64_t)(hi))
167
+ #else
168
+ #define FAISS_CHECK_RANGE_DEBUG(val, lo, hi) ((void)0)
169
+ #endif
170
+
113
171
  #endif
@@ -7,15 +7,15 @@
7
7
 
8
8
  #include <faiss/impl/HNSW.h>
9
9
 
10
+ #include <cinttypes>
10
11
  #include <cstddef>
11
12
 
12
13
  #include <faiss/IndexHNSW.h>
13
14
 
14
- #include <faiss/impl/AuxIndexStructures.h>
15
15
  #include <faiss/impl/DistanceComputer.h>
16
16
  #include <faiss/impl/IDSelector.h>
17
17
  #include <faiss/impl/ResultHandler.h>
18
- #include <faiss/utils/prefetch.h>
18
+ #include <faiss/impl/VisitedTable.h>
19
19
 
20
20
  #ifdef __AVX2__
21
21
  #include <immintrin.h>
@@ -45,11 +45,15 @@ void HNSW::set_nb_neighbors(int level_no, int n) {
45
45
  }
46
46
 
47
47
  int HNSW::cum_nb_neighbors(int layer_no) const {
48
+ FAISS_CHECK_RANGE_DEBUG(layer_no, 0, (int)cum_nneighbor_per_level.size());
48
49
  return cum_nneighbor_per_level[layer_no];
49
50
  }
50
51
 
51
52
  void HNSW::neighbor_range(idx_t no, int layer_no, size_t* begin, size_t* end)
52
53
  const {
54
+ FAISS_CHECK_RANGE_DEBUG(no, 0, (idx_t)offsets.size());
55
+ FAISS_CHECK_RANGE_DEBUG(
56
+ layer_no, 0, (int)cum_nneighbor_per_level.size() - 1);
53
57
  size_t o = offsets[no];
54
58
  *begin = o + cum_nb_neighbors(layer_no);
55
59
  *end = o + cum_nb_neighbors(layer_no + 1);
@@ -407,10 +411,9 @@ void search_neighbors_to_add(
407
411
  if (nodeId < 0) {
408
412
  break;
409
413
  }
410
- if (vt.get(nodeId)) {
414
+ if (!vt.set(nodeId)) {
411
415
  continue;
412
416
  }
413
- vt.set(nodeId);
414
417
 
415
418
  float dis = qdis(nodeId);
416
419
  NodeDistFarther evE1(dis, nodeId);
@@ -448,10 +451,9 @@ void search_neighbors_to_add(
448
451
  if (nodeId < 0) {
449
452
  break;
450
453
  }
451
- if (vt.get(nodeId)) {
454
+ if (!vt.set(nodeId)) {
452
455
  continue;
453
456
  }
454
- vt.set(nodeId);
455
457
 
456
458
  buffered_ids[n_buffered] = nodeId;
457
459
  n_buffered += 1;
@@ -616,7 +618,7 @@ static inline void extract_search_params(
616
618
  int search_from_candidates(
617
619
  const HNSW& hnsw,
618
620
  DistanceComputer& qdis,
619
- ResultHandler<C>& res,
621
+ ResultHandler& res,
620
622
  MinimaxHeap& candidates,
621
623
  VisitedTable& vt,
622
624
  HNSWStats& stats,
@@ -675,7 +677,7 @@ int search_from_candidates(
675
677
  break;
676
678
  }
677
679
 
678
- prefetch_L2(vt.visited.data() + v1);
680
+ vt.prefetch(v1);
679
681
  jmax += 1;
680
682
  }
681
683
 
@@ -699,10 +701,8 @@ int search_from_candidates(
699
701
  for (size_t j = begin; j < jmax; j++) {
700
702
  int v1 = hnsw.neighbors[j];
701
703
 
702
- bool vget = vt.get(v1);
703
- vt.set(v1);
704
704
  saved_j[counter] = v1;
705
- counter += vget ? 0 : 1;
705
+ counter += vt.set(v1) ? 1 : 0;
706
706
 
707
707
  if (counter == 4) {
708
708
  float dis[4];
@@ -755,7 +755,7 @@ int search_from_candidates_panorama(
755
755
  const HNSW& hnsw,
756
756
  const IndexHNSW* index,
757
757
  DistanceComputer& qdis,
758
- ResultHandler<C>& res,
758
+ ResultHandler& res,
759
759
  MinimaxHeap& candidates,
760
760
  VisitedTable& vt,
761
761
  HNSWStats& stats,
@@ -802,13 +802,8 @@ int search_from_candidates_panorama(
802
802
  std::vector<float> exact_distances(M);
803
803
 
804
804
  const float* query = flat_codes_qdis->q;
805
- std::vector<float> query_cum_sums(panorama_index->num_panorama_levels + 1);
806
- IndexHNSWFlatPanorama::compute_cum_sums(
807
- query,
808
- query_cum_sums.data(),
809
- panorama_index->d,
810
- panorama_index->num_panorama_levels,
811
- panorama_index->panorama_level_width);
805
+ std::vector<float> query_cum_sums(panorama_index->pano.n_levels + 1);
806
+ panorama_index->pano.compute_query_cum_sums(query, query_cum_sums.data());
812
807
  float query_norm_sq = query_cum_sums[0] * query_cum_sums[0];
813
808
 
814
809
  int nstep = 0;
@@ -847,21 +842,19 @@ int search_from_candidates_panorama(
847
842
  query_norm_sq + cum_sums_v1[0] * cum_sums_v1[0];
848
843
 
849
844
  bool is_selected = !sel || sel->is_member(v1);
850
- initial_size += is_selected && !vt.get(v1) ? 1 : 0;
851
-
852
- vt.set(v1);
845
+ initial_size += is_selected && vt.set(v1) ? 1 : 0;
853
846
  }
854
847
 
855
848
  size_t batch_size = initial_size;
856
849
  size_t curr_panorama_level = 0;
857
- const size_t num_panorama_levels = panorama_index->num_panorama_levels;
850
+ const size_t num_panorama_levels = panorama_index->pano.n_levels;
858
851
  while (curr_panorama_level < num_panorama_levels && batch_size > 0) {
859
852
  float query_cum_norm = query_cum_sums[curr_panorama_level + 1];
860
853
 
861
- const size_t panorama_level_width =
862
- panorama_index->panorama_level_width;
863
- size_t start_dim = curr_panorama_level * panorama_level_width;
864
- size_t end_dim = (curr_panorama_level + 1) * panorama_level_width;
854
+ size_t start_dim = curr_panorama_level *
855
+ panorama_index->pano.level_width_floats;
856
+ size_t end_dim = (curr_panorama_level + 1) *
857
+ panorama_index->pano.level_width_floats;
865
858
  end_dim = std::min(end_dim, static_cast<size_t>(panorama_index->d));
866
859
 
867
860
  size_t i = 0;
@@ -1037,7 +1030,7 @@ std::priority_queue<HNSW::Node> search_from_candidate_unbounded(
1037
1030
  break;
1038
1031
  }
1039
1032
 
1040
- prefetch_L2(vt->visited.data() + v1);
1033
+ vt->prefetch(v1);
1041
1034
  jmax += 1;
1042
1035
  }
1043
1036
 
@@ -1059,10 +1052,8 @@ std::priority_queue<HNSW::Node> search_from_candidate_unbounded(
1059
1052
  for (size_t j = begin; j < jmax; j++) {
1060
1053
  int v1 = hnsw.neighbors[j];
1061
1054
 
1062
- bool vget = vt->get(v1);
1063
- vt->set(v1);
1064
1055
  saved_j[counter] = v1;
1065
- counter += vget ? 0 : 1;
1056
+ counter += vt->set(v1) ? 1 : 0;
1066
1057
 
1067
1058
  if (counter == 4) {
1068
1059
  float dis[4];
@@ -1187,7 +1178,7 @@ using Node = HNSW::Node;
1187
1178
  using C = HNSW::C;
1188
1179
 
1189
1180
  // just used as a lower bound for the minmaxheap, but it is set for heap search
1190
- int extract_k_from_ResultHandler(ResultHandler<C>& res) {
1181
+ int extract_k_from_ResultHandler(ResultHandler& res) {
1191
1182
  using RH = HeapBlockResultHandler<C>;
1192
1183
  if (auto hres = dynamic_cast<RH::SingleResultHandler*>(&res)) {
1193
1184
  return hres->k;
@@ -1200,7 +1191,7 @@ int extract_k_from_ResultHandler(ResultHandler<C>& res) {
1200
1191
  HNSWStats HNSW::search(
1201
1192
  DistanceComputer& qdis,
1202
1193
  const IndexHNSW* index,
1203
- ResultHandler<C>& res,
1194
+ ResultHandler& res,
1204
1195
  VisitedTable& vt,
1205
1196
  const SearchParameters* params) const {
1206
1197
  HNSWStats stats;
@@ -1277,7 +1268,7 @@ HNSWStats HNSW::search(
1277
1268
 
1278
1269
  void HNSW::search_level_0(
1279
1270
  DistanceComputer& qdis,
1280
- ResultHandler<C>& res,
1271
+ ResultHandler& res,
1281
1272
  idx_t nprobe,
1282
1273
  const storage_idx_t* nearest_i,
1283
1274
  const float* nearest_d,
@@ -7,6 +7,7 @@
7
7
 
8
8
  #pragma once
9
9
 
10
+ #include <optional>
10
11
  #include <queue>
11
12
  #include <vector>
12
13
 
@@ -45,8 +46,6 @@ struct IndexHNSWFlatPanorama;
45
46
  struct VisitedTable;
46
47
  struct DistanceComputer; // from AuxIndexStructures
47
48
  struct HNSWStats;
48
- template <class C>
49
- struct ResultHandler;
50
49
 
51
50
  struct SearchParametersHNSW : SearchParameters {
52
51
  int efSearch = 16;
@@ -153,6 +152,9 @@ struct HNSW {
153
152
  /// use Panorama progressive pruning in search
154
153
  bool is_panorama = false;
155
154
 
155
+ // See impl/VisitedTable.h.
156
+ std::optional<bool> use_visited_hashset;
157
+
156
158
  // methods that initialize the tree sizes
157
159
 
158
160
  /// initialize the assign_probas and cum_nneighbor_per_level to
@@ -212,14 +214,14 @@ struct HNSW {
212
214
  HNSWStats search(
213
215
  DistanceComputer& qdis,
214
216
  const IndexHNSW* index,
215
- ResultHandler<C>& res,
217
+ ResultHandler& res,
216
218
  VisitedTable& vt,
217
219
  const SearchParameters* params = nullptr) const;
218
220
 
219
221
  /// search only in level 0 from a given vertex
220
222
  void search_level_0(
221
223
  DistanceComputer& qdis,
222
- ResultHandler<C>& res,
224
+ ResultHandler& res,
223
225
  idx_t nprobe,
224
226
  const storage_idx_t* nearest_i,
225
227
  const float* nearest_d,
@@ -272,7 +274,7 @@ FAISS_API extern HNSWStats hnsw_stats;
272
274
  int search_from_candidates(
273
275
  const HNSW& hnsw,
274
276
  DistanceComputer& qdis,
275
- ResultHandler<HNSW::C>& res,
277
+ ResultHandler& res,
276
278
  HNSW::MinimaxHeap& candidates,
277
279
  VisitedTable& vt,
278
280
  HNSWStats& stats,
@@ -288,7 +290,7 @@ int search_from_candidates_panorama(
288
290
  const HNSW& hnsw,
289
291
  const IndexHNSW* index,
290
292
  DistanceComputer& qdis,
291
- ResultHandler<HNSW::C>& res,
293
+ ResultHandler& res,
292
294
  HNSW::MinimaxHeap& candidates,
293
295
  VisitedTable& vt,
294
296
  HNSWStats& stats,
@@ -18,6 +18,7 @@
18
18
 
19
19
  #include <faiss/impl/AuxIndexStructures.h>
20
20
  #include <faiss/impl/FaissAssert.h>
21
+ #include <faiss/impl/simd_dispatch.h>
21
22
  #include <faiss/utils/distances.h>
22
23
  #include <faiss/utils/utils.h>
23
24
 
@@ -684,22 +685,24 @@ void LocalSearchQuantizer::perturb_codes(
684
685
  void LocalSearchQuantizer::compute_binary_terms(float* binaries) const {
685
686
  LSQTimerScope scope(&lsq_timer, "compute_binary_terms");
686
687
 
688
+ with_simd_level([&]<SIMDLevel SL>() {
687
689
  #pragma omp parallel for
688
- for (int64_t m12 = 0; m12 < M * M; m12++) {
689
- size_t m1 = m12 / M;
690
- size_t m2 = m12 % M;
691
-
692
- for (size_t code1 = 0; code1 < K; code1++) {
693
- for (size_t code2 = 0; code2 < K; code2++) {
694
- const float* c1 = codebooks.data() + m1 * K * d + code1 * d;
695
- const float* c2 = codebooks.data() + m2 * K * d + code2 * d;
696
- float ip = fvec_inner_product(c1, c2, d);
697
- // binaries[m1, m2, code1, code2] = ip * 2
698
- binaries[m1 * M * K * K + m2 * K * K + code1 * K + code2] =
699
- ip * 2;
690
+ for (int64_t m12 = 0; m12 < M * M; m12++) {
691
+ size_t m1 = m12 / M;
692
+ size_t m2 = m12 % M;
693
+
694
+ for (size_t code1 = 0; code1 < K; code1++) {
695
+ for (size_t code2 = 0; code2 < K; code2++) {
696
+ const float* c1 = codebooks.data() + m1 * K * d + code1 * d;
697
+ const float* c2 = codebooks.data() + m2 * K * d + code2 * d;
698
+ float ip = fvec_inner_product<SL>(c1, c2, d);
699
+ // binaries[m1, m2, code1, code2] = ip * 2
700
+ binaries[m1 * M * K * K + m2 * K * K + code1 * K + code2] =
701
+ ip * 2;
702
+ }
700
703
  }
701
704
  }
702
- }
705
+ });
703
706
  }
704
707
 
705
708
  void LocalSearchQuantizer::compute_unary_terms(
@@ -760,23 +763,27 @@ float LocalSearchQuantizer::evaluate(
760
763
  std::vector<float> decoded_x(n * d, 0.0f);
761
764
  float obj = 0.0f;
762
765
 
763
- #pragma omp parallel for reduction(+ : obj)
764
- for (int64_t i = 0; i < n; i++) {
765
- const auto code = codes + i * M;
766
- const auto decoded_i = decoded_x.data() + i * d;
767
- for (size_t m = 0; m < M; m++) {
768
- // c = codebooks[m, code[m]]
769
- const auto c = codebooks.data() + m * K * d + code[m] * d;
770
- fvec_add(d, decoded_i, c, decoded_i);
771
- }
766
+ with_simd_level([&]<SIMDLevel SL>() {
767
+ float local_obj = 0.0f;
768
+ #pragma omp parallel for reduction(+ : local_obj)
769
+ for (int64_t i = 0; i < n; i++) {
770
+ const auto code = codes + i * M;
771
+ const auto decoded_i = decoded_x.data() + i * d;
772
+ for (size_t m = 0; m < M; m++) {
773
+ // c = codebooks[m, code[m]]
774
+ const auto c = codebooks.data() + m * K * d + code[m] * d;
775
+ fvec_add(d, decoded_i, c, decoded_i);
776
+ }
772
777
 
773
- float err = faiss::fvec_L2sqr(x + i * d, decoded_i, d);
774
- obj += err;
778
+ float err = fvec_L2sqr<SL>(x + i * d, decoded_i, d);
779
+ local_obj += err;
775
780
 
776
- if (objs) {
777
- objs[i] = err;
781
+ if (objs) {
782
+ objs[i] = err;
783
+ }
778
784
  }
779
- }
785
+ obj = local_obj;
786
+ });
780
787
 
781
788
  obj = obj / n;
782
789
  return obj;
@@ -10,10 +10,10 @@
10
10
  #include <faiss/impl/NNDescent.h>
11
11
 
12
12
  #include <mutex>
13
- #include <string>
14
13
 
15
14
  #include <faiss/impl/AuxIndexStructures.h>
16
15
  #include <faiss/impl/DistanceComputer.h>
16
+ #include <faiss/impl/VisitedTable.h>
17
17
 
18
18
  namespace faiss {
19
19
 
@@ -13,6 +13,7 @@
13
13
  #include <stack>
14
14
 
15
15
  #include <faiss/impl/DistanceComputer.h>
16
+ #include <faiss/impl/VisitedTable.h>
16
17
 
17
18
  namespace faiss {
18
19
 
@@ -233,7 +234,7 @@ void NSG::init_graph(Index* storage, const nsg::Graph<idx_t>& knn_graph) {
233
234
  std::unique_ptr<DistanceComputer> dis(storage_distance_computer(storage));
234
235
 
235
236
  dis->set_query(center.get());
236
- VisitedTable vt(ntotal);
237
+ VisitedTable vt(ntotal, use_visited_hashset);
237
238
 
238
239
  // Do not collect the visited nodes
239
240
  search_on_graph<false>(knn_graph, *dis, vt, ep, L, retset, tmpset);
@@ -304,7 +305,7 @@ void NSG::search_on_graph(
304
305
  size_t nneigh_for_n = graph.get_neighbors(n, neighbors.data());
305
306
  for (int m = 0; m < nneigh_for_n; m++) {
306
307
  int id = neighbors[m];
307
- if (id > ntotal || vt.get(id)) {
308
+ if (id >= ntotal || vt.get(id)) {
308
309
  continue;
309
310
  }
310
311
  vt.set(id);
@@ -341,7 +342,7 @@ void NSG::link(
341
342
  std::vector<Node> pool;
342
343
  std::vector<Neighbor> tmp;
343
344
 
344
- VisitedTable vt(ntotal);
345
+ VisitedTable vt(ntotal, use_visited_hashset);
345
346
  std::unique_ptr<DistanceComputer> dis(
346
347
  storage_distance_computer(storage));
347
348
 
@@ -513,8 +514,8 @@ void NSG::add_reverse_links(
513
514
 
514
515
  int NSG::tree_grow(Index* storage, std::vector<int>& degrees) {
515
516
  int root = enterpoint;
516
- VisitedTable vt(ntotal);
517
- VisitedTable vt2(ntotal);
517
+ VisitedTable vt(ntotal, use_visited_hashset);
518
+ VisitedTable vt2(ntotal, use_visited_hashset);
518
519
 
519
520
  int num_attached = 0;
520
521
  int cnt = 0;
@@ -9,12 +9,12 @@
9
9
 
10
10
  #include <memory>
11
11
  #include <mutex>
12
+ #include <optional>
12
13
  #include <vector>
13
14
 
14
15
  #include <omp.h>
15
16
 
16
17
  #include <faiss/Index.h>
17
- #include <faiss/impl/AuxIndexStructures.h>
18
18
  #include <faiss/impl/FaissAssert.h>
19
19
  #include <faiss/utils/Heap.h>
20
20
  #include <faiss/utils/random.h>
@@ -38,6 +38,7 @@ namespace faiss {
38
38
  */
39
39
 
40
40
  struct DistanceComputer; // from AuxIndexStructures
41
+ struct VisitedTable;
41
42
 
42
43
  namespace nsg {
43
44
 
@@ -65,12 +66,14 @@ struct Graph {
65
66
  // construct an empty graph
66
67
  // NOTE: the newly allocated data needs to be destroyed at destruction time
67
68
  Graph(int N, int K) : K(K), N(N), own_fields(true) {
68
- data = new node_t[N * K];
69
+ size_t total = faiss::mul_no_overflow(
70
+ (size_t)N, (size_t)K, "Graph allocation");
71
+ data = new node_t[total];
69
72
  }
70
73
 
71
74
  // copy constructor
72
75
  Graph(const Graph& g) : Graph(g.N, g.K) {
73
- memcpy(data, g.data, N * K * sizeof(node_t));
76
+ memcpy(data, g.data, (size_t)N * (size_t)K * sizeof(node_t));
74
77
  }
75
78
 
76
79
  // release the allocated memory if needed
@@ -82,21 +85,25 @@ struct Graph {
82
85
 
83
86
  // access the j-th neighbor of node i
84
87
  inline node_t at(int i, int j) const {
85
- return data[i * K + j];
88
+ FAISS_CHECK_RANGE_DEBUG(i, 0, N);
89
+ FAISS_CHECK_RANGE_DEBUG(j, 0, K);
90
+ return data[(size_t)i * K + j];
86
91
  }
87
92
 
88
93
  // access the j-th neighbor of node i by reference
89
94
  inline node_t& at(int i, int j) {
90
- return data[i * K + j];
95
+ FAISS_CHECK_RANGE_DEBUG(i, 0, N);
96
+ FAISS_CHECK_RANGE_DEBUG(j, 0, K);
97
+ return data[(size_t)i * K + j];
91
98
  }
92
99
 
93
100
  // get all neighbors of node i (used during search only)
94
101
  virtual size_t get_neighbors(int i, node_t* neighbors) const {
95
102
  for (int j = 0; j < K; j++) {
96
- if (data[i * K + j] < 0) {
103
+ if (data[(size_t)i * K + j] < 0) {
97
104
  return j;
98
105
  }
99
- neighbors[j] = data[i * K + j];
106
+ neighbors[j] = data[(size_t)i * K + j];
100
107
  }
101
108
  return K;
102
109
  }
@@ -122,6 +129,9 @@ struct NSG {
122
129
  // search-time parameters
123
130
  int search_L = 16; ///< length of the search path
124
131
 
132
+ // See impl/VisitedTable.h.
133
+ std::optional<bool> use_visited_hashset;
134
+
125
135
  int enterpoint; ///< enterpoint
126
136
 
127
137
  std::shared_ptr<nsg::Graph<int32_t>> final_graph; ///< NSG graph structure