faiss 0.2.4 → 0.2.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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +23 -21
  4. data/ext/faiss/extconf.rb +11 -0
  5. data/ext/faiss/index.cpp +4 -4
  6. data/ext/faiss/index_binary.cpp +6 -6
  7. data/ext/faiss/product_quantizer.cpp +4 -4
  8. data/lib/faiss/version.rb +1 -1
  9. data/vendor/faiss/faiss/AutoTune.cpp +13 -0
  10. data/vendor/faiss/faiss/IVFlib.cpp +101 -2
  11. data/vendor/faiss/faiss/IVFlib.h +26 -2
  12. data/vendor/faiss/faiss/Index.cpp +36 -3
  13. data/vendor/faiss/faiss/Index.h +43 -6
  14. data/vendor/faiss/faiss/Index2Layer.cpp +6 -2
  15. data/vendor/faiss/faiss/Index2Layer.h +6 -1
  16. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +219 -16
  17. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +63 -5
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +299 -0
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +199 -0
  20. data/vendor/faiss/faiss/IndexBinary.cpp +20 -4
  21. data/vendor/faiss/faiss/IndexBinary.h +18 -3
  22. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -2
  23. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -2
  24. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -1
  25. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +2 -1
  26. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
  27. data/vendor/faiss/faiss/IndexBinaryHNSW.h +2 -1
  28. data/vendor/faiss/faiss/IndexBinaryHash.cpp +17 -4
  29. data/vendor/faiss/faiss/IndexBinaryHash.h +8 -4
  30. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +28 -13
  31. data/vendor/faiss/faiss/IndexBinaryIVF.h +10 -7
  32. data/vendor/faiss/faiss/IndexFastScan.cpp +626 -0
  33. data/vendor/faiss/faiss/IndexFastScan.h +145 -0
  34. data/vendor/faiss/faiss/IndexFlat.cpp +34 -21
  35. data/vendor/faiss/faiss/IndexFlat.h +7 -4
  36. data/vendor/faiss/faiss/IndexFlatCodes.cpp +35 -1
  37. data/vendor/faiss/faiss/IndexFlatCodes.h +12 -0
  38. data/vendor/faiss/faiss/IndexHNSW.cpp +66 -138
  39. data/vendor/faiss/faiss/IndexHNSW.h +4 -2
  40. data/vendor/faiss/faiss/IndexIDMap.cpp +247 -0
  41. data/vendor/faiss/faiss/IndexIDMap.h +107 -0
  42. data/vendor/faiss/faiss/IndexIVF.cpp +121 -33
  43. data/vendor/faiss/faiss/IndexIVF.h +35 -16
  44. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +84 -7
  45. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +63 -1
  46. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +590 -0
  47. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +171 -0
  48. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +1290 -0
  49. data/vendor/faiss/faiss/IndexIVFFastScan.h +213 -0
  50. data/vendor/faiss/faiss/IndexIVFFlat.cpp +37 -17
  51. data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
  52. data/vendor/faiss/faiss/IndexIVFPQ.cpp +234 -50
  53. data/vendor/faiss/faiss/IndexIVFPQ.h +5 -1
  54. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +23 -852
  55. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -112
  56. data/vendor/faiss/faiss/IndexIVFPQR.cpp +3 -3
  57. data/vendor/faiss/faiss/IndexIVFPQR.h +1 -1
  58. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +3 -1
  59. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +2 -1
  60. data/vendor/faiss/faiss/IndexLSH.cpp +4 -2
  61. data/vendor/faiss/faiss/IndexLSH.h +2 -1
  62. data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
  63. data/vendor/faiss/faiss/IndexLattice.h +3 -1
  64. data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -3
  65. data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
  66. data/vendor/faiss/faiss/IndexNSG.cpp +37 -3
  67. data/vendor/faiss/faiss/IndexNSG.h +25 -1
  68. data/vendor/faiss/faiss/IndexPQ.cpp +106 -69
  69. data/vendor/faiss/faiss/IndexPQ.h +19 -5
  70. data/vendor/faiss/faiss/IndexPQFastScan.cpp +15 -450
  71. data/vendor/faiss/faiss/IndexPQFastScan.h +15 -78
  72. data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -8
  73. data/vendor/faiss/faiss/IndexPreTransform.h +15 -3
  74. data/vendor/faiss/faiss/IndexRefine.cpp +8 -4
  75. data/vendor/faiss/faiss/IndexRefine.h +4 -2
  76. data/vendor/faiss/faiss/IndexReplicas.cpp +4 -2
  77. data/vendor/faiss/faiss/IndexReplicas.h +2 -1
  78. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +438 -0
  79. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +92 -0
  80. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +26 -15
  81. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -7
  82. data/vendor/faiss/faiss/IndexShards.cpp +4 -1
  83. data/vendor/faiss/faiss/IndexShards.h +2 -1
  84. data/vendor/faiss/faiss/MetaIndexes.cpp +5 -178
  85. data/vendor/faiss/faiss/MetaIndexes.h +3 -81
  86. data/vendor/faiss/faiss/VectorTransform.cpp +43 -0
  87. data/vendor/faiss/faiss/VectorTransform.h +22 -4
  88. data/vendor/faiss/faiss/clone_index.cpp +23 -1
  89. data/vendor/faiss/faiss/clone_index.h +3 -0
  90. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +300 -0
  91. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +24 -0
  92. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +195 -0
  93. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +2058 -0
  94. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +408 -0
  95. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +2147 -0
  96. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +460 -0
  97. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +465 -0
  98. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +1618 -0
  99. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +251 -0
  100. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +1452 -0
  101. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +1 -0
  102. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +0 -4
  103. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  104. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +2 -1
  105. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +10 -8
  106. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +75 -14
  107. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +19 -32
  108. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -31
  109. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +22 -28
  110. data/vendor/faiss/faiss/gpu/GpuResources.cpp +14 -0
  111. data/vendor/faiss/faiss/gpu/GpuResources.h +16 -3
  112. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +3 -3
  113. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +32 -0
  114. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +1 -0
  115. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +311 -75
  116. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +10 -0
  117. data/vendor/faiss/faiss/gpu/test/TestUtils.h +3 -0
  118. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +2 -2
  119. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +5 -4
  120. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +116 -47
  121. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +44 -13
  122. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +0 -54
  123. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -76
  124. data/vendor/faiss/faiss/impl/DistanceComputer.h +64 -0
  125. data/vendor/faiss/faiss/impl/HNSW.cpp +123 -27
  126. data/vendor/faiss/faiss/impl/HNSW.h +19 -16
  127. data/vendor/faiss/faiss/impl/IDSelector.cpp +125 -0
  128. data/vendor/faiss/faiss/impl/IDSelector.h +135 -0
  129. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -28
  130. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +6 -1
  131. data/vendor/faiss/faiss/impl/LookupTableScaler.h +77 -0
  132. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -0
  133. data/vendor/faiss/faiss/impl/NSG.cpp +1 -1
  134. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +383 -0
  135. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +154 -0
  136. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +225 -145
  137. data/vendor/faiss/faiss/impl/ProductQuantizer.h +29 -10
  138. data/vendor/faiss/faiss/impl/Quantizer.h +43 -0
  139. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +192 -36
  140. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +40 -20
  141. data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
  142. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +97 -173
  143. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
  144. data/vendor/faiss/faiss/impl/index_read.cpp +240 -9
  145. data/vendor/faiss/faiss/impl/index_write.cpp +237 -5
  146. data/vendor/faiss/faiss/impl/kmeans1d.cpp +6 -4
  147. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +56 -16
  148. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +25 -8
  149. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +66 -25
  150. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +75 -27
  151. data/vendor/faiss/faiss/index_factory.cpp +196 -7
  152. data/vendor/faiss/faiss/index_io.h +5 -0
  153. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -0
  154. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +4 -1
  155. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +2 -1
  156. data/vendor/faiss/faiss/python/python_callbacks.cpp +27 -0
  157. data/vendor/faiss/faiss/python/python_callbacks.h +15 -0
  158. data/vendor/faiss/faiss/utils/Heap.h +31 -15
  159. data/vendor/faiss/faiss/utils/distances.cpp +380 -56
  160. data/vendor/faiss/faiss/utils/distances.h +113 -15
  161. data/vendor/faiss/faiss/utils/distances_simd.cpp +726 -6
  162. data/vendor/faiss/faiss/utils/extra_distances.cpp +12 -7
  163. data/vendor/faiss/faiss/utils/extra_distances.h +3 -1
  164. data/vendor/faiss/faiss/utils/fp16-fp16c.h +21 -0
  165. data/vendor/faiss/faiss/utils/fp16-inl.h +101 -0
  166. data/vendor/faiss/faiss/utils/fp16.h +11 -0
  167. data/vendor/faiss/faiss/utils/hamming-inl.h +54 -0
  168. data/vendor/faiss/faiss/utils/hamming.cpp +0 -48
  169. data/vendor/faiss/faiss/utils/ordered_key_value.h +10 -0
  170. data/vendor/faiss/faiss/utils/quantize_lut.cpp +62 -0
  171. data/vendor/faiss/faiss/utils/quantize_lut.h +20 -0
  172. data/vendor/faiss/faiss/utils/random.cpp +53 -0
  173. data/vendor/faiss/faiss/utils/random.h +5 -0
  174. data/vendor/faiss/faiss/utils/simdlib_avx2.h +4 -0
  175. data/vendor/faiss/faiss/utils/simdlib_emulated.h +6 -1
  176. data/vendor/faiss/faiss/utils/simdlib_neon.h +7 -2
  177. metadata +37 -3
