use std::borrow::Cow;
use crate::common::types::ScoreType;
use crate::quantization::turboquant::quantization::TurboQuantizer;
use crate::quantization::turboquant::{EncodedQueryTQ, TQBits, TQMode, TQRotation};
use crate::segment::data_types::named_vectors::CowVector;
use crate::segment::data_types::vectors::{DenseVector, VectorElementType};
use crate::segment::spaces::metric::Metric;
use crate::segment::spaces::simple::{CosineMetric, DotProductMetric, EuclidMetric, ManhattanMetric};
use crate::segment::types::Distance;
pub(crate) const TQDT_BITS: TQBits = TQBits::Bits4;
pub(crate) const TQDT_MODE: TQMode = TQMode::Normal;
pub(crate) const TQDT_ROTATION: TQRotation = TQRotation::Unpadded;
pub(crate) const VECTORS_PATH: &str = "tq_vectors.dat";
pub(crate) const VECTORS_DIR_PATH: &str = "tq_vectors";
pub(crate) const DELETED_DIR_PATH: &str = "deleted";
pub(super) fn build_quantizer(dim: usize, distance: Distance) -> TurboQuantizer {
TurboQuantizer::new(
dim,
TQDT_BITS,
TQDT_MODE,
crate::quantization::DistanceType::from(distance),
TQDT_ROTATION,
None,
)
}
pub fn turbo_storage_roundtrip(vector: &[f32], distance: Distance) -> Vec<f32> {
let dim = vector.len();
let quantizer = build_quantizer(dim, distance);
let mut buf = vec![0.0; quantizer.get_padded_dim()];
let encoded = quantizer.quantize(vector, &mut buf);
let mut dequantized = quantizer.dequantize::<f64>(&encoded);
quantizer.apply_inverse_rotation(&mut dequantized);
dequantized[..dim].iter().map(|&x| x as f32).collect()
}
pub(super) fn invert_score(distance: Distance) -> bool {
matches!(distance, Distance::Euclid | Distance::Manhattan)
}
pub(super) fn preprocess_query(
quantizer: &TurboQuantizer,
distance: Distance,
query: DenseVector,
) -> EncodedQueryTQ {
let preprocessed = match distance {
Distance::Cosine => <CosineMetric as Metric<VectorElementType>>::preprocess(query),
Distance::Euclid => <EuclidMetric as Metric<VectorElementType>>::preprocess(query),
Distance::Dot => <DotProductMetric as Metric<VectorElementType>>::preprocess(query),
Distance::Manhattan => <ManhattanMetric as Metric<VectorElementType>>::preprocess(query),
};
quantizer.precompute_query(&preprocessed)
}
pub(super) fn score_query_bytes(
quantizer: &TurboQuantizer,
distance: Distance,
query: &EncodedQueryTQ,
bytes: &[u8],
) -> ScoreType {
let score = quantizer.score_precomputed(query, bytes);
if invert_score(distance) {
-score
} else {
score
}
}
pub(super) fn score_symmetric_bytes(
quantizer: &TurboQuantizer,
distance: Distance,
a: &[u8],
b: &[u8],
) -> ScoreType {
let score = quantizer.score_symmetric(a, b);
if invert_score(distance) {
-score
} else {
score
}
}
pub(super) fn dequantize_vector<'a>(
quantizer: &TurboQuantizer,
dim: usize,
quantized: &[u8],
) -> CowVector<'a> {
let mut dequantized = quantizer.dequantize::<f64>(quantized);
quantizer.apply_inverse_rotation(&mut dequantized);
CowVector::Dense(Cow::Owned(
dequantized[..dim].iter().map(|i| *i as f32).collect(),
))
}
pub(super) fn dequantize_for_requantization(
quantizer: &TurboQuantizer,
dim: usize,
quantized: &[u8],
keep_rotated: bool,
) -> DenseVector {
if keep_rotated {
let mut dequantized = quantizer.dequantize::<VectorElementType>(quantized);
dequantized.truncate(dim);
dequantized
} else {
let mut dequantized = quantizer.dequantize::<f64>(quantized);
quantizer.apply_inverse_rotation(&mut dequantized);
dequantized[..dim]
.iter()
.map(|&x| x as VectorElementType)
.collect()
}
}