ann_router.backends.turbovec_backend module
turbovec backend: the dynamic-corpus specialist.
turbovec (Rust + PyO3, ships wheels on PyPI incl. Apple Silicon) is the engine
the router reaches for when the corpus changes constantly: it supports O(1)
add_with_ids and remove(id) with no index rebuild, and its TurboQuant
2-4 bit quantisation gives ~16x compression while keeping recall above
FAISS-PQ. That combination (mutable and compact and fast on Apple Silicon)
is what earns it the “frequent updates” branch of the policy, ahead of the
graph indexes whose deletes rot the structure.
This is the extracted, packaged form of the brute-force → turbovec routing that
already ships inside the roitelet prototype’s core/personal.py.
Consumes: turbovec (optional, pip install 'ann-router[turbovec]').
Produces: TurboVecIndex.
Author: Warith Harchaoui <warith.harchaoui@deraison.ai>
- class ann_router.backends.turbovec_backend.TurboVecIndex(dim, metric='cosine', **kwargs)[source]
Bases:
ANNIndexturbovec
IdMapIndex: mutable, quantised, id-native.turbovec is id-native (
add_with_ids/remove(id)) and returns(distances, ids)fromsearch— this adapter flips that to the package’s(ids, distances)order. Vectors are normalised for cosine so the quantiser’s inner product matches cosine similarity.- Parameters:
dim (int) – Embedding dimensionality.
metric ({"cosine", "l2", "ip"}, optional) – Distance metric. Defaults to
"cosine". turbovec is inner-product / cosine oriented; L2 is approximated on normalised vectors.bit_width (int, optional) – TurboQuant bit width (2 or 4). Defaults to 4 — the recall/size sweet spot measured in the roitelet study.
kwargs (object)
Examples
>>> TurboVecIndex.capabilities().supports_remove True
- add(vectors)[source]
Append vectors with the next contiguous ids.
- Parameters:
vectors (numpy.ndarray) – Shape
(m, dim).- Raises:
RuntimeError – If called on an index that was populated via
load()with no subsequentbuild()/add_with_ids()call in this process — the high-water mark can’t be recovered from disk (seeload()’s docstring), so guessing0here would silently collide with ids already on disk instead of failing loudly. Calladd_with_ids()with explicit ids instead.- Return type:
None
- add_with_ids(vectors, ids)[source]
Append vectors with explicit ids (O(1), no rebuild).
- Parameters:
vectors (numpy.ndarray) – Shape
(m, dim).ids (numpy.ndarray) – Shape
(m,)integer ids.
- Return type:
None
- build(vectors, ids=None)[source]
Create the index and insert the initial corpus.
- Parameters:
vectors (numpy.ndarray) – Shape
(n, dim).ids (numpy.ndarray, optional) – Shape
(n,); defaults torange(n).
- Returns:
self.- Return type:
- classmethod capabilities()[source]
Return the turbovec capability descriptor (fully mutable).
- Return type:
- classmethod is_available()[source]
Return
Trueif turbovec is importable.Examples
>>> isinstance(TurboVecIndex.is_available(), bool) True
- Return type:
- load(path)[source]
Load an index written by
save().- Parameters:
- Returns:
self, populated from disk.- Return type:
Notes
turbovec’s native
IdMapIndexexposes no way to enumerate or count the ids it holds, so the id high-water markadd()relies on cannot be recovered here._next_idis set toNone— a sentineladd()checks for and refuses to guess past, raising a clear error rather than silently restarting id assignment at 0 and colliding with ids already in the loaded index. Useadd_with_ids()with explicit ids after loading.
- remove(ids)[source]
Delete vectors by id — O(1) each, no structural degradation.
- Parameters:
ids (numpy.ndarray) – Shape
(m,)integer ids to drop.- Return type:
None
- save(path)[source]
Persist via turbovec’s native
write.- Parameters:
path (str) – Destination file path.
- Return type:
None