# Faiss Admin & Architecture Guide

This guide is for engineers, architects, and operators who build Faiss from source, embed it in a service, tune it for production, or harden it against untrusted input. It documents Faiss **v1.14.2** as a system: its architecture, build configuration, runtime dispatch, persistence format, security posture, and internals — at a depth sufficient for an AI or human to reason about, deploy, or extend the library without consulting other sources.

For the end-user API (how to build and query indexes from Python), see the **User Guide**. This document does not repeat that material; it links to it.

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Architecture](#2-architecture)
3. [Repository Structure](#3-repository-structure)
4. [System Requirements](#4-system-requirements)
5. [Building from Source](#5-building-from-source)
6. [Build Configuration Reference](#6-build-configuration-reference)
7. [Runtime SIMD Dispatch](#7-runtime-simd-dispatch)
8. [The Index Class Hierarchy](#8-the-index-class-hierarchy)
9. [Persistence & I/O](#9-persistence--io)
10. [Security](#10-security)
11. [GPU & Accelerator Backends](#11-gpu--accelerator-backends)
12. [Operations & Scaling](#12-operations--scaling)
13. [Performance Tuning](#13-performance-tuning)
14. [The C API](#14-the-c-api)
15. [Code Quality & Conventions](#15-code-quality--conventions)
16. [Testing](#16-testing)
17. [Potential Improvements & Known Issues](#17-potential-improvements--known-issues)
18. [Quick Reference](#18-quick-reference)

---

## 1. Executive Summary

Faiss is a C++17/C++20 library for similarity search and clustering of dense vectors, with complete SWIG-generated Python bindings and an optional C API. Its single architectural abstraction is the `Index`: an object that stores vectors and answers nearest-neighbor queries. Everything else — inverted files, product quantization, graph indexes, GPU acceleration, preprocessing transforms — is a concrete `Index` subclass or a wrapper composing other indexes.

**Key architectural facts:**

- **Language:** C++ core (only hard dependency: a BLAS implementation). Python bindings via SWIG over NumPy. Optional C API.
- **Compute backends:** CPU (with runtime SIMD dispatch across AVX2/AVX512/AVX512-SPR/SVE/RVV), NVIDIA GPU (CUDA, optionally via NVIDIA cuVS), AMD GPU (ROCm), and Apple Silicon (Metal, `IndexFlat` only as of v1.14.2).
- **No daemon, no network surface.** Faiss is linked into your process. It is not a server; it has no listening sockets, no authentication, and no built-in access control. Security concerns are about the **data you feed it** (training vectors, queries) and the **index files you deserialize**.
- **Persistence:** any index serializes to a single file via `write_index` / `read_index`, with flags for read-only, memory-mapped, and on-disk loading.
- **Build system:** CMake. Distributed as conda packages (`faiss-cpu`, `faiss-gpu`, `faiss-gpu-cuvs`) and, as of v1.14.2, pip wheels.

> [!NOTE]
> Because Faiss runs in-process, "deployment" means deciding how your service builds, loads, and queries indexes — and how it isolates that work. There is no Faiss service to operate, monitor, or patch independently of your application.

---

## 2. Architecture

### Layered view

```
┌──────────────────────────────────────────────────────────────┐
│  Your application (Python or C++)                              │
├──────────────────────────────────────────────────────────────┤
│  Python API layer  (faiss/python/)                             │
│    __init__.py        – Pythonic method replacements           │
│    class_wrappers.py  – numpy<->C++ argument adaptation        │
│    extra_wrappers.py  – Kmeans, ResultHeap, MapInt64ToInt64    │
│    gpu_wrappers.py    – index_cpu_to_gpu, all-GPU helpers      │
│    loader.py          – runtime SIMD-level library selection   │
│    swigfaiss*.swig    – SWIG interface (generates bindings)    │
├──────────────────────────────────────────────────────────────┤
│  C API (optional, c_api/)  – flat C functions over the C++ API │
├──────────────────────────────────────────────────────────────┤
│  C++ core  (faiss/)                                            │
│    Index (abstract)  ── IndexFlat, IndexIVF*, IndexPQ*,        │
│                          IndexHNSW, IndexNSG, IndexLSH, ...     │
│    IndexBinary (abstract) ── IndexBinaryFlat, ...IVF, ...HNSW  │
│    index_factory()   – string → index pipeline builder         │
│    index_io          – write_index / read_index               │
│    Clustering, VectorTransform, InvertedLists                  │
│    impl/   – algorithm internals (HNSW, PQ, ScalarQuantizer…)  │
│    utils/  – distances, heaps, SIMD kernels, random            │
│    gpu/ gpu_metal/ svs/ – accelerator & 3rd-party backends     │
├──────────────────────────────────────────────────────────────┤
│  BLAS (MKL / OpenBLAS)   +   OpenMP   [ + CUDA / ROCm / Metal ] │
└──────────────────────────────────────────────────────────────┘
```

### The Index abstraction

The entire library hangs off `faiss::Index` (`faiss/Index.h`). It is an abstract struct with public data members and virtual methods:

**Data members:** `int d` (dimension), `idx_t ntotal` (count; `idx_t = int64_t`), `bool is_trained`, `bool verbose`, `MetricType metric_type`, `float metric_arg`.

**Pure virtual (every index must implement):** `add(n, x)`, `search(n, x, k, distances, labels, params)`, `reset()`.

**Virtual with defaults:** `train`, `train_with_queries`, `add_with_ids`, `range_search`, `assign`, `remove_ids`, `reconstruct`, `reconstruct_batch`, `reconstruct_n`, `search_and_reconstruct`, `compute_residual(_n)`, `merge_from`, `check_compatible_for_merge`, and the **standalone codec** interface (`sa_code_size`, `sa_encode`, `sa_decode`, `add_sa_codes`).

A newer **numeric-type** family (`train_ex`, `add_ex`, `search_ex`, `add_with_ids_ex`) accepts a `NumericType` (`Float32`, `Float16`, `UInt8`, `Int8`) so indexes can ingest non-`float32` data where supported; the base implementations handle `Float32` and throw on the rest.

> [!NOTE]
> Search accepts an optional `SearchParameters*`. Subclasses extend it (e.g. `IVFSearchParameters` with `nprobe`, `IndexRefineSearchParameters` with `k_factor`) so per-query parameters can be passed without mutating the index — important for thread-safe concurrent search with different settings.

### Composition over inheritance

Many capabilities are added by **wrapping** rather than subclassing the algorithm:

- `IndexPreTransform` — applies a `VectorTransform` (PCA, OPQ rotation, L2 normalization) before delegating to an inner index.
- `IndexRefine` / `IndexRefineFlat` — re-ranks an inner index's top `k_factor · k` candidates with finer distances.
- `IndexIDMap` / `IndexIDMap2` — adds custom-ID support (and, for IDMap2, reconstruction by ID) to indexes that lack it.
- `IndexIVF*` — composes a **coarse quantizer** (itself an `Index`, usually `IndexFlatL2`) with an encoding (`Flat`, `PQ`, `ScalarQuantizer`, additive quantizers, RaBitQ...).

The `index_factory` string grammar is exactly a serialization of these compositions: `OPQ16_64,IVF1000,PQ16` means "OPQ pre-transform → IVF with 1000 cells → PQ16 encoding."

---

## 3. Repository Structure

```
faiss/                  C++ core library (114 files at top level)
  Index.h / Index.cpp       abstract base + version macros (FAISS_VERSION 1.14.2)
  MetricType.h              MetricType enum, idx_t typedef
  index_factory.{h,cpp}     regex-based string → index builder
  index_io.{h,cpp}          serialization + IO flags + deser. hardening
  IndexFlat, IndexIVF*, IndexPQ*, IndexHNSW, IndexNSG, IndexLSH,
  IndexScalarQuantizer, IndexAdditiveQuantizer*, IndexRaBitQ*,
  IndexRefine, IndexPreTransform, IndexIDMap, IndexBinary*  ...
  impl/                 algorithm internals (HNSW, ProductQuantizer,
                        ScalarQuantizer, AdditiveQuantizer, fast_scan,
                        simdlib, AuxIndexStructures, IDSelector, ...)
  utils/                distances, heaps, partitioning, random, SIMD,
                        hamming_distance, transpose, quantization kernels
  invlists/             InvertedLists storage (RAM, on-disk, capped)
  gpu/                  CUDA/ROCm GPU indexes + StandardGpuResources
  gpu_metal/            Apple Silicon Metal backend (IndexFlat)
  svs/                  Intel Scalable Vector Search integration (optional)
  python/               SWIG bindings + Pythonic wrappers + loader
  cppcontrib/           header-only helpers (sa_decode, etc.)
c_api/                  optional flat C API (c_api/, c_api/gpu, impl, utils)
contrib/                Python helper modules (datasets, evaluation, ondisk,
                        torch_utils, clustering, ivf_tools, rpc, ...)
benchs/                 benchmark scripts (bench_fw framework, IVF, HNSW, ...)
demos/                  example programs (offline_ivf, rocksdb_ivf, ...)
perf_tests/             micro-benchmarks
tutorial/cpp, tutorial/python   getting-started examples
tests/                  C++ (GoogleTest) + Python test suites
conda/                  conda recipes for faiss / faiss-gpu / faiss-gpu-cuvs
cmake/                  CMake helpers + toolchains
CMakeLists.txt, INSTALL.md, Doxyfile, pyproject.toml, pyproject-gpu.toml
```

> [!NOTE]
> The `benchs/`, `demos/`, and `perf_tests/` scripts use `argparse` and look like CLI tools to automated scanners, but they are **not** a supported command-line interface — Faiss has no CLI. They are reproducibility harnesses for the research papers and performance regression checks.

---

## 4. System Requirements

### Runtime (using a prebuilt package)

| Requirement | Detail |
|---|---|
| OS | Linux (x86-64, aarch64), macOS (arm64), Windows (x86-64) for `faiss-cpu` |
| BLAS | Bundled by the conda/pip package (MKL on x86-64, OpenBLAS on ARM) |
| Python | 3.x with NumPy (for the Python bindings) |
| GPU (optional) | NVIDIA CUDA 11.4/12.1 (`faiss-gpu`), CUDA 13.2 + cuVS 26.06 (`faiss-gpu-cuvs`) — Linux x86-64 only |

### Build (from source)

| Requirement | Detail |
|---|---|
| Compiler | C++20 compiler with OpenMP ≥ 2 |
| BLAS | Any; Intel MKL strongly recommended on Intel for performance |
| CMake | Recent version |
| GPU (optional) | `nvcc` + CUDA toolkit (NVIDIA); AMD ROCm (AMD); `libcuvs=26.06` (cuVS) |
| Python bindings (optional) | Python 3, NumPy, SWIG |

---

## 5. Building from Source

Faiss builds with CMake in the standard configure → build → install flow.

### Step 1 — configure

```bash
cmake -B build .
```

### Step 2 — build the C++ library

```bash
make -C build -j faiss
```

This produces `libfaiss.a` (or `libfaiss.so` with `-DBUILD_SHARED_LIBS=ON`).

> [!IMPORTANT]
> If you build with a non-generic SIMD level, build the corresponding optimized target **before** `swigfaiss`, e.g. `make -C build -j faiss_avx2` (or `faiss_avx512`, `faiss_avx512_spr`). The Python loader selects the matching `swigfaiss_*` extension at import time (see [Runtime SIMD Dispatch](#7-runtime-simd-dispatch)).

### Step 3 — Python bindings (optional)

```bash
make -C build -j swigfaiss
(cd build/faiss/python && python setup.py install)
```

### Step 4 — install C++ library & headers (optional)

```bash
make -C build install
```

### Step 5 — test (optional)

```bash
# C++ (requires -DBUILD_TESTING=ON at configure time)
make -C build test

# Python
(cd build/faiss/python && python setup.py build)
PYTHONPATH="$(ls -d ./build/faiss/python/build/lib*/)" pytest tests/test_*.py
```

> [!TIP]
> Pass `-j` without a number to use all cores, but on memory-constrained machines pin it (`-j4`) — Faiss translation units, especially GPU and SIMD kernels, are memory-hungry to compile.

---

## 6. Build Configuration Reference

All options are passed to the `cmake -B build .` invocation as `-D<OPTION>=<VALUE>`.

### General

| Option | Default | Effect |
|---|---|---|
| `FAISS_ENABLE_GPU` | `ON` | Build GPU indices. |
| `FAISS_ENABLE_PYTHON` | `ON` | Build the Python bindings. |
| `FAISS_ENABLE_C_API` | `OFF` | Build the [C API](#14-the-c-api). |
| `BUILD_TESTING` | — | Build the C++ test suite. |
| `BUILD_SHARED_LIBS` | `OFF` | Build a shared library (`libfaiss.so`) instead of static. |

### Optimization

| Option | Values | Effect |
|---|---|---|
| `CMAKE_BUILD_TYPE` | `Release`, ... | `Release` enables `-O3`-class optimization. |
| `FAISS_OPT_LEVEL` | x86: `generic`, `avx2`, `avx512`, `avx512_spr`; aarch64: `generic`, `sve` | SIMD instruction set to compile for (increasing optimization). |
| `FAISS_USE_LTO` | `ON`/`OFF` (`OFF`) | Link-Time Optimization. |

### BLAS

| Option | Effect |
|---|---|
| `BLA_VENDOR=Intel10_64_dyn` + `MKL_LIBRARIES=/path/to/mkl/libs` | Use Intel MKL (significantly faster than OpenBLAS on Intel). |

### GPU

| Option | Effect |
|---|---|
| `FAISS_ENABLE_CUVS=ON` | Use NVIDIA cuVS implementations for IVF-Flat, IVF-PQ, and CAGRA. Requires `FAISS_ENABLE_GPU=ON`. |
| `FAISS_ENABLE_ROCM=ON` | Build GPU indices for AMD GPUs. Requires `FAISS_ENABLE_GPU=ON`. |
| `CUDAToolkit_ROOT=/path/to/cuda` | Hint the CUDA toolkit location. |
| `CMAKE_CUDA_ARCHITECTURES="75;72"` | Target specific GPU architectures. |

### Optional integrations

| Option | Effect |
|---|---|
| `FAISS_ENABLE_SVS=ON` | Enable Intel Scalable Vector Search (Vamana, LVQ, LeanVec). CMake fetches and builds `libsvs_runtime.so`, copied into the Python package; for C++ usage put it on your library path. |
| `FAISS_ENABLE_METAL` | Apple Silicon Metal backend (builds Metal tests when combined with `BUILD_TESTING`). |

### Python

| Option | Effect |
|---|---|
| `Python_EXECUTABLE=/path/to/python` | Build bindings for a specific Python interpreter. |

---

## 7. Runtime SIMD Dispatch

A subtle but operationally important behavior: the Python package selects the best CPU-optimized extension **at import time**, based on the CPU it is running on. This is implemented in `faiss/python/loader.py`.

The loader determines the supported instruction sets (via NumPy's `__cpu_features__`, plus an SVE probe on aarch64 Linux), then tries to import the most-optimized matching extension first, falling back down the chain:

```
swigfaiss_avx512_spr  →  swigfaiss_avx512  →  swigfaiss_avx2  →  swigfaiss_sve  →  swigfaiss (generic)
```

Two environment variables control this:

| Variable | Effect |
|---|---|
| `FAISS_OPT_LEVEL` | If set (e.g. `avx2`, `avx512`, `avx512_spr`, `sve`), forces that level instead of auto-detecting. |
| `FAISS_DISABLE_CPU_FEATURES` | A whitespace/comma-separated list of features to remove from the detected set (e.g. disable `AVX512` to work around a bad path or a CPU that throttles under AVX512). |

> [!WARNING]
> If no matching `swigfaiss*` extension is present (common in incomplete from-source builds), import **fails hard** with a detailed message telling you which `FAISS_OPT_LEVEL` your CPU supports and which target to build (`swigfaiss`, `swigfaiss_avx2`, `swigfaiss_avx512`, `swigfaiss_avx512_spr`, or `swigfaiss_sve`). This is `No module named 'faiss.swigfaiss'` — almost always a build, not a usage, problem.

> [!NOTE]
> v1.14.2 also adds dynamic dispatch (DD) for several kernel families (hamming, fast_scan) and a build mode where you select a subset of SIMD levels at dispatch time, plus RVV (RISC-V Vector) support with cross-compilation for riscv64.

---

## 8. The Index Class Hierarchy

`index_factory.cpp` includes every index type it can construct; that include list is the authoritative catalog of the C++ index families:

**CPU float indexes**

| Family | Classes | Notes |
|---|---|---|
| Exact | `IndexFlat`, `IndexFlatL2`, `IndexFlatIP` | Brute force; supports the widest metric set. |
| Inverted file | `IndexIVFFlat`, `IndexIVFFlatPanorama`, `IndexIVFPQ`, `IndexIVFPQR`, `IndexIVFPQFastScan`, `IndexIVFScalarQuantizer`, `IndexIVFSpectralHash`, `IndexIVFAdditiveQuantizer(FastScan)`, `IndexIVFRaBitQ(FastScan)` | Coarse quantizer + per-cell encoding. `nprobe` at search. |
| Product quantization | `IndexPQ`, `IndexPQFastScan` | Compact codes; FastScan uses SIMD LUTs. |
| Additive quantization | `IndexAdditiveQuantizer`, `IndexAdditiveQuantizerFastScan` | Residual / Local Search quantizers. |
| Graph | `IndexHNSW` (Flat/PQ/SQ storage), `IndexNSG` | High recall, no training, higher memory. |
| Compact / hashing | `IndexLSH`, `IndexLattice`, `IndexRaBitQ`, `IndexScalarQuantizer`, `IndexRowwiseMinMax` | Various compression schemes. |
| Wrappers | `IndexPreTransform`, `IndexRefine`/`IndexRefineFlat`, `Index2Layer`, `IndexIDMap`/`IndexIDMap2` | Compose other indexes. |

**Binary indexes** (Hamming distance over bit vectors): `IndexBinaryFlat`, `IndexBinaryIVF`, `IndexBinaryHNSW`, `IndexBinaryHash`. Built via `index_binary_factory`.

**Intel SVS** (compile-time `FAISS_ENABLE_SVS`): `IndexSVSFlat`, `IndexSVSIVF`, `IndexSVSIVFLVQ`, `IndexSVSIVFLeanVec`, `IndexSVSVamana`, `IndexSVSVamanaLVQ`, `IndexSVSVamanaLeanVec`. As of v1.14.2 an SVS Vamana index can also serve as an IVF coarse quantizer via the factory.

### Pre-processing transforms

`VectorTransform` subclasses applied through `IndexPreTransform`: PCA reduction, OPQ rotation (optimized for PQ), random rotation (`RR`), and L2 normalization (`L2norm`, the basis for cosine search).

---

## 9. Persistence & I/O

`faiss/index_io.h` defines the serialization API. Any index round-trips through a single file (or `FILE*`, or a custom `IOReader`/`IOWriter` abstraction).

```cpp
void write_index(const Index* idx, const char* fname, int io_flags = 0);
Index* read_index(const char* fname, int io_flags = 0);
std::unique_ptr<Index> read_index_up(const char* fname, int io_flags = 0); // owning
```

Parallel functions exist for binary indexes (`write_index_binary`/`read_index_binary`), `VectorTransform`, `ProductQuantizer`, and `InvertedLists`.

### I/O flags

| Flag | Value | Effect |
|---|---|---|
| `IO_FLAG_SKIP_STORAGE` | 1 | Skip the raw storage for graph indexes (graph structure only). |
| `IO_FLAG_READ_ONLY` | 2 | Open read-only; no in-place modification. |
| `IO_FLAG_ONDISK_SAME_DIR` | 4 | Strip the directory from an on-disk inverted-list filename and assume it sits beside the index file. |
| `IO_FLAG_SKIP_IVF_DATA` | 8 | Load list sizes only, not the IVF payload. |
| `IO_FLAG_SKIP_PRECOMPUTE_TABLE` | 16 | Don't rebuild the precomputed table after load. |
| `IO_FLAG_PQ_SKIP_SDC_TABLE` | 32 | Skip the PQ symmetric-distance table (blocks some distance computations; blocks HNSWPQ graph building). |
| `IO_FLAG_MMAP` | (composite) | Memory-map the data (loads `ArrayInvertedLists` as `OnDiskInvertedLists`). |
| `IO_FLAG_MMAP_IFC` | `1<<9` | Mmap codes for `IndexFlatCodes`-derived indexes and HNSW (also supported on Darwin as of v1.14.2). |

> [!TIP]
> For indexes larger than RAM, the combination of on-disk inverted lists plus `IO_FLAG_MMAP` lets the OS page index data in on demand. The `faiss.contrib.ondisk` helpers and the `demos/offline_ivf` example show the full merge-to-on-disk workflow.

---

## 10. Security

Faiss has **no network surface, no authentication, and no access control** — it executes in your process. Its security profile is therefore about two inputs you control: index files you deserialize, and the vectors you process.

### Untrusted index files are the primary risk

`read_index` deserializes a binary format that contains size and count fields (number of inverted lists, vector-transform chain length, hash counts, etc.). A malicious or corrupt file can specify enormous values to trigger pathological allocations or compute. Faiss v1.14.x ships explicit hardening knobs in `index_io.h`:

| Control | Default | Purpose |
|---|---|---|
| `set_deserialization_loop_limit(n)` | 0 (no limit) | Reject loop-driving fields (`nlist`, `nsplits`, VT chain length, `nhash`, ...) that exceed `n`. |
| `set_deserialization_vector_byte_limit(n)` | 1 TB (`1<<40`) | Cap the bytes a single `READVECTOR` call may allocate. |
| `set_deserialization_lattice_r2_limit(n)` | 0 (no limit) | Reject `IndexLattice` payloads whose squared radius `r2` would build an unboundedly expensive decode cache. |

> [!CAUTION]
> If your service loads index files supplied by users or fetched from untrusted storage, **set these limits before any deserialization** and run the load in an isolated process or sandbox. The functions are explicitly **not thread-safe**: configure them before any concurrent deserialization begins and do not change them mid-flight. There were also recent hardening commits validating HNSW and SVS deserialization read sites and adding format-enum sentinels.

### Data-handling notes

- Faiss does not encrypt index files; stored vectors and PQ codes are recoverable. If your vectors are sensitive (e.g. derived from personal data), protect the files at rest and in transit at the storage layer.
- Reconstruction (`reconstruct`, `sa_decode`) can return approximations of the original vectors from compressed indexes — relevant if you considered the codes "anonymized."
- The library trusts caller-provided array shapes/dtypes; the Python layer validates dtype and contiguity and throws clear `TypeError`s, but C++ callers are responsible for correct sizes.

### License & provenance

MIT-licensed, Copyright © Meta Platforms, Inc. Third-party components are listed in `THIRD_PARTY_NOTICES`. cuVS and SVS integrations pull in their own (Apache-2.0) licensed code.

---

## 11. GPU & Accelerator Backends

### NVIDIA (CUDA / cuVS)

GPU support lives in `faiss/gpu/`. The entry object is `StandardGpuResources`, which manages per-device scratch memory and CUDA streams. Indexes move between host and device with `index_cpu_to_gpu(res, device, index)`, `index_cpu_to_all_gpus(index)`, and back with `index_gpu_to_cpu(index)`. GPU indexes accept input from CPU or GPU memory; staying resident on the GPU avoids copy overhead.

When built with `FAISS_ENABLE_CUVS=ON`, IVF-Flat, IVF-PQ, and CAGRA can dispatch to NVIDIA cuVS implementations, and v1.14.2 adds filtered search for cuVS indexes and lets cuVS supply default values.

### AMD (ROCm)

`FAISS_ENABLE_ROCM=ON` builds the GPU indices for AMD GPUs through HIP. The same `gpu/` code path is compiled for HIP targets.

### Apple Silicon (Metal)

`faiss/gpu_metal/` adds a Metal backend for Apple Silicon. As of v1.14.2 it covers `IndexFlat`; the Metal shaders are extracted into standalone `.metal` files with a kernel wrapper class.

> [!NOTE]
> GPU indexes do not implement every CPU index type or every operation. The drop-in story (`IndexFlatL2` → `GpuIndexFlatL2`, or `index_cpu_to_gpu`) holds for the common Flat/IVF/PQ paths; exotic CPU index types may have no GPU equivalent.

---

## 12. Operations & Scaling

Because Faiss is embedded, "operations" is about how your service uses it.

### Threading

Faiss parallelizes batch `add`/`search` with OpenMP. Control thread count with the standard `OMP_NUM_THREADS` environment variable or `faiss.omp_set_num_threads(n)`. Search throughput scales with batch size — submit queries in batches rather than one at a time.

> [!IMPORTANT]
> A single index is generally safe for concurrent **search** from multiple threads (search is `const`), but concurrent **add**/`train`/`remove` with search is not. For IVF, prefer passing per-query `SearchParameters` over mutating `index.nprobe` from multiple threads. HNSW gained optional persistent locks in v1.14.2 for safe incremental adds.

### Indexes larger than RAM

Three complementary strategies:

1. **Compression** — `IndexIVFPQ` and additive-quantizer indexes shrink each vector to a few bytes, letting billions fit in RAM.
2. **On-disk inverted lists** — build per-shard indexes and merge to a single on-disk index (`faiss.contrib.ondisk`, `demos/offline_ivf`), then load with `IO_FLAG_MMAP`.
3. **Sharding / distributed** — split the database across machines and query in parallel (`contrib/rpc.py`, `contrib/client_server.py`, `benchs/distributed_ondisk`).

### Reproducibility & monitoring

Seed RNGs (`np.random.seed`, `Kmeans(seed=...)`). Faiss has no built-in metrics export; instrument query latency and recall in your service. Validate recall against an `IndexFlatL2` ground truth in CI when you change index parameters.

---

## 13. Performance Tuning

| Lever | Index family | Effect |
|---|---|---|
| `nprobe` | IVF | More cells scanned → higher recall, lower QPS. The primary recall/speed dial. |
| `nlist` | IVF (build) | More cells → finer partitioning; rule of thumb ~`sqrt(N)` to `16*sqrt(N)`. Larger `nlist` needs more training data. |
| `efSearch` | HNSW | Higher → higher recall, slower search. |
| `efConstruction`, `M` | HNSW (build) | Higher → better graph quality, slower build, more memory. |
| `m`, `nbits` | PQ | More sub-quantizers / bits → better accuracy, more memory and compute. |
| `Refine(...)` + `k_factor` | any compressed | Re-rank more candidates with exact distances → recover recall at modest cost. |
| OPQ pre-transform | PQ-based | Rotates space so PQ quantizes better → higher accuracy for free at query time. |
| `FAISS_OPT_LEVEL` / SIMD build | all CPU | AVX512/AVX512-SPR/SVE kernels are substantially faster than generic. |
| Intel MKL BLAS | flat / exact | MKL is markedly faster than OpenBLAS on Intel for the BLAS-bound exact path. |

> [!TIP]
> The `benchs/bench_fw` framework and `demos/demo_auto_tune.py` automate the recall-vs-speed sweep across index types and parameters, producing Pareto fronts. Use them to pick an operating point rather than guessing.

> [!NOTE]
> v1.14.2 adds throughput-oriented features worth knowing: database-parallel flat search for few-query workloads, IVF early-termination, a Kmeans early-stop threshold, TurboQuant (CPU), Panorama optimizations, and `SuperKMeans` (ADSampling + PDX pruning) for faster clustering.

---

## 14. The C API

`c_api/` provides a flat C interface over the C++ library, enabled with `-DFAISS_ENABLE_C_API=ON`. It mirrors the C++ surface — index construction, `faiss_Index_train/add/search`, `index_factory`, `write_index`/`read_index` — using opaque handles and integer error codes instead of exceptions. Subdirectories: `c_api/impl` (error handling), `c_api/utils`, and `c_api/gpu` (GPU bindings). This is the integration point for languages other than C++/Python (Rust, Go, Java, etc. binders build on it).

> [!NOTE]
> The C API is opt-in and not built by the default conda/pip packages. Build it from source if you need it.

---

## 15. Code Quality & Conventions

- **Language standard:** C++17/20. Header + implementation split (`IndexX.h` / `IndexX.cpp`); algorithm internals isolated under `impl/`, reusable numeric kernels under `utils/`.
- **Error handling:** C++ uses `FAISS_THROW_MSG` / `FAISS_THROW_FMT` / `FAISS_THROW_IF_NOT_FMT` (see `impl/FaissAssert.h`) to raise `FaissException`. Recent work replaced `FAISS_ASSERT` with throwing variants for recoverable conditions (e.g. unsupported SVS storage kinds) and added OpenMP exception-capture helpers so exceptions thrown inside parallel regions propagate correctly.
- **Matrix convention:** all vector batches are compact, row-major `n × d` arrays of `float32`; element `j` of vector `i` is `x[i*d + j]`.
- **SIMD strategy:** a `simdlib` abstraction plus per-level translation units, increasingly via dynamic dispatch so one binary can pick kernels at runtime. Cross-SIMD-level correctness is enforced with bit-exact reference tests (`@for_all_simd_levels`, `NoneSIMDLevel` context manager).
- **Python ergonomics:** SWIG generates raw bindings; `faiss/python/*.py` then *replaces* methods so they accept NumPy arrays and return `(D, I)` tuples instead of requiring explicit pointers and counts. `class_wrappers.py` validates dtype/contiguity and raises clear `TypeError`s.

---

## 16. Testing

- **C++:** GoogleTest, fetched via CMake `FetchContent` (release-1.12.1). The suite (`tests/CMakeLists.txt`) covers IVF, PQ encoding/codec, HNSW, NSG, scalar quantizer, merge/on-disk/mmap (POSIX-only), heaps, partitioning, fast-scan, SIMD levels, callbacks, and zero-copy paths. x86 AVX2/AVX512 intrinsic tests compile only under `FAISS_OPT_LEVEL=dd` on x86-64; SVS tests gate on `FAISS_ENABLE_SVS`. Windows defers gtest discovery to ctest time (the DLL isn't on `PATH` at build time) and skips POSIX-API tests.
- **Python:** `pytest tests/test_*.py` against the built extension; GPU tests under `faiss/gpu/test/`, Metal tests under `faiss/gpu_metal/test/`.
- **Backward compatibility:** `tests/index_io_backward_compatibility/` verifies that indexes written by older versions still load — important given the serialization format is a public contract.

> [!IMPORTANT]
> When changing any serialization code, run the backward-compatibility tests and add a fixture for the new format. Index files in the wild outlive the code that wrote them.

---

## 17. Potential Improvements & Known Issues

Drawn from the live issue tracker at the documented commit:

| Issue | Status | Impact |
|---|---|---|
| Data race in `NNDescent::update()` — unlocked read of `other.pool.back()` before acquiring the lock (#5276) | Open bug | Potential corruption/crash during concurrent NNDescent graph construction. |
| `fast_scan` fails to compile on AMD Zen5 with any `FAISS_OPT_LEVEL` (#5245) | Open bug | Blocks from-source builds on Zen5; use prebuilt packages or a different opt level. |
| Missing `musllinux` wheels on 1.14.2 (#5272) | Open | Alpine/musl users cannot `pip install`; use conda or build from source. |
| New Python type stubs not included in the conda package (#5261) | Open | Editor type-checking is degraded under conda installs. |
| `Index.reconstruct_n()` stub resolves to `torch.Tensor` under mypy for default CPU calls returning `numpy.ndarray` (#5232) | Open | Type-checker false signal; runtime behavior is correct. |
| SWIG 4.4 `DeprecationWarning: builtin type has no __module__ attribute` (#4481) | Open feature/upgrade | Forward-compat with newer SWIG. |
| Import failure on Python 3.12 via deprecated `numpy.distutils` (#3936) | Resolved | Fixed by NumPy ≥ 2.0 `__cpu_features__` path in `loader.py`. |
| Windows ARM64 (MSVC) build broken by NEON SIMD templatization (#4993) | Resolved | — |

**Architectural opportunities (observed from the source):**

- The serialization hardening limits ([Security](#10-security)) default to permissive (`0`/1 TB). Services accepting untrusted index files should consider whether Faiss should ship safer defaults or a documented "untrusted load" preset.
- SIMD dispatch is mid-migration from static per-level TUs to dynamic dispatch; consolidating fully would simplify the build matrix and the loader fallback chain.
- GPU coverage is uneven across index types; a capability matrix in the docs (which `IndexX` has a GPU/Metal/cuVS equivalent) would reduce surprises.

---

## 18. Quick Reference

### Build cheat sheet

```bash
# CPU, AVX2, shared lib, with Python and C API
cmake -B build . -DCMAKE_BUILD_TYPE=Release -DFAISS_OPT_LEVEL=avx2 \
      -DBUILD_SHARED_LIBS=ON -DFAISS_ENABLE_GPU=OFF \
      -DFAISS_ENABLE_PYTHON=ON -DFAISS_ENABLE_C_API=ON
make -C build -j faiss_avx2 swigfaiss
(cd build/faiss/python && python setup.py install)

# NVIDIA GPU with cuVS
cmake -B build . -DFAISS_ENABLE_GPU=ON -DFAISS_ENABLE_CUVS=ON \
      -DCMAKE_CUDA_ARCHITECTURES="80;90"
make -C build -j faiss swigfaiss
```

### Key environment variables

| Variable | Scope | Effect |
|---|---|---|
| `FAISS_OPT_LEVEL` | runtime + build | Force SIMD level. |
| `FAISS_DISABLE_CPU_FEATURES` | runtime | Disable specific CPU features at load. |
| `OMP_NUM_THREADS` | runtime | OpenMP thread count for add/search. |

### Deserialization hardening (untrusted index files)

```python
faiss.set_deserialization_loop_limit(10_000_000)        # cap nlist/nhash/etc.
faiss.set_deserialization_vector_byte_limit(1 << 32)    # cap single-vector alloc to 4 GB
faiss.set_deserialization_lattice_r2_limit(1 << 16)     # cap IndexLattice r2
index = faiss.read_index("untrusted.faiss", faiss.IO_FLAG_READ_ONLY)
```

### Deployment checklist

- [ ] Install a prebuilt package (conda/pip) unless you need a custom build.
- [ ] Confirm the SIMD level matches the deployment CPU (or rely on auto-dispatch).
- [ ] Pin `OMP_NUM_THREADS` to your CPU allocation in containerized deployments.
- [ ] Validate recall against an `IndexFlatL2` ground truth before shipping parameter changes.
- [ ] If loading untrusted index files, set deserialization limits and sandbox the load.
- [ ] Run backward-compatibility tests after any serialization change.
- [ ] For >RAM datasets, choose compression, on-disk+mmap, or sharding deliberately.

### Version & provenance

| Fact | Value |
|---|---|
| Version | 1.14.2 |
| License | MIT (© Meta Platforms, Inc.) |
| Language | C++17/20 + SWIG Python bindings + optional C API |
| Hard dependency | BLAS (MKL / OpenBLAS) |
| Documented commit | `eb4c1ea` |

---

_Generated June 2026 from facebookresearch/faiss at eb4c1ea. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
