Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)

project(RaBitQLib VERSION 0.8.0 LANGUAGES CXX)
project(RaBitQLib VERSION 0.8.1 LANGUAGES CXX)

include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ approximate nearest-neighbor search. See the [research papers](https://vectordb-

## News

- **v0.8.1:** The default `num_threads=0` now respects `OMP_NUM_THREADS`, fixing a
macOS crash when Faiss and PyTorch share the process. See the [release notes](https://vectordb-ntu.github.io/RaBitQ-Library/releases/0.8.1/).
- **v0.8.0:** Faiss-style `train`, `add` and `search` for all Python indexes,
with 0.7 calls kept as deprecated forms until 0.9; optional k-means sampling
and assignment; stricter input validation and atomic index saves. C++ query-factor
Expand Down Expand Up @@ -52,7 +54,7 @@ settings, and limitations.
### Python

```bash
python -m pip install --upgrade "rabitqlib>=0.8.0"
python -m pip install --upgrade "rabitqlib>=0.8.1"
```

Wheels support CPython 3.11–3.14 on Linux x86-64/ARM64, Windows x86-64,
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/clustering.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Set Python keyword arguments or fields of the corresponding C++ parameter type:
| --- | --- | --- |
| `niter` | `25` | Maximum clustering iterations. |
| `early_stop_threshold` | `0.0` | Stop from iteration 2 when the absolute relative objective change is at most this value; range `[0, 1]`. Zero stops only on an unchanged objective. |
| `num_threads` | `0` | Use detected available logical CPUs; positive requests are capped at that count. See [threading](index/usage.md#threading-and-file-paths). |
| `num_threads` | `0` | Use detected available logical CPUs, capped by `OMP_NUM_THREADS`; positive requests are capped at the CPU count. See [threading](index/usage.md#threading-and-file-paths). |
| `spherical` | `false` | Normalize centroids and assign by inner product; input must already be normalized. |
| `seed` | `42` | Seed for centroid selection and rotation. |
| `min_points_per_centroid` | `39` | Warn below this training-points-per-centroid ratio when verbose. |
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/cpp_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ The core example is built as the `core_example` CMake target. For the GIST bench

The [core quantization v1 API](rabitq/core_api.md) has a C++ source-compatibility contract.
Other C++ APIs may evolve, and no cross-version C++ binary ABI is promised.
Pin the `v0.8.0` release and include RaBitQ-Library as a Git submodule:
Pin the `v0.8.1` release and include RaBitQ-Library as a Git submodule:

```bash
git submodule add https://github.com/VectorDB-NTU/RaBitQ-Library.git third_party/rabitqlib
git submodule update --init --recursive
git -C third_party/rabitqlib checkout v0.8.0
git -C third_party/rabitqlib checkout v0.8.1
git add third_party/rabitqlib
```

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ estimation into your own <span class="nowrap">C++</span> search engine.</p>
</div>

```bash
python -m pip install "rabitqlib>=0.8.0"
python -m pip install "rabitqlib>=0.8.1"
```

[Installation and supported platforms](installation.md) ·
Expand Down Expand Up @@ -112,5 +112,5 @@ on your own dataset when choosing an index.
## Explore further

- [Algorithm overview](rabitq/rabitq.md) for the rotation, encoding, and scoring workflow.
- [RaBitQ Library 0.8.0 release notes](releases/0.8.0.md) for the latest changes and upgrade guidance.
- [RaBitQ Library 0.8.1 release notes](releases/0.8.1.md) for the latest changes and upgrade guidance.
- [Papers and citations](papers.md) for the original RaBitQ method, its multi-bit extension, and SymphonyQG.
9 changes: 7 additions & 2 deletions docs/docs/index/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,13 @@ thread. Returned result arrays own their storage.
These access checks belong to the Python wrappers. C++ callers must synchronize
index updates themselves and use separate search output buffers.

`num_threads=0` selects the detected available logical CPU count. Positive values
set an upper limit, capped at that count; small workloads may use fewer workers.
`num_threads=0` selects the detected available logical CPU count, capped by the
OpenMP thread limit (`OMP_NUM_THREADS`, or `omp_set_num_threads` in C++). Positive
values set an upper limit, capped at the CPU count only; small workloads may use
fewer workers. On macOS, OpenMP runtimes bundled by different packages (for
example Faiss or PyTorch wheels) can crash when more than one of them starts
worker threads in the same process; set `OMP_NUM_THREADS=1` before the first
native call, or pass `num_threads=1`, in such processes.
`train` and `add` on every index default to `0`, as does clustering; `search`
and the deprecated `build` default to one thread.
Multithreaded HNSW-RaBitQ `add` links points in a nondeterministic order, so pass
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/installation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Installation

Platform requirements and source installation for RaBitQ Library **0.8.0**.
Platform requirements and source installation for RaBitQ Library **0.8.1**.
For the first Python example, see [Quick Start](quick_start.md).

## Requirements
Expand Down Expand Up @@ -40,7 +40,7 @@ build can use scalar kernels without the FastScan CPU baseline.
## Python wheels

```bash
python -m pip install "rabitqlib>=0.8.0"
python -m pip install "rabitqlib>=0.8.1"
```

For changes from 0.6.0, see the [0.7.0 upgrade notes](releases/0.7.0.md).
Expand All @@ -61,11 +61,11 @@ importing those classes. Array shapes and parameter ranges are still checked at

## Get the source

For Python source builds or C++ use, obtain the 0.8.0 checkout once. With Git
For Python source builds or C++ use, obtain the 0.8.1 checkout once. With Git
installed, run:

```bash
git clone --branch v0.8.0 --depth 1 https://github.com/VectorDB-NTU/RaBitQ-Library.git
git clone --branch v0.8.1 --depth 1 https://github.com/VectorDB-NTU/RaBitQ-Library.git
cd RaBitQ-Library
```

Expand Down
9 changes: 5 additions & 4 deletions docs/docs/python_migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ work if you want to run k-means yourself.
### Behavior changes

- **Thread defaults.** `train` and `add` now default to every available CPU
(`num_threads=0`); 0.7 `build` and `add` defaulted to one thread. This applies
to every `add` call that does not pass `num_threads`, including 0.7 code such as
`index.add(x)`, without a warning. `search` still defaults to one thread, and
the deprecated `build` keeps its default of 1.
(`num_threads=0`), capped by `OMP_NUM_THREADS` since 0.8.1; 0.7 `build` and
`add` defaulted to one thread. This applies to every `add` call that does not
pass `num_threads`, including 0.7 code such as `index.add(x)`, without a
warning. `search` still defaults to one thread, and the deprecated `build`
keeps its default of 1.
- **HNSW-RaBitQ builds are not reproducible by default.** With more than one
thread, `add` links points in a nondeterministic order. Pass `num_threads=1`
to `add` for the same graph on every run. With one thread and the same seed,
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/quick_start.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Quick start

Build, search, save and reload a small IVF-RaBitQ index with Python. This guide describes
**0.8.0** and uses synthetic data, so no dataset download is required. Coming from 0.7?
**0.8.1** and uses synthetic data, so no dataset download is required. Coming from 0.7?
See the [migration guide](python_migration.md).
For C++, go directly to [C++ integration](cpp_integration.md).

## Install

```bash
python -m pip install "rabitqlib>=0.8.0"
python -m pip install "rabitqlib>=0.8.1"
```

Wheels support CPython 3.11–3.14 on Linux x86-64/ARM64, Windows x86-64 and
Expand Down Expand Up @@ -47,9 +47,9 @@ print(ids[0])
iterations on at most 256 sampled vectors per centroid, spherical k-means for
`metric="ip"`, and the index `seed`. Change `index.cp` before training to tune
them, or call `index.set_centroids(centroids)` to use centroids you computed
elsewhere. `train` and `add` use every available CPU by default; pass
`num_threads=` to limit them. Without `seed`, each index draws a random rotation
seed and reports it as `index.seed`.
elsewhere. `train` and `add` use every available CPU by default, capped by
`OMP_NUM_THREADS`; pass `num_threads=` to limit them. Without `seed`, each index
draws a random rotation seed and reports it as `index.seed`.

## Read the results

Expand Down
32 changes: 32 additions & 0 deletions docs/docs/releases/0.8.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# RaBitQ Library 0.8.1

This patch release fixes a crash on macOS when RaBitQ Library runs in the same
process as Faiss and PyTorch, reported through txtai
([#207](https://github.com/VectorDB-NTU/RaBitQ-Library/issues/207)).

## Fixes

- `num_threads=0`, the default for `train`, `add` and clustering, now selects
the available logical CPUs capped by the OpenMP thread limit
(`OMP_NUM_THREADS`, or `omp_set_num_threads` in C++), as Faiss does. Positive
requests are unchanged and remain capped only by the CPU count. Without
`OMP_NUM_THREADS`, the default still uses every available CPU.
- In 0.8.0, 0.7-style `add(x)` calls switched to every CPU and ignored
`OMP_NUM_THREADS`. On macOS, the Faiss, PyTorch and RaBitQ Library wheels each
bundle their own OpenMP runtime; with Faiss and PyTorch loaded, starting RaBitQ
Library's worker threads crashed with `OMP: Error #179` followed by a
segmentation fault. Applications that set `OMP_NUM_THREADS=1` for this reason,
such as txtai, run `add` single-threaded again. Processes that mix these
runtimes without that setting should set it before the first native call or
pass `num_threads=1`; see [threading](../index/usage.md#threading-and-file-paths).

## Upgrading

From 0.8.0, public APIs, index file formats and the stable core API v1 are
unchanged; no index conversion is required. If you set `OMP_NUM_THREADS` and want
`train` or `add` to use more threads, pass `num_threads` explicitly. Rebuild C++
consumers with matching headers and libraries; no cross-version C++ binary ABI is
promised.

When upgrading from 0.7, follow the [0.8.0 release notes](0.8.0.md) and the
[migration guide](../python_migration.md).
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ nav:
- Installation: installation.md
- C++ Integration: cpp_integration.md
- Release notes:
- "0.8.1": releases/0.8.1.md
- "0.8.0": releases/0.8.0.md
- "0.7.2": releases/0.7.2.md
- "0.7.1": releases/0.7.1.md
Expand Down
12 changes: 9 additions & 3 deletions include/rabitqlib/utils/tools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,19 @@ inline bool is_powerof2(size_t n) { return n > 0 && (n & (n - 1)) == 0; }
// Available logical CPUs in the calling context, with a hardware-count fallback.
size_t total_threads();

// Zero selects all available CPUs; explicit requests cannot exceed that count.
// total_threads() capped by the OpenMP thread limit (OMP_NUM_THREADS or
// omp_set_num_threads), so applications can limit every automatic team.
size_t default_threads();

// Zero selects default_threads(); explicit requests cannot exceed total_threads().
inline size_t resolve_num_threads(size_t requested) {
if (requested == 1) {
return 1;
}
const size_t available = total_threads();
return requested == 0 ? available : std::min(requested, available);
if (requested == 0) {
return default_threads();
}
return std::min(requested, total_threads());
}

namespace detail {
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "rabitqlib"
version = "0.8.0"
version = "0.8.1"
description = "Official RaBitQ library for vector quantization and approximate nearest-neighbor search"
readme = "README.md"
requires-python = ">=3.11"
Expand Down
12 changes: 8 additions & 4 deletions python_bindings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ def build(
Centroid ID per vector, in [0, num_clusters). Floating-point and
boolean IDs are rejected.
num_threads : int, optional
Worker count. Default is 1; 0 selects the available CPU count.
Worker count. Default is 1; 0 selects the available CPU count,
capped by OMP_NUM_THREADS.
fast_quantization : bool, optional
Use faster quantizer configuration. Default is False.
"""
Expand Down Expand Up @@ -328,7 +329,8 @@ def build(self, data, ef_construction, num_threads=1, init="pipnn"):
ef_construction : int
Positive construction search breadth fitting uint32.
num_threads : int, optional
Worker count. Default is 1; 0 selects the available CPU count.
Worker count. Default is 1; 0 selects the available CPU count,
capped by OMP_NUM_THREADS.
init : {'pipnn', 'random'}, optional
Graph initialization method. Default is 'pipnn'.
"""
Expand Down Expand Up @@ -522,7 +524,8 @@ class QGKMeans(_KMeans):
Stop when the absolute relative objective change is at most this
threshold. Default is 0.0.
num_threads : int, optional
Worker count; 0 selects the available CPU count. Default is 0.
Worker count; 0 selects the available CPU count,
capped by OMP_NUM_THREADS. Default is 0.
final_assignment : FinalAssignmentMode, optional
Approximate uses the training assignment method; Exact uses exhaustive
assignment against final centroids. Default is
Expand Down Expand Up @@ -586,7 +589,8 @@ class RaBitQKMeans(_KMeans):
Stop when the absolute relative objective change is at most this
threshold. Default is 0.0.
num_threads : int, optional
Worker count; 0 selects the available CPU count. Default is 0.
Worker count; 0 selects the available CPU count,
capped by OMP_NUM_THREADS. Default is 0.
final_assignment : FinalAssignmentMode, optional
Approximate uses the training assignment method; Exact uses exhaustive
assignment against final centroids. Default is
Expand Down
Loading
Loading