@@ -26,10 +26,12 @@
26
26
 
27
27
  #include <faiss/Index2Layer.h>
28
28
  #include <faiss/IndexAdditiveQuantizer.h>
29
+ #include <faiss/IndexAdditiveQuantizerFastScan.h>
29
30
  #include <faiss/IndexFlat.h>
30
31
  #include <faiss/IndexHNSW.h>
31
32
  #include <faiss/IndexIVF.h>
32
33
  #include <faiss/IndexIVFAdditiveQuantizer.h>
34
+ #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
33
35
  #include <faiss/IndexIVFFlat.h>
34
36
  #include <faiss/IndexIVFPQ.h>
35
37
  #include <faiss/IndexIVFPQFastScan.h>
@@ -37,11 +39,13 @@
37
39
  #include <faiss/IndexIVFSpectralHash.h>
38
40
  #include <faiss/IndexLSH.h>
39
41
  #include <faiss/IndexLattice.h>
42
+ #include <faiss/IndexNNDescent.h>
40
43
  #include <faiss/IndexNSG.h>
41
44
  #include <faiss/IndexPQ.h>
42
45
  #include <faiss/IndexPQFastScan.h>
43
46
  #include <faiss/IndexPreTransform.h>
44
47
  #include <faiss/IndexRefine.h>
48
+ #include <faiss/IndexRowwiseMinMax.h>
45
49
  #include <faiss/IndexScalarQuantizer.h>
46
50
  #include <faiss/MetaIndexes.h>
47
51
  #include <faiss/VectorTransform.h>
@@ -271,9 +275,17 @@ static void read_AdditiveQuantizer(AdditiveQuantizer* aq, IOReader* f) {
271
275
  READ1(aq->norm_min);
272
276
  READ1(aq->norm_max);
273
277
  if (aq->search_type == AdditiveQuantizer::ST_norm_cqint8 ||
274
- aq->search_type == AdditiveQuantizer::ST_norm_cqint4) {
278
+ aq->search_type == AdditiveQuantizer::ST_norm_cqint4 ||
279
+ aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
280
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
275
281
  READXBVECTOR(aq->qnorm.codes);
276
282
  }
283
+
284
+ if (aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
285
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
286
+ READVECTOR(aq->norm_tabs);
287
+ }
288
+
277
289
  aq->set_derived_values();
278
290
  }
279
291
 
@@ -301,6 +313,37 @@ static void read_LocalSearchQuantizer(LocalSearchQuantizer* lsq, IOReader* f) {
301
313
  READ1(lsq->update_codebooks_with_double);
302
314
  }
303
315
 
316
+ static void read_ProductAdditiveQuantizer(
317
+ ProductAdditiveQuantizer* paq,
318
+ IOReader* f) {
319
+ read_AdditiveQuantizer(paq, f);
320
+ READ1(paq->nsplits);
321
+ }
322
+
323
+ static void read_ProductResidualQuantizer(
324
+ ProductResidualQuantizer* prq,
325
+ IOReader* f) {
326
+ read_ProductAdditiveQuantizer(prq, f);
327
+
328
+ for (size_t i = 0; i < prq->nsplits; i++) {
329
+ auto rq = new ResidualQuantizer();
330
+ read_ResidualQuantizer(rq, f);
331
+ prq->quantizers.push_back(rq);
332
+ }
333
+ }
334
+
335
+ static void read_ProductLocalSearchQuantizer(
336
+ ProductLocalSearchQuantizer* plsq,
337
+ IOReader* f) {
338
+ read_ProductAdditiveQuantizer(plsq, f);
339
+
340
+ for (size_t i = 0; i < plsq->nsplits; i++) {
341
+ auto lsq = new LocalSearchQuantizer();
342
+ read_LocalSearchQuantizer(lsq, f);
343
+ plsq->quantizers.push_back(lsq);
344
+ }
345
+ }
346
+
304
347
  static void read_ScalarQuantizer(ScalarQuantizer* ivsc, IOReader* f) {
305
348
  READ1(ivsc->qtype);
306
349
  READ1(ivsc->rangestat);
@@ -361,6 +404,21 @@ static void read_NSG(NSG* nsg, IOReader* f) {
361
404
  }
362
405
  }
363
406
 
