faiss 0.6.4 → 0.6.5

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 (228) 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/vendor/faiss/faiss/AutoTune.cpp +175 -0
  6. data/vendor/faiss/faiss/Clustering.cpp +150 -60
  7. data/vendor/faiss/faiss/Clustering.h +29 -0
  8. data/vendor/faiss/faiss/IVFlib.cpp +99 -0
  9. data/vendor/faiss/faiss/IVFlib.h +15 -0
  10. data/vendor/faiss/faiss/Index.cpp +44 -0
  11. data/vendor/faiss/faiss/Index.h +19 -14
  12. data/vendor/faiss/faiss/IndexBinary.cpp +8 -0
  13. data/vendor/faiss/faiss/IndexBinary.h +8 -0
  14. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +82 -4
  15. data/vendor/faiss/faiss/IndexBinaryHNSW.h +19 -0
  16. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +34 -0
  17. data/vendor/faiss/faiss/IndexFastScan.cpp +33 -17
  18. data/vendor/faiss/faiss/IndexFastScan.h +6 -3
  19. data/vendor/faiss/faiss/IndexFlat.cpp +56 -0
  20. data/vendor/faiss/faiss/IndexFlat.h +31 -0
  21. data/vendor/faiss/faiss/IndexFlatCodes.cpp +6 -1
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +456 -10
  23. data/vendor/faiss/faiss/IndexHNSW.h +38 -0
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +32 -0
  25. data/vendor/faiss/faiss/IndexIDMap.h +7 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +281 -31
  27. data/vendor/faiss/faiss/IndexIVF.h +53 -1
  28. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +46 -14
  29. data/vendor/faiss/faiss/IndexIVFFastScan.h +4 -2
  30. data/vendor/faiss/faiss/IndexIVFFlat.cpp +33 -0
  31. data/vendor/faiss/faiss/IndexIVFFlat.h +16 -0
  32. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1 -0
  33. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +3 -20
  34. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +50 -14
  35. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -2
  36. data/vendor/faiss/faiss/IndexIVFSQFastScan.cpp +855 -0
  37. data/vendor/faiss/faiss/IndexIVFSQFastScan.h +145 -0
  38. data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -3
  39. data/vendor/faiss/faiss/IndexPiPNN.cpp +201 -0
  40. data/vendor/faiss/faiss/IndexPiPNN.h +83 -0
  41. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +6 -3
  42. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +10 -4
  43. data/vendor/faiss/faiss/IndexReplicas.cpp +20 -0
  44. data/vendor/faiss/faiss/IndexReplicas.h +9 -0
  45. data/vendor/faiss/faiss/IndexSQFastScan.cpp +648 -0
  46. data/vendor/faiss/faiss/IndexSQFastScan.h +129 -0
  47. data/vendor/faiss/faiss/IndexShards.cpp +10 -0
  48. data/vendor/faiss/faiss/IndexShards.h +5 -0
  49. data/vendor/faiss/faiss/SuperKMeans.cpp +57 -15
  50. data/vendor/faiss/faiss/SuperKMeans.h +9 -4
  51. data/vendor/faiss/faiss/VectorTransform.cpp +3 -2
  52. data/vendor/faiss/faiss/clone_index.cpp +24 -0
  53. data/vendor/faiss/faiss/gpu/Dataset.h +112 -0
  54. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +16 -13
  55. data/vendor/faiss/faiss/gpu/GpuCloner.h +4 -0
  56. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -0
  57. data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -13
  58. data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +26 -13
  59. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +45 -22
  60. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -0
  61. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
  62. data/vendor/faiss/faiss/gpu/test/TestGpuDatasetHeader.cpp +18 -0
  63. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +215 -0
  64. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +98 -0
  65. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +11 -0
  66. data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -1
  67. data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +11 -0
  68. data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +92 -0
  69. data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +4 -0
  70. data/vendor/faiss/faiss/gpu_metal/MetalIndexBinaryFlat.h +69 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +38 -0
  72. data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +106 -0
  73. data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +10 -0
  74. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -0
  75. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -6
  76. data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +134 -45
  77. data/vendor/faiss/faiss/impl/ClusteringHelpers.h +36 -0
  78. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +286 -136
  79. data/vendor/faiss/faiss/impl/DistanceComputer.cpp +63 -0
  80. data/vendor/faiss/faiss/impl/DistanceComputer.h +3 -29
  81. data/vendor/faiss/faiss/impl/HNSW.cpp +46 -10
  82. data/vendor/faiss/faiss/impl/HNSW.h +72 -0
  83. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -19
  84. data/vendor/faiss/faiss/impl/NNDescent.cpp +2 -1
  85. data/vendor/faiss/faiss/impl/NSG.cpp +3 -2
  86. data/vendor/faiss/faiss/impl/Panorama.h +3 -2
  87. data/vendor/faiss/faiss/impl/PiPNN.cpp +822 -0
  88. data/vendor/faiss/faiss/impl/PiPNN.h +122 -0
  89. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +54 -11
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.h +1 -1
  91. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +81 -57
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +15 -0
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -0
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -6
  95. data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +0 -4
  96. data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +0 -4
  97. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +5 -2
  98. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +0 -4
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +0 -4
  100. data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +0 -4
  101. data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +0 -4
  102. data/vendor/faiss/faiss/impl/expanded_scanners.h +88 -0
  103. data/vendor/faiss/faiss/impl/fast_scan/FastScanDistancePostProcessing.h +4 -0
  104. data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +61 -64
  105. data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +13 -14
  106. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +17 -129
  107. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +25 -19
  108. data/vendor/faiss/faiss/impl/fast_scan/fast_scan.cpp +5 -0
  109. data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +0 -4
  110. data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +0 -4
  111. data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +0 -88
  112. data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +0 -4
  113. data/vendor/faiss/faiss/impl/fast_scan/kernels_neon.h +155 -0
  114. data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +22 -1
  115. data/vendor/faiss/faiss/impl/fast_scan/kernels_simd512.h +3 -2
  116. data/vendor/faiss/faiss/impl/fast_scan/simd_result_handlers.h +41 -23
  117. data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +0 -4
  118. data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +0 -4
  119. data/vendor/faiss/faiss/impl/index_read.cpp +172 -0
  120. data/vendor/faiss/faiss/impl/index_write.cpp +95 -0
  121. data/vendor/faiss/faiss/impl/pipnn/HashPrune.cpp +159 -0
  122. data/vendor/faiss/faiss/impl/pipnn/HashPrune.h +69 -0
  123. data/vendor/faiss/faiss/impl/pipnn/Partition.cpp +587 -0
  124. data/vendor/faiss/faiss/impl/pipnn/Partition.h +93 -0
  125. data/vendor/faiss/faiss/impl/pipnn/kernels.cpp +326 -0
  126. data/vendor/faiss/faiss/impl/pipnn/kernels.h +92 -0
  127. data/vendor/faiss/faiss/impl/platform_macros.h +45 -0
  128. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +0 -4
  129. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +79 -4
  130. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +6 -0
  131. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +0 -4
  132. data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +0 -4
  133. data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +0 -4
  134. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx2.h +4 -0
  135. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx512.h +4 -1
  136. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +19 -0
  137. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +6 -6
  138. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +131 -6
  139. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +0 -4
  140. data/vendor/faiss/faiss/impl/pq_code_distance/pq_rvv_kernel.h +89 -0
  141. data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +21 -10
  142. data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +45 -18
  143. data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +2 -1
  144. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +0 -4
  145. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +0 -4
  146. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +0 -4
  147. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +0 -4
  148. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +5 -1
  149. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +28 -52
  150. data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +59 -11
  151. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +226 -77
  152. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +482 -103
  153. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +2 -149
  154. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +3 -698
  155. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +66 -57
  156. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +101 -96
  157. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +3185 -144
  158. data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_coefficients.h +48 -0
  159. data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_rvv_kernel.h +546 -0
  160. data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +2 -2
  161. data/vendor/faiss/faiss/impl/simd_dispatch.h +7 -0
  162. data/vendor/faiss/faiss/impl/simdlib/simdlib_avx2.h +14 -0
  163. data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +7 -8
  164. data/vendor/faiss/faiss/impl/sq_fastscan_utils.h +232 -0
  165. data/vendor/faiss/faiss/index_factory.cpp +76 -0
  166. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -1
  167. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +3 -2
  168. data/vendor/faiss/faiss/utils/AlignedTable.h +6 -1
  169. data/vendor/faiss/faiss/utils/Heap.cpp +4 -3
  170. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +16 -5
  171. data/vendor/faiss/faiss/utils/bf16.h +36 -0
  172. data/vendor/faiss/faiss/utils/distances.cpp +226 -15
  173. data/vendor/faiss/faiss/utils/distances.h +34 -0
  174. data/vendor/faiss/faiss/utils/distances_dispatch.h +6 -4
  175. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +2 -5
  176. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +0 -14
  177. data/vendor/faiss/faiss/utils/distances_fused/rvv.cpp +25 -0
  178. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +0 -4
  179. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +0 -4
  180. data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +2 -1
  181. data/vendor/faiss/faiss/utils/distances_simd.cpp +9 -0
  182. data/vendor/faiss/faiss/utils/fp16-fp16c.h +4 -0
  183. data/vendor/faiss/faiss/utils/fp16-inl.h +26 -52
  184. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +0 -4
  185. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +0 -4
  186. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +0 -4
  187. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +33 -5
  188. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h +15 -30
  189. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +0 -4
  190. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +2 -1
  191. data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +0 -4
  192. data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +0 -4
  193. data/vendor/faiss/faiss/utils/pq_code_distance.h +8 -4
  194. data/vendor/faiss/faiss/utils/prefetch.h +1 -26
  195. data/vendor/faiss/faiss/utils/quantize_lut.cpp +26 -27
  196. data/vendor/faiss/faiss/utils/quantize_lut.h +11 -0
  197. data/vendor/faiss/faiss/utils/rabitq_simd.h +51 -16
  198. data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +9 -4
  199. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +37 -5
  200. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +64 -5
  201. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +64 -5
  202. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +353 -71
  203. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv_kernel.h +68 -0
  204. data/vendor/faiss/faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h +93 -0
  205. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels.h +76 -0
  206. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx2.cpp +52 -0
  207. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx512.cpp +52 -0
  208. data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_neon.cpp +48 -0
  209. data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx2.h +44 -0
  210. data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx512.h +43 -0
  211. data/vendor/faiss/faiss/utils/simd_impl/masked_sum.h +38 -0
  212. data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +0 -4
  213. data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +0 -4
  214. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +54 -15
  215. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +38 -21
  216. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_vpopcnt.cpp +51 -14
  217. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +297 -10
  218. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +0 -4
  219. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +0 -4
  220. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +0 -4
  221. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +0 -4
  222. data/vendor/faiss/faiss/utils/simd_levels.cpp +19 -3
  223. data/vendor/faiss/faiss/utils/simd_levels.h +74 -1
  224. data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +0 -4
  225. data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +0 -4
  226. data/vendor/faiss/faiss/utils/utils.cpp +80 -0
  227. data/vendor/faiss/faiss/utils/utils.h +24 -0
  228. metadata +33 -1
