# How Lazy Dimension Initialization Works in TurboQuantIndex

> Discover how TurboQuantIndex implements lazy dimension initialization, delaying dimension assignment until the first batch insertion for optimized performance.

- Repository: [Ryan Codrai/turbovec](https://github.com/RyanCodrai/turbovec)
- Tags: internals
- Published: 2026-07-27

---

**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`](https://github.com/RyanCodrai/turbovec/blob/main/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`](https://github.com/RyanCodrai/turbovec/blob/main/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.

```rust
/// 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:

```rust
// 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`](https://github.com/RyanCodrai/turbovec/blob/main/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`](https://github.com/RyanCodrai/turbovec/blob/main/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.