use nodedb_types::vector_dtype::VectorStorageDtype;
use super::HnswIndex;
use crate::distance::dispatch::distance_typed;
use crate::distance::distance;
use crate::dtype::cast_from_f32;
use crate::hnsw::graph::MAX_LAYER_CAP;
impl HnswIndex {
pub(crate) fn random_layer(&mut self) -> usize {
let ml = 1.0 / (self.params.m as f64).ln();
let r = self.rng.next_f64().max(f64::MIN_POSITIVE);
let layer = (-r.ln() * ml).floor() as usize;
layer.min(MAX_LAYER_CAP)
}
pub(crate) fn dist_to_node(&self, query_bytes: &[u8], node_id: u32) -> f32 {
let node_bytes = self.nodes[node_id as usize].storage.as_bytes();
#[cfg(not(target_arch = "wasm32"))]
let node_bytes: &[u8] = if node_bytes.is_empty() {
if let Some(ref b) = self.backing {
if let Some(v) = b.get_vector(node_id) {
bytemuck::cast_slice(v)
} else {
node_bytes
}
} else {
node_bytes
}
} else {
node_bytes
};
distance_typed(
self.params.metric,
self.params.dtype,
query_bytes,
node_bytes,
self.dim,
)
.expect("dist_to_node: byte-length mismatch; byte lengths are validated at insert")
}
#[allow(dead_code)]
pub(crate) fn dist_to_node_f32(&self, query: &[f32], node_id: u32) -> f32 {
match self.params.dtype {
VectorStorageDtype::F32 => distance(
query,
self.nodes[node_id as usize]
.storage
.as_f32_slice()
.expect("F32 dtype must have F32 storage"),
self.params.metric,
),
_ => {
let query_bytes = cast_from_f32(query, self.params.dtype);
self.dist_to_node(&query_bytes, node_id)
}
}
}
pub(crate) fn max_neighbors(&self, layer: usize) -> usize {
if layer == 0 {
self.params.m0
} else {
self.params.m
}
}
}