weavatrix-search-vector 0.3.1

Persistent, mutable, bounded vector candidate search for Rust and Weavatrix
Documentation
use super::MappedVectorIndex;
use super::format::to_usize;
use crate::error::SearchError;
use crate::hnsw::{Graph, NodeLinks, RoutingIndex, VectorIndex};
use crate::vector::VectorStore;

impl MappedVectorIndex {
    /// Materializes the mapped index without rebuilding its graph.
    ///
    /// # Errors
    ///
    /// Returns an allocation, integrity, or config error.
    pub fn to_owned(&self) -> Result<VectorIndex, SearchError> {
        let vectors = VectorStore::from_values(
            self.header.config.dimensions,
            self.header.config.metric,
            self.key_slice().to_vec(),
            self.vector_slice().to_vec(),
        )?;
        let graphs = self.materialize_graphs()?;
        let routing = RoutingIndex {
            entries: self
                .routing_codes()
                .iter()
                .copied()
                .zip(self.routing_nodes().iter().copied())
                .collect(),
        };
        VectorIndex::from_parts(self.header.config.clone(), vectors, graphs, routing)
    }

    fn materialize_graphs(&self) -> Result<Vec<Graph>, SearchError> {
        let mut graphs = Vec::new();
        graphs
            .try_reserve_exact(self.graphs.len())
            .map_err(|_| SearchError::AllocationFailed)?;
        for graph in &self.graphs {
            let node_layers = graph.node_layers(&self.mapping);
            let layer_neighbors = graph.layer_neighbors(&self.mapping);
            let neighbors = graph.neighbors(&self.mapping);
            let mut nodes = Vec::new();
            nodes
                .try_reserve_exact(self.len())
                .map_err(|_| SearchError::AllocationFailed)?;
            for node in 0..self.len() {
                let layer_start = to_usize(node_layers[node])?;
                let layer_end = to_usize(node_layers[node + 1])?;
                let mut layers = Vec::new();
                layers
                    .try_reserve_exact(layer_end.saturating_sub(layer_start))
                    .map_err(|_| SearchError::AllocationFailed)?;
                for layer in layer_start..layer_end {
                    let start = to_usize(layer_neighbors[layer])?;
                    let end = to_usize(layer_neighbors[layer + 1])?;
                    layers.push(neighbors[start..end].to_vec());
                }
                nodes.push(NodeLinks { layers });
            }
            graphs.push(Graph {
                entry: graph.entry,
                max_level: graph.max_level,
                nodes,
            });
        }
        Ok(graphs)
    }
}