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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a22f4ad8f3c626f1d6571c4cefcb8292965e52eb3b0b77c354f39ed117570c5
4
- data.tar.gz: b848af534bebc2ecfdfa5fe7eaa270b530d17d5fe5381aea350451aa03c22d9f
3
+ metadata.gz: f7ff5a38fc140c730f7dfca4bbbfa2e2e4980fd63bf9f069ebbb9eb8deb4d50c
4
+ data.tar.gz: 919723a22c26f62267c9be7e34250ef7a30a5da682679634dd64471eef5187c4
5
5
  SHA512:
6
- metadata.gz: 4c5083b9733f589fc30c93f429ed4da74fbb4bbdbe2bde17787506cafb178e2715d114e04ed17bd21a1161a096df66a0c502ae6dc245455c1e221737e80a1f3e
7
- data.tar.gz: 41eb8ce7434c4408fccf238893468e8c808b1961966a9fc495f960d27ff950d5d6a9cafff18a11e14287f5fedc77f83db9118c47c60e06fdc9f86d9987592c7c
6
+ metadata.gz: 28e32877ea44804c5f73fcae9b8df462a024c56198156c0928a7ac2405d8cb4263e266bcc1fba2f88c41e3d62ba626fc55a4a228fe06e2d4e24421bb6e02b61b
7
+ data.tar.gz: 56cfa780d1d5361e3b43937c1b392a26528e4f3bd8166b0945c9cda63b32942e7001b7703e5705ba158a70ed92da69ef6983d1bbacd94362a9167403874aeb1e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.6.5 (2026-11-10)
2
+
3
+ - Updated Faiss to 1.16.0
4
+
1
5
  ## 0.6.4 (2026-09-17)
2
6
 
3
7
  - Updated Faiss to 1.15.1
data/ext/faiss/extconf.rb CHANGED
@@ -33,7 +33,7 @@ ext = File.expand_path(".", __dir__)
33
33
  vendor = File.expand_path("../../vendor/faiss", __dir__)
34
34
 
35
35
  $srcs = Dir["{#{ext},#{vendor}/faiss,#{vendor}/faiss/{impl,invlists,utils}/**}/*.{cpp}"]
36
- $srcs -= ["avx2", "avx512", "aarch64", "arm_sve"].map { |v| "#{vendor}/faiss/utils/simd_impl/distances_#{v}.cpp" }
36
+ $srcs.reject! { |v| v.match?(/avx2|avx512|neon|sve|rvv|simdlib_based|distances_aarch64/) }
37
37
  $objs = $srcs.map { |v| v.sub(/cpp\z/, "o") }
38
38
  abort "Faiss not found" unless find_header("faiss/Index.h", vendor)
39
39
  $VPATH << vendor
data/lib/faiss/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Faiss
2
- VERSION = "0.6.4"
2
+ VERSION = "0.6.5"
3
3
  end
@@ -14,6 +14,7 @@
14
14
  #include <faiss/AutoTune.h>
15
15
 
16
16
  #include <cinttypes>
17
+ #include <cmath>
17
18
 
18
19
  #include <faiss/impl/FaissAssert.h>
19
20
  #include <faiss/utils/random.h>
@@ -31,6 +32,11 @@
31
32
  #include <faiss/IndexRefine.h>
32
33
  #include <faiss/IndexShardsIVF.h>
33
34
 
35
+ #ifdef FAISS_ENABLE_SVS
36
+ #include <faiss/svs/IndexSVSVamana.h>
37
+ #include <faiss/svs/IndexSVSVamanaLeanVec.h>
38
+ #endif
39
+
34
40
  namespace faiss {
35
41
 
36
42
  AutoTuneCriterion::AutoTuneCriterion(idx_t nq_in, idx_t nnn_in)
@@ -484,6 +490,166 @@ void ParameterSpace::set_index_parameters(
484
490
  });
485
491
  }
486
492
 