@@ -0,0 +1,232 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #include <algorithm>
11
+ #include <cstring>
12
+
13
+ #include <faiss/impl/ScalarQuantizer.h>
14
+ #include <faiss/utils/hamming.h>
15
+
16
+ /** Helpers shared by IndexSQFastScan and IndexIVFSQFastScan.
17
+ *
18
+ * Both re-quantise a higher-precision scalar quantizer down to 4-bit nibbles
19
+ * for the SIMD scan and keep the original codes to rerank with, so the
20
+ * classification of quantizer types and the nibble packing have to agree
21
+ * between them.
22
+ */
23
+
24
+ namespace faiss {
25
+ namespace sq_fastscan {
26
+
27
+ inline size_t roundup(size_t a, size_t b) {
28
+ return (a + b - 1) / b * b;
29
+ }
30
+
31
+ inline bool is_native_4bit(ScalarQuantizer::QuantizerType qtype) {
32
+ return qtype == ScalarQuantizer::QT_4bit ||
33
+ qtype == ScalarQuantizer::QT_4bit_uniform;
34
+ }
35
+
36
+ inline bool needs_rerank(ScalarQuantizer::QuantizerType qtype) {
37
+ return qtype == ScalarQuantizer::QT_6bit ||
38
+ qtype == ScalarQuantizer::QT_8bit ||
39
+ qtype == ScalarQuantizer::QT_8bit_uniform ||
40
+ qtype == ScalarQuantizer::QT_8bit_direct ||
41
+ qtype == ScalarQuantizer::QT_8bit_direct_signed;
42
+ }
43
+
44
+ inline bool is_fallback(ScalarQuantizer::QuantizerType qtype) {
45
+ return !is_native_4bit(qtype) && !needs_rerank(qtype);
46
+ }
47
+
48
+ inline bool is_uniform_range(ScalarQuantizer::QuantizerType qtype) {
49
+ return qtype == ScalarQuantizer::QT_8bit_uniform ||
50
+ qtype == ScalarQuantizer::QT_8bit_direct ||
51
+ qtype == ScalarQuantizer::QT_8bit_direct_signed;
52
+ }
53
+
54
+ inline void get_uniform_range(
55
+ const ScalarQuantizer& sq,
56
+ float& vmin,
57
+ float& vdiff) {
58
+ if (sq.qtype == ScalarQuantizer::QT_8bit_direct) {
59
+ vmin = 0;
60
+ vdiff = 255;
61
+ } else if (sq.qtype == ScalarQuantizer::QT_8bit_direct_signed) {
62
+ vmin = -128;
63
+ vdiff = 255;
64
+ } else {
65
+ vmin = sq.trained[0];
66
+ vdiff = sq.trained[1];
67
+ }
68
+ }
69
+
70
+ /// Bits per dimension the quantizer stores.
71
+ inline int sq_bits(ScalarQuantizer::QuantizerType qtype) {
72
+ if (qtype == ScalarQuantizer::QT_6bit) {
73
+ return 6;
74
+ }
75
+ return is_native_4bit(qtype) ? 4 : 8;
76
+ }
77
+
78
+ /// Bits left over once the scan has taken its 4. Zero for a native 4-bit
79
+ /// code, which needs no rerank and therefore stores nothing extra.
80
+ inline int sq_rerank_bits(ScalarQuantizer::QuantizerType qtype) {
81
+ return sq_bits(qtype) - 4;
82
+ }
83
+
84
+ /// Bytes per vector needed to hold the leftover bits of every dimension.
85
+ inline size_t sq_rerank_size(int d, ScalarQuantizer::QuantizerType qtype) {
86
+ const int bits = sq_rerank_bits(qtype);
87
+ return bits > 0 ? (size_t(d) * bits + 7) / 8 : 0;
88
+ }
89
+
90
+ /// The code for one value at the quantizer's own width.
91
+ inline int sq_code_of(float x, float vmin, float vdiff, int bits) {
92
+ const int maxv = (1 << bits) - 1;
93
+ const float f = (vdiff > 0) ? (x - vmin) / vdiff : 0.0f;
94
+ return std::min(maxv, std::max(0, int(f * float(maxv))));
95
+ }
96
+
97
+ /// Per-dimension range of the trained quantizer, resolved once for a batch.
98
+ struct SQRanges {
99
+ SQRanges(const ScalarQuantizer& sq, int d)
100
+ : uniform(is_uniform_range(sq.qtype) ||
101
+ sq.qtype == ScalarQuantizer::QT_4bit_uniform) {
102
+ if (uniform) {
103
+ get_uniform_range(sq, vmin_s, vdiff_s);
104
+ } else {
105
+ vmin_arr = sq.trained.data();
106
+ vdiff_arr = sq.trained.data() + d;
107
+ }
108
+ }
109
+
110
+ float vmin(int m) const {
111
+ return uniform ? vmin_s : vmin_arr[m];
112
+ }
113
+ float vdiff(int m) const {
114
+ return uniform ? vdiff_s : vdiff_arr[m];
115
+ }
116
+
117
+ const bool uniform;
118
+ const float* vmin_arr = nullptr;
119
+ const float* vdiff_arr = nullptr;
120
+ float vmin_s = 0, vdiff_s = 0;
121
+ };
122
+
123
+ /** Split each code into the top 4 bits the SIMD kernel scans and the rest,
124
+ * which rerank keeps. `hi` is packed two dimensions per byte as
125
+ * pq4_pack_codes expects. `lo` is bit-packed at `bits - 4` per dimension.
126
+ * Total width is the quantizer's own, not that width plus 4.
127
+ */
128
+ inline void float_to_split_codes(
129
+ const float* x,
130
+ uint8_t* hi,
131
+ uint8_t* lo,
132
+ idx_t n,
133
+ int d,
134
+ size_t M2,
135
+ const ScalarQuantizer& sq) {
136
+ const int bits = sq_bits(sq.qtype);
137
+ const int lo_bits = bits - 4;
138
+ const size_t hi_stride = M2 / 2;
139
+ const size_t lo_stride = sq_rerank_size(d, sq.qtype);
140
+ const SQRanges ranges(sq, d);
141
+ for (idx_t i = 0; i < n; i++) {
142
+ const float* xi = x + i * d;
143
+ uint8_t* hdst = hi + i * hi_stride;
144
+ memset(hdst, 0, hi_stride);
145
+ uint8_t* ldst = lo + i * lo_stride;
146
+ memset(ldst, 0, lo_stride);
147
+ BitstringWriter bsw(ldst, lo_stride);
148
+ for (int m = 0; m < d; m++) {
149
+ const int code =
150
+ sq_code_of(xi[m], ranges.vmin(m), ranges.vdiff(m), bits);
151
+ const int h = code >> lo_bits;
152
+ hdst[m / 2] |= (m & 1) ? uint8_t(h << 4) : uint8_t(h);
153
+ bsw.write(code & ((1 << lo_bits) - 1), lo_bits);
154
+ }
155
+ }
156
+ }
157
+
158
+ /// Rebuild the code values of one vector from its two halves.
159
+ inline void split_to_codes(
160
+ const uint8_t* hi,
161
+ const uint8_t* lo,
162
+ int d,
163
+ ScalarQuantizer::QuantizerType qtype,
164
+ int* codes_out) {
165
+ const int lo_bits = sq_rerank_bits(qtype);
166
+ BitstringReader bsr(lo, sq_rerank_size(d, qtype));
167
+ for (int m = 0; m < d; m++) {
168
+ const int h = (m & 1) ? (hi[m / 2] >> 4) : (hi[m / 2] & 0xF);
169
+ codes_out[m] = (h << lo_bits) | int(bsr.read(lo_bits));
170
+ }
171
+ }
172
+
173
+ inline void float_to_4bit_nibbles(
174
+ const float* x,
175
+ uint8_t* nibbles,
176
+ idx_t n,
177
+ int d,
178
+ int M2,
179
+ const ScalarQuantizer& sq) {
180
+ const bool is_uniform = is_uniform_range(sq.qtype) ||
181
+ sq.qtype == ScalarQuantizer::QT_4bit_uniform;
182
+ const float* vmin_arr = nullptr;
183
+ const float* vdiff_arr = nullptr;
184
+ float vmin_s = 0, inv_vdiff_s = 0;
185
+
186
+ if (is_uniform) {
187
+ float vdiff;
188
+ get_uniform_range(sq, vmin_s, vdiff);
189
+ inv_vdiff_s = (vdiff > 0) ? (1.0f / vdiff) : 0;
190
+ } else {
191
+ vmin_arr = sq.trained.data();
192
+ vdiff_arr = sq.trained.data() + d;
193
+ }
194
+
195
+ const int half = M2 / 2;
196
+ for (idx_t i = 0; i < n; i++) {
197
+ const float* xi = x + i * d;
198
+ uint8_t* dst = nibbles + i * half;
199
+ memset(dst, 0, half);
200
+ for (int m = 0; m + 1 < d; m += 2) {
201
+ float f0, f1;
202
+ if (is_uniform) {
203
+ f0 = (xi[m] - vmin_s) * inv_vdiff_s;
204
+ f1 = (xi[m + 1] - vmin_s) * inv_vdiff_s;
205
+ } else {
206
+ f0 = (vdiff_arr[m] > 0) ? (xi[m] - vmin_arr[m]) / vdiff_arr[m]
207
+ : 0;
208
+ f1 = (vdiff_arr[m + 1] > 0)
209
+ ? (xi[m + 1] - vmin_arr[m + 1]) / vdiff_arr[m + 1]
210
+ : 0;
211
+ }
212
+ uint8_t lo = (uint8_t)std::min(15, std::max(0, (int)(f0 * 15.0f)));
213
+ uint8_t hi = (uint8_t)std::min(15, std::max(0, (int)(f1 * 15.0f)));
214
+ dst[m / 2] = lo | (hi << 4);
215
+ }
216
+ if (d & 1) {
217
+ float f;
218
+ if (is_uniform) {
219
+ f = (xi[d - 1] - vmin_s) * inv_vdiff_s;
220
+ } else {
221
+ f = (vdiff_arr[d - 1] > 0)
222
+ ? (xi[d - 1] - vmin_arr[d - 1]) / vdiff_arr[d - 1]
223
+ : 0;
224
+ }
225
+ dst[(d - 1) / 2] =
226
+ (uint8_t)std::min(15, std::max(0, (int)(f * 15.0f)));
227
+ }
228
+ }
229
+ }
230
+
231
+ } // namespace sq_fastscan
232
+ } // namespace faiss
@@ -35,17 +35,20 @@
35
35
  #include <faiss/IndexIVFPQR.h>