407
+ static void read_NNDescent(NNDescent* nnd, IOReader* f) {
408
+ READ1(nnd->ntotal);
409
+ READ1(nnd->d);
410
+ READ1(nnd->K);
411
+ READ1(nnd->S);
412
+ READ1(nnd->R);
413
+ READ1(nnd->L);
414
+ READ1(nnd->iter);
415
+ READ1(nnd->search_L);
416
+ READ1(nnd->random_seed);
417
+ READ1(nnd->has_built);
418
+
419
+ READVECTOR(nnd->final_graph);
420
+ }
421
+
364
422
  ProductQuantizer* read_ProductQuantizer(const char* fname) {
365
423
  FileIOReader reader(fname);
366
424
  return read_ProductQuantizer(&reader);
@@ -444,10 +502,14 @@ static IndexIVFPQ* read_ivfpq(IOReader* f, uint32_t h, int io_flags) {
444
502
  }
445
503
 
446
504
  if (ivpq->is_trained) {
447
- // precomputed table not stored. It is cheaper to recompute it
505
+ // precomputed table not stored. It is cheaper to recompute it.
506
+ // precompute_table() may be disabled with a flag.
448
507
  ivpq->use_precomputed_table = 0;
449
- if (ivpq->by_residual)
450
- ivpq->precompute_table();
508
+ if (ivpq->by_residual) {
509
+ if ((io_flags & IO_FLAG_SKIP_PRECOMPUTE_TABLE) == 0) {
510
+ ivpq->precompute_table();
511
+ }
512
+ }
451
513
  if (ivfpqr) {
452
514
  read_ProductQuantizer(&ivfpqr->refine_pq, f);
453
515
  READVECTOR(ivfpqr->refine_codes);
@@ -549,6 +611,20 @@ Index* read_index(IOReader* f, int io_flags) {
549
611
  READ1(idxr->code_size);
550
612
  READVECTOR(idxr->codes);
551
613
  idx = idxr;
614
+ } else if (h == fourcc("IxPR")) {
615
+ auto idxpr = new IndexProductResidualQuantizer();
616
+ read_index_header(idxpr, f);
617
+ read_ProductResidualQuantizer(&idxpr->prq, f);
618
+ READ1(idxpr->code_size);
619
+ READVECTOR(idxpr->codes);
620
+ idx = idxpr;
621
+ } else if (h == fourcc("IxPL")) {
622
+ auto idxpl = new IndexProductLocalSearchQuantizer();
623
+ read_index_header(idxpl, f);
624
+ read_ProductLocalSearchQuantizer(&idxpl->plsq, f);
625
+ READ1(idxpl->code_size);
626
+ READVECTOR(idxpl->codes);
627
+ idx = idxpl;
552
628
  } else if (h == fourcc("ImRQ")) {
553
629
  ResidualCoarseQuantizer* idxr = new ResidualCoarseQuantizer();
554
630
  read_index_header(idxr, f);
@@ -556,6 +632,103 @@ Index* read_index(IOReader* f, int io_flags) {
556
632
  READ1(idxr->beam_factor);
557
633
  idxr->set_beam_factor(idxr->beam_factor);
558
634
  idx = idxr;
635
+ } else if (
636
+ h == fourcc("ILfs") || h == fourcc("IRfs") || h == fourcc("IPRf") ||
637
+ h == fourcc("IPLf")) {
638
+ bool is_LSQ = h == fourcc("ILfs");
639
+ bool is_RQ = h == fourcc("IRfs");
640
+ bool is_PLSQ = h == fourcc("IPLf");
641
+
642
+ IndexAdditiveQuantizerFastScan* idxaqfs;
643
+ if (is_LSQ) {
644
+ idxaqfs = new IndexLocalSearchQuantizerFastScan();
645
+ } else if (is_RQ) {
646
+ idxaqfs = new IndexResidualQuantizerFastScan();
647
+ } else if (is_PLSQ) {
648
+ idxaqfs = new IndexProductLocalSearchQuantizerFastScan();
649
+ } else {
650
+ idxaqfs = new IndexProductResidualQuantizerFastScan();
651
+ }
652
+ read_index_header(idxaqfs, f);
653
+
654
+ if (is_LSQ) {
655
+ read_LocalSearchQuantizer((LocalSearchQuantizer*)idxaqfs->aq, f);
656
+ } else if (is_RQ) {
657
+ read_ResidualQuantizer((ResidualQuantizer*)idxaqfs->aq, f);
658
+ } else if (is_PLSQ) {
659
+ read_ProductLocalSearchQuantizer(
660
+ (ProductLocalSearchQuantizer*)idxaqfs->aq, f);
661
+ } else {
662
+ read_ProductResidualQuantizer(
663
+ (ProductResidualQuantizer*)idxaqfs->aq, f);
664
+ }
665
+
666
+ READ1(idxaqfs->implem);
667
+ READ1(idxaqfs->bbs);
668
+ READ1(idxaqfs->qbs);
669
+
670
+ READ1(idxaqfs->M);
671
+ READ1(idxaqfs->nbits);
672
+ READ1(idxaqfs->ksub);
673
+ READ1(idxaqfs->code_size);
674
+ READ1(idxaqfs->ntotal2);
675
+ READ1(idxaqfs->M2);
676
+
677
+ READ1(idxaqfs->rescale_norm);
678
+ READ1(idxaqfs->norm_scale);
679
+ READ1(idxaqfs->max_train_points);
680
+
681
+ READVECTOR(idxaqfs->codes);
682
+ idx = idxaqfs;
683
+ } else if (
684
+ h == fourcc("IVLf") || h == fourcc("IVRf") || h == fourcc("NPLf") ||
685
+ h == fourcc("NPRf")) {
686
+ bool is_LSQ = h == fourcc("IVLf");
687
+ bool is_RQ = h == fourcc("IVRf");
688
+ bool is_PLSQ = h == fourcc("NPLf");
689
+
690
+ IndexIVFAdditiveQuantizerFastScan* ivaqfs;
691
+ if (is_LSQ) {
692
+ ivaqfs = new IndexIVFLocalSearchQuantizerFastScan();
693
+ } else if (is_RQ) {
694
+ ivaqfs = new IndexIVFResidualQuantizerFastScan();
695
+ } else if (is_PLSQ) {
696
+ ivaqfs = new IndexIVFProductLocalSearchQuantizerFastScan();
697
+ } else {
698
+ ivaqfs = new IndexIVFProductResidualQuantizerFastScan();
699
+ }
700
+ read_ivf_header(ivaqfs, f);
701
+
702
+ if (is_LSQ) {
703
+ read_LocalSearchQuantizer((LocalSearchQuantizer*)ivaqfs->aq, f);
704
+ } else if (is_RQ) {
705
+ read_ResidualQuantizer((ResidualQuantizer*)ivaqfs->aq, f);
706
+ } else if (is_PLSQ) {
707
+ read_ProductLocalSearchQuantizer(
708
+ (ProductLocalSearchQuantizer*)ivaqfs->aq, f);
709
+ } else {
710
+ read_ProductResidualQuantizer(
711
+ (ProductResidualQuantizer*)ivaqfs->aq, f);
712
+ }
713
+
714
+ READ1(ivaqfs->by_residual);
715
+ READ1(ivaqfs->implem);
716
+ READ1(ivaqfs->bbs);
717
+ READ1(ivaqfs->qbs);
718
+
719
+ READ1(ivaqfs->M);
720
+ READ1(ivaqfs->nbits);
721
+ READ1(ivaqfs->ksub);
722
+ READ1(ivaqfs->code_size);
723
+ READ1(ivaqfs->qbs2);
724
+ READ1(ivaqfs->M2);
725
+
726
+ READ1(ivaqfs->rescale_norm);
727
+ READ1(ivaqfs->norm_scale);
728
+ READ1(ivaqfs->max_train_points);
729
+
730
+ read_InvertedLists(ivaqfs, f, io_flags);
731
+ idx = ivaqfs;
559
732
  } else if (h == fourcc("IvFl") || h == fourcc("IvFL")) { // legacy
560
733
  IndexIVFFlat* ivfl = new IndexIVFFlat();
561
734
  std::vector<std::vector<Index::idx_t>> ids;
@@ -635,20 +808,34 @@ Index* read_index(IOReader* f, int io_flags) {
635
808
  }
636
809
  read_InvertedLists(ivsc, f, io_flags);
637
810
  idx = ivsc;
638
- } else if (h == fourcc("IwLS") || h == fourcc("IwRQ")) {
811
+ } else if (
812
+ h == fourcc("IwLS") || h == fourcc("IwRQ") || h == fourcc("IwPL") ||
813
+ h == fourcc("IwPR")) {
639
814
  bool is_LSQ = h == fourcc("IwLS");
815
+ bool is_RQ = h == fourcc("IwRQ");
816
+ bool is_PLSQ = h == fourcc("IwPL");
640
817
  IndexIVFAdditiveQuantizer* iva;
641
818
  if (is_LSQ) {
642
819
  iva = new IndexIVFLocalSearchQuantizer();
643
- } else {
820
+ } else if (is_RQ) {
644
821
  iva = new IndexIVFResidualQuantizer();
822
+ } else if (is_PLSQ) {
823
+ iva = new IndexIVFProductLocalSearchQuantizer();
824
+ } else {
825
+ iva = new IndexIVFProductResidualQuantizer();
645
826
  }
646
827
  read_ivf_header(iva, f);
647
828
  READ1(iva->code_size);
648
829
  if (is_LSQ) {
649
830
  read_LocalSearchQuantizer((LocalSearchQuantizer*)iva->aq, f);
650
- } else {
831
+ } else if (is_RQ) {
651
832
  read_ResidualQuantizer((ResidualQuantizer*)iva->aq, f);
833
+ } else if (is_PLSQ) {
834
+ read_ProductLocalSearchQuantizer(
835
+ (ProductLocalSearchQuantizer*)iva->aq, f);
836
+ } else {
837
+ read_ProductResidualQuantizer(
838
+ (ProductResidualQuantizer*)iva->aq, f);
652
839
  }
653
840
  READ1(iva->by_residual);
654
841
  READ1(iva->use_precomputed_table);
@@ -751,8 +938,15 @@ Index* read_index(IOReader* f, int io_flags) {
751
938
  dynamic_cast<IndexPQ*>(idxhnsw->storage)->pq.compute_sdc_table();
752
939
  }
753
940
  idx = idxhnsw;
754
- } else if (h == fourcc("INSf")) {
755
- IndexNSG* idxnsg = new IndexNSGFlat();
941
+ } else if (
942
+ h == fourcc("INSf") || h == fourcc("INSp") || h == fourcc("INSs")) {
943
+ IndexNSG* idxnsg;
944
+ if (h == fourcc("INSf"))
945
+ idxnsg = new IndexNSGFlat();
946
+ if (h == fourcc("INSp"))
947
+ idxnsg = new IndexNSGPQ();
948
+ if (h == fourcc("INSs"))
949
+ idxnsg = new IndexNSGSQ();
756
950
  read_index_header(idxnsg, f);
757
951
  READ1(idxnsg->GK);
758
952
  READ1(idxnsg->build_type);
@@ -764,6 +958,13 @@ Index* read_index(IOReader* f, int io_flags) {
764
958
  idxnsg->storage = read_index(f, io_flags);
765
959
  idxnsg->own_fields = true;
766
960
  idx = idxnsg;
961
+ } else if (h == fourcc("INNf")) {
962
+ IndexNNDescent* idxnnd = new IndexNNDescentFlat();
963
+ read_index_header(idxnnd, f);
964
+ read_NNDescent(&idxnnd->nndescent, f);
965
+ idxnnd->storage = read_index(f, io_flags);
966
+ idxnnd->own_fields = true;
967
+ idx = idxnnd;
767
968
  } else if (h == fourcc("IPfs")) {
768
969
  IndexPQFastScan* idxpqfs = new IndexPQFastScan();
769
970
  read_index_header(idxpqfs, f);
@@ -774,6 +975,13 @@ Index* read_index(IOReader* f, int io_flags) {
774
975
  READ1(idxpqfs->ntotal2);
775
976
  READ1(idxpqfs->M2);
776
977
  READVECTOR(idxpqfs->codes);
978
+
979
+ const auto& pq = idxpqfs->pq;
980
+ idxpqfs->M = pq.M;
981
+ idxpqfs->nbits = pq.nbits;
982
+ idxpqfs->ksub = (1 << pq.nbits);
983
+ idxpqfs->code_size = pq.code_size;
984
+
777
985
  idx = idxpqfs;
778
986
 
779
987
  } else if (h == fourcc("IwPf")) {
@@ -788,7 +996,30 @@ Index* read_index(IOReader* f, int io_flags) {
788
996
  read_ProductQuantizer(&ivpq->pq, f);
789
997
  read_InvertedLists(ivpq, f, io_flags);
790
998
  ivpq->precompute_table();
999
+
1000
+ const auto& pq = ivpq->pq;
1001
+ ivpq->M = pq.M;
1002
+ ivpq->nbits = pq.nbits;
1003
+ ivpq->ksub = (1 << pq.nbits);
1004
+ ivpq->code_size = pq.code_size;
1005
+
791
1006
  idx = ivpq;
1007
+ } else if (h == fourcc("IRMf")) {
1008
+ IndexRowwiseMinMax* imm = new IndexRowwiseMinMax();
1009
+ read_index_header(imm, f);
1010
+
1011
+ imm->index = read_index(f, io_flags);
1012
+ imm->own_fields = true;
1013
+
1014
+ idx = imm;
1015
+ } else if (h == fourcc("IRMh")) {
1016
+ IndexRowwiseMinMaxFP16* imm = new IndexRowwiseMinMaxFP16();
1017
+ read_index_header(imm, f);
1018
+
1019
+ imm->index = read_index(f, io_flags);
1020
+ imm->own_fields = true;
1021
+
1022
+ idx = imm;
792
1023
  } else {
793
1024
  FAISS_THROW_FMT(
794
1025
  "Index type 0x%08x (\"%s\") not recognized",
@@ -27,10 +27,12 @@
27
27
 
28
28
  #include <faiss/Index2Layer.h>
29
29
  #include <faiss/IndexAdditiveQuantizer.h>
30
+ #include <faiss/IndexAdditiveQuantizerFastScan.h>
30
31
  #include <faiss/IndexFlat.h>
31
32
  #include <faiss/IndexHNSW.h>
32
33
  #include <faiss/IndexIVF.h>
33
34
  #include <faiss/IndexIVFAdditiveQuantizer.h>
35
+ #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
34
36
  #include <faiss/IndexIVFFlat.h>
35
37
  #include <faiss/IndexIVFPQ.h>
36
38
  #include <faiss/IndexIVFPQFastScan.h>
@@ -38,11 +40,13 @@
38
40
  #include <faiss/IndexIVFSpectralHash.h>
39
41
  #include <faiss/IndexLSH.h>
40
42
  #include <faiss/IndexLattice.h>
43
+ #include <faiss/IndexNNDescent.h>
41
44
  #include <faiss/IndexNSG.h>
42
45
  #include <faiss/IndexPQ.h>
43
46
  #include <faiss/IndexPQFastScan.h>
44
47
  #include <faiss/IndexPreTransform.h>
45
48
  #include <faiss/IndexRefine.h>
49
+ #include <faiss/IndexRowwiseMinMax.h>
46
50
  #include <faiss/IndexScalarQuantizer.h>
47
51
  #include <faiss/MetaIndexes.h>
48
52
  #include <faiss/VectorTransform.h>
@@ -170,9 +174,16 @@ static void write_AdditiveQuantizer(const AdditiveQuantizer* aq, IOWriter* f) {
170
174
  WRITE1(aq->norm_min);
171
175
  WRITE1(aq->norm_max);
172
176
  if (aq->search_type == AdditiveQuantizer::ST_norm_cqint8 ||
173
- aq->search_type == AdditiveQuantizer::ST_norm_cqint4) {
177
+ aq->search_type == AdditiveQuantizer::ST_norm_cqint4 ||
178
+ aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
179
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
174
180
  WRITEXBVECTOR(aq->qnorm.codes);
175
181
  }
182
+
183
+ if (aq->search_type == AdditiveQuantizer::ST_norm_lsq2x4 ||
184
+ aq->search_type == AdditiveQuantizer::ST_norm_rq2x4) {
185
+ WRITEVECTOR(aq->norm_tabs);
186
+ }
176
187
  }
177
188
 
178
189
  static void write_ResidualQuantizer(const ResidualQuantizer* rq, IOWriter* f) {
@@ -198,6 +209,33 @@ static void write_LocalSearchQuantizer(
198
209
  WRITE1(lsq->update_codebooks_with_double);
199
210
  }
200
211
 
212
+ static void write_ProductAdditiveQuantizer(
213
+ const ProductAdditiveQuantizer* paq,
214
+ IOWriter* f) {
215
+ write_AdditiveQuantizer(paq, f);
216
+ WRITE1(paq->nsplits);
217
+ }
218
+
219
+ static void write_ProductResidualQuantizer(
220
+ const ProductResidualQuantizer* prq,
221
+ IOWriter* f) {
222
+ write_ProductAdditiveQuantizer(prq, f);
223
+ for (const auto aq : prq->quantizers) {
224
+ auto rq = dynamic_cast<const ResidualQuantizer*>(aq);
225
+ write_ResidualQuantizer(rq, f);
226
+ }
227
+ }
228
+
229
+ static void write_ProductLocalSearchQuantizer(
230
+ const ProductLocalSearchQuantizer* plsq,
231
+ IOWriter* f) {
232
+ write_ProductAdditiveQuantizer(plsq, f);
233
+ for (const auto aq : plsq->quantizers) {
234
+ auto lsq = dynamic_cast<const LocalSearchQuantizer*>(aq);
235
+ write_LocalSearchQuantizer(lsq, f);
236
+ }
237
+ }
238
+
201
239
  static void write_ScalarQuantizer(const ScalarQuantizer* ivsc, IOWriter* f) {
202
240
  WRITE1(ivsc->qtype);
203
241
  WRITE1(ivsc->rangestat);
@@ -314,6 +352,21 @@ static void write_NSG(const NSG* nsg, IOWriter* f) {
314
352
  }
315
353
  }
316
354
 
355
+ static void write_NNDescent(const NNDescent* nnd, IOWriter* f) {
356
+ WRITE1(nnd->ntotal);
357
+ WRITE1(nnd->d);
358
+ WRITE1(nnd->K);
359
+ WRITE1(nnd->S);
360
+ WRITE1(nnd->R);
361
+ WRITE1(nnd->L);
362
+ WRITE1(nnd->iter);
363
+ WRITE1(nnd->search_L);
364
+ WRITE1(nnd->random_seed);
365
+ WRITE1(nnd->has_built);
366
+
367
+ WRITEVECTOR(nnd->final_graph);
368
+ }
369
+
317
370
  static void write_direct_map(const DirectMap* dm, IOWriter* f) {
318
371
  char maintain_direct_map =
319
372
  (char)dm->type; // for backwards compatibility with bool
@@ -385,6 +438,137 @@ void write_index(const Index* idx, IOWriter* f) {
385
438
  write_LocalSearchQuantizer(&idxr->lsq, f);
386
439
  WRITE1(idxr->code_size);
387
440
  WRITEVECTOR(idxr->codes);
441
+ } else if (
442
+ const IndexProductResidualQuantizer* idxpr =
443
+ dynamic_cast<const IndexProductResidualQuantizer*>(idx)) {
444
+ uint32_t h = fourcc("IxPR");
445
+ WRITE1(h);
446
+ write_index_header(idx, f);
447
+ write_ProductResidualQuantizer(&idxpr->prq, f);
448
+ WRITE1(idxpr->code_size);
449
+ WRITEVECTOR(idxpr->codes);
450
+ } else if (
451
+ const IndexProductLocalSearchQuantizer* idxpl =
452
+ dynamic_cast<const IndexProductLocalSearchQuantizer*>(
453
+ idx)) {
454
+ uint32_t h = fourcc("IxPL");
455
+ WRITE1(h);
456
+ write_index_header(idx, f);
457
+ write_ProductLocalSearchQuantizer(&idxpl->plsq, f);
458
+ WRITE1(idxpl->code_size);
459
+ WRITEVECTOR(idxpl->codes);
460
+ } else if (
461
+ auto* idxaqfs =
462
+ dynamic_cast<const IndexAdditiveQuantizerFastScan*>(idx)) {
463
+ auto idxlsqfs =
464
+ dynamic_cast<const IndexLocalSearchQuantizerFastScan*>(idx);
465
+ auto idxrqfs = dynamic_cast<const IndexResidualQuantizerFastScan*>(idx);
466
+ auto idxplsqfs =
467
+ dynamic_cast<const IndexProductLocalSearchQuantizerFastScan*>(
468
+ idx);
469
+ auto idxprqfs =
470
+ dynamic_cast<const IndexProductResidualQuantizerFastScan*>(idx);
471
+ FAISS_THROW_IF_NOT(idxlsqfs || idxrqfs || idxplsqfs || idxprqfs);
472
+
473
+ if (idxlsqfs) {
474
+ uint32_t h = fourcc("ILfs");
475
+ WRITE1(h);
476
+ } else if (idxrqfs) {
477
+ uint32_t h = fourcc("IRfs");
478
+ WRITE1(h);
479
+ } else if (idxplsqfs) {
480
+ uint32_t h = fourcc("IPLf");
481
+ WRITE1(h);
482
+ } else if (idxprqfs) {
483
+ uint32_t h = fourcc("IPRf");
484
+ WRITE1(h);
485
+ }
486
+
487
+ write_index_header(idxaqfs, f);
488
+
489
+ if (idxlsqfs) {
490
+ write_LocalSearchQuantizer(&idxlsqfs->lsq, f);
491
+ } else if (idxrqfs) {
492
+ write_ResidualQuantizer(&idxrqfs->rq, f);
493
+ } else if (idxplsqfs) {
494
+ write_ProductLocalSearchQuantizer(&idxplsqfs->plsq, f);
495
+ } else if (idxprqfs) {
496
+ write_ProductResidualQuantizer(&idxprqfs->prq, f);
497
+ }
498
+ WRITE1(idxaqfs->implem);
499
+ WRITE1(idxaqfs->bbs);
500
+ WRITE1(idxaqfs->qbs);
501
+
502
+ WRITE1(idxaqfs->M);
503
+ WRITE1(idxaqfs->nbits);
504
+ WRITE1(idxaqfs->ksub);
505
+ WRITE1(idxaqfs->code_size);
506
+ WRITE1(idxaqfs->ntotal2);
507
+ WRITE1(idxaqfs->M2);
508
+
509
+ WRITE1(idxaqfs->rescale_norm);
510
+ WRITE1(idxaqfs->norm_scale);
511
+ WRITE1(idxaqfs->max_train_points);
512
+
513
+ WRITEVECTOR(idxaqfs->codes);
514
+ } else if (
515
+ auto* ivaqfs =
516
+ dynamic_cast<const IndexIVFAdditiveQuantizerFastScan*>(
517
+ idx)) {
518
+ auto ivlsqfs =
519
+ dynamic_cast<const IndexIVFLocalSearchQuantizerFastScan*>(idx);
520
+ auto ivrqfs =
521
+ dynamic_cast<const IndexIVFResidualQuantizerFastScan*>(idx);
522
+ auto ivplsqfs = dynamic_cast<
523
+ const IndexIVFProductLocalSearchQuantizerFastScan*>(idx);
524
+ auto ivprqfs =
525
+ dynamic_cast<const IndexIVFProductResidualQuantizerFastScan*>(
526
+ idx);
527
+ FAISS_THROW_IF_NOT(ivlsqfs || ivrqfs || ivplsqfs || ivprqfs);
528
+
529
+ if (ivlsqfs) {
530
+ uint32_t h = fourcc("IVLf");
531
+ WRITE1(h);
532
+ } else if (ivrqfs) {
533
+ uint32_t h = fourcc("IVRf");
534
+ WRITE1(h);
535
+ } else if (ivplsqfs) {
536
+ uint32_t h = fourcc("NPLf"); // N means IV ...
537
+ WRITE1(h);
538
+ } else {
539
+ uint32_t h = fourcc("NPRf");
540
+ WRITE1(h);
541
+ }
542
+
543
+ write_ivf_header(ivaqfs, f);
544
+
545
+ if (ivlsqfs) {
546
+ write_LocalSearchQuantizer(&ivlsqfs->lsq, f);
547
+ } else if (ivrqfs) {
548
+ write_ResidualQuantizer(&ivrqfs->rq, f);
549
+ } else if (ivplsqfs) {
550
+ write_ProductLocalSearchQuantizer(&ivplsqfs->plsq, f);
551
+ } else {
552
+ write_ProductResidualQuantizer(&ivprqfs->prq, f);
553
+ }
554
+
555
+ WRITE1(ivaqfs->by_residual);
556
+ WRITE1(ivaqfs->implem);
557
+ WRITE1(ivaqfs->bbs);
558
+ WRITE1(ivaqfs->qbs);
559
+
560
+ WRITE1(ivaqfs->M);
561
+ WRITE1(ivaqfs->nbits);
562
+ WRITE1(ivaqfs->ksub);
563
+ WRITE1(ivaqfs->code_size);
564
+ WRITE1(ivaqfs->qbs2);
565
+ WRITE1(ivaqfs->M2);
566
+
567
+ WRITE1(ivaqfs->rescale_norm);
568
+ WRITE1(ivaqfs->norm_scale);
569
+ WRITE1(ivaqfs->max_train_points);
570
+
571
+ write_InvertedLists(ivaqfs->invlists, f);
388
572
  } else if (
389
573
  const ResidualCoarseQuantizer* idxr =
390
574
  dynamic_cast<const ResidualCoarseQuantizer*>(idx)) {
@@ -459,14 +643,33 @@ void write_index(const Index* idx, IOWriter* f) {
459
643
  write_InvertedLists(ivsc->invlists, f);
460
644
  } else if (auto iva = dynamic_cast<const IndexIVFAdditiveQuantizer*>(idx)) {
461
645
  bool is_LSQ = dynamic_cast<const IndexIVFLocalSearchQuantizer*>(iva);
462
- uint32_t h = fourcc(is_LSQ ? "IwLS" : "IwRQ");
646
+ bool is_RQ = dynamic_cast<const IndexIVFResidualQuantizer*>(iva);
647
+ bool is_PLSQ =
648
+ dynamic_cast<const IndexIVFProductLocalSearchQuantizer*>(iva);
649
+ uint32_t h;
650
+ if (is_LSQ) {
651
+ h = fourcc("IwLS");
652
+ } else if (is_RQ) {
653
+ h = fourcc("IwRQ");
654
+ } else if (is_PLSQ) {
655
+ h = fourcc("IwPL");
656
+ } else {
657
+ h = fourcc("IwPR");
658
+ }
659
+
463
660
  WRITE1(h);
464
661
  write_ivf_header(iva, f);
465
662
  WRITE1(iva->code_size);
466
663
  if (is_LSQ) {
467
664
  write_LocalSearchQuantizer((LocalSearchQuantizer*)iva->aq, f);
468
- } else {
665
+ } else if (is_RQ) {
469
666
  write_ResidualQuantizer((ResidualQuantizer*)iva->aq, f);
667
+ } else if (is_PLSQ) {
668
+ write_ProductLocalSearchQuantizer(
669
+ (ProductLocalSearchQuantizer*)iva->aq, f);
670
+ } else {
671
+ write_ProductResidualQuantizer(
672
+ (ProductResidualQuantizer*)iva->aq, f);
470
673
  }
471
674
  WRITE1(iva->by_residual);
472
675
  WRITE1(iva->use_precomputed_table);
@@ -546,8 +749,10 @@ void write_index(const Index* idx, IOWriter* f) {
546
749
  write_HNSW(&idxhnsw->hnsw, f);
547
750
  write_index(idxhnsw->storage, f);
548
751
  } else if (const IndexNSG* idxnsg = dynamic_cast<const IndexNSG*>(idx)) {
549
- uint32_t h =
550
- dynamic_cast<const IndexNSGFlat*>(idx) ? fourcc("INSf") : 0;
752
+ uint32_t h = dynamic_cast<const IndexNSGFlat*>(idx) ? fourcc("INSf")
753
+ : dynamic_cast<const IndexNSGPQ*>(idx) ? fourcc("INSp")
754
+ : dynamic_cast<const IndexNSGSQ*>(idx) ? fourcc("INSs")
755
+ : 0;
551
756
  FAISS_THROW_IF_NOT(h != 0);
552
757
  WRITE1(h);
553
758
  write_index_header(idxnsg, f);
@@ -559,6 +764,17 @@ void write_index(const Index* idx, IOWriter* f) {
559
764
  WRITE1(idxnsg->nndescent_iter);
560
765
  write_NSG(&idxnsg->nsg, f);
561
766
  write_index(idxnsg->storage, f);
767
+ } else if (
768
+ const IndexNNDescent* idxnnd =
769
+ dynamic_cast<const IndexNNDescent*>(idx)) {
770
+ auto idxnndflat = dynamic_cast<const IndexNNDescentFlat*>(idx);
771
+ FAISS_THROW_IF_NOT(idxnndflat != nullptr);
772
+ uint32_t h = fourcc("INNf");
773
+ FAISS_THROW_IF_NOT(h != 0);
774
+ WRITE1(h);
775
+ write_index_header(idxnnd, f);
776
+ write_NNDescent(&idxnnd->nndescent, f);
777
+ write_index(idxnnd->storage, f);
562
778
  } else if (
563
779
  const IndexPQFastScan* idxpqfs =
564
780
  dynamic_cast<const IndexPQFastScan*>(idx)) {
@@ -586,6 +802,22 @@ void write_index(const Index* idx, IOWriter* f) {
586
802
  WRITE1(ivpq->qbs2);
587
803
  write_ProductQuantizer(&ivpq->pq, f);
588
804
  write_InvertedLists(ivpq->invlists, f);
805
+ } else if (
806
+ const IndexRowwiseMinMax* imm =
807
+ dynamic_cast<const IndexRowwiseMinMax*>(idx)) {
808
+ // IndexRowwiseMinmaxFloat
809
+ uint32_t h = fourcc("IRMf");
810
+ WRITE1(h);
811
+ write_index_header(imm, f);
812
+ write_index(imm->index, f);
813
+ } else if (
814
+ const IndexRowwiseMinMaxFP16* imm =
815
+ dynamic_cast<const IndexRowwiseMinMaxFP16*>(idx)) {
816
+ // IndexRowwiseMinmaxHalf
817
+ uint32_t h = fourcc("IRMh");
818
+ WRITE1(h);
819
+ write_index_header(imm, f);
820
+ write_index(imm->index, f);
589
821
  } else {
590
822
  FAISS_THROW_MSG("don't know how to serialize this type of index");
591
823
  }