use core::fmt::Debug;
use diskann::ANNResult;
use diskann_providers::model::FixedChunkPQTable;
use diskann_quantization::{error::Format, product::TransposedTable};
use diskann_utils::views::Matrix;
use crate::error::{diskann_error, ErrorKind};
#[derive(Debug)]
pub struct PQData {
pq_pivot_table: TransposedTable,
pq_compressed_data: Matrix<u8>,
}
impl PQData {
pub fn new(
pq_pivot_table: FixedChunkPQTable,
pq_compressed_data: Matrix<u8>,
) -> ANNResult<Self> {
let pq_pivot_table = TransposedTable::from_parts(
pq_pivot_table.view_pivots(),
pq_pivot_table.view_offsets().to_owned(),
)
.map_err(|err| diskann_error!(ErrorKind::PQError, "{}", Format(err)))?;
Ok(Self {
pq_pivot_table,
pq_compressed_data,
})
}
pub fn pq_table(&self) -> &TransposedTable {
&self.pq_pivot_table
}
pub fn get_dim(&self) -> usize {
self.pq_pivot_table.dim()
}
pub fn get_num_chunks(&self) -> usize {
self.pq_pivot_table.nchunks()
}
pub fn get_num_centers(&self) -> usize {
self.pq_pivot_table.ncenters()
}
pub fn pq_compressed_data(&self) -> &Matrix<u8> {
&self.pq_compressed_data
}
pub fn get_compressed_vector(&self, vector_id: usize) -> ANNResult<&[u8]> {
self.pq_compressed_data.get_row(vector_id).ok_or_else(|| {
diskann_error!(
ErrorKind::IndexError,
"Vector id is out of boundary in the compressed dataset."
)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_pq_data() -> ANNResult<PQData> {
let dim = 2;
let pq_pivot_table =
FixedChunkPQTable::new(dim, Box::new([0.0, 0.0, 1.0, 1.0]), Box::new([0, 2])).unwrap();
let pq_compressed_data = Matrix::try_from(Box::new([123u8, 111, 255]) as Box<[u8]>, 3, 1)
.expect("valid matrix shape");
PQData::new(pq_pivot_table, pq_compressed_data)
}
#[test]
fn test_get_compressed_vector() {
let dataset = create_pq_data().unwrap();
let vector_id = 0;
let result = dataset.get_compressed_vector(vector_id).unwrap();
assert_eq!(result, &[123]);
let vector_id = 1;
let result = dataset.get_compressed_vector(vector_id).unwrap();
assert_eq!(result, &[111]);
let vector_id = 2;
let result = dataset.get_compressed_vector(vector_id).unwrap();
assert_eq!(result, &[255]);
}
#[test]
fn test_get_num_chunks() {
let dataset = create_pq_data().unwrap();
assert_eq!(dataset.get_num_chunks(), 1);
}
#[test]
fn test_get_num_centers() {
let dataset = create_pq_data().unwrap();
assert_eq!(dataset.get_num_centers(), 2);
}
}