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,145 @@
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 <faiss/IndexIVFFastScan.h>
11
+ #include <faiss/IndexScalarQuantizer.h>
12
+ #include <faiss/impl/ScalarQuantizer.h>
13
+ #include <faiss/impl/sq_fastscan_utils.h>
14
+
15
+ namespace faiss {
16
+
17
+ /** Fast scan version of IndexIVFScalarQuantizer.
18
+ *
19
+ * Uses the PQ4 FastScan SIMD infrastructure (vpshufb) for accelerated
20
+ * scanning within inverted lists. Supported quantizer types:
21
+ *
22
+ * - QT_4bit, QT_4bit_uniform: native 4-bit codes are packed directly
23
+ * into the SIMD block layout. No precision loss.
24
+ *
25
+ * - QT_6bit, QT_8bit, QT_8bit_uniform, QT_8bit_direct,
26
+ * QT_8bit_direct_signed: re-quantised to 4-bit for the SIMD scan,
27
+ * then reranked with exact original-precision distances.
28
+ *
29
+ * - All other types (QT_fp16, QT_bf16, TurboQuant): fall back to the
30
+ * ScalarQuantizer's own SIMD-optimised InvertedListScanner (same
31
+ * behavior as IndexIVFScalarQuantizer, no fast-scan acceleration).
32
+ *
33
+ * For reranked types the block inverted lists hold the packed high nibbles
34
+ * and a parallel ArrayInvertedLists (lo_codes_invlists) holds the low ones.
35
+ */
36
+ struct IndexIVFSQFastScan : IndexIVFFastScan {
37
+ ScalarQuantizer sq;
38
+
39
+ /// Overselection ratio for reranking (default 2).
40
+ float rerank_factor = 2;
41
+
42
+ /// Parallel inverted lists holding the leftover low bits of each code.
43
+ /// The top 4 bits of every code live in the packed scan blocks.
44
+ /// Owned by this index. nullptr for native 4-bit and fallback types.
45
+ InvertedLists* lo_codes_invlists = nullptr;
46
+
47
+ /// Bytes per vector in lo_codes_invlists: the bits of each code left
48
+ /// over once the scan has taken the top 4.
49
+ size_t lo_code_size() const {
50
+ return sq_fastscan::sq_rerank_size(d, sq.qtype);
51
+ }
52
+
53
+ /// Rebuild the code at (list_no, offset) from its two halves. `scratch`
54
+ /// needs M2 / 2 bytes, `code_out` needs sq.code_size.
55
+ void recombine_code(
56
+ int64_t list_no,
57
+ int64_t offset,
58
+ uint8_t* scratch,
59
+ int* values,
60
+ uint8_t* code_out) const;
61
+
62
+ IndexIVFSQFastScan(
63
+ Index* quantizer,
64
+ size_t d,
65
+ size_t nlist,
66
+ ScalarQuantizer::QuantizerType qtype,
67
+ MetricType metric = METRIC_L2,
68
+ int bbs = 32,
69
+ bool by_residual = true);
70
+
71
+ IndexIVFSQFastScan();
72
+
73
+ /// Build from an existing IndexIVFScalarQuantizer.
74
+ explicit IndexIVFSQFastScan(
75
+ const IndexIVFScalarQuantizer& orig,
76
+ int bbs = 32);
77
+
78
+ ~IndexIVFSQFastScan() override;
79
+
80
+ size_t fast_scan_code_size() const override;
81
+
82
+ void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
83
+
84
+ idx_t train_encoder_num_vectors() const override;
85
+
86
+ void encode_vectors(
87
+ idx_t n,
88
+ const float* x,
89
+ const idx_t* list_nos,
90
+ uint8_t* codes,
91
+ bool include_listno = false) const override;
92
+
93
+ bool lookup_table_is_3d() const override;
94
+
95
+ void compute_LUT(
96
+ size_t n,
97
+ const float* x,
98
+ const CoarseQuantized& cq,
99
+ AlignedTable<float>& dis_tables,
100
+ AlignedTable<float>& biases,
101
+ const FastScanDistancePostProcessing& context) const override;
102
+
103
+ void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
104
+
105
+ void reconstruct_from_offset(int64_t list_no, int64_t offset, float* recons)
106
+ const override;
107
+
108
+ InvertedListScanner* get_InvertedListScanner(
109
+ bool store_pairs,
110
+ const IDSelector* sel,
111
+ const IVFSearchParameters*) const override;
112
+
113
+ void search(
114
+ idx_t n,
115
+ const float* x,
116
+ idx_t k,
117
+ float* distances,
118
+ idx_t* labels,
119
+ const SearchParameters* params = nullptr) const override;
120
+
121
+ void search_preassigned(
122
+ idx_t n,
123
+ const float* x,
124
+ idx_t k,
125
+ const idx_t* assign,
126
+ const float* centroid_dis,
127
+ float* distances,
128
+ idx_t* labels,
129
+ bool store_pairs,
130
+ const IVFSearchParameters* params = nullptr,
131
+ IndexIVFStats* stats = nullptr) const override;
132
+
133
+ void range_search(
134
+ idx_t n,
135
+ const float* x,
136
+ float radius,
137
+ RangeSearchResult* result,
138
+ const SearchParameters* params = nullptr) const override;
139
+
140
+ void add_with_ids(idx_t n, const float* x, const idx_t* xids) override;
141
+
142
+ void reset() override;
143
+ };
144
+
145
+ } // namespace faiss
@@ -14,9 +14,6 @@
14
14
  #include <cstdio>
