How Lazy Dimension Initialization Works in TurboQuantIndex

TurboQuantIndex supports lazy dimension initialization by deferring dimension assignment until the first batch insertion, using Option<usize> to represent an unset state and OnceLock to delay expensive structural allocations until the dimension is known.

The turbovec crate provides a Rust-native vector search implementation where the TurboQuantIndex struct can be constructed without prior knowledge of vector dimensionality. According to the source code in turbovec/src/lib.rs, this pattern allows flexible index creation while ensuring type safety and zero-allocation overhead until the first data batch arrives.

The Lazy Initialization Pattern

TurboQuantIndex implements lazy dimension initialization through an Option<usize> field named dim. When constructed via the lazy constructor, this field starts as None, indicating that the index dimensionality remains unspecified.

Creating a Lazy Index with new_lazy

The TurboQuantIndex::new_lazy method, defined in turbovec/src/lib.rs at lines 54–71, validates that the requested bit-width belongs to the set {2, 3, 4} and returns an index instance where dim is None. At this stage, all internal buffers remain uninitialized empty vectors or OnceLock instances, consuming minimal memory.

/// In turbovec/src/lib.rs
pub fn new_lazy(bit_width: usize) -> Result<Self, TurboError> {
    if ![2, 3, 4].contains(&bit_width) {
        return Err(TurboError::InvalidBitWidth);
    }
    Ok(Self {
        dim: None,
        // ... other fields set to Vec::new() or OnceLock::new()
    })
}

Locking the Dimension on First Insertion

The dimensionality resolves only when add_2d receives its first batch of vectors. This method checks if self.dim is None, sets it to Some(dim) using the provided dimension parameter, allocates the rotation matrix and codebook, then delegates to the standard addition logic. Subsequent calls to add or add_2d use this locked dimension; calling add before the initial add_2d triggers a panic with a clear error message.

Deferred Structural Allocation with OnceLock

Beyond the dimension field itself, heavy auxiliary structures—including rotation matrices, centroid boundaries, and codebooks—are stored as OnceLock<T> fields. These structures initialize on-demand during the first add_2d operation, ensuring that memory-intensive allocations occur only after the dimensionality becomes known. This design mirrors the lazy dimension handling, preventing premature resource consumption.

Practical Code Example

The following pattern demonstrates how to initialize a lazy index, infer dimensions from the first batch, and continue with standard additions:

// 1️⃣ Create a lazy index (no dimension yet)
let mut idx = TurboQuantIndex::new_lazy(4).expect("valid bit‑width");

// 2️⃣ First insertion – the dimension is inferred and locked
let vectors = vec![0.1_f32, 0.2, 0.3, 0.4, 0.5, 0.6]; // 2‑dimensional data
idx.add_2d(&vectors, 2).expect("add succeeds");

// 3️⃣ Subsequent insertion – dimension is already known
let more_vectors = vec![0.7_f32, 0.8, 0.9, 1.0];
idx.add(&more_vectors); // works because `dim` is now Some(2)

The add_2d method expects a flattened vector slice and an explicit dim parameter. After the first successful call, the index stores Some(2), allowing the simpler add method to accept subsequent vectors without repeating the dimension argument.

Wrapper Type Integration

The lazy initialization pattern extends to wrapper APIs. In turbovec/src/id_map.rs, the IdMapIndex struct forwards its lazy constructor directly to TurboQuantIndex::new_lazy, exposing the same deferred dimension semantics to users requiring ID remapping capabilities. Additionally, the Python bindings in turbovec-python/src/lib.rs surface this functionality to Python callers through equivalent lazy constructor methods.

Summary

  • Deferred dimension assignment: TurboQuantIndex starts with dim: None and requires no upfront vector size.
  • First-batch locking: The add_2d method simultaneously sets the dimension and initializes structural caches.
  • Resource efficiency: OnceLock fields ensure rotation matrices and codebooks allocate only after dimensionality is established.
  • Safety guarantees: Attempting to call add before the initial add_2d produces an explicit panic rather than silent failure.

Frequently Asked Questions

What is lazy dimension initialization in vector databases?

Lazy dimension initialization allows creating a vector index without specifying the embedding size upfront. In turbovec, this enables runtime dimension inference from the first data batch rather than requiring compile-time or construction-time constants.

How does TurboQuantIndex infer the dimension from the first batch?

The add_2d method receives an explicit dim parameter alongside the vector data. When self.dim is None, the implementation writes Some(dim) to the field and initializes dependant structures. This locks the dimension for the index's lifetime.

What happens if I call add before add_2d on a lazy index?

The code panics with a descriptive error because add assumes self.dim is Some(dim). This guard ensures consistent dimensionality across all stored vectors and prevents undefined behavior from mixing different dimensionalities.

Can I reset the dimension after initialization?

No. Once add_2d sets self.dim to Some(dim), subsequent calls validate that new batches match the locked dimension. Attempting to insert a different dimensionality results in an error, maintaining index integrity.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →