@@ -621,13 +621,90 @@ struct Quantizer8bitDirect<8> : Quantizer8bitDirect<1> {
621621
622622 FAISS_ALWAYS_INLINE float32x4x2_t
623623 reconstruct_8_components (const uint8_t * code, int i) const {
624- float32_t result[8 ] = {};
625- for (size_t j = 0 ; j < 8 ; j++) {
626- result[j] = code[i + j];
624+ uint8x8_t x8 = vld1_u8 ((const uint8_t *)(code + i));
625+ uint16x8_t y8 = vmovl_u8 (x8);
626+ uint16x4_t y8_0 = vget_low_u16 (y8);
627+ uint16x4_t y8_1 = vget_high_u16 (y8);
628+
629+ // convert uint16 -> uint32 -> fp32
630+ return {vcvtq_f32_u32 (vmovl_u16 (y8_0)), vcvtq_f32_u32 (vmovl_u16 (y8_1))};
631+ }
632+ };
633+
634+ #endif
635+
636+ /* ******************************************************************
637+ * 8bit_direct_signed quantizer
638+ *******************************************************************/
639+
640+ template <int SIMDWIDTH >
641+ struct Quantizer8bitDirectSigned {};
642+
643+ template <>
644+ struct Quantizer8bitDirectSigned <1 > : ScalarQuantizer::SQuantizer {
645+ const size_t d;
646+
647+ Quantizer8bitDirectSigned (size_t d, const std::vector<float >& /* unused */ )
648+ : d(d) {}
649+
650+ void encode_vector (const float * x, uint8_t * code) const final {
651+ for (size_t i = 0 ; i < d; i++) {
652+ code[i] = (uint8_t )(x[i] + 128 );
627653 }
628- float32x4_t res1 = vld1q_f32 (result);
629- float32x4_t res2 = vld1q_f32 (result + 4 );
630- return {res1, res2};
654+ }
655+
656+ void decode_vector (const uint8_t * code, float * x) const final {
657+ for (size_t i = 0 ; i < d; i++) {
658+ x[i] = code[i] - 128 ;
659+ }
660+ }
661+
662+ FAISS_ALWAYS_INLINE float reconstruct_component (const uint8_t * code, int i)
663+ const {
664+ return code[i] - 128 ;
665+ }
666+ };
667+
668+ #ifdef __AVX2__
669+
670+ template <>
671+ struct Quantizer8bitDirectSigned <8 > : Quantizer8bitDirectSigned<1 > {
672+ Quantizer8bitDirectSigned (size_t d, const std::vector<float >& trained)
673+ : Quantizer8bitDirectSigned<1 >(d, trained) {}
674+
675+ FAISS_ALWAYS_INLINE __m256
676+ reconstruct_8_components (const uint8_t * code, int i) const {
677+ __m128i x8 = _mm_loadl_epi64 ((__m128i*)(code + i)); // 8 * int8
678+ __m256i y8 = _mm256_cvtepu8_epi32 (x8); // 8 * int32
679+ __m256i c8 = _mm256_set1_epi32 (128 );
680+ __m256i z8 = _mm256_sub_epi32 (y8, c8); // subtract 128 from all lanes
681+ return _mm256_cvtepi32_ps (z8); // 8 * float32
682+ }
683+ };
684+
685+ #endif
686+
687+ #ifdef __aarch64__
688+
689+ template <>
690+ struct Quantizer8bitDirectSigned <8 > : Quantizer8bitDirectSigned<1 > {
691+ Quantizer8bitDirectSigned (size_t d, const std::vector<float >& trained)
692+ : Quantizer8bitDirectSigned<1 >(d, trained) {}
693+
694+ FAISS_ALWAYS_INLINE float32x4x2_t
695+ reconstruct_8_components (const uint8_t * code, int i) const {
696+ uint8x8_t x8 = vld1_u8 ((const uint8_t *)(code + i));
697+ uint16x8_t y8 = vmovl_u8 (x8); // convert uint8 -> uint16
698+ uint16x4_t y8_0 = vget_low_u16 (y8);
699+ uint16x4_t y8_1 = vget_high_u16 (y8);
700+
701+ float32x4_t z8_0 = vcvtq_f32_u32 (
702+ vmovl_u16 (y8_0)); // convert uint16 -> uint32 -> fp32
703+ float32x4_t z8_1 = vcvtq_f32_u32 (vmovl_u16 (y8_1));
704+
705+ // subtract 128 to convert into signed numbers
706+ return {vsubq_f32 (z8_0, vmovq_n_f32 (128.0 )),
707+ vsubq_f32 (z8_1, vmovq_n_f32 (128.0 ))};
631708 }
632709};
633710
@@ -660,6 +737,8 @@ ScalarQuantizer::SQuantizer* select_quantizer_1(
660737 return new QuantizerBF16<SIMDWIDTH >(d, trained);
661738 case ScalarQuantizer::QT_8bit_direct:
662739 return new Quantizer8bitDirect<SIMDWIDTH >(d, trained);
740+ case ScalarQuantizer::QT_8bit_direct_signed:
741+ return new Quantizer8bitDirectSigned<SIMDWIDTH >(d, trained);
663742 }
664743 FAISS_THROW_MSG (" unknown qtype" );
665744}
@@ -1460,6 +1539,11 @@ SQDistanceComputer* select_distance_computer(
14601539 Sim,
14611540 SIMDWIDTH >(d, trained);
14621541 }
1542+ case ScalarQuantizer::QT_8bit_direct_signed:
1543+ return new DCTemplate<
1544+ Quantizer8bitDirectSigned<SIMDWIDTH >,
1545+ Sim,
1546+ SIMDWIDTH >(d, trained);
14631547 }
14641548 FAISS_THROW_MSG (" unknown qtype" );
14651549 return nullptr ;
@@ -1483,6 +1567,7 @@ void ScalarQuantizer::set_derived_sizes() {
14831567 case QT_8bit:
14841568 case QT_8bit_uniform:
14851569 case QT_8bit_direct:
1570+ case QT_8bit_direct_signed:
14861571 code_size = d;
14871572 bits = 8 ;
14881573 break ;
@@ -1540,6 +1625,7 @@ void ScalarQuantizer::train(size_t n, const float* x) {
15401625 case QT_fp16:
15411626 case QT_8bit_direct:
15421627 case QT_bf16:
1628+ case QT_8bit_direct_signed:
15431629 // no training necessary
15441630 break ;
15451631 }
@@ -1885,6 +1971,11 @@ InvertedListScanner* sel1_InvertedListScanner(
18851971 Similarity,
18861972 SIMDWIDTH >>(sq, quantizer, store_pairs, sel, r);
18871973 }
1974+ case ScalarQuantizer::QT_8bit_direct_signed:
1975+ return sel2_InvertedListScanner<DCTemplate<
1976+ Quantizer8bitDirectSigned<SIMDWIDTH >,
1977+ Similarity,
1978+ SIMDWIDTH >>(sq, quantizer, store_pairs, sel, r);
18881979 }
18891980
18901981 FAISS_THROW_MSG (" unknown qtype" );
0 commit comments