Compute asymmetric L2 distance from a prepared query to a BBQ-encoded candidate. The query is the exact centered FP32 vector. The stored candidate is reconstructed from its sign bits and `residual_norm` (each dim ≈ ±norm/√dim). Returns L2 distance between them. Expects `PreparedQuery::Bytes` produced by `prepare_query`.
(
&self,
prepared: &PreparedQuery,
encoded: &[u8],
)
| 182 | /// |
| 183 | /// Expects `PreparedQuery::Bytes` produced by `prepare_query`. |
| 184 | fn distance_prepared( |
| 185 | &self, |
| 186 | prepared: &PreparedQuery, |
| 187 | encoded: &[u8], |
| 188 | ) -> Result<f32, RerankError> { |
| 189 | let payload = match prepared { |
| 190 | PreparedQuery::Bytes(b) => b.as_slice(), |
| 191 | _ => { |
| 192 | return Err(RerankError::BadInput( |
| 193 | "bbq distance: prepared query is not Bytes".to_string(), |
| 194 | )); |
| 195 | } |
| 196 | }; |
| 197 | |
| 198 | let (_query_norm, centered) = decode_payload(payload, self.dim)?; |
| 199 | |
| 200 | let packed_len = self.dim.div_ceil(8); |
| 201 | let uqv_ref = UnifiedQuantizedVectorRef::from_bytes(encoded, packed_len).map_err(|e| { |
| 202 | RerankError::BadInput(format!("bbq distance: failed to parse encoded bytes: {e}")) |
| 203 | })?; |
| 204 | |
| 205 | let header = uqv_ref.header(); |
| 206 | let recon = bbq_dequantize(uqv_ref.packed_bits(), header.residual_norm, self.dim); |
| 207 | let dist = centered |
| 208 | .iter() |
| 209 | .zip(recon.iter()) |
| 210 | .map(|(&a, &b)| (a - b) * (a - b)) |
| 211 | .sum::<f32>() |
| 212 | .sqrt(); |
| 213 | Ok(dist) |
| 214 | } |
| 215 | |
| 216 | fn name(&self) -> CodecName { |
| 217 | CodecName::Bbq |