faiss 0.2.0 → 0.2.1

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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/faiss/version.rb +1 -1
  4. data/vendor/faiss/faiss/AutoTune.cpp +292 -291
  5. data/vendor/faiss/faiss/AutoTune.h +55 -56
  6. data/vendor/faiss/faiss/Clustering.cpp +334 -195
  7. data/vendor/faiss/faiss/Clustering.h +88 -35
  8. data/vendor/faiss/faiss/IVFlib.cpp +171 -195
  9. data/vendor/faiss/faiss/IVFlib.h +48 -51
  10. data/vendor/faiss/faiss/Index.cpp +85 -103
  11. data/vendor/faiss/faiss/Index.h +54 -48
  12. data/vendor/faiss/faiss/Index2Layer.cpp +139 -164
  13. data/vendor/faiss/faiss/Index2Layer.h +22 -22
  14. data/vendor/faiss/faiss/IndexBinary.cpp +45 -37
  15. data/vendor/faiss/faiss/IndexBinary.h +140 -132
  16. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +73 -53
  17. data/vendor/faiss/faiss/IndexBinaryFlat.h +29 -24
  18. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +46 -43
  19. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +16 -15
  20. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +215 -232
  21. data/vendor/faiss/faiss/IndexBinaryHNSW.h +25 -24
  22. data/vendor/faiss/faiss/IndexBinaryHash.cpp +182 -177
  23. data/vendor/faiss/faiss/IndexBinaryHash.h +41 -34
  24. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +489 -461
  25. data/vendor/faiss/faiss/IndexBinaryIVF.h +97 -68
  26. data/vendor/faiss/faiss/IndexFlat.cpp +116 -147
  27. data/vendor/faiss/faiss/IndexFlat.h +35 -46
  28. data/vendor/faiss/faiss/IndexHNSW.cpp +372 -348
  29. data/vendor/faiss/faiss/IndexHNSW.h +57 -41
  30. data/vendor/faiss/faiss/IndexIVF.cpp +474 -454
  31. data/vendor/faiss/faiss/IndexIVF.h +146 -113
  32. data/vendor/faiss/faiss/IndexIVFFlat.cpp +248 -250
  33. data/vendor/faiss/faiss/IndexIVFFlat.h +48 -51
  34. data/vendor/faiss/faiss/IndexIVFPQ.cpp +457 -516
  35. data/vendor/faiss/faiss/IndexIVFPQ.h +74 -66
  36. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +406 -372
  37. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +82 -57
  38. data/vendor/faiss/faiss/IndexIVFPQR.cpp +104 -102
  39. data/vendor/faiss/faiss/IndexIVFPQR.h +33 -28
  40. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +125 -133
  41. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +19 -21
  42. data/vendor/faiss/faiss/IndexLSH.cpp +75 -96
  43. data/vendor/faiss/faiss/IndexLSH.h +21 -26
  44. data/vendor/faiss/faiss/IndexLattice.cpp +42 -56
  45. data/vendor/faiss/faiss/IndexLattice.h +11 -16
  46. data/vendor/faiss/faiss/IndexNNDescent.cpp +231 -0
  47. data/vendor/faiss/faiss/IndexNNDescent.h +72 -0
  48. data/vendor/faiss/faiss/IndexNSG.cpp +303 -0
  49. data/vendor/faiss/faiss/IndexNSG.h +85 -0
  50. data/vendor/faiss/faiss/IndexPQ.cpp +405 -464
  51. data/vendor/faiss/faiss/IndexPQ.h +64 -67
  52. data/vendor/faiss/faiss/IndexPQFastScan.cpp +143 -170
  53. data/vendor/faiss/faiss/IndexPQFastScan.h +46 -32
  54. data/vendor/faiss/faiss/IndexPreTransform.cpp +120 -150
  55. data/vendor/faiss/faiss/IndexPreTransform.h +33 -36
  56. data/vendor/faiss/faiss/IndexRefine.cpp +115 -131
  57. data/vendor/faiss/faiss/IndexRefine.h +22 -23
  58. data/vendor/faiss/faiss/IndexReplicas.cpp +147 -153
  59. data/vendor/faiss/faiss/IndexReplicas.h +62 -56
  60. data/vendor/faiss/faiss/IndexResidual.cpp +291 -0
  61. data/vendor/faiss/faiss/IndexResidual.h +152 -0
  62. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +120 -155
  63. data/vendor/faiss/faiss/IndexScalarQuantizer.h +41 -45
  64. data/vendor/faiss/faiss/IndexShards.cpp +256 -240
  65. data/vendor/faiss/faiss/IndexShards.h +85 -73
  66. data/vendor/faiss/faiss/MatrixStats.cpp +112 -97
  67. data/vendor/faiss/faiss/MatrixStats.h +7 -10
  68. data/vendor/faiss/faiss/MetaIndexes.cpp +135 -157
  69. data/vendor/faiss/faiss/MetaIndexes.h +40 -34
  70. data/vendor/faiss/faiss/MetricType.h +7 -7
  71. data/vendor/faiss/faiss/VectorTransform.cpp +652 -474
  72. data/vendor/faiss/faiss/VectorTransform.h +61 -89
  73. data/vendor/faiss/faiss/clone_index.cpp +77 -73
  74. data/vendor/faiss/faiss/clone_index.h +4 -9
  75. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +33 -38
  76. data/vendor/faiss/faiss/gpu/GpuAutoTune.h +11 -9
  77. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +197 -170
  78. data/vendor/faiss/faiss/gpu/GpuCloner.h +53 -35
  79. data/vendor/faiss/faiss/gpu/GpuClonerOptions.cpp +12 -14
  80. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +27 -25
  81. data/vendor/faiss/faiss/gpu/GpuDistance.h +116 -112
  82. data/vendor/faiss/faiss/gpu/GpuFaissAssert.h +1 -2
  83. data/vendor/faiss/faiss/gpu/GpuIndex.h +134 -137
  84. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +76 -73
  85. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +173 -162
  86. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +67 -64
  87. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +89 -86
  88. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +150 -141
  89. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +101 -103
  90. data/vendor/faiss/faiss/gpu/GpuIndicesOptions.h +17 -16
  91. data/vendor/faiss/faiss/gpu/GpuResources.cpp +116 -128
  92. data/vendor/faiss/faiss/gpu/GpuResources.h +182 -186
  93. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +433 -422
  94. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +131 -130
  95. data/vendor/faiss/faiss/gpu/impl/InterleavedCodes.cpp +468 -456
  96. data/vendor/faiss/faiss/gpu/impl/InterleavedCodes.h +25 -19
  97. data/vendor/faiss/faiss/gpu/impl/RemapIndices.cpp +22 -20
  98. data/vendor/faiss/faiss/gpu/impl/RemapIndices.h +9 -8
  99. data/vendor/faiss/faiss/gpu/perf/IndexWrapper-inl.h +39 -44
  100. data/vendor/faiss/faiss/gpu/perf/IndexWrapper.h +16 -14
  101. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +77 -71
  102. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +109 -88
  103. data/vendor/faiss/faiss/gpu/perf/WriteIndex.cpp +75 -64
  104. data/vendor/faiss/faiss/gpu/test/TestCodePacking.cpp +230 -215
  105. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +80 -86
  106. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +284 -277
  107. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +416 -416
  108. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +611 -517
  109. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +166 -164
  110. data/vendor/faiss/faiss/gpu/test/TestGpuMemoryException.cpp +61 -53
  111. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +274 -238
  112. data/vendor/faiss/faiss/gpu/test/TestUtils.h +73 -57
  113. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +47 -50
  114. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +79 -72
  115. data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +140 -146
  116. data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.h +69 -71
  117. data/vendor/faiss/faiss/gpu/utils/StaticUtils.h +21 -16
  118. data/vendor/faiss/faiss/gpu/utils/Timer.cpp +25 -29
  119. data/vendor/faiss/faiss/gpu/utils/Timer.h +30 -29
  120. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +270 -0
  121. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +115 -0
  122. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +90 -120
  123. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +81 -65
  124. data/vendor/faiss/faiss/impl/FaissAssert.h +73 -58
  125. data/vendor/faiss/faiss/impl/FaissException.cpp +56 -48
  126. data/vendor/faiss/faiss/impl/FaissException.h +41 -29
  127. data/vendor/faiss/faiss/impl/HNSW.cpp +595 -611
  128. data/vendor/faiss/faiss/impl/HNSW.h +179 -200
  129. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +672 -0
  130. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +172 -0
  131. data/vendor/faiss/faiss/impl/NNDescent.cpp +487 -0
  132. data/vendor/faiss/faiss/impl/NNDescent.h +154 -0
  133. data/vendor/faiss/faiss/impl/NSG.cpp +682 -0
  134. data/vendor/faiss/faiss/impl/NSG.h +199 -0
  135. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +484 -454
  136. data/vendor/faiss/faiss/impl/PolysemousTraining.h +52 -55
  137. data/vendor/faiss/faiss/impl/ProductQuantizer-inl.h +26 -47
  138. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +469 -459
  139. data/vendor/faiss/faiss/impl/ProductQuantizer.h +76 -87
  140. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +448 -0
  141. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +130 -0
  142. data/vendor/faiss/faiss/impl/ResultHandler.h +96 -132
  143. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +648 -701
  144. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +48 -46
  145. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +129 -131
  146. data/vendor/faiss/faiss/impl/ThreadedIndex.h +61 -55
  147. data/vendor/faiss/faiss/impl/index_read.cpp +547 -479
  148. data/vendor/faiss/faiss/impl/index_write.cpp +497 -407
  149. data/vendor/faiss/faiss/impl/io.cpp +75 -94
  150. data/vendor/faiss/faiss/impl/io.h +31 -41
  151. data/vendor/faiss/faiss/impl/io_macros.h +40 -29
  152. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +137 -186
  153. data/vendor/faiss/faiss/impl/lattice_Zn.h +40 -51
  154. data/vendor/faiss/faiss/impl/platform_macros.h +29 -8
  155. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +77 -124
  156. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +39 -48
  157. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +41 -52
  158. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +80 -117
  159. data/vendor/faiss/faiss/impl/simd_result_handlers.h +109 -137
  160. data/vendor/faiss/faiss/index_factory.cpp +269 -218
  161. data/vendor/faiss/faiss/index_factory.h +6 -7
  162. data/vendor/faiss/faiss/index_io.h +23 -26
  163. data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +67 -75
  164. data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +22 -24
  165. data/vendor/faiss/faiss/invlists/DirectMap.cpp +96 -112
  166. data/vendor/faiss/faiss/invlists/DirectMap.h +29 -33
  167. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +307 -364
  168. data/vendor/faiss/faiss/invlists/InvertedLists.h +151 -151
  169. data/vendor/faiss/faiss/invlists/InvertedListsIOHook.cpp +29 -34
  170. data/vendor/faiss/faiss/invlists/InvertedListsIOHook.h +17 -18
  171. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +257 -293
  172. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +50 -45
  173. data/vendor/faiss/faiss/python/python_callbacks.cpp +23 -26
  174. data/vendor/faiss/faiss/python/python_callbacks.h +9 -16
  175. data/vendor/faiss/faiss/utils/AlignedTable.h +79 -44
  176. data/vendor/faiss/faiss/utils/Heap.cpp +40 -48
  177. data/vendor/faiss/faiss/utils/Heap.h +186 -209
  178. data/vendor/faiss/faiss/utils/WorkerThread.cpp +67 -76
  179. data/vendor/faiss/faiss/utils/WorkerThread.h +32 -33
  180. data/vendor/faiss/faiss/utils/distances.cpp +301 -310
  181. data/vendor/faiss/faiss/utils/distances.h +133 -118
  182. data/vendor/faiss/faiss/utils/distances_simd.cpp +456 -516
  183. data/vendor/faiss/faiss/utils/extra_distances-inl.h +117 -0
  184. data/vendor/faiss/faiss/utils/extra_distances.cpp +113 -232
  185. data/vendor/faiss/faiss/utils/extra_distances.h +30 -29
  186. data/vendor/faiss/faiss/utils/hamming-inl.h +260 -209
  187. data/vendor/faiss/faiss/utils/hamming.cpp +375 -469
  188. data/vendor/faiss/faiss/utils/hamming.h +62 -85
  189. data/vendor/faiss/faiss/utils/ordered_key_value.h +16 -18
  190. data/vendor/faiss/faiss/utils/partitioning.cpp +393 -318
  191. data/vendor/faiss/faiss/utils/partitioning.h +26 -21
  192. data/vendor/faiss/faiss/utils/quantize_lut.cpp +78 -66
  193. data/vendor/faiss/faiss/utils/quantize_lut.h +22 -20
  194. data/vendor/faiss/faiss/utils/random.cpp +39 -63
  195. data/vendor/faiss/faiss/utils/random.h +13 -16
  196. data/vendor/faiss/faiss/utils/simdlib.h +4 -2
  197. data/vendor/faiss/faiss/utils/simdlib_avx2.h +88 -85
  198. data/vendor/faiss/faiss/utils/simdlib_emulated.h +226 -165
  199. data/vendor/faiss/faiss/utils/simdlib_neon.h +832 -0
  200. data/vendor/faiss/faiss/utils/utils.cpp +304 -287
  201. data/vendor/faiss/faiss/utils/utils.h +53 -48
  202. metadata +20 -2