36
36
  #include <faiss/IndexIVFRaBitQ.h>
37
37
  #include <faiss/IndexIVFRaBitQFastScan.h>
38
+ #include <faiss/IndexIVFSQFastScan.h>
38
39
  #include <faiss/IndexIVFSpectralHash.h>
39
40
  #include <faiss/IndexLSH.h>
40
41
  #include <faiss/IndexLattice.h>
41
42
  #include <faiss/IndexNSG.h>
42
43
  #include <faiss/IndexPQ.h>
43
44
  #include <faiss/IndexPQFastScan.h>
45
+ #include <faiss/IndexPiPNN.h>
44
46
  #include <faiss/IndexPreTransform.h>
45
47
  #include <faiss/IndexRaBitQ.h>
46
48
  #include <faiss/IndexRaBitQFastScan.h>
47
49
  #include <faiss/IndexRefine.h>
48
50
  #include <faiss/IndexRowwiseMinMax.h>
51
+ #include <faiss/IndexSQFastScan.h>
49
52
  #include <faiss/IndexScalarQuantizer.h>
50
53
  #include <faiss/VectorTransform.h>
51
54
 
@@ -177,6 +180,11 @@ std::map<std::string, ScalarQuantizer::QuantizerType> sq_types = {
177
180
  };
178
181
  const std::string sq_pattern =
