clone_index() loses ArrayInvertedListsPanorama storag
Environment
- FAISS
v1.15.0 faiss-cpu==1.15.0
Description
Calling the public faiss.clone_index() API on a trained and populated IndexIVFFlatPanorama returns an object whose Python type is still IndexIVFFlatPanorama, but whose inverted lists have been downgraded to ordinary ArrayInvertedLists.
The clone cannot execute its normal search() method and raises:
RuntimeError: IndexIVFFlatPanorama requires ArrayInvertedListsPanoramaThe original index searches successfully and returns exact zero distances. This is a deterministic clone/API correctness failure, not an ANN recall miss, quantization effect, tie, or tolerance issue.
Minimal reproduction
import faiss
import numpy as np
d = 4
x = np.array([[1, 1, 1, 1], [11, 11, 11, 11]], "float32")
train = np.array([[0, 0, 0, 0]] * 2 + [[10, 10, 10, 10]] * 2, "float32")
index = faiss.index_factory(d, "IVF2,FlatPanorama2_2")
index.cp.min_points_per_centroid = 1
index.nprobe = 2
index.train(train)
index.add(x)
print(type(index).__name__, type(index.invlists).__name__)
print(index.search(x, 1)[0].ravel().tolist())
clone = faiss.clone_index(index)
print(type(clone).__name__, type(clone.invlists).__name__)
clone.search(x, 1)Observed:
IndexIVFFlatPanorama ArrayInvertedListsPanorama
[0.0, 0.0]
IndexIVFFlatPanorama ArrayInvertedLists
RuntimeError: IndexIVFFlatPanorama requires ArrayInvertedListsPanoramaRoot cause
clone_IndexIVF explicitly recognizes IndexIVFFlatPanorama, but the generic clone_InvertedLists helper checks the base class first:
if (auto* ails = dynamic_cast<const ArrayInvertedLists*>(invlists)) {
return new ArrayInvertedLists(*ails);
}Because ArrayInvertedListsPanorama derives from ArrayInvertedLists, the base-class branch wins and the copied storage is downgraded to ArrayInvertedLists.
The cloned object later reaches IndexIVFFlatPanorama::get_InvertedListScanner, which requires ArrayInvertedListsPanorama. The dynamic cast fails and throws.
Suggested fix
Handle ArrayInvertedListsPanorama before ArrayInvertedLists in clone_InvertedLists, or provide a dedicated Panorama storage clone helper.
Please add a regression test verifying that:
- A valid
IndexIVFFlatPanoramacan be cloned withfaiss.clone_index(); - The clone retains
ArrayInvertedListsPanorama; - Both original and clone can execute
search(); - Both return identical distances and IDs.
Source: facebookresearch/faiss