1616#include < faiss/impl/IDSelector.h>
1717#include < faiss/impl/RaBitQUtils.h>
1818#include < faiss/impl/fast_scan/FastScanDistancePostProcessing.h>
19- #include < faiss/impl/fast_scan/pq4_fast_scan .h>
19+ #include < faiss/impl/fast_scan/fast_scan .h>
2020#include < faiss/impl/fast_scan/simd_result_handlers.h>
2121#include < faiss/utils/hamming.h>
2222#include < faiss/utils/quantize_lut.h>
2323#include < faiss/utils/utils.h>
2424
2525namespace faiss {
2626
27- using namespace simd_result_handlers ;
28-
2927inline size_t roundup (size_t a, size_t b) {
3028 return (a + b - 1 ) / b * b;
3129}
@@ -211,43 +209,18 @@ void estimators_from_tables_generic(
211209
212210} // anonymous namespace
213211
214- // Default implementation of make_knn_handler with centralized fallback logic
215- SIMDResultHandlerToFloat* IndexFastScan::make_knn_handler (
212+ std::unique_ptr<FastScanCodeScanner> IndexFastScan::make_knn_scanner (
216213 bool is_max,
217- int impl,
218214 idx_t n,
219215 idx_t k,
220216 size_t ntotal,
221217 float * distances,
222218 idx_t * labels,
223219 const IDSelector* sel,
220+ int impl,
224221 const FastScanDistancePostProcessing&) const {
225- // Create default handlers based on k and impl
226- if (is_max) {
227- using HeapHC = HeapHandler<CMax<uint16_t , int >, false >;
228- using ReservoirHC = ReservoirHandler<CMax<uint16_t , int >, false >;
229- using SingleResultHC = SingleResultHandler<CMax<uint16_t , int >, false >;
230-
231- if (k == 1 ) {
232- return new SingleResultHC (n, ntotal, distances, labels, sel);
233- } else if (impl % 2 == 0 ) {
234- return new HeapHC (n, ntotal, k, distances, labels, sel);
235- } else {
236- return new ReservoirHC (n, ntotal, k, 2 * k, distances, labels, sel);
237- }
238- } else {
239- using HeapHC = HeapHandler<CMin<uint16_t , int >, false >;
240- using ReservoirHC = ReservoirHandler<CMin<uint16_t , int >, false >;
241- using SingleResultHC = SingleResultHandler<CMin<uint16_t , int >, false >;
242-
243- if (k == 1 ) {
244- return new SingleResultHC (n, ntotal, distances, labels, sel);
245- } else if (impl % 2 == 0 ) {
246- return new HeapHC (n, ntotal, k, distances, labels, sel);
247- } else {
248- return new ReservoirHC (n, ntotal, k, 2 * k, distances, labels, sel);
249- }
250- }
222+ return make_fast_scan_knn_scanner (
223+ is_max, impl, n, ntotal, k, distances, labels, sel);
251224}
252225
253226using namespace quantize_lut ;
@@ -468,7 +441,6 @@ void IndexFastScan::search_implem_12(
468441 idx_t * labels,
469442 int impl,
470443 const FastScanDistancePostProcessing& context) const {
471- using RH = ResultHandlerCompare<C, false >;
472444 FAISS_THROW_IF_NOT (bbs == 32 );
473445
474446 // handle qbs2 blocking by recursive call
@@ -519,36 +491,26 @@ void IndexFastScan::search_implem_12(
519491 pq4_pack_LUT_qbs (qbs, M2, quantized_dis_tables.get (), LUT.get ());
520492 FAISS_THROW_IF_NOT (LUT_nq == n);
521493
522- std::unique_ptr<RH> handler (
523- static_cast <RH*>(make_knn_handler (
524- C::is_max,
525- impl,
526- n,
527- k,
528- ntotal,
529- distances,
530- labels,
531- nullptr ,
532- context)));
533-
534- handler->disable = bool (skip & 2 );
535- handler->normalizers = normalizers.get ();
536-
537- if (skip & 4 ) {
538- // pass
539- } else {
540- pq4_accumulate_loop_qbs (
494+ auto scanner = make_knn_scanner (
495+ C::is_max, n, k, ntotal, distances, labels, nullptr , impl, context);
496+ auto * rh = scanner->handler ();
497+ rh->normalizers = normalizers.get ();
498+ // Note: skip & 2 previously set handler->disable (run kernel,
499+ // discard results). Through the scanner path, skip & 2 now skips
500+ // the kernel entirely (same as skip & 4), since disable is not
501+ // accessible through the SIMDResultHandlerToFloat* interface.
502+ if (!(skip & (2 | 4 ))) {
503+ scanner->accumulate_loop_qbs (
541504 qbs,
542505 ntotal2,
543506 M2,
544507 codes.get (),
545508 LUT.get (),
546- *handler.get (),
547509 context.pq2x4_scale ,
548510 get_block_stride ());
549511 }
550512 if (!(skip & 8 )) {
551- handler ->end ();
513+ rh ->end ();
552514 }
553515}
554516
@@ -563,7 +525,6 @@ void IndexFastScan::search_implem_14(
563525 idx_t * labels,
564526 int impl,
565527 const FastScanDistancePostProcessing& context) const {
566- using RH = ResultHandlerCompare<C, false >;
567528 FAISS_THROW_IF_NOT (bbs % 32 == 0 );
568529
569530 int qbs2 = qbs == 0 ? 4 : qbs;
@@ -603,36 +564,27 @@ void IndexFastScan::search_implem_14(
603564 AlignedTable<uint8_t > LUT (n * dim12);
604565 pq4_pack_LUT (n, M2, quantized_dis_tables.get (), LUT.get ());
605566
606- std::unique_ptr<RH> handler (
607- static_cast <RH*>(make_knn_handler (
608- C::is_max,
609- impl,
610- n,
611- k,
612- ntotal,
613- distances,
614- labels,
615- nullptr ,
616- context)));
617- handler->disable = bool (skip & 2 );
618- handler->normalizers = normalizers.get ();
619-
620- if (skip & 4 ) {
621- // pass
622- } else {
623- pq4_accumulate_loop (
567+ auto scanner = make_knn_scanner (
568+ C::is_max, n, k, ntotal, distances, labels, nullptr , impl, context);
569+ auto * rh = scanner->handler ();
570+ rh->normalizers = normalizers.get ();
571+ // Note: skip & 2 previously set handler->disable (run kernel,
572+ // discard results). Through the scanner path, skip & 2 now skips
573+ // the kernel entirely (same as skip & 4), since disable is not
574+ // accessible through the SIMDResultHandlerToFloat* interface.
575+ if (!(skip & (2 | 4 ))) {
576+ scanner->accumulate_loop (
624577 n,
625578 ntotal2,
626579 bbs,
627580 M2,
628581 codes.get (),
629582 LUT.get (),
630- *handler.get (),
631583 context.pq2x4_scale ,
632584 get_block_stride ());
633585 }
634586 if (!(skip & 8 )) {
635- handler ->end ();
587+ rh ->end ();
636588 }
637589}
638590
0 commit comments