15
15
  #include <cstdlib>
16
16
 
17
- #ifdef __SSE__
18
- #endif
19
-
20
17
  #include <faiss/IndexFlat.h>
21
18
  #include <faiss/impl/AuxIndexStructures.h>
22
19
  #include <faiss/impl/FaissAssert.h>
@@ -0,0 +1,201 @@
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
+ #include <faiss/IndexPiPNN.h>
9
+
10
+ #include <omp.h>
11
+ #include <algorithm>
12
+ #include <atomic>
13
+ #include <exception>
14
+ #include <memory>
15
+ #include <string>
16
+ #include <typeinfo>
17
+
18
+ #include <faiss/IndexFlat.h>
19
+ #include <faiss/IndexScalarQuantizer.h>
20
+ #include <faiss/impl/AuxIndexStructures.h>
21
+ #include <faiss/impl/DistanceComputer.h>
22
+ #include <faiss/impl/FaissAssert.h>
23
+ #include <faiss/impl/FaissException.h>
24
+ #include <faiss/impl/VisitedTable.h>
25
+
26
+ namespace faiss {
27
+
28
+ IndexPiPNN::IndexPiPNN() = default;
29
+
30
+ IndexPiPNN::IndexPiPNN(Index* storage_in, int R)
31
+ : pipnn(R), storage(storage_in) {
32
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
33
+ check_storage_supported(*storage);
34
+ d = storage->d;
35
+ metric_type = storage->metric_type;
36
+ is_trained = storage->is_trained;
37
+ ntotal = storage->ntotal;
38
+ }
39
+
40
+ IndexPiPNN::~IndexPiPNN() {
41
+ if (own_fields) {
42
+ delete storage;
43
+ }
44
+ }
45
+
46
+ void IndexPiPNN::train(idx_t n, const float* x) {
47
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
48
+ storage->train(n, x);
49
+ is_trained = storage->is_trained;
50
+ }
51
+
52
+ void IndexPiPNN::add(idx_t n, const float* x) {
53
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
54
+ FAISS_THROW_IF_MSG(
55
+ is_built(), "IndexPiPNN does not support incremental addition");
56
+ storage->add(n, x);
57
+ ntotal = storage->ntotal;
58
+ if (!defer_build && ntotal > 0) {
59
+ build();
60
+ }
61
+ }
62
+
63
+ void IndexPiPNN::build() {
64
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
65
+ check_storage_supported(*storage);
66
+ FAISS_THROW_IF_NOT_MSG(
67
+ storage->ntotal > 0, "IndexPiPNN: cannot build over 0 vectors");
68
+ pipnn.build(*storage, verbose);
69
+ ntotal = storage->ntotal;
70
+ }
71
+
72
+ void IndexPiPNN::search(
73
+ idx_t n,
74
+ const float* x,
75
+ idx_t k,
76
+ float* distances,
77
+ idx_t* labels,
78
+ const SearchParameters* params) const {
79
+ FAISS_THROW_IF_NOT(k > 0);
80
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
81
+ FAISS_THROW_IF_NOT_MSG(
82
+ storage->is_trained,
83
+ "IndexPiPNN: storage must be trained before search()");
84
+ FAISS_THROW_IF_NOT_MSG(
85
+ pipnn.ntotal == ntotal && storage->ntotal == ntotal,
86
+ "IndexPiPNN: the index is not built over its storage; call "
87
+ "build()");
88
+ const auto* pipnn_params =
89
+ dynamic_cast<const SearchParametersPiPNN*>(params);
90
+ const int search_L = pipnn_params && pipnn_params->search_L != 0
91
+ ? pipnn_params->search_L
92
+ : pipnn.search_L;
93
+ const IDSelector* sel = params ? params->sel : nullptr;
94
+ const bool negate = metric_type == METRIC_INNER_PRODUCT;
95
+
96
+ const idx_t check_period =
97
+ InterruptCallback::get_period_hint(
98
+ size_t(d) * size_t(std::max(idx_t(search_L), k))) *
99
+ omp_get_max_threads();
100
+
101
+ for (idx_t i0 = 0; i0 < n; i0 += check_period) {
102
+ const idx_t i1 = std::min(i0 + check_period, n);
103
+ std::exception_ptr ex;
104
+ std::atomic<bool> interrupt{false};
105
+
106
+ #pragma omp parallel if (i1 - i0 > 1)
107
+ {
108
+ VisitedTable* vt = nullptr;
109
+ std::unique_ptr<DistanceComputer> dis;
110
+ try {
111
+ vt = &VisitedTable::get_reusable(ntotal, use_visited_hashset);
112
+ dis.reset(
113
+ negate ? new NegativeDistanceComputer(
114
+ storage->get_distance_computer())
115
+ : storage->get_distance_computer());
116
+ } catch (...) {
117
+ omp_capture_exception(ex, [&] { interrupt = true; });
118
+ }
119
+
120
+ #pragma omp for schedule(guided)
121
+ for (idx_t i = i0; i < i1; i++) {
122
+ if (interrupt.load(std::memory_order_relaxed)) {
123
+ continue;
124
+ }
125
+ try {
126
+ dis->set_query(x + i * d);
127
+ pipnn.search(
128
+ *dis,
129
+ search_L,
130
+ k,
131
+ labels + i * k,
132
+ distances + i * k,
133
+ *vt,
134
+ sel);
135
+ } catch (...) {
136
+ omp_capture_exception(ex, [&] { interrupt = true; });
137
+ }
138
+ }
139
+ }
140
+ omp_rethrow_if_exception(ex);
141
+ InterruptCallback::check();
142
+ }
143
+
144
+ if (negate) {
145
+ for (idx_t i = 0; i < n * k; i++) {
146
+ distances[i] = -distances[i];
147
+ }
148
+ }
149
+ }
150
+
151
+ void IndexPiPNN::reconstruct(idx_t key, float* recons) const {
152
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
153
+ storage->reconstruct(key, recons);
154
+ }
155
+
156
+ void IndexPiPNN::reset() {
157
+ FAISS_THROW_IF_NOT_MSG(storage, "IndexPiPNN has no storage");
158
+ storage->reset();
159
+ pipnn.reset();
160
+ ntotal = 0;
161
+ }
162
+
163
+ void IndexPiPNN::check_storage_supported(const Index& storage) {
164
+ const std::type_info& t = typeid(storage);
165
+ bool ok = t == typeid(IndexFlat) || t == typeid(IndexFlatL2) ||
166
+ t == typeid(IndexFlatIP);
167
+ if (t == typeid(IndexScalarQuantizer)) {
168
+ const auto qt =
169
+ static_cast<const IndexScalarQuantizer&>(storage).sq.qtype;
170
+ ok = qt != ScalarQuantizer::QT_0bit &&
171
+ !ScalarQuantizer::TurboQuantRefine::is_turboq_full(qt);
172
+ }
173
+ ok = ok &&
174
+ (storage.metric_type == METRIC_L2 ||
175
+ storage.metric_type == METRIC_INNER_PRODUCT);
176
+ FAISS_THROW_IF_NOT_FMT(
177
+ ok,
178
+ "IndexPiPNN: unsupported storage %s; use IndexFlat or "
179
+ "IndexScalarQuantizer (not QT_0bit or QT_*bit_tq), L2 or IP",
180
+ demangle_cpp_symbol(t.name()).c_str());
181
+ }
182
+
183
+ IndexPiPNNFlat::IndexPiPNNFlat() = default;
184
+
185
+ IndexPiPNNFlat::IndexPiPNNFlat(int d_in, int R, MetricType metric)
186
+ : IndexPiPNN(new IndexFlat(d_in, metric), R) {
187
+ own_fields = true;
188
+ }
189
+
190
+ IndexPiPNNSQ::IndexPiPNNSQ() = default;
191
+
192
+ IndexPiPNNSQ::IndexPiPNNSQ(
193
+ int d_in,
194
+ ScalarQuantizer::QuantizerType qtype,
195
+ int R,
196
+ MetricType metric)
197
+ : IndexPiPNN(new IndexScalarQuantizer(d_in, qtype, metric), R) {
198
+ own_fields = true;
199
+ }
200
+
201
+ } // namespace faiss
@@ -0,0 +1,83 @@
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 <optional>
11
+
12
+ #include <faiss/Index.h>
13
+ #include <faiss/impl/PiPNN.h>
14
+ #include <faiss/impl/ScalarQuantizer.h>
15
+
16
+ namespace faiss {
17
+
18
+ struct SearchParametersPiPNN : SearchParameters {
19
+ /// beam width L; if 0, pipnn.search_L is used
20
+ int search_L = 0;
21
+ };
22
+
23
+ /** The PiPNN index is a normal random-access index with a PiPNN graph built
24
+ * on top of a flat storage (IndexFlat or IndexScalarQuantizer). */
25
+ struct IndexPiPNN : Index {
26
+ PiPNN pipnn;
27
+ Index* storage = nullptr;
28
+ bool own_fields = false;
29
+ /// if true, add() only appends to storage; call build() afterwards
30
+ bool defer_build = false;
31
+ /// See impl/VisitedTable.h.
32
+ std::optional<bool> use_visited_hashset;
33
+
34
+ IndexPiPNN();
35
+ IndexPiPNN(Index* storage, int R = 64);
36
+
37
+ ~IndexPiPNN() override;
38
+
39
+ void train(idx_t n, const float* x) override;
40
+
41
+ void add(idx_t n, const float* x) override;
42
+
43
+ /// Builds the graph over all vectors in storage.
44
+ void build();
45
+
46
+ bool is_built() const {
47
+ return pipnn.ntotal > 0;
48
+ }
49
+
50
+ void search(
51
+ idx_t n,
52
+ const float* x,
53
+ idx_t k,
54
+ float* distances,
55
+ idx_t* labels,
56
+ const SearchParameters* params = nullptr) const override;
57
+
58
+ void reconstruct(idx_t key, float* recons) const override;
59
+
60
+ /// Empties storage (whatever own_fields says) and drops the graph.
61
+ void reset() override;
62
+
63
+ /// Throws unless IndexPiPNN supports the type and metric of `storage`.
64
+ static void check_storage_supported(const Index& storage);
65
+ };
66
+
67
+ /// IndexPiPNN over an owned IndexFlat.
68
+ struct IndexPiPNNFlat : IndexPiPNN {
69
+ IndexPiPNNFlat();
70
+ IndexPiPNNFlat(int d, int R, MetricType metric = METRIC_L2);
71
+ };
72
+
73
+ /// IndexPiPNN over an owned IndexScalarQuantizer.
74
+ struct IndexPiPNNSQ : IndexPiPNN {
75
+ IndexPiPNNSQ();
76
+ IndexPiPNNSQ(
77
+ int d,
78
+ ScalarQuantizer::QuantizerType qtype,
79
+ int R,
80
+ MetricType metric = METRIC_L2);
81
+ };
82
+
83
+ } // namespace faiss
@@ -512,7 +512,8 @@ void IndexRaBitQFastScan::search(
512
512
  float* distances,
513
513
  idx_t* labels,
514
514
  const SearchParameters* params) const {
515
- FAISS_THROW_IF_MSG(params, "search params not supported for this index");
515
+ // The kernel applies the selector after each SIMD block.
516
+ const IDSelector* rabitq_sel = params ? params->sel : nullptr;
516
517
 
517
518
  // Create query factors array on stack - memory managed by caller
518
519
  std::vector<rabitq_utils::QueryFactorsData> query_factors_storage(n);
@@ -523,9 +524,11 @@ void IndexRaBitQFastScan::search(
523
524
  FastScanDistancePostProcessing context;
524
525
  context.query_factors = query_factors_storage.data();
525
526
  if (metric_type == METRIC_L2) {
526
- search_dispatch_implem<true>(n, x, k, distances, labels, context);
527
+ search_dispatch_implem<true>(
528
+ n, x, k, distances, labels, context, rabitq_sel);
527
529
  } else {
528
- search_dispatch_implem<false>(n, x, k, distances, labels, context);
530
+ search_dispatch_implem<false>(
531
+ n, x, k, distances, labels, context, rabitq_sel);
529
532
  }
530
533
  }
531
534
 
@@ -195,10 +195,12 @@ struct RaBitQHeapHandler
195
195
  float* const heap_dis = heap_distances + q * k;
196
196
  int64_t* const heap_ids = heap_labels + q * k;
197
197
 
198
- rabitq_utils::QueryFactorsData query_factors_data = {};
199
- if (context && context->query_factors != nullptr) {
200
- query_factors_data = context->query_factors[q];
201
- }
198
+ // Not a copy: QueryFactorsData owns a std::vector (malloc per block).
199
+ static const rabitq_utils::QueryFactorsData kNoQueryFactors{};
200
+ const rabitq_utils::QueryFactorsData& query_factors_data =
201
+ (context && context->query_factors != nullptr)
202
+ ? context->query_factors[q]
203
+ : kNoQueryFactors;
202
204
 
203
205
  const float one_a = normalizers ? (1.0f / normalizers[2 * q]) : 1.0f;
204
206
  const float bias = normalizers ? normalizers[2 * q + 1] : 0.0f;
@@ -218,6 +220,10 @@ struct RaBitQHeapHandler
218
220
 
219
221
  for (size_t i = 0; i < max_vectors; i++) {
220
222
  const size_t db_idx = base_db_idx + i;
223
+ if (this->sel != nullptr &&
224
+ !this->sel->is_member(static_cast<int64_t>(db_idx))) {
225
+ continue;
226
+ }
221
227
  const float normalized_distance = d32tab[i] * one_a + bias;
222
228
  const uint8_t* base_ptr = aux_base + i * storage_size;
223
229
 
@@ -111,6 +111,26 @@ void IndexReplicasTemplate<IndexT>::add(idx_t n, const component_t* x) {
111
111
  syncWithSubIndexes();
112
112
  }
113
113
 
114
+ template <typename IndexT>
115
+ void IndexReplicasTemplate<IndexT>::add_with_ids(
116
+ idx_t n,
117
+ const component_t* x,
118
+ const idx_t* xids) {
119
+ this->runOnIndex([n, x, xids](int, IndexT* index) {
120
+ index->add_with_ids(n, x, xids);
121
+ });
122
+ syncWithSubIndexes();
123
+ }
124
+
125
+ template <typename IndexT>
126
+ size_t IndexReplicasTemplate<IndexT>::remove_ids(const IDSelector& sel) {
127
+ const idx_t before = this->ntotal;
128
+ this->runOnIndex([&sel](int, IndexT* index) { index->remove_ids(sel); });
129
+ // Throws when the replicas removed different counts.
130
+ syncWithSubIndexes();
131
+ return before - this->ntotal;
132
+ }
133
+
114
134
  template <typename IndexT>
115
135
  void IndexReplicasTemplate<IndexT>::reconstruct(idx_t n, component_t* x) const {
116
136
  FAISS_THROW_IF_NOT_MSG(this->count() > 0, "no replicas in index");
@@ -56,6 +56,15 @@ class IndexReplicasTemplate : public ThreadedIndex<IndexT> {
56
56
  /// All indices receive the same call
57
57
  void add(idx_t n, const component_t* x) override;
58
58
 
59
+ /// faiss::Index API
60
+ /// All indices receive the same call
61
+ void add_with_ids(idx_t n, const component_t* x, const idx_t* xids)
62
+ override;
63
+
64
+ /// faiss::Index API
65
+ /// All indices receive the same call
66
+ size_t remove_ids(const IDSelector& sel) override;
67
+
59
68
  /// faiss::Index API
60
69
  /// Query is partitioned into a slice for each sub-index
61
70
  /// split by ceil(n / #indices) for our sub-indices