@@ -21,26 +21,25 @@ namespace faiss {
21
21
 
22
22
  /** Product Quantizer. Implemented only for METRIC_L2 */
23
23
  struct ProductQuantizer {
24
-
25
24
  using idx_t = Index::idx_t;
26
25
 
27
- size_t d; ///< size of the input vectors
28
- size_t M; ///< number of subquantizers
29
- size_t nbits; ///< number of bits per quantization index
26
+ size_t d; ///< size of the input vectors
27
+ size_t M; ///< number of subquantizers
28
+ size_t nbits; ///< number of bits per quantization index
30
29
 
31
30
  // values derived from the above
32
- size_t dsub; ///< dimensionality of each subvector
33
- size_t code_size; ///< bytes per indexed vector
34
- size_t ksub; ///< number of centroids for each subquantizer
35
- bool verbose; ///< verbose during training?
31
+ size_t dsub; ///< dimensionality of each subvector
32
+ size_t code_size; ///< bytes per indexed vector
33
+ size_t ksub; ///< number of centroids for each subquantizer
34
+ bool verbose; ///< verbose during training?
36
35
 
37
36
  /// initialization
38
37
  enum train_type_t {
39
38
  Train_default,
40
- Train_hot_start, ///< the centroids are already initialized
41
- Train_shared, ///< share dictionary accross PQ segments
42
- Train_hypercube, ///< intialize centroids with nbits-D hypercube
43
- Train_hypercube_pca, ///< intialize centroids with nbits-D hypercube
39
+ Train_hot_start, ///< the centroids are already initialized
40
+ Train_shared, ///< share dictionary accross PQ segments
41
+ Train_hypercube, ///< intialize centroids with nbits-D hypercube
42
+ Train_hypercube_pca, ///< intialize centroids with nbits-D hypercube
44
43
  };
45
44
  train_type_t train_type;
46
45
 
@@ -48,59 +47,57 @@ struct ProductQuantizer {
48
47
 
49
48
  /// if non-NULL, use this index for assignment (should be of size
50
49
  /// d / M)
51
- Index *assign_index;
50
+ Index* assign_index;
52
51
 
53
52
  /// Centroid table, size M * ksub * dsub
54
53
  std::vector<float> centroids;
55
54
 
56
55
  /// return the centroids associated with subvector m
57
- float * get_centroids (size_t m, size_t i) {
58
- return &centroids [(m * ksub + i) * dsub];
56
+ float* get_centroids(size_t m, size_t i) {
57
+ return &centroids[(m * ksub + i) * dsub];
59
58
  }
60
- const float * get_centroids (size_t m, size_t i) const {
61
- return &centroids [(m * ksub + i) * dsub];
59
+ const float* get_centroids(size_t m, size_t i) const {
60
+ return &centroids[(m * ksub + i) * dsub];
62
61
  }
63
62
 
64
63
  // Train the product quantizer on a set of points. A clustering
65
64
  // can be set on input to define non-default clustering parameters
66
- void train (int n, const float *x);
65
+ void train(int n, const float* x);
67
66
 
68
- ProductQuantizer(size_t d, /* dimensionality of the input vectors */
69
- size_t M, /* number of subquantizers */
70
- size_t nbits); /* number of bit per subvector index */
67
+ ProductQuantizer(
68
+ size_t d, /* dimensionality of the input vectors */
69
+ size_t M, /* number of subquantizers */
70
+ size_t nbits); /* number of bit per subvector index */
71
71
 
72
- ProductQuantizer ();
72
+ ProductQuantizer();
73
73
 
74
74
  /// compute derived values when d, M and nbits have been set
75
- void set_derived_values ();
75
+ void set_derived_values();
76
76
 
77
77
  /// Define the centroids for subquantizer m
78
- void set_params (const float * centroids, int m);
78
+ void set_params(const float* centroids, int m);
79
79
 
80
80
  /// Quantize one vector with the product quantizer
81
- void compute_code (const float * x, uint8_t * code) const ;
81
+ void compute_code(const float* x, uint8_t* code) const;
82
82
 
83
83
  /// same as compute_code for several vectors
84
- void compute_codes (const float * x,
85
- uint8_t * codes,
86
- size_t n) const ;
84
+ void compute_codes(const float* x, uint8_t* codes, size_t n) const;
87
85
 
88
86
  /// speed up code assignment using assign_index
89
87
  /// (non-const because the index is changed)
90
- void compute_codes_with_assign_index (
91
- const float * x,
92
- uint8_t * codes,
93
- size_t n);
88
+ void compute_codes_with_assign_index(
89
+ const float* x,
90
+ uint8_t* codes,
91
+ size_t n);
94
92
 
95
93
  /// decode a vector from a given code (or n vectors if third argument)
96
- void decode (const uint8_t *code, float *x) const;
97
- void decode (const uint8_t *code, float *x, size_t n) const;
94
+ void decode(const uint8_t* code, float* x) const;
95
+ void decode(const uint8_t* code, float* x, size_t n) const;
98
96
 
99
97
  /// If we happen to have the distance tables precomputed, this is
100
98
  /// more efficient to compute the codes.
101
- void compute_code_from_distance_table (const float *tab,
102
- uint8_t *code) const;
103
-
99
+ void compute_code_from_distance_table(const float* tab, uint8_t* code)
100
+ const;
104
101
 
105
102
  /** Compute distance table for one vector.
106
103
  *
@@ -115,26 +112,20 @@ struct ProductQuantizer {
115
112
  * @param x input vector size d
116
113
  * @param dis_table output table, size M * ksub
117
114
  */
118
- void compute_distance_table (const float * x,
119
- float * dis_table) const;
120
-
121
- void compute_inner_prod_table (const float * x,
122
- float * dis_table) const;
115
+ void compute_distance_table(const float* x, float* dis_table) const;
123
116
 
117
+ void compute_inner_prod_table(const float* x, float* dis_table) const;
124
118
 
125
119
  /** compute distance table for several vectors
126
120
  * @param nx nb of input vectors
127
121
  * @param x input vector size nx * d
128
122
  * @param dis_table output table, size nx * M * ksub
129
123
  */
130
- void compute_distance_tables (size_t nx,
131
- const float * x,
132
- float * dis_tables) const;
133
-
134
- void compute_inner_prod_tables (size_t nx,
135
- const float * x,
136
- float * dis_tables) const;
124
+ void compute_distance_tables(size_t nx, const float* x, float* dis_tables)
125
+ const;
137
126
 
127
+ void compute_inner_prod_tables(size_t nx, const float* x, float* dis_tables)
128
+ const;
138
129
 
139
130
  /** perform a search (L2 distance)
140
131
  * @param x query vectors, size nx * d
@@ -144,95 +135,93 @@ struct ProductQuantizer {
144
135
  * @param res heap array to store results (nh == nx)
145
136
  * @param init_finalize_heap initialize heap (input) and sort (output)?
146
137
  */
147
- void search (const float * x,
148
- size_t nx,
149
- const uint8_t * codes,
150
- const size_t ncodes,
151
- float_maxheap_array_t *res,
152
- bool init_finalize_heap = true) const;
138
+ void search(
139
+ const float* x,
140
+ size_t nx,
141
+ const uint8_t* codes,
142
+ const size_t ncodes,
143
+ float_maxheap_array_t* res,
144
+ bool init_finalize_heap = true) const;
153
145
 
154
146
  /** same as search, but with inner product similarity */
155
- void search_ip (const float * x,
156
- size_t nx,
157
- const uint8_t * codes,
158
- const size_t ncodes,
159
- float_minheap_array_t *res,
160
- bool init_finalize_heap = true) const;
161
-
147
+ void search_ip(
148
+ const float* x,
149
+ size_t nx,
150
+ const uint8_t* codes,
151
+ const size_t ncodes,
152
+ float_minheap_array_t* res,
153
+ bool init_finalize_heap = true) const;
162
154
 
163
155
  /// Symmetric Distance Table
164
156
  std::vector<float> sdc_table;
165
157
 
166
158
  // intitialize the SDC table from the centroids
167
- void compute_sdc_table ();
168
-
169
- void search_sdc (const uint8_t * qcodes,
170
- size_t nq,
171
- const uint8_t * bcodes,
172
- const size_t ncodes,
173
- float_maxheap_array_t * res,
174
- bool init_finalize_heap = true) const;
175
-
159
+ void compute_sdc_table();
160
+
161
+ void search_sdc(
162
+ const uint8_t* qcodes,
163
+ size_t nq,
164
+ const uint8_t* bcodes,
165
+ const size_t ncodes,
166
+ float_maxheap_array_t* res,
167
+ bool init_finalize_heap = true) const;
176
168
  };
177
169
 
178
-
179
170
  /*************************************************
180
171
  * Objects to encode / decode strings of bits
181
172
  *************************************************/
182
173
 
183
174
  struct PQEncoderGeneric {
184
- uint8_t *code; ///< code for this vector
175
+ uint8_t* code; ///< code for this vector
185
176
  uint8_t offset;
186
177
  const int nbits; ///< number of bits per subquantizer index
187
178
 
188
179
  uint8_t reg;
189
180
 
190
- PQEncoderGeneric(uint8_t *code, int nbits, uint8_t offset = 0);
181
+ PQEncoderGeneric(uint8_t* code, int nbits, uint8_t offset = 0);
191
182
 
192
183
  void encode(uint64_t x);
193
184
 
194
185
  ~PQEncoderGeneric();
195
186
  };
196
187
 
197
-
198
188
  struct PQEncoder8 {
199
- uint8_t *code;
200
- PQEncoder8(uint8_t *code, int nbits);
189
+ uint8_t* code;
190
+ PQEncoder8(uint8_t* code, int nbits);
201
191
  void encode(uint64_t x);
202
192
  };
203
193
 
204
194
  struct PQEncoder16 {
205
- uint16_t *code;
206
- PQEncoder16(uint8_t *code, int nbits);
195
+ uint16_t* code;
196
+ PQEncoder16(uint8_t* code, int nbits);
207
197
  void encode(uint64_t x);
208
198
  };
209
199
 
210
-
211
200
  struct PQDecoderGeneric {
212
- const uint8_t *code;
201
+ const uint8_t* code;
213
202
  uint8_t offset;
214
203
  const int nbits;
215
204
  const uint64_t mask;
216
205
  uint8_t reg;
217
- PQDecoderGeneric(const uint8_t *code, int nbits);
206
+ PQDecoderGeneric(const uint8_t* code, int nbits);
218
207
  uint64_t decode();
219
208
  };
220
209
 
221
210
  struct PQDecoder8 {
222
211
  static const int nbits = 8;
223
- const uint8_t *code;
224
- PQDecoder8(const uint8_t *code, int nbits);
212
+ const uint8_t* code;
213
+ PQDecoder8(const uint8_t* code, int nbits);
225
214
  uint64_t decode();
226
215
  };
227
216
 
228
217
  struct PQDecoder16 {
229
218
  static const int nbits = 16;
230
- const uint16_t *code;
231
- PQDecoder16(const uint8_t *code, int nbits);
219
+ const uint16_t* code;
220
+ PQDecoder16(const uint8_t* code, int nbits);
232
221
  uint64_t decode();
233
222
  };
234
223
 
235
- } // namespace faiss
224
+ } // namespace faiss
236
225
 
237
226
  #include <faiss/impl/ProductQuantizer-inl.h>
238
227
 
@@ -0,0 +1,448 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its 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
+ // -*- c++ -*-
9
+
10
+ #include "faiss/impl/ResidualQuantizer.h"
11
+ #include <faiss/impl/FaissAssert.h>
12
+ #include <faiss/impl/ResidualQuantizer.h>
13
+ #include "faiss/utils/utils.h"
14
+
15
+ #include <cstddef>
16
+ #include <cstdio>
17
+ #include <cstring>
18
+ #include <memory>
19
+
20
+ #include <algorithm>
21
+
22
+ #include <faiss/IndexFlat.h>
23
+ #include <faiss/VectorTransform.h>
24
+ #include <faiss/impl/AuxIndexStructures.h>
25
+ #include <faiss/impl/FaissAssert.h>
26
+ #include <faiss/utils/Heap.h>
27
+ #include <faiss/utils/distances.h>
28
+ #include <faiss/utils/hamming.h>
29
+ #include <faiss/utils/utils.h>
30
+
31
+ namespace faiss {
32
+
33
+ ResidualQuantizer::ResidualQuantizer()
34
+ : train_type(Train_progressive_dim),
35
+ max_beam_size(30),
36
+ max_mem_distances(5 * (size_t(1) << 30)), // 5 GiB
37
+ assign_index_factory(nullptr) {
38
+ d = 0;
39
+ M = 0;
40
+ verbose = false;
41
+ }
42
+
43
+ ResidualQuantizer::ResidualQuantizer(size_t d, const std::vector<size_t>& nbits)
44
+ : ResidualQuantizer() {
45
+ this->d = d;
46
+ M = nbits.size();
47
+ this->nbits = nbits;
48
+ set_derived_values();
49
+ }
50
+
51
+ ResidualQuantizer::ResidualQuantizer(size_t d, size_t M, size_t nbits)
52
+ : ResidualQuantizer(d, std::vector<size_t>(M, nbits)) {}
53
+
54
+ namespace {
55
+
56
+ void fvec_sub(size_t d, const float* a, const float* b, float* c) {
57
+ for (size_t i = 0; i < d; i++) {
58
+ c[i] = a[i] - b[i];
59
+ }
60
+ }
61
+
62
+ } // anonymous namespace
63
+
64
+ void beam_search_encode_step(
65
+ size_t d,
66
+ size_t K,
67
+ const float* cent, /// size (K, d)
68
+ size_t n,
69
+ size_t beam_size,
70
+ const float* residuals, /// size (n, beam_size, d)
71
+ size_t m,
72
+ const int32_t* codes, /// size (n, beam_size, m)
73
+ size_t new_beam_size,
74
+ int32_t* new_codes, /// size (n, new_beam_size, m + 1)
75
+ float* new_residuals, /// size (n, new_beam_size, d)
76
+ float* new_distances, /// size (n, new_beam_size)
77
+ Index* assign_index) {
78
+ // we have to fill in the whole output matrix
79
+ FAISS_THROW_IF_NOT(new_beam_size <= beam_size * K);
80
+
81
+ using idx_t = Index::idx_t;
82
+
83
+ std::vector<float> cent_distances;
84
+ std::vector<idx_t> cent_ids;
85
+
86
+ if (assign_index) {
87
+ // search beam_size distances per query
88
+ FAISS_THROW_IF_NOT(assign_index->d == d);
89
+ cent_distances.resize(n * beam_size * new_beam_size);
90
+ cent_ids.resize(n * beam_size * new_beam_size);
91
+ if (assign_index->ntotal != 0) {
92
+ // then we assume the codebooks are already added to the index
93
+ FAISS_THROW_IF_NOT(assign_index->ntotal != K);
94
+ } else {
95
+ assign_index->add(K, cent);
96
+ }
97
+
98
+ // printf("beam_search_encode_step -- mem usage %zd\n",
99
+ // get_mem_usage_kb());
100
+ assign_index->search(
101
+ n * beam_size,
102
+ residuals,
103
+ new_beam_size,
104
+ cent_distances.data(),
105
+ cent_ids.data());
106
+ } else {
107
+ // do one big distance computation
108
+ cent_distances.resize(n * beam_size * K);
109
+ pairwise_L2sqr(
110
+ d, n * beam_size, residuals, K, cent, cent_distances.data());
111
+ }
112
+ InterruptCallback::check();
113
+
114
+ #pragma omp parallel for if (n > 100)
115
+ for (int64_t i = 0; i < n; i++) {
116
+ const int32_t* codes_i = codes + i * m * beam_size;
117
+ int32_t* new_codes_i = new_codes + i * (m + 1) * new_beam_size;
118
+ const float* residuals_i = residuals + i * d * beam_size;
119
+ float* new_residuals_i = new_residuals + i * d * new_beam_size;
120
+
121
+ float* new_distances_i = new_distances + i * new_beam_size;
122
+ using C = CMax<float, int>;
123
+
124
+ if (assign_index) {
125
+ const float* cent_distances_i =
126
+ cent_distances.data() + i * beam_size * new_beam_size;
127
+ const idx_t* cent_ids_i =
128
+ cent_ids.data() + i * beam_size * new_beam_size;
129
+
130
+ // here we could be a tad more efficient by merging sorted arrays
131
+ for (int i = 0; i < new_beam_size; i++) {
132
+ new_distances_i[i] = C::neutral();
133
+ }
134
+ std::vector<int> perm(new_beam_size, -1);
135
+ heap_addn<C>(
136
+ new_beam_size,
137
+ new_distances_i,
138
+ perm.data(),
139
+ cent_distances_i,
140
+ nullptr,
141
+ beam_size * new_beam_size);
142
+ heap_reorder<C>(new_beam_size, new_distances_i, perm.data());
143
+
144
+ for (int j = 0; j < new_beam_size; j++) {
145
+ int js = perm[j] / new_beam_size;
146
+ int ls = cent_ids_i[perm[j]];
147
+ if (m > 0) {
148
+ memcpy(new_codes_i, codes_i + js * m, sizeof(*codes) * m);
149
+ }
150
+ new_codes_i[m] = ls;
151
+ new_codes_i += m + 1;
152
+ fvec_sub(
153
+ d,
154
+ residuals_i + js * d,
155
+ cent + ls * d,
156
+ new_residuals_i);
157
+ new_residuals_i += d;
158
+ }
159
+
160
+ } else {
161
+ const float* cent_distances_i =
162
+ cent_distances.data() + i * beam_size * K;
163
+ // then we have to select the best results
164
+ for (int i = 0; i < new_beam_size; i++) {
165
+ new_distances_i[i] = C::neutral();
166
+ }
167
+ std::vector<int> perm(new_beam_size, -1);
168
+ heap_addn<C>(
169
+ new_beam_size,
170
+ new_distances_i,
171
+ perm.data(),
172
+ cent_distances_i,
173
+ nullptr,
174
+ beam_size * K);
175
+ heap_reorder<C>(new_beam_size, new_distances_i, perm.data());
176
+
177
+ for (int j = 0; j < new_beam_size; j++) {
178
+ int js = perm[j] / K;
179
+ int ls = perm[j] % K;
180
+ if (m > 0) {
181
+ memcpy(new_codes_i, codes_i + js * m, sizeof(*codes) * m);
182
+ }
183
+ new_codes_i[m] = ls;
184
+ new_codes_i += m + 1;
185
+ fvec_sub(
186
+ d,
187
+ residuals_i + js * d,
188
+ cent + ls * d,
189
+ new_residuals_i);
190
+ new_residuals_i += d;
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ void ResidualQuantizer::train(size_t n, const float* x) {
197
+ codebooks.resize(d * codebook_offsets.back());
198
+
199
+ if (verbose) {
200
+ printf("Training ResidualQuantizer, with %zd steps on %zd %zdD vectors\n",
201
+ M,
202
+ n,
203
+ size_t(d));
204
+ }
205
+
206
+ int cur_beam_size = 1;
207
+ std::vector<float> residuals(x, x + n * d);
208
+ std::vector<int32_t> codes;
209
+ std::vector<float> distances;
210
+ double t0 = getmillisecs();
211
+
212
+ for (int m = 0; m < M; m++) {
213
+ int K = 1 << nbits[m];
214
+
215
+ // on which residuals to train
216
+ std::vector<float>& train_residuals = residuals;
217
+ std::vector<float> residuals1;
218
+ if (train_type & Train_top_beam) {
219
+ residuals1.resize(n * d);
220
+ for (size_t j = 0; j < n; j++) {
221
+ memcpy(residuals1.data() + j * d,
222
+ residuals.data() + j * d * cur_beam_size,
223
+ sizeof(residuals[0]) * d);
224
+ }
225
+ train_residuals = residuals1;
226
+ }
227
+ train_type_t tt = train_type_t(train_type & ~Train_top_beam);
228
+
229
+ std::vector<float> codebooks;
230
+ float obj = 0;
231
+
232
+ std::unique_ptr<Index> assign_index;
233
+ if (assign_index_factory) {
234
+ assign_index.reset((*assign_index_factory)(d));
235
+ } else {
236
+ assign_index.reset(new IndexFlatL2(d));
237
+ }
238
+ if (tt == Train_default) {
239
+ Clustering clus(d, K, cp);
240
+ clus.train(
241
+ train_residuals.size() / d,
242
+ train_residuals.data(),
243
+ *assign_index.get());
244
+ codebooks.swap(clus.centroids);
245
+ assign_index->reset();
246
+ obj = clus.iteration_stats.back().obj;
247
+ } else if (tt == Train_progressive_dim) {
248
+ ProgressiveDimClustering clus(d, K, cp);
249
+ ProgressiveDimIndexFactory default_fac;
250
+ clus.train(
251
+ train_residuals.size() / d,
252
+ train_residuals.data(),
253
+ assign_index_factory ? *assign_index_factory : default_fac);
254
+ codebooks.swap(clus.centroids);
255
+ obj = clus.iteration_stats.back().obj;
256
+ } else {
257
+ FAISS_THROW_MSG("train type not supported");
258
+ }
259
+
260
+ memcpy(this->codebooks.data() + codebook_offsets[m] * d,
261
+ codebooks.data(),
262
+ codebooks.size() * sizeof(codebooks[0]));
263
+
264
+ // quantize using the new codebooks
265
+
266
+ int new_beam_size = std::min(cur_beam_size * K, max_beam_size);
267
+ std::vector<int32_t> new_codes(n * new_beam_size * (m + 1));
268
+ std::vector<float> new_residuals(n * new_beam_size * d);
269
+ std::vector<float> new_distances(n * new_beam_size);
270
+
271
+ beam_search_encode_step(
272
+ d,
273
+ K,
274
+ codebooks.data(),
275
+ n,
276
+ cur_beam_size,
277
+ residuals.data(),
278
+ m,
279
+ codes.data(),
280
+ new_beam_size,
281
+ new_codes.data(),
282
+ new_residuals.data(),
283
+ new_distances.data(),
284
+ assign_index.get());
285
+
286
+ codes.swap(new_codes);
287
+ residuals.swap(new_residuals);
288
+ distances.swap(new_distances);
289
+
290
+ float sum_distances = 0;
291
+ for (int j = 0; j < distances.size(); j++) {
292
+ sum_distances += distances[j];
293
+ }
294
+
295
+ if (verbose) {
296
+ printf("[%.3f s] train stage %d, %d bits, kmeans objective %g, "
297
+ "total distance %g, beam_size %d->%d\n",
298
+ (getmillisecs() - t0) / 1000,
299
+ m,
300
+ int(nbits[m]),
301
+ obj,
302
+ sum_distances,
303
+ cur_beam_size,
304
+ new_beam_size);
305
+ }
306
+ cur_beam_size = new_beam_size;
307
+ }
308
+
309
+ is_trained = true;
310
+ }
311
+
312
+ size_t ResidualQuantizer::memory_per_point(int beam_size) const {
313
+ if (beam_size < 0) {
314
+ beam_size = max_beam_size;
315
+ }
316
+ size_t mem;
317
+ mem = beam_size * d * 2 * sizeof(float); // size for 2 beams at a time
318
+ mem += beam_size * beam_size *
319
+ (sizeof(float) +
320
+ sizeof(Index::idx_t)); // size for 1 beam search result
321
+ return mem;
322
+ }
323
+
324
+ void ResidualQuantizer::compute_codes(
325
+ const float* x,
326
+ uint8_t* codes_out,
327
+ size_t n) const {
328
+ FAISS_THROW_IF_NOT_MSG(is_trained, "RQ is not trained yet.");
329
+
330
+ size_t mem = memory_per_point();
331
+ if (n > 1 && mem * n > max_mem_distances) {
332
+ // then split queries to reduce temp memory
333
+ size_t bs = max_mem_distances / mem;
334
+ if (bs == 0) {
335
+ bs = 1; // otherwise we can't do much
336
+ }
337
+ for (size_t i0 = 0; i0 < n; i0 += bs) {
338
+ size_t i1 = std::min(n, i0 + bs);
339
+ compute_codes(x + i0 * d, codes_out + i0 * code_size, i1 - i0);
340
+ }
341
+ return;
342
+ }
343
+
344
+ std::vector<float> residuals(max_beam_size * n * d);
345
+ std::vector<int32_t> codes(max_beam_size * M * n);
346
+ std::vector<float> distances(max_beam_size * n);
347
+
348
+ refine_beam(
349
+ n,
350
+ 1,
351
+ x,
352
+ max_beam_size,
353
+ codes.data(),
354
+ residuals.data(),
355
+ distances.data());
356
+
357
+ // pack only the first code of the beam (hence the ld_codes=M *
358
+ // max_beam_size)
359
+ pack_codes(n, codes.data(), codes_out, M * max_beam_size);
360
+ }
361
+
362
+ void ResidualQuantizer::refine_beam(
363
+ size_t n,
364
+ size_t beam_size,
365
+ const float* x,
366
+ int out_beam_size,
367
+ int32_t* out_codes,
368
+ float* out_residuals,
369
+ float* out_distances) const {
370
+ int cur_beam_size = beam_size;
371
+
372
+ std::vector<float> residuals(x, x + n * d * beam_size);
373
+ std::vector<int32_t> codes;
374
+ std::vector<float> distances;
375
+ double t0 = getmillisecs();
376
+
377
+ std::unique_ptr<Index> assign_index;
378
+ if (assign_index_factory) {
379
+ assign_index.reset((*assign_index_factory)(d));
380
+ } else {
381
+ assign_index.reset(new IndexFlatL2(d));
382
+ }
383
+
384
+ for (int m = 0; m < M; m++) {
385
+ int K = 1 << nbits[m];
386
+
387
+ const float* codebooks_m =
388
+ this->codebooks.data() + codebook_offsets[m] * d;
389
+
390
+ int new_beam_size = std::min(cur_beam_size * K, out_beam_size);
391
+
392
+ std::vector<int32_t> new_codes(n * new_beam_size * (m + 1));
393
+ std::vector<float> new_residuals(n * new_beam_size * d);
394
+ distances.resize(n * new_beam_size);
395
+
396
+ beam_search_encode_step(
397
+ d,
398
+ K,
399
+ codebooks_m,
400
+ n,
401
+ cur_beam_size,
402
+ residuals.data(),
403
+ m,
404
+ codes.data(),
405
+ new_beam_size,
406
+ new_codes.data(),
407
+ new_residuals.data(),
408
+ distances.data(),
409
+ assign_index.get());
410
+
411
+ assign_index->reset();
412
+
413
+ codes.swap(new_codes);
414
+ residuals.swap(new_residuals);
415
+
416
+ cur_beam_size = new_beam_size;
417
+
418
+ if (verbose) {
419
+ float sum_distances = 0;
420
+ for (int j = 0; j < distances.size(); j++) {
421
+ sum_distances += distances[j];
422
+ }
423
+ printf("[%.3f s] encode stage %d, %d bits, "
424
+ "total error %g, beam_size %d\n",
425
+ (getmillisecs() - t0) / 1000,
426
+ m,
427
+ int(nbits[m]),
428
+ sum_distances,
429
+ cur_beam_size);
430
+ }
431
+ }
432
+
433
+ if (out_codes) {
434
+ memcpy(out_codes, codes.data(), codes.size() * sizeof(codes[0]));
435
+ }
436
+ if (out_residuals) {
437
+ memcpy(out_residuals,
438
+ residuals.data(),
439
+ residuals.size() * sizeof(residuals[0]));
440
+ }
441
+ if (out_distances) {
442
+ memcpy(out_distances,
443
+ distances.data(),
444
+ distances.size() * sizeof(distances[0]));
445
+ }
446
+ }
447
+
448
+ } // namespace faiss