493
+ #ifdef FAISS_ENABLE_SVS
494
+
495
+ namespace {
496
+
497
+ size_t svs_size_param(const std::string& name, double val) {
498
+ FAISS_THROW_IF_NOT_FMT(
499
+ std::isfinite(val) && val >= 0,
500
+ "ParameterSpace::set_index_parameter: %s cannot be negative (%g)",
501
+ name.c_str(),
502
+ val);
503
+ FAISS_THROW_IF_NOT_FMT(
504
+ val == std::floor(val),
505
+ "ParameterSpace::set_index_parameter: %s must be an integer (%g)",
506
+ name.c_str(),
507
+ val);
508
+ // The double -> size_t cast below is undefined behavior on overflow.
509
+ // 2^(8*sizeof(size_t)) is exact in double, so a value below it always
510
+ // fits.
511
+ FAISS_THROW_IF_NOT_FMT(
512
+ val < std::ldexp(1.0, static_cast<int>(8 * sizeof(size_t))),
513
+ "ParameterSpace::set_index_parameter: %s is too large (%g)",
514
+ name.c_str(),
515
+ val);
516
+ return size_t(val);
517
+ }
518
+
519
+ /* Checks to make sure ix->impl is null. The SVS build parameters are consumed
520
+ when the backend index is created on the first add() (ix->impl != nullptr
521
+ afterwards), so setting them later would be silently ignored. For LeanVec,
522
+ train() only builds training_data (consuming leanvec_d); the remaining build
523
+ parameters are still consumed at the first add(), hence remain settable after
524
+ train() but before add(). */
525
+ void check_svs_not_built(const IndexSVSVamana* ix, const std::string& name) {
526
+ FAISS_THROW_IF_NOT_FMT(
527
+ ix->impl == nullptr,
528
+ "ParameterSpace::set_index_parameter: %s is a build-time "
529
+ "parameter, it cannot be changed after the SVS index is built",
530
+ name.c_str());
531
+ }
532
+
533
+ /* Sets a parameter of IndexSVSVamana or of its LVQ / LeanVec subclasses.
534
+ Returns false if the name is not an SVS Vamana parameter. */
535
+ bool set_svs_vamana_parameter(
536
+ IndexSVSVamana* ix,
537
+ const std::string& name,
538
+ double val) {
539
+ // Search parameters: re-read on every search(), hence tunable at any point
540
+ // in the index lifetime.
541
+ if (name == "search_window_size") {
542
+ ix->search_window_size = svs_size_param(name, val);
543
+ return true;
544
+ }
545
+ if (name == "search_buffer_capacity") {
546
+ ix->search_buffer_capacity = svs_size_param(name, val);
547
+ return true;
548
+ }
549
+
550
+ // Graph build parameters.
551
+ if (name == "graph_max_degree") {
552
+ check_svs_not_built(ix, name);
553
+ ix->graph_max_degree = svs_size_param(name, val);
554
+ return true;
555
+ }
556
+ if (name == "prune_to") {
557
+ check_svs_not_built(ix, name);
558
+ ix->prune_to = svs_size_param(name, val);
559
+ return true;
560
+ }
561
+ if (name == "alpha") {
562
+ check_svs_not_built(ix, name);
563
+ ix->alpha = float(val);
564
+ return true;
565
+ }
566
+ if (name == "construction_window_size") {
567
+ check_svs_not_built(ix, name);
568
+ ix->construction_window_size = svs_size_param(name, val);
569
+ return true;
570
+ }
571
+ if (name == "max_candidate_pool_size") {
572
+ check_svs_not_built(ix, name);
573
+ ix->max_candidate_pool_size = svs_size_param(name, val);
574
+ return true;
575
+ }
576
+ if (name == "use_full_search_history") {
577
+ check_svs_not_built(ix, name);
578
+ ix->use_full_search_history = val != 0;
579
+ return true;
580
+ }
581
+
582
+ // Vector storage, which includes the LVQ and LeanVec compression levels.
583
+ if (name == "storage_kind") {
584
+ check_svs_not_built(ix, name);
585
+ size_t kind_idx = svs_size_param(name, val);
586
+ FAISS_THROW_IF_NOT_FMT(
587
+ kind_idx < static_cast<size_t>(SVS_count),
588
+ "ParameterSpace::set_index_parameter: %g is not a valid "
589
+ "SVSStorageKind",
590
+ val);
591
+ auto kind = static_cast<SVSStorageKind>(kind_idx);
592
+ // Reject a kind that this build or machine does not support here
593
+ // rather than at build time, like the IndexSVSVamana constructor does.
594
+ // Both backends are accepted because storage_kind and is_static are
595
+ // build-time parameters that can be set in any order; the backend
596
+ // selected by is_static re-checks the kind at build time.
597
+ auto svs_kind = to_svs_storage_kind(kind);
598
+ auto status_static =
599
+ svs_runtime::VamanaIndex::check_storage_kind(svs_kind);
600
+ auto status_dynamic =
601
+ svs_runtime::DynamicVamanaIndex::check_storage_kind(svs_kind);
602
+ if (!status_static.ok() && !status_dynamic.ok()) {
603
+ FAISS_THROW_FMT(
604
+ "ParameterSpace::set_index_parameter: %s value %g is not "
605
+ "supported (static: %s; dynamic: %s)",
606
+ name.c_str(),
607
+ val,
608
+ status_static.message(),
609
+ status_dynamic.message());
610
+ }
611
+ ix->storage_kind = kind;
612
+ return true;
613
+ }
614
+ if (name == "is_static") {
615
+ check_svs_not_built(ix, name);
616
+ ix->is_static = val != 0;
617
+ return true;
618
+ }
619
+ if (name == "store_vectors") {
620
+ // Dropping the copy of the added vectors is always possible, but it
621
+ // cannot be undone: the copy left would not line up with the ids.
622
+ FAISS_THROW_IF_MSG(
623
+ val != 0 && !ix->stored_vectors_valid,
624
+ "ParameterSpace::set_index_parameter: store_vectors cannot be "
625
+ "re-enabled once the stored vectors have been dropped");
626
+ ix->store_vectors = val != 0;
627
+ return true;
628
+ }
629
+
630
+ // LeanVec only: dimensionality of the reduced (primary) vectors.
631
+ if (name == "leanvec_d") {
632
+ auto* lv = dynamic_cast<IndexSVSVamanaLeanVec*>(ix);
633
+ FAISS_THROW_IF_NOT_MSG(
634
+ lv,
635
+ "ParameterSpace::set_index_parameter: leanvec_d only applies "
636
+ "to IndexSVSVamanaLeanVec");
637
+ check_svs_not_built(lv, name);
638
+ FAISS_THROW_IF_MSG(
639
+ lv->training_data,
640
+ "ParameterSpace::set_index_parameter: leanvec_d cannot be "
641
+ "changed after the LeanVec index has been trained");
642
+ lv->leanvec_d = svs_size_param(name, val);
643
+ return true;
644
+ }
645
+
646
+ return false;
647
+ }
648
+
649
+ } // anonymous namespace
650
+
651
+ #endif // FAISS_ENABLE_SVS
652
+
487
653
  // non-const version
