How to Handle Float64 Arrays in Turbovec: Casting to Float32

Turbovec's Python and Rust APIs strictly enforce float32 inputs and will raise errors or panic if float64 arrays are passed without an explicit cast to float32 first.

If your pipeline produces NumPy float64 embeddings or Rust Vec<f64> vectors, you must explicitly cast them before indexing. Turbovec is optimized strictly for 32-bit floating-point storage and SIMD search, so learning how to handle float64 arrays in turbovec is essential for integrating standard double-precision outputs without runtime errors.

Why Turbovec Requires Float32

Turbovec is engineered around 32-bit floating-point vectors to minimize memory footprint and power its hand-written SIMD kernels. In turbovec/src/lib.rs, the public Rust API—methods such as TurboQuantIndex::add and TurboQuantIndex::search—accepts slices of f32 (&[f32]) and validates the input type, panicking when a different precision is supplied. The Python bindings mirror this contract, documenting in README.md lines 44-45 that vectors and queries must be 2-D float32 arrays and that other dtypes are rejected rather than silently converted.

How to Cast Float64 Arrays in Python

According to the README.md, you must preemptively convert NumPy arrays with np.asarray(x, dtype=np.float32). This cast is computationally cheap and preserves the algorithmic correctness of nearest-neighbor search, which depends on vector direction rather than absolute scalar magnitude.

import numpy as np
from turbovec import TurboQuantIndex

# Suppose `vectors64` is a NumPy array with dtype=float64

vectors64 = np.random.rand(1000, 1536)          # float64 by default

queries64  = np.random.rand(10, 1536)

# Cast to float32 before creating the index

vectors32 = np.asarray(vectors64, dtype=np.float32)
queries32 = np.asarray(queries64, dtype=np.float32)

index = TurboQuantIndex(dim=1536, bit_width=4)
index.add(vectors32)                # OK

scores, ids = index.search(queries32, k=10)   # OK

How to Cast Float64 Arrays in Rust

On the Rust side, turbovec/src/lib.rs lines 72-78 implement the type enforcement that restricts the public API to &[f32]. If your source data arrives as f64, iterate through the collection and cast each element to f32 before flattening into a contiguous slice.

use turbovec::TurboQuantIndex;

// Example `f64` data (could come from any source)
let vectors_f64: Vec<Vec<f64>> = (0..1000)
    .map(|_| (0..1536).map(|_| rand::random::<f64>()).collect())
    .collect();

// Convert to `f32` – one-by-one or with an iterator
let vectors_f32: Vec<Vec<f32>> = vectors_f64
    .iter()
    .map(|row| row.iter().map(|&x| x as f32).collect())
    .collect();

// Flatten into a single slice if the API expects `&[f32]`
let flat_f32: Vec<f32> = vectors_f32.iter().flat_map(|r| r.iter()).cloned().collect();

let mut index = TurboQuantIndex::new(1536, 4).unwrap();
index.add(&flat_f32).unwrap();                // Works with f32 slices only

Converting Float64 Data for Command-Line Usage

If you are feeding serialized arrays to a Turbovec binary via .npy files, convert the file offline with NumPy before loading it into the Rust process. The one-liner below performs the cast without loading the full array into an interactive session.


# Convert a .npy file from float64 to float32 using NumPy, then feed it to turbovec

python -c "import numpy as np, sys; a = np.load('vectors64.npy'); np.save('vectors32.npy', a.astype(np.float32))"

# Now the Rust binary can load `vectors32.npy` without error

Internal Precision vs. Public API

While the public API remains locked to f32 for storage efficiency, some internal routines temporarily promote to higher precision. For example, turbovec/src/rotation.rs lines 19-46 performs rotation-matrix calculations using f64 internally. This pattern is also echoed in the test suite: turbovec/tests/io_v4.rs lines 58-59 demonstrate converting raw state through intermediate f64 casts before landing on f32. The takeaway is that your application should handle the float64 to float32 reduction at the boundary, not inside the library.

Summary

  • Turbovec's core is f32-only: The Rust crate in turbovec/src/lib.rs and the Python bindings both reject non-float32 inputs at the API boundary.
  • Explicit casting is required: Use np.asarray(x, dtype=np.float32) in Python or element-wise as f32 in Rust before calling TurboQuantIndex::add or TurboQuantIndex::search.
  • File workflow: Pre-convert serialized .npy files from float64 to float32 before loading them into Turbovec CLI tools.
  • Correctness is preserved: The cast does not affect nearest-neighbor accuracy because quantization and search rely on vector direction, not absolute magnitude.

Frequently Asked Questions

Does Turbovec support float64 arrays natively?

No. As implemented in RyanCodrai/turbovec, the public API in turbovec/src/lib.rs accepts only &[f32] slices, and the Python bindings require 2-D float32 NumPy arrays. Passing float64 data results in an explicit error or panic rather than a silent conversion.

What happens if I pass a float64 array without casting?

The library validates dtypes at the boundary. In Python, the binding returns an error; in Rust, turbovec/src/lib.rs enforces the f32 contract and will panic if a different precision is supplied. This strict behavior prevents accidental memory misinterpretation.

Is casting from float64 to float32 expensive?

No. The conversion is a cheap per-element reinterpretation that runs in linear time relative to the number of vector dimensions. Because Turbovec's quantization algorithms depend on vector direction rather than absolute scalar magnitude, the cast does not degrade search quality.

Why does Turbovec use f64 in some internal files if the API is f32?

Internal calculations—such as those in turbovec/src/rotation.rs—may temporarily promote values to f64 for numerical stability when building rotation matrices. However, the public surface stays f32 to keep index memory low and to align with the hand-optimized SIMD kernels.

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 →