179
182
  "(SQ0|SQ4|SQ8|SQ6|SQfp16|SQbf16|SQ8_direct_signed|SQ8_direct|SQtqmse1|SQtqmse2|SQtqmse3|SQtqmse4|SQtqmse8|SQtq2|SQtq3|SQtq4|SQtq5)";
183
+ const std::string sq_fs_pattern =
184
+ "(SQ4|SQ6|SQ8|SQ8_direct_signed|SQ8_direct)fs(_[0-9]+)?";
185
+ // All SQ types with "fs" suffix for IndexIVFSQFastScan, optional _bbs
186
+ const std::string ivf_sq_fs_pattern =
187
+ "(SQ0|SQ4|SQ8|SQ6|SQfp16|SQbf16|SQ8_direct_signed|SQ8_direct|SQtqmse1|SQtqmse2|SQtqmse3|SQtqmse4|SQtqmse8|SQtq2|SQtq3|SQtq4|SQtq5)fs(_[0-9]+)?";
180
188
 
181
189
  std::map<std::string, AdditiveQuantizer::Search_type_t> aq_search_type = {
182
190
  {"_Nfloat", AdditiveQuantizer::ST_norm_float},
@@ -310,6 +318,11 @@ Index* parse_coarse_quantizer(
310
318
  int R = std::stoi(sm[2]);
311
319
  return new IndexNSGFlat(d, R, mt);
312
320
  }
321
+ if (match("IVF([0-9]+[kM]?)_PiPNN([0-9]*)")) {
322
+ nlist = parse_nlist(sm[1].str());
323
+ int R = mres_to_int(sm[2], 64);
324
+ return new IndexPiPNNFlat(d, R, mt);
325
+ }
313
326
  #ifdef FAISS_ENABLE_SVS
314
327
  if (match("IVF([0-9]+[kM]?)_SVSVamana([0-9]*)(_.+)?")) {
315
328
  nlist = parse_nlist(sm[1].str());
@@ -389,6 +402,17 @@ IndexIVF* parse_IndexIVF(
389
402
  return new IndexIVFFlatPanorama(
390
403
  get_q(), d, nlist, nlevels, mt, own_il, bs);
391
404
  }
405
+ if (match(ivf_sq_fs_pattern)) {
406
+ int bbs = mres_to_int(sm[2], 32, 1);
407
+ return new IndexIVFSQFastScan(
408
+ get_q(),
409
+ d,
410
+ nlist,
411
+ sq_types[sm[1].str()],
412
+ mt,
413
+ bbs,
414
+ /*by_residual=*/true);
415
+ }
392
416
  if (match(sq_pattern)) {
393
417
  return new IndexIVFScalarQuantizer(
394
418
  get_q(),
@@ -637,6 +661,30 @@ IndexNSG* parse_IndexNSG(
637
661
  return nullptr;
638
662
  }
639
663
 
664
+ /***************************************************************
665
+ * Parse IndexPiPNN
666
+ */
667
+
668
+ IndexPiPNN* parse_IndexPiPNN(
669
+ const std::string& code_string,
670
+ int d,
671
+ MetricType mt,
672
+ int pipnn_R) {
673
+ std::smatch sm;
674
+ auto match = [&sm, &code_string](const std::string& pattern) {
675
+ return re_match(code_string, pattern, sm);
676
+ };
677
+
678
+ if (match("Flat|")) {
679
+ return new IndexPiPNNFlat(d, pipnn_R, mt);
680
+ }
681
+ if (match(sq_pattern)) {
682
+ return new IndexPiPNNSQ(d, sq_types[sm[1].str()], pipnn_R, mt);
683
+ }
684
+
685
+ return nullptr;
686
+ }
687
+
640
688
  #ifdef FAISS_ENABLE_SVS
641
689
  /***************************************************************
642
690
  * Parse IndexSVS
@@ -831,6 +879,12 @@ Index* parse_other_indexes(
831
879
  return new IndexLattice(d, M, nbit, r2);
832
880
  }
833
881
 
882
+ // IndexSQFastScan (must be checked before IndexScalarQuantizer)
883
+ if (match(sq_fs_pattern)) {
884
+ int bbs = mres_to_int(sm[2], 32, 1);
885
+ return new IndexSQFastScan(d, sq_types[sm[1].str()], metric, bbs);
886
+ }
887
+
834
888
  // IndexScalarQuantizer
835
889
  if (match(sq_pattern)) {
836
890
  return new IndexScalarQuantizer(d, sq_types[description], metric);
@@ -1156,6 +1210,28 @@ std::unique_ptr<Index> index_factory_sub(
1156
1210
  return std::unique_ptr<Index>(index);
1157
1211
  }
1158
1212
 
1213
+ // PiPNN variants (separator "," or "_", as for HNSW and NSG)
1214
+ if (re_match(description, "PiPNN([0-9]*)([,_].*)?", sm)) {
1215
+ int pipnn_R = mres_to_int(sm[1], 64);
1216
+ // We also accept empty code string (synonym of Flat)
1217
+ std::string code_string =
1218
+ sm[2].length() > 0 ? sm[2].str().substr(1) : "";
1219
+ if (verbose) {
1220
+ printf("parsing PiPNN string %s code_string=%s pipnn_R=%d\n",
1221
+ description.c_str(),
1222
+ code_string.c_str(),
1223
+ pipnn_R);
1224
+ }
1225
+
1226
+ IndexPiPNN* index = parse_IndexPiPNN(code_string, d, metric, pipnn_R);
1227
+ FAISS_THROW_IF_NOT_FMT(
1228
+ index,
1229
+ "could not parse PiPNN code description %s in %s",
1230
+ code_string.c_str(),
1231
+ description.c_str());
1232
+ return std::unique_ptr<Index>(index);
1233
+ }
1234
+
1159
1235
  // IndexRowwiseMinMax, fp32 version
1160
1236
  if (description.compare(0, 7, "MinMax,") == 0) {
1161
1237
  size_t comma = description.find(',');
@@ -127,7 +127,9 @@ size_t InvertedLists::copy_subset_to(
127
127
  } else if (subset_type == SUBSET_TYPE_ID_MOD) {
128
128
  for (size_t i = 0; i < n; i++) {
129
129
  idx_t id = ids_in[i];
130
- if (id % a1 == a2) {
130
+ // C++ gives a negative remainder, so a plain `id % a1` never
131
+ // matches for a negative id. Fold it into [0, a1) instead.
132
+ if (((id % a1) + a1) % a1 == a2) {
131
133
  oivf.add_entry(
132
134
  list_no,
133
135
  get_single_id(list_no, i),
@@ -90,8 +90,9 @@ inline svs_runtime::StorageKind to_svs_storage_kind(SVSStorageKind kind) {
90
90
  }
91
91
 
92
92
  struct IndexSVSVamana : Index {
93
- size_t graph_max_degree;
94
- size_t prune_to;
93
+ // Same defaults as IndexSVSVamana(d, /*degree=*/64).
94
+ size_t graph_max_degree = 64;
95
+ size_t prune_to = 60;
95
96
  float alpha = 1.2;
96
97
  size_t search_window_size = 10;
97
98
  size_t search_buffer_capacity = 10;
@@ -117,6 +117,8 @@ template <class T, int A = 32>
117
117
  struct AlignedTable {
118
118
  AlignedTableTightAlloc<T, A> tab;
119
119
  size_t numel = 0;
120
+ // If true, resize() reallocates only when n is larger than the capacity.
121
+ bool keep_capacity = false;
120
122
 
121
123
  static size_t round_capacity(size_t n) {
122
124
  if (n == 0) {
@@ -141,7 +143,10 @@ struct AlignedTable {
141
143
  }
142
144
 
143
145
  void resize(size_t n) {
144
- tab.resize(round_capacity(n));
146
+ const size_t capacity = round_capacity(n);
147
+ if (!keep_capacity || capacity > tab.numel) {
148
+ tab.resize(capacity);
149
+ }
145
150
  numel = n;
146
151
  }
147
152
 
@@ -194,10 +194,11 @@ void merge_knn_results(
194
194
  const idx_t* I_in = all_labels + i * k;
195
195
  int heap_size = 0;
196
196
 
197
- // push the first element of each shard (if not -1)
197
+ // push the first element of each shard (if not -1). A caller id
198
+ // may be negative, so only -1 marks a missing result.
198
199
  for (long s = 0; s < static_cast<long>(nshard); s++) {
199
200
  pointer[s] = 0;
200
- if (I_in[stride * s] >= 0) {
201
+ if (I_in[stride * s] != -1) {
201
202
  heap_push<C>(
202
203
  ++heap_size,
203
204
  heap_vals,
@@ -221,7 +222,7 @@ void merge_knn_results(
221
222
  // pop from shard, advance pointer for this shard
222
223
  heap_pop<C>(heap_size--, heap_vals, shard_ids);
223
224
  p++;
224
- if (static_cast<size_t>(p) < k && I_in[stride * s + p] >= 0) {
225
+ if (static_cast<size_t>(p) < k && I_in[stride * s + p] != -1) {
225
226
  heap_push<C>(
226
227
  ++heap_size,
227
228
  heap_vals,
@@ -21,19 +21,30 @@ using simd8uint32 = simd8uint32_tpl<SINGLE_SIMD_LEVEL_256>;
21
21
  using simd16uint16 = simd16uint16_tpl<SINGLE_SIMD_LEVEL_256>;
22
22
 
23
23
  // HeapWithBucketsForHamming32 uses simd8uint32 under the
24
- // hood.
25
-
26
- template <typename C, uint32_t NBUCKETS, uint32_t N, typename HammingComputerT>
24
+ // hood. SL is the SIMD level of the file that uses it, so each level compiles
25
+ // its own copy under its own name.
26
+
27
+ template <
28
+ typename C,
29
+ uint32_t NBUCKETS,
30
+ uint32_t N,
31
+ typename HammingComputerT,
32
+ SIMDLevel SL>
27
33
  struct HeapWithBucketsForHamming32 {
28
34
  // this case was not implemented yet.
29
35
  };
30
36
 
31
- template <uint32_t NBUCKETS, uint32_t N, typename HammingComputerT>
37
+ template <
38
+ uint32_t NBUCKETS,
39
+ uint32_t N,
40
+ typename HammingComputerT,
41
+ SIMDLevel SL>
32
42
  struct HeapWithBucketsForHamming32<
33
43
  CMax<int, int64_t>,
34
44
  NBUCKETS,
35
45
  N,
36
- HammingComputerT> {
46
+ HammingComputerT,
47
+ SL> {
37
48
  static constexpr uint32_t NBUCKETS_8 = NBUCKETS / 8;
38
49
  static_assert(
39
50
  (NBUCKETS) > 0 && ((NBUCKETS % 8) == 0),
@@ -14,6 +14,10 @@
14
14
  #include <immintrin.h>
15
15
  #endif
16
16
 
17
+ #if defined(__riscv_vector)
18
+ #include <riscv_vector.h>
19
+ #endif
20
+
17
21
  namespace faiss {
18
22
 
19
23
  namespace {
@@ -38,6 +42,8 @@ inline float decode_bf16(const uint16_t v) {
38
42
  return fp.as_f32;
39
43
  }
40
44
 
45
+ namespace {
46
+
41
47
  inline void encode_bf16_simd(const float* src, uint16_t* dst, size_t n) {
42
48
  size_t i = 0;
43
49
  #ifdef __AVX512BF16__
@@ -61,10 +67,40 @@ inline void decode_bf16_simd(const uint16_t* src, float* dst, size_t n) {
61
67
  w = _mm512_slli_epi32(w, 16);
62
68
  _mm512_storeu_ps(dst + i, _mm512_castsi512_ps(w));
63
69
  }
70
+ #elif defined(__riscv_vector)
71
+ if (n == 1) {
72
+ dst[0] = decode_bf16(src[0]);
73
+ return;
74
+ }
75
+ if (n < 16) {
76
+ for (; i < n; ++i) {
77
+ dst[i] = decode_bf16(src[i]);
78
+ }
79
+ return;
80
+ }
81
+ const size_t vlmax = __riscv_vsetvlmax_e16m1();
82
+ for (; i + vlmax <= n; i += vlmax) {
83
+ vuint16m1_t v = __riscv_vle16_v_u16m1(src + i, vlmax);
84
+ vuint32m2_t w = __riscv_vzext_vf2_u32m2(v, vlmax);
85
+ w = __riscv_vsll_vx_u32m2(w, 16, vlmax);
86
+ __riscv_vse32_v_f32m2(
87
+ dst + i, __riscv_vreinterpret_v_u32m2_f32m2(w), vlmax);
88
+ }
89
+ if (i < n) {
90
+ const size_t vl = __riscv_vsetvl_e16m1(n - i);
91
+ vuint16m1_t v = __riscv_vle16_v_u16m1(src + i, vl);
92
+ vuint32m2_t w = __riscv_vzext_vf2_u32m2(v, vl);
93
+ w = __riscv_vsll_vx_u32m2(w, 16, vl);
94
+ __riscv_vse32_v_f32m2(
95
+ dst + i, __riscv_vreinterpret_v_u32m2_f32m2(w), vl);
96
+ i += vl;
97
+ }
64
98
  #endif
65
99
  for (; i < n; i++) {
66
100
  dst[i] = decode_bf16(src[i]);
67
101
  }
68
102
  }
69
103
 
104
+ } // namespace
105
+
70
106
  } // namespace faiss