488
654
  // Do not use this macro if ix will be unused
489
655
  #define DC(classname) classname* ix_ = dynamic_cast<classname*>(index)
@@ -613,6 +779,15 @@ void ParameterSpace::set_index_parameter(
613
779
  }
614
780
  }
615
781
 
782
+ #ifdef FAISS_ENABLE_SVS
783
+ // Covers IndexSVSVamanaLVQ and IndexSVSVamanaLeanVec as well
784
+ if (DC(IndexSVSVamana)) {
785
+ if (set_svs_vamana_parameter(ix_, name, val)) {
786
+ return;
787
+ }
788
+ }
789
+ #endif
790
+
616
791
  if (name.find("quantizer_") == 0) {
617
792
  if (DC(IndexIVF)) {
618
793
  std::string sub_name = name.substr(strlen("quantizer_"));
@@ -11,6 +11,7 @@
11
11
  #include <faiss/VectorTransform.h>
12
12
  #include <faiss/impl/AuxIndexStructures.h>
13
13
 
14
+ #include <algorithm>
14
15
  #include <cinttypes>
15
16
  #include <cmath>
16
17
  #include <cstdio>
@@ -63,6 +64,47 @@ void Clustering::train_encoded(
63
64
  const Index* codec,
64
65
  Index& index,
65
66
  const float* weights) {
67
+ train_impl(nx, x_in, codec, NumericType::Float32, index, weights);
68
+ }
69
+
70
+ void Clustering::train_ex(
71
+ idx_t nx,
72
+ const void* x_in,
73
+ NumericType numeric_type,
74
+ Index& index,
75
+ const float* weights) {
76
+ if (numeric_type == NumericType::Float32) {
77
+ train(nx, static_cast<const float*>(x_in), index, weights);
78
+ return;
79
+ }
80
+ FAISS_THROW_IF_NOT_MSG(
81
+ numeric_type == NumericType::Float16,
82
+ "Clustering::train_ex: unsupported numeric type");
83
+ train_impl(
84
+ nx,
85
+ static_cast<const uint8_t*>(x_in),
86
+ nullptr,
87
+ numeric_type,
88
+ index,
89
+ weights);
90
+ }
91
+
92
+ void Clustering::train_impl(
93
+ idx_t nx,
94
+ const uint8_t* x_in,
95
+ const Index* codec,
96
+ NumericType numeric_type,
97
+ Index& index,
98
+ const float* weights) {
99
+ FAISS_THROW_IF_NOT_MSG(
100
+ codec || numeric_type == NumericType::Float32 ||
101
+ numeric_type == NumericType::Float16,
102
+ "unsupported numeric type for clustering");
103
+ // packed IEEE binary16 rows, consumed without a codec
104
+ const bool fp16 = !codec && numeric_type == NumericType::Float16;
105
+ // rows that are not fp32 are widened by blocks for the assignment index
106
+ const bool encoded = codec || fp16;
107
+
66
108
  FAISS_THROW_IF_NOT_FMT(
67
109
  nx >= static_cast<idx_t>(k),
68
110
  "Number of training points (%" PRId64
@@ -70,6 +112,7 @@ void Clustering::train_encoded(
70
112
  "as large as number of clusters (%zd)",
71
113
  nx,
72
114
  k);
115
+ FAISS_THROW_IF_NOT_MSG(x_in, "training data must not be null");
73
116
 
74
117
  FAISS_THROW_IF_NOT_FMT(
75
118
  (!codec || static_cast<size_t>(codec->d) == d),
@@ -83,23 +126,46 @@ void Clustering::train_encoded(
83
126
  int(index.d),
84
127
  int(d));
85
128
 
129
+ FAISS_THROW_IF_NOT_MSG(
130
+ !encoded || decode_block_size > 0,
131
+ "decode_block_size must be positive");
132
+
86
133
  double t0 = getmillisecs();
87
134
 
88
135
  if (!codec && check_input_data_for_NaNs) {
89
136
  // Check for NaNs in input data. Normally it is the user's
90
- // responsibility, but it may spare us some hard-to-debug
91
- // reports.
92
- const float* x = reinterpret_cast<const float*>(x_in);
93
- for (size_t i = 0; i < nx * d; i++) {
137
+ // responsibility, but it may spare us some hard-to-debug reports.
138
+ if (fp16) {
94
139
  FAISS_THROW_IF_NOT_MSG(
95
- std::isfinite(x[i]), "input contains NaN's or Inf's");
140
+ detail::fp16_all_finite(
141
+ nx * d, reinterpret_cast<const uint16_t*>(x_in)),
142
+ "input contains NaN's or Inf's");
143
+ } else {
144
+ const float* x = reinterpret_cast<const float*>(x_in);
145
+ for (size_t i = 0; i < nx * d; i++) {
146
+ FAISS_THROW_IF_NOT_MSG(
147
+ std::isfinite(x[i]), "input contains NaN's or Inf's");
148
+ }
96
149
  }
97
150
  }
98
151
 
99
152
  const uint8_t* x = x_in;
100
153
  std::unique_ptr<uint8_t[]> del1;
101
154
  std::unique_ptr<float[]> del3;
102
- size_t line_size = codec ? codec->sa_code_size() : sizeof(float) * d;
155
+ size_t line_size = codec ? codec->sa_code_size()
156
+ : fp16 ? sizeof(uint16_t) * d
157
+ : sizeof(float) * d;
158
+
159
+ // widen n consecutive training rows to fp32
160
+ auto decode_rows = [&](size_t n, const uint8_t* rows, float* out) {
161
+ if (codec) {
162
+ codec->sa_decode(n, rows, out);
163
+ } else if (fp16) {
164
+ fp16_to_fp32(n * d, reinterpret_cast<const uint16_t*>(rows), out);
165
+ } else {
166
+ memcpy(out, rows, n * line_size);
167
+ }
168
+ };
103
169
 
104
170
  if (static_cast<size_t>(nx) > k * max_points_per_centroid) {
105
171
  uint8_t* x_new;
@@ -129,11 +195,7 @@ void Clustering::train_encoded(
129
195
  nx);
130
196
  }
131
197
  centroids.resize(d * k);
132
- if (!codec) {
133
- memcpy(centroids.data(), x_in, sizeof(float) * d * k);
134
- } else {
135
- codec->sa_decode(nx, x_in, centroids.data());
136
- }
198
+ decode_rows(k, x_in, centroids.data());
137
199
 
138
200
  // one fake iteration...
139
201
  ClusteringIterationStats stats = {0.0, 0.0, 0.0, 1.0, 0};
@@ -153,9 +215,8 @@ void Clustering::train_encoded(
153
215
  k,
154
216
  nredo,
155
217
  niter);
156
- if (codec) {
157
- printf("Input data encoded in %zd bytes per vector\n",
158
- codec->sa_code_size());
218
+ if (encoded) {
219
+ printf("Input data encoded in %zd bytes per vector\n", line_size);
159
220
  }
160
221
  }
161
222
 
@@ -191,8 +252,10 @@ void Clustering::train_encoded(
191
252
  // initialize seed
192
253
  const uint64_t actual_seed = detail::get_actual_rng_seed(seed);
193
254
 
194
- // temporary buffer to decode vectors during the optimization
195
- std::vector<float> decode_buffer(codec ? d * decode_block_size : 0);
255
+ // temporary buffer to decode codec-encoded vectors during the optimization
256
+ std::vector<float> decode_buffer(
257
+ codec ? d * std::min(static_cast<size_t>(nx), decode_block_size)
258
+ : 0);
196
259
 
197
260
  for (int redo = 0; redo < nredo; redo++) {
198
261
  if (verbose && nredo > 1) {
@@ -210,41 +273,44 @@ void Clustering::train_encoded(
210
273
  std::vector<int> perm(nx);
211
274
  rand_perm(perm.data(), nx, actual_seed + 1 + redo * 15486557L);
212
275
  for (size_t i = 0; i < k_to_init; i++) {
213
- if (!codec) {
214
- memcpy(centroids.data() + (n_input_centroids + i) * d,
215
- x + perm[n_input_centroids + i] * line_size,
216
- line_size);
217
- } else {
218
- codec->sa_decode(
219
- 1,
220
- x + perm[n_input_centroids + i] * line_size,
221
- centroids.data() + (n_input_centroids + i) * d);
222
- }
276
+ decode_rows(
277
+ 1,
278
+ x + perm[n_input_centroids + i] * line_size,
279
+ centroids.data() + (n_input_centroids + i) * d);
223
280
  }
224
281
  } else {
225
- // For k-means++ and AFK-MC², we need all vectors decoded
226
- const float* x_float = nullptr;
227
- std::vector<float> x_decoded;
228
-
229
- if (!codec) {
230
- x_float = reinterpret_cast<const float*>(x);
231
- } else {
232
- // Decode all vectors for initialization
233
- x_decoded.resize(nx * d);
234
- codec->sa_decode(nx, x, x_decoded.data());
235
- x_float = x_decoded.data();
236
- }
237
-
238
282
  ClusteringInitialization initializer(d, k_to_init);
239
283
  initializer.method = init_method;
240
284
  initializer.seed = actual_seed + 1 + redo * 15486557L;
241
285
  initializer.afkmc2_chain_length = afkmc2_chain_length;
242
- initializer.init_centroids(
243
- nx,
244
- x_float,
245
- centroids.data() + n_input_centroids * d,
246
- n_input_centroids,
247
- n_input_centroids > 0 ? centroids.data() : nullptr);
286
+
287
+ if (fp16) {
288
+ detail::init_centroids_fp16(
289
+ initializer,
290
+ nx,
291
+ reinterpret_cast<const uint16_t*>(x),
292
+ centroids.data() + n_input_centroids * d,
293
+ n_input_centroids,
294
+ n_input_centroids > 0 ? centroids.data() : nullptr);
295
+ } else {
296
+ const float* x_float = nullptr;
297
+ std::vector<float> x_decoded;
298
+
299
+ if (!encoded) {
300
+ x_float = reinterpret_cast<const float*>(x);
301
+ } else {
302
+ x_decoded.resize(nx * d);
303
+ decode_rows(nx, x, x_decoded.data());
304
+ x_float = x_decoded.data();
305
+ }
306
+
307
+ initializer.init_centroids(
308
+ nx,
309
+ x_float,
310
+ centroids.data() + n_input_centroids * d,
311
+ n_input_centroids,
312
+ n_input_centroids > 0 ? centroids.data() : nullptr);
313
+ }
248
314
  }
249
315
  }
250
316
 
@@ -268,7 +334,7 @@ void Clustering::train_encoded(
268
334
  for (int i = 0; i < niter; i++) {
269
335
  double t0s = getmillisecs();
270
336
 
271
- if (!codec) {
337
+ if (!encoded) {
272
338
  index.search(
273
339
  nx,
274
340
  reinterpret_cast<const float*>(x),
@@ -277,15 +343,26 @@ void Clustering::train_encoded(
277
343
  assign.get());
278
344
  } else {
279
345
  // search by blocks of decode_block_size vectors
280
- size_t code_size = codec->sa_code_size();
281
346
  for (size_t i0 = 0; i0 < static_cast<size_t>(nx);
282
347
  i0 += decode_block_size) {
283
348
  size_t i1 = i0 + decode_block_size;
284
349
  if (i1 > static_cast<size_t>(nx)) {
285
350
  i1 = nx;
286
351
  }
287
- codec->sa_decode(
288
- i1 - i0, x + code_size * i0, decode_buffer.data());
352
+ if (fp16) {
353
+ // the index consumes fp16 queries itself (natively
354
+ // if it can, see Index::search_ex)
355
+ index.search_ex(
356
+ i1 - i0,
357
+ x + line_size * i0,
358
+ NumericType::Float16,
359
+ 1,
360
+ dis.get() + i0,
361
+ assign.get() + i0);
362
+ continue;
363
+ }
364
+ decode_rows(
365
+ i1 - i0, x + line_size * i0, decode_buffer.data());
289
366
  index.search(
290
367
  i1 - i0,
291
368
  decode_buffer.data(),
@@ -308,17 +385,30 @@ void Clustering::train_encoded(
308
385
  std::vector<float> hassign(k);
309
386
 
310
387
  size_t k_frozen = frozen_centroids ? n_input_centroids : 0;
311
- detail::compute_centroids(
312
- d,
313
- k,
314
- nx,
315
- k_frozen,
316
- x,
317
- codec,
318
- assign.get(),
319
- weights,
320
- hassign.data(),
321
- centroids.data());
388
+ if (fp16) {
389
+ detail::compute_centroids_fp16(
390
+ d,
391
+ k,
392
+ nx,
393
+ k_frozen,
394
+ reinterpret_cast<const uint16_t*>(x),
395
+ assign.get(),
396
+ weights,
397
+ hassign.data(),
398
+ centroids.data());
399
+ } else {
400
+ detail::compute_centroids(
401
+ d,
402
+ k,
403
+ nx,
404
+ k_frozen,
405
+ x,
406
+ codec,
407
+ assign.get(),
408
+ weights,
409
+ hassign.data(),
410
+ centroids.data());
411
+ }
322
412
 
323
413
  int nsplit = detail::split_clusters(
324
414
  d, k, nx, k_frozen, hassign.data(), centroids.data());
@@ -148,11 +148,40 @@ struct Clustering : ClusteringParameters {
148
148
  Index& index,
149
149
  const float* weights = nullptr);
150
150
 
151
+ /** run k-means on vectors of the given numeric type
152
+ *
153
+ * Float32 is the same as train(). Float16 takes packed IEEE binary16
154
+ * vectors (n * d uint16_t) and runs k-means natively on them: the NaN
155
+ * check, subsampling, initialization and centroid updates read the fp16
156
+ * rows directly, and the assignment step passes blocks of at most
157
+ * decode_block_size fp16 rows to index.search_ex(Float16). Indexes with a
158
+ * native fp16 search consume them directly; the Index::search_ex default
159
+ * widens them block by block. There is no fp32 copy of the training set,
160
+ * unless init_method needs one. Centroids are fp32.
161
+ */
162
+ void train_ex(
163
+ idx_t n,
164
+ const void* x,
165
+ NumericType numeric_type,
166
+ Index& index,
167
+ const float* weights = nullptr);
168
+
151
169
  /// Post-process the centroids after each centroid update.
152
170
  /// includes optional L2 normalization and nearest integer rounding
153
171
  void post_process_centroids();
154
172
 
155
173
  virtual ~Clustering() {}
174
+
175
+ protected:
176
+ /// k-means on rows encoded by `codec` or, if codec is null, stored as
177
+ /// `numeric_type` (Float32 or Float16)
178
+ void train_impl(
179
+ idx_t nx,
180
+ const uint8_t* x_in,
181
+ const Index* codec,
182
+ NumericType numeric_type,
183
+ Index& index,
184
+ const float* weights);
156
185
  };
157
186
 
158
187
  /** Exact 1D clustering algorithm